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