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

Quelle  svdopath.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 <o3tl/unit_conversion.hxx>
#include <tools/bigint.hxx>
#include <tools/helpers.hxx>
#include <svx/svdopath.hxx>
#include <math.h>
#include <svx/xpoly.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svddrag.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdhdl.hxx>
#include <svx/svdview.hxx>
#include <svx/dialmgr.hxx>
#include <svx/strings.hrc>

#include <svx/polypolygoneditor.hxx>
#include <sdr/contact/viewcontactofsdrpathobj.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/range/b2drange.hxx>
#include <basegfx/curve/b2dcubicbezier.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <sdr/attribute/sdrtextattribute.hxx>
#include <sdr/primitive2d/sdrattributecreator.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <sdr/attribute/sdrformtextattribute.hxx>
#include <utility>
#include <vcl/ptrstyle.hxx>
#include <memory>
#include <sal/log.hxx>
#include <osl/diagnose.h>

using namespace sdr;

static sal_uInt16 GetPrevPnt(sal_uInt16 nPnt, sal_uInt16 nPntMax, bool bClosed)
{
    if (nPnt>0) {
        nPnt--;
    } else {
        nPnt=nPntMax;
        if (bClosed) nPnt--;
    }
    return nPnt;
}

static sal_uInt16 GetNextPnt(sal_uInt16 nPnt, sal_uInt16 nPntMax, bool bClosed)
{
    nPnt++;
    if (nPnt>nPntMax || (bClosed && nPnt>=nPntMax)) nPnt=0;
    return nPnt;
}

namespace {

struct ImpSdrPathDragData  : public SdrDragStatUserData
{
    XPolygon                    aXP;            // section of the original polygon
    bool                        bValid;         // FALSE = too few points
    bool                        bClosed;        // closed object?
    sal_uInt16                  nPoly;          // number of the polygon in the PolyPolygon
    sal_uInt16                  nPnt;           // number of point in the above polygon
    sal_uInt16                  nPointCount;    // number of points of the polygon
    bool                        bBegPnt;        // dragged point is first point of a Polyline
    bool                        bEndPnt;        // dragged point is finishing point of a Polyline
    sal_uInt16                  nPrevPnt;       // index of previous point
    sal_uInt16                  nNextPnt;       // index of next point
    bool                        bPrevIsBegPnt;  // previous point is first point of a Polyline
    bool                        bNextIsEndPnt;  // next point is first point of a Polyline
    sal_uInt16                  nPrevPrevPnt;   // index of point before previous point
    sal_uInt16                  nNextNextPnt;   // index of point after next point
    bool                        bControl;       // point is a control point
    bool                        bIsNextControl; // point is a control point after a support point
    bool                        bPrevIsControl; // if nPnt is a support point: a control point comes before
    bool                        bNextIsControl; // if nPnt is a support point: a control point comes after
    sal_uInt16                  nPrevPrevPnt0;
    sal_uInt16                  nPrevPnt0;
    sal_uInt16                  nPnt0;
    sal_uInt16                  nNextPnt0;
    sal_uInt16                  nNextNextPnt0;
    bool                        bEliminate;     // delete point? (is set by MovDrag)

    bool                        mbMultiPointDrag;
    const XPolyPolygon          maOrig;
    XPolyPolygon                maMove;
    std::vector<SdrHdl*>        maHandles;

public:
    ImpSdrPathDragData(const SdrPathObj& rPO, const SdrHdl& rHdl, bool bMuPoDr, const SdrDragStat& rDrag);
    void ResetPoly(const SdrPathObj& rPO);
    bool IsMultiPointDrag() const { return mbMultiPointDrag; }
};

}

ImpSdrPathDragData::ImpSdrPathDragData(const SdrPathObj& rPO, const SdrHdl& rHdl, bool bMuPoDr, const SdrDragStat& rDrag)
    : aXP(5)
    , bValid(false)
    , bClosed(false)
    , nPoly(0)
    , nPnt(0)
    , nPointCount(0)
    , bBegPnt(false)
    , bEndPnt(false)
    , nPrevPnt(0)
    , nNextPnt(0)
    , bPrevIsBegPnt(false)
    , bNextIsEndPnt(false)
    , nPrevPrevPnt(0)
    , nNextNextPnt(0)
    , bControl(false)
    , bIsNextControl(false)
    , bPrevIsControl(false)
    , bNextIsControl(false)
    , nPrevPrevPnt0(0)
    , nPrevPnt0(0)
    , nPnt0(0)
    , nNextPnt0(0)
    , nNextNextPnt0(0)
    , bEliminate(false)
    , mbMultiPointDrag(bMuPoDr)
    , maOrig(rPO.GetPathPoly())
    , maHandles(0)
{
    if(mbMultiPointDrag)
    {
        const SdrMarkView& rMarkView = *rDrag.GetView();
        const SdrHdlList& rHdlList = rMarkView.GetHdlList();
        const size_t nHdlCount = rHdlList.GetHdlCount();
        const SdrObject* pInteractionObject(nHdlCount && rHdlList.GetHdl(0) ? rHdlList.GetHdl(0)->GetObj() : nullptr);

        for(size_t a = 0; a < nHdlCount; ++a)
        {
            SdrHdl* pTestHdl = rHdlList.GetHdl(a);

            if(pTestHdl && pTestHdl->IsSelected() && pTestHdl->GetObj() == pInteractionObject)
            {
                maHandles.push_back(pTestHdl);
            }
        }

        maMove = maOrig;
        bValid = true;
    }
    else
    {
        sal_uInt16 nPntMax = 0; // maximum index
        bValid=false;
        bClosed=rPO.IsClosed();          // closed object?
        nPoly=static_cast<sal_uInt16>(rHdl.GetPolyNum());            // number of the polygon in the PolyPolygon
        nPnt=static_cast<sal_uInt16>(rHdl.GetPointNum());            // number of points in the above polygon
        const XPolygon aTmpXP(rPO.GetPathPoly().getB2DPolygon(nPoly));
        nPointCount=aTmpXP.GetPointCount();        // number of point of the polygon
        if (nPointCount==0 || (bClosed && nPointCount==1)) return// minimum of 1 points for Lines, minimum of 2 points for Polygon
        nPntMax=nPointCount-1;                  // maximum index
        bBegPnt=!bClosed && nPnt==0;        // dragged point is first point of a Polyline
        bEndPnt=!bClosed && nPnt==nPntMax;  // dragged point is finishing point of a Polyline
        if (bClosed && nPointCount<=3) {        // if polygon is only a line
            bBegPnt=(nPointCount<3) || nPnt==0;
            bEndPnt=(nPointCount<3) || nPnt==nPntMax-1;
        }
        nPrevPnt=nPnt;                      // index of previous point
        nNextPnt=nPnt;                      // index of next point
        if (!bBegPnt) nPrevPnt=GetPrevPnt(nPnt,nPntMax,bClosed);
        if (!bEndPnt) nNextPnt=GetNextPnt(nPnt,nPntMax,bClosed);
        bPrevIsBegPnt=bBegPnt || (!bClosed && nPrevPnt==0);
        bNextIsEndPnt=bEndPnt || (!bClosed && nNextPnt==nPntMax);
        nPrevPrevPnt=nPnt;                  // index of point before previous point
        nNextNextPnt=nPnt;                  // index of point after next point
        if (!bPrevIsBegPnt) nPrevPrevPnt=GetPrevPnt(nPrevPnt,nPntMax,bClosed);
        if (!bNextIsEndPnt) nNextNextPnt=GetNextPnt(nNextPnt,nPntMax,bClosed);
        bControl=rHdl.IsPlusHdl();          // point is a control point
        bIsNextControl=false;               // point is a control point after a support point
        bPrevIsControl=false;               // if nPnt is a support point: a control point comes before
        bNextIsControl=false;               // if nPnt is a support point: a control point comes after
        if (bControl) {
            bIsNextControl=!aTmpXP.IsControl(nPrevPnt);
        } else {
            bPrevIsControl=!bBegPnt && !bPrevIsBegPnt && aTmpXP.GetFlags(nPrevPnt)==PolyFlags::Control;
            bNextIsControl=!bEndPnt && !bNextIsEndPnt && aTmpXP.GetFlags(nNextPnt)==PolyFlags::Control;
        }
        nPrevPrevPnt0=nPrevPrevPnt;
        nPrevPnt0    =nPrevPnt;
        nPnt0        =nPnt;
        nNextPnt0    =nNextPnt;
        nNextNextPnt0=nNextNextPnt;
        nPrevPrevPnt=0;
        nPrevPnt=1;
        nPnt=2;
        nNextPnt=3;
        nNextNextPnt=4;
        bEliminate=false;
        ResetPoly(rPO);
        bValid=true;
    }
}

void ImpSdrPathDragData::ResetPoly(const SdrPathObj& rPO)
{
    const XPolygon aTmpXP(rPO.GetPathPoly().getB2DPolygon(nPoly));
    aXP[0]=aTmpXP[nPrevPrevPnt0];  aXP.SetFlags(0,aTmpXP.GetFlags(nPrevPrevPnt0));
    aXP[1]=aTmpXP[nPrevPnt0];      aXP.SetFlags(1,aTmpXP.GetFlags(nPrevPnt0));
    aXP[2]=aTmpXP[nPnt0];          aXP.SetFlags(2,aTmpXP.GetFlags(nPnt0));
    aXP[3]=aTmpXP[nNextPnt0];      aXP.SetFlags(3,aTmpXP.GetFlags(nNextPnt0));
    aXP[4]=aTmpXP[nNextNextPnt0];  aXP.SetFlags(4,aTmpXP.GetFlags(nNextNextPnt0));
}

namespace {

struct ImpPathCreateUser  : public SdrDragStatUserData
{
    Point                   aBezControl0;
    Point                   aBezStart;
    Point                   aBezCtrl1;
    Point                   aBezCtrl2;
    Point                   aBezEnd;
    Point                   aCircStart;
    Point                   aCircEnd;
    Point                   aCircCenter;
    Point                   aLineStart;
    Point                   aLineEnd;
    Point                   aRectP1;
    Point                   aRectP2;
    Point                   aRectP3;
    tools::Long                    nCircRadius;
    Degree100               nCircStAngle;
    Degree100               nCircRelAngle;
    bool                    bBezier;
    bool                    bBezHasCtrl0;
    bool                    bCircle;
    bool                    bAngleSnap;
    bool                    bLine;
    bool                    bLine90;
    bool                    bRect;
    bool                    bMixedCreate;
    sal_uInt16                  nBezierStartPoint;
    SdrObjKind              eStartKind;
    SdrObjKind              eCurrentKind;

public:
    ImpPathCreateUser(): nCircRadius(0),nCircStAngle(0),nCircRelAngle(0),
        bBezier(false),bBezHasCtrl0(false),bCircle(false),bAngleSnap(false),bLine(false),bLine90(false),bRect(false),
        bMixedCreate(false),nBezierStartPoint(0),eStartKind(SdrObjKind::NONE),eCurrentKind(SdrObjKind::NONE) { }

    void ResetFormFlags() { bBezier=false; bCircle=false; bLine=false; bRect=false; }
    bool IsFormFlag() const { return bBezier || bCircle || bLine || bRect; }
    XPolygon GetFormPoly() const;
    void CalcBezier(const Point& rP1, const Point& rP2, const Point& rDir, bool bMouseDown);
    XPolygon GetBezierPoly() const;
    void CalcCircle(const Point& rP1, const Point& rP2, const Point& rDir, SdrView const * pView);
    XPolygon GetCirclePoly() const;
    void CalcLine(const Point& rP1, const Point& rP2, const Point& rDir, SdrView const * pView);
    static Point    CalcLine(const Point& rCsr, tools::Long nDirX, tools::Long nDirY, SdrVieconst * pView);
    XPolygon GetLinePoly() const;
    void CalcRect(const Point& rP1, const Point& rP2, const Point& rDir, SdrView const * pView);
    XPolygon GetRectPoly() const;
};

}

XPolygon ImpPathCreateUser::GetFormPoly() const
{
    if (bBezier) return GetBezierPoly();
    if (bCircle) return GetCirclePoly();
    if (bLine)   return GetLinePoly();
    if (bRect)   return GetRectPoly();
    return XPolygon();
}

void ImpPathCreateUser::CalcBezier(const Point& rP1, const Point& rP2, const Point& rDir, bool bMouseDown)
{
    aBezStart=rP1;
    aBezCtrl1=rP1+rDir;
    aBezCtrl2=rP2;

    // #i21479#
    // Also copy the end point when no end point is set yet
    if (!bMouseDown || (0 == aBezEnd.X() && 0 == aBezEnd.Y())) aBezEnd=rP2;

    bBezier=true;
}

XPolygon ImpPathCreateUser::GetBezierPoly() const
{
    XPolygon aXP(4);
    aXP[0]=aBezStart; aXP.SetFlags(0,PolyFlags::Smooth);
    aXP[1]=aBezCtrl1; aXP.SetFlags(1,PolyFlags::Control);
    aXP[2]=aBezCtrl2; aXP.SetFlags(2,PolyFlags::Control);
    aXP[3]=aBezEnd;
    return aXP;
}

void ImpPathCreateUser::CalcCircle(const Point& rP1, const Point& rP2, const Point& rDir, SdrView const * pView)
{
    Degree100 nTangAngle=GetAngle(rDir);
    aCircStart=rP1;
    aCircEnd=rP2;
    aCircCenter=rP1;
    tools::Long dx=rP2.X()-rP1.X();
    tools::Long dy=rP2.Y()-rP1.Y();
    Degree100 dAngle=GetAngle(Point(dx,dy))-nTangAngle;
    dAngle=NormAngle36000(dAngle);
    Degree100 nTmpAngle=NormAngle36000(9000_deg100-dAngle);
    bool bRet=nTmpAngle!=9000_deg100 && nTmpAngle!=27000_deg100;
    tools::Long nRad=0;
    if (bRet) {
        double cs = cos(toRadians(nTmpAngle));
        double nR=static_cast<double>(GetLen(Point(dx,dy)))/cs/2;
        nRad = std::abs(basegfx::fround<tools::Long>(nR));
    }
    if (dAngle<18000_deg100) {
        nCircStAngle=NormAngle36000(nTangAngle-9000_deg100);
        nCircRelAngle=NormAngle36000(2_deg100*dAngle);
        aCircCenter.AdjustX(basegfx::fround<tools::Long>(nRad * cos(toRadians(nTangAngle + 9000_deg100))));
        aCircCenter.AdjustY(basegfx::fround<tools::Long>(nRad * -sin(toRadians(nTangAngle + 9000_deg100))));
    } else {
        nCircStAngle=NormAngle36000(nTangAngle+9000_deg100);
        nCircRelAngle=-NormAngle36000(36000_deg100-2_deg100*dAngle);
        aCircCenter.AdjustX(basegfx::fround<tools::Long>(nRad * cos(toRadians(nTangAngle - 9000_deg100))));
        aCircCenter.AdjustY(basegfx::fround<tools::Long>(nRad * -sin(toRadians(nTangAngle - 9000_deg100))));
    }
    bAngleSnap=pView!=nullptr && pView->IsAngleSnapEnabled();
    if (bAngleSnap) {
        Degree100 nSA=pView->GetSnapAngle();
        if (nSA) { // angle snapping
            bool bNeg=nCircRelAngle<0_deg100;
            if (bNeg) nCircRelAngle=-nCircRelAngle;
            nCircRelAngle+=nSA/2_deg100;
            nCircRelAngle/=nSA;
            nCircRelAngle*=nSA;
            nCircRelAngle=NormAngle36000(nCircRelAngle);
            if (bNeg) nCircRelAngle=-nCircRelAngle;
        }
    }
    nCircRadius=nRad;
    if (nRad==0 || abs(nCircRelAngle).get()<5) bRet=false;
    bCircle=bRet;
}

XPolygon ImpPathCreateUser::GetCirclePoly() const
{
    if (nCircRelAngle>=0_deg100) {
        XPolygon aXP(aCircCenter,nCircRadius,nCircRadius,
                     nCircStAngle, nCircStAngle+nCircRelAngle,false);
        aXP[0]=aCircStart; aXP.SetFlags(0,PolyFlags::Smooth);
        if (!bAngleSnap) aXP[aXP.GetPointCount()-1]=aCircEnd;
        return aXP;
    } else {
        XPolygon aXP(aCircCenter,nCircRadius,nCircRadius,
                     NormAngle36000(nCircStAngle+nCircRelAngle), nCircStAngle,false);
        sal_uInt16 nCount=aXP.GetPointCount();
        for (sal_uInt16 nNum=nCount/2; nNum>0;) {
            nNum--; // reverse XPoly's order of points
            sal_uInt16 n2=nCount-nNum-1;
            Point aPt(aXP[nNum]);
            aXP[nNum]=aXP[n2];
            aXP[n2]=aPt;
        }
        aXP[0]=aCircStart; aXP.SetFlags(0,PolyFlags::Smooth);
        if (!bAngleSnap) aXP[aXP.GetPointCount()-1]=aCircEnd;
        return aXP;
    }
}

Point ImpPathCreateUser::CalcLine(const Point& aCsr, tools::Long nDirX, tools::Long nDirY, SdrView const * pView)
{
    tools::Long x=aCsr.X();
    tools::Long y=aCsr.Y();
    bool bHLin=nDirY==0;
    bool bVLin=nDirX==0;
    if (bHLin) y=0;
    else if (bVLin) x=0;
    else {
        tools::Long x2=BigMulDiv(y,nDirX,nDirY);
        tools::Long y2=BigMulDiv(x,nDirY,nDirX);
        tools::Long l1=std::abs(x2)+std::abs(y);
        tools::Long l2=std::abs(x)+std::abs(y2);
        if ((l1<=l2) != (pView!=nullptr && pView->IsBigOrtho())) {
            x = x2;
        } else {
            y = y2;
        }
    }
    return Point(x,y);
}

void ImpPathCreateUser::CalcLine(const Point& rP1, const Point& rP2, const Point&&nbsp;rDir, SdrView const * pView)
{
    aLineStart=rP1;
    aLineEnd=rP2;
    bLine90=false;
    if (rP1==rP2 || (rDir.X()==0 && rDir.Y()==0)) { bLine=falsereturn; }
    Point aTmpPt(rP2-rP1);
    tools::Long nDirX=rDir.X();
    tools::Long nDirY=rDir.Y();
    Point aP1(CalcLine(aTmpPt, nDirX, nDirY,pView)); aP1-=aTmpPt; tools::Long nQ1=std::abs(aP1.X())+std::abs(aP1.Y());
    Point aP2(CalcLine(aTmpPt, nDirY,-nDirX,pView)); aP2-=aTmpPt; tools::Long nQ2=std::abs(aP2.X())+std::abs(aP2.Y());
    if (pView!=nullptr && pView->IsOrtho()) nQ1=0; // Ortho turns off at right angle
    bLine90=nQ1>2*nQ2;
    if (!bLine90) { // smooth transition
        aLineEnd+=aP1;
    } else {          // rectangular transition
        aLineEnd+=aP2;
    }
    bLine=true;
}

XPolygon ImpPathCreateUser::GetLinePoly() const
{
    XPolygon aXP(2);
    aXP[0]=aLineStart; if (!bLine90) aXP.SetFlags(0,PolyFlags::Smooth);
    aXP[1]=aLineEnd;
    return aXP;
}

void ImpPathCreateUser::CalcRect(const Point& rP1, const Point& rP2, const Point&&nbsp;rDir, SdrView const * pView)
{
    aRectP1=rP1;
    aRectP2=rP1;
    aRectP3=rP2;
    if (rP1==rP2 || (rDir.X()==0 && rDir.Y()==0)) { bRect=falsereturn; }
    Point aTmpPt(rP2-rP1);
    tools::Long nDirX=rDir.X();
    tools::Long nDirY=rDir.Y();
    tools::Long x=aTmpPt.X();
    tools::Long y=aTmpPt.Y();
    bool bHLin=nDirY==0;
    bool bVLin=nDirX==0;
    if (bHLin) y=0;
    else if (bVLin) x=0;
    else {
        y=BigMulDiv(x,nDirY,nDirX);
        tools::Long nHypLen=aTmpPt.Y()-y;
        Degree100 nTangAngle=-GetAngle(rDir);
        // sin=g/h, g=h*sin
        double a = toRadians(nTangAngle);
        double sn=sin(a);
        double cs=cos(a);
        double nGKathLen=nHypLen*sn;
        y += basegfx::fround<tools::Long>(nGKathLen * sn);
        x += basegfx::fround<tools::Long>(nGKathLen * cs);
    }
    aRectP2.AdjustX(x );
    aRectP2.AdjustY(y );
    if (pView!=nullptr && pView->IsOrtho()) {
        tools::Long dx1=aRectP2.X()-aRectP1.X(); tools::Long dx1a=std::abs(dx1);
        tools::Long dy1=aRectP2.Y()-aRectP1.Y(); tools::Long dy1a=std::abs(dy1);
        tools::Long dx2=aRectP3.X()-aRectP2.X(); tools::Long dx2a=std::abs(dx2);
        tools::Long dy2=aRectP3.Y()-aRectP2.Y(); tools::Long dy2a=std::abs(dy2);
        bool b1MoreThan2=dx1a+dy1a>dx2a+dy2a;
        if (b1MoreThan2 != pView->IsBigOrtho()) {
            tools::Long xtemp=dy2a-dx1a; if (dx1<0) xtemp=-xtemp;
            tools::Long ytemp=dx2a-dy1a; if (dy1<0) ytemp=-ytemp;
            aRectP2.AdjustX(xtemp );
            aRectP2.AdjustY(ytemp );
            aRectP3.AdjustX(xtemp );
            aRectP3.AdjustY(ytemp );
        } else {
            tools::Long xtemp=dy1a-dx2a; if (dx2<0) xtemp=-xtemp;
            tools::Long ytemp=dx1a-dy2a; if (dy2<0) ytemp=-ytemp;
            aRectP3.AdjustX(xtemp );
            aRectP3.AdjustY(ytemp );
        }
    }
    bRect=true;
}

XPolygon ImpPathCreateUser::GetRectPoly() const
{
    XPolygon aXP(3);
    aXP[0]=aRectP1; aXP.SetFlags(0,PolyFlags::Smooth);
    aXP[1]=aRectP2;
    if (aRectP3!=aRectP2) aXP[2]=aRectP3;
    return aXP;
}

class ImpPathForDragAndCreate
{
    SdrPathObj&                 mrSdrPathObject;
    XPolyPolygon                aPathPolygon;
    SdrObjKind                  meObjectKind;
    std::unique_ptr<ImpSdrPathDragData>
                                mpSdrPathDragData;
    bool                        mbCreating;

public:
    explicit ImpPathForDragAndCreate(SdrPathObj& rSdrPathObject);

    // drag stuff
    bool beginPathDrag( SdrDragStat const & rDrag )  const;
    bool movePathDrag( SdrDragStat& rDrag ) const;
    bool endPathDrag( SdrDragStat const & rDrag );
    OUString getSpecialDragComment(const SdrDragStat& rDrag) const;
    basegfx::B2DPolyPolygon getSpecialDragPoly(const SdrDragStat& rDrag) const;

    // create stuff
    void BegCreate(SdrDragStat& rStat);
    bool MovCreate(SdrDragStat& rStat);
    bool EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd);
    bool BckCreate(SdrDragStat const & rStat);
    void BrkCreate(SdrDragStat& rStat);
    PointerStyle GetCreatePointer() const;

    // helping stuff
    static bool IsClosed(SdrObjKind eKind) { return eKind==SdrObjKind::Polygon || eKind==SdrObjKind::PathPoly || eKind==SdrObjKind::PathFill || eKind==SdrObjKind::FreehandFill; }
    static bool IsFreeHand(SdrObjKind eKind) { return eKind==SdrObjKind::FreehandLine || eKind==SdrObjKind::FreehandFill; }
    static bool IsBezier(SdrObjKind eKind) { return eKind==SdrObjKind::PathLine || eKind==SdrObjKind::PathFill; }
    bool IsCreating() const { return mbCreating; }

    // get the polygon
    basegfx::B2DPolyPolygon TakeObjectPolyPolygon(const SdrDragStat& rDrag) const;
    static basegfx::B2DPolyPolygon TakeDragPolyPolygon(const SdrDragStat& rDrag);
    basegfx::B2DPolyPolygon getModifiedPolyPolygon() const { return  aPathPolygon.getB2DPolyPolygon(); }
};

ImpPathForDragAndCreate::ImpPathForDragAndCreate(SdrPathObj& rSdrPathObject)
:   mrSdrPathObject(rSdrPathObject),
    aPathPolygon(rSdrPathObject.GetPathPoly()),
    meObjectKind(mrSdrPathObject.meKind),
    mbCreating(false)
{
}

bool ImpPathForDragAndCreate::beginPathDrag( SdrDragStat const & rDrag )  const
{
    const SdrHdl* pHdl=rDrag.GetHdl();
    if(!pHdl)
        return false;

    bool bMultiPointDrag(true);

    if(aPathPolygon[static_cast<sal_uInt16>(pHdl->GetPolyNum())].IsControl(static_cast<sal_uInt16>(pHdl->GetPointNum())))
        bMultiPointDrag = false;

    if(bMultiPointDrag)
    {
        const SdrMarkView& rMarkView = *rDrag.GetView();
        const SdrHdlList& rHdlList = rMarkView.GetHdlList();
        const size_t nHdlCount = rHdlList.GetHdlCount();
        const SdrObject* pInteractionObject(nHdlCount && rHdlList.GetHdl(0) ? rHdlList.GetHdl(0)->GetObj() : nullptr);
        sal_uInt32 nSelectedPoints(0);

        for(size_t a = 0; a < nHdlCount; ++a)
        {
            SdrHdl* pTestHdl = rHdlList.GetHdl(a);

            if(pTestHdl && pTestHdl->IsSelected() && pTestHdl->GetObj() == pInteractionObject)
            {
                nSelectedPoints++;
            }
        }

        if(nSelectedPoints <= 1)
            bMultiPointDrag = false;
    }

    const_cast<ImpPathForDragAndCreate*>(this)->mpSdrPathDragData.reset( new ImpSdrPathDragData(mrSdrPathObject,*pHdl,bMultiPointDrag,rDrag) );

    if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
    {
        OSL_FAIL("ImpPathForDragAndCreate::BegDrag(): ImpSdrPathDragData is invalid.");
        const_cast<ImpPathForDragAndCreate*>(this)->mpSdrPathDragData.reset();
        return false;
    }

    return true;
}

