Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ShapeFactory.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */


#include <ShapeFactory.hxx>
#include <BaseGFXHelper.hxx>
#include <ViewDefines.hxx>
#include <Stripe.hxx>
#include <CommonConverters.hxx>
#include <RelativeSizeHelper.hxx>
#include <PropertyMapper.hxx>
#include <VLineProperties.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/chart2/XFormattedString.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/PolyPolygonBezierCoords.hpp>
#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
#include <com/sun/star/drawing/TextureProjectionMode.hpp>
#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
#include <com/sun/star/drawing/XShapes2.hpp>
#include <com/sun/star/graphic/XGraphic.hpp>
#include <com/sun/star/drawing/XShapes.hpp>
#include <com/sun/star/style/ParagraphAdjust.hpp>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/uno/Any.hxx>

#include <editeng/unoprnms.hxx>
#include <rtl/math.hxx>

#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/matrix/b3dhommatrix.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdopath.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <tools/helpers.hxx>
#include <tools/UnitConversion.hxx>
#include <sal/log.hxx>

#include <algorithm>
#include <cmath>
#include <cstddef>
#include <numbers>

using namespace ::com::sun::star;
using ::com::sun::star::uno::Reference;

namespace chart
{

namespace
{

void lcl_addProperty(uno::Sequence<OUString> & rPropertyNames, uno::Sequence<uno::Any> & rPropertyValues,
                 OUString const & rName, uno::Any const & rAny)
{
    rPropertyNames.realloc(rPropertyNames.getLength() + 1);
    rPropertyNames.getArray()[rPropertyNames.getLength() - 1] = rName;

    rPropertyValues.realloc(rPropertyValues.getLength() + 1);
    rPropertyValues.getArray()[rPropertyValues.getLength() - 1] = rAny;
}

css::drawing::PolyPolygonShape3D toPolyPolygonShape3D(const std::vector<std::vector<css::drawing::Position3D>>& rPoints)
{
    css::drawing::PolyPolygonShape3D aUnoPoly;
    aUnoPoly.SequenceX.realloc(rPoints.size());
    aUnoPoly.SequenceY.realloc(rPoints.size());
    aUnoPoly.SequenceZ.realloc(rPoints.size());
    for (std::size_t nPolygonIndex=0; nPolygonIndex<rPoints.size(); ++nPolygonIndex)
    {
        drawing::DoubleSequence* pOuterSequenceX = &aUnoPoly.SequenceX.getArray()[nPolygonIndex];
        drawing::DoubleSequence* pOuterSequenceY = &aUnoPoly.SequenceY.getArray()[nPolygonIndex];
        drawing::DoubleSequence* pOuterSequenceZ = &aUnoPoly.SequenceZ.getArray()[nPolygonIndex];
        pOuterSequenceX->realloc(rPoints[nPolygonIndex].size());
        pOuterSequenceY->realloc(rPoints[nPolygonIndex].size());
        pOuterSequenceZ->realloc(rPoints[nPolygonIndex].size());
        double* pInnerSequenceX = pOuterSequenceX->getArray();
        double* pInnerSequenceY = pOuterSequenceY->getArray();
        double* pInnerSequenceZ = pOuterSequenceZ->getArray();
        for (std::size_t nPointIndex=0; nPointIndex<rPoints[nPolygonIndex].size(); ++nPointIndex)
        {
            auto& rPos = rPoints[nPolygonIndex][nPointIndex];
            pInnerSequenceX[nPointIndex] = rPos.PositionX;
            pInnerSequenceY[nPointIndex] = rPos.PositionY;
            pInnerSequenceZ[nPointIndex] = rPos.PositionZ;
        }
    }
    return aUnoPoly;
}

// end anonymous namespace

rtl::Reference<SvxShapeGroupAnyD> ShapeFactory::getOrCreateChartRootShape(
    const rtl::Reference<SvxDrawPage>& xDrawPage )
{
    rtl::Reference<SvxShapeGroupAnyD> xRet = ShapeFactory::getChartRootShape(xDrawPage);
    if (xRet.is())
        return xRet;

    // Create a new root shape and set it to the bottom of the page.  The root
    // shape is identified by having the name com.sun.star.chart2.shapes.
    rtl::Reference<SvxShapeGroup> xShapeGroup = new SvxShapeGroup(nullptr, nullptr);
    xShapeGroup->setShapeKind(SdrObjKind::Group);
    // cast to resolve ambiguity in converting to XShape
    xDrawPage->addBottom(static_cast<SvxShape*>(xShapeGroup.get()));

    setShapeName(xShapeGroup, u"com.sun.star.chart2.shapes"_ustr);
    xShapeGroup->setSize(awt::Size(0,0));

    return xShapeGroup;
}

void ShapeFactory::setPageSize(const rtl::Reference<SvxShapeGroupAnyD>&, const awt::Size&) {}

//  diverse tools::PolyPolygon create methods

static uno::Any createPolyPolygon_Cube(
            const drawing::Direction3D& rSize, double fRoundedEdge, bool bRounded )
{
    OSL_PRECOND(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 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;

    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, cppu::UnoType<drawing::PolyPolygonShape3D>::get());
}

static uno::Any createPolyPolygon_Cylinder(
             double fHeight
           , double fRadius
           , sal_Int32& nVerticalSegmentCount )
{
    //fHeight may be negative
    OSL_PRECOND(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, cppu::UnoType<drawing::PolyPolygonShape3D>::get());
}

static uno::Any createPolyPolygon_Cone( double fHeight, double fRadius, double fTopHeight
            , sal_Int32& nVerticalSegmentCount )
{
    OSL_PRECOND(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, cppu::UnoType<drawing::PolyPolygonShape3D>::get());
}

//  methods for 3D shape creation

rtl::Reference<Svx3DExtrudeObject>
        ShapeFactory::createCube(
            const rtl::Reference<SvxShapeGroupAnyD>& 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 nullptr;
    if( bRounded )
    {
        try
        {
            if( xSourceProp.is() )
            {
                drawing::LineStyle aLineStyle;
                xSourceProp->getPropertyValue( u"BorderStyle"_ustr ) >>= aLineStyle;
                if( aLineStyle == drawing::LineStyle_SOLID )
                    bRounded = false;
            }
        }
        catchconst uno::Exception& )
        {
            TOOLS_WARN_EXCEPTION("chart2""" );
        }
    }
    rtl::Reference<Svx3DExtrudeObject> xShape = impl_createCube( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree, bRounded );
    if( xSourceProp.is())
        PropertyMapper::setMappedProperties( *xShape, xSourceProp, rPropertyNameMap );
    return xShape;
}

rtl::Reference<Svx3DExtrudeObject>
        ShapeFactory::impl_createCube(
              const rtl::Reference<SvxShapeGroupAnyD>& xTarget
            , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize
            , sal_Int32 nRotateZAngleHundredthDegree
            , bool bRounded )
{
    if( !xTarget.is() )
        return nullptr;

    //create shape
    rtl::Reference<Svx3DExtrudeObject> xShape = new Svx3DExtrudeObject(nullptr);
    xShape->setShapeKind(SdrObjKind::E3D_Extrusion);
    xTarget->addShape(*xShape);

    //set properties
    try
    {
        //depth
        double fDepth = rSize.DirectionZ;
        if (fDepth<0)
            fDepth*=-1.0;

        //PercentDiagonal
        sal_Int16 nPercentDiagonal = bRounded ? 3 : 0;

        //Matrix for position
        basegfx::B3DHomMatrix aHomMatrix;
        if (nRotateZAngleHundredthDegree != 0)
            aHomMatrix.rotate(0.0, 0.0, -basegfx::deg2rad<100>(nRotateZAngleHundredthDegree));
        aHomMatrix.translate(rPosition.PositionX, rPosition.PositionY,
                             rPosition.PositionZ - (fDepth / 2.0));

        uno::Sequence<OUString> aPropertyNames {
            UNO_NAME_3D_EXTRUDE_DEPTH,
            UNO_NAME_3D_PERCENT_DIAGONAL,
            UNO_NAME_3D_POLYPOLYGON3D,
            UNO_NAME_3D_TRANSFORM_MATRIX,
        };

        uno::Sequence<uno::Any> aPropertyValues {
            uno::Any(sal_Int32(fDepth)), // Depth
            uno::Any(nPercentDiagonal),  // PercentDiagonal
            createPolyPolygon_Cube(rSize, double(nPercentDiagonal) / 200.0, bRounded),
            uno::Any(B3DHomMatrixToHomogenMatrix(aHomMatrix))
        };

        xShape->setPropertyValues(aPropertyNames, aPropertyValues);
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return xShape;
}

rtl::Reference<Svx3DLatheObject>
        ShapeFactory::createCylinder(
            const rtl::Reference<SvxShapeGroupAnyD>& xTarget
          , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize
          , sal_Int32 nRotateZAngleHundredthDegree )
{
    return impl_createConeOrCylinder(
              xTarget, rPosition, rSize, 0.0, nRotateZAngleHundredthDegree, true );
}

rtl::Reference<Svx3DSceneObject>
        ShapeFactory::createPyramid(
            const rtl::Reference<SvxShapeGroupAnyD>& 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 nullptr;

    rtl::Reference<Svx3DSceneObject> xGroup( ShapeFactory::createGroup3D( xTarget ) );

    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 xGroup;
}

rtl::Reference<Svx3DLatheObject>
        ShapeFactory::createCone(
            const rtl::Reference<SvxShapeGroupAnyD>& xTarget
          , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize
          , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree )
{
    return impl_createConeOrCylinder( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree, false );
}

rtl::Reference<Svx3DLatheObject>
        ShapeFactory::impl_createConeOrCylinder(
              const rtl::Reference<SvxShapeGroupAnyD>& xTarget
            , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize
            , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree
            , bool bCylinder )
{
    if( !xTarget.is() )
        return nullptr;

    //create shape
    rtl::Reference<Svx3DLatheObject> xShape = new Svx3DLatheObject(nullptr);
    xShape->setShapeKind(SdrObjKind::E3D_Lathe);
    xTarget->addShape(*xShape);

    double fWidth      = rSize.DirectionX/2.0; //The depth will be corrected 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
    try
    {
        //Polygon
        sal_Int32 nVerticalSegmentCount = 0;
        uno::Any aPPolygon = bCylinder
            ? createPolyPolygon_Cylinder(fHeight, fRadius, nVerticalSegmentCount)
            : createPolyPolygon_Cone(fHeight, fRadius, fTopHeight, nVerticalSegmentCount);

        //Matrix for position
        basegfx::B3DHomMatrix aHomMatrix;
        if (nRotateZAngleHundredthDegree != 0)
            aHomMatrix.rotate(0.0,0.0,-basegfx::deg2rad<100>(nRotateZAngleHundredthDegree));
        //stretch the symmetric objects to given depth
        aHomMatrix.scale(1.0,1.0,rSize.DirectionZ/rSize.DirectionX);
        aHomMatrix.translate(rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ);

        uno::Sequence<OUString> aPropertyNames{
            UNO_NAME_3D_PERCENT_DIAGONAL,
            UNO_NAME_3D_POLYPOLYGON3D,
            UNO_NAME_3D_TRANSFORM_MATRIX,
            UNO_NAME_3D_HORZ_SEGS,
            UNO_NAME_3D_VERT_SEGS,
            UNO_NAME_3D_REDUCED_LINE_GEOMETRY
        };

        uno::Sequence<uno::Any> aPropertyValues {
            uno::Any(sal_Int16(5)),  // PercentDiagonal
            aPPolygon,               // Polygon
            uno::Any(B3DHomMatrixToHomogenMatrix(aHomMatrix)), // Matrix
            uno::Any(CHART_3DOBJECT_SEGMENTCOUNT), // Horizontal Segments
            uno::Any(nVerticalSegmentCount),       // Vertical Segments
            uno::Any(true)                         // Reduced lines
        };

        xShape->setPropertyValues(aPropertyNames, aPropertyValues);
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return xShape;
}

static void appendAndCloseBezierCoords( drawing::PolyPolygonBezierCoords& rReturn, const drawing::PolyPolygonBezierCoords& rAdd, bool bAppendInverse )
{
    if(!rAdd.Coordinates.hasElements())
        return;
    sal_Int32 nAddCount = rAdd.Coordinates[0].getLength();
    if(!nAddCount)
        return;

    sal_Int32 nOldCount = rReturn.Coordinates[0].getLength();

    auto pCoordinates = rReturn.Coordinates.getArray();
    pCoordinates[0].realloc(nOldCount + nAddCount + 1);
    auto pCoordinates0 = pCoordinates[0].getArray();
    auto pFlags = rReturn.Flags.getArray();
    pFlags[0].realloc(nOldCount+nAddCount+1);
    auto pFlags0 = pFlags[0].getArray();

    for(sal_Int32 nN=0;nN<nAddCount; nN++ )
    {
        sal_Int32 nAdd = bAppendInverse ? (nAddCount-1-nN) : nN;
        pCoordinates0[nOldCount+nN] = rAdd.Coordinates[0][nAdd];
        pFlags0[nOldCount+nN] = rAdd.Flags[0][nAdd];
    }

    //close
    pCoordinates0[nOldCount+nAddCount] = rReturn.Coordinates[0][0];
    pFlags0[nOldCount+nAddCount] = rReturn.Flags[0][0];
}

static 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;
    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 fFirstAngleOnSubDivision = (static_cast<sal_Int32>(fStartAngleRadian/fAngleSubdivisionRadian)+1)*fAngleSubdivisionRadian;
        if( !::rtl::math::approxEqual( fStartAngleRadian, fFirstAngleOnSubDivision ) )
            fFirstSegmentAngle = fFirstAngleOnSubDivision-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

    drawing::PointSequence aPoints(nPointCount);
    auto pPoints = aPoints.getArray();
    drawing::FlagSequence  aFlags(nPointCount);
    auto pFlags = aFlags.getArray();

    //!! 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;

    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 subdivision
            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);

        pPoints[nPoint].X = static_cast< sal_Int32 >( P0.getX());
        pPoints[nPoint].Y = static_cast< sal_Int32 >( P0.getY());
        pFlags [nPoint++] = drawing::PolygonFlags_NORMAL;

        pPoints[nPoint].X = static_cast< sal_Int32 >( P1.getX());
        pPoints[nPoint].Y = static_cast< sal_Int32 >( P1.getY());
        pFlags[nPoint++] = drawing::PolygonFlags_CONTROL;

        pPoints[nPoint].X = static_cast< sal_Int32 >( P2.getX());
        pPoints[nPoint].Y = static_cast< sal_Int32 >( P2.getY());
        pFlags [nPoint++] = drawing::PolygonFlags_CONTROL;

        if(nSegment==(nSegmentCount-1))
        {
            pPoints[nPoint].X = static_cast< sal_Int32 >( P3.getX());
            pPoints[nPoint].Y = static_cast< sal_Int32 >( P3.getY());
            pFlags [nPoint++] = drawing::PolygonFlags_NORMAL;
        }
    }

