Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/svx/source/customshapes/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 134 kB image not shown  

Quelle  EnhancedCustomShape2d.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 <sal/config.h>

#include <o3tl/string_view.hxx>
#include <svx/EnhancedCustomShape2d.hxx>
#include <svx/EnhancedCustomShapeGeometry.hxx>
#include <svx/EnhancedCustomShapeTypeNames.hxx>
#include <svx/svdoashp.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdopath.hxx>
#include <svx/svdorect.hxx>
#include <svx/svdpage.hxx>
#include <svx/xflclit.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xlineit0.hxx>
#include <svx/xlnstit.hxx>
#include <svx/xlnedit.hxx>
#include <svx/xlnstwit.hxx>
#include <svx/xlnedwit.hxx>
#include <svx/xlnstcit.hxx>
#include <svx/xlnedcit.hxx>
#include <svx/xflgrit.hxx>
#include <svx/xflhtit.hxx>
#include <svx/xbtmpit.hxx>
#include <svx/xhatch.hxx>
#include <svx/sdshitm.hxx>
#include <comphelper/configuration.hxx>
#include <com/sun/star/awt/Size.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
#include <basegfx/numeric/ftools.hxx>
#include <basegfx/color/bcolortools.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <sal/log.hxx>

#include <algorithm>
#include <cstdlib>
#include <string_view>
#include <unordered_set>

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::drawing::EnhancedCustomShapeSegmentCommand;

void EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( EnhancedCustomShapeParameter& rParameter, const sal_Int32 nValue )
{
    sal_uInt32 nDat = static_cast<sal_uInt32>(nValue);
    sal_Int32  nNewValue = nValue;

    // check if this is a special point
    if ( ( nDat >> 16 ) == 0x8000 )
    {
        nNewValue = static_cast<sal_uInt16>(nDat);
        rParameter.Type = EnhancedCustomShapeParameterType::EQUATION;
    }
    else
        rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
    rParameter.Value <<= nNewValue;
}

OUString EnhancedCustomShape2d::GetEquation( const sal_uInt16 nFlags, sal_Int32 nP1, sal_Int32 nP2, sal_Int32 nP3 )
{
    OUString aEquation;
    bool b1Special = ( nFlags & 0x2000 ) != 0;
    bool b2Special = ( nFlags & 0x4000 ) != 0;
    bool b3Special = ( nFlags & 0x8000 ) != 0;
    switch( nFlags & 0xff )
    {
        case 0 :
        case 14 :
        {
            sal_Int32 nOptimize = 0;
            if ( nP1 )
                nOptimize |= 1;
            if ( nP2 )
                nOptimize |= 2;
            if ( b1Special )
                nOptimize |= 4;
            if ( b2Special )
                nOptimize |= 8;
            switch( nOptimize )
            {
                case 0 :
                break;
                case 1 :
                case 4 :
                case 5 :
                    EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
                break;
                case 2 :
                case 8 :
                case 10:
                    EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
                break;
                default :
                {
                    EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
                    aEquation += "+";
                    EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
                }
                break;
            }
            if ( b3Special || nP3 )
            {
                aEquation += "-";
                EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            }
        }
        break;
        case 1 :
        {
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            if ( b2Special || ( nP2 != 1 ) )
            {
                aEquation += "*";
                EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            }
            if ( b3Special || ( ( nP3 != 1 ) && ( nP3 != 0 ) ) )
            {
                aEquation += "/";
                EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            }
        }
        break;
        case 2 :
        {
            aEquation += "(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "+";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += ")/2";
        }
        break;
        case 3 :
        {
            aEquation += "abs(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += ")";
        }
        break;
        case 4 :
        {
            aEquation += "min(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += ",";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += ")";
        }
        break;
        case 5 :
        {
            aEquation += "max(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += ",";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += ")";
        }
        break;
        case 6 :
        {
            aEquation += "if(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += ",";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += ",";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += ")";
        }
        break;
        case 7 :
        {
            aEquation += "sqrt(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "*";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "+";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += "*";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += "+";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += "*";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += ")";
        }
        break;
        case 8 :
        {
            aEquation += "atan2(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += ",";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += ")/(pi/180)";
        }
        break;
        case 9 :
        {
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "*sin(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += "*(pi/180))";
        }
        break;
        case 10 :
        {
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "*cos(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += "*(pi/180))";
        }
        break;
        case 11 :
        {
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "*cos(atan2(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += ",";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += "))";
        }
        break;
        case 12 :
        {
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "*sin(atan2(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += ",";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += "))";
        }
        break;
        case 13 :
        {
            aEquation += "sqrt(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += ")";
        }
        break;
        case 15 :
        {
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += "*sqrt(1-(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "/";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += ")"
                "*(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "/";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += "))";
        }
        break;
        case 16 :
        {
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "*tan(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += ")";
        }
        break;
        case 0x80 :
        {
            aEquation += "sqrt(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += "*";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += "-";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "*";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += ")";
        }
        break;
        case 0x81 :
        {
            aEquation += "(cos(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += "*(pi/180))*(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "-10800)+sin(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += "*(pi/180))*(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += "-10800))+10800";
        }
        break;
        case 0x82 :
        {
            aEquation += "-(sin(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += "*(pi/180))*(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
            aEquation += "-10800)-cos(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
            aEquation += "*(pi/180))*(";
            EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
            aEquation += "-10800))+10800";
        }
        break;
    }
    return aEquation;
}

void EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( OUString&&nbsp;rParameter, const sal_Int32 nPara, const bool bIsSpecialValue )
{
    if ( bIsSpecialValue )
    {
        if ( nPara & 0x400 )
        {
            rParameter += "?";
            rParameter += OUString::number( nPara & 0xff );
            rParameter += " ";
        }
        else
        {
            switch( nPara )
            {
                case DFF_Prop_adjustValue :
                case DFF_Prop_adjust2Value :
                case DFF_Prop_adjust3Value :
                case DFF_Prop_adjust4Value :
                case DFF_Prop_adjust5Value :
                case DFF_Prop_adjust6Value :
                case DFF_Prop_adjust7Value :
                case DFF_Prop_adjust8Value :
                case DFF_Prop_adjust9Value :
                case DFF_Prop_adjust10Value :
                {
                    rParameter += "$";
                    rParameter += OUString::number( nPara - DFF_Prop_adjustValue );
                    rParameter += " ";
                }
                break;
                case DFF_Prop_geoLeft :
                {
                    rParameter += "left";
                }
                break;
                case DFF_Prop_geoTop :
                {
                    rParameter += "top";
                }
                break;
                case DFF_Prop_geoRight :
                {
                    rParameter += "right";
                }
                break;
                case DFF_Prop_geoBottom :
                {
                    rParameter += "bottom";
                }
                break;
            }
        }
    }
    else
    {
        rParameter += OUString::number( nPara );
    }
}

void EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( EnhancedCustomShapeParameter& rParameter, const sal_Int32 nPara, const bool bIsSpecialValue, bool bHorz )
{
    sal_Int32 nValue = 0;
    if ( bIsSpecialValue )
    {
        if ( ( nPara >= 0x100 ) && ( nPara <= 0x107 ) )
        {
            nValue = nPara & 0xff;
            rParameter.Type = EnhancedCustomShapeParameterType::ADJUSTMENT;
        }
        else if ( ( nPara >= 3 ) && ( nPara <= 0x82 ) )
        {
            nValue = nPara - 3;
            rParameter.Type = EnhancedCustomShapeParameterType::EQUATION;
        }
        else if ( nPara == 0 )
        {
            nValue = 0;
            if ( bHorz )
                rParameter.Type = EnhancedCustomShapeParameterType::LEFT;
            else
                rParameter.Type = EnhancedCustomShapeParameterType::TOP;
        }
        else if ( nPara == 1 )
        {
            nValue = 0;
            if ( bHorz )
                rParameter.Type = EnhancedCustomShapeParameterType::RIGHT;
            else
                rParameter.Type = EnhancedCustomShapeParameterType::BOTTOM;
        }
        else if ( nPara == 2 )  // means to be centered, but should not be
        {                       // used in our implementation
            nValue = 5600;
            rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
        }
        else
        {
            nValue = nPara;
            rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
        }
    }
    else
    {
        nValue = nPara;
        rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
    }
    rParameter.Value <<= nValue;
}

bool EnhancedCustomShape2d::ConvertSequenceToEnhancedCustomShape2dHandle(
    const css::beans::PropertyValues& rHandleProperties,
        EnhancedCustomShape2d::Handle& rDestinationHandle )
{
    bool bRetValue = false;
    if ( rHandleProperties.hasElements() )
    {
        rDestinationHandle.nFlags = HandleFlags::NONE;
        for ( const css::beans::PropertyValue& rPropVal : rHandleProperties )
        {
            if ( rPropVal.Name == "Position" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.aPosition )
                    bRetValue = true;
            }
            else if ( rPropVal.Name == "MirroredX" )
            {
                bool bMirroredX;
                if ( rPropVal.Value >>= bMirroredX )
                {
                    if ( bMirroredX )
                        rDestinationHandle.nFlags |= HandleFlags::MIRRORED_X;
                }
            }
            else if ( rPropVal.Name == "MirroredY" )
            {
                bool bMirroredY;
                if ( rPropVal.Value >>= bMirroredY )
                {
                    if ( bMirroredY )
                        rDestinationHandle.nFlags |= HandleFlags::MIRRORED_Y;
                }
            }
            else if ( rPropVal.Name == "Switched" )
            {
                bool bSwitched;
                if ( rPropVal.Value >>= bSwitched )
                {
                    if ( bSwitched )
                        rDestinationHandle.nFlags |= HandleFlags::SWITCHED;
                }
            }
            else if ( rPropVal.Name == "Polar" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.aPolar )
                    rDestinationHandle.nFlags |= HandleFlags::POLAR;
            }
            else if ( rPropVal.Name == "RefX" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.nRefX )
                    rDestinationHandle.nFlags |= HandleFlags::REFX;
            }
            else if ( rPropVal.Name == "RefY" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.nRefY )
                    rDestinationHandle.nFlags |= HandleFlags::REFY;
            }
            else if ( rPropVal.Name == "RefAngle" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.nRefAngle )
                    rDestinationHandle.nFlags |= HandleFlags::REFANGLE;
            }
            else if ( rPropVal.Name == "RefR" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.nRefR )
                    rDestinationHandle.nFlags |= HandleFlags::REFR;
            }
            else if ( rPropVal.Name == "RadiusRangeMinimum" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.aRadiusRangeMinimum )
                    rDestinationHandle.nFlags |= HandleFlags::RADIUS_RANGE_MINIMUM;
            }
            else if ( rPropVal.Name == "RadiusRangeMaximum" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.aRadiusRangeMaximum )
                    rDestinationHandle.nFlags |= HandleFlags::RADIUS_RANGE_MAXIMUM;
            }
            else if ( rPropVal.Name == "RangeXMinimum" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.aXRangeMinimum )
                    rDestinationHandle.nFlags |= HandleFlags::RANGE_X_MINIMUM;
            }
            else if ( rPropVal.Name == "RangeXMaximum" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.aXRangeMaximum )
                    rDestinationHandle.nFlags |= HandleFlags::RANGE_X_MAXIMUM;
            }
            else if ( rPropVal.Name == "RangeYMinimum" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.aYRangeMinimum )
                    rDestinationHandle.nFlags |= HandleFlags::RANGE_Y_MINIMUM;
            }
            else if ( rPropVal.Name == "RangeYMaximum" )
            {
                if ( rPropVal.Value >>= rDestinationHandle.aYRangeMaximum )
                    rDestinationHandle.nFlags |= HandleFlags::RANGE_Y_MAXIMUM;
            }
        }
    }
    return bRetValue;
}

void EnhancedCustomShape2d::ApplyShapeAttributes( const SdrCustomShapeGeometryItem&&nbsp;rGeometryItem )
{
    // AdjustmentValues
    static constexpr OUStringLiteral sAdjustmentValues( u"AdjustmentValues" );
    const Any* pAny = rGeometryItem.GetPropertyValueByName( sAdjustmentValues );
    if ( pAny )
        *pAny >>= m_seqAdjustmentValues;


    // Coordsize
    static constexpr OUStringLiteral sViewBox( u"ViewBox" );
    const Any* pViewBox = rGeometryItem.GetPropertyValueByName( sViewBox );
    css::awt::Rectangle aViewBox;
    if ( pViewBox && (*pViewBox >>= aViewBox ) )
    {
        m_nCoordLeft    = aViewBox.X;
        m_nCoordTop     = aViewBox.Y;
        m_nCoordWidthG  = aViewBox.Width;
        if (m_nCoordWidthG < 0)
            m_nCoordWidthG = o3tl::saturating_toggle_sign(m_nCoordWidthG);
        m_nCoordHeightG = aViewBox.Height;
        if (m_nCoordHeightG < 0)
            m_nCoordHeightG = o3tl::saturating_toggle_sign(m_nCoordHeightG);
    }
    static constexpr OUString sPath( u"Path"_ustr );
    static constexpr OUStringLiteral sCoordinates( u"Coordinates" );
    static constexpr OUStringLiteral sGluePoints( u"GluePoints" );
    static constexpr OUStringLiteral sGluePointLeavingDirections( u"GluePointLeavingDirections" );
    static constexpr OUStringLiteral sSegments( u"Segments" );
    static constexpr OUStringLiteral sSubViewSize( u"SubViewSize" );
    static constexpr OUStringLiteral sStretchX( u"StretchX" );
    static constexpr OUStringLiteral sStretchY( u"StretchY" );
    static constexpr OUStringLiteral sTextFrames( u"TextFrames" );
    static constexpr OUStringLiteral sEquations( u"Equations" );
    static constexpr OUStringLiteral sHandles( u"Handles" );


    // Path/Coordinates
    pAny = rGeometryItem.GetPropertyValueByName( sPath, sCoordinates );
    if ( pAny )
        *pAny >>= m_seqCoordinates;


    // Path/GluePoints
    pAny = rGeometryItem.GetPropertyValueByName( sPath, sGluePoints );
    if ( pAny )
        *pAny >>= m_seqGluePoints;

    // Path/GluePointLeavingDirections
    pAny = rGeometryItem.GetPropertyValueByName(sPath, sGluePointLeavingDirections);
    if (pAny)
        *pAny >>= m_seqGluePointLeavingDirections;

    // Path/Segments
    pAny = rGeometryItem.GetPropertyValueByName( sPath, sSegments );
    if ( pAny )
        *pAny >>= m_seqSegments;


    // Path/SubViewSize
    pAny = rGeometryItem.GetPropertyValueByName( sPath, sSubViewSize );
    if ( pAny )
        *pAny >>= m_seqSubViewSize;


    // Path/StretchX
    pAny = rGeometryItem.GetPropertyValueByName( sPath, sStretchX );
    if ( pAny )
    {
        sal_Int32 nStretchX = 0;
        if ( *pAny >>= nStretchX )
            m_nXRef = nStretchX;
    }


    // Path/StretchY
    pAny = rGeometryItem.GetPropertyValueByName( sPath, sStretchY );
    if ( pAny )
    {
        sal_Int32 nStretchY = 0;
        if ( *pAny >>= nStretchY )
            m_nYRef = nStretchY;
    }


    // Path/TextFrames
    pAny = rGeometryItem.GetPropertyValueByName( sPath, sTextFrames );
    if ( pAny )
        *pAny >>= m_seqTextFrames;


    // Equations
    pAny = rGeometryItem.GetPropertyValueByName( sEquations );
    if ( pAny )
        *pAny >>= m_seqEquations;


    // Handles
    pAny = rGeometryItem.GetPropertyValueByName( sHandles );
    if ( pAny )
        *pAny >>= m_seqHandles;
}

