1
#include <cxxtest/TestSuite.h>
5
#include <2geom/matrix.h>
12
class SvgAffineTest : public CxxTest::TestSuite
19
struct approx_equal_pred {
20
bool operator()(Geom::Matrix const &ref, Geom::Matrix const &cm) const
22
double maxabsdiff = 0;
23
for(size_t i=0; i<6; i++) {
24
maxabsdiff = std::max(std::abs(ref[i]-cm[i]), maxabsdiff);
26
return maxabsdiff < 1e-14;
29
static test_t const read_matrix_tests[3];
30
static test_t const read_translate_tests[3];
31
static test_t const read_scale_tests[3];
32
static test_t const read_rotate_tests[4];
33
static test_t const read_skew_tests[3];
34
static char const * const read_fail_tests[25];
35
static test_t const write_matrix_tests[2];
36
static test_t const write_translate_tests[3];
37
static test_t const write_scale_tests[2];
38
static test_t const write_rotate_tests[2];
39
static test_t const write_skew_tests[3];
44
// createSuite and destroySuite get us per-suite setup and teardown
45
// without us having to worry about static initialization order, etc.
46
static SvgAffineTest *createSuite() { return new SvgAffineTest(); }
47
static void destroySuite( SvgAffineTest *suite ) { delete suite; }
49
void testReadIdentity()
51
char const* strs[] = {
54
"matrix(1,0,0,1,0,0)",
60
size_t n = G_N_ELEMENTS(strs);
61
for(size_t i=0; i<n; i++) {
63
TSM_ASSERT(strs[i] , sp_svg_transform_read(strs[i], &cm));
64
TSM_ASSERT_EQUALS(strs[i] , Geom::identity() , cm);
68
void testWriteIdentity()
70
TS_ASSERT_EQUALS(sp_svg_transform_write(Geom::identity()) , (void*)0)
75
for(size_t i=0; i<G_N_ELEMENTS(read_matrix_tests); i++) {
77
TSM_ASSERT(read_matrix_tests[i].str , sp_svg_transform_read(read_matrix_tests[i].str, &cm));
78
TSM_ASSERT_RELATION(read_matrix_tests[i].str , approx_equal_pred , read_matrix_tests[i].matrix , cm);
82
void testReadTranslate()
84
for(size_t i=0; i<G_N_ELEMENTS(read_translate_tests); i++) {
86
TSM_ASSERT(read_translate_tests[i].str , sp_svg_transform_read(read_translate_tests[i].str, &cm));
87
TSM_ASSERT_RELATION(read_translate_tests[i].str , approx_equal_pred , read_translate_tests[i].matrix , cm);
93
for(size_t i=0; i<G_N_ELEMENTS(read_scale_tests); i++) {
95
TSM_ASSERT(read_scale_tests[i].str , sp_svg_transform_read(read_scale_tests[i].str, &cm));
96
TSM_ASSERT_RELATION(read_scale_tests[i].str , approx_equal_pred , read_scale_tests[i].matrix , cm);
100
void testReadRotate()
102
for(size_t i=0; i<G_N_ELEMENTS(read_rotate_tests); i++) {
104
TSM_ASSERT(read_rotate_tests[i].str , sp_svg_transform_read(read_rotate_tests[i].str, &cm));
105
TSM_ASSERT_RELATION(read_rotate_tests[i].str , approx_equal_pred , read_rotate_tests[i].matrix , cm);
111
for(size_t i=0; i<G_N_ELEMENTS(read_skew_tests); i++) {
113
TSM_ASSERT(read_skew_tests[i].str , sp_svg_transform_read(read_skew_tests[i].str, &cm));
114
TSM_ASSERT_RELATION(read_skew_tests[i].str , approx_equal_pred , read_skew_tests[i].matrix , cm);
118
void testWriteMatrix()
120
for(size_t i=0; i<G_N_ELEMENTS(write_matrix_tests); i++) {
121
char * str = sp_svg_transform_write(write_matrix_tests[i].matrix);
122
TS_ASSERT_RELATION(streq_rel , str , write_matrix_tests[i].str);
127
void testWriteTranslate()
129
for(size_t i=0; i<G_N_ELEMENTS(write_translate_tests); i++) {
130
char * str = sp_svg_transform_write(write_translate_tests[i].matrix);
131
TS_ASSERT_RELATION(streq_rel , str , write_translate_tests[i].str);
136
void testWriteScale()
138
for(size_t i=0; i<G_N_ELEMENTS(write_scale_tests); i++) {
139
char * str = sp_svg_transform_write(write_scale_tests[i].matrix);
140
TS_ASSERT_RELATION(streq_rel , str , write_scale_tests[i].str);
145
void testWriteRotate()
147
for(size_t i=0; i<G_N_ELEMENTS(write_rotate_tests); i++) {
148
char * str = sp_svg_transform_write(write_rotate_tests[i].matrix);
149
TS_ASSERT_RELATION(streq_rel , str , write_rotate_tests[i].str);
156
for(size_t i=0; i<G_N_ELEMENTS(write_skew_tests); i++) {
157
char * str = sp_svg_transform_write(write_skew_tests[i].matrix);
158
TS_ASSERT_RELATION(streq_rel , str , write_skew_tests[i].str);
163
void testReadConcatenation()
165
// NOTE: According to the SVG specification (see the syntax at http://www.w3.org/TR/SVG/coords.html#TransformAttribute
166
// there should be 1 or more comma-wsp sequences between transforms... This doesn't make sense and it seems
167
// likely that instead of a + they meant a ? (zero or one comma-wsp sequences).
168
char const * str = "skewY(17)skewX(9)translate(7,13)scale(2)rotate(13)translate(3,5)";
169
Geom::Matrix ref(2.0199976232558053, 1.0674773585906016, -0.14125199392774669, 1.9055550612095459, 14.412730624347654, 28.499820929377454); // Precomputed using Mathematica
171
TS_ASSERT(sp_svg_transform_read(str, &cm));
172
TS_ASSERT_RELATION(approx_equal_pred , ref , cm);
175
void testReadFailures()
177
for(size_t i=0; i<G_N_ELEMENTS(read_fail_tests); i++) {
179
TSM_ASSERT(read_fail_tests[i] , !sp_svg_transform_read(read_fail_tests[i], &cm));
184
static double const DEGREE = M_PI/180.;
186
SvgAffineTest::test_t const SvgAffineTest::read_matrix_tests[3] = {
187
{"matrix(0,0,0,0,0,0)",Geom::Matrix(0,0,0,0,0,0)},
188
{" matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)},
189
{"matrix (1 2 -3,-4,5e6,-6e-7)",Geom::Matrix(1,2,-3,-4,5e6,-6e-7)}};
190
SvgAffineTest::test_t const SvgAffineTest::read_translate_tests[3] = {
191
{"translate(1)",Geom::Matrix(1,0,0,1,1,0)},
192
{"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)},
193
{"translate(-1e3 .123e2)",Geom::Matrix(1,0,0,1,-1e3,.123e2)}};
194
SvgAffineTest::test_t const SvgAffineTest::read_scale_tests[3] = {
195
{"scale(2)",Geom::Matrix(2,0,0,2,0,0)},
196
{"scale(2,3)",Geom::Matrix(2,0,0,3,0,0)},
197
{"scale(0.1e-2 -.475e0)",Geom::Matrix(0.1e-2,0,0,-.475e0,0,0)}};
198
SvgAffineTest::test_t const SvgAffineTest::read_rotate_tests[4] = {
199
{"rotate(13 )",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)},
200
{"rotate(-13)",Geom::Matrix(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),0,0)},
201
{"rotate(373)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)},
202
{"rotate(13,7,11)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),(1-cos(13.*DEGREE))*7+sin(13.*DEGREE)*11,(1-cos(13.*DEGREE))*11-sin(13.*DEGREE)*7)}};
203
SvgAffineTest::test_t const SvgAffineTest::read_skew_tests[3] = {
204
{"skewX( 30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)},
205
{"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)},
206
{"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}};
207
char const * const SvgAffineTest::read_fail_tests[25] = {
208
"matrix((1,2,3,4,5,6)",
209
"matrix((1,2,3,4,5,6))",
210
"matrix(1,2,3,4,5,6))",
211
"matrix(,1,2,3,4,5,6)",
212
"matrix(1,2,3,4,5,6,)",
213
"matrix(1,2,3,4,5,)",
215
"matrix(1,2,3,4,5e6-3)", // Here numbers HAVE to be separated by a comma-wsp sequence
216
"matrix(1,2,3,4,5e6.3)", // Here numbers HAVE to be separated by a comma-wsp sequence
234
SvgAffineTest::test_t const SvgAffineTest::write_matrix_tests[2] = {
235
{"matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)},
236
{"matrix(-1,2123,3,0.4,1e-8,1e20)",Geom::Matrix(-1,2.123e3,3+1e-14,0.4,1e-8,1e20)}};
237
SvgAffineTest::test_t const SvgAffineTest::write_translate_tests[3] = {
238
{"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)},
239
{"translate(1)",Geom::Matrix(1,0,0,1,1,0)},
240
{"translate(-1345,0.123)",Geom::Matrix(1,0,0,1,-1.345e3,.123)}};
241
SvgAffineTest::test_t const SvgAffineTest::write_scale_tests[2] = {
242
{"scale(0)",Geom::Matrix(0,0,0,0,0,0)},
243
{"scale(2,3)",Geom::Matrix(2,0,0,3,0,0)}};
244
SvgAffineTest::test_t const SvgAffineTest::write_rotate_tests[2] = {
245
{"rotate(13)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)},
246
{"rotate(-13,7,11)",Geom::Matrix(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),(1-cos(-13.*DEGREE))*7+sin(-13.*DEGREE)*11,(1-cos(-13.*DEGREE))*11-sin(-13.*DEGREE)*7)}};
247
SvgAffineTest::test_t const SvgAffineTest::write_skew_tests[3] = {
248
{"skewX(30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)},
249
{"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)},
250
{"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}};
255
c-file-style:"stroustrup"
256
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
261
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :