diff options
Diffstat (limited to 'basegfx/source/tools')
-rwxr-xr-x | basegfx/source/tools/canvastools.cxx | 674 | ||||
-rwxr-xr-x | basegfx/source/tools/debugplotter.cxx | 413 | ||||
-rw-r--r-- | basegfx/source/tools/gradienttools.cxx | 360 | ||||
-rw-r--r-- | basegfx/source/tools/liangbarsky.cxx | 132 | ||||
-rwxr-xr-x | basegfx/source/tools/makefile.mk | 49 | ||||
-rw-r--r-- | basegfx/source/tools/tools.cxx | 124 | ||||
-rwxr-xr-x | basegfx/source/tools/unopolypolygon.cxx | 486 |
7 files changed, 2238 insertions, 0 deletions
diff --git a/basegfx/source/tools/canvastools.cxx b/basegfx/source/tools/canvastools.cxx new file mode 100755 index 000000000000..2192148461dc --- /dev/null +++ b/basegfx/source/tools/canvastools.cxx @@ -0,0 +1,674 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basegfx.hxx" + +#include <com/sun/star/geometry/RealSize2D.hpp> +#include <com/sun/star/geometry/RealPoint2D.hpp> +#include <com/sun/star/geometry/RealRectangle2D.hpp> +#include <com/sun/star/geometry/RealRectangle3D.hpp> +#include <com/sun/star/geometry/RealBezierSegment2D.hpp> +#include <com/sun/star/geometry/AffineMatrix2D.hpp> +#include <com/sun/star/geometry/AffineMatrix3D.hpp> +#include <com/sun/star/geometry/Matrix2D.hpp> +#include <com/sun/star/geometry/IntegerSize2D.hpp> +#include <com/sun/star/geometry/IntegerPoint2D.hpp> +#include <com/sun/star/geometry/IntegerRectangle2D.hpp> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <basegfx/tools/unopolypolygon.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/range/b3drange.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <limits> + +using namespace ::com::sun::star; + +namespace basegfx +{ + + namespace unotools + { + namespace + { + uno::Sequence< geometry::RealBezierSegment2D > bezierSequenceFromB2DPolygon(const ::basegfx::B2DPolygon& rPoly) + { + const sal_uInt32 nPointCount(rPoly.count()); + uno::Sequence< geometry::RealBezierSegment2D > outputSequence(nPointCount); + geometry::RealBezierSegment2D* pOutput = outputSequence.getArray(); + + // fill sequences and imply clodes polygon on this implementation layer + for(sal_uInt32 a(0); a < nPointCount; a++) + { + const basegfx::B2DPoint aStart(rPoly.getB2DPoint(a)); + const basegfx::B2DPoint aControlA(rPoly.getNextControlPoint(a)); + const basegfx::B2DPoint aControlB(rPoly.getPrevControlPoint((a + 1) % nPointCount)); + + pOutput[a] = geometry::RealBezierSegment2D( + aStart.getX(), aStart.getY(), + aControlA.getX(), aControlA.getY(), + aControlB.getX(), aControlB.getY()); + } + + return outputSequence; + } + + uno::Sequence< geometry::RealPoint2D > pointSequenceFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly ) + { + const sal_uInt32 nNumPoints( rPoly.count() ); + + uno::Sequence< geometry::RealPoint2D > outputSequence( nNumPoints ); + geometry::RealPoint2D* pOutput = outputSequence.getArray(); + + // fill sequence from polygon + sal_uInt32 i; + for( i=0; i<nNumPoints; ++i ) + { + const ::basegfx::B2DPoint aPoint( rPoly.getB2DPoint(i) ); + + pOutput[i] = geometry::RealPoint2D( aPoint.getX(), + aPoint.getY() ); + } + + return outputSequence; + } + } + + //--------------------------------------------------------------------------------------- + + uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > > bezierSequenceSequenceFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly ) + { + const sal_uInt32 nNumPolies( rPolyPoly.count() ); + sal_uInt32 i; + + uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > > outputSequence( nNumPolies ); + uno::Sequence< geometry::RealBezierSegment2D >* pOutput = outputSequence.getArray(); + + for( i=0; i<nNumPolies; ++i ) + { + pOutput[i] = bezierSequenceFromB2DPolygon( rPolyPoly.getB2DPolygon(i) ); + } + + return outputSequence; + } + + //--------------------------------------------------------------------------------------- + + uno::Sequence< uno::Sequence< geometry::RealPoint2D > > pointSequenceSequenceFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly ) + { + const sal_uInt32 nNumPolies( rPolyPoly.count() ); + sal_uInt32 i; + + uno::Sequence< uno::Sequence< geometry::RealPoint2D > > outputSequence( nNumPolies ); + uno::Sequence< geometry::RealPoint2D >* pOutput = outputSequence.getArray(); + + for( i=0; i<nNumPolies; ++i ) + { + pOutput[i] = pointSequenceFromB2DPolygon( rPolyPoly.getB2DPolygon(i) ); + } + + return outputSequence; + } + + //--------------------------------------------------------------------------------------- + + uno::Reference< rendering::XPolyPolygon2D > xPolyPolygonFromB2DPolygon( const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice, + const ::basegfx::B2DPolygon& rPoly ) + { + uno::Reference< rendering::XPolyPolygon2D > xRes; + + if( !xGraphicDevice.is() ) + return xRes; + + if( rPoly.areControlPointsUsed() ) + { + uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > > outputSequence( 1 ); + outputSequence[0] = bezierSequenceFromB2DPolygon( rPoly ); + + xRes.set( xGraphicDevice->createCompatibleBezierPolyPolygon( outputSequence ), + uno::UNO_QUERY ); + } + else + { + uno::Sequence< uno::Sequence< geometry::RealPoint2D > > outputSequence( 1 ); + outputSequence[0] = pointSequenceFromB2DPolygon( rPoly ); + + xRes.set( xGraphicDevice->createCompatibleLinePolyPolygon( outputSequence ), + uno::UNO_QUERY ); + } + + if( xRes.is() && rPoly.isClosed() ) + xRes->setClosed( 0, sal_True ); + + return xRes; + } + + //--------------------------------------------------------------------------------------- + + uno::Reference< rendering::XPolyPolygon2D > xPolyPolygonFromB2DPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice, + const ::basegfx::B2DPolyPolygon& rPolyPoly ) + { + uno::Reference< rendering::XPolyPolygon2D > xRes; + + if( !xGraphicDevice.is() ) + return xRes; + + const sal_uInt32 nNumPolies( rPolyPoly.count() ); + sal_uInt32 i; + + if( rPolyPoly.areControlPointsUsed() ) + { + xRes.set( xGraphicDevice->createCompatibleBezierPolyPolygon( + bezierSequenceSequenceFromB2DPolyPolygon( rPolyPoly ) ), + uno::UNO_QUERY ); + } + else + { + xRes.set( xGraphicDevice->createCompatibleLinePolyPolygon( + pointSequenceSequenceFromB2DPolyPolygon( rPolyPoly ) ), + uno::UNO_QUERY ); + } + + for( i=0; i<nNumPolies; ++i ) + { + xRes->setClosed( i, rPolyPoly.getB2DPolygon(i).isClosed() ); + } + + return xRes; + } + + //--------------------------------------------------------------------------------------- + + ::basegfx::B2DPolygon polygonFromPoint2DSequence( const uno::Sequence< geometry::RealPoint2D >& points ) + { + const sal_Int32 nCurrSize( points.getLength() ); + + ::basegfx::B2DPolygon aPoly; + + for( sal_Int32 nCurrPoint=0; nCurrPoint<nCurrSize; ++nCurrPoint ) + aPoly.append( b2DPointFromRealPoint2D( points[nCurrPoint] ) ); + + return aPoly; + } + + //--------------------------------------------------------------------------------------- + + ::basegfx::B2DPolyPolygon polyPolygonFromPoint2DSequenceSequence( const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) + { + ::basegfx::B2DPolyPolygon aRes; + + for( sal_Int32 nCurrPoly=0; nCurrPoly<points.getLength(); ++nCurrPoly ) + { + aRes.append( polygonFromPoint2DSequence( points[nCurrPoly] ) ); + } + + return aRes; + } + + //--------------------------------------------------------------------------------------- + + ::basegfx::B2DPolygon polygonFromBezier2DSequence( const uno::Sequence< geometry::RealBezierSegment2D >& curves ) + { + const sal_Int32 nSize(curves.getLength()); + basegfx::B2DPolygon aRetval; + + if(nSize) + { + // prepare start with providing a start point. Use the first point from + // the sequence for this + const geometry::RealBezierSegment2D& rFirstSegment(curves[0]); // #i79917# first segment, not last + aRetval.append(basegfx::B2DPoint(rFirstSegment.Px, rFirstSegment.Py)); + + for(sal_Int32 a(0); a < nSize; a++) + { + const geometry::RealBezierSegment2D& rCurrSegment(curves[a]); + const geometry::RealBezierSegment2D& rNextSegment(curves[(a + 1) % nSize]); + + // append curved edge with the control points and the next point + aRetval.appendBezierSegment( + basegfx::B2DPoint(rCurrSegment.C1x, rCurrSegment.C1y), + basegfx::B2DPoint(rCurrSegment.C2x, rCurrSegment.C2y), // #i79917# Argh! An x for an y!! + basegfx::B2DPoint(rNextSegment.Px, rNextSegment.Py)); + } + + // rescue the control point and remove the now double-added point + aRetval.setPrevControlPoint(0, aRetval.getPrevControlPoint(aRetval.count() - 1)); + aRetval.remove(aRetval.count() - 1); + } + + return aRetval; + } + + //--------------------------------------------------------------------------------------- + + ::basegfx::B2DPolyPolygon polyPolygonFromBezier2DSequenceSequence( const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& curves ) + { + ::basegfx::B2DPolyPolygon aRes; + + for( sal_Int32 nCurrPoly=0; nCurrPoly<curves.getLength(); ++nCurrPoly ) + { + aRes.append( polygonFromBezier2DSequence( curves[nCurrPoly] ) ); + } + + return aRes; + } + + //--------------------------------------------------------------------------------------- + + ::basegfx::B2DPolyPolygon b2DPolyPolygonFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly ) + { + ::basegfx::unotools::UnoPolyPolygon* pPolyImpl = + dynamic_cast< ::basegfx::unotools::UnoPolyPolygon* >( xPoly.get() ); + + if( pPolyImpl ) + { + return pPolyImpl->getPolyPolygon(); + } + else + { + // not a known implementation object - try data source + // interfaces + const sal_Int32 nPolys( xPoly->getNumberOfPolygons() ); + + uno::Reference< rendering::XBezierPolyPolygon2D > xBezierPoly( + xPoly, + uno::UNO_QUERY ); + + if( xBezierPoly.is() ) + { + return ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( + xBezierPoly->getBezierSegments( 0, + nPolys, + 0, + -1 ) ); + } + else + { + uno::Reference< rendering::XLinePolyPolygon2D > xLinePoly( + xPoly, + uno::UNO_QUERY ); + + // no implementation class and no data provider + // found - contract violation. + if( !xLinePoly.is() ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii( + "basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(): Invalid input" + "poly-polygon, cannot retrieve vertex data"), + uno::Reference< uno::XInterface >(), + 0 ); + } + + return ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( + xLinePoly->getPoints( 0, + nPolys, + 0, + -1 )); + } + } + } + + //--------------------------------------------------------------------------------------- + + ::basegfx::B2DHomMatrix& homMatrixFromAffineMatrix( ::basegfx::B2DHomMatrix& output, + const geometry::AffineMatrix2D& input ) + { + // ensure last row is [0,0,1] (and optimized away) + output.identity(); + + output.set(0,0, input.m00); + output.set(0,1, input.m01); + output.set(0,2, input.m02); + output.set(1,0, input.m10); + output.set(1,1, input.m11); + output.set(1,2, input.m12); + + return output; + } + + ::basegfx::B2DHomMatrix homMatrixFromAffineMatrix( const geometry::AffineMatrix2D& input ) + { + ::basegfx::B2DHomMatrix output; + + output.set(0,0, input.m00); + output.set(0,1, input.m01); + output.set(0,2, input.m02); + output.set(1,0, input.m10); + output.set(1,1, input.m11); + output.set(1,2, input.m12); + + return output; + } + + ::basegfx::B3DHomMatrix homMatrixFromAffineMatrix3D( const ::com::sun::star::geometry::AffineMatrix3D& input ) + { + ::basegfx::B3DHomMatrix output; + + output.set(0,0, input.m00); + output.set(0,1, input.m01); + output.set(0,2, input.m02); + output.set(0,3, input.m03); + + output.set(1,0, input.m10); + output.set(1,1, input.m11); + output.set(1,2, input.m12); + output.set(1,3, input.m13); + + output.set(2,0, input.m20); + output.set(2,1, input.m21); + output.set(2,2, input.m22); + output.set(2,3, input.m23); + + return output; + } + + geometry::AffineMatrix2D& affineMatrixFromHomMatrix( geometry::AffineMatrix2D& output, + const ::basegfx::B2DHomMatrix& input) + { + output.m00 = input.get(0,0); + output.m01 = input.get(0,1); + output.m02 = input.get(0,2); + output.m10 = input.get(1,0); + output.m11 = input.get(1,1); + output.m12 = input.get(1,2); + + return output; + } + + geometry::AffineMatrix3D& affineMatrixFromHomMatrix3D( + geometry::AffineMatrix3D& output, + const ::basegfx::B3DHomMatrix& input) + { + output.m00 = input.get(0,0); + output.m01 = input.get(0,1); + output.m02 = input.get(0,2); + output.m03 = input.get(0,3); + + output.m10 = input.get(1,0); + output.m11 = input.get(1,1); + output.m12 = input.get(1,2); + output.m13 = input.get(1,3); + + output.m20 = input.get(2,0); + output.m21 = input.get(2,1); + output.m22 = input.get(2,2); + output.m23 = input.get(2,3); + + return output; + } + + //--------------------------------------------------------------------------------------- + + ::basegfx::B2DHomMatrix& homMatrixFromMatrix( ::basegfx::B2DHomMatrix& output, + const geometry::Matrix2D& input ) + { + // ensure last row is [0,0,1] (and optimized away) + output.identity(); + + output.set(0,0, input.m00); + output.set(0,1, input.m01); + output.set(1,0, input.m10); + output.set(1,1, input.m11); + + return output; + } + + //--------------------------------------------------------------------------------------- + + geometry::RealSize2D size2DFromB2DSize( const ::basegfx::B2DVector& rVec ) + { + return geometry::RealSize2D( rVec.getX(), + rVec.getY() ); + } + + geometry::RealPoint2D point2DFromB2DPoint( const ::basegfx::B2DPoint& rPoint ) + { + return geometry::RealPoint2D( rPoint.getX(), + rPoint.getY() ); + } + + geometry::RealRectangle2D rectangle2DFromB2DRectangle( const ::basegfx::B2DRange& rRect ) + { + return geometry::RealRectangle2D( rRect.getMinX(), + rRect.getMinY(), + rRect.getMaxX(), + rRect.getMaxY() ); + } + + geometry::RealRectangle3D rectangle3DFromB3DRectangle( const ::basegfx::B3DRange& rRect ) + { + return geometry::RealRectangle3D( rRect.getMinX(), + rRect.getMinY(), + rRect.getMinZ(), + rRect.getMaxX(), + rRect.getMaxY(), + rRect.getMaxZ()); + } + + ::basegfx::B2DVector b2DSizeFromRealSize2D( const geometry::RealSize2D& rSize ) + { + return ::basegfx::B2DVector( rSize.Width, + rSize.Height ); + } + + ::basegfx::B2DPoint b2DPointFromRealPoint2D( const geometry::RealPoint2D& rPoint ) + { + return ::basegfx::B2DPoint( rPoint.X, + rPoint.Y ); + } + + ::basegfx::B2DRange b2DRectangleFromRealRectangle2D( const geometry::RealRectangle2D& rRect ) + { + return ::basegfx::B2DRange( rRect.X1, + rRect.Y1, + rRect.X2, + rRect.Y2 ); + } + + ::basegfx::B3DRange b3DRectangleFromRealRectangle3D( const geometry::RealRectangle3D& rRect ) + { + return ::basegfx::B3DRange( rRect.X1, + rRect.Y1, + rRect.Z1, + rRect.X2, + rRect.Y2, + rRect.Z2); + } + + geometry::IntegerSize2D integerSize2DFromB2ISize( const ::basegfx::B2IVector& rSize ) + { + return geometry::IntegerSize2D( rSize.getX(), + rSize.getY() ); + } + + geometry::IntegerPoint2D integerPoint2DFromB2IPoint( const ::basegfx::B2IPoint& rPoint ) + { + return geometry::IntegerPoint2D( rPoint.getX(), + rPoint.getY() ); + } + + geometry::IntegerRectangle2D integerRectangle2DFromB2IRectangle( const ::basegfx::B2IRange& rRectangle ) + { + return geometry::IntegerRectangle2D( rRectangle.getMinX(), rRectangle.getMinY(), + rRectangle.getMaxX(), rRectangle.getMaxY() ); + } + + ::basegfx::B2IVector b2ISizeFromIntegerSize2D( const geometry::IntegerSize2D& rSize ) + { + return ::basegfx::B2IVector( rSize.Width, + rSize.Height ); + } + + ::basegfx::B2IPoint b2IPointFromIntegerPoint2D( const geometry::IntegerPoint2D& rPoint ) + { + return ::basegfx::B2IPoint( rPoint.X, + rPoint.Y ); + } + + ::basegfx::B2IRange b2IRectangleFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRectangle ) + { + return ::basegfx::B2IRange( rRectangle.X1, rRectangle.Y1, + rRectangle.X2, rRectangle.Y2 ); + } + + awt::Size awtSizeFromB2ISize( const ::basegfx::B2IVector& rVec ) + { + return awt::Size( rVec.getX(), + rVec.getY() ); + } + + awt::Point awtPointFromB2IPoint( const ::basegfx::B2IPoint& rPoint ) + { + return awt::Point( rPoint.getX(), + rPoint.getY() ); + } + + awt::Rectangle awtRectangleFromB2IRectangle( const ::basegfx::B2IRange& rRect ) + { + OSL_ENSURE( rRect.getWidth() < ::std::numeric_limits< sal_Int32 >::max() && + rRect.getWidth() > ::std::numeric_limits< sal_Int32 >::min(), + "awtRectangleFromB2IRectangle(): width overflow" ); + OSL_ENSURE( rRect.getHeight() < ::std::numeric_limits< sal_Int32 >::max() && + rRect.getHeight() > ::std::numeric_limits< sal_Int32 >::min(), + "awtRectangleFromB2IRectangle(): height overflow" ); + + return awt::Rectangle( rRect.getMinX(), + rRect.getMinY(), + static_cast< sal_Int32 >(rRect.getWidth()), + static_cast< sal_Int32 >(rRect.getHeight()) ); + } + + ::basegfx::B2IVector b2ISizeFromAwtSize( const awt::Size& rSize ) + { + return ::basegfx::B2IVector( rSize.Width, + rSize.Height ); + } + + ::basegfx::B2IPoint b2IPointFromAwtPoint( const awt::Point& rPoint ) + { + return ::basegfx::B2IPoint( rPoint.X, + rPoint.Y ); + } + + ::basegfx::B2IRange b2IRectangleFromAwtRectangle( const awt::Rectangle& rRect ) + { + return ::basegfx::B2IRange( rRect.X, + rRect.Y, + rRect.X + rRect.Width, + rRect.Y + rRect.Height ); + } + + ::basegfx::B2IRange b2ISurroundingRangeFromB2DRange( const ::basegfx::B2DRange& rRange ) + { + return ::basegfx::B2IRange( static_cast<sal_Int32>( floor(rRange.getMinX()) ), + static_cast<sal_Int32>( floor(rRange.getMinY()) ), + static_cast<sal_Int32>( ceil(rRange.getMaxX()) ), + static_cast<sal_Int32>( ceil(rRange.getMaxY()) ) ); + } + + ::basegfx::B2DRange b2DSurroundingIntegerRangeFromB2DRange( const ::basegfx::B2DRange& rRange ) + { + return ::basegfx::B2DRange( floor(rRange.getMinX()), + floor(rRange.getMinY()), + ceil(rRange.getMaxX()), + ceil(rRange.getMaxY()) ); + } + + // Geometry comparisons + // =================================================================== + + bool RealSize2DAreEqual( const ::com::sun::star::geometry::RealSize2D& rA, const ::com::sun::star::geometry::RealSize2D& rB ) + { + return (rA.Width == rB.Width && rA.Height == rB.Height); + } + + bool RealPoint2DAreEqual( const ::com::sun::star::geometry::RealPoint2D& rA, const ::com::sun::star::geometry::RealPoint2D& rB ) + { + return (rA.X == rB.X && rA.Y == rB.Y); + } + + bool RealRectangle2DAreEqual( const ::com::sun::star::geometry::RealRectangle2D& rA, const ::com::sun::star::geometry::RealRectangle2D& rB ) + { + return (rA.X1 == rB.X1 && rA.Y1 == rB.Y1 && rA.X2 == rB.X2 && rA.Y2 == rB.Y2); + } + + bool RealRectangle3DAreEqual( const ::com::sun::star::geometry::RealRectangle3D& rA, const ::com::sun::star::geometry::RealRectangle3D& rB ) + { + return (rA.X1 == rB.X1 && rA.Y1 == rB.Y1 && rA.Z1 == rB.Z1 && rA.X2 == rB.X2 && rA.Y2 == rB.Y2 && rA.Z2 == rB.Z2); + } + + bool AffineMatrix2DAreEqual( const ::com::sun::star::geometry::AffineMatrix2D& rA, const ::com::sun::star::geometry::AffineMatrix2D& rB ) + { + return (rA.m00 == rB.m00 && rA.m01 == rB.m01 && rA.m02 == rB.m02 && rA.m10 == rB.m10 && rA.m11 == rB.m11 && rA.m12 == rB.m12); + } + + bool IntegerSize2DAreEqual( const ::com::sun::star::geometry::IntegerSize2D& rA, const ::com::sun::star::geometry::IntegerSize2D& rB ) + { + return (rA.Width == rB.Width && rA.Height == rB.Height); + } + + bool IntegerPoint2DAreEqual( const ::com::sun::star::geometry::IntegerPoint2D& rA, const ::com::sun::star::geometry::IntegerPoint2D& rB ) + { + return (rA.X == rB.X && rA.Y == rB.Y); + } + + bool IntegerRectangle2DAreEqual( const ::com::sun::star::geometry::IntegerRectangle2D& rA, const ::com::sun::star::geometry::IntegerRectangle2D& rB ) + { + return (rA.X1 == rB.X1 && rA.Y1 == rB.Y1 && rA.X2 == rB.X2 && rA.Y2 == rB.Y2); + } + + bool awtSizeAreEqual( const ::com::sun::star::awt::Size& rA, const ::com::sun::star::awt::Size& rB ) + { + return (rA.Width == rB.Width && rA.Height == rB.Height); + } + + bool awtPointAreEqual( const ::com::sun::star::awt::Point& rA, const ::com::sun::star::awt::Point& rB ) + { + return (rA.X == rB.X && rA.Y == rB.Y); + } + + bool awtRectangleAreEqual( const ::com::sun::star::awt::Rectangle& rA, const ::com::sun::star::awt::Rectangle& rB ) + { + return (rA.X == rB.X && rA.Y == rB.Y && rA.Width == rB.Width && rA.Height == rB.Height); + } + } // namespace bgfxtools + +} // namespace canvas diff --git a/basegfx/source/tools/debugplotter.cxx b/basegfx/source/tools/debugplotter.cxx new file mode 100755 index 000000000000..2c68eb44a846 --- /dev/null +++ b/basegfx/source/tools/debugplotter.cxx @@ -0,0 +1,413 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basegfx.hxx" +#include <osl/diagnose.h> + +#include <basegfx/curve/b2dcubicbezier.hxx> + +#include <basegfx/tools/debugplotter.hxx> +#include <boost/bind.hpp> + + +namespace basegfx +{ + namespace + { + void outputHeader( const ::rtl::OString& rTitle, + ::std::ostream* pStm ) + { + // output gnuplot setup + if( pStm ) + { + *pStm << "#!/usr/bin/gnuplot -persist" << ::std::endl << + "#" << ::std::endl << + "# automatically generated by basegfx, don't change!" << ::std::endl << + "#" << ::std::endl << + "# --- " << (const sal_Char*)rTitle << " ---" << ::std::endl << + "#" << ::std::endl << + "set parametric" << ::std::endl << + "# set terminal postscript eps enhanced color " << ::std::endl << + "# set output \"plot.eps\"" << ::std::endl << + // This function plots a cubic bezier curve. P,q,r,s + // are the control point elements of the corresponding + // output coordinate component (i.e. x components for + // the x plot, and y components for the y plot) + "cubicBezier(p,q,r,s,t) = p*(1-t)**3+q*3*(1-t)**2*t+r*3*(1-t)*t**2+s*t**3" << ::std::endl << + // This function plots the derivative of a cubic + // bezier curve. P,q,r,s are the control point + // components of the _original_ curve + "cubicBezDerivative(p,q,r,s,t) = 3*(q-p)*(1-t)**2+6*(r-q)*(1-t)*t+3*(s-r)*t**2" << ::std::endl << + // Plot a line's component of a line between a and b + // (where a and b should be the corresponding + // components of the line's start and end point, + // respectively) + "line(p,q,r) = p*(1-t)+q*t" << ::std::endl << + // Plot a line's x component of a line in implicit + // form ax + by + c = 0 + "implicitLineX(a,b,c,t) = a*-c + t*-b" << ::std::endl << + // Plot a line's y component of a line in implicit + // form ax + by + c = 0 + "implicitLineY(a,b,c,t) = b*-c + t*a" << ::std::endl << + "pointmarkx(c,t) = c-0.03*t" << ::std::endl << // hack for displaying single points in parametric form + "pointmarky(c,t) = c+0.03*t" << ::std::endl << // hack for displaying single points in parametric form + "# end of setup" << ::std::endl; + } + else + { + OSL_TRACE( "#!/usr/bin/gnuplot -persist\n", + "#\n", + "# automatically generated by basegfx, don't change!\n", + "#\n", + "# --- %s ---\n", + "#\n", + "set parametric\n", + // This function plots a cubic bezier curve. P,q,r,s + // are the control point elements of the corresponding + // output coordinate component (i.e. x components for + // the x plot, and y components for the y plot) + "cubicBezier(p,q,r,s,t) = p*(1-t)**3+q*3*(1-t)**2*t+r*3*(1-t)*t**2+s*t**3\n", + // This function plots the derivative of a cubic + // bezier curve. P,q,r,s are the control point + // components of the _original_ curve + "cubicBezDerivative(p,q,r,s,t) = 3*(q-p)*(1-t)**2+6*(r-q)*(1-t)*t+3*(s-r)*t**2\n", + // Plot a line's component of a line between a and b + // (where a and b should be the corresponding + // components of the line's start and end point, + // respectively) + "line(p,q,r) = p*(1-t)+q*t\n", + // Plot a line's x component of a line in implicit + // form ax + by + c = 0 + "implicitLineX(a,b,c,t) = a*-c + t*-b\n", + // Plot a line's y component of a line in implicit + // form ax + by + c = 0 + "implicitLineY(a,b,c,t) = b*-c + t*a\n", + "pointmarkx(c,t) = c-0.03*t\n", // hack for displaying single points in parametric form + "pointmarky(c,t) = c+0.03*t\n", // hack for displaying single points in parametric form + "# end of setup\n", + (const sal_Char*)rTitle ); + } + } + + class Writer + { + public: + Writer( ::std::ostream* pStm ) : + mpStream( pStm ) + { + } + + void outputPoint( const ::std::pair< B2DPoint, ::rtl::OString >& rElem ) + { + if( mpStream ) + *mpStream << " " << rElem.first.getX() << "\t" << rElem.first.getY() << ::std::endl; + else + OSL_TRACE( " %f\t%f\n", rElem.first.getX(), rElem.first.getY() ); + } + + void outputVector( const ::std::pair< B2DVector, ::rtl::OString >& rElem ) + { + if( mpStream ) + *mpStream << " " << rElem.first.getX() << "\t" << rElem.first.getY() << ::std::endl << ::std::endl; + else + OSL_TRACE( " %f\t%f\n\n", rElem.first.getX(), rElem.first.getY() ); + } + + void outputRect( const ::std::pair< B2DRange, ::rtl::OString >& rElem ) + { + const double nX0( rElem.first.getMinX() ); + const double nY0( rElem.first.getMinY() ); + const double nX1( rElem.first.getMaxX() ); + const double nY1( rElem.first.getMaxY() ); + + if( mpStream ) + *mpStream << " " + << nX0 << "\t" << nY0 << "\t" + << nX1 << "\t" << nY0 << "\t" + << nX1 << "\t" << nY1 << "\t" + << nX0 << "\t" << nY1 << "\t" + << nX0 << "\t" << nY0 << ::std::endl << ::std::endl; + + else + OSL_TRACE( " %f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n\n", + nX0, nY0, + nX1, nY0, + nX1, nY1, + nX0, nY1, + nX0, nY0 ); + } + + private: + ::std::ostream* mpStream; + }; + } + + DebugPlotter::DebugPlotter( const sal_Char* pTitle ) : + maTitle( pTitle ), + maPoints(), + maVectors(), + maRanges(), + maPolygons(), + mpOutputStream(NULL) + { + } + + DebugPlotter::DebugPlotter( const sal_Char* pTitle, + ::std::ostream& rOutputStream ) : + maTitle( pTitle ), + maPoints(), + maVectors(), + maRanges(), + maPolygons(), + mpOutputStream(&rOutputStream) + { + } + + DebugPlotter::~DebugPlotter() + { + const bool bHavePoints( !maPoints.empty() ); + const bool bHaveVectors( !maVectors.empty() ); + const bool bHaveRanges( !maRanges.empty() ); + const bool bHavePolygons( !maPolygons.empty() ); + + if( bHavePoints || + bHaveVectors || + bHaveRanges || + bHavePolygons ) + { + outputHeader( maTitle, mpOutputStream ); + + print( "\n\n# parametric primitive output\n" + "plot [t=0:1] \\\n" ); + + // output plot declarations for used entities + bool bNeedColon( false ); + if( bHavePoints ) + { + print( " '-' using ($1):($2) title \"Points\" with points" ); + bNeedColon = true; + } + if( bHaveVectors ) + { + if( bNeedColon ) + print( ", \\\n" ); + + print( " '-' using ($1):($2) title \"Vectors\" with lp" ); + bNeedColon = true; + } + if( bHaveRanges ) + { + if( bNeedColon ) + print( ", \\\n" ); + + print( " '-' using ($1):($2) title \"Ranges\" with lines" ); + bNeedColon = true; + } + if( bHavePolygons ) + { + const ::std::size_t nSize( maPolygons.size() ); + for( ::std::size_t i=0; i<nSize; ++i ) + { + if( maPolygons.at(i).first.areControlPointsUsed() ) + { + const B2DPolygon& rCurrPoly( maPolygons.at(i).first ); + + const sal_uInt32 nCount( rCurrPoly.count() ); + for( sal_uInt32 k=0; k<nCount; ++k ) + { + if( bNeedColon ) + print( ", \\\n" ); + + const B2DPoint& rP0( rCurrPoly.getB2DPoint(k) ); + const B2DPoint& rP1( rCurrPoly.getNextControlPoint(k) ); + const B2DPoint& rP2( rCurrPoly.getPrevControlPoint((k + 1) % nCount) ); + const B2DPoint& rP3( k+1<nCount ? rCurrPoly.getB2DPoint(k+1) : rCurrPoly.getB2DPoint(k) ); + + if( mpOutputStream ) + *mpOutputStream << " cubicBezier(" + << rP0.getX() << "," + << rP1.getX() << "," + << rP2.getX() << "," + << rP3.getX() << ",t), \\\n cubicBezier(" + << rP0.getY() << "," + << rP1.getY() << "," + << rP2.getY() << "," + << rP3.getY() << ",t)"; + else + OSL_TRACE( " cubicBezier(%f,%f,%f,%f,t), \\\n" + " cubicBezier(%f,%f,%f,%f,t)", + rP0.getX(), + rP1.getX(), + rP2.getX(), + rP3.getX(), + rP0.getY(), + rP1.getY(), + rP2.getY(), + rP3.getY() ); + + bNeedColon = true; + } + } + else + { + if( bNeedColon ) + print( ", \\\n" ); + + if( mpOutputStream ) + *mpOutputStream << " '-' using ($1):($2) title \"Polygon " + << (const sal_Char*)maPolygons.at(i).second << "\" with lp"; + else + OSL_TRACE( " '-' using ($1):($2) title \"Polygon %s\" with lp", + (const sal_Char*)maPolygons.at(i).second ); + + bNeedColon = true; + } + } + } + + if( bHavePoints ) + { + Writer aWriter( mpOutputStream ); + + ::std::for_each( maPoints.begin(), + maPoints.end(), + ::boost::bind( &Writer::outputPoint, + ::boost::ref( aWriter ), + _1 ) ); + print( "e\n" ); + } + + if( bHaveVectors ) + { + Writer aWriter( mpOutputStream ); + + ::std::for_each( maVectors.begin(), + maVectors.end(), + ::boost::bind( &Writer::outputVector, + ::boost::ref( aWriter ), + _1 ) ); + print( "e\n" ); + } + + if( bHaveRanges ) + { + Writer aWriter( mpOutputStream ); + + ::std::for_each( maRanges.begin(), + maRanges.end(), + ::boost::bind( &Writer::outputRect, + ::boost::ref( aWriter ), + _1 ) ); + print( "e\n" ); + } + + if( bHavePolygons ) + { + const ::std::size_t nSize( maPolygons.size() ); + for( ::std::size_t i=0; i<nSize; ++i ) + { + if( !maPolygons.at(i).first.areControlPointsUsed() ) + { + const B2DPolygon& rCurrPoly( maPolygons.at(i).first ); + + const sal_uInt32 nCount( rCurrPoly.count() ); + for( sal_uInt32 k=0; k<nCount; ++k ) + { + const B2DPoint& rP( rCurrPoly.getB2DPoint(k) ); + + if( mpOutputStream ) + *mpOutputStream << " " << rP.getX() << "," << rP.getY(); + else + OSL_TRACE( " %f,%f", + rP.getX(), + rP.getX() ); + } + + print( "\ne\n" ); + } + } + } + } + } + + void DebugPlotter::plot( const B2DPoint& rPoint, + const sal_Char* pTitle ) + { + maPoints.push_back( ::std::make_pair( rPoint, + ::rtl::OString( pTitle ) ) ); + } + + void DebugPlotter::plot( const B2DVector& rVec, + const sal_Char* pTitle ) + { + maVectors.push_back( ::std::make_pair( rVec, + ::rtl::OString( pTitle ) ) ); + } + + void DebugPlotter::plot( const B2DCubicBezier& rBezier, + const sal_Char* pTitle ) + { + B2DPolygon aPoly; + aPoly.append(rBezier.getStartPoint()); + aPoly.appendBezierSegment(rBezier.getControlPointA(), rBezier.getControlPointB(), rBezier.getEndPoint()); + maPolygons.push_back( ::std::make_pair( aPoly, + ::rtl::OString( pTitle ) ) ); + } + + void DebugPlotter::plot( const B2DRange& rRange, + const sal_Char* pTitle ) + { + maRanges.push_back( ::std::make_pair( rRange, + ::rtl::OString( pTitle ) ) ); + } + + void DebugPlotter::plot( const B2DPolygon& rPoly, + const sal_Char* pTitle ) + { + maPolygons.push_back( ::std::make_pair( rPoly, + ::rtl::OString( pTitle ) ) ); + } + + void DebugPlotter::plot( const B2DPolyPolygon& rPoly, + const sal_Char* pTitle ) + { + const ::rtl::OString aTitle( pTitle ); + const sal_uInt32 nCount( rPoly.count() ); + for( sal_uInt32 i=0; i<nCount; ++i ) + maPolygons.push_back( ::std::make_pair( rPoly.getB2DPolygon( i ), + aTitle ) ); + } + + void DebugPlotter::print( const sal_Char* pStr ) + { + if( mpOutputStream ) + *mpOutputStream << pStr; + else + OSL_TRACE( pStr ); + } +} diff --git a/basegfx/source/tools/gradienttools.cxx b/basegfx/source/tools/gradienttools.cxx new file mode 100644 index 000000000000..89293cfcb61c --- /dev/null +++ b/basegfx/source/tools/gradienttools.cxx @@ -0,0 +1,360 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basegfx.hxx" + +#include <basegfx/tools/gradienttools.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +namespace basegfx +{ + /** Most of the setup for linear & axial gradient is the same, except + for the border treatment. Factored out here. + */ + static void init1DGradientInfo(ODFGradientInfo& o_rGradientInfo, + const B2DRange& rTargetRange, + sal_uInt32 nSteps, + double fBorder, + double fAngle, + bool bAxial) + { + o_rGradientInfo.maTextureTransform.identity(); + o_rGradientInfo.maBackTextureTransform.identity(); + o_rGradientInfo.mnSteps = nSteps; + + double fTargetSizeX(rTargetRange.getWidth()); + double fTargetSizeY(rTargetRange.getHeight()); + double fTargetOffsetX(rTargetRange.getMinX()); + double fTargetOffsetY(rTargetRange.getMinY()); + + // add object expansion + if(0.0 != fAngle) + { + const double fAbsCos(fabs(cos(fAngle))); + const double fAbsSin(fabs(sin(fAngle))); + const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin); + const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin); + fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0; + fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0; + fTargetSizeX = fNewX; + fTargetSizeY = fNewY; + } + + // add object scale before rotate + o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY); + + // add texture rotate after scale to keep perpendicular angles + if(0.0 != fAngle) + { + B2DPoint aCenter(0.5, 0.5); + aCenter *= o_rGradientInfo.maTextureTransform; + + o_rGradientInfo.maTextureTransform = basegfx::tools::createRotateAroundPoint(aCenter, fAngle) + * o_rGradientInfo.maTextureTransform; + } + + // add object translate + o_rGradientInfo.maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY); + + // prepare aspect for texture + o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0; + + // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform + o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform; + o_rGradientInfo.maBackTextureTransform.invert(); + + double fSizeWithoutBorder=0; + if( bAxial ) + { + fSizeWithoutBorder = (1.0 - fBorder) * 0.5; + o_rGradientInfo.maBackTextureTransform.translate(0.0, -0.5); + } + else + { + fSizeWithoutBorder = 1.0 - fBorder; + o_rGradientInfo.maBackTextureTransform.translate(0.0, -fBorder); + } + + if(!fTools::equal(fSizeWithoutBorder, 0.0)) + o_rGradientInfo.maBackTextureTransform.scale(1.0, 1.0 / fSizeWithoutBorder); + } + + /** Most of the setup for radial & ellipsoidal gradient is the same, + except for the border treatment. Factored out here. + */ + static void initEllipticalGradientInfo(ODFGradientInfo& o_rGradientInfo, + const B2DRange& rTargetRange, + const B2DVector& rOffset, + sal_uInt32 nSteps, + double fBorder, + double fAngle, + bool bCircular) + { + o_rGradientInfo.maTextureTransform.identity(); + o_rGradientInfo.maBackTextureTransform.identity(); + o_rGradientInfo.mnSteps = nSteps; + + double fTargetSizeX(rTargetRange.getWidth()); + double fTargetSizeY(rTargetRange.getHeight()); + double fTargetOffsetX(rTargetRange.getMinX()); + double fTargetOffsetY(rTargetRange.getMinY()); + + // add object expansion + if( bCircular ) + { + const double fOriginalDiag(sqrt((fTargetSizeX * fTargetSizeX) + (fTargetSizeY * fTargetSizeY))); + fTargetOffsetX -= (fOriginalDiag - fTargetSizeX) / 2.0; + fTargetOffsetY -= (fOriginalDiag - fTargetSizeY) / 2.0; + fTargetSizeX = fOriginalDiag; + fTargetSizeY = fOriginalDiag; + } + else + { + fTargetOffsetX -= (0.4142 / 2.0 ) * fTargetSizeX; + fTargetOffsetY -= (0.4142 / 2.0 ) * fTargetSizeY; + fTargetSizeX = 1.4142 * fTargetSizeX; + fTargetSizeY = 1.4142 * fTargetSizeY; + } + + // add object scale before rotate + o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY); + + if( !bCircular ) + { + // add texture rotate after scale to keep perpendicular angles + if(0.0 != fAngle) + { + B2DPoint aCenter(0.5, 0.5); + aCenter *= o_rGradientInfo.maTextureTransform; + + o_rGradientInfo.maTextureTransform = basegfx::tools::createRotateAroundPoint(aCenter, fAngle) + * o_rGradientInfo.maTextureTransform; + } + } + + // add defined offsets after rotation + if(0.5 != rOffset.getX() || 0.5 != rOffset.getY()) + { + // use original target size + fTargetOffsetX += (rOffset.getX() - 0.5) * rTargetRange.getWidth(); + fTargetOffsetY += (rOffset.getY() - 0.5) * rTargetRange.getHeight(); + } + + // add object translate + o_rGradientInfo.maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY); + + // prepare aspect for texture + o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0; + + // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform + o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform; + o_rGradientInfo.maBackTextureTransform.invert(); + o_rGradientInfo.maBackTextureTransform.translate(-0.5, -0.5); + const double fHalfBorder((1.0 - fBorder) * 0.5); + + if(!fTools::equal(fHalfBorder, 0.0)) + { + const double fFactor(1.0 / fHalfBorder); + o_rGradientInfo.maBackTextureTransform.scale(fFactor, fFactor); + } + } + + /** Setup for rect & square gradient is exactly the same. Factored out + here. + */ + static void initRectGradientInfo(ODFGradientInfo& o_rGradientInfo, + const B2DRange& rTargetRange, + const B2DVector& rOffset, + sal_uInt32 nSteps, + double fBorder, + double fAngle) + { + o_rGradientInfo.maTextureTransform.identity(); + o_rGradientInfo.maBackTextureTransform.identity(); + o_rGradientInfo.mnSteps = nSteps; + + double fTargetSizeX(rTargetRange.getWidth()); + double fTargetSizeY(rTargetRange.getHeight()); + double fTargetOffsetX(rTargetRange.getMinX()); + double fTargetOffsetY(rTargetRange.getMinY()); + + // add object expansion + if(0.0 != fAngle) + { + const double fAbsCos(fabs(cos(fAngle))); + const double fAbsSin(fabs(sin(fAngle))); + const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin); + const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin); + fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0; + fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0; + fTargetSizeX = fNewX; + fTargetSizeY = fNewY; + } + + // add object scale before rotate + o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY); + + // add texture rotate after scale to keep perpendicular angles + if(0.0 != fAngle) + { + B2DPoint aCenter(0.5, 0.5); + aCenter *= o_rGradientInfo.maTextureTransform; + + o_rGradientInfo.maTextureTransform = basegfx::tools::createRotateAroundPoint(aCenter, fAngle) + * o_rGradientInfo.maTextureTransform; + } + + // add defined offsets after rotation + if(0.5 != rOffset.getX() || 0.5 != rOffset.getY()) + { + // use scaled target size + fTargetOffsetX += (rOffset.getX() - 0.5) * fTargetSizeX; + fTargetOffsetY += (rOffset.getY() - 0.5) * fTargetSizeY; + } + + // add object translate + o_rGradientInfo.maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY); + + // prepare aspect for texture + o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0; + + // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform + o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform; + o_rGradientInfo.maBackTextureTransform.invert(); + o_rGradientInfo.maBackTextureTransform.translate(-0.5, -0.5); + const double fHalfBorder((1.0 - fBorder) * 0.5); + + if(!fTools::equal(fHalfBorder, 0.0)) + { + const double fFactor(1.0 / fHalfBorder); + o_rGradientInfo.maBackTextureTransform.scale(fFactor, fFactor); + } + } + + namespace tools + { + ODFGradientInfo& createLinearODFGradientInfo(ODFGradientInfo& o_rGradientInfo, + const B2DRange& rTargetArea, + sal_uInt32 nSteps, + double fBorder, + double fAngle) + { + init1DGradientInfo(o_rGradientInfo, + rTargetArea, + nSteps, + fBorder, + fAngle, + false); + return o_rGradientInfo; + } + + ODFGradientInfo& createAxialODFGradientInfo(ODFGradientInfo& o_rGradientInfo, + const B2DRange& rTargetArea, + sal_uInt32 nSteps, + double fBorder, + double fAngle) + { + init1DGradientInfo(o_rGradientInfo, + rTargetArea, + nSteps, + fBorder, + fAngle, + true); + return o_rGradientInfo; + } + + ODFGradientInfo& createRadialODFGradientInfo(ODFGradientInfo& o_rGradientInfo, + const B2DRange& rTargetArea, + const B2DVector& rOffset, + sal_uInt32 nSteps, + double fBorder) + { + initEllipticalGradientInfo(o_rGradientInfo, + rTargetArea, + rOffset, + nSteps, + fBorder, + 0.0, + true); + return o_rGradientInfo; + } + + ODFGradientInfo& createEllipticalODFGradientInfo(ODFGradientInfo& o_rGradientInfo, + const B2DRange& rTargetArea, + const B2DVector& rOffset, + sal_uInt32 nSteps, + double fBorder, + double fAngle) + { + initEllipticalGradientInfo(o_rGradientInfo, + rTargetArea, + rOffset, + nSteps, + fBorder, + fAngle, + false); + return o_rGradientInfo; + } + + ODFGradientInfo& createSquareODFGradientInfo(ODFGradientInfo& o_rGradientInfo, + const B2DRange& rTargetArea, + const B2DVector& rOffset, + sal_uInt32 nSteps, + double fBorder, + double fAngle) + { + initRectGradientInfo(o_rGradientInfo, + rTargetArea, + rOffset, + nSteps, + fBorder, + fAngle); + return o_rGradientInfo; + } + + ODFGradientInfo& createRectangularODFGradientInfo(ODFGradientInfo& o_rGradientInfo, + const B2DRange& rTargetArea, + const B2DVector& rOffset, + sal_uInt32 nSteps, + double fBorder, + double fAngle) + { + initRectGradientInfo(o_rGradientInfo, + rTargetArea, + rOffset, + nSteps, + fBorder, + fAngle); + return o_rGradientInfo; + } + + } // namespace tools + +} // namespace basegfx diff --git a/basegfx/source/tools/liangbarsky.cxx b/basegfx/source/tools/liangbarsky.cxx new file mode 100644 index 000000000000..f07cea4a34d9 --- /dev/null +++ b/basegfx/source/tools/liangbarsky.cxx @@ -0,0 +1,132 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basegfx.hxx" + +#include "basegfx/tools/tools.hxx" +#include "basegfx/numeric/ftools.hxx" +#include "basegfx/range/b2drange.hxx" + + +namespace basegfx +{ + namespace tools + { + namespace + { + // see Foley/vanDam, pp. 122 for the Liang-Barsky line + // clipping algorithm + inline bool liangBarskyClipT( double nDenom, + double nNumerator, + double& io_rTE, + double& io_rTL ) + { + double t; + if( nDenom > 0 ) + { + t = nNumerator / nDenom; + if( t > io_rTL ) + return false; + else if( t > io_rTE ) + io_rTE = t; + } + else if( nDenom < 0 ) + { + t = nNumerator / nDenom; + if( t < io_rTE ) + return false; + else + io_rTL = t; + } + else if( nNumerator > 0 ) + { + return false; + } + + return true; + } + } + + // see Foley/vanDam, pp. 122 for the Liang-Barsky line + // clipping algorithm + bool liangBarskyClip2D( ::basegfx::B2DPoint& io_rStart, + ::basegfx::B2DPoint& io_rEnd, + const ::basegfx::B2DRange& rClipRect ) + { + const double nDX( io_rEnd.getX() - io_rStart.getX() ); + const double nDY( io_rEnd.getY() - io_rStart.getY() ); + + if( ::basegfx::fTools::equalZero( nDX ) && + ::basegfx::fTools::equalZero( nDY ) ) + { + return rClipRect.isInside( io_rStart ); + } + else + { + double nTE( 0.0 ); + double nTL( 1.0 ); + if( liangBarskyClipT(nDX, rClipRect.getMinX() - io_rStart.getX(), + nTE, nTL ) ) // inside wrt. left edge + { + if( liangBarskyClipT(-nDX, io_rStart.getX() - rClipRect.getMaxX(), + nTE, nTL ) ) // inside wrt. right edge + { + if( liangBarskyClipT(nDY, rClipRect.getMinY() - io_rStart.getY(), + nTE, nTL ) ) // inside wrt. bottom edge + { + if( liangBarskyClipT(-nDY, io_rStart.getY() - rClipRect.getMaxY(), + nTE, nTL ) ) // inside wrt. top edge + { + // compute actual intersection points, + // if nTL has changed + if( nTL < 1.0 ) + { + io_rEnd.setX( io_rStart.getX() + nTL*nDX ); + io_rEnd.setY( io_rStart.getY() + nTL*nDY ); + } + + // compute actual intersection points, + // if nTE has changed + if( nTE > 0.0 ) + { + io_rStart.setX( io_rStart.getX() + nTE*nDX ); + io_rStart.setY( io_rStart.getY() + nTE*nDY ); + } + + // line is (at least partially) visible + return true; + } + } + } + } + } + + return false; + } + } +} diff --git a/basegfx/source/tools/makefile.mk b/basegfx/source/tools/makefile.mk new file mode 100755 index 000000000000..c70b78be5d4b --- /dev/null +++ b/basegfx/source/tools/makefile.mk @@ -0,0 +1,49 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=basegfx +TARGET=tools + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk + +# --- Files ------------------------------------- + +SLOFILES= $(SLO)$/canvastools.obj \ + $(SLO)$/gradienttools.obj \ + $(SLO)$/debugplotter.obj \ + $(SLO)$/liangbarsky.obj \ + $(SLO)$/tools.obj \ + $(SLO)$/unopolypolygon.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk diff --git a/basegfx/source/tools/tools.cxx b/basegfx/source/tools/tools.cxx new file mode 100644 index 000000000000..d375f144169d --- /dev/null +++ b/basegfx/source/tools/tools.cxx @@ -0,0 +1,124 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basegfx.hxx" + +#include "basegfx/tools/tools.hxx" +#include "basegfx/range/b2drange.hxx" + +#include <algorithm> + + +namespace basegfx +{ + namespace tools + { + namespace + { + inline double distance( const double& nX, + const double& nY, + const ::basegfx::B2DVector& rNormal, + const double& nC ) + { + return nX*rNormal.getX() + nY*rNormal.getY() - nC; + } + + void moveLineOutsideRect( ::basegfx::B2DPoint& io_rStart, + ::basegfx::B2DPoint& io_rEnd, + const ::basegfx::B2DVector& rMoveDirection, + const ::basegfx::B2DRange& rFitTarget ) + { + // calc c for normal line form equation n x - c = 0 + const double nC( rMoveDirection.scalar( io_rStart ) ); + + // calc maximum orthogonal distance for all four bound + // rect corners to the line + const double nMaxDistance( ::std::max( + 0.0, + ::std::max( + distance(rFitTarget.getMinX(), + rFitTarget.getMinY(), + rMoveDirection, + nC), + ::std::max( + distance(rFitTarget.getMinX(), + rFitTarget.getMaxY(), + rMoveDirection, + nC), + ::std::max( + distance(rFitTarget.getMaxX(), + rFitTarget.getMinY(), + rMoveDirection, + nC), + distance(rFitTarget.getMaxX(), + rFitTarget.getMaxY(), + rMoveDirection, + nC) ) ) ) ) ); + + // now move line points, such that the bound rect + // points are all either 'on' or on the negative side + // of the half-plane + io_rStart += nMaxDistance*rMoveDirection; + io_rEnd += nMaxDistance*rMoveDirection; + } + } + + void infiniteLineFromParallelogram( ::basegfx::B2DPoint& io_rLeftTop, + ::basegfx::B2DPoint& io_rLeftBottom, + ::basegfx::B2DPoint& io_rRightTop, + ::basegfx::B2DPoint& io_rRightBottom, + const ::basegfx::B2DRange& rFitTarget ) + { + // For the top and bottom border line of the + // parallelogram, we determine the distance to all four + // corner points of the bound rect (tl, tr, bl, br). When + // using the unit normal form for lines (n x - c = 0), and + // choosing n to point 'outwards' the parallelogram, then + // all bound rect corner points having positive distance + // to the line lie outside the extended gradient rect, and + // thus, the corresponding border line must be moved the + // maximum distance outwards. + + // don't use the top and bottom border line direction, and + // calculate the normal from them. Instead, use the + // vertical lines (lt - lb or rt - rb), as they more + // faithfully represent the direction of the + // to-be-generated infinite line + ::basegfx::B2DVector aDirectionVertical( io_rLeftTop - io_rLeftBottom ); + aDirectionVertical.normalize(); + + const ::basegfx::B2DVector aNormalTop( aDirectionVertical ); + const ::basegfx::B2DVector aNormalBottom( -aDirectionVertical ); + + // now extend parallelogram, such that the bound rect + // point are included + moveLineOutsideRect( io_rLeftTop, io_rRightTop, aNormalTop, rFitTarget ); + moveLineOutsideRect( io_rLeftBottom, io_rRightBottom, aNormalBottom, rFitTarget ); + } + } +} diff --git a/basegfx/source/tools/unopolypolygon.cxx b/basegfx/source/tools/unopolypolygon.cxx new file mode 100755 index 000000000000..871fed7c7d18 --- /dev/null +++ b/basegfx/source/tools/unopolypolygon.cxx @@ -0,0 +1,486 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basegfx.hxx" + +#include <com/sun/star/geometry/AffineMatrix2D.hpp> +#include <com/sun/star/rendering/RenderState.hpp> +#include <com/sun/star/rendering/ViewState.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/CompositeOperation.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/tools/unopolypolygon.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + + +using namespace ::com::sun::star; + +namespace basegfx +{ +namespace unotools +{ + UnoPolyPolygon::UnoPolyPolygon( const B2DPolyPolygon& rPolyPoly ) : + UnoPolyPolygonBase( m_aMutex ), + maPolyPoly( rPolyPoly ), + meFillRule( rendering::FillRule_EVEN_ODD ) + { + // or else races will haunt us. + maPolyPoly.makeUnique(); + } + + void SAL_CALL UnoPolyPolygon::addPolyPolygon( + const geometry::RealPoint2D& position, + const uno::Reference< rendering::XPolyPolygon2D >& polyPolygon ) throw (lang::IllegalArgumentException,uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + modifying(); + + // TODO(F1): Correctly fulfill the UNO API + // specification. This will probably result in a vector of + // poly-polygons to be stored in this object. + + const sal_Int32 nPolys( polyPolygon->getNumberOfPolygons() ); + + if( !polyPolygon.is() || !nPolys ) + { + // invalid or empty polygon - nothing to do. + return; + } + + B2DPolyPolygon aSrcPoly; + const UnoPolyPolygon* pSrc( dynamic_cast< UnoPolyPolygon* >(polyPolygon.get()) ); + + // try to extract polygon data from interface. First, + // check whether it's the same implementation object, + // which we can tunnel then. + if( pSrc ) + { + aSrcPoly = pSrc->getPolyPolygon(); + } + else + { + // not a known implementation object - try data source + // interfaces + uno::Reference< rendering::XBezierPolyPolygon2D > xBezierPoly( + polyPolygon, + uno::UNO_QUERY ); + + if( xBezierPoly.is() ) + { + aSrcPoly = unotools::polyPolygonFromBezier2DSequenceSequence( + xBezierPoly->getBezierSegments( 0, + nPolys, + 0, + -1 ) ); + } + else + { + uno::Reference< rendering::XLinePolyPolygon2D > xLinePoly( + polyPolygon, + uno::UNO_QUERY ); + + // no implementation class and no data provider + // found - contract violation. + if( !xLinePoly.is() ) + throw lang::IllegalArgumentException( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "UnoPolyPolygon::addPolyPolygon(): Invalid input " + "poly-polygon, cannot retrieve vertex data")), + static_cast<cppu::OWeakObject*>(this), 1); + + aSrcPoly = unotools::polyPolygonFromPoint2DSequenceSequence( + xLinePoly->getPoints( 0, + nPolys, + 0, + -1 ) ); + } + } + + const B2DRange aBounds( tools::getRange( aSrcPoly ) ); + const B2DVector aOffset( unotools::b2DPointFromRealPoint2D( position ) - + aBounds.getMinimum() ); + + if( !aOffset.equalZero() ) + { + const B2DHomMatrix aTranslate(tools::createTranslateB2DHomMatrix(aOffset)); + aSrcPoly.transform( aTranslate ); + } + + maPolyPoly.append( aSrcPoly ); + } + + sal_Int32 SAL_CALL UnoPolyPolygon::getNumberOfPolygons() throw (uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + return maPolyPoly.count(); + } + + sal_Int32 SAL_CALL UnoPolyPolygon::getNumberOfPolygonPoints( + sal_Int32 polygon ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + checkIndex( polygon ); + + return maPolyPoly.getB2DPolygon(polygon).count(); + } + + rendering::FillRule SAL_CALL UnoPolyPolygon::getFillRule() throw (uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + return meFillRule; + } + + void SAL_CALL UnoPolyPolygon::setFillRule( + rendering::FillRule fillRule ) throw (uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + modifying(); + + meFillRule = fillRule; + } + + sal_Bool SAL_CALL UnoPolyPolygon::isClosed( + sal_Int32 index ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + checkIndex( index ); + + return maPolyPoly.getB2DPolygon(index).isClosed(); + } + + void SAL_CALL UnoPolyPolygon::setClosed( + sal_Int32 index, + sal_Bool closedState ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + modifying(); + + if( index == -1L ) + { + // set all + maPolyPoly.setClosed( closedState ); + } + else + { + checkIndex( index ); + + // fetch referenced polygon, change state + B2DPolygon aTmp( maPolyPoly.getB2DPolygon(index) ); + aTmp.setClosed( closedState ); + + // set back to container + maPolyPoly.setB2DPolygon( index, aTmp ); + } + } + + uno::Sequence< uno::Sequence< geometry::RealPoint2D > > SAL_CALL UnoPolyPolygon::getPoints( + sal_Int32 nPolygonIndex, + sal_Int32 nNumberOfPolygons, + sal_Int32 nPointIndex, + sal_Int32 nNumberOfPoints ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + + return unotools::pointSequenceSequenceFromB2DPolyPolygon( + getSubsetPolyPolygon( nPolygonIndex, + nNumberOfPolygons, + nPointIndex, + nNumberOfPoints ) ); + } + + void SAL_CALL UnoPolyPolygon::setPoints( + const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points, + sal_Int32 nPolygonIndex ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + modifying(); + + const B2DPolyPolygon& rNewPolyPoly( + unotools::polyPolygonFromPoint2DSequenceSequence( points ) ); + + if( nPolygonIndex == -1 ) + { + maPolyPoly = rNewPolyPoly; + } + else + { + checkIndex( nPolygonIndex ); + + maPolyPoly.insert( nPolygonIndex, rNewPolyPoly ); + } + } + + geometry::RealPoint2D SAL_CALL UnoPolyPolygon::getPoint( + sal_Int32 nPolygonIndex, + sal_Int32 nPointIndex ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + checkIndex( nPolygonIndex ); + + const B2DPolygon& rPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) ); + + if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(rPoly.count()) ) + throw lang::IndexOutOfBoundsException(); + + return unotools::point2DFromB2DPoint( rPoly.getB2DPoint( nPointIndex ) ); + } + + void SAL_CALL UnoPolyPolygon::setPoint( + const geometry::RealPoint2D& point, + sal_Int32 nPolygonIndex, + sal_Int32 nPointIndex ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + checkIndex( nPolygonIndex ); + modifying(); + + B2DPolygon aPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) ); + + if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(aPoly.count()) ) + throw lang::IndexOutOfBoundsException(); + + aPoly.setB2DPoint( nPointIndex, + unotools::b2DPointFromRealPoint2D( point ) ); + maPolyPoly.setB2DPolygon( nPolygonIndex, aPoly ); + } + + uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > > SAL_CALL UnoPolyPolygon::getBezierSegments( + sal_Int32 nPolygonIndex, + sal_Int32 nNumberOfPolygons, + sal_Int32 nPointIndex, + sal_Int32 nNumberOfPoints ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + return unotools::bezierSequenceSequenceFromB2DPolyPolygon( + getSubsetPolyPolygon( nPolygonIndex, + nNumberOfPolygons, + nPointIndex, + nNumberOfPoints ) ); + } + + void SAL_CALL UnoPolyPolygon::setBezierSegments( + const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& points, + sal_Int32 nPolygonIndex ) throw (lang::IndexOutOfBoundsException, + uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + modifying(); + const B2DPolyPolygon& rNewPolyPoly( + unotools::polyPolygonFromBezier2DSequenceSequence( points ) ); + + if( nPolygonIndex == -1 ) + { + maPolyPoly = rNewPolyPoly; + } + else + { + checkIndex( nPolygonIndex ); + + maPolyPoly.insert( nPolygonIndex, rNewPolyPoly ); + } + } + + geometry::RealBezierSegment2D SAL_CALL UnoPolyPolygon::getBezierSegment( sal_Int32 nPolygonIndex, + sal_Int32 nPointIndex ) throw (lang::IndexOutOfBoundsException, + uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + checkIndex( nPolygonIndex ); + + const B2DPolygon& rPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) ); + const sal_uInt32 nPointCount(rPoly.count()); + + if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(nPointCount) ) + throw lang::IndexOutOfBoundsException(); + + const B2DPoint& rPt( rPoly.getB2DPoint( nPointIndex ) ); + const B2DPoint& rCtrl0( rPoly.getNextControlPoint(nPointIndex) ); + const B2DPoint& rCtrl1( rPoly.getPrevControlPoint((nPointIndex + 1) % nPointCount) ); + + return geometry::RealBezierSegment2D( rPt.getX(), + rPt.getY(), + rCtrl0.getX(), + rCtrl0.getY(), + rCtrl1.getX(), + rCtrl1.getY() ); + } + + void SAL_CALL UnoPolyPolygon::setBezierSegment( const geometry::RealBezierSegment2D& segment, + sal_Int32 nPolygonIndex, + sal_Int32 nPointIndex ) throw (lang::IndexOutOfBoundsException, + uno::RuntimeException) + { + osl::MutexGuard const guard( m_aMutex ); + checkIndex( nPolygonIndex ); + modifying(); + + B2DPolygon aPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) ); + const sal_uInt32 nPointCount(aPoly.count()); + + if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(nPointCount) ) + throw lang::IndexOutOfBoundsException(); + + aPoly.setB2DPoint( nPointIndex, + B2DPoint( segment.Px, + segment.Py ) ); + aPoly.setNextControlPoint(nPointIndex, + B2DPoint(segment.C1x, segment.C1y)); + aPoly.setPrevControlPoint((nPointIndex + 1) % nPointCount, + B2DPoint(segment.C2x, segment.C2y)); + + maPolyPoly.setB2DPolygon( nPolygonIndex, aPoly ); + } + + B2DPolyPolygon UnoPolyPolygon::getSubsetPolyPolygon( + sal_Int32 nPolygonIndex, + sal_Int32 nNumberOfPolygons, + sal_Int32 nPointIndex, + sal_Int32 nNumberOfPoints ) const + { + osl::MutexGuard const guard( m_aMutex ); + checkIndex( nPolygonIndex ); + + const sal_Int32 nPolyCount( maPolyPoly.count() ); + + // check for "full polygon" case + if( !nPolygonIndex && + !nPointIndex && + nNumberOfPolygons == nPolyCount && + nNumberOfPoints == -1 ) + { + return maPolyPoly; + } + + B2DPolyPolygon aSubsetPoly; + + // create temporary polygon (as an extract from maPoly, + // which contains the requested subset) + for( sal_Int32 i=nPolygonIndex; i<nNumberOfPolygons; ++i ) + { + checkIndex(i); + + const B2DPolygon& rCurrPoly( maPolyPoly.getB2DPolygon(i) ); + + sal_Int32 nFirstPoint(0); + sal_Int32 nLastPoint(nPolyCount-1); + + if( nPointIndex && i==nPolygonIndex ) + { + // very first polygon - respect nPointIndex, if + // not zero + + // empty polygon - impossible to specify _any_ + // legal value except 0 here! + if( !nPolyCount && nPointIndex ) + throw lang::IndexOutOfBoundsException(); + + nFirstPoint = nPointIndex; + } + + if( i==nNumberOfPolygons-1 && nNumberOfPoints != -1 ) + { + // very last polygon - respect nNumberOfPoints + + // empty polygon - impossible to specify _any_ + // legal value except -1 here! + if( !nPolyCount ) + throw lang::IndexOutOfBoundsException(); + + nLastPoint = nFirstPoint+nNumberOfPoints; + } + + if( !nPolyCount ) + { + // empty polygon - index checks already performed + // above, now simply append empty polygon + aSubsetPoly.append( rCurrPoly ); + } + else + { + if( nFirstPoint < 0 || nFirstPoint >= nPolyCount ) + throw lang::IndexOutOfBoundsException(); + + if( nLastPoint < 0 || nLastPoint >= nPolyCount ) + throw lang::IndexOutOfBoundsException(); + + B2DPolygon aTmp; + for( sal_Int32 j=nFirstPoint; j<nLastPoint; ++j ) + aTmp.append( rCurrPoly.getB2DPoint(j) ); + + aSubsetPoly.append( aTmp ); + } + } + + return aSubsetPoly; + } + + B2DPolyPolygon UnoPolyPolygon::getPolyPolygonUnsafe() const + { + return maPolyPoly; + } + +#define IMPLEMENTATION_NAME "gfx::internal::UnoPolyPolygon" +#define SERVICE_NAME "com.sun.star.rendering.PolyPolygon2D" + ::rtl::OUString SAL_CALL UnoPolyPolygon::getImplementationName() throw( uno::RuntimeException ) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL UnoPolyPolygon::supportsService( const ::rtl::OUString& ServiceName ) throw( uno::RuntimeException ) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL UnoPolyPolygon::getSupportedServiceNames() throw( uno::RuntimeException ) + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + + return aRet; + } + + B2DPolyPolygon UnoPolyPolygon::getPolyPolygon() const + { + osl::MutexGuard const guard( m_aMutex ); + + // detach result from us + B2DPolyPolygon aRet( maPolyPoly ); + aRet.makeUnique(); + return aRet; + } + +} +} |