1bcc5fb17de6d35d578ba91b9c410cc19f54a8ac
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