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