1
#include <cxxtest/TestSuite.h>
2
#include "2geom/coord.h"
3
#include "2geom/curves.h"
4
#include "2geom/pathvector.h"
6
#include "preferences.h"
11
#include <glib/gmem.h>
13
class SvgPathGeomTest : public CxxTest::TestSuite
16
std::vector<std::string> rectanglesAbsoluteClosed;
17
std::vector<std::string> rectanglesRelativeClosed;
18
std::vector<std::string> rectanglesAbsoluteOpen;
19
std::vector<std::string> rectanglesRelativeOpen;
20
std::vector<std::string> rectanglesAbsoluteClosed2;
21
std::vector<std::string> rectanglesRelativeClosed2;
22
Geom::PathVector rectanglepvopen;
23
Geom::PathVector rectanglepvclosed;
24
Geom::PathVector rectanglepvclosed2;
27
// Lots of ways to define the same rectangle
28
rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 z");
29
rectanglesAbsoluteClosed.push_back("M 1,2 4,2 4,8 1,8 z");
30
rectanglesAbsoluteClosed.push_back("M 1,2 H 4 V 8 H 1 z");
31
rectanglesRelativeClosed.push_back("m 1,2 l 3,0 l 0,6 l -3,0 z");
32
rectanglesRelativeClosed.push_back("m 1,2 3,0 0,6 -3,0 z");
33
rectanglesRelativeClosed.push_back("m 1,2 h 3 v 6 h -3 z");
34
rectanglesAbsoluteOpen.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2");
35
rectanglesAbsoluteOpen.push_back("M 1,2 4,2 4,8 1,8 1,2");
36
rectanglesAbsoluteOpen.push_back("M 1,2 H 4 V 8 H 1 V 2");
37
rectanglesRelativeOpen.push_back("m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6");
38
rectanglesRelativeOpen.push_back("m 1,2 3,0 0,6 -3,0 0,-6");
39
rectanglesRelativeOpen.push_back("m 1,2 h 3 v 6 h -3 v -6");
40
rectanglesAbsoluteClosed2.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2 z");
41
rectanglesAbsoluteClosed2.push_back("M 1,2 4,2 4,8 1,8 1,2 z");
42
rectanglesAbsoluteClosed2.push_back("M 1,2 H 4 V 8 H 1 V 2 z");
43
rectanglesRelativeClosed2.push_back("m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6 z");
44
rectanglesRelativeClosed2.push_back("m 1,2 3,0 0,6 -3,0 0,-6 z");
45
rectanglesRelativeClosed2.push_back("m 1,2 h 3 v 6 h -3 v -6 z");
46
rectanglepvopen.push_back(Geom::Path(Geom::Point(1,2)));
47
rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(1,2),Geom::Point(4,2)));
48
rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(4,2),Geom::Point(4,8)));
49
rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(4,8),Geom::Point(1,8)));
50
rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(1,8),Geom::Point(1,2)));
51
rectanglepvclosed.push_back(Geom::Path(Geom::Point(1,2)));
52
rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(1,2),Geom::Point(4,2)));
53
rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(4,2),Geom::Point(4,8)));
54
rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(4,8),Geom::Point(1,8)));
55
rectanglepvclosed.back().close();
56
rectanglepvclosed2.push_back(Geom::Path(Geom::Point(1,2)));
57
rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(1,2),Geom::Point(4,2)));
58
rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(4,2),Geom::Point(4,8)));
59
rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(4,8),Geom::Point(1,8)));
60
rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(1,8),Geom::Point(1,2)));
61
rectanglepvclosed2.back().close();
62
// TODO: Also test some (smooth) cubic/quadratic beziers and elliptical arcs
63
// TODO: Should we make it mandatory that h/v in the path data results in a H/VLineSegment?
64
// If so, the tests should be modified to reflect this.
67
// createSuite and destroySuite get us per-suite setup and teardown
68
// without us having to worry about static initialization order, etc.
69
static SvgPathGeomTest *createSuite() { return new SvgPathGeomTest(); }
70
static void destroySuite( SvgPathGeomTest *suite ) { delete suite; }
72
void testReadRectanglesAbsoluteClosed()
74
for(size_t i=0; i<rectanglesAbsoluteClosed.size(); i++) {
75
Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteClosed[i].c_str());
76
TSM_ASSERT(rectanglesAbsoluteClosed[i].c_str(), bpathEqual(pv,rectanglepvclosed));
80
void testReadRectanglesRelativeClosed()
82
for(size_t i=0; i<rectanglesRelativeClosed.size(); i++) {
83
Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeClosed[i].c_str());
84
TSM_ASSERT(rectanglesRelativeClosed[i].c_str(), bpathEqual(pv,rectanglepvclosed));
88
void testReadRectanglesAbsoluteOpen()
90
for(size_t i=0; i<rectanglesAbsoluteOpen.size(); i++) {
91
Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteOpen[i].c_str());
92
TSM_ASSERT(rectanglesAbsoluteOpen[i].c_str(), bpathEqual(pv,rectanglepvopen));
96
void testReadRectanglesRelativeOpen()
98
for(size_t i=0; i<rectanglesRelativeOpen.size(); i++) {
99
Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeOpen[i].c_str());
100
TSM_ASSERT(rectanglesRelativeOpen[i].c_str(), bpathEqual(pv,rectanglepvopen));
104
void testReadRectanglesAbsoluteClosed2()
106
for(size_t i=0; i<rectanglesAbsoluteClosed2.size(); i++) {
107
Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteClosed2[i].c_str());
108
TSM_ASSERT(rectanglesAbsoluteClosed2[i].c_str(), bpathEqual(pv,rectanglepvclosed2));
112
void testReadRectanglesRelativeClosed2()
114
for(size_t i=0; i<rectanglesRelativeClosed2.size(); i++) {
115
Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeClosed2[i].c_str());
116
TSM_ASSERT(rectanglesRelativeClosed2[i].c_str(), bpathEqual(pv,rectanglepvclosed2));
120
void testReadConcatenatedPaths()
122
// Note that finalPoint doesn't actually return the final point of the path, just the last given point... (but since this might be intentional and we're not testing lib2geom here, we just specify the final point explicitly
123
Geom::PathVector pv_good;
124
pv_good.push_back(rectanglepvclosed.back());
125
pv_good.push_back(rectanglepvopen.back() * Geom::Translate(1,2)/* * Geom::Translate(pv_good[0].finalPoint())*/);
126
pv_good.push_back(rectanglepvclosed.back() * Geom::Translate(2,4)/* *Geom::Translate(pv_good[1].finalPoint())*/);
127
pv_good.push_back(rectanglepvopen.back());
129
pv_good[1].close(false);
131
pv_good[3].close(false);
132
std::string path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];
133
Geom::PathVector pv = sp_svg_read_pathv(path_str.c_str());
134
TS_ASSERT(bpathEqual(pv,pv_good));
137
void testReadZeroLengthSubpaths() {
138
// Per the SVG 1.1 specification (section F5) zero-length subpaths are relevant
139
Geom::PathVector pv_good;
140
pv_good.push_back(Geom::Path(Geom::Point(0,0)));
141
pv_good.push_back(Geom::Path(Geom::Point(1,1)));
142
pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(2,2)));
143
pv_good.push_back(Geom::Path(Geom::Point(3,3)));
144
pv_good.back().close();
145
pv_good.push_back(Geom::Path(Geom::Point(4,4)));
146
pv_good.back().append(Geom::LineSegment(Geom::Point(4,4),Geom::Point(5,5)));
147
pv_good.back().close();
148
pv_good.push_back(Geom::Path(Geom::Point(6,6)));
149
{ // Test absolute version
150
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";
151
Geom::PathVector pv = sp_svg_read_pathv(path_str);
152
TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
154
{ // Test relative version
155
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";
156
Geom::PathVector pv = sp_svg_read_pathv(path_str);
157
TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
161
void testReadImplicitMoveto() {
162
TS_WARN("Currently lib2geom (/libnr) has no way of specifying the difference between '... z M 0,0 L 1,0' and '... z L 1,0', the SVG specification does state that these should be handled differently with respect to markers however, see the description of the 'orient' attribute of the 'marker' element.");
163
Geom::PathVector pv_good;
164
pv_good.push_back(Geom::Path(Geom::Point(1,1)));
165
pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(2,2)));
166
pv_good.back().close();
167
pv_good.push_back(Geom::Path(Geom::Point(1,1)));
168
pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(3,3)));
169
pv_good.back().close();
170
{ // Test absolute version
171
char const * path_str = "M 1,1 L 2,2 z L 3,3 z";
172
Geom::PathVector pv = sp_svg_read_pathv(path_str);
173
TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
175
{ // Test relative version
176
char const * path_str = "M 1,1 L 2,2 z L 3,3 z";
177
Geom::PathVector pv = sp_svg_read_pathv(path_str);
178
TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
182
void testReadFloatingPoint() {
183
Geom::PathVector pv_good1;
184
pv_good1.push_back(Geom::Path(Geom::Point(.01,.02)));
185
pv_good1.back().append(Geom::LineSegment(Geom::Point(.01,.02),Geom::Point(.04,.02)));
186
pv_good1.back().append(Geom::LineSegment(Geom::Point(.04,.02),Geom::Point(1.5,1.6)));
187
pv_good1.back().append(Geom::LineSegment(Geom::Point(1.5,1.6),Geom::Point(.01,.08)));
188
pv_good1.back().append(Geom::LineSegment(Geom::Point(.01,.08),Geom::Point(.01,.02)));
189
pv_good1.back().close();
191
char const * path_str = "M .01,.02 L.04.02 L1.5,1.6L0.01,0.08 .01.02 z";
192
Geom::PathVector pv = sp_svg_read_pathv(path_str);
193
TSM_ASSERT(path_str, bpathEqual(pv,pv_good1));
195
Geom::PathVector pv_good2;
196
pv_good2.push_back(Geom::Path(Geom::Point(.01,.02)));
197
pv_good2.back().append(Geom::LineSegment(Geom::Point(.01,.02),Geom::Point(.04,.02)));
198
pv_good2.back().append(Geom::LineSegment(Geom::Point(.04,.02),Geom::Point(1.5,1.6)));
199
pv_good2.back().append(Geom::LineSegment(Geom::Point(1.5,1.6),Geom::Point(.01,.08)));
200
pv_good2.back().close();
202
char const * path_str = "M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L0150E-2,1.6e0L1.0e-2,80e-3 z";
203
Geom::PathVector pv = sp_svg_read_pathv(path_str);
204
TSM_ASSERT(path_str, bpathEqual(pv,pv_good2));
208
void testReadImplicitSeparation() {
209
// Coordinates need not be separated by whitespace if they can still be read unambiguously
210
Geom::PathVector pv_good;
211
pv_good.push_back(Geom::Path(Geom::Point(.1,.2)));
212
pv_good.back().append(Geom::LineSegment(Geom::Point(.1,.2),Geom::Point(.4,.2)));
213
pv_good.back().append(Geom::LineSegment(Geom::Point(.4,.2),Geom::Point(.4,.8)));
214
pv_good.back().append(Geom::LineSegment(Geom::Point(.4,.8),Geom::Point(.1,.8)));
215
pv_good.back().close();
217
char const * path_str = "M .1.2+0.4.2e0.4e0+8e-1.1.8 z";
218
Geom::PathVector pv = sp_svg_read_pathv(path_str);
219
TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
222
char const * path_str = "m .1.2+0.3.0e0.0e0+6e-1-.3.0 z";
223
Geom::PathVector pv = sp_svg_read_pathv(path_str);
224
TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
228
void testReadErrorMisplacedCharacter() {
229
char const * path_str;
231
// Comma in the wrong place (commas may only appear between parameters)
232
path_str = "M 1,2 4,2 4,8 1,8 z , m 13,15";
233
pv = sp_svg_read_pathv(path_str);
234
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
235
// Comma in the wrong place (commas may only appear between parameters)
236
path_str = "M 1,2 4,2 4,8 1,8 z m,13,15";
237
pv = sp_svg_read_pathv(path_str);
238
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
239
// Period in the wrong place (no numbers after a 'z')
240
path_str = "M 1,2 4,2 4,8 1,8 z . m 13,15";
241
pv = sp_svg_read_pathv(path_str);
242
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
243
// Sign in the wrong place (no numbers after a 'z')
244
path_str = "M 1,2 4,2 4,8 1,8 z + - m 13,15";
245
pv = sp_svg_read_pathv(path_str);
246
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
247
// Digit in the wrong place (no numbers after a 'z')
248
path_str = "M 1,2 4,2 4,8 1,8 z 9809 m 13,15";
249
pv = sp_svg_read_pathv(path_str);
250
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
251
// Digit in the wrong place (no numbers after a 'z')
252
path_str = "M 1,2 4,2 4,8 1,8 z 9809 876 m 13,15";
253
pv = sp_svg_read_pathv(path_str);
254
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
257
void testReadErrorUnrecognizedCharacter() {
258
char const * path_str;
260
// Unrecognized character
261
path_str = "M 1,2 4,2 4,8 1,8 z&m 13,15";
262
pv = sp_svg_read_pathv(path_str);
263
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
264
// Unrecognized character
265
path_str = "M 1,2 4,2 4,8 1,8 z m &13,15";
266
pv = sp_svg_read_pathv(path_str);
267
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
270
void testReadErrorTypo() {
271
char const * path_str;
274
path_str = "M 1,2 4,2 4,8 1,8 z j 13,15";
275
pv = sp_svg_read_pathv(path_str);
276
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
279
path_str = "M 1,2 4,2 4,8 1,8 L 1,2 x m 13,15";
280
pv = sp_svg_read_pathv(path_str);
281
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvopen));
284
void testReadErrorIllformedNumbers() {
285
char const * path_str;
288
path_str = "M 1,2 4,2 4,8 1,8 z m 13e4e5,15";
289
pv = sp_svg_read_pathv(path_str);
290
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
292
path_str = "M 1,2 4,2 4,8 1,8 z m +-13,15";
293
pv = sp_svg_read_pathv(path_str);
294
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
296
path_str = "M 1,2 4,2 4,8 1,8 z m 13e+-12,15";
297
pv = sp_svg_read_pathv(path_str);
298
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
300
path_str = "M 1,2 4,2 4,8 1,8 z m .e12,15";
301
pv = sp_svg_read_pathv(path_str);
302
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
304
path_str = "M 1,2 4,2 4,8 1,8 z m .,15";
305
pv = sp_svg_read_pathv(path_str);
306
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
308
path_str = "M 1,2 4,2 4,8 1,8 z m +,15";
309
pv = sp_svg_read_pathv(path_str);
310
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
312
path_str = "M 1,2 4,2 4,8 1,8 z m +.e+,15";
313
pv = sp_svg_read_pathv(path_str);
314
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
317
void testReadErrorJunk() {
318
char const * path_str;
321
path_str = "M 1,2 4,2 4,8 1,8 z j 357 hkjh.,34e34 90ih6kj4 h5k6vlh4N.,6,45wikuyi3yere..3487 m 13,23";
322
pv = sp_svg_read_pathv(path_str);
323
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
326
void testReadErrorStopReading() {
327
char const * path_str;
329
// Unrecognized parameter
330
path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";
331
pv = sp_svg_read_pathv(path_str);
332
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
334
path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";
335
pv = sp_svg_read_pathv(path_str);
336
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
337
// Illformed parameter
338
path_str = "M 1,2 4,2 4,8 1,8 z m +-12,23,34";
339
pv = sp_svg_read_pathv(path_str);
340
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
343
path_str = "M 1,2 4,2 4,8 1,8 1,2,3 M 12,23";
344
pv = sp_svg_read_pathv(path_str);
345
TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvopen));
348
void testRoundTrip() {
349
// This is the easiest way to (also) test writing path data, as a path can be written in more than one way.
351
Geom::PathVector new_pv;
352
std::string org_path_str;
354
// Rectangle (closed)
355
org_path_str = rectanglesAbsoluteClosed[0];
356
pv = sp_svg_read_pathv(org_path_str.c_str());
357
path_str = sp_svg_write_path(pv);
358
new_pv = sp_svg_read_pathv(path_str);
359
TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));
362
org_path_str = rectanglesAbsoluteOpen[0];
363
pv = sp_svg_read_pathv(org_path_str.c_str());
364
path_str = sp_svg_write_path(pv);
365
new_pv = sp_svg_read_pathv(path_str);
366
TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));
368
// Concatenated rectangles
369
org_path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];
370
pv = sp_svg_read_pathv(org_path_str.c_str());
371
path_str = sp_svg_write_path(pv);
372
new_pv = sp_svg_read_pathv(path_str);
373
TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));
375
// Zero-length subpaths
376
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";
377
pv = sp_svg_read_pathv(org_path_str.c_str());
378
path_str = sp_svg_write_path(pv);
379
new_pv = sp_svg_read_pathv(path_str);
380
TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));
383
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";
384
pv = sp_svg_read_pathv(org_path_str.c_str());
385
path_str = sp_svg_write_path(pv);
386
new_pv = sp_svg_read_pathv(path_str);
387
TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv, new_pv, 1e-17));
391
void testMinexpPrecision() {
395
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
396
prefs->setBool("/options/svgoutput/allowrelativecoordinates", true);
397
prefs->setBool("/options/svgoutput/forcerepeatcommands", false);
398
prefs->setInt("/options/svgoutput/numericprecision", 8);
399
prefs->setInt("/options/svgoutput/minimumexponent", -8);
400
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");
401
path_str = sp_svg_write_path(pv);
402
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 );
407
bool bpathEqual(Geom::PathVector const &a, Geom::PathVector const &b, double eps = 1e-16) {
408
if (a.size() != b.size()) {
410
sprintf(temp, "PathVectors not the same size: %u != %u", a.size(), b.size());
414
for(size_t i=0; i<a.size(); i++) {
415
Geom::Path const &pa = a[i];
416
Geom::Path const &pb = b[i];
417
if (pa.closed() && !pb.closed()) {
419
sprintf(temp, "Left subpath is closed, right subpath is open. Subpath: %u", i);
423
if (!pa.closed() && pb.closed()) {
425
sprintf(temp, "Right subpath is closed, left subpath is open. Subpath: %u", i);
429
if (pa.size() != pb.size()) {
431
sprintf(temp, "Not the same number of segments: %u != %u, subpath: %u", pa.size(), pb.size(), i);
435
for(size_t j=0; j<pa.size(); j++) {
436
Geom::Curve const* ca = &pa[j];
437
Geom::Curve const* cb = &pb[j];
438
if (typeid(*ca) == typeid(*cb))
440
if(Geom::LineSegment const *la = dynamic_cast<Geom::LineSegment const*>(ca))
442
Geom::LineSegment const *lb = dynamic_cast<Geom::LineSegment const*>(cb);
443
if (!Geom::are_near((*la)[0],(*lb)[0], eps)) {
445
sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[0][Geom::X], (*la)[0][Geom::Y], (*lb)[0][Geom::X], (*lb)[0][Geom::Y], i, j);
449
if (!Geom::are_near((*la)[1],(*lb)[1], eps)) {
451
sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[1][Geom::X], (*la)[1][Geom::Y], (*lb)[1][Geom::X], (*lb)[1][Geom::Y], i, j);
456
else if(Geom::HLineSegment const *la = dynamic_cast<Geom::HLineSegment const*>(ca))
458
Geom::HLineSegment const *lb = dynamic_cast<Geom::HLineSegment const*>(cb);
459
if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
461
sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
465
if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
467
sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
472
else if(Geom::VLineSegment const *la = dynamic_cast<Geom::VLineSegment const*>(ca))
474
Geom::VLineSegment const *lb = dynamic_cast<Geom::VLineSegment const*>(cb);
475
if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
477
sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
481
if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
483
sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
488
else if(Geom::CubicBezier const *la = dynamic_cast<Geom::CubicBezier const*>(ca))
490
Geom::CubicBezier const *lb = dynamic_cast<Geom::CubicBezier const*>(cb);
491
if (!Geom::are_near((*la)[0],(*lb)[0], eps)) {
493
sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[0][Geom::X], (*la)[0][Geom::Y], (*lb)[0][Geom::X], (*lb)[0][Geom::Y], i, j);
497
if (!Geom::are_near((*la)[1],(*lb)[1], eps)) {
499
sprintf(temp, "Different 1st control point: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[1][Geom::X], (*la)[1][Geom::Y], (*lb)[1][Geom::X], (*lb)[1][Geom::Y], i, j);
503
if (!Geom::are_near((*la)[2],(*lb)[2], eps)) {
505
sprintf(temp, "Different 2nd control point: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[2][Geom::X], (*la)[2][Geom::Y], (*lb)[2][Geom::X], (*lb)[2][Geom::Y], i, j);
509
if (!Geom::are_near((*la)[3],(*lb)[3], eps)) {
511
sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[3][Geom::X], (*la)[3][Geom::Y], (*lb)[3][Geom::X], (*lb)[3][Geom::Y], i, j);
519
sprintf(temp, "Unknown curve type: %s, subpath: %u, segment: %u", typeid(*ca).name(), i, j);
523
else // not same type
525
if(Geom::LineSegment const *la = dynamic_cast<Geom::LineSegment const*>(ca))
527
if (Geom::HLineSegment const *lb = dynamic_cast<Geom::HLineSegment const*>(cb)) {
528
if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
530
sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
534
if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
536
sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
541
sprintf(temp, "A LineSegment and an HLineSegment have been considered equal. Subpath: %u, segment: %u", i, j);
543
} else if (Geom::VLineSegment const *lb = dynamic_cast<Geom::VLineSegment const*>(cb)) {
544
if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
546
sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
550
if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
552
sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
557
sprintf(temp, "A LineSegment and a VLineSegment have been considered equal. Subpath: %u, segment: %u", i, j);
561
sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), i, j);
565
else if(Geom::LineSegment const *lb = dynamic_cast<Geom::LineSegment const*>(cb))
567
if (Geom::HLineSegment const *la = dynamic_cast<Geom::HLineSegment const*>(ca)) {
568
if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
570
sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
574
if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
576
sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
581
sprintf(temp, "An HLineSegment and a LineSegment have been considered equal. Subpath: %u, segment: %u", i, j);
583
} else if (Geom::VLineSegment const *la = dynamic_cast<Geom::VLineSegment const*>(ca)) {
584
if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
586
sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
590
if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
592
sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
597
sprintf(temp, "A VLineSegment and a LineSegment have been considered equal. Subpath: %u, segment: %u", i, j);
601
sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), i, j);
607
sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), i, j);
621
c-file-style:"stroustrup"
622
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
627
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :