Code

moving trunk for module inkscape
[inkscape.git] / src / svg / svg-affine.cpp
1 #define __SP_SVG_AFFINE_C__
3 /*
4  * SVG data parser
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   Raph Levien <raph@acm.org>
9  *
10  * Copyright (C) 1999-2002 Lauris Kaplinski
11  * Copyright (C) 1999 Raph Levien
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
20 #include <glib/gstrfuncs.h>
21 #include <libnr/nr-matrix-fns.h>
22 #include <libnr/nr-matrix-ops.h>
23 #include <libnr/nr-matrix-translate-ops.h>
24 #include <libnr/nr-rotate-fns.h>
25 #include <libnr/nr-rotate-matrix-ops.h>
26 #include <libnr/nr-scale-matrix-ops.h>
27 #include <libnr/nr-translate-matrix-ops.h>
28 #include <libnr/nr-translate-rotate-ops.h>
29 #include "svg.h"
31 #ifndef M_PI
32 # define M_PI 3.14159265358979323846
33 #endif
35 bool
36 sp_svg_transform_read(gchar const *str, NR::Matrix *transform)
37 {
38         int idx;
39         char keyword[32];
40         double args[6];
41         int n_args;
42         size_t key_len;
44         if (str == NULL) return false;
46         NR::Matrix a(NR::identity());
48         idx = 0;
49         while (str[idx]) {
50                 /* skip initial whitespace */
51                 while (g_ascii_isspace (str[idx])) idx++;
53                 /* parse keyword */
54                 for (key_len = 0; key_len < sizeof (keyword); key_len++) {
55                         char c;
57                         c = str[idx];
58                         if (g_ascii_isalpha (c) || c == '-') {
59                                 keyword[key_len] = str[idx++];
60                         } else {
61                                 break;
62                         }
63                 }
64                 if (key_len >= sizeof (keyword)) return false;
65                 keyword[key_len] = '\0';
67                 /* skip whitespace */
68                 while (g_ascii_isspace (str[idx])) idx++;
70                 if (str[idx] != '(') return false;
71                 idx++;
73                 for (n_args = 0; ; n_args++) {
74                         char c;
75                         char *end_ptr;
77                         /* skip whitespace */
78                         while (g_ascii_isspace (str[idx])) idx++;
79                         c = str[idx];
80                         if (g_ascii_isdigit (c) || c == '+' || c == '-' || c == '.') {
81                                 if (n_args == sizeof (args) / sizeof (args[0])) return false; /* Too many args */
82                                 args[n_args] = g_ascii_strtod (str + idx, &end_ptr);
83                                 
84                                 //printf("took %d chars from '%s' to make %f\n",
85                                 //              end_ptr-(str+idx),
86                                 //              str+idx,
87                                 //              args[n_args]);
89                                 idx = end_ptr - (char *) str;
91                                 while (g_ascii_isspace (str[idx])) idx++;
93                                 /* skip optional comma */
94                                 if (str[idx] == ',') idx++;
95                         } else if (c == ')') {
96                                 break;
97                         } else {
98                                 return false;
99                         }
100                 }
101                 idx++;
103                 /* ok, have parsed keyword and args, now modify the transform */
104                 if (!strcmp (keyword, "matrix")) {
105                         if (n_args != 6) return false;
106                         a = NR_MATRIX_D_FROM_DOUBLE(args) * a;
107                 } else if (!strcmp (keyword, "translate")) {
108                         if (n_args == 1) {
109                                 args[1] = 0;
110                         } else if (n_args != 2) {
111                                 return false;
112                         }
113                         a = NR::translate(args[0], args[1]) * a;
114                 } else if (!strcmp (keyword, "scale")) {
115                         if (n_args == 1) {
116                                 args[1] = args[0];
117                         } else if (n_args != 2) {
118                                 return false;
119                         }
120                         a = NR::scale(args[0], args[1]) * a;
121                 } else if (!strcmp (keyword, "rotate")) {
122                         if (n_args != 1 && n_args != 3) {
123                                 return false;
124                         }
125                         NR::rotate const rot(rotate_degrees(args[0]));
126                         if (n_args == 3) {
127                                 a = ( NR::translate(-args[1], -args[2])
128                                       * rot
129                                       * NR::translate(args[1], args[2])
130                                       * a );
131                         } else {
132                                 a = rot * a;
133                         }
134                 } else if (!strcmp (keyword, "skewX")) {
135                         if (n_args != 1) return false;
136                         a = ( NR::Matrix(1, 0,
137                                          tan(args[0] * M_PI / 180.0), 1,
138                                          0, 0)
139                               * a );
140                 } else if (!strcmp (keyword, "skewY")) {
141                         if (n_args != 1) return false;
142                         a = ( NR::Matrix(1, tan(args[0] * M_PI / 180.0),
143                                          0, 1,
144                                          0, 0)
145                               * a );
146                 } else {
147                         return false; /* unknown keyword */
148                 }
149                 /* Skip trailing whitespace */
150              while (g_ascii_isspace (str[idx])) idx++;
151         }
153         *transform = a;
154         return true;
157 #define EQ(a,b) (fabs ((a) - (b)) < 1e-9)
159 unsigned
160 sp_svg_transform_write(gchar str[], unsigned const size, NR::Matrix const &transform)
162         NRMatrix const t(transform);
163         return sp_svg_transform_write(str, size, &t);
166 unsigned
167 sp_svg_transform_write(gchar str[], unsigned const size, NRMatrix const *transform)
169         double e;
171         if (!transform) {
172                 *str = 0;
173                 return 0;
174         }
176         e = 0.000001 * NR_MATRIX_DF_EXPANSION (transform);
178         /* fixme: We could use t1 * t1 + t2 * t2 here instead */
179         if (NR_DF_TEST_CLOSE (transform->c[1], 0.0, e) && NR_DF_TEST_CLOSE (transform->c[2], 0.0, e)) {
180                 if (NR_DF_TEST_CLOSE (transform->c[4], 0.0, e) && NR_DF_TEST_CLOSE (transform->c[5], 0.0, e)) {
181                         if (NR_DF_TEST_CLOSE (transform->c[0], 1.0, e) && NR_DF_TEST_CLOSE (transform->c[3], 1.0, e)) {
182                                 /* We are more or less identity */
183                                 *str = 0;
184                                 return 0;
185                         } else {
186                                 /* We are more or less scale */
187                                 gchar c[256];
188                                 unsigned p = 0;
189                                 strcpy (c + p, "scale(");
190                                 p += 6;
191                                 p += sp_svg_number_write_de (c + p, transform->c[0], 6, FALSE);
192                                 c[p++] = ',';
193                                 p += sp_svg_number_write_de (c + p, transform->c[3], 6, FALSE);
194                                 c[p++] = ')';
195                                 g_assert( p <= sizeof(c) );
196                                 p = MIN (p, size - 1 );
197                                 memcpy (str, c, p);
198                                 str[p] = 0;
199                                 return p;
200                         }
201                 } else {
202                         if (NR_DF_TEST_CLOSE (transform->c[0], 1.0, e) && NR_DF_TEST_CLOSE (transform->c[3], 1.0, e)) {
203                                 /* We are more or less translate */
204                                 gchar c[256];
205                                 unsigned p = 0;
206                                 strcpy (c + p, "translate(");
207                                 p += 10;
208                                 p += sp_svg_number_write_de (c + p, transform->c[4], 6, FALSE);
209                                 c[p++] = ',';
210                                 p += sp_svg_number_write_de (c + p, transform->c[5], 6, FALSE);
211                                 c[p++] = ')';
212                                 g_assert( p <= sizeof(c) );
213                                 p = MIN(p, size - 1);
214                                 memcpy (str, c, p);
215                                 str[p] = 0;
216                                 return p;
217                         } else {
218                                 gchar c[256];
219                                 unsigned p = 0;
220                                 strcpy (c + p, "matrix(");
221                                 p += 7;
222                                 p += sp_svg_number_write_de (c + p, transform->c[0], 6, FALSE);
223                                 c[p++] = ',';
224                                 p += sp_svg_number_write_de (c + p, transform->c[1], 6, FALSE);
225                                 c[p++] = ',';
226                                 p += sp_svg_number_write_de (c + p, transform->c[2], 6, FALSE);
227                                 c[p++] = ',';
228                                 p += sp_svg_number_write_de (c + p, transform->c[3], 6, FALSE);
229                                 c[p++] = ',';
230                                 p += sp_svg_number_write_de (c + p, transform->c[4], 6, FALSE);
231                                 c[p++] = ',';
232                                 p += sp_svg_number_write_de (c + p, transform->c[5], 6, FALSE);
233                                 c[p++] = ')';
234                                 g_assert( p <= sizeof(c) );
235                                 p = MIN(p, size - 1);
236                                 memcpy (str, c, p);
237                                 str[p] = 0;
238                                 return p;
239                         }
240                 }
241         } else {
242                 gchar c[256];
243                 unsigned p = 0;
244                 strcpy (c + p, "matrix(");
245                 p += 7;
246                 p += sp_svg_number_write_de (c + p, transform->c[0], 6, FALSE);
247                 c[p++] = ',';
248                 p += sp_svg_number_write_de (c + p, transform->c[1], 6, FALSE);
249                 c[p++] = ',';
250                 p += sp_svg_number_write_de (c + p, transform->c[2], 6, FALSE);
251                 c[p++] = ',';
252                 p += sp_svg_number_write_de (c + p, transform->c[3], 6, FALSE);
253                 c[p++] = ',';
254                 p += sp_svg_number_write_de (c + p, transform->c[4], 6, FALSE);
255                 c[p++] = ',';
256                 p += sp_svg_number_write_de (c + p, transform->c[5], 6, FALSE);
257                 c[p++] = ')';
258                 g_assert( p <= sizeof(c) );
259                 p = MIN(p, size - 1);
260                 memcpy (str, c, p);
261                 str[p] = 0;
262                 return p;
263         }