Code

2geomify, remove warnings and other fixes
[inkscape.git] / src / svg / svg-path-nr-test.h
1 /* WARNING: These tests are not completely correct!
2  * Specifically, 'M 0,0 L 1,1 z' and 'M 0,0 L 1,1 L 0,0 z' are treated as equal, but aren't.
3  * This difference is (probably?) only relevant in the context of markers.
4  * However, since NArtBpath has no (valid) way to distinguish these two and is being retired,
5  * these tests have not been updated to reflect this.
6  */
8 #include <cxxtest/TestSuite.h>
9 #include "libnr/n-art-bpath.h"
10 #include "svg/svg.h"
11 #include "2geom/coord.h"
12 #include "prefs-utils.h"
13 #include "streq.h"
14 #include <string>
15 #include <vector>
16 #include <glib/gmem.h>
18 class SvgPathNRTest : public CxxTest::TestSuite
19 {
20 private:
21     std::vector<std::string> rectanglesAbsoluteClosed;
22     std::vector<std::string> rectanglesRelativeClosed;
23     std::vector<std::string> rectanglesAbsoluteOpen;
24     std::vector<std::string> rectanglesRelativeOpen;
25     NArtBpath rectangleBpath[5+1];
26 public:
27     SvgPathNRTest() {
28         // Lots of ways to define the same rectangle
29         rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2 Z");
30         rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 z");
31         rectanglesAbsoluteClosed.push_back("M 1,2 4,2 4,8 1,8 z");
32         rectanglesAbsoluteClosed.push_back("M 1,2 H 4 V 8 H 1 z");
33         rectanglesRelativeClosed.push_back("m 1,2 l 3,0 l 0,6 l -3,0 z");
34         rectanglesRelativeClosed.push_back("m 1,2 3,0 0,6 -3,0 z");
35         rectanglesRelativeClosed.push_back("m 1,2 h 3 v 6 h -3 z");
36         rectanglesAbsoluteOpen.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2");
37         rectanglesAbsoluteOpen.push_back("M 1,2 4,2 4,8 1,8 1,2");
38         rectanglesAbsoluteOpen.push_back("M 1,2 H 4 V 8 H 1 V 2");
39         rectanglesRelativeOpen.push_back("m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6");
40         rectanglesRelativeOpen.push_back("m 1,2 3,0 0,6 -3,0 0,-6");
41         rectanglesRelativeOpen.push_back("m 1,2 h 3 v 6 h -3 v -6");
42         rectangleBpath[0].code = NR_MOVETO;
43         rectangleBpath[0].x3 = 1;
44         rectangleBpath[0].y3 = 2;
45         rectangleBpath[1].code = NR_LINETO;
46         rectangleBpath[1].x3 = 4;
47         rectangleBpath[1].y3 = 2;
48         rectangleBpath[2].code = NR_LINETO;
49         rectangleBpath[2].x3 = 4;
50         rectangleBpath[2].y3 = 8;
51         rectangleBpath[3].code = NR_LINETO;
52         rectangleBpath[3].x3 = 1;
53         rectangleBpath[3].y3 = 8;
54         rectangleBpath[4].code = NR_LINETO;
55         rectangleBpath[4].x3 = 1;
56         rectangleBpath[4].y3 = 2;
57         rectangleBpath[5].code = NR_END;
58         // TODO: Also test some (smooth) cubic/quadratic beziers and elliptical arcs
59     }
61 // createSuite and destroySuite get us per-suite setup and teardown
62 // without us having to worry about static initialization order, etc.
63     static SvgPathNRTest *createSuite() { return new SvgPathNRTest(); }
64     static void destroySuite( SvgPathNRTest *suite ) { delete suite; }
66     void testReadRectanglesAbsoluteClosed()
67     {
68         rectangleBpath[0].code = NR_MOVETO;
69         for(size_t i=0; i<rectanglesAbsoluteClosed.size(); i++) {
70             NArtBpath * bpath = sp_svg_read_path(rectanglesAbsoluteClosed[i].c_str());
71             TS_ASSERT(bpathEqual(bpath,rectangleBpath));
72             g_free(bpath);
73         }
74     }
76     void testReadRectanglesRelativeClosed()
77     {
78         rectangleBpath[0].code = NR_MOVETO;
79         for(size_t i=0; i<rectanglesRelativeClosed.size(); i++) {
80             NArtBpath * bpath = sp_svg_read_path(rectanglesRelativeClosed[i].c_str());
81             TS_ASSERT(bpathEqual(bpath,rectangleBpath));
82             g_free(bpath);
83         }
84     }
86     void testReadRectanglesAbsoluteOpen()
87     {
88         rectangleBpath[0].code = NR_MOVETO_OPEN;
89         for(size_t i=0; i<rectanglesAbsoluteOpen.size(); i++) {
90             NArtBpath * bpath = sp_svg_read_path(rectanglesAbsoluteOpen[i].c_str());
91             TS_ASSERT(bpathEqual(bpath,rectangleBpath));
92             g_free(bpath);
93         }
94     }
96     void testReadRectanglesRelativeOpen()
97     {
98         rectangleBpath[0].code = NR_MOVETO_OPEN;
99         for(size_t i=0; i<rectanglesRelativeOpen.size(); i++) {
100             NArtBpath * bpath = sp_svg_read_path(rectanglesRelativeOpen[i].c_str());
101             TS_ASSERT(bpathEqual(bpath,rectangleBpath));
102             g_free(bpath);
103         }
104     }
106     void testReadConcatenatedPaths()
107     {
108         NArtBpath bpath_good[4*5+1];
109         for(size_t i=0; i<4; i++) {
110             memcpy(bpath_good+i*5,rectangleBpath,sizeof(rectangleBpath[0])*5);
111         }
112         bpath_good[0*5].code = NR_MOVETO;
113         bpath_good[1*5].code = NR_MOVETO_OPEN;
114         bpath_good[2*5].code = NR_MOVETO;
115         bpath_good[3*5].code = NR_MOVETO_OPEN;
116         bpath_good[4*5].code = NR_END;
117         for(size_t i=0; i<5; i++) {
118             bpath_good[1*5+i].x3 += bpath_good[0*5+4].x3;
119             bpath_good[1*5+i].y3 += bpath_good[0*5+4].y3;
120         }
121         for(size_t i=0; i<5; i++) {
122             bpath_good[2*5+i].x3 += bpath_good[1*5+4].x3;
123             bpath_good[2*5+i].y3 += bpath_good[1*5+4].y3;
124         }
125         std::string path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];
126         NArtBpath * bpath = sp_svg_read_path(path_str.c_str());
127         TS_ASSERT(bpathEqual(bpath,bpath_good));
128         g_free(bpath);
129     }
131     void testReadZeroLengthSubpaths() {
132         // Per the SVG 1.1 specification (section F5) zero-length subpaths are relevant
133         NArtBpath bpath_good[8+1];
134         bpath_good[0].code = NR_MOVETO_OPEN;
135         bpath_good[0].x3 = bpath_good[0].y3 = 0;
136         bpath_good[1].code = NR_MOVETO_OPEN;
137         bpath_good[1].x3 = bpath_good[1].y3 = 1;
138         bpath_good[2].code = NR_LINETO;
139         bpath_good[2].x3 = bpath_good[2].y3 = 2;
140         bpath_good[3].code = NR_MOVETO;
141         bpath_good[3].x3 = bpath_good[3].y3 = 3;
142         bpath_good[4].code = NR_MOVETO;
143         bpath_good[4].x3 = bpath_good[4].y3 = 4;
144         bpath_good[5].code = NR_LINETO;
145         bpath_good[5].x3 = bpath_good[5].y3 = 5;
146         bpath_good[6].code = NR_LINETO;
147         bpath_good[6].x3 = bpath_good[6].y3 = 4;
148         bpath_good[7].code = NR_MOVETO_OPEN;
149         bpath_good[7].x3 = bpath_good[7].y3 = 6;
150         bpath_good[8].code = NR_END;
151         {   // Test absolute version
152             char const * path_str = "M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6";
153             NArtBpath * bpath = sp_svg_read_path(path_str);
154             TS_ASSERT(bpathEqual(bpath,bpath_good));
155             g_free(bpath);
156         }
157         {   // Test relative version
158             char const * path_str = "m 0,0 m 1,1 l 1,1 m 1,1 z m 1,1 l 1,1 z m 2,2";
159             NArtBpath * bpath = sp_svg_read_path(path_str);
160             TS_ASSERT(bpathEqual(bpath,bpath_good));
161             g_free(bpath);
162         }
163     }
165     void testReadImplicitMoveto() {
166         NArtBpath bpath_good[6+1];
167         bpath_good[0].code = NR_MOVETO;
168         bpath_good[0].x3 = bpath_good[0].y3 = 1;
169         bpath_good[1].code = NR_LINETO;
170         bpath_good[1].x3 = bpath_good[1].y3 = 2;
171         bpath_good[2].code = NR_LINETO;
172         bpath_good[2].x3 = bpath_good[2].y3 = 1;
173         bpath_good[3].code = NR_MOVETO;
174         bpath_good[3].x3 = bpath_good[3].y3 = 1;
175         bpath_good[4].code = NR_LINETO;
176         bpath_good[4].x3 = bpath_good[4].y3 = 3;
177         bpath_good[5].code = NR_LINETO;
178         bpath_good[5].x3 = bpath_good[5].y3 = 1;
179         bpath_good[6].code = NR_END;
180         {   // Test absolute version
181             char const * path_str = "M 1,1 L 2,2 z L 3,3 z";
182             NArtBpath * bpath = sp_svg_read_path(path_str);
183             TS_ASSERT(bpathEqual(bpath,bpath_good));
184             g_free(bpath);
185         }
186         {   // Test relative version
187             char const * path_str = "M 1,1 L 2,2 z L 3,3 z";
188             NArtBpath * bpath = sp_svg_read_path(path_str);
189             TS_ASSERT(bpathEqual(bpath,bpath_good));
190             g_free(bpath);
191         }
192     }
194     void testReadFloatingPoint() {
195         NArtBpath bpath_good[5+1];
196         bpath_good[0].code = NR_MOVETO;
197         bpath_good[0].x3 = .01;
198         bpath_good[0].y3 = .02;
199         bpath_good[1].code = NR_LINETO;
200         bpath_good[1].x3 = .04;
201         bpath_good[1].y3 = .02;
202         bpath_good[2].code = NR_LINETO;
203         bpath_good[2].x3 = 1.5;
204         bpath_good[2].y3 = 1.6;
205         bpath_good[3].code = NR_LINETO;
206         bpath_good[3].x3 = .01;
207         bpath_good[3].y3 = .08;
208         bpath_good[4].code = NR_LINETO;
209         bpath_good[4].x3 = .01;
210         bpath_good[4].y3 = .02;
211         bpath_good[5].code = NR_END;
212         {   // Test decimals
213             char const * path_str = "M .01,.02 L.04.02 L1.5,1.6L0.01,0.08 .01.02 z";
214             NArtBpath * bpath = sp_svg_read_path(path_str);
215             TS_ASSERT(bpathEqual(bpath,bpath_good));
216             g_free(bpath);
217         }
218         {   // Test exponent
219             char const * path_str = "M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L0150E-2,1.6e0L1.0e-2,80e-3 z";
220             NArtBpath * bpath = sp_svg_read_path(path_str);
221             TS_ASSERT(bpathEqual(bpath,bpath_good));
222             g_free(bpath);
223         }
224     }
226     void testReadImplicitSeparation() {
227         // Coordinates need not be separated by whitespace if they can still be read unambiguously
228         NArtBpath bpath_good[5+1];
229         bpath_good[0].code = NR_MOVETO;
230         bpath_good[0].x3 = .1;
231         bpath_good[0].y3 = .2;
232         bpath_good[1].code = NR_LINETO;
233         bpath_good[1].x3 = .4;
234         bpath_good[1].y3 = .2;
235         bpath_good[2].code = NR_LINETO;
236         bpath_good[2].x3 = .4;
237         bpath_good[2].y3 = .8;
238         bpath_good[3].code = NR_LINETO;
239         bpath_good[3].x3 = .1;
240         bpath_good[3].y3 = .8;
241         bpath_good[4].code = NR_LINETO;
242         bpath_good[4].x3 = .1;
243         bpath_good[4].y3 = .2;
244         bpath_good[5].code = NR_END;
245         {   // Test absolute
246             char const * path_str = "M .1.2+0.4.2e0.4e0+8e-1.1.8 z";
247             NArtBpath * bpath = sp_svg_read_path(path_str);
248             TS_ASSERT(bpathEqual(bpath,bpath_good));
249             g_free(bpath);
250         }
251         {   // Test relative
252             char const * path_str = "m .1.2+0.3.0e0.0e0+6e-1-.3.0 z";
253             NArtBpath * bpath = sp_svg_read_path(path_str);
254             TS_ASSERT(bpathEqual(bpath,bpath_good));
255             g_free(bpath);
256         }
257     }
259     void testReadErrorMisplacedCharacter() {
260         char const * path_str;
261         NArtBpath * bpath;
262         NArtBpath * bpath_good = rectangleBpath;
263         bpath_good[0].code = NR_MOVETO;
264         // Comma in the wrong place (commas may only appear between parameters)
265         path_str = "M 1,2 4,2 4,8 1,8 z , m 13,15";
266         bpath = sp_svg_read_path(path_str);
267         TS_ASSERT(bpathEqual(bpath,bpath_good));
268         g_free(bpath);
269         // Comma in the wrong place (commas may only appear between parameters)
270         path_str = "M 1,2 4,2 4,8 1,8 z m,13,15";
271         bpath = sp_svg_read_path(path_str);
272         TS_ASSERT(bpathEqual(bpath,bpath_good));
273         g_free(bpath);
274         // Period in the wrong place (no numbers after a 'z')
275         path_str = "M 1,2 4,2 4,8 1,8 z . m 13,15";
276         bpath = sp_svg_read_path(path_str);
277         TS_ASSERT(bpathEqual(bpath,bpath_good));
278         g_free(bpath);
279         // Sign in the wrong place (no numbers after a 'z')
280         path_str = "M 1,2 4,2 4,8 1,8 z + - m 13,15";
281         bpath = sp_svg_read_path(path_str);
282         TS_ASSERT(bpathEqual(bpath,bpath_good));
283         g_free(bpath);
284         // Digit in the wrong place (no numbers after a 'z')
285         path_str = "M 1,2 4,2 4,8 1,8 z 9809 m 13,15";
286         bpath = sp_svg_read_path(path_str);
287         TS_ASSERT(bpathEqual(bpath,bpath_good));
288         g_free(bpath);
289         // Digit in the wrong place (no numbers after a 'z')
290         path_str = "M 1,2 4,2 4,8 1,8 z 9809 876 m 13,15";
291         bpath = sp_svg_read_path(path_str);
292         TS_ASSERT(bpathEqual(bpath,bpath_good));
293         g_free(bpath);
294     }
296     void testReadErrorUnrecognizedCharacter() {
297         char const * path_str;
298         NArtBpath * bpath;
299         NArtBpath * bpath_good = rectangleBpath;
300         bpath_good[0].code = NR_MOVETO;
301         // Unrecognized character
302         path_str = "M 1,2 4,2 4,8 1,8 z&m 13,15";
303         bpath = sp_svg_read_path(path_str);
304         TS_ASSERT(bpathEqual(bpath,bpath_good));
305         g_free(bpath);
306         // Unrecognized character
307         path_str = "M 1,2 4,2 4,8 1,8 z m &13,15";
308         bpath = sp_svg_read_path(path_str);
309         TS_ASSERT(bpathEqual(bpath,bpath_good));
310         g_free(bpath);
311     }
313     void testReadErrorTypo() {
314         char const * path_str;
315         NArtBpath * bpath;
316         NArtBpath * bpath_good = rectangleBpath;
317         bpath_good[0].code = NR_MOVETO;
318         // Typo
319         path_str = "M 1,2 4,2 4,8 1,8 z j 13,15";
320         bpath = sp_svg_read_path(path_str);
321         TS_ASSERT(bpathEqual(bpath,bpath_good));
322         g_free(bpath);
324         bpath_good[0].code = NR_MOVETO_OPEN;
325         // Typo
326         path_str = "M 1,2 4,2 4,8 1,8 L 1,2 x m 13,15";
327         bpath = sp_svg_read_path(path_str);
328         TS_ASSERT(bpathEqual(bpath,bpath_good));
329         g_free(bpath);
330     }
332     void testReadErrorIllformedNumbers() {
333         char const * path_str;
334         NArtBpath * bpath;
335         NArtBpath * bpath_good = rectangleBpath;
336         bpath_good[0].code = NR_MOVETO;
337         // Double exponent
338         path_str = "M 1,2 4,2 4,8 1,8 z m 13e4e5,15";
339         bpath = sp_svg_read_path(path_str);
340         TS_ASSERT(bpathEqual(bpath,bpath_good));
341         g_free(bpath);
342         // Double sign
343         path_str = "M 1,2 4,2 4,8 1,8 z m +-13,15";
344         bpath = sp_svg_read_path(path_str);
345         TS_ASSERT(bpathEqual(bpath,bpath_good));
346         g_free(bpath);
347         // Double sign
348         path_str = "M 1,2 4,2 4,8 1,8 z m 13e+-12,15";
349         bpath = sp_svg_read_path(path_str);
350         TS_ASSERT(bpathEqual(bpath,bpath_good));
351         g_free(bpath);
352         // No digit
353         path_str = "M 1,2 4,2 4,8 1,8 z m .e12,15";
354         bpath = sp_svg_read_path(path_str);
355         TS_ASSERT(bpathEqual(bpath,bpath_good));
356         g_free(bpath);
357         // No digit
358         path_str = "M 1,2 4,2 4,8 1,8 z m .,15";
359         bpath = sp_svg_read_path(path_str);
360         TS_ASSERT(bpathEqual(bpath,bpath_good));
361         g_free(bpath);
362         // No digit
363         path_str = "M 1,2 4,2 4,8 1,8 z m +,15";
364         bpath = sp_svg_read_path(path_str);
365         TS_ASSERT(bpathEqual(bpath,bpath_good));
366         g_free(bpath);
367         // No digit
368         path_str = "M 1,2 4,2 4,8 1,8 z m +.e+,15";
369         bpath = sp_svg_read_path(path_str);
370         TS_ASSERT(bpathEqual(bpath,bpath_good));
371         g_free(bpath);
372     }
374     void testReadErrorJunk() {
375         char const * path_str;
376         NArtBpath * bpath;
377         NArtBpath * bpath_good = rectangleBpath;
378         bpath_good[0].code = NR_MOVETO;
379         // Junk
380         path_str = "M 1,2 4,2 4,8 1,8 z j 357 hkjh.,34e34 90ih6kj4 h5k6vlh4N.,6,45wikuyi3yere..3487 m 13,23";
381         bpath = sp_svg_read_path(path_str);
382         TS_ASSERT(bpathEqual(bpath,bpath_good));
383         g_free(bpath);
384     }
386     void testReadErrorStopReading() {
387         char const * path_str;
388         NArtBpath * bpath;
389         NArtBpath * bpath_good = rectangleBpath;
390         bpath_good[0].code = NR_MOVETO;
391         // Unrecognized parameter
392         path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";
393         bpath = sp_svg_read_path(path_str);
394         TS_ASSERT(bpathEqual(bpath,bpath_good));
395         g_free(bpath);
396         // Invalid parameter
397         path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";
398         bpath = sp_svg_read_path(path_str);
399         TS_ASSERT(bpathEqual(bpath,bpath_good));
400         g_free(bpath);
401         // Illformed parameter
402         path_str = "M 1,2 4,2 4,8 1,8 z m +-12,23,34";
403         bpath = sp_svg_read_path(path_str);
404         TS_ASSERT(bpathEqual(bpath,bpath_good));
405         g_free(bpath);
407         bpath_good[0].code = NR_MOVETO_OPEN;
408         // "Third" parameter
409         path_str = "M 1,2 4,2 4,8 1,8 1,2,3 M 12,23";
410         bpath = sp_svg_read_path(path_str);
411         TS_ASSERT(bpathEqual(bpath,bpath_good));
412         g_free(bpath);
413     }
415     void testRoundTrip() {
416         // This is the easiest way to (also) test writing path data, as a path can be written in more than one way.
417         NArtBpath * bpath;
418         NArtBpath * new_bpath;
419         char * path_str;
420         // Rectangle (closed)
421         bpath = sp_svg_read_path(rectanglesAbsoluteClosed[0].c_str());
422         path_str = sp_svg_write_path(bpath);
423         new_bpath = sp_svg_read_path(path_str);
424         TS_ASSERT(bpathEqual(bpath,new_bpath));
425         g_free(bpath); g_free(path_str); g_free(new_bpath);
426         // Rectangle (open)
427         bpath = sp_svg_read_path(rectanglesAbsoluteOpen[0].c_str());
428         path_str = sp_svg_write_path(bpath);
429         new_bpath = sp_svg_read_path(path_str);
430         TS_ASSERT(bpathEqual(bpath,new_bpath));
431         g_free(bpath); g_free(path_str); g_free(new_bpath);
432         // Concatenated rectangles
433         bpath = sp_svg_read_path((rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0]).c_str());
434         path_str = sp_svg_write_path(bpath);
435         new_bpath = sp_svg_read_path(path_str);
436         TS_ASSERT(bpathEqual(bpath,new_bpath));
437         g_free(bpath); g_free(path_str); g_free(new_bpath);
438         // Zero-length subpaths
439         bpath = sp_svg_read_path("M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6");
440         path_str = sp_svg_write_path(bpath);
441         new_bpath = sp_svg_read_path(path_str);
442         TS_ASSERT(bpathEqual(bpath,new_bpath));
443         g_free(bpath); g_free(path_str); g_free(new_bpath);
444         // Floating-point
445         bpath = sp_svg_read_path("M .01,.02 L 0.04,0.02 L.04,.08L0.01,0.08 z""M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L04E-2,.08e0L1.0e-2,80e-3 z");
446         path_str = sp_svg_write_path(bpath);
447         new_bpath = sp_svg_read_path(path_str);
448         TS_ASSERT(bpathEqual(bpath, new_bpath, 1e-17));
449         g_free(bpath); g_free(path_str); g_free(new_bpath);
450     }
452     void testMinexpPrecision() {
453         NArtBpath * bpath;
454         char * path_str;
455         // Default values
456         prefs_set_int_attribute("options.svgoutput", "allowrelativecoordinates", 1);
457         prefs_set_int_attribute("options.svgoutput", "forcerepeatcommands", 0);
458         prefs_set_int_attribute("options.svgoutput", "numericprecision", 8);
459         prefs_set_int_attribute("options.svgoutput", "minimumexponent", -8);
460         bpath = sp_svg_read_path("M 123456781,1.23456781e-8 L 123456782,1.23456782e-8 L 123456785,1.23456785e-8 L 10123456400,1.23456785e-8 L 123456789,1.23456789e-8 L 123456789,101.234564e-8 L 123456789,1.23456789e-8");
461         path_str = sp_svg_write_path(bpath);
462         TS_ASSERT_RELATION( streq_rel , "m 123456780,1.2345678e-8 0,0 10,1e-15 9999999210,0 -9999999210,0 0,9.99999921e-7 0,-9.99999921e-7" , path_str );
463         g_free(bpath); g_free(path_str);
464     }
466 private:
467     bool bpathEqual(NArtBpath const * a, NArtBpath const * b, double eps = 1e-16) {
468         while(a->code != NR_END && b->code == a->code) {
469             switch(a->code) {
470             case NR_MOVETO:
471             case NR_MOVETO_OPEN:
472             case NR_LINETO:
473                 if (!Geom::are_near(a->x3,b->x3, eps) || !Geom::are_near(a->y3,b->y3, eps)) return false;
474                 break;
475             case NR_CURVETO:
476                 if (!Geom::are_near(a->x1,b->x1, eps) || !Geom::are_near(a->y1,b->y1, eps)) return false;
477                 if (!Geom::are_near(a->x2,b->x2, eps) || !Geom::are_near(a->y2,b->y2, eps)) return false;
478                 if (!Geom::are_near(a->x3,b->x3, eps) || !Geom::are_near(a->y3,b->y3, eps)) return false;
479                 break;
480             default:
481                 TS_FAIL("Unknown path code!");
482             }
483             a++;
484             b++;
485         }
486         return a->code == b->code;
487     }
488 };
491 /*
492   Local Variables:
493   mode:c++
494   c-file-style:"stroustrup"
495   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
496   indent-tabs-mode:nil
497   fill-column:99
498   End:
499 */
500 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :