1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: svdopath.cxx,v $
10 * $Revision: 1.51.18.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #include <tools/bigint.hxx>
35 #include <svx/svdopath.hxx>
37 #include <svx/xpool.hxx>
38 #include <svx/xpoly.hxx>
39 #include <svx/svdattr.hxx>
40 #include <svx/svdtrans.hxx>
41 #include <svx/svdetc.hxx>
42 #include <svx/svddrag.hxx>
43 #include <svx/svdmodel.hxx>
44 #include <svx/svdpage.hxx>
45 #include <svx/svdhdl.hxx>
46 #include <svx/svdview.hxx> // fuer MovCreate bei Freihandlinien
47 #include "svdglob.hxx" // Stringcache
48 #include "svdstr.hrc" // Objektname
51 #pragma optimize ("",off)
52 #pragma warning(disable: 4748) // "... because optimizations are disabled ..."
55 #include <svx/xlnwtit.hxx>
56 #include <svx/xlnclit.hxx>
57 #include <svx/xflclit.hxx>
58 #include <svx/svdogrp.hxx>
60 #include <svx/polypolygoneditor.hxx>
61 #include <svx/xlntrit.hxx>
62 #include <vcl/salbtype.hxx> // FRound
63 #include "svdoimp.hxx"
64 #include <svx/sdr/contact/viewcontactofsdrpathobj.hxx>
65 #include <basegfx/matrix/b2dhommatrix.hxx>
67 // #104018# replace macros above with type-safe methods
68 inline sal_Int32
ImplTwipsToMM(sal_Int32 nVal
) { return ((nVal
* 127 + 36) / 72); }
69 inline sal_Int32
ImplMMToTwips(sal_Int32 nVal
) { return ((nVal
* 72 + 63) / 127); }
70 inline sal_Int64
ImplTwipsToMM(sal_Int64 nVal
) { return ((nVal
* 127 + 36) / 72); }
71 inline sal_Int64
ImplMMToTwips(sal_Int64 nVal
) { return ((nVal
* 72 + 63) / 127); }
72 inline double ImplTwipsToMM(double fVal
) { return (fVal
* (127.0 / 72.0)); }
73 inline double ImplMMToTwips(double fVal
) { return (fVal
* (72.0 / 127.0)); }
74 #include <basegfx/point/b2dpoint.hxx>
75 #include <basegfx/polygon/b2dpolypolygontools.hxx>
76 #include <basegfx/matrix/b2dhommatrix.hxx>
77 #include <basegfx/range/b2drange.hxx>
78 #include <basegfx/curve/b2dcubicbezier.hxx>
79 #include <basegfx/polygon/b2dpolygontools.hxx>
82 #include <svx/sdr/attribute/sdrtextattribute.hxx>
83 #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
87 inline USHORT
GetPrevPnt(USHORT nPnt
, USHORT nPntMax
, FASTBOOL bClosed
)
98 inline USHORT
GetNextPnt(USHORT nPnt
, USHORT nPntMax
, FASTBOOL bClosed
)
101 if (nPnt
>nPntMax
|| (bClosed
&& nPnt
>=nPntMax
)) nPnt
=0;
105 struct ImpSdrPathDragData
: public SdrDragStatUserData
107 XPolygon aXP
; // Ausschnitt aud dem Originalpolygon
108 FASTBOOL bValid
; // FALSE = zu wenig Punkte
109 FASTBOOL bClosed
; // geschlossenes Objekt?
110 USHORT nPoly
; // Nummer des Polygons im PolyPolygon
111 USHORT nPnt
; // Punktnummer innerhalb des obigen Polygons
112 USHORT nPntAnz
; // Punktanzahl des Polygons
113 USHORT nPntMax
; // Maximaler Index
114 FASTBOOL bBegPnt
; // Gedraggter Punkt ist der Anfangspunkt einer Polyline
115 FASTBOOL bEndPnt
; // Gedraggter Punkt ist der Endpunkt einer Polyline
116 USHORT nPrevPnt
; // Index des vorherigen Punkts
117 USHORT nNextPnt
; // Index des naechsten Punkts
118 FASTBOOL bPrevIsBegPnt
; // Vorheriger Punkt ist Anfangspunkt einer Polyline
119 FASTBOOL bNextIsEndPnt
; // Folgepunkt ist Endpunkt einer Polyline
120 USHORT nPrevPrevPnt
; // Index des vorvorherigen Punkts
121 USHORT nNextNextPnt
; // Index des uebernaechsten Punkts
122 FASTBOOL bControl
; // Punkt ist ein Kontrollpunkt
123 FASTBOOL bIsPrevControl
; // Punkt ist Kontrollpunkt vor einem Stuetzpunkt
124 FASTBOOL bIsNextControl
; // Punkt ist Kontrollpunkt hinter einem Stuetzpunkt
125 FASTBOOL bPrevIsControl
; // Falls nPnt ein StPnt: Davor ist ein Kontrollpunkt
126 FASTBOOL bNextIsControl
; // Falls nPnt ein StPnt: Dahinter ist ein Kontrollpunkt
127 USHORT nPrevPrevPnt0
;
131 USHORT nNextNextPnt0
;
132 FASTBOOL bEliminate
; // Punkt loeschen? (wird von MovDrag gesetzt)
135 BOOL mbMultiPointDrag
;
136 const XPolyPolygon maOrig
;
141 ImpSdrPathDragData(const SdrPathObj
& rPO
, const SdrHdl
& rHdl
, BOOL bMuPoDr
, const SdrDragStat
& rDrag
);
142 void ResetPoly(const SdrPathObj
& rPO
);
143 BOOL
IsMultiPointDrag() const { return mbMultiPointDrag
; }
146 ImpSdrPathDragData::ImpSdrPathDragData(const SdrPathObj
& rPO
, const SdrHdl
& rHdl
, BOOL bMuPoDr
, const SdrDragStat
& rDrag
)
148 mbMultiPointDrag(bMuPoDr
),
149 maOrig(rPO
.GetPathPoly()),
154 const SdrMarkView
& rMarkView
= *rDrag
.GetView();
155 const SdrHdlList
& rHdlList
= rMarkView
.GetHdlList();
156 const sal_uInt32 nHdlCount
= rHdlList
.GetHdlCount();
157 const SdrObject
* pInteractionObject(nHdlCount
&& rHdlList
.GetHdl(0) ? rHdlList
.GetHdl(0)->GetObj() : 0);
159 for(sal_uInt32
a(0); a
< nHdlCount
; a
++)
161 SdrHdl
* pTestHdl
= rHdlList
.GetHdl(a
);
163 if(pTestHdl
&& pTestHdl
->IsSelected() && pTestHdl
->GetObj() == pInteractionObject
)
165 maHandles
.Insert(pTestHdl
, CONTAINER_APPEND
);
175 bClosed
=rPO
.IsClosed(); // geschlossenes Objekt?
176 nPoly
=(sal_uInt16
)rHdl
.GetPolyNum(); // Nummer des Polygons im PolyPolygon
177 nPnt
=(sal_uInt16
)rHdl
.GetPointNum(); // Punktnummer innerhalb des obigen Polygons
178 const XPolygon
aTmpXP(rPO
.GetPathPoly().getB2DPolygon(nPoly
));
179 nPntAnz
=aTmpXP
.GetPointCount(); // Punktanzahl des Polygons
180 if (nPntAnz
==0 || (bClosed
&& nPntAnz
==1)) return; // min. 1Pt bei Line, min. 2 bei Polygon
181 nPntMax
=nPntAnz
-1; // Maximaler Index
182 bBegPnt
=!bClosed
&& nPnt
==0; // Gedraggter Punkt ist der Anfangspunkt einer Polyline
183 bEndPnt
=!bClosed
&& nPnt
==nPntMax
; // Gedraggter Punkt ist der Endpunkt einer Polyline
184 if (bClosed
&& nPntAnz
<=3) { // Falls Polygon auch nur eine Linie ist
185 bBegPnt
=(nPntAnz
<3) || nPnt
==0;
186 bEndPnt
=(nPntAnz
<3) || nPnt
==nPntMax
-1;
188 nPrevPnt
=nPnt
; // Index des vorherigen Punkts
189 nNextPnt
=nPnt
; // Index des naechsten Punkts
190 if (!bBegPnt
) nPrevPnt
=GetPrevPnt(nPnt
,nPntMax
,bClosed
);
191 if (!bEndPnt
) nNextPnt
=GetNextPnt(nPnt
,nPntMax
,bClosed
);
192 bPrevIsBegPnt
=bBegPnt
|| (!bClosed
&& nPrevPnt
==0);
193 bNextIsEndPnt
=bEndPnt
|| (!bClosed
&& nNextPnt
==nPntMax
);
194 nPrevPrevPnt
=nPnt
; // Index des vorvorherigen Punkts
195 nNextNextPnt
=nPnt
; // Index des uebernaechsten Punkts
196 if (!bPrevIsBegPnt
) nPrevPrevPnt
=GetPrevPnt(nPrevPnt
,nPntMax
,bClosed
);
197 if (!bNextIsEndPnt
) nNextNextPnt
=GetNextPnt(nNextPnt
,nPntMax
,bClosed
);
198 bControl
=rHdl
.IsPlusHdl(); // Punkt ist ein Kontrollpunkt
199 bIsPrevControl
=FALSE
; // Punkt ist Kontrollpunkt vor einem Stuetzpunkt
200 bIsNextControl
=FALSE
; // Punkt ist Kontrollpunkt hinter einem Stuetzpunkt
201 bPrevIsControl
=FALSE
; // Falls nPnt ein StPnt: Davor ist ein Kontrollpunkt
202 bNextIsControl
=FALSE
; // Falls nPnt ein StPnt: Dahinter ist ein Kontrollpunkt
204 bIsPrevControl
=aTmpXP
.IsControl(nPrevPnt
);
205 bIsNextControl
=!bIsPrevControl
;
207 bPrevIsControl
=!bBegPnt
&& !bPrevIsBegPnt
&& aTmpXP
.GetFlags(nPrevPnt
)==XPOLY_CONTROL
;
208 bNextIsControl
=!bEndPnt
&& !bNextIsEndPnt
&& aTmpXP
.GetFlags(nNextPnt
)==XPOLY_CONTROL
;
210 nPrevPrevPnt0
=nPrevPrevPnt
;
214 nNextNextPnt0
=nNextNextPnt
;
226 void ImpSdrPathDragData::ResetPoly(const SdrPathObj
& rPO
)
228 const XPolygon
aTmpXP(rPO
.GetPathPoly().getB2DPolygon(nPoly
));
229 aXP
[0]=aTmpXP
[nPrevPrevPnt0
]; aXP
.SetFlags(0,aTmpXP
.GetFlags(nPrevPrevPnt0
));
230 aXP
[1]=aTmpXP
[nPrevPnt0
]; aXP
.SetFlags(1,aTmpXP
.GetFlags(nPrevPnt0
));
231 aXP
[2]=aTmpXP
[nPnt0
]; aXP
.SetFlags(2,aTmpXP
.GetFlags(nPnt0
));
232 aXP
[3]=aTmpXP
[nNextPnt0
]; aXP
.SetFlags(3,aTmpXP
.GetFlags(nNextPnt0
));
233 aXP
[4]=aTmpXP
[nNextNextPnt0
]; aXP
.SetFlags(4,aTmpXP
.GetFlags(nNextNextPnt0
));
236 /*************************************************************************/
238 struct ImpPathCreateUser
: public SdrDragStatUserData
257 FASTBOOL bBezHasCtrl0
;
264 FASTBOOL bMixedCreate
;
265 USHORT nBezierStartPoint
;
266 SdrObjKind eStartKind
;
270 ImpPathCreateUser(): nCircRadius(0),nCircStWink(0),nCircRelWink(0),
271 bBezier(FALSE
),bBezHasCtrl0(FALSE
),bCurve(FALSE
),bCircle(FALSE
),bAngleSnap(FALSE
),bLine(FALSE
),bLine90(FALSE
),bRect(FALSE
),
272 bMixedCreate(FALSE
),nBezierStartPoint(0),eStartKind(OBJ_NONE
),eAktKind(OBJ_NONE
) { }
274 void ResetFormFlags() { bBezier
=FALSE
; bCurve
=FALSE
; bCircle
=FALSE
; bLine
=FALSE
; bRect
=FALSE
; }
275 FASTBOOL
IsFormFlag() const { return bBezier
|| bCurve
|| bCircle
|| bLine
|| bRect
; }
276 XPolygon
GetFormPoly() const;
277 FASTBOOL
CalcBezier(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, FASTBOOL bMouseDown
);
278 XPolygon
GetBezierPoly() const;
279 //FASTBOOL CalcCurve(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView) { return FALSE; }
280 XPolygon
GetCurvePoly() const { return XPolygon(); }
281 FASTBOOL
CalcCircle(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
);
282 XPolygon
GetCirclePoly() const;
283 FASTBOOL
CalcLine(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
);
284 Point
CalcLine(const Point
& rCsr
, long nDirX
, long nDirY
, SdrView
* pView
) const;
285 XPolygon
GetLinePoly() const;
286 FASTBOOL
CalcRect(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
);
287 XPolygon
GetRectPoly() const;
290 XPolygon
ImpPathCreateUser::GetFormPoly() const
292 if (bBezier
) return GetBezierPoly();
293 if (bCurve
) return GetCurvePoly();
294 if (bCircle
) return GetCirclePoly();
295 if (bLine
) return GetLinePoly();
296 if (bRect
) return GetRectPoly();
300 FASTBOOL
ImpPathCreateUser::CalcBezier(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, FASTBOOL bMouseDown
)
308 // Also copy the end point when no end point is set yet
309 if (!bMouseDown
|| (0L == aBezEnd
.X() && 0L == aBezEnd
.Y())) aBezEnd
=rP2
;
315 XPolygon
ImpPathCreateUser::GetBezierPoly() const
318 aXP
[0]=aBezStart
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
319 aXP
[1]=aBezCtrl1
; aXP
.SetFlags(1,XPOLY_CONTROL
);
320 aXP
[2]=aBezCtrl2
; aXP
.SetFlags(2,XPOLY_CONTROL
);
325 FASTBOOL
ImpPathCreateUser::CalcCircle(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
)
327 long nTangAngle
=GetAngle(rDir
);
331 long dx
=rP2
.X()-rP1
.X();
332 long dy
=rP2
.Y()-rP1
.Y();
333 long dAngle
=GetAngle(Point(dx
,dy
))-nTangAngle
;
334 dAngle
=NormAngle360(dAngle
);
335 long nTmpAngle
=NormAngle360(9000-dAngle
);
336 FASTBOOL bRet
=nTmpAngle
!=9000 && nTmpAngle
!=27000;
339 double cs
=cos(nTmpAngle
*nPi180
);
340 double nR
=(double)GetLen(Point(dx
,dy
))/cs
/2;
344 nCircStWink
=NormAngle360(nTangAngle
-9000);
345 nCircRelWink
=NormAngle360(2*dAngle
);
346 aCircCenter
.X()+=Round(nRad
*cos((nTangAngle
+9000)*nPi180
));
347 aCircCenter
.Y()-=Round(nRad
*sin((nTangAngle
+9000)*nPi180
));
349 nCircStWink
=NormAngle360(nTangAngle
+9000);
350 nCircRelWink
=-NormAngle360(36000-2*dAngle
);
351 aCircCenter
.X()+=Round(nRad
*cos((nTangAngle
-9000)*nPi180
));
352 aCircCenter
.Y()-=Round(nRad
*sin((nTangAngle
-9000)*nPi180
));
354 bAngleSnap
=pView
!=NULL
&& pView
->IsAngleSnapEnabled();
356 long nSA
=pView
->GetSnapAngle();
357 if (nSA
!=0) { // Winkelfang
358 FASTBOOL bNeg
=nCircRelWink
<0;
359 if (bNeg
) nCircRelWink
=-nCircRelWink
;
363 nCircRelWink
=NormAngle360(nCircRelWink
);
364 if (bNeg
) nCircRelWink
=-nCircRelWink
;
368 if (nRad
==0 || Abs(nCircRelWink
)<5) bRet
=FALSE
;
373 XPolygon
ImpPathCreateUser::GetCirclePoly() const
375 if (nCircRelWink
>=0) {
376 XPolygon
aXP(aCircCenter
,nCircRadius
,nCircRadius
,
377 USHORT((nCircStWink
+5)/10),USHORT((nCircStWink
+nCircRelWink
+5)/10),FALSE
);
378 aXP
[0]=aCircStart
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
379 if (!bAngleSnap
) aXP
[aXP
.GetPointCount()-1]=aCircEnd
;
382 XPolygon
aXP(aCircCenter
,nCircRadius
,nCircRadius
,
383 USHORT(NormAngle360(nCircStWink
+nCircRelWink
+5)/10),USHORT((nCircStWink
+5)/10),FALSE
);
384 USHORT nAnz
=aXP
.GetPointCount();
385 for (USHORT nNum
=nAnz
/2; nNum
>0;) {
386 nNum
--; // XPoly Punktreihenfolge umkehren
387 USHORT n2
=nAnz
-nNum
-1;
388 Point
aPt(aXP
[nNum
]);
392 aXP
[0]=aCircStart
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
393 if (!bAngleSnap
) aXP
[aXP
.GetPointCount()-1]=aCircEnd
;
398 Point
ImpPathCreateUser::CalcLine(const Point
& aCsr
, long nDirX
, long nDirY
, SdrView
* pView
) const
400 long x
=aCsr
.X(),x1
=x
,x2
=x
;
401 long y
=aCsr
.Y(),y1
=y
,y2
=y
;
402 FASTBOOL bHLin
=nDirY
==0;
403 FASTBOOL bVLin
=nDirX
==0;
407 x1
=BigMulDiv(y
,nDirX
,nDirY
);
408 y2
=BigMulDiv(x
,nDirY
,nDirX
);
409 long l1
=Abs(x1
)+Abs(y1
);
410 long l2
=Abs(x2
)+Abs(y2
);
411 if (l1
<=l2
!=(pView
!=NULL
&& pView
->IsBigOrtho())) {
420 FASTBOOL
ImpPathCreateUser::CalcLine(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
)
425 if (rP1
==rP2
|| (rDir
.X()==0 && rDir
.Y()==0)) { bLine
=FALSE
; return FALSE
; }
426 Point
aTmpPt(rP2
-rP1
);
429 Point
aP1(CalcLine(aTmpPt
, nDirX
, nDirY
,pView
)); aP1
-=aTmpPt
; long nQ1
=Abs(aP1
.X())+Abs(aP1
.Y());
430 Point
aP2(CalcLine(aTmpPt
, nDirY
,-nDirX
,pView
)); aP2
-=aTmpPt
; long nQ2
=Abs(aP2
.X())+Abs(aP2
.Y());
431 if (pView
!=NULL
&& pView
->IsOrtho()) nQ1
=0; // Ortho schaltet rechtwinklig aus
433 if (!bLine90
) { // glatter Uebergang
435 } else { // rechtwinkliger Uebergang
442 XPolygon
ImpPathCreateUser::GetLinePoly() const
445 aXP
[0]=aLineStart
; if (!bLine90
) aXP
.SetFlags(0,XPOLY_SMOOTH
);
450 FASTBOOL
ImpPathCreateUser::CalcRect(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
)
455 if (rP1
==rP2
|| (rDir
.X()==0 && rDir
.Y()==0)) { bRect
=FALSE
; return FALSE
; }
456 Point
aTmpPt(rP2
-rP1
);
461 FASTBOOL bHLin
=nDirY
==0;
462 FASTBOOL bVLin
=nDirX
==0;
466 y
=BigMulDiv(x
,nDirY
,nDirX
);
467 long nHypLen
=aTmpPt
.Y()-y
;
468 long nTangAngle
=-GetAngle(rDir
);
470 double a
=nTangAngle
*nPi180
;
473 double nGKathLen
=nHypLen
*sn
;
474 y
+=Round(nGKathLen
*sn
);
475 x
+=Round(nGKathLen
*cs
);
479 if (pView
!=NULL
&& pView
->IsOrtho()) {
480 long dx1
=aRectP2
.X()-aRectP1
.X(); long dx1a
=Abs(dx1
);
481 long dy1
=aRectP2
.Y()-aRectP1
.Y(); long dy1a
=Abs(dy1
);
482 long dx2
=aRectP3
.X()-aRectP2
.X(); long dx2a
=Abs(dx2
);
483 long dy2
=aRectP3
.Y()-aRectP2
.Y(); long dy2a
=Abs(dy2
);
484 FASTBOOL b1MoreThan2
=dx1a
+dy1a
>dx2a
+dy2a
;
485 if (b1MoreThan2
!= pView
->IsBigOrtho()) {
486 long xtemp
=dy2a
-dx1a
; if (dx1
<0) xtemp
=-xtemp
;
487 long ytemp
=dx2a
-dy1a
; if (dy1
<0) ytemp
=-ytemp
;
493 long xtemp
=dy1a
-dx2a
; if (dx2
<0) xtemp
=-xtemp
;
494 long ytemp
=dx1a
-dy2a
; if (dy2
<0) ytemp
=-ytemp
;
503 XPolygon
ImpPathCreateUser::GetRectPoly() const
506 aXP
[0]=aRectP1
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
508 if (aRectP3
!=aRectP2
) aXP
[2]=aRectP3
;
512 /*************************************************************************/
514 class ImpPathForDragAndCreate
516 SdrPathObj
& mrSdrPathObject
;
517 XPolyPolygon aPathPolygon
;
518 SdrObjKind meObjectKind
;
519 ImpSdrPathDragData
* mpSdrPathDragData
;
523 ImpPathForDragAndCreate(SdrPathObj
& rSdrPathObject
);
524 ~ImpPathForDragAndCreate();
527 bool beginPathDrag( SdrDragStat
& rDrag
) const;
528 bool movePathDrag( SdrDragStat
& rDrag
) const;
529 bool endPathDrag( SdrDragStat
& rDrag
);
530 //void cancelSpecialDrag( SdrDragStat& rDrag ) const;
531 String
getSpecialDragComment(const SdrDragStat
& rDrag
) const;
532 basegfx::B2DPolyPolygon
getSpecialDragPoly(const SdrDragStat
& rDrag
) const;
535 FASTBOOL
BegCreate(SdrDragStat
& rStat
);
536 FASTBOOL
MovCreate(SdrDragStat
& rStat
);
537 FASTBOOL
EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
);
538 FASTBOOL
BckCreate(SdrDragStat
& rStat
);
539 void BrkCreate(SdrDragStat
& rStat
);
540 Pointer
GetCreatePointer() const;
543 bool IsClosed(SdrObjKind eKind
) const { return eKind
==OBJ_POLY
|| eKind
==OBJ_PATHPOLY
|| eKind
==OBJ_PATHFILL
|| eKind
==OBJ_FREEFILL
|| eKind
==OBJ_SPLNFILL
; }
544 bool IsFreeHand(SdrObjKind eKind
) const { return eKind
==OBJ_FREELINE
|| eKind
==OBJ_FREEFILL
; }
545 bool IsBezier(SdrObjKind eKind
) const { return eKind
==OBJ_PATHLINE
|| eKind
==OBJ_PATHFILL
; }
546 bool IsCreating() const { return mbCreating
; }
549 basegfx::B2DPolyPolygon
TakeObjectPolyPolygon(const SdrDragStat
& rDrag
) const;
550 basegfx::B2DPolyPolygon
TakeDragPolyPolygon(const SdrDragStat
& rDrag
) const;
551 basegfx::B2DPolyPolygon
getModifiedPolyPolygon() const { return aPathPolygon
.getB2DPolyPolygon(); }
554 ImpPathForDragAndCreate::ImpPathForDragAndCreate(SdrPathObj
& rSdrPathObject
)
555 : mrSdrPathObject(rSdrPathObject
),
556 aPathPolygon(rSdrPathObject
.GetPathPoly()),
557 meObjectKind(mrSdrPathObject
.meKind
),
558 mpSdrPathDragData(0),
563 ImpPathForDragAndCreate::~ImpPathForDragAndCreate()
565 if(mpSdrPathDragData
)
567 delete mpSdrPathDragData
;
571 bool ImpPathForDragAndCreate::beginPathDrag( SdrDragStat
& rDrag
) const
573 const SdrHdl
* pHdl
=rDrag
.GetHdl();
577 BOOL
bMultiPointDrag(TRUE
);
579 if(aPathPolygon
[(sal_uInt16
)pHdl
->GetPolyNum()].IsControl((sal_uInt16
)pHdl
->GetPointNum()))
580 bMultiPointDrag
= FALSE
;
584 const SdrMarkView
& rMarkView
= *rDrag
.GetView();
585 const SdrHdlList
& rHdlList
= rMarkView
.GetHdlList();
586 const sal_uInt32 nHdlCount
= rHdlList
.GetHdlCount();
587 const SdrObject
* pInteractionObject(nHdlCount
&& rHdlList
.GetHdl(0) ? rHdlList
.GetHdl(0)->GetObj() : 0);
588 sal_uInt32
nSelectedPoints(0);
590 for(sal_uInt32
a(0); a
< nHdlCount
; a
++)
592 SdrHdl
* pTestHdl
= rHdlList
.GetHdl(a
);
594 if(pTestHdl
&& pTestHdl
->IsSelected() && pTestHdl
->GetObj() == pInteractionObject
)
600 if(nSelectedPoints
<= 1)
601 bMultiPointDrag
= FALSE
;
604 ((ImpPathForDragAndCreate
*)this)->mpSdrPathDragData
= new ImpSdrPathDragData(mrSdrPathObject
,*pHdl
,bMultiPointDrag
,rDrag
);
606 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
608 DBG_ERROR("ImpPathForDragAndCreate::BegDrag(): ImpSdrPathDragData ist ungueltig");
609 delete mpSdrPathDragData
;
610 ((ImpPathForDragAndCreate
*)this)->mpSdrPathDragData
= 0;
617 bool ImpPathForDragAndCreate::movePathDrag( SdrDragStat
& rDrag
) const
619 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
621 DBG_ERROR("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData ist ungueltig");
625 if(mpSdrPathDragData
->IsMultiPointDrag())
627 Point
aDelta(rDrag
.GetNow() - rDrag
.GetStart());
629 if(aDelta
.X() || aDelta
.Y())
631 for(sal_uInt32
a(0); a
< mpSdrPathDragData
->maHandles
.Count(); a
++)
633 SdrHdl
* pHandle
= (SdrHdl
*)mpSdrPathDragData
->maHandles
.GetObject(a
);
634 const sal_uInt16
nPolyIndex((sal_uInt16
)pHandle
->GetPolyNum());
635 const sal_uInt16
nPointIndex((sal_uInt16
)pHandle
->GetPointNum());
636 const XPolygon
& rOrig
= mpSdrPathDragData
->maOrig
[nPolyIndex
];
637 XPolygon
& rMove
= mpSdrPathDragData
->maMove
[nPolyIndex
];
638 const sal_uInt16
nPointCount(rOrig
.GetPointCount());
639 BOOL
bClosed(rOrig
[0] == rOrig
[nPointCount
-1]);
642 rMove
[nPointIndex
] = rOrig
[nPointIndex
] + aDelta
;
644 // when point is first and poly closed, move close point, too.
645 if(nPointCount
> 0 && !nPointIndex
&& bClosed
)
647 rMove
[nPointCount
- 1] = rOrig
[nPointCount
- 1] + aDelta
;
649 // when moving the last point it may be necessary to move the
650 // control point in front of this one, too.
651 if(nPointCount
> 1 && rOrig
.IsControl(nPointCount
- 2))
652 rMove
[nPointCount
- 2] = rOrig
[nPointCount
- 2] + aDelta
;
655 // is a control point before this?
656 if(nPointIndex
> 0 && rOrig
.IsControl(nPointIndex
- 1))
659 rMove
[nPointIndex
- 1] = rOrig
[nPointIndex
- 1] + aDelta
;
662 // is a control point after this?
663 if(nPointIndex
+ 1 < nPointCount
&& rOrig
.IsControl(nPointIndex
+ 1))
666 rMove
[nPointIndex
+ 1] = rOrig
[nPointIndex
+ 1] + aDelta
;
673 mpSdrPathDragData
->ResetPoly(mrSdrPathObject
);
675 // Div. Daten lokal Kopieren fuer weniger Code und schnelleren Zugriff
676 FASTBOOL bClosed
=mpSdrPathDragData
->bClosed
; // geschlossenes Objekt?
677 USHORT nPnt
=mpSdrPathDragData
->nPnt
; // Punktnummer innerhalb des obigen Polygons
678 FASTBOOL bBegPnt
=mpSdrPathDragData
->bBegPnt
; // Gedraggter Punkt ist der Anfangspunkt einer Polyline
679 FASTBOOL bEndPnt
=mpSdrPathDragData
->bEndPnt
; // Gedraggter Punkt ist der Endpunkt einer Polyline
680 USHORT nPrevPnt
=mpSdrPathDragData
->nPrevPnt
; // Index des vorherigen Punkts
681 USHORT nNextPnt
=mpSdrPathDragData
->nNextPnt
; // Index des naechsten Punkts
682 FASTBOOL bPrevIsBegPnt
=mpSdrPathDragData
->bPrevIsBegPnt
; // Vorheriger Punkt ist Anfangspunkt einer Polyline
683 FASTBOOL bNextIsEndPnt
=mpSdrPathDragData
->bNextIsEndPnt
; // Folgepunkt ist Endpunkt einer Polyline
684 USHORT nPrevPrevPnt
=mpSdrPathDragData
->nPrevPrevPnt
; // Index des vorvorherigen Punkts
685 USHORT nNextNextPnt
=mpSdrPathDragData
->nNextNextPnt
; // Index des uebernaechsten Punkts
686 FASTBOOL bControl
=mpSdrPathDragData
->bControl
; // Punkt ist ein Kontrollpunkt
687 //FASTBOOL bIsPrevControl=mpSdrPathDragData->bIsPrevControl; // Punkt ist Kontrollpunkt vor einem Stuetzpunkt
688 FASTBOOL bIsNextControl
=mpSdrPathDragData
->bIsNextControl
; // Punkt ist Kontrollpunkt hinter einem Stuetzpunkt
689 FASTBOOL bPrevIsControl
=mpSdrPathDragData
->bPrevIsControl
; // Falls nPnt ein StPnt: Davor ist ein Kontrollpunkt
690 FASTBOOL bNextIsControl
=mpSdrPathDragData
->bNextIsControl
; // Falls nPnt ein StPnt: Dahinter ist ein Kontrollpunkt
692 // Ortho bei Linien/Polygonen = Winkel beibehalten
693 if (!bControl
&& rDrag
.GetView()!=NULL
&& rDrag
.GetView()->IsOrtho()) {
694 FASTBOOL bBigOrtho
=rDrag
.GetView()->IsBigOrtho();
695 Point
aPos(rDrag
.GetNow()); // die aktuelle Position
696 Point
aPnt(mpSdrPathDragData
->aXP
[nPnt
]); // der gedraggte Punkt
697 USHORT nPnt1
=0xFFFF,nPnt2
=0xFFFF; // seine Nachbarpunkte
698 Point aNeuPos1
,aNeuPos2
; // die neuen Alternativen fuer aPos
699 FASTBOOL bPnt1
=FALSE
,bPnt2
=FALSE
; // die neuen Alternativen gueltig?
700 if (!bClosed
&& mpSdrPathDragData
->nPntAnz
>=2) { // Mind. 2 Pt bei Linien
701 if (!bBegPnt
) nPnt1
=nPrevPnt
;
702 if (!bEndPnt
) nPnt2
=nNextPnt
;
704 if (bClosed
&& mpSdrPathDragData
->nPntAnz
>=3) { // Mind. 3 Pt bei Polygon
708 if (nPnt1
!=0xFFFF && !bPrevIsControl
) {
709 Point aPnt1
=mpSdrPathDragData
->aXP
[nPnt1
];
710 long ndx0
=aPnt
.X()-aPnt1
.X();
711 long ndy0
=aPnt
.Y()-aPnt1
.Y();
712 FASTBOOL bHLin
=ndy0
==0;
713 FASTBOOL bVLin
=ndx0
==0;
714 if (!bHLin
|| !bVLin
) {
715 long ndx
=aPos
.X()-aPnt1
.X();
716 long ndy
=aPos
.Y()-aPnt1
.Y();
718 double nXFact
=0; if (!bVLin
) nXFact
=(double)ndx
/(double)ndx0
;
719 double nYFact
=0; if (!bHLin
) nYFact
=(double)ndy
/(double)ndy0
;
720 FASTBOOL bHor
=bHLin
|| (!bVLin
&& (nXFact
>nYFact
) ==bBigOrtho
);
721 FASTBOOL bVer
=bVLin
|| (!bHLin
&& (nXFact
<=nYFact
)==bBigOrtho
);
722 if (bHor
) ndy
=long(ndy0
*nXFact
);
723 if (bVer
) ndx
=long(ndx0
*nYFact
);
729 if (nPnt2
!=0xFFFF && !bNextIsControl
) {
730 Point aPnt2
=mpSdrPathDragData
->aXP
[nPnt2
];
731 long ndx0
=aPnt
.X()-aPnt2
.X();
732 long ndy0
=aPnt
.Y()-aPnt2
.Y();
733 FASTBOOL bHLin
=ndy0
==0;
734 FASTBOOL bVLin
=ndx0
==0;
735 if (!bHLin
|| !bVLin
) {
736 long ndx
=aPos
.X()-aPnt2
.X();
737 long ndy
=aPos
.Y()-aPnt2
.Y();
739 double nXFact
=0; if (!bVLin
) nXFact
=(double)ndx
/(double)ndx0
;
740 double nYFact
=0; if (!bHLin
) nYFact
=(double)ndy
/(double)ndy0
;
741 FASTBOOL bHor
=bHLin
|| (!bVLin
&& (nXFact
>nYFact
) ==bBigOrtho
);
742 FASTBOOL bVer
=bVLin
|| (!bHLin
&& (nXFact
<=nYFact
)==bBigOrtho
);
743 if (bHor
) ndy
=long(ndy0
*nXFact
);
744 if (bVer
) ndx
=long(ndx0
*nYFact
);
750 if (bPnt1
&& bPnt2
) { // beide Alternativen vorhanden (Konkurenz)
751 BigInt
nX1(aNeuPos1
.X()-aPos
.X()); nX1
*=nX1
;
752 BigInt
nY1(aNeuPos1
.Y()-aPos
.Y()); nY1
*=nY1
;
753 BigInt
nX2(aNeuPos2
.X()-aPos
.X()); nX2
*=nX2
;
754 BigInt
nY2(aNeuPos2
.Y()-aPos
.Y()); nY2
*=nY2
;
755 nX1
+=nY1
; // Korrekturabstand zum Quadrat
756 nX2
+=nY2
; // Korrekturabstand zum Quadrat
757 // Die Alternative mit dem geringeren Korrekturbedarf gewinnt
758 if (nX1
<nX2
) bPnt2
=FALSE
; else bPnt1
=FALSE
;
760 if (bPnt1
) rDrag
.Now()=aNeuPos1
;
761 if (bPnt2
) rDrag
.Now()=aNeuPos2
;
763 rDrag
.SetActionRect(Rectangle(rDrag
.GetNow(),rDrag
.GetNow()));
765 // IBM Special: Punkte eliminieren, wenn die beiden angrenzenden
766 // Linien eh' fast 180 deg sind.
767 if (!bControl
&& rDrag
.GetView()!=NULL
&& rDrag
.GetView()->IsEliminatePolyPoints() &&
768 !bBegPnt
&& !bEndPnt
&& !bPrevIsControl
&& !bNextIsControl
)
770 Point
aPt(mpSdrPathDragData
->aXP
[nNextPnt
]);
772 long nWink1
=GetAngle(aPt
);
774 aPt
-=mpSdrPathDragData
->aXP
[nPrevPnt
];
775 long nWink2
=GetAngle(aPt
);
776 long nDiff
=nWink1
-nWink2
;
778 mpSdrPathDragData
->bEliminate
=nDiff
<=rDrag
.GetView()->GetEliminatePolyPointLimitAngle();
779 if (mpSdrPathDragData
->bEliminate
) { // Position anpassen, damit Smooth an den Enden stimmt
780 aPt
=mpSdrPathDragData
->aXP
[nNextPnt
];
781 aPt
+=mpSdrPathDragData
->aXP
[nPrevPnt
];
787 // Um diese Entfernung wurde insgesamt gedraggd
788 Point
aDiff(rDrag
.GetNow()); aDiff
-=mpSdrPathDragData
->aXP
[nPnt
];
790 // Insgesamt sind 8 Faelle moeglich:
791 // X 1. Weder rechts noch links Ctrl.
792 // o--X--o 2. Rechts und links Ctrl, gedraggd wird St.
793 // o--X 3. Nur links Ctrl, gedraggd wird St.
794 // X--o 4. Nur rechts Ctrl, gedraggd wird St.
795 // x--O--o 5. Rechts und links Ctrl, gedraggd wird links.
796 // x--O 6. Nur links Ctrl, gedraggd wird links.
797 // o--O--x 7. Rechts und links Ctrl, gedraggd wird rechts.
798 // O--x 8. Nur rechts Ctrl, gedraggd wird rechts.
799 // Zusaetzlich ist zu beachten, dass das Veraendern einer Linie (keine Kurve)
800 // eine evtl. Kurve am anderen Ende der Linie bewirkt, falls dort Smooth
801 // gesetzt ist (Kontrollpunktausrichtung an Gerade).
803 mpSdrPathDragData
->aXP
[nPnt
]+=aDiff
;
805 // Nun symmetrische PlusHandles etc. checken
806 if (bControl
) { // Faelle 5,6,7,8
807 USHORT nSt
=nPnt
; // der zugehoerige Stuetzpunkt
808 USHORT nFix
=nPnt
; // der gegenueberliegende Kontrollpunkt
809 if (bIsNextControl
) { // Wenn der naechste ein Kontrollpunkt ist, muss der vorh. der Stuetzpunkt sein
816 if (mpSdrPathDragData
->aXP
.IsSmooth(nSt
)) {
817 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nSt
,nPnt
,nFix
);
821 if (!bControl
) { // Faelle 1,2,3,4 wobei bei 1 nix passiert und bei 3+4 unten noch mehr folgt
822 // die beiden Kontrollpunkte mit verschieben
823 if (bPrevIsControl
) mpSdrPathDragData
->aXP
[nPrevPnt
]+=aDiff
;
824 if (bNextIsControl
) mpSdrPathDragData
->aXP
[nNextPnt
]+=aDiff
;
825 // Kontrollpunkt ggf. an Gerade ausrichten
826 if (mpSdrPathDragData
->aXP
.IsSmooth(nPnt
)) {
827 if (bPrevIsControl
&& !bNextIsControl
&& !bEndPnt
) { // Fall 3
828 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nPnt
,nNextPnt
,nPrevPnt
);
830 if (bNextIsControl
&& !bPrevIsControl
&& !bBegPnt
) { // Fall 4
831 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nPnt
,nPrevPnt
,nNextPnt
);
834 // Und nun noch die anderen Enden der Strecken ueberpruefen (nPnt+-1).
835 // Ist dort eine Kurve (IsControl(nPnt+-2)) mit SmoothJoin (nPnt+-1),
836 // so muss der entsprechende Kontrollpunkt (nPnt+-2) angepasst werden.
837 if (!bBegPnt
&& !bPrevIsControl
&& !bPrevIsBegPnt
&& mpSdrPathDragData
->aXP
.IsSmooth(nPrevPnt
)) {
838 if (mpSdrPathDragData
->aXP
.IsControl(nPrevPrevPnt
)) {
839 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nPrevPnt
,nPnt
,nPrevPrevPnt
);
842 if (!bEndPnt
&& !bNextIsControl
&& !bNextIsEndPnt
&& mpSdrPathDragData
->aXP
.IsSmooth(nNextPnt
)) {
843 if (mpSdrPathDragData
->aXP
.IsControl(nNextNextPnt
)) {
844 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nNextPnt
,nPnt
,nNextNextPnt
);
853 bool ImpPathForDragAndCreate::endPathDrag(SdrDragStat
& rDrag
)
857 bool bLineGlueMirror(OBJ_LINE
== meObjectKind
);
858 if (bLineGlueMirror
) { // #40549#
859 XPolygon
& rXP
=aPathPolygon
[0];
864 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
866 DBG_ERROR("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData ist ungueltig");
870 if(mpSdrPathDragData
->IsMultiPointDrag())
872 aPathPolygon
= mpSdrPathDragData
->maMove
;
876 const SdrHdl
* pHdl
=rDrag
.GetHdl();
878 // Referenz auf das Polygon
879 XPolygon
& rXP
=aPathPolygon
[(sal_uInt16
)pHdl
->GetPolyNum()];
881 // Die 5 Punkte die sich evtl. geaendert haben
882 if (!mpSdrPathDragData
->bPrevIsBegPnt
) rXP
[mpSdrPathDragData
->nPrevPrevPnt0
]=mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nPrevPrevPnt
];
883 if (!mpSdrPathDragData
->bNextIsEndPnt
) rXP
[mpSdrPathDragData
->nNextNextPnt0
]=mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nNextNextPnt
];
884 if (!mpSdrPathDragData
->bBegPnt
) rXP
[mpSdrPathDragData
->nPrevPnt0
] =mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nPrevPnt
];
885 if (!mpSdrPathDragData
->bEndPnt
) rXP
[mpSdrPathDragData
->nNextPnt0
] =mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nNextPnt
];
886 rXP
[mpSdrPathDragData
->nPnt0
] =mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nPnt
];
888 // Letzter Punkt muss beim Geschlossenen immer gleich dem Ersten sein
889 if (mpSdrPathDragData
->bClosed
) rXP
[rXP
.GetPointCount()-1]=rXP
[0];
891 if (mpSdrPathDragData
->bEliminate
)
893 basegfx::B2DPolyPolygon
aTempPolyPolygon(aPathPolygon
.getB2DPolyPolygon());
894 sal_uInt32 nPoly
,nPnt
;
896 if(PolyPolygonEditor::GetRelativePolyPoint(aTempPolyPolygon
, rDrag
.GetHdl()->GetSourceHdlNum(), nPoly
, nPnt
))
898 basegfx::B2DPolygon
aCandidate(aTempPolyPolygon
.getB2DPolygon(nPoly
));
899 aCandidate
.remove(nPnt
);
901 if((IsClosed(meObjectKind
) && aCandidate
.count() < 3L) || aCandidate
.count() < 2L)
903 aTempPolyPolygon
.remove(nPoly
);
907 aTempPolyPolygon
.setB2DPolygon(nPoly
, aCandidate
);
911 aPathPolygon
= XPolyPolygon(aTempPolyPolygon
);
914 // Winkel anpassen fuer Text an einfacher Linie
917 Point
aLinePt1_(aPathPolygon
[0][0]);
918 Point
aLinePt2_(aPathPolygon
[0][1]);
919 FASTBOOL bXMirr
=(aLinePt1_
.X()>aLinePt2_
.X())!=(aLinePt1
.X()>aLinePt2
.X());
920 FASTBOOL bYMirr
=(aLinePt1_
.Y()>aLinePt2_
.Y())!=(aLinePt1
.Y()>aLinePt2
.Y());
921 if (bXMirr
|| bYMirr
) {
922 Point
aRef1(mrSdrPathObject
.GetSnapRect().Center());
926 mrSdrPathObject
.NbcMirrorGluePoints(aRef1
,aRef2
);
931 mrSdrPathObject
.NbcMirrorGluePoints(aRef1
,aRef2
);
937 delete mpSdrPathDragData
;
938 mpSdrPathDragData
= 0;
943 /*void ImpPathForDragAndCreate::cancelSpecialDrag( SdrDragStat& rDrag ) const
945 ImpSdrPathDragData* pID=(ImpSdrPathDragData*)rDrag.GetUser();
952 String
ImpPathForDragAndCreate::getSpecialDragComment(const SdrDragStat
& rDrag
) const
955 const SdrHdl
* pHdl
= rDrag
.GetHdl();
956 const bool bCreateComment(rDrag
.GetView() && &mrSdrPathObject
== rDrag
.GetView()->GetCreateObj());
958 if(bCreateComment
&& rDrag
.GetUser())
960 // #i103058# re-add old creation comment mode
961 ImpPathCreateUser
* pU
= (ImpPathCreateUser
*)rDrag
.GetUser();
962 const SdrObjKind
eKindMerk(meObjectKind
);
963 mrSdrPathObject
.meKind
= pU
->eAktKind
;
964 mrSdrPathObject
.ImpTakeDescriptionStr(STR_ViewCreateObj
, aStr
);
965 mrSdrPathObject
.meKind
= eKindMerk
;
967 Point
aPrev(rDrag
.GetPrev());
968 Point
aNow(rDrag
.GetNow());
974 aStr
.AppendAscii(" (");
980 mrSdrPathObject
.GetModel()->TakeWinkStr(Abs(pU
->nCircRelWink
), aMetr
);
982 aStr
.AppendAscii(" r=");
983 mrSdrPathObject
.GetModel()->TakeMetricStr(pU
->nCircRadius
, aMetr
, TRUE
);
987 aStr
.AppendAscii("dx=");
988 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.X(), aMetr
, TRUE
);
991 aStr
.AppendAscii(" dy=");
992 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.Y(), aMetr
, TRUE
);
995 if(!IsFreeHand(meObjectKind
))
997 INT32
nLen(GetLen(aNow
));
998 aStr
.AppendAscii(" l=");
999 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, TRUE
);
1002 INT32
nWink(GetAngle(aNow
));
1003 aStr
+= sal_Unicode(' ');
1004 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
1008 aStr
+= sal_Unicode(')');
1010 else if(!mrSdrPathObject
.GetModel() || !pHdl
)
1012 // #i103058# fallback when no model and/or Handle, both needed
1014 mrSdrPathObject
.ImpTakeDescriptionStr(STR_DragPathObj
, aStr
);
1018 // #i103058# standard for modification; model and handle needed
1019 ImpSdrPathDragData
* pDragData
= mpSdrPathDragData
;
1023 // getSpecialDragComment is also used from create, so fallback to GetUser()
1024 // when mpSdrPathDragData is not set
1025 pDragData
= (ImpSdrPathDragData
*)rDrag
.GetUser();
1030 DBG_ERROR("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData ist ungueltig");
1034 if(!pDragData
->IsMultiPointDrag() && pDragData
->bEliminate
)
1037 mrSdrPathObject
.ImpTakeDescriptionStr(STR_ViewMarkedPoint
, aStr
);
1040 XubString
aStr2(ImpGetResStr(STR_EditDelete
));
1042 // UNICODE: Punkt von ... loeschen
1043 aStr2
.SearchAndReplaceAscii("%1", aStr
);
1048 // dx=0.00 dy=0.00 // Beide Seiten Bezier
1049 // dx=0.00 dy=0.00 l=0.00 0.00ø // Anfang oder Ende oder eine Seite Bezier bzw. Hebel
1050 // dx=0.00 dy=0.00 l=0.00 0.00ø / l=0.00 0.00ø // Mittendrin
1052 Point
aBeg(rDrag
.GetStart());
1053 Point
aNow(rDrag
.GetNow());
1056 aStr
.AppendAscii("dx=");
1057 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.X() - aBeg
.X(), aMetr
, TRUE
);
1060 aStr
.AppendAscii(" dy=");
1061 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.Y() - aBeg
.Y(), aMetr
, TRUE
);
1064 if(!pDragData
->IsMultiPointDrag())
1066 UINT16
nPntNum((sal_uInt16
)pHdl
->GetPointNum());
1067 const XPolygon
& rXPoly
= aPathPolygon
[(sal_uInt16
)rDrag
.GetHdl()->GetPolyNum()];
1068 UINT16
nPntAnz((sal_uInt16
)rXPoly
.GetPointCount());
1069 BOOL
bClose(IsClosed(meObjectKind
));
1074 if(pHdl
->IsPlusHdl())
1077 UINT16
nRef(nPntNum
);
1079 if(rXPoly
.IsControl(nPntNum
+ 1))
1084 aNow
-= rXPoly
[nRef
];
1086 INT32
nLen(GetLen(aNow
));
1087 aStr
.AppendAscii(" l=");
1088 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, TRUE
);
1091 INT32
nWink(GetAngle(aNow
));
1092 aStr
+= sal_Unicode(' ');
1093 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
1096 else if(nPntAnz
> 1)
1098 UINT16
nPntMax(nPntAnz
- 1);
1100 BOOL
bIsClosed(IsClosed(meObjectKind
));
1101 BOOL
bPt1(nPntNum
> 0);
1102 BOOL
bPt2(nPntNum
< nPntMax
);
1104 if(bIsClosed
&& nPntAnz
> 2)
1117 if(nPntNum
< nPntMax
)
1122 if(bPt1
&& rXPoly
.IsControl(nPt1
))
1123 bPt1
= FALSE
; // Keine Anzeige
1125 if(bPt2
&& rXPoly
.IsControl(nPt2
))
1126 bPt2
= FALSE
; // von Bezierdaten
1131 aPt
-= rXPoly
[nPt1
];
1133 INT32
nLen(GetLen(aPt
));
1134 aStr
.AppendAscii(" l=");
1135 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, TRUE
);
1138 INT32
nWink(GetAngle(aPt
));
1139 aStr
+= sal_Unicode(' ');
1140 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
1147 aStr
.AppendAscii(" / ");
1149 aStr
.AppendAscii(" ");
1152 aPt
-= rXPoly
[nPt2
];
1154 INT32
nLen(GetLen(aPt
));
1155 aStr
.AppendAscii("l=");
1156 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, TRUE
);
1159 INT32
nWink(GetAngle(aPt
));
1160 aStr
+= sal_Unicode(' ');
1161 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
1171 basegfx::B2DPolyPolygon
ImpPathForDragAndCreate::getSpecialDragPoly(const SdrDragStat
& rDrag
) const
1173 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
1175 DBG_ERROR("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData ist ungueltig");
1176 return basegfx::B2DPolyPolygon();
1179 XPolyPolygon aRetval
;
1181 if(mpSdrPathDragData
->IsMultiPointDrag())
1183 aRetval
.Insert(mpSdrPathDragData
->maMove
);
1187 const XPolygon
& rXP
=aPathPolygon
[(sal_uInt16
)rDrag
.GetHdl()->GetPolyNum()];
1188 if (rXP
.GetPointCount()<=2) { //|| rXPoly.GetFlags(1)==XPOLY_CONTROL && rXPoly.GetPointCount()<=4
1189 XPolygon
aXPoly(rXP
);
1190 aXPoly
[(sal_uInt16
)rDrag
.GetHdl()->GetPointNum()]=rDrag
.GetNow();
1191 aRetval
.Insert(aXPoly
);
1192 return aRetval
.getB2DPolyPolygon();
1194 // Div. Daten lokal Kopieren fuer weniger Code und schnelleren Zugriff
1195 FASTBOOL bClosed
=mpSdrPathDragData
->bClosed
; // geschlossenes Objekt?
1196 USHORT nPntAnz
=mpSdrPathDragData
->nPntAnz
; // Punktanzahl
1197 USHORT nPnt
=mpSdrPathDragData
->nPnt
; // Punktnummer innerhalb des Polygons
1198 FASTBOOL bBegPnt
=mpSdrPathDragData
->bBegPnt
; // Gedraggter Punkt ist der Anfangspunkt einer Polyline
1199 FASTBOOL bEndPnt
=mpSdrPathDragData
->bEndPnt
; // Gedraggter Punkt ist der Endpunkt einer Polyline
1200 USHORT nPrevPnt
=mpSdrPathDragData
->nPrevPnt
; // Index des vorherigen Punkts
1201 USHORT nNextPnt
=mpSdrPathDragData
->nNextPnt
; // Index des naechsten Punkts
1202 FASTBOOL bPrevIsBegPnt
=mpSdrPathDragData
->bPrevIsBegPnt
; // Vorheriger Punkt ist Anfangspunkt einer Polyline
1203 FASTBOOL bNextIsEndPnt
=mpSdrPathDragData
->bNextIsEndPnt
; // Folgepunkt ist Endpunkt einer Polyline
1204 USHORT nPrevPrevPnt
=mpSdrPathDragData
->nPrevPrevPnt
; // Index des vorvorherigen Punkts
1205 USHORT nNextNextPnt
=mpSdrPathDragData
->nNextNextPnt
; // Index des uebernaechsten Punkts
1206 FASTBOOL bControl
=mpSdrPathDragData
->bControl
; // Punkt ist ein Kontrollpunkt
1207 //FASTBOOL bIsPrevControl=mpSdrPathDragData->bIsPrevControl; // Punkt ist Kontrollpunkt vor einem Stuetzpunkt
1208 FASTBOOL bIsNextControl
=mpSdrPathDragData
->bIsNextControl
; // Punkt ist Kontrollpunkt hinter einem Stuetzpunkt
1209 FASTBOOL bPrevIsControl
=mpSdrPathDragData
->bPrevIsControl
; // Falls nPnt ein StPnt: Davor ist ein Kontrollpunkt
1210 FASTBOOL bNextIsControl
=mpSdrPathDragData
->bNextIsControl
; // Falls nPnt ein StPnt: Dahinter ist ein Kontrollpunkt
1211 XPolygon
aXPoly(mpSdrPathDragData
->aXP
);
1217 aLine1
[1]=mpSdrPathDragData
->aXP
[nPnt
];
1218 if (bIsNextControl
) { // bin ich Kontrollpunkt hinter der Stuetzstelle?
1219 aLine1
[0]=mpSdrPathDragData
->aXP
[nPrevPnt
];
1220 aLine2
[0]=mpSdrPathDragData
->aXP
[nNextNextPnt
];
1221 aLine2
[1]=mpSdrPathDragData
->aXP
[nNextPnt
];
1222 if (mpSdrPathDragData
->aXP
.IsSmooth(nPrevPnt
) && !bPrevIsBegPnt
&& mpSdrPathDragData
->aXP
.IsControl(nPrevPrevPnt
)) {
1223 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1],XPOLY_CONTROL
);
1224 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-2],XPOLY_NORMAL
);
1225 // Hebellienien fuer das gegenueberliegende Kurvensegment
1226 aLine3
[0]=mpSdrPathDragData
->aXP
[nPrevPnt
];
1227 aLine3
[1]=mpSdrPathDragData
->aXP
[nPrevPrevPnt
];
1228 aLine4
[0]=rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-2];
1229 aLine4
[1]=rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1];
1233 } else { // ansonsten bin ich Kontrollpunkt vor der Stuetzstelle
1234 aLine1
[0]=mpSdrPathDragData
->aXP
[nNextPnt
];
1235 aLine2
[0]=mpSdrPathDragData
->aXP
[nPrevPrevPnt
];
1236 aLine2
[1]=mpSdrPathDragData
->aXP
[nPrevPnt
];
1237 if (mpSdrPathDragData
->aXP
.IsSmooth(nNextPnt
) && !bNextIsEndPnt
&& mpSdrPathDragData
->aXP
.IsControl(nNextNextPnt
)) {
1238 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+1],XPOLY_CONTROL
);
1239 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+2],XPOLY_NORMAL
);
1240 // Hebellinien fuer das gegenueberliegende Kurvensegment
1241 aLine3
[0]=mpSdrPathDragData
->aXP
[nNextPnt
];
1242 aLine3
[1]=mpSdrPathDragData
->aXP
[nNextNextPnt
];
1243 aLine4
[0]=rXP
[mpSdrPathDragData
->nNextNextPnt0
+2];
1244 aLine4
[1]=rXP
[mpSdrPathDragData
->nNextNextPnt0
+1];
1246 aXPoly
.Remove(aXPoly
.GetPointCount()-1,1);
1249 } else { // ansonsten kein Kontrollpunkt
1250 if (mpSdrPathDragData
->bEliminate
) {
1253 if (bPrevIsControl
) aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1],XPOLY_NORMAL
);
1254 else if (!bBegPnt
&& !bPrevIsBegPnt
&& mpSdrPathDragData
->aXP
.IsControl(nPrevPrevPnt
)) {
1255 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1],XPOLY_CONTROL
);
1256 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-2],XPOLY_NORMAL
);
1259 if (bBegPnt
) aXPoly
.Remove(0,1);
1261 if (bNextIsControl
) aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+1],XPOLY_NORMAL
);
1262 else if (!bEndPnt
&& !bNextIsEndPnt
&& mpSdrPathDragData
->aXP
.IsControl(nNextNextPnt
)) {
1263 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+1],XPOLY_CONTROL
);
1264 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+2],XPOLY_NORMAL
);
1266 aXPoly
.Remove(aXPoly
.GetPointCount()-1,1);
1267 if (bEndPnt
) aXPoly
.Remove(aXPoly
.GetPointCount()-1,1);
1269 if (bClosed
) { // "Birnenproblem": 2 Linien, 1 Kurve, alles Smooth, Punkt zw. beiden Linien wird gedraggt
1270 if (aXPoly
.GetPointCount()>nPntAnz
&& aXPoly
.IsControl(1)) {
1271 USHORT a
=aXPoly
.GetPointCount();
1272 aXPoly
[a
-2]=aXPoly
[2]; aXPoly
.SetFlags(a
-2,aXPoly
.GetFlags(2));
1273 aXPoly
[a
-1]=aXPoly
[3]; aXPoly
.SetFlags(a
-1,aXPoly
.GetFlags(3));
1278 aRetval
.Insert(aXPoly
);
1279 if (aLine1
.GetPointCount()>1) aRetval
.Insert(aLine1
);
1280 if (aLine2
.GetPointCount()>1) aRetval
.Insert(aLine2
);
1281 if (aLine3
.GetPointCount()>1) aRetval
.Insert(aLine3
);
1282 if (aLine4
.GetPointCount()>1) aRetval
.Insert(aLine4
);
1285 return aRetval
.getB2DPolyPolygon();
1288 FASTBOOL
ImpPathForDragAndCreate::BegCreate(SdrDragStat
& rStat
)
1290 bool bFreeHand(IsFreeHand(meObjectKind
));
1291 rStat
.SetNoSnap(bFreeHand
);
1292 rStat
.SetOrtho8Possible();
1293 aPathPolygon
.Clear();
1295 FASTBOOL bMakeStartPoint
=TRUE
;
1296 SdrView
* pView
=rStat
.GetView();
1297 if (pView
!=NULL
&& pView
->IsUseIncompatiblePathCreateInterface() &&
1298 (meObjectKind
==OBJ_POLY
|| meObjectKind
==OBJ_PLIN
|| meObjectKind
==OBJ_PATHLINE
|| meObjectKind
==OBJ_PATHFILL
)) {
1299 bMakeStartPoint
=FALSE
;
1301 aPathPolygon
.Insert(XPolygon());
1302 aPathPolygon
[0][0]=rStat
.GetStart();
1303 if (bMakeStartPoint
) {
1304 aPathPolygon
[0][1]=rStat
.GetNow();
1306 ImpPathCreateUser
* pU
=new ImpPathCreateUser
;
1307 pU
->eStartKind
=meObjectKind
;
1308 pU
->eAktKind
=meObjectKind
;
1313 FASTBOOL
ImpPathForDragAndCreate::MovCreate(SdrDragStat
& rStat
)
1315 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1316 SdrView
* pView
=rStat
.GetView();
1317 XPolygon
& rXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1318 if (pView
!=NULL
&& pView
->IsCreateMode()) {
1319 // ggf. auf anderes CreateTool umschalten
1322 pView
->TakeCurrentObj(nIdent
,nInvent
);
1323 if (nInvent
==SdrInventor
&& pU
->eAktKind
!=(SdrObjKind
)nIdent
) {
1324 SdrObjKind eNewKind
=(SdrObjKind
)nIdent
;
1326 case OBJ_CARC
: case OBJ_CIRC
: case OBJ_CCUT
: case OBJ_SECT
: eNewKind
=OBJ_CARC
;
1328 case OBJ_LINE
: case OBJ_PLIN
: case OBJ_POLY
:
1329 case OBJ_PATHLINE
: case OBJ_PATHFILL
:
1330 case OBJ_FREELINE
: case OBJ_FREEFILL
:
1331 case OBJ_SPLNLINE
: case OBJ_SPLNFILL
: {
1332 pU
->eAktKind
=eNewKind
;
1333 pU
->bMixedCreate
=TRUE
;
1334 pU
->nBezierStartPoint
=rXPoly
.GetPointCount();
1335 if (pU
->nBezierStartPoint
>0) pU
->nBezierStartPoint
--;
1341 USHORT nActPoint
=rXPoly
.GetPointCount();
1342 if (aPathPolygon
.Count()>1 && rStat
.IsMouseDown() && nActPoint
<2) {
1343 rXPoly
[0]=rStat
.GetPos0();
1344 rXPoly
[1]=rStat
.GetNow();
1348 rXPoly
[0]=rStat
.GetPos0();
1350 FASTBOOL bFreeHand
=IsFreeHand(pU
->eAktKind
);
1351 rStat
.SetNoSnap(bFreeHand
/*|| (pU->bMixed && pU->eAktKind==OBJ_LINE)*/);
1352 rStat
.SetOrtho8Possible(pU
->eAktKind
!=OBJ_CARC
&& pU
->eAktKind
!=OBJ_RECT
&& (!pU
->bMixedCreate
|| pU
->eAktKind
!=OBJ_LINE
));
1353 Point
aActMerk(rXPoly
[nActPoint
]);
1354 rXPoly
[nActPoint
]=rStat
.Now();
1355 if (!pU
->bMixedCreate
&& pU
->eStartKind
==OBJ_LINE
&& rXPoly
.GetPointCount()>=1) {
1356 Point
aPt(rStat
.Start());
1357 if (pView
!=NULL
&& pView
->IsCreate1stPointAsCenter()) {
1363 OutputDevice
* pOut
=pView
==NULL
? NULL
: pView
->GetFirstOutputDevice(); // GetWin(0);
1365 if (pU
->nBezierStartPoint
>nActPoint
) pU
->nBezierStartPoint
=nActPoint
;
1366 if (rStat
.IsMouseDown() && nActPoint
>0) {
1367 // keine aufeinanderfolgenden Punkte an zu Nahe gelegenen Positionen zulassen
1369 if (pView
!=NULL
) nMinDist
=pView
->GetFreeHandMinDistPix();
1370 if (pOut
!=NULL
) nMinDist
=pOut
->PixelToLogic(Size(nMinDist
,0)).Width();
1371 if (nMinDist
<1) nMinDist
=1;
1373 Point
aPt0(rXPoly
[nActPoint
-1]);
1374 Point
aPt1(rStat
.Now());
1375 long dx
=aPt0
.X()-aPt1
.X(); if (dx
<0) dx
=-dx
;
1376 long dy
=aPt0
.Y()-aPt1
.Y(); if (dy
<0) dy
=-dy
;
1377 if (dx
<nMinDist
&& dy
<nMinDist
) return FALSE
;
1379 // folgendes ist aus EndCreate kopiert (nur kleine Modifikationen)
1380 // und sollte dann mal in eine Methode zusammengefasst werden:
1382 if (nActPoint
-pU
->nBezierStartPoint
>=3 && ((nActPoint
-pU
->nBezierStartPoint
)%3)==0) {
1383 rXPoly
.PointsToBezier(nActPoint
-3);
1384 rXPoly
.SetFlags(nActPoint
-1,XPOLY_CONTROL
);
1385 rXPoly
.SetFlags(nActPoint
-2,XPOLY_CONTROL
);
1387 if (nActPoint
>=6 && rXPoly
.IsControl(nActPoint
-4)) {
1388 rXPoly
.CalcTangent(nActPoint
-3,nActPoint
-4,nActPoint
-2);
1389 rXPoly
.SetFlags(nActPoint
-3,XPOLY_SMOOTH
);
1392 rXPoly
[nActPoint
+1]=rStat
.Now();
1395 pU
->nBezierStartPoint
=nActPoint
;
1399 pU
->ResetFormFlags();
1400 if (IsBezier(pU
->eAktKind
)) {
1402 pU
->CalcBezier(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],rStat
.IsMouseDown());
1403 } else if (pU
->bBezHasCtrl0
) {
1404 pU
->CalcBezier(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],pU
->aBezControl0
-rXPoly
[nActPoint
-1],rStat
.IsMouseDown());
1407 if (pU
->eAktKind
==OBJ_CARC
&& nActPoint
>=2) {
1408 pU
->CalcCircle(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],pView
);
1410 if (pU
->eAktKind
==OBJ_LINE
&& nActPoint
>=2) {
1411 pU
->CalcLine(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],pView
);
1413 if (pU
->eAktKind
==OBJ_RECT
&& nActPoint
>=2) {
1414 pU
->CalcRect(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],pView
);
1420 FASTBOOL
ImpPathForDragAndCreate::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
1422 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1423 FASTBOOL bRet
=FALSE
;
1424 SdrView
* pView
=rStat
.GetView();
1425 FASTBOOL bIncomp
=pView
!=NULL
&& pView
->IsUseIncompatiblePathCreateInterface();
1426 XPolygon
& rXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1427 USHORT nActPoint
=rXPoly
.GetPointCount()-1;
1428 Point
aAktMerk(rXPoly
[nActPoint
]);
1429 rXPoly
[nActPoint
]=rStat
.Now();
1430 if (!pU
->bMixedCreate
&& pU
->eStartKind
==OBJ_LINE
) {
1431 if (rStat
.GetPointAnz()>=2) eCmd
=SDRCREATE_FORCEEND
;
1432 bRet
=eCmd
==SDRCREATE_FORCEEND
;
1436 rStat
.SetUser(NULL
);
1441 if (!pU
->bMixedCreate
&& IsFreeHand(pU
->eStartKind
)) {
1442 if (rStat
.GetPointAnz()>=2) eCmd
=SDRCREATE_FORCEEND
;
1443 bRet
=eCmd
==SDRCREATE_FORCEEND
;
1447 rStat
.SetUser(NULL
);
1451 if (eCmd
==SDRCREATE_NEXTPOINT
|| eCmd
==SDRCREATE_NEXTOBJECT
) {
1452 // keine aufeinanderfolgenden Punkte an identischer Position zulassen
1453 if (nActPoint
==0 || rStat
.Now()!=rXPoly
[nActPoint
-1]) {
1455 if (pU
->nBezierStartPoint
>nActPoint
) pU
->nBezierStartPoint
=nActPoint
;
1456 if (IsBezier(pU
->eAktKind
) && nActPoint
-pU
->nBezierStartPoint
>=3 && ((nActPoint
-pU
->nBezierStartPoint
)%3)==0) {
1457 rXPoly
.PointsToBezier(nActPoint
-3);
1458 rXPoly
.SetFlags(nActPoint
-1,XPOLY_CONTROL
);
1459 rXPoly
.SetFlags(nActPoint
-2,XPOLY_CONTROL
);
1461 if (nActPoint
>=6 && rXPoly
.IsControl(nActPoint
-4)) {
1462 rXPoly
.CalcTangent(nActPoint
-3,nActPoint
-4,nActPoint
-2);
1463 rXPoly
.SetFlags(nActPoint
-3,XPOLY_SMOOTH
);
1467 if (nActPoint
==1 && IsBezier(pU
->eAktKind
) && !pU
->bBezHasCtrl0
) {
1468 pU
->aBezControl0
=rStat
.GetNow();;
1469 pU
->bBezHasCtrl0
=TRUE
;
1472 if (pU
->IsFormFlag()) {
1473 USHORT nPtAnz0
=rXPoly
.GetPointCount();
1474 rXPoly
.Remove(nActPoint
-1,2); // die letzten beiden Punkte entfernen und durch die Form ersetzen
1475 rXPoly
.Insert(XPOLY_APPEND
,pU
->GetFormPoly());
1476 USHORT nPtAnz1
=rXPoly
.GetPointCount();
1477 for (USHORT i
=nPtAnz0
+1; i
<nPtAnz1
-1; i
++) { // Damit BckAction richtig funktioniert
1478 if (!rXPoly
.IsControl(i
)) rStat
.NextPoint();
1480 nActPoint
=rXPoly
.GetPointCount()-1;
1484 rXPoly
[nActPoint
]=rStat
.GetNow();
1486 if (eCmd
==SDRCREATE_NEXTOBJECT
) {
1487 if (rXPoly
.GetPointCount()>=2) {
1488 pU
->bBezHasCtrl0
=FALSE
;
1489 // nur einzelnes Polygon kann offen sein, deshalb schliessen
1490 rXPoly
[nActPoint
]=rXPoly
[0];
1492 aXP
[0]=rStat
.GetNow();
1493 aPathPolygon
.Insert(aXP
);
1498 USHORT nPolyAnz
=aPathPolygon
.Count();
1500 // den letzten Punkt ggf. wieder loeschen
1501 if (eCmd
==SDRCREATE_FORCEEND
) {
1502 XPolygon
& rXP
=aPathPolygon
[nPolyAnz
-1];
1503 USHORT nPtAnz
=rXP
.GetPointCount();
1505 if (!rXP
.IsControl(nPtAnz
-2)) {
1506 if (rXP
[nPtAnz
-1]==rXP
[nPtAnz
-2]) {
1507 rXP
.Remove(nPtAnz
-1,1);
1510 if (rXP
[nPtAnz
-3]==rXP
[nPtAnz
-2]) {
1511 rXP
.Remove(nPtAnz
-3,3);
1516 for (USHORT nPolyNum
=nPolyAnz
; nPolyNum
>0;) {
1518 XPolygon
& rXP
=aPathPolygon
[nPolyNum
];
1519 USHORT nPtAnz
=rXP
.GetPointCount();
1520 // Polygone mit zu wenig Punkten werden geloescht
1521 if (nPolyNum
<nPolyAnz
-1 || eCmd
==SDRCREATE_FORCEEND
) {
1522 if (nPtAnz
<2) aPathPolygon
.Remove(nPolyNum
);
1526 pU
->ResetFormFlags();
1527 bRet
=eCmd
==SDRCREATE_FORCEEND
;
1531 rStat
.SetUser(NULL
);
1536 FASTBOOL
ImpPathForDragAndCreate::BckCreate(SdrDragStat
& rStat
)
1538 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1539 if (aPathPolygon
.Count()>0) {
1540 XPolygon
& rXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1541 USHORT nActPoint
=rXPoly
.GetPointCount();
1544 // Das letzte Stueck einer Bezierkurve wird erstmal zu 'ner Linie
1545 rXPoly
.Remove(nActPoint
,1);
1546 if (nActPoint
>=3 && rXPoly
.IsControl(nActPoint
-1)) {
1547 // Beziersegment am Ende sollte zwar nicht vorkommen, aber falls doch ...
1548 rXPoly
.Remove(nActPoint
-1,1);
1549 if (rXPoly
.IsControl(nActPoint
-2)) rXPoly
.Remove(nActPoint
-2,1);
1552 nActPoint
=rXPoly
.GetPointCount();
1553 if (nActPoint
>=4) { // Kein Beziersegment am Ende
1555 if (rXPoly
.IsControl(nActPoint
-1)) {
1556 rXPoly
.Remove(nActPoint
-1,1);
1557 if (rXPoly
.IsControl(nActPoint
-2)) rXPoly
.Remove(nActPoint
-2,1);
1560 if (rXPoly
.GetPointCount()<2) {
1561 aPathPolygon
.Remove(aPathPolygon
.Count()-1);
1563 if (aPathPolygon
.Count()>0) {
1564 XPolygon
& rLocalXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1565 USHORT nLocalActPoint
=rLocalXPoly
.GetPointCount();
1566 if (nLocalActPoint
>0) {
1568 rLocalXPoly
[nLocalActPoint
]=rStat
.Now();
1572 pU
->ResetFormFlags();
1573 return aPathPolygon
.Count()!=0;
1576 void ImpPathForDragAndCreate::BrkCreate(SdrDragStat
& rStat
)
1578 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1579 aPathPolygon
.Clear();
1582 rStat
.SetUser(NULL
);
1585 basegfx::B2DPolyPolygon
ImpPathForDragAndCreate::TakeObjectPolyPolygon(const SdrDragStat
& rDrag
) const
1587 basegfx::B2DPolyPolygon
aRetval(aPathPolygon
.getB2DPolyPolygon());
1588 SdrView
* pView
= rDrag
.GetView();
1590 if(pView
&& pView
->IsUseIncompatiblePathCreateInterface())
1593 ImpPathCreateUser
* pU
= (ImpPathCreateUser
*)rDrag
.GetUser();
1594 basegfx::B2DPolygon
aNewPolygon(aRetval
.count() ? aRetval
.getB2DPolygon(aRetval
.count() - 1L) : basegfx::B2DPolygon());
1596 if(pU
->IsFormFlag() && aNewPolygon
.count() > 1L)
1598 // remove last segment and replace with current
1599 // do not forget to rescue the previous control point which will be lost when
1600 // the point it's associated with is removed
1601 const sal_uInt32
nChangeIndex(aNewPolygon
.count() - 2);
1602 const basegfx::B2DPoint
aSavedPrevCtrlPoint(aNewPolygon
.getPrevControlPoint(nChangeIndex
));
1604 aNewPolygon
.remove(nChangeIndex
, 2L);
1605 aNewPolygon
.append(pU
->GetFormPoly().getB2DPolygon());
1607 if(nChangeIndex
< aNewPolygon
.count())
1609 // if really something was added, set the saved prev control point at the
1610 // point where it belongs
1611 aNewPolygon
.setPrevControlPoint(nChangeIndex
, aSavedPrevCtrlPoint
);
1617 aRetval
.setB2DPolygon(aRetval
.count() - 1L, aNewPolygon
);
1621 aRetval
.append(aNewPolygon
);
1627 basegfx::B2DPolyPolygon
ImpPathForDragAndCreate::TakeDragPolyPolygon(const SdrDragStat
& rDrag
) const
1629 basegfx::B2DPolyPolygon aRetval
;
1630 SdrView
* pView
= rDrag
.GetView();
1632 if(pView
&& pView
->IsUseIncompatiblePathCreateInterface())
1635 ImpPathCreateUser
* pU
= (ImpPathCreateUser
*)rDrag
.GetUser();
1637 if(pU
&& pU
->bBezier
&& rDrag
.IsMouseDown())
1639 // no more XOR, no need for complicated helplines
1640 basegfx::B2DPolygon aHelpline
;
1641 aHelpline
.append(basegfx::B2DPoint(pU
->aBezCtrl2
.X(), pU
->aBezCtrl2
.Y()));
1642 aHelpline
.append(basegfx::B2DPoint(pU
->aBezEnd
.X(), pU
->aBezEnd
.Y()));
1643 aRetval
.append(aHelpline
);
1649 Pointer
ImpPathForDragAndCreate::GetCreatePointer() const
1651 switch (meObjectKind
) {
1652 case OBJ_LINE
: return Pointer(POINTER_DRAW_LINE
);
1653 case OBJ_POLY
: return Pointer(POINTER_DRAW_POLYGON
);
1654 case OBJ_PLIN
: return Pointer(POINTER_DRAW_POLYGON
);
1655 case OBJ_PATHLINE
: return Pointer(POINTER_DRAW_BEZIER
);
1656 case OBJ_PATHFILL
: return Pointer(POINTER_DRAW_BEZIER
);
1657 case OBJ_FREELINE
: return Pointer(POINTER_DRAW_FREEHAND
);
1658 case OBJ_FREEFILL
: return Pointer(POINTER_DRAW_FREEHAND
);
1659 case OBJ_SPLNLINE
: return Pointer(POINTER_DRAW_FREEHAND
);
1660 case OBJ_SPLNFILL
: return Pointer(POINTER_DRAW_FREEHAND
);
1661 case OBJ_PATHPOLY
: return Pointer(POINTER_DRAW_POLYGON
);
1662 case OBJ_PATHPLIN
: return Pointer(POINTER_DRAW_POLYGON
);
1665 return Pointer(POINTER_CROSS
);
1668 /*************************************************************************/
1670 SdrPathObjGeoData::SdrPathObjGeoData()
1674 SdrPathObjGeoData::~SdrPathObjGeoData()
1678 //////////////////////////////////////////////////////////////////////////////
1679 // DrawContact section
1681 sdr::contact::ViewContact
* SdrPathObj::CreateObjectSpecificViewContact()
1683 return new sdr::contact::ViewContactOfSdrPathObj(*this);
1686 /*************************************************************************/
1688 TYPEINIT1(SdrPathObj
,SdrTextObj
);
1690 SdrPathObj::SdrPathObj(SdrObjKind eNewKind
)
1694 bClosedObj
= IsClosed();
1697 SdrPathObj::SdrPathObj(SdrObjKind eNewKind
, const basegfx::B2DPolyPolygon
& rPathPoly
)
1698 : maPathPolygon(rPathPoly
),
1702 bClosedObj
= IsClosed();
1706 SdrPathObj::~SdrPathObj()
1711 sal_Bool
ImpIsLine(const basegfx::B2DPolyPolygon
& rPolyPolygon
)
1713 return (1L == rPolyPolygon
.count() && 2L == rPolyPolygon
.getB2DPolygon(0L).count());
1716 Rectangle
ImpGetBoundRect(const basegfx::B2DPolyPolygon
& rPolyPolygon
)
1718 basegfx::B2DRange
aRange(basegfx::tools::getRange(rPolyPolygon
));
1721 FRound(aRange
.getMinX()), FRound(aRange
.getMinY()),
1722 FRound(aRange
.getMaxX()), FRound(aRange
.getMaxY()));
1725 void SdrPathObj::ImpForceLineWink()
1727 if(OBJ_LINE
== meKind
&& ImpIsLine(GetPathPoly()))
1729 const basegfx::B2DPolygon
aPoly(GetPathPoly().getB2DPolygon(0L));
1730 const basegfx::B2DPoint
aB2DPoint0(aPoly
.getB2DPoint(0L));
1731 const basegfx::B2DPoint
aB2DPoint1(aPoly
.getB2DPoint(1L));
1732 const Point
aPoint0(FRound(aB2DPoint0
.getX()), FRound(aB2DPoint0
.getY()));
1733 const Point
aPoint1(FRound(aB2DPoint1
.getX()), FRound(aB2DPoint1
.getY()));
1734 const Point
aDelt(aPoint1
- aPoint0
);
1736 aGeo
.nDrehWink
=GetAngle(aDelt
);
1738 aGeo
.RecalcSinCos();
1741 // #101412# for SdrTextObj, keep aRect up to date
1742 aRect
= Rectangle(aPoint0
, aPoint1
);
1747 void SdrPathObj::ImpForceKind()
1749 if (meKind
==OBJ_PATHPLIN
) meKind
=OBJ_PLIN
;
1750 if (meKind
==OBJ_PATHPOLY
) meKind
=OBJ_POLY
;
1752 if(GetPathPoly().areControlPointsUsed())
1756 case OBJ_LINE
: meKind
=OBJ_PATHLINE
; break;
1757 case OBJ_PLIN
: meKind
=OBJ_PATHLINE
; break;
1758 case OBJ_POLY
: meKind
=OBJ_PATHFILL
; break;
1766 case OBJ_PATHLINE
: meKind
=OBJ_PLIN
; break;
1767 case OBJ_FREELINE
: meKind
=OBJ_PLIN
; break;
1768 case OBJ_PATHFILL
: meKind
=OBJ_POLY
; break;
1769 case OBJ_FREEFILL
: meKind
=OBJ_POLY
; break;
1774 if (meKind
==OBJ_LINE
&& !ImpIsLine(GetPathPoly())) meKind
=OBJ_PLIN
;
1775 if (meKind
==OBJ_PLIN
&& ImpIsLine(GetPathPoly())) meKind
=OBJ_LINE
;
1777 bClosedObj
=IsClosed();
1779 if (meKind
==OBJ_LINE
)
1785 // #i10659#, similar to #101412# but for polys with more than 2 points.
1787 // Here i again need to fix something, because when Path-Polys are Copy-Pasted
1788 // between Apps with different measurements (e.g. 100TH_MM and TWIPS) there is
1789 // a scaling loop started from SdrExchangeView::Paste. This is principally nothing
1790 // wrong, but aRect is wrong here and not even updated by RecalcSnapRect(). If
1791 // this is the case, some size needs to be set here in aRect to avoid that the cyclus
1792 // through Rect2Poly - Poly2Rect does something badly wrong since that cycle is
1793 // BASED on aRect. That cycle is triggered in SdrTextObj::NbcResize() which is called
1794 // from the local Resize() implementation.
1796 // Basic problem is that the member aRect in SdrTextObj basically is a unrotated
1797 // text rectangle for the text object itself and methods at SdrTextObj do handle it
1798 // in that way. Many draw objects derived from SdrTextObj 'abuse' aRect as SnapRect
1799 // which is basically wrong. To make the SdrText methods which deal with aRect directly
1800 // work it is necessary to always keep aRect updated. This e.g. not done after a Clone()
1801 // command for SdrPathObj. Since adding this update mechanism with #101412# to
1802 // ImpForceLineWink() for lines was very successful, i add it to where ImpForceLineWink()
1803 // was called, once here below and once on a 2nd place below.
1805 // #i10659# for SdrTextObj, keep aRect up to date
1806 if(GetPathPoly().count())
1808 aRect
= ImpGetBoundRect(GetPathPoly());
1812 // #i75974# adapt polygon state to object type. This may include a reinterpretation
1813 // of a closed geometry as open one, but with identical first and last point
1814 for(sal_uInt32
a(0); a
< maPathPolygon
.count(); a
++)
1816 basegfx::B2DPolygon
aCandidate(maPathPolygon
.getB2DPolygon(a
));
1818 if((bool)IsClosed() != aCandidate
.isClosed())
1820 // #i80213# really change polygon geometry; else e.g. the last point which
1821 // needs to be identical with the first one will be missing when opening
1822 // due to OBJ_PATH type
1823 if(aCandidate
.isClosed())
1825 basegfx::tools::openWithGeometryChange(aCandidate
);
1829 basegfx::tools::closeWithGeometryChange(aCandidate
);
1832 maPathPolygon
.setB2DPolygon(a
, aCandidate
);
1837 void SdrPathObj::ImpSetClosed(sal_Bool bClose
)
1843 case OBJ_LINE
: meKind
=OBJ_POLY
; break;
1844 case OBJ_PLIN
: meKind
=OBJ_POLY
; break;
1845 case OBJ_PATHLINE
: meKind
=OBJ_PATHFILL
; break;
1846 case OBJ_FREELINE
: meKind
=OBJ_FREEFILL
; break;
1847 case OBJ_SPLNLINE
: meKind
=OBJ_SPLNFILL
; break;
1857 case OBJ_POLY
: meKind
=OBJ_PLIN
; break;
1858 case OBJ_PATHFILL
: meKind
=OBJ_PATHLINE
; break;
1859 case OBJ_FREEFILL
: meKind
=OBJ_FREELINE
; break;
1860 case OBJ_SPLNFILL
: meKind
=OBJ_SPLNLINE
; break;
1870 void SdrPathObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
1872 rInfo
.bNoContortion
=FALSE
;
1874 FASTBOOL bCanConv
= !HasText() || ImpCanConvTextToCurve();
1875 FASTBOOL bIsPath
= IsBezier() || IsSpline();
1877 rInfo
.bEdgeRadiusAllowed
= FALSE
;
1878 rInfo
.bCanConvToPath
= bCanConv
&& !bIsPath
;
1879 rInfo
.bCanConvToPoly
= bCanConv
&& bIsPath
;
1880 rInfo
.bCanConvToContour
= !IsFontwork() && (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
1883 UINT16
SdrPathObj::GetObjIdentifier() const
1885 return USHORT(meKind
);
1888 void SdrPathObj::operator=(const SdrObject
& rObj
)
1890 SdrTextObj::operator=(rObj
);
1891 SdrPathObj
& rPath
=(SdrPathObj
&)rObj
;
1892 maPathPolygon
=rPath
.GetPathPoly();
1895 void SdrPathObj::TakeObjNameSingul(XubString
& rName
) const
1897 if(OBJ_LINE
== meKind
)
1899 sal_uInt16
nId(STR_ObjNameSingulLINE
);
1901 if(ImpIsLine(GetPathPoly()))
1903 const basegfx::B2DPolygon
aPoly(GetPathPoly().getB2DPolygon(0L));
1904 const basegfx::B2DPoint
aB2DPoint0(aPoly
.getB2DPoint(0L));
1905 const basegfx::B2DPoint
aB2DPoint1(aPoly
.getB2DPoint(1L));
1906 const Point
aPoint0(FRound(aB2DPoint0
.getX()), FRound(aB2DPoint0
.getY()));
1907 const Point
aPoint1(FRound(aB2DPoint0
.getX()), FRound(aB2DPoint0
.getY()));
1909 if(aB2DPoint0
!= aB2DPoint1
)
1911 if(aB2DPoint0
.getY() == aB2DPoint1
.getY())
1913 nId
= STR_ObjNameSingulLINE_Hori
;
1915 else if(aB2DPoint0
.getX() == aB2DPoint1
.getX())
1917 nId
= STR_ObjNameSingulLINE_Vert
;
1921 const double fDx(fabs(aB2DPoint0
.getX() - aB2DPoint1
.getX()));
1922 const double fDy(fabs(aB2DPoint0
.getY() - aB2DPoint1
.getY()));
1926 nId
= STR_ObjNameSingulLINE_Diag
;
1932 rName
= ImpGetResStr(nId
);
1934 else if(OBJ_PLIN
== meKind
|| OBJ_POLY
== meKind
)
1936 const sal_Bool
bClosed(OBJ_POLY
== meKind
);
1939 if(mpDAC
&& mpDAC
->IsCreating())
1943 nId
= STR_ObjNameSingulPOLY
;
1947 nId
= STR_ObjNameSingulPLIN
;
1950 rName
= ImpGetResStr(nId
);
1955 sal_uInt32
nPointCount(0L);
1956 const sal_uInt32
nPolyCount(GetPathPoly().count());
1958 for(sal_uInt32
a(0L); a
< nPolyCount
; a
++)
1960 nPointCount
+= GetPathPoly().getB2DPolygon(a
).count();
1965 nId
= STR_ObjNameSingulPOLY_PntAnz
;
1969 nId
= STR_ObjNameSingulPLIN_PntAnz
;
1972 rName
= ImpGetResStr(nId
);
1973 sal_uInt16
nPos(rName
.SearchAscii("%2")); // #i96537#
1975 if(STRING_NOTFOUND
!= nPos
)
1977 rName
.Erase(nPos
, 2);
1978 rName
.Insert(UniString::CreateFromInt32(nPointCount
), nPos
);
1986 case OBJ_PATHLINE
: rName
=ImpGetResStr(STR_ObjNameSingulPATHLINE
); break;
1987 case OBJ_FREELINE
: rName
=ImpGetResStr(STR_ObjNameSingulFREELINE
); break;
1988 case OBJ_SPLNLINE
: rName
=ImpGetResStr(STR_ObjNameSingulNATSPLN
); break;
1989 case OBJ_PATHFILL
: rName
=ImpGetResStr(STR_ObjNameSingulPATHFILL
); break;
1990 case OBJ_FREEFILL
: rName
=ImpGetResStr(STR_ObjNameSingulFREEFILL
); break;
1991 case OBJ_SPLNFILL
: rName
=ImpGetResStr(STR_ObjNameSingulPERSPLN
); break;
1996 String
aName(GetName());
1999 rName
+= sal_Unicode(' ');
2000 rName
+= sal_Unicode('\'');
2002 rName
+= sal_Unicode('\'');
2006 void SdrPathObj::TakeObjNamePlural(XubString
& rName
) const
2010 case OBJ_LINE
: rName
=ImpGetResStr(STR_ObjNamePluralLINE
); break;
2011 case OBJ_PLIN
: rName
=ImpGetResStr(STR_ObjNamePluralPLIN
); break;
2012 case OBJ_POLY
: rName
=ImpGetResStr(STR_ObjNamePluralPOLY
); break;
2013 case OBJ_PATHLINE
: rName
=ImpGetResStr(STR_ObjNamePluralPATHLINE
); break;
2014 case OBJ_FREELINE
: rName
=ImpGetResStr(STR_ObjNamePluralFREELINE
); break;
2015 case OBJ_SPLNLINE
: rName
=ImpGetResStr(STR_ObjNamePluralNATSPLN
); break;
2016 case OBJ_PATHFILL
: rName
=ImpGetResStr(STR_ObjNamePluralPATHFILL
); break;
2017 case OBJ_FREEFILL
: rName
=ImpGetResStr(STR_ObjNamePluralFREEFILL
); break;
2018 case OBJ_SPLNFILL
: rName
=ImpGetResStr(STR_ObjNamePluralPERSPLN
); break;
2023 basegfx::B2DPolyPolygon
SdrPathObj::TakeXorPoly() const
2025 return GetPathPoly();
2028 sal_uInt32
SdrPathObj::GetHdlCount() const
2030 sal_uInt32
nRetval(0L);
2031 const sal_uInt32
nPolyCount(GetPathPoly().count());
2033 for(sal_uInt32
a(0L); a
< nPolyCount
; a
++)
2035 nRetval
+= GetPathPoly().getB2DPolygon(a
).count();
2041 SdrHdl
* SdrPathObj::GetHdl(sal_uInt32 nHdlNum
) const
2044 // Warn the user that this is ineffective and show alternatives. Should not be used at all.
2045 OSL_ENSURE(false, "SdrPathObj::GetHdl(): ineffective, use AddToHdlList instead (!)");
2047 // to have an alternative, get single handle using the ineffective way
2048 SdrHdl
* pRetval
= 0;
2049 SdrHdlList
aLocalList(0);
2050 AddToHdlList(aLocalList
);
2051 const sal_uInt32
nHdlCount(aLocalList
.GetHdlCount());
2053 if(nHdlCount
&& nHdlNum
< nHdlCount
)
2055 // remove and remember. The other created handles will be deleted again with the
2056 // destruction of the local list
2057 pRetval
= aLocalList
.RemoveHdl(nHdlNum
);
2063 void SdrPathObj::AddToHdlList(SdrHdlList
& rHdlList
) const
2065 // keep old stuff to be able to keep old SdrHdl stuff, too
2066 const XPolyPolygon
aOldPathPolygon(GetPathPoly());
2067 USHORT nPolyCnt
=aOldPathPolygon
.Count();
2068 FASTBOOL bClosed
=IsClosed();
2071 for (USHORT i
=0; i
<nPolyCnt
; i
++) {
2072 const XPolygon
& rXPoly
=aOldPathPolygon
.GetObject(i
);
2073 USHORT nPntCnt
=rXPoly
.GetPointCount();
2074 if (bClosed
&& nPntCnt
>1) nPntCnt
--;
2076 for (USHORT j
=0; j
<nPntCnt
; j
++) {
2077 if (rXPoly
.GetFlags(j
)!=XPOLY_CONTROL
) {
2078 const Point
& rPnt
=rXPoly
[j
];
2079 SdrHdl
* pHdl
=new SdrHdl(rPnt
,HDL_POLY
);
2080 pHdl
->SetPolyNum(i
);
2081 pHdl
->SetPointNum(j
);
2082 pHdl
->Set1PixMore(j
==0);
2083 pHdl
->SetSourceHdlNum(nIdx
);
2085 rHdlList
.AddHdl(pHdl
);
2091 sal_uInt32
SdrPathObj::GetPlusHdlCount(const SdrHdl
& rHdl
) const
2093 // keep old stuff to be able to keep old SdrHdl stuff, too
2094 const XPolyPolygon
aOldPathPolygon(GetPathPoly());
2095 sal_uInt16 nCnt
= 0;
2096 sal_uInt16 nPnt
= (sal_uInt16
)rHdl
.GetPointNum();
2097 sal_uInt16 nPolyNum
= (sal_uInt16
)rHdl
.GetPolyNum();
2099 if(nPolyNum
< aOldPathPolygon
.Count())
2101 const XPolygon
& rXPoly
= aOldPathPolygon
[nPolyNum
];
2102 sal_uInt16 nPntMax
= rXPoly
.GetPointCount();
2108 if (rXPoly
.GetFlags(nPnt
)!=XPOLY_CONTROL
)
2110 if (nPnt
==0 && IsClosed()) nPnt
=nPntMax
;
2111 if (nPnt
>0 && rXPoly
.GetFlags(nPnt
-1)==XPOLY_CONTROL
) nCnt
++;
2112 if (nPnt
==nPntMax
&& IsClosed()) nPnt
=0;
2113 if (nPnt
<nPntMax
&& rXPoly
.GetFlags(nPnt
+1)==XPOLY_CONTROL
) nCnt
++;
2122 SdrHdl
* SdrPathObj::GetPlusHdl(const SdrHdl
& rHdl
, sal_uInt32 nPlusNum
) const
2124 // keep old stuff to be able to keep old SdrHdl stuff, too
2125 const XPolyPolygon
aOldPathPolygon(GetPathPoly());
2127 sal_uInt16 nPnt
= (sal_uInt16
)rHdl
.GetPointNum();
2128 sal_uInt16 nPolyNum
= (sal_uInt16
)rHdl
.GetPolyNum();
2130 if (nPolyNum
<aOldPathPolygon
.Count())
2132 const XPolygon
& rXPoly
= aOldPathPolygon
[nPolyNum
];
2133 sal_uInt16 nPntMax
= rXPoly
.GetPointCount();
2140 pHdl
=new SdrHdlBezWgt(&rHdl
);
2141 pHdl
->SetPolyNum(rHdl
.GetPolyNum());
2143 if (nPnt
==0 && IsClosed()) nPnt
=nPntMax
;
2144 if (nPnt
>0 && rXPoly
.GetFlags(nPnt
-1)==XPOLY_CONTROL
&& nPlusNum
==0)
2146 pHdl
->SetPos(rXPoly
[nPnt
-1]);
2147 pHdl
->SetPointNum(nPnt
-1);
2151 if (nPnt
==nPntMax
&& IsClosed()) nPnt
=0;
2152 if (nPnt
<rXPoly
.GetPointCount()-1 && rXPoly
.GetFlags(nPnt
+1)==XPOLY_CONTROL
)
2154 pHdl
->SetPos(rXPoly
[nPnt
+1]);
2155 pHdl
->SetPointNum(nPnt
+1);
2159 pHdl
->SetSourceHdlNum(rHdl
.GetSourceHdlNum());
2160 pHdl
->SetPlusHdl(TRUE
);
2167 ////////////////////////////////////////////////////////////////////////////////////////////////////
2169 bool SdrPathObj::hasSpecialDrag() const
2174 bool SdrPathObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
2176 ImpPathForDragAndCreate
aDragAndCreate(*((SdrPathObj
*)this));
2178 return aDragAndCreate
.beginPathDrag(rDrag
);
2181 bool SdrPathObj::applySpecialDrag(SdrDragStat
& rDrag
)
2183 ImpPathForDragAndCreate
aDragAndCreate(*this);
2184 bool bRetval(aDragAndCreate
.beginPathDrag(rDrag
));
2188 bRetval
= aDragAndCreate
.movePathDrag(rDrag
);
2193 bRetval
= aDragAndCreate
.endPathDrag(rDrag
);
2198 NbcSetPathPoly(aDragAndCreate
.getModifiedPolyPolygon());
2204 String
SdrPathObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
2210 // #i103058# also get a comment when in creation
2211 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
2215 aRetval
= mpDAC
->getSpecialDragComment(rDrag
);
2220 ImpPathForDragAndCreate
aDragAndCreate(*((SdrPathObj
*)this));
2221 bool bDidWork(aDragAndCreate
.beginPathDrag((SdrDragStat
&)rDrag
));
2225 aRetval
= aDragAndCreate
.getSpecialDragComment(rDrag
);
2232 basegfx::B2DPolyPolygon
SdrPathObj::getSpecialDragPoly(const SdrDragStat
& rDrag
) const
2234 basegfx::B2DPolyPolygon aRetval
;
2235 ImpPathForDragAndCreate
aDragAndCreate(*((SdrPathObj
*)this));
2236 bool bDidWork(aDragAndCreate
.beginPathDrag((SdrDragStat
&)rDrag
));
2240 aRetval
= aDragAndCreate
.getSpecialDragPoly(rDrag
);
2246 ////////////////////////////////////////////////////////////////////////////////////////////////////
2248 FASTBOOL
SdrPathObj::BegCreate(SdrDragStat
& rStat
)
2251 return impGetDAC().BegCreate(rStat
);
2254 FASTBOOL
SdrPathObj::MovCreate(SdrDragStat
& rStat
)
2256 return impGetDAC().MovCreate(rStat
);
2259 FASTBOOL
SdrPathObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
2261 FASTBOOL
bRetval(impGetDAC().EndCreate(rStat
, eCmd
));
2263 if(bRetval
&& mpDAC
)
2265 SetPathPoly(mpDAC
->getModifiedPolyPolygon());
2267 // #i75974# Check for AutoClose feature. Moved here from ImpPathForDragAndCreate::EndCreate
2268 // to be able to use the type-changing ImpSetClosed method
2271 SdrView
* pView
= rStat
.GetView();
2273 if(pView
&& pView
->IsAutoClosePolys() && !pView
->IsUseIncompatiblePathCreateInterface())
2275 OutputDevice
* pOut
= pView
->GetFirstOutputDevice();
2279 if(GetPathPoly().count())
2281 const basegfx::B2DPolygon
aCandidate(GetPathPoly().getB2DPolygon(0));
2283 if(aCandidate
.count() > 2)
2285 // check distance of first and last point
2286 const sal_Int32
nCloseDist(pOut
->PixelToLogic(Size(pView
->GetAutoCloseDistPix(), 0)).Width());
2287 const basegfx::B2DVector
aDistVector(aCandidate
.getB2DPoint(aCandidate
.count() - 1) - aCandidate
.getB2DPoint(0));
2289 if(aDistVector
.getLength() <= (double)nCloseDist
)
2306 FASTBOOL
SdrPathObj::BckCreate(SdrDragStat
& rStat
)
2308 return impGetDAC().BckCreate(rStat
);
2311 void SdrPathObj::BrkCreate(SdrDragStat
& rStat
)
2313 impGetDAC().BrkCreate(rStat
);
2317 basegfx::B2DPolyPolygon
SdrPathObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
2319 basegfx::B2DPolyPolygon aRetval
;
2323 aRetval
= mpDAC
->TakeObjectPolyPolygon(rDrag
);
2324 aRetval
.append(mpDAC
->TakeDragPolyPolygon(rDrag
));
2330 // during drag or create, allow accessing the so-far created/modified polyPolygon
2331 basegfx::B2DPolyPolygon
SdrPathObj::getObjectPolyPolygon(const SdrDragStat
& rDrag
) const
2333 basegfx::B2DPolyPolygon aRetval
;
2337 aRetval
= mpDAC
->TakeObjectPolyPolygon(rDrag
);
2343 basegfx::B2DPolyPolygon
SdrPathObj::getDragPolyPolygon(const SdrDragStat
& rDrag
) const
2345 basegfx::B2DPolyPolygon aRetval
;
2349 aRetval
= mpDAC
->TakeDragPolyPolygon(rDrag
);
2355 Pointer
SdrPathObj::GetCreatePointer() const
2357 return impGetDAC().GetCreatePointer();
2360 void SdrPathObj::NbcMove(const Size
& rSiz
)
2362 basegfx::B2DHomMatrix aTrans
;
2363 aTrans
.translate(rSiz
.Width(), rSiz
.Height());
2364 maPathPolygon
.transform(aTrans
);
2366 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2367 SdrTextObj::NbcMove(rSiz
);
2370 void SdrPathObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
2372 basegfx::B2DHomMatrix aTrans
;
2373 aTrans
.translate(-rRef
.X(), -rRef
.Y());
2374 aTrans
.scale(double(xFact
), double(yFact
));
2375 aTrans
.translate(rRef
.X(), rRef
.Y());
2376 maPathPolygon
.transform(aTrans
);
2378 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2379 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
2382 void SdrPathObj::NbcRotate(const Point
& rRef
, long nWink
, double sn
, double cs
)
2384 basegfx::B2DHomMatrix aTrans
;
2385 aTrans
.translate(-rRef
.X(), -rRef
.Y());
2386 aTrans
.rotate(-nWink
* nPi180
); // Thank JOE, the angles are defined mirrored to the mathematical meanings
2387 aTrans
.translate(rRef
.X(), rRef
.Y());
2388 maPathPolygon
.transform(aTrans
);
2390 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2391 SdrTextObj::NbcRotate(rRef
,nWink
,sn
,cs
);
2394 void SdrPathObj::NbcShear(const Point
& rRefPnt
, long nAngle
, double fTan
, FASTBOOL bVShear
)
2396 basegfx::B2DHomMatrix aTrans
;
2397 aTrans
.translate(-rRefPnt
.X(), -rRefPnt
.Y());
2401 // Thank JOE, the angles are defined mirrored to the mathematical meanings
2402 aTrans
.shearY(-fTan
);
2406 aTrans
.shearX(-fTan
);
2409 aTrans
.translate(rRefPnt
.X(), rRefPnt
.Y());
2410 maPathPolygon
.transform(aTrans
);
2412 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2413 SdrTextObj::NbcShear(rRefPnt
,nAngle
,fTan
,bVShear
);
2416 void SdrPathObj::NbcMirror(const Point
& rRefPnt1
, const Point
& rRefPnt2
)
2418 basegfx::B2DHomMatrix aTrans
;
2419 const double fDiffX(rRefPnt2
.X() - rRefPnt1
.X());
2420 const double fDiffY(rRefPnt2
.Y() - rRefPnt1
.Y());
2421 const double fRot(atan2(fDiffY
, fDiffX
));
2422 aTrans
.translate(-rRefPnt1
.X(), -rRefPnt1
.Y());
2423 aTrans
.rotate(-fRot
);
2424 aTrans
.scale(1.0, -1.0);
2425 aTrans
.rotate(fRot
);
2426 aTrans
.translate(rRefPnt1
.X(), rRefPnt1
.Y());
2427 maPathPolygon
.transform(aTrans
);
2429 // #97538# Do Joe's special handling for lines when mirroring, too
2432 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2433 SdrTextObj::NbcMirror(rRefPnt1
,rRefPnt2
);
2436 void SdrPathObj::TakeUnrotatedSnapRect(Rectangle
& rRect
) const
2440 rRect
= GetSnapRect();
2444 XPolyPolygon
aXPP(GetPathPoly());
2445 RotateXPoly(aXPP
,Point(),-aGeo
.nSin
,aGeo
.nCos
);
2446 rRect
=aXPP
.GetBoundRect();
2447 Point
aTmp(rRect
.TopLeft());
2448 RotatePoint(aTmp
,Point(),aGeo
.nSin
,aGeo
.nCos
);
2449 aTmp
-=rRect
.TopLeft();
2450 rRect
.Move(aTmp
.X(),aTmp
.Y());
2454 void SdrPathObj::RecalcSnapRect()
2456 if(GetPathPoly().count())
2458 maSnapRect
= ImpGetBoundRect(GetPathPoly());
2462 void SdrPathObj::NbcSetSnapRect(const Rectangle
& rRect
)
2464 Rectangle
aOld(GetSnapRect());
2466 // #95736# Take RECT_EMPTY into account when calculating scale factors
2467 long nMulX
= (RECT_EMPTY
== rRect
.Right()) ? 0 : rRect
.Right() - rRect
.Left();
2469 long nDivX
= aOld
.Right() - aOld
.Left();
2471 // #95736# Take RECT_EMPTY into account when calculating scale factors
2472 long nMulY
= (RECT_EMPTY
== rRect
.Bottom()) ? 0 : rRect
.Bottom() - rRect
.Top();
2474 long nDivY
= aOld
.Bottom() - aOld
.Top();
2475 if ( nDivX
== 0 ) { nMulX
= 1; nDivX
= 1; }
2476 if ( nDivY
== 0 ) { nMulY
= 1; nDivY
= 1; }
2477 Fraction
aX(nMulX
,nDivX
);
2478 Fraction
aY(nMulY
,nDivY
);
2479 NbcResize(aOld
.TopLeft(), aX
, aY
);
2480 NbcMove(Size(rRect
.Left() - aOld
.Left(), rRect
.Top() - aOld
.Top()));
2483 sal_uInt32
SdrPathObj::GetSnapPointCount() const
2485 return GetHdlCount();
2488 Point
SdrPathObj::GetSnapPoint(sal_uInt32 nSnapPnt
) const
2490 sal_uInt32 nPoly
,nPnt
;
2491 if(!PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nSnapPnt
, nPoly
, nPnt
))
2493 DBG_ASSERT(FALSE
,"SdrPathObj::GetSnapPoint: Punkt nSnapPnt nicht vorhanden!");
2496 const basegfx::B2DPoint
aB2DPoint(GetPathPoly().getB2DPolygon(nPoly
).getB2DPoint(nPnt
));
2497 return Point(FRound(aB2DPoint
.getX()), FRound(aB2DPoint
.getY()));
2500 sal_Bool
SdrPathObj::IsPolyObj() const
2505 sal_uInt32
SdrPathObj::GetPointCount() const
2507 const sal_uInt32
nPolyCount(GetPathPoly().count());
2508 sal_uInt32
nRetval(0L);
2510 for(sal_uInt32
a(0L); a
< nPolyCount
; a
++)
2512 nRetval
+= GetPathPoly().getB2DPolygon(a
).count();
2518 Point
SdrPathObj::GetPoint(sal_uInt32 nHdlNum
) const
2521 sal_uInt32 nPoly
,nPnt
;
2523 if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum
, nPoly
, nPnt
))
2525 const basegfx::B2DPolygon
aPoly(GetPathPoly().getB2DPolygon(nPoly
));
2526 const basegfx::B2DPoint
aPoint(aPoly
.getB2DPoint(nPnt
));
2527 aRetval
= Point(FRound(aPoint
.getX()), FRound(aPoint
.getY()));
2533 void SdrPathObj::NbcSetPoint(const Point
& rPnt
, sal_uInt32 nHdlNum
)
2535 sal_uInt32 nPoly
,nPnt
;
2537 if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum
, nPoly
, nPnt
))
2539 basegfx::B2DPolygon
aNewPolygon(GetPathPoly().getB2DPolygon(nPoly
));
2540 aNewPolygon
.setB2DPoint(nPnt
, basegfx::B2DPoint(rPnt
.X(), rPnt
.Y()));
2541 maPathPolygon
.setB2DPolygon(nPoly
, aNewPolygon
);
2543 if(meKind
==OBJ_LINE
)
2549 if(GetPathPoly().count())
2551 // #i10659# for SdrTextObj, keep aRect up to date
2552 aRect
= ImpGetBoundRect(GetPathPoly()); // fuer SdrTextObj#
2560 sal_uInt32
SdrPathObj::NbcInsPointOld(const Point
& rPos
, sal_Bool bNewObj
, sal_Bool bHideHim
)
2566 nNewHdl
= NbcInsPoint(0L, rPos
, sal_True
, bHideHim
);
2570 // look for smallest distance data
2571 const basegfx::B2DPoint
aTestPoint(rPos
.X(), rPos
.Y());
2572 sal_uInt32
nSmallestPolyIndex(0L);
2573 sal_uInt32
nSmallestEdgeIndex(0L);
2574 double fSmallestCut
;
2575 basegfx::tools::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint
, nSmallestPolyIndex
, nSmallestEdgeIndex
, fSmallestCut
);
2577 // create old polygon index from it
2578 sal_uInt32
nPolyIndex(nSmallestEdgeIndex
);
2580 for(sal_uInt32
a(0L); a
< nSmallestPolyIndex
; a
++)
2582 nPolyIndex
+= GetPathPoly().getB2DPolygon(a
).count();
2585 nNewHdl
= NbcInsPoint(nPolyIndex
, rPos
, sal_False
, bHideHim
);
2592 sal_uInt32
SdrPathObj::NbcInsPoint(sal_uInt32
/*nHdlNum*/, const Point
& rPos
, sal_Bool bNewObj
, sal_Bool
/*bHideHim*/)
2598 basegfx::B2DPolygon aNewPoly
;
2599 const basegfx::B2DPoint
aPoint(rPos
.X(), rPos
.Y());
2600 aNewPoly
.append(aPoint
);
2601 aNewPoly
.setClosed(IsClosed());
2602 maPathPolygon
.append(aNewPoly
);
2604 nNewHdl
= GetHdlCount();
2608 // look for smallest distance data
2609 const basegfx::B2DPoint
aTestPoint(rPos
.X(), rPos
.Y());
2610 sal_uInt32
nSmallestPolyIndex(0L);
2611 sal_uInt32
nSmallestEdgeIndex(0L);
2612 double fSmallestCut
;
2613 basegfx::tools::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint
, nSmallestPolyIndex
, nSmallestEdgeIndex
, fSmallestCut
);
2614 basegfx::B2DPolygon
aCandidate(GetPathPoly().getB2DPolygon(nSmallestPolyIndex
));
2615 const bool bBefore(!aCandidate
.isClosed() && 0L == nSmallestEdgeIndex
&& 0.0 == fSmallestCut
);
2616 const bool bAfter(!aCandidate
.isClosed() && aCandidate
.count() == nSmallestEdgeIndex
+ 2L && 1.0 == fSmallestCut
);
2620 // before first point
2621 aCandidate
.insert(0L, aTestPoint
);
2623 if(aCandidate
.areControlPointsUsed())
2625 if(aCandidate
.isNextControlPointUsed(1))
2627 aCandidate
.setNextControlPoint(0, interpolate(aTestPoint
, aCandidate
.getB2DPoint(1), (1.0 / 3.0)));
2628 aCandidate
.setPrevControlPoint(1, interpolate(aTestPoint
, aCandidate
.getB2DPoint(1), (2.0 / 3.0)));
2637 aCandidate
.append(aTestPoint
);
2639 if(aCandidate
.areControlPointsUsed())
2641 if(aCandidate
.isPrevControlPointUsed(aCandidate
.count() - 2))
2643 aCandidate
.setNextControlPoint(aCandidate
.count() - 2, interpolate(aCandidate
.getB2DPoint(aCandidate
.count() - 2), aTestPoint
, (1.0 / 3.0)));
2644 aCandidate
.setPrevControlPoint(aCandidate
.count() - 1, interpolate(aCandidate
.getB2DPoint(aCandidate
.count() - 2), aTestPoint
, (2.0 / 3.0)));
2648 nNewHdl
= aCandidate
.count() - 1L;
2653 bool bSegmentSplit(false);
2654 const sal_uInt32
nNextIndex((nSmallestEdgeIndex
+ 1) % aCandidate
.count());
2656 if(aCandidate
.areControlPointsUsed())
2658 if(aCandidate
.isNextControlPointUsed(nSmallestEdgeIndex
) || aCandidate
.isPrevControlPointUsed(nNextIndex
))
2660 bSegmentSplit
= true;
2666 // rebuild original segment to get the split data
2667 basegfx::B2DCubicBezier aBezierA
, aBezierB
;
2668 const basegfx::B2DCubicBezier
aBezier(
2669 aCandidate
.getB2DPoint(nSmallestEdgeIndex
),
2670 aCandidate
.getNextControlPoint(nSmallestEdgeIndex
),
2671 aCandidate
.getPrevControlPoint(nNextIndex
),
2672 aCandidate
.getB2DPoint(nNextIndex
));
2674 // split and insert hit point
2675 aBezier
.split(fSmallestCut
, &aBezierA
, &aBezierB
);
2676 aCandidate
.insert(nSmallestEdgeIndex
+ 1, aTestPoint
);
2678 // since we inserted hit point and not split point, we need to add an offset
2679 // to the control points to get the C1 continuity we want to achieve
2680 const basegfx::B2DVector
aOffset(aTestPoint
- aBezierA
.getEndPoint());
2681 aCandidate
.setNextControlPoint(nSmallestEdgeIndex
, aBezierA
.getControlPointA() + aOffset
);
2682 aCandidate
.setPrevControlPoint(nSmallestEdgeIndex
+ 1, aBezierA
.getControlPointB() + aOffset
);
2683 aCandidate
.setNextControlPoint(nSmallestEdgeIndex
+ 1, aBezierB
.getControlPointA() + aOffset
);
2684 aCandidate
.setPrevControlPoint((nSmallestEdgeIndex
+ 2) % aCandidate
.count(), aBezierB
.getControlPointB() + aOffset
);
2688 aCandidate
.insert(nSmallestEdgeIndex
+ 1L, aTestPoint
);
2691 nNewHdl
= nSmallestEdgeIndex
+ 1L;
2694 maPathPolygon
.setB2DPolygon(nSmallestPolyIndex
, aCandidate
);
2696 // create old polygon index from it
2697 for(sal_uInt32
a(0L); a
< nSmallestPolyIndex
; a
++)
2699 nNewHdl
+= GetPathPoly().getB2DPolygon(a
).count();
2707 SdrObject
* SdrPathObj::RipPoint(sal_uInt32 nHdlNum
, sal_uInt32
& rNewPt0Index
)
2709 SdrPathObj
* pNewObj
= 0L;
2710 const basegfx::B2DPolyPolygon
aLocalPolyPolygon(GetPathPoly());
2711 sal_uInt32 nPoly
, nPnt
;
2713 if(PolyPolygonEditor::GetRelativePolyPoint(aLocalPolyPolygon
, nHdlNum
, nPoly
, nPnt
))
2717 const basegfx::B2DPolygon
aCandidate(aLocalPolyPolygon
.getB2DPolygon(nPoly
));
2718 const sal_uInt32
nPointCount(aCandidate
.count());
2724 // when closed, RipPoint means to open the polygon at the selected point. To
2725 // be able to do that, it is necessary to make the selected point the first one
2726 basegfx::B2DPolygon
aNewPolygon(basegfx::tools::makeStartPoint(aCandidate
, nPnt
));
2727 SetPathPoly(basegfx::B2DPolyPolygon(aNewPolygon
));
2730 // give back new position of old start point (historical reasons)
2731 rNewPt0Index
= (nPointCount
- nPnt
) % nPointCount
;
2735 if(nPointCount
>= 3L && nPnt
!= 0L && nPnt
+ 1L < nPointCount
)
2737 // split in two objects at point nPnt
2738 basegfx::B2DPolygon
aSplitPolyA(aCandidate
, 0L, nPnt
+ 1L);
2739 SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyA
));
2741 pNewObj
= (SdrPathObj
*)Clone();
2742 basegfx::B2DPolygon
aSplitPolyB(aCandidate
, nPnt
, nPointCount
- nPnt
);
2743 pNewObj
->SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyB
));
2753 SdrObject
* SdrPathObj::DoConvertToPolyObj(BOOL bBezier
) const
2755 // #i89784# check for FontWork with activated HideContour
2756 bool bHideContour(false);
2759 drawinglayer::attribute::SdrTextAttribute
* pText
= drawinglayer::primitive2d::createNewSdrTextAttribute(GetObjectItemSet(), *getText(0));
2760 bHideContour
= pText
&& pText
->getSdrFormTextAttribute() && pText
->isHideContour();
2764 SdrObject
* pRet
= bHideContour
?
2766 ImpConvertMakeObj(GetPathPoly(), IsClosed(), bBezier
);
2768 SdrPathObj
* pPath
= PTR_CAST(SdrPathObj
, pRet
);
2772 if(pPath
->GetPathPoly().areControlPointsUsed())
2776 // reduce all bezier curves
2777 pPath
->SetPathPoly(basegfx::tools::adaptiveSubdivideByAngle(pPath
->GetPathPoly()));
2784 // create bezier curves
2785 pPath
->SetPathPoly(basegfx::tools::expandToCurve(pPath
->GetPathPoly()));
2790 pRet
= ImpConvertAddText(pRet
, bBezier
);
2795 SdrObjGeoData
* SdrPathObj::NewGeoData() const
2797 return new SdrPathObjGeoData
;
2800 void SdrPathObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
2802 SdrTextObj::SaveGeoData(rGeo
);
2803 SdrPathObjGeoData
& rPGeo
= (SdrPathObjGeoData
&) rGeo
;
2804 rPGeo
.maPathPolygon
=GetPathPoly();
2805 rPGeo
.meKind
=meKind
;
2808 void SdrPathObj::RestGeoData(const SdrObjGeoData
& rGeo
)
2810 SdrTextObj::RestGeoData(rGeo
);
2811 SdrPathObjGeoData
& rPGeo
=(SdrPathObjGeoData
&)rGeo
;
2812 maPathPolygon
=rPGeo
.maPathPolygon
;
2813 meKind
=rPGeo
.meKind
;
2814 ImpForceKind(); // damit u.a. bClosed gesetzt wird
2817 void SdrPathObj::NbcSetPathPoly(const basegfx::B2DPolyPolygon
& rPathPoly
)
2819 if(GetPathPoly() != rPathPoly
)
2821 maPathPolygon
=rPathPoly
;
2827 void SdrPathObj::SetPathPoly(const basegfx::B2DPolyPolygon
& rPathPoly
)
2829 if(GetPathPoly() != rPathPoly
)
2831 Rectangle aBoundRect0
; if (pUserCall
!=NULL
) aBoundRect0
=GetLastBoundRect();
2832 NbcSetPathPoly(rPathPoly
);
2834 BroadcastObjectChange();
2835 SendUserCall(SDRUSERCALL_RESIZE
,aBoundRect0
);
2839 void SdrPathObj::ToggleClosed() // long nOpenDistance)
2841 Rectangle aBoundRect0
;
2842 if(pUserCall
!= NULL
)
2843 aBoundRect0
= GetLastBoundRect();
2844 ImpSetClosed(!IsClosed()); // neuen ObjKind setzen
2845 ImpForceKind(); // wg. Line->Poly->PolyLine statt Line->Poly->Line
2848 BroadcastObjectChange();
2849 SendUserCall(SDRUSERCALL_RESIZE
, aBoundRect0
);
2852 // fuer friend class SdrPolyEditView auf einigen Compilern:
2853 void SdrPathObj::SetRectsDirty(sal_Bool bNotMyself
)
2855 SdrTextObj::SetRectsDirty(bNotMyself
);
2858 ImpPathForDragAndCreate
& SdrPathObj::impGetDAC() const
2862 ((SdrPathObj
*)this)->mpDAC
= new ImpPathForDragAndCreate(*((SdrPathObj
*)this));
2868 void SdrPathObj::impDeleteDAC() const
2873 ((SdrPathObj
*)this)->mpDAC
= 0L;
2877 ////////////////////////////////////////////////////////////////////////////////////////////////////
2879 // transformation interface for StarOfficeAPI. This implements support for
2880 // homogen 3x3 matrices containing the transformation of the SdrObject. At the
2881 // moment it contains a shearX, rotation and translation, but for setting all linear
2882 // transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
2884 ////////////////////////////////////////////////////////////////////////////////////////////////////
2885 // gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
2886 // with the base geometry and returns TRUE. Otherwise it returns FALSE.
2887 sal_Bool
SdrPathObj::TRGetBaseGeometry(basegfx::B2DHomMatrix
& rMatrix
, basegfx::B2DPolyPolygon
& rPolyPolygon
) const
2889 double fRotate(0.0);
2890 double fShearX(0.0);
2891 basegfx::B2DTuple
aScale(1.0, 1.0);
2892 basegfx::B2DTuple
aTranslate(0.0, 0.0);
2894 if(GetPathPoly().count())
2897 basegfx::B2DHomMatrix aMoveToZeroMatrix
;
2898 rPolyPolygon
= GetPathPoly();
2900 if(OBJ_LINE
== meKind
)
2902 // ignore shear and rotate, just use scale and translate
2903 OSL_ENSURE(GetPathPoly().count() > 0L && GetPathPoly().getB2DPolygon(0L).count() > 1L, "OBJ_LINE with too less polygons (!)");
2904 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
2905 // itself, else this method will no longer return the full polygon information (curve will
2907 const basegfx::B2DRange
aPolyRangeNoCurve(basegfx::tools::getRange(rPolyPolygon
));
2908 aScale
= aPolyRangeNoCurve
.getRange();
2909 aTranslate
= aPolyRangeNoCurve
.getMinimum();
2911 // define matrix for move polygon to zero point
2912 aMoveToZeroMatrix
.translate(-aTranslate
.getX(), -aTranslate
.getY());
2916 if(aGeo
.nShearWink
|| aGeo
.nDrehWink
)
2918 // get rotate and shear in drawingLayer notation
2919 fRotate
= aGeo
.nDrehWink
* F_PI18000
;
2920 fShearX
= aGeo
.nShearWink
* F_PI18000
;
2922 // build mathematically correct (negative shear and rotate) object transform
2923 // containing shear and rotate to extract unsheared, unrotated polygon
2924 basegfx::B2DHomMatrix aObjectMatrix
;
2925 aObjectMatrix
.shearX(tan((36000 - aGeo
.nShearWink
) * F_PI18000
));
2926 aObjectMatrix
.rotate((36000 - aGeo
.nDrehWink
) * F_PI18000
);
2928 // create inverse from it and back-transform polygon
2929 basegfx::B2DHomMatrix
aInvObjectMatrix(aObjectMatrix
);
2930 aInvObjectMatrix
.invert();
2931 rPolyPolygon
.transform(aInvObjectMatrix
);
2933 // get range from unsheared, unrotated polygon and extract scale and translate.
2934 // transform topLeft from it back to transformed state to get original
2935 // topLeft (rotation center)
2936 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
2937 // itself, else this method will no longer return the full polygon information (curve will
2939 const basegfx::B2DRange
aCorrectedRangeNoCurve(basegfx::tools::getRange(rPolyPolygon
));
2940 aTranslate
= aObjectMatrix
* aCorrectedRangeNoCurve
.getMinimum();
2941 aScale
= aCorrectedRangeNoCurve
.getRange();
2943 // define matrix for move polygon to zero point
2944 aMoveToZeroMatrix
.translate(-aCorrectedRangeNoCurve
.getMinX(), aCorrectedRangeNoCurve
.getMinY());
2948 // get scale and translate from unsheared, unrotated polygon
2949 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
2950 // itself, else this method will no longer return the full polygon information (curve will
2952 const basegfx::B2DRange
aPolyRangeNoCurve(basegfx::tools::getRange(rPolyPolygon
));
2953 aScale
= aPolyRangeNoCurve
.getRange();
2954 aTranslate
= aPolyRangeNoCurve
.getMinimum();
2956 // define matrix for move polygon to zero point
2957 aMoveToZeroMatrix
.translate(-aTranslate
.getX(), -aTranslate
.getY());
2961 // move polygon to zero point with pre-defined matrix
2962 rPolyPolygon
.transform(aMoveToZeroMatrix
);
2965 // position maybe relative to anchorpos, convert
2966 if( pModel
&& pModel
->IsWriter() )
2968 if(GetAnchorPos().X() || GetAnchorPos().Y())
2970 aTranslate
-= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
2974 // force MapUnit to 100th mm
2975 SfxMapUnit eMapUnit
= GetObjectItemSet().GetPool()->GetMetric(0);
2976 if(eMapUnit
!= SFX_MAPUNIT_100TH_MM
)
2980 case SFX_MAPUNIT_TWIP
:
2983 aTranslate
.setX(ImplTwipsToMM(aTranslate
.getX()));
2984 aTranslate
.setY(ImplTwipsToMM(aTranslate
.getY()));
2987 aScale
.setX(ImplTwipsToMM(aScale
.getX()));
2988 aScale
.setY(ImplTwipsToMM(aScale
.getY()));
2991 basegfx::B2DHomMatrix aTwipsToMM
;
2992 const double fFactorTwipsToMM(127.0 / 72.0);
2993 aTwipsToMM
.scale(fFactorTwipsToMM
, fFactorTwipsToMM
);
2994 rPolyPolygon
.transform(aTwipsToMM
);
3000 DBG_ERROR("TRGetBaseGeometry: Missing unit translation to 100th mm!");
3005 // build return value matrix
3008 if(!basegfx::fTools::equal(aScale
.getX(), 1.0) || !basegfx::fTools::equal(aScale
.getY(), 1.0))
3010 rMatrix
.scale(aScale
.getX(), aScale
.getY());
3013 if(!basegfx::fTools::equalZero(fShearX
))
3015 rMatrix
.shearX(tan(fShearX
));
3018 if(!basegfx::fTools::equalZero(fRotate
))
3021 // fRotate is from the old GeoStat and thus mathematically wrong orientated. For
3022 // the linear combination of matrices it needed to be fixed in the API, so it needs to
3024 rMatrix
.rotate(-fRotate
);
3027 if(!aTranslate
.equalZero())
3029 rMatrix
.translate(aTranslate
.getX(), aTranslate
.getY());
3035 // sets the base geometry of the object using infos contained in the homogen 3x3 matrix.
3036 // If it's an SdrPathObj it will use the provided geometry information. The Polygon has
3037 // to use (0,0) as upper left and will be scaled to the given size in the matrix.
3038 void SdrPathObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& rPolyPolygon
)
3041 basegfx::B2DTuple aScale
;
3042 basegfx::B2DTuple aTranslate
;
3043 double fRotate
, fShearX
;
3044 rMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
3046 // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
3047 // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
3048 if(basegfx::fTools::less(aScale
.getX(), 0.0) && basegfx::fTools::less(aScale
.getY(), 0.0))
3050 aScale
.setX(fabs(aScale
.getX()));
3051 aScale
.setY(fabs(aScale
.getY()));
3052 fRotate
= fmod(fRotate
+ F_PI
, F_2PI
);
3056 basegfx::B2DPolyPolygon
aNewPolyPolygon(rPolyPolygon
);
3058 // reset object shear and rotations
3060 aGeo
.RecalcSinCos();
3061 aGeo
.nShearWink
= 0;
3064 // force metric to pool metric
3065 SfxMapUnit eMapUnit
= GetObjectItemSet().GetPool()->GetMetric(0);
3066 if(eMapUnit
!= SFX_MAPUNIT_100TH_MM
)
3070 case SFX_MAPUNIT_TWIP
:
3073 aTranslate
.setX(ImplMMToTwips(aTranslate
.getX()));
3074 aTranslate
.setY(ImplMMToTwips(aTranslate
.getY()));
3077 aScale
.setX(ImplMMToTwips(aScale
.getX()));
3078 aScale
.setY(ImplMMToTwips(aScale
.getY()));
3081 basegfx::B2DHomMatrix aMMToTwips
;
3082 const double fFactorMMToTwips(72.0 / 127.0);
3083 aMMToTwips
.scale(fFactorMMToTwips
, fFactorMMToTwips
);
3084 aNewPolyPolygon
.transform(aMMToTwips
);
3090 DBG_ERROR("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
3095 if( pModel
&& pModel
->IsWriter() )
3097 // if anchor is used, make position relative to it
3098 if(GetAnchorPos().X() || GetAnchorPos().Y())
3100 aTranslate
+= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
3104 // create transformation for polygon, set values at aGeo direct
3105 basegfx::B2DHomMatrix aTransform
;
3108 // Given polygon is already scaled (for historical reasons), but not mirrored yet.
3109 // Thus, when scale is negative in X or Y, apply the needed mirroring accordingly.
3110 if(basegfx::fTools::less(aScale
.getX(), 0.0) || basegfx::fTools::less(aScale
.getY(), 0.0))
3113 basegfx::fTools::less(aScale
.getX(), 0.0) ? -1.0 : 1.0,
3114 basegfx::fTools::less(aScale
.getY(), 0.0) ? -1.0 : 1.0);
3117 if(!basegfx::fTools::equalZero(fShearX
))
3119 aTransform
.shearX(tan(-atan(fShearX
)));
3120 aGeo
.nShearWink
= FRound(atan(fShearX
) / F_PI18000
);
3124 if(!basegfx::fTools::equalZero(fRotate
))
3127 // fRotate is matematically correct for linear transformations, so it's
3128 // the one to use for the geometry change
3129 aTransform
.rotate(fRotate
);
3132 // fRotate is matematically correct, but aGeoStat.nDrehWink is
3133 // mirrored -> mirror value here
3134 aGeo
.nDrehWink
= NormAngle360(FRound(-fRotate
/ F_PI18000
));
3135 aGeo
.RecalcSinCos();
3138 if(!aTranslate
.equalZero())
3140 // #i39529# absolute positioning, so get current position (without control points (!))
3141 const basegfx::B2DRange
aCurrentRange(basegfx::tools::getRange(aNewPolyPolygon
));
3142 aTransform
.translate(aTranslate
.getX() - aCurrentRange
.getMinX(), aTranslate
.getY() - aCurrentRange
.getMinY());
3145 // transform polygon and trigger change
3146 aNewPolyPolygon
.transform(aTransform
);
3147 SetPathPoly(aNewPolyPolygon
);
3150 //////////////////////////////////////////////////////////////////////////////