EnhancedCustomShape2d::~EnhancedCustomShape2d()
{
}

void EnhancedCustomShape2d::SetPathSize( sal_Int32 nIndex )
{
    sal_Int32 nWidth = 0;
    sal_Int32 nHeight = 0;

    if ( m_seqSubViewSize.hasElements() && nIndex < m_seqSubViewSize.getLength() ) {
        nWidth = m_seqSubViewSize[ nIndex ].Width;
        nHeight = m_seqSubViewSize[ nIndex ].Height;
        SAL_INFO(
            "svx",
            "set subpath " << nIndex << " size: " << nWidth << " x "
                << nHeight);
    }

    if ( nWidth && nHeight ) {
        m_nCoordWidth = nWidth;
        m_nCoordHeight = nHeight;
    } else {
        m_nCoordWidth = m_nCoordWidthG;
        m_nCoordHeight = m_nCoordHeightG;
    }

    m_fXScale = m_nCoordWidth == 0 ? 0.0 : static_cast<double>(m_aLogicRect.GetWidth()) / static_cast<double>(m_nCoordWidth);
    m_fYScale = m_nCoordHeight == 0 ? 0.0 : static_cast<double>(m_aLogicRect.GetHeight()) / static_cast<double>(m_nCoordHeight);
    if ( m_bOOXMLShape )
    {
        SAL_INFO(
            "svx",
            "ooxml shape, path width: " << m_nCoordWidth << " height: "
                << m_nCoordHeight);

        // Try to set up scale separately, if given only width or height
        // This is possible case in OOXML when only width or height is non-zero
        if ( m_nCoordWidth == 0 )
        {
            if ( nWidth )
                m_fXScale = static_cast<double>(m_aLogicRect.GetWidth()) / static_cast<double>(nWidth);
            else
                m_fXScale = 1.0;
        }
        if ( m_nCoordHeight == 0 )
        {
            if ( nHeight )
                m_fYScale = static_cast<double>(m_aLogicRect.GetHeight()) / static_cast<double>(nHeight);
            else
                m_fYScale = 1.0;
        }
    }
    if ( static_cast<sal_uInt32>(m_nXRef) != 0x80000000 && m_aLogicRect.GetHeight() )
    {
        m_fXRatio = static_cast<double>(m_aLogicRect.GetWidth()) / static_cast<double>(m_aLogicRect.GetHeight());
        if ( m_fXRatio > 1 )
            m_fXScale /= m_fXRatio;
        else
            m_fXRatio = 1.0;
    }
    else
        m_fXRatio = 1.0;
    if ( static_cast<sal_uInt32>(m_nYRef) != 0x80000000 && m_aLogicRect.GetWidth() )
    {
        m_fYRatio = static_cast<double>(m_aLogicRect.GetHeight()) / static_cast<double>(m_aLogicRect.GetWidth());
        if ( m_fYRatio > 1 )
            m_fYScale /= m_fYRatio;
        else
            m_fYRatio = 1.0;
    }
    else
        m_fYRatio = 1.0;

    if (comphelper::IsFuzzing())
    {
        if (fabs(m_fXScale) > 100000)
        {
            SAL_WARN("svx""unreasonable X Scale of: " << m_fXScale);
            m_fXScale = 1.0;
        }
        if (fabs(m_fYScale) > 100000)
        {
            SAL_WARN("svx""unreasonable Y Scale of: " << m_fYScale);
            m_fYScale = 1.0;
        }
    }
}

EnhancedCustomShape2d::EnhancedCustomShape2d(SdrObjCustomShape& rSdrObjCustomShape)
:   SfxItemSet          ( rSdrObjCustomShape.GetMergedItemSet() ),
    mrSdrObjCustomShape ( rSdrObjCustomShape ),
    m_eSpType             ( mso_sptNil ),
    m_nCoordLeft          ( 0 ),
    m_nCoordTop           ( 0 ),
    m_nCoordWidthG        ( 21600 ),
    m_nCoordHeightG       ( 21600 ),
    m_bOOXMLShape         ( false ),
    m_nXRef               ( 0x80000000 ),
    m_nYRef               ( 0x80000000 ),
    m_nColorData          ( 0 ),
    m_bFilled             ( rSdrObjCustomShape.GetMergedItem( XATTR_FILLSTYLE ).GetValue() != drawing::FillStyle_NONE ),
    m_bStroked            ( rSdrObjCustomShape.GetMergedItem( XATTR_LINESTYLE ).GetValue() != drawing::LineStyle_NONE ),
    m_bFlipH              ( false ),
    m_bFlipV              ( false )
{
    // bTextFlow needs to be set before clearing the TextDirection Item

    ClearItem( SDRATTR_TEXTDIRECTION ); //SJ: vertical writing is not required, by removing this item no outliner is created

    // #i105323# For 2D AutoShapes, the shadow attribute does not need to be applied to any
    // of the constructed helper SdrObjects. This would lead to problems since the shadow
    // of one helper object would fall on one helper object behind it (e.g. with the
    // eyes of the smiley shape). This is not wanted; instead a single shadow 'behind'
    // the AutoShape visualisation is wanted. This is done with primitive functionality
    // now in SdrCustomShapePrimitive2D::create2DDecomposition, but only for 2D objects
    // (see there and in EnhancedCustomShape3d::Create3DObject to read more).
    // This exception may be removed later when AutoShapes will create primitives directly.
    // So, currently remove the ShadowAttribute from the ItemSet to not apply it to any
    // 2D helper shape.
    ClearItem(SDRATTR_SHADOW);

    Point aP( mrSdrObjCustomShape.GetSnapRect().Center() );
    Size aS( mrSdrObjCustomShape.GetLogicRect().GetSize() );
    aP.AdjustX( -(aS.Width() / 2) );
    aP.AdjustY( -(aS.Height() / 2) );
    m_aLogicRect = tools::Rectangle( aP, aS );

    OUString sShapeType;
    const SdrCustomShapeGeometryItem& rGeometryItem(mrSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
    static constexpr OUStringLiteral sType = u"Type";
    const Any* pAny = rGeometryItem.GetPropertyValueByName( sType );
    if ( pAny ) {
        *pAny >>= sShapeType;
        m_bOOXMLShape = sShapeType.startsWith("ooxml-");
        SAL_INFO("svx""shape type: " << sShapeType << " " << m_bOOXMLShape);
    }
    m_eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );

    static constexpr OUStringLiteral sMirroredX = u"MirroredX";
    static constexpr OUStringLiteral sMirroredY = u"MirroredY";
    pAny = rGeometryItem.GetPropertyValueByName( sMirroredX );
    if ( pAny )
        *pAny >>= m_bFlipH;
    pAny = rGeometryItem.GetPropertyValueByName( sMirroredY );
    if ( pAny )
        *pAny >>= m_bFlipV;

    m_nRotateAngle = Degree100(static_cast<sal_Int32>(mrSdrObjCustomShape.GetObjectRotation() * 100.0));

    /*const sal_Int32* pDefData =*/ ApplyShapeAttributes( rGeometryItem );
    SetPathSize();

    switch( m_eSpType )
    {
        case mso_sptCan :                       m_nColorData = 0x20400000; break;
        case mso_sptCube :                      m_nColorData = 0x302e0000; break;
        case mso_sptActionButtonBlank :         m_nColorData = 0x502ce400; break;
        case mso_sptActionButtonHome :          m_nColorData = 0x702ce4ce; break;
        case mso_sptActionButtonHelp :          m_nColorData = 0x602ce4c0; break;
        case mso_sptActionButtonInformation :   m_nColorData = 0x702ce4c5; break;
        case mso_sptActionButtonBackPrevious :  m_nColorData = 0x602ce4c0; break;
        case mso_sptActionButtonForwardNext :   m_nColorData = 0x602ce4c0; break;
        case mso_sptActionButtonBeginning :     m_nColorData = 0x602ce4c0; break;
        case mso_sptActionButtonEnd :           m_nColorData = 0x602ce4c0; break;
        case mso_sptActionButtonReturn :        m_nColorData = 0x602ce4c0; break;
        case mso_sptActionButtonDocument :      m_nColorData = 0x702ce4ec; break;
        case mso_sptActionButtonSound :         m_nColorData = 0x602ce4c0; break;
        case mso_sptActionButtonMovie :         m_nColorData = 0x602ce4c0; break;
        case mso_sptBevel :                     m_nColorData = 0x502ce400; break;
        case mso_sptFoldedCorner :              m_nColorData = 0x20e00000; break;
        case mso_sptSmileyFace :                m_nColorData = 0x20e00000; break;
        case mso_sptNil :
        {
            // Because calculation method has changed in #i102797 original color encoding for
            // Octagon Bevel and Diamond Bevel can no longer be used. We keep the color coding
            // only for self-created shapes, as authors may have already considered the change.
            // We use ColorData compatible to OOXML.
            if (sShapeType == "col-60da8460"// Octagon Bevel
            {
                m_nColorData = 0x60ecc240;
            }
            else if (sShapeType == "col-502ad400"// Diamond Bevel
            {
                m_nColorData = 0x502ce400;
            }
            else if (sShapeType.getLength() > 4 && sShapeType.match( "col-" ))
            {
                m_nColorData = o3tl::toUInt32(sShapeType.subView( 4 ), 16);
            }
        }
        break;
        case mso_sptCurvedLeftArrow :
        case mso_sptCurvedRightArrow :
        case mso_sptCurvedUpArrow :
        case mso_sptCurvedDownArrow :           m_nColorData = 0x20d00000; break;
        case mso_sptRibbon2 :                   m_nColorData = 0x30ee0000; break;
        case mso_sptRibbon :                    m_nColorData = 0x30ee0000; break;

        case mso_sptEllipseRibbon2 :            m_nColorData = 0x30ee0000; break;
        case mso_sptEllipseRibbon :             m_nColorData = 0x30ee0000; break;

        case mso_sptVerticalScroll :            m_nColorData = 0x30ee0000; break;
        case mso_sptHorizontalScroll :          m_nColorData = 0x30ee0000; break;
        default:
            break;
    }

    sal_Int32 nLength = m_seqEquations.getLength();

    if ( !nLength )
        return;

    m_vEquationResults.resize( nLength );
}

using EnhancedCustomShape::ExpressionFunct;

double EnhancedCustomShape2d::GetEnumFunc( const ExpressionFunct eFunc ) const
{
    double fRet = 0.0;
    switch( eFunc )
    {
        case ExpressionFunct::EnumPi :         fRet = M_PI; break;
        case ExpressionFunct::EnumLeft :       fRet = static_cast<double>(m_nCoordLeft); break;
        case ExpressionFunct::EnumTop :        fRet = static_cast<double>(m_nCoordTop); break;
        case ExpressionFunct::EnumRight :      fRet = (static_cast<double>(m_nCoordLeft) + static_cast<double>(m_nCoordWidth)) * m_fXRatio; break;
        case ExpressionFunct::EnumBottom :     fRet = (static_cast<double>(m_nCoordTop) + static_cast<double>(m_nCoordHeight)) * m_fYRatio; break;
        case ExpressionFunct::EnumXStretch :   fRet = m_nXRef; break;
        case ExpressionFunct::EnumYStretch :   fRet = m_nYRef; break;
        case ExpressionFunct::EnumHasStroke :  fRet = m_bStroked ? 1.0 : 0.0; break;
        case ExpressionFunct::EnumHasFill :    fRet = m_bFilled ? 1.0 : 0.0; break;
        case ExpressionFunct::EnumWidth :      fRet = m_nCoordWidth; break;
        case ExpressionFunct::EnumHeight :     fRet = m_nCoordHeight; break;
        case ExpressionFunct::EnumLogWidth :   fRet = m_aLogicRect.GetWidth(); break;
        case ExpressionFunct::EnumLogHeight :  fRet = m_aLogicRect.GetHeight(); break;
        defaultbreak;
    }
    return fRet;
}
double EnhancedCustomShape2d::GetAdjustValueAsDouble( const sal_Int32 nIndex ) const
{
    double fNumber = 0.0;
    if ( nIndex < m_seqAdjustmentValues.getLength() )
    {
        if ( m_seqAdjustmentValues[ nIndex ].Value.getValueTypeClass() == TypeClass_DOUBLE )
            m_seqAdjustmentValues[ nIndex ].Value >>= fNumber;
        else
        {
            sal_Int32 nNumber = 0;
            m_seqAdjustmentValues[ nIndex ].Value >>= nNumber;
            fNumber = static_cast<double>(nNumber);
        }
    }
    return fNumber;
}
double EnhancedCustomShape2d::GetEquationValueAsDouble( const sal_Int32 nIndex ) const
{
    double fNumber = 0.0;
    static sal_uInt32 nLevel = 0;
    if ( nIndex >= static_cast<sal_Int32>(m_vEquationResults.size()) )
        return fNumber;

    if (!m_vEquationResults[nIndex].bParsed)
    {
        m_vEquationResults[nIndex].bParsed = true;
        try
        {
            m_vEquationResults[nIndex].xNode = EnhancedCustomShape::FunctionParser::parseFunction( m_seqEquations[ nIndex ], *this );
        }
        catch ( EnhancedCustomShape::ParseError& )
        {
            SAL_INFO(
                "svx",
                "error: equation number: " << nIndex << ", parser failed ("
                    << m_seqEquations[nIndex] << ")");
        }
    }
    if ( m_vEquationResults[ nIndex ].xNode )
    {
        nLevel ++;
        try
        {
            if ( m_vEquationResults[ nIndex ].bReady )
                fNumber = m_vEquationResults[ nIndex ].fValue;
            else {
                // cast to non const, so that we can optimize by caching
                // equation results, without changing all the const in the stack
                struct EquationResult &aResult = const_cast<EnhancedCustomShape2d*>(this)->m_vEquationResults[ nIndex ];

                fNumber = aResult.fValue = (*m_vEquationResults[ nIndex ].xNode)();
                aResult.bReady = true;

                SAL_INFO("svx""equation " << nLevel << " (level: " << m_seqEquations[nIndex] << "): "
                         << fNumber << " --> " << 180.0*fNumber/10800000.0);
            }
            if ( !std::isfinite( fNumber ) )
                fNumber = 0.0;
        }
        catch ( ... )
        {
            SAL_WARN("svx""EnhancedCustomShape2d::GetEquationValueAsDouble failed");
        }
        nLevel --;
    }
    SAL_INFO(
        "svx",
        "?" << nIndex << " --> " << fNumber << " (angle: "
            << 180.0*fNumber/10800000.0 << ")");

    return fNumber;
}

bool EnhancedCustomShape2d::SetAdjustValueAsDouble( const double& rValue, const sal_Int32 nIndex )
{
    bool bRetValue = false;
    if ( nIndex < m_seqAdjustmentValues.getLength() )
    {
        // updating our local adjustment sequence
        auto pseqAdjustmentValues = m_seqAdjustmentValues.getArray();
        pseqAdjustmentValues[ nIndex ].Value <<= rValue;
        pseqAdjustmentValues[ nIndex ].State = css::beans::PropertyState_DIRECT_VALUE;
        bRetValue = true;
    }
    return bRetValue;
}

basegfx::B2DPoint EnhancedCustomShape2d::GetPointAsB2DPoint( const css::drawing::EnhancedCustomShapeParameterPair& rPair,
                                        const bool bScale, const bool bReplaceGeoSize ) const
{
    double fValX, fValY;
    // width
    GetParameter(fValX, rPair.First, bReplaceGeoSize, false);
    fValX -= m_nCoordLeft;
    if (bScale)
    {
        fValX *= m_fXScale;
    }
    // height
    GetParameter(fValY, rPair.Second, false, bReplaceGeoSize);
    fValY -= m_nCoordTop;
    if (bScale)
    {
        fValY *= m_fYScale;
    }
    return basegfx::B2DPoint(fValX,fValY);
}

Point EnhancedCustomShape2d::GetPoint( const css::drawing::EnhancedCustomShapeParameterPair& rPair,
                                        const bool bScale, const bool bReplaceGeoSize ) const
{
    basegfx::B2DPoint aPoint(GetPointAsB2DPoint(rPair, bScale, bReplaceGeoSize));
    return Point(static_cast<tools::Long>(aPoint.getX()), static_cast<tools::Long>(aPoint.getY()));
}

void EnhancedCustomShape2d::GetParameter( double& rRetValue, const EnhancedCustomShapeParameter& rParameter,
                                              const bool bReplaceGeoWidth, const bool bReplaceGeoHeight ) const
{
    rRetValue = 0.0;
    switch ( rParameter.Type )
    {
        case EnhancedCustomShapeParameterType::ADJUSTMENT :
        {
            sal_Int32 nAdjustmentIndex = 0;
            if ( rParameter.Value >>= nAdjustmentIndex )
            {
                rRetValue = GetAdjustValueAsDouble( nAdjustmentIndex );
            }
        }
        break;
        case EnhancedCustomShapeParameterType::EQUATION :
        {
            sal_Int32 nEquationIndex = 0;
            if ( rParameter.Value >>= nEquationIndex )
            {
                rRetValue = GetEquationValueAsDouble( nEquationIndex );
            }
        }
        break;
        case EnhancedCustomShapeParameterType::NORMAL :
        {
            if ( rParameter.Value.getValueTypeClass() == TypeClass_DOUBLE )
            {
                double fValue(0.0);
                if ( rParameter.Value >>= fValue )
                {
                    rRetValue = fValue;
                }
            }
            else
            {
                sal_Int32 nValue = 0;
                if ( rParameter.Value >>= nValue )
                {
                    rRetValue = nValue;
                    if ( bReplaceGeoWidth && ( nValue == m_nCoordWidth ) )
                        rRetValue *= m_fXRatio;
                    else if ( bReplaceGeoHeight && ( nValue == m_nCoordHeight ) )
                        rRetValue *= m_fYRatio;
                }
            }
        }
        break;
        case EnhancedCustomShapeParameterType::LEFT :
        case EnhancedCustomShapeParameterType::TOP :
        {
            rRetValue  = 0.0;
        }
        break;
        case EnhancedCustomShapeParameterType::RIGHT :
        {
            rRetValue = m_nCoordWidth;
        }
        break;
        case EnhancedCustomShapeParameterType::BOTTOM :
        {
            rRetValue = m_nCoordHeight;
        }
        break;
    }
}

// nLumDat 28-31 = number of luminance entries in nLumDat
// nLumDat 27-24 = nLumDatEntry 0
// nLumDat 23-20 = nLumDatEntry 1 ...
// each 4bit entry is to be interpreted as a 10 percent signed luminance changing
sal_Int32 EnhancedCustomShape2d::GetLuminanceChange( sal_uInt32 nIndex ) const
{
    const sal_uInt32 nCount = m_nColorData >> 28;
    if ( !nCount )
        return 0;

    if ( nIndex >= nCount )
        nIndex = nCount - 1;

    const sal_Int32 nLumDat = m_nColorData << ( ( 1 + nIndex ) << 2 );
    return ( nLumDat >> 28 ) * 10;
}

Color EnhancedCustomShape2d::GetColorData( const Color& rFillColor, sal_uInt32 nIndex, double dBrightness ) const
{
    if ( m_bOOXMLShape || ( mso_sptMin == m_eSpType /* ODF "non-primitive" */ ) )
    { //do LibreOffice way, using dBrightness
        if ( dBrightness == 0.0)
        {
            return rFillColor;
        }
        else
        {
            if (dBrightness >=0.0)
            { //lighten, blending with white
                return Color( static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetRed() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0)  )),
                              static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetGreen() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0) )),
                              static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetBlue() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0) ))  );
            }
            else
            { //darken (indicated by negative sign), blending with black
                return Color( static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetRed() * (1.0+dBrightness), 0.0, 255.0)  )),
                              static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetGreen() * (1.0+dBrightness), 0.0, 255.0) )),
                              static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetBlue() * (1.0+dBrightness), 0.0, 255.0) ))  );
            }
        }
    }
    else
    { //do OpenOffice way, using nColorData
        const sal_Int32 nLuminance = GetLuminanceChange(nIndex);
        if( !nLuminance )
            return rFillColor;

        basegfx::BColor aHSVColor=
                basegfx::utils::rgb2hsv(
                    basegfx::BColor(rFillColor.GetRed()/255.0,
                                    rFillColor.GetGreen()/255.0,
                                    rFillColor.GetBlue()/255.0));

        if( nLuminance > 0 )
        {
            aHSVColor.setGreen(
                aHSVColor.getGreen() * (1.0-nLuminance/100.0));
            aHSVColor.setBlue(
                nLuminance/100.0 +
                (1.0-nLuminance/100.0)*aHSVColor.getBlue());
        }
        else if( nLuminance < 0 )
        {
            aHSVColor.setBlue(
                (1.0+nLuminance/100.0)*aHSVColor.getBlue());
        }

        aHSVColor = basegfx::utils::hsv2rgb(aHSVColor);
        return Color( static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(aHSVColor.getRed(),0.0,1.0) * 255.0 + 0.5 )),
                    static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(aHSVColor.getGreen(),0.0,1.0) * 255.0 + 0.5 )),
                    static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(aHSVColor.getBlue(),0.0,1.0) * 255.0 + 0.5 )) );
    }
}

tools::Rectangle EnhancedCustomShape2d::GetTextRect() const
{
    if ( !m_seqTextFrames.hasElements() )
        return m_aLogicRect;
    sal_Int32 nIndex = 0;
    Point aTopLeft( GetPoint( m_seqTextFrames[ nIndex ].TopLeft, !m_bOOXMLShape, true ) );
    Point aBottomRight( GetPoint( m_seqTextFrames[ nIndex ].BottomRight, !m_bOOXMLShape, true ) );
    tools::Rectangle aRect( aTopLeft, aBottomRight );
    if ( m_bFlipH )
    {
        aRect.SetLeft(m_aLogicRect.GetWidth() - 1 - aBottomRight.X());
        aRect.SetRight( m_aLogicRect.GetWidth() - 1 - aTopLeft.X());
    }
    if ( m_bFlipV )
    {
        aRect.SetTop(m_aLogicRect.GetHeight() - 1 - aBottomRight.Y());
        aRect.SetBottom(m_aLogicRect.GetHeight() - 1 - aTopLeft.Y());
    }
    SAL_INFO("svx", aRect.GetWidth() << " x " << aRect.GetHeight());
    if( aRect.GetWidth() <= 1 || aRect.GetHeight() <= 1 )
        return m_aLogicRect;
    aRect.Move( m_aLogicRect.Left(), m_aLogicRect.Top() );
    aRect.Normalize();
    return aRect;
}

sal_uInt32 EnhancedCustomShape2d::GetHdlCount() const
{
    return m_seqHandles.getLength();
}

bool EnhancedCustomShape2d::GetHandlePosition( const sal_uInt32 nIndex, Point& rReturnPosition ) const
{
    bool bRetValue = false;
    if ( nIndex < GetHdlCount() )
    {
        Handle aHandle;
        if ( ConvertSequenceToEnhancedCustomShape2dHandle( m_seqHandles[ nIndex ], aHandle ) )
        {
            if ( aHandle.nFlags & HandleFlags::POLAR )
            {
                Point aReferencePoint( GetPoint( aHandle.aPolar ) );

                double      fAngle;
                double      fRadius;
                GetParameter( fRadius, aHandle.aPosition.First, falsefalse );
                GetParameter( fAngle,  aHandle.aPosition.Second, falsefalse );

                double a = basegfx::deg2rad(360.0 - fAngle);
                double dx = fRadius * m_fXScale;
                double fX = dx * cos( a );
                double fY =-dx * sin( a );
                rReturnPosition =
                    Point(
                        basegfx::fround<tools::Long>( fX + aReferencePoint.X() ),
                        basegfx::fTools::equalZero(m_fXScale) ? aReferencePoint.Y() :
                        basegfx::fround<tools::Long>( ( fY * m_fYScale ) / m_fXScale + aReferencePoint.Y() ) );
            }
            else
            {
                if ( aHandle.nFlags & HandleFlags::SWITCHED )
                {
                    if ( m_aLogicRect.GetHeight() > m_aLogicRect.GetWidth() )
                    {
                        std::swap(aHandle.aPosition.First, aHandle.aPosition.Second);
                    }
                }
                if (m_bOOXMLShape)
                    rReturnPosition = GetPoint(aHandle.aPosition, false /*bScale*/);
                else
                    rReturnPosition = GetPoint(aHandle.aPosition, true /*bScale*/);
            }
            const GeoStat aGeoStat(mrSdrObjCustomShape.GetGeoStat());
            if ( aGeoStat.m_nShearAngle )
            {
                double nTan = aGeoStat.mfTanShearAngle;
                if (m_bFlipV != m_bFlipH)
                    nTan = -nTan;
                ShearPoint( rReturnPosition, Point( m_aLogicRect.GetWidth() / 2, m_aLogicRect.GetHeight() / 2 ), nTan );
            }
            if ( m_nRotateAngle )
            {
                double a = toRadians(m_nRotateAngle);
                RotatePoint( rReturnPosition, Point( m_aLogicRect.GetWidth() / 2, m_aLogicRect.GetHeight() / 2 ), sin( a ), cos( a ) );
            }
            if ( m_bFlipH )
                rReturnPosition.setX( m_aLogicRect.GetWidth() - rReturnPosition.X() );
            if ( m_bFlipV )
                rReturnPosition.setY( m_aLogicRect.GetHeight() - rReturnPosition.Y() );
            rReturnPosition.Move( m_aLogicRect.Left(), m_aLogicRect.Top() );
            bRetValue = true;
        }
    }
    return bRetValue;
}

static double lcl_getXAdjustmentValue(std::u16string_view rShapeType, const sal_uInt32 nHandleIndex,
                                      const double fX, const double fW, const double fH)
{
    // degenerated shapes are not worth to calculate special case for each shape type
    if (fW <= 0.0 || fH <= 0.0)
        return 50000;

    // pattern (w - x) / ss * 100000 or (r - x) / ss * 100000
    if ((rShapeType == u"ooxml-bentArrow" && nHandleIndex == 2) || (rShapeType == u"ooxml-chevron")
        || (rShapeType == u"ooxml-curvedRightArrow") || (rShapeType == u"ooxml-foldedCorner")
        || (rShapeType == u"ooxml-homePlate") || (rShapeType == u"ooxml-notchedRightArrow")
        || (rShapeType == u"ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-rightArrow")
        || (rShapeType == u"ooxml-rightArrowCallout" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-round1Rect")
        || (rShapeType == u"ooxml-round2DiagRect" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-round2SameRect" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-snip1Rect")
        || (rShapeType == u"ooxml-snip2DiagRect" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-snip2SameRect" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-snipRoundRect" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-swooshArrow") || (rShapeType == u"ooxml-stripedRightArrow"))
        return (fW - fX) / std::min(fW, fH) * 100000.0;

    // pattern  x / ss * 100000 or (x - l) / ss * 100000
    if ((rShapeType == u"ooxml-bentArrow" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-bentArrow" && nHandleIndex == 3)
        || (rShapeType == u"ooxml-corner")
        || (rShapeType == u"ooxml-curvedDownArrow") || (rShapeType == u"ooxml-curvedLeftArrow")
        || (rShapeType == u"ooxml-curvedUpArrow") || (rShapeType == u"ooxml-leftArrow")
        || (rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-leftRightArrow")
        || (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-leftRightRibbon")
        || (rShapeType == u"ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-parallelogram")
        || (rShapeType == u"ooxml-round2DiagRect" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-round2SameRect" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-roundRect")
        || (rShapeType == u"ooxml-snip2DiagRect" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-snip2SameRect" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-snipRoundRect" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 3))
        return fX / std::min(fW, fH) * 100000.0;

    // pattern (hc - x) / ss * 200000
    if ((rShapeType == u"ooxml-downArrowCallout" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-leftRightUpArrow" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-quadArrow" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 0))
        return (fW / 2.0 - fX) / std::min(fW, fH) * 200000.0;

    // pattern (hc - x) / ss * 100000
    if ((rShapeType == u"ooxml-downArrowCallout" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-leftRightUpArrow" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-quadArrow" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 1))
        return (fW / 2.0 - fX) / std::min(fW, fH) * 100000.0;

    // pattern (w - x) / ss * 50000 or (r - x) / ss * 50000
    if ((rShapeType == u"ooxml-bentUpArrow") || (rShapeType == u"ooxml-leftUpArrow")
        || (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 1))
        return (fW - fX) / std::min(fW, fH) * 50000.0;

    // pattern x / ss * 200000
    if (rShapeType == u"ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 0)
        return fX / std::min(fW, fH) * 200000.0;

    // pattern (hc - x) / w * 200000
    if ((rShapeType == u"ooxml-downArrow" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-ellipseRibbon") || (rShapeType == u"ooxml-ellipseRibbon2")
        || (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 3)
        || (rShapeType == u"ooxml-ribbon") || (rShapeType == u"ooxml-ribbon2")
        || (rShapeType == u"ooxml-upArrow" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-upDownArrow" && nHandleIndex == 0))
        return (fW / 2.0 - fX) / fW * 200000.0;

    // pattern (x - hc) / w * 100000
    if ((rShapeType == u"ooxml-cloudCallout") || (rShapeType == u"ooxml-doubleWave")
        || (rShapeType == u"ooxml-wave") || (rShapeType == u"ooxml-wedgeEllipseCallout")
        || (rShapeType == u"ooxml-wedgeRectCallout")
        || (rShapeType == u"ooxml-wedgeRoundRectCallout"))
        return (fX - fW / 2.0) / fW * 100000.0;

    // pattern (x - hc) / w * 200000
    if (rShapeType == u"ooxml-teardrop")
        return (fX - fW / 2.0) / fW * 200000.0;

    // pattern (w - x) / w * 100000 or (r - x) / w * 100000
    if (rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 3)
        return (fW - fX) / fW * 100000.0;

    // pattern (hc - x) / h * 100000
    if (rShapeType == u"ooxml-mathDivide")
        return (fW / 2.0 - fX) / fH * 100000.0;

    // pattern x / w * 100000, simple scaling
    if (o3tl::starts_with(rShapeType, u"ooxml-"))
        return fX / fW * 100000.0;

    return fX; // method is unknown
}

static double lcl_getYAdjustmentValue(std::u16string_view rShapeType, const sal_uInt32 nHandleIndex,
                                      const double fY, const double fW, const double fH)
{
    // degenerated shapes are not worth to calculate a special case for each shape type
    if (fW <= 0.0 || fH <= 0.0)
        return 50000;

    // pattern (vc - y) / ss * 100000
    if ((rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-rightArrowCallout" && nHandleIndex == 1))
        return (fH / 2.0 - fY) / std::min(fW, fH) * 100000.0;

    // pattern (vc - y) / ss * 200000
    if ((rShapeType == u"ooxml-curvedLeftArrow") || (rShapeType == u"ooxml-curvedRightArrow")
        || (rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-mathPlus")
        || (rShapeType == u"ooxml-rightArrowCallout" && nHandleIndex == 0))
        return (fH / 2.0 - fY) / std::min(fW, fH) * 200000.0;

    // pattern (h - y) / ss * 100000 or (b - y) / ss * 100000
    if ((rShapeType == u"ooxml-bentUpArrow" && nHandleIndex == 0) || (rShapeType == u"ooxml-corner")
        || (rShapeType == u"ooxml-curvedDownArrow") || (rShapeType == u"ooxml-downArrow")
        || (rShapeType == u"ooxml-downArrowCallout" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 2))
        return (fH - fY) / std::min(fW, fH) * 100000.0;

    // pattern (h - y) / ss * 200000 or (b - y) / ss * 200000
    if (rShapeType == u"ooxml-leftUpArrow" && nHandleIndex == 0) // - adj2 * 2 outside
        return (fH - fY) / std::min(fW, fH) * 200000.0;

    // pattern  y / ss * 100000 or (y - t) / ss * 100000
    if ((rShapeType == u"ooxml-bentUpArrow" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-bracePair") || (rShapeType == u"ooxml-bracketPair")
        || (rShapeType == u"ooxml-can") || (rShapeType == u"ooxml-cube")
        || (rShapeType == u"ooxml-curvedUpArrow") || (rShapeType == u"ooxml-halfFrame")
        || (rShapeType == u"ooxml-leftBrace" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-leftBracket") || (rShapeType == u"ooxml-leftRightUpArrow")
        || (rShapeType == u"ooxml-leftUpArrow" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-mathMultiply") || (rShapeType == u"ooxml-quadArrow")
        || (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-rightBrace" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-rightBracket") || (rShapeType == u"ooxml-upArrow")
        || (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-upDownArrow")
        || (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-verticalScroll"))
        return fY / std::min(fW, fH) * 100000.0;

    // pattern y / ss * 50000
    if (rShapeType == u"ooxml-bentArrow")
        return fY / std::min(fW, fH) * 50000.0;

    // pattern (vc - y) / h * 100000
    if ((rShapeType == u"ooxml-mathDivide" && nHandleIndex == 1) // -adj1 / 2 - adj3 outside
        || (rShapeType == u"ooxml-mathEqual" && nHandleIndex == 0) // -adj2 / 2 outside
        || (rShapeType == u"ooxml-mathNotEqual" && nHandleIndex == 0) // -adj3 / 2 outside
        || (rShapeType == u"ooxml-star4") || (rShapeType == u"ooxml-star6")
        || (rShapeType == u"ooxml-star8") || (rShapeType == u"ooxml-star10")
        || (rShapeType == u"ooxml-star12") || (rShapeType == u"ooxml-star16")
        || (rShapeType == u"ooxml-star24") || (rShapeType == u"ooxml-star32"))
        return (fH / 2.0 - fY) / fH * 100000.0;

    // pattern (vc - y) / h * 200000
    if ((rShapeType == u"ooxml-leftArrow") || (rShapeType == u"ooxml-leftRightArrow")
        || (rShapeType == u"ooxml-mathDivide" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-mathEqual" && nHandleIndex == 1)
        || (rShapeType == u"ooxml-mathMinus") || (rShapeType == u"ooxml-notchedRightArrow")
        || (rShapeType == u"ooxml-mathNotEqual" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 3)
        || (rShapeType == u"ooxml-rightArrow") || (rShapeType == u"ooxml-stripedRightArrow")
        || (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 3))
        return (fH / 2.0 - fY) / fH * 200000.0;

    // pattern (y - vc) / h * 100000
    if ((rShapeType == u"ooxml-cloudCallout") || (rShapeType == u"ooxml-wedgeEllipseCallout")
        || (rShapeType == u"ooxml-wedgeRectCallout")
        || (rShapeType == u"ooxml-wedgeRoundRectCallout"))
        return (fY - fH / 2.0) / fH * 100000.0;

    // pattern (h - y) / h * 100000 or (b - y) / h * 100000
    if ((rShapeType == u"ooxml-ellipseRibbon" && nHandleIndex == 2)
        || (rShapeType == u"ooxml-ellipseRibbon2" && nHandleIndex == 0)
        || (rShapeType == u"ooxml-ribbon2")
        || (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 3))
        return (fH - fY) / fH * 100000.0;

    // special pattern smiley
    if (rShapeType == u"ooxml-smileyFace")
        return (fY - fH * 16515.0 / 21600.0) / fH * 100000.0;

    // special pattern for star with odd number of tips, because center of star not center of shape
    if (rShapeType == u"ooxml-star5")
        return (fH / 2.0 - fY * 100000.0 / 110557.0) / fH * 100000.0;
    if (rShapeType == u"ooxml-star7")
        return (fH / 2.0 - fY * 100000.0 / 105210.0) / fH * 100000.0;

    // special pattern swooshArrow
    if (rShapeType == u"ooxml-swooshArrow")
        return (fY - std::min(fW, fH) / 8.0) / fH * 100000.0;

    // special pattern leftRightRibbon
    if (rShapeType == u"ooxml-leftRightRibbon")
        return fY / fH * 200000 - 100000;

    // pattern y / h * 100000, simple scaling
    if (o3tl::starts_with(rShapeType, u"ooxml-"))
        return fY / fH * 100000.0;

    return fY; // method is unknown
}

static double lcl_getAngleInOOXMLUnit(double fDY, double fDX)
{
    if (fDX != 0.0 || fDY != 0.0)
    {
        double fAngleRad(atan2(fDY, fDX));
        double fAngle = basegfx::rad2deg(fAngleRad);
        // atan2 returns angle in ]-pi; pi], OOXML preset shapes use [0;360[.
        if (fAngle < 0.0)
            fAngle += 360.0;
        // OOXML uses angle unit 1/60000 degree.
        fAngle *= 60000.0;
        return fAngle;
    }
    return 0.0; // no angle defined for origin in polar coordinate system
}

static double lcl_getRadiusDistance(double fWR, double fHR, double fX, double fY)
{
    // Get D so, that point (fX|fY) is on the ellipse, that has width fWR-D and
    // height fHR-D and center in origin.
    // Get solution of ellipse equation (fX/(fWR-D))^2 + (fY/(fHR-D)^2 = 1 by solving
    // fX^2*(fHR-D)^2 + fY^2*(fWR-D)^2 - (fWR-D)^2 * (fHR-D)^2 = 0 with Newton-method.
    if (fX == 0.0)
        return std::min(fHR - fY, fWR);
    else if (fY == 0.0)
        return std::min(fWR - fX, fHR);

    double fD = std::min(fWR, fHR) - std::hypot(fX, fY); // iteration start value
    sal_uInt8 nIter(0);
    bool bFound(false);
    do
    {
        ++nIter;
        const double fOldD(fD);
        const double fWRmD(fWR - fD);
        const double fHRmD(fHR - fD);
        double fNumerator
            = fX * fX * fHRmD * fHRmD + fY * fY * fWRmD * fWRmD - fWRmD * fWRmD * fHRmD * fHRmD;
        double fDenominator
            = 2.0 * (fHRmD * (fWRmD * fWRmD - fX * fX) + fWRmD * (fHRmD * fHRmD - fY * fY));
        if (fDenominator != 0.0)
        {
            fD = fD - fNumerator / fDenominator;
            bFound = fabs(fOldD - fD) < 1.0E-12;
        }
        else
            fD = fD * 0.9; // new start value
    } while (nIter < 50 && !bFound);
    return fD;
}

bool EnhancedCustomShape2d::SetHandleControllerPosition( const sal_uInt32 nIndex, const css::awt::Point& rPosition )
{
    // The method name is misleading. Essentially it calculates the adjustment values from a given
    // handle position.

    // For ooxml-foo shapes, the way to calculate the adjustment value from the handle position depends on
    // the type of the shape, therefore need 'Type'.
    OUString sShapeType(u"non-primitive"_ustr); // default for ODF
    const SdrCustomShapeGeometryItem& rGeometryItem(mrSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
    const Any* pAny = rGeometryItem.GetPropertyValueByName(u"Type"_ustr);
    if (pAny)
        *pAny >>= sShapeType;

    bool bRetValue = false;
    if ( nIndex < GetHdlCount() )
    {
        Handle aHandle;
        if ( ConvertSequenceToEnhancedCustomShape2dHandle( m_seqHandles[ nIndex ], aHandle ) )
        {
            Point aP( rPosition.X, rPosition.Y );
            // apply the negative object rotation to the controller position

            aP.Move( -m_aLogicRect.Left(), -m_aLogicRect.Top() );
            if ( m_bFlipH )
                aP.setX( m_aLogicRect.GetWidth() - aP.X() );
            if ( m_bFlipV )
                aP.setY( m_aLogicRect.GetHeight() - aP.Y() );
            if ( m_nRotateAngle )
            {
                double a = -toRadians(m_nRotateAngle);
                RotatePoint( aP, Point( m_aLogicRect.GetWidth() / 2, m_aLogicRect.GetHeight() / 2 ), sin( a ), cos( a ) );
            }
            const GeoStat aGeoStat(mrSdrObjCustomShape.GetGeoStat());
            if ( aGeoStat.m_nShearAngle )
            {
                double nTan = -aGeoStat.mfTanShearAngle;
                if (m_bFlipV != m_bFlipH)
                    nTan = -nTan;
                ShearPoint( aP, Point( m_aLogicRect.GetWidth() / 2, m_aLogicRect.GetHeight() / 2 ), nTan );
            }

            double fPos1 = aP.X();  //( bFlipH ) ? aLogicRect.GetWidth() - aP.X() : aP.X();
            double fPos2 = aP.Y();  //( bFlipV ) ? aLogicRect.GetHeight() -aP.Y() : aP.Y();
            fPos1 = !basegfx::fTools::equalZero(m_fXScale) ? (fPos1 / m_fXScale) : SAL_MAX_INT32;
            fPos2 = !basegfx::fTools::equalZero(m_fYScale) ? (fPos2 / m_fYScale) : SAL_MAX_INT32;
            // revert -nCoordLeft and -nCoordTop aus GetPoint()
            fPos1 += m_nCoordLeft;
            fPos2 += m_nCoordTop;

            // Used for scaling the adjustment values based on handle positions
            double fWidth;
            double fHeight;

            if ( m_nCoordWidth || m_nCoordHeight )
            {
                fWidth = m_nCoordWidth;
                fHeight = m_nCoordHeight;
            }
            else
            {
                fWidth = m_aLogicRect.GetWidth();
                fHeight = m_aLogicRect.GetHeight();
            }

            if ( aHandle.nFlags & HandleFlags::SWITCHED )
            {
                if ( m_aLogicRect.GetHeight() > m_aLogicRect.GetWidth() )
                {
                    double fX = fPos1;
                    double fY = fPos2;
                    double fTmp = fWidth;
                    fPos1 = fY;
                    fPos2 = fX;
--> --------------------

--> maximum size reached

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

Messung V0.5
C=91 H=96 G=93

¤ Dauer der Verarbeitung: 0.22 Sekunden  ¤

*© 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.