24
22
#include <glib/gstrfuncs.h>
25
23
#include <libnr/nr-matrix-fns.h>
26
24
#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>
25
#include <2geom/transforms.h>
26
#include <2geom/angle.h>
27
#include <libnr/nr-convert2geom.h>
34
#include "prefs-utils.h"
29
#include "preferences.h"
37
32
# define M_PI 3.14159265358979323846
41
sp_svg_transform_read(gchar const *str, NR::Matrix *transform)
36
sp_svg_transform_read(gchar const *str, Geom::Matrix *transform)
49
if (str == NULL) return false;
51
NR::Matrix a(NR::identity());
55
/* skip initial whitespace */
56
while (g_ascii_isspace (str[idx])) idx++;
59
for (key_len = 0; key_len < sizeof (keyword); key_len++) {
63
if (g_ascii_isalpha (c) || c == '-') {
64
keyword[key_len] = str[idx++];
69
if (key_len >= sizeof (keyword)) return false;
70
keyword[key_len] = '\0';
73
while (g_ascii_isspace (str[idx])) idx++;
75
if (str[idx] != '(') return false;
78
for (n_args = 0; ; n_args++) {
83
while (g_ascii_isspace (str[idx])) idx++;
85
if (g_ascii_isdigit (c) || c == '+' || c == '-' || c == '.') {
86
if (n_args == sizeof (args) / sizeof (args[0])) return false; /* Too many args */
87
args[n_args] = g_ascii_strtod (str + idx, &end_ptr);
89
//printf("took %d chars from '%s' to make %f\n",
94
idx = end_ptr - (char *) str;
96
while (g_ascii_isspace (str[idx])) idx++;
98
/* skip optional comma */
99
if (str[idx] == ',') idx++;
100
} else if (c == ')') {
108
/* ok, have parsed keyword and args, now modify the transform */
109
if (!strcmp (keyword, "matrix")) {
110
if (n_args != 6) return false;
111
a = NR_MATRIX_D_FROM_DOUBLE(args) * a;
112
} else if (!strcmp (keyword, "translate")) {
115
} else if (n_args != 2) {
118
a = NR::translate(args[0], args[1]) * a;
119
} else if (!strcmp (keyword, "scale")) {
122
} else if (n_args != 2) {
125
a = NR::scale(args[0], args[1]) * a;
126
} else if (!strcmp (keyword, "rotate")) {
127
if (n_args != 1 && n_args != 3) {
130
NR::rotate const rot(rotate_degrees(args[0]));
132
a = ( NR::translate(-args[1], -args[2])
134
* NR::translate(args[1], args[2])
139
} else if (!strcmp (keyword, "skewX")) {
140
if (n_args != 1) return false;
141
a = ( NR::Matrix(1, 0,
142
tan(args[0] * M_PI / 180.0), 1,
145
} else if (!strcmp (keyword, "skewY")) {
146
if (n_args != 1) return false;
147
a = ( NR::Matrix(1, tan(args[0] * M_PI / 180.0),
152
return false; /* unknown keyword */
154
/* Skip trailing whitespace */
44
if (str == NULL) return false;
46
Geom::Matrix a(Geom::identity());
50
/* skip initial whitespace */
51
while (g_ascii_isspace (str[idx])) idx++;
54
for (key_len = 0; key_len < sizeof (keyword); key_len++) {
58
if (g_ascii_isalpha (c) || c == '-') {
59
keyword[key_len] = str[idx++];
64
if (key_len >= sizeof (keyword)) return false;
65
keyword[key_len] = '\0';
68
while (g_ascii_isspace (str[idx])) idx++;
70
if (str[idx] != '(') return false;
73
for (n_args = 0; ; n_args++) {
78
while (g_ascii_isspace (str[idx])) 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);
84
//printf("took %d chars from '%s' to make %f\n",
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 == ')') {
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 = (*((Geom::Matrix *) &(args)[0])) * a;
107
} else if (!strcmp (keyword, "translate")) {
110
} else if (n_args != 2) {
113
a = Geom::Translate(args[0], args[1]) * a;
114
} else if (!strcmp (keyword, "scale")) {
117
} else if (n_args != 2) {
120
a = Geom::Scale(args[0], args[1]) * a;
121
} else if (!strcmp (keyword, "rotate")) {
122
if (n_args != 1 && n_args != 3) {
125
Geom::Rotate const rot(Geom::deg_to_rad(args[0]));
127
a = ( Geom::Translate(-args[1], -args[2])
129
* Geom::Translate(args[1], args[2])
134
} else if (!strcmp (keyword, "skewX")) {
135
if (n_args != 1) return false;
136
a = ( Geom::Matrix(1, 0,
137
tan(args[0] * M_PI / 180.0), 1,
140
} else if (!strcmp (keyword, "skewY")) {
141
if (n_args != 1) return false;
142
a = ( Geom::Matrix(1, tan(args[0] * M_PI / 180.0),
147
return false; /* unknown keyword */
149
/* Skip trailing whitespace */
155
150
while (g_ascii_isspace (str[idx])) idx++;
162
157
#define EQ(a,b) (fabs ((a) - (b)) < 1e-9)
165
sp_svg_transform_write(NR::Matrix const &transform)
160
sp_svg_transform_write(Geom::Matrix const &transform)
167
NRMatrix const t(transform);
168
return sp_svg_transform_write(&t);
162
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
164
double e = 0.000001 * transform.descrim();
165
int prec = prefs->getInt("/options/svgoutput/numericprecision", 8);
166
int min_exp = prefs->getInt("/options/svgoutput/minimumexponent", -8);
168
/* fixme: We could use t1 * t1 + t2 * t2 here instead */
169
if ( Geom::are_near(transform[1], 0.0, e) && Geom::are_near (transform[2], 0.0, e)) {
170
if (Geom::are_near (transform[4], 0.0, e) && Geom::are_near (transform[5], 0.0, e)) {
171
if (Geom::are_near (transform[0], 1.0, e) && Geom::are_near (transform[3], 1.0, e)) {
172
/* We are more or less identity */
175
/* We are more or less scale */
178
strcpy (c + p, "scale(");
180
p += sp_svg_number_write_de (c + p, transform[0], prec, min_exp);
182
p += sp_svg_number_write_de (c + p, transform[3], prec, min_exp);
185
g_assert( p <= sizeof(c) );
189
if (Geom::are_near (transform[0], 1.0, e) && Geom::are_near (transform[3], 1.0, e)) {
190
/* We are more or less translate */
193
strcpy (c + p, "translate(");
195
p += sp_svg_number_write_de (c + p, transform[4], prec, min_exp);
197
p += sp_svg_number_write_de (c + p, transform[5], prec, min_exp);
200
g_assert( p <= sizeof(c) );
205
strcpy (c + p, "matrix(");
207
p += sp_svg_number_write_de (c + p, transform[0], prec, min_exp);
209
p += sp_svg_number_write_de (c + p, transform[1], prec, min_exp);
211
p += sp_svg_number_write_de (c + p, transform[2], prec, min_exp);
213
p += sp_svg_number_write_de (c + p, transform[3], prec, min_exp);
215
p += sp_svg_number_write_de (c + p, transform[4], prec, min_exp);
217
p += sp_svg_number_write_de (c + p, transform[5], prec, min_exp);
220
g_assert( p <= sizeof(c) );
227
strcpy (c + p, "matrix(");
229
p += sp_svg_number_write_de (c + p, transform[0], prec, min_exp);
231
p += sp_svg_number_write_de (c + p, transform[1], prec, min_exp);
233
p += sp_svg_number_write_de (c + p, transform[2], prec, min_exp);
235
p += sp_svg_number_write_de (c + p, transform[3], prec, min_exp);
237
p += sp_svg_number_write_de (c + p, transform[4], prec, min_exp);
239
p += sp_svg_number_write_de (c + p, transform[5], prec, min_exp);
242
g_assert( p <= sizeof(c) );
172
sp_svg_transform_write(NRMatrix const *transform)
249
sp_svg_transform_write(Geom::Matrix const *transform)
180
e = 0.000001 * NR_MATRIX_DF_EXPANSION (transform);
181
int prec = prefs_get_int_attribute("options.svgoutput", "numericprecision", 8);
182
int min_exp = prefs_get_int_attribute("options.svgoutput", "minimumexponent", -8);
184
/* fixme: We could use t1 * t1 + t2 * t2 here instead */
185
if (NR_DF_TEST_CLOSE (transform->c[1], 0.0, e) && NR_DF_TEST_CLOSE (transform->c[2], 0.0, e)) {
186
if (NR_DF_TEST_CLOSE (transform->c[4], 0.0, e) && NR_DF_TEST_CLOSE (transform->c[5], 0.0, e)) {
187
if (NR_DF_TEST_CLOSE (transform->c[0], 1.0, e) && NR_DF_TEST_CLOSE (transform->c[3], 1.0, e)) {
188
/* We are more or less identity */
191
/* We are more or less scale */
194
strcpy (c + p, "scale(");
196
p += sp_svg_number_write_de (c + p, transform->c[0], prec, min_exp, FALSE);
198
p += sp_svg_number_write_de (c + p, transform->c[3], prec, min_exp, FALSE);
201
g_assert( p <= sizeof(c) );
205
if (NR_DF_TEST_CLOSE (transform->c[0], 1.0, e) && NR_DF_TEST_CLOSE (transform->c[3], 1.0, e)) {
206
/* We are more or less translate */
209
strcpy (c + p, "translate(");
211
p += sp_svg_number_write_de (c + p, transform->c[4], prec, min_exp, FALSE);
213
p += sp_svg_number_write_de (c + p, transform->c[5], prec, min_exp, FALSE);
216
g_assert( p <= sizeof(c) );
221
strcpy (c + p, "matrix(");
223
p += sp_svg_number_write_de (c + p, transform->c[0], prec, min_exp, FALSE);
225
p += sp_svg_number_write_de (c + p, transform->c[1], prec, min_exp, FALSE);
227
p += sp_svg_number_write_de (c + p, transform->c[2], prec, min_exp, FALSE);
229
p += sp_svg_number_write_de (c + p, transform->c[3], prec, min_exp, FALSE);
231
p += sp_svg_number_write_de (c + p, transform->c[4], prec, min_exp, FALSE);
233
p += sp_svg_number_write_de (c + p, transform->c[5], prec, min_exp, FALSE);
236
g_assert( p <= sizeof(c) );
243
strcpy (c + p, "matrix(");
245
p += sp_svg_number_write_de (c + p, transform->c[0], prec, min_exp, FALSE);
247
p += sp_svg_number_write_de (c + p, transform->c[1], prec, min_exp, FALSE);
249
p += sp_svg_number_write_de (c + p, transform->c[2], prec, min_exp, FALSE);
251
p += sp_svg_number_write_de (c + p, transform->c[3], prec, min_exp, FALSE);
253
p += sp_svg_number_write_de (c + p, transform->c[4], prec, min_exp, FALSE);
255
p += sp_svg_number_write_de (c + p, transform->c[5], prec, min_exp, FALSE);
258
g_assert( p <= sizeof(c) );
251
return sp_svg_transform_write(*transform);
257
c-file-style:"stroustrup"
258
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
263
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :