1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <tools/bigint.hxx>
22 #include <tools/helpers.hxx>
23 #include <svx/svdopath.hxx>
25 #include <svx/xpool.hxx>
26 #include <svx/xpoly.hxx>
27 #include <svx/svdattr.hxx>
28 #include <svx/svdtrans.hxx>
29 #include <svx/svdetc.hxx>
30 #include <svx/svddrag.hxx>
31 #include <svx/svdmodel.hxx>
32 #include <svx/svdpage.hxx>
33 #include <svx/svdhdl.hxx>
34 #include <svx/svdview.hxx> // for MovCreate when using curves
35 #include "svx/svdglob.hxx" // Stringcache
36 #include "svx/svdstr.hrc" // the object's name
38 #include <svx/xlnwtit.hxx>
39 #include <svx/xlnclit.hxx>
40 #include <svx/xflclit.hxx>
41 #include <svx/svdogrp.hxx>
42 #include <svx/polypolygoneditor.hxx>
43 #include <svx/xlntrit.hxx>
44 #include <svx/sdr/contact/viewcontactofsdrpathobj.hxx>
45 #include <basegfx/matrix/b2dhommatrix.hxx>
46 #include "svdconv.hxx"
47 #include <basegfx/point/b2dpoint.hxx>
48 #include <basegfx/polygon/b2dpolypolygontools.hxx>
49 #include <basegfx/range/b2drange.hxx>
50 #include <basegfx/curve/b2dcubicbezier.hxx>
51 #include <basegfx/polygon/b2dpolygontools.hxx>
52 #include <svx/sdr/attribute/sdrtextattribute.hxx>
53 #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
54 #include <basegfx/matrix/b2dhommatrixtools.hxx>
55 #include <svx/sdr/attribute/sdrformtextattribute.hxx>
59 inline sal_uInt16
GetPrevPnt(sal_uInt16 nPnt
, sal_uInt16 nPntMax
, bool bClosed
)
70 inline sal_uInt16
GetNextPnt(sal_uInt16 nPnt
, sal_uInt16 nPntMax
, bool bClosed
)
73 if (nPnt
>nPntMax
|| (bClosed
&& nPnt
>=nPntMax
)) nPnt
=0;
77 struct ImpSdrPathDragData
: public SdrDragStatUserData
79 XPolygon aXP
; // section of the original polygon
80 bool bValid
; // FALSE = too few points
81 bool bClosed
; // closed object?
82 sal_uInt16 nPoly
; // number of the polygon in the PolyPolygon
83 sal_uInt16 nPnt
; // number of point in the above polygon
84 sal_uInt16 nPntAnz
; // number of points of the polygon
85 sal_uInt16 nPntMax
; // maximum index
86 bool bBegPnt
; // dragged point is first point of a Polyline
87 bool bEndPnt
; // dragged point is finishing point of a Polyline
88 sal_uInt16 nPrevPnt
; // index of previous point
89 sal_uInt16 nNextPnt
; // index of next point
90 bool bPrevIsBegPnt
; // previous point is first point of a Polyline
91 bool bNextIsEndPnt
; // next point is first point of a Polyline
92 sal_uInt16 nPrevPrevPnt
; // index of point before previous point
93 sal_uInt16 nNextNextPnt
; // index of point after next point
94 bool bControl
; // point is a control point
95 bool bIsPrevControl
; // point is a control point before a support point
96 bool bIsNextControl
; // point is a control point after a support point
97 bool bPrevIsControl
; // if nPnt is a support point: a control point comes before
98 bool bNextIsControl
; // if nPnt is a support point: a control point comes after
99 sal_uInt16 nPrevPrevPnt0
;
100 sal_uInt16 nPrevPnt0
;
102 sal_uInt16 nNextPnt0
;
103 sal_uInt16 nNextNextPnt0
;
104 bool bEliminate
; // delete point? (is set by MovDrag)
106 bool mbMultiPointDrag
;
107 const XPolyPolygon maOrig
;
109 std::vector
<SdrHdl
*> maHandles
;
112 ImpSdrPathDragData(const SdrPathObj
& rPO
, const SdrHdl
& rHdl
, bool bMuPoDr
, const SdrDragStat
& rDrag
);
113 void ResetPoly(const SdrPathObj
& rPO
);
114 bool IsMultiPointDrag() const { return mbMultiPointDrag
; }
117 ImpSdrPathDragData::ImpSdrPathDragData(const SdrPathObj
& rPO
, const SdrHdl
& rHdl
, bool bMuPoDr
, const SdrDragStat
& rDrag
)
119 mbMultiPointDrag(bMuPoDr
),
120 maOrig(rPO
.GetPathPoly()),
125 const SdrMarkView
& rMarkView
= *rDrag
.GetView();
126 const SdrHdlList
& rHdlList
= rMarkView
.GetHdlList();
127 const sal_uInt32 nHdlCount
= rHdlList
.GetHdlCount();
128 const SdrObject
* pInteractionObject(nHdlCount
&& rHdlList
.GetHdl(0) ? rHdlList
.GetHdl(0)->GetObj() : 0);
130 for(sal_uInt32
a(0); a
< nHdlCount
; a
++)
132 SdrHdl
* pTestHdl
= rHdlList
.GetHdl(a
);
134 if(pTestHdl
&& pTestHdl
->IsSelected() && pTestHdl
->GetObj() == pInteractionObject
)
136 maHandles
.push_back(pTestHdl
);
146 bClosed
=rPO
.IsClosed(); // closed object?
147 nPoly
=(sal_uInt16
)rHdl
.GetPolyNum(); // number of the polygon in the PolyPolygon
148 nPnt
=(sal_uInt16
)rHdl
.GetPointNum(); // number of points in the above polygon
149 const XPolygon
aTmpXP(rPO
.GetPathPoly().getB2DPolygon(nPoly
));
150 nPntAnz
=aTmpXP
.GetPointCount(); // number of point of the polygon
151 if (nPntAnz
==0 || (bClosed
&& nPntAnz
==1)) return; // minimum of 1 points for Lines, minimum of 2 points for Polygon
152 nPntMax
=nPntAnz
-1; // maximum index
153 bBegPnt
=!bClosed
&& nPnt
==0; // dragged point is first point of a Polyline
154 bEndPnt
=!bClosed
&& nPnt
==nPntMax
; // dragged point is finishing point of a Polyline
155 if (bClosed
&& nPntAnz
<=3) { // if polygon is only a line
156 bBegPnt
=(nPntAnz
<3) || nPnt
==0;
157 bEndPnt
=(nPntAnz
<3) || nPnt
==nPntMax
-1;
159 nPrevPnt
=nPnt
; // index of previous point
160 nNextPnt
=nPnt
; // index of next point
161 if (!bBegPnt
) nPrevPnt
=GetPrevPnt(nPnt
,nPntMax
,bClosed
);
162 if (!bEndPnt
) nNextPnt
=GetNextPnt(nPnt
,nPntMax
,bClosed
);
163 bPrevIsBegPnt
=bBegPnt
|| (!bClosed
&& nPrevPnt
==0);
164 bNextIsEndPnt
=bEndPnt
|| (!bClosed
&& nNextPnt
==nPntMax
);
165 nPrevPrevPnt
=nPnt
; // index of point before previous point
166 nNextNextPnt
=nPnt
; // index of point after next point
167 if (!bPrevIsBegPnt
) nPrevPrevPnt
=GetPrevPnt(nPrevPnt
,nPntMax
,bClosed
);
168 if (!bNextIsEndPnt
) nNextNextPnt
=GetNextPnt(nNextPnt
,nPntMax
,bClosed
);
169 bControl
=rHdl
.IsPlusHdl(); // point is a control point
170 bIsPrevControl
=sal_False
; // point is a control point before a support point
171 bIsNextControl
=sal_False
; // point is a control point after a support point
172 bPrevIsControl
=sal_False
; // if nPnt is a support point: a control point comes before
173 bNextIsControl
=sal_False
; // if nPnt is a support point: a control point comes after
175 bIsPrevControl
=aTmpXP
.IsControl(nPrevPnt
);
176 bIsNextControl
=!bIsPrevControl
;
178 bPrevIsControl
=!bBegPnt
&& !bPrevIsBegPnt
&& aTmpXP
.GetFlags(nPrevPnt
)==XPOLY_CONTROL
;
179 bNextIsControl
=!bEndPnt
&& !bNextIsEndPnt
&& aTmpXP
.GetFlags(nNextPnt
)==XPOLY_CONTROL
;
181 nPrevPrevPnt0
=nPrevPrevPnt
;
185 nNextNextPnt0
=nNextNextPnt
;
191 bEliminate
=sal_False
;
197 void ImpSdrPathDragData::ResetPoly(const SdrPathObj
& rPO
)
199 const XPolygon
aTmpXP(rPO
.GetPathPoly().getB2DPolygon(nPoly
));
200 aXP
[0]=aTmpXP
[nPrevPrevPnt0
]; aXP
.SetFlags(0,aTmpXP
.GetFlags(nPrevPrevPnt0
));
201 aXP
[1]=aTmpXP
[nPrevPnt0
]; aXP
.SetFlags(1,aTmpXP
.GetFlags(nPrevPnt0
));
202 aXP
[2]=aTmpXP
[nPnt0
]; aXP
.SetFlags(2,aTmpXP
.GetFlags(nPnt0
));
203 aXP
[3]=aTmpXP
[nNextPnt0
]; aXP
.SetFlags(3,aTmpXP
.GetFlags(nNextPnt0
));
204 aXP
[4]=aTmpXP
[nNextNextPnt0
]; aXP
.SetFlags(4,aTmpXP
.GetFlags(nNextNextPnt0
));
207 /*************************************************************************/
209 struct ImpPathCreateUser
: public SdrDragStatUserData
236 sal_uInt16 nBezierStartPoint
;
237 SdrObjKind eStartKind
;
241 ImpPathCreateUser(): nCircRadius(0),nCircStWink(0),nCircRelWink(0),
242 bBezier(sal_False
),bBezHasCtrl0(sal_False
),bCurve(sal_False
),bCircle(sal_False
),bAngleSnap(sal_False
),bLine(sal_False
),bLine90(sal_False
),bRect(sal_False
),
243 bMixedCreate(sal_False
),nBezierStartPoint(0),eStartKind(OBJ_NONE
),eAktKind(OBJ_NONE
) { }
245 void ResetFormFlags() { bBezier
=sal_False
; bCurve
=sal_False
; bCircle
=sal_False
; bLine
=sal_False
; bRect
=sal_False
; }
246 bool IsFormFlag() const { return bBezier
|| bCurve
|| bCircle
|| bLine
|| bRect
; }
247 XPolygon
GetFormPoly() const;
248 bool CalcBezier(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, bool bMouseDown
);
249 XPolygon
GetBezierPoly() const;
250 XPolygon
GetCurvePoly() const { return XPolygon(); }
251 bool CalcCircle(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
);
252 XPolygon
GetCirclePoly() const;
253 bool CalcLine(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
);
254 Point
CalcLine(const Point
& rCsr
, long nDirX
, long nDirY
, SdrView
* pView
) const;
255 XPolygon
GetLinePoly() const;
256 bool CalcRect(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
);
257 XPolygon
GetRectPoly() const;
260 XPolygon
ImpPathCreateUser::GetFormPoly() const
262 if (bBezier
) return GetBezierPoly();
263 if (bCurve
) return GetCurvePoly();
264 if (bCircle
) return GetCirclePoly();
265 if (bLine
) return GetLinePoly();
266 if (bRect
) return GetRectPoly();
270 bool ImpPathCreateUser::CalcBezier(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, bool bMouseDown
)
278 // Also copy the end point when no end point is set yet
279 if (!bMouseDown
|| (0L == aBezEnd
.X() && 0L == aBezEnd
.Y())) aBezEnd
=rP2
;
285 XPolygon
ImpPathCreateUser::GetBezierPoly() const
288 aXP
[0]=aBezStart
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
289 aXP
[1]=aBezCtrl1
; aXP
.SetFlags(1,XPOLY_CONTROL
);
290 aXP
[2]=aBezCtrl2
; aXP
.SetFlags(2,XPOLY_CONTROL
);
295 bool ImpPathCreateUser::CalcCircle(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
)
297 long nTangAngle
=GetAngle(rDir
);
301 long dx
=rP2
.X()-rP1
.X();
302 long dy
=rP2
.Y()-rP1
.Y();
303 long dAngle
=GetAngle(Point(dx
,dy
))-nTangAngle
;
304 dAngle
=NormAngle360(dAngle
);
305 long nTmpAngle
=NormAngle360(9000-dAngle
);
306 bool bRet
=nTmpAngle
!=9000 && nTmpAngle
!=27000;
309 double cs
=cos(nTmpAngle
*nPi180
);
310 double nR
=(double)GetLen(Point(dx
,dy
))/cs
/2;
311 nRad
=std::abs(Round(nR
));
314 nCircStWink
=NormAngle360(nTangAngle
-9000);
315 nCircRelWink
=NormAngle360(2*dAngle
);
316 aCircCenter
.X()+=Round(nRad
*cos((nTangAngle
+9000)*nPi180
));
317 aCircCenter
.Y()-=Round(nRad
*sin((nTangAngle
+9000)*nPi180
));
319 nCircStWink
=NormAngle360(nTangAngle
+9000);
320 nCircRelWink
=-NormAngle360(36000-2*dAngle
);
321 aCircCenter
.X()+=Round(nRad
*cos((nTangAngle
-9000)*nPi180
));
322 aCircCenter
.Y()-=Round(nRad
*sin((nTangAngle
-9000)*nPi180
));
324 bAngleSnap
=pView
!=NULL
&& pView
->IsAngleSnapEnabled();
326 long nSA
=pView
->GetSnapAngle();
327 if (nSA
!=0) { // angle snapping
328 bool bNeg
=nCircRelWink
<0;
329 if (bNeg
) nCircRelWink
=-nCircRelWink
;
333 nCircRelWink
=NormAngle360(nCircRelWink
);
334 if (bNeg
) nCircRelWink
=-nCircRelWink
;
338 if (nRad
==0 || std::abs(nCircRelWink
)<5) bRet
=sal_False
;
343 XPolygon
ImpPathCreateUser::GetCirclePoly() const
345 if (nCircRelWink
>=0) {
346 XPolygon
aXP(aCircCenter
,nCircRadius
,nCircRadius
,
347 sal_uInt16((nCircStWink
+5)/10),sal_uInt16((nCircStWink
+nCircRelWink
+5)/10),sal_False
);
348 aXP
[0]=aCircStart
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
349 if (!bAngleSnap
) aXP
[aXP
.GetPointCount()-1]=aCircEnd
;
352 XPolygon
aXP(aCircCenter
,nCircRadius
,nCircRadius
,
353 sal_uInt16(NormAngle360(nCircStWink
+nCircRelWink
+5)/10),sal_uInt16((nCircStWink
+5)/10),sal_False
);
354 sal_uInt16 nAnz
=aXP
.GetPointCount();
355 for (sal_uInt16 nNum
=nAnz
/2; nNum
>0;) {
356 nNum
--; // reverse XPoly's order of points
357 sal_uInt16 n2
=nAnz
-nNum
-1;
358 Point
aPt(aXP
[nNum
]);
362 aXP
[0]=aCircStart
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
363 if (!bAngleSnap
) aXP
[aXP
.GetPointCount()-1]=aCircEnd
;
368 Point
ImpPathCreateUser::CalcLine(const Point
& aCsr
, long nDirX
, long nDirY
, SdrView
* pView
) const
370 long x
=aCsr
.X(),x1
=x
,x2
=x
;
371 long y
=aCsr
.Y(),y1
=y
,y2
=y
;
377 x1
=BigMulDiv(y
,nDirX
,nDirY
);
378 y2
=BigMulDiv(x
,nDirY
,nDirX
);
379 long l1
=std::abs(x1
)+std::abs(y1
);
380 long l2
=std::abs(x2
)+std::abs(y2
);
381 if ((l1
<=l2
) != (pView
!=NULL
&& pView
->IsBigOrtho())) {
390 bool ImpPathCreateUser::CalcLine(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
)
395 if (rP1
==rP2
|| (rDir
.X()==0 && rDir
.Y()==0)) { bLine
=sal_False
; return sal_False
; }
396 Point
aTmpPt(rP2
-rP1
);
399 Point
aP1(CalcLine(aTmpPt
, nDirX
, nDirY
,pView
)); aP1
-=aTmpPt
; long nQ1
=std::abs(aP1
.X())+std::abs(aP1
.Y());
400 Point
aP2(CalcLine(aTmpPt
, nDirY
,-nDirX
,pView
)); aP2
-=aTmpPt
; long nQ2
=std::abs(aP2
.X())+std::abs(aP2
.Y());
401 if (pView
!=NULL
&& pView
->IsOrtho()) nQ1
=0; // Ortho turns off at right angle
403 if (!bLine90
) { // smooth transition
405 } else { // rectangular transition
412 XPolygon
ImpPathCreateUser::GetLinePoly() const
415 aXP
[0]=aLineStart
; if (!bLine90
) aXP
.SetFlags(0,XPOLY_SMOOTH
);
420 bool ImpPathCreateUser::CalcRect(const Point
& rP1
, const Point
& rP2
, const Point
& rDir
, SdrView
* pView
)
425 if (rP1
==rP2
|| (rDir
.X()==0 && rDir
.Y()==0)) { bRect
=sal_False
; return sal_False
; }
426 Point
aTmpPt(rP2
-rP1
);
436 y
=BigMulDiv(x
,nDirY
,nDirX
);
437 long nHypLen
=aTmpPt
.Y()-y
;
438 long nTangAngle
=-GetAngle(rDir
);
440 double a
=nTangAngle
*nPi180
;
443 double nGKathLen
=nHypLen
*sn
;
444 y
+=Round(nGKathLen
*sn
);
445 x
+=Round(nGKathLen
*cs
);
449 if (pView
!=NULL
&& pView
->IsOrtho()) {
450 long dx1
=aRectP2
.X()-aRectP1
.X(); long dx1a
=std::abs(dx1
);
451 long dy1
=aRectP2
.Y()-aRectP1
.Y(); long dy1a
=std::abs(dy1
);
452 long dx2
=aRectP3
.X()-aRectP2
.X(); long dx2a
=std::abs(dx2
);
453 long dy2
=aRectP3
.Y()-aRectP2
.Y(); long dy2a
=std::abs(dy2
);
454 bool b1MoreThan2
=dx1a
+dy1a
>dx2a
+dy2a
;
455 if (b1MoreThan2
!= pView
->IsBigOrtho()) {
456 long xtemp
=dy2a
-dx1a
; if (dx1
<0) xtemp
=-xtemp
;
457 long ytemp
=dx2a
-dy1a
; if (dy1
<0) ytemp
=-ytemp
;
463 long xtemp
=dy1a
-dx2a
; if (dx2
<0) xtemp
=-xtemp
;
464 long ytemp
=dx1a
-dy2a
; if (dy2
<0) ytemp
=-ytemp
;
473 XPolygon
ImpPathCreateUser::GetRectPoly() const
476 aXP
[0]=aRectP1
; aXP
.SetFlags(0,XPOLY_SMOOTH
);
478 if (aRectP3
!=aRectP2
) aXP
[2]=aRectP3
;
482 /*************************************************************************/
484 class ImpPathForDragAndCreate
486 SdrPathObj
& mrSdrPathObject
;
487 XPolyPolygon aPathPolygon
;
488 SdrObjKind meObjectKind
;
489 ImpSdrPathDragData
* mpSdrPathDragData
;
493 ImpPathForDragAndCreate(SdrPathObj
& rSdrPathObject
);
494 ~ImpPathForDragAndCreate();
497 bool beginPathDrag( SdrDragStat
& rDrag
) const;
498 bool movePathDrag( SdrDragStat
& rDrag
) const;
499 bool endPathDrag( SdrDragStat
& rDrag
);
500 String
getSpecialDragComment(const SdrDragStat
& rDrag
) const;
501 basegfx::B2DPolyPolygon
getSpecialDragPoly(const SdrDragStat
& rDrag
) const;
504 bool BegCreate(SdrDragStat
& rStat
);
505 bool MovCreate(SdrDragStat
& rStat
);
506 bool EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
);
507 bool BckCreate(SdrDragStat
& rStat
);
508 void BrkCreate(SdrDragStat
& rStat
);
509 Pointer
GetCreatePointer() const;
512 bool IsClosed(SdrObjKind eKind
) const { return eKind
==OBJ_POLY
|| eKind
==OBJ_PATHPOLY
|| eKind
==OBJ_PATHFILL
|| eKind
==OBJ_FREEFILL
|| eKind
==OBJ_SPLNFILL
; }
513 bool IsFreeHand(SdrObjKind eKind
) const { return eKind
==OBJ_FREELINE
|| eKind
==OBJ_FREEFILL
; }
514 bool IsBezier(SdrObjKind eKind
) const { return eKind
==OBJ_PATHLINE
|| eKind
==OBJ_PATHFILL
; }
515 bool IsCreating() const { return mbCreating
; }
518 basegfx::B2DPolyPolygon
TakeObjectPolyPolygon(const SdrDragStat
& rDrag
) const;
519 basegfx::B2DPolyPolygon
TakeDragPolyPolygon(const SdrDragStat
& rDrag
) const;
520 basegfx::B2DPolyPolygon
getModifiedPolyPolygon() const { return aPathPolygon
.getB2DPolyPolygon(); }
523 ImpPathForDragAndCreate::ImpPathForDragAndCreate(SdrPathObj
& rSdrPathObject
)
524 : mrSdrPathObject(rSdrPathObject
),
525 aPathPolygon(rSdrPathObject
.GetPathPoly()),
526 meObjectKind(mrSdrPathObject
.meKind
),
527 mpSdrPathDragData(0),
532 ImpPathForDragAndCreate::~ImpPathForDragAndCreate()
534 if(mpSdrPathDragData
)
536 delete mpSdrPathDragData
;
540 bool ImpPathForDragAndCreate::beginPathDrag( SdrDragStat
& rDrag
) const
542 const SdrHdl
* pHdl
=rDrag
.GetHdl();
546 bool bMultiPointDrag(true);
548 if(aPathPolygon
[(sal_uInt16
)pHdl
->GetPolyNum()].IsControl((sal_uInt16
)pHdl
->GetPointNum()))
549 bMultiPointDrag
= false;
553 const SdrMarkView
& rMarkView
= *rDrag
.GetView();
554 const SdrHdlList
& rHdlList
= rMarkView
.GetHdlList();
555 const sal_uInt32 nHdlCount
= rHdlList
.GetHdlCount();
556 const SdrObject
* pInteractionObject(nHdlCount
&& rHdlList
.GetHdl(0) ? rHdlList
.GetHdl(0)->GetObj() : 0);
557 sal_uInt32
nSelectedPoints(0);
559 for(sal_uInt32
a(0); a
< nHdlCount
; a
++)
561 SdrHdl
* pTestHdl
= rHdlList
.GetHdl(a
);
563 if(pTestHdl
&& pTestHdl
->IsSelected() && pTestHdl
->GetObj() == pInteractionObject
)
569 if(nSelectedPoints
<= 1)
570 bMultiPointDrag
= false;
573 ((ImpPathForDragAndCreate
*)this)->mpSdrPathDragData
= new ImpSdrPathDragData(mrSdrPathObject
,*pHdl
,bMultiPointDrag
,rDrag
);
575 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
577 OSL_FAIL("ImpPathForDragAndCreate::BegDrag(): ImpSdrPathDragData is invalid.");
578 delete mpSdrPathDragData
;
579 ((ImpPathForDragAndCreate
*)this)->mpSdrPathDragData
= 0;
586 bool ImpPathForDragAndCreate::movePathDrag( SdrDragStat
& rDrag
) const
588 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
590 OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
594 if(mpSdrPathDragData
->IsMultiPointDrag())
596 Point
aDelta(rDrag
.GetNow() - rDrag
.GetStart());
598 if(aDelta
.X() || aDelta
.Y())
600 for(sal_uInt32
a(0); a
< mpSdrPathDragData
->maHandles
.size(); a
++)
602 SdrHdl
* pHandle
= mpSdrPathDragData
->maHandles
[a
];
603 const sal_uInt16
nPolyIndex((sal_uInt16
)pHandle
->GetPolyNum());
604 const sal_uInt16
nPointIndex((sal_uInt16
)pHandle
->GetPointNum());
605 const XPolygon
& rOrig
= mpSdrPathDragData
->maOrig
[nPolyIndex
];
606 XPolygon
& rMove
= mpSdrPathDragData
->maMove
[nPolyIndex
];
607 const sal_uInt16
nPointCount(rOrig
.GetPointCount());
608 bool bClosed(rOrig
[0] == rOrig
[nPointCount
-1]);
611 rMove
[nPointIndex
] = rOrig
[nPointIndex
] + aDelta
;
613 // when point is first and poly closed, move close point, too.
614 if(nPointCount
> 0 && !nPointIndex
&& bClosed
)
616 rMove
[nPointCount
- 1] = rOrig
[nPointCount
- 1] + aDelta
;
618 // when moving the last point it may be necessary to move the
619 // control point in front of this one, too.
620 if(nPointCount
> 1 && rOrig
.IsControl(nPointCount
- 2))
621 rMove
[nPointCount
- 2] = rOrig
[nPointCount
- 2] + aDelta
;
624 // is a control point before this?
625 if(nPointIndex
> 0 && rOrig
.IsControl(nPointIndex
- 1))
628 rMove
[nPointIndex
- 1] = rOrig
[nPointIndex
- 1] + aDelta
;
631 // is a control point after this?
632 if(nPointIndex
+ 1 < nPointCount
&& rOrig
.IsControl(nPointIndex
+ 1))
635 rMove
[nPointIndex
+ 1] = rOrig
[nPointIndex
+ 1] + aDelta
;
642 mpSdrPathDragData
->ResetPoly(mrSdrPathObject
);
644 // copy certain data locally to use less code and have faster access times
645 bool bClosed
=mpSdrPathDragData
->bClosed
; // closed object?
646 sal_uInt16 nPnt
=mpSdrPathDragData
->nPnt
; // number of point in the above polygon
647 bool bBegPnt
=mpSdrPathDragData
->bBegPnt
; // dragged point is first point of a Polyline
648 bool bEndPnt
=mpSdrPathDragData
->bEndPnt
; // dragged point is last point of a Polyline
649 sal_uInt16 nPrevPnt
=mpSdrPathDragData
->nPrevPnt
; // index of previous point
650 sal_uInt16 nNextPnt
=mpSdrPathDragData
->nNextPnt
; // index of next point
651 bool bPrevIsBegPnt
=mpSdrPathDragData
->bPrevIsBegPnt
; // previous point is first point of a Polyline
652 bool bNextIsEndPnt
=mpSdrPathDragData
->bNextIsEndPnt
; // next point is last point of a Polyline
653 sal_uInt16 nPrevPrevPnt
=mpSdrPathDragData
->nPrevPrevPnt
; // index of the point before the previous point
654 sal_uInt16 nNextNextPnt
=mpSdrPathDragData
->nNextNextPnt
; // index if the point after the next point
655 bool bControl
=mpSdrPathDragData
->bControl
; // point is a control point
656 bool bIsNextControl
=mpSdrPathDragData
->bIsNextControl
; // point is a control point after a support point
657 bool bPrevIsControl
=mpSdrPathDragData
->bPrevIsControl
; // if nPnt is a support point: there's a control point before
658 bool bNextIsControl
=mpSdrPathDragData
->bNextIsControl
; // if nPnt is a support point: there's a control point after
660 // Ortho for lines/polygons: keep angle
661 if (!bControl
&& rDrag
.GetView()!=NULL
&& rDrag
.GetView()->IsOrtho()) {
662 bool bBigOrtho
=rDrag
.GetView()->IsBigOrtho();
663 Point
aPos(rDrag
.GetNow()); // current position
664 Point
aPnt(mpSdrPathDragData
->aXP
[nPnt
]); // the dragged point
665 sal_uInt16 nPnt1
=0xFFFF,nPnt2
=0xFFFF; // its neighboring points
666 Point aNeuPos1
,aNeuPos2
; // new alternative for aPos
667 bool bPnt1
= false, bPnt2
= false; // are these valid alternatives?
668 if (!bClosed
&& mpSdrPathDragData
->nPntAnz
>=2) { // minimum of 2 points for lines
669 if (!bBegPnt
) nPnt1
=nPrevPnt
;
670 if (!bEndPnt
) nPnt2
=nNextPnt
;
672 if (bClosed
&& mpSdrPathDragData
->nPntAnz
>=3) { // minimum of 3 points for polygon
676 if (nPnt1
!=0xFFFF && !bPrevIsControl
) {
677 Point aPnt1
=mpSdrPathDragData
->aXP
[nPnt1
];
678 long ndx0
=aPnt
.X()-aPnt1
.X();
679 long ndy0
=aPnt
.Y()-aPnt1
.Y();
682 if (!bHLin
|| !bVLin
) {
683 long ndx
=aPos
.X()-aPnt1
.X();
684 long ndy
=aPos
.Y()-aPnt1
.Y();
686 double nXFact
=0; if (!bVLin
) nXFact
=(double)ndx
/(double)ndx0
;
687 double nYFact
=0; if (!bHLin
) nYFact
=(double)ndy
/(double)ndy0
;
688 bool bHor
=bHLin
|| (!bVLin
&& (nXFact
>nYFact
) ==bBigOrtho
);
689 bool bVer
=bVLin
|| (!bHLin
&& (nXFact
<=nYFact
)==bBigOrtho
);
690 if (bHor
) ndy
=long(ndy0
*nXFact
);
691 if (bVer
) ndx
=long(ndx0
*nYFact
);
697 if (nPnt2
!=0xFFFF && !bNextIsControl
) {
698 Point aPnt2
=mpSdrPathDragData
->aXP
[nPnt2
];
699 long ndx0
=aPnt
.X()-aPnt2
.X();
700 long ndy0
=aPnt
.Y()-aPnt2
.Y();
703 if (!bHLin
|| !bVLin
) {
704 long ndx
=aPos
.X()-aPnt2
.X();
705 long ndy
=aPos
.Y()-aPnt2
.Y();
707 double nXFact
=0; if (!bVLin
) nXFact
=(double)ndx
/(double)ndx0
;
708 double nYFact
=0; if (!bHLin
) nYFact
=(double)ndy
/(double)ndy0
;
709 bool bHor
=bHLin
|| (!bVLin
&& (nXFact
>nYFact
) ==bBigOrtho
);
710 bool bVer
=bVLin
|| (!bHLin
&& (nXFact
<=nYFact
)==bBigOrtho
);
711 if (bHor
) ndy
=long(ndy0
*nXFact
);
712 if (bVer
) ndx
=long(ndx0
*nYFact
);
718 if (bPnt1
&& bPnt2
) { // both alternatives exist (and compete)
719 BigInt
nX1(aNeuPos1
.X()-aPos
.X()); nX1
*=nX1
;
720 BigInt
nY1(aNeuPos1
.Y()-aPos
.Y()); nY1
*=nY1
;
721 BigInt
nX2(aNeuPos2
.X()-aPos
.X()); nX2
*=nX2
;
722 BigInt
nY2(aNeuPos2
.Y()-aPos
.Y()); nY2
*=nY2
;
723 nX1
+=nY1
; // correction distance to square
724 nX2
+=nY2
; // correction distance to square
725 // let the alternative that allows fewer correction win
726 if (nX1
<nX2
) bPnt2
=sal_False
; else bPnt1
=sal_False
;
728 if (bPnt1
) rDrag
.Now()=aNeuPos1
;
729 if (bPnt2
) rDrag
.Now()=aNeuPos2
;
731 rDrag
.SetActionRect(Rectangle(rDrag
.GetNow(),rDrag
.GetNow()));
733 // specially for IBM: Eliminate points if both adjoining lines form near 180 degrees angle anyway
734 if (!bControl
&& rDrag
.GetView()!=NULL
&& rDrag
.GetView()->IsEliminatePolyPoints() &&
735 !bBegPnt
&& !bEndPnt
&& !bPrevIsControl
&& !bNextIsControl
)
737 Point
aPt(mpSdrPathDragData
->aXP
[nNextPnt
]);
739 long nWink1
=GetAngle(aPt
);
741 aPt
-=mpSdrPathDragData
->aXP
[nPrevPnt
];
742 long nWink2
=GetAngle(aPt
);
743 long nDiff
=nWink1
-nWink2
;
744 nDiff
=std::abs(nDiff
);
745 mpSdrPathDragData
->bEliminate
=nDiff
<=rDrag
.GetView()->GetEliminatePolyPointLimitAngle();
746 if (mpSdrPathDragData
->bEliminate
) { // adapt position, Smooth is true for the ends
747 aPt
=mpSdrPathDragData
->aXP
[nNextPnt
];
748 aPt
+=mpSdrPathDragData
->aXP
[nPrevPnt
];
754 // we dragged by this distance
755 Point
aDiff(rDrag
.GetNow()); aDiff
-=mpSdrPathDragData
->aXP
[nPnt
];
757 /* There are 8 possible cases:
758 X 1. A control point neither on the left nor on the right.
759 o--X--o 2. There are control points on the left and the right, we are dragging a support point.
760 o--X 3. There is a control point on the left, we are dragging a support point.
761 X--o 4. There is a control point on the right, we are dragging a support point.
762 x--O--o 5. There are control points on the left and the right, we are dragging the left one.
763 x--O 6. There is a control point on the left, we are dragging it.
764 o--O--x 7. There are control points on the left and the right, we are dragging the right one.
765 O--x 8. There is a control point on the right, we are dragging it.
766 Note: modifying a line (not a curve!) might create a curve on the other end of the line
767 if Smooth is set there (with control points aligned to line).
770 mpSdrPathDragData
->aXP
[nPnt
]+=aDiff
;
772 // now check symmetric plus handles
773 if (bControl
) { // cases 5,6,7,8
774 sal_uInt16 nSt
=nPnt
; // the associated support point
775 sal_uInt16 nFix
=nPnt
; // the opposing control point
776 if (bIsNextControl
) { // if the next one is a control point, the on before has to be a support point
783 if (mpSdrPathDragData
->aXP
.IsSmooth(nSt
)) {
784 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nSt
,nPnt
,nFix
);
788 if (!bControl
) { // Cases 1,2,3,4. In case 1, nothing happens; in cases 3 and 4, there is more following below.
789 // move both control points
790 if (bPrevIsControl
) mpSdrPathDragData
->aXP
[nPrevPnt
]+=aDiff
;
791 if (bNextIsControl
) mpSdrPathDragData
->aXP
[nNextPnt
]+=aDiff
;
792 // align control point to line, if appropriate
793 if (mpSdrPathDragData
->aXP
.IsSmooth(nPnt
)) {
794 if (bPrevIsControl
&& !bNextIsControl
&& !bEndPnt
) { // case 3
795 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nPnt
,nNextPnt
,nPrevPnt
);
797 if (bNextIsControl
&& !bPrevIsControl
&& !bBegPnt
) { // case 4
798 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nPnt
,nPrevPnt
,nNextPnt
);
801 // Now check the other ends of the line (nPnt+-1). If there is a
802 // curve (IsControl(nPnt+-2)) with SmoothJoin (nPnt+-1), the
803 // associated control point (nPnt+-2) has to be adapted.
804 if (!bBegPnt
&& !bPrevIsControl
&& !bPrevIsBegPnt
&& mpSdrPathDragData
->aXP
.IsSmooth(nPrevPnt
)) {
805 if (mpSdrPathDragData
->aXP
.IsControl(nPrevPrevPnt
)) {
806 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nPrevPnt
,nPnt
,nPrevPrevPnt
);
809 if (!bEndPnt
&& !bNextIsControl
&& !bNextIsEndPnt
&& mpSdrPathDragData
->aXP
.IsSmooth(nNextPnt
)) {
810 if (mpSdrPathDragData
->aXP
.IsControl(nNextNextPnt
)) {
811 mpSdrPathDragData
->aXP
.CalcSmoothJoin(nNextPnt
,nPnt
,nNextNextPnt
);
820 bool ImpPathForDragAndCreate::endPathDrag(SdrDragStat
& rDrag
)
824 bool bLineGlueMirror(OBJ_LINE
== meObjectKind
);
825 if (bLineGlueMirror
) {
826 XPolygon
& rXP
=aPathPolygon
[0];
831 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
833 OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
837 if(mpSdrPathDragData
->IsMultiPointDrag())
839 aPathPolygon
= mpSdrPathDragData
->maMove
;
843 const SdrHdl
* pHdl
=rDrag
.GetHdl();
845 // reference the polygon
846 XPolygon
& rXP
=aPathPolygon
[(sal_uInt16
)pHdl
->GetPolyNum()];
848 // the 5 points that might have changed
849 if (!mpSdrPathDragData
->bPrevIsBegPnt
) rXP
[mpSdrPathDragData
->nPrevPrevPnt0
]=mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nPrevPrevPnt
];
850 if (!mpSdrPathDragData
->bNextIsEndPnt
) rXP
[mpSdrPathDragData
->nNextNextPnt0
]=mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nNextNextPnt
];
851 if (!mpSdrPathDragData
->bBegPnt
) rXP
[mpSdrPathDragData
->nPrevPnt0
] =mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nPrevPnt
];
852 if (!mpSdrPathDragData
->bEndPnt
) rXP
[mpSdrPathDragData
->nNextPnt0
] =mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nNextPnt
];
853 rXP
[mpSdrPathDragData
->nPnt0
] =mpSdrPathDragData
->aXP
[mpSdrPathDragData
->nPnt
];
855 // for closed objects: last point has to be equal to first point
856 if (mpSdrPathDragData
->bClosed
) rXP
[rXP
.GetPointCount()-1]=rXP
[0];
858 if (mpSdrPathDragData
->bEliminate
)
860 basegfx::B2DPolyPolygon
aTempPolyPolygon(aPathPolygon
.getB2DPolyPolygon());
861 sal_uInt32 nPoly
,nPnt
;
863 if(PolyPolygonEditor::GetRelativePolyPoint(aTempPolyPolygon
, rDrag
.GetHdl()->GetSourceHdlNum(), nPoly
, nPnt
))
865 basegfx::B2DPolygon
aCandidate(aTempPolyPolygon
.getB2DPolygon(nPoly
));
866 aCandidate
.remove(nPnt
);
868 if((IsClosed(meObjectKind
) && aCandidate
.count() < 3L) || aCandidate
.count() < 2L)
870 aTempPolyPolygon
.remove(nPoly
);
874 aTempPolyPolygon
.setB2DPolygon(nPoly
, aCandidate
);
878 aPathPolygon
= XPolyPolygon(aTempPolyPolygon
);
881 // adapt angle for text beneath a simple line
884 Point
aLinePt1_(aPathPolygon
[0][0]);
885 Point
aLinePt2_(aPathPolygon
[0][1]);
886 bool bXMirr
=(aLinePt1_
.X()>aLinePt2_
.X())!=(aLinePt1
.X()>aLinePt2
.X());
887 bool bYMirr
=(aLinePt1_
.Y()>aLinePt2_
.Y())!=(aLinePt1
.Y()>aLinePt2
.Y());
888 if (bXMirr
|| bYMirr
) {
889 Point
aRef1(mrSdrPathObject
.GetSnapRect().Center());
893 mrSdrPathObject
.NbcMirrorGluePoints(aRef1
,aRef2
);
898 mrSdrPathObject
.NbcMirrorGluePoints(aRef1
,aRef2
);
904 delete mpSdrPathDragData
;
905 mpSdrPathDragData
= 0;
911 String
ImpPathForDragAndCreate::getSpecialDragComment(const SdrDragStat
& rDrag
) const
914 const SdrHdl
* pHdl
= rDrag
.GetHdl();
915 const bool bCreateComment(rDrag
.GetView() && &mrSdrPathObject
== rDrag
.GetView()->GetCreateObj());
917 if(bCreateComment
&& rDrag
.GetUser())
919 // #i103058# re-add old creation comment mode
920 ImpPathCreateUser
* pU
= (ImpPathCreateUser
*)rDrag
.GetUser();
921 const SdrObjKind
eKindMerk(meObjectKind
);
922 mrSdrPathObject
.meKind
= pU
->eAktKind
;
924 mrSdrPathObject
.ImpTakeDescriptionStr(STR_ViewCreateObj
, aTmp
);
926 mrSdrPathObject
.meKind
= eKindMerk
;
928 Point
aPrev(rDrag
.GetPrev());
929 Point
aNow(rDrag
.GetNow());
935 aStr
.AppendAscii(" (");
941 mrSdrPathObject
.GetModel()->TakeWinkStr(std::abs(pU
->nCircRelWink
), aMetr
);
943 aStr
.AppendAscii(" r=");
944 mrSdrPathObject
.GetModel()->TakeMetricStr(pU
->nCircRadius
, aMetr
, sal_True
);
948 aStr
.AppendAscii("dx=");
949 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.X(), aMetr
, sal_True
);
952 aStr
.AppendAscii(" dy=");
953 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.Y(), aMetr
, sal_True
);
956 if(!IsFreeHand(meObjectKind
))
958 sal_Int32
nLen(GetLen(aNow
));
959 aStr
.AppendAscii(" l=");
960 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, sal_True
);
963 sal_Int32
nWink(GetAngle(aNow
));
964 aStr
+= sal_Unicode(' ');
965 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
969 aStr
+= sal_Unicode(')');
971 else if(!mrSdrPathObject
.GetModel() || !pHdl
)
973 // #i103058# fallback when no model and/or Handle, both needed
976 mrSdrPathObject
.ImpTakeDescriptionStr(STR_DragPathObj
, aTmp
);
981 // #i103058# standard for modification; model and handle needed
982 ImpSdrPathDragData
* pDragData
= mpSdrPathDragData
;
986 // getSpecialDragComment is also used from create, so fallback to GetUser()
987 // when mpSdrPathDragData is not set
988 pDragData
= (ImpSdrPathDragData
*)rDrag
.GetUser();
993 OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
997 if(!pDragData
->IsMultiPointDrag() && pDragData
->bEliminate
)
1001 mrSdrPathObject
.ImpTakeDescriptionStr(STR_ViewMarkedPoint
, aTmp
);
1005 XubString
aStr2(ImpGetResStr(STR_EditDelete
));
1007 // UNICODE: delete point of ...
1008 aStr2
.SearchAndReplaceAscii("%1", aStr
);
1013 // dx=0.00 dy=0.00 -- both sides bezier
1014 // dx=0.00 dy=0.00 l=0.00 0.00° -- one bezier/lever on one side, a start, or an ending
1015 // dx=0.00 dy=0.00 l=0.00 0.00° / l=0.00 0.00° -- in between
1017 Point
aBeg(rDrag
.GetStart());
1018 Point
aNow(rDrag
.GetNow());
1021 aStr
.AppendAscii("dx=");
1022 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.X() - aBeg
.X(), aMetr
, sal_True
);
1025 aStr
.AppendAscii(" dy=");
1026 mrSdrPathObject
.GetModel()->TakeMetricStr(aNow
.Y() - aBeg
.Y(), aMetr
, sal_True
);
1029 if(!pDragData
->IsMultiPointDrag())
1031 sal_uInt16
nPntNum((sal_uInt16
)pHdl
->GetPointNum());
1032 const XPolygon
& rXPoly
= aPathPolygon
[(sal_uInt16
)rDrag
.GetHdl()->GetPolyNum()];
1033 sal_uInt16
nPntAnz((sal_uInt16
)rXPoly
.GetPointCount());
1034 sal_Bool
bClose(IsClosed(meObjectKind
));
1039 if(pHdl
->IsPlusHdl())
1042 sal_uInt16
nRef(nPntNum
);
1044 if(rXPoly
.IsControl(nPntNum
+ 1))
1049 aNow
-= rXPoly
[nRef
];
1051 sal_Int32
nLen(GetLen(aNow
));
1052 aStr
.AppendAscii(" l=");
1053 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, sal_True
);
1056 sal_Int32
nWink(GetAngle(aNow
));
1057 aStr
+= sal_Unicode(' ');
1058 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
1061 else if(nPntAnz
> 1)
1063 sal_uInt16
nPntMax(nPntAnz
- 1);
1064 sal_Bool
bIsClosed(IsClosed(meObjectKind
));
1065 bool bPt1(nPntNum
> 0);
1066 bool bPt2(nPntNum
< nPntMax
);
1068 if(bIsClosed
&& nPntAnz
> 2)
1074 sal_uInt16 nPt1
,nPt2
;
1081 if(nPntNum
< nPntMax
)
1086 if(bPt1
&& rXPoly
.IsControl(nPt1
))
1087 bPt1
= false; // don't display
1089 if(bPt2
&& rXPoly
.IsControl(nPt2
))
1090 bPt2
= false; // of bezier data
1095 aPt
-= rXPoly
[nPt1
];
1097 sal_Int32
nLen(GetLen(aPt
));
1098 aStr
.AppendAscii(" l=");
1099 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, sal_True
);
1102 sal_Int32
nWink(GetAngle(aPt
));
1103 aStr
+= sal_Unicode(' ');
1104 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
1111 aStr
.AppendAscii(" / ");
1113 aStr
.AppendAscii(" ");
1116 aPt
-= rXPoly
[nPt2
];
1118 sal_Int32
nLen(GetLen(aPt
));
1119 aStr
.AppendAscii("l=");
1120 mrSdrPathObject
.GetModel()->TakeMetricStr(nLen
, aMetr
, sal_True
);
1123 sal_Int32
nWink(GetAngle(aPt
));
1124 aStr
+= sal_Unicode(' ');
1125 mrSdrPathObject
.GetModel()->TakeWinkStr(nWink
, aMetr
);
1135 basegfx::B2DPolyPolygon
ImpPathForDragAndCreate::getSpecialDragPoly(const SdrDragStat
& rDrag
) const
1137 if(!mpSdrPathDragData
|| !mpSdrPathDragData
->bValid
)
1139 OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
1140 return basegfx::B2DPolyPolygon();
1143 XPolyPolygon aRetval
;
1145 if(mpSdrPathDragData
->IsMultiPointDrag())
1147 aRetval
.Insert(mpSdrPathDragData
->maMove
);
1151 const XPolygon
& rXP
=aPathPolygon
[(sal_uInt16
)rDrag
.GetHdl()->GetPolyNum()];
1152 if (rXP
.GetPointCount()<=2) {
1153 XPolygon
aXPoly(rXP
);
1154 aXPoly
[(sal_uInt16
)rDrag
.GetHdl()->GetPointNum()]=rDrag
.GetNow();
1155 aRetval
.Insert(aXPoly
);
1156 return aRetval
.getB2DPolyPolygon();
1158 // copy certain data locally to use less code and have faster access times
1159 bool bClosed
=mpSdrPathDragData
->bClosed
; // closed object?
1160 sal_uInt16 nPntAnz
=mpSdrPathDragData
->nPntAnz
; // number of points
1161 sal_uInt16 nPnt
=mpSdrPathDragData
->nPnt
; // number of points in the polygon
1162 bool bBegPnt
=mpSdrPathDragData
->bBegPnt
; // dragged point is the first point of a Polyline
1163 bool bEndPnt
=mpSdrPathDragData
->bEndPnt
; // dragged point is the last point of a Polyline
1164 sal_uInt16 nPrevPnt
=mpSdrPathDragData
->nPrevPnt
; // index of the previous point
1165 sal_uInt16 nNextPnt
=mpSdrPathDragData
->nNextPnt
; // index of the next point
1166 bool bPrevIsBegPnt
=mpSdrPathDragData
->bPrevIsBegPnt
; // previous point is first point of a Polyline
1167 bool bNextIsEndPnt
=mpSdrPathDragData
->bNextIsEndPnt
; // next point is last point of a Polyline
1168 sal_uInt16 nPrevPrevPnt
=mpSdrPathDragData
->nPrevPrevPnt
; // index of the point before the previous point
1169 sal_uInt16 nNextNextPnt
=mpSdrPathDragData
->nNextNextPnt
; // index of the point after the last point
1170 bool bControl
=mpSdrPathDragData
->bControl
; // point is a control point
1171 bool bIsNextControl
=mpSdrPathDragData
->bIsNextControl
; //point is a control point after a support point
1172 bool bPrevIsControl
=mpSdrPathDragData
->bPrevIsControl
; // if nPnt is a support point: there's a control point before
1173 bool bNextIsControl
=mpSdrPathDragData
->bNextIsControl
; // if nPnt is a support point: there's a control point after
1174 XPolygon
aXPoly(mpSdrPathDragData
->aXP
);
1180 aLine1
[1]=mpSdrPathDragData
->aXP
[nPnt
];
1181 if (bIsNextControl
) { // is this a control point after the support point?
1182 aLine1
[0]=mpSdrPathDragData
->aXP
[nPrevPnt
];
1183 aLine2
[0]=mpSdrPathDragData
->aXP
[nNextNextPnt
];
1184 aLine2
[1]=mpSdrPathDragData
->aXP
[nNextPnt
];
1185 if (mpSdrPathDragData
->aXP
.IsSmooth(nPrevPnt
) && !bPrevIsBegPnt
&& mpSdrPathDragData
->aXP
.IsControl(nPrevPrevPnt
)) {
1186 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1],XPOLY_CONTROL
);
1187 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-2],XPOLY_NORMAL
);
1188 // leverage lines for the opposing curve segment
1189 aLine3
[0]=mpSdrPathDragData
->aXP
[nPrevPnt
];
1190 aLine3
[1]=mpSdrPathDragData
->aXP
[nPrevPrevPnt
];
1191 aLine4
[0]=rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-2];
1192 aLine4
[1]=rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1];
1196 } else { // else this is a control point before a support point
1197 aLine1
[0]=mpSdrPathDragData
->aXP
[nNextPnt
];
1198 aLine2
[0]=mpSdrPathDragData
->aXP
[nPrevPrevPnt
];
1199 aLine2
[1]=mpSdrPathDragData
->aXP
[nPrevPnt
];
1200 if (mpSdrPathDragData
->aXP
.IsSmooth(nNextPnt
) && !bNextIsEndPnt
&& mpSdrPathDragData
->aXP
.IsControl(nNextNextPnt
)) {
1201 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+1],XPOLY_CONTROL
);
1202 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+2],XPOLY_NORMAL
);
1203 // leverage lines for the opposing curve segment
1204 aLine3
[0]=mpSdrPathDragData
->aXP
[nNextPnt
];
1205 aLine3
[1]=mpSdrPathDragData
->aXP
[nNextNextPnt
];
1206 aLine4
[0]=rXP
[mpSdrPathDragData
->nNextNextPnt0
+2];
1207 aLine4
[1]=rXP
[mpSdrPathDragData
->nNextNextPnt0
+1];
1209 aXPoly
.Remove(aXPoly
.GetPointCount()-1,1);
1212 } else { // else is not a control point
1213 if (mpSdrPathDragData
->bEliminate
) {
1216 if (bPrevIsControl
) aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1],XPOLY_NORMAL
);
1217 else if (!bBegPnt
&& !bPrevIsBegPnt
&& mpSdrPathDragData
->aXP
.IsControl(nPrevPrevPnt
)) {
1218 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-1],XPOLY_CONTROL
);
1219 aXPoly
.Insert(0,rXP
[mpSdrPathDragData
->nPrevPrevPnt0
-2],XPOLY_NORMAL
);
1222 if (bBegPnt
) aXPoly
.Remove(0,1);
1224 if (bNextIsControl
) aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+1],XPOLY_NORMAL
);
1225 else if (!bEndPnt
&& !bNextIsEndPnt
&& mpSdrPathDragData
->aXP
.IsControl(nNextNextPnt
)) {
1226 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+1],XPOLY_CONTROL
);
1227 aXPoly
.Insert(XPOLY_APPEND
,rXP
[mpSdrPathDragData
->nNextNextPnt0
+2],XPOLY_NORMAL
);
1229 aXPoly
.Remove(aXPoly
.GetPointCount()-1,1);
1230 if (bEndPnt
) aXPoly
.Remove(aXPoly
.GetPointCount()-1,1);
1232 if (bClosed
) { // "pear problem": 2 lines, 1 curve, everything smoothed, a point between both lines is dragged
1233 if (aXPoly
.GetPointCount()>nPntAnz
&& aXPoly
.IsControl(1)) {
1234 sal_uInt16 a
=aXPoly
.GetPointCount();
1235 aXPoly
[a
-2]=aXPoly
[2]; aXPoly
.SetFlags(a
-2,aXPoly
.GetFlags(2));
1236 aXPoly
[a
-1]=aXPoly
[3]; aXPoly
.SetFlags(a
-1,aXPoly
.GetFlags(3));
1241 aRetval
.Insert(aXPoly
);
1242 if (aLine1
.GetPointCount()>1) aRetval
.Insert(aLine1
);
1243 if (aLine2
.GetPointCount()>1) aRetval
.Insert(aLine2
);
1244 if (aLine3
.GetPointCount()>1) aRetval
.Insert(aLine3
);
1245 if (aLine4
.GetPointCount()>1) aRetval
.Insert(aLine4
);
1248 return aRetval
.getB2DPolyPolygon();
1251 bool ImpPathForDragAndCreate::BegCreate(SdrDragStat
& rStat
)
1253 bool bFreeHand(IsFreeHand(meObjectKind
));
1254 rStat
.SetNoSnap(bFreeHand
);
1255 rStat
.SetOrtho8Possible();
1256 aPathPolygon
.Clear();
1257 mbCreating
=sal_True
;
1258 bool bMakeStartPoint
= true;
1259 SdrView
* pView
=rStat
.GetView();
1260 if (pView
!=NULL
&& pView
->IsUseIncompatiblePathCreateInterface() &&
1261 (meObjectKind
==OBJ_POLY
|| meObjectKind
==OBJ_PLIN
|| meObjectKind
==OBJ_PATHLINE
|| meObjectKind
==OBJ_PATHFILL
)) {
1262 bMakeStartPoint
= false;
1264 aPathPolygon
.Insert(XPolygon());
1265 aPathPolygon
[0][0]=rStat
.GetStart();
1266 if (bMakeStartPoint
) {
1267 aPathPolygon
[0][1]=rStat
.GetNow();
1269 ImpPathCreateUser
* pU
=new ImpPathCreateUser
;
1270 pU
->eStartKind
=meObjectKind
;
1271 pU
->eAktKind
=meObjectKind
;
1276 bool ImpPathForDragAndCreate::MovCreate(SdrDragStat
& rStat
)
1278 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1279 SdrView
* pView
=rStat
.GetView();
1280 XPolygon
& rXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1281 if (pView
!=NULL
&& pView
->IsCreateMode()) {
1282 // switch to different CreateTool, if appropriate
1285 pView
->TakeCurrentObj(nIdent
,nInvent
);
1286 if (nInvent
==SdrInventor
&& pU
->eAktKind
!=(SdrObjKind
)nIdent
) {
1287 SdrObjKind eNewKind
=(SdrObjKind
)nIdent
;
1289 case OBJ_CARC
: case OBJ_CIRC
: case OBJ_CCUT
: case OBJ_SECT
: eNewKind
=OBJ_CARC
;
1291 case OBJ_LINE
: case OBJ_PLIN
: case OBJ_POLY
:
1292 case OBJ_PATHLINE
: case OBJ_PATHFILL
:
1293 case OBJ_FREELINE
: case OBJ_FREEFILL
:
1294 case OBJ_SPLNLINE
: case OBJ_SPLNFILL
: {
1295 pU
->eAktKind
=eNewKind
;
1296 pU
->bMixedCreate
=sal_True
;
1297 pU
->nBezierStartPoint
=rXPoly
.GetPointCount();
1298 if (pU
->nBezierStartPoint
>0) pU
->nBezierStartPoint
--;
1304 sal_uInt16 nActPoint
=rXPoly
.GetPointCount();
1305 if (aPathPolygon
.Count()>1 && rStat
.IsMouseDown() && nActPoint
<2) {
1306 rXPoly
[0]=rStat
.GetPos0();
1307 rXPoly
[1]=rStat
.GetNow();
1311 rXPoly
[0]=rStat
.GetPos0();
1313 bool bFreeHand
=IsFreeHand(pU
->eAktKind
);
1314 rStat
.SetNoSnap(bFreeHand
);
1315 rStat
.SetOrtho8Possible(pU
->eAktKind
!=OBJ_CARC
&& pU
->eAktKind
!=OBJ_RECT
&& (!pU
->bMixedCreate
|| pU
->eAktKind
!=OBJ_LINE
));
1316 rXPoly
[nActPoint
]=rStat
.Now();
1317 if (!pU
->bMixedCreate
&& pU
->eStartKind
==OBJ_LINE
&& rXPoly
.GetPointCount()>=1) {
1318 Point
aPt(rStat
.Start());
1319 if (pView
!=NULL
&& pView
->IsCreate1stPointAsCenter()) {
1325 OutputDevice
* pOut
=pView
==NULL
? NULL
: pView
->GetFirstOutputDevice();
1327 if (pU
->nBezierStartPoint
>nActPoint
) pU
->nBezierStartPoint
=nActPoint
;
1328 if (rStat
.IsMouseDown() && nActPoint
>0) {
1329 // don't allow two consecutive points to occupy too similar positions
1331 if (pView
!=NULL
) nMinDist
=pView
->GetFreeHandMinDistPix();
1332 if (pOut
!=NULL
) nMinDist
=pOut
->PixelToLogic(Size(nMinDist
,0)).Width();
1333 if (nMinDist
<1) nMinDist
=1;
1335 Point
aPt0(rXPoly
[nActPoint
-1]);
1336 Point
aPt1(rStat
.Now());
1337 long dx
=aPt0
.X()-aPt1
.X(); if (dx
<0) dx
=-dx
;
1338 long dy
=aPt0
.Y()-aPt1
.Y(); if (dy
<0) dy
=-dy
;
1339 if (dx
<nMinDist
&& dy
<nMinDist
) return sal_False
;
1341 // TODO: the following is copied from EndCreate (with a few smaller modifications)
1342 // and should be combined into a method with the code there.
1344 if (nActPoint
-pU
->nBezierStartPoint
>=3 && ((nActPoint
-pU
->nBezierStartPoint
)%3)==0) {
1345 rXPoly
.PointsToBezier(nActPoint
-3);
1346 rXPoly
.SetFlags(nActPoint
-1,XPOLY_CONTROL
);
1347 rXPoly
.SetFlags(nActPoint
-2,XPOLY_CONTROL
);
1349 if (nActPoint
>=6 && rXPoly
.IsControl(nActPoint
-4)) {
1350 rXPoly
.CalcTangent(nActPoint
-3,nActPoint
-4,nActPoint
-2);
1351 rXPoly
.SetFlags(nActPoint
-3,XPOLY_SMOOTH
);
1354 rXPoly
[nActPoint
+1]=rStat
.Now();
1357 pU
->nBezierStartPoint
=nActPoint
;
1361 pU
->ResetFormFlags();
1362 if (IsBezier(pU
->eAktKind
)) {
1364 pU
->CalcBezier(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],rStat
.IsMouseDown());
1365 } else if (pU
->bBezHasCtrl0
) {
1366 pU
->CalcBezier(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],pU
->aBezControl0
-rXPoly
[nActPoint
-1],rStat
.IsMouseDown());
1369 if (pU
->eAktKind
==OBJ_CARC
&& nActPoint
>=2) {
1370 pU
->CalcCircle(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],pView
);
1372 if (pU
->eAktKind
==OBJ_LINE
&& nActPoint
>=2) {
1373 pU
->CalcLine(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],pView
);
1375 if (pU
->eAktKind
==OBJ_RECT
&& nActPoint
>=2) {
1376 pU
->CalcRect(rXPoly
[nActPoint
-1],rXPoly
[nActPoint
],rXPoly
[nActPoint
-1]-rXPoly
[nActPoint
-2],pView
);
1382 bool ImpPathForDragAndCreate::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
1384 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1386 SdrView
* pView
=rStat
.GetView();
1387 bool bIncomp
=pView
!=NULL
&& pView
->IsUseIncompatiblePathCreateInterface();
1388 XPolygon
& rXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1389 sal_uInt16 nActPoint
=rXPoly
.GetPointCount()-1;
1390 rXPoly
[nActPoint
]=rStat
.Now();
1391 if (!pU
->bMixedCreate
&& pU
->eStartKind
==OBJ_LINE
) {
1392 if (rStat
.GetPointAnz()>=2) eCmd
=SDRCREATE_FORCEEND
;
1393 bRet
= eCmd
==SDRCREATE_FORCEEND
;
1395 mbCreating
= sal_False
;
1397 rStat
.SetUser(NULL
);
1402 if (!pU
->bMixedCreate
&& IsFreeHand(pU
->eStartKind
)) {
1403 if (rStat
.GetPointAnz()>=2) eCmd
=SDRCREATE_FORCEEND
;
1404 bRet
=eCmd
==SDRCREATE_FORCEEND
;
1406 mbCreating
=sal_False
;
1408 rStat
.SetUser(NULL
);
1412 if (eCmd
==SDRCREATE_NEXTPOINT
|| eCmd
==SDRCREATE_NEXTOBJECT
) {
1413 // don't allow two consecutive points to occupy the same position
1414 if (nActPoint
==0 || rStat
.Now()!=rXPoly
[nActPoint
-1]) {
1416 if (pU
->nBezierStartPoint
>nActPoint
) pU
->nBezierStartPoint
=nActPoint
;
1417 if (IsBezier(pU
->eAktKind
) && nActPoint
-pU
->nBezierStartPoint
>=3 && ((nActPoint
-pU
->nBezierStartPoint
)%3)==0) {
1418 rXPoly
.PointsToBezier(nActPoint
-3);
1419 rXPoly
.SetFlags(nActPoint
-1,XPOLY_CONTROL
);
1420 rXPoly
.SetFlags(nActPoint
-2,XPOLY_CONTROL
);
1422 if (nActPoint
>=6 && rXPoly
.IsControl(nActPoint
-4)) {
1423 rXPoly
.CalcTangent(nActPoint
-3,nActPoint
-4,nActPoint
-2);
1424 rXPoly
.SetFlags(nActPoint
-3,XPOLY_SMOOTH
);
1428 if (nActPoint
==1 && IsBezier(pU
->eAktKind
) && !pU
->bBezHasCtrl0
) {
1429 pU
->aBezControl0
=rStat
.GetNow();
1430 pU
->bBezHasCtrl0
=sal_True
;
1433 if (pU
->IsFormFlag()) {
1434 sal_uInt16 nPtAnz0
=rXPoly
.GetPointCount();
1435 rXPoly
.Remove(nActPoint
-1,2); // remove last two points and replace by form
1436 rXPoly
.Insert(XPOLY_APPEND
,pU
->GetFormPoly());
1437 sal_uInt16 nPtAnz1
=rXPoly
.GetPointCount();
1438 for (sal_uInt16 i
=nPtAnz0
+1; i
<nPtAnz1
-1; i
++) { // to make BckAction work
1439 if (!rXPoly
.IsControl(i
)) rStat
.NextPoint();
1441 nActPoint
=rXPoly
.GetPointCount()-1;
1445 rXPoly
[nActPoint
]=rStat
.GetNow();
1447 if (eCmd
==SDRCREATE_NEXTOBJECT
) {
1448 if (rXPoly
.GetPointCount()>=2) {
1449 pU
->bBezHasCtrl0
=sal_False
;
1450 // only a singular polygon may be opened, so close this
1451 rXPoly
[nActPoint
]=rXPoly
[0];
1453 aXP
[0]=rStat
.GetNow();
1454 aPathPolygon
.Insert(aXP
);
1459 sal_uInt16 nPolyAnz
=aPathPolygon
.Count();
1461 // delete last point, if necessary
1462 if (eCmd
==SDRCREATE_FORCEEND
) {
1463 XPolygon
& rXP
=aPathPolygon
[nPolyAnz
-1];
1464 sal_uInt16 nPtAnz
=rXP
.GetPointCount();
1466 if (!rXP
.IsControl(nPtAnz
-2)) {
1467 if (rXP
[nPtAnz
-1]==rXP
[nPtAnz
-2]) {
1468 rXP
.Remove(nPtAnz
-1,1);
1471 if (rXP
[nPtAnz
-3]==rXP
[nPtAnz
-2]) {
1472 rXP
.Remove(nPtAnz
-3,3);
1477 for (sal_uInt16 nPolyNum
=nPolyAnz
; nPolyNum
>0;) {
1479 XPolygon
& rXP
=aPathPolygon
[nPolyNum
];
1480 sal_uInt16 nPtAnz
=rXP
.GetPointCount();
1481 // delete polygons with too few points
1482 if (nPolyNum
<nPolyAnz
-1 || eCmd
==SDRCREATE_FORCEEND
) {
1483 if (nPtAnz
<2) aPathPolygon
.Remove(nPolyNum
);
1487 pU
->ResetFormFlags();
1488 bRet
=eCmd
==SDRCREATE_FORCEEND
;
1490 mbCreating
=sal_False
;
1492 rStat
.SetUser(NULL
);
1497 bool ImpPathForDragAndCreate::BckCreate(SdrDragStat
& rStat
)
1499 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1500 if (aPathPolygon
.Count()>0) {
1501 XPolygon
& rXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1502 sal_uInt16 nActPoint
=rXPoly
.GetPointCount();
1505 // make the last part of a bezier curve a line
1506 rXPoly
.Remove(nActPoint
,1);
1507 if (nActPoint
>=3 && rXPoly
.IsControl(nActPoint
-1)) {
1508 // there should never be a bezier segment at the end, so this is just in case...
1509 rXPoly
.Remove(nActPoint
-1,1);
1510 if (rXPoly
.IsControl(nActPoint
-2)) rXPoly
.Remove(nActPoint
-2,1);
1513 nActPoint
=rXPoly
.GetPointCount();
1514 if (nActPoint
>=4) { // no bezier segment at the end
1516 if (rXPoly
.IsControl(nActPoint
-1)) {
1517 rXPoly
.Remove(nActPoint
-1,1);
1518 if (rXPoly
.IsControl(nActPoint
-2)) rXPoly
.Remove(nActPoint
-2,1);
1521 if (rXPoly
.GetPointCount()<2) {
1522 aPathPolygon
.Remove(aPathPolygon
.Count()-1);
1524 if (aPathPolygon
.Count()>0) {
1525 XPolygon
& rLocalXPoly
=aPathPolygon
[aPathPolygon
.Count()-1];
1526 sal_uInt16 nLocalActPoint
=rLocalXPoly
.GetPointCount();
1527 if (nLocalActPoint
>0) {
1529 rLocalXPoly
[nLocalActPoint
]=rStat
.Now();
1533 pU
->ResetFormFlags();
1534 return aPathPolygon
.Count()!=0;
1537 void ImpPathForDragAndCreate::BrkCreate(SdrDragStat
& rStat
)
1539 ImpPathCreateUser
* pU
=(ImpPathCreateUser
*)rStat
.GetUser();
1540 aPathPolygon
.Clear();
1541 mbCreating
=sal_False
;
1543 rStat
.SetUser(NULL
);
1546 basegfx::B2DPolyPolygon
ImpPathForDragAndCreate::TakeObjectPolyPolygon(const SdrDragStat
& rDrag
) const
1548 basegfx::B2DPolyPolygon
aRetval(aPathPolygon
.getB2DPolyPolygon());
1549 SdrView
* pView
= rDrag
.GetView();
1551 if(pView
&& pView
->IsUseIncompatiblePathCreateInterface())
1554 ImpPathCreateUser
* pU
= (ImpPathCreateUser
*)rDrag
.GetUser();
1555 basegfx::B2DPolygon
aNewPolygon(aRetval
.count() ? aRetval
.getB2DPolygon(aRetval
.count() - 1L) : basegfx::B2DPolygon());
1557 if(pU
->IsFormFlag() && aNewPolygon
.count() > 1L)
1559 // remove last segment and replace with current
1560 // do not forget to rescue the previous control point which will be lost when
1561 // the point it's associated with is removed
1562 const sal_uInt32
nChangeIndex(aNewPolygon
.count() - 2);
1563 const basegfx::B2DPoint
aSavedPrevCtrlPoint(aNewPolygon
.getPrevControlPoint(nChangeIndex
));
1565 aNewPolygon
.remove(nChangeIndex
, 2L);
1566 aNewPolygon
.append(pU
->GetFormPoly().getB2DPolygon());
1568 if(nChangeIndex
< aNewPolygon
.count())
1570 // if really something was added, set the saved previous control point to the
1571 // point where it belongs
1572 aNewPolygon
.setPrevControlPoint(nChangeIndex
, aSavedPrevCtrlPoint
);
1578 aRetval
.setB2DPolygon(aRetval
.count() - 1L, aNewPolygon
);
1582 aRetval
.append(aNewPolygon
);
1588 basegfx::B2DPolyPolygon
ImpPathForDragAndCreate::TakeDragPolyPolygon(const SdrDragStat
& rDrag
) const
1590 basegfx::B2DPolyPolygon aRetval
;
1591 SdrView
* pView
= rDrag
.GetView();
1593 if(pView
&& pView
->IsUseIncompatiblePathCreateInterface())
1596 ImpPathCreateUser
* pU
= (ImpPathCreateUser
*)rDrag
.GetUser();
1598 if(pU
&& pU
->bBezier
&& rDrag
.IsMouseDown())
1600 // no more XOR, no need for complicated helplines
1601 basegfx::B2DPolygon aHelpline
;
1602 aHelpline
.append(basegfx::B2DPoint(pU
->aBezCtrl2
.X(), pU
->aBezCtrl2
.Y()));
1603 aHelpline
.append(basegfx::B2DPoint(pU
->aBezEnd
.X(), pU
->aBezEnd
.Y()));
1604 aRetval
.append(aHelpline
);
1610 Pointer
ImpPathForDragAndCreate::GetCreatePointer() const
1612 switch (meObjectKind
) {
1613 case OBJ_LINE
: return Pointer(POINTER_DRAW_LINE
);
1614 case OBJ_POLY
: return Pointer(POINTER_DRAW_POLYGON
);
1615 case OBJ_PLIN
: return Pointer(POINTER_DRAW_POLYGON
);
1616 case OBJ_PATHLINE
: return Pointer(POINTER_DRAW_BEZIER
);
1617 case OBJ_PATHFILL
: return Pointer(POINTER_DRAW_BEZIER
);
1618 case OBJ_FREELINE
: return Pointer(POINTER_DRAW_FREEHAND
);
1619 case OBJ_FREEFILL
: return Pointer(POINTER_DRAW_FREEHAND
);
1620 case OBJ_SPLNLINE
: return Pointer(POINTER_DRAW_FREEHAND
);
1621 case OBJ_SPLNFILL
: return Pointer(POINTER_DRAW_FREEHAND
);
1622 case OBJ_PATHPOLY
: return Pointer(POINTER_DRAW_POLYGON
);
1623 case OBJ_PATHPLIN
: return Pointer(POINTER_DRAW_POLYGON
);
1626 return Pointer(POINTER_CROSS
);
1629 /*************************************************************************/
1631 SdrPathObjGeoData::SdrPathObjGeoData()
1635 SdrPathObjGeoData::~SdrPathObjGeoData()
1639 //////////////////////////////////////////////////////////////////////////////
1640 // DrawContact section
1642 sdr::contact::ViewContact
* SdrPathObj::CreateObjectSpecificViewContact()
1644 return new sdr::contact::ViewContactOfSdrPathObj(*this);
1647 /*************************************************************************/
1649 TYPEINIT1(SdrPathObj
,SdrTextObj
);
1651 SdrPathObj::SdrPathObj(SdrObjKind eNewKind
)
1656 bClosedObj
= IsClosed();
1659 SdrPathObj::SdrPathObj(SdrObjKind eNewKind
, const basegfx::B2DPolyPolygon
& rPathPoly
, double dBrightness
)
1660 : maPathPolygon(rPathPoly
),
1663 mdBrightness(dBrightness
)
1665 bClosedObj
= IsClosed();
1669 SdrPathObj::~SdrPathObj()
1674 static bool lcl_ImpIsLine(const basegfx::B2DPolyPolygon
& rPolyPolygon
)
1676 return (1L == rPolyPolygon
.count() && 2L == rPolyPolygon
.getB2DPolygon(0L).count());
1679 static Rectangle
lcl_ImpGetBoundRect(const basegfx::B2DPolyPolygon
& rPolyPolygon
)
1681 basegfx::B2DRange
aRange(basegfx::tools::getRange(rPolyPolygon
));
1684 FRound(aRange
.getMinX()), FRound(aRange
.getMinY()),
1685 FRound(aRange
.getMaxX()), FRound(aRange
.getMaxY()));
1688 void SdrPathObj::ImpForceLineWink()
1690 if(OBJ_LINE
== meKind
&& lcl_ImpIsLine(GetPathPoly()))
1692 const basegfx::B2DPolygon
aPoly(GetPathPoly().getB2DPolygon(0L));
1693 const basegfx::B2DPoint
aB2DPoint0(aPoly
.getB2DPoint(0L));
1694 const basegfx::B2DPoint
aB2DPoint1(aPoly
.getB2DPoint(1L));
1695 const Point
aPoint0(FRound(aB2DPoint0
.getX()), FRound(aB2DPoint0
.getY()));
1696 const Point
aPoint1(FRound(aB2DPoint1
.getX()), FRound(aB2DPoint1
.getY()));
1697 const Point
aDelt(aPoint1
- aPoint0
);
1699 aGeo
.nDrehWink
=GetAngle(aDelt
);
1701 aGeo
.RecalcSinCos();
1704 // for SdrTextObj, keep aRect up to date
1705 aRect
= Rectangle(aPoint0
, aPoint1
);
1710 void SdrPathObj::ImpForceKind()
1712 if (meKind
==OBJ_PATHPLIN
) meKind
=OBJ_PLIN
;
1713 if (meKind
==OBJ_PATHPOLY
) meKind
=OBJ_POLY
;
1715 if(GetPathPoly().areControlPointsUsed())
1719 case OBJ_LINE
: meKind
=OBJ_PATHLINE
; break;
1720 case OBJ_PLIN
: meKind
=OBJ_PATHLINE
; break;
1721 case OBJ_POLY
: meKind
=OBJ_PATHFILL
; break;
1729 case OBJ_PATHLINE
: meKind
=OBJ_PLIN
; break;
1730 case OBJ_FREELINE
: meKind
=OBJ_PLIN
; break;
1731 case OBJ_PATHFILL
: meKind
=OBJ_POLY
; break;
1732 case OBJ_FREEFILL
: meKind
=OBJ_POLY
; break;
1737 if (meKind
==OBJ_LINE
&& !lcl_ImpIsLine(GetPathPoly())) meKind
=OBJ_PLIN
;
1738 if (meKind
==OBJ_PLIN
&& lcl_ImpIsLine(GetPathPoly())) meKind
=OBJ_LINE
;
1740 bClosedObj
=IsClosed();
1742 if (meKind
==OBJ_LINE
)
1748 // #i10659#, for polys with more than 2 points.
1750 // Here i again need to fix something, because when Path-Polys are Copy-Pasted
1751 // between Apps with different measurements (e.g. 100TH_MM and TWIPS) there is
1752 // a scaling loop started from SdrExchangeView::Paste. In itself, this is not
1753 // wrong, but aRect is wrong here and not even updated by RecalcSnapRect(). If
1754 // this is the case, some size needs to be set here in aRect to avoid that the cycle
1755 // through Rect2Poly - Poly2Rect does something badly wrong since that cycle is
1756 // BASED on aRect. That cycle is triggered in SdrTextObj::NbcResize() which is called
1757 // from the local Resize() implementation.
1759 // Basic problem is that the member aRect in SdrTextObj basically is a unrotated
1760 // text rectangle for the text object itself and methods at SdrTextObj do handle it
1761 // in that way. Many draw objects derived from SdrTextObj 'abuse' aRect as SnapRect
1762 // which is basically wrong. To make the SdrText methods which deal with aRect directly
1763 // work it is necessary to always keep aRect updated. This e.g. not done after a Clone()
1764 // command for SdrPathObj. Since adding this update mechanism with #101412# to
1765 // ImpForceLineWink() for lines was very successful, i add it to where ImpForceLineWink()
1766 // was called, once here below and once on a 2nd place below.
1768 // #i10659# for SdrTextObj, keep aRect up to date
1769 if(GetPathPoly().count())
1771 aRect
= lcl_ImpGetBoundRect(GetPathPoly());
1774 // #i116244# reset rotation
1775 aGeo
.nDrehWink
= aGeo
.nShearWink
= 0;
1776 aGeo
.RecalcSinCos(); aGeo
.RecalcTan();
1779 // #i75974# adapt polygon state to object type. This may include a reinterpretation
1780 // of a closed geometry as open one, but with identical first and last point
1781 for(sal_uInt32
a(0); a
< maPathPolygon
.count(); a
++)
1783 basegfx::B2DPolygon
aCandidate(maPathPolygon
.getB2DPolygon(a
));
1785 if((bool)IsClosed() != aCandidate
.isClosed())
1787 // #i80213# really change polygon geometry; else e.g. the last point which
1788 // needs to be identical with the first one will be missing when opening
1789 // due to OBJ_PATH type
1790 if(aCandidate
.isClosed())
1792 basegfx::tools::openWithGeometryChange(aCandidate
);
1796 basegfx::tools::closeWithGeometryChange(aCandidate
);
1799 maPathPolygon
.setB2DPolygon(a
, aCandidate
);
1804 void SdrPathObj::ImpSetClosed(sal_Bool bClose
)
1810 case OBJ_LINE
: meKind
=OBJ_POLY
; break;
1811 case OBJ_PLIN
: meKind
=OBJ_POLY
; break;
1812 case OBJ_PATHLINE
: meKind
=OBJ_PATHFILL
; break;
1813 case OBJ_FREELINE
: meKind
=OBJ_FREEFILL
; break;
1814 case OBJ_SPLNLINE
: meKind
=OBJ_SPLNFILL
; break;
1818 bClosedObj
= sal_True
;
1824 case OBJ_POLY
: meKind
=OBJ_PLIN
; break;
1825 case OBJ_PATHFILL
: meKind
=OBJ_PATHLINE
; break;
1826 case OBJ_FREEFILL
: meKind
=OBJ_FREELINE
; break;
1827 case OBJ_SPLNFILL
: meKind
=OBJ_SPLNLINE
; break;
1831 bClosedObj
= sal_False
;
1837 void SdrPathObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
1839 rInfo
.bNoContortion
=sal_False
;
1841 bool bCanConv
= !HasText() || ImpCanConvTextToCurve();
1842 bool bIsPath
= IsBezier() || IsSpline();
1844 rInfo
.bEdgeRadiusAllowed
= sal_False
;
1845 rInfo
.bCanConvToPath
= bCanConv
&& !bIsPath
;
1846 rInfo
.bCanConvToPoly
= bCanConv
&& bIsPath
;
1847 rInfo
.bCanConvToContour
= !IsFontwork() && (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
1850 sal_uInt16
SdrPathObj::GetObjIdentifier() const
1852 return sal_uInt16(meKind
);
1855 SdrPathObj
* SdrPathObj::Clone() const
1857 return CloneHelper
< SdrPathObj
>();
1860 SdrPathObj
& SdrPathObj::operator=(const SdrPathObj
& rObj
)
1864 SdrTextObj::operator=(rObj
);
1865 maPathPolygon
=rObj
.GetPathPoly();
1869 void SdrPathObj::TakeObjNameSingul(XubString
& rName
) const
1871 if(OBJ_LINE
== meKind
)
1873 sal_uInt16
nId(STR_ObjNameSingulLINE
);
1875 if(lcl_ImpIsLine(GetPathPoly()))
1877 const basegfx::B2DPolygon
aPoly(GetPathPoly().getB2DPolygon(0L));
1878 const basegfx::B2DPoint
aB2DPoint0(aPoly
.getB2DPoint(0L));
1879 const basegfx::B2DPoint
aB2DPoint1(aPoly
.getB2DPoint(1L));
1881 if(aB2DPoint0
!= aB2DPoint1
)
1883 if(aB2DPoint0
.getY() == aB2DPoint1
.getY())
1885 nId
= STR_ObjNameSingulLINE_Hori
;
1887 else if(aB2DPoint0
.getX() == aB2DPoint1
.getX())
1889 nId
= STR_ObjNameSingulLINE_Vert
;
1893 const double fDx(fabs(aB2DPoint0
.getX() - aB2DPoint1
.getX()));
1894 const double fDy(fabs(aB2DPoint0
.getY() - aB2DPoint1
.getY()));
1898 nId
= STR_ObjNameSingulLINE_Diag
;
1904 rName
= ImpGetResStr(nId
);
1906 else if(OBJ_PLIN
== meKind
|| OBJ_POLY
== meKind
)
1908 const bool bClosed(OBJ_POLY
== meKind
);
1911 if(mpDAC
&& mpDAC
->IsCreating())
1915 nId
= STR_ObjNameSingulPOLY
;
1919 nId
= STR_ObjNameSingulPLIN
;
1922 rName
= ImpGetResStr(nId
);
1927 sal_uInt32
nPointCount(0L);
1928 const sal_uInt32
nPolyCount(GetPathPoly().count());
1930 for(sal_uInt32
a(0L); a
< nPolyCount
; a
++)
1932 nPointCount
+= GetPathPoly().getB2DPolygon(a
).count();
1937 nId
= STR_ObjNameSingulPOLY_PntAnz
;
1941 nId
= STR_ObjNameSingulPLIN_PntAnz
;
1944 rName
= ImpGetResStr(nId
);
1945 sal_uInt16
nPos(rName
.SearchAscii("%2")); // #i96537#
1947 if(STRING_NOTFOUND
!= nPos
)
1949 rName
.Erase(nPos
, 2);
1950 rName
.Insert(OUString::number(nPointCount
), nPos
);
1958 case OBJ_PATHLINE
: rName
=ImpGetResStr(STR_ObjNameSingulPATHLINE
); break;
1959 case OBJ_FREELINE
: rName
=ImpGetResStr(STR_ObjNameSingulFREELINE
); break;
1960 case OBJ_SPLNLINE
: rName
=ImpGetResStr(STR_ObjNameSingulNATSPLN
); break;
1961 case OBJ_PATHFILL
: rName
=ImpGetResStr(STR_ObjNameSingulPATHFILL
); break;
1962 case OBJ_FREEFILL
: rName
=ImpGetResStr(STR_ObjNameSingulFREEFILL
); break;
1963 case OBJ_SPLNFILL
: rName
=ImpGetResStr(STR_ObjNameSingulPERSPLN
); break;
1968 String
aName(GetName());
1971 rName
+= sal_Unicode(' ');
1972 rName
+= sal_Unicode('\'');
1974 rName
+= sal_Unicode('\'');
1978 void SdrPathObj::TakeObjNamePlural(XubString
& rName
) const
1982 case OBJ_LINE
: rName
=ImpGetResStr(STR_ObjNamePluralLINE
); break;
1983 case OBJ_PLIN
: rName
=ImpGetResStr(STR_ObjNamePluralPLIN
); break;
1984 case OBJ_POLY
: rName
=ImpGetResStr(STR_ObjNamePluralPOLY
); break;
1985 case OBJ_PATHLINE
: rName
=ImpGetResStr(STR_ObjNamePluralPATHLINE
); break;
1986 case OBJ_FREELINE
: rName
=ImpGetResStr(STR_ObjNamePluralFREELINE
); break;
1987 case OBJ_SPLNLINE
: rName
=ImpGetResStr(STR_ObjNamePluralNATSPLN
); break;
1988 case OBJ_PATHFILL
: rName
=ImpGetResStr(STR_ObjNamePluralPATHFILL
); break;
1989 case OBJ_FREEFILL
: rName
=ImpGetResStr(STR_ObjNamePluralFREEFILL
); break;
1990 case OBJ_SPLNFILL
: rName
=ImpGetResStr(STR_ObjNamePluralPERSPLN
); break;
1995 basegfx::B2DPolyPolygon
SdrPathObj::TakeXorPoly() const
1997 return GetPathPoly();
2000 sal_uInt32
SdrPathObj::GetHdlCount() const
2002 sal_uInt32
nRetval(0L);
2003 const sal_uInt32
nPolyCount(GetPathPoly().count());
2005 for(sal_uInt32
a(0L); a
< nPolyCount
; a
++)
2007 nRetval
+= GetPathPoly().getB2DPolygon(a
).count();
2013 SdrHdl
* SdrPathObj::GetHdl(sal_uInt32 nHdlNum
) const
2016 // Warn the user that this is ineffective and show alternatives. Should not be used at all.
2017 OSL_FAIL("SdrPathObj::GetHdl(): ineffective, use AddToHdlList instead (!)");
2019 // to have an alternative, get single handle using the ineffective way
2020 SdrHdl
* pRetval
= 0;
2021 SdrHdlList
aLocalList(0);
2022 AddToHdlList(aLocalList
);
2023 const sal_uInt32
nHdlCount(aLocalList
.GetHdlCount());
2025 if(nHdlCount
&& nHdlNum
< nHdlCount
)
2027 // remove and remember. The other created handles will be deleted again with the
2028 // destruction of the local list
2029 pRetval
= aLocalList
.RemoveHdl(nHdlNum
);
2035 void SdrPathObj::AddToHdlList(SdrHdlList
& rHdlList
) const
2037 // keep old stuff to be able to keep old SdrHdl stuff, too
2038 const XPolyPolygon
aOldPathPolygon(GetPathPoly());
2039 sal_uInt16 nPolyCnt
=aOldPathPolygon
.Count();
2040 bool bClosed
=IsClosed();
2043 for (sal_uInt16 i
=0; i
<nPolyCnt
; i
++) {
2044 const XPolygon
& rXPoly
=aOldPathPolygon
.GetObject(i
);
2045 sal_uInt16 nPntCnt
=rXPoly
.GetPointCount();
2046 if (bClosed
&& nPntCnt
>1) nPntCnt
--;
2048 for (sal_uInt16 j
=0; j
<nPntCnt
; j
++) {
2049 if (rXPoly
.GetFlags(j
)!=XPOLY_CONTROL
) {
2050 const Point
& rPnt
=rXPoly
[j
];
2051 SdrHdl
* pHdl
=new SdrHdl(rPnt
,HDL_POLY
);
2052 pHdl
->SetPolyNum(i
);
2053 pHdl
->SetPointNum(j
);
2054 pHdl
->Set1PixMore(j
==0);
2055 pHdl
->SetSourceHdlNum(nIdx
);
2057 rHdlList
.AddHdl(pHdl
);
2063 sal_uInt32
SdrPathObj::GetPlusHdlCount(const SdrHdl
& rHdl
) const
2065 // keep old stuff to be able to keep old SdrHdl stuff, too
2066 const XPolyPolygon
aOldPathPolygon(GetPathPoly());
2067 sal_uInt16 nCnt
= 0;
2068 sal_uInt16 nPnt
= (sal_uInt16
)rHdl
.GetPointNum();
2069 sal_uInt16 nPolyNum
= (sal_uInt16
)rHdl
.GetPolyNum();
2071 if(nPolyNum
< aOldPathPolygon
.Count())
2073 const XPolygon
& rXPoly
= aOldPathPolygon
[nPolyNum
];
2074 sal_uInt16 nPntMax
= rXPoly
.GetPointCount();
2080 if (rXPoly
.GetFlags(nPnt
)!=XPOLY_CONTROL
)
2082 if (nPnt
==0 && IsClosed()) nPnt
=nPntMax
;
2083 if (nPnt
>0 && rXPoly
.GetFlags(nPnt
-1)==XPOLY_CONTROL
) nCnt
++;
2084 if (nPnt
==nPntMax
&& IsClosed()) nPnt
=0;
2085 if (nPnt
<nPntMax
&& rXPoly
.GetFlags(nPnt
+1)==XPOLY_CONTROL
) nCnt
++;
2094 SdrHdl
* SdrPathObj::GetPlusHdl(const SdrHdl
& rHdl
, sal_uInt32 nPlusNum
) const
2096 // keep old stuff to be able to keep old SdrHdl stuff, too
2097 const XPolyPolygon
aOldPathPolygon(GetPathPoly());
2099 sal_uInt16 nPnt
= (sal_uInt16
)rHdl
.GetPointNum();
2100 sal_uInt16 nPolyNum
= (sal_uInt16
)rHdl
.GetPolyNum();
2102 if (nPolyNum
<aOldPathPolygon
.Count())
2104 const XPolygon
& rXPoly
= aOldPathPolygon
[nPolyNum
];
2105 sal_uInt16 nPntMax
= rXPoly
.GetPointCount();
2112 pHdl
=new SdrHdlBezWgt(&rHdl
);
2113 pHdl
->SetPolyNum(rHdl
.GetPolyNum());
2115 if (nPnt
==0 && IsClosed()) nPnt
=nPntMax
;
2116 if (nPnt
>0 && rXPoly
.GetFlags(nPnt
-1)==XPOLY_CONTROL
&& nPlusNum
==0)
2118 pHdl
->SetPos(rXPoly
[nPnt
-1]);
2119 pHdl
->SetPointNum(nPnt
-1);
2123 if (nPnt
==nPntMax
&& IsClosed()) nPnt
=0;
2124 if (nPnt
<rXPoly
.GetPointCount()-1 && rXPoly
.GetFlags(nPnt
+1)==XPOLY_CONTROL
)
2126 pHdl
->SetPos(rXPoly
[nPnt
+1]);
2127 pHdl
->SetPointNum(nPnt
+1);
2131 pHdl
->SetSourceHdlNum(rHdl
.GetSourceHdlNum());
2132 pHdl
->SetPlusHdl(sal_True
);
2139 ////////////////////////////////////////////////////////////////////////////////////////////////////
2141 bool SdrPathObj::hasSpecialDrag() const
2146 bool SdrPathObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
2148 ImpPathForDragAndCreate
aDragAndCreate(*((SdrPathObj
*)this));
2150 return aDragAndCreate
.beginPathDrag(rDrag
);
2153 bool SdrPathObj::applySpecialDrag(SdrDragStat
& rDrag
)
2155 ImpPathForDragAndCreate
aDragAndCreate(*this);
2156 bool bRetval(aDragAndCreate
.beginPathDrag(rDrag
));
2160 bRetval
= aDragAndCreate
.movePathDrag(rDrag
);
2165 bRetval
= aDragAndCreate
.endPathDrag(rDrag
);
2170 NbcSetPathPoly(aDragAndCreate
.getModifiedPolyPolygon());
2176 String
SdrPathObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
2182 // #i103058# also get a comment when in creation
2183 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
2187 aRetval
= mpDAC
->getSpecialDragComment(rDrag
);
2192 ImpPathForDragAndCreate
aDragAndCreate(*((SdrPathObj
*)this));
2193 bool bDidWork(aDragAndCreate
.beginPathDrag((SdrDragStat
&)rDrag
));
2197 aRetval
= aDragAndCreate
.getSpecialDragComment(rDrag
);
2204 basegfx::B2DPolyPolygon
SdrPathObj::getSpecialDragPoly(const SdrDragStat
& rDrag
) const
2206 basegfx::B2DPolyPolygon aRetval
;
2207 ImpPathForDragAndCreate
aDragAndCreate(*((SdrPathObj
*)this));
2208 bool bDidWork(aDragAndCreate
.beginPathDrag((SdrDragStat
&)rDrag
));
2212 aRetval
= aDragAndCreate
.getSpecialDragPoly(rDrag
);
2218 ////////////////////////////////////////////////////////////////////////////////////////////////////
2220 bool SdrPathObj::BegCreate(SdrDragStat
& rStat
)
2223 return impGetDAC().BegCreate(rStat
);
2226 bool SdrPathObj::MovCreate(SdrDragStat
& rStat
)
2228 return impGetDAC().MovCreate(rStat
);
2231 bool SdrPathObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
2233 bool bRetval(impGetDAC().EndCreate(rStat
, eCmd
));
2235 if(bRetval
&& mpDAC
)
2237 SetPathPoly(mpDAC
->getModifiedPolyPolygon());
2239 // #i75974# Check for AutoClose feature. Moved here from ImpPathForDragAndCreate::EndCreate
2240 // to be able to use the type-changing ImpSetClosed method
2243 SdrView
* pView
= rStat
.GetView();
2245 if(pView
&& pView
->IsAutoClosePolys() && !pView
->IsUseIncompatiblePathCreateInterface())
2247 OutputDevice
* pOut
= pView
->GetFirstOutputDevice();
2251 if(GetPathPoly().count())
2253 const basegfx::B2DPolygon
aCandidate(GetPathPoly().getB2DPolygon(0));
2255 if(aCandidate
.count() > 2)
2257 // check distance of first and last point
2258 const sal_Int32
nCloseDist(pOut
->PixelToLogic(Size(pView
->GetAutoCloseDistPix(), 0)).Width());
2259 const basegfx::B2DVector
aDistVector(aCandidate
.getB2DPoint(aCandidate
.count() - 1) - aCandidate
.getB2DPoint(0));
2261 if(aDistVector
.getLength() <= (double)nCloseDist
)
2278 bool SdrPathObj::BckCreate(SdrDragStat
& rStat
)
2280 return impGetDAC().BckCreate(rStat
);
2283 void SdrPathObj::BrkCreate(SdrDragStat
& rStat
)
2285 impGetDAC().BrkCreate(rStat
);
2289 basegfx::B2DPolyPolygon
SdrPathObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
2291 basegfx::B2DPolyPolygon aRetval
;
2295 aRetval
= mpDAC
->TakeObjectPolyPolygon(rDrag
);
2296 aRetval
.append(mpDAC
->TakeDragPolyPolygon(rDrag
));
2302 // during drag or create, allow accessing the so-far created/modified polyPolygon
2303 basegfx::B2DPolyPolygon
SdrPathObj::getObjectPolyPolygon(const SdrDragStat
& rDrag
) const
2305 basegfx::B2DPolyPolygon aRetval
;
2309 aRetval
= mpDAC
->TakeObjectPolyPolygon(rDrag
);
2315 basegfx::B2DPolyPolygon
SdrPathObj::getDragPolyPolygon(const SdrDragStat
& rDrag
) const
2317 basegfx::B2DPolyPolygon aRetval
;
2321 aRetval
= mpDAC
->TakeDragPolyPolygon(rDrag
);
2327 Pointer
SdrPathObj::GetCreatePointer() const
2329 return impGetDAC().GetCreatePointer();
2332 void SdrPathObj::NbcMove(const Size
& rSiz
)
2334 maPathPolygon
.transform(basegfx::tools::createTranslateB2DHomMatrix(rSiz
.Width(), rSiz
.Height()));
2336 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2337 SdrTextObj::NbcMove(rSiz
);
2340 void SdrPathObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
2342 basegfx::B2DHomMatrix
aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRef
.X(), -rRef
.Y()));
2343 aTrans
= basegfx::tools::createScaleTranslateB2DHomMatrix(
2344 double(xFact
), double(yFact
), rRef
.X(), rRef
.Y()) * aTrans
;
2345 maPathPolygon
.transform(aTrans
);
2347 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2348 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
2351 void SdrPathObj::NbcRotate(const Point
& rRef
, long nWink
, double sn
, double cs
)
2353 // Thank JOE, the angles are defined mirrored to the mathematical meanings
2354 const basegfx::B2DHomMatrix
aTrans(basegfx::tools::createRotateAroundPoint(rRef
.X(), rRef
.Y(), -nWink
* nPi180
));
2355 maPathPolygon
.transform(aTrans
);
2357 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2358 SdrTextObj::NbcRotate(rRef
,nWink
,sn
,cs
);
2361 void SdrPathObj::NbcShear(const Point
& rRefPnt
, long nAngle
, double fTan
, bool bVShear
)
2363 basegfx::B2DHomMatrix
aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRefPnt
.X(), -rRefPnt
.Y()));
2367 // Thank JOE, the angles are defined mirrored to the mathematical meanings
2368 aTrans
.shearY(-fTan
);
2372 aTrans
.shearX(-fTan
);
2375 aTrans
.translate(rRefPnt
.X(), rRefPnt
.Y());
2376 maPathPolygon
.transform(aTrans
);
2378 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2379 SdrTextObj::NbcShear(rRefPnt
,nAngle
,fTan
,bVShear
);
2382 void SdrPathObj::NbcMirror(const Point
& rRefPnt1
, const Point
& rRefPnt2
)
2384 const double fDiffX(rRefPnt2
.X() - rRefPnt1
.X());
2385 const double fDiffY(rRefPnt2
.Y() - rRefPnt1
.Y());
2386 const double fRot(atan2(fDiffY
, fDiffX
));
2387 basegfx::B2DHomMatrix
aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRefPnt1
.X(), -rRefPnt1
.Y()));
2388 aTrans
.rotate(-fRot
);
2389 aTrans
.scale(1.0, -1.0);
2390 aTrans
.rotate(fRot
);
2391 aTrans
.translate(rRefPnt1
.X(), rRefPnt1
.Y());
2392 maPathPolygon
.transform(aTrans
);
2394 // Do Joe's special handling for lines when mirroring, too
2397 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
2398 SdrTextObj::NbcMirror(rRefPnt1
,rRefPnt2
);
2401 void SdrPathObj::TakeUnrotatedSnapRect(Rectangle
& rRect
) const
2405 rRect
= GetSnapRect();
2409 XPolyPolygon
aXPP(GetPathPoly());
2410 RotateXPoly(aXPP
,Point(),-aGeo
.nSin
,aGeo
.nCos
);
2411 rRect
=aXPP
.GetBoundRect();
2412 Point
aTmp(rRect
.TopLeft());
2413 RotatePoint(aTmp
,Point(),aGeo
.nSin
,aGeo
.nCos
);
2414 aTmp
-=rRect
.TopLeft();
2415 rRect
.Move(aTmp
.X(),aTmp
.Y());
2419 void SdrPathObj::RecalcSnapRect()
2421 if(GetPathPoly().count())
2423 maSnapRect
= lcl_ImpGetBoundRect(GetPathPoly());
2427 void SdrPathObj::NbcSetSnapRect(const Rectangle
& rRect
)
2429 Rectangle
aOld(GetSnapRect());
2431 // Take RECT_EMPTY into account when calculating scale factors
2432 long nMulX
= (RECT_EMPTY
== rRect
.Right()) ? 0 : rRect
.Right() - rRect
.Left();
2434 long nDivX
= aOld
.Right() - aOld
.Left();
2436 // Take RECT_EMPTY into account when calculating scale factors
2437 long nMulY
= (RECT_EMPTY
== rRect
.Bottom()) ? 0 : rRect
.Bottom() - rRect
.Top();
2439 long nDivY
= aOld
.Bottom() - aOld
.Top();
2440 if ( nDivX
== 0 ) { nMulX
= 1; nDivX
= 1; }
2441 if ( nDivY
== 0 ) { nMulY
= 1; nDivY
= 1; }
2442 Fraction
aX(nMulX
,nDivX
);
2443 Fraction
aY(nMulY
,nDivY
);
2444 NbcResize(aOld
.TopLeft(), aX
, aY
);
2445 NbcMove(Size(rRect
.Left() - aOld
.Left(), rRect
.Top() - aOld
.Top()));
2448 sal_uInt32
SdrPathObj::GetSnapPointCount() const
2450 return GetHdlCount();
2453 Point
SdrPathObj::GetSnapPoint(sal_uInt32 nSnapPnt
) const
2455 sal_uInt32 nPoly
,nPnt
;
2456 if(!PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nSnapPnt
, nPoly
, nPnt
))
2458 DBG_ASSERT(sal_False
,"SdrPathObj::GetSnapPoint: Point nSnapPnt does not exist.");
2461 const basegfx::B2DPoint
aB2DPoint(GetPathPoly().getB2DPolygon(nPoly
).getB2DPoint(nPnt
));
2462 return Point(FRound(aB2DPoint
.getX()), FRound(aB2DPoint
.getY()));
2465 sal_Bool
SdrPathObj::IsPolyObj() const
2470 sal_uInt32
SdrPathObj::GetPointCount() const
2472 const sal_uInt32
nPolyCount(GetPathPoly().count());
2473 sal_uInt32
nRetval(0L);
2475 for(sal_uInt32
a(0L); a
< nPolyCount
; a
++)
2477 nRetval
+= GetPathPoly().getB2DPolygon(a
).count();
2483 Point
SdrPathObj::GetPoint(sal_uInt32 nHdlNum
) const
2486 sal_uInt32 nPoly
,nPnt
;
2488 if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum
, nPoly
, nPnt
))
2490 const basegfx::B2DPolygon
aPoly(GetPathPoly().getB2DPolygon(nPoly
));
2491 const basegfx::B2DPoint
aPoint(aPoly
.getB2DPoint(nPnt
));
2492 aRetval
= Point(FRound(aPoint
.getX()), FRound(aPoint
.getY()));
2498 void SdrPathObj::NbcSetPoint(const Point
& rPnt
, sal_uInt32 nHdlNum
)
2500 sal_uInt32 nPoly
,nPnt
;
2502 if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum
, nPoly
, nPnt
))
2504 basegfx::B2DPolygon
aNewPolygon(GetPathPoly().getB2DPolygon(nPoly
));
2505 aNewPolygon
.setB2DPoint(nPnt
, basegfx::B2DPoint(rPnt
.X(), rPnt
.Y()));
2506 maPathPolygon
.setB2DPolygon(nPoly
, aNewPolygon
);
2508 if(meKind
==OBJ_LINE
)
2514 if(GetPathPoly().count())
2516 // #i10659# for SdrTextObj, keep aRect up to date
2517 aRect
= lcl_ImpGetBoundRect(GetPathPoly());
2525 sal_uInt32
SdrPathObj::NbcInsPointOld(const Point
& rPos
, sal_Bool bNewObj
, sal_Bool bHideHim
)
2531 nNewHdl
= NbcInsPoint(0L, rPos
, sal_True
, bHideHim
);
2535 // look for smallest distance data
2536 const basegfx::B2DPoint
aTestPoint(rPos
.X(), rPos
.Y());
2537 sal_uInt32
nSmallestPolyIndex(0L);
2538 sal_uInt32
nSmallestEdgeIndex(0L);
2539 double fSmallestCut
;
2540 basegfx::tools::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint
, nSmallestPolyIndex
, nSmallestEdgeIndex
, fSmallestCut
);
2542 // create old polygon index from it
2543 sal_uInt32
nPolyIndex(nSmallestEdgeIndex
);
2545 for(sal_uInt32
a(0L); a
< nSmallestPolyIndex
; a
++)
2547 nPolyIndex
+= GetPathPoly().getB2DPolygon(a
).count();
2550 nNewHdl
= NbcInsPoint(nPolyIndex
, rPos
, sal_False
, bHideHim
);
2557 sal_uInt32
SdrPathObj::NbcInsPoint(sal_uInt32
/*nHdlNum*/, const Point
& rPos
, sal_Bool bNewObj
, sal_Bool
/*bHideHim*/)
2563 basegfx::B2DPolygon aNewPoly
;
2564 const basegfx::B2DPoint
aPoint(rPos
.X(), rPos
.Y());
2565 aNewPoly
.append(aPoint
);
2566 aNewPoly
.setClosed(IsClosed());
2567 maPathPolygon
.append(aNewPoly
);
2569 nNewHdl
= GetHdlCount();
2573 // look for smallest distance data
2574 const basegfx::B2DPoint
aTestPoint(rPos
.X(), rPos
.Y());
2575 sal_uInt32
nSmallestPolyIndex(0L);
2576 sal_uInt32
nSmallestEdgeIndex(0L);
2577 double fSmallestCut
;
2578 basegfx::tools::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint
, nSmallestPolyIndex
, nSmallestEdgeIndex
, fSmallestCut
);
2579 basegfx::B2DPolygon
aCandidate(GetPathPoly().getB2DPolygon(nSmallestPolyIndex
));
2580 const bool bBefore(!aCandidate
.isClosed() && 0L == nSmallestEdgeIndex
&& 0.0 == fSmallestCut
);
2581 const bool bAfter(!aCandidate
.isClosed() && aCandidate
.count() == nSmallestEdgeIndex
+ 2L && 1.0 == fSmallestCut
);
2585 // before first point
2586 aCandidate
.insert(0L, aTestPoint
);
2588 if(aCandidate
.areControlPointsUsed())
2590 if(aCandidate
.isNextControlPointUsed(1))
2592 aCandidate
.setNextControlPoint(0, interpolate(aTestPoint
, aCandidate
.getB2DPoint(1), (1.0 / 3.0)));
2593 aCandidate
.setPrevControlPoint(1, interpolate(aTestPoint
, aCandidate
.getB2DPoint(1), (2.0 / 3.0)));
2602 aCandidate
.append(aTestPoint
);
2604 if(aCandidate
.areControlPointsUsed())
2606 if(aCandidate
.isPrevControlPointUsed(aCandidate
.count() - 2))
2608 aCandidate
.setNextControlPoint(aCandidate
.count() - 2, interpolate(aCandidate
.getB2DPoint(aCandidate
.count() - 2), aTestPoint
, (1.0 / 3.0)));
2609 aCandidate
.setPrevControlPoint(aCandidate
.count() - 1, interpolate(aCandidate
.getB2DPoint(aCandidate
.count() - 2), aTestPoint
, (2.0 / 3.0)));
2613 nNewHdl
= aCandidate
.count() - 1L;
2618 bool bSegmentSplit(false);
2619 const sal_uInt32
nNextIndex((nSmallestEdgeIndex
+ 1) % aCandidate
.count());
2621 if(aCandidate
.areControlPointsUsed())
2623 if(aCandidate
.isNextControlPointUsed(nSmallestEdgeIndex
) || aCandidate
.isPrevControlPointUsed(nNextIndex
))
2625 bSegmentSplit
= true;
2631 // rebuild original segment to get the split data
2632 basegfx::B2DCubicBezier aBezierA
, aBezierB
;
2633 const basegfx::B2DCubicBezier
aBezier(
2634 aCandidate
.getB2DPoint(nSmallestEdgeIndex
),
2635 aCandidate
.getNextControlPoint(nSmallestEdgeIndex
),
2636 aCandidate
.getPrevControlPoint(nNextIndex
),
2637 aCandidate
.getB2DPoint(nNextIndex
));
2639 // split and insert hit point
2640 aBezier
.split(fSmallestCut
, &aBezierA
, &aBezierB
);
2641 aCandidate
.insert(nSmallestEdgeIndex
+ 1, aTestPoint
);
2643 // since we inserted hit point and not split point, we need to add an offset
2644 // to the control points to get the C1 continuity we want to achieve
2645 const basegfx::B2DVector
aOffset(aTestPoint
- aBezierA
.getEndPoint());
2646 aCandidate
.setNextControlPoint(nSmallestEdgeIndex
, aBezierA
.getControlPointA() + aOffset
);
2647 aCandidate
.setPrevControlPoint(nSmallestEdgeIndex
+ 1, aBezierA
.getControlPointB() + aOffset
);
2648 aCandidate
.setNextControlPoint(nSmallestEdgeIndex
+ 1, aBezierB
.getControlPointA() + aOffset
);
2649 aCandidate
.setPrevControlPoint((nSmallestEdgeIndex
+ 2) % aCandidate
.count(), aBezierB
.getControlPointB() + aOffset
);
2653 aCandidate
.insert(nSmallestEdgeIndex
+ 1L, aTestPoint
);
2656 nNewHdl
= nSmallestEdgeIndex
+ 1L;
2659 maPathPolygon
.setB2DPolygon(nSmallestPolyIndex
, aCandidate
);
2661 // create old polygon index from it
2662 for(sal_uInt32
a(0L); a
< nSmallestPolyIndex
; a
++)
2664 nNewHdl
+= GetPathPoly().getB2DPolygon(a
).count();
2672 SdrObject
* SdrPathObj::RipPoint(sal_uInt32 nHdlNum
, sal_uInt32
& rNewPt0Index
)
2674 SdrPathObj
* pNewObj
= 0L;
2675 const basegfx::B2DPolyPolygon
aLocalPolyPolygon(GetPathPoly());
2676 sal_uInt32 nPoly
, nPnt
;
2678 if(PolyPolygonEditor::GetRelativePolyPoint(aLocalPolyPolygon
, nHdlNum
, nPoly
, nPnt
))
2682 const basegfx::B2DPolygon
aCandidate(aLocalPolyPolygon
.getB2DPolygon(nPoly
));
2683 const sal_uInt32
nPointCount(aCandidate
.count());
2689 // when closed, RipPoint means to open the polygon at the selected point. To
2690 // be able to do that, it is necessary to make the selected point the first one
2691 basegfx::B2DPolygon
aNewPolygon(basegfx::tools::makeStartPoint(aCandidate
, nPnt
));
2692 SetPathPoly(basegfx::B2DPolyPolygon(aNewPolygon
));
2695 // give back new position of old start point (historical reasons)
2696 rNewPt0Index
= (nPointCount
- nPnt
) % nPointCount
;
2700 if(nPointCount
>= 3L && nPnt
!= 0L && nPnt
+ 1L < nPointCount
)
2702 // split in two objects at point nPnt
2703 basegfx::B2DPolygon
aSplitPolyA(aCandidate
, 0L, nPnt
+ 1L);
2704 SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyA
));
2706 pNewObj
= (SdrPathObj
*)Clone();
2707 basegfx::B2DPolygon
aSplitPolyB(aCandidate
, nPnt
, nPointCount
- nPnt
);
2708 pNewObj
->SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyB
));
2718 SdrObject
* SdrPathObj::DoConvertToPolyObj(sal_Bool bBezier
, bool bAddText
) const
2720 // #i89784# check for FontWork with activated HideContour
2721 const drawinglayer::attribute::SdrTextAttribute
aText(
2722 drawinglayer::primitive2d::createNewSdrTextAttribute(GetObjectItemSet(), *getText(0)));
2723 const bool bHideContour(
2724 !aText
.isDefault() && !aText
.getSdrFormTextAttribute().isDefault() && aText
.isHideContour());
2726 SdrObject
* pRet
= bHideContour
?
2728 ImpConvertMakeObj(GetPathPoly(), IsClosed(), bBezier
);
2730 SdrPathObj
* pPath
= PTR_CAST(SdrPathObj
, pRet
);
2734 if(pPath
->GetPathPoly().areControlPointsUsed())
2738 // reduce all bezier curves
2739 pPath
->SetPathPoly(basegfx::tools::adaptiveSubdivideByAngle(pPath
->GetPathPoly()));
2746 // create bezier curves
2747 pPath
->SetPathPoly(basegfx::tools::expandToCurve(pPath
->GetPathPoly()));
2754 pRet
= ImpConvertAddText(pRet
, bBezier
);
2760 SdrObjGeoData
* SdrPathObj::NewGeoData() const
2762 return new SdrPathObjGeoData
;
2765 void SdrPathObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
2767 SdrTextObj::SaveGeoData(rGeo
);
2768 SdrPathObjGeoData
& rPGeo
= (SdrPathObjGeoData
&) rGeo
;
2769 rPGeo
.maPathPolygon
=GetPathPoly();
2770 rPGeo
.meKind
=meKind
;
2773 void SdrPathObj::RestGeoData(const SdrObjGeoData
& rGeo
)
2775 SdrTextObj::RestGeoData(rGeo
);
2776 SdrPathObjGeoData
& rPGeo
=(SdrPathObjGeoData
&)rGeo
;
2777 maPathPolygon
=rPGeo
.maPathPolygon
;
2778 meKind
=rPGeo
.meKind
;
2779 ImpForceKind(); // to set bClosed (among other things)
2782 void SdrPathObj::NbcSetPathPoly(const basegfx::B2DPolyPolygon
& rPathPoly
)
2784 if(GetPathPoly() != rPathPoly
)
2786 maPathPolygon
=rPathPoly
;
2792 void SdrPathObj::SetPathPoly(const basegfx::B2DPolyPolygon
& rPathPoly
)
2794 if(GetPathPoly() != rPathPoly
)
2796 Rectangle aBoundRect0
; if (pUserCall
!=NULL
) aBoundRect0
=GetLastBoundRect();
2797 NbcSetPathPoly(rPathPoly
);
2799 BroadcastObjectChange();
2800 SendUserCall(SDRUSERCALL_RESIZE
,aBoundRect0
);
2804 void SdrPathObj::ToggleClosed()
2806 Rectangle aBoundRect0
;
2807 if(pUserCall
!= NULL
)
2808 aBoundRect0
= GetLastBoundRect();
2809 ImpSetClosed(!IsClosed()); // set new ObjKind
2810 ImpForceKind(); // because we want Line -> Poly -> PolyLine instead of Line -> Poly -> Line
2813 BroadcastObjectChange();
2814 SendUserCall(SDRUSERCALL_RESIZE
, aBoundRect0
);
2817 // for friend class SdrPolyEditView in some compilers:
2818 void SdrPathObj::SetRectsDirty(sal_Bool bNotMyself
)
2820 SdrTextObj::SetRectsDirty(bNotMyself
);
2823 ImpPathForDragAndCreate
& SdrPathObj::impGetDAC() const
2827 ((SdrPathObj
*)this)->mpDAC
= new ImpPathForDragAndCreate(*((SdrPathObj
*)this));
2833 void SdrPathObj::impDeleteDAC() const
2838 ((SdrPathObj
*)this)->mpDAC
= 0L;
2842 ////////////////////////////////////////////////////////////////////////////////////////////////////
2844 // transformation interface for StarOfficeAPI. This implements support for
2845 // homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
2846 // moment it contains a shearX, rotation and translation, but for setting all linear
2847 // transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
2849 ////////////////////////////////////////////////////////////////////////////////////////////////////
2850 // gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
2851 // with the base geometry and returns TRUE. Otherwise it returns FALSE.
2852 sal_Bool
SdrPathObj::TRGetBaseGeometry(basegfx::B2DHomMatrix
& rMatrix
, basegfx::B2DPolyPolygon
& rPolyPolygon
) const
2854 double fRotate(0.0);
2855 double fShearX(0.0);
2856 basegfx::B2DTuple
aScale(1.0, 1.0);
2857 basegfx::B2DTuple
aTranslate(0.0, 0.0);
2859 if(GetPathPoly().count())
2862 basegfx::B2DHomMatrix aMoveToZeroMatrix
;
2863 rPolyPolygon
= GetPathPoly();
2865 if(OBJ_LINE
== meKind
)
2867 // ignore shear and rotate, just use scale and translate
2868 OSL_ENSURE(GetPathPoly().count() > 0L && GetPathPoly().getB2DPolygon(0L).count() > 1L, "OBJ_LINE with too few polygons (!)");
2869 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
2870 // itself, else this method will no longer return the full polygon information (curve will
2872 const basegfx::B2DRange
aPolyRangeNoCurve(basegfx::tools::getRange(rPolyPolygon
));
2873 aScale
= aPolyRangeNoCurve
.getRange();
2874 aTranslate
= aPolyRangeNoCurve
.getMinimum();
2876 // define matrix for move polygon to zero point
2877 aMoveToZeroMatrix
.translate(-aTranslate
.getX(), -aTranslate
.getY());
2881 if(aGeo
.nShearWink
|| aGeo
.nDrehWink
)
2883 // get rotate and shear in drawingLayer notation
2884 fRotate
= aGeo
.nDrehWink
* F_PI18000
;
2885 fShearX
= aGeo
.nShearWink
* F_PI18000
;
2887 // build mathematically correct (negative shear and rotate) object transform
2888 // containing shear and rotate to extract unsheared, unrotated polygon
2889 basegfx::B2DHomMatrix aObjectMatrix
;
2890 aObjectMatrix
.shearX(tan((36000 - aGeo
.nShearWink
) * F_PI18000
));
2891 aObjectMatrix
.rotate((36000 - aGeo
.nDrehWink
) * F_PI18000
);
2893 // create inverse from it and back-transform polygon
2894 basegfx::B2DHomMatrix
aInvObjectMatrix(aObjectMatrix
);
2895 aInvObjectMatrix
.invert();
2896 rPolyPolygon
.transform(aInvObjectMatrix
);
2898 // get range from unsheared, unrotated polygon and extract scale and translate.
2899 // transform topLeft from it back to transformed state to get original
2900 // topLeft (rotation center)
2901 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
2902 // itself, else this method will no longer return the full polygon information (curve will
2904 const basegfx::B2DRange
aCorrectedRangeNoCurve(basegfx::tools::getRange(rPolyPolygon
));
2905 aTranslate
= aObjectMatrix
* aCorrectedRangeNoCurve
.getMinimum();
2906 aScale
= aCorrectedRangeNoCurve
.getRange();
2908 // define matrix for move polygon to zero point
2909 // #i112280# Added missing minus for Y-Translation
2910 aMoveToZeroMatrix
.translate(-aCorrectedRangeNoCurve
.getMinX(), -aCorrectedRangeNoCurve
.getMinY());
2914 // get scale and translate from unsheared, unrotated polygon
2915 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
2916 // itself, else this method will no longer return the full polygon information (curve will
2918 const basegfx::B2DRange
aPolyRangeNoCurve(basegfx::tools::getRange(rPolyPolygon
));
2919 aScale
= aPolyRangeNoCurve
.getRange();
2920 aTranslate
= aPolyRangeNoCurve
.getMinimum();
2922 // define matrix for move polygon to zero point
2923 aMoveToZeroMatrix
.translate(-aTranslate
.getX(), -aTranslate
.getY());
2927 // move polygon to zero point with pre-defined matrix
2928 rPolyPolygon
.transform(aMoveToZeroMatrix
);
2931 // position maybe relative to anchorpos, convert
2932 if( pModel
&& pModel
->IsWriter() )
2934 if(GetAnchorPos().X() || GetAnchorPos().Y())
2936 aTranslate
-= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
2940 // force MapUnit to 100th mm
2941 const SfxMapUnit
eMapUnit(GetObjectMapUnit());
2942 if(eMapUnit
!= SFX_MAPUNIT_100TH_MM
)
2946 case SFX_MAPUNIT_TWIP
:
2949 aTranslate
.setX(ImplTwipsToMM(aTranslate
.getX()));
2950 aTranslate
.setY(ImplTwipsToMM(aTranslate
.getY()));
2953 aScale
.setX(ImplTwipsToMM(aScale
.getX()));
2954 aScale
.setY(ImplTwipsToMM(aScale
.getY()));
2957 basegfx::B2DHomMatrix aTwipsToMM
;
2958 const double fFactorTwipsToMM(127.0 / 72.0);
2959 aTwipsToMM
.scale(fFactorTwipsToMM
, fFactorTwipsToMM
);
2960 rPolyPolygon
.transform(aTwipsToMM
);
2966 OSL_FAIL("TRGetBaseGeometry: Missing unit translation to 100th mm!");
2971 // build return value matrix
2972 rMatrix
= basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
2974 basegfx::fTools::equalZero(fShearX
) ? 0.0 : tan(fShearX
),
2975 basegfx::fTools::equalZero(fRotate
) ? 0.0 : -fRotate
,
2981 // Sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
2982 // If it's an SdrPathObj it will use the provided geometry information. The Polygon has
2983 // to use (0,0) as upper left and will be scaled to the given size in the matrix.
2984 void SdrPathObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& rPolyPolygon
)
2987 basegfx::B2DTuple aScale
;
2988 basegfx::B2DTuple aTranslate
;
2989 double fRotate
, fShearX
;
2990 rMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
2992 // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
2993 // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
2994 if(basegfx::fTools::less(aScale
.getX(), 0.0) && basegfx::fTools::less(aScale
.getY(), 0.0))
2996 aScale
.setX(fabs(aScale
.getX()));
2997 aScale
.setY(fabs(aScale
.getY()));
2998 fRotate
= fmod(fRotate
+ F_PI
, F_2PI
);
3002 basegfx::B2DPolyPolygon
aNewPolyPolygon(rPolyPolygon
);
3004 // reset object shear and rotations
3006 aGeo
.RecalcSinCos();
3007 aGeo
.nShearWink
= 0;
3010 // force metric to pool metric
3011 const SfxMapUnit
eMapUnit(GetObjectMapUnit());
3012 if(eMapUnit
!= SFX_MAPUNIT_100TH_MM
)
3016 case SFX_MAPUNIT_TWIP
:
3019 aTranslate
.setX(ImplMMToTwips(aTranslate
.getX()));
3020 aTranslate
.setY(ImplMMToTwips(aTranslate
.getY()));
3023 aScale
.setX(ImplMMToTwips(aScale
.getX()));
3024 aScale
.setY(ImplMMToTwips(aScale
.getY()));
3027 basegfx::B2DHomMatrix aMMToTwips
;
3028 const double fFactorMMToTwips(72.0 / 127.0);
3029 aMMToTwips
.scale(fFactorMMToTwips
, fFactorMMToTwips
);
3030 aNewPolyPolygon
.transform(aMMToTwips
);
3036 OSL_FAIL("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
3041 if( pModel
&& pModel
->IsWriter() )
3043 // if anchor is used, make position relative to it
3044 if(GetAnchorPos().X() || GetAnchorPos().Y())
3046 aTranslate
+= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
3050 // create transformation for polygon, set values at aGeo direct
3051 basegfx::B2DHomMatrix aTransform
;
3054 // Given polygon is already scaled (for historical reasons), but not mirrored yet.
3055 // Thus, when scale is negative in X or Y, apply the needed mirroring accordingly.
3056 if(basegfx::fTools::less(aScale
.getX(), 0.0) || basegfx::fTools::less(aScale
.getY(), 0.0))
3059 basegfx::fTools::less(aScale
.getX(), 0.0) ? -1.0 : 1.0,
3060 basegfx::fTools::less(aScale
.getY(), 0.0) ? -1.0 : 1.0);
3063 if(!basegfx::fTools::equalZero(fShearX
))
3065 aTransform
.shearX(tan(-atan(fShearX
)));
3066 aGeo
.nShearWink
= FRound(atan(fShearX
) / F_PI18000
);
3070 if(!basegfx::fTools::equalZero(fRotate
))
3073 // fRotate is mathematically correct for linear transformations, so it's
3074 // the one to use for the geometry change
3075 aTransform
.rotate(fRotate
);
3078 // fRotate is mathematically correct, but aGeoStat.nDrehWink is
3079 // mirrored -> mirror value here
3080 aGeo
.nDrehWink
= NormAngle360(FRound(-fRotate
/ F_PI18000
));
3081 aGeo
.RecalcSinCos();
3084 if(!aTranslate
.equalZero())
3086 // #i39529# absolute positioning, so get current position (without control points (!))
3087 const basegfx::B2DRange
aCurrentRange(basegfx::tools::getRange(aNewPolyPolygon
));
3088 aTransform
.translate(aTranslate
.getX() - aCurrentRange
.getMinX(), aTranslate
.getY() - aCurrentRange
.getMinY());
3091 // transform polygon and trigger change
3092 aNewPolyPolygon
.transform(aTransform
);
3093 SetPathPoly(aNewPolyPolygon
);
3096 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */