xref: /aoo42x/main/basegfx/test/basegfx2d.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 
29 // MARKER(update_precomp.py): autogen include statement, do not remove
30 #include "precompiled_basegfx.hxx"
31 // autogenerated file with codegen.pl
32 
33 #include "preextstl.h"
34 #include "cppunit/TestAssert.h"
35 #include "cppunit/TestFixture.h"
36 #include "cppunit/extensions/HelperMacros.h"
37 #include "postextstl.h"
38 
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <basegfx/polygon/b2dpolygon.hxx>
41 #include <basegfx/polygon/b2dpolygontools.hxx>
42 #include <basegfx/curve/b2dcubicbezier.hxx>
43 #include <basegfx/curve/b2dbeziertools.hxx>
44 #include <basegfx/polygon/b2dpolypolygontools.hxx>
45 #include <basegfx/polygon/b2dpolygonclipper.hxx>
46 #include <basegfx/polygon/b2dpolypolygon.hxx>
47 #include <basegfx/range/b2dpolyrange.hxx>
48 #include <basegfx/numeric/ftools.hxx>
49 #include <basegfx/color/bcolor.hxx>
50 #include <basegfx/color/bcolortools.hxx>
51 
52 #include <basegfx/tools/debugplotter.hxx>
53 
54 #include <iostream>
55 #include <fstream>
56 
57 using namespace ::basegfx;
58 
59 
60 namespace basegfx2d
61 {
62 
63 class b2dsvgdimpex : public CppUnit::TestFixture
64 {
65 private:
66     ::rtl::OUString aPath0;
67     ::rtl::OUString aPath1;
68     ::rtl::OUString aPath2;
69     ::rtl::OUString aPath3;
70 
71 public:
72     // initialise your test code values here.
73     void setUp()
74     {
75         // simple rectangle
76         aPath0 = ::rtl::OUString::createFromAscii(
77             "M 10 10-10 10-10-10 10-10Z" );
78 
79         // simple bezier polygon
80         aPath1 = ::rtl::OUString::createFromAscii(
81             "m11430 0c-8890 3810 5715 6985 5715 6985 "
82             "0 0-17145-1905-17145-1905 0 0 22860-10160 "
83             "16510 6350-6350 16510-3810-11430-3810-11430z" );
84 
85         // '@' as a bezier polygon
86         aPath2 = ::rtl::OUString::createFromAscii(
87             "m1917 1114c-89-189-233-284-430-284-167 "
88             "0-306 91-419 273-113 182-170 370-170 564 "
89             "0 145 33 259 98 342 65 84 150 126 257 126 "
90             "77 0 154-19 231-57 77-38 147-97 210-176 63"
91             "-79 99-143 109-190 38-199 76-398 114-598z"
92             "m840 1646c-133 73-312 139-537 197-225 57"
93             "-440 86-644 87-483-1-866-132-1150-392-284"
94             "-261-426-619-426-1076 0-292 67-560 200-803 "
95             "133-243 321-433 562-569 241-136 514-204 821"
96             "-204 405 0 739 125 1003 374 264 250 396 550 "
97             "396 899 0 313-88 576-265 787-177 212-386 318"
98             "-627 318-191 0-308-94-352-281-133 187-315 281"
99             "-546 281-172 0-315-67-428-200-113-133-170-301"
100             "-170-505 0-277 90-527 271-751 181-223 394"
101             "-335 640-335 196 0 353 83 470 250 13-68 26"
102             "-136 41-204 96 0 192 0 288 0-74 376-148 752"
103             "-224 1128-21 101-31 183-31 245 0 39 9 70 26 "
104             "93 17 24 39 36 67 36 145 0 279-80 400-240 121"
105             "-160 182-365 182-615 0-288-107-533-322-734"
106             "-215-201-487-301-816-301-395 0-715 124-960 "
107             "373-245 249-368 569-368 958 0 385 119 685 "
108             "357 900 237 216 557 324 958 325 189-1 389-27 "
109             "600-77 211-52 378-110 503-174 27 70 54 140 81 210z" );
110 
111         // first part of 'Hello World' as a line polygon
112         aPath3 = ::rtl::OUString::createFromAscii(
113             "m1598 125h306v2334h-306v-1105h-1293v1105h-305v"
114             "-2334h305v973h1293zm2159 1015 78-44 85 235-91 "
115             "47-91 40-90 34-90 29-89 21-88 16-88 10-88 3-102"
116             "-4-97-12-91-19-85-26-40-16-39-18-38-20-36-22-34"
117             "-24-33-26-32-27-30-30-29-31-27-33-25-33-23-36-21"
118             "-36-19-38-18-40-16-40-26-86-18-91-11-97-4-103 3"
119             "-98 11-94 17-89 24-84 31-79 37-75 22-35 23-34 24"
120             "-33 27-32 28-30 29-28 31-27 31-24 33-22 34-21 35"
121             "-18 37-17 38-14 38-13 41-11 41-8 86-12 91-4 82 4 "
122             "78 10 37 9 37 9 36 12 35 14 33 15 33 17 32 19 31 "
123             "21 30 22 30 25 55 54 26 29 24 31 22 32 21 33 19 "
124             "34 18 36 30 74 23 80 17 84 10 89 3 94v78h-1277l6 "
125             "75 10 70 14 66 19 62 23 57 13 26 14 26 15 25 17 "
126             "23 17 22 19 21 19 20 21 18 21 18 23 16 23 14 24 "
127             "14 26 12 26 11 27 10 28 8 59 13 63 7 67 3 80-3 81"
128             "-9 79-14 80-21 78-26 79-32zm-1049-808-12 53h963l"
129             "-7-51-11-49-14-46-17-43-21-40-24-38-27-36-31-32"
130             "-33-29-35-25-37-22-38-17-40-14-41-9-42-6-44-2-48 "
131             "2-46 6-44 9-42 13-40 17-38 21-36 24-34 28-32 32"
132             "-29 34-26 38-23 41-20 44-17 47zm1648-1293h288v"
133             "2459h-288zm752-2459h288v2459h-288zm1286-1750 86-11 "
134             "91-4 91 4 85 12 42 8 39 11 39 13 38 14 36 17 35 18 "
135             "34 20 33 23 31 24 30 26 29 28 28 30 26 32 25 33 23 "
136             "34 21 35 37 75 31 80 24 84 16 90 11 94 3 100-3 100"
137             "-11 95-16 89-24 85-31 80-37 74-21 35-23 35-25 32-26 "
138             "32-28 30-29 28-30 26-31 24-33 22-34 21-35 18-36 17"
139             "-38 14-39 13-39 10-42 9-85 12-91 4-91-4-86-12-41-9"
140             "-40-10-39-13-37-14-36-17-35-18-34-21-33-22-31-24-30"
141             "-26-29-28-28-30-26-32-25-32-23-35-21-35-38-74-30-80"
142             "-24-85-17-89-11-95-3-100 3-101 11-95 17-90 24-85 30"
143             "-79 38-75 21-35 23-35 25-32 26-32 28-30 29-28 30-26 "
144             "31-24 33-22 34-20 35-18 36-16 37-15 39-12 40-11z" );
145     }
146 
147     void tearDown()
148     {
149     }
150 
151     void impex()
152     {
153         B2DPolyPolygon 	aPoly;
154         ::rtl::OUString aExport;
155 
156         CPPUNIT_ASSERT_MESSAGE("importing simple rectangle from SVG-D",
157                                tools::importFromSvgD( aPoly,
158                                                       aPath0 ));
159         aExport = tools::exportToSvgD( aPoly );
160         const char* sExportString = "m10 10h-20v-20h20z";
161         CPPUNIT_ASSERT_MESSAGE("exporting rectangle to SVG-D",
162                                !aExport.compareToAscii(sExportString) );
163         CPPUNIT_ASSERT_MESSAGE("importing simple rectangle from SVG-D (round-trip",
164                                tools::importFromSvgD( aPoly,
165                                                       aExport ));
166         aExport = tools::exportToSvgD( aPoly );
167         CPPUNIT_ASSERT_MESSAGE("exporting rectangle to SVG-D (round-trip)",
168                                !aExport.compareToAscii(sExportString));
169 
170         CPPUNIT_ASSERT_MESSAGE("importing simple bezier polygon from SVG-D",
171                                tools::importFromSvgD( aPoly,
172                                                       aPath1 ));
173         aExport = tools::exportToSvgD( aPoly );
174 
175 		// Adaptions for B2DPolygon bezier change (see #i77162#):
176 		//
177 		// The import/export of aPath1 does not reproduce aExport again. This is
178 		// correct since aPath1 contains a segment with non-used control points
179 		// which gets exported now correctly as 'l' and also a point (#4, index 3)
180 		// with C2 continuity which produces a 's' staement now.
181 		//
182 		// The old SVGexport identified nun-used ControlVectors erraneously as bezier segments
183 		// because the 2nd vector at the start point was used, even when added
184 		// with start point was identical to end point. Exactly for that reason
185 		// i reworked the B2DPolygon to use prev, next control points.
186 		//
187 		// so for correct unit test i add the new exported string here as sExportStringSimpleBezier
188 		// and compare to it.
189 		const char* sExportStringSimpleBezier =
190 			"m11430 0c-8890 3810 5715 6985 5715 6985"
191 			"l-17145-1905c0 0 22860-10160 16510 6350"
192 			"s-3810-11430-3810-11430z";
193 		CPPUNIT_ASSERT_MESSAGE("exporting bezier polygon to SVG-D", !aExport.compareToAscii(sExportStringSimpleBezier));
194 
195 		// Adaptions for B2DPolygon bezier change (see #i77162#):
196 		//
197 		// a 2nd good test is that re-importing of aExport has to create the same
198 		// B2DPolPolygon again:
199 		B2DPolyPolygon aReImport;
200         CPPUNIT_ASSERT_MESSAGE("importing simple bezier polygon from SVG-D", tools::importFromSvgD( aReImport, aExport));
201         CPPUNIT_ASSERT_MESSAGE("re-imported polygon needs to be identical", aReImport == aPoly);
202 
203 		CPPUNIT_ASSERT_MESSAGE("importing '@' from SVG-D", tools::importFromSvgD( aPoly, aPath2 ));
204         aExport = tools::exportToSvgD( aPoly );
205 
206 		// Adaptions for B2DPolygon bezier change (see #i77162#):
207 		//
208 		// same here, the corrected export with the corrected B2DPolygon is simply more efficient,
209 		// so i needed to change the compare string. Also adding the re-import comparison below.
210 		const char* sExportString1 =
211 			"m1917 1114c-89-189-233-284-430-284-167 0-306 91-419 273s-170 370-17"
212 			"0 564c0 145 33 259 98 342 65 84 150 126 257 126q115.5 0 231-57s147-97 210-176 99-143 109-190c38-199 76-398 114"
213 			"-598zm840 1646c-133 73-312 139-537 197-225 57-440 86-644 87-483-1-866-132-1150-392-284-261-426-619-426-1076 0-"
214 			"292 67-560 200-803s321-433 562-569 514-204 821-204c405 0 739 125 1003 374 264 250 396 550 396 899 0 313-88 576"
215 			"-265 787q-265.5 318-627 318c-191 0-308-94-352-281-133 187-315 281-546 281-172 0-315-67-428-200s-170-301-170-50"
216 			"5c0-277 90-527 271-751 181-223 394-335 640-335 196 0 353 83 470 250 13-68 26-136 41-204q144 0 288 0c-74 376-14"
217 			"8 752-224 1128-21 101-31 183-31 245 0 39 9 70 26 93 17 24 39 36 67 36 145 0 279-80 400-240s182-365 182-615c0-2"
218 			"88-107-533-322-734s-487-301-816-301c-395 0-715 124-960 373s-368 569-368 958q0 577.5 357 900c237 216 557 324 95"
219 			"8 325 189-1 389-27 600-77 211-52 378-110 503-174q40.5 105 81 210z";
220         CPPUNIT_ASSERT_MESSAGE("re-importing '@' from SVG-D", tools::importFromSvgD( aReImport, aExport));
221         CPPUNIT_ASSERT_MESSAGE("re-imported '@' needs to be identical", aReImport == aPoly);
222 
223         CPPUNIT_ASSERT_MESSAGE("exporting '@' to SVG-D", !aExport.compareToAscii(sExportString1));
224         CPPUNIT_ASSERT_MESSAGE("importing '@' from SVG-D (round-trip",
225                                tools::importFromSvgD( aPoly,
226                                                       aExport ));
227         aExport = tools::exportToSvgD( aPoly );
228         CPPUNIT_ASSERT_MESSAGE("exporting '@' to SVG-D (round-trip)",
229                                !aExport.compareToAscii(sExportString1));
230 
231 
232         CPPUNIT_ASSERT_MESSAGE("importing complex polygon from SVG-D",
233                                tools::importFromSvgD( aPoly,
234                                                       aPath3 ));
235         aExport = tools::exportToSvgD( aPoly );
236         const char* sExportString2 =
237             "m1598 125h306v2334h-306v-1105h-1293v1105h-305v-2334h305v973h1293"
238             "zm2159 1015 78-44 85 235-91 47-91 40-90 34-90 29-89 21-88 16-88 10-88 3-102-4-97"
239             "-12-91-19-85-26-40-16-39-18-38-20-36-22-34-24-33-26-32-27-30-30-29-31-27-33-25-3"
240             "3-23-36-21-36-19-38-18-40-16-40-26-86-18-91-11-97-4-103 3-98 11-94 17-89 24-84 3"
241             "1-79 37-75 22-35 23-34 24-33 27-32 28-30 29-28 31-27 31-24 33-22 34-21 35-18 37-"
242             "17 38-14 38-13 41-11 41-8 86-12 91-4 82 4 78 10 37 9 37 9 36 12 35 14 33 15 33 1"
243             "7 32 19 31 21 30 22 30 25 55 54 26 29 24 31 22 32 21 33 19 34 18 36 30 74 23 80 "
244             "17 84 10 89 3 94v78h-1277l6 75 10 70 14 66 19 62 23 57 13 26 14 26 15 25 17 23 1"
245             "7 22 19 21 19 20 21 18 21 18 23 16 23 14 24 14 26 12 26 11 27 10 28 8 59 13 63 7"
246             " 67 3 80-3 81-9 79-14 80-21 78-26 79-32zm-1049-808-12 53h963l-7-51-11-49-14-46-1"
247             "7-43-21-40-24-38-27-36-31-32-33-29-35-25-37-22-38-17-40-14-41-9-42-6-44-2-48 2-4"
248             "6 6-44 9-42 13-40 17-38 21-36 24-34 28-32 32-29 34-26 38-23 41-20 44-17 47zm1648"
249             "-1293h288v2459h-288zm752-2459h288v2459h-288zm1286-1750 86-11 91-4 91 4 85 12 42 "
250             "8 39 11 39 13 38 14 36 17 35 18 34 20 33 23 31 24 30 26 29 28 28 30 26 32 25 33 "
251             "23 34 21 35 37 75 31 80 24 84 16 90 11 94 3 100-3 100-11 95-16 89-24 85-31 80-37"
252             " 74-21 35-23 35-25 32-26 32-28 30-29 28-30 26-31 24-33 22-34 21-35 18-36 17-38 1"
253             "4-39 13-39 10-42 9-85 12-91 4-91-4-86-12-41-9-40-10-39-13-37-14-36-17-35-18-34-2"
254             "1-33-22-31-24-30-26-29-28-28-30-26-32-25-32-23-35-21-35-38-74-30-80-24-85-17-89-"
255             "11-95-3-100 3-101 11-95 17-90 24-85 30-79 38-75 21-35 23-35 25-32 26-32 28-30 29"
256             "-28 30-26 31-24 33-22 34-20 35-18 36-16 37-15 39-12 40-11z";
257         CPPUNIT_ASSERT_MESSAGE("exporting complex polygon to SVG-D",
258                                !aExport.compareToAscii(sExportString2));
259         CPPUNIT_ASSERT_MESSAGE("importing complex polygon from SVG-D (round-trip",
260                                tools::importFromSvgD( aPoly,
261                                                       aExport ));
262         aExport = tools::exportToSvgD( aPoly );
263         CPPUNIT_ASSERT_MESSAGE("exporting complex polygon to SVG-D (round-trip)",
264                                !aExport.compareToAscii(sExportString2));
265 
266         const B2DPolygon aRect(
267             tools::createPolygonFromRect( B2DRange(0.0,0.0,4000.0,4000.0) ));
268         aExport = tools::exportToSvgD( B2DPolyPolygon(aRect), false, false);
269 
270 		const char* sExportStringRect = "M0 0H4000V4000H0Z";
271 		CPPUNIT_ASSERT_MESSAGE("exporting to rectangle svg-d string",
272                                !aExport.compareToAscii(sExportStringRect));
273     }
274 
275     // Change the following lines only, if you add, remove or rename
276     // member functions of the current class,
277     // because these macros are need by auto register mechanism.
278 
279     CPPUNIT_TEST_SUITE(b2dsvgdimpex);
280     CPPUNIT_TEST(impex);
281     CPPUNIT_TEST_SUITE_END();
282 }; // class b2dsvgdimpex
283 
284 class b2dpolyrange : public CppUnit::TestFixture
285 {
286 private:
287 public:
288     void setUp()
289     {}
290 
291     void tearDown()
292     {}
293 
294     void check()
295     {
296         B2DPolyRange aRange;
297         aRange.appendElement(B2DRange(0,0,1,1),ORIENTATION_POSITIVE);
298         aRange.appendElement(B2DRange(2,2,3,3),ORIENTATION_POSITIVE);
299 
300         CPPUNIT_ASSERT_MESSAGE("simple poly range - count",
301                                aRange.count() == 2);
302         CPPUNIT_ASSERT_MESSAGE("simple poly range - first element",
303                                aRange.getElement(0).head == B2DRange(0,0,1,1));
304         CPPUNIT_ASSERT_MESSAGE("simple poly range - second element",
305                                aRange.getElement(1).head == B2DRange(2,2,3,3));
306 
307         // B2DPolyRange relies on correctly orientated rects
308         const B2DRange aRect(0,0,1,1);
309         CPPUNIT_ASSERT_MESSAGE("createPolygonFromRect - correct orientation",
310                                tools::getOrientation(
311                                    tools::createPolygonFromRect(aRect)) == ORIENTATION_POSITIVE );
312     }
313 
314     // Change the following lines only, if you add, remove or rename
315     // member functions of the current class,
316     // because these macros are need by auto register mechanism.
317 
318     CPPUNIT_TEST_SUITE(b2dpolyrange);
319     CPPUNIT_TEST(check);
320     CPPUNIT_TEST_SUITE_END();
321 };
322 
323 class b2dbeziertools : public CppUnit::TestFixture
324 {
325 private:
326     B2DCubicBezier aHalfCircle; 					// not exactly, but a look-alike
327     B2DCubicBezier aQuarterCircle; 					// not exactly, but a look-alike
328     B2DCubicBezier aLoop; 							// identical endpoints, curve goes back to where it started
329     B2DCubicBezier aStraightLineDistinctEndPoints;	// truly a line
330     B2DCubicBezier aStraightLineDistinctEndPoints2;	// truly a line, with slightly different control points
331     B2DCubicBezier aStraightLineIdenticalEndPoints;	// degenerate case of aLoop
332     B2DCubicBezier aStraightLineIdenticalEndPoints2;// degenerate case of aLoop, with slightly different control points
333     B2DCubicBezier aCrossing;						// curve self-intersects somewhere in the middle
334     B2DCubicBezier aCusp;							// curve has a point of undefined tangency
335 
336 
337 public:
338     // initialise your test code values here.
339     void setUp()
340     {
341         const B2DPoint a00(0.0, 0.0);
342         const B2DPoint a10(1.0, 0.0);
343         const B2DPoint a11(1.0, 1.0);
344         const B2DPoint a01(0.0, 1.0);
345         const B2DPoint middle( 0.5, 0.5 );
346         const B2DPoint quarterDown( 0.25, 0.25 );
347         const B2DPoint quarterUp( 0.75, 0.75 );
348 
349         aHalfCircle 	= B2DCubicBezier(a00, a01, a11, a10);
350 
351 		// The spline control points become
352 		//
353 		// 	(R * cos(A), R * sin(A))
354 		// 	(R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
355 		// 	(R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
356 		// 	(R * cos(B), R * sin(B))
357 		//
358 		// where	h = 4/3 * R * tan ((B-A)/4)
359         //
360         // with R being the radius, A start angle and B end angle (A < B).
361         //
362         // (This calculation courtesy Carl Worth, himself based on
363         // Michael Goldapp and Dokken/Daehlen)
364 
365         // Choosing R=1, A=0, B=pi/2
366         const double h( 4.0/3.0 * tan(M_PI/8.0) );
367         aQuarterCircle 	= B2DCubicBezier(a10 + B2DPoint(1.0,0.0),
368                                          B2DPoint(B2DPoint( 1.0, h ) + B2DPoint(1.0,0.0)),
369                                          B2DPoint(B2DPoint( h, 1.0) + B2DPoint(1.0,0.0)),
370                                          a01 + B2DPoint(1.0,0.0));
371 
372         aCusp 			= B2DCubicBezier(a00 + B2DPoint(2.0,0.0),
373                                          B2DPoint(a11 + B2DPoint(2.0,0.0)),
374                                          B2DPoint(a01 + B2DPoint(2.0,0.0)),
375                                          a10 + B2DPoint(2.0,0.0));
376 
377         aLoop			= B2DCubicBezier(a00 + B2DPoint(3.0,0.0),
378                                          B2DPoint(a01 + B2DPoint(3.0,0.0)),
379                                          B2DPoint(a10 + B2DPoint(3.0,0.0)),
380                                          a00 + B2DPoint(3.0,0.0));
381 
382         aStraightLineDistinctEndPoints  = B2DCubicBezier(a00 + B2DPoint(4.0,0.0),
383                                                          B2DPoint(middle + B2DPoint(4.0,0.0)),
384                                                          B2DPoint(middle + B2DPoint(4.0,0.0)),
385                                                          a11 + B2DPoint(4.0,0.0));
386 
387         aStraightLineDistinctEndPoints2  = B2DCubicBezier(a00 + B2DPoint(5.0,0.0),
388                                                           B2DPoint(quarterDown + B2DPoint(5.0,0.0)),
389                                                           B2DPoint(quarterUp + B2DPoint(5.0,0.0)),
390                                                           a11 + B2DPoint(5.0,0.0));
391 
392         aStraightLineIdenticalEndPoints = B2DCubicBezier(a00 + B2DPoint(6.0,0.0),
393                                                          B2DPoint(a11 + B2DPoint(6.0,0.0)),
394                                                          B2DPoint(a11 + B2DPoint(6.0,0.0)),
395                                                          a00 + B2DPoint(6.0,0.0));
396 
397         aStraightLineIdenticalEndPoints2 = B2DCubicBezier(a00 + B2DPoint(7.0,0.0),
398                                                           B2DPoint(quarterDown + B2DPoint(7.0,0.0)),
399                                                           B2DPoint(quarterUp + B2DPoint(7.0,0.0)),
400                                                           a00 + B2DPoint(7.0,0.0));
401 
402         aCrossing		= B2DCubicBezier(a00 + B2DPoint(8.0,0.0),
403                                          B2DPoint(B2DPoint(2.0,2.0) + B2DPoint(8.0,0.0)),
404                                          B2DPoint(B2DPoint(-1.0,2.0) + B2DPoint(8.0,0.0)),
405                                          a10 + B2DPoint(8.0,0.0));
406 
407         ::std::ofstream output("bez_testcases.gnuplot");
408         DebugPlotter aPlotter( "Original curves",
409                                output );
410 
411         aPlotter.plot( aHalfCircle,
412                        "half circle" );
413         aPlotter.plot( aQuarterCircle,
414                        "quarter circle" );
415         aPlotter.plot( aCusp,
416                        "cusp" );
417         aPlotter.plot( aLoop,
418                        "loop" );
419         aPlotter.plot( aStraightLineDistinctEndPoints,
420                        "straight line 0" );
421         aPlotter.plot( aStraightLineDistinctEndPoints2,
422                        "straight line 1" );
423         aPlotter.plot( aStraightLineIdenticalEndPoints,
424                        "straight line 2" );
425         aPlotter.plot( aStraightLineIdenticalEndPoints2,
426                        "straight line 3" );
427         aPlotter.plot( aCrossing,
428                        "crossing" );
429 
430         // break up a complex bezier (loopy, spiky or self intersecting)
431         // into simple segments (left to right)
432         B2DCubicBezier aSegment = aCrossing;
433 		double fExtremePos(0.0);
434 
435         aPlotter.plot( aSegment, "segment" );
436 		while(aSegment.getMinimumExtremumPosition(fExtremePos))
437 		{
438             aSegment.split(fExtremePos, 0, &aSegment);
439 	        aPlotter.plot( aSegment, "segment" );
440 		}
441     }
442 
443     void tearDown()
444     {
445     }
446 
447     void adaptiveByDistance()
448     {
449         ::std::ofstream output("bez_adaptiveByDistance.gnuplot");
450         DebugPlotter aPlotter( "distance-adaptive subdivision",
451                                output );
452 
453         const double fBound( 0.0001 );
454         B2DPolygon result;
455 
456 		aHalfCircle.adaptiveSubdivideByDistance(result, fBound);
457         aPlotter.plot(result,
458                       "half circle"); result.clear();
459 
460         aQuarterCircle.adaptiveSubdivideByDistance(result, fBound);
461         aPlotter.plot(result,
462                       "quarter circle"); result.clear();
463 
464         aLoop.adaptiveSubdivideByDistance(result, fBound);
465         aPlotter.plot(result,
466                       "loop"); result.clear();
467 
468         aStraightLineDistinctEndPoints.adaptiveSubdivideByDistance(result, fBound);
469         aPlotter.plot(result,
470                       "straight line 0"); result.clear();
471 
472         aStraightLineDistinctEndPoints2.adaptiveSubdivideByDistance(result, fBound);
473         aPlotter.plot(result,
474                       "straight line 1"); result.clear();
475 
476         aStraightLineIdenticalEndPoints.adaptiveSubdivideByDistance(result, fBound);
477         aPlotter.plot(result,
478                       "straight line 2"); result.clear();
479 
480         aStraightLineIdenticalEndPoints2.adaptiveSubdivideByDistance(result, fBound);
481         aPlotter.plot(result,
482                       "straight line 3"); result.clear();
483 
484         aCrossing.adaptiveSubdivideByDistance(result, fBound);
485         aPlotter.plot(result,
486                       "straight line 4"); result.clear();
487 
488         aCusp.adaptiveSubdivideByDistance(result, fBound);
489         aPlotter.plot(result,
490                       "straight line 5"); result.clear();
491 
492         CPPUNIT_ASSERT_MESSAGE("adaptiveByDistance", true );
493     }
494 
495     void adaptiveByAngle()
496     {
497         const double fBound( 5.0 );
498         B2DPolygon result;
499 
500         ::std::ofstream output("bez_adaptiveByAngle.gnuplot");
501         DebugPlotter aPlotter( "angle-adaptive subdivision",
502                                output );
503 
504         aHalfCircle.adaptiveSubdivideByAngle(result, fBound, true);
505         aPlotter.plot(result,
506                       "half circle"); result.clear();
507 
508         aQuarterCircle.adaptiveSubdivideByAngle(result, fBound, true);
509         aPlotter.plot(result,
510                       "quarter cirle"); result.clear();
511 
512         aLoop.adaptiveSubdivideByAngle(result, fBound, true);
513         aPlotter.plot(result,
514                       "loop"); result.clear();
515 
516         aStraightLineDistinctEndPoints.adaptiveSubdivideByAngle(result, fBound, true);
517         aPlotter.plot(result,
518                       "straight line 0"); result.clear();
519 
520         aStraightLineDistinctEndPoints2.adaptiveSubdivideByAngle(result, fBound, true);
521         aPlotter.plot(result,
522                       "straight line 1"); result.clear();
523 
524         aStraightLineIdenticalEndPoints.adaptiveSubdivideByAngle(result, fBound, true);
525         aPlotter.plot(result,
526                       "straight line 2"); result.clear();
527 
528         aStraightLineIdenticalEndPoints2.adaptiveSubdivideByAngle(result, fBound, true);
529         aPlotter.plot(result,
530                       "straight line 3"); result.clear();
531 
532         aCrossing.adaptiveSubdivideByAngle(result, fBound, true);
533         aPlotter.plot(result,
534                       "straight line 4"); result.clear();
535 
536         aCusp.adaptiveSubdivideByAngle(result, fBound, true);
537         aPlotter.plot(result,
538                       "straight line 5"); result.clear();
539 
540         CPPUNIT_ASSERT_MESSAGE("adaptiveByAngle", true );
541     }
542 
543     // Change the following lines only, if you add, remove or rename
544     // member functions of the current class,
545     // because these macros are need by auto register mechanism.
546 
547     CPPUNIT_TEST_SUITE(b2dbeziertools);
548     CPPUNIT_TEST(adaptiveByDistance);	// TODO: add tests for quadratic bezier (subdivide and degree reduction)
549     CPPUNIT_TEST(adaptiveByAngle);
550     CPPUNIT_TEST_SUITE_END();
551 }; // class b2dcubicbezier
552 
553 
554 class b2dcubicbezier : public CppUnit::TestFixture
555 {
556 public:
557     // initialise your test code values here.
558     void setUp()
559     {
560     }
561 
562     void tearDown()
563     {
564     }
565 
566     // insert your test code here.
567     void EmptyMethod()
568     {
569         // this is demonstration code
570         // CPPUNIT_ASSERT_MESSAGE("a message", 1 == 1);
571     }
572 
573     // Change the following lines only, if you add, remove or rename
574     // member functions of the current class,
575     // because these macros are need by auto register mechanism.
576 
577     CPPUNIT_TEST_SUITE(b2dcubicbezier);
578     CPPUNIT_TEST(EmptyMethod);
579     CPPUNIT_TEST_SUITE_END();
580 }; // class b2dcubicbezier
581 
582 
583 class b2dhommatrix : public CppUnit::TestFixture
584 {
585 private:
586     B2DHomMatrix	maIdentity;
587     B2DHomMatrix	maScale;
588     B2DHomMatrix	maTranslate;
589     B2DHomMatrix	maShear;
590     B2DHomMatrix	maAffine;
591     B2DHomMatrix	maPerspective;
592 
593 public:
594     // initialise your test code values here.
595     void setUp()
596     {
597         // setup some test matrices
598         maIdentity.identity(); // force compact layout
599         maIdentity.set(0,0, 1.0);
600         maIdentity.set(0,1, 0.0);
601         maIdentity.set(0,2, 0.0);
602         maIdentity.set(1,0, 0.0);
603         maIdentity.set(1,1, 1.0);
604         maIdentity.set(1,2, 0.0);
605 
606         maScale.identity(); // force compact layout
607         maScale.set(0,0, 2.0);
608         maScale.set(1,1, 20.0);
609 
610         maTranslate.identity(); // force compact layout
611         maTranslate.set(0,2, 20.0);
612         maTranslate.set(1,2, 2.0);
613 
614         maShear.identity(); // force compact layout
615         maShear.set(0,1, 3.0);
616         maShear.set(1,0, 7.0);
617         maShear.set(1,1, 22.0);
618 
619         maAffine.identity(); // force compact layout
620         maAffine.set(0,0, 1.0);
621         maAffine.set(0,1, 2.0);
622         maAffine.set(0,2, 3.0);
623         maAffine.set(1,0, 4.0);
624         maAffine.set(1,1, 5.0);
625         maAffine.set(1,2, 6.0);
626 
627         maPerspective.set(0,0, 1.0);
628         maPerspective.set(0,1, 2.0);
629         maPerspective.set(0,2, 3.0);
630         maPerspective.set(1,0, 4.0);
631         maPerspective.set(1,1, 5.0);
632         maPerspective.set(1,2, 6.0);
633         maPerspective.set(2,0, 7.0);
634         maPerspective.set(2,1, 8.0);
635         maPerspective.set(2,2, 9.0);
636     }
637 
638     void tearDown()
639     {
640     }
641 
642     void equal()
643     {
644         B2DHomMatrix	aIdentity;
645         B2DHomMatrix	aScale;
646         B2DHomMatrix	aTranslate;
647         B2DHomMatrix	aShear;
648         B2DHomMatrix	aAffine;
649         B2DHomMatrix	aPerspective;
650 
651         // setup some test matrices
652         aIdentity.identity(); // force compact layout
653         aIdentity.set(0,0, 1.0);
654         aIdentity.set(0,1, 0.0);
655         aIdentity.set(0,2, 0.0);
656         aIdentity.set(1,0, 0.0);
657         aIdentity.set(1,1, 1.0);
658         aIdentity.set(1,2, 0.0);
659 
660         aScale.identity(); // force compact layout
661         aScale.set(0,0, 2.0);
662         aScale.set(1,1, 20.0);
663 
664         aTranslate.identity(); // force compact layout
665         aTranslate.set(0,2, 20.0);
666         aTranslate.set(1,2, 2.0);
667 
668         aShear.identity(); // force compact layout
669         aShear.set(0,1, 3.0);
670         aShear.set(1,0, 7.0);
671         aShear.set(1,1, 22.0);
672 
673         aAffine.identity(); // force compact layout
674         aAffine.set(0,0, 1.0);
675         aAffine.set(0,1, 2.0);
676         aAffine.set(0,2, 3.0);
677         aAffine.set(1,0, 4.0);
678         aAffine.set(1,1, 5.0);
679         aAffine.set(1,2, 6.0);
680 
681         aPerspective.set(0,0, 1.0);
682         aPerspective.set(0,1, 2.0);
683         aPerspective.set(0,2, 3.0);
684         aPerspective.set(1,0, 4.0);
685         aPerspective.set(1,1, 5.0);
686         aPerspective.set(1,2, 6.0);
687         aPerspective.set(2,0, 7.0);
688         aPerspective.set(2,1, 8.0);
689         aPerspective.set(2,2, 9.0);
690 
691         CPPUNIT_ASSERT_MESSAGE("operator==: identity matrix", aIdentity == maIdentity);
692         CPPUNIT_ASSERT_MESSAGE("operator==: scale matrix", aScale == maScale);
693         CPPUNIT_ASSERT_MESSAGE("operator==: translate matrix", aTranslate == maTranslate);
694         CPPUNIT_ASSERT_MESSAGE("operator==: shear matrix", aShear == maShear);
695         CPPUNIT_ASSERT_MESSAGE("operator==: affine matrix", aAffine == maAffine);
696         CPPUNIT_ASSERT_MESSAGE("operator==: perspective matrix", aPerspective == maPerspective);
697     }
698 
699     void identity()
700     {
701         B2DHomMatrix ident;
702 
703         CPPUNIT_ASSERT_MESSAGE("identity", maIdentity == ident);
704     }
705 
706     void scale()
707     {
708         B2DHomMatrix mat;
709         mat.scale(2.0,20.0);
710         CPPUNIT_ASSERT_MESSAGE("scale", maScale == mat);
711     }
712 
713     void translate()
714     {
715         B2DHomMatrix mat;
716         mat.translate(20.0,2.0);
717         CPPUNIT_ASSERT_MESSAGE("translate", maTranslate == mat);
718     }
719 
720     void shear()
721     {
722         B2DHomMatrix mat;
723         mat.shearX(3.0);
724         mat.shearY(7.0);
725         CPPUNIT_ASSERT_MESSAGE("translate", maShear == mat);
726     }
727 
728     void multiply()
729     {
730         B2DHomMatrix affineAffineProd;
731 
732         affineAffineProd.set(0,0, 9);
733         affineAffineProd.set(0,1, 12);
734         affineAffineProd.set(0,2, 18);
735         affineAffineProd.set(1,0, 24);
736         affineAffineProd.set(1,1, 33);
737         affineAffineProd.set(1,2, 48);
738 
739         B2DHomMatrix affinePerspectiveProd;
740 
741         affinePerspectiveProd.set(0,0, 30);
742         affinePerspectiveProd.set(0,1, 36);
743         affinePerspectiveProd.set(0,2, 42);
744         affinePerspectiveProd.set(1,0, 66);
745         affinePerspectiveProd.set(1,1, 81);
746         affinePerspectiveProd.set(1,2, 96);
747         affinePerspectiveProd.set(2,0, 7);
748         affinePerspectiveProd.set(2,1, 8);
749         affinePerspectiveProd.set(2,2, 9);
750 
751         B2DHomMatrix perspectiveAffineProd;
752 
753         perspectiveAffineProd.set(0,0, 9);
754         perspectiveAffineProd.set(0,1, 12);
755         perspectiveAffineProd.set(0,2, 18);
756         perspectiveAffineProd.set(1,0, 24);
757         perspectiveAffineProd.set(1,1, 33);
758         perspectiveAffineProd.set(1,2, 48);
759         perspectiveAffineProd.set(2,0, 39);
760         perspectiveAffineProd.set(2,1, 54);
761         perspectiveAffineProd.set(2,2, 78);
762 
763         B2DHomMatrix perspectivePerspectiveProd;
764 
765         perspectivePerspectiveProd.set(0,0, 30);
766         perspectivePerspectiveProd.set(0,1, 36);
767         perspectivePerspectiveProd.set(0,2, 42);
768         perspectivePerspectiveProd.set(1,0, 66);
769         perspectivePerspectiveProd.set(1,1, 81);
770         perspectivePerspectiveProd.set(1,2, 96);
771         perspectivePerspectiveProd.set(2,0, 102);
772         perspectivePerspectiveProd.set(2,1, 126);
773         perspectivePerspectiveProd.set(2,2, 150);
774 
775         B2DHomMatrix temp;
776 
777         temp = maAffine;
778         temp*=maAffine;
779         CPPUNIT_ASSERT_MESSAGE("multiply: both compact", temp == affineAffineProd);
780 
781         temp = maPerspective;
782         temp*=maAffine;
783         CPPUNIT_ASSERT_MESSAGE("multiply: first compact", temp == affinePerspectiveProd);
784 
785         temp = maAffine;
786         temp*=maPerspective;
787         CPPUNIT_ASSERT_MESSAGE("multiply: second compact", temp == perspectiveAffineProd);
788 
789         temp = maPerspective;
790         temp*=maPerspective;
791         CPPUNIT_ASSERT_MESSAGE("multiply: none compact", temp == perspectivePerspectiveProd);
792     }
793 
794 	void impFillMatrix(B2DHomMatrix& rSource, double fScaleX, double fScaleY, double fShearX, double fRotate)
795 	{
796 		// fill rSource with a linear combination of scale, shear and rotate
797 		rSource.identity();
798 		rSource.scale(fScaleX, fScaleY);
799 		rSource.shearX(fShearX);
800 		rSource.rotate(fRotate);
801 	}
802 
803 	bool impDecomposeComposeTest(double fScaleX, double fScaleY, double fShearX, double fRotate)
804 	{
805 		// linear combine matrix with given values
806 		B2DHomMatrix aSource;
807 		impFillMatrix(aSource, fScaleX, fScaleY, fShearX, fRotate);
808 
809 		// decompose that matrix
810 		B2DTuple aDScale;
811 		B2DTuple aDTrans;
812 		double fDRot;
813 		double fDShX;
814 		bool bWorked = aSource.decompose(aDScale, aDTrans, fDRot, fDShX);
815 
816 		// linear combine another matrix with decomposition results
817 		B2DHomMatrix aRecombined;
818 		impFillMatrix(aRecombined, aDScale.getX(), aDScale.getY(), fDShX, fDRot);
819 
820 		// if decomposition worked, matrices need to be the same
821 		return bWorked && aSource == aRecombined;
822 	}
823 
824     void decompose()
825     {
826 		// test matrix decompositions. Each matrix decomposed and rebuilt
827 		// using the decompose result should be the same as before. Test
828 		// with all ranges of values. Translations are not tested since these
829 		// are just the two rightmost values and uncritical
830 		static double fSX(10.0);
831 		static double fSY(12.0);
832 		static double fR(45.0 * F_PI180);
833 		static double fS(15.0 * F_PI180);
834 
835 		// check all possible scaling combinations
836 		CPPUNIT_ASSERT_MESSAGE("decompose: error test A1", impDecomposeComposeTest(fSX, fSY, 0.0, 0.0));
837 		CPPUNIT_ASSERT_MESSAGE("decompose: error test A2", impDecomposeComposeTest(-fSX, fSY, 0.0, 0.0));
838 		CPPUNIT_ASSERT_MESSAGE("decompose: error test A3", impDecomposeComposeTest(fSX, -fSY, 0.0, 0.0));
839 		CPPUNIT_ASSERT_MESSAGE("decompose: error test A4", impDecomposeComposeTest(-fSX, -fSY, 0.0, 0.0));
840 
841 		// check all possible scaling combinations with positive rotation
842 		CPPUNIT_ASSERT_MESSAGE("decompose: error test B1", impDecomposeComposeTest(fSX, fSY, 0.0, fR));
843 		CPPUNIT_ASSERT_MESSAGE("decompose: error test B2", impDecomposeComposeTest(-fSX, fSY, 0.0, fR));
844 		CPPUNIT_ASSERT_MESSAGE("decompose: error test B3", impDecomposeComposeTest(fSX, -fSY, 0.0, fR));
845 		CPPUNIT_ASSERT_MESSAGE("decompose: error test B4", impDecomposeComposeTest(-fSX, -fSY, 0.0, fR));
846 
847 		// check all possible scaling combinations with negative rotation
848 		CPPUNIT_ASSERT_MESSAGE("decompose: error test C1", impDecomposeComposeTest(fSX, fSY, 0.0, -fR));
849 		CPPUNIT_ASSERT_MESSAGE("decompose: error test C2", impDecomposeComposeTest(-fSX, fSY, 0.0, -fR));
850 		CPPUNIT_ASSERT_MESSAGE("decompose: error test C3", impDecomposeComposeTest(fSX, -fSY, 0.0, -fR));
851 		CPPUNIT_ASSERT_MESSAGE("decompose: error test C4", impDecomposeComposeTest(-fSX, -fSY, 0.0, -fR));
852 
853 		// check all possible scaling combinations with positive shear
854 		CPPUNIT_ASSERT_MESSAGE("decompose: error test D1", impDecomposeComposeTest(fSX, fSY, tan(fS), 0.0));
855 		CPPUNIT_ASSERT_MESSAGE("decompose: error test D2", impDecomposeComposeTest(-fSX, fSY, tan(fS), 0.0));
856 		CPPUNIT_ASSERT_MESSAGE("decompose: error test D3", impDecomposeComposeTest(fSX, -fSY, tan(fS), 0.0));
857 		CPPUNIT_ASSERT_MESSAGE("decompose: error test D4", impDecomposeComposeTest(-fSX, -fSY, tan(fS), 0.0));
858 
859 		// check all possible scaling combinations with negative shear
860 		CPPUNIT_ASSERT_MESSAGE("decompose: error test E1", impDecomposeComposeTest(fSX, fSY, tan(-fS), 0.0));
861 		CPPUNIT_ASSERT_MESSAGE("decompose: error test E2", impDecomposeComposeTest(-fSX, fSY, tan(-fS), 0.0));
862 		CPPUNIT_ASSERT_MESSAGE("decompose: error test E3", impDecomposeComposeTest(fSX, -fSY, tan(-fS), 0.0));
863 		CPPUNIT_ASSERT_MESSAGE("decompose: error test E4", impDecomposeComposeTest(-fSX, -fSY, tan(-fS), 0.0));
864 
865 		// check all possible scaling combinations with positive rotate and positive shear
866 		CPPUNIT_ASSERT_MESSAGE("decompose: error test F1", impDecomposeComposeTest(fSX, fSY, tan(fS), fR));
867 		CPPUNIT_ASSERT_MESSAGE("decompose: error test F2", impDecomposeComposeTest(-fSX, fSY, tan(fS), fR));
868 		CPPUNIT_ASSERT_MESSAGE("decompose: error test F3", impDecomposeComposeTest(fSX, -fSY, tan(fS), fR));
869 		CPPUNIT_ASSERT_MESSAGE("decompose: error test F4", impDecomposeComposeTest(-fSX, -fSY, tan(fS), fR));
870 
871 		// check all possible scaling combinations with negative rotate and positive shear
872 		CPPUNIT_ASSERT_MESSAGE("decompose: error test G1", impDecomposeComposeTest(fSX, fSY, tan(fS), -fR));
873 		CPPUNIT_ASSERT_MESSAGE("decompose: error test G2", impDecomposeComposeTest(-fSX, fSY, tan(fS), -fR));
874 		CPPUNIT_ASSERT_MESSAGE("decompose: error test G3", impDecomposeComposeTest(fSX, -fSY, tan(fS), -fR));
875 		CPPUNIT_ASSERT_MESSAGE("decompose: error test G4", impDecomposeComposeTest(-fSX, -fSY, tan(fS), -fR));
876 
877 		// check all possible scaling combinations with positive rotate and negative shear
878 		CPPUNIT_ASSERT_MESSAGE("decompose: error test H1", impDecomposeComposeTest(fSX, fSY, tan(-fS), fR));
879 		CPPUNIT_ASSERT_MESSAGE("decompose: error test H2", impDecomposeComposeTest(-fSX, fSY, tan(-fS), fR));
880 		CPPUNIT_ASSERT_MESSAGE("decompose: error test H3", impDecomposeComposeTest(fSX, -fSY, tan(-fS), fR));
881 		CPPUNIT_ASSERT_MESSAGE("decompose: error test H4", impDecomposeComposeTest(-fSX, -fSY, tan(-fS), fR));
882 
883 		// check all possible scaling combinations with negative rotate and negative shear
884 		CPPUNIT_ASSERT_MESSAGE("decompose: error test I1", impDecomposeComposeTest(fSX, fSY, tan(-fS), -fR));
885 		CPPUNIT_ASSERT_MESSAGE("decompose: error test I2", impDecomposeComposeTest(-fSX, fSY, tan(-fS), -fR));
886 		CPPUNIT_ASSERT_MESSAGE("decompose: error test I3", impDecomposeComposeTest(fSX, -fSY, tan(-fS), -fR));
887 		CPPUNIT_ASSERT_MESSAGE("decompose: error test I4", impDecomposeComposeTest(-fSX, -fSY, tan(-fS), -fR));
888 	}
889 
890     // Change the following lines only, if you add, remove or rename
891     // member functions of the current class,
892     // because these macros are need by auto register mechanism.
893 
894     CPPUNIT_TEST_SUITE(b2dhommatrix);
895     CPPUNIT_TEST(equal);
896     CPPUNIT_TEST(identity);
897     CPPUNIT_TEST(scale);
898     CPPUNIT_TEST(translate);
899     CPPUNIT_TEST(shear);
900     CPPUNIT_TEST(multiply);
901     CPPUNIT_TEST(decompose);
902     CPPUNIT_TEST_SUITE_END();
903 
904 }; // class b2dhommatrix
905 
906 
907 class b2dhompoint : public CppUnit::TestFixture
908 {
909 public:
910     // initialise your test code values here.
911     void setUp()
912     {
913     }
914 
915     void tearDown()
916     {
917     }
918 
919     // insert your test code here.
920     void EmptyMethod()
921     {
922     }
923 
924     // Change the following lines only, if you add, remove or rename
925     // member functions of the current class,
926     // because these macros are need by auto register mechanism.
927 
928     CPPUNIT_TEST_SUITE(b2dhompoint);
929     CPPUNIT_TEST(EmptyMethod);
930     CPPUNIT_TEST_SUITE_END();
931 }; // class b2dhompoint
932 
933 
934 class b2dpoint : public CppUnit::TestFixture
935 {
936 public:
937     // initialise your test code values here.
938     void setUp()
939     {
940     }
941 
942     void tearDown()
943     {
944     }
945 
946     // insert your test code here.
947     // this is only demonstration code
948     void EmptyMethod()
949     {
950     	  // CPPUNIT_ASSERT_MESSAGE("a message", 1 == 1);
951     }
952 
953     // Change the following lines only, if you add, remove or rename
954     // member functions of the current class,
955     // because these macros are need by auto register mechanism.
956 
957     CPPUNIT_TEST_SUITE(b2dpoint);
958     CPPUNIT_TEST(EmptyMethod);
959     CPPUNIT_TEST_SUITE_END();
960 }; // class b2dpoint
961 
962 
963 class b2dpolygon : public CppUnit::TestFixture
964 {
965 public:
966     // initialise your test code values here.
967     void setUp()
968     {
969     }
970 
971     void tearDown()
972     {
973     }
974 
975     // insert your test code here.
976     void testBasics()
977     {
978         B2DPolygon aPoly;
979 
980         aPoly.appendBezierSegment(B2DPoint(1,1),B2DPoint(2,2),B2DPoint(3,3));
981 
982         CPPUNIT_ASSERT_MESSAGE("#1 first polygon point wrong",
983                                aPoly.getB2DPoint(0) == B2DPoint(3,3));
984         CPPUNIT_ASSERT_MESSAGE("#1 first control point wrong",
985                                aPoly.getPrevControlPoint(0) == B2DPoint(2,2));
986         CPPUNIT_ASSERT_MESSAGE("#1 second control point wrong",
987                                aPoly.getNextControlPoint(0) == B2DPoint(3,3));
988         CPPUNIT_ASSERT_MESSAGE("next control point not used",
989                                aPoly.isNextControlPointUsed(0) == false);
990 
991 		aPoly.setNextControlPoint(0,B2DPoint(4,4));
992         CPPUNIT_ASSERT_MESSAGE("#1.1 second control point wrong",
993                                aPoly.getNextControlPoint(0) == B2DPoint(4,4));
994         CPPUNIT_ASSERT_MESSAGE("next control point used",
995                                aPoly.isNextControlPointUsed(0) == true);
996         CPPUNIT_ASSERT_MESSAGE("areControlPointsUsed() wrong",
997                                aPoly.areControlPointsUsed() == true);
998         CPPUNIT_ASSERT_MESSAGE("getContinuityInPoint() wrong",
999                                aPoly.getContinuityInPoint(0) == CONTINUITY_C2);
1000 
1001 		aPoly.resetControlPoints();
1002         CPPUNIT_ASSERT_MESSAGE("resetControlPoints() did not clear",
1003                                aPoly.getB2DPoint(0) == B2DPoint(3,3));
1004         CPPUNIT_ASSERT_MESSAGE("resetControlPoints() did not clear",
1005                                aPoly.getPrevControlPoint(0) == B2DPoint(3,3));
1006         CPPUNIT_ASSERT_MESSAGE("resetControlPoints() did not clear",
1007                                aPoly.getNextControlPoint(0) == B2DPoint(3,3));
1008         CPPUNIT_ASSERT_MESSAGE("areControlPointsUsed() wrong #2",
1009                                aPoly.areControlPointsUsed() == false);
1010 
1011         aPoly.clear();
1012         aPoly.append(B2DPoint(0,0));
1013         aPoly.appendBezierSegment(B2DPoint(1,1),B2DPoint(2,2),B2DPoint(3,3));
1014 
1015         CPPUNIT_ASSERT_MESSAGE("#2 first polygon point wrong",
1016                                aPoly.getB2DPoint(0) == B2DPoint(0,0));
1017         CPPUNIT_ASSERT_MESSAGE("#2 first control point wrong",
1018                                aPoly.getPrevControlPoint(0) == B2DPoint(0,0));
1019         CPPUNIT_ASSERT_MESSAGE("#2 second control point wrong",
1020                                aPoly.getNextControlPoint(0) == B2DPoint(1,1));
1021         CPPUNIT_ASSERT_MESSAGE("#2 third control point wrong",
1022                                aPoly.getPrevControlPoint(1) == B2DPoint(2,2));
1023         CPPUNIT_ASSERT_MESSAGE("#2 fourth control point wrong",
1024                                aPoly.getNextControlPoint(1) == B2DPoint(3,3));
1025         CPPUNIT_ASSERT_MESSAGE("#2 second polygon point wrong",
1026                                aPoly.getB2DPoint(1) == B2DPoint(3,3));
1027     }
1028     // Change the following lines only, if you add, remove or rename
1029     // member functions of the current class,
1030     // because these macros are need by auto register mechanism.
1031 
1032     CPPUNIT_TEST_SUITE(b2dpolygon);
1033     CPPUNIT_TEST(testBasics);
1034     CPPUNIT_TEST_SUITE_END();
1035 }; // class b2dpolygon
1036 
1037 
1038 class b2dpolygontools : public CppUnit::TestFixture
1039 {
1040 public:
1041     // initialise your test code values here.
1042     void setUp()
1043     {
1044     }
1045 
1046     void tearDown()
1047     {
1048     }
1049 
1050     // insert your test code here.
1051     // this is only demonstration code
1052     void testIsRectangle()
1053     {
1054         B2DPolygon aRect1(
1055             tools::createPolygonFromRect(
1056                 B2DRange(0,0,1,1) ) );
1057 
1058         B2DPolygon aRect2;
1059         aRect2.append( B2DPoint(0,0) );
1060         aRect2.append( B2DPoint(1,0) );
1061         aRect2.append( B2DPoint(1,.5));
1062         aRect2.append( B2DPoint(1,1) );
1063         aRect2.append( B2DPoint(0,1) );
1064         aRect2.setClosed(true);
1065 
1066         B2DPolygon aNonRect1;
1067         aNonRect1.append( B2DPoint(0,0) );
1068         aNonRect1.append( B2DPoint(1,0) );
1069         aNonRect1.append( B2DPoint(1,1) );
1070         aNonRect1.append( B2DPoint(0.5,1) );
1071         aNonRect1.append( B2DPoint(0.5,0) );
1072         aNonRect1.setClosed(true);
1073 
1074         B2DPolygon aNonRect2;
1075         aNonRect2.append( B2DPoint(0,0) );
1076         aNonRect2.append( B2DPoint(1,1) );
1077         aNonRect2.append( B2DPoint(1,0) );
1078         aNonRect2.append( B2DPoint(0,1) );
1079         aNonRect2.setClosed(true);
1080 
1081         B2DPolygon aNonRect3;
1082         aNonRect3.append( B2DPoint(0,0) );
1083         aNonRect3.append( B2DPoint(1,0) );
1084         aNonRect3.append( B2DPoint(1,1) );
1085         aNonRect3.setClosed(true);
1086 
1087         B2DPolygon aNonRect4;
1088         aNonRect4.append( B2DPoint(0,0) );
1089         aNonRect4.append( B2DPoint(1,0) );
1090         aNonRect4.append( B2DPoint(1,1) );
1091         aNonRect4.append( B2DPoint(0,1) );
1092 
1093         B2DPolygon aNonRect5;
1094         aNonRect5.append( B2DPoint(0,0) );
1095         aNonRect5.append( B2DPoint(1,0) );
1096         aNonRect5.append( B2DPoint(1,1) );
1097         aNonRect5.append( B2DPoint(0,1) );
1098         aNonRect5.setControlPoints(1,B2DPoint(1,0),B2DPoint(-11,0));
1099         aNonRect5.setClosed(true);
1100 
1101         CPPUNIT_ASSERT_MESSAGE("checking rectangle-ness of rectangle 1",
1102                                tools::isRectangle( aRect1 ));
1103         CPPUNIT_ASSERT_MESSAGE("checking rectangle-ness of rectangle 2",
1104                                tools::isRectangle( aRect2 ));
1105         CPPUNIT_ASSERT_MESSAGE("checking non-rectangle-ness of polygon 1",
1106                                !tools::isRectangle( aNonRect1 ));
1107         CPPUNIT_ASSERT_MESSAGE("checking non-rectangle-ness of polygon 2",
1108                                !tools::isRectangle( aNonRect2 ));
1109         CPPUNIT_ASSERT_MESSAGE("checking non-rectangle-ness of polygon 3",
1110                                !tools::isRectangle( aNonRect3 ));
1111         CPPUNIT_ASSERT_MESSAGE("checking non-rectangle-ness of polygon 4",
1112                                !tools::isRectangle( aNonRect4 ));
1113         CPPUNIT_ASSERT_MESSAGE("checking non-rectangle-ness of polygon 5",
1114                                !tools::isRectangle( aNonRect5 ));
1115     }
1116 
1117     // Change the following lines only, if you add, remove or rename
1118     // member functions of the current class,
1119     // because these macros are need by auto register mechanism.
1120 
1121     CPPUNIT_TEST_SUITE(b2dpolygontools);
1122     CPPUNIT_TEST(testIsRectangle);
1123     CPPUNIT_TEST_SUITE_END();
1124 }; // class b2dpolygontools
1125 
1126 
1127 class b2dpolypolygon : public CppUnit::TestFixture
1128 {
1129 public:
1130     // initialise your test code values here.
1131     void setUp()
1132     {
1133     }
1134 
1135     void tearDown()
1136     {
1137     }
1138 
1139     // insert your test code here.
1140     void EmptyMethod()
1141     {
1142     }
1143 
1144     // Change the following lines only, if you add, remove or rename
1145     // member functions of the current class,
1146     // because these macros are need by auto register mechanism.
1147 
1148     CPPUNIT_TEST_SUITE(b2dpolypolygon);
1149     CPPUNIT_TEST(EmptyMethod);
1150     CPPUNIT_TEST_SUITE_END();
1151 }; // class b2dpolypolygon
1152 
1153 
1154 class b2dquadraticbezier : public CppUnit::TestFixture
1155 {
1156 public:
1157     // initialise your test code values here.
1158     void setUp()
1159     {
1160     }
1161 
1162     void tearDown()
1163     {
1164     }
1165 
1166     // insert your test code here.
1167     // this is only demonstration code
1168     void EmptyMethod()
1169     {
1170     	  // CPPUNIT_ASSERT_MESSAGE("a message", 1 == 1);
1171     }
1172 
1173     // Change the following lines only, if you add, remove or rename
1174     // member functions of the current class,
1175     // because these macros are need by auto register mechanism.
1176 
1177     CPPUNIT_TEST_SUITE(b2dquadraticbezier);
1178     CPPUNIT_TEST(EmptyMethod);
1179     CPPUNIT_TEST_SUITE_END();
1180 }; // class b2dquadraticbezier
1181 
1182 
1183 class b2drange : public CppUnit::TestFixture
1184 {
1185 public:
1186     // initialise your test code values here.
1187     void setUp()
1188     {
1189     }
1190 
1191     void tearDown()
1192     {
1193     }
1194 
1195     // insert your test code here.
1196     void EmptyMethod()
1197     {
1198     }
1199 
1200     // Change the following lines only, if you add, remove or rename
1201     // member functions of the current class,
1202     // because these macros are need by auto register mechanism.
1203 
1204     CPPUNIT_TEST_SUITE(b2drange);
1205     CPPUNIT_TEST(EmptyMethod);
1206     CPPUNIT_TEST_SUITE_END();
1207 }; // class b2drange
1208 
1209 
1210 class b2dtuple : public CppUnit::TestFixture
1211 {
1212 public:
1213     // initialise your test code values here.
1214     void setUp()
1215     {
1216     }
1217 
1218     void tearDown()
1219     {
1220     }
1221 
1222     // insert your test code here.
1223     // this is only demonstration code
1224     void EmptyMethod()
1225     {
1226     	  // CPPUNIT_ASSERT_MESSAGE("a message", 1 == 1);
1227     }
1228 
1229     // Change the following lines only, if you add, remove or rename
1230     // member functions of the current class,
1231     // because these macros are need by auto register mechanism.
1232 
1233     CPPUNIT_TEST_SUITE(b2dtuple);
1234     CPPUNIT_TEST(EmptyMethod);
1235     CPPUNIT_TEST_SUITE_END();
1236 }; // class b2dtuple
1237 
1238 
1239 class b2dvector : public CppUnit::TestFixture
1240 {
1241 public:
1242     // initialise your test code values here.
1243     void setUp()
1244     {
1245     }
1246 
1247     void tearDown()
1248     {
1249     }
1250 
1251     // insert your test code here.
1252     void EmptyMethod()
1253     {
1254     }
1255 
1256     // Change the following lines only, if you add, remove or rename
1257     // member functions of the current class,
1258     // because these macros are need by auto register mechanism.
1259 
1260     CPPUNIT_TEST_SUITE(b2dvector);
1261     CPPUNIT_TEST(EmptyMethod);
1262     CPPUNIT_TEST_SUITE_END();
1263 }; // class b2dvector
1264 
1265 class bcolor : public CppUnit::TestFixture
1266 {
1267     BColor maWhite;
1268     BColor maBlack;
1269     BColor maRed;
1270     BColor maGreen;
1271     BColor maBlue;
1272     BColor maYellow;
1273     BColor maMagenta;
1274     BColor maCyan;
1275 
1276 public:
1277     bcolor() :
1278         maWhite(1,1,1),
1279         maBlack(0,0,0),
1280         maRed(1,0,0),
1281         maGreen(0,1,0),
1282         maBlue(0,0,1),
1283         maYellow(1,1,0),
1284         maMagenta(1,0,1),
1285         maCyan(0,1,1)
1286     {}
1287 
1288 
1289     // initialise your test code values here.
1290     void setUp()
1291     {
1292     }
1293 
1294     void tearDown()
1295     {
1296     }
1297 
1298     // insert your test code here.
1299     void hslTest()
1300     {
1301         CPPUNIT_ASSERT_MESSAGE("white",
1302                                tools::rgb2hsl(maWhite) == BColor(0,0,1));
1303         CPPUNIT_ASSERT_MESSAGE("black",
1304                                tools::rgb2hsl(maBlack) == BColor(0,0,0));
1305         CPPUNIT_ASSERT_MESSAGE("red",
1306                                tools::rgb2hsl(maRed) == BColor(0,1,0.5));
1307         CPPUNIT_ASSERT_MESSAGE("green",
1308                                tools::rgb2hsl(maGreen) == BColor(120,1,0.5));
1309         CPPUNIT_ASSERT_MESSAGE("blue",
1310                                tools::rgb2hsl(maBlue) == BColor(240,1,0.5));
1311         CPPUNIT_ASSERT_MESSAGE("yellow",
1312                                tools::rgb2hsl(maYellow) == BColor(60,1,0.5));
1313         CPPUNIT_ASSERT_MESSAGE("magenta",
1314                                tools::rgb2hsl(maMagenta) == BColor(300,1,0.5));
1315         CPPUNIT_ASSERT_MESSAGE("cyan",
1316                                tools::rgb2hsl(maCyan) == BColor(180,1,0.5));
1317         CPPUNIT_ASSERT_MESSAGE("third hue case",
1318                                tools::rgb2hsl(BColor(0,0.5,1)) == BColor(210,1,0.5));
1319 
1320         CPPUNIT_ASSERT_MESSAGE("roundtrip white",
1321                                tools::hsl2rgb(tools::rgb2hsl(maWhite)) == maWhite);
1322         CPPUNIT_ASSERT_MESSAGE("roundtrip black",
1323                                tools::hsl2rgb(tools::rgb2hsl(maBlack)) == maBlack);
1324         CPPUNIT_ASSERT_MESSAGE("roundtrip red",
1325                                tools::hsl2rgb(tools::rgb2hsl(maRed)) == maRed);
1326         CPPUNIT_ASSERT_MESSAGE("roundtrip green",
1327                                tools::hsl2rgb(tools::rgb2hsl(maGreen)) == maGreen);
1328         CPPUNIT_ASSERT_MESSAGE("roundtrip blue",
1329                                tools::hsl2rgb(tools::rgb2hsl(maBlue)) == maBlue);
1330         CPPUNIT_ASSERT_MESSAGE("roundtrip yellow",
1331                                tools::hsl2rgb(tools::rgb2hsl(maYellow)) == maYellow);
1332         CPPUNIT_ASSERT_MESSAGE("roundtrip magenta",
1333                                tools::hsl2rgb(tools::rgb2hsl(maMagenta)) == maMagenta);
1334         CPPUNIT_ASSERT_MESSAGE("roundtrip cyan",
1335                                tools::hsl2rgb(tools::rgb2hsl(maCyan)) == maCyan);
1336 
1337         CPPUNIT_ASSERT_MESSAGE("grey10",
1338                                tools::rgb2hsl(maWhite*.1) == BColor(0,0,.1));
1339         CPPUNIT_ASSERT_MESSAGE("grey90",
1340                                tools::rgb2hsl(maWhite*.9) == BColor(0,0,.9));
1341         CPPUNIT_ASSERT_MESSAGE("red/2",
1342                                tools::rgb2hsl(maRed*.5) == BColor(0,1,0.25));
1343         CPPUNIT_ASSERT_MESSAGE("green/2",
1344                                tools::rgb2hsl(maGreen*.5) == BColor(120,1,0.25));
1345         CPPUNIT_ASSERT_MESSAGE("blue/2",
1346                                tools::rgb2hsl(maBlue*.5) == BColor(240,1,0.25));
1347         CPPUNIT_ASSERT_MESSAGE("yellow/2",
1348                                tools::rgb2hsl(maYellow*.5) == BColor(60,1,0.25));
1349         CPPUNIT_ASSERT_MESSAGE("magenta/2",
1350                                tools::rgb2hsl(maMagenta*.5) == BColor(300,1,0.25));
1351         CPPUNIT_ASSERT_MESSAGE("cyan/2",
1352                                tools::rgb2hsl(maCyan*.5) == BColor(180,1,0.25));
1353 
1354         CPPUNIT_ASSERT_MESSAGE("pastel",
1355                                tools::rgb2hsl(BColor(.75,.25,.25)) == BColor(0,.5,.5));
1356     }
1357 
1358     // insert your test code here.
1359     void hsvTest()
1360     {
1361         CPPUNIT_ASSERT_MESSAGE("white",
1362                                tools::rgb2hsv(maWhite) == BColor(0,0,1));
1363         CPPUNIT_ASSERT_MESSAGE("black",
1364                                tools::rgb2hsv(maBlack) == BColor(0,0,0));
1365         CPPUNIT_ASSERT_MESSAGE("red",
1366                                tools::rgb2hsv(maRed) == BColor(0,1,1));
1367         CPPUNIT_ASSERT_MESSAGE("green",
1368                                tools::rgb2hsv(maGreen) == BColor(120,1,1));
1369         CPPUNIT_ASSERT_MESSAGE("blue",
1370                                tools::rgb2hsv(maBlue) == BColor(240,1,1));
1371         CPPUNIT_ASSERT_MESSAGE("yellow",
1372                                tools::rgb2hsv(maYellow) == BColor(60,1,1));
1373         CPPUNIT_ASSERT_MESSAGE("magenta",
1374                                tools::rgb2hsv(maMagenta) == BColor(300,1,1));
1375         CPPUNIT_ASSERT_MESSAGE("cyan",
1376                                tools::rgb2hsv(maCyan) == BColor(180,1,1));
1377 
1378         CPPUNIT_ASSERT_MESSAGE("roundtrip white",
1379                                tools::hsv2rgb(tools::rgb2hsv(maWhite)) == maWhite);
1380         CPPUNIT_ASSERT_MESSAGE("roundtrip black",
1381                                tools::hsv2rgb(tools::rgb2hsv(maBlack)) == maBlack);
1382         CPPUNIT_ASSERT_MESSAGE("roundtrip red",
1383                                tools::hsv2rgb(tools::rgb2hsv(maRed)) == maRed);
1384         CPPUNIT_ASSERT_MESSAGE("roundtrip green",
1385                                tools::hsv2rgb(tools::rgb2hsv(maGreen)) == maGreen);
1386         CPPUNIT_ASSERT_MESSAGE("roundtrip blue",
1387                                tools::hsv2rgb(tools::rgb2hsv(maBlue)) == maBlue);
1388         CPPUNIT_ASSERT_MESSAGE("roundtrip yellow",
1389                                tools::hsv2rgb(tools::rgb2hsv(maYellow)) == maYellow);
1390         CPPUNIT_ASSERT_MESSAGE("roundtrip magenta",
1391                                tools::hsv2rgb(tools::rgb2hsv(maMagenta)) == maMagenta);
1392         CPPUNIT_ASSERT_MESSAGE("roundtrip cyan",
1393                                tools::hsv2rgb(tools::rgb2hsv(maCyan)) == maCyan);
1394 
1395         CPPUNIT_ASSERT_MESSAGE("grey10",
1396                                tools::rgb2hsv(maWhite*.1) == BColor(0,0,.1));
1397         CPPUNIT_ASSERT_MESSAGE("grey90",
1398                                tools::rgb2hsv(maWhite*.9) == BColor(0,0,.9));
1399         CPPUNIT_ASSERT_MESSAGE("red/2",
1400                                tools::rgb2hsv(maRed*.5) == BColor(0,1,0.5));
1401         CPPUNIT_ASSERT_MESSAGE("green/2",
1402                                tools::rgb2hsv(maGreen*.5) == BColor(120,1,0.5));
1403         CPPUNIT_ASSERT_MESSAGE("blue/2",
1404                                tools::rgb2hsv(maBlue*.5) == BColor(240,1,0.5));
1405         CPPUNIT_ASSERT_MESSAGE("yellow/2",
1406                                tools::rgb2hsv(maYellow*.5) == BColor(60,1,0.5));
1407         CPPUNIT_ASSERT_MESSAGE("magenta/2",
1408                                tools::rgb2hsv(maMagenta*.5) == BColor(300,1,0.5));
1409         CPPUNIT_ASSERT_MESSAGE("cyan/2",
1410                                tools::rgb2hsv(maCyan*.5) == BColor(180,1,0.5));
1411 
1412         CPPUNIT_ASSERT_MESSAGE("pastel",
1413                                tools::rgb2hsv(BColor(.5,.25,.25)) == BColor(0,.5,.5));
1414     }
1415 
1416     void ciexyzTest()
1417     {
1418         tools::rgb2ciexyz(maWhite);
1419         tools::rgb2ciexyz(maBlack);
1420         tools::rgb2ciexyz(maRed);
1421         tools::rgb2ciexyz(maGreen);
1422         tools::rgb2ciexyz(maBlue);
1423         tools::rgb2ciexyz(maYellow);
1424         tools::rgb2ciexyz(maMagenta);
1425         tools::rgb2ciexyz(maCyan);
1426     }
1427 
1428     // Change the following lines only, if you add, remove or rename
1429     // member functions of the current class,
1430     // because these macros are need by auto register mechanism.
1431 
1432     CPPUNIT_TEST_SUITE(bcolor);
1433     CPPUNIT_TEST(hslTest);
1434     CPPUNIT_TEST(hsvTest);
1435     CPPUNIT_TEST(ciexyzTest);
1436     CPPUNIT_TEST_SUITE_END();
1437 }; // class b2dvector
1438 
1439 // -----------------------------------------------------------------------------
1440 
1441 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dsvgdimpex);
1442 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dpolyrange);
1443 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dcubicbezier);
1444 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dhommatrix);
1445 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dhompoint);
1446 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dpoint);
1447 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dpolygon);
1448 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dpolygontools);
1449 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dpolypolygon);
1450 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dquadraticbezier);
1451 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2drange);
1452 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dtuple);
1453 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::b2dvector);
1454 CPPUNIT_TEST_SUITE_REGISTRATION(basegfx2d::bcolor);
1455 } // namespace basegfx2d
1456 
1457 
1458 // -----------------------------------------------------------------------------
1459 
1460 // this macro creates an empty function, which will called by the RegisterAllFunctions()
1461 // to let the user the possibility to also register some functions by hand.
1462 // NOADDITIONAL;
1463 
1464