diff options
Diffstat (limited to 'chart2/source/view/main/ShapeFactory.cxx')
-rw-r--r-- | chart2/source/view/main/ShapeFactory.cxx | 2101 |
1 files changed, 2101 insertions, 0 deletions
diff --git a/chart2/source/view/main/ShapeFactory.cxx b/chart2/source/view/main/ShapeFactory.cxx new file mode 100644 index 000000000000..311b5e076e9a --- /dev/null +++ b/chart2/source/view/main/ShapeFactory.cxx @@ -0,0 +1,2101 @@ +/************************************************************************* + * + * 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_chart2.hxx" +#include "ShapeFactory.hxx" +#include "ViewDefines.hxx" +#include "Stripe.hxx" +#include "CommonConverters.hxx" +#include "macros.hxx" +#include "PropertyMapper.hxx" +#include <comphelper/InlineContainer.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/CircleKind.hpp> +#include <com/sun/star/drawing/DoubleSequence.hpp> +#include <com/sun/star/drawing/FlagSequence.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/NormalsKind.hpp> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <com/sun/star/drawing/PolygonKind.hpp> +#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> +#include <com/sun/star/drawing/ProjectionMode.hpp> +#include <com/sun/star/drawing/ShadeMode.hpp> +#include <com/sun/star/drawing/TextFitToSizeType.hpp> +#include <com/sun/star/drawing/TextureProjectionMode.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/uno/Any.hxx> + + +#include <editeng/unoprnms.hxx> +#include <tools/color.hxx> +#include <tools/debug.hxx> +#include <rtl/math.hxx> +#include <svx/svdocirc.hxx> +#include <svx/svdopath.hxx> + +#ifndef _BGFX_VECTOR_B2DPOINT_HXX +#include <basegfx/point/b2dpoint.hxx> +#endif +#include <basegfx/matrix/b3dhommatrix.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// set a name/CID at a shape (is used for selection handling) +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +void ShapeFactory::setShapeName( const uno::Reference< drawing::XShape >& xShape + , const rtl::OUString& rName ) +{ + if(!xShape.is()) + return; + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + xProp->setPropertyValue( C2U( UNO_NAME_MISC_OBJ_NAME ) + , uno::makeAny( rName ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +//----------------------------------------------------------------------------- + +rtl::OUString ShapeFactory::getShapeName( const uno::Reference< drawing::XShape >& xShape ) +{ + rtl::OUString aRet; + + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + xProp->getPropertyValue( C2U( UNO_NAME_MISC_OBJ_NAME ) ) >>= aRet; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + + return aRet; +} + +//----------------------------------------------------------------------------- + +uno::Reference< drawing::XShapes > ShapeFactory::getChartRootShape( + const uno::Reference< drawing::XDrawPage>& xDrawPage ) +{ + uno::Reference< drawing::XShapes > xRet; + uno::Reference< drawing::XShapes > xShapes( xDrawPage, uno::UNO_QUERY ); + if( xShapes.is() ) + { + sal_Int32 nCount = xShapes->getCount(); + uno::Reference< drawing::XShape > xShape; + for( sal_Int32 nN = nCount; nN--; ) + { + if( xShapes->getByIndex( nN ) >>= xShape ) + { + if( ShapeFactory::getShapeName( xShape ).equals(C2U("com.sun.star.chart2.shapes")) ) + { + xRet = uno::Reference< drawing::XShapes >( xShape, uno::UNO_QUERY ); + break; + } + } + } + } + return xRet; +} + +//----------------------------------------------------------------------------- + +uno::Reference< drawing::XShapes > ShapeFactory::getOrCreateChartRootShape( + const uno::Reference< drawing::XDrawPage>& xDrawPage ) +{ + uno::Reference< drawing::XShapes > xRet( ShapeFactory::getChartRootShape( xDrawPage ) ); + if( !xRet.is() ) + { + //create the root shape + xRet = this->createGroup2D( + uno::Reference<drawing::XShapes>( xDrawPage, uno::UNO_QUERY ) + , C2U("com.sun.star.chart2.shapes") ); + } + return xRet; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// diverse PolyPolygon create methods +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +uno::Any createPolyPolygon_Cube( + const drawing::Direction3D& rSize, double fRoundedEdge, bool bRounded = true ) +{ + DBG_ASSERT(fRoundedEdge>=0, "fRoundedEdge needs to be >= 0"); + + // always use extra points, so set percent diagonal to 0.4 which is 0% in the UI (old Chart comment) + if( fRoundedEdge == 0.0 && bRounded) + fRoundedEdge = 0.4 / 200.0; + else if(!bRounded) + fRoundedEdge = 0.0; + + //fWidthH stands for Half Width + const double fWidthH = rSize.DirectionX >=0.0? rSize.DirectionX/2.0 : -rSize.DirectionX/2.0; + const double fHeight = rSize.DirectionY; +// const double fDepth = rSize.DirectionZ >=0.0? rSize.DirectionZ : -rSize.DirectionZ ; + + const double fHeightSign = fHeight >= 0.0 ? 1.0 : -1.0; + + const double fOffset = (fWidthH * fRoundedEdge) * 1.05; // increase by 5% for safety + const bool bRoundEdges = fRoundedEdge && fOffset < fWidthH && 2.0 * fOffset < fHeightSign*fHeight; + const sal_Int32 nPointCount = bRoundEdges ? 13 : 5; + + //-------------------------------------- + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(nPointCount); + pOuterSequenceY->realloc(nPointCount); + pOuterSequenceZ->realloc(nPointCount); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + for(sal_Int32 nN = nPointCount; nN--;) + *pInnerSequenceZ++ = 0.0; + //*pInnerSequenceZ++ = -fDepth/2.0; + + if(nPointCount == 5) + { + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = 0.0; + + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + } + else + { + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = fHeightSign*fOffset; + *pInnerSequenceY++ = fHeight - fHeightSign*fOffset; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight - fHeightSign*fOffset; + *pInnerSequenceY++ = fHeightSign*fOffset; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + + *pInnerSequenceX++ = -fWidthH + fOffset; + *pInnerSequenceX++ = fWidthH - fOffset; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH - fOffset; + *pInnerSequenceX++ = -fWidthH + fOffset; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH + fOffset; + } + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +uno::Any createPolyPolygon_Cylinder( + double fHeight + , double fRadius + , sal_Int32& nVerticalSegmentCount ) +{ + //fHeight may be negative + DBG_ASSERT(fRadius>0, "The radius of a cylinder needs to be > 0"); + + //-------------------------------------- + drawing::PolyPolygonShape3D aPP; + + nVerticalSegmentCount=1; + + aPP.SequenceX.realloc(3); + aPP.SequenceY.realloc(3); + aPP.SequenceZ.realloc(3); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + double fY1 = 0.0; + double fY2 = fHeight; + + if( fHeight<0.0 ) + ::std::swap(fY1,fY2); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = fY1; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY1; + //---------------------------- + + pOuterSequenceX++;pOuterSequenceY++;pOuterSequenceZ++; + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + pInnerSequenceX = pOuterSequenceX->getArray(); + pInnerSequenceY = pOuterSequenceY->getArray(); + pInnerSequenceZ = pOuterSequenceZ->getArray(); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY1; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY2; + //---------------------------- + + pOuterSequenceX++;pOuterSequenceY++;pOuterSequenceZ++; + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + pInnerSequenceX = pOuterSequenceX->getArray(); + pInnerSequenceY = pOuterSequenceY->getArray(); + pInnerSequenceZ = pOuterSequenceZ->getArray(); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY2; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = fY2; + //---------------------------- + + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +uno::Any createPolyPolygon_Cone( double fHeight, double fRadius, double fTopHeight + , sal_Int32& nVerticalSegmentCount ) +{ + DBG_ASSERT(fRadius>0, "The radius of a cone needs to be > 0"); + + //for stacked charts we need cones without top -> fTopHeight != 0 resp. bTopless == true + //fTopHeight indicates the high of the cutted top only (not the full height) + bool bTopless = !::rtl::math::approxEqual( fHeight, fHeight + fTopHeight ); + + double r1= 0.0, r2 = fRadius; + if(bTopless) + // #i63212# fHeight may be negative, fTopHeight is always positive -> use fabs(fHeight) + r1 = fRadius * (fTopHeight)/(fabs(fHeight)+fTopHeight); + + nVerticalSegmentCount=1; + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(2); + aPP.SequenceY.realloc(2); + aPP.SequenceZ.realloc(2); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + double fX1 = 0.0; + double fX2 = r2; + double fX3 = r1; + + double fY1 = 0.0; + double fY2 = 0.0; + double fY3 = fHeight; + + if( fHeight<0.0 ) + { + ::std::swap(fX1,fX3); + ::std::swap(fY1,fY3); + } + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceY++ = fY1; + *pInnerSequenceX++ = fX1; + + *pInnerSequenceY++ = fY2; + *pInnerSequenceX++ = fX2; + //---------------------------- + + pOuterSequenceX++;pOuterSequenceY++;pOuterSequenceZ++; + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + pInnerSequenceX = pOuterSequenceX->getArray(); + pInnerSequenceY = pOuterSequenceY->getArray(); + pInnerSequenceZ = pOuterSequenceZ->getArray(); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceY++ = fY2; + *pInnerSequenceX++ = fX2; + + *pInnerSequenceY++ = fY3; + *pInnerSequenceX++ = fX3; + //---------------------------- + + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// methods for 3D shape creation +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +uno::Reference<drawing::XShape> + ShapeFactory::createCube( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , bool bRounded ) +{ + if( !xTarget.is() ) + return 0; + if( bRounded ) + { + try + { + if( xSourceProp.is() ) + { + drawing::LineStyle aLineStyle; + xSourceProp->getPropertyValue( C2U( "BorderStyle" ) ) >>= aLineStyle; + if( aLineStyle == drawing::LineStyle_SOLID ) + bRounded = false; + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + uno::Reference<drawing::XShape> xShape = impl_createCube( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree, bRounded ); + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + if( xSourceProp.is()) + PropertyMapper::setMappedProperties( xProp, xSourceProp, rPropertyNameMap ); + return xShape; +} + +uno::Reference<drawing::XShape> + ShapeFactory::impl_createCube( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree + , bool bRounded ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DExtrudeObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //depth + double fDepth = rSize.DirectionZ; + if(fDepth<0) + fDepth*=-1.0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_EXTRUDE_DEPTH ) + , uno::makeAny((sal_Int32)fDepth) ); + + //PercentDiagonal + sal_Int16 nPercentDiagonal = bRounded ? 3 : 0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , createPolyPolygon_Cube( rSize, double(nPercentDiagonal)/200.0,bRounded) ); + + //Matrix for position + { + ::basegfx::B3DHomMatrix aM; + if(nRotateZAngleHundredthDegree!=0) + aM.rotate(0.0,0.0,-nRotateZAngleHundredthDegree/18000.00*F_PI); + aM.translate(rPosition.PositionX + , rPosition.PositionY + , rPosition.PositionZ - (fDepth/2.0)); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(aHM) ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference<drawing::XShape> + ShapeFactory::createCylinder( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree ) +{ + return impl_createConeOrCylinder( + xTarget, rPosition, rSize, 0.0, nRotateZAngleHundredthDegree, true ); +} + +uno::Reference<drawing::XShape> + ShapeFactory::createPyramid( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, bool bRotateZ + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap ) +{ + if( !xTarget.is() ) + return 0; + + Reference< drawing::XShapes > xGroup( ShapeFactory::createGroup3D( xTarget, rtl::OUString() ) ); + + sal_Bool bDoubleSided = false; + short nRotatedTexture = 0; + + const double fWidth = rSize.DirectionX; + const double fDepth = rSize.DirectionZ; + const double fHeight = rSize.DirectionY; + + drawing::Position3D aBottomP1( rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ - fDepth/2.0 ); + if(bRotateZ) + aBottomP1.PositionY -= fWidth/2.0; + else + aBottomP1.PositionX -= fWidth/2.0; + drawing::Position3D aBottomP2( aBottomP1 ); + if(bRotateZ) + aBottomP2.PositionY += fWidth; + else + aBottomP2.PositionX += fWidth; + drawing::Position3D aBottomP3( aBottomP2 ); + drawing::Position3D aBottomP4( aBottomP1 ); + aBottomP3.PositionZ += fDepth; + aBottomP4.PositionZ += fDepth; + + const double fTopFactor = (fTopHeight)/(fabs(fHeight)+fTopHeight); + drawing::Position3D aTopP1( rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ - fDepth*fTopFactor/2.0 ); + if(bRotateZ) + { + aTopP1.PositionY -= fWidth*fTopFactor/2.0; + aTopP1.PositionX += fHeight; + } + else + { + aTopP1.PositionX -= fWidth*fTopFactor/2.0; + aTopP1.PositionY += fHeight; + } + drawing::Position3D aTopP2( aTopP1 ); + if(bRotateZ) + aTopP2.PositionY += fWidth*fTopFactor; + else + aTopP2.PositionX += fWidth*fTopFactor; + drawing::Position3D aTopP3( aTopP2 ); + drawing::Position3D aTopP4( aTopP1 ); + aTopP3.PositionZ += fDepth*fTopFactor; + aTopP4.PositionZ += fDepth*fTopFactor; + + Stripe aStripeBottom( aBottomP1, aBottomP4, aBottomP3, aBottomP2 ); + + drawing::Position3D aNormalsBottomP1( aBottomP1 ); + drawing::Position3D aNormalsBottomP2( aBottomP2 ); + drawing::Position3D aNormalsBottomP3( aBottomP3 ); + drawing::Position3D aNormalsBottomP4( aBottomP4 ); + drawing::Position3D aNormalsTopP1( aBottomP1 ); + drawing::Position3D aNormalsTopP2( aBottomP2 ); + drawing::Position3D aNormalsTopP3( aBottomP3 ); + drawing::Position3D aNormalsTopP4( aBottomP4 ); + if( bRotateZ ) + { + aNormalsTopP1.PositionX += fHeight; + aNormalsTopP2.PositionX += fHeight; + aNormalsTopP3.PositionX += fHeight; + aNormalsTopP4.PositionX += fHeight; + } + else + { + aNormalsTopP1.PositionY += fHeight; + aNormalsTopP2.PositionY += fHeight; + aNormalsTopP3.PositionY += fHeight; + aNormalsTopP4.PositionY += fHeight; + } + + bool bInvertPolygon = false; + bool bInvertNormals = false; + + if(bRotateZ) + { + //bars + if(fHeight>=0.0) + { + nRotatedTexture = 2; + bInvertNormals = true; + aStripeBottom = Stripe( aBottomP1, aBottomP4, aBottomP3, aBottomP2 ); + } + else + { + bInvertPolygon = true; + nRotatedTexture = 1; + aStripeBottom = Stripe( aBottomP2, aBottomP3, aBottomP4, aBottomP1 ); + } + } + else + { + //columns + if(fHeight>=0.0) + { + bInvertPolygon = true; + nRotatedTexture = 2; + aStripeBottom = Stripe( aBottomP2, aBottomP3, aBottomP4, aBottomP1 ); + } + else + { + nRotatedTexture = 3; + bInvertNormals = true; + aStripeBottom = Stripe( aBottomP4, aBottomP3, aBottomP2, aBottomP1 ); + } + } + aStripeBottom.InvertNormal(true); + + Stripe aStripe1( aTopP2, aTopP1, aBottomP1, aBottomP2 ); + Stripe aStripe2( aTopP3, aTopP2, aBottomP2, aBottomP3 ); + Stripe aStripe3( aTopP4, aTopP3, aBottomP3, aBottomP4 ); + Stripe aStripe4( aTopP1, aTopP4, aBottomP4, aBottomP1 ); + + if( bInvertPolygon ) + { + aStripe1 = Stripe( aBottomP1, aTopP1, aTopP2, aBottomP2 ); + aStripe2 = Stripe( aBottomP2, aTopP2, aTopP3, aBottomP3 ); + aStripe3 = Stripe( aBottomP3, aTopP3, aTopP4, aBottomP4 ); + aStripe4 = Stripe( aBottomP4, aTopP4, aTopP1, aBottomP1 ); + } + + Stripe aNormalsStripe1( aNormalsTopP1, aNormalsBottomP1, aNormalsBottomP2, aNormalsTopP2 ); + Stripe aNormalsStripe2( aNormalsTopP2, aNormalsBottomP2, aNormalsBottomP3, aNormalsTopP3 ); + Stripe aNormalsStripe3( aNormalsTopP3, aNormalsBottomP3, aNormalsBottomP4, aNormalsTopP4 ); + Stripe aNormalsStripe4( aNormalsTopP4, aNormalsBottomP4, aNormalsBottomP1, aNormalsTopP1 ); + + if( bInvertNormals ) + { + aNormalsStripe1 = Stripe( aNormalsTopP2, aNormalsBottomP2, aNormalsBottomP1, aNormalsTopP1 ); + aNormalsStripe2 = Stripe( aNormalsTopP3, aNormalsBottomP3, aNormalsBottomP2, aNormalsTopP2 ); + aNormalsStripe3 = Stripe( aNormalsTopP4, aNormalsBottomP4, aNormalsBottomP3, aNormalsTopP3 ); + aNormalsStripe4 = Stripe( aNormalsTopP1, aNormalsBottomP1, aNormalsBottomP4, aNormalsTopP4 ); + } + + aStripe1.SetManualNormal( aNormalsStripe1.getNormal() ); + aStripe2.SetManualNormal( aNormalsStripe2.getNormal() ); + aStripe3.SetManualNormal( aNormalsStripe3.getNormal() ); + aStripe4.SetManualNormal( aNormalsStripe4.getNormal() ); + + const bool bFlatNormals = false; + ShapeFactory::createStripe( xGroup, aStripe1, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripe2, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripe3, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripe4, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripeBottom, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + + return Reference< drawing::XShape >( xGroup, uno::UNO_QUERY ); +} + +uno::Reference<drawing::XShape> + ShapeFactory::createCone( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree ) +{ + return impl_createConeOrCylinder( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree ); +} + +uno::Reference<drawing::XShape> + ShapeFactory::impl_createConeOrCylinder( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree + , bool bCylinder ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DLatheObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + double fWidth = rSize.DirectionX/2.0; //The depth will be corrrected within Matrix + double fRadius = fWidth; //!!!!!!!! problem in drawing layer: rotation object calculates wrong needed size -> wrong camera (it's a problem with bounding boxes) + double fHeight = rSize.DirectionY; + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //PercentDiagonal + sal_Int16 nPercentDiagonal = 5; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + sal_Int32 nVerticalSegmentCount = 0; + uno::Any aPPolygon = bCylinder ? createPolyPolygon_Cylinder( + fHeight, fRadius, nVerticalSegmentCount) + : createPolyPolygon_Cone( + fHeight, fRadius, fTopHeight, nVerticalSegmentCount); + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ), aPPolygon ); + + //Matrix for position + { + ::basegfx::B3DHomMatrix aM; + if(nRotateZAngleHundredthDegree!=0) + aM.rotate(0.0,0.0,-nRotateZAngleHundredthDegree/18000.00*F_PI); + //stretch the symmetric objects to given depth + aM.scale(1.0,1.0,rSize.DirectionZ/rSize.DirectionX); + aM.translate(rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(aHM) ); + } + + //Segments + xProp->setPropertyValue( C2U( UNO_NAME_3D_HORZ_SEGS ) + , uno::makeAny(CHART_3DOBJECT_SEGMENTCOUNT) ); + xProp->setPropertyValue( C2U( UNO_NAME_3D_VERT_SEGS ) + , uno::makeAny((sal_Int32)nVerticalSegmentCount) );//depends on point count of the used polygon + + //Reduced lines + xProp->setPropertyValue( C2U( UNO_NAME_3D_REDUCED_LINE_GEOMETRY ) + , uno::makeAny((sal_Bool)sal_True) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ + +void appendAndCloseBezierCoords( drawing::PolyPolygonBezierCoords& rReturn, const drawing::PolyPolygonBezierCoords& rAdd, sal_Bool bAppendInverse ) +{ + if(!rAdd.Coordinates.getLength()) + return; + sal_Int32 nAddCount = rAdd.Coordinates[0].getLength(); + if(!nAddCount) + return; + + sal_Int32 nOldCount = rReturn.Coordinates[0].getLength(); + + rReturn.Coordinates[0].realloc(nOldCount+nAddCount+1); + rReturn.Flags[0].realloc(nOldCount+nAddCount+1); + + for(sal_Int32 nN=0;nN<nAddCount; nN++ ) + { + sal_Int32 nAdd = bAppendInverse ? (nAddCount-1-nN) : nN; + rReturn.Coordinates[0][nOldCount+nN] = rAdd.Coordinates[0][nAdd]; + rReturn.Flags[0][nOldCount+nN] = rAdd.Flags[0][nAdd]; + } + + //close + rReturn.Coordinates[0][nOldCount+nAddCount] = rReturn.Coordinates[0][0]; + rReturn.Flags[0][nOldCount+nAddCount] = rReturn.Flags[0][0]; +} + +//------------------------------------------------------------------------------------------------------------ + +drawing::PolyPolygonBezierCoords getCircularArcBezierCoords( + double fStartAngleRadian, double fWidthAngleRadian, double fUnitRadius + , const ::basegfx::B2DHomMatrix& rTransformationFromUnitCircle + , const double fAngleSubdivisionRadian ) +{ + //at least one polygon is created using two normal and two control points + //if the angle is larger it is separated into multiple sub angles + + drawing::PolyPolygonBezierCoords aReturn = drawing::PolyPolygonBezierCoords(); + sal_Int32 nSegmentCount = static_cast< sal_Int32 >( fWidthAngleRadian/fAngleSubdivisionRadian ); + if( fWidthAngleRadian > fAngleSubdivisionRadian*nSegmentCount ) + nSegmentCount++; + + double fFirstSegmentAngle = fAngleSubdivisionRadian; + double fLastSegmentAngle = fAngleSubdivisionRadian; + if(nSegmentCount==1) + { + fFirstSegmentAngle = fWidthAngleRadian; + fLastSegmentAngle = 0.0; + } + else + { + double fFirstAngleOnSubDevision = (static_cast<sal_Int32>(fStartAngleRadian/fAngleSubdivisionRadian)+1)*fAngleSubdivisionRadian; + if( !::rtl::math::approxEqual( fStartAngleRadian, fFirstAngleOnSubDevision ) ) + fFirstSegmentAngle = fFirstAngleOnSubDevision-fStartAngleRadian; + + if(nSegmentCount>1) + { + fLastSegmentAngle = fWidthAngleRadian-fFirstSegmentAngle-fAngleSubdivisionRadian*(nSegmentCount-2); + if( fLastSegmentAngle<0 ) + nSegmentCount--; + if( fLastSegmentAngle>fAngleSubdivisionRadian ) + { + fLastSegmentAngle-=fAngleSubdivisionRadian; + nSegmentCount++; + } + } + } + + sal_Int32 nPointCount = 1 + 3*nSegmentCount; //first point of next segment equals last point of former segment + + aReturn.Coordinates = drawing::PointSequenceSequence(1); + aReturn.Flags = drawing::FlagSequenceSequence(1); + + drawing::PointSequence aPoints(nPointCount); + drawing::FlagSequence aFlags(nPointCount); + + // + + //!! applying matrix to vector does ignore translation, so it is important to use a B2DPoint here instead of B2DVector + ::basegfx::B2DPoint P0,P1,P2,P3; + ::basegfx::B2DPoint POrigin = rTransformationFromUnitCircle * ::basegfx::B2DPoint(0.0, 0.0); + + sal_Int32 nPoint=0; + double fCurrentRotateAngle = fStartAngleRadian; + for(sal_Int32 nSegment=0; nSegment<nSegmentCount; nSegment++) + { + double fCurrentSegmentAngle = fAngleSubdivisionRadian; + if(nSegment==0)//first segment gets only a smaller peace until the next subdevision + fCurrentSegmentAngle = fFirstSegmentAngle; + else if(nSegment==(nSegmentCount-1)) //the last segment gets the rest angle that does not fit into equal pieces + fCurrentSegmentAngle = fLastSegmentAngle; + + //first create untransformed points for a unit circle arc: + const double fCos = cos(fCurrentSegmentAngle/2.0); + const double fSin = sin(fCurrentSegmentAngle/2.0); + P0.setX(fCos); + P3.setX(fCos); + P0.setY(-fSin); + P3.setY(-P0.getY()); + + P1.setX((4.0-fCos)/3.0); + P2.setX(P1.getX()); + P1.setY((1.0-fCos)*(fCos-3.0)/(3.0*fSin)); + P2.setY(-P1.getY()); + //transform thus startangle equals NULL + ::basegfx::B2DHomMatrix aStart; + aStart.rotate(fCurrentSegmentAngle/2.0 + fCurrentRotateAngle ); + fCurrentRotateAngle+=fCurrentSegmentAngle; + + aStart.scale( fUnitRadius, fUnitRadius ); + + //apply given transformation to get final points + P0 = rTransformationFromUnitCircle*(aStart*P0); + P1 = rTransformationFromUnitCircle*(aStart*P1); + P2 = rTransformationFromUnitCircle*(aStart*P2); + P3 = rTransformationFromUnitCircle*(aStart*P3); + + aPoints[nPoint].X = static_cast< sal_Int32 >( P0.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P0.getY()); + aFlags [nPoint++] = drawing::PolygonFlags_NORMAL; + + aPoints[nPoint].X = static_cast< sal_Int32 >( P1.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P1.getY()); + aFlags[nPoint++] = drawing::PolygonFlags_CONTROL; + + aPoints[nPoint].X = static_cast< sal_Int32 >( P2.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P2.getY()); + aFlags [nPoint++] = drawing::PolygonFlags_CONTROL; + + if(nSegment==(nSegmentCount-1)) + { + aPoints[nPoint].X = static_cast< sal_Int32 >( P3.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P3.getY()); + aFlags [nPoint++] = drawing::PolygonFlags_NORMAL; + } + } + + aReturn.Coordinates[0] = aPoints; + aReturn.Flags[0] = aFlags; + + return aReturn; +} + +//------------------------------------------------------------------------------------------------------------ + +drawing::PolyPolygonBezierCoords getRingBezierCoords( + double fUnitCircleInnerRadius + , double fUnitCircleOuterRadius + , double fStartAngleRadian, double fWidthAngleRadian + , ::basegfx::B2DHomMatrix aTransformationFromUnitCircle + , const double fAngleSubdivisionRadian ) +{ + drawing::PolyPolygonBezierCoords aReturn = drawing::PolyPolygonBezierCoords(); + + aReturn.Coordinates = drawing::PointSequenceSequence(1); + aReturn.Flags = drawing::FlagSequenceSequence(1); + + drawing::PolyPolygonBezierCoords aOuterArc = getCircularArcBezierCoords( + fStartAngleRadian, fWidthAngleRadian, fUnitCircleOuterRadius, aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + aReturn.Coordinates[0] = aOuterArc.Coordinates[0]; + aReturn.Flags[0] = aOuterArc.Flags[0]; + + drawing::PolyPolygonBezierCoords aInnerArc = getCircularArcBezierCoords( + fStartAngleRadian, fWidthAngleRadian, fUnitCircleInnerRadius, aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + appendAndCloseBezierCoords( aReturn, aInnerArc, sal_True ); + + //fill rMarkHandlePoints + /* + { + rMarkHandlePoints.realloc(1); + rMarkHandlePoints[0].realloc(6); + sal_Int32 nHandleCount=0; + sal_Int32 nOuterArcCount = aOuterArc.Coordinates[0].getLength(); + if(nOuterArcCount>0) + rMarkHandlePoints[0][nHandleCount++]=aOuterArc.Coordinates[0][0]; + if(nOuterArcCount>1) + rMarkHandlePoints[0][nHandleCount++]=aOuterArc.Coordinates[0][nOuterArcCount-1]; + sal_Int32 nInnerArcCount = aInnerArc.Coordinates[0].getLength(); + if(nInnerArcCount>0) + rMarkHandlePoints[0][nHandleCount++]=aInnerArc.Coordinates[0][0]; + if(nInnerArcCount>1) + rMarkHandlePoints[0][nHandleCount++]=aInnerArc.Coordinates[0][nInnerArcCount-1]; + rMarkHandlePoints[0].realloc(nHandleCount); + } + */ + + return aReturn; +} + +//------------------------------------------------------------------------------------------------------------ + +uno::Reference< drawing::XShape > + ShapeFactory::createPieSegment2D( + const uno::Reference< drawing::XShapes >& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const drawing::Direction3D& rOffset + , const drawing::HomogenMatrix& rUnitCircleToScene ) +{ + if( !xTarget.is() ) + return 0; + + while(fUnitCircleWidthAngleDegree>360) + fUnitCircleWidthAngleDegree -= 360.0; + while(fUnitCircleWidthAngleDegree<0) + fUnitCircleWidthAngleDegree += 360.0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( + C2U("com.sun.star.drawing.ClosedBezierShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); //need to add the shape before setting of properties + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + ::basegfx::B2DHomMatrix aTransformationFromUnitCircle( IgnoreZ( HomogenMatrixToB3DHomMatrix(rUnitCircleToScene) ) ); + aTransformationFromUnitCircle.translate(rOffset.DirectionX,rOffset.DirectionY); + + const double fAngleSubdivisionRadian = F_PI/10.0; + + drawing::PolyPolygonBezierCoords aCoords = getRingBezierCoords( + fUnitCircleInnerRadius, fUnitCircleOuterRadius + , fUnitCircleStartAngleDegree*F_PI/180.0, fUnitCircleWidthAngleDegree*F_PI/180.0 + , aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + + xProp->setPropertyValue( C2U( "PolyPolygonBezier" ), uno::makeAny( aCoords ) ); + + //add shape for markhandles + /* + drawing::PointSequenceSequence aMarkHandlePoints(1); to be filled within getRingBezierCoords + if( xGroup.is() ) + { + VLineProperties aHandleLineProperties; + aHandleLineProperties.LineStyle = uno::makeAny( drawing::LineStyle_NONE ); + uno::Reference< drawing::XShape > xHandleShape = + this->createLine2D( xGroup, aMarkHandlePoints, &aHandleLineProperties ); + this->setShapeName( xHandleShape, C2U("HandlesOnly") ); + } + */ + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + + return xShape; +} + +//------------------------------------------------------------------------------------------------------------ + +uno::Reference< drawing::XShape > + ShapeFactory::createPieSegment( + const uno::Reference< drawing::XShapes >& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const drawing::Direction3D& rOffset + , const drawing::HomogenMatrix& rUnitCircleToScene + , double fDepth ) +{ + if( !xTarget.is() ) + return 0; + + while(fUnitCircleWidthAngleDegree>360) + fUnitCircleWidthAngleDegree -= 360.0; + while(fUnitCircleWidthAngleDegree<0) + fUnitCircleWidthAngleDegree += 360.0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DExtrudeObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); //need to add the shape before setting of properties + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + ::basegfx::B2DHomMatrix aTransformationFromUnitCircle( IgnoreZ( HomogenMatrixToB3DHomMatrix(rUnitCircleToScene) ) ); + aTransformationFromUnitCircle.translate(rOffset.DirectionX,rOffset.DirectionY); + + const double fAngleSubdivisionRadian = F_PI/32.0; + + drawing::PolyPolygonBezierCoords aCoords = getRingBezierCoords( + fUnitCircleInnerRadius, fUnitCircleOuterRadius + , fUnitCircleStartAngleDegree*F_PI/180.0, fUnitCircleWidthAngleDegree*F_PI/180.0 + , aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + + //depth + xProp->setPropertyValue( C2U( UNO_NAME_3D_EXTRUDE_DEPTH ) + , uno::makeAny((sal_Int32)fDepth) ); + + //PercentDiagonal + sal_Int16 nPercentDiagonal = 0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + drawing::PolyPolygonShape3D aPoly( BezierToPoly(aCoords) ); + ShapeFactory::closePolygon( aPoly ); + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , uno::makeAny( aPoly ) ); + + //DoubleSided + xProp->setPropertyValue( C2U( UNO_NAME_3D_DOUBLE_SIDED ) + , uno::makeAny( (sal_Bool)true) ); + + //Reduced lines + xProp->setPropertyValue( C2U( UNO_NAME_3D_REDUCED_LINE_GEOMETRY ) + , uno::makeAny((sal_Bool)sal_True) ); + + //TextureProjectionMode + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTURE_PROJ_Y ) + , uno::makeAny( drawing::TextureProjectionMode_OBJECTSPECIFIC ) ); + + //TextureProjectionMode + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTURE_PROJ_X ) + , uno::makeAny( drawing::TextureProjectionMode_PARALLEL ) ); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTURE_PROJ_Y ) + , uno::makeAny( drawing::TextureProjectionMode_OBJECTSPECIFIC ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ + +uno::Reference< drawing::XShape > + ShapeFactory::createStripe( const uno::Reference< drawing::XShapes >& xTarget + , const Stripe& rStripe + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , sal_Bool bDoubleSided + , short nRotatedTexture + , bool bFlatNormals ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DPolygonObject" ) ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , rStripe.getPolyPolygonShape3D() ); + + //TexturePolygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTUREPOLYGON3D ) + , rStripe.getTexturePolygon( nRotatedTexture ) ); + + //Normals Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_NORMALSPOLYGON3D ) + , rStripe.getNormalsPolygon() ); + //NormalsKind + if(bFlatNormals) + xProp->setPropertyValue( C2U( UNO_NAME_3D_NORMALS_KIND ) + , uno::makeAny( drawing::NormalsKind_FLAT ) ); + + //LineOnly + xProp->setPropertyValue( C2U( UNO_NAME_3D_LINEONLY ) + , uno::makeAny( (sal_Bool)false) ); + + //DoubleSided + xProp->setPropertyValue( C2U( UNO_NAME_3D_DOUBLE_SIDED ) + , uno::makeAny(bDoubleSided) ); + + if( xSourceProp.is()) + PropertyMapper::setMappedProperties( xProp, xSourceProp, rPropertyNameMap ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createArea3D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PolyPolygonShape3D& rPolyPolygon + , double fDepth ) +{ + if( !xTarget.is() ) + return 0; + + if( !rPolyPolygon.SequenceX.getLength()) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DExtrudeObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //depth + xProp->setPropertyValue( C2U( UNO_NAME_3D_EXTRUDE_DEPTH ) + , uno::makeAny((sal_Int32)fDepth) ); + + //PercentDiagonal + sal_Int16 nPercentDiagonal = 0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , uno::makeAny( rPolyPolygon ) ); + + //DoubleSided + xProp->setPropertyValue( C2U( UNO_NAME_3D_DOUBLE_SIDED ) + , uno::makeAny( (sal_Bool)true) ); + + //the z component of the polygon is now ignored by the drawing layer, + //so we nned to translate the object via transformation matrix + + //Matrix for position + if( rPolyPolygon.SequenceZ.getLength()&& rPolyPolygon.SequenceZ[0].getLength() ) + { + ::basegfx::B3DHomMatrix aM; + aM.translate( 0 + , 0 + , rPolyPolygon.SequenceZ[0][0] ); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(aHM) ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createArea2D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PolyPolygonShape3D& rPolyPolygon ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.PolyPolygonShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //UNO_NAME_POLYGON "Polygon" drawing::PointSequence* + drawing::PointSequenceSequence aPoints( PolyToPointSequence(rPolyPolygon) ); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ) + , uno::makeAny( aPoints ) ); + + //ZOrder + //an area should always be behind other shapes + xProp->setPropertyValue( C2U( UNO_NAME_MISC_OBJ_ZORDER ) + , uno::makeAny( sal_Int32(0) ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +enum SymbolType { SYMBOL_SQUARE=0 + , SYMBOL_DIAMOND + , SYMBOL_ARROW_DOWN + , SYMBOL_ARROW_UP + , SYMBOL_ARROW_RIGHT + , SYMBOL_ARROW_LEFT + , SYMBOL_BOWTIE + , SYMBOL_SANDGLASS + , SYMBOL_COUNT + }; + +sal_Int32 ShapeFactory::getSymbolCount() +{ + return SYMBOL_COUNT; +} + +drawing::PolyPolygonShape3D createPolyPolygon_Symbol( const drawing::Position3D& rPos + , const drawing::Direction3D& rSize + , sal_Int32 nStandardSymbol ) +{ + if(nStandardSymbol<0) + nStandardSymbol*=-1; + nStandardSymbol = nStandardSymbol%ShapeFactory::getSymbolCount(); + SymbolType eSymbolType=static_cast<SymbolType>(nStandardSymbol); + + const double& fX = rPos.PositionX; + const double& fY = rPos.PositionY; + + const double fWidthH = rSize.DirectionX/2.0; //fWidthH stands for Half Width + const double fHeightH = rSize.DirectionY/2.0; //fHeightH stands for Half Height + + sal_Int32 nPointCount = 4; //all arrow symbols only need 4 points + switch( eSymbolType ) + { + case SYMBOL_SQUARE: + case SYMBOL_DIAMOND: + case SYMBOL_BOWTIE: + case SYMBOL_SANDGLASS: + nPointCount = 5; + break; + default: + break; + } + + //-------------------------------------- + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(nPointCount); + pOuterSequenceY->realloc(nPointCount); + pOuterSequenceZ->realloc(nPointCount); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + for(sal_Int32 nN = nPointCount; nN--;) + *pInnerSequenceZ++ = 0.0; + + switch(eSymbolType) + { + case SYMBOL_ARROW_UP: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + break; + } + case SYMBOL_ARROW_DOWN: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + case SYMBOL_ARROW_RIGHT: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + case SYMBOL_ARROW_LEFT: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + break; + } + case SYMBOL_BOWTIE: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + case SYMBOL_SANDGLASS: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + break; + } + case SYMBOL_DIAMOND: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + break; + } + default: //case SYMBOL_SQUARE: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + } + //return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); + return aPP; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createSymbol2D( + const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize + , sal_Int32 nStandardSymbol + , sal_Int32 nBorderColor + , sal_Int32 nFillColor ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.PolyPolygonShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + drawing::PointSequenceSequence aPoints( PolyToPointSequence( + createPolyPolygon_Symbol( rPosition, rSize, nStandardSymbol ) )); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ) + , uno::makeAny( aPoints ) ); + + //LineColor + xProp->setPropertyValue( C2U( UNO_NAME_LINECOLOR ) + , uno::makeAny( nBorderColor ) ); + + //FillColor + xProp->setPropertyValue( C2U( UNO_NAME_FILLCOLOR ) + , uno::makeAny( nFillColor ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createGraphic2D( + const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize + , const uno::Reference< graphic::XGraphic >& xGraphic ) +{ + if( !xTarget.is() || !xGraphic.is() ) + return 0; + + // @todo: change this to a rectangle shape with a fill bitmap for + // performance reasons (ask AW, said CL) + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.GraphicObjectShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + try + { + // assume position is upper left corner. Transform to center. + drawing::Position3D aCenterPosition( + rPosition.PositionX - (rSize.DirectionX / 2.0), + rPosition.PositionY - (rSize.DirectionY / 2.0), + rPosition.PositionZ ); + xShape->setPosition( Position3DToAWTPoint( aCenterPosition )); + xShape->setSize( Direction3DToAWTSize( rSize )); + } + catch( const uno::Exception & e ) + { + ASSERT_EXCEPTION( e ); + } + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + xProp->setPropertyValue( C2U("Graphic"), uno::makeAny( xGraphic )); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShapes > + ShapeFactory::createGroup2D( const uno::Reference< drawing::XShapes >& xTarget + , ::rtl::OUString aName ) +{ + if( !xTarget.is() ) + return 0; + try + { + //create and add to target + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.GroupShape" ) ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set name + if(aName.getLength()) + setShapeName( xShape , aName ); + + {//workaround + //need this null size as otherwise empty group shapes where painted with a gray border + xShape->setSize(awt::Size(0,0)); + } + + //return + uno::Reference< drawing::XShapes > xShapes = + uno::Reference<drawing::XShapes>( xShape, uno::UNO_QUERY ); + return xShapes; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + return 0; +} + +uno::Reference< drawing::XShapes > + ShapeFactory::createGroup3D( const uno::Reference< drawing::XShapes >& xTarget + , ::rtl::OUString aName ) +{ + if( !xTarget.is() ) + return 0; + try + { + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DSceneObject" ) ), uno::UNO_QUERY ); + + xTarget->add(xShape); + + //it is necessary to set the transform matrix to initialize the scene properly (bug #106316#) + //otherwise all objects which are placed into this Group will not be visible + //the following should be unnecessary after a the bug is fixed + { + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + ::basegfx::B3DHomMatrix aM; + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(B3DHomMatrixToHomogenMatrix(aM)) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + + //set name + if(aName.getLength()) + setShapeName( xShape , aName ); + + //return + uno::Reference< drawing::XShapes > xShapes = + uno::Reference<drawing::XShapes>( xShape, uno::UNO_QUERY ); + return xShapes; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + return 0; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createCircle2D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.EllipseShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + try + { + drawing::Position3D aCenterPosition( + rPosition.PositionX - (rSize.DirectionX / 2.0), + rPosition.PositionY - (rSize.DirectionY / 2.0), + rPosition.PositionZ ); + xShape->setPosition( Position3DToAWTPoint( aCenterPosition )); + xShape->setSize( Direction3DToAWTSize( rSize )); + } + catch( const uno::Exception & e ) + { + ASSERT_EXCEPTION( e ); + } + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + drawing::CircleKind eKind = drawing::CircleKind_FULL; + xProp->setPropertyValue( C2U( UNO_NAME_CIRCKIND ) + , uno::makeAny( eKind ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createLine3D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PolyPolygonShape3D& rPoints + , const VLineProperties& rLineProperties ) +{ + if( !xTarget.is() ) + return 0; + + if(!rPoints.SequenceX.getLength()) + return NULL; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DPolygonObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , uno::makeAny( rPoints ) ); + + //LineOnly + xProp->setPropertyValue( C2U( UNO_NAME_3D_LINEONLY ) + , uno::makeAny( (sal_Bool)true ) ); + + //Transparency + if(rLineProperties.Transparence.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINETRANSPARENCE ) + , rLineProperties.Transparence ); + + //LineStyle + if(rLineProperties.LineStyle.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINESTYLE ) + , rLineProperties.LineStyle ); + + //LineWidth + if(rLineProperties.Width.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINEWIDTH ) + , rLineProperties.Width ); + + //LineColor + if(rLineProperties.Color.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINECOLOR ) + , rLineProperties.Color ); + //, uno::makeAny( sal_Int32( Color(COL_RED).GetColor()) ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createLine2D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PointSequenceSequence& rPoints + , const VLineProperties* pLineProperties ) +{ + if( !xTarget.is() ) + return 0; + + if(!rPoints.getLength()) + return NULL; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + //"com.sun.star.drawing.LineShape") ), uno::UNO_QUERY ); + "com.sun.star.drawing.PolyLineShape") ), uno::UNO_QUERY ); + //"com.sun.star.drawing.PolyLinePathShape") ), uno::UNO_QUERY ); + //"com.sun.star.drawing.PolyPolygonPathShape") ), uno::UNO_QUERY ); + //"com.sun.star.drawing.PolyPolygonShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ) + , uno::makeAny( rPoints ) ); + + if(pLineProperties) + { + //Transparency + if(pLineProperties->Transparence.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINETRANSPARENCE ) + , pLineProperties->Transparence ); + + //LineStyle + if(pLineProperties->LineStyle.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINESTYLE ) + , pLineProperties->LineStyle ); + + //LineWidth + if(pLineProperties->Width.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINEWIDTH ) + , pLineProperties->Width ); + + //LineColor + if(pLineProperties->Color.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINECOLOR ) + , pLineProperties->Color ); + + //LineDashName + if(pLineProperties->DashName.hasValue()) + xProp->setPropertyValue( C2U( "LineDashName" ) + , pLineProperties->DashName ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Any ShapeFactory::makeTransformation( const awt::Point& rScreenPosition2D, double fRotationAnglePi ) +{ + ::basegfx::B2DHomMatrix aM; + //As autogrow is active the rectangle is automatically expanded to that side + //to which the text is not adjusted. + // aM.scale( 1, 1 ); Oops? A scale with this parameters is neutral, line commented out + aM.rotate( fRotationAnglePi ); + aM.translate( rScreenPosition2D.X, rScreenPosition2D.Y ); + uno::Any aATransformation = uno::makeAny( B2DHomMatrixToHomogenMatrix3(aM) ); + return aATransformation; +} + +void ShapeFactory::makeShapeInvisible( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xShapeProp.is(), "created shape offers no XPropertySet"); + if( xShapeProp.is()) + { + try + { + xShapeProp->setPropertyValue( C2U("LineStyle"), uno::makeAny( drawing::LineStyle_NONE )); + xShapeProp->setPropertyValue( C2U("FillStyle"), uno::makeAny( drawing::FillStyle_NONE )); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +uno::Reference< drawing::XShape > ShapeFactory::createInvisibleRectangle( + const uno::Reference< drawing::XShapes >& xTarget + , const awt::Size& rSize ) +{ + try + { + if(!xTarget.is()) + return 0; + + uno::Reference< drawing::XShape > xShape( m_xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + if( xTarget.is() && xShape.is()) + { + xTarget->add( xShape ); + ShapeFactory::makeShapeInvisible( xShape ); + xShape->setSize( rSize ); + } + return xShape; + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + return 0; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createText( const uno::Reference< drawing::XShapes >& xTarget + , const ::rtl::OUString& rText + , const tNameSequence& rPropNames + , const tAnySequence& rPropValues + , const uno::Any& rATransformation ) +{ + if( !xTarget.is() ) + return 0; + + if(!rText.getLength()) + return 0; + + //create shape and add to page + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.TextShape" ) ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set text + uno::Reference< text::XTextRange > xTextRange( xShape, uno::UNO_QUERY ); + if( xTextRange.is() ) + xTextRange->setString( rText ); + + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + if( xProp.is() ) + { + //set properties + PropertyMapper::setMultiProperties( rPropNames, rPropValues, xProp ); + + //set position matrix + //the matrix needs to be set at the end behind autogrow and such position influencing properties + try + { + xProp->setPropertyValue( C2U( "Transformation" ), rATransformation ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +rtl::OUString ShapeFactory::getStackedString( const rtl::OUString& rString, bool bStacked ) +{ + sal_Int32 nLen = rString.getLength(); + if(!bStacked || !nLen) + return rString; + + rtl::OUStringBuffer aStackStr; + rtl::OUStringBuffer aSource(rString); + + //add a newline after each letter + //as we do not no letters here add a newline after each char + for( sal_Int32 nPosSrc=0; nPosSrc < nLen; nPosSrc++ ) + { + if( nPosSrc ) + aStackStr.append( sal_Unicode('\r') ); + aStackStr.append( aSource.charAt( nPosSrc ) ); + } + return aStackStr.makeStringAndClear(); +} + +bool ShapeFactory::hasPolygonAnyLines( drawing::PolyPolygonShape3D& rPoly) +{ + // #i67757# check all contained polygons, if at least one polygon contains 2 or more points, return true + for( sal_Int32 nIdx = 0, nCount = rPoly.SequenceX.getLength(); nIdx < nCount; ++nIdx ) + if( rPoly.SequenceX[ nIdx ].getLength() > 1 ) + return true; + return false; +} + +bool ShapeFactory::isPolygonEmptyOrSinglePoint( drawing::PolyPolygonShape3D& rPoly) +{ + // true, if empty polypolygon or one polygon with one point + return (rPoly.SequenceX.getLength() == 0) || + ((rPoly.SequenceX.getLength() == 1) && (rPoly.SequenceX[0].getLength() <= 1)); +} + +void ShapeFactory::closePolygon( drawing::PolyPolygonShape3D& rPoly) +{ + DBG_ASSERT( rPoly.SequenceX.getLength() <= 1, "ShapeFactory::closePolygon - single polygon expected" ); + //add a last point == first point + if(isPolygonEmptyOrSinglePoint(rPoly)) + return; + drawing::Position3D aFirst(rPoly.SequenceX[0][0],rPoly.SequenceY[0][0],rPoly.SequenceZ[0][0]); + AddPointToPoly( rPoly, aFirst ); +} + +awt::Size ShapeFactory::calculateNewSizeRespectingAspectRatio( + const awt::Size& rTargetSize + , const awt::Size& rSourceSizeWithCorrectAspectRatio ) +{ + awt::Size aNewSize; + + double fFactorWidth = double(rTargetSize.Width)/double(rSourceSizeWithCorrectAspectRatio.Width); + double fFactorHeight = double(rTargetSize.Height)/double(rSourceSizeWithCorrectAspectRatio.Height); + double fFactor = std::min(fFactorWidth,fFactorHeight); + aNewSize.Width=static_cast<sal_Int32>(fFactor*rSourceSizeWithCorrectAspectRatio.Width); + aNewSize.Height=static_cast<sal_Int32>(fFactor*rSourceSizeWithCorrectAspectRatio.Height); + + return aNewSize; +} + +awt::Point ShapeFactory::calculateTopLeftPositionToCenterObject( + const awt::Point& rTargetAreaPosition + , const awt::Size& rTargetAreaSize + , const awt::Size& rObjectSize ) +{ + awt::Point aNewPosition(rTargetAreaPosition); + aNewPosition.X += static_cast<sal_Int32>(double(rTargetAreaSize.Width-rObjectSize.Width)/2.0); + aNewPosition.Y += static_cast<sal_Int32>(double(rTargetAreaSize.Height-rObjectSize.Height)/2.0); + return aNewPosition; +} + +::basegfx::B2IRectangle ShapeFactory::getRectangleOfShape( + const uno::Reference< drawing::XShape >& xShape ) +{ + ::basegfx::B2IRectangle aRet; + + if( xShape.is() ) + { + awt::Point aPos = xShape->getPosition(); + awt::Size aSize = xShape->getSize(); + aRet = BaseGFXHelper::makeRectangle(aPos,aSize); + } + return aRet; + +} + +awt::Size ShapeFactory::getSizeAfterRotation( + const uno::Reference< drawing::XShape >& xShape, double fRotationAngleDegree ) +{ + awt::Size aRet(0,0); + if(xShape.is()) + { + const awt::Size aSize( xShape->getSize() ); + + if( ::rtl::math::approxEqual( fRotationAngleDegree, 0.0 ) ) + aRet = aSize; + else + { + while(fRotationAngleDegree>=360.0) + fRotationAngleDegree-=360.0; + while(fRotationAngleDegree<0.0) + fRotationAngleDegree+=360.0; + if(fRotationAngleDegree>270.0) + fRotationAngleDegree=360.0-fRotationAngleDegree; + else if(fRotationAngleDegree>180.0) + fRotationAngleDegree=fRotationAngleDegree-180.0; + else if(fRotationAngleDegree>90.0) + fRotationAngleDegree=180.0-fRotationAngleDegree; + + const double fAnglePi = fRotationAngleDegree*F_PI/180.0; + + aRet.Height = static_cast<sal_Int32>( + aSize.Width*rtl::math::sin( fAnglePi ) + + aSize.Height*rtl::math::cos( fAnglePi )); + aRet.Width = static_cast<sal_Int32>( + aSize.Width*rtl::math::cos( fAnglePi ) + + aSize.Height*rtl::math::sin( fAnglePi )); + } + } + return aRet; +} + +void ShapeFactory::removeSubShapes( const uno::Reference< drawing::XShapes >& xShapes ) +{ + if( xShapes.is() ) + { + sal_Int32 nSubCount = xShapes->getCount(); + uno::Reference< drawing::XShape > xShape; + for( sal_Int32 nS = nSubCount; nS--; ) + { + if( xShapes->getByIndex( nS ) >>= xShape ) + xShapes->remove( xShape ); + } + } +} + +//............................................................................. +} //namespace chart +//............................................................................. |