bool ImpPathForDragAndCreate::movePathDrag( SdrDragStat& rDrag ) const
{
    if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
    {
        OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
        return false;
    }

    if(mpSdrPathDragData->IsMultiPointDrag())
    {
        Point aDelta(rDrag.GetNow() - rDrag.GetStart());

        if(aDelta.X() || aDelta.Y())
        {
            for(SdrHdl* pHandle : mpSdrPathDragData->maHandles)
            {
                const sal_uInt16 nPolyIndex(static_cast<sal_uInt16>(pHandle->GetPolyNum()));
                const sal_uInt16 nPointIndex(static_cast<sal_uInt16>(pHandle->GetPointNum()));
                const XPolygon& rOrig = mpSdrPathDragData->maOrig[nPolyIndex];
                XPolygon& rMove = mpSdrPathDragData->maMove[nPolyIndex];
                const sal_uInt16 nPointCount(rOrig.GetPointCount());
                bool bClosed(rOrig[0] == rOrig[nPointCount-1]);

                // move point itself
                rMove[nPointIndex] = rOrig[nPointIndex] + aDelta;

                // when point is first and poly closed, move close point, too.
                if(nPointCount > 0 && !nPointIndex && bClosed)
                {
                    rMove[nPointCount - 1] = rOrig[nPointCount - 1] + aDelta;

                    // when moving the last point it may be necessary to move the
                    // control point in front of this one, too.
                    if(nPointCount > 1 && rOrig.IsControl(nPointCount - 2))
                        rMove[nPointCount - 2] = rOrig[nPointCount - 2] + aDelta;
                }

                // is a control point before this?
                if(nPointIndex > 0 && rOrig.IsControl(nPointIndex - 1))
                {
                    // Yes, move it, too
                    rMove[nPointIndex - 1] = rOrig[nPointIndex - 1] + aDelta;
                }

                // is a control point after this?
                if(nPointIndex + 1 < nPointCount && rOrig.IsControl(nPointIndex + 1))
                {
                    // Yes, move it, too
                    rMove[nPointIndex + 1] = rOrig[nPointIndex + 1] + aDelta;
                }
            }
        }
    }
    else
    {
        mpSdrPathDragData->ResetPoly(mrSdrPathObject);

        // copy certain data locally to use less code and have faster access times
        bool bClosed           =mpSdrPathDragData->bClosed       ; // closed object?
        sal_uInt16   nPnt          =mpSdrPathDragData->nPnt          ; // number of point in the above polygon
        bool bBegPnt           =mpSdrPathDragData->bBegPnt       ; // dragged point is first point of a Polyline
        bool bEndPnt           =mpSdrPathDragData->bEndPnt       ; // dragged point is last point of a Polyline
        sal_uInt16   nPrevPnt      =mpSdrPathDragData->nPrevPnt      ; // index of previous point
        sal_uInt16   nNextPnt      =mpSdrPathDragData->nNextPnt      ; // index of next point
        bool bPrevIsBegPnt     =mpSdrPathDragData->bPrevIsBegPnt ; // previous point is first point of a Polyline
        bool bNextIsEndPnt     =mpSdrPathDragData->bNextIsEndPnt ; // next point is last point of a Polyline
        sal_uInt16   nPrevPrevPnt  =mpSdrPathDragData->nPrevPrevPnt  ; // index of the point before the previous point
        sal_uInt16   nNextNextPnt  =mpSdrPathDragData->nNextNextPnt  ; // index if the point after the next point
        bool bControl          =mpSdrPathDragData->bControl      ; // point is a control point
        bool bIsNextControl    =mpSdrPathDragData->bIsNextControl; // point is a control point after a support point
        bool bPrevIsControl    =mpSdrPathDragData->bPrevIsControl; // if nPnt is a support point: there's a control point before
        bool bNextIsControl    =mpSdrPathDragData->bNextIsControl; // if nPnt is a support point: there's a control point after

        // Ortho for lines/polygons: keep angle
        if (!bControl && rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho()) {
            bool bBigOrtho=rDrag.GetView()->IsBigOrtho();
            Point  aPos(rDrag.GetNow());      // current position
            Point  aPnt(mpSdrPathDragData->aXP[nPnt]);      // the dragged point
            sal_uInt16 nPnt1=0xFFFF,nPnt2=0xFFFF; // its neighboring points
            Point  aNewPos1,aNewPos2;         // new alternative for aPos
            bool bPnt1 = false, bPnt2 = false// are these valid alternatives?
            if (!bClosed && mpSdrPathDragData->nPointCount>=2) { // minimum of 2 points for lines
                if (!bBegPnt) nPnt1=nPrevPnt;
                if (!bEndPnt) nPnt2=nNextPnt;
            }
            if (bClosed && mpSdrPathDragData->nPointCount>=3) { // minimum of 3 points for polygon
                nPnt1=nPrevPnt;
                nPnt2=nNextPnt;
            }
            if (nPnt1!=0xFFFF && !bPrevIsControl) {
                Point aPnt1=mpSdrPathDragData->aXP[nPnt1];
                tools::Long ndx0=aPnt.X()-aPnt1.X();
                tools::Long ndy0=aPnt.Y()-aPnt1.Y();
                bool bHLin=ndy0==0;
                bool bVLin=ndx0==0;
                if (!bHLin || !bVLin) {
                    tools::Long ndx=aPos.X()-aPnt1.X();
                    tools::Long ndy=aPos.Y()-aPnt1.Y();
                    bPnt1=true;
                    double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0);
                    double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0);
                    bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
                    bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
                    if (bHor) ndy=tools::Long(ndy0*nXFact);
                    if (bVer) ndx=tools::Long(ndx0*nYFact);
                    aNewPos1=aPnt1;
                    aNewPos1.AdjustX(ndx );
                    aNewPos1.AdjustY(ndy );
                }
            }
            if (nPnt2!=0xFFFF && !bNextIsControl) {
                Point aPnt2=mpSdrPathDragData->aXP[nPnt2];
                tools::Long ndx0=aPnt.X()-aPnt2.X();
                tools::Long ndy0=aPnt.Y()-aPnt2.Y();
                bool bHLin=ndy0==0;
                bool bVLin=ndx0==0;
                if (!bHLin || !bVLin) {
                    tools::Long ndx=aPos.X()-aPnt2.X();
                    tools::Long ndy=aPos.Y()-aPnt2.Y();
                    bPnt2=true;
                    double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0);
                    double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0);
                    bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
                    bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
                    if (bHor) ndy=tools::Long(ndy0*nXFact);
                    if (bVer) ndx=tools::Long(ndx0*nYFact);
                    aNewPos2=aPnt2;
                    aNewPos2.AdjustX(ndx );
                    aNewPos2.AdjustY(ndy );
                }
            }
            if (bPnt1 && bPnt2) { // both alternatives exist (and compete)
                BigInt nX1(aNewPos1.X()-aPos.X()); nX1*=nX1;
                BigInt nY1(aNewPos1.Y()-aPos.Y()); nY1*=nY1;
                BigInt nX2(aNewPos2.X()-aPos.X()); nX2*=nX2;
                BigInt nY2(aNewPos2.Y()-aPos.Y()); nY2*=nY2;
                nX1+=nY1; // correction distance to square
                nX2+=nY2; // correction distance to square
                // let the alternative that allows fewer correction win
                if (nX1<nX2) bPnt2=falseelse bPnt1=false;
            }
            if (bPnt1) rDrag.SetNow(aNewPos1);
            if (bPnt2) rDrag.SetNow(aNewPos2);
        }
        rDrag.SetActionRect(tools::Rectangle(rDrag.GetNow(),rDrag.GetNow()));

        // specially for IBM: Eliminate points if both adjoining lines form near 180 degrees angle anyway
        if (!bControl && rDrag.GetView()!=nullptr && rDrag.GetView()->IsEliminatePolyPoints() &&
            !bBegPnt && !bEndPnt && !bPrevIsControl && !bNextIsControl)
        {
            Point aPt(mpSdrPathDragData->aXP[nNextPnt]);
            aPt-=rDrag.GetNow();
            Degree100 nAngle1=GetAngle(aPt);
            aPt=rDrag.GetNow();
            aPt-=mpSdrPathDragData->aXP[nPrevPnt];
            Degree100 nAngle2=GetAngle(aPt);
            Degree100 nDiff=nAngle1-nAngle2;
            nDiff=abs(nDiff);
            mpSdrPathDragData->bEliminate=nDiff<=rDrag.GetView()->GetEliminatePolyPointLimitAngle();
            if (mpSdrPathDragData->bEliminate) { // adapt position, Smooth is true for the ends
                aPt=mpSdrPathDragData->aXP[nNextPnt];
                aPt+=mpSdrPathDragData->aXP[nPrevPnt];
                aPt/=2;
                rDrag.SetNow(aPt);
            }
        }

        // we dragged by this distance
        Point aDiff(rDrag.GetNow()); aDiff-=mpSdrPathDragData->aXP[nPnt];

        /* There are 8 possible cases:
              X      1. A control point neither on the left nor on the right.
           o--X--o   2. There are control points on the left and the right, we are dragging a support point.
           o--X      3. There is a control point on the left, we are dragging a support point.
              X--o   4. There is a control point on the right, we are dragging a support point.
           x--O--o   5. There are control points on the left and the right, we are dragging the left one.
           x--O      6. There is a control point on the left, we are dragging it.
           o--O--x   7. There are control points on the left and the right, we are dragging the right one.
              O--x   8. There is a control point on the right, we are dragging it.
           Note: modifying a line (not a curve!) might create a curve on the other end of the line
           if Smooth is set there (with control points aligned to line).
        */


        mpSdrPathDragData->aXP[nPnt]+=aDiff;

        // now check symmetric plus handles
        if (bControl) { // cases 5,6,7,8
            sal_uInt16   nSt; // the associated support point
            sal_uInt16   nFix;  // the opposing control point
            if (bIsNextControl) { // if the next one is a control point, the on before has to be a support point
                nSt=nPrevPnt;
                nFix=nPrevPrevPnt;
            } else {
                nSt=nNextPnt;
                nFix=nNextNextPnt;
            }
            if (mpSdrPathDragData->aXP.IsSmooth(nSt)) {
                mpSdrPathDragData->aXP.CalcSmoothJoin(nSt,nPnt,nFix);
            }
        }

        if (!bControl) { // Cases 1,2,3,4. In case 1, nothing happens; in cases 3 and 4, there is more following below.
            // move both control points
            if (bPrevIsControl) mpSdrPathDragData->aXP[nPrevPnt]+=aDiff;
            if (bNextIsControl) mpSdrPathDragData->aXP[nNextPnt]+=aDiff;
            // align control point to line, if appropriate
            if (mpSdrPathDragData->aXP.IsSmooth(nPnt)) {
                if (bPrevIsControl && !bNextIsControl && !bEndPnt) { // case 3
                    mpSdrPathDragData->aXP.CalcSmoothJoin(nPnt,nNextPnt,nPrevPnt);
                }
                if (bNextIsControl && !bPrevIsControl && !bBegPnt) { // case 4
                    mpSdrPathDragData->aXP.CalcSmoothJoin(nPnt,nPrevPnt,nNextPnt);
                }
            }
            // Now check the other ends of the line (nPnt+-1). If there is a
            // curve (IsControl(nPnt+-2)) with SmoothJoin (nPnt+-1), the
            // associated control point (nPnt+-2) has to be adapted.
            if (!bBegPnt && !bPrevIsControl && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsSmooth(nPrevPnt)) {
                if (mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
                    mpSdrPathDragData->aXP.CalcSmoothJoin(nPrevPnt,nPnt,nPrevPrevPnt);
                }
            }
            if (!bEndPnt && !bNextIsControl && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsSmooth(nNextPnt)) {
                if (mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
                    mpSdrPathDragData->aXP.CalcSmoothJoin(nNextPnt,nPnt,nNextNextPnt);
                }
            }
        }
    }

    return true;
}