    aReturn.Coordinates = { aPoints };
    aReturn.Flags = { aFlags };

    return aReturn;
}

static drawing::PolyPolygonBezierCoords getRingBezierCoords(
            double fUnitCircleInnerRadius
            , double fUnitCircleOuterRadius
            , double fStartAngleRadian, double fWidthAngleRadian
            , const ::basegfx::B2DHomMatrix& aTransformationFromUnitCircle
            , const double fAngleSubdivisionRadian )
{
    drawing::PolyPolygonBezierCoords aReturn;

    drawing::PolyPolygonBezierCoords aOuterArc = getCircularArcBezierCoords(
        fStartAngleRadian, fWidthAngleRadian, fUnitCircleOuterRadius, aTransformationFromUnitCircle, fAngleSubdivisionRadian );
    aReturn.Coordinates = { aOuterArc.Coordinates[0] };
    aReturn.Flags = { aOuterArc.Flags[0] };

    drawing::PolyPolygonBezierCoords aInnerArc = getCircularArcBezierCoords(
        fStartAngleRadian, fWidthAngleRadian, fUnitCircleInnerRadius, aTransformationFromUnitCircle, fAngleSubdivisionRadian );
    appendAndCloseBezierCoords( aReturn, aInnerArc, true );

    return aReturn;
}

rtl::Reference<SvxShapePolyPolygon>
        ShapeFactory::createPieSegment2D(
                    const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree
                    , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius
                    , const drawing::Direction3D& rOffset
                    , const drawing::HomogenMatrix& rUnitCircleToScene )
{
    if( !xTarget.is() )
        return nullptr;

    // tdf#123504: both 0 and 360 are valid and different values here!
    while (fUnitCircleWidthAngleDegree > 360)
        fUnitCircleWidthAngleDegree -= 360.0;
    while (fUnitCircleWidthAngleDegree < 0)
        fUnitCircleWidthAngleDegree += 360.0;

    //create shape
    rtl::Reference<SvxShapePolyPolygon> xShape = new SvxShapePolyPolygon(nullptr);
    xShape->setShapeKind(SdrObjKind::PathFill); // aka ClosedBezierShape
    xTarget->addShape(*xShape); //need to add the shape before setting of properties

    if (std::isnan(fUnitCircleWidthAngleDegree))
    {
        SAL_WARN("chart2""fUnitCircleWidthAngleDegree isNaN");
        return xShape;
    }

    //set properties
    try
    {
        ::basegfx::B2DHomMatrix aTransformationFromUnitCircle( IgnoreZ( HomogenMatrixToB3DHomMatrix(rUnitCircleToScene) ) );
        aTransformationFromUnitCircle.translate(rOffset.DirectionX,rOffset.DirectionY);

        const double fAngleSubdivisionRadian = M_PI/10.0;

        drawing::PolyPolygonBezierCoords aCoords
            = getRingBezierCoords(fUnitCircleInnerRadius, fUnitCircleOuterRadius,
                                  basegfx::deg2rad(fUnitCircleStartAngleDegree),
                                  basegfx::deg2rad(fUnitCircleWidthAngleDegree),
                                  aTransformationFromUnitCircle, fAngleSubdivisionRadian);

        xShape->SvxShape::setPropertyValue( u"PolyPolygonBezier"_ustr, uno::Any( aCoords ) );
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }

    return xShape;
}

rtl::Reference<Svx3DExtrudeObject>
        ShapeFactory::createPieSegment(
                    const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree
                    , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius
                    , const drawing::Direction3D& rOffset
                    , const drawing::HomogenMatrix& rUnitCircleToScene
                    , double fDepth )
{
    if( !xTarget.is() )
        return nullptr;

    // tdf#123504: both 0 and 360 are valid and different values here!
    while (fUnitCircleWidthAngleDegree > 360)
        fUnitCircleWidthAngleDegree -= 360.0;
    while (fUnitCircleWidthAngleDegree < 0)
        fUnitCircleWidthAngleDegree += 360.0;

    //create shape
    rtl::Reference<Svx3DExtrudeObject> xShape = new Svx3DExtrudeObject(nullptr);
    xShape->setShapeKind(SdrObjKind::E3D_Extrusion);
    xTarget->addShape(*xShape); //need to add the shape before setting of properties

    //set properties
    try
    {
        ::basegfx::B2DHomMatrix aTransformationFromUnitCircle( IgnoreZ( HomogenMatrixToB3DHomMatrix(rUnitCircleToScene) ) );
        aTransformationFromUnitCircle.translate(rOffset.DirectionX,rOffset.DirectionY);

        const double fAngleSubdivisionRadian = M_PI/32.0;

        drawing::PolyPolygonBezierCoords aCoords
            = getRingBezierCoords(fUnitCircleInnerRadius, fUnitCircleOuterRadius,
                                  basegfx::deg2rad(fUnitCircleStartAngleDegree),
                                  basegfx::deg2rad(fUnitCircleWidthAngleDegree),
                                  aTransformationFromUnitCircle, fAngleSubdivisionRadian);

        //depth
        xShape->setPropertyValue( UNO_NAME_3D_EXTRUDE_DEPTH
            , uno::Any(static_cast<sal_Int32>(fDepth)) );

        //PercentDiagonal
        xShape->setPropertyValue( UNO_NAME_3D_PERCENT_DIAGONAL
            , uno::Any( sal_Int16(0) ) );

        //Polygon
        drawing::PolyPolygonShape3D aPoly( BezierToPoly(aCoords) );
        ShapeFactory::closePolygon( aPoly );
        xShape->setPropertyValue( UNO_NAME_3D_POLYPOLYGON3D
            , uno::Any( aPoly ) );

        //DoubleSided
        xShape->setPropertyValue( UNO_NAME_3D_DOUBLE_SIDED
            , uno::Any( true ) );

        //Reduced lines
        xShape->setPropertyValue( UNO_NAME_3D_REDUCED_LINE_GEOMETRY
            , uno::Any( true ) );

        //TextureProjectionMode
        xShape->setPropertyValue( UNO_NAME_3D_TEXTURE_PROJ_Y
            , uno::Any( drawing::TextureProjectionMode_OBJECTSPECIFIC ) );

        //TextureProjectionMode
        xShape->setPropertyValue( UNO_NAME_3D_TEXTURE_PROJ_X
            , uno::Any( drawing::TextureProjectionMode_PARALLEL ) );
        xShape->setPropertyValue( UNO_NAME_3D_TEXTURE_PROJ_Y
            , uno::Any( drawing::TextureProjectionMode_OBJECTSPECIFIC ) );
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return xShape;
}

rtl::Reference<Svx3DPolygonObject>
        ShapeFactory::createStripe( const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , const Stripe& rStripe
                    , const uno::Reference< beans::XPropertySet >& xSourceProp
                    , const tPropertyNameMap& rPropertyNameMap
                    , bool bDoubleSided
                    , short nRotatedTexture
                    , bool bFlatNormals )
{
    if( !xTarget.is() )
        return nullptr;

    //create shape
    rtl::Reference<Svx3DPolygonObject> xShape = new Svx3DPolygonObject(nullptr);
    xShape->setShapeKind(SdrObjKind::E3D_Polygon);
    xTarget->addShape(*xShape);

    //set properties
    try
    {
        uno::Sequence<OUString> aPropertyNames{
            UNO_NAME_3D_POLYPOLYGON3D,
            UNO_NAME_3D_TEXTUREPOLYGON3D,
            UNO_NAME_3D_NORMALSPOLYGON3D,
            UNO_NAME_3D_LINEONLY,
            UNO_NAME_3D_DOUBLE_SIDED
        };

        uno::Sequence<uno::Any> aPropertyValues {
            rStripe.getPolyPolygonShape3D(),            // Polygon
            Stripe::getTexturePolygon(nRotatedTexture), // TexturePolygon
            rStripe.getNormalsPolygon(),                // Normals Polygon
            uno::Any(false),        // LineOnly
            uno::Any(bDoubleSided)  // DoubleSided
        };

        //NormalsKind
        if (bFlatNormals)
            lcl_addProperty(aPropertyNames, aPropertyValues,
                            UNO_NAME_3D_NORMALS_KIND, uno::Any(drawing::NormalsKind_FLAT));

        xShape->setPropertyValues(aPropertyNames, aPropertyValues);

        if (xSourceProp)
        {
            PropertyMapper::setMappedProperties(*xShape, xSourceProp, rPropertyNameMap);
        }
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return xShape;
}

rtl::Reference<Svx3DExtrudeObject>
        ShapeFactory::createArea3D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , const std::vector<std::vector<css::drawing::Position3D>>& rPolyPolygon
                    , double fDepth )
{
    if( !xTarget.is() )
        return nullptr;

    if( rPolyPolygon.empty() )
        return nullptr;

    //create shape
    rtl::Reference<Svx3DExtrudeObject> xShape = new Svx3DExtrudeObject(nullptr);
    xShape->setShapeKind(SdrObjKind::E3D_Extrusion);
    xTarget->addShape(*xShape);

    css::drawing::PolyPolygonShape3D aUnoPolyPolygon = toPolyPolygonShape3D(rPolyPolygon);

    //set properties
    try
    {
        uno::Sequence<OUString> aPropertyNames{
            UNO_NAME_3D_EXTRUDE_DEPTH,
            UNO_NAME_3D_PERCENT_DIAGONAL,
            UNO_NAME_3D_POLYPOLYGON3D,
            UNO_NAME_3D_DOUBLE_SIDED,
        };

        uno::Sequence<uno::Any> aPropertyValues {
            uno::Any(sal_Int32(fDepth)), // depth
            uno::Any(sal_Int16(0)),      // PercentDiagonal
            uno::Any(aUnoPolyPolygon),      // Polygon
            uno::Any(true)               // DoubleSided
        };

        //the z component of the polygon is now ignored by the drawing layer,
        //so we need to translate the object via transformation matrix

        //Matrix for position
        if (!rPolyPolygon[0].empty())
        {
            basegfx::B3DHomMatrix aM;
            aM.translate(0, 0, rPolyPolygon[0][0].PositionZ);
            drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM);
            lcl_addProperty(aPropertyNames, aPropertyValues, UNO_NAME_3D_TRANSFORM_MATRIX, uno::Any(aHM));
        }
        xShape->setPropertyValues(aPropertyNames, aPropertyValues);
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return xShape;
}

rtl::Reference<SvxShapePolyPolygon>
        ShapeFactory::createArea2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , const std::vector<std::vector<css::drawing::Position3D>>& rPolyPolygon )
{
    if( !xTarget.is() )
        return nullptr;

    //create shape
    rtl::Reference<SdrPathObj> pPath = new SdrPathObj(xTarget->GetSdrObject()->getSdrModelFromSdrObject(), SdrObjKind::Polygon);
    xTarget->GetSdrObject()->GetSubList()->InsertObject(pPath.get());

    //set properties
    try
    {
        // Polygon
        basegfx::B2DPolyPolygon aNewPolyPolygon( PolyToB2DPolyPolygon(rPolyPolygon) );
        // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
        pPath->ForceMetricToItemPoolMetric(aNewPolyPolygon);
        pPath->SetPathPoly(aNewPolyPolygon);
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return static_cast<SvxShapePolyPolygon*>(pPath->getUnoShape().get());
}

static drawing::PointSequenceSequence createPolyPolygon_Symbol( const drawing::Position3D& rPos
                                 , const drawing::Direction3D& rSize
                                 , sal_Int32 nStandardSymbol )
{
    if(nStandardSymbol<0)
        nStandardSymbol*=-1;
    nStandardSymbol = nStandardSymbol%ShapeFactory::getSymbolCount();
    SymbolEnum eSymbolType=static_cast<SymbolEnum>(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

    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_HorizontalBar:
        case Symbol_VerticalBar:
            nPointCount = 5;
            break;
        case Symbol_X:
        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::PointSequenceSequence aPP;

    aPP.realloc(1);

    uno::Sequence<awt::Point>* pOuterSequence = aPP.getArray();

    pOuterSequence->realloc(nPointCount);

    awt::Point* pInnerSequence = pOuterSequence->getArray();

    auto toPoint = [](double x, double y) -> awt::Point
        {
            return { static_cast<sal_Int32>(x), static_cast<sal_Int32>(y) };
        };
    switch(eSymbolType)
    {
        case Symbol_Square:
        {
            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );
            break;
        }
        case Symbol_UpArrow:
        {
            *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH );
            break;
        }
        case Symbol_DownArrow:
        {
            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );
            break;
        }
        case Symbol_RightArrow:
        {
            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH  );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );
            break;
        }
        case Symbol_LeftArrow:
        {
            *pInnerSequence++ = toPoint( fX-fWidthH, fY );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY );
            break;
        }
        case Symbol_Bowtie:
        {
            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );
            break;
        }
        case Symbol_Sandglass:
        {
            *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH );
            break;
        }
        case Symbol_Diamond:
        {
            *pInnerSequence++ = toPoint( fX-fWidthH, fY );

            *pInnerSequence++ = toPoint( fX, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY );

            *pInnerSequence++ = toPoint( fX, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY );
            break;
        }
        case Symbol_HorizontalBar:
        {
            *pInnerSequence++ = toPoint( fX-fWidthH, fY-0.2*fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY-0.2*fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY+0.2*fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY+0.2*fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY-0.2*fHeightH );
            break;
        }
        case Symbol_VerticalBar:
        {
            *pInnerSequence++ = toPoint( fX-0.2*fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX+0.2*fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX+0.2*fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX-0.2*fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX-0.2*fWidthH, fY-fHeightH );

            break;
        }
        case Symbol_Circle:
        {
            double fOmega = M_PI_2 / (nQuarterCount + 1.0);
            // one point in the middle of each edge to get full size bounding rectangle
            *pInnerSequence++ = toPoint( fX + fWidthH, fY );
            // 0 to PI/2
            for (sal_Int32 i = 1; i <= nQuarterCount; ++i)
            {
                *pInnerSequence++ = toPoint( fX + fWidthH * cos( i * fOmega ), fY - fHeightH * sin( i * fOmega ) );
            }
            // PI/2 to PI
            *pInnerSequence++ = toPoint( fX, fY - fHeightH );
            for (sal_Int32 i = 1; i <= nQuarterCount; ++i)
            {
                *pInnerSequence++ = toPoint( fX - fWidthH * sin( i * fOmega), fY - fHeightH * cos( i * fOmega) );
            }
            // PI to 3/2*PI
            *pInnerSequence++ = toPoint( fX - fWidthH, fY );
            for (sal_Int32 i = 1; i <= nQuarterCount; ++i)
            {
                *pInnerSequence++ = toPoint( fX - fWidthH * cos( i * fOmega), fY + fHeightH * sin( i * fOmega) );
            }
            // 3/2*PI to 2*PI
            *pInnerSequence++ = toPoint( fX, fY + fHeightH );
            for (sal_Int32 i = 1; i <= nQuarterCount; ++i)
            {
                *pInnerSequence++ = toPoint( fX + fWidthH * sin(i * fOmega), fY + fHeightH * cos(i * fOmega) );
            }
            // close polygon
            *pInnerSequence++ = toPoint( fX + fWidthH, fY );
            break;
        }
        case Symbol_Star:
        {
            *pInnerSequence++ = toPoint( fX, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX+0.2*fWidthH, fY-0.2*fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY );

            *pInnerSequence++ = toPoint( fX+0.2*fWidthH, fY+0.2*fHeightH );

            *pInnerSequence++ = toPoint( fX, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX-0.2*fWidthH, fY+0.2*fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY );

            *pInnerSequence++ = toPoint( fX-0.2*fWidthH, fY-0.2*fHeightH );

            *pInnerSequence++ = toPoint( fX, fY-fHeightH );
            break;
        }
        case Symbol_X:
        {
            const double fScaleX = fWidthH / 128.0;
            const double fScaleY = fHeightH / 128.0;
            constexpr double fSmall = std::numbers::sqrt2 * 10;
            constexpr double fLarge = 128.0 - fSmall;

            *pInnerSequence++ = toPoint( fX, fY - fScaleY * fSmall );

            *pInnerSequence++ = toPoint( fX - fScaleX * fLarge, fY - fHeightH );

            *pInnerSequence++ = toPoint( fX - fWidthH, fY - fScaleY * fLarge );

            *pInnerSequence++ = toPoint( fX - fScaleX * fSmall, fY );

            *pInnerSequence++ = toPoint( fX - fWidthH, fY + fScaleY * fLarge );

            *pInnerSequence++ = toPoint( fX - fScaleX * fLarge, fY + fHeightH );

            *pInnerSequence++ = toPoint( fX, fY + fScaleY * fSmall );

            *pInnerSequence++ = toPoint( fX + fScaleX * fLarge, fY + fHeightH );

            *pInnerSequence++ = toPoint( fX + fWidthH, fY + fScaleY * fLarge );

            *pInnerSequence++ = toPoint( fX + fScaleX * fSmall, fY );

            *pInnerSequence++ = toPoint( fX + fWidthH, fY - fScaleY * fLarge );

            *pInnerSequence++ = toPoint( fX + fScaleX * fLarge, fY - fHeightH );

            *pInnerSequence++ = toPoint( fX, fY - fScaleY * fSmall );
            break;

        }
        case Symbol_Plus:
        {
            const double fScaleX = fWidthH / 128.0;
            const double fScaleY = fHeightH / 128.0;
            constexpr double fHalf = 10.0; //half line width on 256 size square
            const double fdX = fScaleX * fHalf;
            const double fdY = fScaleY * fHalf;

            *pInnerSequence++ = toPoint( fX-fdX, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fdX, fY-fdY );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fdY );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY+fdY );

            *pInnerSequence++ = toPoint( fX-fdX, fY+fdY );

            *pInnerSequence++ = toPoint( fX-fdX, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fdX, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fdX, fY+fdY );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY+fdY );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY-fdY );

            *pInnerSequence++ = toPoint( fX+fdX, fY-fdY );

            *pInnerSequence++ = toPoint( fX+fdY, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fdX, fY-fHeightH );
            break;

        }
        case Symbol_Asterisk:
        {
            constexpr double fHalf = 10.0; // half line width on 256 size square
            constexpr double fTwoY = fHalf * std::numbers::sqrt3;
            constexpr double fFourY = (128.0 - 2.0 * fHalf ) * std::numbers::inv_sqrt3;
            constexpr double fThreeX = 128.0 - fHalf;
            constexpr double fThreeY = fHalf * std::numbers::sqrt3 + fFourY;
            constexpr double fFiveX = 2.0 * fHalf;

            const double fScaleX = fWidthH / 128.0;
            const double fScaleY = fHeightH / 128.0;

            //1
            *pInnerSequence++ = toPoint( fX-fScaleX * fHalf, fY-fHeightH );
            //2
            *pInnerSequence++ = toPoint( fX-fScaleX * fHalf, fY-fScaleY * fTwoY );
            //3
            *pInnerSequence++ = toPoint( fX-fScaleX * fThreeX, fY-fScaleY * fThreeY );
            //4
            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fScaleY * fFourY );
            //5
            *pInnerSequence++ = toPoint( fX-fScaleX * fFiveX, fY );
            //6 as 4
            *pInnerSequence++ = toPoint( fX-fWidthH, fY+fScaleY * fFourY );
            //7 as 3
            *pInnerSequence++ = toPoint( fX-fScaleX * fThreeX, fY+fScaleY * fThreeY );
            //8 as 2
            *pInnerSequence++ = toPoint( fX-fScaleX * fHalf, fY+fScaleY * fTwoY );
            //9 as 1
            *pInnerSequence++ = toPoint( fX-fScaleX * fHalf, fY+fHeightH );
            //10 as 1
            *pInnerSequence++ = toPoint( fX+fScaleX * fHalf, fY+fHeightH );
            //11 as 2
            *pInnerSequence++ = toPoint( fX+fScaleX * fHalf, fY+fScaleY * fTwoY );
            //12 as 3
            *pInnerSequence++ = toPoint( fX+fScaleX * fThreeX, fY+fScaleY * fThreeY );
            //13 as 4
            *pInnerSequence++ = toPoint( fX+fWidthH, fY+fScaleY * fFourY );
            //14 as 5
            *pInnerSequence++ = toPoint( fX+fScaleX * fFiveX, fY );
            //15 as 4
            *pInnerSequence++ = toPoint( fX+fWidthH, fY-fScaleY * fFourY );
            //16 as 3
            *pInnerSequence++ = toPoint( fX+fScaleX * fThreeX, fY-fScaleY * fThreeY );
            //17 as 2
            *pInnerSequence++ = toPoint( fX+fScaleX * fHalf, fY-fScaleY * fTwoY );
            // 18 as 1
            *pInnerSequence++ = toPoint( fX+fScaleX * fHalf, fY-fHeightH );
            // 19 = 1, closing
            *pInnerSequence++ = toPoint( fX-fScaleX * fHalf, fY-fHeightH );
            break;
        }
        default//case Symbol_Square:
        {
            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH );

            *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH );

            *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH );
            break;
        }
    }

    return aPP;
}

rtl::Reference<SvxShapePolyPolygon>
        ShapeFactory::createSymbol2D(
                      const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , const drawing::Position3D& rPosition
                    , const drawing::Direction3D& rSize
                    , sal_Int32 nStandardSymbol
                    , sal_Int32 nBorderColor
                    , sal_Int32 nFillColor )
{
    if( !xTarget.is() )
        return nullptr;

    //create shape
    rtl::Reference<SvxShapePolyPolygon> xShape = new SvxShapePolyPolygon(nullptr);
    xShape->setShapeKind(SdrObjKind::Polygon);
    xTarget->addShape(*xShape);

    //set properties
    try
    {
        drawing::PointSequenceSequence aPoints =
            createPolyPolygon_Symbol( rPosition, rSize, nStandardSymbol );

        //Polygon
        xShape->SvxShape::setPropertyValue( UNO_NAME_POLYPOLYGON
            , uno::Any( aPoints ) );

        //LineColor
        xShape->SvxShape::setPropertyValue( UNO_NAME_LINECOLOR
            , uno::Any( nBorderColor ) );

        //FillColor
        xShape->SvxShape::setPropertyValue( UNO_NAME_FILLCOLOR
            , uno::Any( nFillColor ) );
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return xShape;
}

rtl::Reference<SvxGraphicObject>
        ShapeFactory::createGraphic2D(
                      const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , const drawing::Position3D& rPosition
                    , const drawing::Direction3D& rSize
                    , const uno::Reference< graphic::XGraphic >& xGraphic )
{
    if( !xTarget.is() || !xGraphic.is() )
        return nullptr;

    // @todo: change this to a rectangle shape with a fill bitmap for
    // performance reasons (ask AW, said CL)

    //create shape
    rtl::Reference<SvxGraphicObject> xShape = new SvxGraphicObject(nullptr);
    xShape->setShapeKind(SdrObjKind::Graphic);
    xTarget->addShape(*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 ));
    }
    catchconst uno::Exception & )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    try
    {
        xShape->SvxShape::setPropertyValue( u"Graphic"_ustr, uno::Any( xGraphic ));
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return xShape;
}

