61db58881e
2007/11/16 13:50:13 aw 1.9.18.1: #i83695# added unit tests for B2DHomMatrix::decompose()
1435 lines
56 KiB
C++
1435 lines
56 KiB
C++
/*************************************************************************
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: basegfx2d.cxx,v $
|
|
*
|
|
* $Revision: 1.10 $
|
|
*
|
|
* last change: $Author: vg $ $Date: 2008-02-12 16:25:33 $
|
|
*
|
|
* The Contents of this file are made available subject to
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
|
*
|
|
*
|
|
* GNU Lesser General Public License Version 2.1
|
|
* =============================================
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
#include "precompiled_basegfx.hxx"
|
|
// autogenerated file with codegen.pl
|
|
|
|
#include <cppunit/simpleheader.hxx>
|
|
|
|
#include <basegfx/matrix/b2dhommatrix.hxx>
|
|
#include <basegfx/polygon/b2dpolygon.hxx>
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
#include <basegfx/curve/b2dcubicbezier.hxx>
|
|
#include <basegfx/curve/b2dbeziertools.hxx>
|
|
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
|
#include <basegfx/range/b2dmultirange.hxx>
|
|
#include <basegfx/numeric/ftools.hxx>
|
|
|
|
#include <basegfx/tools/debugplotter.hxx>
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
using namespace ::basegfx;
|
|
|
|
|
|
namespace basegfx2d
|
|
{
|
|
/// Gets a random ordinal [0,n)
|
|
inline double getRandomOrdinal( const ::std::size_t n )
|
|
{
|
|
return double(n) * rand() / (RAND_MAX + 1.0);
|
|
}
|
|
|
|
class b2dmultirange : public CppUnit::TestFixture
|
|
{
|
|
private:
|
|
B2DMultiRange aDisjunctRanges;
|
|
B2DMultiRange aEqualRanges;
|
|
B2DMultiRange aIntersectionN;
|
|
B2DMultiRange aIntersectionE;
|
|
B2DMultiRange aIntersectionS;
|
|
B2DMultiRange aIntersectionW;
|
|
B2DMultiRange aIntersectionNE;
|
|
B2DMultiRange aIntersectionSE;
|
|
B2DMultiRange aIntersectionSW;
|
|
B2DMultiRange aIntersectionNW;
|
|
B2DMultiRange aRingIntersection;
|
|
B2DMultiRange aComplexIntersections;
|
|
B2DMultiRange aRandomIntersections;
|
|
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
B2DRange aCenter(1.0, 1.0, -1.0, -1.0);
|
|
B2DRange aOffside(9.0, 9.0, 11.0, 11.0);
|
|
B2DRange aNorth(1.0, 0.0, -1.0, -2.0);
|
|
B2DRange aSouth(1.0, 2.0, -1.0, 0.0);
|
|
B2DRange aEast(0.0, 1.0, 2.0, -1.0);
|
|
B2DRange aWest(-2.0, 1.0, 0.0, -1.0);
|
|
B2DRange aNorthEast(0.0, 0.0, 2.0, -2.0);
|
|
B2DRange aSouthEast(0.0, 0.0, 2.0, 2.0);
|
|
B2DRange aSouthWest(0.0, 0.0, -2.0, 2.0);
|
|
B2DRange aNorthWest(0.0, 0.0, -2.0, -2.0);
|
|
|
|
B2DRange aNorth2(-1.5, 0.5, 1.5, 3.5);
|
|
B2DRange aSouth2(-1.5, -0.5, 1.5, -3.5);
|
|
B2DRange aEast2 (0.5, -1.5, 3.5, 1.5);
|
|
B2DRange aWest2 (-0.5, -1.5,-3.5, 1.5);
|
|
|
|
::std::ofstream output("multirange_testcases.gnuplot");
|
|
DebugPlotter aPlotter( "multirange testcases",
|
|
output );
|
|
|
|
aPlotter.plot( aCenter, "center" );
|
|
aPlotter.plot( aOffside, "offside" );
|
|
aPlotter.plot( aNorth, "north" );
|
|
aPlotter.plot( aSouth, "south" );
|
|
aPlotter.plot( aEast, "east" );
|
|
aPlotter.plot( aWest, "west" );
|
|
aPlotter.plot( aNorthEast, "northeast" );
|
|
aPlotter.plot( aSouthEast, "southeast" );
|
|
aPlotter.plot( aSouthWest, "southwest" );
|
|
aPlotter.plot( aNorthWest, "northwest" );
|
|
|
|
aDisjunctRanges.addRange( aCenter );
|
|
aDisjunctRanges.addRange( aOffside );
|
|
|
|
aEqualRanges.addRange( aCenter );
|
|
aEqualRanges.addRange( aCenter );
|
|
|
|
aIntersectionN.addRange( aCenter );
|
|
aIntersectionN.addRange( aNorth );
|
|
|
|
aIntersectionE.addRange( aCenter );
|
|
aIntersectionE.addRange( aEast );
|
|
|
|
aIntersectionS.addRange( aCenter );
|
|
aIntersectionS.addRange( aSouth );
|
|
|
|
aIntersectionW.addRange( aCenter );
|
|
aIntersectionW.addRange( aWest );
|
|
|
|
aIntersectionNE.addRange( aCenter );
|
|
aIntersectionNE.addRange( aNorthEast );
|
|
|
|
aIntersectionSE.addRange( aCenter );
|
|
aIntersectionSE.addRange( aSouthEast );
|
|
|
|
aIntersectionSW.addRange( aCenter );
|
|
aIntersectionSW.addRange( aSouthWest );
|
|
|
|
aIntersectionNW.addRange( aCenter );
|
|
aIntersectionNW.addRange( aNorthWest );
|
|
|
|
aRingIntersection.addRange( aNorth2 );
|
|
aRingIntersection.addRange( aEast2 );
|
|
aRingIntersection.addRange( aSouth2 );
|
|
aRingIntersection.addRange( aWest2 );
|
|
|
|
aComplexIntersections.addRange( aCenter );
|
|
aComplexIntersections.addRange( aOffside );
|
|
aComplexIntersections.addRange( aCenter );
|
|
aComplexIntersections.addRange( aNorth );
|
|
aComplexIntersections.addRange( aEast );
|
|
aComplexIntersections.addRange( aSouth );
|
|
aComplexIntersections.addRange( aWest );
|
|
aComplexIntersections.addRange( aNorthEast );
|
|
aComplexIntersections.addRange( aSouthEast );
|
|
aComplexIntersections.addRange( aSouthWest );
|
|
aComplexIntersections.addRange( aNorthWest );
|
|
|
|
/*
|
|
for( int i=0; i<10; ++i )
|
|
{
|
|
B2DRange aRandomRange(
|
|
getRandomOrdinal( 10 ),
|
|
getRandomOrdinal( 10 ),
|
|
getRandomOrdinal( 10 ),
|
|
getRandomOrdinal( 10 ) );
|
|
|
|
aRandomIntersections.addRange( aRandomRange );
|
|
}
|
|
*/
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
::basegfx::B2DPolyPolygon shiftPoly( int nCount,
|
|
const ::basegfx::B2DPolyPolygon& rPoly )
|
|
{
|
|
B2DHomMatrix aMatrix;
|
|
aMatrix.translate( nCount*4.0,
|
|
10.0-nCount*2.0 );
|
|
|
|
::basegfx::B2DPolyPolygon aRes( rPoly );
|
|
aRes.transform( aMatrix );
|
|
|
|
return aRes;
|
|
}
|
|
|
|
void getPolyPolygon()
|
|
{
|
|
::std::ofstream output("multirange_getpolypolygon.gnuplot");
|
|
DebugPlotter aPlotter( "multirange getPolyPolygon",
|
|
output );
|
|
|
|
B2DPolyPolygon result;
|
|
|
|
aPlotter.plot( shiftPoly(
|
|
0,
|
|
aDisjunctRanges.getPolyPolygon() ),
|
|
"disjunct" );
|
|
aPlotter.plot( shiftPoly(
|
|
1,
|
|
aEqualRanges.getPolyPolygon() ),
|
|
"equal" );
|
|
aPlotter.plot( shiftPoly(
|
|
2,
|
|
aIntersectionN.getPolyPolygon() ),
|
|
"intersectionN" );
|
|
aPlotter.plot( shiftPoly(
|
|
3,
|
|
aIntersectionE.getPolyPolygon() ),
|
|
"intersectionE" );
|
|
aPlotter.plot( shiftPoly(
|
|
4,
|
|
aIntersectionS.getPolyPolygon() ),
|
|
"intersectionS" );
|
|
aPlotter.plot( shiftPoly(
|
|
5,
|
|
aIntersectionW.getPolyPolygon() ),
|
|
"intersectionW" );
|
|
aPlotter.plot( shiftPoly(
|
|
6,
|
|
aIntersectionNE.getPolyPolygon() ),
|
|
"intersectionNE" );
|
|
aPlotter.plot( shiftPoly(
|
|
7,
|
|
aIntersectionSE.getPolyPolygon() ),
|
|
"intersectionSE" );
|
|
aPlotter.plot( shiftPoly(
|
|
8,
|
|
aIntersectionSW.getPolyPolygon() ),
|
|
"intersectionSW" );
|
|
aPlotter.plot( shiftPoly(
|
|
9,
|
|
aIntersectionNW.getPolyPolygon() ),
|
|
"intersectionNW" );
|
|
aPlotter.plot( shiftPoly(
|
|
10,
|
|
aRingIntersection.getPolyPolygon() ),
|
|
"intersection ring" );
|
|
aPlotter.plot( shiftPoly(
|
|
11,
|
|
aComplexIntersections.getPolyPolygon() ),
|
|
"intersection complex" );
|
|
aPlotter.plot( shiftPoly(
|
|
12,
|
|
aRandomIntersections.getPolyPolygon() ),
|
|
"intersection random" );
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("getPolyPolygon", true );
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dmultirange);
|
|
CPPUNIT_TEST(getPolyPolygon);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dmultirange
|
|
|
|
class b2dsvgdimpex : public CppUnit::TestFixture
|
|
{
|
|
private:
|
|
::rtl::OUString aPath0;
|
|
::rtl::OUString aPath1;
|
|
::rtl::OUString aPath2;
|
|
::rtl::OUString aPath3;
|
|
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
// simple rectangle
|
|
aPath0 = ::rtl::OUString::createFromAscii(
|
|
"M 10 10-10 10-10-10 10-10Z" );
|
|
|
|
// simple bezier polygon
|
|
aPath1 = ::rtl::OUString::createFromAscii(
|
|
"m11430 0c-8890 3810 5715 6985 5715 6985 "
|
|
"0 0-17145-1905-17145-1905 0 0 22860-10160 "
|
|
"16510 6350-6350 16510-3810-11430-3810-11430z" );
|
|
|
|
// '@' as a bezier polygon
|
|
aPath2 = ::rtl::OUString::createFromAscii(
|
|
"m1917 1114c-89-189-233-284-430-284-167 "
|
|
"0-306 91-419 273-113 182-170 370-170 564 "
|
|
"0 145 33 259 98 342 65 84 150 126 257 126 "
|
|
"77 0 154-19 231-57 77-38 147-97 210-176 63"
|
|
"-79 99-143 109-190 38-199 76-398 114-598z"
|
|
"m840 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-292 67-560 200-803 "
|
|
"133-243 321-433 562-569 241-136 514-204 821"
|
|
"-204 405 0 739 125 1003 374 264 250 396 550 "
|
|
"396 899 0 313-88 576-265 787-177 212-386 318"
|
|
"-627 318-191 0-308-94-352-281-133 187-315 281"
|
|
"-546 281-172 0-315-67-428-200-113-133-170-301"
|
|
"-170-505 0-277 90-527 271-751 181-223 394"
|
|
"-335 640-335 196 0 353 83 470 250 13-68 26"
|
|
"-136 41-204 96 0 192 0 288 0-74 376-148 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-240 121"
|
|
"-160 182-365 182-615 0-288-107-533-322-734"
|
|
"-215-201-487-301-816-301-395 0-715 124-960 "
|
|
"373-245 249-368 569-368 958 0 385 119 685 "
|
|
"357 900 237 216 557 324 958 325 189-1 389-27 "
|
|
"600-77 211-52 378-110 503-174 27 70 54 140 81 210z" );
|
|
|
|
// first part of 'Hello World' as a line polygon
|
|
aPath3 = ::rtl::OUString::createFromAscii(
|
|
"m1598 125h306v2334h-306v-1105h-1293v1105h-305v"
|
|
"-2334h305v973h1293zm2159 1015 78-44 85 235-91 "
|
|
"47-91 40-90 34-90 29-89 21-88 16-88 10-88 3-102"
|
|
"-4-97-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-33-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 31-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-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 17 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 17 84 10 89 3 94v78h-1277l6 "
|
|
"75 10 70 14 66 19 62 23 57 13 26 14 26 15 25 17 "
|
|
"23 17 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 67 3 80-3 81"
|
|
"-9 79-14 80-21 78-26 79-32zm-1049-808-12 53h963l"
|
|
"-7-51-11-49-14-46-17-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-46 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-1293h288v"
|
|
"2459h-288zm752-2459h288v2459h-288zm1286-1750 86-11 "
|
|
"91-4 91 4 85 12 42 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 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 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 14-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-21-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-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-28 30-26 "
|
|
"31-24 33-22 34-20 35-18 36-16 37-15 39-12 40-11z" );
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
void impex()
|
|
{
|
|
B2DPolyPolygon aPoly;
|
|
::rtl::OUString aExport;
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("importing simple rectangle from SVG-D",
|
|
tools::importFromSvgD( aPoly,
|
|
aPath0 ));
|
|
aExport = tools::exportToSvgD( aPoly );
|
|
const char* sExportString = "m10 10h-20v-20h20z";
|
|
CPPUNIT_ASSERT_MESSAGE("exporting rectangle to SVG-D",
|
|
!aExport.compareToAscii(sExportString) );
|
|
CPPUNIT_ASSERT_MESSAGE("importing simple rectangle from SVG-D (round-trip",
|
|
tools::importFromSvgD( aPoly,
|
|
aExport ));
|
|
aExport = tools::exportToSvgD( aPoly );
|
|
CPPUNIT_ASSERT_MESSAGE("exporting rectangle to SVG-D (round-trip)",
|
|
!aExport.compareToAscii(sExportString));
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("importing simple bezier polygon from SVG-D",
|
|
tools::importFromSvgD( aPoly,
|
|
aPath1 ));
|
|
aExport = tools::exportToSvgD( aPoly );
|
|
|
|
// Adaptions for B2DPolygon bezier change (see #i77162#):
|
|
//
|
|
// The import/export of aPath1 does not reproduce aExport again. This is
|
|
// correct since aPath1 contains a segment with non-used control points
|
|
// which gets exported now correctly as 'l' and also a point (#4, index 3)
|
|
// with C2 continuity which produces a 's' staement now.
|
|
//
|
|
// The old SVGexport identified nun-used ControlVectors erraneously as bezier segments
|
|
// because the 2nd vector at the start point was used, even when added
|
|
// with start point was identical to end point. Exactly for that reason
|
|
// i reworked the B2DPolygon to use prev, next control points.
|
|
//
|
|
// so for correct unit test i add the new exported string here as sExportStringSimpleBezier
|
|
// and compare to it.
|
|
const char* sExportStringSimpleBezier =
|
|
"m11430 0c-8890 3810 5715 6985 5715 6985"
|
|
"l-17145-1905c0 0 22860-10160 16510 6350"
|
|
"s-3810-11430-3810-11430z";
|
|
CPPUNIT_ASSERT_MESSAGE("exporting bezier polygon to SVG-D", !aExport.compareToAscii(sExportStringSimpleBezier));
|
|
|
|
// Adaptions for B2DPolygon bezier change (see #i77162#):
|
|
//
|
|
// a 2nd good test is that re-importing of aExport has to create the same
|
|
// B2DPolPolygon again:
|
|
B2DPolyPolygon aReImport;
|
|
CPPUNIT_ASSERT_MESSAGE("importing simple bezier polygon from SVG-D", tools::importFromSvgD( aReImport, aExport));
|
|
CPPUNIT_ASSERT_MESSAGE("re-imported polygon needs to be identical", aReImport == aPoly);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("importing '@' from SVG-D", tools::importFromSvgD( aPoly, aPath2 ));
|
|
aExport = tools::exportToSvgD( aPoly );
|
|
|
|
// Adaptions for B2DPolygon bezier change (see #i77162#):
|
|
//
|
|
// same here, the corrected export with the corrected B2DPolygon is simply more efficient,
|
|
// so i needed to change the compare string. Also adding the re-import comparison below.
|
|
const char* sExportString1 =
|
|
"m1917 1114c-89-189-233-284-430-284-167 0-306 91-419 273s-170 370-17"
|
|
"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"
|
|
"-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-"
|
|
"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"
|
|
"-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"
|
|
"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"
|
|
"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"
|
|
"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"
|
|
"8 325 189-1 389-27 600-77 211-52 378-110 503-174q40.5 105 81 210z";
|
|
CPPUNIT_ASSERT_MESSAGE("re-importing '@' from SVG-D", tools::importFromSvgD( aReImport, aExport));
|
|
CPPUNIT_ASSERT_MESSAGE("re-imported '@' needs to be identical", aReImport == aPoly);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("exporting '@' to SVG-D", !aExport.compareToAscii(sExportString1));
|
|
CPPUNIT_ASSERT_MESSAGE("importing '@' from SVG-D (round-trip",
|
|
tools::importFromSvgD( aPoly,
|
|
aExport ));
|
|
aExport = tools::exportToSvgD( aPoly );
|
|
CPPUNIT_ASSERT_MESSAGE("exporting '@' to SVG-D (round-trip)",
|
|
!aExport.compareToAscii(sExportString1));
|
|
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("importing complex polygon from SVG-D",
|
|
tools::importFromSvgD( aPoly,
|
|
aPath3 ));
|
|
aExport = tools::exportToSvgD( aPoly );
|
|
const char* sExportString2 =
|
|
"m1598 125h306v2334h-306v-1105h-1293v1105h-305v-2334h305v973h1293"
|
|
"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"
|
|
"-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"
|
|
"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"
|
|
"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-"
|
|
"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"
|
|
"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 "
|
|
"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"
|
|
"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"
|
|
" 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"
|
|
"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"
|
|
"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"
|
|
"-1293h288v2459h-288zm752-2459h288v2459h-288zm1286-1750 86-11 91-4 91 4 85 12 42 "
|
|
"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 "
|
|
"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"
|
|
" 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"
|
|
"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"
|
|
"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-"
|
|
"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"
|
|
"-28 30-26 31-24 33-22 34-20 35-18 36-16 37-15 39-12 40-11z";
|
|
CPPUNIT_ASSERT_MESSAGE("exporting complex polygon to SVG-D",
|
|
!aExport.compareToAscii(sExportString2));
|
|
CPPUNIT_ASSERT_MESSAGE("importing complex polygon from SVG-D (round-trip",
|
|
tools::importFromSvgD( aPoly,
|
|
aExport ));
|
|
aExport = tools::exportToSvgD( aPoly );
|
|
CPPUNIT_ASSERT_MESSAGE("exporting complex polygon to SVG-D (round-trip)",
|
|
!aExport.compareToAscii(sExportString2));
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dsvgdimpex);
|
|
CPPUNIT_TEST(impex);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dsvgdimpex
|
|
|
|
class b2dbeziertools : public CppUnit::TestFixture
|
|
{
|
|
private:
|
|
B2DCubicBezier aHalfCircle; // not exactly, but a look-alike
|
|
B2DCubicBezier aQuarterCircle; // not exactly, but a look-alike
|
|
B2DCubicBezier aLoop; // identical endpoints, curve goes back to where it started
|
|
B2DCubicBezier aStraightLineDistinctEndPoints; // truly a line
|
|
B2DCubicBezier aStraightLineDistinctEndPoints2; // truly a line, with slightly different control points
|
|
B2DCubicBezier aStraightLineIdenticalEndPoints; // degenerate case of aLoop
|
|
B2DCubicBezier aStraightLineIdenticalEndPoints2;// degenerate case of aLoop, with slightly different control points
|
|
B2DCubicBezier aCrossing; // curve self-intersects somewhere in the middle
|
|
B2DCubicBezier aCusp; // curve has a point of undefined tangency
|
|
|
|
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
const B2DPoint a00(0.0, 0.0);
|
|
const B2DPoint a10(1.0, 0.0);
|
|
const B2DPoint a11(1.0, 1.0);
|
|
const B2DPoint a01(0.0, 1.0);
|
|
const B2DPoint middle( 0.5, 0.5 );
|
|
const B2DPoint quarterDown( 0.25, 0.25 );
|
|
const B2DPoint quarterUp( 0.75, 0.75 );
|
|
|
|
aHalfCircle = B2DCubicBezier(a00, a01, a11, a10);
|
|
|
|
// The spline control points become
|
|
//
|
|
// (R * cos(A), R * sin(A))
|
|
// (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
|
|
// (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
|
|
// (R * cos(B), R * sin(B))
|
|
//
|
|
// where h = 4/3 * R * tan ((B-A)/4)
|
|
//
|
|
// with R being the radius, A start angle and B end angle (A < B).
|
|
//
|
|
// (This calculation courtesy Carl Worth, himself based on
|
|
// Michael Goldapp and Dokken/Daehlen)
|
|
|
|
// Choosing R=1, A=0, B=pi/2
|
|
const double h( 4.0/3.0 * tan(M_PI/8.0) );
|
|
aQuarterCircle = B2DCubicBezier(a10 + B2DPoint(1.0,0.0),
|
|
B2DPoint(B2DPoint( 1.0, h ) + B2DPoint(1.0,0.0)),
|
|
B2DPoint(B2DPoint( h, 1.0) + B2DPoint(1.0,0.0)),
|
|
a01 + B2DPoint(1.0,0.0));
|
|
|
|
aCusp = B2DCubicBezier(a00 + B2DPoint(2.0,0.0),
|
|
B2DPoint(a11 + B2DPoint(2.0,0.0)),
|
|
B2DPoint(a01 + B2DPoint(2.0,0.0)),
|
|
a10 + B2DPoint(2.0,0.0));
|
|
|
|
aLoop = B2DCubicBezier(a00 + B2DPoint(3.0,0.0),
|
|
B2DPoint(a01 + B2DPoint(3.0,0.0)),
|
|
B2DPoint(a10 + B2DPoint(3.0,0.0)),
|
|
a00 + B2DPoint(3.0,0.0));
|
|
|
|
aStraightLineDistinctEndPoints = B2DCubicBezier(a00 + B2DPoint(4.0,0.0),
|
|
B2DPoint(middle + B2DPoint(4.0,0.0)),
|
|
B2DPoint(middle + B2DPoint(4.0,0.0)),
|
|
a11 + B2DPoint(4.0,0.0));
|
|
|
|
aStraightLineDistinctEndPoints2 = B2DCubicBezier(a00 + B2DPoint(5.0,0.0),
|
|
B2DPoint(quarterDown + B2DPoint(5.0,0.0)),
|
|
B2DPoint(quarterUp + B2DPoint(5.0,0.0)),
|
|
a11 + B2DPoint(5.0,0.0));
|
|
|
|
aStraightLineIdenticalEndPoints = B2DCubicBezier(a00 + B2DPoint(6.0,0.0),
|
|
B2DPoint(a11 + B2DPoint(6.0,0.0)),
|
|
B2DPoint(a11 + B2DPoint(6.0,0.0)),
|
|
a00 + B2DPoint(6.0,0.0));
|
|
|
|
aStraightLineIdenticalEndPoints2 = B2DCubicBezier(a00 + B2DPoint(7.0,0.0),
|
|
B2DPoint(quarterDown + B2DPoint(7.0,0.0)),
|
|
B2DPoint(quarterUp + B2DPoint(7.0,0.0)),
|
|
a00 + B2DPoint(7.0,0.0));
|
|
|
|
aCrossing = B2DCubicBezier(a00 + B2DPoint(8.0,0.0),
|
|
B2DPoint(B2DPoint(2.0,2.0) + B2DPoint(8.0,0.0)),
|
|
B2DPoint(B2DPoint(-1.0,2.0) + B2DPoint(8.0,0.0)),
|
|
a10 + B2DPoint(8.0,0.0));
|
|
|
|
::std::ofstream output("bez_testcases.gnuplot");
|
|
DebugPlotter aPlotter( "Original curves",
|
|
output );
|
|
|
|
aPlotter.plot( aHalfCircle,
|
|
"half circle" );
|
|
aPlotter.plot( aQuarterCircle,
|
|
"quarter circle" );
|
|
aPlotter.plot( aCusp,
|
|
"cusp" );
|
|
aPlotter.plot( aLoop,
|
|
"loop" );
|
|
aPlotter.plot( aStraightLineDistinctEndPoints,
|
|
"straight line 0" );
|
|
aPlotter.plot( aStraightLineDistinctEndPoints2,
|
|
"straight line 1" );
|
|
aPlotter.plot( aStraightLineIdenticalEndPoints,
|
|
"straight line 2" );
|
|
aPlotter.plot( aStraightLineIdenticalEndPoints2,
|
|
"straight line 3" );
|
|
aPlotter.plot( aCrossing,
|
|
"crossing" );
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
void adaptiveByDistance()
|
|
{
|
|
::std::ofstream output("bez_adaptiveByDistance.gnuplot");
|
|
DebugPlotter aPlotter( "distance-adaptive subdivision",
|
|
output );
|
|
|
|
const double fBound( 0.0001 );
|
|
B2DPolygon result;
|
|
|
|
aHalfCircle.adaptiveSubdivideByDistance(result, fBound);
|
|
aPlotter.plot(result,
|
|
"half circle"); result.clear();
|
|
|
|
aQuarterCircle.adaptiveSubdivideByDistance(result, fBound);
|
|
aPlotter.plot(result,
|
|
"quarter circle"); result.clear();
|
|
|
|
aLoop.adaptiveSubdivideByDistance(result, fBound);
|
|
aPlotter.plot(result,
|
|
"loop"); result.clear();
|
|
|
|
aStraightLineDistinctEndPoints.adaptiveSubdivideByDistance(result, fBound);
|
|
aPlotter.plot(result,
|
|
"straight line 0"); result.clear();
|
|
|
|
aStraightLineDistinctEndPoints2.adaptiveSubdivideByDistance(result, fBound);
|
|
aPlotter.plot(result,
|
|
"straight line 1"); result.clear();
|
|
|
|
aStraightLineIdenticalEndPoints.adaptiveSubdivideByDistance(result, fBound);
|
|
aPlotter.plot(result,
|
|
"straight line 2"); result.clear();
|
|
|
|
aStraightLineIdenticalEndPoints2.adaptiveSubdivideByDistance(result, fBound);
|
|
aPlotter.plot(result,
|
|
"straight line 3"); result.clear();
|
|
|
|
aCrossing.adaptiveSubdivideByDistance(result, fBound);
|
|
aPlotter.plot(result,
|
|
"straight line 4"); result.clear();
|
|
|
|
aCusp.adaptiveSubdivideByDistance(result, fBound);
|
|
aPlotter.plot(result,
|
|
"straight line 5"); result.clear();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("adaptiveByDistance", true );
|
|
}
|
|
|
|
void adaptiveByAngle()
|
|
{
|
|
const double fBound( 5.0 );
|
|
B2DPolygon result;
|
|
|
|
::std::ofstream output("bez_adaptiveByAngle.gnuplot");
|
|
DebugPlotter aPlotter( "angle-adaptive subdivision",
|
|
output );
|
|
|
|
aHalfCircle.adaptiveSubdivideByAngle(result, fBound, true);
|
|
aPlotter.plot(result,
|
|
"half circle"); result.clear();
|
|
|
|
aQuarterCircle.adaptiveSubdivideByAngle(result, fBound, true);
|
|
aPlotter.plot(result,
|
|
"quarter cirle"); result.clear();
|
|
|
|
aLoop.adaptiveSubdivideByAngle(result, fBound, true);
|
|
aPlotter.plot(result,
|
|
"loop"); result.clear();
|
|
|
|
aStraightLineDistinctEndPoints.adaptiveSubdivideByAngle(result, fBound, true);
|
|
aPlotter.plot(result,
|
|
"straight line 0"); result.clear();
|
|
|
|
aStraightLineDistinctEndPoints2.adaptiveSubdivideByAngle(result, fBound, true);
|
|
aPlotter.plot(result,
|
|
"straight line 1"); result.clear();
|
|
|
|
aStraightLineIdenticalEndPoints.adaptiveSubdivideByAngle(result, fBound, true);
|
|
aPlotter.plot(result,
|
|
"straight line 2"); result.clear();
|
|
|
|
aStraightLineIdenticalEndPoints2.adaptiveSubdivideByAngle(result, fBound, true);
|
|
aPlotter.plot(result,
|
|
"straight line 3"); result.clear();
|
|
|
|
aCrossing.adaptiveSubdivideByAngle(result, fBound, true);
|
|
aPlotter.plot(result,
|
|
"straight line 4"); result.clear();
|
|
|
|
aCusp.adaptiveSubdivideByAngle(result, fBound, true);
|
|
aPlotter.plot(result,
|
|
"straight line 5"); result.clear();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("adaptiveByAngle", true );
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dbeziertools);
|
|
CPPUNIT_TEST(adaptiveByDistance); // TODO: add tests for quadratic bezier (subdivide and degree reduction)
|
|
CPPUNIT_TEST(adaptiveByAngle);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dcubicbezier
|
|
|
|
|
|
class b2dcubicbezier : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
// insert your test code here.
|
|
void EmptyMethod()
|
|
{
|
|
// this is demonstration code
|
|
// CPPUNIT_ASSERT_MESSAGE("a message", 1 == 1);
|
|
CPPUNIT_ASSERT_STUB();
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dcubicbezier);
|
|
CPPUNIT_TEST(EmptyMethod);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dcubicbezier
|
|
|
|
|
|
class b2dhommatrix : public CppUnit::TestFixture
|
|
{
|
|
private:
|
|
B2DHomMatrix maIdentity;
|
|
B2DHomMatrix maScale;
|
|
B2DHomMatrix maTranslate;
|
|
B2DHomMatrix maShear;
|
|
B2DHomMatrix maAffine;
|
|
B2DHomMatrix maPerspective;
|
|
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
// setup some test matrices
|
|
maIdentity.identity(); // force compact layout
|
|
maIdentity.set(0,0, 1.0);
|
|
maIdentity.set(0,1, 0.0);
|
|
maIdentity.set(0,2, 0.0);
|
|
maIdentity.set(1,0, 0.0);
|
|
maIdentity.set(1,1, 1.0);
|
|
maIdentity.set(1,2, 0.0);
|
|
|
|
maScale.identity(); // force compact layout
|
|
maScale.set(0,0, 2.0);
|
|
maScale.set(1,1, 20.0);
|
|
|
|
maTranslate.identity(); // force compact layout
|
|
maTranslate.set(0,2, 20.0);
|
|
maTranslate.set(1,2, 2.0);
|
|
|
|
maShear.identity(); // force compact layout
|
|
maShear.set(0,1, 3.0);
|
|
maShear.set(1,0, 7.0);
|
|
maShear.set(1,1, 22.0);
|
|
|
|
maAffine.identity(); // force compact layout
|
|
maAffine.set(0,0, 1.0);
|
|
maAffine.set(0,1, 2.0);
|
|
maAffine.set(0,2, 3.0);
|
|
maAffine.set(1,0, 4.0);
|
|
maAffine.set(1,1, 5.0);
|
|
maAffine.set(1,2, 6.0);
|
|
|
|
maPerspective.set(0,0, 1.0);
|
|
maPerspective.set(0,1, 2.0);
|
|
maPerspective.set(0,2, 3.0);
|
|
maPerspective.set(1,0, 4.0);
|
|
maPerspective.set(1,1, 5.0);
|
|
maPerspective.set(1,2, 6.0);
|
|
maPerspective.set(2,0, 7.0);
|
|
maPerspective.set(2,1, 8.0);
|
|
maPerspective.set(2,2, 9.0);
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
void equal()
|
|
{
|
|
B2DHomMatrix aIdentity;
|
|
B2DHomMatrix aScale;
|
|
B2DHomMatrix aTranslate;
|
|
B2DHomMatrix aShear;
|
|
B2DHomMatrix aAffine;
|
|
B2DHomMatrix aPerspective;
|
|
|
|
// setup some test matrices
|
|
aIdentity.identity(); // force compact layout
|
|
aIdentity.set(0,0, 1.0);
|
|
aIdentity.set(0,1, 0.0);
|
|
aIdentity.set(0,2, 0.0);
|
|
aIdentity.set(1,0, 0.0);
|
|
aIdentity.set(1,1, 1.0);
|
|
aIdentity.set(1,2, 0.0);
|
|
|
|
aScale.identity(); // force compact layout
|
|
aScale.set(0,0, 2.0);
|
|
aScale.set(1,1, 20.0);
|
|
|
|
aTranslate.identity(); // force compact layout
|
|
aTranslate.set(0,2, 20.0);
|
|
aTranslate.set(1,2, 2.0);
|
|
|
|
aShear.identity(); // force compact layout
|
|
aShear.set(0,1, 3.0);
|
|
aShear.set(1,0, 7.0);
|
|
aShear.set(1,1, 22.0);
|
|
|
|
aAffine.identity(); // force compact layout
|
|
aAffine.set(0,0, 1.0);
|
|
aAffine.set(0,1, 2.0);
|
|
aAffine.set(0,2, 3.0);
|
|
aAffine.set(1,0, 4.0);
|
|
aAffine.set(1,1, 5.0);
|
|
aAffine.set(1,2, 6.0);
|
|
|
|
aPerspective.set(0,0, 1.0);
|
|
aPerspective.set(0,1, 2.0);
|
|
aPerspective.set(0,2, 3.0);
|
|
aPerspective.set(1,0, 4.0);
|
|
aPerspective.set(1,1, 5.0);
|
|
aPerspective.set(1,2, 6.0);
|
|
aPerspective.set(2,0, 7.0);
|
|
aPerspective.set(2,1, 8.0);
|
|
aPerspective.set(2,2, 9.0);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("operator==: identity matrix", aIdentity == maIdentity);
|
|
CPPUNIT_ASSERT_MESSAGE("operator==: scale matrix", aScale == maScale);
|
|
CPPUNIT_ASSERT_MESSAGE("operator==: translate matrix", aTranslate == maTranslate);
|
|
CPPUNIT_ASSERT_MESSAGE("operator==: shear matrix", aShear == maShear);
|
|
CPPUNIT_ASSERT_MESSAGE("operator==: affine matrix", aAffine == maAffine);
|
|
CPPUNIT_ASSERT_MESSAGE("operator==: perspective matrix", aPerspective == maPerspective);
|
|
}
|
|
|
|
void identity()
|
|
{
|
|
B2DHomMatrix ident;
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("identity", maIdentity == ident);
|
|
}
|
|
|
|
void scale()
|
|
{
|
|
B2DHomMatrix mat;
|
|
mat.scale(2.0,20.0);
|
|
CPPUNIT_ASSERT_MESSAGE("scale", maScale == mat);
|
|
}
|
|
|
|
void translate()
|
|
{
|
|
B2DHomMatrix mat;
|
|
mat.translate(20.0,2.0);
|
|
CPPUNIT_ASSERT_MESSAGE("translate", maTranslate == mat);
|
|
}
|
|
|
|
void shear()
|
|
{
|
|
B2DHomMatrix mat;
|
|
mat.shearX(3.0);
|
|
mat.shearY(7.0);
|
|
CPPUNIT_ASSERT_MESSAGE("translate", maShear == mat);
|
|
}
|
|
|
|
void multiply()
|
|
{
|
|
B2DHomMatrix affineAffineProd;
|
|
|
|
affineAffineProd.set(0,0, 9);
|
|
affineAffineProd.set(0,1, 12);
|
|
affineAffineProd.set(0,2, 18);
|
|
affineAffineProd.set(1,0, 24);
|
|
affineAffineProd.set(1,1, 33);
|
|
affineAffineProd.set(1,2, 48);
|
|
|
|
B2DHomMatrix affinePerspectiveProd;
|
|
|
|
affinePerspectiveProd.set(0,0, 30);
|
|
affinePerspectiveProd.set(0,1, 36);
|
|
affinePerspectiveProd.set(0,2, 42);
|
|
affinePerspectiveProd.set(1,0, 66);
|
|
affinePerspectiveProd.set(1,1, 81);
|
|
affinePerspectiveProd.set(1,2, 96);
|
|
affinePerspectiveProd.set(2,0, 7);
|
|
affinePerspectiveProd.set(2,1, 8);
|
|
affinePerspectiveProd.set(2,2, 9);
|
|
|
|
B2DHomMatrix perspectiveAffineProd;
|
|
|
|
perspectiveAffineProd.set(0,0, 9);
|
|
perspectiveAffineProd.set(0,1, 12);
|
|
perspectiveAffineProd.set(0,2, 18);
|
|
perspectiveAffineProd.set(1,0, 24);
|
|
perspectiveAffineProd.set(1,1, 33);
|
|
perspectiveAffineProd.set(1,2, 48);
|
|
perspectiveAffineProd.set(2,0, 39);
|
|
perspectiveAffineProd.set(2,1, 54);
|
|
perspectiveAffineProd.set(2,2, 78);
|
|
|
|
B2DHomMatrix perspectivePerspectiveProd;
|
|
|
|
perspectivePerspectiveProd.set(0,0, 30);
|
|
perspectivePerspectiveProd.set(0,1, 36);
|
|
perspectivePerspectiveProd.set(0,2, 42);
|
|
perspectivePerspectiveProd.set(1,0, 66);
|
|
perspectivePerspectiveProd.set(1,1, 81);
|
|
perspectivePerspectiveProd.set(1,2, 96);
|
|
perspectivePerspectiveProd.set(2,0, 102);
|
|
perspectivePerspectiveProd.set(2,1, 126);
|
|
perspectivePerspectiveProd.set(2,2, 150);
|
|
|
|
B2DHomMatrix temp;
|
|
|
|
temp = maAffine;
|
|
temp*=maAffine;
|
|
CPPUNIT_ASSERT_MESSAGE("multiply: both compact", temp == affineAffineProd);
|
|
|
|
temp = maPerspective;
|
|
temp*=maAffine;
|
|
CPPUNIT_ASSERT_MESSAGE("multiply: first compact", temp == affinePerspectiveProd);
|
|
|
|
temp = maAffine;
|
|
temp*=maPerspective;
|
|
CPPUNIT_ASSERT_MESSAGE("multiply: second compact", temp == perspectiveAffineProd);
|
|
|
|
temp = maPerspective;
|
|
temp*=maPerspective;
|
|
CPPUNIT_ASSERT_MESSAGE("multiply: none compact", temp == perspectivePerspectiveProd);
|
|
}
|
|
|
|
void impFillMatrix(B2DHomMatrix& rSource, double fScaleX, double fScaleY, double fShearX, double fRotate)
|
|
{
|
|
// fill rSource with a linear combination of scale, shear and rotate
|
|
rSource.identity();
|
|
rSource.scale(fScaleX, fScaleY);
|
|
rSource.shearX(fShearX);
|
|
rSource.rotate(fRotate);
|
|
}
|
|
|
|
bool impDecomposeComposeTest(double fScaleX, double fScaleY, double fShearX, double fRotate)
|
|
{
|
|
// linear combine matrix with given values
|
|
B2DHomMatrix aSource;
|
|
impFillMatrix(aSource, fScaleX, fScaleY, fShearX, fRotate);
|
|
|
|
// decompose that matrix
|
|
B2DTuple aDScale;
|
|
B2DTuple aDTrans;
|
|
double fDRot;
|
|
double fDShX;
|
|
bool bWorked = aSource.decompose(aDScale, aDTrans, fDRot, fDShX);
|
|
|
|
// linear combine another matrix with decomposition results
|
|
B2DHomMatrix aRecombined;
|
|
impFillMatrix(aRecombined, aDScale.getX(), aDScale.getY(), fDShX, fDRot);
|
|
|
|
// if decomposition worked, matrices need to be the same
|
|
return bWorked && aSource == aRecombined;
|
|
}
|
|
|
|
void decompose()
|
|
{
|
|
// test matrix decompositions. Each matrix decomposed and rebuilt
|
|
// using the decompose result should be the same as before. Test
|
|
// with all ranges of values. Translations are not tested since these
|
|
// are just the two rightmost values and uncritical
|
|
static double fSX(10.0);
|
|
static double fSY(12.0);
|
|
static double fR(45.0 * F_PI180);
|
|
static double fS(15.0 * F_PI180);
|
|
|
|
// check all possible scaling combinations
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test A1", impDecomposeComposeTest(fSX, fSY, 0.0, 0.0));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test A2", impDecomposeComposeTest(-fSX, fSY, 0.0, 0.0));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test A3", impDecomposeComposeTest(fSX, -fSY, 0.0, 0.0));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test A4", impDecomposeComposeTest(-fSX, -fSY, 0.0, 0.0));
|
|
|
|
// check all possible scaling combinations with positive rotation
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test B1", impDecomposeComposeTest(fSX, fSY, 0.0, fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test B2", impDecomposeComposeTest(-fSX, fSY, 0.0, fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test B3", impDecomposeComposeTest(fSX, -fSY, 0.0, fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test B4", impDecomposeComposeTest(-fSX, -fSY, 0.0, fR));
|
|
|
|
// check all possible scaling combinations with negative rotation
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test C1", impDecomposeComposeTest(fSX, fSY, 0.0, -fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test C2", impDecomposeComposeTest(-fSX, fSY, 0.0, -fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test C3", impDecomposeComposeTest(fSX, -fSY, 0.0, -fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test C4", impDecomposeComposeTest(-fSX, -fSY, 0.0, -fR));
|
|
|
|
// check all possible scaling combinations with positive shear
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test D1", impDecomposeComposeTest(fSX, fSY, tan(fS), 0.0));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test D2", impDecomposeComposeTest(-fSX, fSY, tan(fS), 0.0));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test D3", impDecomposeComposeTest(fSX, -fSY, tan(fS), 0.0));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test D4", impDecomposeComposeTest(-fSX, -fSY, tan(fS), 0.0));
|
|
|
|
// check all possible scaling combinations with negative shear
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test E1", impDecomposeComposeTest(fSX, fSY, tan(-fS), 0.0));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test E2", impDecomposeComposeTest(-fSX, fSY, tan(-fS), 0.0));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test E3", impDecomposeComposeTest(fSX, -fSY, tan(-fS), 0.0));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test E4", impDecomposeComposeTest(-fSX, -fSY, tan(-fS), 0.0));
|
|
|
|
// check all possible scaling combinations with positive rotate and positive shear
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test F1", impDecomposeComposeTest(fSX, fSY, tan(fS), fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test F2", impDecomposeComposeTest(-fSX, fSY, tan(fS), fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test F3", impDecomposeComposeTest(fSX, -fSY, tan(fS), fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test F4", impDecomposeComposeTest(-fSX, -fSY, tan(fS), fR));
|
|
|
|
// check all possible scaling combinations with negative rotate and positive shear
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test G1", impDecomposeComposeTest(fSX, fSY, tan(fS), -fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test G2", impDecomposeComposeTest(-fSX, fSY, tan(fS), -fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test G3", impDecomposeComposeTest(fSX, -fSY, tan(fS), -fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test G4", impDecomposeComposeTest(-fSX, -fSY, tan(fS), -fR));
|
|
|
|
// check all possible scaling combinations with positive rotate and negative shear
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test H1", impDecomposeComposeTest(fSX, fSY, tan(-fS), fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test H2", impDecomposeComposeTest(-fSX, fSY, tan(-fS), fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test H3", impDecomposeComposeTest(fSX, -fSY, tan(-fS), fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test H4", impDecomposeComposeTest(-fSX, -fSY, tan(-fS), fR));
|
|
|
|
// check all possible scaling combinations with negative rotate and negative shear
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test I1", impDecomposeComposeTest(fSX, fSY, tan(-fS), -fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test I2", impDecomposeComposeTest(-fSX, fSY, tan(-fS), -fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test I3", impDecomposeComposeTest(fSX, -fSY, tan(-fS), -fR));
|
|
CPPUNIT_ASSERT_MESSAGE("decompose: error test I4", impDecomposeComposeTest(-fSX, -fSY, tan(-fS), -fR));
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dhommatrix);
|
|
CPPUNIT_TEST(equal);
|
|
CPPUNIT_TEST(identity);
|
|
CPPUNIT_TEST(scale);
|
|
CPPUNIT_TEST(translate);
|
|
CPPUNIT_TEST(shear);
|
|
CPPUNIT_TEST(multiply);
|
|
CPPUNIT_TEST(decompose);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
|
|
}; // class b2dhommatrix
|
|
|
|
|
|
class b2dhompoint : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
// insert your test code here.
|
|
void EmptyMethod()
|
|
{
|
|
CPPUNIT_ASSERT_STUB();
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dhompoint);
|
|
CPPUNIT_TEST(EmptyMethod);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dhompoint
|
|
|
|
|
|
class b2dpoint : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
// insert your test code here.
|
|
// this is only demonstration code
|
|
void EmptyMethod()
|
|
{
|
|
// CPPUNIT_ASSERT_MESSAGE("a message", 1 == 1);
|
|
CPPUNIT_ASSERT_STUB();
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dpoint);
|
|
CPPUNIT_TEST(EmptyMethod);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dpoint
|
|
|
|
|
|
class b2dpolygon : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
// insert your test code here.
|
|
void testBasics()
|
|
{
|
|
B2DPolygon aPoly;
|
|
|
|
aPoly.appendBezierSegment(B2DPoint(1,1),B2DPoint(2,2),B2DPoint(3,3));
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("#1 first polygon point wrong",
|
|
aPoly.getB2DPoint(0) == B2DPoint(3,3));
|
|
CPPUNIT_ASSERT_MESSAGE("#1 first control point wrong",
|
|
aPoly.getPrevControlPoint(0) == B2DPoint(2,2));
|
|
CPPUNIT_ASSERT_MESSAGE("#1 second control point wrong",
|
|
aPoly.getNextControlPoint(0) == B2DPoint(3,3));
|
|
CPPUNIT_ASSERT_MESSAGE("next control point not used",
|
|
aPoly.isNextControlPointUsed(0) == false);
|
|
|
|
aPoly.setNextControlPoint(0,B2DPoint(4,4));
|
|
CPPUNIT_ASSERT_MESSAGE("#1.1 second control point wrong",
|
|
aPoly.getNextControlPoint(0) == B2DPoint(4,4));
|
|
CPPUNIT_ASSERT_MESSAGE("next control point used",
|
|
aPoly.isNextControlPointUsed(0) == true);
|
|
CPPUNIT_ASSERT_MESSAGE("areControlPointsUsed() wrong",
|
|
aPoly.areControlPointsUsed() == true);
|
|
CPPUNIT_ASSERT_MESSAGE("getContinuityInPoint() wrong",
|
|
aPoly.getContinuityInPoint(0) == CONTINUITY_C2);
|
|
|
|
aPoly.resetControlPoints();
|
|
CPPUNIT_ASSERT_MESSAGE("resetControlPoints() did not clear",
|
|
aPoly.getB2DPoint(0) == B2DPoint(3,3));
|
|
CPPUNIT_ASSERT_MESSAGE("resetControlPoints() did not clear",
|
|
aPoly.getPrevControlPoint(0) == B2DPoint(3,3));
|
|
CPPUNIT_ASSERT_MESSAGE("resetControlPoints() did not clear",
|
|
aPoly.getNextControlPoint(0) == B2DPoint(3,3));
|
|
CPPUNIT_ASSERT_MESSAGE("areControlPointsUsed() wrong #2",
|
|
aPoly.areControlPointsUsed() == false);
|
|
|
|
aPoly.clear();
|
|
aPoly.append(B2DPoint(0,0));
|
|
aPoly.appendBezierSegment(B2DPoint(1,1),B2DPoint(2,2),B2DPoint(3,3));
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("#2 first polygon point wrong",
|
|
aPoly.getB2DPoint(0) == B2DPoint(0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("#2 first control point wrong",
|
|
aPoly.getPrevControlPoint(0) == B2DPoint(0,0));
|
|
CPPUNIT_ASSERT_MESSAGE("#2 second control point wrong",
|
|
aPoly.getNextControlPoint(0) == B2DPoint(1,1));
|
|
CPPUNIT_ASSERT_MESSAGE("#2 third control point wrong",
|
|
aPoly.getPrevControlPoint(1) == B2DPoint(2,2));
|
|
CPPUNIT_ASSERT_MESSAGE("#2 fourth control point wrong",
|
|
aPoly.getNextControlPoint(1) == B2DPoint(3,3));
|
|
CPPUNIT_ASSERT_MESSAGE("#2 second polygon point wrong",
|
|
aPoly.getB2DPoint(1) == B2DPoint(3,3));
|
|
}
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dpolygon);
|
|
CPPUNIT_TEST(testBasics);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dpolygon
|
|
|
|
|
|
class b2dpolygontools : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
// insert your test code here.
|
|
// this is only demonstration code
|
|
void testIsRectangle()
|
|
{
|
|
B2DPolygon aRect1(
|
|
tools::createPolygonFromRect(
|
|
B2DRange(0,0,1,1) ) );
|
|
|
|
B2DPolygon aRect2;
|
|
aRect2.append( B2DPoint(0,0) );
|
|
aRect2.append( B2DPoint(1,0) );
|
|
aRect2.append( B2DPoint(1,.5));
|
|
aRect2.append( B2DPoint(1,1) );
|
|
aRect2.append( B2DPoint(0,1) );
|
|
aRect2.setClosed(true);
|
|
|
|
B2DPolygon aNonRect1;
|
|
aNonRect1.append( B2DPoint(0,0) );
|
|
aNonRect1.append( B2DPoint(1,0) );
|
|
aNonRect1.append( B2DPoint(1,1) );
|
|
aNonRect1.append( B2DPoint(0.5,1) );
|
|
aNonRect1.append( B2DPoint(0.5,0) );
|
|
aNonRect1.setClosed(true);
|
|
|
|
B2DPolygon aNonRect2;
|
|
aNonRect2.append( B2DPoint(0,0) );
|
|
aNonRect2.append( B2DPoint(1,1) );
|
|
aNonRect2.append( B2DPoint(1,0) );
|
|
aNonRect2.append( B2DPoint(0,1) );
|
|
aNonRect2.setClosed(true);
|
|
|
|
B2DPolygon aNonRect3;
|
|
aNonRect3.append( B2DPoint(0,0) );
|
|
aNonRect3.append( B2DPoint(1,0) );
|
|
aNonRect3.append( B2DPoint(1,1) );
|
|
aNonRect3.setClosed(true);
|
|
|
|
B2DPolygon aNonRect4;
|
|
aNonRect4.append( B2DPoint(0,0) );
|
|
aNonRect4.append( B2DPoint(1,0) );
|
|
aNonRect4.append( B2DPoint(1,1) );
|
|
aNonRect4.append( B2DPoint(0,1) );
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("checking rectangle-ness of rectangle 1",
|
|
tools::isRectangle( aRect1 ));
|
|
CPPUNIT_ASSERT_MESSAGE("checking rectangle-ness of rectangle 2",
|
|
tools::isRectangle( aRect2 ));
|
|
CPPUNIT_ASSERT_MESSAGE("checking non-rectangle-ness of polygon 1",
|
|
!tools::isRectangle( aNonRect1 ));
|
|
CPPUNIT_ASSERT_MESSAGE("checking non-rectangle-ness of polygon 2",
|
|
!tools::isRectangle( aNonRect2 ));
|
|
CPPUNIT_ASSERT_MESSAGE("checking non-rectangle-ness of polygon 3",
|
|
!tools::isRectangle( aNonRect3 ));
|
|
CPPUNIT_ASSERT_MESSAGE("checking non-rectangle-ness of polygon 4",
|
|
!tools::isRectangle( aNonRect4 ));
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dpolygontools);
|
|
CPPUNIT_TEST(testIsRectangle);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dpolygontools
|
|
|
|
|
|
class b2dpolypolygon : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
// insert your test code here.
|
|
void EmptyMethod()
|
|
{
|
|
CPPUNIT_ASSERT_STUB();
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dpolypolygon);
|
|
CPPUNIT_TEST(EmptyMethod);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dpolypolygon
|
|
|
|
|
|
class b2dquadraticbezier : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
// insert your test code here.
|
|
// this is only demonstration code
|
|
void EmptyMethod()
|
|
{
|
|
// CPPUNIT_ASSERT_MESSAGE("a message", 1 == 1);
|
|
CPPUNIT_ASSERT_STUB();
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dquadraticbezier);
|
|
CPPUNIT_TEST(EmptyMethod);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dquadraticbezier
|
|
|
|
|
|
class b2drange : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
// insert your test code here.
|
|
void EmptyMethod()
|
|
{
|
|
CPPUNIT_ASSERT_STUB();
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2drange);
|
|
CPPUNIT_TEST(EmptyMethod);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2drange
|
|
|
|
|
|
class b2dtuple : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
// insert your test code here.
|
|
// this is only demonstration code
|
|
void EmptyMethod()
|
|
{
|
|
// CPPUNIT_ASSERT_MESSAGE("a message", 1 == 1);
|
|
CPPUNIT_ASSERT_STUB();
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dtuple);
|
|
CPPUNIT_TEST(EmptyMethod);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dtuple
|
|
|
|
|
|
class b2dvector : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
// initialise your test code values here.
|
|
void setUp()
|
|
{
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
|
|
// insert your test code here.
|
|
void EmptyMethod()
|
|
{
|
|
CPPUNIT_ASSERT_STUB();
|
|
}
|
|
|
|
// Change the following lines only, if you add, remove or rename
|
|
// member functions of the current class,
|
|
// because these macros are need by auto register mechanism.
|
|
|
|
CPPUNIT_TEST_SUITE(b2dvector);
|
|
CPPUNIT_TEST(EmptyMethod);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
}; // class b2dvector
|
|
|
|
// -----------------------------------------------------------------------------
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dmultirange, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dsvgdimpex, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dbeziertools, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dcubicbezier, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dhommatrix, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dhompoint, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dpoint, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dpolygon, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dpolygontools, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dpolypolygon, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dquadraticbezier, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2drange, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dtuple, "basegfx2d");
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dvector, "basegfx2d");
|
|
} // namespace basegfx2d
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// this macro creates an empty function, which will called by the RegisterAllFunctions()
|
|
// to let the user the possibility to also register some functions by hand.
|
|
// NOADDITIONAL;
|
|
|