bool ImpPathForDragAndCreate::endPathDrag(SdrDragStat const & rDrag)
{
    Point aLinePt1;
    Point aLinePt2;
    bool bLineGlueMirror(SdrObjKind::Line == meObjectKind);
    if (bLineGlueMirror) {
        XPolygon& rXP=aPathPolygon[0];
        aLinePt1=rXP[0];
        aLinePt2=rXP[1];
    }

    if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
    {
        OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
        return false;
    }

    if(mpSdrPathDragData->IsMultiPointDrag())
    {
        aPathPolygon = mpSdrPathDragData->maMove;
    }
    else
    {
        const SdrHdl* pHdl=rDrag.GetHdl();

        // reference the polygon
        XPolygon& rXP=aPathPolygon[static_cast<sal_uInt16>(pHdl->GetPolyNum())];

        // the 5 points that might have changed
        if (!mpSdrPathDragData->bPrevIsBegPnt) rXP[mpSdrPathDragData->nPrevPrevPnt0]=mpSdrPathDragData->aXP[mpSdrPathDragData->nPrevPrevPnt];
        if (!mpSdrPathDragData->bNextIsEndPnt) rXP[mpSdrPathDragData->nNextNextPnt0]=mpSdrPathDragData->aXP[mpSdrPathDragData->nNextNextPnt];
        if (!mpSdrPathDragData->bBegPnt)       rXP[mpSdrPathDragData->nPrevPnt0]    =mpSdrPathDragData->aXP[mpSdrPathDragData->nPrevPnt];
        if (!mpSdrPathDragData->bEndPnt)       rXP[mpSdrPathDragData->nNextPnt0]    =mpSdrPathDragData->aXP[mpSdrPathDragData->nNextPnt];
        rXP[mpSdrPathDragData->nPnt0]        =mpSdrPathDragData->aXP[mpSdrPathDragData->nPnt];

        // for closed objects: last point has to be equal to first point
        if (mpSdrPathDragData->bClosed) rXP[rXP.GetPointCount()-1]=rXP[0];

        if (mpSdrPathDragData->bEliminate)
        {
            basegfx::B2DPolyPolygon aTempPolyPolygon(aPathPolygon.getB2DPolyPolygon());
            sal_uInt32 nPoly,nPnt;

            if(PolyPolygonEditor::GetRelativePolyPoint(aTempPolyPolygon, rDrag.GetHdl()->GetSourceHdlNum(), nPoly, nPnt))
            {
                basegfx::B2DPolygon aCandidate(aTempPolyPolygon.getB2DPolygon(nPoly));
                aCandidate.remove(nPnt);

                if(aCandidate.count() < 2)
                {
                    aTempPolyPolygon.remove(nPoly);
                }
                else
                {
                    aTempPolyPolygon.setB2DPolygon(nPoly, aCandidate);
                }
            }

            aPathPolygon = XPolyPolygon(aTempPolyPolygon);
        }

        // adapt angle for text beneath a simple line
        if (bLineGlueMirror)
        {
            Point aLinePt1_(aPathPolygon[0][0]);
            Point aLinePt2_(aPathPolygon[0][1]);
            bool bXMirr=(aLinePt1_.X()>aLinePt2_.X())!=(aLinePt1.X()>aLinePt2.X());
            bool bYMirr=(aLinePt1_.Y()>aLinePt2_.Y())!=(aLinePt1.Y()>aLinePt2.Y());
            if (bXMirr || bYMirr) {
                Point aRef1(mrSdrPathObject.GetSnapRect().Center());
                if (bXMirr) {
                    Point aRef2(aRef1);
                    aRef2.AdjustY( 1 );
                    mrSdrPathObject.NbcMirrorGluePoints(aRef1,aRef2);
                }
                if (bYMirr) {
                    Point aRef2(aRef1);
                    aRef2.AdjustX( 1 );
                    mrSdrPathObject.NbcMirrorGluePoints(aRef1,aRef2);
                }
            }
        }
    }

    mpSdrPathDragData.reset();

    return true;
}

OUString ImpPathForDragAndCreate::getSpecialDragComment(const SdrDragStat& rDrag) const
{
    OUString aStr;
    const SdrHdl* pHdl = rDrag.GetHdl();
    const bool bCreateComment(rDrag.GetView() && &mrSdrPathObject == rDrag.GetView()->GetCreateObj());

    if(bCreateComment && rDrag.GetUser())
    {
        // #i103058# re-add old creation comment mode
        const ImpPathCreateUser* pU = static_cast<const ImpPathCreateUser*>(rDrag.GetUser());
        const SdrObjKind eOriginalKind(meObjectKind);
        mrSdrPathObject.meKind = pU->eCurrentKind;
        aStr = mrSdrPathObject.ImpGetDescriptionStr(STR_ViewCreateObj);
        mrSdrPathObject.meKind = eOriginalKind;

        Point aPrev(rDrag.GetPrev());
        Point aNow(rDrag.GetNow());

        if(pU->bLine)
            aNow = pU->aLineEnd;

        aNow -= aPrev;
        aStr += " (";

        if(pU->bCircle)
        {
            aStr += SdrModel::GetAngleString(abs(pU->nCircRelAngle))
                    + " r="
                    + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(pU->nCircRadius, true);
        }

        aStr += "dx="
                + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(aNow.X(), true)
                + " dy="
                + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(aNow.Y(), true);

        if(!IsFreeHand(meObjectKind))
        {
            sal_Int32 nLen(GetLen(aNow));
            Degree100 nAngle(GetAngle(aNow));
            aStr += " l="
                    + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(nLen, true)
                    + " "
                    + SdrModel::GetAngleString(nAngle);
        }

        aStr += ")";
    }
    else if(!pHdl)
    {
        // #i103058# fallback when no model and/or Handle, both needed
        // for else-path
        aStr = mrSdrPathObject.ImpGetDescriptionStr(STR_DragPathObj);
    }
    else
    {
        // #i103058# standard for modification; model and handle needed
        ImpSdrPathDragData* pDragData = mpSdrPathDragData.get();

        if(!pDragData)
        {
            // getSpecialDragComment is also used from create, so fallback to GetUser()
            // when mpSdrPathDragData is not set
            pDragData = static_cast<ImpSdrPathDragData*>(rDrag.GetUser());
        }

        if(!pDragData)
        {
            OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
            return OUString();
        }

        if(!pDragData->IsMultiPointDrag() && pDragData->bEliminate)
        {
            // point of ...
            aStr = mrSdrPathObject.ImpGetDescriptionStr(STR_ViewMarkedPoint);

            // delete %O
            OUString aStr2(SvxResId(STR_EditDelete));

            // UNICODE: delete point of ...
            aStr2 = aStr2.replaceFirst("%1", aStr);

            return aStr2;
        }

        // dx=0.00 dy=0.00                -- both sides bezier
        // dx=0.00 dy=0.00  l=0.00 0.00\302\260  -- one bezier/lever on one side, a start, or an ending
        // dx=0.00 dy=0.00  l=0.00 0.00\302\260 / l=0.00 0.00\302\260 -- in between
        Point aBeg(rDrag.GetStart());
        Point aNow(rDrag.GetNow());

        aStr.clear();
        aStr += "dx="
                + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(aNow.X() - aBeg.X(), true)
                + " dy="
                + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(aNow.Y() - aBeg.Y(), true);

        if(!pDragData->IsMultiPointDrag())
        {
            sal_uInt16 nPntNum(static_cast<sal_uInt16>(pHdl->GetPointNum()));
            const XPolygon& rXPoly = aPathPolygon[static_cast<sal_uInt16>(rDrag.GetHdl()->GetPolyNum())];
            sal_uInt16 nPointCount(rXPoly.GetPointCount());
            bool bClose(IsClosed(meObjectKind));

            if(bClose)
                nPointCount--;

            if(pHdl->IsPlusHdl())
            {
                // lever
                sal_uInt16 nRef(nPntNum);

                if(rXPoly.IsControl(nPntNum + 1))
                    nRef--;
                else
                    nRef++;

                aNow -= rXPoly[nRef];

                sal_Int32 nLen(GetLen(aNow));
                Degree100 nAngle(GetAngle(aNow));
                aStr += " l="
                        + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(nLen, true)
                        + " "
                        + SdrModel::GetAngleString(nAngle);
            }
            else if(nPointCount > 1)
            {
                sal_uInt16 nPntMax(nPointCount - 1);
                bool bIsClosed(IsClosed(meObjectKind));
                bool bPt1(nPntNum > 0);
                bool bPt2(nPntNum < nPntMax);

                if(bIsClosed && nPointCount > 2)
                {
                    bPt1 = true;
                    bPt2 = true;
                }

                sal_uInt16 nPt1,nPt2;

                if(nPntNum > 0)
                    nPt1 = nPntNum - 1;
                else
                    nPt1 = nPntMax;

                if(nPntNum < nPntMax)
                    nPt2 = nPntNum + 1;
                else
                    nPt2 = 0;

                if(bPt1 && rXPoly.IsControl(nPt1))
                    bPt1 = false// don't display

                if(bPt2 && rXPoly.IsControl(nPt2))
                    bPt2 = false// of bezier data

                if(bPt1)
                {
                    Point aPt(aNow);
                    aPt -= rXPoly[nPt1];

                    sal_Int32 nLen(GetLen(aPt));
                    Degree100 nAngle(GetAngle(aPt));
                    aStr += " l="
                            + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(nLen, true)
                            + " "
                            + SdrModel::GetAngleString(nAngle);
                }

                if(bPt2)
                {
                    if(bPt1)
                        aStr += " / ";
                    else
                        aStr += " ";

                    Point aPt(aNow);
                    aPt -= rXPoly[nPt2];

                    sal_Int32 nLen(GetLen(aPt));
                    Degree100 nAngle(GetAngle(aPt));
                    aStr += "l="
                            + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(nLen, true)
                            + " "
                            + SdrModel::GetAngleString(nAngle);
                }
            }
        }
    }

    return aStr;
}

basegfx::B2DPolyPolygon ImpPathForDragAndCreate::getSpecialDragPoly(const SdrDragStat& rDrag) const
{
    if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
    {
        OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
        return basegfx::B2DPolyPolygon();
    }

    XPolyPolygon aRetval;

    if(mpSdrPathDragData->IsMultiPointDrag())
    {
        aRetval.Insert(mpSdrPathDragData->maMove);
    }
    else
    {
        const XPolygon& rXP=aPathPolygon[static_cast<sal_uInt16>(rDrag.GetHdl()->GetPolyNum())];
        if (rXP.GetPointCount()<=2) {
            XPolygon aXPoly(rXP);
            aXPoly[static_cast<sal_uInt16>(rDrag.GetHdl()->GetPointNum())]=rDrag.GetNow();
            aRetval.Insert(std::move(aXPoly));
            return aRetval.getB2DPolyPolygon();
        }
        // copy certain data locally to use less code and have faster access times
        bool bClosed           =mpSdrPathDragData->bClosed       ; // closed object?
        sal_uInt16 nPointCount = mpSdrPathDragData->nPointCount; // number of points
        sal_uInt16   nPnt          =mpSdrPathDragData->nPnt          ; // number of points in the polygon
        bool bBegPnt           =mpSdrPathDragData->bBegPnt       ; // dragged point is the first point of a Polyline
        bool bEndPnt           =mpSdrPathDragData->bEndPnt       ; // dragged point is the last point of a Polyline
        sal_uInt16   nPrevPnt      =mpSdrPathDragData->nPrevPnt      ; // index of the previous point
        sal_uInt16   nNextPnt      =mpSdrPathDragData->nNextPnt      ; // index of the next point
        bool bPrevIsBegPnt     =mpSdrPathDragData->bPrevIsBegPnt ; // previous point is first point of a Polyline
        bool bNextIsEndPnt     =mpSdrPathDragData->bNextIsEndPnt ; // next point is last point of a Polyline
        sal_uInt16   nPrevPrevPnt  =mpSdrPathDragData->nPrevPrevPnt  ; // index of the point before the previous point
        sal_uInt16   nNextNextPnt  =mpSdrPathDragData->nNextNextPnt  ; // index of the point after the last point
        bool bControl          =mpSdrPathDragData->bControl      ; // point is a control point
        bool bIsNextControl    =mpSdrPathDragData->bIsNextControl; //point is a control point after a support point
        bool bPrevIsControl    =mpSdrPathDragData->bPrevIsControl; // if nPnt is a support point: there's a control point before
        bool bNextIsControl    =mpSdrPathDragData->bNextIsControl; // if nPnt is a support point: there's a control point after
        XPolygon aXPoly(mpSdrPathDragData->aXP);
        XPolygon aLine1(2);
        XPolygon aLine2(2);
        XPolygon aLine3(2);
        XPolygon aLine4(2);
        if (bControl) {
            aLine1[1]=mpSdrPathDragData->aXP[nPnt];
            if (bIsNextControl) { // is this a control point after the support point?
                aLine1[0]=mpSdrPathDragData->aXP[nPrevPnt];
                aLine2[0]=mpSdrPathDragData->aXP[nNextNextPnt];
                aLine2[1]=mpSdrPathDragData->aXP[nNextPnt];
                if (mpSdrPathDragData->aXP.IsSmooth(nPrevPnt) && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
                    aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],PolyFlags::Control);
                    aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-2],PolyFlags::Normal);
                    // leverage lines for the opposing curve segment
                    aLine3[0]=mpSdrPathDragData->aXP[nPrevPnt];
                    aLine3[1]=mpSdrPathDragData->aXP[nPrevPrevPnt];
                    aLine4[0]=rXP[mpSdrPathDragData->nPrevPrevPnt0-2];
                    aLine4[1]=rXP[mpSdrPathDragData->nPrevPrevPnt0-1];
                } else {
                    aXPoly.Remove(0,1);
                }
            } else { // else this is a control point before a support point
                aLine1[0]=mpSdrPathDragData->aXP[nNextPnt];
                aLine2[0]=mpSdrPathDragData->aXP[nPrevPrevPnt];
                aLine2[1]=mpSdrPathDragData->aXP[nPrevPnt];
                if (mpSdrPathDragData->aXP.IsSmooth(nNextPnt) && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
                    aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],PolyFlags::Control);
                    aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+2],PolyFlags::Normal);
                    // leverage lines for the opposing curve segment
                    aLine3[0]=mpSdrPathDragData->aXP[nNextPnt];
                    aLine3[1]=mpSdrPathDragData->aXP[nNextNextPnt];
                    aLine4[0]=rXP[mpSdrPathDragData->nNextNextPnt0+2];
                    aLine4[1]=rXP[mpSdrPathDragData->nNextNextPnt0+1];
                } else {
                    aXPoly.Remove(aXPoly.GetPointCount()-1,1);
                }
            }
        } else { // else is not a control point
            if (mpSdrPathDragData->bEliminate) {
                aXPoly.Remove(2,1);
            }
            if (bPrevIsControl) aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],PolyFlags::Normal);
            else if (!bBegPnt && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
                aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],PolyFlags::Control);
                aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-2],PolyFlags::Normal);
            } else {
                aXPoly.Remove(0,1);
                if (bBegPnt) aXPoly.Remove(0,1);
            }
            if (bNextIsControl) aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],PolyFlags::Normal);
            else if (!bEndPnt && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
                aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],PolyFlags::Control);
                aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+2],PolyFlags::Normal);
            } else {
                aXPoly.Remove(aXPoly.GetPointCount()-1,1);
                if (bEndPnt) aXPoly.Remove(aXPoly.GetPointCount()-1,1);
            }
            if (bClosed) { // "pear problem": 2 lines, 1 curve, everything smoothed, a point between both lines is dragged
                if (aXPoly.GetPointCount()>nPointCount && aXPoly.IsControl(1)) {
                    sal_uInt16 a=aXPoly.GetPointCount();
                    aXPoly[a-2]=aXPoly[2]; aXPoly.SetFlags(a-2,aXPoly.GetFlags(2));
                    aXPoly[a-1]=aXPoly[3]; aXPoly.SetFlags(a-1,aXPoly.GetFlags(3));
                    aXPoly.Remove(0,3);
                }
            }
        }
        aRetval.Insert(std::move(aXPoly));
        if (aLine1.GetPointCount()>1) aRetval.Insert(std::move(aLine1));
        if (aLine2.GetPointCount()>1) aRetval.Insert(std::move(aLine2));
        if (aLine3.GetPointCount()>1) aRetval.Insert(std::move(aLine3));
        if (aLine4.GetPointCount()>1) aRetval.Insert(std::move(aLine4));
    }

    return aRetval.getB2DPolyPolygon();
}