rtl::Reference< SvxShapeGroup >
        ShapeFactory::createGroup2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget
        , const OUString& aName )
{
    if( !xTarget.is() )
        return nullptr;
    try
    {
        //create and add to target
        rtl::Reference<SvxShapeGroup> xShapeGroup = new SvxShapeGroup(nullptr, nullptr);
        xShapeGroup->setShapeKind(SdrObjKind::Group);
        // cast to resolve ambiguity in converting to XShape
        xTarget->addShape(*xShapeGroup);

        //set name
        if(!aName.isEmpty())
            setShapeName( xShapeGroup, aName );

        {//workaround
            //need this null size as otherwise empty group shapes where painted with a gray border
            xShapeGroup->setSize(awt::Size(0,0));
        }

        return xShapeGroup;
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return nullptr;
}

rtl::Reference< SvxShapeGroup >
        ShapeFactory::createGroup2D( const rtl::Reference<SvxDrawPage>& xTarget
        , const OUString& aName )
{
    if( !xTarget.is() )
        return nullptr;
    try
    {
        //create and add to target
        rtl::Reference<SvxShapeGroup> xShapeGroup = new SvxShapeGroup(nullptr, nullptr);
        xShapeGroup->setShapeKind(SdrObjKind::Group);
        // cast to resolve ambiguity in converting to XShape
        xTarget->add(static_cast<SvxShape*>(xShapeGroup.get()));

        //set name
        if(!aName.isEmpty())
            setShapeName( xShapeGroup, aName );

        {//workaround
            //need this null size as otherwise empty group shapes where painted with a gray border
            xShapeGroup->setSize(awt::Size(0,0));
        }

        return xShapeGroup;
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return nullptr;
}

rtl::Reference<Svx3DSceneObject>
        ShapeFactory::createGroup3D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget
        , const OUString& aName )
{
    if( !xTarget.is() )
        return nullptr;
    try
    {
        //create shape
        rtl::Reference<Svx3DSceneObject> xShape = new Svx3DSceneObject(nullptr, nullptr);
        xShape->setShapeKind(SdrObjKind::E3D_Scene);
        xTarget->addShape(*xShape);

        //it is necessary to set the transform matrix to initialize the scene properly
        //otherwise all objects which are placed into this Group will not be visible
        //the following should be unnecessary after the bug is fixed
        //set properties
        try
        {
            ::basegfx::B3DHomMatrix aM;
            xShape->SvxShape::setPropertyValue( UNO_NAME_3D_TRANSFORM_MATRIX
                , uno::Any(B3DHomMatrixToHomogenMatrix(aM)) );
        }
        catchconst uno::Exception& )
        {
            TOOLS_WARN_EXCEPTION("chart2""" );
        }

        //set name
        if(!aName.isEmpty())
            setShapeName( xShape , aName );

        //return
        return xShape;
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return nullptr;
}

rtl::Reference<SvxShapeCircle>
        ShapeFactory::createCircle2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , const drawing::Position3D& rPosition
                    , const drawing::Direction3D& rSize )
{
    if( !xTarget.is() )
        return nullptr;

    //create shape
    rtl::Reference<SvxShapeCircle> xShape = new SvxShapeCircle(nullptr);
    xShape->setShapeKind(SdrObjKind::CircleOrEllipse);
    xTarget->addShape(*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 ));
    }
    catchconst uno::Exception & )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }

    //set properties
    try
    {
        xShape->SvxShape::setPropertyValue( UNO_NAME_CIRCKIND, uno::Any( drawing::CircleKind_FULL ) );
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return xShape;
}

rtl::Reference<SvxShapeCircle>
    ShapeFactory::createCircle( const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , const awt::Size& rSize
                    , const awt::Point& rPosition )
{
    rtl::Reference<SvxShapeCircle> xShape = new SvxShapeCircle(nullptr);
    xShape->setShapeKind(SdrObjKind::CircleOrEllipse);
    xTarget->addShape(*xShape);
    xShape->setSize( rSize );
    xShape->setPosition( rPosition );

    return xShape;
}

rtl::Reference<Svx3DPolygonObject>
        ShapeFactory::createLine3D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , const std::vector<std::vector<css::drawing::Position3D>>& rPoints
                    , const VLineProperties& rLineProperties )
{
    if( !xTarget.is() )
        return nullptr;

    if(rPoints.empty())
        return nullptr;

    //create shape
    rtl::Reference<Svx3DPolygonObject> xShape = new Svx3DPolygonObject(nullptr);
    xShape->setShapeKind(SdrObjKind::E3D_Polygon);
    xTarget->addShape(*xShape);

    css::drawing::PolyPolygonShape3D aUnoPoly = toPolyPolygonShape3D(rPoints);

    //set properties
    try
    {
        uno::Sequence<OUString> aPropertyNames {
            UNO_NAME_3D_POLYPOLYGON3D,
            UNO_NAME_3D_LINEONLY
        };

        uno::Sequence<uno::Any> aPropertyValues {
            uno::Any(aUnoPoly),  // Polygon
            uno::Any(true)      // LineOnly
        };

        //Transparency
        if(rLineProperties.Transparence.hasValue())
        {
            lcl_addProperty(aPropertyNames, aPropertyValues,
                            UNO_NAME_LINETRANSPARENCE,
                            rLineProperties.Transparence);
        }

        //LineStyle
        if(rLineProperties.LineStyle.hasValue())
        {
            lcl_addProperty(aPropertyNames, aPropertyValues,
                            UNO_NAME_LINESTYLE,
                            rLineProperties.LineStyle);
        }

        //LineWidth
        if(rLineProperties.Width.hasValue())
        {
            lcl_addProperty(aPropertyNames, aPropertyValues,
                            UNO_NAME_LINEWIDTH,
                            rLineProperties.Width);
        }

        //LineColor
        if(rLineProperties.Color.hasValue())
        {
            lcl_addProperty(aPropertyNames, aPropertyValues,
                            UNO_NAME_LINECOLOR,
                            rLineProperties.Color);
        }
        xShape->setPropertyValues(aPropertyNames, aPropertyValues);
    }
    catchconst uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("chart2""" );
    }
    return xShape;
}

rtl::Reference<SvxShapePolyPolygon>
        ShapeFactory::createLine2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget
                    , const drawing::PointSequenceSequence& rPoints
                    , const VLineProperties* pLineProperties )
{
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=97 G=94

¤ Dauer der Verarbeitung: 0.26 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge