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 .
20 #include <basegfx/matrix/b2dhommatrix.hxx>
21 #include <basegfx/matrix/b2dhommatrixtools.hxx>
22 #include <basegfx/point/b2dpoint.hxx>
23 #include <basegfx/polygon/b2dpolygon.hxx>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
25 #include <editeng/eeitem.hxx>
27 #include <svl/style.hxx>
29 #include "svdglob.hxx"
30 #include "svx/svdstr.hrc"
32 #include <sdr/contact/viewcontactofsdrcircobj.hxx>
33 #include <sdr/properties/circleproperties.hxx>
34 #include <svx/svdattr.hxx>
35 #include <svx/svddrag.hxx>
36 #include <svx/svdetc.hxx>
37 #include <svx/svdmodel.hxx>
38 #include <svx/svdocirc.hxx>
39 #include <svx/svdopath.hxx>
40 #include <svx/svdpage.hxx>
41 #include <svx/svdpool.hxx>
42 #include <svx/svdtrans.hxx>
43 #include <svx/svdview.hxx>
44 #include <svx/sxciaitm.hxx>
45 #include <sxcikitm.hxx>
46 #include <svx/xlnedit.hxx>
47 #include <svx/xlnedwit.hxx>
48 #include <svx/xlnstit.hxx>
49 #include <svx/xlnstwit.hxx>
50 #include <svx/xlnwtit.hxx>
51 #include <svx/xpool.hxx>
55 Point
GetWinkPnt(const Rectangle
& rR
, long nWink
)
57 Point
aCenter(rR
.Center());
58 long nWdt
=rR
.Right()-rR
.Left();
59 long nHgt
=rR
.Bottom()-rR
.Top();
60 long nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
63 Point
aRetval(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
64 if (nWdt
==0) aRetval
.X()=0;
65 if (nHgt
==0) aRetval
.Y()=0;
69 // stop possible overruns for very large objects
70 if (std::abs(nHgt
)>32767 || std::abs(aRetval
.Y())>32767) {
71 aRetval
.Y()=BigMulDiv(aRetval
.Y(),nHgt
,nWdt
);
73 aRetval
.Y()=aRetval
.Y()*nHgt
/nWdt
;
78 // stop possible overruns for very large objects
79 if (std::abs(nWdt
)>32767 || std::abs(aRetval
.X())>32767) {
80 aRetval
.X()=BigMulDiv(aRetval
.X(),nWdt
,nHgt
);
82 aRetval
.X()=aRetval
.X()*nWdt
/nHgt
;
92 // BaseProperties section
94 sdr::properties::BaseProperties
* SdrCircObj::CreateObjectSpecificProperties()
96 return new sdr::properties::CircleProperties(*this);
100 // DrawContact section
102 sdr::contact::ViewContact
* SdrCircObj::CreateObjectSpecificViewContact()
104 return new sdr::contact::ViewContactOfSdrCircObj(*this);
109 TYPEINIT1(SdrCircObj
,SdrRectObj
);
111 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
)
115 meCircleKind
=eNewKind
;
116 bClosedObj
=eNewKind
!=OBJ_CARC
;
119 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
, const Rectangle
& rRect
):
124 meCircleKind
=eNewKind
;
125 bClosedObj
=eNewKind
!=OBJ_CARC
;
128 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
, const Rectangle
& rRect
, long nNewStartWink
, long nNewEndWink
):
131 long nWinkDif
=nNewEndWink
-nNewStartWink
;
132 nStartWink
=NormAngle360(nNewStartWink
);
133 nEndWink
=NormAngle360(nNewEndWink
);
134 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // full circle
135 meCircleKind
=eNewKind
;
136 bClosedObj
=eNewKind
!=OBJ_CARC
;
139 SdrCircObj::~SdrCircObj()
143 void SdrCircObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
145 bool bCanConv
=!HasText() || ImpCanConvTextToCurve();
146 rInfo
.bEdgeRadiusAllowed
= false;
147 rInfo
.bCanConvToPath
=bCanConv
;
148 rInfo
.bCanConvToPoly
=bCanConv
;
149 rInfo
.bCanConvToContour
= !IsFontwork() && (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
152 sal_uInt16
SdrCircObj::GetObjIdentifier() const
154 return sal_uInt16(meCircleKind
);
157 bool SdrCircObj::PaintNeedsXPolyCirc() const
159 // XPoly is necessary for all rotated ellipse objects, circle and
161 // If not WIN, then (for now) also for circle/ellipse segments and circle/
162 // ellipse arcs (for precision)
163 bool bNeed
=aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0 || meCircleKind
==OBJ_CCUT
;
164 // If not WIN, then for everything except full circle (for now!)
165 if (meCircleKind
!=OBJ_CIRC
) bNeed
= true;
167 const SfxItemSet
& rSet
= GetObjectItemSet();
170 // XPoly is necessary for everything that isn't LineSolid or LineNone
171 XLineStyle eLine
= ((XLineStyleItem
&)(rSet
.Get(XATTR_LINESTYLE
))).GetValue();
172 bNeed
= eLine
!= XLINE_NONE
&& eLine
!= XLINE_SOLID
;
174 // XPoly is necessary for thick lines
175 if(!bNeed
&& eLine
!= XLINE_NONE
)
176 bNeed
= ((XLineWidthItem
&)(rSet
.Get(XATTR_LINEWIDTH
))).GetValue() != 0;
178 // XPoly is necessary for circle arcs with line ends
179 if(!bNeed
&& meCircleKind
== OBJ_CARC
)
181 // start of the line is here if StartPolygon, StartWidth!=0
182 bNeed
=((XLineStartItem
&)(rSet
.Get(XATTR_LINESTART
))).GetLineStartValue().count() != 0L &&
183 ((XLineStartWidthItem
&)(rSet
.Get(XATTR_LINESTARTWIDTH
))).GetValue() != 0;
187 // end of the line is here if EndPolygon, EndWidth!=0
188 bNeed
= ((XLineEndItem
&)(rSet
.Get(XATTR_LINEEND
))).GetLineEndValue().count() != 0L &&
189 ((XLineEndWidthItem
&)(rSet
.Get(XATTR_LINEENDWIDTH
))).GetValue() != 0;
194 // XPoly is necessary if Fill !=None and !=Solid
195 if(!bNeed
&& meCircleKind
!= OBJ_CARC
)
197 XFillStyle eFill
=((XFillStyleItem
&)(rSet
.Get(XATTR_FILLSTYLE
))).GetValue();
198 bNeed
= eFill
!= XFILL_NONE
&& eFill
!= XFILL_SOLID
;
201 if(!bNeed
&& meCircleKind
!= OBJ_CIRC
&& nStartWink
== nEndWink
)
202 bNeed
= true; // otherwise we're drawing a full circle
207 basegfx::B2DPolygon
SdrCircObj::ImpCalcXPolyCirc(const SdrObjKind eCicrleKind
, const Rectangle
& rRect1
, long nStart
, long nEnd
) const
209 const basegfx::B2DRange
aRange(rRect1
.Left(), rRect1
.Top(), rRect1
.Right(), rRect1
.Bottom());
210 basegfx::B2DPolygon aCircPolygon
;
212 if(OBJ_CIRC
== eCicrleKind
)
214 // create full circle. Do not use createPolygonFromEllipse; it's necessary
215 // to get the start point to the bottom of the circle to keep compatible to
216 // old geometry creation
217 aCircPolygon
= basegfx::tools::createPolygonFromUnitCircle(1);
219 // needs own scaling and translation from unit circle to target size (same as
220 // would be in createPolygonFromEllipse)
221 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
222 const basegfx::B2DHomMatrix
aMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix(
223 aRange
.getWidth() / 2.0, aRange
.getHeight() / 2.0,
224 aCenter
.getX(), aCenter
.getY()));
225 aCircPolygon
.transform(aMatrix
);
229 // mirror start, end for geometry creation since model coordinate system is mirrored in Y
230 // #i111715# increase numerical correctness by first dividing and not using F_PI1800
231 const double fStart((((36000 - nEnd
) % 36000) / 18000.0) * F_PI
);
232 const double fEnd((((36000 - nStart
) % 36000) / 18000.0) * F_PI
);
234 // create circle segment. This is not closed by default
235 aCircPolygon
= basegfx::tools::createPolygonFromEllipseSegment(
236 aRange
.getCenter(), aRange
.getWidth() / 2.0, aRange
.getHeight() / 2.0,
239 // check closing states
240 const bool bCloseSegment(OBJ_CARC
!= eCicrleKind
);
241 const bool bCloseUsingCenter(OBJ_SECT
== eCicrleKind
);
245 if(bCloseUsingCenter
)
247 // add center point at start (for historical reasons)
248 basegfx::B2DPolygon aSector
;
249 aSector
.append(aRange
.getCenter());
250 aSector
.append(aCircPolygon
);
251 aCircPolygon
= aSector
;
255 aCircPolygon
.setClosed(true);
260 if(aGeo
.nShearWink
|| aGeo
.nDrehWink
)
262 // translate top left to (0,0)
263 const basegfx::B2DPoint
aTopLeft(aRange
.getMinimum());
264 basegfx::B2DHomMatrix
aMatrix(basegfx::tools::createTranslateB2DHomMatrix(
265 -aTopLeft
.getX(), -aTopLeft
.getY()));
267 // shear, rotate and back to top left (if needed)
268 aMatrix
= basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
269 aGeo
.nShearWink
? tan((36000 - aGeo
.nShearWink
) * F_PI18000
) : 0.0,
270 aGeo
.nDrehWink
? (36000 - aGeo
.nDrehWink
) * F_PI18000
: 0.0,
273 // apply transformation
274 aCircPolygon
.transform(aMatrix
);
280 void SdrCircObj::RecalcXPoly()
282 const basegfx::B2DPolygon
aPolyCirc(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
283 mpXPoly
= new XPolygon(aPolyCirc
);
286 OUString
SdrCircObj::TakeObjNameSingul() const
288 sal_uInt16 nID
=STR_ObjNameSingulCIRC
;
289 if (aRect
.GetWidth()==aRect
.GetHeight() && aGeo
.nShearWink
==0) {
290 switch (meCircleKind
) {
291 case OBJ_CIRC
: nID
=STR_ObjNameSingulCIRC
; break;
292 case OBJ_SECT
: nID
=STR_ObjNameSingulSECT
; break;
293 case OBJ_CARC
: nID
=STR_ObjNameSingulCARC
; break;
294 case OBJ_CCUT
: nID
=STR_ObjNameSingulCCUT
; break;
298 switch (meCircleKind
) {
299 case OBJ_CIRC
: nID
=STR_ObjNameSingulCIRCE
; break;
300 case OBJ_SECT
: nID
=STR_ObjNameSingulSECTE
; break;
301 case OBJ_CARC
: nID
=STR_ObjNameSingulCARCE
; break;
302 case OBJ_CCUT
: nID
=STR_ObjNameSingulCCUTE
; break;
306 OUStringBuffer
sName(ImpGetResStr(nID
));
308 OUString
aName(GetName());
309 if (!aName
.isEmpty())
316 return sName
.makeStringAndClear();
319 OUString
SdrCircObj::TakeObjNamePlural() const
321 sal_uInt16 nID
=STR_ObjNamePluralCIRC
;
322 if (aRect
.GetWidth()==aRect
.GetHeight() && aGeo
.nShearWink
==0) {
323 switch (meCircleKind
) {
324 case OBJ_CIRC
: nID
=STR_ObjNamePluralCIRC
; break;
325 case OBJ_SECT
: nID
=STR_ObjNamePluralSECT
; break;
326 case OBJ_CARC
: nID
=STR_ObjNamePluralCARC
; break;
327 case OBJ_CCUT
: nID
=STR_ObjNamePluralCCUT
; break;
331 switch (meCircleKind
) {
332 case OBJ_CIRC
: nID
=STR_ObjNamePluralCIRCE
; break;
333 case OBJ_SECT
: nID
=STR_ObjNamePluralSECTE
; break;
334 case OBJ_CARC
: nID
=STR_ObjNamePluralCARCE
; break;
335 case OBJ_CCUT
: nID
=STR_ObjNamePluralCCUTE
; break;
339 return ImpGetResStr(nID
);
342 SdrCircObj
* SdrCircObj::Clone() const
344 return CloneHelper
< SdrCircObj
>();
347 basegfx::B2DPolyPolygon
SdrCircObj::TakeXorPoly() const
349 const basegfx::B2DPolygon
aCircPolygon(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
350 return basegfx::B2DPolyPolygon(aCircPolygon
);
353 struct ImpCircUser
: public SdrDragStatUserData
366 bool bRight
; // not yet implemented
378 void SetCreateParams(SdrDragStat
& rStat
);
381 sal_uInt32
SdrCircObj::GetHdlCount() const
383 if(OBJ_CIRC
!= meCircleKind
)
393 SdrHdl
* SdrCircObj::GetHdl(sal_uInt32 nHdlNum
) const
395 if (meCircleKind
==OBJ_CIRC
)
402 SdrHdlKind
eLocalKind(HDL_MOVE
);
408 aPnt
= GetWinkPnt(aRect
,nStartWink
);
409 eLocalKind
= HDL_CIRC
;
413 aPnt
= GetWinkPnt(aRect
,nEndWink
);
414 eLocalKind
= HDL_CIRC
;
418 aPnt
= aRect
.TopLeft();
419 eLocalKind
= HDL_UPLFT
;
422 aPnt
= aRect
.TopCenter();
423 eLocalKind
= HDL_UPPER
;
426 aPnt
= aRect
.TopRight();
427 eLocalKind
= HDL_UPRGT
;
430 aPnt
= aRect
.LeftCenter();
431 eLocalKind
= HDL_LEFT
;
434 aPnt
= aRect
.RightCenter();
435 eLocalKind
= HDL_RIGHT
;
438 aPnt
= aRect
.BottomLeft();
439 eLocalKind
= HDL_LWLFT
;
442 aPnt
= aRect
.BottomCenter();
443 eLocalKind
= HDL_LOWER
;
446 aPnt
= aRect
.BottomRight();
447 eLocalKind
= HDL_LWRGT
;
453 ShearPoint(aPnt
,aRect
.TopLeft(),aGeo
.nTan
);
458 RotatePoint(aPnt
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
461 if (eLocalKind
!= HDL_MOVE
)
463 pH
= new SdrHdl(aPnt
,eLocalKind
);
464 pH
->SetPointNum(nPNum
);
465 pH
->SetObj((SdrObject
*)this);
466 pH
->SetDrehWink(aGeo
.nDrehWink
);
474 bool SdrCircObj::hasSpecialDrag() const
479 bool SdrCircObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
481 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
485 if(1 == rDrag
.GetHdl()->GetPointNum() || 2 == rDrag
.GetHdl()->GetPointNum())
487 rDrag
.SetNoSnap(true);
493 return SdrTextObj::beginSpecialDrag(rDrag
);
496 bool SdrCircObj::applySpecialDrag(SdrDragStat
& rDrag
)
498 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
502 Point
aPt(rDrag
.GetNow());
504 if (aGeo
.nDrehWink
!=0)
505 RotatePoint(aPt
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
);
507 if (aGeo
.nShearWink
!=0)
508 ShearPoint(aPt
,aRect
.TopLeft(),-aGeo
.nTan
);
512 long nWdt
=aRect
.Right()-aRect
.Left();
513 long nHgt
=aRect
.Bottom()-aRect
.Top();
517 aPt
.Y()=BigMulDiv(aPt
.Y(),nWdt
,nHgt
);
521 aPt
.X()=BigMulDiv(aPt
.X(),nHgt
,nWdt
);
524 long nWink
=NormAngle360(GetAngle(aPt
));
526 if (rDrag
.GetView() && rDrag
.GetView()->IsAngleSnapEnabled())
528 long nSA
=rDrag
.GetView()->GetSnapAngle();
535 nWink
=NormAngle360(nWink
);
539 if(1 == rDrag
.GetHdl()->GetPointNum())
543 else if(2 == rDrag
.GetHdl()->GetPointNum())
550 ImpSetCircInfoToAttr();
557 return SdrTextObj::applySpecialDrag(rDrag
);
561 OUString
SdrCircObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
563 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
568 ImpTakeDescriptionStr(STR_ViewCreateObj
, aStr
);
569 OUStringBuffer
aBuf(aStr
);
570 const sal_uInt32
nPntAnz(rDrag
.GetPointAnz());
572 if(OBJ_CIRC
!= meCircleKind
&& nPntAnz
> 2)
574 ImpCircUser
* pU
= (ImpCircUser
*)rDrag
.GetUser();
577 aBuf
.appendAscii(" (");
588 aBuf
.append(GetWinkStr(nWink
,false));
592 return aBuf
.makeStringAndClear();
596 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
600 const sal_Int32
nWink(1 == rDrag
.GetHdl()->GetPointNum() ? nStartWink
: nEndWink
);
603 ImpTakeDescriptionStr(STR_DragCircAngle
, aStr
);
604 OUStringBuffer
aBuf(aStr
);
605 aBuf
.appendAscii(" (");
606 aBuf
.append(GetWinkStr(nWink
,false));
609 return aBuf
.makeStringAndClear();
613 return SdrTextObj::getSpecialDragComment(rDrag
);
620 void ImpCircUser::SetCreateParams(SdrDragStat
& rStat
)
622 rStat
.TakeCreateRect(aR
);
625 nWdt
=aR
.Right()-aR
.Left();
626 nHgt
=aR
.Bottom()-aR
.Top();
627 nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
630 if (rStat
.GetPointAnz()>2) {
631 Point
aP(rStat
.GetPoint(2)-aCenter
);
632 if (nWdt
==0) aP
.X()=0;
633 if (nHgt
==0) aP
.Y()=0;
635 if (nHgt
!=0) aP
.Y()=aP
.Y()*nWdt
/nHgt
;
637 if (nWdt
!=0) aP
.X()=aP
.X()*nHgt
/nWdt
;
639 nStart
=NormAngle360(GetAngle(aP
));
640 if (rStat
.GetView()!=NULL
&& rStat
.GetView()->IsAngleSnapEnabled()) {
641 long nSA
=rStat
.GetView()->GetSnapAngle();
642 if (nSA
!=0) { // angle snapping
646 nStart
=NormAngle360(nStart
);
649 aP1
= GetWinkPnt(aR
,nStart
);
653 if (rStat
.GetPointAnz()>3) {
654 Point
aP(rStat
.GetPoint(3)-aCenter
);
656 aP
.Y()=BigMulDiv(aP
.Y(),nWdt
,nHgt
);
658 aP
.X()=BigMulDiv(aP
.X(),nHgt
,nWdt
);
660 nEnd
=NormAngle360(GetAngle(aP
));
661 if (rStat
.GetView()!=NULL
&& rStat
.GetView()->IsAngleSnapEnabled()) {
662 long nSA
=rStat
.GetView()->GetSnapAngle();
663 if (nSA
!=0) { // angle snapping
667 nEnd
=NormAngle360(nEnd
);
670 aP2
= GetWinkPnt(aR
,nEnd
);
674 void SdrCircObj::ImpSetCreateParams(SdrDragStat
& rStat
) const
676 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
681 pU
->SetCreateParams(rStat
);
684 bool SdrCircObj::BegCreate(SdrDragStat
& rStat
)
686 rStat
.SetOrtho4Possible();
687 Rectangle
aRect1(rStat
.GetStart(), rStat
.GetNow());
689 rStat
.SetActionRect(aRect1
);
691 ImpSetCreateParams(rStat
);
695 bool SdrCircObj::MovCreate(SdrDragStat
& rStat
)
697 ImpSetCreateParams(rStat
);
698 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
699 rStat
.SetActionRect(pU
->aR
);
700 aRect
=pU
->aR
; // for ObjName
701 ImpJustifyRect(aRect
);
702 nStartWink
=pU
->nStart
;
708 // #i103058# push current angle settings to ItemSet to
709 // allow FullDrag visualisation
710 if(rStat
.GetPointAnz() >= 4)
712 ImpSetCircInfoToAttr();
718 bool SdrCircObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
720 ImpSetCreateParams(rStat
);
721 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
723 if (eCmd
==SDRCREATE_FORCEEND
&& rStat
.GetPointAnz()<4) meCircleKind
=OBJ_CIRC
;
724 if (meCircleKind
==OBJ_CIRC
) {
725 bRet
=rStat
.GetPointAnz()>=2;
728 ImpJustifyRect(aRect
);
731 rStat
.SetNoSnap(rStat
.GetPointAnz()>=2);
732 rStat
.SetOrtho4Possible(rStat
.GetPointAnz()<2);
733 bRet
=rStat
.GetPointAnz()>=4;
736 ImpJustifyRect(aRect
);
737 nStartWink
=pU
->nStart
;
741 bClosedObj
=meCircleKind
!=OBJ_CARC
;
744 ImpSetCircInfoToAttr();
752 void SdrCircObj::BrkCreate(SdrDragStat
& rStat
)
754 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
759 bool SdrCircObj::BckCreate(SdrDragStat
& rStat
)
761 rStat
.SetNoSnap(rStat
.GetPointAnz()>=3);
762 rStat
.SetOrtho4Possible(rStat
.GetPointAnz()<3);
763 return meCircleKind
!=OBJ_CIRC
;
766 basegfx::B2DPolyPolygon
SdrCircObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
768 ImpCircUser
* pU
= (ImpCircUser
*)rDrag
.GetUser();
770 if(rDrag
.GetPointAnz() < 4L)
772 // force to OBJ_CIRC to get full visualisation
773 basegfx::B2DPolyPolygon
aRetval(ImpCalcXPolyCirc(OBJ_CIRC
, pU
->aR
, pU
->nStart
, pU
->nEnd
));
775 if(3L == rDrag
.GetPointAnz())
777 // add edge to first point on ellipse
778 basegfx::B2DPolygon aNew
;
780 aNew
.append(basegfx::B2DPoint(pU
->aCenter
.X(), pU
->aCenter
.Y()));
781 aNew
.append(basegfx::B2DPoint(pU
->aP1
.X(), pU
->aP1
.Y()));
782 aRetval
.append(aNew
);
789 return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind
, pU
->aR
, pU
->nStart
, pU
->nEnd
));
793 Pointer
SdrCircObj::GetCreatePointer() const
795 switch (meCircleKind
) {
796 case OBJ_CIRC
: return Pointer(POINTER_DRAW_ELLIPSE
);
797 case OBJ_SECT
: return Pointer(POINTER_DRAW_PIE
);
798 case OBJ_CARC
: return Pointer(POINTER_DRAW_ARC
);
799 case OBJ_CCUT
: return Pointer(POINTER_DRAW_CIRCLECUT
);
802 return Pointer(POINTER_CROSS
);
805 void SdrCircObj::NbcMove(const Size
& aSiz
)
807 MoveRect(aRect
,aSiz
);
808 MoveRect(aOutRect
,aSiz
);
809 MoveRect(maSnapRect
,aSiz
);
814 void SdrCircObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
816 long nWink0
=aGeo
.nDrehWink
;
817 bool bNoShearRota
=(aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0);
818 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
819 bNoShearRota
|=(aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0);
820 if (meCircleKind
!=OBJ_CIRC
) {
821 bool bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
822 bool bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
823 if (bXMirr
|| bYMirr
) {
824 // At bXMirr!=bYMirr we should actually swap both line ends.
825 // That, however, is pretty bad (because of forced "hard" formatting).
826 // Alternatively, we could implement a bMirrored flag (maybe even
827 // a more general one, e. g. for mirrored text, ...).
831 // the RectObj already mirrors at VMirror because of a 180deg rotation
832 if (! (bXMirr
&& bYMirr
)) {
837 } else { // mirror contorted ellipses
838 if (bXMirr
!=bYMirr
) {
855 long nWinkDif
=nE0
-nS0
;
856 nStartWink
=NormAngle360(nS0
);
857 nEndWink
=NormAngle360(nE0
);
858 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // full circle
862 ImpSetCircInfoToAttr();
865 void SdrCircObj::NbcShear(const Point
& rRef
, long nWink
, double tn
, bool bVShear
)
867 SdrTextObj::NbcShear(rRef
,nWink
,tn
,bVShear
);
869 ImpSetCircInfoToAttr();
872 void SdrCircObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
874 bool bFreeMirr
=meCircleKind
!=OBJ_CIRC
;
877 if (bFreeMirr
) { // some preparations for using an arbitrary axis of reflection
878 Point
aCenter(aRect
.Center());
879 long nWdt
=aRect
.GetWidth()-1;
880 long nHgt
=aRect
.GetHeight()-1;
881 long nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
885 aTmpPt1
=Point(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
886 if (nWdt
==0) aTmpPt1
.X()=0;
887 if (nHgt
==0) aTmpPt1
.Y()=0;
891 aTmpPt2
=Point(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
892 if (nWdt
==0) aTmpPt2
.X()=0;
893 if (nHgt
==0) aTmpPt2
.Y()=0;
895 if (aGeo
.nDrehWink
!=0) {
896 RotatePoint(aTmpPt1
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
897 RotatePoint(aTmpPt2
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
899 if (aGeo
.nShearWink
!=0) {
900 ShearPoint(aTmpPt1
,aRect
.TopLeft(),aGeo
.nTan
);
901 ShearPoint(aTmpPt2
,aRect
.TopLeft(),aGeo
.nTan
);
904 SdrTextObj::NbcMirror(rRef1
,rRef2
);
905 if (meCircleKind
!=OBJ_CIRC
) { // adapt starting and finishing angle
906 MirrorPoint(aTmpPt1
,rRef1
,rRef2
);
907 MirrorPoint(aTmpPt2
,rRef1
,rRef2
);
909 if (aGeo
.nDrehWink
!=0) {
910 RotatePoint(aTmpPt1
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
); // -sin for reversion
911 RotatePoint(aTmpPt2
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
); // -sin for reversion
914 if (aGeo
.nShearWink
!=0) {
915 ShearPoint(aTmpPt1
,aRect
.TopLeft(),-aGeo
.nTan
); // -tan for reversion
916 ShearPoint(aTmpPt2
,aRect
.TopLeft(),-aGeo
.nTan
); // -tan for reversion
918 Point
aCenter(aRect
.Center());
921 // because it's mirrored, the angles are swapped, too
922 nStartWink
=GetAngle(aTmpPt2
);
923 nEndWink
=GetAngle(aTmpPt1
);
924 long nWinkDif
=nEndWink
-nStartWink
;
925 nStartWink
=NormAngle360(nStartWink
);
926 nEndWink
=NormAngle360(nEndWink
);
927 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // full circle
930 ImpSetCircInfoToAttr();
933 SdrObjGeoData
* SdrCircObj::NewGeoData() const
935 return new SdrCircObjGeoData
;
938 void SdrCircObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
940 SdrRectObj::SaveGeoData(rGeo
);
941 SdrCircObjGeoData
& rCGeo
=(SdrCircObjGeoData
&)rGeo
;
942 rCGeo
.nStartWink
=nStartWink
;
943 rCGeo
.nEndWink
=nEndWink
;
946 void SdrCircObj::RestGeoData(const SdrObjGeoData
& rGeo
)
948 SdrRectObj::RestGeoData(rGeo
);
949 SdrCircObjGeoData
& rCGeo
=(SdrCircObjGeoData
&)rGeo
;
950 nStartWink
=rCGeo
.nStartWink
;
951 nEndWink
=rCGeo
.nEndWink
;
953 ImpSetCircInfoToAttr();
956 void Union(Rectangle
& rR
, const Point
& rP
)
958 if (rP
.X()<rR
.Left ()) rR
.Left ()=rP
.X();
959 if (rP
.X()>rR
.Right ()) rR
.Right ()=rP
.X();
960 if (rP
.Y()<rR
.Top ()) rR
.Top ()=rP
.Y();
961 if (rP
.Y()>rR
.Bottom()) rR
.Bottom()=rP
.Y();
964 void SdrCircObj::TakeUnrotatedSnapRect(Rectangle
& rRect
) const
967 if (meCircleKind
!=OBJ_CIRC
) {
968 const Point
aPntStart(GetWinkPnt(aRect
,nStartWink
));
969 const Point
aPntEnd(GetWinkPnt(aRect
,nEndWink
));
972 rRect
.Left ()=aRect
.Right();
973 rRect
.Right ()=aRect
.Left();
974 rRect
.Top ()=aRect
.Bottom();
975 rRect
.Bottom()=aRect
.Top();
976 Union(rRect
,aPntStart
);
977 Union(rRect
,aPntEnd
);
978 if ((a
<=18000 && e
>=18000) || (a
>e
&& (a
<=18000 || e
>=18000))) {
979 Union(rRect
,aRect
.LeftCenter());
981 if ((a
<=27000 && e
>=27000) || (a
>e
&& (a
<=27000 || e
>=27000))) {
982 Union(rRect
,aRect
.BottomCenter());
985 Union(rRect
,aRect
.RightCenter());
987 if ((a
<=9000 && e
>=9000) || (a
>e
&& (a
<=9000 || e
>=9000))) {
988 Union(rRect
,aRect
.TopCenter());
990 if (meCircleKind
==OBJ_SECT
) {
991 Union(rRect
,aRect
.Center());
993 if (aGeo
.nDrehWink
!=0) {
994 Point
aDst(rRect
.TopLeft());
995 aDst
-=aRect
.TopLeft();
997 RotatePoint(aDst
,Point(),aGeo
.nSin
,aGeo
.nCos
);
999 rRect
.Move(aDst
.X(),aDst
.Y());
1002 if (aGeo
.nShearWink
!=0) {
1003 long nDst
=Round((rRect
.Bottom()-rRect
.Top())*aGeo
.nTan
);
1004 if (aGeo
.nShearWink
>0) {
1005 Point
aRef(rRect
.TopLeft());
1007 Point
aTmpPt(rRect
.TopLeft());
1008 RotatePoint(aTmpPt
,aRef
,aGeo
.nSin
,aGeo
.nCos
);
1009 aTmpPt
-=rRect
.TopLeft();
1010 rRect
.Move(aTmpPt
.X(),aTmpPt
.Y());
1012 rRect
.Right()-=nDst
;
1017 void SdrCircObj::RecalcSnapRect()
1019 if (PaintNeedsXPolyCirc()) {
1020 maSnapRect
=GetXPoly().GetBoundRect();
1022 TakeUnrotatedSnapRect(maSnapRect
);
1026 void SdrCircObj::NbcSetSnapRect(const Rectangle
& rRect
)
1028 if (aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0 || meCircleKind
!=OBJ_CIRC
) {
1029 Rectangle
aSR0(GetSnapRect());
1030 long nWdt0
=aSR0
.Right()-aSR0
.Left();
1031 long nHgt0
=aSR0
.Bottom()-aSR0
.Top();
1032 long nWdt1
=rRect
.Right()-rRect
.Left();
1033 long nHgt1
=rRect
.Bottom()-rRect
.Top();
1034 NbcResize(maSnapRect
.TopLeft(),Fraction(nWdt1
,nWdt0
),Fraction(nHgt1
,nHgt0
));
1035 NbcMove(Size(rRect
.Left()-aSR0
.Left(),rRect
.Top()-aSR0
.Top()));
1038 ImpJustifyRect(aRect
);
1042 ImpSetCircInfoToAttr();
1045 sal_uInt32
SdrCircObj::GetSnapPointCount() const
1047 if (meCircleKind
==OBJ_CIRC
) {
1054 Point
SdrCircObj::GetSnapPoint(sal_uInt32 i
) const
1057 case 1 : return GetWinkPnt(aRect
,nStartWink
);
1058 case 2 : return GetWinkPnt(aRect
,nEndWink
);
1059 default: return aRect
.Center();
1063 void SdrCircObj::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
1066 SdrRectObj::Notify(rBC
,rHint
);
1067 ImpSetAttrToCircInfo();
1072 void SdrCircObj::ImpSetAttrToCircInfo()
1074 const SfxItemSet
& rSet
= GetObjectItemSet();
1075 SdrCircKind eNewKindA
= ((SdrCircKindItem
&)rSet
.Get(SDRATTR_CIRCKIND
)).GetValue();
1076 SdrObjKind eNewKind
= meCircleKind
;
1078 if(eNewKindA
== SDRCIRC_FULL
)
1079 eNewKind
= OBJ_CIRC
;
1080 else if(eNewKindA
== SDRCIRC_SECT
)
1081 eNewKind
= OBJ_SECT
;
1082 else if(eNewKindA
== SDRCIRC_ARC
)
1083 eNewKind
= OBJ_CARC
;
1084 else if(eNewKindA
== SDRCIRC_CUT
)
1085 eNewKind
= OBJ_CCUT
;
1087 sal_Int32 nNewStart
= ((SdrCircStartAngleItem
&)rSet
.Get(SDRATTR_CIRCSTARTANGLE
)).GetValue();
1088 sal_Int32 nNewEnd
= ((SdrCircEndAngleItem
&)rSet
.Get(SDRATTR_CIRCENDANGLE
)).GetValue();
1090 bool bKindChg
= meCircleKind
!= eNewKind
;
1091 bool bWinkChg
= nNewStart
!= nStartWink
|| nNewEnd
!= nEndWink
;
1093 if(bKindChg
|| bWinkChg
)
1095 meCircleKind
= eNewKind
;
1096 nStartWink
= nNewStart
;
1099 if(bKindChg
|| (meCircleKind
!= OBJ_CIRC
&& bWinkChg
))
1107 void SdrCircObj::ImpSetCircInfoToAttr()
1109 SdrCircKind eNewKindA
= SDRCIRC_FULL
;
1110 const SfxItemSet
& rSet
= GetObjectItemSet();
1112 if(meCircleKind
== OBJ_SECT
)
1113 eNewKindA
= SDRCIRC_SECT
;
1114 else if(meCircleKind
== OBJ_CARC
)
1115 eNewKindA
= SDRCIRC_ARC
;
1116 else if(meCircleKind
== OBJ_CCUT
)
1117 eNewKindA
= SDRCIRC_CUT
;
1119 SdrCircKind eOldKindA
= ((SdrCircKindItem
&)rSet
.Get(SDRATTR_CIRCKIND
)).GetValue();
1120 sal_Int32 nOldStartWink
= ((SdrCircStartAngleItem
&)rSet
.Get(SDRATTR_CIRCSTARTANGLE
)).GetValue();
1121 sal_Int32 nOldEndWink
= ((SdrCircEndAngleItem
&)rSet
.Get(SDRATTR_CIRCENDANGLE
)).GetValue();
1123 if(eNewKindA
!= eOldKindA
|| nStartWink
!= nOldStartWink
|| nEndWink
!= nOldEndWink
)
1125 // since SetItem() implicitly calls ImpSetAttrToCircInfo()
1126 // setting the item directly is necessary here.
1127 if(eNewKindA
!= eOldKindA
)
1129 GetProperties().SetObjectItemDirect(SdrCircKindItem(eNewKindA
));
1132 if(nStartWink
!= nOldStartWink
)
1134 GetProperties().SetObjectItemDirect(SdrCircStartAngleItem(nStartWink
));
1137 if(nEndWink
!= nOldEndWink
)
1139 GetProperties().SetObjectItemDirect(SdrCircEndAngleItem(nEndWink
));
1143 ImpSetAttrToCircInfo();
1147 SdrObject
* SdrCircObj::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
1149 const bool bFill(OBJ_CARC
== meCircleKind
? sal_False
: sal_True
);
1150 const basegfx::B2DPolygon
aCircPolygon(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
1151 SdrObject
* pRet
= ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon
), bFill
, bBezier
);
1155 pRet
= ImpConvertAddText(pRet
, bBezier
);
1161 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */