blob: b6ed6c9f65b4d69f3fc7b78219ba085c80ddf4f1 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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_CIRCLE
, SYMBOL_STAR
, SYMBOL_X
, SYMBOL_PLUS
, SYMBOL_ASTERISK
, SYMBOL_HORIZONTAL_BAR
, SYMBOL_VERTICAL_BAR
, 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
// double fMaxSize = fHeightH > fWidthH ? fHeightH : fWidthH; //assumes non negative
const sal_Int32 nQuarterCount = 35; // points inside a quadrant, used in case circle
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:
case SYMBOL_HORIZONTAL_BAR:
case SYMBOL_VERTICAL_BAR:
nPointCount = 5;
break;
case SYMBOL_X:
nPointCount = 13;
break;
case SYMBOL_PLUS:
nPointCount = 13;
break;
case SYMBOL_STAR:
nPointCount = 9;
break;
case SYMBOL_ASTERISK:
nPointCount = 19;
break;
case SYMBOL_CIRCLE:
nPointCount = 5 + 4 * nQuarterCount;
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_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;
}
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;
}
case SYMBOL_HORIZONTAL_BAR:
{
*pInnerSequenceX++ = fX-fWidthH;
*pInnerSequenceY++ = fY-0.2*fHeightH;
*pInnerSequenceX++ = fX+fWidthH;
*pInnerSequenceY++ = fY-0.2*fHeightH;
*pInnerSequenceX++ = fX+fWidthH;
*pInnerSequenceY++ = fY+0.2*fHeightH;
*pInnerSequenceX++ = fX-fWidthH;
*pInnerSequenceY++ = fY+0.2*fHeightH;
*pInnerSequenceX++ = fX-fWidthH;
*pInnerSequenceY++ = fY-0.2*fHeightH;
break;
}
case SYMBOL_VERTICAL_BAR:
{
*pInnerSequenceX++ = fX-0.2*fWidthH;
*pInnerSequenceY++ = fY-fHeightH;
*pInnerSequenceX++ = fX+0.2*fWidthH;
*pInnerSequenceY++ = fY-fHeightH;
*pInnerSequenceX++ = fX+0.2*fWidthH;
*pInnerSequenceY++ = fY+fHeightH;
*pInnerSequenceX++ = fX-0.2*fWidthH;
*pInnerSequenceY++ = fY+fHeightH;
*pInnerSequenceX++ = fX-0.2*fWidthH;
*pInnerSequenceY++ = fY-fHeightH;
break;
}
case SYMBOL_CIRCLE:
{
double fOmega = 1.5707963267948966192 / (nQuarterCount + 1.0);
// one point in the middle of each edge to get full size bounding rectangle
*pInnerSequenceX++ = fX + fWidthH;
*pInnerSequenceY++ = fY;
// 0 to PI/2
for (sal_Int32 i = 1; i <= nQuarterCount; ++i)
{
*pInnerSequenceX++ = fX + fWidthH * cos( i * fOmega );
*pInnerSequenceY++ = fY - fHeightH * sin( i * fOmega );
}
// PI/2 to PI
*pInnerSequenceX++ = fX;
*pInnerSequenceY++ = fY - fHeightH;
for (sal_Int32 i = 1; i <= nQuarterCount; ++i)
{
*pInnerSequenceX++ = fX - fWidthH * sin( i * fOmega);
*pInnerSequenceY++ = fY - fHeightH * cos( i * fOmega);
}
// PI to 3/2*PI
*pInnerSequenceX++ = fX - fWidthH;
*pInnerSequenceY++ = fY;
for (sal_Int32 i = 1; i <= nQuarterCount; ++i)
{
*pInnerSequenceX++ = fX - fWidthH * cos( i * fOmega);
*pInnerSequenceY++ = fY + fHeightH * sin( i * fOmega);
}
// 3/2*PI to 2*PI
*pInnerSequenceX++ = fX;
*pInnerSequenceY++ = fY + fHeightH;
for (sal_Int32 i = 1; i <= nQuarterCount; ++i)
{
*pInnerSequenceX++ = fX + fWidthH * sin(i * fOmega);
*pInnerSequenceY++ = fY + fHeightH * cos(i * fOmega);
}
// close polygon
*pInnerSequenceX++ = fX + fWidthH;
*pInnerSequenceY++ = fY;
break;
}
case SYMBOL_STAR:
{
*pInnerSequenceX++ = fX;
*pInnerSequenceY++ = fY-fHeightH;
*pInnerSequenceX++ = fX+0.2*fWidthH;
*pInnerSequenceY++ = fY-0.2*fHeightH;
*pInnerSequenceX++ = fX+fWidthH;
*pInnerSequenceY++ = fY;
*pInnerSequenceX++ = fX+0.2*fWidthH;
*pInnerSequenceY++ = fY+0.2*fHeightH;
*pInnerSequenceX++ = fX;
*pInnerSequenceY++ = fY+fHeightH;
*pInnerSequenceX++ = fX-0.2*fWidthH;
*pInnerSequenceY++ = fY+0.2*fHeightH;
*pInnerSequenceX++ = fX-fWidthH;
*pInnerSequenceY++ = fY;
*pInnerSequenceX++ = fX-0.2*fWidthH;
*pInnerSequenceY++ = fY-0.2*fHeightH;
*pInnerSequenceX++ = fX;
*pInnerSequenceY++ = fY-fHeightH;
break;
}
case SYMBOL_X:
{
const double fScaleX = fWidthH / 128.0;
const double fScaleY = fHeightH / 128.0;
const double fSmall = sqrt(200.0);
const double fLarge = 128.0 - fSmall;
*pInnerSequenceX++ = fX;
*pInnerSequenceY++ = fY - fScaleY * fSmall;
*pInnerSequenceX++ = fX - fScaleX * fLarge;
*pInnerSequenceY++ = fY - fHeightH;
*pInnerSequenceX++ = fX - fWidthH;
*pInnerSequenceY++ = fY - fScaleY * fLarge;
*pInnerSequenceX++ = fX - fScaleX * fSmall;
*pInnerSequenceY++ = fY;
*pInnerSequenceX++ = fX - fWidthH;
*pInnerSequenceY++ = fY + fScaleY * fLarge;
*pInnerSequenceX++ = fX - fScaleX * fLarge;
*pInnerSequenceY++ = fY + fHeightH;
*pInnerSequenceX++ = fX;
*pInnerSequenceY++ = fY + fScaleY * fSmall;
*pInnerSequenceX++ = fX + fScaleX * fLarge;
*pInnerSequenceY++ = fY + fHeightH;
*pInnerSequenceX++ = fX + fWidthH;
*pInnerSequenceY++ = fY + fScaleY * fLarge;
*pInnerSequenceX++ = fX + fScaleX * fSmall;
*pInnerSequenceY++ = fY;
*pInnerSequenceX++ = fX + fWidthH;
*pInnerSequenceY++ = fY - fScaleY * fLarge;
*pInnerSequenceX++ = fX + fScaleX * fLarge;
*pInnerSequenceY++ = fY - fHeightH;
*pInnerSequenceX++ = fX;
*pInnerSequenceY++ = fY - fScaleY * fSmall;
break;
}
case SYMBOL_PLUS:
{
const double fScaleX = fWidthH / 128.0;
const double fScaleY = fHeightH / 128.0;
const double fHalf = 10.0; //half line width on 256 size square
const double fdX = fScaleX * fHalf;
const double fdY = fScaleY * fHalf;
*pInnerSequenceX++ = fX-fdX;
*pInnerSequenceY++ = fY-fHeightH;
*pInnerSequenceX++ = fX-fdX;
*pInnerSequenceY++ = fY-fdY;
*pInnerSequenceX++ = fX-fWidthH;
*pInnerSequenceY++ = fY-fdY;
*pInnerSequenceX++ = fX-fWidthH;
*pInnerSequenceY++ = fY+fdY;
*pInnerSequenceX++ = fX-fdX;
*pInnerSequenceY++ = fY+fdY;
*pInnerSequenceX++ = fX-fdX;
*pInnerSequenceY++ = fY+fHeightH;
*pInnerSequenceX++ = fX+fdX;
*pInnerSequenceY++ = fY+fHeightH;
*pInnerSequenceX++ = fX+fdX;
*pInnerSequenceY++ = fY+fdY;
*pInnerSequenceX++ = fX+fWidthH;
*pInnerSequenceY++ = fY+fdY;
*pInnerSequenceX++ = fX+fWidthH;
*pInnerSequenceY++ = fY-fdY;
*pInnerSequenceX++ = fX+fdX;
*pInnerSequenceY++ = fY-fdY;
*pInnerSequenceX++ = fX+fdY;
*pInnerSequenceY++ = fY-fHeightH;
*pInnerSequenceX++ = fX-fdX;
*pInnerSequenceY++ = fY-fHeightH;
break;
}
case SYMBOL_ASTERISK:
{
const double fHalf = 10.0; // half line width on 256 size square
const double fTwoY = fHalf * sqrt(3.0);
const double fFourY = (128.0 - 2.0 * fHalf ) / sqrt(3.0);
const double fThreeX = 128.0 - fHalf;
const double fThreeY = fHalf * sqrt(3.0) + fFourY;
const double fFiveX = 2.0 * fHalf;
const double fScaleX = fWidthH / 128.0;
const double fScaleY = fHeightH / 128.0;
//1
*pInnerSequenceX++ = fX-fScaleX * fHalf;
*pInnerSequenceY++ = fY-fHeightH;
//2
*pInnerSequenceX++ = fX-fScaleX * fHalf;
*pInnerSequenceY++ = fY-fScaleY * fTwoY;
//3
*pInnerSequenceX++ = fX-fScaleX * fThreeX;
*pInnerSequenceY++ = fY-fScaleY * fThreeY;
//4
*pInnerSequenceX++ = fX-fWidthH;
*pInnerSequenceY++ = fY-fScaleY * fFourY;
//5
*pInnerSequenceX++ = fX-fScaleX * fFiveX;
*pInnerSequenceY++ = fY;
//6 as 4
*pInnerSequenceX++ = fX-fWidthH;
*pInnerSequenceY++ = fY+fScaleY * fFourY;
//7 as 3
*pInnerSequenceX++ = fX-fScaleX * fThreeX;
*pInnerSequenceY++ = fY+fScaleY * fThreeY;
//8 as 2
*pInnerSequenceX++ = fX-fScaleX * fHalf;
*pInnerSequenceY++ = fY+fScaleY * fTwoY;
//9 as 1
*pInnerSequenceX++ = fX-fScaleX * fHalf;
*pInnerSequenceY++ = fY+fHeightH;
//10 as 1
*pInnerSequenceX++ = fX+fScaleX * fHalf;
*pInnerSequenceY++ = fY+fHeightH;
//11 as 2
*pInnerSequenceX++ = fX+fScaleX * fHalf;
*pInnerSequenceY++ = fY+fScaleY * fTwoY;
//12 as 3
*pInnerSequenceX++ = fX+fScaleX * fThreeX;
*pInnerSequenceY++ = fY+fScaleY * fThreeY;
//13 as 4
*pInnerSequenceX++ = fX+fWidthH;
*pInnerSequenceY++ = fY+fScaleY * fFourY;
//14 as 5
*pInnerSequenceX++ = fX+fScaleX * fFiveX;
*pInnerSequenceY++ = fY;
//15 as 4
*pInnerSequenceX++ = fX+fWidthH;
*pInnerSequenceY++ = fY-fScaleY * fFourY;
//16 as 3
*pInnerSequenceX++ = fX+fScaleX * fThreeX;
*pInnerSequenceY++ = fY-fScaleY * fThreeY;
//17 as 2
*pInnerSequenceX++ = fX+fScaleX * fHalf;
*pInnerSequenceY++ = fY-fScaleY * fTwoY;
// 18 as 1
*pInnerSequenceX++ = fX+fScaleX * fHalf;
*pInnerSequenceY++ = fY-fHeightH;
// 19 = 1, closing
*pInnerSequenceX++ = fX-fScaleX * fHalf;
*pInnerSequenceY++ = fY-fHeightH;
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.isEmpty() )
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.isEmpty() )
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.isEmpty() )
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
//.............................................................................