LCOV - code coverage report
Current view: top level - svx/source/svdraw - svdopath.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 339 1628 20.8 %
Date: 2015-06-13 12:38:46 Functions: 40 115 34.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <tools/bigint.hxx>
      21             : #include <tools/helpers.hxx>
      22             : #include <svx/svdopath.hxx>
      23             : #include <math.h>
      24             : #include <svx/xpool.hxx>
      25             : #include <svx/xpoly.hxx>
      26             : #include <svx/svdattr.hxx>
      27             : #include <svx/svdtrans.hxx>
      28             : #include <svx/svdetc.hxx>
      29             : #include <svx/svddrag.hxx>
      30             : #include <svx/svdmodel.hxx>
      31             : #include <svx/svdpage.hxx>
      32             : #include <svx/svdhdl.hxx>
      33             : #include <svx/svdview.hxx>
      34             : #include "svdglob.hxx"
      35             : #include "svx/svdstr.hrc"
      36             : 
      37             : #include <svx/xlnwtit.hxx>
      38             : #include <svx/xlnclit.hxx>
      39             : #include <svx/xflclit.hxx>
      40             : #include <svx/svdogrp.hxx>
      41             : #include <svx/polypolygoneditor.hxx>
      42             : #include <svx/xlntrit.hxx>
      43             : #include <sdr/contact/viewcontactofsdrpathobj.hxx>
      44             : #include <basegfx/matrix/b2dhommatrix.hxx>
      45             : #include "svdconv.hxx"
      46             : #include <basegfx/point/b2dpoint.hxx>
      47             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      48             : #include <basegfx/range/b2drange.hxx>
      49             : #include <basegfx/curve/b2dcubicbezier.hxx>
      50             : #include <basegfx/polygon/b2dpolygontools.hxx>
      51             : #include <svx/sdr/attribute/sdrtextattribute.hxx>
      52             : #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
      53             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      54             : #include <svx/sdr/attribute/sdrformtextattribute.hxx>
      55             : 
      56             : using namespace sdr;
      57             : 
      58           0 : inline sal_uInt16 GetPrevPnt(sal_uInt16 nPnt, sal_uInt16 nPntMax, bool bClosed)
      59             : {
      60           0 :     if (nPnt>0) {
      61           0 :         nPnt--;
      62             :     } else {
      63           0 :         nPnt=nPntMax;
      64           0 :         if (bClosed) nPnt--;
      65             :     }
      66           0 :     return nPnt;
      67             : }
      68             : 
      69           0 : inline sal_uInt16 GetNextPnt(sal_uInt16 nPnt, sal_uInt16 nPntMax, bool bClosed)
      70             : {
      71           0 :     nPnt++;
      72           0 :     if (nPnt>nPntMax || (bClosed && nPnt>=nPntMax)) nPnt=0;
      73           0 :     return nPnt;
      74             : }
      75             : 
      76           0 : struct ImpSdrPathDragData  : public SdrDragStatUserData
      77             : {
      78             :     XPolygon                    aXP;            // section of the original polygon
      79             :     bool                        bValid;         // FALSE = too few points
      80             :     bool                        bClosed;        // closed object?
      81             :     sal_uInt16                  nPoly;          // number of the polygon in the PolyPolygon
      82             :     sal_uInt16                  nPnt;           // number of point in the above polygon
      83             :     sal_uInt16                  nPointCount;    // number of points of the polygon
      84             :     sal_uInt16                  nPntMax;        // maximum index
      85             :     bool                        bBegPnt;        // dragged point is first point of a Polyline
      86             :     bool                        bEndPnt;        // dragged point is finishing point of a Polyline
      87             :     sal_uInt16                  nPrevPnt;       // index of previous point
      88             :     sal_uInt16                  nNextPnt;       // index of next point
      89             :     bool                        bPrevIsBegPnt;  // previous point is first point of a Polyline
      90             :     bool                        bNextIsEndPnt;  // next point is first point of a Polyline
      91             :     sal_uInt16                  nPrevPrevPnt;   // index of point before previous point
      92             :     sal_uInt16                  nNextNextPnt;   // index of point after next point
      93             :     bool                        bControl;       // point is a control point
      94             :     bool                        bIsPrevControl; // point is a control point before a support point
      95             :     bool                        bIsNextControl; // point is a control point after a support point
      96             :     bool                        bPrevIsControl; // if nPnt is a support point: a control point comes before
      97             :     bool                        bNextIsControl; // if nPnt is a support point: a control point comes after
      98             :     sal_uInt16                  nPrevPrevPnt0;
      99             :     sal_uInt16                  nPrevPnt0;
     100             :     sal_uInt16                  nPnt0;
     101             :     sal_uInt16                  nNextPnt0;
     102             :     sal_uInt16                  nNextNextPnt0;
     103             :     bool                        bEliminate;     // delete point? (is set by MovDrag)
     104             : 
     105             :     bool                        mbMultiPointDrag;
     106             :     const XPolyPolygon          maOrig;
     107             :     XPolyPolygon                maMove;
     108             :     std::vector<SdrHdl*>        maHandles;
     109             : 
     110             : public:
     111             :     ImpSdrPathDragData(const SdrPathObj& rPO, const SdrHdl& rHdl, bool bMuPoDr, const SdrDragStat& rDrag);
     112             :     void ResetPoly(const SdrPathObj& rPO);
     113           0 :     bool IsMultiPointDrag() const { return mbMultiPointDrag; }
     114             : };
     115             : 
     116           0 : ImpSdrPathDragData::ImpSdrPathDragData(const SdrPathObj& rPO, const SdrHdl& rHdl, bool bMuPoDr, const SdrDragStat& rDrag)
     117             :     : aXP(5)
     118             :     , bValid(false)
     119             :     , bClosed(false)
     120             :     , nPoly(0)
     121             :     , nPnt(0)
     122             :     , nPointCount(0)
     123             :     , nPntMax(0)
     124             :     , bBegPnt(false)
     125             :     , bEndPnt(false)
     126             :     , nPrevPnt(0)
     127             :     , nNextPnt(0)
     128             :     , bPrevIsBegPnt(false)
     129             :     , bNextIsEndPnt(false)
     130             :     , nPrevPrevPnt(0)
     131             :     , nNextNextPnt(0)
     132             :     , bControl(false)
     133             :     , bIsPrevControl(false)
     134             :     , bIsNextControl(false)
     135             :     , bPrevIsControl(false)
     136             :     , bNextIsControl(false)
     137             :     , nPrevPrevPnt0(0)
     138             :     , nPrevPnt0(0)
     139             :     , nPnt0(0)
     140             :     , nNextPnt0(0)
     141             :     , nNextNextPnt0(0)
     142             :     , bEliminate(false)
     143             :     , mbMultiPointDrag(bMuPoDr)
     144           0 :     , maOrig(rPO.GetPathPoly())
     145           0 :     , maHandles(0)
     146             : {
     147           0 :     if(mbMultiPointDrag)
     148             :     {
     149           0 :         const SdrMarkView& rMarkView = *rDrag.GetView();
     150           0 :         const SdrHdlList& rHdlList = rMarkView.GetHdlList();
     151           0 :         const size_t nHdlCount = rHdlList.GetHdlCount();
     152           0 :         const SdrObject* pInteractionObject(nHdlCount && rHdlList.GetHdl(0) ? rHdlList.GetHdl(0)->GetObj() : 0);
     153             : 
     154           0 :         for(size_t a = 0; a < nHdlCount; ++a)
     155             :         {
     156           0 :             SdrHdl* pTestHdl = rHdlList.GetHdl(a);
     157             : 
     158           0 :             if(pTestHdl && pTestHdl->IsSelected() && pTestHdl->GetObj() == pInteractionObject)
     159             :             {
     160           0 :                 maHandles.push_back(pTestHdl);
     161             :             }
     162             :         }
     163             : 
     164           0 :         maMove = maOrig;
     165           0 :         bValid = true;
     166             :     }
     167             :     else
     168             :     {
     169           0 :         bValid=false;
     170           0 :         bClosed=rPO.IsClosed();          // closed object?
     171           0 :         nPoly=(sal_uInt16)rHdl.GetPolyNum();            // number of the polygon in the PolyPolygon
     172           0 :         nPnt=(sal_uInt16)rHdl.GetPointNum();            // number of points in the above polygon
     173           0 :         const XPolygon aTmpXP(rPO.GetPathPoly().getB2DPolygon(nPoly));
     174           0 :         nPointCount=aTmpXP.GetPointCount();        // number of point of the polygon
     175           0 :         if (nPointCount==0 || (bClosed && nPointCount==1)) return; // minimum of 1 points for Lines, minimum of 2 points for Polygon
     176           0 :         nPntMax=nPointCount-1;                  // maximum index
     177           0 :         bBegPnt=!bClosed && nPnt==0;        // dragged point is first point of a Polyline
     178           0 :         bEndPnt=!bClosed && nPnt==nPntMax;  // dragged point is finishing point of a Polyline
     179           0 :         if (bClosed && nPointCount<=3) {        // if polygon is only a line
     180           0 :             bBegPnt=(nPointCount<3) || nPnt==0;
     181           0 :             bEndPnt=(nPointCount<3) || nPnt==nPntMax-1;
     182             :         }
     183           0 :         nPrevPnt=nPnt;                      // index of previous point
     184           0 :         nNextPnt=nPnt;                      // index of next point
     185           0 :         if (!bBegPnt) nPrevPnt=GetPrevPnt(nPnt,nPntMax,bClosed);
     186           0 :         if (!bEndPnt) nNextPnt=GetNextPnt(nPnt,nPntMax,bClosed);
     187           0 :         bPrevIsBegPnt=bBegPnt || (!bClosed && nPrevPnt==0);
     188           0 :         bNextIsEndPnt=bEndPnt || (!bClosed && nNextPnt==nPntMax);
     189           0 :         nPrevPrevPnt=nPnt;                  // index of point before previous point
     190           0 :         nNextNextPnt=nPnt;                  // index of point after next point
     191           0 :         if (!bPrevIsBegPnt) nPrevPrevPnt=GetPrevPnt(nPrevPnt,nPntMax,bClosed);
     192           0 :         if (!bNextIsEndPnt) nNextNextPnt=GetNextPnt(nNextPnt,nPntMax,bClosed);
     193           0 :         bControl=rHdl.IsPlusHdl();          // point is a control point
     194           0 :         bIsPrevControl=false;               // point is a control point before a support point
     195           0 :         bIsNextControl=false;               // point is a control point after a support point
     196           0 :         bPrevIsControl=false;               // if nPnt is a support point: a control point comes before
     197           0 :         bNextIsControl=false;               // if nPnt is a support point: a control point comes after
     198           0 :         if (bControl) {
     199           0 :             bIsPrevControl=aTmpXP.IsControl(nPrevPnt);
     200           0 :             bIsNextControl=!bIsPrevControl;
     201             :         } else {
     202           0 :             bPrevIsControl=!bBegPnt && !bPrevIsBegPnt && aTmpXP.GetFlags(nPrevPnt)==XPOLY_CONTROL;
     203           0 :             bNextIsControl=!bEndPnt && !bNextIsEndPnt && aTmpXP.GetFlags(nNextPnt)==XPOLY_CONTROL;
     204             :         }
     205           0 :         nPrevPrevPnt0=nPrevPrevPnt;
     206           0 :         nPrevPnt0    =nPrevPnt;
     207           0 :         nPnt0        =nPnt;
     208           0 :         nNextPnt0    =nNextPnt;
     209           0 :         nNextNextPnt0=nNextNextPnt;
     210           0 :         nPrevPrevPnt=0;
     211           0 :         nPrevPnt=1;
     212           0 :         nPnt=2;
     213           0 :         nNextPnt=3;
     214           0 :         nNextNextPnt=4;
     215           0 :         bEliminate=false;
     216           0 :         ResetPoly(rPO);
     217           0 :         bValid=true;
     218             :     }
     219             : }
     220             : 
     221           0 : void ImpSdrPathDragData::ResetPoly(const SdrPathObj& rPO)
     222             : {
     223           0 :     const XPolygon aTmpXP(rPO.GetPathPoly().getB2DPolygon(nPoly));
     224           0 :     aXP[0]=aTmpXP[nPrevPrevPnt0];  aXP.SetFlags(0,aTmpXP.GetFlags(nPrevPrevPnt0));
     225           0 :     aXP[1]=aTmpXP[nPrevPnt0];      aXP.SetFlags(1,aTmpXP.GetFlags(nPrevPnt0));
     226           0 :     aXP[2]=aTmpXP[nPnt0];          aXP.SetFlags(2,aTmpXP.GetFlags(nPnt0));
     227           0 :     aXP[3]=aTmpXP[nNextPnt0];      aXP.SetFlags(3,aTmpXP.GetFlags(nNextPnt0));
     228           0 :     aXP[4]=aTmpXP[nNextNextPnt0];  aXP.SetFlags(4,aTmpXP.GetFlags(nNextNextPnt0));
     229           0 : }
     230             : 
     231             : struct ImpPathCreateUser  : public SdrDragStatUserData
     232             : {
     233             :     Point                   aBezControl0;
     234             :     Point                   aBezStart;
     235             :     Point                   aBezCtrl1;
     236             :     Point                   aBezCtrl2;
     237             :     Point                   aBezEnd;
     238             :     Point                   aCircStart;
     239             :     Point                   aCircEnd;
     240             :     Point                   aCircCenter;
     241             :     Point                   aLineStart;
     242             :     Point                   aLineEnd;
     243             :     Point                   aRectP1;
     244             :     Point                   aRectP2;
     245             :     Point                   aRectP3;
     246             :     long                    nCircRadius;
     247             :     long                    nCircStAngle;
     248             :     long                    nCircRelAngle;
     249             :     bool                    bBezier;
     250             :     bool                    bBezHasCtrl0;
     251             :     bool                    bCurve;
     252             :     bool                    bCircle;
     253             :     bool                    bAngleSnap;
     254             :     bool                    bLine;
     255             :     bool                    bLine90;
     256             :     bool                    bRect;
     257             :     bool                    bMixedCreate;
     258             :     sal_uInt16                  nBezierStartPoint;
     259             :     SdrObjKind              eStartKind;
     260             :     SdrObjKind              eAktKind;
     261             : 
     262             : public:
     263           0 :     ImpPathCreateUser(): nCircRadius(0),nCircStAngle(0),nCircRelAngle(0),
     264             :         bBezier(false),bBezHasCtrl0(false),bCurve(false),bCircle(false),bAngleSnap(false),bLine(false),bLine90(false),bRect(false),
     265           0 :         bMixedCreate(false),nBezierStartPoint(0),eStartKind(OBJ_NONE),eAktKind(OBJ_NONE) { }
     266             : 
     267           0 :     void ResetFormFlags() { bBezier=false; bCurve=false; bCircle=false; bLine=false; bRect=false; }
     268           0 :     bool IsFormFlag() const { return bBezier || bCurve || bCircle || bLine || bRect; }
     269             :     XPolygon GetFormPoly() const;
     270             :     bool CalcBezier(const Point& rP1, const Point& rP2, const Point& rDir, bool bMouseDown);
     271             :     XPolygon GetBezierPoly() const;
     272           0 :     static XPolygon GetCurvePoly() { return XPolygon(); }
     273             :     bool CalcCircle(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView);
     274             :     XPolygon GetCirclePoly() const;
     275             :     bool CalcLine(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView);
     276             :     static Point    CalcLine(const Point& rCsr, long nDirX, long nDirY, SdrView* pView);
     277             :     XPolygon GetLinePoly() const;
     278             :     bool CalcRect(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView);
     279             :     XPolygon GetRectPoly() const;
     280             : };
     281             : 
     282           0 : XPolygon ImpPathCreateUser::GetFormPoly() const
     283             : {
     284           0 :     if (bBezier) return GetBezierPoly();
     285           0 :     if (bCurve)  return GetCurvePoly();
     286           0 :     if (bCircle) return GetCirclePoly();
     287           0 :     if (bLine)   return GetLinePoly();
     288           0 :     if (bRect)   return GetRectPoly();
     289           0 :     return XPolygon();
     290             : }
     291             : 
     292           0 : bool ImpPathCreateUser::CalcBezier(const Point& rP1, const Point& rP2, const Point& rDir, bool bMouseDown)
     293             : {
     294           0 :     bool bRet = true;
     295           0 :     aBezStart=rP1;
     296           0 :     aBezCtrl1=rP1+rDir;
     297           0 :     aBezCtrl2=rP2;
     298             : 
     299             :     // #i21479#
     300             :     // Also copy the end point when no end point is set yet
     301           0 :     if (!bMouseDown || (0L == aBezEnd.X() && 0L == aBezEnd.Y())) aBezEnd=rP2;
     302             : 
     303           0 :     bBezier=bRet;
     304           0 :     return bRet;
     305             : }
     306             : 
     307           0 : XPolygon ImpPathCreateUser::GetBezierPoly() const
     308             : {
     309           0 :     XPolygon aXP(4);
     310           0 :     aXP[0]=aBezStart; aXP.SetFlags(0,XPOLY_SMOOTH);
     311           0 :     aXP[1]=aBezCtrl1; aXP.SetFlags(1,XPOLY_CONTROL);
     312           0 :     aXP[2]=aBezCtrl2; aXP.SetFlags(2,XPOLY_CONTROL);
     313           0 :     aXP[3]=aBezEnd;
     314           0 :     return aXP;
     315             : }
     316             : 
     317           0 : bool ImpPathCreateUser::CalcCircle(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView)
     318             : {
     319           0 :     long nTangAngle=GetAngle(rDir);
     320           0 :     aCircStart=rP1;
     321           0 :     aCircEnd=rP2;
     322           0 :     aCircCenter=rP1;
     323           0 :     long dx=rP2.X()-rP1.X();
     324           0 :     long dy=rP2.Y()-rP1.Y();
     325           0 :     long dAngle=GetAngle(Point(dx,dy))-nTangAngle;
     326           0 :     dAngle=NormAngle360(dAngle);
     327           0 :     long nTmpAngle=NormAngle360(9000-dAngle);
     328           0 :     bool bRet=nTmpAngle!=9000 && nTmpAngle!=27000;
     329           0 :     long nRad=0;
     330           0 :     if (bRet) {
     331           0 :         double cs=cos(nTmpAngle*nPi180);
     332           0 :         double nR=(double)GetLen(Point(dx,dy))/cs/2;
     333           0 :         nRad=std::abs(Round(nR));
     334             :     }
     335           0 :     if (dAngle<18000) {
     336           0 :         nCircStAngle=NormAngle360(nTangAngle-9000);
     337           0 :         nCircRelAngle=NormAngle360(2*dAngle);
     338           0 :         aCircCenter.X()+=Round(nRad*cos((nTangAngle+9000)*nPi180));
     339           0 :         aCircCenter.Y()-=Round(nRad*sin((nTangAngle+9000)*nPi180));
     340             :     } else {
     341           0 :         nCircStAngle=NormAngle360(nTangAngle+9000);
     342           0 :         nCircRelAngle=-NormAngle360(36000-2*dAngle);
     343           0 :         aCircCenter.X()+=Round(nRad*cos((nTangAngle-9000)*nPi180));
     344           0 :         aCircCenter.Y()-=Round(nRad*sin((nTangAngle-9000)*nPi180));
     345             :     }
     346           0 :     bAngleSnap=pView!=NULL && pView->IsAngleSnapEnabled();
     347           0 :     if (bAngleSnap) {
     348           0 :         long nSA=pView->GetSnapAngle();
     349           0 :         if (nSA!=0) { // angle snapping
     350           0 :             bool bNeg=nCircRelAngle<0;
     351           0 :             if (bNeg) nCircRelAngle=-nCircRelAngle;
     352           0 :             nCircRelAngle+=nSA/2;
     353           0 :             nCircRelAngle/=nSA;
     354           0 :             nCircRelAngle*=nSA;
     355           0 :             nCircRelAngle=NormAngle360(nCircRelAngle);
     356           0 :             if (bNeg) nCircRelAngle=-nCircRelAngle;
     357             :         }
     358             :     }
     359           0 :     nCircRadius=nRad;
     360           0 :     if (nRad==0 || std::abs(nCircRelAngle)<5) bRet=false;
     361           0 :     bCircle=bRet;
     362           0 :     return bRet;
     363             : }
     364             : 
     365           0 : XPolygon ImpPathCreateUser::GetCirclePoly() const
     366             : {
     367           0 :     if (nCircRelAngle>=0) {
     368             :         XPolygon aXP(aCircCenter,nCircRadius,nCircRadius,
     369           0 :                      sal_uInt16((nCircStAngle+5)/10),sal_uInt16((nCircStAngle+nCircRelAngle+5)/10),false);
     370           0 :         aXP[0]=aCircStart; aXP.SetFlags(0,XPOLY_SMOOTH);
     371           0 :         if (!bAngleSnap) aXP[aXP.GetPointCount()-1]=aCircEnd;
     372           0 :         return aXP;
     373             :     } else {
     374             :         XPolygon aXP(aCircCenter,nCircRadius,nCircRadius,
     375           0 :                      sal_uInt16(NormAngle360(nCircStAngle+nCircRelAngle+5)/10),sal_uInt16((nCircStAngle+5)/10),false);
     376           0 :         sal_uInt16 nCount=aXP.GetPointCount();
     377           0 :         for (sal_uInt16 nNum=nCount/2; nNum>0;) {
     378           0 :             nNum--; // reverse XPoly's order of points
     379           0 :             sal_uInt16 n2=nCount-nNum-1;
     380           0 :             Point aPt(aXP[nNum]);
     381           0 :             aXP[nNum]=aXP[n2];
     382           0 :             aXP[n2]=aPt;
     383             :         }
     384           0 :         aXP[0]=aCircStart; aXP.SetFlags(0,XPOLY_SMOOTH);
     385           0 :         if (!bAngleSnap) aXP[aXP.GetPointCount()-1]=aCircEnd;
     386           0 :         return aXP;
     387             :     }
     388             : }
     389             : 
     390           0 : Point ImpPathCreateUser::CalcLine(const Point& aCsr, long nDirX, long nDirY, SdrView* pView)
     391             : {
     392           0 :     long x=aCsr.X(),x1=x,x2=x;
     393           0 :     long y=aCsr.Y(),y1=y,y2=y;
     394           0 :     bool bHLin=nDirY==0;
     395           0 :     bool bVLin=nDirX==0;
     396           0 :     if (bHLin) y=0;
     397           0 :     else if (bVLin) x=0;
     398             :     else {
     399           0 :         x1=BigMulDiv(y,nDirX,nDirY);
     400           0 :         y2=BigMulDiv(x,nDirY,nDirX);
     401           0 :         long l1=std::abs(x1)+std::abs(y1);
     402           0 :         long l2=std::abs(x2)+std::abs(y2);
     403           0 :         if ((l1<=l2) != (pView!=NULL && pView->IsBigOrtho())) {
     404           0 :             x=x1; y=y1;
     405             :         } else {
     406           0 :             x=x2; y=y2;
     407             :         }
     408             :     }
     409           0 :     return Point(x,y);
     410             : }
     411             : 
     412           0 : bool ImpPathCreateUser::CalcLine(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView)
     413             : {
     414           0 :     aLineStart=rP1;
     415           0 :     aLineEnd=rP2;
     416           0 :     bLine90=false;
     417           0 :     if (rP1==rP2 || (rDir.X()==0 && rDir.Y()==0)) { bLine=false; return false; }
     418           0 :     Point aTmpPt(rP2-rP1);
     419           0 :     long nDirX=rDir.X();
     420           0 :     long nDirY=rDir.Y();
     421           0 :     Point aP1(CalcLine(aTmpPt, nDirX, nDirY,pView)); aP1-=aTmpPt; long nQ1=std::abs(aP1.X())+std::abs(aP1.Y());
     422           0 :     Point aP2(CalcLine(aTmpPt, nDirY,-nDirX,pView)); aP2-=aTmpPt; long nQ2=std::abs(aP2.X())+std::abs(aP2.Y());
     423           0 :     if (pView!=NULL && pView->IsOrtho()) nQ1=0; // Ortho turns off at right angle
     424           0 :     bLine90=nQ1>2*nQ2;
     425           0 :     if (!bLine90) { // smooth transition
     426           0 :         aLineEnd+=aP1;
     427             :     } else {          // rectangular transition
     428           0 :         aLineEnd+=aP2;
     429             :     }
     430           0 :     bLine=true;
     431           0 :     return true;
     432             : }
     433             : 
     434           0 : XPolygon ImpPathCreateUser::GetLinePoly() const
     435             : {
     436           0 :     XPolygon aXP(2);
     437           0 :     aXP[0]=aLineStart; if (!bLine90) aXP.SetFlags(0,XPOLY_SMOOTH);
     438           0 :     aXP[1]=aLineEnd;
     439           0 :     return aXP;
     440             : }
     441             : 
     442           0 : bool ImpPathCreateUser::CalcRect(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView)
     443             : {
     444           0 :     aRectP1=rP1;
     445           0 :     aRectP2=rP1;
     446           0 :     aRectP3=rP2;
     447           0 :     if (rP1==rP2 || (rDir.X()==0 && rDir.Y()==0)) { bRect=false; return false; }
     448           0 :     Point aTmpPt(rP2-rP1);
     449           0 :     long nDirX=rDir.X();
     450           0 :     long nDirY=rDir.Y();
     451           0 :     long x=aTmpPt.X();
     452           0 :     long y=aTmpPt.Y();
     453           0 :     bool bHLin=nDirY==0;
     454           0 :     bool bVLin=nDirX==0;
     455           0 :     if (bHLin) y=0;
     456           0 :     else if (bVLin) x=0;
     457             :     else {
     458           0 :         y=BigMulDiv(x,nDirY,nDirX);
     459           0 :         long nHypLen=aTmpPt.Y()-y;
     460           0 :         long nTangAngle=-GetAngle(rDir);
     461             :         // sin=g/h, g=h*sin
     462           0 :         double a=nTangAngle*nPi180;
     463           0 :         double sn=sin(a);
     464           0 :         double cs=cos(a);
     465           0 :         double nGKathLen=nHypLen*sn;
     466           0 :         y+=Round(nGKathLen*sn);
     467           0 :         x+=Round(nGKathLen*cs);
     468             :     }
     469           0 :     aRectP2.X()+=x;
     470           0 :     aRectP2.Y()+=y;
     471           0 :     if (pView!=NULL && pView->IsOrtho()) {
     472           0 :         long dx1=aRectP2.X()-aRectP1.X(); long dx1a=std::abs(dx1);
     473           0 :         long dy1=aRectP2.Y()-aRectP1.Y(); long dy1a=std::abs(dy1);
     474           0 :         long dx2=aRectP3.X()-aRectP2.X(); long dx2a=std::abs(dx2);
     475           0 :         long dy2=aRectP3.Y()-aRectP2.Y(); long dy2a=std::abs(dy2);
     476           0 :         bool b1MoreThan2=dx1a+dy1a>dx2a+dy2a;
     477           0 :         if (b1MoreThan2 != pView->IsBigOrtho()) {
     478           0 :             long xtemp=dy2a-dx1a; if (dx1<0) xtemp=-xtemp;
     479           0 :             long ytemp=dx2a-dy1a; if (dy1<0) ytemp=-ytemp;
     480           0 :             aRectP2.X()+=xtemp;
     481           0 :             aRectP2.Y()+=ytemp;
     482           0 :             aRectP3.X()+=xtemp;
     483           0 :             aRectP3.Y()+=ytemp;
     484             :         } else {
     485           0 :             long xtemp=dy1a-dx2a; if (dx2<0) xtemp=-xtemp;
     486           0 :             long ytemp=dx1a-dy2a; if (dy2<0) ytemp=-ytemp;
     487           0 :             aRectP3.X()+=xtemp;
     488           0 :             aRectP3.Y()+=ytemp;
     489             :         }
     490             :     }
     491           0 :     bRect=true;
     492           0 :     return true;
     493             : }
     494             : 
     495           0 : XPolygon ImpPathCreateUser::GetRectPoly() const
     496             : {
     497           0 :     XPolygon aXP(3);
     498           0 :     aXP[0]=aRectP1; aXP.SetFlags(0,XPOLY_SMOOTH);
     499           0 :     aXP[1]=aRectP2;
     500           0 :     if (aRectP3!=aRectP2) aXP[2]=aRectP3;
     501           0 :     return aXP;
     502             : }
     503             : 
     504             : class ImpPathForDragAndCreate
     505             : {
     506             :     SdrPathObj&                 mrSdrPathObject;
     507             :     XPolyPolygon                aPathPolygon;
     508             :     SdrObjKind                  meObjectKind;
     509             :     ImpSdrPathDragData*         mpSdrPathDragData;
     510             :     bool                        mbCreating;
     511             : 
     512             : public:
     513             :     explicit ImpPathForDragAndCreate(SdrPathObj& rSdrPathObject);
     514             :     ~ImpPathForDragAndCreate();
     515             : 
     516             :     // drag stuff
     517             :     bool beginPathDrag( SdrDragStat& rDrag )  const;
     518             :     bool movePathDrag( SdrDragStat& rDrag ) const;
     519             :     bool endPathDrag( SdrDragStat& rDrag );
     520             :     OUString getSpecialDragComment(const SdrDragStat& rDrag) const;
     521             :     basegfx::B2DPolyPolygon getSpecialDragPoly(const SdrDragStat& rDrag) const;
     522             : 
     523             :     // create stuff
     524             :     bool BegCreate(SdrDragStat& rStat);
     525             :     bool MovCreate(SdrDragStat& rStat);
     526             :     bool EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd);
     527             :     bool BckCreate(SdrDragStat& rStat);
     528             :     void BrkCreate(SdrDragStat& rStat);
     529             :     Pointer GetCreatePointer() const;
     530             : 
     531             :     // helping stuff
     532           0 :     static bool IsClosed(SdrObjKind eKind) { return eKind==OBJ_POLY || eKind==OBJ_PATHPOLY || eKind==OBJ_PATHFILL || eKind==OBJ_FREEFILL || eKind==OBJ_SPLNFILL; }
     533           0 :     static bool IsFreeHand(SdrObjKind eKind) { return eKind==OBJ_FREELINE || eKind==OBJ_FREEFILL; }
     534           0 :     static bool IsBezier(SdrObjKind eKind) { return eKind==OBJ_PATHLINE || eKind==OBJ_PATHFILL; }
     535           0 :     bool IsCreating() const { return mbCreating; }
     536             : 
     537             :     // get the polygon
     538             :     basegfx::B2DPolyPolygon TakeObjectPolyPolygon(const SdrDragStat& rDrag) const;
     539             :     static basegfx::B2DPolyPolygon TakeDragPolyPolygon(const SdrDragStat& rDrag);
     540           0 :     basegfx::B2DPolyPolygon getModifiedPolyPolygon() const { return  aPathPolygon.getB2DPolyPolygon(); }
     541             : };
     542             : 
     543           0 : ImpPathForDragAndCreate::ImpPathForDragAndCreate(SdrPathObj& rSdrPathObject)
     544             : :   mrSdrPathObject(rSdrPathObject),
     545           0 :     aPathPolygon(rSdrPathObject.GetPathPoly()),
     546             :     meObjectKind(mrSdrPathObject.meKind),
     547             :     mpSdrPathDragData(0),
     548           0 :     mbCreating(false)
     549             : {
     550           0 : }
     551             : 
     552           0 : ImpPathForDragAndCreate::~ImpPathForDragAndCreate()
     553             : {
     554           0 :     if(mpSdrPathDragData)
     555             :     {
     556           0 :         delete mpSdrPathDragData;
     557             :     }
     558           0 : }
     559             : 
     560           0 : bool ImpPathForDragAndCreate::beginPathDrag( SdrDragStat& rDrag )  const
     561             : {
     562           0 :     const SdrHdl* pHdl=rDrag.GetHdl();
     563           0 :     if(!pHdl)
     564           0 :         return false;
     565             : 
     566           0 :     bool bMultiPointDrag(true);
     567             : 
     568           0 :     if(aPathPolygon[(sal_uInt16)pHdl->GetPolyNum()].IsControl((sal_uInt16)pHdl->GetPointNum()))
     569           0 :         bMultiPointDrag = false;
     570             : 
     571           0 :     if(bMultiPointDrag)
     572             :     {
     573           0 :         const SdrMarkView& rMarkView = *rDrag.GetView();
     574           0 :         const SdrHdlList& rHdlList = rMarkView.GetHdlList();
     575           0 :         const size_t nHdlCount = rHdlList.GetHdlCount();
     576           0 :         const SdrObject* pInteractionObject(nHdlCount && rHdlList.GetHdl(0) ? rHdlList.GetHdl(0)->GetObj() : 0);
     577           0 :         sal_uInt32 nSelectedPoints(0);
     578             : 
     579           0 :         for(size_t a = 0; a < nHdlCount; ++a)
     580             :         {
     581           0 :             SdrHdl* pTestHdl = rHdlList.GetHdl(a);
     582             : 
     583           0 :             if(pTestHdl && pTestHdl->IsSelected() && pTestHdl->GetObj() == pInteractionObject)
     584             :             {
     585           0 :                 nSelectedPoints++;
     586             :             }
     587             :         }
     588             : 
     589           0 :         if(nSelectedPoints <= 1)
     590           0 :             bMultiPointDrag = false;
     591             :     }
     592             : 
     593           0 :     const_cast<ImpPathForDragAndCreate*>(this)->mpSdrPathDragData = new ImpSdrPathDragData(mrSdrPathObject,*pHdl,bMultiPointDrag,rDrag);
     594             : 
     595           0 :     if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
     596             :     {
     597             :         OSL_FAIL("ImpPathForDragAndCreate::BegDrag(): ImpSdrPathDragData is invalid.");
     598           0 :         delete mpSdrPathDragData;
     599           0 :         const_cast<ImpPathForDragAndCreate*>(this)->mpSdrPathDragData = 0;
     600           0 :         return false;
     601             :     }
     602             : 
     603           0 :     return true;
     604             : }
     605             : 
     606           0 : bool ImpPathForDragAndCreate::movePathDrag( SdrDragStat& rDrag ) const
     607             : {
     608           0 :     if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
     609             :     {
     610             :         OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
     611           0 :         return false;
     612             :     }
     613             : 
     614           0 :     if(mpSdrPathDragData->IsMultiPointDrag())
     615             :     {
     616           0 :         Point aDelta(rDrag.GetNow() - rDrag.GetStart());
     617             : 
     618           0 :         if(aDelta.X() || aDelta.Y())
     619             :         {
     620           0 :             for(size_t a(0); a < mpSdrPathDragData->maHandles.size(); a++)
     621             :             {
     622           0 :                 SdrHdl* pHandle = mpSdrPathDragData->maHandles[a];
     623           0 :                 const sal_uInt16 nPolyIndex((sal_uInt16)pHandle->GetPolyNum());
     624           0 :                 const sal_uInt16 nPointIndex((sal_uInt16)pHandle->GetPointNum());
     625           0 :                 const XPolygon& rOrig = mpSdrPathDragData->maOrig[nPolyIndex];
     626           0 :                 XPolygon& rMove = mpSdrPathDragData->maMove[nPolyIndex];
     627           0 :                 const sal_uInt16 nPointCount(rOrig.GetPointCount());
     628           0 :                 bool bClosed(rOrig[0] == rOrig[nPointCount-1]);
     629             : 
     630             :                 // move point itself
     631           0 :                 rMove[nPointIndex] = rOrig[nPointIndex] + aDelta;
     632             : 
     633             :                 // when point is first and poly closed, move close point, too.
     634           0 :                 if(nPointCount > 0 && !nPointIndex && bClosed)
     635             :                 {
     636           0 :                     rMove[nPointCount - 1] = rOrig[nPointCount - 1] + aDelta;
     637             : 
     638             :                     // when moving the last point it may be necessary to move the
     639             :                     // control point in front of this one, too.
     640           0 :                     if(nPointCount > 1 && rOrig.IsControl(nPointCount - 2))
     641           0 :                         rMove[nPointCount - 2] = rOrig[nPointCount - 2] + aDelta;
     642             :                 }
     643             : 
     644             :                 // is a control point before this?
     645           0 :                 if(nPointIndex > 0 && rOrig.IsControl(nPointIndex - 1))
     646             :                 {
     647             :                     // Yes, move it, too
     648           0 :                     rMove[nPointIndex - 1] = rOrig[nPointIndex - 1] + aDelta;
     649             :                 }
     650             : 
     651             :                 // is a control point after this?
     652           0 :                 if(nPointIndex + 1 < nPointCount && rOrig.IsControl(nPointIndex + 1))
     653             :                 {
     654             :                     // Yes, move it, too
     655           0 :                     rMove[nPointIndex + 1] = rOrig[nPointIndex + 1] + aDelta;
     656             :                 }
     657             :             }
     658             :         }
     659             :     }
     660             :     else
     661             :     {
     662           0 :         mpSdrPathDragData->ResetPoly(mrSdrPathObject);
     663             : 
     664             :         // copy certain data locally to use less code and have faster access times
     665           0 :         bool bClosed           =mpSdrPathDragData->bClosed       ; // closed object?
     666           0 :         sal_uInt16   nPnt          =mpSdrPathDragData->nPnt          ; // number of point in the above polygon
     667           0 :         bool bBegPnt           =mpSdrPathDragData->bBegPnt       ; // dragged point is first point of a Polyline
     668           0 :         bool bEndPnt           =mpSdrPathDragData->bEndPnt       ; // dragged point is last point of a Polyline
     669           0 :         sal_uInt16   nPrevPnt      =mpSdrPathDragData->nPrevPnt      ; // index of previous point
     670           0 :         sal_uInt16   nNextPnt      =mpSdrPathDragData->nNextPnt      ; // index of next point
     671           0 :         bool bPrevIsBegPnt     =mpSdrPathDragData->bPrevIsBegPnt ; // previous point is first point of a Polyline
     672           0 :         bool bNextIsEndPnt     =mpSdrPathDragData->bNextIsEndPnt ; // next point is last point of a Polyline
     673           0 :         sal_uInt16   nPrevPrevPnt  =mpSdrPathDragData->nPrevPrevPnt  ; // index of the point before the previous point
     674           0 :         sal_uInt16   nNextNextPnt  =mpSdrPathDragData->nNextNextPnt  ; // index if the point after the next point
     675           0 :         bool bControl          =mpSdrPathDragData->bControl      ; // point is a control point
     676           0 :         bool bIsNextControl    =mpSdrPathDragData->bIsNextControl; // point is a control point after a support point
     677           0 :         bool bPrevIsControl    =mpSdrPathDragData->bPrevIsControl; // if nPnt is a support point: there's a control point before
     678           0 :         bool bNextIsControl    =mpSdrPathDragData->bNextIsControl; // if nPnt is a support point: there's a control point after
     679             : 
     680             :         // Ortho for lines/polygons: keep angle
     681           0 :         if (!bControl && rDrag.GetView()!=NULL && rDrag.GetView()->IsOrtho()) {
     682           0 :             bool bBigOrtho=rDrag.GetView()->IsBigOrtho();
     683           0 :             Point  aPos(rDrag.GetNow());      // current position
     684           0 :             Point  aPnt(mpSdrPathDragData->aXP[nPnt]);      // the dragged point
     685           0 :             sal_uInt16 nPnt1=0xFFFF,nPnt2=0xFFFF; // its neighboring points
     686           0 :             Point  aNeuPos1,aNeuPos2;         // new alternative for aPos
     687           0 :             bool bPnt1 = false, bPnt2 = false; // are these valid alternatives?
     688           0 :             if (!bClosed && mpSdrPathDragData->nPointCount>=2) { // minimum of 2 points for lines
     689           0 :                 if (!bBegPnt) nPnt1=nPrevPnt;
     690           0 :                 if (!bEndPnt) nPnt2=nNextPnt;
     691             :             }
     692           0 :             if (bClosed && mpSdrPathDragData->nPointCount>=3) { // minimum of 3 points for polygon
     693           0 :                 nPnt1=nPrevPnt;
     694           0 :                 nPnt2=nNextPnt;
     695             :             }
     696           0 :             if (nPnt1!=0xFFFF && !bPrevIsControl) {
     697           0 :                 Point aPnt1=mpSdrPathDragData->aXP[nPnt1];
     698           0 :                 long ndx0=aPnt.X()-aPnt1.X();
     699           0 :                 long ndy0=aPnt.Y()-aPnt1.Y();
     700           0 :                 bool bHLin=ndy0==0;
     701           0 :                 bool bVLin=ndx0==0;
     702           0 :                 if (!bHLin || !bVLin) {
     703           0 :                     long ndx=aPos.X()-aPnt1.X();
     704           0 :                     long ndy=aPos.Y()-aPnt1.Y();
     705           0 :                     bPnt1=true;
     706           0 :                     double nXFact=0; if (!bVLin) nXFact=(double)ndx/(double)ndx0;
     707           0 :                     double nYFact=0; if (!bHLin) nYFact=(double)ndy/(double)ndy0;
     708           0 :                     bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
     709           0 :                     bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
     710           0 :                     if (bHor) ndy=long(ndy0*nXFact);
     711           0 :                     if (bVer) ndx=long(ndx0*nYFact);
     712           0 :                     aNeuPos1=aPnt1;
     713           0 :                     aNeuPos1.X()+=ndx;
     714           0 :                     aNeuPos1.Y()+=ndy;
     715             :                 }
     716             :             }
     717           0 :             if (nPnt2!=0xFFFF && !bNextIsControl) {
     718           0 :                 Point aPnt2=mpSdrPathDragData->aXP[nPnt2];
     719           0 :                 long ndx0=aPnt.X()-aPnt2.X();
     720           0 :                 long ndy0=aPnt.Y()-aPnt2.Y();
     721           0 :                 bool bHLin=ndy0==0;
     722           0 :                 bool bVLin=ndx0==0;
     723           0 :                 if (!bHLin || !bVLin) {
     724           0 :                     long ndx=aPos.X()-aPnt2.X();
     725           0 :                     long ndy=aPos.Y()-aPnt2.Y();
     726           0 :                     bPnt2=true;
     727           0 :                     double nXFact=0; if (!bVLin) nXFact=(double)ndx/(double)ndx0;
     728           0 :                     double nYFact=0; if (!bHLin) nYFact=(double)ndy/(double)ndy0;
     729           0 :                     bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
     730           0 :                     bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
     731           0 :                     if (bHor) ndy=long(ndy0*nXFact);
     732           0 :                     if (bVer) ndx=long(ndx0*nYFact);
     733           0 :                     aNeuPos2=aPnt2;
     734           0 :                     aNeuPos2.X()+=ndx;
     735           0 :                     aNeuPos2.Y()+=ndy;
     736             :                 }
     737             :             }
     738           0 :             if (bPnt1 && bPnt2) { // both alternatives exist (and compete)
     739           0 :                 BigInt nX1(aNeuPos1.X()-aPos.X()); nX1*=nX1;
     740           0 :                 BigInt nY1(aNeuPos1.Y()-aPos.Y()); nY1*=nY1;
     741           0 :                 BigInt nX2(aNeuPos2.X()-aPos.X()); nX2*=nX2;
     742           0 :                 BigInt nY2(aNeuPos2.Y()-aPos.Y()); nY2*=nY2;
     743           0 :                 nX1+=nY1; // correction distance to square
     744           0 :                 nX2+=nY2; // correction distance to square
     745             :                 // let the alternative that allows fewer correction win
     746           0 :                 if (nX1<nX2) bPnt2=false; else bPnt1=false;
     747             :             }
     748           0 :             if (bPnt1) rDrag.Now()=aNeuPos1;
     749           0 :             if (bPnt2) rDrag.Now()=aNeuPos2;
     750             :         }
     751           0 :         rDrag.SetActionRect(Rectangle(rDrag.GetNow(),rDrag.GetNow()));
     752             : 
     753             :         // specially for IBM: Eliminate points if both adjoining lines form near 180 degrees angle anyway
     754           0 :         if (!bControl && rDrag.GetView()!=NULL && rDrag.GetView()->IsEliminatePolyPoints() &&
     755           0 :             !bBegPnt && !bEndPnt && !bPrevIsControl && !bNextIsControl)
     756             :         {
     757           0 :             Point aPt(mpSdrPathDragData->aXP[nNextPnt]);
     758           0 :             aPt-=rDrag.GetNow();
     759           0 :             long nAngle1=GetAngle(aPt);
     760           0 :             aPt=rDrag.GetNow();
     761           0 :             aPt-=mpSdrPathDragData->aXP[nPrevPnt];
     762           0 :             long nAngle2=GetAngle(aPt);
     763           0 :             long nDiff=nAngle1-nAngle2;
     764           0 :             nDiff=std::abs(nDiff);
     765           0 :             mpSdrPathDragData->bEliminate=nDiff<=rDrag.GetView()->GetEliminatePolyPointLimitAngle();
     766           0 :             if (mpSdrPathDragData->bEliminate) { // adapt position, Smooth is true for the ends
     767           0 :                 aPt=mpSdrPathDragData->aXP[nNextPnt];
     768           0 :                 aPt+=mpSdrPathDragData->aXP[nPrevPnt];
     769           0 :                 aPt/=2;
     770           0 :                 rDrag.Now()=aPt;
     771             :             }
     772             :         }
     773             : 
     774             :         // we dragged by this distance
     775           0 :         Point aDiff(rDrag.GetNow()); aDiff-=mpSdrPathDragData->aXP[nPnt];
     776             : 
     777             :         /* There are 8 possible cases:
     778             :               X      1. A control point neither on the left nor on the right.
     779             :            o--X--o   2. There are control points on the left and the right, we are dragging a support point.
     780             :            o--X      3. There is a control point on the left, we are dragging a support point.
     781             :               X--o   4. There is a control point on the right, we are dragging a support point.
     782             :            x--O--o   5. There are control points on the left and the right, we are dragging the left one.
     783             :            x--O      6. There is a control point on the left, we are dragging it.
     784             :            o--O--x   7. There are control points on the left and the right, we are dragging the right one.
     785             :               O--x   8. There is a control point on the right, we are dragging it.
     786             :            Note: modifying a line (not a curve!) might create a curve on the other end of the line
     787             :            if Smooth is set there (with control points aligned to line).
     788             :         */
     789             : 
     790           0 :         mpSdrPathDragData->aXP[nPnt]+=aDiff;
     791             : 
     792             :         // now check symmetric plus handles
     793           0 :         if (bControl) { // cases 5,6,7,8
     794             :             sal_uInt16   nSt; // the associated support point
     795           0 :             sal_uInt16   nFix=nPnt;  // the opposing control point
     796           0 :             if (bIsNextControl) { // if the next one is a control point, the on before has to be a support point
     797           0 :                 nSt=nPrevPnt;
     798           0 :                 nFix=nPrevPrevPnt;
     799             :             } else {
     800           0 :                 nSt=nNextPnt;
     801           0 :                 nFix=nNextNextPnt;
     802             :             }
     803           0 :             if (mpSdrPathDragData->aXP.IsSmooth(nSt)) {
     804           0 :                 mpSdrPathDragData->aXP.CalcSmoothJoin(nSt,nPnt,nFix);
     805             :             }
     806             :         }
     807             : 
     808           0 :         if (!bControl) { // Cases 1,2,3,4. In case 1, nothing happens; in cases 3 and 4, there is more following below.
     809             :             // move both control points
     810           0 :             if (bPrevIsControl) mpSdrPathDragData->aXP[nPrevPnt]+=aDiff;
     811           0 :             if (bNextIsControl) mpSdrPathDragData->aXP[nNextPnt]+=aDiff;
     812             :             // align control point to line, if appropriate
     813           0 :             if (mpSdrPathDragData->aXP.IsSmooth(nPnt)) {
     814           0 :                 if (bPrevIsControl && !bNextIsControl && !bEndPnt) { // case 3
     815           0 :                     mpSdrPathDragData->aXP.CalcSmoothJoin(nPnt,nNextPnt,nPrevPnt);
     816             :                 }
     817           0 :                 if (bNextIsControl && !bPrevIsControl && !bBegPnt) { // case 4
     818           0 :                     mpSdrPathDragData->aXP.CalcSmoothJoin(nPnt,nPrevPnt,nNextPnt);
     819             :                 }
     820             :             }
     821             :             // Now check the other ends of the line (nPnt+-1). If there is a
     822             :             // curve (IsControl(nPnt+-2)) with SmoothJoin (nPnt+-1), the
     823             :             // associated control point (nPnt+-2) has to be adapted.
     824           0 :             if (!bBegPnt && !bPrevIsControl && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsSmooth(nPrevPnt)) {
     825           0 :                 if (mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
     826           0 :                     mpSdrPathDragData->aXP.CalcSmoothJoin(nPrevPnt,nPnt,nPrevPrevPnt);
     827             :                 }
     828             :             }
     829           0 :             if (!bEndPnt && !bNextIsControl && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsSmooth(nNextPnt)) {
     830           0 :                 if (mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
     831           0 :                     mpSdrPathDragData->aXP.CalcSmoothJoin(nNextPnt,nPnt,nNextNextPnt);
     832             :                 }
     833             :             }
     834             :         }
     835             :     }
     836             : 
     837           0 :     return true;
     838             : }
     839             : 
     840           0 : bool ImpPathForDragAndCreate::endPathDrag(SdrDragStat& rDrag)
     841             : {
     842           0 :     Point aLinePt1;
     843           0 :     Point aLinePt2;
     844           0 :     bool bLineGlueMirror(OBJ_LINE == meObjectKind);
     845           0 :     if (bLineGlueMirror) {
     846           0 :         XPolygon& rXP=aPathPolygon[0];
     847           0 :         aLinePt1=rXP[0];
     848           0 :         aLinePt2=rXP[1];
     849             :     }
     850             : 
     851           0 :     if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
     852             :     {
     853             :         OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
     854           0 :         return false;
     855             :     }
     856             : 
     857           0 :     if(mpSdrPathDragData->IsMultiPointDrag())
     858             :     {
     859           0 :         aPathPolygon = mpSdrPathDragData->maMove;
     860             :     }
     861             :     else
     862             :     {
     863           0 :         const SdrHdl* pHdl=rDrag.GetHdl();
     864             : 
     865             :         // reference the polygon
     866           0 :         XPolygon& rXP=aPathPolygon[(sal_uInt16)pHdl->GetPolyNum()];
     867             : 
     868             :         // the 5 points that might have changed
     869           0 :         if (!mpSdrPathDragData->bPrevIsBegPnt) rXP[mpSdrPathDragData->nPrevPrevPnt0]=mpSdrPathDragData->aXP[mpSdrPathDragData->nPrevPrevPnt];
     870           0 :         if (!mpSdrPathDragData->bNextIsEndPnt) rXP[mpSdrPathDragData->nNextNextPnt0]=mpSdrPathDragData->aXP[mpSdrPathDragData->nNextNextPnt];
     871           0 :         if (!mpSdrPathDragData->bBegPnt)       rXP[mpSdrPathDragData->nPrevPnt0]    =mpSdrPathDragData->aXP[mpSdrPathDragData->nPrevPnt];
     872           0 :         if (!mpSdrPathDragData->bEndPnt)       rXP[mpSdrPathDragData->nNextPnt0]    =mpSdrPathDragData->aXP[mpSdrPathDragData->nNextPnt];
     873           0 :         rXP[mpSdrPathDragData->nPnt0]        =mpSdrPathDragData->aXP[mpSdrPathDragData->nPnt];
     874             : 
     875             :         // for closed objects: last point has to be equal to first point
     876           0 :         if (mpSdrPathDragData->bClosed) rXP[rXP.GetPointCount()-1]=rXP[0];
     877             : 
     878           0 :         if (mpSdrPathDragData->bEliminate)
     879             :         {
     880           0 :             basegfx::B2DPolyPolygon aTempPolyPolygon(aPathPolygon.getB2DPolyPolygon());
     881             :             sal_uInt32 nPoly,nPnt;
     882             : 
     883           0 :             if(PolyPolygonEditor::GetRelativePolyPoint(aTempPolyPolygon, rDrag.GetHdl()->GetSourceHdlNum(), nPoly, nPnt))
     884             :             {
     885           0 :                 basegfx::B2DPolygon aCandidate(aTempPolyPolygon.getB2DPolygon(nPoly));
     886           0 :                 aCandidate.remove(nPnt);
     887             : 
     888           0 :                 if((IsClosed(meObjectKind) && aCandidate.count() < 3L) || aCandidate.count() < 2L)
     889             :                 {
     890           0 :                     aTempPolyPolygon.remove(nPoly);
     891             :                 }
     892             :                 else
     893             :                 {
     894           0 :                     aTempPolyPolygon.setB2DPolygon(nPoly, aCandidate);
     895           0 :                 }
     896             :             }
     897             : 
     898           0 :             aPathPolygon = XPolyPolygon(aTempPolyPolygon);
     899             :         }
     900             : 
     901             :         // adapt angle for text beneath a simple line
     902           0 :         if (bLineGlueMirror)
     903             :         {
     904           0 :             Point aLinePt1_(aPathPolygon[0][0]);
     905           0 :             Point aLinePt2_(aPathPolygon[0][1]);
     906           0 :             bool bXMirr=(aLinePt1_.X()>aLinePt2_.X())!=(aLinePt1.X()>aLinePt2.X());
     907           0 :             bool bYMirr=(aLinePt1_.Y()>aLinePt2_.Y())!=(aLinePt1.Y()>aLinePt2.Y());
     908           0 :             if (bXMirr || bYMirr) {
     909           0 :                 Point aRef1(mrSdrPathObject.GetSnapRect().Center());
     910           0 :                 if (bXMirr) {
     911           0 :                     Point aRef2(aRef1);
     912           0 :                     aRef2.Y()++;
     913           0 :                     mrSdrPathObject.NbcMirrorGluePoints(aRef1,aRef2);
     914             :                 }
     915           0 :                 if (bYMirr) {
     916           0 :                     Point aRef2(aRef1);
     917           0 :                     aRef2.X()++;
     918           0 :                     mrSdrPathObject.NbcMirrorGluePoints(aRef1,aRef2);
     919             :                 }
     920             :             }
     921             :         }
     922             :     }
     923             : 
     924           0 :     delete mpSdrPathDragData;
     925           0 :     mpSdrPathDragData = 0;
     926             : 
     927           0 :     return true;
     928             : }
     929             : 
     930           0 : OUString ImpPathForDragAndCreate::getSpecialDragComment(const SdrDragStat& rDrag) const
     931             : {
     932           0 :     OUString aStr;
     933           0 :     const SdrHdl* pHdl = rDrag.GetHdl();
     934           0 :     const bool bCreateComment(rDrag.GetView() && &mrSdrPathObject == rDrag.GetView()->GetCreateObj());
     935             : 
     936           0 :     if(bCreateComment && rDrag.GetUser())
     937             :     {
     938             :         // #i103058# re-add old creation comment mode
     939           0 :         const ImpPathCreateUser* pU = static_cast<const ImpPathCreateUser*>(rDrag.GetUser());
     940           0 :         const SdrObjKind eKindMerk(meObjectKind);
     941           0 :         mrSdrPathObject.meKind = pU->eAktKind;
     942           0 :         OUString aTmp;
     943           0 :         mrSdrPathObject.ImpTakeDescriptionStr(STR_ViewCreateObj, aTmp);
     944           0 :         aStr = aTmp;
     945           0 :         mrSdrPathObject.meKind = eKindMerk;
     946             : 
     947           0 :         Point aPrev(rDrag.GetPrev());
     948           0 :         Point aNow(rDrag.GetNow());
     949             : 
     950           0 :         if(pU->bLine)
     951           0 :             aNow = pU->aLineEnd;
     952             : 
     953           0 :         aNow -= aPrev;
     954           0 :         aStr += " (";
     955             : 
     956           0 :         OUString aMetr;
     957             : 
     958           0 :         if(pU->bCircle)
     959             :         {
     960           0 :             SdrModel::TakeAngleStr(std::abs(pU->nCircRelAngle), aMetr);
     961           0 :             aStr += aMetr;
     962           0 :             aStr += " r=";
     963           0 :             mrSdrPathObject.GetModel()->TakeMetricStr(pU->nCircRadius, aMetr, true);
     964           0 :             aStr += aMetr;
     965             :         }
     966             : 
     967           0 :         aStr += "dx=";
     968           0 :         mrSdrPathObject.GetModel()->TakeMetricStr(aNow.X(), aMetr, true);
     969           0 :         aStr += aMetr;
     970             : 
     971           0 :         aStr += " dy=";
     972           0 :         mrSdrPathObject.GetModel()->TakeMetricStr(aNow.Y(), aMetr, true);
     973           0 :         aStr += aMetr;
     974             : 
     975           0 :         if(!IsFreeHand(meObjectKind))
     976             :         {
     977           0 :             sal_Int32 nLen(GetLen(aNow));
     978           0 :             aStr += "  l=";
     979           0 :             mrSdrPathObject.GetModel()->TakeMetricStr(nLen, aMetr, true);
     980           0 :             aStr += aMetr;
     981             : 
     982           0 :             sal_Int32 nAngle(GetAngle(aNow));
     983           0 :             aStr += " ";
     984           0 :             SdrModel::TakeAngleStr(nAngle, aMetr);
     985           0 :             aStr += aMetr;
     986             :         }
     987             : 
     988           0 :         aStr += ")";
     989             :     }
     990           0 :     else if(!mrSdrPathObject.GetModel() || !pHdl)
     991             :     {
     992             :         // #i103058# fallback when no model and/or Handle, both needed
     993             :         // for else-path
     994           0 :         OUString aTmp;
     995           0 :         mrSdrPathObject.ImpTakeDescriptionStr(STR_DragPathObj, aTmp);
     996           0 :         aStr = aTmp;
     997             :     }
     998             :     else
     999             :     {
    1000             :         // #i103058# standard for modification; model and handle needed
    1001           0 :         ImpSdrPathDragData* pDragData = mpSdrPathDragData;
    1002             : 
    1003           0 :         if(!pDragData)
    1004             :         {
    1005             :             // getSpecialDragComment is also used from create, so fallback to GetUser()
    1006             :             // when mpSdrPathDragData is not set
    1007           0 :             pDragData = static_cast<ImpSdrPathDragData*>(rDrag.GetUser());
    1008             :         }
    1009             : 
    1010           0 :         if(!pDragData)
    1011             :         {
    1012             :             OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
    1013           0 :             return OUString();
    1014             :         }
    1015             : 
    1016           0 :         if(!pDragData->IsMultiPointDrag() && pDragData->bEliminate)
    1017             :         {
    1018             :             // point of ...
    1019           0 :             OUString aTmp;
    1020           0 :             mrSdrPathObject.ImpTakeDescriptionStr(STR_ViewMarkedPoint, aTmp);
    1021           0 :             aStr = aTmp;
    1022             : 
    1023             :             // delete %O
    1024           0 :             OUString aStr2(ImpGetResStr(STR_EditDelete));
    1025             : 
    1026             :             // UNICODE: delete point of ...
    1027           0 :             aStr2 = aStr2.replaceFirst("%1", aStr);
    1028             : 
    1029           0 :             return aStr2;
    1030             :         }
    1031             : 
    1032             :         // dx=0.00 dy=0.00                -- both sides bezier
    1033             :         // dx=0.00 dy=0.00  l=0.00 0.00\302\260  -- one bezier/lever on one side, a start, or an ending
    1034             :         // dx=0.00 dy=0.00  l=0.00 0.00\302\260 / l=0.00 0.00\302\260 -- in between
    1035           0 :         OUString aMetr;
    1036           0 :         Point aBeg(rDrag.GetStart());
    1037           0 :         Point aNow(rDrag.GetNow());
    1038             : 
    1039           0 :         aStr.clear();
    1040           0 :         aStr += "dx=";
    1041           0 :         mrSdrPathObject.GetModel()->TakeMetricStr(aNow.X() - aBeg.X(), aMetr, true);
    1042           0 :         aStr += aMetr;
    1043             : 
    1044           0 :         aStr += " dy=";
    1045           0 :         mrSdrPathObject.GetModel()->TakeMetricStr(aNow.Y() - aBeg.Y(), aMetr, true);
    1046           0 :         aStr += aMetr;
    1047             : 
    1048           0 :         if(!pDragData->IsMultiPointDrag())
    1049             :         {
    1050           0 :             sal_uInt16 nPntNum((sal_uInt16)pHdl->GetPointNum());
    1051           0 :             const XPolygon& rXPoly = aPathPolygon[(sal_uInt16)rDrag.GetHdl()->GetPolyNum()];
    1052           0 :             sal_uInt16 nPointCount((sal_uInt16)rXPoly.GetPointCount());
    1053           0 :             bool bClose(IsClosed(meObjectKind));
    1054             : 
    1055           0 :             if(bClose)
    1056           0 :                 nPointCount--;
    1057             : 
    1058           0 :             if(pHdl->IsPlusHdl())
    1059             :             {
    1060             :                 // lever
    1061           0 :                 sal_uInt16 nRef(nPntNum);
    1062             : 
    1063           0 :                 if(rXPoly.IsControl(nPntNum + 1))
    1064           0 :                     nRef--;
    1065             :                 else
    1066           0 :                     nRef++;
    1067             : 
    1068           0 :                 aNow -= rXPoly[nRef];
    1069             : 
    1070           0 :                 sal_Int32 nLen(GetLen(aNow));
    1071           0 :                 aStr += "  l=";
    1072           0 :                 mrSdrPathObject.GetModel()->TakeMetricStr(nLen, aMetr, true);
    1073           0 :                 aStr += aMetr;
    1074             : 
    1075           0 :                 sal_Int32 nAngle(GetAngle(aNow));
    1076           0 :                 aStr += " ";
    1077           0 :                 SdrModel::TakeAngleStr(nAngle, aMetr);
    1078           0 :                 aStr += aMetr;
    1079             :             }
    1080           0 :             else if(nPointCount > 1)
    1081             :             {
    1082           0 :                 sal_uInt16 nPntMax(nPointCount - 1);
    1083           0 :                 bool bIsClosed(IsClosed(meObjectKind));
    1084           0 :                 bool bPt1(nPntNum > 0);
    1085           0 :                 bool bPt2(nPntNum < nPntMax);
    1086             : 
    1087           0 :                 if(bIsClosed && nPointCount > 2)
    1088             :                 {
    1089           0 :                     bPt1 = true;
    1090           0 :                     bPt2 = true;
    1091             :                 }
    1092             : 
    1093             :                 sal_uInt16 nPt1,nPt2;
    1094             : 
    1095           0 :                 if(nPntNum > 0)
    1096           0 :                     nPt1 = nPntNum - 1;
    1097             :                 else
    1098           0 :                     nPt1 = nPntMax;
    1099             : 
    1100           0 :                 if(nPntNum < nPntMax)
    1101           0 :                     nPt2 = nPntNum + 1;
    1102             :                 else
    1103           0 :                     nPt2 = 0;
    1104             : 
    1105           0 :                 if(bPt1 && rXPoly.IsControl(nPt1))
    1106           0 :                     bPt1 = false; // don't display
    1107             : 
    1108           0 :                 if(bPt2 && rXPoly.IsControl(nPt2))
    1109           0 :                     bPt2 = false; // of bezier data
    1110             : 
    1111           0 :                 if(bPt1)
    1112             :                 {
    1113           0 :                     Point aPt(aNow);
    1114           0 :                     aPt -= rXPoly[nPt1];
    1115             : 
    1116           0 :                     sal_Int32 nLen(GetLen(aPt));
    1117           0 :                     aStr += "  l=";
    1118           0 :                     mrSdrPathObject.GetModel()->TakeMetricStr(nLen, aMetr, true);
    1119           0 :                     aStr += aMetr;
    1120             : 
    1121           0 :                     sal_Int32 nAngle(GetAngle(aPt));
    1122           0 :                     aStr += " ";
    1123           0 :                     SdrModel::TakeAngleStr(nAngle, aMetr);
    1124           0 :                     aStr += aMetr;
    1125             :                 }
    1126             : 
    1127           0 :                 if(bPt2)
    1128             :                 {
    1129           0 :                     if(bPt1)
    1130           0 :                         aStr += " / ";
    1131             :                     else
    1132           0 :                         aStr += "  ";
    1133             : 
    1134           0 :                     Point aPt(aNow);
    1135           0 :                     aPt -= rXPoly[nPt2];
    1136             : 
    1137           0 :                     sal_Int32 nLen(GetLen(aPt));
    1138           0 :                     aStr += "l=";
    1139           0 :                     mrSdrPathObject.GetModel()->TakeMetricStr(nLen, aMetr, true);
    1140           0 :                     aStr += aMetr;
    1141             : 
    1142           0 :                     sal_Int32 nAngle(GetAngle(aPt));
    1143           0 :                     aStr += " ";
    1144           0 :                     SdrModel::TakeAngleStr(nAngle, aMetr);
    1145           0 :                     aStr += aMetr;
    1146             :                 }
    1147             :             }
    1148           0 :         }
    1149             :     }
    1150             : 
    1151           0 :     return aStr;
    1152             : }
    1153             : 
    1154           0 : basegfx::B2DPolyPolygon ImpPathForDragAndCreate::getSpecialDragPoly(const SdrDragStat& rDrag) const
    1155             : {
    1156           0 :     if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
    1157             :     {
    1158             :         OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
    1159           0 :         return basegfx::B2DPolyPolygon();
    1160             :     }
    1161             : 
    1162           0 :     XPolyPolygon aRetval;
    1163             : 
    1164           0 :     if(mpSdrPathDragData->IsMultiPointDrag())
    1165             :     {
    1166           0 :         aRetval.Insert(mpSdrPathDragData->maMove);
    1167             :     }
    1168             :     else
    1169             :     {
    1170           0 :         const XPolygon& rXP=aPathPolygon[(sal_uInt16)rDrag.GetHdl()->GetPolyNum()];
    1171           0 :         if (rXP.GetPointCount()<=2) {
    1172           0 :             XPolygon aXPoly(rXP);
    1173           0 :             aXPoly[(sal_uInt16)rDrag.GetHdl()->GetPointNum()]=rDrag.GetNow();
    1174           0 :             aRetval.Insert(aXPoly);
    1175           0 :             return aRetval.getB2DPolyPolygon();
    1176             :         }
    1177             :         // copy certain data locally to use less code and have faster access times
    1178           0 :         bool bClosed           =mpSdrPathDragData->bClosed       ; // closed object?
    1179           0 :         sal_uInt16 nPointCount = mpSdrPathDragData->nPointCount; // number of points
    1180           0 :         sal_uInt16   nPnt          =mpSdrPathDragData->nPnt          ; // number of points in the polygon
    1181           0 :         bool bBegPnt           =mpSdrPathDragData->bBegPnt       ; // dragged point is the first point of a Polyline
    1182           0 :         bool bEndPnt           =mpSdrPathDragData->bEndPnt       ; // dragged point is the last point of a Polyline
    1183           0 :         sal_uInt16   nPrevPnt      =mpSdrPathDragData->nPrevPnt      ; // index of the previous point
    1184           0 :         sal_uInt16   nNextPnt      =mpSdrPathDragData->nNextPnt      ; // index of the next point
    1185           0 :         bool bPrevIsBegPnt     =mpSdrPathDragData->bPrevIsBegPnt ; // previous point is first point of a Polyline
    1186           0 :         bool bNextIsEndPnt     =mpSdrPathDragData->bNextIsEndPnt ; // next point is last point of a Polyline
    1187           0 :         sal_uInt16   nPrevPrevPnt  =mpSdrPathDragData->nPrevPrevPnt  ; // index of the point before the previous point
    1188           0 :         sal_uInt16   nNextNextPnt  =mpSdrPathDragData->nNextNextPnt  ; // index of the point after the last point
    1189           0 :         bool bControl          =mpSdrPathDragData->bControl      ; // point is a control point
    1190           0 :         bool bIsNextControl    =mpSdrPathDragData->bIsNextControl; //point is a control point after a support point
    1191           0 :         bool bPrevIsControl    =mpSdrPathDragData->bPrevIsControl; // if nPnt is a support point: there's a control point before
    1192           0 :         bool bNextIsControl    =mpSdrPathDragData->bNextIsControl; // if nPnt is a support point: there's a control point after
    1193           0 :         XPolygon aXPoly(mpSdrPathDragData->aXP);
    1194           0 :         XPolygon aLine1(2);
    1195           0 :         XPolygon aLine2(2);
    1196           0 :         XPolygon aLine3(2);
    1197           0 :         XPolygon aLine4(2);
    1198           0 :         if (bControl) {
    1199           0 :             aLine1[1]=mpSdrPathDragData->aXP[nPnt];
    1200           0 :             if (bIsNextControl) { // is this a control point after the support point?
    1201           0 :                 aLine1[0]=mpSdrPathDragData->aXP[nPrevPnt];
    1202           0 :                 aLine2[0]=mpSdrPathDragData->aXP[nNextNextPnt];
    1203           0 :                 aLine2[1]=mpSdrPathDragData->aXP[nNextPnt];
    1204           0 :                 if (mpSdrPathDragData->aXP.IsSmooth(nPrevPnt) && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
    1205           0 :                     aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],XPOLY_CONTROL);
    1206           0 :                     aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-2],XPOLY_NORMAL);
    1207             :                     // leverage lines for the opposing curve segment
    1208           0 :                     aLine3[0]=mpSdrPathDragData->aXP[nPrevPnt];
    1209           0 :                     aLine3[1]=mpSdrPathDragData->aXP[nPrevPrevPnt];
    1210           0 :                     aLine4[0]=rXP[mpSdrPathDragData->nPrevPrevPnt0-2];
    1211           0 :                     aLine4[1]=rXP[mpSdrPathDragData->nPrevPrevPnt0-1];
    1212             :                 } else {
    1213           0 :                     aXPoly.Remove(0,1);
    1214             :                 }
    1215             :             } else { // else this is a control point before a support point
    1216           0 :                 aLine1[0]=mpSdrPathDragData->aXP[nNextPnt];
    1217           0 :                 aLine2[0]=mpSdrPathDragData->aXP[nPrevPrevPnt];
    1218           0 :                 aLine2[1]=mpSdrPathDragData->aXP[nPrevPnt];
    1219           0 :                 if (mpSdrPathDragData->aXP.IsSmooth(nNextPnt) && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
    1220           0 :                     aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],XPOLY_CONTROL);
    1221           0 :                     aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+2],XPOLY_NORMAL);
    1222             :                     // leverage lines for the opposing curve segment
    1223           0 :                     aLine3[0]=mpSdrPathDragData->aXP[nNextPnt];
    1224           0 :                     aLine3[1]=mpSdrPathDragData->aXP[nNextNextPnt];
    1225           0 :                     aLine4[0]=rXP[mpSdrPathDragData->nNextNextPnt0+2];
    1226           0 :                     aLine4[1]=rXP[mpSdrPathDragData->nNextNextPnt0+1];
    1227             :                 } else {
    1228           0 :                     aXPoly.Remove(aXPoly.GetPointCount()-1,1);
    1229             :                 }
    1230             :             }
    1231             :         } else { // else is not a control point
    1232           0 :             if (mpSdrPathDragData->bEliminate) {
    1233           0 :                 aXPoly.Remove(2,1);
    1234             :             }
    1235           0 :             if (bPrevIsControl) aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],XPOLY_NORMAL);
    1236           0 :             else if (!bBegPnt && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
    1237           0 :                 aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],XPOLY_CONTROL);
    1238           0 :                 aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-2],XPOLY_NORMAL);
    1239             :             } else {
    1240           0 :                 aXPoly.Remove(0,1);
    1241           0 :                 if (bBegPnt) aXPoly.Remove(0,1);
    1242             :             }
    1243           0 :             if (bNextIsControl) aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],XPOLY_NORMAL);
    1244           0 :             else if (!bEndPnt && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
    1245           0 :                 aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],XPOLY_CONTROL);
    1246           0 :                 aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+2],XPOLY_NORMAL);
    1247             :             } else {
    1248           0 :                 aXPoly.Remove(aXPoly.GetPointCount()-1,1);
    1249           0 :                 if (bEndPnt) aXPoly.Remove(aXPoly.GetPointCount()-1,1);
    1250             :             }
    1251           0 :             if (bClosed) { // "pear problem": 2 lines, 1 curve, everything smoothed, a point between both lines is dragged
    1252           0 :                 if (aXPoly.GetPointCount()>nPointCount && aXPoly.IsControl(1)) {
    1253           0 :                     sal_uInt16 a=aXPoly.GetPointCount();
    1254           0 :                     aXPoly[a-2]=aXPoly[2]; aXPoly.SetFlags(a-2,aXPoly.GetFlags(2));
    1255           0 :                     aXPoly[a-1]=aXPoly[3]; aXPoly.SetFlags(a-1,aXPoly.GetFlags(3));
    1256           0 :                     aXPoly.Remove(0,3);
    1257             :                 }
    1258             :             }
    1259             :         }
    1260           0 :         aRetval.Insert(aXPoly);
    1261           0 :         if (aLine1.GetPointCount()>1) aRetval.Insert(aLine1);
    1262           0 :         if (aLine2.GetPointCount()>1) aRetval.Insert(aLine2);
    1263           0 :         if (aLine3.GetPointCount()>1) aRetval.Insert(aLine3);
    1264           0 :         if (aLine4.GetPointCount()>1) aRetval.Insert(aLine4);
    1265             :     }
    1266             : 
    1267           0 :     return aRetval.getB2DPolyPolygon();
    1268             : }
    1269             : 
    1270           0 : bool ImpPathForDragAndCreate::BegCreate(SdrDragStat& rStat)
    1271             : {
    1272           0 :     bool bFreeHand(IsFreeHand(meObjectKind));
    1273           0 :     rStat.SetNoSnap(bFreeHand);
    1274           0 :     rStat.SetOrtho8Possible();
    1275           0 :     aPathPolygon.Clear();
    1276           0 :     mbCreating=true;
    1277           0 :     bool bMakeStartPoint = true;
    1278           0 :     SdrView* pView=rStat.GetView();
    1279           0 :     if (pView!=NULL && pView->IsUseIncompatiblePathCreateInterface() &&
    1280           0 :         (meObjectKind==OBJ_POLY || meObjectKind==OBJ_PLIN || meObjectKind==OBJ_PATHLINE || meObjectKind==OBJ_PATHFILL)) {
    1281           0 :         bMakeStartPoint = false;
    1282             :     }
    1283           0 :     aPathPolygon.Insert(XPolygon());
    1284           0 :     aPathPolygon[0][0]=rStat.GetStart();
    1285           0 :     if (bMakeStartPoint) {
    1286           0 :         aPathPolygon[0][1]=rStat.GetNow();
    1287             :     }
    1288           0 :     ImpPathCreateUser* pU=new ImpPathCreateUser;
    1289           0 :     pU->eStartKind=meObjectKind;
    1290           0 :     pU->eAktKind=meObjectKind;
    1291           0 :     rStat.SetUser(pU);
    1292           0 :     return true;
    1293             : }
    1294             : 
    1295           0 : bool ImpPathForDragAndCreate::MovCreate(SdrDragStat& rStat)
    1296             : {
    1297           0 :     ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
    1298           0 :     SdrView* pView=rStat.GetView();
    1299           0 :     XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1];
    1300           0 :     if (pView!=NULL && pView->IsCreateMode()) {
    1301             :         // switch to different CreateTool, if appropriate
    1302             :         sal_uInt16 nIdent;
    1303             :         sal_uInt32 nInvent;
    1304           0 :         pView->TakeCurrentObj(nIdent,nInvent);
    1305           0 :         if (nInvent==SdrInventor && pU->eAktKind!=(SdrObjKind)nIdent) {
    1306           0 :             SdrObjKind eNewKind=(SdrObjKind)nIdent;
    1307           0 :             switch (eNewKind) {
    1308           0 :                 case OBJ_CARC: case OBJ_CIRC: case OBJ_CCUT: case OBJ_SECT: eNewKind=OBJ_CARC;
    1309             :                 //fall-through
    1310             :                 case OBJ_RECT:
    1311             :                 case OBJ_LINE: case OBJ_PLIN: case OBJ_POLY:
    1312             :                 case OBJ_PATHLINE: case OBJ_PATHFILL:
    1313             :                 case OBJ_FREELINE: case OBJ_FREEFILL:
    1314             :                 case OBJ_SPLNLINE: case OBJ_SPLNFILL: {
    1315           0 :                     pU->eAktKind=eNewKind;
    1316           0 :                     pU->bMixedCreate=true;
    1317           0 :                     pU->nBezierStartPoint=rXPoly.GetPointCount();
    1318           0 :                     if (pU->nBezierStartPoint>0) pU->nBezierStartPoint--;
    1319           0 :                 } break;
    1320           0 :                 default: break;
    1321             :             } // switch
    1322             :         }
    1323             :     }
    1324           0 :     sal_uInt16 nActPoint=rXPoly.GetPointCount();
    1325           0 :     if (aPathPolygon.Count()>1 && rStat.IsMouseDown() && nActPoint<2) {
    1326           0 :         rXPoly[0]=rStat.GetPos0();
    1327           0 :         rXPoly[1]=rStat.GetNow();
    1328           0 :         nActPoint=2;
    1329             :     }
    1330           0 :     if (nActPoint==0) {
    1331           0 :         rXPoly[0]=rStat.GetPos0();
    1332           0 :     } else nActPoint--;
    1333           0 :     bool bFreeHand=IsFreeHand(pU->eAktKind);
    1334           0 :     rStat.SetNoSnap(bFreeHand);
    1335           0 :     rStat.SetOrtho8Possible(pU->eAktKind!=OBJ_CARC && pU->eAktKind!=OBJ_RECT && (!pU->bMixedCreate || pU->eAktKind!=OBJ_LINE));
    1336           0 :     rXPoly[nActPoint]=rStat.Now();
    1337           0 :     if (!pU->bMixedCreate && pU->eStartKind==OBJ_LINE && rXPoly.GetPointCount()>=1) {
    1338           0 :         Point aPt(rStat.Start());
    1339           0 :         if (pView!=NULL && pView->IsCreate1stPointAsCenter()) {
    1340           0 :             aPt+=aPt;
    1341           0 :             aPt-=rStat.Now();
    1342             :         }
    1343           0 :         rXPoly[0]=aPt;
    1344             :     }
    1345           0 :     OutputDevice* pOut=pView==NULL ? NULL : pView->GetFirstOutputDevice();
    1346           0 :     if (bFreeHand) {
    1347           0 :         if (pU->nBezierStartPoint>nActPoint) pU->nBezierStartPoint=nActPoint;
    1348           0 :         if (rStat.IsMouseDown() && nActPoint>0) {
    1349             :             // don't allow two consecutive points to occupy too similar positions
    1350           0 :             long nMinDist=1;
    1351           0 :             if (pView!=NULL) nMinDist=pView->GetFreeHandMinDistPix();
    1352           0 :             if (pOut!=NULL) nMinDist=pOut->PixelToLogic(Size(nMinDist,0)).Width();
    1353           0 :             if (nMinDist<1) nMinDist=1;
    1354             : 
    1355           0 :             Point aPt0(rXPoly[nActPoint-1]);
    1356           0 :             Point aPt1(rStat.Now());
    1357           0 :             long dx=aPt0.X()-aPt1.X(); if (dx<0) dx=-dx;
    1358           0 :             long dy=aPt0.Y()-aPt1.Y(); if (dy<0) dy=-dy;
    1359           0 :             if (dx<nMinDist && dy<nMinDist) return false;
    1360             : 
    1361             :             // TODO: the following is copied from EndCreate (with a few smaller modifications)
    1362             :             // and should be combined into a method with the code there.
    1363             : 
    1364           0 :             if (nActPoint-pU->nBezierStartPoint>=3 && ((nActPoint-pU->nBezierStartPoint)%3)==0) {
    1365           0 :                 rXPoly.PointsToBezier(nActPoint-3);
    1366           0 :                 rXPoly.SetFlags(nActPoint-1,XPOLY_CONTROL);
    1367           0 :                 rXPoly.SetFlags(nActPoint-2,XPOLY_CONTROL);
    1368             : 
    1369           0 :                 if (nActPoint>=6 && rXPoly.IsControl(nActPoint-4)) {
    1370           0 :                     rXPoly.CalcTangent(nActPoint-3,nActPoint-4,nActPoint-2);
    1371           0 :                     rXPoly.SetFlags(nActPoint-3,XPOLY_SMOOTH);
    1372             :                 }
    1373             :             }
    1374           0 :             rXPoly[nActPoint+1]=rStat.Now();
    1375           0 :             rStat.NextPoint();
    1376             :         } else {
    1377           0 :             pU->nBezierStartPoint=nActPoint;
    1378             :         }
    1379             :     }
    1380             : 
    1381           0 :     pU->ResetFormFlags();
    1382           0 :     if (IsBezier(pU->eAktKind)) {
    1383           0 :         if (nActPoint>=2) {
    1384           0 :             pU->CalcBezier(rXPoly[nActPoint-1],rXPoly[nActPoint],rXPoly[nActPoint-1]-rXPoly[nActPoint-2],rStat.IsMouseDown());
    1385           0 :         } else if (pU->bBezHasCtrl0) {
    1386           0 :             pU->CalcBezier(rXPoly[nActPoint-1],rXPoly[nActPoint],pU->aBezControl0-rXPoly[nActPoint-1],rStat.IsMouseDown());
    1387             :         }
    1388             :     }
    1389           0 :     if (pU->eAktKind==OBJ_CARC && nActPoint>=2) {
    1390           0 :         pU->CalcCircle(rXPoly[nActPoint-1],rXPoly[nActPoint],rXPoly[nActPoint-1]-rXPoly[nActPoint-2],pView);
    1391             :     }
    1392           0 :     if (pU->eAktKind==OBJ_LINE && nActPoint>=2) {
    1393           0 :         pU->CalcLine(rXPoly[nActPoint-1],rXPoly[nActPoint],rXPoly[nActPoint-1]-rXPoly[nActPoint-2],pView);
    1394             :     }
    1395           0 :     if (pU->eAktKind==OBJ_RECT && nActPoint>=2) {
    1396           0 :         pU->CalcRect(rXPoly[nActPoint-1],rXPoly[nActPoint],rXPoly[nActPoint-1]-rXPoly[nActPoint-2],pView);
    1397             :     }
    1398             : 
    1399           0 :     return true;
    1400             : }
    1401             : 
    1402           0 : bool ImpPathForDragAndCreate::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
    1403             : {
    1404           0 :     ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
    1405           0 :     bool bRet = false;
    1406           0 :     SdrView* pView=rStat.GetView();
    1407           0 :     bool bIncomp=pView!=NULL && pView->IsUseIncompatiblePathCreateInterface();
    1408           0 :     XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1];
    1409           0 :     sal_uInt16 nActPoint=rXPoly.GetPointCount()-1;
    1410           0 :     rXPoly[nActPoint]=rStat.Now();
    1411           0 :     if (!pU->bMixedCreate && pU->eStartKind==OBJ_LINE) {
    1412           0 :         if (rStat.GetPointAnz()>=2) eCmd=SDRCREATE_FORCEEND;
    1413           0 :         bRet = eCmd==SDRCREATE_FORCEEND;
    1414           0 :         if (bRet) {
    1415           0 :             mbCreating = false;
    1416           0 :             delete pU;
    1417           0 :             rStat.SetUser(NULL);
    1418             :         }
    1419           0 :         return bRet;
    1420             :     }
    1421             : 
    1422           0 :     if (!pU->bMixedCreate && IsFreeHand(pU->eStartKind)) {
    1423           0 :         if (rStat.GetPointAnz()>=2) eCmd=SDRCREATE_FORCEEND;
    1424           0 :         bRet=eCmd==SDRCREATE_FORCEEND;
    1425           0 :         if (bRet) {
    1426           0 :             mbCreating=false;
    1427           0 :             delete pU;
    1428           0 :             rStat.SetUser(NULL);
    1429             :         }
    1430           0 :         return bRet;
    1431             :     }
    1432           0 :     if (eCmd==SDRCREATE_NEXTPOINT || eCmd==SDRCREATE_NEXTOBJECT) {
    1433             :         // don't allow two consecutive points to occupy the same position
    1434           0 :         if (nActPoint==0 || rStat.Now()!=rXPoly[nActPoint-1]) {
    1435           0 :             if (bIncomp) {
    1436           0 :                 if (pU->nBezierStartPoint>nActPoint) pU->nBezierStartPoint=nActPoint;
    1437           0 :                 if (IsBezier(pU->eAktKind) && nActPoint-pU->nBezierStartPoint>=3 && ((nActPoint-pU->nBezierStartPoint)%3)==0) {
    1438           0 :                     rXPoly.PointsToBezier(nActPoint-3);
    1439           0 :                     rXPoly.SetFlags(nActPoint-1,XPOLY_CONTROL);
    1440           0 :                     rXPoly.SetFlags(nActPoint-2,XPOLY_CONTROL);
    1441             : 
    1442           0 :                     if (nActPoint>=6 && rXPoly.IsControl(nActPoint-4)) {
    1443           0 :                         rXPoly.CalcTangent(nActPoint-3,nActPoint-4,nActPoint-2);
    1444           0 :                         rXPoly.SetFlags(nActPoint-3,XPOLY_SMOOTH);
    1445             :                     }
    1446             :                 }
    1447             :             } else {
    1448           0 :                 if (nActPoint==1 && IsBezier(pU->eAktKind) && !pU->bBezHasCtrl0) {
    1449           0 :                     pU->aBezControl0=rStat.GetNow();
    1450           0 :                     pU->bBezHasCtrl0=true;
    1451           0 :                     nActPoint--;
    1452             :                 }
    1453           0 :                 if (pU->IsFormFlag()) {
    1454           0 :                     sal_uInt16 nPointCount0=rXPoly.GetPointCount();
    1455           0 :                     rXPoly.Remove(nActPoint-1,2); // remove last two points and replace by form
    1456           0 :                     rXPoly.Insert(XPOLY_APPEND,pU->GetFormPoly());
    1457           0 :                     sal_uInt16 nPointCount1=rXPoly.GetPointCount();
    1458           0 :                     for (sal_uInt16 i=nPointCount0+1; i<nPointCount1-1; i++) { // to make BckAction work
    1459           0 :                         if (!rXPoly.IsControl(i)) rStat.NextPoint();
    1460             :                     }
    1461           0 :                     nActPoint=rXPoly.GetPointCount()-1;
    1462             :                 }
    1463             :             }
    1464           0 :             nActPoint++;
    1465           0 :             rXPoly[nActPoint]=rStat.GetNow();
    1466             :         }
    1467           0 :         if (eCmd==SDRCREATE_NEXTOBJECT) {
    1468           0 :             if (rXPoly.GetPointCount()>=2) {
    1469           0 :                 pU->bBezHasCtrl0=false;
    1470             :                 // only a singular polygon may be opened, so close this
    1471           0 :                 rXPoly[nActPoint]=rXPoly[0];
    1472           0 :                 XPolygon aXP;
    1473           0 :                 aXP[0]=rStat.GetNow();
    1474           0 :                 aPathPolygon.Insert(aXP);
    1475             :             }
    1476             :         }
    1477             :     }
    1478             : 
    1479           0 :     sal_uInt16 nPolyCount=aPathPolygon.Count();
    1480           0 :     if (nPolyCount!=0) {
    1481             :         // delete last point, if necessary
    1482           0 :         if (eCmd==SDRCREATE_FORCEEND) {
    1483           0 :             XPolygon& rXP=aPathPolygon[nPolyCount-1];
    1484           0 :             sal_uInt16 nPointCount=rXP.GetPointCount();
    1485           0 :             if (nPointCount>=2) {
    1486           0 :                 if (!rXP.IsControl(nPointCount-2)) {
    1487           0 :                     if (rXP[nPointCount-1]==rXP[nPointCount-2]) {
    1488           0 :                         rXP.Remove(nPointCount-1,1);
    1489             :                     }
    1490             :                 } else {
    1491           0 :                     if (rXP[nPointCount-3]==rXP[nPointCount-2]) {
    1492           0 :                         rXP.Remove(nPointCount-3,3);
    1493             :                     }
    1494             :                 }
    1495             :             }
    1496             :         }
    1497           0 :         for (sal_uInt16 nPolyNum=nPolyCount; nPolyNum>0;) {
    1498           0 :             nPolyNum--;
    1499           0 :             XPolygon& rXP=aPathPolygon[nPolyNum];
    1500           0 :             sal_uInt16 nPointCount=rXP.GetPointCount();
    1501             :             // delete polygons with too few points
    1502           0 :             if (nPolyNum<nPolyCount-1 || eCmd==SDRCREATE_FORCEEND) {
    1503           0 :                 if (nPointCount<2) aPathPolygon.Remove(nPolyNum);
    1504             :             }
    1505             :         }
    1506             :     }
    1507           0 :     pU->ResetFormFlags();
    1508           0 :     bRet=eCmd==SDRCREATE_FORCEEND;
    1509           0 :     if (bRet) {
    1510           0 :         mbCreating=false;
    1511           0 :         delete pU;
    1512           0 :         rStat.SetUser(NULL);
    1513             :     }
    1514           0 :     return bRet;
    1515             : }
    1516             : 
    1517           0 : bool ImpPathForDragAndCreate::BckCreate(SdrDragStat& rStat)
    1518             : {
    1519           0 :     ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
    1520           0 :     if (aPathPolygon.Count()>0) {
    1521           0 :         XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1];
    1522           0 :         sal_uInt16 nActPoint=rXPoly.GetPointCount();
    1523           0 :         if (nActPoint>0) {
    1524           0 :             nActPoint--;
    1525             :             // make the last part of a bezier curve a line
    1526           0 :             rXPoly.Remove(nActPoint,1);
    1527           0 :             if (nActPoint>=3 && rXPoly.IsControl(nActPoint-1)) {
    1528             :                 // there should never be a bezier segment at the end, so this is just in case...
    1529           0 :                 rXPoly.Remove(nActPoint-1,1);
    1530           0 :                 if (rXPoly.IsControl(nActPoint-2)) rXPoly.Remove(nActPoint-2,1);
    1531             :             }
    1532             :         }
    1533           0 :         nActPoint=rXPoly.GetPointCount();
    1534           0 :         if (nActPoint>=4) { // no bezier segment at the end
    1535           0 :             nActPoint--;
    1536           0 :             if (rXPoly.IsControl(nActPoint-1)) {
    1537           0 :                 rXPoly.Remove(nActPoint-1,1);
    1538           0 :                 if (rXPoly.IsControl(nActPoint-2)) rXPoly.Remove(nActPoint-2,1);
    1539             :             }
    1540             :         }
    1541           0 :         if (rXPoly.GetPointCount()<2) {
    1542           0 :             aPathPolygon.Remove(aPathPolygon.Count()-1);
    1543             :         }
    1544           0 :         if (aPathPolygon.Count()>0) {
    1545           0 :             XPolygon& rLocalXPoly=aPathPolygon[aPathPolygon.Count()-1];
    1546           0 :             sal_uInt16 nLocalActPoint=rLocalXPoly.GetPointCount();
    1547           0 :             if (nLocalActPoint>0) {
    1548           0 :                 nLocalActPoint--;
    1549           0 :                 rLocalXPoly[nLocalActPoint]=rStat.Now();
    1550             :             }
    1551             :         }
    1552             :     }
    1553           0 :     pU->ResetFormFlags();
    1554           0 :     return aPathPolygon.Count()!=0;
    1555             : }
    1556             : 
    1557           0 : void ImpPathForDragAndCreate::BrkCreate(SdrDragStat& rStat)
    1558             : {
    1559           0 :     ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
    1560           0 :     aPathPolygon.Clear();
    1561           0 :     mbCreating=false;
    1562           0 :     delete pU;
    1563           0 :     rStat.SetUser(NULL);
    1564           0 : }
    1565             : 
    1566           0 : basegfx::B2DPolyPolygon ImpPathForDragAndCreate::TakeObjectPolyPolygon(const SdrDragStat& rDrag) const
    1567             : {
    1568           0 :     basegfx::B2DPolyPolygon aRetval(aPathPolygon.getB2DPolyPolygon());
    1569           0 :     SdrView* pView = rDrag.GetView();
    1570             : 
    1571           0 :     if(pView && pView->IsUseIncompatiblePathCreateInterface())
    1572           0 :         return aRetval;
    1573             : 
    1574           0 :     ImpPathCreateUser* pU = static_cast<ImpPathCreateUser*>(rDrag.GetUser());
    1575           0 :     basegfx::B2DPolygon aNewPolygon(aRetval.count() ? aRetval.getB2DPolygon(aRetval.count() - 1L) : basegfx::B2DPolygon());
    1576             : 
    1577           0 :     if(pU->IsFormFlag() && aNewPolygon.count() > 1L)
    1578             :     {
    1579             :         // remove last segment and replace with current
    1580             :         // do not forget to rescue the previous control point which will be lost when
    1581             :         // the point it's associated with is removed
    1582           0 :         const sal_uInt32 nChangeIndex(aNewPolygon.count() - 2);
    1583           0 :         const basegfx::B2DPoint aSavedPrevCtrlPoint(aNewPolygon.getPrevControlPoint(nChangeIndex));
    1584             : 
    1585           0 :         aNewPolygon.remove(nChangeIndex, 2L);
    1586           0 :         aNewPolygon.append(pU->GetFormPoly().getB2DPolygon());
    1587             : 
    1588           0 :         if(nChangeIndex < aNewPolygon.count())
    1589             :         {
    1590             :             // if really something was added, set the saved previous control point to the
    1591             :             // point where it belongs
    1592           0 :             aNewPolygon.setPrevControlPoint(nChangeIndex, aSavedPrevCtrlPoint);
    1593           0 :         }
    1594             :     }
    1595             : 
    1596           0 :     if(aRetval.count())
    1597             :     {
    1598           0 :         aRetval.setB2DPolygon(aRetval.count() - 1L, aNewPolygon);
    1599             :     }
    1600             :     else
    1601             :     {
    1602           0 :         aRetval.append(aNewPolygon);
    1603             :     }
    1604             : 
    1605           0 :     return aRetval;
    1606             : }
    1607             : 
    1608           0 : basegfx::B2DPolyPolygon ImpPathForDragAndCreate::TakeDragPolyPolygon(const SdrDragStat& rDrag)
    1609             : {
    1610           0 :     basegfx::B2DPolyPolygon aRetval;
    1611           0 :     SdrView* pView = rDrag.GetView();
    1612             : 
    1613           0 :     if(pView && pView->IsUseIncompatiblePathCreateInterface())
    1614           0 :         return aRetval;
    1615             : 
    1616           0 :     const ImpPathCreateUser* pU = static_cast<const ImpPathCreateUser*>(rDrag.GetUser());
    1617             : 
    1618           0 :     if(pU && pU->bBezier && rDrag.IsMouseDown())
    1619             :     {
    1620             :         // no more XOR, no need for complicated helplines
    1621           0 :         basegfx::B2DPolygon aHelpline;
    1622           0 :         aHelpline.append(basegfx::B2DPoint(pU->aBezCtrl2.X(), pU->aBezCtrl2.Y()));
    1623           0 :         aHelpline.append(basegfx::B2DPoint(pU->aBezEnd.X(), pU->aBezEnd.Y()));
    1624           0 :         aRetval.append(aHelpline);
    1625             :     }
    1626             : 
    1627           0 :     return aRetval;
    1628             : }
    1629             : 
    1630           0 : Pointer ImpPathForDragAndCreate::GetCreatePointer() const
    1631             : {
    1632           0 :     switch (meObjectKind) {
    1633           0 :         case OBJ_LINE    : return Pointer(PointerStyle::DrawLine);
    1634           0 :         case OBJ_POLY    : return Pointer(PointerStyle::DrawPolygon);
    1635           0 :         case OBJ_PLIN    : return Pointer(PointerStyle::DrawPolygon);
    1636           0 :         case OBJ_PATHLINE: return Pointer(PointerStyle::DrawBezier);
    1637           0 :         case OBJ_PATHFILL: return Pointer(PointerStyle::DrawBezier);
    1638           0 :         case OBJ_FREELINE: return Pointer(PointerStyle::DrawFreehand);
    1639           0 :         case OBJ_FREEFILL: return Pointer(PointerStyle::DrawFreehand);
    1640           0 :         case OBJ_SPLNLINE: return Pointer(PointerStyle::DrawFreehand);
    1641           0 :         case OBJ_SPLNFILL: return Pointer(PointerStyle::DrawFreehand);
    1642           0 :         case OBJ_PATHPOLY: return Pointer(PointerStyle::DrawPolygon);
    1643           0 :         case OBJ_PATHPLIN: return Pointer(PointerStyle::DrawPolygon);
    1644           0 :         default: break;
    1645             :     } // switch
    1646           0 :     return Pointer(PointerStyle::Cross);
    1647             : }
    1648             : 
    1649           0 : SdrPathObjGeoData::SdrPathObjGeoData()
    1650           0 :     : meKind(OBJ_NONE)
    1651             : {
    1652           0 : }
    1653             : 
    1654           0 : SdrPathObjGeoData::~SdrPathObjGeoData()
    1655             : {
    1656           0 : }
    1657             : 
    1658             : // DrawContact section
    1659             : 
    1660       22030 : sdr::contact::ViewContact* SdrPathObj::CreateObjectSpecificViewContact()
    1661             : {
    1662       22030 :     return new sdr::contact::ViewContactOfSdrPathObj(*this);
    1663             : }
    1664             : 
    1665     1405979 : TYPEINIT1(SdrPathObj,SdrTextObj);
    1666             : 
    1667       18363 : SdrPathObj::SdrPathObj(SdrObjKind eNewKind)
    1668             : :   meKind(eNewKind),
    1669             :     mpDAC(0L),
    1670       18363 :     mdBrightness(1.0)
    1671             : {
    1672       18363 :     bClosedObj = IsClosed();
    1673       18363 : }
    1674             : 
    1675        3673 : SdrPathObj::SdrPathObj(SdrObjKind eNewKind, const basegfx::B2DPolyPolygon& rPathPoly, double dBrightness)
    1676             : :   maPathPolygon(rPathPoly),
    1677             :     meKind(eNewKind),
    1678             :     mpDAC(0L),
    1679        3673 :     mdBrightness(dBrightness)
    1680             : {
    1681        3673 :     bClosedObj = IsClosed();
    1682        3673 :     ImpForceKind();
    1683        3673 : }
    1684             : 
    1685       65220 : SdrPathObj::~SdrPathObj()
    1686             : {
    1687       21740 :     impDeleteDAC();
    1688       43480 : }
    1689             : 
    1690       11639 : static bool lcl_ImpIsLine(const basegfx::B2DPolyPolygon& rPolyPolygon)
    1691             : {
    1692       11639 :     return (1L == rPolyPolygon.count() && 2L == rPolyPolygon.getB2DPolygon(0L).count());
    1693             : }
    1694             : 
    1695       37598 : static Rectangle lcl_ImpGetBoundRect(const basegfx::B2DPolyPolygon& rPolyPolygon)
    1696             : {
    1697       37598 :     basegfx::B2DRange aRange(basegfx::tools::getRange(rPolyPolygon));
    1698             : 
    1699             :     return Rectangle(
    1700             :         FRound(aRange.getMinX()), FRound(aRange.getMinY()),
    1701       37598 :         FRound(aRange.getMaxX()), FRound(aRange.getMaxY()));
    1702             : }
    1703             : 
    1704        3534 : void SdrPathObj::ImpForceLineAngle()
    1705             : {
    1706        3534 :     if(OBJ_LINE == meKind && lcl_ImpIsLine(GetPathPoly()))
    1707             :     {
    1708        3534 :         const basegfx::B2DPolygon aPoly(GetPathPoly().getB2DPolygon(0L));
    1709        7068 :         const basegfx::B2DPoint aB2DPoint0(aPoly.getB2DPoint(0L));
    1710        7068 :         const basegfx::B2DPoint aB2DPoint1(aPoly.getB2DPoint(1L));
    1711        3534 :         const Point aPoint0(FRound(aB2DPoint0.getX()), FRound(aB2DPoint0.getY()));
    1712        3534 :         const Point aPoint1(FRound(aB2DPoint1.getX()), FRound(aB2DPoint1.getY()));
    1713        3534 :         const Point aDelt(aPoint1 - aPoint0);
    1714             : 
    1715        3534 :         aGeo.nRotationAngle=GetAngle(aDelt);
    1716        3534 :         aGeo.nShearAngle=0;
    1717        3534 :         aGeo.RecalcSinCos();
    1718        3534 :         aGeo.RecalcTan();
    1719             : 
    1720             :         // for SdrTextObj, keep aRect up to date
    1721        3534 :         maRect = Rectangle(aPoint0, aPoint1);
    1722        7068 :         maRect.Justify();
    1723             :     }
    1724        3534 : }
    1725             : 
    1726       22766 : void SdrPathObj::ImpForceKind()
    1727             : {
    1728       22766 :     if (meKind==OBJ_PATHPLIN) meKind=OBJ_PLIN;
    1729       22766 :     if (meKind==OBJ_PATHPOLY) meKind=OBJ_POLY;
    1730             : 
    1731       22766 :     if(GetPathPoly().areControlPointsUsed())
    1732             :     {
    1733        1218 :         switch (meKind)
    1734             :         {
    1735           3 :             case OBJ_LINE: meKind=OBJ_PATHLINE; break;
    1736          47 :             case OBJ_PLIN: meKind=OBJ_PATHLINE; break;
    1737         236 :             case OBJ_POLY: meKind=OBJ_PATHFILL; break;
    1738         932 :             default: break;
    1739             :         }
    1740             :     }
    1741             :     else
    1742             :     {
    1743       21548 :         switch (meKind)
    1744             :         {
    1745          28 :             case OBJ_PATHLINE: meKind=OBJ_PLIN; break;
    1746           0 :             case OBJ_FREELINE: meKind=OBJ_PLIN; break;
    1747         280 :             case OBJ_PATHFILL: meKind=OBJ_POLY; break;
    1748           0 :             case OBJ_FREEFILL: meKind=OBJ_POLY; break;
    1749       21240 :             default: break;
    1750             :         }
    1751             :     }
    1752             : 
    1753       22766 :     if (meKind==OBJ_LINE && !lcl_ImpIsLine(GetPathPoly())) meKind=OBJ_PLIN;
    1754       22766 :     if (meKind==OBJ_PLIN && lcl_ImpIsLine(GetPathPoly())) meKind=OBJ_LINE;
    1755             : 
    1756       22766 :     bClosedObj=IsClosed();
    1757             : 
    1758       22766 :     if (meKind==OBJ_LINE)
    1759             :     {
    1760        3534 :         ImpForceLineAngle();
    1761             :     }
    1762             :     else
    1763             :     {
    1764             :         // #i10659#, for polys with more than 2 points.
    1765             : 
    1766             :         // Here i again need to fix something, because when Path-Polys are Copy-Pasted
    1767             :         // between Apps with different measurements (e.g. 100TH_MM and TWIPS) there is
    1768             :         // a scaling loop started from SdrExchangeView::Paste. In itself, this is not
    1769             :         // wrong, but aRect is wrong here and not even updated by RecalcSnapRect(). If
    1770             :         // this is the case, some size needs to be set here in aRect to avoid that the cycle
    1771             :         // through Rect2Poly - Poly2Rect does something badly wrong since that cycle is
    1772             :         // BASED on aRect. That cycle is triggered in SdrTextObj::NbcResize() which is called
    1773             :         // from the local Resize() implementation.
    1774             : 
    1775             :         // Basic problem is that the member aRect in SdrTextObj basically is a unrotated
    1776             :         // text rectangle for the text object itself and methods at SdrTextObj do handle it
    1777             :         // in that way. Many draw objects derived from SdrTextObj 'abuse' aRect as SnapRect
    1778             :         // which is basically wrong. To make the SdrText methods which deal with aRect directly
    1779             :         // work it is necessary to always keep aRect updated. This e.g. not done after a Clone()
    1780             :         // command for SdrPathObj. Since adding this update mechanism with #101412# to
    1781             :         // ImpForceLineAngle() for lines was very successful, i add it to where ImpForceLineAngle()
    1782             :         // was called, once here below and once on a 2nd place below.
    1783             : 
    1784             :         // #i10659# for SdrTextObj, keep aRect up to date
    1785       19232 :         if(GetPathPoly().count())
    1786             :         {
    1787       19232 :             maRect = lcl_ImpGetBoundRect(GetPathPoly());
    1788             :         }
    1789             :     }
    1790             : 
    1791             :     // #i75974# adapt polygon state to object type. This may include a reinterpretation
    1792             :     // of a closed geometry as open one, but with identical first and last point
    1793       76559 :     for(sal_uInt32 a(0); a < maPathPolygon.count(); a++)
    1794             :     {
    1795       53793 :         basegfx::B2DPolygon aCandidate(maPathPolygon.getB2DPolygon(a));
    1796             : 
    1797       53793 :         if((bool)IsClosed() != aCandidate.isClosed())
    1798             :         {
    1799             :             // #i80213# really change polygon geometry; else e.g. the last point which
    1800             :             // needs to be identical with the first one will be missing when opening
    1801             :             // due to OBJ_PATH type
    1802         849 :             if(aCandidate.isClosed())
    1803             :             {
    1804         821 :                 basegfx::tools::openWithGeometryChange(aCandidate);
    1805             :             }
    1806             :             else
    1807             :             {
    1808          28 :                 basegfx::tools::closeWithGeometryChange(aCandidate);
    1809             :             }
    1810             : 
    1811         849 :             maPathPolygon.setB2DPolygon(a, aCandidate);
    1812             :         }
    1813       53793 :     }
    1814       22766 : }
    1815             : 
    1816           0 : void SdrPathObj::ImpSetClosed(bool bClose)
    1817             : {
    1818           0 :     if(bClose)
    1819             :     {
    1820           0 :         switch (meKind)
    1821             :         {
    1822           0 :             case OBJ_LINE    : meKind=OBJ_POLY;     break;
    1823           0 :             case OBJ_PLIN    : meKind=OBJ_POLY;     break;
    1824           0 :             case OBJ_PATHLINE: meKind=OBJ_PATHFILL; break;
    1825           0 :             case OBJ_FREELINE: meKind=OBJ_FREEFILL; break;
    1826           0 :             case OBJ_SPLNLINE: meKind=OBJ_SPLNFILL; break;
    1827           0 :             default: break;
    1828             :         }
    1829             : 
    1830           0 :         bClosedObj = true;
    1831             :     }
    1832             :     else
    1833             :     {
    1834           0 :         switch (meKind)
    1835             :         {
    1836           0 :             case OBJ_POLY    : meKind=OBJ_PLIN;     break;
    1837           0 :             case OBJ_PATHFILL: meKind=OBJ_PATHLINE; break;
    1838           0 :             case OBJ_FREEFILL: meKind=OBJ_FREELINE; break;
    1839           0 :             case OBJ_SPLNFILL: meKind=OBJ_SPLNLINE; break;
    1840           0 :             default: break;
    1841             :         }
    1842             : 
    1843           0 :         bClosedObj = false;
    1844             :     }
    1845             : 
    1846           0 :     ImpForceKind();
    1847           0 : }
    1848             : 
    1849          29 : void SdrPathObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
    1850             : {
    1851          29 :     rInfo.bNoContortion=false;
    1852             : 
    1853          29 :     bool bCanConv = !HasText() || ImpCanConvTextToCurve();
    1854          29 :     bool bIsPath = IsBezier() || IsSpline();
    1855             : 
    1856          29 :     rInfo.bEdgeRadiusAllowed    = false;
    1857          29 :     rInfo.bCanConvToPath = bCanConv && !bIsPath;
    1858          29 :     rInfo.bCanConvToPoly = bCanConv && bIsPath;
    1859          29 :     rInfo.bCanConvToContour = !IsFontwork() && (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
    1860          29 : }
    1861             : 
    1862      177493 : sal_uInt16 SdrPathObj::GetObjIdentifier() const
    1863             : {
    1864      177493 :     return sal_uInt16(meKind);
    1865             : }
    1866             : 
    1867         413 : SdrPathObj* SdrPathObj::Clone() const
    1868             : {
    1869         413 :     return CloneHelper< SdrPathObj >();
    1870             : }
    1871             : 
    1872         413 : SdrPathObj& SdrPathObj::operator=(const SdrPathObj& rObj)
    1873             : {
    1874         413 :     if( this == &rObj )
    1875           0 :         return *this;
    1876         413 :     SdrTextObj::operator=(rObj);
    1877         413 :     maPathPolygon=rObj.GetPathPoly();
    1878         413 :     return *this;
    1879             : }
    1880             : 
    1881         169 : OUString SdrPathObj::TakeObjNameSingul() const
    1882             : {
    1883         169 :     OUStringBuffer sName;
    1884             : 
    1885         169 :     if(OBJ_LINE == meKind)
    1886             :     {
    1887          48 :         sal_uInt16 nId(STR_ObjNameSingulLINE);
    1888             : 
    1889          48 :         if(lcl_ImpIsLine(GetPathPoly()))
    1890             :         {
    1891          48 :             const basegfx::B2DPolygon aPoly(GetPathPoly().getB2DPolygon(0L));
    1892          96 :             const basegfx::B2DPoint aB2DPoint0(aPoly.getB2DPoint(0L));
    1893          96 :             const basegfx::B2DPoint aB2DPoint1(aPoly.getB2DPoint(1L));
    1894             : 
    1895          48 :             if(aB2DPoint0 != aB2DPoint1)
    1896             :             {
    1897          48 :                 if(aB2DPoint0.getY() == aB2DPoint1.getY())
    1898             :                 {
    1899           7 :                     nId = STR_ObjNameSingulLINE_Hori;
    1900             :                 }
    1901          41 :                 else if(aB2DPoint0.getX() == aB2DPoint1.getX())
    1902             :                 {
    1903           5 :                     nId = STR_ObjNameSingulLINE_Vert;
    1904             :                 }
    1905             :                 else
    1906             :                 {
    1907          36 :                     const double fDx(fabs(aB2DPoint0.getX() - aB2DPoint1.getX()));
    1908          36 :                     const double fDy(fabs(aB2DPoint0.getY() - aB2DPoint1.getY()));
    1909             : 
    1910          36 :                     if(fDx == fDy)
    1911             :                     {
    1912           5 :                         nId = STR_ObjNameSingulLINE_Diag;
    1913             :                     }
    1914             :                 }
    1915          48 :             }
    1916             :         }
    1917             : 
    1918          48 :         sName.append(ImpGetResStr(nId));
    1919             :     }
    1920         121 :     else if(OBJ_PLIN == meKind || OBJ_POLY == meKind)
    1921             :     {
    1922          32 :         const bool bClosed(OBJ_POLY == meKind);
    1923          32 :         sal_uInt16 nId(0);
    1924             : 
    1925          32 :         if(mpDAC && mpDAC->IsCreating())
    1926             :         {
    1927           0 :             if(bClosed)
    1928             :             {
    1929           0 :                 nId = STR_ObjNameSingulPOLY;
    1930             :             }
    1931             :             else
    1932             :             {
    1933           0 :                 nId = STR_ObjNameSingulPLIN;
    1934             :             }
    1935             : 
    1936           0 :             sName.append(ImpGetResStr(nId));
    1937             :         }
    1938             :         else
    1939             :         {
    1940             :             // get point count
    1941          32 :             sal_uInt32 nPointCount(0L);
    1942          32 :             const sal_uInt32 nPolyCount(GetPathPoly().count());
    1943             : 
    1944          45 :             for(sal_uInt32 a(0L); a < nPolyCount; a++)
    1945             :             {
    1946          13 :                 nPointCount += GetPathPoly().getB2DPolygon(a).count();
    1947             :             }
    1948             : 
    1949          32 :             if(bClosed)
    1950             :             {
    1951          14 :                 nId = STR_ObjNameSingulPOLY_PntAnz;
    1952             :             }
    1953             :             else
    1954             :             {
    1955          18 :                 nId = STR_ObjNameSingulPLIN_PntAnz;
    1956             :             }
    1957             : 
    1958          32 :             OUString sTemp(ImpGetResStr(nId));
    1959             :             // #i96537#
    1960          32 :             sName.append(sTemp.replaceFirst("%2", OUString::number(nPointCount)));
    1961          32 :         }
    1962             :     }
    1963             :     else
    1964             :     {
    1965          89 :         switch (meKind)
    1966             :         {
    1967          39 :             case OBJ_PATHLINE: sName.append(ImpGetResStr(STR_ObjNameSingulPATHLINE)); break;
    1968           0 :             case OBJ_FREELINE: sName.append(ImpGetResStr(STR_ObjNameSingulFREELINE)); break;
    1969           0 :             case OBJ_SPLNLINE: sName.append(ImpGetResStr(STR_ObjNameSingulNATSPLN)); break;
    1970          50 :             case OBJ_PATHFILL: sName.append(ImpGetResStr(STR_ObjNameSingulPATHFILL)); break;
    1971           0 :             case OBJ_FREEFILL: sName.append(ImpGetResStr(STR_ObjNameSingulFREEFILL)); break;
    1972           0 :             case OBJ_SPLNFILL: sName.append(ImpGetResStr(STR_ObjNameSingulPERSPLN)); break;
    1973           0 :             default: break;
    1974             :         }
    1975             :     }
    1976             : 
    1977         169 :     OUString aName(GetName());
    1978         169 :     if (!aName.isEmpty())
    1979             :     {
    1980           0 :         sName.append(' ');
    1981           0 :         sName.append('\'');
    1982           0 :         sName.append(aName);
    1983           0 :         sName.append('\'');
    1984             :     }
    1985             : 
    1986         169 :     return sName.makeStringAndClear();
    1987             : }
    1988             : 
    1989          74 : OUString SdrPathObj::TakeObjNamePlural() const
    1990             : {
    1991          74 :     OUString sName;
    1992          74 :     switch(meKind)
    1993             :     {
    1994          48 :         case OBJ_LINE    : sName=ImpGetResStr(STR_ObjNamePluralLINE    ); break;
    1995           0 :         case OBJ_PLIN    : sName=ImpGetResStr(STR_ObjNamePluralPLIN    ); break;
    1996           3 :         case OBJ_POLY    : sName=ImpGetResStr(STR_ObjNamePluralPOLY    ); break;
    1997           3 :         case OBJ_PATHLINE: sName=ImpGetResStr(STR_ObjNamePluralPATHLINE); break;
    1998           0 :         case OBJ_FREELINE: sName=ImpGetResStr(STR_ObjNamePluralFREELINE); break;
    1999           0 :         case OBJ_SPLNLINE: sName=ImpGetResStr(STR_ObjNamePluralNATSPLN); break;
    2000          20 :         case OBJ_PATHFILL: sName=ImpGetResStr(STR_ObjNamePluralPATHFILL); break;
    2001           0 :         case OBJ_FREEFILL: sName=ImpGetResStr(STR_ObjNamePluralFREEFILL); break;
    2002           0 :         case OBJ_SPLNFILL: sName=ImpGetResStr(STR_ObjNamePluralPERSPLN); break;
    2003           0 :         default: break;
    2004             :     }
    2005          74 :     return sName;
    2006             : }
    2007             : 
    2008           0 : basegfx::B2DPolyPolygon SdrPathObj::TakeXorPoly() const
    2009             : {
    2010           0 :     return GetPathPoly();
    2011             : }
    2012             : 
    2013           0 : sal_uInt32 SdrPathObj::GetHdlCount() const
    2014             : {
    2015           0 :     sal_uInt32 nRetval(0L);
    2016           0 :     const sal_uInt32 nPolyCount(GetPathPoly().count());
    2017             : 
    2018           0 :     for(sal_uInt32 a(0L); a < nPolyCount; a++)
    2019             :     {
    2020           0 :         nRetval += GetPathPoly().getB2DPolygon(a).count();
    2021             :     }
    2022             : 
    2023           0 :     return nRetval;
    2024             : }
    2025             : 
    2026           0 : SdrHdl* SdrPathObj::GetHdl(sal_uInt32 nHdlNum) const
    2027             : {
    2028             :     // #i73248#
    2029             :     // Warn the user that this is ineffective and show alternatives. Should not be used at all.
    2030             :     OSL_FAIL("SdrPathObj::GetHdl(): ineffective, use AddToHdlList instead (!)");
    2031             : 
    2032             :     // to have an alternative, get single handle using the ineffective way
    2033           0 :     SdrHdl* pRetval = 0;
    2034           0 :     SdrHdlList aLocalList(0);
    2035           0 :     AddToHdlList(aLocalList);
    2036           0 :     const sal_uInt32 nHdlCount(aLocalList.GetHdlCount());
    2037             : 
    2038           0 :     if(nHdlCount && nHdlNum < nHdlCount)
    2039             :     {
    2040             :         // remove and remember. The other created handles will be deleted again with the
    2041             :         // destruction of the local list
    2042           0 :         pRetval = aLocalList.RemoveHdl(nHdlNum);
    2043             :     }
    2044             : 
    2045           0 :     return pRetval;
    2046             : }
    2047             : 
    2048         156 : void SdrPathObj::AddToHdlList(SdrHdlList& rHdlList) const
    2049             : {
    2050             :     // keep old stuff to be able to keep old SdrHdl stuff, too
    2051         156 :     const XPolyPolygon aOldPathPolygon(GetPathPoly());
    2052         156 :     sal_uInt16 nPolyCnt=aOldPathPolygon.Count();
    2053         156 :     bool bClosed=IsClosed();
    2054         156 :     sal_uInt16 nIdx=0;
    2055             : 
    2056         326 :     for (sal_uInt16 i=0; i<nPolyCnt; i++) {
    2057         170 :         const XPolygon& rXPoly=aOldPathPolygon.GetObject(i);
    2058         170 :         sal_uInt16 nPntCnt=rXPoly.GetPointCount();
    2059         170 :         if (bClosed && nPntCnt>1) nPntCnt--;
    2060             : 
    2061        1553 :         for (sal_uInt16 j=0; j<nPntCnt; j++) {
    2062        1383 :             if (rXPoly.GetFlags(j)!=XPOLY_CONTROL) {
    2063         701 :                 const Point& rPnt=rXPoly[j];
    2064         701 :                 SdrHdl* pHdl=new SdrHdl(rPnt,HDL_POLY);
    2065         701 :                 pHdl->SetPolyNum(i);
    2066         701 :                 pHdl->SetPointNum(j);
    2067         701 :                 pHdl->Set1PixMore(j==0);
    2068         701 :                 pHdl->SetSourceHdlNum(nIdx);
    2069         701 :                 nIdx++;
    2070         701 :                 rHdlList.AddHdl(pHdl);
    2071             :             }
    2072             :         }
    2073         156 :     }
    2074         156 : }
    2075             : 
    2076           0 : sal_uInt32 SdrPathObj::GetPlusHdlCount(const SdrHdl& rHdl) const
    2077             : {
    2078             :     // keep old stuff to be able to keep old SdrHdl stuff, too
    2079           0 :     const XPolyPolygon aOldPathPolygon(GetPathPoly());
    2080           0 :     sal_uInt16 nCnt = 0;
    2081           0 :     sal_uInt16 nPnt = (sal_uInt16)rHdl.GetPointNum();
    2082           0 :     sal_uInt16 nPolyNum = (sal_uInt16)rHdl.GetPolyNum();
    2083             : 
    2084           0 :     if(nPolyNum < aOldPathPolygon.Count())
    2085             :     {
    2086           0 :         const XPolygon& rXPoly = aOldPathPolygon[nPolyNum];
    2087           0 :         sal_uInt16 nPntMax = rXPoly.GetPointCount();
    2088           0 :         if (nPntMax>0)
    2089             :         {
    2090           0 :             nPntMax--;
    2091           0 :             if (nPnt<=nPntMax)
    2092             :             {
    2093           0 :                 if (rXPoly.GetFlags(nPnt)!=XPOLY_CONTROL)
    2094             :                 {
    2095           0 :                     if (nPnt==0 && IsClosed()) nPnt=nPntMax;
    2096           0 :                     if (nPnt>0 && rXPoly.GetFlags(nPnt-1)==XPOLY_CONTROL) nCnt++;
    2097           0 :                     if (nPnt==nPntMax && IsClosed()) nPnt=0;
    2098           0 :                     if (nPnt<nPntMax && rXPoly.GetFlags(nPnt+1)==XPOLY_CONTROL) nCnt++;
    2099             :                 }
    2100             :             }
    2101             :         }
    2102             :     }
    2103             : 
    2104           0 :     return nCnt;
    2105             : }
    2106             : 
    2107           0 : SdrHdl* SdrPathObj::GetPlusHdl(const SdrHdl& rHdl, sal_uInt32 nPlusNum) const
    2108             : {
    2109             :     // keep old stuff to be able to keep old SdrHdl stuff, too
    2110           0 :     const XPolyPolygon aOldPathPolygon(GetPathPoly());
    2111           0 :     SdrHdl* pHdl = 0L;
    2112           0 :     sal_uInt16 nPnt = (sal_uInt16)rHdl.GetPointNum();
    2113           0 :     sal_uInt16 nPolyNum = (sal_uInt16)rHdl.GetPolyNum();
    2114             : 
    2115           0 :     if (nPolyNum<aOldPathPolygon.Count())
    2116             :     {
    2117           0 :         const XPolygon& rXPoly = aOldPathPolygon[nPolyNum];
    2118           0 :         sal_uInt16 nPntMax = rXPoly.GetPointCount();
    2119             : 
    2120           0 :         if (nPntMax>0)
    2121             :         {
    2122           0 :             nPntMax--;
    2123           0 :             if (nPnt<=nPntMax)
    2124             :             {
    2125           0 :                 pHdl=new SdrHdlBezWgt(&rHdl);
    2126           0 :                 pHdl->SetPolyNum(rHdl.GetPolyNum());
    2127             : 
    2128           0 :                 if (nPnt==0 && IsClosed()) nPnt=nPntMax;
    2129           0 :                 if (nPnt>0 && rXPoly.GetFlags(nPnt-1)==XPOLY_CONTROL && nPlusNum==0)
    2130             :                 {
    2131           0 :                     pHdl->SetPos(rXPoly[nPnt-1]);
    2132           0 :                     pHdl->SetPointNum(nPnt-1);
    2133             :                 }
    2134             :                 else
    2135             :                 {
    2136           0 :                     if (nPnt==nPntMax && IsClosed()) nPnt=0;
    2137           0 :                     if (nPnt<rXPoly.GetPointCount()-1 && rXPoly.GetFlags(nPnt+1)==XPOLY_CONTROL)
    2138             :                     {
    2139           0 :                         pHdl->SetPos(rXPoly[nPnt+1]);
    2140           0 :                         pHdl->SetPointNum(nPnt+1);
    2141             :                     }
    2142             :                 }
    2143             : 
    2144           0 :                 pHdl->SetSourceHdlNum(rHdl.GetSourceHdlNum());
    2145           0 :                 pHdl->SetPlusHdl(true);
    2146             :             }
    2147             :         }
    2148             :     }
    2149           0 :     return pHdl;
    2150             : }
    2151             : 
    2152             : // dragging
    2153             : 
    2154         165 : bool SdrPathObj::hasSpecialDrag() const
    2155             : {
    2156         165 :     return true;
    2157             : }
    2158             : 
    2159           0 : bool SdrPathObj::beginSpecialDrag(SdrDragStat& rDrag) const
    2160             : {
    2161           0 :     ImpPathForDragAndCreate aDragAndCreate(*const_cast<SdrPathObj*>(this));
    2162             : 
    2163           0 :     return aDragAndCreate.beginPathDrag(rDrag);
    2164             : }
    2165             : 
    2166           0 : bool SdrPathObj::applySpecialDrag(SdrDragStat& rDrag)
    2167             : {
    2168           0 :     ImpPathForDragAndCreate aDragAndCreate(*this);
    2169           0 :     bool bRetval(aDragAndCreate.beginPathDrag(rDrag));
    2170             : 
    2171           0 :     if(bRetval)
    2172             :     {
    2173           0 :         bRetval = aDragAndCreate.movePathDrag(rDrag);
    2174             :     }
    2175             : 
    2176           0 :     if(bRetval)
    2177             :     {
    2178           0 :         bRetval = aDragAndCreate.endPathDrag(rDrag);
    2179             :     }
    2180             : 
    2181           0 :     if(bRetval)
    2182             :     {
    2183           0 :            NbcSetPathPoly(aDragAndCreate.getModifiedPolyPolygon());
    2184             :     }
    2185             : 
    2186           0 :     return bRetval;
    2187             : }
    2188             : 
    2189           0 : OUString SdrPathObj::getSpecialDragComment(const SdrDragStat& rDrag) const
    2190             : {
    2191           0 :     OUString aRetval;
    2192             : 
    2193           0 :     if(mpDAC)
    2194             :     {
    2195             :         // #i103058# also get a comment when in creation
    2196           0 :         const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
    2197             : 
    2198           0 :         if(bCreateComment)
    2199             :         {
    2200           0 :             aRetval = mpDAC->getSpecialDragComment(rDrag);
    2201             :         }
    2202             :     }
    2203             :     else
    2204             :     {
    2205           0 :         ImpPathForDragAndCreate aDragAndCreate(*const_cast<SdrPathObj*>(this));
    2206           0 :         bool bDidWork(aDragAndCreate.beginPathDrag((SdrDragStat&)rDrag));
    2207             : 
    2208           0 :         if(bDidWork)
    2209             :         {
    2210           0 :             aRetval = aDragAndCreate.getSpecialDragComment(rDrag);
    2211           0 :         }
    2212             :     }
    2213             : 
    2214           0 :     return aRetval;
    2215             : }
    2216             : 
    2217           0 : basegfx::B2DPolyPolygon SdrPathObj::getSpecialDragPoly(const SdrDragStat& rDrag) const
    2218             : {
    2219           0 :     basegfx::B2DPolyPolygon aRetval;
    2220           0 :     ImpPathForDragAndCreate aDragAndCreate(*const_cast<SdrPathObj*>(this));
    2221           0 :     bool bDidWork(aDragAndCreate.beginPathDrag((SdrDragStat&)rDrag));
    2222             : 
    2223           0 :     if(bDidWork)
    2224             :     {
    2225           0 :         aRetval = aDragAndCreate.getSpecialDragPoly(rDrag);
    2226             :     }
    2227             : 
    2228           0 :     return aRetval;
    2229             : }
    2230             : 
    2231             : // creation
    2232             : 
    2233           0 : bool SdrPathObj::BegCreate(SdrDragStat& rStat)
    2234             : {
    2235           0 :     impDeleteDAC();
    2236           0 :     return impGetDAC().BegCreate(rStat);
    2237             : }
    2238             : 
    2239           0 : bool SdrPathObj::MovCreate(SdrDragStat& rStat)
    2240             : {
    2241           0 :     return impGetDAC().MovCreate(rStat);
    2242             : }
    2243             : 
    2244           0 : bool SdrPathObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
    2245             : {
    2246           0 :     bool bRetval(impGetDAC().EndCreate(rStat, eCmd));
    2247             : 
    2248           0 :     if(bRetval && mpDAC)
    2249             :     {
    2250           0 :         SetPathPoly(mpDAC->getModifiedPolyPolygon());
    2251             : 
    2252             :         // #i75974# Check for AutoClose feature. Moved here from ImpPathForDragAndCreate::EndCreate
    2253             :         // to be able to use the type-changing ImpSetClosed method
    2254           0 :         if(!IsClosedObj())
    2255             :         {
    2256           0 :             SdrView* pView = rStat.GetView();
    2257             : 
    2258           0 :             if(pView && pView->IsAutoClosePolys() && !pView->IsUseIncompatiblePathCreateInterface())
    2259             :             {
    2260           0 :                 OutputDevice* pOut = pView->GetFirstOutputDevice();
    2261             : 
    2262           0 :                 if(pOut)
    2263             :                 {
    2264           0 :                     if(GetPathPoly().count())
    2265             :                     {
    2266           0 :                         const basegfx::B2DPolygon aCandidate(GetPathPoly().getB2DPolygon(0));
    2267             : 
    2268           0 :                         if(aCandidate.count() > 2)
    2269             :                         {
    2270             :                             // check distance of first and last point
    2271           0 :                             const sal_Int32 nCloseDist(pOut->PixelToLogic(Size(pView->GetAutoCloseDistPix(), 0)).Width());
    2272           0 :                             const basegfx::B2DVector aDistVector(aCandidate.getB2DPoint(aCandidate.count() - 1) - aCandidate.getB2DPoint(0));
    2273             : 
    2274           0 :                             if(aDistVector.getLength() <= (double)nCloseDist)
    2275             :                             {
    2276             :                                 // close it
    2277           0 :                                 ImpSetClosed(true);
    2278           0 :                             }
    2279           0 :                         }
    2280             :                     }
    2281             :                 }
    2282             :             }
    2283             :         }
    2284             : 
    2285           0 :         impDeleteDAC();
    2286             :     }
    2287             : 
    2288           0 :     return bRetval;
    2289             : }
    2290             : 
    2291           0 : bool SdrPathObj::BckCreate(SdrDragStat& rStat)
    2292             : {
    2293           0 :     return impGetDAC().BckCreate(rStat);
    2294             : }
    2295             : 
    2296           0 : void SdrPathObj::BrkCreate(SdrDragStat& rStat)
    2297             : {
    2298           0 :     impGetDAC().BrkCreate(rStat);
    2299           0 :     impDeleteDAC();
    2300           0 : }
    2301             : 
    2302             : // polygons
    2303             : 
    2304           0 : basegfx::B2DPolyPolygon SdrPathObj::TakeCreatePoly(const SdrDragStat& rDrag) const
    2305             : {
    2306           0 :     basegfx::B2DPolyPolygon aRetval;
    2307             : 
    2308           0 :     if(mpDAC)
    2309             :     {
    2310           0 :         aRetval = mpDAC->TakeObjectPolyPolygon(rDrag);
    2311           0 :         aRetval.append(ImpPathForDragAndCreate::TakeDragPolyPolygon(rDrag));
    2312             :     }
    2313             : 
    2314           0 :     return aRetval;
    2315             : }
    2316             : 
    2317             : // during drag or create, allow accessing the so-far created/modified polyPolygon
    2318           0 : basegfx::B2DPolyPolygon SdrPathObj::getObjectPolyPolygon(const SdrDragStat& rDrag) const
    2319             : {
    2320           0 :     basegfx::B2DPolyPolygon aRetval;
    2321             : 
    2322           0 :     if(mpDAC)
    2323             :     {
    2324           0 :         aRetval = mpDAC->TakeObjectPolyPolygon(rDrag);
    2325             :     }
    2326             : 
    2327           0 :     return aRetval;
    2328             : }
    2329             : 
    2330           0 : basegfx::B2DPolyPolygon SdrPathObj::getDragPolyPolygon(const SdrDragStat& rDrag) const
    2331             : {
    2332           0 :     basegfx::B2DPolyPolygon aRetval;
    2333             : 
    2334           0 :     if(mpDAC)
    2335             :     {
    2336           0 :         aRetval = ImpPathForDragAndCreate::TakeDragPolyPolygon(rDrag);
    2337             :     }
    2338             : 
    2339           0 :     return aRetval;
    2340             : }
    2341             : 
    2342           0 : Pointer SdrPathObj::GetCreatePointer() const
    2343             : {
    2344           0 :     return impGetDAC().GetCreatePointer();
    2345             : }
    2346             : 
    2347       47228 : void SdrPathObj::NbcMove(const Size& rSiz)
    2348             : {
    2349       47228 :     maPathPolygon.transform(basegfx::tools::createTranslateB2DHomMatrix(rSiz.Width(), rSiz.Height()));
    2350             : 
    2351             :     // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
    2352       47228 :     SdrTextObj::NbcMove(rSiz);
    2353       47228 : }
    2354             : 
    2355       37848 : void SdrPathObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
    2356             : {
    2357       37848 :     basegfx::B2DHomMatrix aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRef.X(), -rRef.Y()));
    2358             :     aTrans = basegfx::tools::createScaleTranslateB2DHomMatrix(
    2359       37848 :         double(xFact), double(yFact), rRef.X(), rRef.Y()) * aTrans;
    2360       37848 :     maPathPolygon.transform(aTrans);
    2361             : 
    2362             :     // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
    2363       37848 :     SdrTextObj::NbcResize(rRef,xFact,yFact);
    2364       37848 : }
    2365             : 
    2366         219 : void SdrPathObj::NbcRotate(const Point& rRef, long nAngle, double sn, double cs)
    2367             : {
    2368             :     // Thank JOE, the angles are defined mirrored to the mathematical meanings
    2369         219 :     const basegfx::B2DHomMatrix aTrans(basegfx::tools::createRotateAroundPoint(rRef.X(), rRef.Y(), -nAngle * nPi180));
    2370         219 :     maPathPolygon.transform(aTrans);
    2371             : 
    2372             :     // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
    2373         219 :     SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
    2374         219 : }
    2375             : 
    2376           2 : void SdrPathObj::NbcShear(const Point& rRefPnt, long nAngle, double fTan, bool bVShear)
    2377             : {
    2378           2 :     basegfx::B2DHomMatrix aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRefPnt.X(), -rRefPnt.Y()));
    2379             : 
    2380           2 :     if(bVShear)
    2381             :     {
    2382             :         // Thank JOE, the angles are defined mirrored to the mathematical meanings
    2383           0 :         aTrans.shearY(-fTan);
    2384             :     }
    2385             :     else
    2386             :     {
    2387           2 :         aTrans.shearX(-fTan);
    2388             :     }
    2389             : 
    2390           2 :     aTrans.translate(rRefPnt.X(), rRefPnt.Y());
    2391           2 :     maPathPolygon.transform(aTrans);
    2392             : 
    2393             :     // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
    2394           2 :     SdrTextObj::NbcShear(rRefPnt,nAngle,fTan,bVShear);
    2395           2 : }
    2396             : 
    2397         282 : void SdrPathObj::NbcMirror(const Point& rRefPnt1, const Point& rRefPnt2)
    2398             : {
    2399         282 :     const double fDiffX(rRefPnt2.X() - rRefPnt1.X());
    2400         282 :     const double fDiffY(rRefPnt2.Y() - rRefPnt1.Y());
    2401         282 :     const double fRot(atan2(fDiffY, fDiffX));
    2402         282 :     basegfx::B2DHomMatrix aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRefPnt1.X(), -rRefPnt1.Y()));
    2403         282 :     aTrans.rotate(-fRot);
    2404         282 :     aTrans.scale(1.0, -1.0);
    2405         282 :     aTrans.rotate(fRot);
    2406         282 :     aTrans.translate(rRefPnt1.X(), rRefPnt1.Y());
    2407         282 :     maPathPolygon.transform(aTrans);
    2408             : 
    2409             :     // Do Joe's special handling for lines when mirroring, too
    2410         282 :     ImpForceKind();
    2411             : 
    2412             :     // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
    2413         282 :     SdrTextObj::NbcMirror(rRefPnt1,rRefPnt2);
    2414         282 : }
    2415             : 
    2416           0 : void SdrPathObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
    2417             : {
    2418           0 :     if(!aGeo.nRotationAngle)
    2419             :     {
    2420           0 :         rRect = GetSnapRect();
    2421             :     }
    2422             :     else
    2423             :     {
    2424           0 :         XPolyPolygon aXPP(GetPathPoly());
    2425           0 :         RotateXPoly(aXPP,Point(),-aGeo.nSin,aGeo.nCos);
    2426           0 :         rRect=aXPP.GetBoundRect();
    2427           0 :         Point aTmp(rRect.TopLeft());
    2428           0 :         RotatePoint(aTmp,Point(),aGeo.nSin,aGeo.nCos);
    2429           0 :         aTmp-=rRect.TopLeft();
    2430           0 :         rRect.Move(aTmp.X(),aTmp.Y());
    2431             :     }
    2432           0 : }
    2433             : 
    2434       54648 : void SdrPathObj::RecalcSnapRect()
    2435             : {
    2436       54648 :     if(GetPathPoly().count())
    2437             :     {
    2438       18366 :         maSnapRect = lcl_ImpGetBoundRect(GetPathPoly());
    2439             :     }
    2440       54648 : }
    2441             : 
    2442       37820 : void SdrPathObj::NbcSetSnapRect(const Rectangle& rRect)
    2443             : {
    2444       37820 :     Rectangle aOld(GetSnapRect());
    2445             : 
    2446             :     // Take RECT_EMPTY into account when calculating scale factors
    2447       37820 :     long nMulX = (RECT_EMPTY == rRect.Right()) ? 0 : rRect.Right()  - rRect.Left();
    2448             : 
    2449       37820 :     long nDivX = aOld.Right()   - aOld.Left();
    2450             : 
    2451             :     // Take RECT_EMPTY into account when calculating scale factors
    2452       37820 :     long nMulY = (RECT_EMPTY == rRect.Bottom()) ? 0 : rRect.Bottom() - rRect.Top();
    2453             : 
    2454       37820 :     long nDivY = aOld.Bottom()  - aOld.Top();
    2455       37820 :     if ( nDivX == 0 ) { nMulX = 1; nDivX = 1; }
    2456       37820 :     if ( nDivY == 0 ) { nMulY = 1; nDivY = 1; }
    2457       37820 :     Fraction aX(nMulX,nDivX);
    2458       75640 :     Fraction aY(nMulY,nDivY);
    2459       37820 :     NbcResize(aOld.TopLeft(), aX, aY);
    2460       75640 :     NbcMove(Size(rRect.Left() - aOld.Left(), rRect.Top() - aOld.Top()));
    2461       37820 : }
    2462             : 
    2463           0 : sal_uInt32 SdrPathObj::GetSnapPointCount() const
    2464             : {
    2465           0 :     return GetHdlCount();
    2466             : }
    2467             : 
    2468           0 : Point SdrPathObj::GetSnapPoint(sal_uInt32 nSnapPnt) const
    2469             : {
    2470             :     sal_uInt32 nPoly,nPnt;
    2471           0 :     if(!PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nSnapPnt, nPoly, nPnt))
    2472             :     {
    2473             :         DBG_ASSERT(false,"SdrPathObj::GetSnapPoint: Point nSnapPnt does not exist.");
    2474             :     }
    2475             : 
    2476           0 :     const basegfx::B2DPoint aB2DPoint(GetPathPoly().getB2DPolygon(nPoly).getB2DPoint(nPnt));
    2477           0 :     return Point(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
    2478             : }
    2479             : 
    2480         596 : bool SdrPathObj::IsPolyObj() const
    2481             : {
    2482         596 :     return true;
    2483             : }
    2484             : 
    2485        1892 : sal_uInt32 SdrPathObj::GetPointCount() const
    2486             : {
    2487        1892 :     const sal_uInt32 nPolyCount(GetPathPoly().count());
    2488        1892 :     sal_uInt32 nRetval(0L);
    2489             : 
    2490        3784 :     for(sal_uInt32 a(0L); a < nPolyCount; a++)
    2491             :     {
    2492        1892 :         nRetval += GetPathPoly().getB2DPolygon(a).count();
    2493             :     }
    2494             : 
    2495        1892 :     return nRetval;
    2496             : }
    2497             : 
    2498         664 : Point SdrPathObj::GetPoint(sal_uInt32 nHdlNum) const
    2499             : {
    2500         664 :     Point aRetval;
    2501             :     sal_uInt32 nPoly,nPnt;
    2502             : 
    2503         664 :     if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum, nPoly, nPnt))
    2504             :     {
    2505         664 :         const basegfx::B2DPolygon aPoly(GetPathPoly().getB2DPolygon(nPoly));
    2506        1328 :         const basegfx::B2DPoint aPoint(aPoly.getB2DPoint(nPnt));
    2507        1328 :         aRetval = Point(FRound(aPoint.getX()), FRound(aPoint.getY()));
    2508             :     }
    2509             : 
    2510         664 :     return aRetval;
    2511             : }
    2512             : 
    2513           0 : void SdrPathObj::NbcSetPoint(const Point& rPnt, sal_uInt32 nHdlNum)
    2514             : {
    2515             :     sal_uInt32 nPoly,nPnt;
    2516             : 
    2517           0 :     if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum, nPoly, nPnt))
    2518             :     {
    2519           0 :         basegfx::B2DPolygon aNewPolygon(GetPathPoly().getB2DPolygon(nPoly));
    2520           0 :         aNewPolygon.setB2DPoint(nPnt, basegfx::B2DPoint(rPnt.X(), rPnt.Y()));
    2521           0 :         maPathPolygon.setB2DPolygon(nPoly, aNewPolygon);
    2522             : 
    2523           0 :         if(meKind==OBJ_LINE)
    2524             :         {
    2525           0 :             ImpForceLineAngle();
    2526             :         }
    2527             :         else
    2528             :         {
    2529           0 :             if(GetPathPoly().count())
    2530             :             {
    2531             :                 // #i10659# for SdrTextObj, keep aRect up to date
    2532           0 :                 maRect = lcl_ImpGetBoundRect(GetPathPoly());
    2533             :             }
    2534             :         }
    2535             : 
    2536           0 :         SetRectsDirty();
    2537             :     }
    2538           0 : }
    2539             : 
    2540           0 : sal_uInt32 SdrPathObj::NbcInsPointOld(const Point& rPos, bool bNewObj, bool bHideHim)
    2541             : {
    2542             :     sal_uInt32 nNewHdl;
    2543             : 
    2544           0 :     if(bNewObj)
    2545             :     {
    2546           0 :         nNewHdl = NbcInsPoint(0L, rPos, true, bHideHim);
    2547             :     }
    2548             :     else
    2549             :     {
    2550             :         // look for smallest distance data
    2551           0 :         const basegfx::B2DPoint aTestPoint(rPos.X(), rPos.Y());
    2552           0 :         sal_uInt32 nSmallestPolyIndex(0L);
    2553           0 :         sal_uInt32 nSmallestEdgeIndex(0L);
    2554             :         double fSmallestCut;
    2555           0 :         basegfx::tools::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint, nSmallestPolyIndex, nSmallestEdgeIndex, fSmallestCut);
    2556             : 
    2557             :         // create old polygon index from it
    2558           0 :         sal_uInt32 nPolyIndex(nSmallestEdgeIndex);
    2559             : 
    2560           0 :         for(sal_uInt32 a(0L); a < nSmallestPolyIndex; a++)
    2561             :         {
    2562           0 :             nPolyIndex += GetPathPoly().getB2DPolygon(a).count();
    2563             :         }
    2564             : 
    2565           0 :         nNewHdl = NbcInsPoint(nPolyIndex, rPos, false, bHideHim);
    2566             :     }
    2567             : 
    2568           0 :     ImpForceKind();
    2569           0 :     return nNewHdl;
    2570             : }
    2571             : 
    2572           0 : sal_uInt32 SdrPathObj::NbcInsPoint(sal_uInt32 /*nHdlNum*/, const Point& rPos, bool bNewObj, bool /*bHideHim*/)
    2573             : {
    2574             :     sal_uInt32 nNewHdl;
    2575             : 
    2576           0 :     if(bNewObj)
    2577             :     {
    2578           0 :         basegfx::B2DPolygon aNewPoly;
    2579           0 :         const basegfx::B2DPoint aPoint(rPos.X(), rPos.Y());
    2580           0 :         aNewPoly.append(aPoint);
    2581           0 :         aNewPoly.setClosed(IsClosed());
    2582           0 :         maPathPolygon.append(aNewPoly);
    2583           0 :         SetRectsDirty();
    2584           0 :         nNewHdl = GetHdlCount();
    2585             :     }
    2586             :     else
    2587             :     {
    2588             :         // look for smallest distance data
    2589           0 :         const basegfx::B2DPoint aTestPoint(rPos.X(), rPos.Y());
    2590           0 :         sal_uInt32 nSmallestPolyIndex(0L);
    2591           0 :         sal_uInt32 nSmallestEdgeIndex(0L);
    2592             :         double fSmallestCut;
    2593           0 :         basegfx::tools::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint, nSmallestPolyIndex, nSmallestEdgeIndex, fSmallestCut);
    2594           0 :         basegfx::B2DPolygon aCandidate(GetPathPoly().getB2DPolygon(nSmallestPolyIndex));
    2595           0 :         const bool bBefore(!aCandidate.isClosed() && 0L == nSmallestEdgeIndex && 0.0 == fSmallestCut);
    2596           0 :         const bool bAfter(!aCandidate.isClosed() && aCandidate.count() == nSmallestEdgeIndex + 2L && 1.0 == fSmallestCut);
    2597             : 
    2598           0 :         if(bBefore)
    2599             :         {
    2600             :             // before first point
    2601           0 :             aCandidate.insert(0L, aTestPoint);
    2602             : 
    2603           0 :             if(aCandidate.areControlPointsUsed())
    2604             :             {
    2605           0 :                 if(aCandidate.isNextControlPointUsed(1))
    2606             :                 {
    2607           0 :                     aCandidate.setNextControlPoint(0, interpolate(aTestPoint, aCandidate.getB2DPoint(1), (1.0 / 3.0)));
    2608           0 :                     aCandidate.setPrevControlPoint(1, interpolate(aTestPoint, aCandidate.getB2DPoint(1), (2.0 / 3.0)));
    2609             :                 }
    2610             :             }
    2611             : 
    2612           0 :             nNewHdl = 0L;
    2613             :         }
    2614           0 :         else if(bAfter)
    2615             :         {
    2616             :             // after last point
    2617           0 :             aCandidate.append(aTestPoint);
    2618             : 
    2619           0 :             if(aCandidate.areControlPointsUsed())
    2620             :             {
    2621           0 :                 if(aCandidate.isPrevControlPointUsed(aCandidate.count() - 2))
    2622             :                 {
    2623           0 :                     aCandidate.setNextControlPoint(aCandidate.count() - 2, interpolate(aCandidate.getB2DPoint(aCandidate.count() - 2), aTestPoint, (1.0 / 3.0)));
    2624           0 :                     aCandidate.setPrevControlPoint(aCandidate.count() - 1, interpolate(aCandidate.getB2DPoint(aCandidate.count() - 2), aTestPoint, (2.0 / 3.0)));
    2625             :                 }
    2626             :             }
    2627             : 
    2628           0 :             nNewHdl = aCandidate.count() - 1L;
    2629             :         }
    2630             :         else
    2631             :         {
    2632             :             // in between
    2633           0 :             bool bSegmentSplit(false);
    2634           0 :             const sal_uInt32 nNextIndex((nSmallestEdgeIndex + 1) % aCandidate.count());
    2635             : 
    2636           0 :             if(aCandidate.areControlPointsUsed())
    2637             :             {
    2638           0 :                 if(aCandidate.isNextControlPointUsed(nSmallestEdgeIndex) || aCandidate.isPrevControlPointUsed(nNextIndex))
    2639             :                 {
    2640           0 :                     bSegmentSplit = true;
    2641             :                 }
    2642             :             }
    2643             : 
    2644           0 :             if(bSegmentSplit)
    2645             :             {
    2646             :                 // rebuild original segment to get the split data
    2647           0 :                 basegfx::B2DCubicBezier aBezierA, aBezierB;
    2648             :                 const basegfx::B2DCubicBezier aBezier(
    2649             :                     aCandidate.getB2DPoint(nSmallestEdgeIndex),
    2650             :                     aCandidate.getNextControlPoint(nSmallestEdgeIndex),
    2651             :                     aCandidate.getPrevControlPoint(nNextIndex),
    2652           0 :                     aCandidate.getB2DPoint(nNextIndex));
    2653             : 
    2654             :                 // split and insert hit point
    2655           0 :                 aBezier.split(fSmallestCut, &aBezierA, &aBezierB);
    2656           0 :                 aCandidate.insert(nSmallestEdgeIndex + 1, aTestPoint);
    2657             : 
    2658             :                 // since we inserted hit point and not split point, we need to add an offset
    2659             :                 // to the control points to get the C1 continuity we want to achieve
    2660           0 :                 const basegfx::B2DVector aOffset(aTestPoint - aBezierA.getEndPoint());
    2661           0 :                 aCandidate.setNextControlPoint(nSmallestEdgeIndex, aBezierA.getControlPointA() + aOffset);
    2662           0 :                 aCandidate.setPrevControlPoint(nSmallestEdgeIndex + 1, aBezierA.getControlPointB() + aOffset);
    2663           0 :                 aCandidate.setNextControlPoint(nSmallestEdgeIndex + 1, aBezierB.getControlPointA() + aOffset);
    2664           0 :                 aCandidate.setPrevControlPoint((nSmallestEdgeIndex + 2) % aCandidate.count(), aBezierB.getControlPointB() + aOffset);
    2665             :             }
    2666             :             else
    2667             :             {
    2668           0 :                 aCandidate.insert(nSmallestEdgeIndex + 1L, aTestPoint);
    2669             :             }
    2670             : 
    2671           0 :             nNewHdl = nSmallestEdgeIndex + 1L;
    2672             :         }
    2673             : 
    2674           0 :         maPathPolygon.setB2DPolygon(nSmallestPolyIndex, aCandidate);
    2675             : 
    2676             :         // create old polygon index from it
    2677           0 :         for(sal_uInt32 a(0L); a < nSmallestPolyIndex; a++)
    2678             :         {
    2679           0 :             nNewHdl += GetPathPoly().getB2DPolygon(a).count();
    2680           0 :         }
    2681             :     }
    2682             : 
    2683           0 :     ImpForceKind();
    2684           0 :     return nNewHdl;
    2685             : }
    2686             : 
    2687           0 : SdrObject* SdrPathObj::RipPoint(sal_uInt32 nHdlNum, sal_uInt32& rNewPt0Index)
    2688             : {
    2689           0 :     SdrPathObj* pNewObj = 0L;
    2690           0 :     const basegfx::B2DPolyPolygon aLocalPolyPolygon(GetPathPoly());
    2691             :     sal_uInt32 nPoly, nPnt;
    2692             : 
    2693           0 :     if(PolyPolygonEditor::GetRelativePolyPoint(aLocalPolyPolygon, nHdlNum, nPoly, nPnt))
    2694             :     {
    2695           0 :         if(0L == nPoly)
    2696             :         {
    2697           0 :             const basegfx::B2DPolygon aCandidate(aLocalPolyPolygon.getB2DPolygon(nPoly));
    2698           0 :             const sal_uInt32 nPointCount(aCandidate.count());
    2699             : 
    2700           0 :             if(nPointCount)
    2701             :             {
    2702           0 :                 if(IsClosed())
    2703             :                 {
    2704             :                     // when closed, RipPoint means to open the polygon at the selected point. To
    2705             :                     // be able to do that, it is necessary to make the selected point the first one
    2706           0 :                     basegfx::B2DPolygon aNewPolygon(basegfx::tools::makeStartPoint(aCandidate, nPnt));
    2707           0 :                     SetPathPoly(basegfx::B2DPolyPolygon(aNewPolygon));
    2708           0 :                     ToggleClosed();
    2709             : 
    2710             :                     // give back new position of old start point (historical reasons)
    2711           0 :                     rNewPt0Index = (nPointCount - nPnt) % nPointCount;
    2712             :                 }
    2713             :                 else
    2714             :                 {
    2715           0 :                     if(nPointCount >= 3L && nPnt != 0L && nPnt + 1L < nPointCount)
    2716             :                     {
    2717             :                         // split in two objects at point nPnt
    2718           0 :                         basegfx::B2DPolygon aSplitPolyA(aCandidate, 0L, nPnt + 1L);
    2719           0 :                         SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyA));
    2720             : 
    2721           0 :                         pNewObj = Clone();
    2722           0 :                         basegfx::B2DPolygon aSplitPolyB(aCandidate, nPnt, nPointCount - nPnt);
    2723           0 :                         pNewObj->SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyB));
    2724             :                     }
    2725             :                 }
    2726           0 :             }
    2727             :         }
    2728             :     }
    2729             : 
    2730           0 :     return pNewObj;
    2731             : }
    2732             : 
    2733          13 : SdrObject* SdrPathObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
    2734             : {
    2735             :     // #i89784# check for FontWork with activated HideContour
    2736             :     const drawinglayer::attribute::SdrTextAttribute aText(
    2737          13 :         drawinglayer::primitive2d::createNewSdrTextAttribute(GetObjectItemSet(), *getText(0)));
    2738             :     const bool bHideContour(
    2739          13 :         !aText.isDefault() && !aText.getSdrFormTextAttribute().isDefault() && aText.isHideContour());
    2740             : 
    2741             :     SdrObject* pRet = bHideContour ?
    2742             :         0 :
    2743          13 :         ImpConvertMakeObj(GetPathPoly(), IsClosed(), bBezier);
    2744             : 
    2745          13 :     SdrPathObj* pPath = PTR_CAST(SdrPathObj, pRet);
    2746             : 
    2747          13 :     if(pPath)
    2748             :     {
    2749          13 :         if(pPath->GetPathPoly().areControlPointsUsed())
    2750             :         {
    2751          13 :             if(!bBezier)
    2752             :             {
    2753             :                 // reduce all bezier curves
    2754           0 :                 pPath->SetPathPoly(basegfx::tools::adaptiveSubdivideByAngle(pPath->GetPathPoly()));
    2755             :             }
    2756             :         }
    2757             :         else
    2758             :         {
    2759           0 :             if(bBezier)
    2760             :             {
    2761             :                 // create bezier curves
    2762           0 :                 pPath->SetPathPoly(basegfx::tools::expandToCurve(pPath->GetPathPoly()));
    2763             :             }
    2764             :         }
    2765             :     }
    2766             : 
    2767          13 :     if(bAddText)
    2768             :     {
    2769          13 :         pRet = ImpConvertAddText(pRet, bBezier);
    2770             :     }
    2771             : 
    2772          13 :     return pRet;
    2773             : }
    2774             : 
    2775           0 : SdrObjGeoData* SdrPathObj::NewGeoData() const
    2776             : {
    2777           0 :     return new SdrPathObjGeoData;
    2778             : }
    2779             : 
    2780           0 : void SdrPathObj::SaveGeoData(SdrObjGeoData& rGeo) const
    2781             : {
    2782           0 :     SdrTextObj::SaveGeoData(rGeo);
    2783           0 :     SdrPathObjGeoData& rPGeo = static_cast<SdrPathObjGeoData&>( rGeo );
    2784           0 :     rPGeo.maPathPolygon=GetPathPoly();
    2785           0 :     rPGeo.meKind=meKind;
    2786           0 : }
    2787             : 
    2788           0 : void SdrPathObj::RestGeoData(const SdrObjGeoData& rGeo)
    2789             : {
    2790           0 :     SdrTextObj::RestGeoData(rGeo);
    2791           0 :     const SdrPathObjGeoData& rPGeo=static_cast<const SdrPathObjGeoData&>(rGeo);
    2792           0 :     maPathPolygon=rPGeo.maPathPolygon;
    2793           0 :     meKind=rPGeo.meKind;
    2794           0 :     ImpForceKind(); // to set bClosed (among other things)
    2795           0 : }
    2796             : 
    2797       18811 : void SdrPathObj::NbcSetPathPoly(const basegfx::B2DPolyPolygon& rPathPoly)
    2798             : {
    2799       18811 :     if(GetPathPoly() != rPathPoly)
    2800             :     {
    2801       18811 :         maPathPolygon=rPathPoly;
    2802       18811 :         ImpForceKind();
    2803       18811 :         SetRectsDirty();
    2804             :     }
    2805       18811 : }
    2806             : 
    2807       18829 : void SdrPathObj::SetPathPoly(const basegfx::B2DPolyPolygon& rPathPoly)
    2808             : {
    2809       18829 :     if(GetPathPoly() != rPathPoly)
    2810             :     {
    2811       18811 :         Rectangle aBoundRect0; if (pUserCall!=NULL) aBoundRect0=GetLastBoundRect();
    2812       18811 :         NbcSetPathPoly(rPathPoly);
    2813       18811 :         SetChanged();
    2814       18811 :         BroadcastObjectChange();
    2815       18811 :         SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0);
    2816             :     }
    2817       18829 : }
    2818             : 
    2819           0 : void SdrPathObj::ToggleClosed()
    2820             : {
    2821           0 :     Rectangle aBoundRect0;
    2822           0 :     if(pUserCall != NULL)
    2823           0 :         aBoundRect0 = GetLastBoundRect();
    2824           0 :     ImpSetClosed(!IsClosed()); // set new ObjKind
    2825           0 :     ImpForceKind(); // because we want Line -> Poly -> PolyLine instead of Line -> Poly -> Line
    2826           0 :     SetRectsDirty();
    2827           0 :     SetChanged();
    2828           0 :     BroadcastObjectChange();
    2829           0 :     SendUserCall(SDRUSERCALL_RESIZE, aBoundRect0);
    2830           0 : }
    2831             : 
    2832             : // for friend class SdrPolyEditView in some compilers:
    2833      193282 : void SdrPathObj::SetRectsDirty(bool bNotMyself)
    2834             : {
    2835      193282 :     SdrTextObj::SetRectsDirty(bNotMyself);
    2836      193282 : }
    2837             : 
    2838           0 : ImpPathForDragAndCreate& SdrPathObj::impGetDAC() const
    2839             : {
    2840           0 :     if(!mpDAC)
    2841             :     {
    2842           0 :         const_cast<SdrPathObj*>(this)->mpDAC = new ImpPathForDragAndCreate(*const_cast<SdrPathObj*>(this));
    2843             :     }
    2844             : 
    2845           0 :     return *mpDAC;
    2846             : }
    2847             : 
    2848       21740 : void SdrPathObj::impDeleteDAC() const
    2849             : {
    2850       21740 :     if(mpDAC)
    2851             :     {
    2852           0 :         delete mpDAC;
    2853           0 :         const_cast<SdrPathObj*>(this)->mpDAC = 0L;
    2854             :     }
    2855       21740 : }
    2856             : 
    2857             : 
    2858             : 
    2859             : // transformation interface for StarOfficeAPI. This implements support for
    2860             : // homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
    2861             : // moment it contains a shearX, rotation and translation, but for setting all linear
    2862             : // transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
    2863             : 
    2864             : 
    2865             : // gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
    2866             : // with the base geometry and returns TRUE. Otherwise it returns FALSE.
    2867        1927 : bool SdrPathObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& rPolyPolygon) const
    2868             : {
    2869        1927 :     double fRotate(0.0);
    2870        1927 :     double fShearX(0.0);
    2871        1927 :     basegfx::B2DTuple aScale(1.0, 1.0);
    2872        3854 :     basegfx::B2DTuple aTranslate(0.0, 0.0);
    2873             : 
    2874        1927 :     if(GetPathPoly().count())
    2875             :     {
    2876             :         // copy geometry
    2877        1117 :         basegfx::B2DHomMatrix aMoveToZeroMatrix;
    2878        1117 :         rPolyPolygon = GetPathPoly();
    2879             : 
    2880        1117 :         if(OBJ_LINE == meKind)
    2881             :         {
    2882             :             // ignore shear and rotate, just use scale and translate
    2883             :             OSL_ENSURE(GetPathPoly().count() > 0L && GetPathPoly().getB2DPolygon(0L).count() > 1L, "OBJ_LINE with too few polygons (!)");
    2884             :             // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
    2885             :             // itself, else this method will no longer return the full polygon information (curve will
    2886             :             // be lost)
    2887         174 :             const basegfx::B2DRange aPolyRangeNoCurve(basegfx::tools::getRange(rPolyPolygon));
    2888         174 :             aScale = aPolyRangeNoCurve.getRange();
    2889         174 :             aTranslate = aPolyRangeNoCurve.getMinimum();
    2890             : 
    2891             :             // define matrix for move polygon to zero point
    2892         174 :             aMoveToZeroMatrix.translate(-aTranslate.getX(), -aTranslate.getY());
    2893             :         }
    2894             :         else
    2895             :         {
    2896         943 :             if(aGeo.nShearAngle || aGeo.nRotationAngle)
    2897             :             {
    2898             :                 // get rotate and shear in drawingLayer notation
    2899         176 :                 fRotate = aGeo.nRotationAngle * F_PI18000;
    2900         176 :                 fShearX = aGeo.nShearAngle * F_PI18000;
    2901             : 
    2902             :                 // build mathematically correct (negative shear and rotate) object transform
    2903             :                 // containing shear and rotate to extract unsheared, unrotated polygon
    2904         176 :                 basegfx::B2DHomMatrix aObjectMatrix;
    2905         176 :                 aObjectMatrix.shearX(tan((36000 - aGeo.nShearAngle) * F_PI18000));
    2906         176 :                 aObjectMatrix.rotate((36000 - aGeo.nRotationAngle) * F_PI18000);
    2907             : 
    2908             :                 // create inverse from it and back-transform polygon
    2909         352 :                 basegfx::B2DHomMatrix aInvObjectMatrix(aObjectMatrix);
    2910         176 :                 aInvObjectMatrix.invert();
    2911         176 :                 rPolyPolygon.transform(aInvObjectMatrix);
    2912             : 
    2913             :                 // get range from unsheared, unrotated polygon and extract scale and translate.
    2914             :                 // transform topLeft from it back to transformed state to get original
    2915             :                 // topLeft (rotation center)
    2916             :                 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
    2917             :                 // itself, else this method will no longer return the full polygon information (curve will
    2918             :                 // be lost)
    2919         176 :                 const basegfx::B2DRange aCorrectedRangeNoCurve(basegfx::tools::getRange(rPolyPolygon));
    2920         176 :                 aTranslate = aObjectMatrix * aCorrectedRangeNoCurve.getMinimum();
    2921         176 :                 aScale = aCorrectedRangeNoCurve.getRange();
    2922             : 
    2923             :                 // define matrix for move polygon to zero point
    2924             :                 // #i112280# Added missing minus for Y-Translation
    2925         352 :                 aMoveToZeroMatrix.translate(-aCorrectedRangeNoCurve.getMinX(), -aCorrectedRangeNoCurve.getMinY());
    2926             :             }
    2927             :             else
    2928             :             {
    2929             :                 // get scale and translate from unsheared, unrotated polygon
    2930             :                 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
    2931             :                 // itself, else this method will no longer return the full polygon information (curve will
    2932             :                 // be lost)
    2933         767 :                 const basegfx::B2DRange aPolyRangeNoCurve(basegfx::tools::getRange(rPolyPolygon));
    2934         767 :                 aScale = aPolyRangeNoCurve.getRange();
    2935         767 :                 aTranslate = aPolyRangeNoCurve.getMinimum();
    2936             : 
    2937             :                 // define matrix for move polygon to zero point
    2938         767 :                 aMoveToZeroMatrix.translate(-aTranslate.getX(), -aTranslate.getY());
    2939             :             }
    2940             :         }
    2941             : 
    2942             :         // move polygon to zero point with pre-defined matrix
    2943        1117 :         rPolyPolygon.transform(aMoveToZeroMatrix);
    2944             :     }
    2945             : 
    2946             :     // position maybe relative to anchorpos, convert
    2947        1927 :     if( pModel && pModel->IsWriter() )
    2948             :     {
    2949         483 :         if(GetAnchorPos().X() || GetAnchorPos().Y())
    2950             :         {
    2951         208 :             aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
    2952             :         }
    2953             :     }
    2954             : 
    2955             :     // force MapUnit to 100th mm
    2956        1927 :     const SfxMapUnit eMapUnit(GetObjectMapUnit());
    2957        1927 :     if(eMapUnit != SFX_MAPUNIT_100TH_MM)
    2958             :     {
    2959         483 :         switch(eMapUnit)
    2960             :         {
    2961             :             case SFX_MAPUNIT_TWIP :
    2962             :             {
    2963             :                 // position
    2964         483 :                 aTranslate.setX(ImplTwipsToMM(aTranslate.getX()));
    2965         483 :                 aTranslate.setY(ImplTwipsToMM(aTranslate.getY()));
    2966             : 
    2967             :                 // size
    2968         483 :                 aScale.setX(ImplTwipsToMM(aScale.getX()));
    2969         483 :                 aScale.setY(ImplTwipsToMM(aScale.getY()));
    2970             : 
    2971             :                 // polygon
    2972         483 :                 basegfx::B2DHomMatrix aTwipsToMM;
    2973         483 :                 const double fFactorTwipsToMM(127.0 / 72.0);
    2974         483 :                 aTwipsToMM.scale(fFactorTwipsToMM, fFactorTwipsToMM);
    2975         483 :                 rPolyPolygon.transform(aTwipsToMM);
    2976             : 
    2977         483 :                 break;
    2978             :             }
    2979             :             default:
    2980             :             {
    2981             :                 OSL_FAIL("TRGetBaseGeometry: Missing unit translation to 100th mm!");
    2982             :             }
    2983             :         }
    2984             :     }
    2985             : 
    2986             :     // build return value matrix
    2987        5781 :     rMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
    2988             :         aScale,
    2989        1927 :         basegfx::fTools::equalZero(fShearX) ? 0.0 : tan(fShearX),
    2990        1927 :         basegfx::fTools::equalZero(fRotate) ? 0.0 : -fRotate,
    2991        1927 :         aTranslate);
    2992             : 
    2993        3854 :     return true;
    2994             : }
    2995             : 
    2996             : // Sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
    2997             : // If it's an SdrPathObj it will use the provided geometry information. The Polygon has
    2998             : // to use (0,0) as upper left and will be scaled to the given size in the matrix.
    2999        1622 : void SdrPathObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& rPolyPolygon)
    3000             : {
    3001             :     // break up matrix
    3002        1622 :     basegfx::B2DTuple aScale;
    3003        3244 :     basegfx::B2DTuple aTranslate;
    3004             :     double fRotate, fShearX;
    3005        1622 :     rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
    3006             : 
    3007             :     // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
    3008             :     // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
    3009        1622 :     if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
    3010             :     {
    3011           0 :         aScale.setX(fabs(aScale.getX()));
    3012           0 :         aScale.setY(fabs(aScale.getY()));
    3013           0 :         fRotate = fmod(fRotate + F_PI, F_2PI);
    3014             :     }
    3015             : 
    3016             :     // copy poly
    3017        3244 :     basegfx::B2DPolyPolygon aNewPolyPolygon(rPolyPolygon);
    3018             : 
    3019             :     // reset object shear and rotations
    3020        1622 :     aGeo.nRotationAngle = 0;
    3021        1622 :     aGeo.RecalcSinCos();
    3022        1622 :     aGeo.nShearAngle = 0;
    3023        1622 :     aGeo.RecalcTan();
    3024             : 
    3025             :     // force metric to pool metric
    3026        1622 :     const SfxMapUnit eMapUnit(GetObjectMapUnit());
    3027        1622 :     if(eMapUnit != SFX_MAPUNIT_100TH_MM)
    3028             :     {
    3029         200 :         switch(eMapUnit)
    3030             :         {
    3031             :             case SFX_MAPUNIT_TWIP :
    3032             :             {
    3033             :                 // position
    3034         200 :                 aTranslate.setX(ImplMMToTwips(aTranslate.getX()));
    3035         200 :                 aTranslate.setY(ImplMMToTwips(aTranslate.getY()));
    3036             : 
    3037             :                 // size
    3038         200 :                 aScale.setX(ImplMMToTwips(aScale.getX()));
    3039         200 :                 aScale.setY(ImplMMToTwips(aScale.getY()));
    3040             : 
    3041             :                 // polygon
    3042         200 :                 basegfx::B2DHomMatrix aMMToTwips;
    3043         200 :                 const double fFactorMMToTwips(72.0 / 127.0);
    3044         200 :                 aMMToTwips.scale(fFactorMMToTwips, fFactorMMToTwips);
    3045         200 :                 aNewPolyPolygon.transform(aMMToTwips);
    3046             : 
    3047         200 :                 break;
    3048             :             }
    3049             :             default:
    3050             :             {
    3051             :                 OSL_FAIL("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
    3052             :             }
    3053             :         }
    3054             :     }
    3055             : 
    3056        1622 :     if( pModel && pModel->IsWriter() )
    3057             :     {
    3058             :         // if anchor is used, make position relative to it
    3059         200 :         if(GetAnchorPos().X() || GetAnchorPos().Y())
    3060             :         {
    3061           0 :             aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
    3062             :         }
    3063             :     }
    3064             : 
    3065             :     // create transformation for polygon, set values at aGeo direct
    3066        1622 :     basegfx::B2DHomMatrix aTransform;
    3067             : 
    3068             :     // #i75086#
    3069             :     // Given polygon is already scaled (for historical reasons), but not mirrored yet.
    3070             :     // Thus, when scale is negative in X or Y, apply the needed mirroring accordingly.
    3071        1622 :     if(basegfx::fTools::less(aScale.getX(), 0.0) || basegfx::fTools::less(aScale.getY(), 0.0))
    3072             :     {
    3073             :         aTransform.scale(
    3074           0 :             basegfx::fTools::less(aScale.getX(), 0.0) ? -1.0 : 1.0,
    3075           0 :             basegfx::fTools::less(aScale.getY(), 0.0) ? -1.0 : 1.0);
    3076             :     }
    3077             : 
    3078        1622 :     if(!basegfx::fTools::equalZero(fShearX))
    3079             :     {
    3080           0 :         aTransform.shearX(tan(-atan(fShearX)));
    3081           0 :         aGeo.nShearAngle = FRound(atan(fShearX) / F_PI18000);
    3082           0 :         aGeo.RecalcTan();
    3083             :     }
    3084             : 
    3085        1622 :     if(!basegfx::fTools::equalZero(fRotate))
    3086             :     {
    3087             :         // #i78696#
    3088             :         // fRotate is mathematically correct for linear transformations, so it's
    3089             :         // the one to use for the geometry change
    3090           4 :         aTransform.rotate(fRotate);
    3091             : 
    3092             :         // #i78696#
    3093             :         // fRotate is mathematically correct, but aGeoStat.nRotationAngle is
    3094             :         // mirrored -> mirror value here
    3095           4 :         aGeo.nRotationAngle = NormAngle360(FRound(-fRotate / F_PI18000));
    3096           4 :         aGeo.RecalcSinCos();
    3097             :     }
    3098             : 
    3099        1622 :     if(!aTranslate.equalZero())
    3100             :     {
    3101             :         // #i39529# absolute positioning, so get current position (without control points (!))
    3102         802 :         const basegfx::B2DRange aCurrentRange(basegfx::tools::getRange(aNewPolyPolygon));
    3103         802 :         aTransform.translate(aTranslate.getX() - aCurrentRange.getMinX(), aTranslate.getY() - aCurrentRange.getMinY());
    3104             :     }
    3105             : 
    3106             :     // transform polygon and trigger change
    3107        1622 :     aNewPolyPolygon.transform(aTransform);
    3108        3244 :     SetPathPoly(aNewPolyPolygon);
    3109        2057 : }
    3110             : 
    3111             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11