void ImpPathForDragAndCreate::BegCreate(SdrDragStat& rStat)
{
    bool bFreeHand(IsFreeHand(meObjectKind));
    rStat.SetNoSnap(bFreeHand);
    rStat.SetOrtho8Possible();
    aPathPolygon.Clear();
    mbCreating=true;
    bool bMakeStartPoint = true;
    SdrView* pView=rStat.GetView();
    if (pView!=nullptr && pView->IsUseIncompatiblePathCreateInterface() &&
        (meObjectKind==SdrObjKind::Polygon || meObjectKind==SdrObjKind::PolyLine || meObjectKind==SdrObjKind::PathLine || meObjectKind==SdrObjKind::PathFill)) {
        bMakeStartPoint = false;
    }
    aPathPolygon.Insert(XPolygon());
    aPathPolygon[0][0]=rStat.GetStart();
    if (bMakeStartPoint) {
        aPathPolygon[0][1]=rStat.GetNow();
    }
    std::unique_ptr<ImpPathCreateUser> pU(new ImpPathCreateUser);
    pU->eStartKind=meObjectKind;
    pU->eCurrentKind=meObjectKind;
    rStat.SetUser(std::move(pU));
}

bool ImpPathForDragAndCreate::MovCreate(SdrDragStat& rStat)
{
    ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
    SdrView* pView=rStat.GetView();
    XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1];
    if (pView!=nullptr && pView->IsCreateMode()) {
        // switch to different CreateTool, if appropriate
        SdrObjKind nIdent;
        SdrInventor nInvent;
        pView->TakeCurrentObj(nIdent,nInvent);
        if (nInvent==SdrInventor::Default && pU->eCurrentKind != nIdent) {
            SdrObjKind eNewKind = nIdent;
            switch (eNewKind) {
                case SdrObjKind::CircleArc:
                case SdrObjKind::CircleOrEllipse:
                case SdrObjKind::CircleCut:
                case SdrObjKind::CircleSection:
                    eNewKind=SdrObjKind::CircleArc;
                    [[fallthrough]];
                case SdrObjKind::Rectangle:
                case SdrObjKind::Line:
                case SdrObjKind::PolyLine:
                case SdrObjKind::Polygon:
                case SdrObjKind::PathLine:
                case SdrObjKind::PathFill:
                case SdrObjKind::FreehandLine:
                case SdrObjKind::FreehandFill:
                {
                    pU->eCurrentKind=eNewKind;
                    pU->bMixedCreate=true;
                    pU->nBezierStartPoint=rXPoly.GetPointCount();
                    if (pU->nBezierStartPoint>0) pU->nBezierStartPoint--;
                } break;
                defaultbreak;
            } // switch
        }
    }
    sal_uInt16 nCurrentPoint=rXPoly.GetPointCount();
    if (aPathPolygon.Count()>1 && rStat.IsMouseDown() && nCurrentPoint<2) {
        rXPoly[0]=rStat.GetPos0();
        rXPoly[1]=rStat.GetNow();
        nCurrentPoint=2;
    }
    if (nCurrentPoint==0) {
        rXPoly[0]=rStat.GetPos0();
    } else nCurrentPoint--;
    bool bFreeHand=IsFreeHand(pU->eCurrentKind);
    rStat.SetNoSnap(bFreeHand);
    rStat.SetOrtho8Possible(pU->eCurrentKind!=SdrObjKind::CircleArc && pU->eCurrentKind!=SdrObjKind::Rectangle && (!pU->bMixedCreate || pU->eCurrentKind!=SdrObjKind::Line));
    rXPoly[nCurrentPoint]=rStat.GetNow();
    if (!pU->bMixedCreate && pU->eStartKind==SdrObjKind::Line && rXPoly.GetPointCount()>=1) {
        Point aPt(rStat.GetStart());
        if (pView!=nullptr && pView->IsCreate1stPointAsCenter()) {
            aPt+=aPt;
            aPt-=rStat.GetNow();
        }
        rXPoly[0]=aPt;
    }
    OutputDevice* pOut=pView==nullptr ? nullptr : pView->GetFirstOutputDevice();
    if (bFreeHand) {
        if (pU->nBezierStartPoint>nCurrentPoint) pU->nBezierStartPoint=nCurrentPoint;
        if (rStat.IsMouseDown() && nCurrentPoint>0) {
            // don't allow two consecutive points to occupy too similar positions
            tools::Long nMinDist=1;
            if (pView!=nullptr) nMinDist=pView->GetFreeHandMinDistPix();
            if (pOut!=nullptr) nMinDist=pOut->PixelToLogic(Size(nMinDist,0)).Width();
            if (nMinDist<1) nMinDist=1;

            Point aPt0(rXPoly[nCurrentPoint-1]);
            Point aPt1(rStat.GetNow());
            tools::Long dx=aPt0.X()-aPt1.X(); if (dx<0) dx=-dx;
            tools::Long dy=aPt0.Y()-aPt1.Y(); if (dy<0) dy=-dy;
            if (dx<nMinDist && dy<nMinDist) return false;

            // TODO: the following is copied from EndCreate (with a few smaller modifications)
            // and should be combined into a method with the code there.

            if (nCurrentPoint-pU->nBezierStartPoint>=3 && ((nCurrentPoint-pU->nBezierStartPoint)%3)==0) {
                rXPoly.PointsToBezier(nCurrentPoint-3);
                rXPoly.SetFlags(nCurrentPoint-1,PolyFlags::Control);
                rXPoly.SetFlags(nCurrentPoint-2,PolyFlags::Control);

                if (nCurrentPoint>=6 && rXPoly.IsControl(nCurrentPoint-4)) {
                    rXPoly.CalcTangent(nCurrentPoint-3,nCurrentPoint-4,nCurrentPoint-2);
                    rXPoly.SetFlags(nCurrentPoint-3,PolyFlags::Smooth);
                }
            }
            rXPoly[nCurrentPoint+1]=rStat.GetNow();
            rStat.NextPoint();
        } else {
            pU->nBezierStartPoint=nCurrentPoint;
        }
    }

    pU->ResetFormFlags();
    if (IsBezier(pU->eCurrentKind)) {
        if (nCurrentPoint>=2) {
            pU->CalcBezier(rXPoly[nCurrentPoint-1],rXPoly[nCurrentPoint],rXPoly[nCurrentPoint-1]-rXPoly[nCurrentPoint-2],rStat.IsMouseDown());
        } else if (pU->bBezHasCtrl0) {
            pU->CalcBezier(rXPoly[nCurrentPoint-1],rXPoly[nCurrentPoint],pU->aBezControl0-rXPoly[nCurrentPoint-1],rStat.IsMouseDown());
        }
    }
    if (pU->eCurrentKind==SdrObjKind::CircleArc && nCurrentPoint>=2) {
        pU->CalcCircle(rXPoly[nCurrentPoint-1],rXPoly[nCurrentPoint],rXPoly[nCurrentPoint-1]-rXPoly[nCurrentPoint-2],pView);
    }
    if (pU->eCurrentKind==SdrObjKind::Line && nCurrentPoint>=2) {
        pU->CalcLine(rXPoly[nCurrentPoint-1],rXPoly[nCurrentPoint],rXPoly[nCurrentPoint-1]-rXPoly[nCurrentPoint-2],pView);
    }
    if (pU->eCurrentKind==SdrObjKind::Rectangle && nCurrentPoint>=2) {
        pU->CalcRect(rXPoly[nCurrentPoint-1],rXPoly[nCurrentPoint],rXPoly[nCurrentPoint-1]-rXPoly[nCurrentPoint-2],pView);
    }

    return true;
}

