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