Code

remove many unnecessary to_2geom and from_2geom calls
[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 <cstring>
21 #include <string>
22 #include <cstdlib>
23 #include <cstdio>
24 #include <glib/gstrfuncs.h>
25 #include <libnr/nr-matrix-fns.h>
26 #include <libnr/nr-matrix-ops.h>
27 #include <libnr/nr-matrix-translate-ops.h>
28 #include <libnr/nr-rotate-fns.h>
29 #include <libnr/nr-rotate-matrix-ops.h>
30 #include <libnr/nr-scale-matrix-ops.h>
31 #include <libnr/nr-translate-matrix-ops.h>
32 #include <libnr/nr-translate-rotate-ops.h>
33 #include <libnr/nr-convert2geom.h>
34 #include "svg.h"
35 #include "prefs-utils.h"
37 #ifndef M_PI
38 # define M_PI 3.14159265358979323846
39 #endif
41 bool
42 sp_svg_transform_read(gchar const *str, Geom::Matrix *transform)
43 {
44     NR::Matrix mat;
45     if (sp_svg_transform_read(str, &mat)) {
46         *transform = mat;
47         return true;
48     } else {
49         return false;
50     }
51 }
53 bool
54 sp_svg_transform_read(gchar const *str, NR::Matrix *transform)
55 {
56         int idx;
57         char keyword[32];
58         double args[6];
59         int n_args;
60         size_t key_len;
62         if (str == NULL) return false;
64         NR::Matrix a(NR::identity());
66         idx = 0;
67         while (str[idx]) {
68                 /* skip initial whitespace */
69                 while (g_ascii_isspace (str[idx])) idx++;
71                 /* parse keyword */
72                 for (key_len = 0; key_len < sizeof (keyword); key_len++) {
73                         char c;
75                         c = str[idx];
76                         if (g_ascii_isalpha (c) || c == '-') {
77                                 keyword[key_len] = str[idx++];
78                         } else {
79                                 break;
80                         }
81                 }
82                 if (key_len >= sizeof (keyword)) return false;
83                 keyword[key_len] = '\0';
85                 /* skip whitespace */
86                 while (g_ascii_isspace (str[idx])) idx++;
88                 if (str[idx] != '(') return false;
89                 idx++;
91                 for (n_args = 0; ; n_args++) {
92                         char c;
93                         char *end_ptr;
95                         /* skip whitespace */
96                         while (g_ascii_isspace (str[idx])) idx++;
97                         c = str[idx];
98                         if (g_ascii_isdigit (c) || c == '+' || c == '-' || c == '.') {
99                                 if (n_args == sizeof (args) / sizeof (args[0])) return false; /* Too many args */
100                                 args[n_args] = g_ascii_strtod (str + idx, &end_ptr);
101                                 
102                                 //printf("took %d chars from '%s' to make %f\n",
103                                 //              end_ptr-(str+idx),
104                                 //              str+idx,
105                                 //              args[n_args]);
107                                 idx = end_ptr - (char *) str;
109                                 while (g_ascii_isspace (str[idx])) idx++;
111                                 /* skip optional comma */
112                                 if (str[idx] == ',') idx++;
113                         } else if (c == ')') {
114                                 break;
115                         } else {
116                                 return false;
117                         }
118                 }
119                 idx++;
121                 /* ok, have parsed keyword and args, now modify the transform */
122                 if (!strcmp (keyword, "matrix")) {
123                         if (n_args != 6) return false;
124                         a = (*NR_MATRIX_D_FROM_DOUBLE(args)) * a;
125                 } else if (!strcmp (keyword, "translate")) {
126                         if (n_args == 1) {
127                                 args[1] = 0;
128                         } else if (n_args != 2) {
129                                 return false;
130                         }
131                         a = NR::translate(args[0], args[1]) * a;
132                 } else if (!strcmp (keyword, "scale")) {
133                         if (n_args == 1) {
134                                 args[1] = args[0];
135                         } else if (n_args != 2) {
136                                 return false;
137                         }
138                         a = NR::scale(args[0], args[1]) * a;
139                 } else if (!strcmp (keyword, "rotate")) {
140                         if (n_args != 1 && n_args != 3) {
141                                 return false;
142                         }
143                         NR::rotate const rot(rotate_degrees(args[0]));
144                         if (n_args == 3) {
145                                 a = ( NR::translate(-args[1], -args[2])
146                                       * rot
147                                       * NR::translate(args[1], args[2])
148                                       * a );
149                         } else {
150                                 a = rot * a;
151                         }
152                 } else if (!strcmp (keyword, "skewX")) {
153                         if (n_args != 1) return false;
154                         a = ( NR::Matrix(1, 0,
155                                          tan(args[0] * M_PI / 180.0), 1,
156                                          0, 0)
157                               * a );
158                 } else if (!strcmp (keyword, "skewY")) {
159                         if (n_args != 1) return false;
160                         a = ( NR::Matrix(1, tan(args[0] * M_PI / 180.0),
161                                          0, 1,
162                                          0, 0)
163                               * a );
164                 } else {
165                         return false; /* unknown keyword */
166                 }
167                 /* Skip trailing whitespace */
168              while (g_ascii_isspace (str[idx])) idx++;
169         }
171         *transform = a;
172         return true;
175 #define EQ(a,b) (fabs ((a) - (b)) < 1e-9)
177 gchar *
178 sp_svg_transform_write(Geom::Matrix const &transform)
180     return sp_svg_transform_write(&transform);
184 gchar *
185 sp_svg_transform_write(Geom::Matrix const *transform)
187     NR::Matrix const t(*transform);
188     return sp_svg_transform_write(&t);
191 gchar *
192 sp_svg_transform_write(NR::Matrix const &transform)
194         NR::Matrix const t(transform);
195         return sp_svg_transform_write(&t);
198 gchar *
199 sp_svg_transform_write(NR::Matrix const *transform)
201         double e;
203         if (!transform) {
204                 return NULL;
205         }
207         e = 0.000001 * NR::expansion(*transform);
208         int prec = prefs_get_int_attribute("options.svgoutput", "numericprecision", 8);
209         int min_exp = prefs_get_int_attribute("options.svgoutput", "minimumexponent", -8);
211         /* fixme: We could use t1 * t1 + t2 * t2 here instead */
212         if (NR_DF_TEST_CLOSE ((*transform)[1], 0.0, e) && NR_DF_TEST_CLOSE ((*transform)[2], 0.0, e)) {
213                 if (NR_DF_TEST_CLOSE ((*transform)[4], 0.0, e) && NR_DF_TEST_CLOSE ((*transform)[5], 0.0, e)) {
214                         if (NR_DF_TEST_CLOSE ((*transform)[0], 1.0, e) && NR_DF_TEST_CLOSE ((*transform)[3], 1.0, e)) {
215                                 /* We are more or less identity */
216                                 return NULL;
217                         } else {
218                                 /* We are more or less scale */
219                                 gchar c[256];
220                                 unsigned p = 0;
221                                 strcpy (c + p, "scale(");
222                                 p += 6;
223                                 p += sp_svg_number_write_de (c + p, (*transform)[0], prec, min_exp);
224                                 c[p++] = ',';
225                                 p += sp_svg_number_write_de (c + p, (*transform)[3], prec, min_exp);
226                                 c[p++] = ')';
227                                 c[p] = '\000';
228                                 g_assert( p <= sizeof(c) );
229                                 return g_strdup(c);
230                         }
231                 } else {
232                         if (NR_DF_TEST_CLOSE ((*transform)[0], 1.0, e) && NR_DF_TEST_CLOSE ((*transform)[3], 1.0, e)) {
233                                 /* We are more or less translate */
234                                 gchar c[256];
235                                 unsigned p = 0;
236                                 strcpy (c + p, "translate(");
237                                 p += 10;
238                                 p += sp_svg_number_write_de (c + p, (*transform)[4], prec, min_exp);
239                                 c[p++] = ',';
240                                 p += sp_svg_number_write_de (c + p, (*transform)[5], prec, min_exp);
241                                 c[p++] = ')';
242                                 c[p] = '\000';
243                                 g_assert( p <= sizeof(c) );
244                                 return g_strdup(c);
245                         } else {
246                                 gchar c[256];
247                                 unsigned p = 0;
248                                 strcpy (c + p, "matrix(");
249                                 p += 7;
250                                 p += sp_svg_number_write_de (c + p, (*transform)[0], prec, min_exp);
251                                 c[p++] = ',';
252                                 p += sp_svg_number_write_de (c + p, (*transform)[1], prec, min_exp);
253                                 c[p++] = ',';
254                                 p += sp_svg_number_write_de (c + p, (*transform)[2], prec, min_exp);
255                                 c[p++] = ',';
256                                 p += sp_svg_number_write_de (c + p, (*transform)[3], prec, min_exp);
257                                 c[p++] = ',';
258                                 p += sp_svg_number_write_de (c + p, (*transform)[4], prec, min_exp);
259                                 c[p++] = ',';
260                                 p += sp_svg_number_write_de (c + p, (*transform)[5], prec, min_exp);
261                                 c[p++] = ')';
262                                 c[p] = '\000';
263                                 g_assert( p <= sizeof(c) );
264                                 return g_strdup(c);
265                         }
266                 }
267         } else {
268                 gchar c[256];
269                 unsigned p = 0;
270                 strcpy (c + p, "matrix(");
271                 p += 7;
272                 p += sp_svg_number_write_de (c + p, (*transform)[0], prec, min_exp);
273                 c[p++] = ',';
274                 p += sp_svg_number_write_de (c + p, (*transform)[1], prec, min_exp);
275                 c[p++] = ',';
276                 p += sp_svg_number_write_de (c + p, (*transform)[2], prec, min_exp);
277                 c[p++] = ',';
278                 p += sp_svg_number_write_de (c + p, (*transform)[3], prec, min_exp);
279                 c[p++] = ',';
280                 p += sp_svg_number_write_de (c + p, (*transform)[4], prec, min_exp);
281                 c[p++] = ',';
282                 p += sp_svg_number_write_de (c + p, (*transform)[5], prec, min_exp);
283                 c[p++] = ')';
284                 c[p] = '\000';
285                 g_assert( p <= sizeof(c) );
286                 return g_strdup(c);
287         }