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