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