Code

1bcc5fb17de6d35d578ba91b9c410cc19f54a8ac
[inkscape.git] / src / svg / svg-path-geom-test.h
1 #include <cxxtest/TestSuite.h>\r
2 #include "2geom/coord.h"\r
3 #include "2geom/curves.h"\r
4 #include "2geom/pathvector.h"\r
5 #include "svg/svg.h"\r
6 #include "prefs-utils.h"\r
7 #include "streq.h"\r
8 #include <stdio.h>\r
9 #include <string>\r
10 #include <vector>\r
11 #include <glib/gmem.h>\r
12 \r
13 class SvgPathGeomTest : public CxxTest::TestSuite\r
14 {\r
15 private:\r
16     std::vector<std::string> rectanglesAbsoluteClosed;\r
17     std::vector<std::string> rectanglesRelativeClosed;\r
18     std::vector<std::string> rectanglesAbsoluteOpen;\r
19     std::vector<std::string> rectanglesRelativeOpen;\r
20     Geom::PathVector rectanglepv;\r
21 public:\r
22     SvgPathGeomTest() {\r
23         // Lots of ways to define the same rectangle\r
24         rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2 Z");\r
25         rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 z");\r
26         rectanglesAbsoluteClosed.push_back("M 1,2 4,2 4,8 1,8 z");\r
27         rectanglesAbsoluteClosed.push_back("M 1,2 H 4 V 8 H 1 z");\r
28         rectanglesRelativeClosed.push_back("m 1,2 l 3,0 l 0,6 l -3,0 z");\r
29         rectanglesRelativeClosed.push_back("m 1,2 3,0 0,6 -3,0 z");\r
30         rectanglesRelativeClosed.push_back("m 1,2 h 3 v 6 h -3 z");\r
31         rectanglesAbsoluteOpen.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2");\r
32         rectanglesAbsoluteOpen.push_back("M 1,2 4,2 4,8 1,8 1,2");\r
33         rectanglesAbsoluteOpen.push_back("M 1,2 H 4 V 8 H 1 V 2");\r
34         rectanglesRelativeOpen.push_back("m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6");\r
35         rectanglesRelativeOpen.push_back("m 1,2 3,0 0,6 -3,0 0,-6");\r
36         rectanglesRelativeOpen.push_back("m 1,2 h 3 v 6 h -3 v -6");\r
37         rectanglepv.push_back(Geom::Path(Geom::Point(1,2)));\r
38         rectanglepv.back().append(Geom::LineSegment(Geom::Point(1,2),Geom::Point(4,2)));\r
39         rectanglepv.back().append(Geom::LineSegment(Geom::Point(4,2),Geom::Point(4,8)));\r
40         rectanglepv.back().append(Geom::LineSegment(Geom::Point(4,8),Geom::Point(1,8)));\r
41         rectanglepv.back().append(Geom::LineSegment(Geom::Point(1,8),Geom::Point(1,2)));\r
42         // TODO: Also test some (smooth) cubic/quadratic beziers and elliptical arcs\r
43     }\r
44 \r
45 // createSuite and destroySuite get us per-suite setup and teardown\r
46 // without us having to worry about static initialization order, etc.\r
47     static SvgPathGeomTest *createSuite() { return new SvgPathGeomTest(); }\r
48     static void destroySuite( SvgPathGeomTest *suite ) { delete suite; }\r
49 \r
50     void testReadRectanglesAbsoluteClosed()\r
51     {\r
52         rectanglepv.back().close();\r
53         for(size_t i=0; i<rectanglesAbsoluteClosed.size(); i++) {\r
54             Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteClosed[i].c_str());\r
55             TSM_ASSERT(rectanglesAbsoluteClosed[i].c_str(), bpathEqual(pv,rectanglepv));\r
56         }\r
57     }\r
58 \r
59     void testReadRectanglesRelativeClosed()\r
60     {\r
61         rectanglepv.back().close();\r
62         for(size_t i=0; i<rectanglesRelativeClosed.size(); i++) {\r
63             Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeClosed[i].c_str());\r
64             TSM_ASSERT(rectanglesRelativeClosed[i].c_str(), bpathEqual(pv,rectanglepv));\r
65         }\r
66     }\r
67 \r
68     void testReadRectanglesAbsoluteOpen()\r
69     {\r
70         rectanglepv.back().close(false);\r
71         for(size_t i=0; i<rectanglesAbsoluteOpen.size(); i++) {\r
72             Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteOpen[i].c_str());\r
73             TSM_ASSERT(rectanglesAbsoluteOpen[i].c_str(), bpathEqual(pv,rectanglepv));\r
74         }\r
75     }\r
76 \r
77     void testReadRectanglesRelativeOpen()\r
78     {\r
79         rectanglepv.back().close(false);\r
80         for(size_t i=0; i<rectanglesRelativeOpen.size(); i++) {\r
81             Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeOpen[i].c_str());\r
82             TSM_ASSERT(rectanglesRelativeOpen[i].c_str(), bpathEqual(pv,rectanglepv));\r
83         }\r
84     }\r
85 \r
86     void testReadConcatenatedPaths()\r
87     {\r
88         Geom::PathVector pv_good;\r
89         pv_good.push_back(rectanglepv.back());\r
90         pv_good.push_back(rectanglepv.back()*Geom::Translate(pv_good[0].finalPoint()));\r
91         pv_good.push_back(rectanglepv.back()*Geom::Translate(pv_good[1].finalPoint()));\r
92         pv_good.push_back(rectanglepv.back());\r
93         pv_good[0].close();\r
94         pv_good[1].close(false);\r
95         pv_good[2].close();\r
96         pv_good[3].close(false);\r
97         std::string path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];\r
98         Geom::PathVector pv = sp_svg_read_pathv(path_str.c_str());\r
99         TS_ASSERT(bpathEqual(pv,pv_good));\r
100     }\r
101 \r
102     void testReadZeroLengthSubpaths() {\r
103         // Per the SVG 1.1 specification (section F5) zero-length subpaths are relevant\r
104         Geom::PathVector pv_good;\r
105         pv_good.push_back(Geom::Path(Geom::Point(0,0)));\r
106         pv_good.push_back(Geom::Path(Geom::Point(1,1)));\r
107         pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(2,2)));\r
108         pv_good.push_back(Geom::Path(Geom::Point(3,3)));\r
109         pv_good.back().close();\r
110         pv_good.push_back(Geom::Path(Geom::Point(4,4)));\r
111         pv_good.back().append(Geom::LineSegment(Geom::Point(4,4),Geom::Point(5,5)));\r
112         pv_good.back().close();\r
113         pv_good.push_back(Geom::Path(Geom::Point(6,6)));\r
114         {   // Test absolute version\r
115             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";\r
116             Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
117             TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
118         }\r
119         {   // Test relative version\r
120             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";\r
121             Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
122             TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
123         }\r
124     }\r
125 \r
126     void testReadImplicitMoveto() {\r
127         Geom::PathVector pv_good;\r
128         pv_good.push_back(Geom::Path(Geom::Point(1,1)));\r
129         pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(2,2)));\r
130         pv_good.back().close();\r
131         pv_good.push_back(Geom::Path(Geom::Point(1,1)));\r
132         pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(3,3)));\r
133         pv_good.back().close();\r
134         {   // Test absolute version\r
135             char const * path_str = "M 1,1 L 2,2 z L 3,3 z";\r
136             Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
137             TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
138         }\r
139         {   // Test relative version\r
140             char const * path_str = "M 1,1 L 2,2 z L 3,3 z";\r
141             Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
142             TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
143         }\r
144     }\r
145 \r
146     void testReadFloatingPoint() {\r
147         Geom::PathVector pv_good;\r
148         pv_good.push_back(Geom::Path(Geom::Point(.01,.02)));\r
149         pv_good.back().append(Geom::LineSegment(Geom::Point(.01,.02),Geom::Point(.04,.02)));\r
150         pv_good.back().append(Geom::LineSegment(Geom::Point(.04,.02),Geom::Point(1.5,1.6)));\r
151         pv_good.back().append(Geom::LineSegment(Geom::Point(1.5,1.6),Geom::Point(.01,.08)));\r
152         pv_good.back().close();\r
153         {   // Test decimals\r
154             char const * path_str = "M .01,.02 L.04.02 L1.5,1.6L0.01,0.08 .01.02 z";\r
155             Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
156             TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
157         }\r
158         {   // Test exponent\r
159             char const * path_str = "M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L0150E-2,1.6e0L1.0e-2,80e-3 z";\r
160             Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
161             TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
162         }\r
163     }\r
164 \r
165     void testReadImplicitSeparation() {\r
166         // Coordinates need not be separated by whitespace if they can still be read unambiguously\r
167         Geom::PathVector pv_good;\r
168         pv_good.push_back(Geom::Path(Geom::Point(.1,.2)));\r
169         pv_good.back().append(Geom::LineSegment(Geom::Point(.1,.2),Geom::Point(.4,.2)));\r
170         pv_good.back().append(Geom::LineSegment(Geom::Point(.4,.2),Geom::Point(.4,.8)));\r
171         pv_good.back().append(Geom::LineSegment(Geom::Point(.4,.8),Geom::Point(.1,.8)));\r
172         pv_good.back().close();\r
173         {   // Test absolute\r
174             char const * path_str = "M .1.2+0.4.2e0.4e0+8e-1.1.8 z";\r
175             Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
176             TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
177         }\r
178         {   // Test relative\r
179             char const * path_str = "m .1.2+0.3.0e0.0e0+6e-1-.3.0 z";\r
180             Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
181             TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
182         }\r
183     }\r
184 \r
185     void testReadErrorMisplacedCharacter() {\r
186         char const * path_str;\r
187         Geom::PathVector pv;\r
188         rectanglepv.back().close();\r
189         // Comma in the wrong place (commas may only appear between parameters)\r
190         path_str = "M 1,2 4,2 4,8 1,8 z , m 13,15";\r
191         pv = sp_svg_read_pathv(path_str);\r
192         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
193         // Comma in the wrong place (commas may only appear between parameters)\r
194         path_str = "M 1,2 4,2 4,8 1,8 z m,13,15";\r
195         pv = sp_svg_read_pathv(path_str);\r
196         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
197         // Period in the wrong place (no numbers after a 'z')\r
198         path_str = "M 1,2 4,2 4,8 1,8 z . m 13,15";\r
199         pv = sp_svg_read_pathv(path_str);\r
200         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
201         // Sign in the wrong place (no numbers after a 'z')\r
202         path_str = "M 1,2 4,2 4,8 1,8 z + - m 13,15";\r
203         pv = sp_svg_read_pathv(path_str);\r
204         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
205         // Digit in the wrong place (no numbers after a 'z')\r
206         path_str = "M 1,2 4,2 4,8 1,8 z 9809 m 13,15";\r
207         pv = sp_svg_read_pathv(path_str);\r
208         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
209         // Digit in the wrong place (no numbers after a 'z')\r
210         path_str = "M 1,2 4,2 4,8 1,8 z 9809 876 m 13,15";\r
211         pv = sp_svg_read_pathv(path_str);\r
212         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
213     }\r
214 \r
215     void testReadErrorUnrecognizedCharacter() {\r
216         char const * path_str;\r
217         Geom::PathVector pv;\r
218         rectanglepv.back().close();\r
219         // Unrecognized character\r
220         path_str = "M 1,2 4,2 4,8 1,8 z&m 13,15";\r
221         pv = sp_svg_read_pathv(path_str);\r
222         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
223         // Unrecognized character\r
224         path_str = "M 1,2 4,2 4,8 1,8 z m &13,15";\r
225         pv = sp_svg_read_pathv(path_str);\r
226         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
227     }\r
228 \r
229     void testReadErrorTypo() {\r
230         char const * path_str;\r
231         Geom::PathVector pv;\r
232         rectanglepv.back().close();\r
233         // Typo\r
234         path_str = "M 1,2 4,2 4,8 1,8 z j 13,15";\r
235         pv = sp_svg_read_pathv(path_str);\r
236         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
237 \r
238         rectanglepv.back().close(false);\r
239         // Typo\r
240         path_str = "M 1,2 4,2 4,8 1,8 L 1,2 x m 13,15";\r
241         pv = sp_svg_read_pathv(path_str);\r
242         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
243     }\r
244 \r
245     void testReadErrorIllformedNumbers() {\r
246         char const * path_str;\r
247         Geom::PathVector pv;\r
248         rectanglepv.back().close();\r
249         // Double exponent\r
250         path_str = "M 1,2 4,2 4,8 1,8 z m 13e4e5,15";\r
251         pv = sp_svg_read_pathv(path_str);\r
252         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
253         // Double sign\r
254         path_str = "M 1,2 4,2 4,8 1,8 z m +-13,15";\r
255         pv = sp_svg_read_pathv(path_str);\r
256         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
257         // Double sign\r
258         path_str = "M 1,2 4,2 4,8 1,8 z m 13e+-12,15";\r
259         pv = sp_svg_read_pathv(path_str);\r
260         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
261         // No digit\r
262         path_str = "M 1,2 4,2 4,8 1,8 z m .e12,15";\r
263         pv = sp_svg_read_pathv(path_str);\r
264         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
265         // No digit\r
266         path_str = "M 1,2 4,2 4,8 1,8 z m .,15";\r
267         pv = sp_svg_read_pathv(path_str);\r
268         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
269         // No digit\r
270         path_str = "M 1,2 4,2 4,8 1,8 z m +,15";\r
271         pv = sp_svg_read_pathv(path_str);\r
272         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
273         // No digit\r
274         path_str = "M 1,2 4,2 4,8 1,8 z m +.e+,15";\r
275         pv = sp_svg_read_pathv(path_str);\r
276         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
277     }\r
278 \r
279     void testReadErrorJunk() {\r
280         char const * path_str;\r
281         Geom::PathVector pv;\r
282         rectanglepv.back().close();\r
283         // Junk\r
284         path_str = "M 1,2 4,2 4,8 1,8 z j 357 hkjh.,34e34 90ih6kj4 h5k6vlh4N.,6,45wikuyi3yere..3487 m 13,23";\r
285         pv = sp_svg_read_pathv(path_str);\r
286         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
287     }\r
288 \r
289     void testReadErrorStopReading() {\r
290         char const * path_str;\r
291         Geom::PathVector pv;\r
292         rectanglepv.back().close();\r
293         // Unrecognized parameter\r
294         path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";\r
295         pv = sp_svg_read_pathv(path_str);\r
296         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
297         // Invalid parameter\r
298         path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";\r
299         pv = sp_svg_read_pathv(path_str);\r
300         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
301         // Illformed parameter\r
302         path_str = "M 1,2 4,2 4,8 1,8 z m +-12,23,34";\r
303         pv = sp_svg_read_pathv(path_str);\r
304         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
305 \r
306         rectanglepv.back().close(false);\r
307         // "Third" parameter\r
308         path_str = "M 1,2 4,2 4,8 1,8 1,2,3 M 12,23";\r
309         pv = sp_svg_read_pathv(path_str);\r
310         TSM_ASSERT(path_str, bpathEqual(pv,rectanglepv));\r
311     }\r
312 \r
313     void testRoundTrip() {\r
314         // This is the easiest way to (also) test writing path data, as a path can be written in more than one way.\r
315         Geom::PathVector pv;\r
316         Geom::PathVector new_pv;\r
317         std::string org_path_str;\r
318         char * path_str;\r
319         // Rectangle (closed)\r
320         org_path_str = rectanglesAbsoluteClosed[0];\r
321         pv = sp_svg_read_pathv(org_path_str.c_str());\r
322         path_str = sp_svg_write_path(pv);\r
323         new_pv = sp_svg_read_pathv(path_str);\r
324         TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));\r
325         g_free(path_str);\r
326         // Rectangle (open)\r
327         org_path_str = rectanglesAbsoluteOpen[0];\r
328         pv = sp_svg_read_pathv(org_path_str.c_str());\r
329         path_str = sp_svg_write_path(pv);\r
330         new_pv = sp_svg_read_pathv(path_str);\r
331         TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));\r
332         g_free(path_str);\r
333         // Concatenated rectangles\r
334         org_path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];\r
335         pv = sp_svg_read_pathv(org_path_str.c_str());\r
336         path_str = sp_svg_write_path(pv);\r
337         new_pv = sp_svg_read_pathv(path_str);\r
338         TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));\r
339         g_free(path_str);\r
340         // Zero-length subpaths\r
341         org_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";\r
342         pv = sp_svg_read_pathv(org_path_str.c_str());\r
343         path_str = sp_svg_write_path(pv);\r
344         new_pv = sp_svg_read_pathv(path_str);\r
345         TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));\r
346         g_free(path_str);\r
347         // Floating-point\r
348         org_path_str = "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";\r
349         pv = sp_svg_read_pathv(org_path_str.c_str());\r
350         path_str = sp_svg_write_path(pv);\r
351         new_pv = sp_svg_read_pathv(path_str);\r
352         TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv, new_pv, 1e-17));\r
353         g_free(path_str);\r
354     }\r
355 \r
356     void testMinexpPrecision() {\r
357         Geom::PathVector pv;\r
358         char * path_str;\r
359         // Default values\r
360         prefs_set_int_attribute("options.svgoutput", "allowrelativecoordinates", 1);\r
361         prefs_set_int_attribute("options.svgoutput", "forcerepeatcommands", 0);\r
362         prefs_set_int_attribute("options.svgoutput", "numericprecision", 8);\r
363         prefs_set_int_attribute("options.svgoutput", "minimumexponent", -8);\r
364         pv = sp_svg_read_pathv("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");\r
365         path_str = sp_svg_write_path(pv);\r
366         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 );\r
367         g_free(path_str);\r
368     }\r
369 \r
370 private:\r
371     bool bpathEqual(Geom::PathVector const &a, Geom::PathVector const &b, double eps = 1e-16) {\r
372         if (a.size() != b.size()) {\r
373             char temp[100];\r
374             sprintf(temp, "PathVectors not the same size. (%u != %u)", a.size(), b.size());\r
375             TS_FAIL(temp);\r
376             return false;\r
377         }\r
378         for(size_t i=0; i<a.size(); i++) {\r
379             Geom::Path const &pa = a[i];\r
380             Geom::Path const &pb = b[i];\r
381             if (pa.closed() != pb.closed()) {\r
382                 TS_FAIL("One path is closed, the other open.");\r
383                 return false;\r
384             }\r
385             if (pa.size() != pb.size()) {\r
386                 char temp[100];\r
387                 sprintf(temp, "Not the same number of curves in path. (%u != %u)", pa.size(), pb.size());\r
388                 TS_FAIL(temp);\r
389                 return false;\r
390             }\r
391             for(size_t j=0; j<pa.size(); j++) {\r
392                 Geom::Curve const* ca = &pa[j];\r
393                 Geom::Curve const* cb = &pb[j];\r
394                 if (typeid(*ca) == typeid(*cb))\r
395                 {\r
396                     if(Geom::LineSegment const *la = dynamic_cast<Geom::LineSegment const*>(ca))\r
397                     {\r
398                         Geom::LineSegment const *lb = dynamic_cast<Geom::LineSegment const*>(cb);\r
399                         if (!Geom::are_near((*la)[0],(*lb)[0], eps)) {\r
400                             char temp[200];\r
401                             sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g)", (*la)[0][Geom::X], (*la)[0][Geom::Y], (*lb)[0][Geom::X], (*lb)[0][Geom::Y]);\r
402                             TS_FAIL(temp);\r
403                             return false;\r
404                         }\r
405                         if (!Geom::are_near((*la)[1],(*lb)[1], eps)) {\r
406                             char temp[200];\r
407                             sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g)", (*la)[1][Geom::X], (*la)[1][Geom::Y], (*lb)[1][Geom::X], (*lb)[1][Geom::Y]);\r
408                             TS_FAIL(temp);\r
409                             return false;\r
410                         }\r
411                     }\r
412                     else if(Geom::HLineSegment const *la = dynamic_cast<Geom::HLineSegment const*>(ca))\r
413                     {\r
414                         Geom::HLineSegment const *lb = dynamic_cast<Geom::HLineSegment const*>(cb);\r
415                         if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
416                             char temp[200];\r
417                             sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g)", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y]);\r
418                             TS_FAIL(temp);\r
419                             return false;\r
420                         }\r
421                         if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
422                             char temp[200];\r
423                             sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g)", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y]);\r
424                             TS_FAIL(temp);\r
425                             return false;\r
426                         }\r
427                     }\r
428                     else if(Geom::VLineSegment const *la = dynamic_cast<Geom::VLineSegment const*>(ca))\r
429                     {\r
430                         Geom::VLineSegment const *lb = dynamic_cast<Geom::VLineSegment const*>(cb);\r
431                         if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
432                             char temp[200];\r
433                             sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g)", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y]);\r
434                             TS_FAIL(temp);\r
435                             return false;\r
436                         }\r
437                         if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
438                             char temp[200];\r
439                             sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g)", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y]);\r
440                             TS_FAIL(temp);\r
441                             return false;\r
442                         }\r
443                     }\r
444                     else if(Geom::CubicBezier const *la = dynamic_cast<Geom::CubicBezier const*>(ca))\r
445                     {\r
446                         Geom::CubicBezier const *lb = dynamic_cast<Geom::CubicBezier const*>(cb);\r
447                         if (!Geom::are_near((*la)[0],(*lb)[0], eps)) {\r
448                             char temp[200];\r
449                             sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g)", (*la)[0][Geom::X], (*la)[0][Geom::Y], (*lb)[0][Geom::X], (*lb)[0][Geom::Y]);\r
450                             TS_FAIL(temp);\r
451                             return false;\r
452                         }\r
453                         if (!Geom::are_near((*la)[1],(*lb)[1], eps)) {\r
454                             char temp[200];\r
455                             sprintf(temp, "Different 1st control point: (%g,%g) != (%g,%g)", (*la)[1][Geom::X], (*la)[1][Geom::Y], (*lb)[1][Geom::X], (*lb)[1][Geom::Y]);\r
456                             TS_FAIL(temp);\r
457                             return false;\r
458                         }\r
459                         if (!Geom::are_near((*la)[2],(*lb)[2], eps)) {\r
460                             char temp[200];\r
461                             sprintf(temp, "Different 2nd control point: (%g,%g) != (%g,%g)", (*la)[2][Geom::X], (*la)[2][Geom::Y], (*lb)[2][Geom::X], (*lb)[2][Geom::Y]);\r
462                             TS_FAIL(temp);\r
463                             return false;\r
464                         }\r
465                         if (!Geom::are_near((*la)[3],(*lb)[3], eps)) {\r
466                             char temp[200];\r
467                             sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g)", (*la)[3][Geom::X], (*la)[3][Geom::Y], (*lb)[3][Geom::X], (*lb)[3][Geom::Y]);\r
468                             TS_FAIL(temp);\r
469                             return false;\r
470                         }\r
471                     }\r
472                     else\r
473                     {\r
474                         TS_FAIL((std::string("Unknown curve type: ") + typeid(*ca).name()).c_str());\r
475                         return false;\r
476                     }\r
477                 }\r
478                 else // not same type\r
479                 {\r
480                     if(Geom::LineSegment const *la = dynamic_cast<Geom::LineSegment const*>(ca))\r
481                     {\r
482                         if (Geom::HLineSegment const *lb = dynamic_cast<Geom::HLineSegment const*>(cb)) {\r
483                             if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
484                                 char temp[200];\r
485                                 sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g)", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y]);\r
486                                 TS_FAIL(temp);\r
487                                 return false;\r
488                             }\r
489                             if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
490                                 char temp[200];\r
491                                 sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g)", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y]);\r
492                                 TS_FAIL(temp);\r
493                                 return false;\r
494                             }\r
495                         } else if (Geom::VLineSegment const *lb = dynamic_cast<Geom::VLineSegment const*>(cb)) {\r
496                             if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
497                                 char temp[200];\r
498                                 sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g)", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y]);\r
499                                 TS_FAIL(temp);\r
500                                 return false;\r
501                             }\r
502                             if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
503                                 char temp[200];\r
504                                 sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g)", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y]);\r
505                                 TS_FAIL(temp);\r
506                                 return false;\r
507                             }\r
508                         } else {\r
509                             TS_FAIL((std::string("Different curve types: ") + typeid(*ca).name() + " != " + typeid(*cb).name()).c_str());\r
510                             return false;\r
511                         }\r
512                     }\r
513                     else if(Geom::LineSegment const *lb = dynamic_cast<Geom::LineSegment const*>(cb))\r
514                     {\r
515                         if (Geom::HLineSegment const *la = dynamic_cast<Geom::HLineSegment const*>(ca)) {\r
516                             if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
517                                 char temp[200];\r
518                                 sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g)", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y]);\r
519                                 TS_FAIL(temp);\r
520                                 return false;\r
521                             }\r
522                             if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
523                                 char temp[200];\r
524                                 sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g)", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y]);\r
525                                 TS_FAIL(temp);\r
526                                 return false;\r
527                             }\r
528                         } else if (Geom::VLineSegment const *la = dynamic_cast<Geom::VLineSegment const*>(ca)) {\r
529                             if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
530                                 char temp[200];\r
531                                 sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g)", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y]);\r
532                                 TS_FAIL(temp);\r
533                                 return false;\r
534                             }\r
535                             if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
536                                 char temp[200];\r
537                                 sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g)", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y]);\r
538                                 TS_FAIL(temp);\r
539                                 return false;\r
540                             }\r
541                         } else {\r
542                             TS_FAIL((std::string("Different curve types: ") + typeid(*ca).name() + " != " + typeid(*cb).name()).c_str());\r
543                             return false;\r
544                         }\r
545                     }\r
546                 }\r
547             }\r
548         }\r
549         return true;\r
550     }\r
551 };\r
552 \r
553 \r
554 /*\r
555   Local Variables:\r
556   mode:c++\r
557   c-file-style:"stroustrup"\r
558   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
559   indent-tabs-mode:nil\r
560   fill-column:99\r
561   End:\r
562 */\r
563 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r