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

Generated by: LCOV version 1.10