bool ImpPathForDragAndCreate::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
{
    ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
    bool bRet = false;
    SdrView* pView=rStat.GetView();
    bool bIncomp=pView!=nullptr && pView->IsUseIncompatiblePathCreateInterface();
    XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1];
    sal_uInt16 nCurrentPoint=rXPoly.GetPointCount()-1;
    rXPoly[nCurrentPoint]=rStat.GetNow();
    if (!pU->bMixedCreate && pU->eStartKind==SdrObjKind::Line) {
        if (rStat.GetPointCount()>=2) eCmd=SdrCreateCmd::ForceEnd;
        bRet = eCmd==SdrCreateCmd::ForceEnd;
        if (bRet) {
            mbCreating = false;
            rStat.SetUser(nullptr);
        }
        return bRet;
    }

    if (!pU->bMixedCreate && IsFreeHand(pU->eStartKind)) {
        if (rStat.GetPointCount()>=2) eCmd=SdrCreateCmd::ForceEnd;
        bRet=eCmd==SdrCreateCmd::ForceEnd;
        if (bRet) {
            mbCreating=false;
            rStat.SetUser(nullptr);
        }
        return bRet;
    }
    if (eCmd==SdrCreateCmd::NextPoint || eCmd==SdrCreateCmd::NextObject) {
        // don't allow two consecutive points to occupy the same position
        if (nCurrentPoint==0 || rStat.GetNow()!=rXPoly[nCurrentPoint-1]) {
            if (bIncomp) {
                if (pU->nBezierStartPoint>nCurrentPoint) pU->nBezierStartPoint=nCurrentPoint;
                if (IsBezier(pU->eCurrentKind) && nCurrentPoint-pU->nBezierStartPoint>=3 && ((nCurrentPoint-pU->nBezierStartPoint)%3)==0) {
                    rXPoly.PointsToBezier(nCurrentPoint-3);
                    rXPoly.SetFlags(nCurrentPoint-1,PolyFlags::Control);
                    rXPoly.SetFlags(nCurrentPoint-2,PolyFlags::Control);

                    if (nCurrentPoint>=6 && rXPoly.IsControl(nCurrentPoint-4)) {
                        rXPoly.CalcTangent(nCurrentPoint-3,nCurrentPoint-4,nCurrentPoint-2);
                        rXPoly.SetFlags(nCurrentPoint-3,PolyFlags::Smooth);
                    }
                }
            } else {
                if (nCurrentPoint==1 && IsBezier(pU->eCurrentKind) && !pU->bBezHasCtrl0) {
                    pU->aBezControl0=rStat.GetNow();
                    pU->bBezHasCtrl0=true;
                    nCurrentPoint--;
                }
                if (pU->IsFormFlag()) {
                    sal_uInt16 nPointCount0=rXPoly.GetPointCount();
                    rXPoly.Remove(nCurrentPoint-1,2); // remove last two points and replace by form
                    rXPoly.Insert(XPOLY_APPEND,pU->GetFormPoly());
                    sal_uInt16 nPointCount1=rXPoly.GetPointCount();
                    for (sal_uInt16 i=nPointCount0+1; i<nPointCount1-1; i++) { // to make BckAction work
                        if (!rXPoly.IsControl(i)) rStat.NextPoint();
                    }
                    nCurrentPoint=rXPoly.GetPointCount()-1;
                }
            }
            nCurrentPoint++;
            rXPoly[nCurrentPoint]=rStat.GetNow();
        }
        if (eCmd==SdrCreateCmd::NextObject) {
            if (rXPoly.GetPointCount()>=2) {
                pU->bBezHasCtrl0=false;
                // only a singular polygon may be opened, so close this
                rXPoly[nCurrentPoint]=rXPoly[0];
                XPolygon aXP;
                aXP[0]=rStat.GetNow();
                aPathPolygon.Insert(std::move(aXP));
            }
        }
    }

    sal_uInt16 nPolyCount=aPathPolygon.Count();
    if (nPolyCount!=0) {
        // delete last point, if necessary
        if (eCmd==SdrCreateCmd::ForceEnd) {
            XPolygon& rXP=aPathPolygon[nPolyCount-1];
            sal_uInt16 nPointCount=rXP.GetPointCount();
            if (nPointCount>=2) {
                if (!rXP.IsControl(nPointCount-2)) {
                    if (rXP[nPointCount-1]==rXP[nPointCount-2]) {
                        rXP.Remove(nPointCount-1,1);
                    }
                } else {
                    if (rXP[nPointCount-3]==rXP[nPointCount-2]) {
                        rXP.Remove(nPointCount-3,3);
                    }
                }
            }
        }
        for (sal_uInt16 nPolyNum=nPolyCount; nPolyNum>0;) {
            nPolyNum--;
            XPolygon& rXP=aPathPolygon[nPolyNum];
            sal_uInt16 nPointCount=rXP.GetPointCount();
            // delete polygons with too few points
            if (nPolyNum<nPolyCount-1 || eCmd==SdrCreateCmd::ForceEnd) {
                if (nPointCount<2) aPathPolygon.Remove(nPolyNum);
            }
        }
    }
    pU->ResetFormFlags();
    bRet=eCmd==SdrCreateCmd::ForceEnd;
    if (bRet) {
        mbCreating=false;
        rStat.SetUser(nullptr);
    }
    return bRet;
}

bool ImpPathForDragAndCreate::BckCreate(SdrDragStat const & rStat)
{
    ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
    if (aPathPolygon.Count()>0) {
        XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1];
        sal_uInt16 nCurrentPoint=rXPoly.GetPointCount();
        if (nCurrentPoint>0) {
            nCurrentPoint--;
            // make the last part of a bezier curve a line
            rXPoly.Remove(nCurrentPoint,1);
            if (nCurrentPoint>=3 && rXPoly.IsControl(nCurrentPoint-1)) {
                // there should never be a bezier segment at the end, so this is just in case...
                rXPoly.Remove(nCurrentPoint-1,1);
                if (rXPoly.IsControl(nCurrentPoint-2)) rXPoly.Remove(nCurrentPoint-2,1);
            }
        }
        nCurrentPoint=rXPoly.GetPointCount();
        if (nCurrentPoint>=4) { // no bezier segment at the end
            nCurrentPoint--;
            if (rXPoly.IsControl(nCurrentPoint-1)) {
                rXPoly.Remove(nCurrentPoint-1,1);
                if (rXPoly.IsControl(nCurrentPoint-2)) rXPoly.Remove(nCurrentPoint-2,1);
            }
        }
        if (rXPoly.GetPointCount()<2) {
            aPathPolygon.Remove(aPathPolygon.Count()-1);
        }
        if (aPathPolygon.Count()>0) {
            XPolygon& rLocalXPoly=aPathPolygon[aPathPolygon.Count()-1];
            sal_uInt16 nLocalCurrentPoint=rLocalXPoly.GetPointCount();
            if (nLocalCurrentPoint>0) {
                nLocalCurrentPoint--;
                rLocalXPoly[nLocalCurrentPoint]=rStat.GetNow();
            }
        }
    }
    pU->ResetFormFlags();
    return aPathPolygon.Count()!=0;
}

void ImpPathForDragAndCreate::BrkCreate(SdrDragStat& rStat)
{
    aPathPolygon.Clear();
    mbCreating=false;
    rStat.SetUser(nullptr);
}

basegfx::B2DPolyPolygon ImpPathForDragAndCreate::TakeObjectPolyPolygon(const SdrDragStat& rDrag) const
{
    basegfx::B2DPolyPolygon aRetval(aPathPolygon.getB2DPolyPolygon());
    SdrView* pView = rDrag.GetView();

    if(pView && pView->IsUseIncompatiblePathCreateInterface())
        return aRetval;

    ImpPathCreateUser* pU = static_cast<ImpPathCreateUser*>(rDrag.GetUser());
    basegfx::B2DPolygon aNewPolygon(aRetval.count() ? aRetval.getB2DPolygon(aRetval.count() - 1) : basegfx::B2DPolygon());

    if(pU->IsFormFlag() && aNewPolygon.count() > 1)
    {
        // remove last segment and replace with current
        // do not forget to rescue the previous control point which will be lost when
--> --------------------

--> maximum size reached

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

Messung V0.5
C=95 H=96 G=95

¤ 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.