1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <tools/bigint.hxx>
31 #include <svx/svdopath.hxx>
33 #include <svx/xpool.hxx>
34 #include <svx/xpoly.hxx>
35 #include <svx/svdattr.hxx>
36 #include <svx/svdtrans.hxx>
37 #include <svx/svdetc.hxx>
38 #include <svx/svddrag.hxx>
39 #include <svx/svdmodel.hxx>
40 #include <svx/svdpage.hxx>
41 #include <svx/svdhdl.hxx>
42 #include <svx/svdview.hxx> // for MovCreate when using curves
43 #include "svx/svdglob.hxx" // Stringcache
44 #include "svx/svdstr.hrc" // the object's name
47 #pragma optimize ("",off)
48 #pragma warning(disable: 4748) // "... because optimizations are disabled ..."
51 #include <svx/xlnwtit.hxx>
52 #include <svx/xlnclit.hxx>
53 #include <svx/xflclit.hxx>
54 #include <svx/svdogrp.hxx>
55 #include <svx/polypolygoneditor.hxx>
56 #include <svx/xlntrit.hxx>
57 #include <vcl/salbtype.hxx> // FRound
58 #include <svx/sdr/contact/viewcontactofsdrpathobj.hxx>
59 #include <basegfx/matrix/b2dhommatrix.hxx>
60 #include "svdconv.hxx"
61 #include <basegfx/point/b2dpoint.hxx>
62 #include <basegfx/polygon/b2dpolypolygontools.hxx>
63 #include <basegfx/range/b2drange.hxx>
64 #include <basegfx/curve/b2dcubicbezier.hxx>
65 #include <basegfx/polygon/b2dpolygontools.hxx>
66 #include <svx/sdr/attribute/sdrtextattribute.hxx>
67 #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
68 #include <basegfx/matrix/b2dhommatrixtools.hxx>
69 #include <svx/sdr/attribute/sdrformtextattribute.hxx>
73 inline sal_uInt16
GetPrevPnt(sal_uInt16 nPnt
, sal_uInt16 nPntMax
, bool bClosed
)
84 inline sal_uInt16
GetNextPnt(sal_uInt16 nPnt
, sal_uInt16 nPntMax
, bool bClosed
)
87 if (nPnt
>nPntMax
|| (bClosed
&& nPnt
>=nPntMax
)) nPnt
=0;
91 struct ImpSdrPathDragData
: public SdrDragStatUserData
93 XPolygon aXP
; // section of the original polygon
94 bool bValid
; // FALSE = too few points
95 bool bClosed
; // closed object?
96 sal_uInt16 nPoly
; // number of the polygon in the PolyPolygon
97 sal_uInt16 nPnt
; // number of point in the above polygon
98 sal_uInt16 nPntAnz
; // number of points of the polygon
99 sal_uInt16 nPntMax
; // maximum index
100 bool bBegPnt
; // dragged point is first point of a Polyline
101 bool bEndPnt
; // dragged point is finishing point of a Polyline
102 sal_uInt16 nPrevPnt
; // index of previous point
103 sal_uInt16 nNextPnt
; // index of next point
104 bool bPrevIsBegPnt
; // previous point is first point of a Polyline
105 bool bNextIsEndPnt
; // next point is first point of a Polyline
106 sal_uInt16 nPrevPrevPnt
; // index of point before previous point
107 sal_uInt16 nNextNextPnt
; // index of point after next point
108 bool bControl
; // point is a control point
109 bool bIsPrevControl
; // point is a control point before a support point
110 bool bIsNextControl
; // point is a control point after a support point
111 bool bPrevIsControl
; // if nPnt is a support point: a control point comes before
112 bool bNextIsControl
; // if nPnt is a support point: a control point comes after
113 sal_uInt16 nPrevPrevPnt0
;
114 sal_uInt16 nPrevPnt0
;
116 sal_uInt16 nNextPnt0
;
117 sal_uInt16 nNextNextPnt0
;
118 bool bEliminate
; // delete point? (is set by MovDrag)
120 sal_Bool mbMultiPointDrag
;
121 const XPolyPolygon maOrig
;
126 ImpSdrPathDragData(const SdrPathObj
& rPO
, const SdrHdl
& rHdl
, sal_Bool bMuPoDr
, const SdrDragStat
& rDrag
);
127 void ResetPoly(const SdrPathObj
& rPO
);
128 sal_Bool
IsMultiPointDrag() const { return mbMultiPointDrag
; }
131 ImpSdrPathDragData::ImpSdrPathDragData(const SdrPathObj
& rPO
, const SdrHdl
& rHdl
, sal_Bool bMuPoDr
, const SdrDragStat
& rDrag
)
133 mbMultiPointDrag(bMuPoDr
),
134 maOrig(rPO
.GetPathPoly()),
139 const SdrMarkView
& rMarkView
= *rDrag
.GetView();
140 const SdrHdlList
& rHdlList
= rMarkView
.GetHdlList();
141 const sal_uInt32 nHdlCount
= rHdlList
.GetHdlCount();
142 const SdrObject
* pInteractionObject(nHdlCount
&& rHdlList
.GetHdl(0) ? rHdlList
.GetHdl(0)->GetObj() : 0);
144 for(sal_uInt32
a(0); a
< nHdlCount
; a
++)
146 SdrHdl
* pTestHdl
= rHdlList
.GetHdl(a
);
148 if(pTestHdl
&& pTestHdl
->IsSelected() && pTestHdl
->GetObj() == pInteractionObject
)
150 maHandles
.Insert(pTestHdl
, CONTAINER_APPEND
);
160 bClosed
=rPO
.IsClosed(); // closed object?
161 nPoly
=(sal_uInt16
)rHdl
.GetPolyNum(); // number of the polygon in the PolyPolygon
162 nPnt
=(sal_uInt16
)rHdl
.GetPointNum(); // number of points in the above polygon
163 const XPolygon
aTmpXP(rPO
.GetPathPoly().getB2DPolygon(nPoly
));
164 nPntAnz
=aTmpXP
.GetPointCount(); // number of point of the polygon
165 if (nPntAnz
==0 || (bClosed
&& nPntAnz
==1)) return; // minimum of 1 points for Lines, minimum of 2 points for Polygon
166 nPntMax
=nPntAnz
-1; // maximum index
167 bBegPnt
=!bClosed
&& nPnt
==0; // dragged point is first point of a Polyline
168 bEndPnt
=!bClosed
&& nPnt
==nPntMax
; // dragged point is finishing point of a Polyline
169 if (bClosed
&& nPntAnz
<=3) { // if polygon is only a line
170 bBegPnt
=(nPntAnz
<3) || nPnt
==0;
171 bEndPnt
=(nPntAnz
<3) || nPnt
==nPntMax
-1;
173 nPrevPnt
=nPnt
; // index of previous point
174 nNextPnt
=nPnt
; // index of next point
175 if (!bBegPnt
) nPrevPnt
=GetPrevPnt(nPnt
,nPntMax
,bClosed
);
176 if (!bEndPnt
) nNextPnt
=GetNextPnt(nPnt
,nPntMax
,bClosed
);
177 bPrevIsBegPnt
=bBegPnt
|| (!bClosed
&& nPrevPnt
==0);
178 bNextIsEndPnt
=bEndPnt
|| (!bClosed
&& nNextPnt
==nPntMax
);
179 nPrevPrevPnt
=nPnt
; // index of point before previous point
180 nNextNextPnt
=nPnt
; // index of point after next point
181 if (!bPrevIsBegPnt
) nPrevPrevPnt
=GetPrevPnt(nPrevPnt
,nPntMax
,bClosed
);
182 if (!bNextIsEndPnt
) nNextNextPnt
=GetNextPnt(nNextPnt
,nPntMax
,bClosed
);
183 bControl
=rHdl
.IsPlusHdl(); // point is a control point
184 bIsPrevControl
=sal_False
; // point is a control point before a support point
185 bIsNextControl
=sal_False
; // point is a control point after a support point
186 bPrevIsControl
=sal_False
; // if nPnt is a support point: a control point comes before
187 bNextIsControl
=sal_False
; // if nPnt is a support point: a control point comes after
189 bIsPrevControl
=aTmpXP
.IsControl(nPrevPnt
);
190 bIsNextControl
=!bIsPrevControl
;
192 bPrevIsControl
=!bBegPnt
&& !bPrevIsBegPnt
&& aTmpXP
.GetFlags(nPrevPnt
)==XPOLY_CONTROL
;
193 bNextIsControl
=!bEndPnt
&& !bNextIsEndPnt
&& aTmpXP
.GetFlags(nNextPnt
)==XPOLY_CONTROL
;
195 nPrevPrevPnt0
=nPrevPrevPnt
;
199 nNextNextPnt0
=nNextNextPnt
;
205 bEliminate
=sal_False
;
211 void ImpSdrPathDragData::ResetPoly(const SdrPathObj
& rPO
)
213 const XPolygon
aTmpXP(rPO
.GetPathPoly().getB2DPolygon(nPoly
));
214 aXP
[0]=aTmpXP
[nPrevPrevPnt0
]; aXP
.SetFlags(0,aTmpXP
.GetFlags(nPrevPrevPnt0
));
215 aXP
[1]=aTmpXP
[nPrevPnt0
]; aXP
.SetFlags(1,aTmpXP
.GetFlags(nPrevPnt0
));
216 aXP
[2]=aTmpXP
[nPnt0
]; aXP
.SetFlags(2,aTmpXP
.GetFlags(nPnt0
));
217 aXP
[3]=aTmpXP
[nNextPnt0
]; aXP
.SetFlags(3,aTmpXP
.GetFlags(nNextPnt0
));
218 aXP
[4]=aTmpXP
[nNextNextPnt0
]; aXP
.SetFlags(4,aTmpXP
.GetFlags(nNextNextPnt0
));
221 /*************************************************************************/
223 struct ImpPathCreateUser
: public SdrDragStatUserData
250 sal_uInt16 nBezierStartPoint
;
251 SdrObjKind eStartKind
;
255 ImpPathCreateUser(): nCircRadius(0),nCircStWink(0),nCircRelWink(0),
256 bBezier(sal_False
),bBezHasCtrl0(sal_False
),bCurve(sal_False
),bCircle(sal_False
),bAngleSnap(sal_False
),bLine(sal_False
),bLine90(sal_False
),bRect(sal_False
),
257 bMixedCreate(sal_False
),nBezierStartPoint(0),eStartKind(OBJ_NONE
),eAktKind(OBJ_NONE
) { }
259 void ResetFormFlags() { bBezier
=sal_False
; bCurve
=sal_False
; bCircle
=sal_False
; bLine
=sal_False
; bRect
=sal_False
; }
260 bool IsFormFlag() const { return bBezier
|| bCurve
|| bCircle
|| bLine
|| bRect
; }
261 XPolygon
GetFormPoly() const;
262 bool CalcBezier(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, bool bMouseDown
);
263 XPolygon
GetBezierPoly() const;
264 XPolygon
GetCurvePoly() const { return XPolygon(); }
265 bool CalcCircle(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
);
266 XPolygon
GetCirclePoly() const;
267 bool CalcLine(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
);
268 Point
CalcLine(const Point
& rCsr
, long nDirX
, long nDirY
, SdrView
* pView
) const;
269 XPolygon
GetLinePoly() const;
270 bool CalcRect(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
);
271 XPolygon
GetRectPoly() const;
274 XPolygon
ImpPathCreateUser::GetFormPoly() const
276 if (bBezier
) return GetBezierPoly();
277 if (bCurve
) return GetCurvePoly();
278 if (bCircle
) return GetCirclePoly();
279 if (bLine
) return GetLinePoly();
280 if (bRect
) return GetRectPoly();
284 bool ImpPathCreateUser::CalcBezier(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, bool bMouseDown
)
292 // Also copy the end point when no end point is set yet
293 if (!bMouseDown
|| (0L == aBezEnd
.X() && 0L == aBezEnd
.Y())) aBezEnd
=rP2
;
299 XPolygon
ImpPathCreateUser::GetBezierPoly() const
302 aXP
[0]=aBezStart
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
303 aXP
[1]=aBezCtrl1
; aXP
.SetFlags(1,XPOLY_CONTROL
);
304 aXP
[2]=aBezCtrl2
; aXP
.SetFlags(2,XPOLY_CONTROL
);
309 bool ImpPathCreateUser::CalcCircle(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
)
311 long nTangAngle
=GetAngle(rDir
);
315 long dx
=rP2
.X()-rP1
.X();
316 long dy
=rP2
.Y()-rP1
.Y();
317 long dAngle
=GetAngle(Point(dx
,dy
))-nTangAngle
;
318 dAngle
=NormAngle360(dAngle
);
319 long nTmpAngle
=NormAngle360(9000-dAngle
);
320 bool bRet
=nTmpAngle
!=9000 && nTmpAngle
!=27000;
323 double cs
=cos(nTmpAngle
*nPi180
);
324 double nR
=(double)GetLen(Point(dx
,dy
))/cs
/2;
328 nCircStWink
=NormAngle360(nTangAngle
-9000);
329 nCircRelWink
=NormAngle360(2*dAngle
);
330 aCircCenter
.X()+=Round(nRad
*cos((nTangAngle
+9000)*nPi180
));
331 aCircCenter
.Y()-=Round(nRad
*sin((nTangAngle
+9000)*nPi180
));
333 nCircStWink
=NormAngle360(nTangAngle
+9000);
334 nCircRelWink
=-NormAngle360(36000-2*dAngle
);
335 aCircCenter
.X()+=Round(nRad
*cos((nTangAngle
-9000)*nPi180
));
336 aCircCenter
.Y()-=Round(nRad
*sin((nTangAngle
-9000)*nPi180
));
338 bAngleSnap
=pView
!=NULL
&& pView
->IsAngleSnapEnabled();
340 long nSA
=pView
->GetSnapAngle();
341 if (nSA
!=0) { // angle snapping
342 bool bNeg
=nCircRelWink
<0;
343 if (bNeg
) nCircRelWink
=-nCircRelWink
;
347 nCircRelWink
=NormAngle360(nCircRelWink
);
348 if (bNeg
) nCircRelWink
=-nCircRelWink
;
352 if (nRad
==0 || Abs(nCircRelWink
)<5) bRet
=sal_False
;
357 XPolygon
ImpPathCreateUser::GetCirclePoly() const
359 if (nCircRelWink
>=0) {
360 XPolygon
aXP(aCircCenter
,nCircRadius
,nCircRadius
,
361 sal_uInt16((nCircStWink
+5)/10),sal_uInt16((nCircStWink
+nCircRelWink
+5)/10),sal_False
);
362 aXP
[0]=aCircStart
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
363 if (!bAngleSnap
) aXP
[aXP
.GetPointCount()-1]=aCircEnd
;
366 XPolygon
aXP(aCircCenter
,nCircRadius
,nCircRadius
,
367 sal_uInt16(NormAngle360(nCircStWink
+nCircRelWink
+5)/10),sal_uInt16((nCircStWink
+5)/10),sal_False
);
368 sal_uInt16 nAnz
=aXP
.GetPointCount();
369 for (sal_uInt16 nNum
=nAnz
/2; nNum
>0;) {
370 nNum
--; // reverse XPoly's order of points
371 sal_uInt16 n2
=nAnz
-nNum
-1;
372 Point
aPt(aXP
[nNum
]);
376 aXP
[0]=aCircStart
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
377 if (!bAngleSnap
) aXP
[aXP
.GetPointCount()-1]=aCircEnd
;
382 Point
ImpPathCreateUser::CalcLine(const Point
& aCsr
, long nDirX
, long nDirY
, SdrView
* pView
) const
384 long x
=aCsr
.X(),x1
=x
,x2
=x
;
385 long y
=aCsr
.Y(),y1
=y
,y2
=y
;
391 x1
=BigMulDiv(y
,nDirX
,nDirY
);
392 y2
=BigMulDiv(x
,nDirY
,nDirX
);
393 long l1
=Abs(x1
)+Abs(y1
);
394 long l2
=Abs(x2
)+Abs(y2
);
395 if ((l1
<=l2
) != (pView
!=NULL
&& pView
->IsBigOrtho())) {
404 bool ImpPathCreateUser::CalcLine(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
)
409 if (rP1
==rP2
|| (rDir
.X()==0 && rDir
.Y()==0)) { bLine
=sal_False
; return sal_False
; }
410 Point
aTmpPt(rP2
-rP1
);
413 Point
aP1(CalcLine(aTmpPt
, nDirX
, nDirY
,pView
)); aP1
-=aTmpPt
; long nQ1
=Abs(aP1
.X())+Abs(aP1
.Y());
414 Point
aP2(CalcLine(aTmpPt
, nDirY
,-nDirX
,pView
)); aP2
-=aTmpPt
; long nQ2
=Abs(aP2
.X())+Abs(aP2
.Y());
415 if (pView
!=NULL
&& pView
->IsOrtho()) nQ1
=0; // Ortho turns off at right angle
417 if (!bLine90
) { // smooth transition
419 } else { // rectangular transition
426 XPolygon
ImpPathCreateUser::GetLinePoly() const
429 aXP
[0]=aLineStart
; if (!bLine90
) aXP
.SetFlags(0,XPOLY_SMOOTH
);
434 bool ImpPathCreateUser::CalcRect(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
)
439 if (rP1
==rP2
|| (rDir
.X()==0 && rDir
.Y()==0)) { bRect
=sal_False
; return sal_False
; }
440 Point
aTmpPt(rP2
-rP1
);
450 y
=BigMulDiv(x
,nDirY
,nDirX
);
451 long nHypLen
=aTmpPt
.Y()-y
;
452 long nTangAngle
=-GetAngle(rDir
);
454 double a
=nTangAngle
*nPi180
;
457 double nGKathLen
=nHypLen
*sn
;
458 y
+=Round(nGKathLen
*sn
);
459 x
+=Round(nGKathLen
*cs
);
463 if (pView
!=NULL
&& pView
->IsOrtho()) {
464 long dx1
=aRectP2
.X()-aRectP1
.X(); long dx1a
=Abs(dx1
);
465 long dy1
=aRectP2
.Y()-aRectP1
.Y(); long dy1a
=Abs(dy1
);
466 long dx2
=aRectP3
.X()-aRectP2
.X(); long dx2a
=Abs(dx2
);
467 long dy2
=aRectP3
.Y()-aRectP2
.Y(); long dy2a
=Abs(dy2
);
468 bool b1MoreThan2
=dx1a
+dy1a
>dx2a
+dy2a
;
469 if (b1MoreThan2
!= pView
->IsBigOrtho()) {
470 long xtemp
=dy2a
-dx1a
; if (dx1
<0) xtemp
=-xtemp
;
471 long ytemp
=dx2a
-dy1a
; if (dy1
<0) ytemp
=-ytemp
;
477 long xtemp
=dy1a
-dx2a
; if (dx2
<0) xtemp
=-xtemp
;
478 long ytemp
=dx1a
-dy2a
; if (dy2
<0) ytemp
=-ytemp
;
487 XPolygon
ImpPathCreateUser::GetRectPoly() const
490 aXP
[0]=aRectP1
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
492 if (aRectP3
!=aRectP2
) aXP
[2]=aRectP3
;
496 /*************************************************************************/
498 class ImpPathForDragAndCreate
500 SdrPathObj
& mrSdrPathObject
;
501 XPolyPolygon aPathPolygon
;
502 SdrObjKind meObjectKind
;
503 ImpSdrPathDragData
* mpSdrPathDragData
;
507 ImpPathForDragAndCreate(SdrPathObj
& rSdrPathObject
);
508 ~ImpPathForDragAndCreate();
511 bool beginPathDrag( SdrDragStat
& rDrag
) const;
512 bool movePathDrag( SdrDragStat
& rDrag
) const;
513 bool endPathDrag( SdrDragStat
& rDrag
);
514 String
getSpecialDragComment(const SdrDragStat
& rDrag
) const;
515 basegfx::B2DPolyPolygon
getSpecialDragPoly(const SdrDragStat
& rDrag
) const;
518 bool BegCreate(SdrDragStat
& rStat
);
519 bool MovCreate(SdrDragStat
& rStat
);
520 bool EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
);
521 bool BckCreate(SdrDragStat
& rStat
);
522 void BrkCreate(SdrDragStat
& rStat
);
523 Pointer
GetCreatePointer() const;
526 bool IsClosed(SdrObjKind eKind
) const { return eKind
==OBJ_POLY
|| eKind
==OBJ_PATHPOLY
|| eKind
==OBJ_PATHFILL
|| eKind
==OBJ_FREEFILL
|| eKind
==OBJ_SPLNFILL
; }
527 bool IsFreeHand(SdrObjKind eKind
) const { return eKind
==OBJ_FREELINE
|| eKind
==OBJ_FREEFILL
; }
528 bool IsBezier(SdrObjKind eKind
) const { return eKind
==OBJ_PATHLINE
|| eKind
==OBJ_PATHFILL
; }
529 bool IsCreating() const { return mbCreating
; }
532 basegfx::B2DPolyPolygon
TakeObjectPolyPolygon(const SdrDragStat
& rDrag
) const;
533 basegfx::B2DPolyPolygon
TakeDragPolyPolygon(const SdrDragStat
& rDrag
) const;
534 basegfx::B2DPolyPolygon
getModifiedPolyPolygon() const { return aPathPolygon
.getB2DPolyPolygon(); }
537 ImpPathForDragAndCreate::ImpPathForDragAndCreate(SdrPathObj
& rSdrPathObject
)
538 : mrSdrPathObject(rSdrPathObject
),
539 aPathPolygon(rSdrPathObject
.GetPathPoly()),
540 meObjectKind(mrSdrPathObject
.meKind
),
541 mpSdrPathDragData(0),
546 ImpPathForDragAndCreate::~ImpPathForDragAndCreate()
548 if(mpSdrPathDragData
)
550 delete mpSdrPathDragData
;
554 bool ImpPathForDragAndCreate::beginPathDrag( SdrDragStat
& rDrag
) const
556 const SdrHdl
* pHdl
=rDrag
.GetHdl();
560 sal_Bool
bMultiPointDrag(sal_True
);
562 if(aPathPolygon
[(sal_uInt16
)pHdl
->GetPolyNum()].IsControl((sal_uInt16
)pHdl
->GetPointNum()))
563 bMultiPointDrag
= sal_False
;
567 const SdrMarkView
& rMarkView
= *rDrag
.GetView();
568 const SdrHdlList
& rHdlList
= rMarkView
.GetHdlList();
569 const sal_uInt32 nHdlCount
= rHdlList
.GetHdlCount();
570 const SdrObject
* pInteractionObject(nHdlCount
&& rHdlList
.GetHdl(0) ? rHdlList
.GetHdl(0)->GetObj() : 0);
571 sal_uInt32
nSelectedPoints(0);
573 for(sal_uInt32
a(0); a
< nHdlCount
; a
++)
575 SdrHdl
* pTestHdl
= rHdlList
.GetHdl(a
);
577 if(pTestHdl
&& pTestHdl
->IsSelected() && pTestHdl
->GetObj() == pInteractionObject
)
583 if(nSelectedPoints
<= 1)
584 bMultiPointDrag
= sal_False
;
587 ((ImpPathForDragAndCreate
*)this)->mpSdrPathDragData
= new ImpSdrPathDragData(mrSdrPathObject
,*pHdl
,bMultiPointDrag
,rDrag
);
589 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
591 OSL_FAIL("ImpPathForDragAndCreate::BegDrag(): ImpSdrPathDragData is invalid.");
592 delete mpSdrPathDragData
;
593 ((ImpPathForDragAndCreate
*)this)->mpSdrPathDragData
= 0;
600 bool ImpPathForDragAndCreate::movePathDrag( SdrDragStat
& rDrag
) const
602 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
604 OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
608 if(mpSdrPathDragData
->IsMultiPointDrag())
610 Point
aDelta(rDrag
.GetNow() - rDrag
.GetStart());
612 if(aDelta
.X() || aDelta
.Y())
614 for(sal_uInt32
a(0); a
< mpSdrPathDragData
->maHandles
.Count(); a
++)
616 SdrHdl
* pHandle
= (SdrHdl
*)mpSdrPathDragData
->maHandles
.GetObject(a
);
617 const sal_uInt16
nPolyIndex((sal_uInt16
)pHandle
->GetPolyNum());
618 const sal_uInt16
nPointIndex((sal_uInt16
)pHandle
->GetPointNum());
619 const XPolygon
& rOrig
= mpSdrPathDragData
->maOrig
[nPolyIndex
];
620 XPolygon
& rMove
= mpSdrPathDragData
->maMove
[nPolyIndex
];
621 const sal_uInt16
nPointCount(rOrig
.GetPointCount());
622 sal_Bool
bClosed(rOrig
[0] == rOrig
[nPointCount
-1]);
625 rMove
[nPointIndex
] = rOrig
[nPointIndex
] + aDelta
;
627 // when point is first and poly closed, move close point, too.
628 if(nPointCount
> 0 && !nPointIndex
&& bClosed
)
630 rMove
[nPointCount
- 1] = rOrig
[nPointCount
- 1] + aDelta
;
632 // when moving the last point it may be necessary to move the
633 // control point in front of this one, too.
634 if(nPointCount
> 1 && rOrig
.IsControl(nPointCount
- 2))
635 rMove
[nPointCount
- 2] = rOrig
[nPointCount
- 2] + aDelta
;
638 // is a control point before this?
639 if(nPointIndex
> 0 && rOrig
.IsControl(nPointIndex
- 1))
642 rMove
[nPointIndex
- 1] = rOrig
[nPointIndex
- 1] + aDelta
;
645 // is a control point after this?
646 if(nPointIndex
+ 1 < nPointCount
&& rOrig
.IsControl(nPointIndex
+ 1))
649 rMove
[nPointIndex
+ 1] = rOrig
[nPointIndex
+ 1] + aDelta
;
656 mpSdrPathDragData
->ResetPoly(mrSdrPathObject
);
658 // copy certain data locally to use less code and have faster access times
659 bool bClosed
=mpSdrPathDragData
->bClosed
; // closed object?
660 sal_uInt16 nPnt
=mpSdrPathDragData
->nPnt
; // number of point in the above polygon
661 bool bBegPnt
=mpSdrPathDragData
->bBegPnt
; // dragged point is first point of a Polyline
662 bool bEndPnt
=mpSdrPathDragData
->bEndPnt
; // dragged point is last point of a Polyline
663 sal_uInt16 nPrevPnt
=mpSdrPathDragData
->nPrevPnt
; // index of previous point
664 sal_uInt16 nNextPnt
=mpSdrPathDragData
->nNextPnt
; // index of next point
665 bool bPrevIsBegPnt
=mpSdrPathDragData
->bPrevIsBegPnt
; // previous point is first point of a Polyline
666 bool bNextIsEndPnt
=mpSdrPathDragData
->bNextIsEndPnt
; // next point is last point of a Polyline
667 sal_uInt16 nPrevPrevPnt
=mpSdrPathDragData
->nPrevPrevPnt
; // index of the point before the previous point
668 sal_uInt16 nNextNextPnt
=mpSdrPathDragData
->nNextNextPnt
; // index if the point after the next point
669 bool bControl
=mpSdrPathDragData
->bControl
; // point is a control point
670 bool bIsNextControl
=mpSdrPathDragData
->bIsNextControl
; // point is a control point after a support point
671 bool bPrevIsControl
=mpSdrPathDragData
->bPrevIsControl
; // if nPnt is a support point: there's a control point before
672 bool bNextIsControl
=mpSdrPathDragData
->bNextIsControl
; // if nPnt is a support point: there's a control point after
674 // Ortho for lines/polygons: keep angle
675 if (!bControl
&& rDrag
.GetView()!=NULL
&& rDrag
.GetView()->IsOrtho()) {
676 bool bBigOrtho
=rDrag
.GetView()->IsBigOrtho();
677 Point
aPos(rDrag
.GetNow()); // current position
678 Point
aPnt(mpSdrPathDragData
->aXP
[nPnt
]); // the dragged point
679 sal_uInt16 nPnt1
=0xFFFF,nPnt2
=0xFFFF; // its neighboring points
680 Point aNeuPos1
,aNeuPos2
; // new alternative for aPos
681 bool bPnt1
= false, bPnt2
= false; // are these valid alternatives?
682 if (!bClosed
&& mpSdrPathDragData
->nPntAnz
>=2) { // minimum of 2 points for lines
683 if (!bBegPnt
) nPnt1
=nPrevPnt
;
684 if (!bEndPnt
) nPnt2
=nNextPnt
;
686 if (bClosed
&& mpSdrPathDragData
->nPntAnz
>=3) { // minimum of 3 points for polygon
690 if (nPnt1
!=0xFFFF && !bPrevIsControl
) {
691 Point aPnt1
=mpSdrPathDragData
->aXP
[nPnt1
];
692 long ndx0
=aPnt
.X()-aPnt1
.X();
693 long ndy0
=aPnt
.Y()-aPnt1
.Y();
696 if (!bHLin
|| !bVLin
) {
697 long ndx
=aPos
.X()-aPnt1
.X();
698 long ndy
=aPos
.Y()-aPnt1
.Y();
700 double nXFact
=0; if (!bVLin
) nXFact
=(double)ndx
/(double)ndx0
;
701 double nYFact
=0; if (!bHLin
) nYFact
=(double)ndy
/(double)ndy0
;
702 bool bHor
=bHLin
|| (!bVLin
&& (nXFact
>nYFact
) ==bBigOrtho
);
703 bool bVer
=bVLin
|| (!bHLin
&& (nXFact
<=nYFact
)==bBigOrtho
);
704 if (bHor
) ndy
=long(ndy0
*nXFact
);
705 if (bVer
) ndx
=long(ndx0
*nYFact
);
711 if (nPnt2
!=0xFFFF && !bNextIsControl
) {
712 Point aPnt2
=mpSdrPathDragData
->aXP
[nPnt2
];
713 long ndx0
=aPnt
.X()-aPnt2
.X();
714 long ndy0
=aPnt
.Y()-aPnt2
.Y();
717 if (!bHLin
|| !bVLin
) {
718 long ndx
=aPos
.X()-aPnt2
.X();
719 long ndy
=aPos
.Y()-aPnt2
.Y();
721 double nXFact
=0; if (!bVLin
) nXFact
=(double)ndx
/(double)ndx0
;
722 double nYFact
=0; if (!bHLin
) nYFact
=(double)ndy
/(double)ndy0
;
723 bool bHor
=bHLin
|| (!bVLin
&& (nXFact
>nYFact
) ==bBigOrtho
);
724 bool bVer
=bVLin
|| (!bHLin
&& (nXFact
<=nYFact
)==bBigOrtho
);
725 if (bHor
) ndy
=long(ndy0
*nXFact
);
726 if (bVer
) ndx
=long(ndx0
*nYFact
);
732 if (bPnt1
&& bPnt2
) { // both alternatives exist (and compete)
733 BigInt
nX1(aNeuPos1
.X()-aPos
.X()); nX1
*=nX1
;
734 BigInt
nY1(aNeuPos1
.Y()-aPos
.Y()); nY1
*=nY1
;
735 BigInt
nX2(aNeuPos2
.X()-aPos
.X()); nX2
*=nX2
;
736 BigInt
nY2(aNeuPos2
.Y()-aPos
.Y()); nY2
*=nY2
;
737 nX1
+=nY1
; // correction distance to square
738 nX2
+=nY2
; // correction distance to square
739 // let the alternative that allows fewer correction win
740 if (nX1
<nX2
) bPnt2
=sal_False
; else bPnt1
=sal_False
;
742 if (bPnt1
) rDrag
.Now()=aNeuPos1
;
743 if (bPnt2
) rDrag
.Now()=aNeuPos2
;
745 rDrag
.SetActionRect(Rectangle(rDrag
.GetNow(),rDrag
.GetNow()));
747 // specially for IBM: Eliminate points if both adjoining lines form near 180 degrees angle anyway
748 if (!bControl
&& rDrag
.GetView()!=NULL
&& rDrag
.GetView()->IsEliminatePolyPoints() &&
749 !bBegPnt
&& !bEndPnt
&& !bPrevIsControl
&& !bNextIsControl
)
751 Point
aPt(mpSdrPathDragData
->aXP
[nNextPnt
]);
753 long nWink1
=GetAngle(aPt
);
755 aPt
-=mpSdrPathDragData
->aXP
[nPrevPnt
];
756 long nWink2
=GetAngle(aPt
);
757 long nDiff
=nWink1
-nWink2
;
759 mpSdrPathDragData
->bEliminate
=nDiff
<=rDrag
.GetView()->GetEliminatePolyPointLimitAngle();
760 if (mpSdrPathDragData
->bEliminate
) { // adapt position, Smooth is true for the ends
761 aPt
=mpSdrPathDragData
->aXP
[nNextPnt
];
762 aPt
+=mpSdrPathDragData
->aXP
[nPrevPnt
];
768 // we dragged by this distance
769 Point
aDiff(rDrag
.GetNow()); aDiff
-=mpSdrPathDragData
->aXP
[nPnt
];
771 /* There are 8 possible cases:
772 X 1. A control point neither on the left nor on the right.
773 o--X--o 2. There are control points on the left and the right, we are dragging a support point.
774 o--X 3. There is a control point on the left, we are dragging a support point.
775 X--o 4. There is a control point on the right, we are dragging a support point.
776 x--O--o 5. There are control points on the left and the right, we are dragging the left one.
777 x--O 6. There is a control point on the left, we are dragging it.
778 o--O--x 7. There are control points on the left and the right, we are dragging the right one.
779 O--x 8. There is a control point on the right, we are dragging it.
780 Note: modifying a line (not a curve!) might create a curve on the other end of the line
781 if Smooth is set there (with control points aligned to line).
784 mpSdrPathDragData
->aXP
[nPnt
]+=aDiff
;
786 // now check symmetric plus handles
787 if (bControl
) { // cases 5,6,7,8
788 sal_uInt16 nSt
=nPnt
; // the associated support point
789 sal_uInt16 nFix
=nPnt
; // the opposing control point
790 if (bIsNextControl
) { // if the next one is a control point, the on before has to be a support point
797 if (mpSdrPathDragData
->aXP
.IsSmooth(nSt
)) {
798 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nSt
,nPnt
,nFix
);
802 if (!bControl
) { // Cases 1,2,3,4. In case 1, nothing happens; in cases 3 and 4, there is more following below.
803 // move both control points
804 if (bPrevIsControl
) mpSdrPathDragData
->aXP
[nPrevPnt
]+=aDiff
;
805 if (bNextIsControl
) mpSdrPathDragData
->aXP
[nNextPnt
]+=aDiff
;
806 // align control point to line, if appropriate
807 if (mpSdrPathDragData
->aXP
.IsSmooth(nPnt
)) {
808 if (bPrevIsControl
&& !bNextIsControl
&& !bEndPnt
) { // case 3
809 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nPnt
,nNextPnt
,nPrevPnt
);
811 if (bNextIsControl
&& !bPrevIsControl
&& !bBegPnt
) { // case 4
812 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nPnt
,nPrevPnt
,nNextPnt
);
815 // Now check the other ends of the line (nPnt+-1). If there is a
816 // curve (IsControl(nPnt+-2)) with SmoothJoin (nPnt+-1), the
817 // associated control point (nPnt+-2) has to be adapted.
818 if (!bBegPnt
&& !bPrevIsControl
&& !bPrevIsBegPnt
&& mpSdrPathDragData
->aXP
.IsSmooth(nPrevPnt
)) {
819 if (mpSdrPathDragData
->aXP
.IsControl(nPrevPrevPnt
)) {
820 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nPrevPnt
,nPnt
,nPrevPrevPnt
);
823 if (!bEndPnt
&& !bNextIsControl
&& !bNextIsEndPnt
&& mpSdrPathDragData
->aXP
.IsSmooth(nNextPnt
)) {
824 if (mpSdrPathDragData
->aXP
.IsControl(nNextNextPnt
)) {
825 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nNextPnt
,nPnt
,nNextNextPnt
);
834 bool ImpPathForDragAndCreate::endPathDrag(SdrDragStat
& rDrag
)
838 bool bLineGlueMirror(OBJ_LINE
== meObjectKind
);
839 if (bLineGlueMirror
) {
840 XPolygon
& rXP
=aPathPolygon
[0];
845 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
847 OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
851 if(mpSdrPathDragData
->IsMultiPointDrag())
853 aPathPolygon
= mpSdrPathDragData
->maMove
;
857 const SdrHdl
* pHdl
=rDrag
.GetHdl();
859 // reference the polygon
860 XPolygon
& rXP
=aPathPolygon
[(sal_uInt16
)pHdl
->GetPolyNum()];
862 // the 5 points that might have changed
863 if (!mpSdrPathDragData
->bPrevIsBegPnt
) rXP
[mpSdrPathDragData
->nPrevPrevPnt0
]=mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nPrevPrevPnt
];
864 if (!mpSdrPathDragData
->bNextIsEndPnt
) rXP
[mpSdrPathDragData
->nNextNextPnt0
]=mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nNextNextPnt
];
865 if (!mpSdrPathDragData
->bBegPnt
) rXP
[mpSdrPathDragData
->nPrevPnt0
] =mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nPrevPnt
];
866 if (!mpSdrPathDragData
->bEndPnt
) rXP
[mpSdrPathDragData
->nNextPnt0
] =mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nNextPnt
];
867 rXP
[mpSdrPathDragData
->nPnt0
] =mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nPnt
];
869 // for closed objects: last point has to be equal to first point
870 if (mpSdrPathDragData
->bClosed
) rXP
[rXP
.GetPointCount()-1]=rXP
[0];
872 if (mpSdrPathDragData
->bEliminate
)
874 basegfx::B2DPolyPolygon
aTempPolyPolygon(aPathPolygon
.getB2DPolyPolygon());
875 sal_uInt32 nPoly
,nPnt
;
877 if(PolyPolygonEditor::GetRelativePolyPoint(aTempPolyPolygon
, rDrag
.GetHdl()->GetSourceHdlNum(), nPoly
, nPnt
))
879 basegfx::B2DPolygon
aCandidate(aTempPolyPolygon
.getB2DPolygon(nPoly
));
880 aCandidate
.remove(nPnt
);
882 if((IsClosed(meObjectKind
) && aCandidate
.count() < 3L) || aCandidate
.count() < 2L)
884 aTempPolyPolygon
.remove(nPoly
);
888 aTempPolyPolygon
.setB2DPolygon(nPoly
, aCandidate
);
892 aPathPolygon
= XPolyPolygon(aTempPolyPolygon
);
895 // adapt angle for text beneath a simple line
898 Point
aLinePt1_(aPathPolygon
[0][0]);
899 Point
aLinePt2_(aPathPolygon
[0][1]);
900 bool bXMirr
=(aLinePt1_
.X()>aLinePt2_
.X())!=(aLinePt1
.X()>aLinePt2
.X());
901 bool bYMirr
=(aLinePt1_
.Y()>aLinePt2_
.Y())!=(aLinePt1
.Y()>aLinePt2
.Y());
902 if (bXMirr
|| bYMirr
) {
903 Point
aRef1(mrSdrPathObject
.GetSnapRect().Center());
907 mrSdrPathObject
.NbcMirrorGluePoints(aRef1
,aRef2
);
912 mrSdrPathObject
.NbcMirrorGluePoints(aRef1
,aRef2
);
918 delete mpSdrPathDragData
;
919 mpSdrPathDragData
= 0;
925 String
ImpPathForDragAndCreate::getSpecialDragComment(const SdrDragStat
& rDrag
) const
928 const SdrHdl
* pHdl
= rDrag
.GetHdl();
929 const bool bCreateComment(rDrag
.GetView() && &mrSdrPathObject
== rDrag
.GetView()->GetCreateObj());
931 if(bCreateComment
&& rDrag
.GetUser())
933 // #i103058# re-add old creation comment mode
934 ImpPathCreateUser
* pU
= (ImpPathCreateUser
*)rDrag
.GetUser();
935 const SdrObjKind
eKindMerk(meObjectKind
);
936 mrSdrPathObject
.meKind
= pU
->eAktKind
;
938 mrSdrPathObject
.ImpTakeDescriptionStr(STR_ViewCreateObj
, aTmp
);
940 mrSdrPathObject
.meKind
= eKindMerk
;
942 Point
aPrev(rDrag
.GetPrev());
943 Point
aNow(rDrag
.GetNow());
949 aStr
.AppendAscii(" (");
955 mrSdrPathObject
.GetModel()->TakeWinkStr(Abs(pU
->nCircRelWink
), aMetr
);
957 aStr
.AppendAscii(" r=");
958 mrSdrPathObject
.GetModel()->TakeMetricStr(pU
->nCircRadius
, aMetr
, sal_True
);
962 aStr
.AppendAscii("dx=");
963 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.X(), aMetr
, sal_True
);
966 aStr
.AppendAscii(" dy=");
967 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.Y(), aMetr
, sal_True
);
970 if(!IsFreeHand(meObjectKind
))
972 sal_Int32
nLen(GetLen(aNow
));
973 aStr
.AppendAscii(" l=");
974 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, sal_True
);
977 sal_Int32
nWink(GetAngle(aNow
));
978 aStr
+= sal_Unicode(' ');
979 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
983 aStr
+= sal_Unicode(')');
985 else if(!mrSdrPathObject
.GetModel() || !pHdl
)
987 // #i103058# fallback when no model and/or Handle, both needed
990 mrSdrPathObject
.ImpTakeDescriptionStr(STR_DragPathObj
, aTmp
);
995 // #i103058# standard for modification; model and handle needed
996 ImpSdrPathDragData
* pDragData
= mpSdrPathDragData
;
1000 // getSpecialDragComment is also used from create, so fallback to GetUser()
1001 // when mpSdrPathDragData is not set
1002 pDragData
= (ImpSdrPathDragData
*)rDrag
.GetUser();
1007 OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
1011 if(!pDragData
->IsMultiPointDrag() && pDragData
->bEliminate
)
1015 mrSdrPathObject
.ImpTakeDescriptionStr(STR_ViewMarkedPoint
, aTmp
);
1019 XubString
aStr2(ImpGetResStr(STR_EditDelete
));
1021 // UNICODE: delete point of ...
1022 aStr2
.SearchAndReplaceAscii("%1", aStr
);
1027 // dx=0.00 dy=0.00 -- both sides bezier
1028 // dx=0.00 dy=0.00 l=0.00 0.00° -- one bezier/lever on one side, a start, or an ending
1029 // dx=0.00 dy=0.00 l=0.00 0.00° / l=0.00 0.00° -- in between
1030 rtl::OUString aMetr
;
1031 Point
aBeg(rDrag
.GetStart());
1032 Point
aNow(rDrag
.GetNow());
1035 aStr
.AppendAscii("dx=");
1036 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.X() - aBeg
.X(), aMetr
, sal_True
);
1039 aStr
.AppendAscii(" dy=");
1040 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.Y() - aBeg
.Y(), aMetr
, sal_True
);
1043 if(!pDragData
->IsMultiPointDrag())
1045 sal_uInt16
nPntNum((sal_uInt16
)pHdl
->GetPointNum());
1046 const XPolygon
& rXPoly
= aPathPolygon
[(sal_uInt16
)rDrag
.GetHdl()->GetPolyNum()];
1047 sal_uInt16
nPntAnz((sal_uInt16
)rXPoly
.GetPointCount());
1048 sal_Bool
bClose(IsClosed(meObjectKind
));
1053 if(pHdl
->IsPlusHdl())
1056 sal_uInt16
nRef(nPntNum
);
1058 if(rXPoly
.IsControl(nPntNum
+ 1))
1063 aNow
-= rXPoly
[nRef
];
1065 sal_Int32
nLen(GetLen(aNow
));
1066 aStr
.AppendAscii(" l=");
1067 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, sal_True
);
1070 sal_Int32
nWink(GetAngle(aNow
));
1071 aStr
+= sal_Unicode(' ');
1072 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
1075 else if(nPntAnz
> 1)
1077 sal_uInt16
nPntMax(nPntAnz
- 1);
1079 sal_Bool
bIsClosed(IsClosed(meObjectKind
));
1080 sal_Bool
bPt1(nPntNum
> 0);
1081 sal_Bool
bPt2(nPntNum
< nPntMax
);
1083 if(bIsClosed
&& nPntAnz
> 2)
1089 sal_uInt16 nPt1
,nPt2
;
1096 if(nPntNum
< nPntMax
)
1101 if(bPt1
&& rXPoly
.IsControl(nPt1
))
1102 bPt1
= sal_False
; // don't display
1104 if(bPt2
&& rXPoly
.IsControl(nPt2
))
1105 bPt2
= sal_False
; // of bezier data
1110 aPt
-= rXPoly
[nPt1
];
1112 sal_Int32
nLen(GetLen(aPt
));
1113 aStr
.AppendAscii(" l=");
1114 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, sal_True
);
1117 sal_Int32
nWink(GetAngle(aPt
));
1118 aStr
+= sal_Unicode(' ');
1119 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
1126 aStr
.AppendAscii(" / ");
1128 aStr
.AppendAscii(" ");
1131 aPt
-= rXPoly
[nPt2
];
1133 sal_Int32
nLen(GetLen(aPt
));
1134 aStr
.AppendAscii("l=");
1135 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, sal_True
);
1138 sal_Int32
nWink(GetAngle(aPt
));
1139 aStr
+= sal_Unicode(' ');
1140 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
1150 basegfx::B2DPolyPolygon
ImpPathForDragAndCreate::getSpecialDragPoly(const SdrDragStat
& rDrag
) const
1152 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
1154 OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
1155 return basegfx::B2DPolyPolygon();
1158 XPolyPolygon aRetval
;
1160 if(mpSdrPathDragData
->IsMultiPointDrag())
1162 aRetval
.Insert(mpSdrPathDragData
->maMove
);
1166 const XPolygon
& rXP
=aPathPolygon
[(sal_uInt16
)rDrag
.GetHdl()->GetPolyNum()];
1167 if (rXP
.GetPointCount()<=2) {
1168 XPolygon
aXPoly(rXP
);
1169 aXPoly
[(sal_uInt16
)rDrag
.GetHdl()->GetPointNum()]=rDrag
.GetNow();
1170 aRetval
.Insert(aXPoly
);
1171 return aRetval
.getB2DPolyPolygon();
1173 // copy certain data locally to use less code and have faster access times
1174 bool bClosed
=mpSdrPathDragData
->bClosed
; // closed object?
1175 sal_uInt16 nPntAnz
=mpSdrPathDragData
->nPntAnz
; // number of points
1176 sal_uInt16 nPnt
=mpSdrPathDragData
->nPnt
; // number of points in the polygon
1177 bool bBegPnt
=mpSdrPathDragData
->bBegPnt
; // dragged point is the first point of a Polyline
1178 bool bEndPnt
=mpSdrPathDragData
->bEndPnt
; // dragged point is the last point of a Polyline
1179 sal_uInt16 nPrevPnt
=mpSdrPathDragData
->nPrevPnt
; // index of the previous point
1180 sal_uInt16 nNextPnt
=mpSdrPathDragData
->nNextPnt
; // index of the next point
1181 bool bPrevIsBegPnt
=mpSdrPathDragData
->bPrevIsBegPnt
; // previous point is first point of a Polyline
1182 bool bNextIsEndPnt
=mpSdrPathDragData
->bNextIsEndPnt
; // next point is last point of a Polyline
1183 sal_uInt16 nPrevPrevPnt
=mpSdrPathDragData
->nPrevPrevPnt
; // index of the point before the previous point
1184 sal_uInt16 nNextNextPnt
=mpSdrPathDragData
->nNextNextPnt
; // index of the point after the last point
1185 bool bControl
=mpSdrPathDragData
->bControl
; // point is a control point
1186 bool bIsNextControl
=mpSdrPathDragData
->bIsNextControl
; //point is a control point after a support point
1187 bool bPrevIsControl
=mpSdrPathDragData
->bPrevIsControl
; // if nPnt is a support point: there's a control point before
1188 bool bNextIsControl
=mpSdrPathDragData
->bNextIsControl
; // if nPnt is a support point: there's a control point after
1189 XPolygon
aXPoly(mpSdrPathDragData
->aXP
);
1195 aLine1
[1]=mpSdrPathDragData
->aXP
[nPnt
];
1196 if (bIsNextControl
) { // is this a control point after the support point?
1197 aLine1
[0]=mpSdrPathDragData
->aXP
[nPrevPnt
];
1198 aLine2
[0]=mpSdrPathDragData
->aXP
[nNextNextPnt
];
1199 aLine2
[1]=mpSdrPathDragData
->aXP
[nNextPnt
];
1200 if (mpSdrPathDragData
->aXP
.IsSmooth(nPrevPnt
) && !bPrevIsBegPnt
&& mpSdrPathDragData
->aXP
.IsControl(nPrevPrevPnt
)) {
1201 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1],XPOLY_CONTROL
);
1202 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-2],XPOLY_NORMAL
);
1203 // leverage lines for the opposing curve segment
1204 aLine3
[0]=mpSdrPathDragData
->aXP
[nPrevPnt
];
1205 aLine3
[1]=mpSdrPathDragData
->aXP
[nPrevPrevPnt
];
1206 aLine4
[0]=rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-2];
1207 aLine4
[1]=rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1];
1211 } else { // else this is a control point before a support point
1212 aLine1
[0]=mpSdrPathDragData
->aXP
[nNextPnt
];
1213 aLine2
[0]=mpSdrPathDragData
->aXP
[nPrevPrevPnt
];
1214 aLine2
[1]=mpSdrPathDragData
->aXP
[nPrevPnt
];
1215 if (mpSdrPathDragData
->aXP
.IsSmooth(nNextPnt
) && !bNextIsEndPnt
&& mpSdrPathDragData
->aXP
.IsControl(nNextNextPnt
)) {
1216 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+1],XPOLY_CONTROL
);
1217 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+2],XPOLY_NORMAL
);
1218 // leverage lines for the opposing curve segment
1219 aLine3
[0]=mpSdrPathDragData
->aXP
[nNextPnt
];
1220 aLine3
[1]=mpSdrPathDragData
->aXP
[nNextNextPnt
];
1221 aLine4
[0]=rXP
[mpSdrPathDragData
->nNextNextPnt0
+2];
1222 aLine4
[1]=rXP
[mpSdrPathDragData
->nNextNextPnt0
+1];
1224 aXPoly
.Remove(aXPoly
.GetPointCount()-1,1);
1227 } else { // else is not a control point
1228 if (mpSdrPathDragData
->bEliminate
) {
1231 if (bPrevIsControl
) aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1],XPOLY_NORMAL
);
1232 else if (!bBegPnt
&& !bPrevIsBegPnt
&& mpSdrPathDragData
->aXP
.IsControl(nPrevPrevPnt
)) {
1233 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1],XPOLY_CONTROL
);
1234 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-2],XPOLY_NORMAL
);
1237 if (bBegPnt
) aXPoly
.Remove(0,1);
1239 if (bNextIsControl
) aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+1],XPOLY_NORMAL
);
1240 else if (!bEndPnt
&& !bNextIsEndPnt
&& mpSdrPathDragData
->aXP
.IsControl(nNextNextPnt
)) {
1241 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+1],XPOLY_CONTROL
);
1242 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+2],XPOLY_NORMAL
);
1244 aXPoly
.Remove(aXPoly
.GetPointCount()-1,1);
1245 if (bEndPnt
) aXPoly
.Remove(aXPoly
.GetPointCount()-1,1);
1247 if (bClosed
) { // "pear problem": 2 lines, 1 curve, everything smoothed, a point between both lines is dragged
1248 if (aXPoly
.GetPointCount()>nPntAnz
&& aXPoly
.IsControl(1)) {
1249 sal_uInt16 a
=aXPoly
.GetPointCount();
1250 aXPoly
[a
-2]=aXPoly
[2]; aXPoly
.SetFlags(a
-2,aXPoly
.GetFlags(2));
1251 aXPoly
[a
-1]=aXPoly
[3]; aXPoly
.SetFlags(a
-1,aXPoly
.GetFlags(3));
1256 aRetval
.Insert(aXPoly
);
1257 if (aLine1
.GetPointCount()>1) aRetval
.Insert(aLine1
);
1258 if (aLine2
.GetPointCount()>1) aRetval
.Insert(aLine2
);
1259 if (aLine3
.GetPointCount()>1) aRetval
.Insert(aLine3
);
1260 if (aLine4
.GetPointCount()>1) aRetval
.Insert(aLine4
);
1263 return aRetval
.getB2DPolyPolygon();
1266 bool ImpPathForDragAndCreate::BegCreate(SdrDragStat
& rStat
)
1268 bool bFreeHand(IsFreeHand(meObjectKind
));
1269 rStat
.SetNoSnap(bFreeHand
);
1270 rStat
.SetOrtho8Possible();
1271 aPathPolygon
.Clear();
1272 mbCreating
=sal_True
;
1273 bool bMakeStartPoint
= true;
1274 SdrView
* pView
=rStat
.GetView();
1275 if (pView
!=NULL
&& pView
->IsUseIncompatiblePathCreateInterface() &&
1276 (meObjectKind
==OBJ_POLY
|| meObjectKind
==OBJ_PLIN
|| meObjectKind
==OBJ_PATHLINE
|| meObjectKind
==OBJ_PATHFILL
)) {
1277 bMakeStartPoint
= false;
1279 aPathPolygon
.Insert(XPolygon());
1280 aPathPolygon
[0][0]=rStat
.GetStart();
1281 if (bMakeStartPoint
) {
1282 aPathPolygon
[0][1]=rStat
.GetNow();
1284 ImpPathCreateUser
* pU
=new ImpPathCreateUser
;
1285 pU
->eStartKind
=meObjectKind
;
1286 pU
->eAktKind
=meObjectKind
;
1291 bool ImpPathForDragAndCreate::MovCreate(SdrDragStat
& rStat
)
1293 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1294 SdrView
* pView
=rStat
.GetView();
1295 XPolygon
& rXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1296 if (pView
!=NULL
&& pView
->IsCreateMode()) {
1297 // switch to different CreateTool, if appropriate
1300 pView
->TakeCurrentObj(nIdent
,nInvent
);
1301 if (nInvent
==SdrInventor
&& pU
->eAktKind
!=(SdrObjKind
)nIdent
) {
1302 SdrObjKind eNewKind
=(SdrObjKind
)nIdent
;
1304 case OBJ_CARC
: case OBJ_CIRC
: case OBJ_CCUT
: case OBJ_SECT
: eNewKind
=OBJ_CARC
;
1306 case OBJ_LINE
: case OBJ_PLIN
: case OBJ_POLY
:
1307 case OBJ_PATHLINE
: case OBJ_PATHFILL
:
1308 case OBJ_FREELINE
: case OBJ_FREEFILL
:
1309 case OBJ_SPLNLINE
: case OBJ_SPLNFILL
: {
1310 pU
->eAktKind
=eNewKind
;
1311 pU
->bMixedCreate
=sal_True
;
1312 pU
->nBezierStartPoint
=rXPoly
.GetPointCount();
1313 if (pU
->nBezierStartPoint
>0) pU
->nBezierStartPoint
--;
1319 sal_uInt16 nActPoint
=rXPoly
.GetPointCount();
1320 if (aPathPolygon
.Count()>1 && rStat
.IsMouseDown() && nActPoint
<2) {
1321 rXPoly
[0]=rStat
.GetPos0();
1322 rXPoly
[1]=rStat
.GetNow();
1326 rXPoly
[0]=rStat
.GetPos0();
1328 bool bFreeHand
=IsFreeHand(pU
->eAktKind
);
1329 rStat
.SetNoSnap(bFreeHand
);
1330 rStat
.SetOrtho8Possible(pU
->eAktKind
!=OBJ_CARC
&& pU
->eAktKind
!=OBJ_RECT
&& (!pU
->bMixedCreate
|| pU
->eAktKind
!=OBJ_LINE
));
1331 Point
aActMerk(rXPoly
[nActPoint
]);
1332 rXPoly
[nActPoint
]=rStat
.Now();
1333 if (!pU
->bMixedCreate
&& pU
->eStartKind
==OBJ_LINE
&& rXPoly
.GetPointCount()>=1) {
1334 Point
aPt(rStat
.Start());
1335 if (pView
!=NULL
&& pView
->IsCreate1stPointAsCenter()) {
1341 OutputDevice
* pOut
=pView
==NULL
? NULL
: pView
->GetFirstOutputDevice();
1343 if (pU
->nBezierStartPoint
>nActPoint
) pU
->nBezierStartPoint
=nActPoint
;
1344 if (rStat
.IsMouseDown() && nActPoint
>0) {
1345 // don't allow two consecutive points to occupy too similar positions
1347 if (pView
!=NULL
) nMinDist
=pView
->GetFreeHandMinDistPix();
1348 if (pOut
!=NULL
) nMinDist
=pOut
->PixelToLogic(Size(nMinDist
,0)).Width();
1349 if (nMinDist
<1) nMinDist
=1;
1351 Point
aPt0(rXPoly
[nActPoint
-1]);
1352 Point
aPt1(rStat
.Now());
1353 long dx
=aPt0
.X()-aPt1
.X(); if (dx
<0) dx
=-dx
;
1354 long dy
=aPt0
.Y()-aPt1
.Y(); if (dy
<0) dy
=-dy
;
1355 if (dx
<nMinDist
&& dy
<nMinDist
) return sal_False
;
1357 // TODO: the following is copied from EndCreate (with a few smaller modifications)
1358 // and should be combined into a method with the code there.
1360 if (nActPoint
-pU
->nBezierStartPoint
>=3 && ((nActPoint
-pU
->nBezierStartPoint
)%3)==0) {
1361 rXPoly
.PointsToBezier(nActPoint
-3);
1362 rXPoly
.SetFlags(nActPoint
-1,XPOLY_CONTROL
);
1363 rXPoly
.SetFlags(nActPoint
-2,XPOLY_CONTROL
);
1365 if (nActPoint
>=6 && rXPoly
.IsControl(nActPoint
-4)) {
1366 rXPoly
.CalcTangent(nActPoint
-3,nActPoint
-4,nActPoint
-2);
1367 rXPoly
.SetFlags(nActPoint
-3,XPOLY_SMOOTH
);
1370 rXPoly
[nActPoint
+1]=rStat
.Now();
1373 pU
->nBezierStartPoint
=nActPoint
;
1377 pU
->ResetFormFlags();
1378 if (IsBezier(pU
->eAktKind
)) {
1380 pU
->CalcBezier(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],rStat
.IsMouseDown());
1381 } else if (pU
->bBezHasCtrl0
) {
1382 pU
->CalcBezier(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],pU
->aBezControl0
-rXPoly
[nActPoint
-1],rStat
.IsMouseDown());
1385 if (pU
->eAktKind
==OBJ_CARC
&& nActPoint
>=2) {
1386 pU
->CalcCircle(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],pView
);
1388 if (pU
->eAktKind
==OBJ_LINE
&& nActPoint
>=2) {
1389 pU
->CalcLine(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],pView
);
1391 if (pU
->eAktKind
==OBJ_RECT
&& nActPoint
>=2) {
1392 pU
->CalcRect(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],pView
);
1398 bool ImpPathForDragAndCreate::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
1400 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1402 SdrView
* pView
=rStat
.GetView();
1403 bool bIncomp
=pView
!=NULL
&& pView
->IsUseIncompatiblePathCreateInterface();
1404 XPolygon
& rXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1405 sal_uInt16 nActPoint
=rXPoly
.GetPointCount()-1;
1406 Point
aAktMerk(rXPoly
[nActPoint
]);
1407 rXPoly
[nActPoint
]=rStat
.Now();
1408 if (!pU
->bMixedCreate
&& pU
->eStartKind
==OBJ_LINE
) {
1409 if (rStat
.GetPointAnz()>=2) eCmd
=SDRCREATE_FORCEEND
;
1410 bRet
= eCmd
==SDRCREATE_FORCEEND
;
1412 mbCreating
= sal_False
;
1414 rStat
.SetUser(NULL
);
1419 if (!pU
->bMixedCreate
&& IsFreeHand(pU
->eStartKind
)) {
1420 if (rStat
.GetPointAnz()>=2) eCmd
=SDRCREATE_FORCEEND
;
1421 bRet
=eCmd
==SDRCREATE_FORCEEND
;
1423 mbCreating
=sal_False
;
1425 rStat
.SetUser(NULL
);
1429 if (eCmd
==SDRCREATE_NEXTPOINT
|| eCmd
==SDRCREATE_NEXTOBJECT
) {
1430 // don't allow two consecutive points to occupy the same position
1431 if (nActPoint
==0 || rStat
.Now()!=rXPoly
[nActPoint
-1]) {
1433 if (pU
->nBezierStartPoint
>nActPoint
) pU
->nBezierStartPoint
=nActPoint
;
1434 if (IsBezier(pU
->eAktKind
) && nActPoint
-pU
->nBezierStartPoint
>=3 && ((nActPoint
-pU
->nBezierStartPoint
)%3)==0) {
1435 rXPoly
.PointsToBezier(nActPoint
-3);
1436 rXPoly
.SetFlags(nActPoint
-1,XPOLY_CONTROL
);
1437 rXPoly
.SetFlags(nActPoint
-2,XPOLY_CONTROL
);
1439 if (nActPoint
>=6 && rXPoly
.IsControl(nActPoint
-4)) {
1440 rXPoly
.CalcTangent(nActPoint
-3,nActPoint
-4,nActPoint
-2);
1441 rXPoly
.SetFlags(nActPoint
-3,XPOLY_SMOOTH
);
1445 if (nActPoint
==1 && IsBezier(pU
->eAktKind
) && !pU
->bBezHasCtrl0
) {
1446 pU
->aBezControl0
=rStat
.GetNow();
1447 pU
->bBezHasCtrl0
=sal_True
;
1450 if (pU
->IsFormFlag()) {
1451 sal_uInt16 nPtAnz0
=rXPoly
.GetPointCount();
1452 rXPoly
.Remove(nActPoint
-1,2); // remove last two points and replace by form
1453 rXPoly
.Insert(XPOLY_APPEND
,pU
->GetFormPoly());
1454 sal_uInt16 nPtAnz1
=rXPoly
.GetPointCount();
1455 for (sal_uInt16 i
=nPtAnz0
+1; i
<nPtAnz1
-1; i
++) { // to make BckAction work
1456 if (!rXPoly
.IsControl(i
)) rStat
.NextPoint();
1458 nActPoint
=rXPoly
.GetPointCount()-1;
1462 rXPoly
[nActPoint
]=rStat
.GetNow();
1464 if (eCmd
==SDRCREATE_NEXTOBJECT
) {
1465 if (rXPoly
.GetPointCount()>=2) {
1466 pU
->bBezHasCtrl0
=sal_False
;
1467 // only a singular polygon may be opened, so close this
1468 rXPoly
[nActPoint
]=rXPoly
[0];
1470 aXP
[0]=rStat
.GetNow();
1471 aPathPolygon
.Insert(aXP
);
1476 sal_uInt16 nPolyAnz
=aPathPolygon
.Count();
1478 // delete last point, if necessary
1479 if (eCmd
==SDRCREATE_FORCEEND
) {
1480 XPolygon
& rXP
=aPathPolygon
[nPolyAnz
-1];
1481 sal_uInt16 nPtAnz
=rXP
.GetPointCount();
1483 if (!rXP
.IsControl(nPtAnz
-2)) {
1484 if (rXP
[nPtAnz
-1]==rXP
[nPtAnz
-2]) {
1485 rXP
.Remove(nPtAnz
-1,1);
1488 if (rXP
[nPtAnz
-3]==rXP
[nPtAnz
-2]) {
1489 rXP
.Remove(nPtAnz
-3,3);
1494 for (sal_uInt16 nPolyNum
=nPolyAnz
; nPolyNum
>0;) {
1496 XPolygon
& rXP
=aPathPolygon
[nPolyNum
];
1497 sal_uInt16 nPtAnz
=rXP
.GetPointCount();
1498 // delete polygons with too few points
1499 if (nPolyNum
<nPolyAnz
-1 || eCmd
==SDRCREATE_FORCEEND
) {
1500 if (nPtAnz
<2) aPathPolygon
.Remove(nPolyNum
);
1504 pU
->ResetFormFlags();
1505 bRet
=eCmd
==SDRCREATE_FORCEEND
;
1507 mbCreating
=sal_False
;
1509 rStat
.SetUser(NULL
);
1514 bool ImpPathForDragAndCreate::BckCreate(SdrDragStat
& rStat
)
1516 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1517 if (aPathPolygon
.Count()>0) {
1518 XPolygon
& rXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1519 sal_uInt16 nActPoint
=rXPoly
.GetPointCount();
1522 // make the last part of a bezier curve a line
1523 rXPoly
.Remove(nActPoint
,1);
1524 if (nActPoint
>=3 && rXPoly
.IsControl(nActPoint
-1)) {
1525 // there should never be a bezier segment at the end, so this is just in case...
1526 rXPoly
.Remove(nActPoint
-1,1);
1527 if (rXPoly
.IsControl(nActPoint
-2)) rXPoly
.Remove(nActPoint
-2,1);
1530 nActPoint
=rXPoly
.GetPointCount();
1531 if (nActPoint
>=4) { // no bezier segment at the end
1533 if (rXPoly
.IsControl(nActPoint
-1)) {
1534 rXPoly
.Remove(nActPoint
-1,1);
1535 if (rXPoly
.IsControl(nActPoint
-2)) rXPoly
.Remove(nActPoint
-2,1);
1538 if (rXPoly
.GetPointCount()<2) {
1539 aPathPolygon
.Remove(aPathPolygon
.Count()-1);
1541 if (aPathPolygon
.Count()>0) {
1542 XPolygon
& rLocalXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1543 sal_uInt16 nLocalActPoint
=rLocalXPoly
.GetPointCount();
1544 if (nLocalActPoint
>0) {
1546 rLocalXPoly
[nLocalActPoint
]=rStat
.Now();
1550 pU
->ResetFormFlags();
1551 return aPathPolygon
.Count()!=0;
1554 void ImpPathForDragAndCreate::BrkCreate(SdrDragStat
& rStat
)
1556 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1557 aPathPolygon
.Clear();
1558 mbCreating
=sal_False
;
1560 rStat
.SetUser(NULL
);
1563 basegfx::B2DPolyPolygon
ImpPathForDragAndCreate::TakeObjectPolyPolygon(const SdrDragStat
& rDrag
) const
1565 basegfx::B2DPolyPolygon
aRetval(aPathPolygon
.getB2DPolyPolygon());
1566 SdrView
* pView
= rDrag
.GetView();
1568 if(pView
&& pView
->IsUseIncompatiblePathCreateInterface())
1571 ImpPathCreateUser
* pU
= (ImpPathCreateUser
*)rDrag
.GetUser();
1572 basegfx::B2DPolygon
aNewPolygon(aRetval
.count() ? aRetval
.getB2DPolygon(aRetval
.count() - 1L) : basegfx::B2DPolygon());
1574 if(pU
->IsFormFlag() && aNewPolygon
.count() > 1L)
1576 // remove last segment and replace with current
1577 // do not forget to rescue the previous control point which will be lost when
1578 // the point it's associated with is removed
1579 const sal_uInt32
nChangeIndex(aNewPolygon
.count() - 2);
1580 const basegfx::B2DPoint
aSavedPrevCtrlPoint(aNewPolygon
.getPrevControlPoint(nChangeIndex
));
1582 aNewPolygon
.remove(nChangeIndex
, 2L);
1583 aNewPolygon
.append(pU
->GetFormPoly().getB2DPolygon());
1585 if(nChangeIndex
< aNewPolygon
.count())
1587 // if really something was added, set the saved previous control point to the
1588 // point where it belongs
1589 aNewPolygon
.setPrevControlPoint(nChangeIndex
, aSavedPrevCtrlPoint
);
1595 aRetval
.setB2DPolygon(aRetval
.count() - 1L, aNewPolygon
);
1599 aRetval
.append(aNewPolygon
);
1605 basegfx::B2DPolyPolygon
ImpPathForDragAndCreate::TakeDragPolyPolygon(const SdrDragStat
& rDrag
) const
1607 basegfx::B2DPolyPolygon aRetval
;
1608 SdrView
* pView
= rDrag
.GetView();
1610 if(pView
&& pView
->IsUseIncompatiblePathCreateInterface())
1613 ImpPathCreateUser
* pU
= (ImpPathCreateUser
*)rDrag
.GetUser();
1615 if(pU
&& pU
->bBezier
&& rDrag
.IsMouseDown())
1617 // no more XOR, no need for complicated helplines
1618 basegfx::B2DPolygon aHelpline
;
1619 aHelpline
.append(basegfx::B2DPoint(pU
->aBezCtrl2
.X(), pU
->aBezCtrl2
.Y()));
1620 aHelpline
.append(basegfx::B2DPoint(pU
->aBezEnd
.X(), pU
->aBezEnd
.Y()));
1621 aRetval
.append(aHelpline
);
1627 Pointer
ImpPathForDragAndCreate::GetCreatePointer() const
1629 switch (meObjectKind
) {
1630 case OBJ_LINE
: return Pointer(POINTER_DRAW_LINE
);
1631 case OBJ_POLY
: return Pointer(POINTER_DRAW_POLYGON
);
1632 case OBJ_PLIN
: return Pointer(POINTER_DRAW_POLYGON
);
1633 case OBJ_PATHLINE
: return Pointer(POINTER_DRAW_BEZIER
);
1634 case OBJ_PATHFILL
: return Pointer(POINTER_DRAW_BEZIER
);
1635 case OBJ_FREELINE
: return Pointer(POINTER_DRAW_FREEHAND
);
1636 case OBJ_FREEFILL
: return Pointer(POINTER_DRAW_FREEHAND
);
1637 case OBJ_SPLNLINE
: return Pointer(POINTER_DRAW_FREEHAND
);
1638 case OBJ_SPLNFILL
: return Pointer(POINTER_DRAW_FREEHAND
);
1639 case OBJ_PATHPOLY
: return Pointer(POINTER_DRAW_POLYGON
);
1640 case OBJ_PATHPLIN
: return Pointer(POINTER_DRAW_POLYGON
);
1643 return Pointer(POINTER_CROSS
);
1646 /*************************************************************************/
1648 SdrPathObjGeoData::SdrPathObjGeoData()
1652 SdrPathObjGeoData::~SdrPathObjGeoData()
1656 //////////////////////////////////////////////////////////////////////////////
1657 // DrawContact section
1659 sdr::contact::ViewContact
* SdrPathObj::CreateObjectSpecificViewContact()
1661 return new sdr::contact::ViewContactOfSdrPathObj(*this);
1664 /*************************************************************************/
1666 TYPEINIT1(SdrPathObj
,SdrTextObj
);
1668 SdrPathObj::SdrPathObj(SdrObjKind eNewKind
)
1673 bClosedObj
= IsClosed();
1676 SdrPathObj::SdrPathObj(SdrObjKind eNewKind
, const basegfx::B2DPolyPolygon
& rPathPoly
, double dBrightness
)
1677 : maPathPolygon(rPathPoly
),
1680 mdBrightness(dBrightness
)
1682 bClosedObj
= IsClosed();
1686 SdrPathObj::~SdrPathObj()
1691 sal_Bool
ImpIsLine(const basegfx::B2DPolyPolygon
& rPolyPolygon
)
1693 return (1L == rPolyPolygon
.count() && 2L == rPolyPolygon
.getB2DPolygon(0L).count());
1696 Rectangle
ImpGetBoundRect(const basegfx::B2DPolyPolygon
& rPolyPolygon
)
1698 basegfx::B2DRange
aRange(basegfx::tools::getRange(rPolyPolygon
));
1701 FRound(aRange
.getMinX()), FRound(aRange
.getMinY()),
1702 FRound(aRange
.getMaxX()), FRound(aRange
.getMaxY()));
1705 void SdrPathObj::ImpForceLineWink()
1707 if(OBJ_LINE
== meKind
&& ImpIsLine(GetPathPoly()))
1709 const basegfx::B2DPolygon
aPoly(GetPathPoly().getB2DPolygon(0L));
1710 const basegfx::B2DPoint
aB2DPoint0(aPoly
.getB2DPoint(0L));
1711 const basegfx::B2DPoint
aB2DPoint1(aPoly
.getB2DPoint(1L));
1712 const Point
aPoint0(FRound(aB2DPoint0
.getX()), FRound(aB2DPoint0
.getY()));
1713 const Point
aPoint1(FRound(aB2DPoint1
.getX()), FRound(aB2DPoint1
.getY()));
1714 const Point
aDelt(aPoint1
- aPoint0
);
1716 aGeo
.nDrehWink
=GetAngle(aDelt
);
1718 aGeo
.RecalcSinCos();
1721 // for SdrTextObj, keep aRect up to date
1722 aRect
= Rectangle(aPoint0
, aPoint1
);
1727 void SdrPathObj::ImpForceKind()
1729 if (meKind
==OBJ_PATHPLIN
) meKind
=OBJ_PLIN
;
1730 if (meKind
==OBJ_PATHPOLY
) meKind
=OBJ_POLY
;
1732 if(GetPathPoly().areControlPointsUsed())
1736 case OBJ_LINE
: meKind
=OBJ_PATHLINE
; break;
1737 case OBJ_PLIN
: meKind
=OBJ_PATHLINE
; break;
1738 case OBJ_POLY
: meKind
=OBJ_PATHFILL
; break;
1746 case OBJ_PATHLINE
: meKind
=OBJ_PLIN
; break;
1747 case OBJ_FREELINE
: meKind
=OBJ_PLIN
; break;
1748 case OBJ_PATHFILL
: meKind
=OBJ_POLY
; break;
1749 case OBJ_FREEFILL
: meKind
=OBJ_POLY
; break;
1754 if (meKind
==OBJ_LINE
&& !ImpIsLine(GetPathPoly())) meKind
=OBJ_PLIN
;
1755 if (meKind
==OBJ_PLIN
&& ImpIsLine(GetPathPoly())) meKind
=OBJ_LINE
;
1757 bClosedObj
=IsClosed();
1759 if (meKind
==OBJ_LINE
)
1765 // #i10659#, for polys with more than 2 points.
1767 // Here i again need to fix something, because when Path-Polys are Copy-Pasted
1768 // between Apps with different measurements (e.g. 100TH_MM and TWIPS) there is
1769 // a scaling loop started from SdrExchangeView::Paste. In itself, this is not
1770 // wrong, but aRect is wrong here and not even updated by RecalcSnapRect(). If
1771 // this is the case, some size needs to be set here in aRect to avoid that the cycle
1772 // through Rect2Poly - Poly2Rect does something badly wrong since that cycle is
1773 // BASED on aRect. That cycle is triggered in SdrTextObj::NbcResize() which is called
1774 // from the local Resize() implementation.
1776 // Basic problem is that the member aRect in SdrTextObj basically is a unrotated
1777 // text rectangle for the text object itself and methods at SdrTextObj do handle it
1778 // in that way. Many draw objects derived from SdrTextObj 'abuse' aRect as SnapRect
1779 // which is basically wrong. To make the SdrText methods which deal with aRect directly
1780 // work it is necessary to always keep aRect updated. This e.g. not done after a Clone()
1781 // command for SdrPathObj. Since adding this update mechanism with #101412# to
1782 // ImpForceLineWink() for lines was very successful, i add it to where ImpForceLineWink()
1783 // was called, once here below and once on a 2nd place below.
1785 // #i10659# for SdrTextObj, keep aRect up to date
1786 if(GetPathPoly().count())
1788 aRect
= ImpGetBoundRect(GetPathPoly());
1792 // #i75974# adapt polygon state to object type. This may include a reinterpretation
1793 // of a closed geometry as open one, but with identical first and last point
1794 for(sal_uInt32
a(0); a
< maPathPolygon
.count(); a
++)
1796 basegfx::B2DPolygon
aCandidate(maPathPolygon
.getB2DPolygon(a
));
1798 if((bool)IsClosed() != aCandidate
.isClosed())
1800 // #i80213# really change polygon geometry; else e.g. the last point which
1801 // needs to be identical with the first one will be missing when opening
1802 // due to OBJ_PATH type
1803 if(aCandidate
.isClosed())
1805 basegfx::tools::openWithGeometryChange(aCandidate
);
1809 basegfx::tools::closeWithGeometryChange(aCandidate
);
1812 maPathPolygon
.setB2DPolygon(a
, aCandidate
);
1817 void SdrPathObj::ImpSetClosed(sal_Bool bClose
)
1823 case OBJ_LINE
: meKind
=OBJ_POLY
; break;
1824 case OBJ_PLIN
: meKind
=OBJ_POLY
; break;
1825 case OBJ_PATHLINE
: meKind
=OBJ_PATHFILL
; break;
1826 case OBJ_FREELINE
: meKind
=OBJ_FREEFILL
; break;
1827 case OBJ_SPLNLINE
: meKind
=OBJ_SPLNFILL
; break;
1831 bClosedObj
= sal_True
;
1837 case OBJ_POLY
: meKind
=OBJ_PLIN
; break;
1838 case OBJ_PATHFILL
: meKind
=OBJ_PATHLINE
; break;
1839 case OBJ_FREEFILL
: meKind
=OBJ_FREELINE
; break;
1840 case OBJ_SPLNFILL
: meKind
=OBJ_SPLNLINE
; break;
1844 bClosedObj
= sal_False
;
1850 void SdrPathObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
1852 rInfo
.bNoContortion
=sal_False
;
1854 bool bCanConv
= !HasText() || ImpCanConvTextToCurve();
1855 bool bIsPath
= IsBezier() || IsSpline();
1857 rInfo
.bEdgeRadiusAllowed
= sal_False
;
1858 rInfo
.bCanConvToPath
= bCanConv
&& !bIsPath
;
1859 rInfo
.bCanConvToPoly
= bCanConv
&& bIsPath
;
1860 rInfo
.bCanConvToContour
= !IsFontwork() && (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
1863 sal_uInt16
SdrPathObj::GetObjIdentifier() const
1865 return sal_uInt16(meKind
);
1868 SdrPathObj
* SdrPathObj::Clone() const
1870 return CloneHelper
< SdrPathObj
>();
1873 SdrPathObj
& SdrPathObj::operator=(const SdrPathObj
& rObj
)
1877 SdrTextObj::operator=(rObj
);
1878 maPathPolygon
=rObj
.GetPathPoly();
1882 void SdrPathObj::TakeObjNameSingul(XubString
& rName
) const
1884 if(OBJ_LINE
== meKind
)
1886 sal_uInt16
nId(STR_ObjNameSingulLINE
);
1888 if(ImpIsLine(GetPathPoly()))
1890 const basegfx::B2DPolygon
aPoly(GetPathPoly().getB2DPolygon(0L));
1891 const basegfx::B2DPoint
aB2DPoint0(aPoly
.getB2DPoint(0L));
1892 const basegfx::B2DPoint
aB2DPoint1(aPoly
.getB2DPoint(1L));
1893 const Point
aPoint0(FRound(aB2DPoint0
.getX()), FRound(aB2DPoint0
.getY()));
1894 const Point
aPoint1(FRound(aB2DPoint0
.getX()), FRound(aB2DPoint0
.getY()));
1896 if(aB2DPoint0
!= aB2DPoint1
)
1898 if(aB2DPoint0
.getY() == aB2DPoint1
.getY())
1900 nId
= STR_ObjNameSingulLINE_Hori
;
1902 else if(aB2DPoint0
.getX() == aB2DPoint1
.getX())
1904 nId
= STR_ObjNameSingulLINE_Vert
;
1908 const double fDx(fabs(aB2DPoint0
.getX() - aB2DPoint1
.getX()));
1909 const double fDy(fabs(aB2DPoint0
.getY() - aB2DPoint1
.getY()));
1913 nId
= STR_ObjNameSingulLINE_Diag
;
1919 rName
= ImpGetResStr(nId
);
1921 else if(OBJ_PLIN
== meKind
|| OBJ_POLY
== meKind
)
1923 const sal_Bool
bClosed(OBJ_POLY
== meKind
);
1926 if(mpDAC
&& mpDAC
->IsCreating())
1930 nId
= STR_ObjNameSingulPOLY
;
1934 nId
= STR_ObjNameSingulPLIN
;
1937 rName
= ImpGetResStr(nId
);
1942 sal_uInt32
nPointCount(0L);
1943 const sal_uInt32
nPolyCount(GetPathPoly().count());
1945 for(sal_uInt32
a(0L); a
< nPolyCount
; a
++)
1947 nPointCount
+= GetPathPoly().getB2DPolygon(a
).count();
1952 nId
= STR_ObjNameSingulPOLY_PntAnz
;
1956 nId
= STR_ObjNameSingulPLIN_PntAnz
;
1959 rName
= ImpGetResStr(nId
);
1960 sal_uInt16
nPos(rName
.SearchAscii("%2")); // #i96537#
1962 if(STRING_NOTFOUND
!= nPos
)
1964 rName
.Erase(nPos
, 2);
1965 rName
.Insert(rtl::OUString::valueOf(static_cast<sal_Int32
>(nPointCount
)), nPos
);
1973 case OBJ_PATHLINE
: rName
=ImpGetResStr(STR_ObjNameSingulPATHLINE
); break;
1974 case OBJ_FREELINE
: rName
=ImpGetResStr(STR_ObjNameSingulFREELINE
); break;
1975 case OBJ_SPLNLINE
: rName
=ImpGetResStr(STR_ObjNameSingulNATSPLN
); break;
1976 case OBJ_PATHFILL
: rName
=ImpGetResStr(STR_ObjNameSingulPATHFILL
); break;
1977 case OBJ_FREEFILL
: rName
=ImpGetResStr(STR_ObjNameSingulFREEFILL
); break;
1978 case OBJ_SPLNFILL
: rName
=ImpGetResStr(STR_ObjNameSingulPERSPLN
); break;
1983 String
aName(GetName());
1986 rName
+= sal_Unicode(' ');
1987 rName
+= sal_Unicode('\'');
1989 rName
+= sal_Unicode('\'');
1993 void SdrPathObj::TakeObjNamePlural(XubString
& rName
) const
1997 case OBJ_LINE
: rName
=ImpGetResStr(STR_ObjNamePluralLINE
); break;
1998 case OBJ_PLIN
: rName
=ImpGetResStr(STR_ObjNamePluralPLIN
); break;
1999 case OBJ_POLY
: rName
=ImpGetResStr(STR_ObjNamePluralPOLY
); break;
2000 case OBJ_PATHLINE
: rName
=ImpGetResStr(STR_ObjNamePluralPATHLINE
); break;
2001 case OBJ_FREELINE
: rName
=ImpGetResStr(STR_ObjNamePluralFREELINE
); break;
2002 case OBJ_SPLNLINE
: rName
=ImpGetResStr(STR_ObjNamePluralNATSPLN
); break;
2003 case OBJ_PATHFILL
: rName
=ImpGetResStr(STR_ObjNamePluralPATHFILL
); break;
2004 case OBJ_FREEFILL
: rName
=ImpGetResStr(STR_ObjNamePluralFREEFILL
); break;
2005 case OBJ_SPLNFILL
: rName
=ImpGetResStr(STR_ObjNamePluralPERSPLN
); break;
2010 basegfx::B2DPolyPolygon
SdrPathObj::TakeXorPoly() const
2012 return GetPathPoly();
2015 sal_uInt32
SdrPathObj::GetHdlCount() const
2017 sal_uInt32
nRetval(0L);
2018 const sal_uInt32
nPolyCount(GetPathPoly().count());
2020 for(sal_uInt32
a(0L); a
< nPolyCount
; a
++)
2022 nRetval
+= GetPathPoly().getB2DPolygon(a
).count();
2028 SdrHdl
* SdrPathObj::GetHdl(sal_uInt32 nHdlNum
) const
2031 // Warn the user that this is ineffective and show alternatives. Should not be used at all.
2032 OSL_FAIL("SdrPathObj::GetHdl(): ineffective, use AddToHdlList instead (!)");
2034 // to have an alternative, get single handle using the ineffective way
2035 SdrHdl
* pRetval
= 0;
2036 SdrHdlList
aLocalList(0);
2037 AddToHdlList(aLocalList
);
2038 const sal_uInt32
nHdlCount(aLocalList
.GetHdlCount());
2040 if(nHdlCount
&& nHdlNum
< nHdlCount
)
2042 // remove and remember. The other created handles will be deleted again with the
2043 // destruction of the local list
2044 pRetval
= aLocalList
.RemoveHdl(nHdlNum
);
2050 void SdrPathObj::AddToHdlList(SdrHdlList
& rHdlList
) const
2052 // keep old stuff to be able to keep old SdrHdl stuff, too
2053 const XPolyPolygon
aOldPathPolygon(GetPathPoly());
2054 sal_uInt16 nPolyCnt
=aOldPathPolygon
.Count();
2055 bool bClosed
=IsClosed();
2058 for (sal_uInt16 i
=0; i
<nPolyCnt
; i
++) {
2059 const XPolygon
& rXPoly
=aOldPathPolygon
.GetObject(i
);
2060 sal_uInt16 nPntCnt
=rXPoly
.GetPointCount();
2061 if (bClosed
&& nPntCnt
>1) nPntCnt
--;
2063 for (sal_uInt16 j
=0; j
<nPntCnt
; j
++) {
2064 if (rXPoly
.GetFlags(j
)!=XPOLY_CONTROL
) {
2065 const Point
& rPnt
=rXPoly
[j
];
2066 SdrHdl
* pHdl
=new SdrHdl(rPnt
,HDL_POLY
);
2067 pHdl
->SetPolyNum(i
);
2068 pHdl
->SetPointNum(j
);
2069 pHdl
->Set1PixMore(j
==0);
2070 pHdl
->SetSourceHdlNum(nIdx
);
2072 rHdlList
.AddHdl(pHdl
);
2078 sal_uInt32
SdrPathObj::GetPlusHdlCount(const SdrHdl
& rHdl
) const
2080 // keep old stuff to be able to keep old SdrHdl stuff, too
2081 const XPolyPolygon
aOldPathPolygon(GetPathPoly());
2082 sal_uInt16 nCnt
= 0;
2083 sal_uInt16 nPnt
= (sal_uInt16
)rHdl
.GetPointNum();
2084 sal_uInt16 nPolyNum
= (sal_uInt16
)rHdl
.GetPolyNum();
2086 if(nPolyNum
< aOldPathPolygon
.Count())
2088 const XPolygon
& rXPoly
= aOldPathPolygon
[nPolyNum
];
2089 sal_uInt16 nPntMax
= rXPoly
.GetPointCount();
2095 if (rXPoly
.GetFlags(nPnt
)!=XPOLY_CONTROL
)
2097 if (nPnt
==0 && IsClosed()) nPnt
=nPntMax
;
2098 if (nPnt
>0 && rXPoly
.GetFlags(nPnt
-1)==XPOLY_CONTROL
) nCnt
++;
2099 if (nPnt
==nPntMax
&& IsClosed()) nPnt
=0;
2100 if (nPnt
<nPntMax
&& rXPoly
.GetFlags(nPnt
+1)==XPOLY_CONTROL
) nCnt
++;
2109 SdrHdl
* SdrPathObj::GetPlusHdl(const SdrHdl
& rHdl
, sal_uInt32 nPlusNum
) const
2111 // keep old stuff to be able to keep old SdrHdl stuff, too
2112 const XPolyPolygon
aOldPathPolygon(GetPathPoly());
2114 sal_uInt16 nPnt
= (sal_uInt16
)rHdl
.GetPointNum();
2115 sal_uInt16 nPolyNum
= (sal_uInt16
)rHdl
.GetPolyNum();
2117 if (nPolyNum
<aOldPathPolygon
.Count())
2119 const XPolygon
& rXPoly
= aOldPathPolygon
[nPolyNum
];
2120 sal_uInt16 nPntMax
= rXPoly
.GetPointCount();
2127 pHdl
=new SdrHdlBezWgt(&rHdl
);
2128 pHdl
->SetPolyNum(rHdl
.GetPolyNum());
2130 if (nPnt
==0 && IsClosed()) nPnt
=nPntMax
;
2131 if (nPnt
>0 && rXPoly
.GetFlags(nPnt
-1)==XPOLY_CONTROL
&& nPlusNum
==0)
2133 pHdl
->SetPos(rXPoly
[nPnt
-1]);
2134 pHdl
->SetPointNum(nPnt
-1);
2138 if (nPnt
==nPntMax
&& IsClosed()) nPnt
=0;
2139 if (nPnt
<rXPoly
.GetPointCount()-1 && rXPoly
.GetFlags(nPnt
+1)==XPOLY_CONTROL
)
2141 pHdl
->SetPos(rXPoly
[nPnt
+1]);
2142 pHdl
->SetPointNum(nPnt
+1);
2146 pHdl
->SetSourceHdlNum(rHdl
.GetSourceHdlNum());
2147 pHdl
->SetPlusHdl(sal_True
);
2154 ////////////////////////////////////////////////////////////////////////////////////////////////////
2156 bool SdrPathObj::hasSpecialDrag() const
2161 bool SdrPathObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
2163 ImpPathForDragAndCreate
aDragAndCreate(*((SdrPathObj
*)this));
2165 return aDragAndCreate
.beginPathDrag(rDrag
);
2168 bool SdrPathObj::applySpecialDrag(SdrDragStat
& rDrag
)
2170 ImpPathForDragAndCreate
aDragAndCreate(*this);
2171 bool bRetval(aDragAndCreate
.beginPathDrag(rDrag
));
2175 bRetval
= aDragAndCreate
.movePathDrag(rDrag
);
2180 bRetval
= aDragAndCreate
.endPathDrag(rDrag
);
2185 NbcSetPathPoly(aDragAndCreate
.getModifiedPolyPolygon());
2191 String
SdrPathObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
2197 // #i103058# also get a comment when in creation
2198 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
2202 aRetval
= mpDAC
->getSpecialDragComment(rDrag
);
2207 ImpPathForDragAndCreate
aDragAndCreate(*((SdrPathObj
*)this));
2208 bool bDidWork(aDragAndCreate
.beginPathDrag((SdrDragStat
&)rDrag
));
2212 aRetval
= aDragAndCreate
.getSpecialDragComment(rDrag
);
2219 basegfx::B2DPolyPolygon
SdrPathObj::getSpecialDragPoly(const SdrDragStat
& rDrag
) const
2221 basegfx::B2DPolyPolygon aRetval
;
2222 ImpPathForDragAndCreate
aDragAndCreate(*((SdrPathObj
*)this));
2223 bool bDidWork(aDragAndCreate
.beginPathDrag((SdrDragStat
&)rDrag
));
2227 aRetval
= aDragAndCreate
.getSpecialDragPoly(rDrag
);
2233 ////////////////////////////////////////////////////////////////////////////////////////////////////
2235 bool SdrPathObj::BegCreate(SdrDragStat
& rStat
)
2238 return impGetDAC().BegCreate(rStat
);
2241 bool SdrPathObj::MovCreate(SdrDragStat
& rStat
)
2243 return impGetDAC().MovCreate(rStat
);
2246 bool SdrPathObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
2248 bool bRetval(impGetDAC().EndCreate(rStat
, eCmd
));
2250 if(bRetval
&& mpDAC
)
2252 SetPathPoly(mpDAC
->getModifiedPolyPolygon());
2254 // #i75974# Check for AutoClose feature. Moved here from ImpPathForDragAndCreate::EndCreate
2255 // to be able to use the type-changing ImpSetClosed method
2258 SdrView
* pView
= rStat
.GetView();
2260 if(pView
&& pView
->IsAutoClosePolys() && !pView
->IsUseIncompatiblePathCreateInterface())
2262 OutputDevice
* pOut
= pView
->GetFirstOutputDevice();
2266 if(GetPathPoly().count())
2268 const basegfx::B2DPolygon
aCandidate(GetPathPoly().getB2DPolygon(0));
2270 if(aCandidate
.count() > 2)
2272 // check distance of first and last point
2273 const sal_Int32
nCloseDist(pOut
->PixelToLogic(Size(pView
->GetAutoCloseDistPix(), 0)).Width());
2274 const basegfx::B2DVector
aDistVector(aCandidate
.getB2DPoint(aCandidate
.count() - 1) - aCandidate
.getB2DPoint(0));
2276 if(aDistVector
.getLength() <= (double)nCloseDist
)
2293 bool SdrPathObj::BckCreate(SdrDragStat
& rStat
)
2295 return impGetDAC().BckCreate(rStat
);
2298 void SdrPathObj::BrkCreate(SdrDragStat
& rStat
)
2300 impGetDAC().BrkCreate(rStat
);
2304 basegfx::B2DPolyPolygon
SdrPathObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
2306 basegfx::B2DPolyPolygon aRetval
;
2310 aRetval
= mpDAC
->TakeObjectPolyPolygon(rDrag
);
2311 aRetval
.append(mpDAC
->TakeDragPolyPolygon(rDrag
));
2317 // during drag or create, allow accessing the so-far created/modified polyPolygon
2318 basegfx::B2DPolyPolygon
SdrPathObj::getObjectPolyPolygon(const SdrDragStat
& rDrag
) const
2320 basegfx::B2DPolyPolygon aRetval
;
2324 aRetval
= mpDAC
->TakeObjectPolyPolygon(rDrag
);
2330 basegfx::B2DPolyPolygon
SdrPathObj::getDragPolyPolygon(const SdrDragStat
& rDrag
) const
2332 basegfx::B2DPolyPolygon aRetval
;
2336 aRetval
= mpDAC
->TakeDragPolyPolygon(rDrag
);
2342 Pointer
SdrPathObj::GetCreatePointer() const
2344 return impGetDAC().GetCreatePointer();
2347 void SdrPathObj::NbcMove(const Size
& rSiz
)
2349 maPathPolygon
.transform(basegfx::tools::createTranslateB2DHomMatrix(rSiz
.Width(), rSiz
.Height()));
2351 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2352 SdrTextObj::NbcMove(rSiz
);
2355 void SdrPathObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
2357 basegfx::B2DHomMatrix
aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRef
.X(), -rRef
.Y()));
2358 aTrans
= basegfx::tools::createScaleTranslateB2DHomMatrix(
2359 double(xFact
), double(yFact
), rRef
.X(), rRef
.Y()) * aTrans
;
2360 maPathPolygon
.transform(aTrans
);
2362 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2363 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
2366 void SdrPathObj::NbcRotate(const Point
& rRef
, long nWink
, double sn
, double cs
)
2368 // Thank JOE, the angles are defined mirrored to the mathematical meanings
2369 const basegfx::B2DHomMatrix
aTrans(basegfx::tools::createRotateAroundPoint(rRef
.X(), rRef
.Y(), -nWink
* nPi180
));
2370 maPathPolygon
.transform(aTrans
);
2372 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2373 SdrTextObj::NbcRotate(rRef
,nWink
,sn
,cs
);
2376 void SdrPathObj::NbcShear(const Point
& rRefPnt
, long nAngle
, double fTan
, bool bVShear
)
2378 basegfx::B2DHomMatrix
aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRefPnt
.X(), -rRefPnt
.Y()));
2382 // Thank JOE, the angles are defined mirrored to the mathematical meanings
2383 aTrans
.shearY(-fTan
);
2387 aTrans
.shearX(-fTan
);
2390 aTrans
.translate(rRefPnt
.X(), rRefPnt
.Y());
2391 maPathPolygon
.transform(aTrans
);
2393 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2394 SdrTextObj::NbcShear(rRefPnt
,nAngle
,fTan
,bVShear
);
2397 void SdrPathObj::NbcMirror(const Point
& rRefPnt1
, const Point
& rRefPnt2
)
2399 const double fDiffX(rRefPnt2
.X() - rRefPnt1
.X());
2400 const double fDiffY(rRefPnt2
.Y() - rRefPnt1
.Y());
2401 const double fRot(atan2(fDiffY
, fDiffX
));
2402 basegfx::B2DHomMatrix
aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRefPnt1
.X(), -rRefPnt1
.Y()));
2403 aTrans
.rotate(-fRot
);
2404 aTrans
.scale(1.0, -1.0);
2405 aTrans
.rotate(fRot
);
2406 aTrans
.translate(rRefPnt1
.X(), rRefPnt1
.Y());
2407 maPathPolygon
.transform(aTrans
);
2409 // Do Joe's special handling for lines when mirroring, too
2412 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2413 SdrTextObj::NbcMirror(rRefPnt1
,rRefPnt2
);
2416 void SdrPathObj::TakeUnrotatedSnapRect(Rectangle
& rRect
) const
2420 rRect
= GetSnapRect();
2424 XPolyPolygon
aXPP(GetPathPoly());
2425 RotateXPoly(aXPP
,Point(),-aGeo
.nSin
,aGeo
.nCos
);
2426 rRect
=aXPP
.GetBoundRect();
2427 Point
aTmp(rRect
.TopLeft());
2428 RotatePoint(aTmp
,Point(),aGeo
.nSin
,aGeo
.nCos
);
2429 aTmp
-=rRect
.TopLeft();
2430 rRect
.Move(aTmp
.X(),aTmp
.Y());
2434 void SdrPathObj::RecalcSnapRect()
2436 if(GetPathPoly().count())
2438 maSnapRect
= ImpGetBoundRect(GetPathPoly());
2442 void SdrPathObj::NbcSetSnapRect(const Rectangle
& rRect
)
2444 Rectangle
aOld(GetSnapRect());
2446 // Take RECT_EMPTY into account when calculating scale factors
2447 long nMulX
= (RECT_EMPTY
== rRect
.Right()) ? 0 : rRect
.Right() - rRect
.Left();
2449 long nDivX
= aOld
.Right() - aOld
.Left();
2451 // Take RECT_EMPTY into account when calculating scale factors
2452 long nMulY
= (RECT_EMPTY
== rRect
.Bottom()) ? 0 : rRect
.Bottom() - rRect
.Top();
2454 long nDivY
= aOld
.Bottom() - aOld
.Top();
2455 if ( nDivX
== 0 ) { nMulX
= 1; nDivX
= 1; }
2456 if ( nDivY
== 0 ) { nMulY
= 1; nDivY
= 1; }
2457 Fraction
aX(nMulX
,nDivX
);
2458 Fraction
aY(nMulY
,nDivY
);
2459 NbcResize(aOld
.TopLeft(), aX
, aY
);
2460 NbcMove(Size(rRect
.Left() - aOld
.Left(), rRect
.Top() - aOld
.Top()));
2463 sal_uInt32
SdrPathObj::GetSnapPointCount() const
2465 return GetHdlCount();
2468 Point
SdrPathObj::GetSnapPoint(sal_uInt32 nSnapPnt
) const
2470 sal_uInt32 nPoly
,nPnt
;
2471 if(!PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nSnapPnt
, nPoly
, nPnt
))
2473 DBG_ASSERT(sal_False
,"SdrPathObj::GetSnapPoint: Point nSnapPnt does not exist.");
2476 const basegfx::B2DPoint
aB2DPoint(GetPathPoly().getB2DPolygon(nPoly
).getB2DPoint(nPnt
));
2477 return Point(FRound(aB2DPoint
.getX()), FRound(aB2DPoint
.getY()));
2480 sal_Bool
SdrPathObj::IsPolyObj() const
2485 sal_uInt32
SdrPathObj::GetPointCount() const
2487 const sal_uInt32
nPolyCount(GetPathPoly().count());
2488 sal_uInt32
nRetval(0L);
2490 for(sal_uInt32
a(0L); a
< nPolyCount
; a
++)
2492 nRetval
+= GetPathPoly().getB2DPolygon(a
).count();
2498 Point
SdrPathObj::GetPoint(sal_uInt32 nHdlNum
) const
2501 sal_uInt32 nPoly
,nPnt
;
2503 if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum
, nPoly
, nPnt
))
2505 const basegfx::B2DPolygon
aPoly(GetPathPoly().getB2DPolygon(nPoly
));
2506 const basegfx::B2DPoint
aPoint(aPoly
.getB2DPoint(nPnt
));
2507 aRetval
= Point(FRound(aPoint
.getX()), FRound(aPoint
.getY()));
2513 void SdrPathObj::NbcSetPoint(const Point
& rPnt
, sal_uInt32 nHdlNum
)
2515 sal_uInt32 nPoly
,nPnt
;
2517 if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum
, nPoly
, nPnt
))
2519 basegfx::B2DPolygon
aNewPolygon(GetPathPoly().getB2DPolygon(nPoly
));
2520 aNewPolygon
.setB2DPoint(nPnt
, basegfx::B2DPoint(rPnt
.X(), rPnt
.Y()));
2521 maPathPolygon
.setB2DPolygon(nPoly
, aNewPolygon
);
2523 if(meKind
==OBJ_LINE
)
2529 if(GetPathPoly().count())
2531 // #i10659# for SdrTextObj, keep aRect up to date
2532 aRect
= ImpGetBoundRect(GetPathPoly());
2540 sal_uInt32
SdrPathObj::NbcInsPointOld(const Point
& rPos
, sal_Bool bNewObj
, sal_Bool bHideHim
)
2546 nNewHdl
= NbcInsPoint(0L, rPos
, sal_True
, bHideHim
);
2550 // look for smallest distance data
2551 const basegfx::B2DPoint
aTestPoint(rPos
.X(), rPos
.Y());
2552 sal_uInt32
nSmallestPolyIndex(0L);
2553 sal_uInt32
nSmallestEdgeIndex(0L);
2554 double fSmallestCut
;
2555 basegfx::tools::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint
, nSmallestPolyIndex
, nSmallestEdgeIndex
, fSmallestCut
);
2557 // create old polygon index from it
2558 sal_uInt32
nPolyIndex(nSmallestEdgeIndex
);
2560 for(sal_uInt32
a(0L); a
< nSmallestPolyIndex
; a
++)
2562 nPolyIndex
+= GetPathPoly().getB2DPolygon(a
).count();
2565 nNewHdl
= NbcInsPoint(nPolyIndex
, rPos
, sal_False
, bHideHim
);
2572 sal_uInt32
SdrPathObj::NbcInsPoint(sal_uInt32
/*nHdlNum*/, const Point
& rPos
, sal_Bool bNewObj
, sal_Bool
/*bHideHim*/)
2578 basegfx::B2DPolygon aNewPoly
;
2579 const basegfx::B2DPoint
aPoint(rPos
.X(), rPos
.Y());
2580 aNewPoly
.append(aPoint
);
2581 aNewPoly
.setClosed(IsClosed());
2582 maPathPolygon
.append(aNewPoly
);
2584 nNewHdl
= GetHdlCount();
2588 // look for smallest distance data
2589 const basegfx::B2DPoint
aTestPoint(rPos
.X(), rPos
.Y());
2590 sal_uInt32
nSmallestPolyIndex(0L);
2591 sal_uInt32
nSmallestEdgeIndex(0L);
2592 double fSmallestCut
;
2593 basegfx::tools::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint
, nSmallestPolyIndex
, nSmallestEdgeIndex
, fSmallestCut
);
2594 basegfx::B2DPolygon
aCandidate(GetPathPoly().getB2DPolygon(nSmallestPolyIndex
));
2595 const bool bBefore(!aCandidate
.isClosed() && 0L == nSmallestEdgeIndex
&& 0.0 == fSmallestCut
);
2596 const bool bAfter(!aCandidate
.isClosed() && aCandidate
.count() == nSmallestEdgeIndex
+ 2L && 1.0 == fSmallestCut
);
2600 // before first point
2601 aCandidate
.insert(0L, aTestPoint
);
2603 if(aCandidate
.areControlPointsUsed())
2605 if(aCandidate
.isNextControlPointUsed(1))
2607 aCandidate
.setNextControlPoint(0, interpolate(aTestPoint
, aCandidate
.getB2DPoint(1), (1.0 / 3.0)));
2608 aCandidate
.setPrevControlPoint(1, interpolate(aTestPoint
, aCandidate
.getB2DPoint(1), (2.0 / 3.0)));
2617 aCandidate
.append(aTestPoint
);
2619 if(aCandidate
.areControlPointsUsed())
2621 if(aCandidate
.isPrevControlPointUsed(aCandidate
.count() - 2))
2623 aCandidate
.setNextControlPoint(aCandidate
.count() - 2, interpolate(aCandidate
.getB2DPoint(aCandidate
.count() - 2), aTestPoint
, (1.0 / 3.0)));
2624 aCandidate
.setPrevControlPoint(aCandidate
.count() - 1, interpolate(aCandidate
.getB2DPoint(aCandidate
.count() - 2), aTestPoint
, (2.0 / 3.0)));
2628 nNewHdl
= aCandidate
.count() - 1L;
2633 bool bSegmentSplit(false);
2634 const sal_uInt32
nNextIndex((nSmallestEdgeIndex
+ 1) % aCandidate
.count());
2636 if(aCandidate
.areControlPointsUsed())
2638 if(aCandidate
.isNextControlPointUsed(nSmallestEdgeIndex
) || aCandidate
.isPrevControlPointUsed(nNextIndex
))
2640 bSegmentSplit
= true;
2646 // rebuild original segment to get the split data
2647 basegfx::B2DCubicBezier aBezierA
, aBezierB
;
2648 const basegfx::B2DCubicBezier
aBezier(
2649 aCandidate
.getB2DPoint(nSmallestEdgeIndex
),
2650 aCandidate
.getNextControlPoint(nSmallestEdgeIndex
),
2651 aCandidate
.getPrevControlPoint(nNextIndex
),
2652 aCandidate
.getB2DPoint(nNextIndex
));
2654 // split and insert hit point
2655 aBezier
.split(fSmallestCut
, &aBezierA
, &aBezierB
);
2656 aCandidate
.insert(nSmallestEdgeIndex
+ 1, aTestPoint
);
2658 // since we inserted hit point and not split point, we need to add an offset
2659 // to the control points to get the C1 continuity we want to achieve
2660 const basegfx::B2DVector
aOffset(aTestPoint
- aBezierA
.getEndPoint());
2661 aCandidate
.setNextControlPoint(nSmallestEdgeIndex
, aBezierA
.getControlPointA() + aOffset
);
2662 aCandidate
.setPrevControlPoint(nSmallestEdgeIndex
+ 1, aBezierA
.getControlPointB() + aOffset
);
2663 aCandidate
.setNextControlPoint(nSmallestEdgeIndex
+ 1, aBezierB
.getControlPointA() + aOffset
);
2664 aCandidate
.setPrevControlPoint((nSmallestEdgeIndex
+ 2) % aCandidate
.count(), aBezierB
.getControlPointB() + aOffset
);
2668 aCandidate
.insert(nSmallestEdgeIndex
+ 1L, aTestPoint
);
2671 nNewHdl
= nSmallestEdgeIndex
+ 1L;
2674 maPathPolygon
.setB2DPolygon(nSmallestPolyIndex
, aCandidate
);
2676 // create old polygon index from it
2677 for(sal_uInt32
a(0L); a
< nSmallestPolyIndex
; a
++)
2679 nNewHdl
+= GetPathPoly().getB2DPolygon(a
).count();
2687 SdrObject
* SdrPathObj::RipPoint(sal_uInt32 nHdlNum
, sal_uInt32
& rNewPt0Index
)
2689 SdrPathObj
* pNewObj
= 0L;
2690 const basegfx::B2DPolyPolygon
aLocalPolyPolygon(GetPathPoly());
2691 sal_uInt32 nPoly
, nPnt
;
2693 if(PolyPolygonEditor::GetRelativePolyPoint(aLocalPolyPolygon
, nHdlNum
, nPoly
, nPnt
))
2697 const basegfx::B2DPolygon
aCandidate(aLocalPolyPolygon
.getB2DPolygon(nPoly
));
2698 const sal_uInt32
nPointCount(aCandidate
.count());
2704 // when closed, RipPoint means to open the polygon at the selected point. To
2705 // be able to do that, it is necessary to make the selected point the first one
2706 basegfx::B2DPolygon
aNewPolygon(basegfx::tools::makeStartPoint(aCandidate
, nPnt
));
2707 SetPathPoly(basegfx::B2DPolyPolygon(aNewPolygon
));
2710 // give back new position of old start point (historical reasons)
2711 rNewPt0Index
= (nPointCount
- nPnt
) % nPointCount
;
2715 if(nPointCount
>= 3L && nPnt
!= 0L && nPnt
+ 1L < nPointCount
)
2717 // split in two objects at point nPnt
2718 basegfx::B2DPolygon
aSplitPolyA(aCandidate
, 0L, nPnt
+ 1L);
2719 SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyA
));
2721 pNewObj
= (SdrPathObj
*)Clone();
2722 basegfx::B2DPolygon
aSplitPolyB(aCandidate
, nPnt
, nPointCount
- nPnt
);
2723 pNewObj
->SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyB
));
2733 SdrObject
* SdrPathObj::DoConvertToPolyObj(sal_Bool bBezier
) const
2735 // #i89784# check for FontWork with activated HideContour
2736 const drawinglayer::attribute::SdrTextAttribute
aText(
2737 drawinglayer::primitive2d::createNewSdrTextAttribute(GetObjectItemSet(), *getText(0)));
2738 const bool bHideContour(
2739 !aText
.isDefault() && !aText
.getSdrFormTextAttribute().isDefault() && aText
.isHideContour());
2741 SdrObject
* pRet
= bHideContour
?
2743 ImpConvertMakeObj(GetPathPoly(), IsClosed(), bBezier
);
2745 SdrPathObj
* pPath
= PTR_CAST(SdrPathObj
, pRet
);
2749 if(pPath
->GetPathPoly().areControlPointsUsed())
2753 // reduce all bezier curves
2754 pPath
->SetPathPoly(basegfx::tools::adaptiveSubdivideByAngle(pPath
->GetPathPoly()));
2761 // create bezier curves
2762 pPath
->SetPathPoly(basegfx::tools::expandToCurve(pPath
->GetPathPoly()));
2767 pRet
= ImpConvertAddText(pRet
, bBezier
);
2772 SdrObjGeoData
* SdrPathObj::NewGeoData() const
2774 return new SdrPathObjGeoData
;
2777 void SdrPathObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
2779 SdrTextObj::SaveGeoData(rGeo
);
2780 SdrPathObjGeoData
& rPGeo
= (SdrPathObjGeoData
&) rGeo
;
2781 rPGeo
.maPathPolygon
=GetPathPoly();
2782 rPGeo
.meKind
=meKind
;
2785 void SdrPathObj::RestGeoData(const SdrObjGeoData
& rGeo
)
2787 SdrTextObj::RestGeoData(rGeo
);
2788 SdrPathObjGeoData
& rPGeo
=(SdrPathObjGeoData
&)rGeo
;
2789 maPathPolygon
=rPGeo
.maPathPolygon
;
2790 meKind
=rPGeo
.meKind
;
2791 ImpForceKind(); // to set bClosed (among other things)
2794 void SdrPathObj::NbcSetPathPoly(const basegfx::B2DPolyPolygon
& rPathPoly
)
2796 if(GetPathPoly() != rPathPoly
)
2798 maPathPolygon
=rPathPoly
;
2804 void SdrPathObj::SetPathPoly(const basegfx::B2DPolyPolygon
& rPathPoly
)
2806 if(GetPathPoly() != rPathPoly
)
2808 Rectangle aBoundRect0
; if (pUserCall
!=NULL
) aBoundRect0
=GetLastBoundRect();
2809 NbcSetPathPoly(rPathPoly
);
2811 BroadcastObjectChange();
2812 SendUserCall(SDRUSERCALL_RESIZE
,aBoundRect0
);
2816 void SdrPathObj::ToggleClosed()
2818 Rectangle aBoundRect0
;
2819 if(pUserCall
!= NULL
)
2820 aBoundRect0
= GetLastBoundRect();
2821 ImpSetClosed(!IsClosed()); // set new ObjKind
2822 ImpForceKind(); // because we want Line -> Poly -> PolyLine instead of Line -> Poly -> Line
2825 BroadcastObjectChange();
2826 SendUserCall(SDRUSERCALL_RESIZE
, aBoundRect0
);
2829 // for friend class SdrPolyEditView in some compilers:
2830 void SdrPathObj::SetRectsDirty(sal_Bool bNotMyself
)
2832 SdrTextObj::SetRectsDirty(bNotMyself
);
2835 ImpPathForDragAndCreate
& SdrPathObj::impGetDAC() const
2839 ((SdrPathObj
*)this)->mpDAC
= new ImpPathForDragAndCreate(*((SdrPathObj
*)this));
2845 void SdrPathObj::impDeleteDAC() const
2850 ((SdrPathObj
*)this)->mpDAC
= 0L;
2854 ////////////////////////////////////////////////////////////////////////////////////////////////////
2856 // transformation interface for StarOfficeAPI. This implements support for
2857 // homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
2858 // moment it contains a shearX, rotation and translation, but for setting all linear
2859 // transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
2861 ////////////////////////////////////////////////////////////////////////////////////////////////////
2862 // gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
2863 // with the base geometry and returns TRUE. Otherwise it returns FALSE.
2864 sal_Bool
SdrPathObj::TRGetBaseGeometry(basegfx::B2DHomMatrix
& rMatrix
, basegfx::B2DPolyPolygon
& rPolyPolygon
) const
2866 double fRotate(0.0);
2867 double fShearX(0.0);
2868 basegfx::B2DTuple
aScale(1.0, 1.0);
2869 basegfx::B2DTuple
aTranslate(0.0, 0.0);
2871 if(GetPathPoly().count())
2874 basegfx::B2DHomMatrix aMoveToZeroMatrix
;
2875 rPolyPolygon
= GetPathPoly();
2877 if(OBJ_LINE
== meKind
)
2879 // ignore shear and rotate, just use scale and translate
2880 OSL_ENSURE(GetPathPoly().count() > 0L && GetPathPoly().getB2DPolygon(0L).count() > 1L, "OBJ_LINE with too few polygons (!)");
2881 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
2882 // itself, else this method will no longer return the full polygon information (curve will
2884 const basegfx::B2DRange
aPolyRangeNoCurve(basegfx::tools::getRange(rPolyPolygon
));
2885 aScale
= aPolyRangeNoCurve
.getRange();
2886 aTranslate
= aPolyRangeNoCurve
.getMinimum();
2888 // define matrix for move polygon to zero point
2889 aMoveToZeroMatrix
.translate(-aTranslate
.getX(), -aTranslate
.getY());
2893 if(aGeo
.nShearWink
|| aGeo
.nDrehWink
)
2895 // get rotate and shear in drawingLayer notation
2896 fRotate
= aGeo
.nDrehWink
* F_PI18000
;
2897 fShearX
= aGeo
.nShearWink
* F_PI18000
;
2899 // build mathematically correct (negative shear and rotate) object transform
2900 // containing shear and rotate to extract unsheared, unrotated polygon
2901 basegfx::B2DHomMatrix aObjectMatrix
;
2902 aObjectMatrix
.shearX(tan((36000 - aGeo
.nShearWink
) * F_PI18000
));
2903 aObjectMatrix
.rotate((36000 - aGeo
.nDrehWink
) * F_PI18000
);
2905 // create inverse from it and back-transform polygon
2906 basegfx::B2DHomMatrix
aInvObjectMatrix(aObjectMatrix
);
2907 aInvObjectMatrix
.invert();
2908 rPolyPolygon
.transform(aInvObjectMatrix
);
2910 // get range from unsheared, unrotated polygon and extract scale and translate.
2911 // transform topLeft from it back to transformed state to get original
2912 // topLeft (rotation center)
2913 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
2914 // itself, else this method will no longer return the full polygon information (curve will
2916 const basegfx::B2DRange
aCorrectedRangeNoCurve(basegfx::tools::getRange(rPolyPolygon
));
2917 aTranslate
= aObjectMatrix
* aCorrectedRangeNoCurve
.getMinimum();
2918 aScale
= aCorrectedRangeNoCurve
.getRange();
2920 // define matrix for move polygon to zero point
2921 // #i112280# Added missing minus for Y-Translation
2922 aMoveToZeroMatrix
.translate(-aCorrectedRangeNoCurve
.getMinX(), -aCorrectedRangeNoCurve
.getMinY());
2926 // get scale and translate from unsheared, unrotated polygon
2927 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
2928 // itself, else this method will no longer return the full polygon information (curve will
2930 const basegfx::B2DRange
aPolyRangeNoCurve(basegfx::tools::getRange(rPolyPolygon
));
2931 aScale
= aPolyRangeNoCurve
.getRange();
2932 aTranslate
= aPolyRangeNoCurve
.getMinimum();
2934 // define matrix for move polygon to zero point
2935 aMoveToZeroMatrix
.translate(-aTranslate
.getX(), -aTranslate
.getY());
2939 // move polygon to zero point with pre-defined matrix
2940 rPolyPolygon
.transform(aMoveToZeroMatrix
);
2943 // position maybe relative to anchorpos, convert
2944 if( pModel
&& pModel
->IsWriter() )
2946 if(GetAnchorPos().X() || GetAnchorPos().Y())
2948 aTranslate
-= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
2952 // force MapUnit to 100th mm
2953 SfxMapUnit eMapUnit
= GetObjectItemSet().GetPool()->GetMetric(0);
2954 if(eMapUnit
!= SFX_MAPUNIT_100TH_MM
)
2958 case SFX_MAPUNIT_TWIP
:
2961 aTranslate
.setX(ImplTwipsToMM(aTranslate
.getX()));
2962 aTranslate
.setY(ImplTwipsToMM(aTranslate
.getY()));
2965 aScale
.setX(ImplTwipsToMM(aScale
.getX()));
2966 aScale
.setY(ImplTwipsToMM(aScale
.getY()));
2969 basegfx::B2DHomMatrix aTwipsToMM
;
2970 const double fFactorTwipsToMM(127.0 / 72.0);
2971 aTwipsToMM
.scale(fFactorTwipsToMM
, fFactorTwipsToMM
);
2972 rPolyPolygon
.transform(aTwipsToMM
);
2978 OSL_FAIL("TRGetBaseGeometry: Missing unit translation to 100th mm!");
2983 // build return value matrix
2984 rMatrix
= basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
2986 basegfx::fTools::equalZero(fShearX
) ? 0.0 : tan(fShearX
),
2987 basegfx::fTools::equalZero(fRotate
) ? 0.0 : -fRotate
,
2993 // Sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
2994 // If it's an SdrPathObj it will use the provided geometry information. The Polygon has
2995 // to use (0,0) as upper left and will be scaled to the given size in the matrix.
2996 void SdrPathObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& rPolyPolygon
)
2999 basegfx::B2DTuple aScale
;
3000 basegfx::B2DTuple aTranslate
;
3001 double fRotate
, fShearX
;
3002 rMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
3004 // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
3005 // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
3006 if(basegfx::fTools::less(aScale
.getX(), 0.0) && basegfx::fTools::less(aScale
.getY(), 0.0))
3008 aScale
.setX(fabs(aScale
.getX()));
3009 aScale
.setY(fabs(aScale
.getY()));
3010 fRotate
= fmod(fRotate
+ F_PI
, F_2PI
);
3014 basegfx::B2DPolyPolygon
aNewPolyPolygon(rPolyPolygon
);
3016 // reset object shear and rotations
3018 aGeo
.RecalcSinCos();
3019 aGeo
.nShearWink
= 0;
3022 // force metric to pool metric
3023 SfxMapUnit eMapUnit
= GetObjectItemSet().GetPool()->GetMetric(0);
3024 if(eMapUnit
!= SFX_MAPUNIT_100TH_MM
)
3028 case SFX_MAPUNIT_TWIP
:
3031 aTranslate
.setX(ImplMMToTwips(aTranslate
.getX()));
3032 aTranslate
.setY(ImplMMToTwips(aTranslate
.getY()));
3035 aScale
.setX(ImplMMToTwips(aScale
.getX()));
3036 aScale
.setY(ImplMMToTwips(aScale
.getY()));
3039 basegfx::B2DHomMatrix aMMToTwips
;
3040 const double fFactorMMToTwips(72.0 / 127.0);
3041 aMMToTwips
.scale(fFactorMMToTwips
, fFactorMMToTwips
);
3042 aNewPolyPolygon
.transform(aMMToTwips
);
3048 OSL_FAIL("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
3053 if( pModel
&& pModel
->IsWriter() )
3055 // if anchor is used, make position relative to it
3056 if(GetAnchorPos().X() || GetAnchorPos().Y())
3058 aTranslate
+= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
3062 // create transformation for polygon, set values at aGeo direct
3063 basegfx::B2DHomMatrix aTransform
;
3066 // Given polygon is already scaled (for historical reasons), but not mirrored yet.
3067 // Thus, when scale is negative in X or Y, apply the needed mirroring accordingly.
3068 if(basegfx::fTools::less(aScale
.getX(), 0.0) || basegfx::fTools::less(aScale
.getY(), 0.0))
3071 basegfx::fTools::less(aScale
.getX(), 0.0) ? -1.0 : 1.0,
3072 basegfx::fTools::less(aScale
.getY(), 0.0) ? -1.0 : 1.0);
3075 if(!basegfx::fTools::equalZero(fShearX
))
3077 aTransform
.shearX(tan(-atan(fShearX
)));
3078 aGeo
.nShearWink
= FRound(atan(fShearX
) / F_PI18000
);
3082 if(!basegfx::fTools::equalZero(fRotate
))
3085 // fRotate is mathematically correct for linear transformations, so it's
3086 // the one to use for the geometry change
3087 aTransform
.rotate(fRotate
);
3090 // fRotate is mathematically correct, but aGeoStat.nDrehWink is
3091 // mirrored -> mirror value here
3092 aGeo
.nDrehWink
= NormAngle360(FRound(-fRotate
/ F_PI18000
));
3093 aGeo
.RecalcSinCos();
3096 if(!aTranslate
.equalZero())
3098 // #i39529# absolute positioning, so get current position (without control points (!))
3099 const basegfx::B2DRange
aCurrentRange(basegfx::tools::getRange(aNewPolyPolygon
));
3100 aTransform
.translate(aTranslate
.getX() - aCurrentRange
.getMinX(), aTranslate
.getY() - aCurrentRange
.getMinY());
3103 // transform polygon and trigger change
3104 aNewPolyPolygon
.transform(aTransform
);
3105 SetPathPoly(aNewPolyPolygon
);
3108 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */