LCOV - code coverage report
Current view: top level - svx/source/svdraw - svdopath.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 328 1631 20.1 %
Date: 2014-04-11 Functions: 38 113 33.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10