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 <svl/style.hxx>
21 #include <svx/xlnwtit.hxx>
22 #include <svx/xlnedwit.hxx>
23 #include <svx/xlnstwit.hxx>
24 #include <svx/xlnstit.hxx>
25 #include <svx/xlnedit.hxx>
26 #include <svx/svdocirc.hxx>
28 #include <svx/xpool.hxx>
29 #include <svx/svdattr.hxx>
30 #include <svx/svdpool.hxx>
31 #include <svx/svdattrx.hxx>
32 #include <svx/svdtrans.hxx>
33 #include <svx/svdetc.hxx>
34 #include <svx/svddrag.hxx>
35 #include <svx/svdmodel.hxx>
36 #include <svx/svdpage.hxx>
37 #include <svx/svdopath.hxx> // for the object conversion
38 #include <svx/svdview.hxx> // for dragging (Ortho)
39 #include "svx/svdglob.hxx" // StringCache
40 #include "svx/svdstr.hrc" // the object's name
41 #include <editeng/eeitem.hxx>
42 #include <svx/sdr/properties/circleproperties.hxx>
43 #include <svx/sdr/contact/viewcontactofsdrcircobj.hxx>
44 #include <basegfx/point/b2dpoint.hxx>
45 #include <basegfx/polygon/b2dpolygon.hxx>
46 #include <basegfx/polygon/b2dpolygontools.hxx>
47 #include <basegfx/matrix/b2dhommatrix.hxx>
48 #include <basegfx/matrix/b2dhommatrixtools.hxx>
50 //////////////////////////////////////////////////////////////////////////////
52 Point
GetWinkPnt(const Rectangle
& rR
, long nWink
)
54 Point
aCenter(rR
.Center());
55 long nWdt
=rR
.Right()-rR
.Left();
56 long nHgt
=rR
.Bottom()-rR
.Top();
57 long nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
60 Point
aRetval(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
61 if (nWdt
==0) aRetval
.X()=0;
62 if (nHgt
==0) aRetval
.Y()=0;
66 // stop possible overruns for very large objects
67 if (std::abs(nHgt
)>32767 || std::abs(aRetval
.Y())>32767) {
68 aRetval
.Y()=BigMulDiv(aRetval
.Y(),nHgt
,nWdt
);
70 aRetval
.Y()=aRetval
.Y()*nHgt
/nWdt
;
75 // stop possible overruns for very large objects
76 if (std::abs(nWdt
)>32767 || std::abs(aRetval
.X())>32767) {
77 aRetval
.X()=BigMulDiv(aRetval
.X(),nWdt
,nHgt
);
79 aRetval
.X()=aRetval
.X()*nWdt
/nHgt
;
88 //////////////////////////////////////////////////////////////////////////////
89 // BaseProperties section
91 sdr::properties::BaseProperties
* SdrCircObj::CreateObjectSpecificProperties()
93 return new sdr::properties::CircleProperties(*this);
96 //////////////////////////////////////////////////////////////////////////////
97 // DrawContact section
99 sdr::contact::ViewContact
* SdrCircObj::CreateObjectSpecificViewContact()
101 return new sdr::contact::ViewContactOfSdrCircObj(*this);
104 //////////////////////////////////////////////////////////////////////////////
106 TYPEINIT1(SdrCircObj
,SdrRectObj
);
108 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
)
112 meCircleKind
=eNewKind
;
113 bClosedObj
=eNewKind
!=OBJ_CARC
;
116 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
, const Rectangle
& rRect
):
121 meCircleKind
=eNewKind
;
122 bClosedObj
=eNewKind
!=OBJ_CARC
;
125 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
, const Rectangle
& rRect
, long nNewStartWink
, long nNewEndWink
):
128 long nWinkDif
=nNewEndWink
-nNewStartWink
;
129 nStartWink
=NormAngle360(nNewStartWink
);
130 nEndWink
=NormAngle360(nNewEndWink
);
131 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // full circle
132 meCircleKind
=eNewKind
;
133 bClosedObj
=eNewKind
!=OBJ_CARC
;
136 SdrCircObj::~SdrCircObj()
140 void SdrCircObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
142 bool bCanConv
=!HasText() || ImpCanConvTextToCurve();
143 rInfo
.bEdgeRadiusAllowed
= sal_False
;
144 rInfo
.bCanConvToPath
=bCanConv
;
145 rInfo
.bCanConvToPoly
=bCanConv
;
146 rInfo
.bCanConvToContour
= !IsFontwork() && (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
149 sal_uInt16
SdrCircObj::GetObjIdentifier() const
151 return sal_uInt16(meCircleKind
);
154 bool SdrCircObj::PaintNeedsXPolyCirc() const
156 // XPoly is necessary for all rotated ellipse objects, circle and
158 // If not WIN, then (for now) also for circle/ellipse segments and circle/
159 // ellipse arcs (for precision)
160 bool bNeed
=aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0 || meCircleKind
==OBJ_CCUT
;
161 // If not WIN, then for everything except full circle (for now!)
162 if (meCircleKind
!=OBJ_CIRC
) bNeed
= true;
164 const SfxItemSet
& rSet
= GetObjectItemSet();
167 // XPoly is necessary for everything that isn't LineSolid or LineNone
168 XLineStyle eLine
= ((XLineStyleItem
&)(rSet
.Get(XATTR_LINESTYLE
))).GetValue();
169 bNeed
= eLine
!= XLINE_NONE
&& eLine
!= XLINE_SOLID
;
171 // XPoly is necessary for thick lines
172 if(!bNeed
&& eLine
!= XLINE_NONE
)
173 bNeed
= ((XLineWidthItem
&)(rSet
.Get(XATTR_LINEWIDTH
))).GetValue() != 0;
175 // XPoly is necessary for circle arcs with line ends
176 if(!bNeed
&& meCircleKind
== OBJ_CARC
)
178 // start of the line is here if StartPolygon, StartWidth!=0
179 bNeed
=((XLineStartItem
&)(rSet
.Get(XATTR_LINESTART
))).GetLineStartValue().count() != 0L &&
180 ((XLineStartWidthItem
&)(rSet
.Get(XATTR_LINESTARTWIDTH
))).GetValue() != 0;
184 // end of the line is here if EndPolygon, EndWidth!=0
185 bNeed
= ((XLineEndItem
&)(rSet
.Get(XATTR_LINEEND
))).GetLineEndValue().count() != 0L &&
186 ((XLineEndWidthItem
&)(rSet
.Get(XATTR_LINEENDWIDTH
))).GetValue() != 0;
191 // XPoly is necessary if Fill !=None and !=Solid
192 if(!bNeed
&& meCircleKind
!= OBJ_CARC
)
194 XFillStyle eFill
=((XFillStyleItem
&)(rSet
.Get(XATTR_FILLSTYLE
))).GetValue();
195 bNeed
= eFill
!= XFILL_NONE
&& eFill
!= XFILL_SOLID
;
198 if(!bNeed
&& meCircleKind
!= OBJ_CIRC
&& nStartWink
== nEndWink
)
199 bNeed
= true; // otherwise we're drawing a full circle
204 basegfx::B2DPolygon
SdrCircObj::ImpCalcXPolyCirc(const SdrObjKind eCicrleKind
, const Rectangle
& rRect1
, long nStart
, long nEnd
) const
206 const basegfx::B2DRange
aRange(rRect1
.Left(), rRect1
.Top(), rRect1
.Right(), rRect1
.Bottom());
207 basegfx::B2DPolygon aCircPolygon
;
209 if(OBJ_CIRC
== eCicrleKind
)
211 // create full circle. Do not use createPolygonFromEllipse; it's necessary
212 // to get the start point to the bottom of the circle to keep compatible to
213 // old geometry creation
214 aCircPolygon
= basegfx::tools::createPolygonFromUnitCircle(1);
216 // needs own scaling and translation from unit circle to target size (same as
217 // would be in createPolygonFromEllipse)
218 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
219 const basegfx::B2DHomMatrix
aMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix(
220 aRange
.getWidth() / 2.0, aRange
.getHeight() / 2.0,
221 aCenter
.getX(), aCenter
.getY()));
222 aCircPolygon
.transform(aMatrix
);
226 // mirror start, end for geometry creation since model coordinate system is mirrored in Y
227 // #i111715# increase numerical correctness by first dividing and not using F_PI1800
228 const double fStart((((36000 - nEnd
) % 36000) / 18000.0) * F_PI
);
229 const double fEnd((((36000 - nStart
) % 36000) / 18000.0) * F_PI
);
231 // create circle segment. This is not closed by default
232 aCircPolygon
= basegfx::tools::createPolygonFromEllipseSegment(
233 aRange
.getCenter(), aRange
.getWidth() / 2.0, aRange
.getHeight() / 2.0,
236 // check closing states
237 const bool bCloseSegment(OBJ_CARC
!= eCicrleKind
);
238 const bool bCloseUsingCenter(OBJ_SECT
== eCicrleKind
);
242 if(bCloseUsingCenter
)
244 // add center point at start (for historical reasons)
245 basegfx::B2DPolygon aSector
;
246 aSector
.append(aRange
.getCenter());
247 aSector
.append(aCircPolygon
);
248 aCircPolygon
= aSector
;
252 aCircPolygon
.setClosed(true);
257 if(aGeo
.nShearWink
|| aGeo
.nDrehWink
)
259 // translate top left to (0,0)
260 const basegfx::B2DPoint
aTopLeft(aRange
.getMinimum());
261 basegfx::B2DHomMatrix
aMatrix(basegfx::tools::createTranslateB2DHomMatrix(
262 -aTopLeft
.getX(), -aTopLeft
.getY()));
264 // shear, rotate and back to top left (if needed)
265 aMatrix
= basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
266 aGeo
.nShearWink
? tan((36000 - aGeo
.nShearWink
) * F_PI18000
) : 0.0,
267 aGeo
.nDrehWink
? (36000 - aGeo
.nDrehWink
) * F_PI18000
: 0.0,
270 // apply transformation
271 aCircPolygon
.transform(aMatrix
);
277 void SdrCircObj::RecalcXPoly()
279 const basegfx::B2DPolygon
aPolyCirc(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
280 mpXPoly
= new XPolygon(aPolyCirc
);
283 void SdrCircObj::TakeObjNameSingul(XubString
& rName
) const
285 sal_uInt16 nID
=STR_ObjNameSingulCIRC
;
286 if (aRect
.GetWidth()==aRect
.GetHeight() && aGeo
.nShearWink
==0) {
287 switch (meCircleKind
) {
288 case OBJ_CIRC
: nID
=STR_ObjNameSingulCIRC
; break;
289 case OBJ_SECT
: nID
=STR_ObjNameSingulSECT
; break;
290 case OBJ_CARC
: nID
=STR_ObjNameSingulCARC
; break;
291 case OBJ_CCUT
: nID
=STR_ObjNameSingulCCUT
; break;
295 switch (meCircleKind
) {
296 case OBJ_CIRC
: nID
=STR_ObjNameSingulCIRCE
; break;
297 case OBJ_SECT
: nID
=STR_ObjNameSingulSECTE
; break;
298 case OBJ_CARC
: nID
=STR_ObjNameSingulCARCE
; break;
299 case OBJ_CCUT
: nID
=STR_ObjNameSingulCCUTE
; break;
303 rName
=ImpGetResStr(nID
);
305 String
aName( GetName() );
308 rName
+= sal_Unicode(' ');
309 rName
+= sal_Unicode('\'');
311 rName
+= sal_Unicode('\'');
315 void SdrCircObj::TakeObjNamePlural(XubString
& rName
) const
317 sal_uInt16 nID
=STR_ObjNamePluralCIRC
;
318 if (aRect
.GetWidth()==aRect
.GetHeight() && aGeo
.nShearWink
==0) {
319 switch (meCircleKind
) {
320 case OBJ_CIRC
: nID
=STR_ObjNamePluralCIRC
; break;
321 case OBJ_SECT
: nID
=STR_ObjNamePluralSECT
; break;
322 case OBJ_CARC
: nID
=STR_ObjNamePluralCARC
; break;
323 case OBJ_CCUT
: nID
=STR_ObjNamePluralCCUT
; break;
327 switch (meCircleKind
) {
328 case OBJ_CIRC
: nID
=STR_ObjNamePluralCIRCE
; break;
329 case OBJ_SECT
: nID
=STR_ObjNamePluralSECTE
; break;
330 case OBJ_CARC
: nID
=STR_ObjNamePluralCARCE
; break;
331 case OBJ_CCUT
: nID
=STR_ObjNamePluralCCUTE
; break;
335 rName
=ImpGetResStr(nID
);
338 SdrCircObj
* SdrCircObj::Clone() const
340 return CloneHelper
< SdrCircObj
>();
343 basegfx::B2DPolyPolygon
SdrCircObj::TakeXorPoly() const
345 const basegfx::B2DPolygon
aCircPolygon(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
346 return basegfx::B2DPolyPolygon(aCircPolygon
);
349 struct ImpCircUser
: public SdrDragStatUserData
362 bool bRight
; // not yet implemented
374 void SetCreateParams(SdrDragStat
& rStat
);
377 sal_uInt32
SdrCircObj::GetHdlCount() const
379 if(OBJ_CIRC
!= meCircleKind
)
389 SdrHdl
* SdrCircObj::GetHdl(sal_uInt32 nHdlNum
) const
391 if (meCircleKind
==OBJ_CIRC
)
398 SdrHdlKind
eLocalKind(HDL_MOVE
);
404 aPnt
= GetWinkPnt(aRect
,nStartWink
);
405 eLocalKind
= HDL_CIRC
;
409 aPnt
= GetWinkPnt(aRect
,nEndWink
);
410 eLocalKind
= HDL_CIRC
;
414 aPnt
= aRect
.TopLeft();
415 eLocalKind
= HDL_UPLFT
;
418 aPnt
= aRect
.TopCenter();
419 eLocalKind
= HDL_UPPER
;
422 aPnt
= aRect
.TopRight();
423 eLocalKind
= HDL_UPRGT
;
426 aPnt
= aRect
.LeftCenter();
427 eLocalKind
= HDL_LEFT
;
430 aPnt
= aRect
.RightCenter();
431 eLocalKind
= HDL_RIGHT
;
434 aPnt
= aRect
.BottomLeft();
435 eLocalKind
= HDL_LWLFT
;
438 aPnt
= aRect
.BottomCenter();
439 eLocalKind
= HDL_LOWER
;
442 aPnt
= aRect
.BottomRight();
443 eLocalKind
= HDL_LWRGT
;
449 ShearPoint(aPnt
,aRect
.TopLeft(),aGeo
.nTan
);
454 RotatePoint(aPnt
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
457 if (eLocalKind
!= HDL_MOVE
)
459 pH
= new SdrHdl(aPnt
,eLocalKind
);
460 pH
->SetPointNum(nPNum
);
461 pH
->SetObj((SdrObject
*)this);
462 pH
->SetDrehWink(aGeo
.nDrehWink
);
468 ////////////////////////////////////////////////////////////////////////////////////////////////////
470 bool SdrCircObj::hasSpecialDrag() const
475 bool SdrCircObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
477 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
481 if(1 == rDrag
.GetHdl()->GetPointNum() || 2 == rDrag
.GetHdl()->GetPointNum())
483 rDrag
.SetNoSnap(true);
489 return SdrTextObj::beginSpecialDrag(rDrag
);
492 bool SdrCircObj::applySpecialDrag(SdrDragStat
& rDrag
)
494 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
498 Point
aPt(rDrag
.GetNow());
500 if (aGeo
.nDrehWink
!=0)
501 RotatePoint(aPt
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
);
503 if (aGeo
.nShearWink
!=0)
504 ShearPoint(aPt
,aRect
.TopLeft(),-aGeo
.nTan
);
508 long nWdt
=aRect
.Right()-aRect
.Left();
509 long nHgt
=aRect
.Bottom()-aRect
.Top();
513 aPt
.Y()=BigMulDiv(aPt
.Y(),nWdt
,nHgt
);
517 aPt
.X()=BigMulDiv(aPt
.X(),nHgt
,nWdt
);
520 long nWink
=NormAngle360(GetAngle(aPt
));
522 if (rDrag
.GetView() && rDrag
.GetView()->IsAngleSnapEnabled())
524 long nSA
=rDrag
.GetView()->GetSnapAngle();
531 nWink
=NormAngle360(nWink
);
535 if(1 == rDrag
.GetHdl()->GetPointNum())
539 else if(2 == rDrag
.GetHdl()->GetPointNum())
546 ImpSetCircInfoToAttr();
553 return SdrTextObj::applySpecialDrag(rDrag
);
557 String
SdrCircObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
559 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
564 ImpTakeDescriptionStr(STR_ViewCreateObj
, aStr
);
565 OUStringBuffer
aBuf(aStr
);
566 const sal_uInt32
nPntAnz(rDrag
.GetPointAnz());
568 if(OBJ_CIRC
!= meCircleKind
&& nPntAnz
> 2)
570 ImpCircUser
* pU
= (ImpCircUser
*)rDrag
.GetUser();
573 aBuf
.appendAscii(" (");
584 aBuf
.append(GetWinkStr(nWink
,false));
585 aBuf
.append(sal_Unicode(')'));
588 return aBuf
.makeStringAndClear();
592 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
596 const sal_Int32
nWink(1 == rDrag
.GetHdl()->GetPointNum() ? nStartWink
: nEndWink
);
599 ImpTakeDescriptionStr(STR_DragCircAngle
, aStr
);
600 OUStringBuffer
aBuf(aStr
);
601 aBuf
.appendAscii(" (");
602 aBuf
.append(GetWinkStr(nWink
,false));
603 aBuf
.append(sal_Unicode(')'));
605 return aBuf
.makeStringAndClear();
609 return SdrTextObj::getSpecialDragComment(rDrag
);
614 ////////////////////////////////////////////////////////////////////////////////////////////////////
616 void ImpCircUser::SetCreateParams(SdrDragStat
& rStat
)
618 rStat
.TakeCreateRect(aR
);
621 nWdt
=aR
.Right()-aR
.Left();
622 nHgt
=aR
.Bottom()-aR
.Top();
623 nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
626 if (rStat
.GetPointAnz()>2) {
627 Point
aP(rStat
.GetPoint(2)-aCenter
);
628 if (nWdt
==0) aP
.X()=0;
629 if (nHgt
==0) aP
.Y()=0;
631 if (nHgt
!=0) aP
.Y()=aP
.Y()*nWdt
/nHgt
;
633 if (nWdt
!=0) aP
.X()=aP
.X()*nHgt
/nWdt
;
635 nStart
=NormAngle360(GetAngle(aP
));
636 if (rStat
.GetView()!=NULL
&& rStat
.GetView()->IsAngleSnapEnabled()) {
637 long nSA
=rStat
.GetView()->GetSnapAngle();
638 if (nSA
!=0) { // angle snapping
642 nStart
=NormAngle360(nStart
);
645 aP1
= GetWinkPnt(aR
,nStart
);
649 if (rStat
.GetPointAnz()>3) {
650 Point
aP(rStat
.GetPoint(3)-aCenter
);
652 aP
.Y()=BigMulDiv(aP
.Y(),nWdt
,nHgt
);
654 aP
.X()=BigMulDiv(aP
.X(),nHgt
,nWdt
);
656 nEnd
=NormAngle360(GetAngle(aP
));
657 if (rStat
.GetView()!=NULL
&& rStat
.GetView()->IsAngleSnapEnabled()) {
658 long nSA
=rStat
.GetView()->GetSnapAngle();
659 if (nSA
!=0) { // angle snapping
663 nEnd
=NormAngle360(nEnd
);
666 aP2
= GetWinkPnt(aR
,nEnd
);
670 void SdrCircObj::ImpSetCreateParams(SdrDragStat
& rStat
) const
672 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
677 pU
->SetCreateParams(rStat
);
680 bool SdrCircObj::BegCreate(SdrDragStat
& rStat
)
682 rStat
.SetOrtho4Possible();
683 Rectangle
aRect1(rStat
.GetStart(), rStat
.GetNow());
685 rStat
.SetActionRect(aRect1
);
687 ImpSetCreateParams(rStat
);
691 bool SdrCircObj::MovCreate(SdrDragStat
& rStat
)
693 ImpSetCreateParams(rStat
);
694 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
695 rStat
.SetActionRect(pU
->aR
);
696 aRect
=pU
->aR
; // for ObjName
697 ImpJustifyRect(aRect
);
698 nStartWink
=pU
->nStart
;
701 bSnapRectDirty
=sal_True
;
704 // #i103058# push current angle settings to ItemSet to
705 // allow FullDrag visualisation
706 if(rStat
.GetPointAnz() >= 4)
708 ImpSetCircInfoToAttr();
714 bool SdrCircObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
716 ImpSetCreateParams(rStat
);
717 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
719 if (eCmd
==SDRCREATE_FORCEEND
&& rStat
.GetPointAnz()<4) meCircleKind
=OBJ_CIRC
;
720 if (meCircleKind
==OBJ_CIRC
) {
721 bRet
=rStat
.GetPointAnz()>=2;
724 ImpJustifyRect(aRect
);
727 rStat
.SetNoSnap(rStat
.GetPointAnz()>=2);
728 rStat
.SetOrtho4Possible(rStat
.GetPointAnz()<2);
729 bRet
=rStat
.GetPointAnz()>=4;
732 ImpJustifyRect(aRect
);
733 nStartWink
=pU
->nStart
;
737 bClosedObj
=meCircleKind
!=OBJ_CARC
;
740 ImpSetCircInfoToAttr();
748 void SdrCircObj::BrkCreate(SdrDragStat
& rStat
)
750 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
755 bool SdrCircObj::BckCreate(SdrDragStat
& rStat
)
757 rStat
.SetNoSnap(rStat
.GetPointAnz()>=3);
758 rStat
.SetOrtho4Possible(rStat
.GetPointAnz()<3);
759 return meCircleKind
!=OBJ_CIRC
;
762 basegfx::B2DPolyPolygon
SdrCircObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
764 ImpCircUser
* pU
= (ImpCircUser
*)rDrag
.GetUser();
766 if(rDrag
.GetPointAnz() < 4L)
768 // force to OBJ_CIRC to get full visualisation
769 basegfx::B2DPolyPolygon
aRetval(ImpCalcXPolyCirc(OBJ_CIRC
, pU
->aR
, pU
->nStart
, pU
->nEnd
));
771 if(3L == rDrag
.GetPointAnz())
773 // add edge to first point on ellipse
774 basegfx::B2DPolygon aNew
;
776 aNew
.append(basegfx::B2DPoint(pU
->aCenter
.X(), pU
->aCenter
.Y()));
777 aNew
.append(basegfx::B2DPoint(pU
->aP1
.X(), pU
->aP1
.Y()));
778 aRetval
.append(aNew
);
785 return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind
, pU
->aR
, pU
->nStart
, pU
->nEnd
));
789 Pointer
SdrCircObj::GetCreatePointer() const
791 switch (meCircleKind
) {
792 case OBJ_CIRC
: return Pointer(POINTER_DRAW_ELLIPSE
);
793 case OBJ_SECT
: return Pointer(POINTER_DRAW_PIE
);
794 case OBJ_CARC
: return Pointer(POINTER_DRAW_ARC
);
795 case OBJ_CCUT
: return Pointer(POINTER_DRAW_CIRCLECUT
);
798 return Pointer(POINTER_CROSS
);
801 void SdrCircObj::NbcMove(const Size
& aSiz
)
803 MoveRect(aRect
,aSiz
);
804 MoveRect(aOutRect
,aSiz
);
805 MoveRect(maSnapRect
,aSiz
);
807 SetRectsDirty(sal_True
);
810 void SdrCircObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
812 long nWink0
=aGeo
.nDrehWink
;
813 bool bNoShearRota
=(aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0);
814 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
815 bNoShearRota
|=(aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0);
816 if (meCircleKind
!=OBJ_CIRC
) {
817 bool bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
818 bool bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
819 if (bXMirr
|| bYMirr
) {
820 // At bXMirr!=bYMirr we should actually swap both line ends.
821 // That, however, is pretty bad (because of forced "hard" formatting).
822 // Alternatively, we could implement a bMirrored flag (maybe even
823 // a more general one, e. g. for mirrored text, ...).
827 // the RectObj already mirrors at VMirror because of a 180deg rotation
828 if (! (bXMirr
&& bYMirr
)) {
833 } else { // mirror contorted ellipses
834 if (bXMirr
!=bYMirr
) {
851 long nWinkDif
=nE0
-nS0
;
852 nStartWink
=NormAngle360(nS0
);
853 nEndWink
=NormAngle360(nE0
);
854 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // full circle
858 ImpSetCircInfoToAttr();
861 void SdrCircObj::NbcShear(const Point
& rRef
, long nWink
, double tn
, bool bVShear
)
863 SdrTextObj::NbcShear(rRef
,nWink
,tn
,bVShear
);
865 ImpSetCircInfoToAttr();
868 void SdrCircObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
870 bool bFreeMirr
=meCircleKind
!=OBJ_CIRC
;
873 if (bFreeMirr
) { // some preparations for using an arbitrary axis of reflection
874 Point
aCenter(aRect
.Center());
875 long nWdt
=aRect
.GetWidth()-1;
876 long nHgt
=aRect
.GetHeight()-1;
877 long nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
881 aTmpPt1
=Point(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
882 if (nWdt
==0) aTmpPt1
.X()=0;
883 if (nHgt
==0) aTmpPt1
.Y()=0;
887 aTmpPt2
=Point(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
888 if (nWdt
==0) aTmpPt2
.X()=0;
889 if (nHgt
==0) aTmpPt2
.Y()=0;
891 if (aGeo
.nDrehWink
!=0) {
892 RotatePoint(aTmpPt1
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
893 RotatePoint(aTmpPt2
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
895 if (aGeo
.nShearWink
!=0) {
896 ShearPoint(aTmpPt1
,aRect
.TopLeft(),aGeo
.nTan
);
897 ShearPoint(aTmpPt2
,aRect
.TopLeft(),aGeo
.nTan
);
900 SdrTextObj::NbcMirror(rRef1
,rRef2
);
901 if (meCircleKind
!=OBJ_CIRC
) { // adapt starting and finishing angle
902 MirrorPoint(aTmpPt1
,rRef1
,rRef2
);
903 MirrorPoint(aTmpPt2
,rRef1
,rRef2
);
905 if (aGeo
.nDrehWink
!=0) {
906 RotatePoint(aTmpPt1
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
); // -sin for reversion
907 RotatePoint(aTmpPt2
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
); // -sin for reversion
910 if (aGeo
.nShearWink
!=0) {
911 ShearPoint(aTmpPt1
,aRect
.TopLeft(),-aGeo
.nTan
); // -tan for reversion
912 ShearPoint(aTmpPt2
,aRect
.TopLeft(),-aGeo
.nTan
); // -tan for reversion
914 Point
aCenter(aRect
.Center());
917 // because it's mirrored, the angles are swapped, too
918 nStartWink
=GetAngle(aTmpPt2
);
919 nEndWink
=GetAngle(aTmpPt1
);
920 long nWinkDif
=nEndWink
-nStartWink
;
921 nStartWink
=NormAngle360(nStartWink
);
922 nEndWink
=NormAngle360(nEndWink
);
923 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // full circle
926 ImpSetCircInfoToAttr();
929 SdrObjGeoData
* SdrCircObj::NewGeoData() const
931 return new SdrCircObjGeoData
;
934 void SdrCircObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
936 SdrRectObj::SaveGeoData(rGeo
);
937 SdrCircObjGeoData
& rCGeo
=(SdrCircObjGeoData
&)rGeo
;
938 rCGeo
.nStartWink
=nStartWink
;
939 rCGeo
.nEndWink
=nEndWink
;
942 void SdrCircObj::RestGeoData(const SdrObjGeoData
& rGeo
)
944 SdrRectObj::RestGeoData(rGeo
);
945 SdrCircObjGeoData
& rCGeo
=(SdrCircObjGeoData
&)rGeo
;
946 nStartWink
=rCGeo
.nStartWink
;
947 nEndWink
=rCGeo
.nEndWink
;
949 ImpSetCircInfoToAttr();
952 void Union(Rectangle
& rR
, const Point
& rP
)
954 if (rP
.X()<rR
.Left ()) rR
.Left ()=rP
.X();
955 if (rP
.X()>rR
.Right ()) rR
.Right ()=rP
.X();
956 if (rP
.Y()<rR
.Top ()) rR
.Top ()=rP
.Y();
957 if (rP
.Y()>rR
.Bottom()) rR
.Bottom()=rP
.Y();
960 void SdrCircObj::TakeUnrotatedSnapRect(Rectangle
& rRect
) const
963 if (meCircleKind
!=OBJ_CIRC
) {
964 const Point
aPntStart(GetWinkPnt(aRect
,nStartWink
));
965 const Point
aPntEnd(GetWinkPnt(aRect
,nEndWink
));
968 rRect
.Left ()=aRect
.Right();
969 rRect
.Right ()=aRect
.Left();
970 rRect
.Top ()=aRect
.Bottom();
971 rRect
.Bottom()=aRect
.Top();
972 Union(rRect
,aPntStart
);
973 Union(rRect
,aPntEnd
);
974 if ((a
<=18000 && e
>=18000) || (a
>e
&& (a
<=18000 || e
>=18000))) {
975 Union(rRect
,aRect
.LeftCenter());
977 if ((a
<=27000 && e
>=27000) || (a
>e
&& (a
<=27000 || e
>=27000))) {
978 Union(rRect
,aRect
.BottomCenter());
981 Union(rRect
,aRect
.RightCenter());
983 if ((a
<=9000 && e
>=9000) || (a
>e
&& (a
<=9000 || e
>=9000))) {
984 Union(rRect
,aRect
.TopCenter());
986 if (meCircleKind
==OBJ_SECT
) {
987 Union(rRect
,aRect
.Center());
989 if (aGeo
.nDrehWink
!=0) {
990 Point
aDst(rRect
.TopLeft());
991 aDst
-=aRect
.TopLeft();
993 RotatePoint(aDst
,Point(),aGeo
.nSin
,aGeo
.nCos
);
995 rRect
.Move(aDst
.X(),aDst
.Y());
998 if (aGeo
.nShearWink
!=0) {
999 long nDst
=Round((rRect
.Bottom()-rRect
.Top())*aGeo
.nTan
);
1000 if (aGeo
.nShearWink
>0) {
1001 Point
aRef(rRect
.TopLeft());
1003 Point
aTmpPt(rRect
.TopLeft());
1004 RotatePoint(aTmpPt
,aRef
,aGeo
.nSin
,aGeo
.nCos
);
1005 aTmpPt
-=rRect
.TopLeft();
1006 rRect
.Move(aTmpPt
.X(),aTmpPt
.Y());
1008 rRect
.Right()-=nDst
;
1013 void SdrCircObj::RecalcSnapRect()
1015 if (PaintNeedsXPolyCirc()) {
1016 maSnapRect
=GetXPoly().GetBoundRect();
1018 TakeUnrotatedSnapRect(maSnapRect
);
1022 void SdrCircObj::NbcSetSnapRect(const Rectangle
& rRect
)
1024 if (aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0 || meCircleKind
!=OBJ_CIRC
) {
1025 Rectangle
aSR0(GetSnapRect());
1026 long nWdt0
=aSR0
.Right()-aSR0
.Left();
1027 long nHgt0
=aSR0
.Bottom()-aSR0
.Top();
1028 long nWdt1
=rRect
.Right()-rRect
.Left();
1029 long nHgt1
=rRect
.Bottom()-rRect
.Top();
1030 NbcResize(maSnapRect
.TopLeft(),Fraction(nWdt1
,nWdt0
),Fraction(nHgt1
,nHgt0
));
1031 NbcMove(Size(rRect
.Left()-aSR0
.Left(),rRect
.Top()-aSR0
.Top()));
1034 ImpJustifyRect(aRect
);
1038 ImpSetCircInfoToAttr();
1041 sal_uInt32
SdrCircObj::GetSnapPointCount() const
1043 if (meCircleKind
==OBJ_CIRC
) {
1050 Point
SdrCircObj::GetSnapPoint(sal_uInt32 i
) const
1053 case 1 : return GetWinkPnt(aRect
,nStartWink
);
1054 case 2 : return GetWinkPnt(aRect
,nEndWink
);
1055 default: return aRect
.Center();
1059 void SdrCircObj::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
1062 SdrRectObj::Notify(rBC
,rHint
);
1063 ImpSetAttrToCircInfo();
1066 ////////////////////////////////////////////////////////////////////////////////////////////////////
1068 void SdrCircObj::ImpSetAttrToCircInfo()
1070 const SfxItemSet
& rSet
= GetObjectItemSet();
1071 SdrCircKind eNewKindA
= ((SdrCircKindItem
&)rSet
.Get(SDRATTR_CIRCKIND
)).GetValue();
1072 SdrObjKind eNewKind
= meCircleKind
;
1074 if(eNewKindA
== SDRCIRC_FULL
)
1075 eNewKind
= OBJ_CIRC
;
1076 else if(eNewKindA
== SDRCIRC_SECT
)
1077 eNewKind
= OBJ_SECT
;
1078 else if(eNewKindA
== SDRCIRC_ARC
)
1079 eNewKind
= OBJ_CARC
;
1080 else if(eNewKindA
== SDRCIRC_CUT
)
1081 eNewKind
= OBJ_CCUT
;
1083 sal_Int32 nNewStart
= ((SdrCircStartAngleItem
&)rSet
.Get(SDRATTR_CIRCSTARTANGLE
)).GetValue();
1084 sal_Int32 nNewEnd
= ((SdrCircEndAngleItem
&)rSet
.Get(SDRATTR_CIRCENDANGLE
)).GetValue();
1086 bool bKindChg
= meCircleKind
!= eNewKind
;
1087 bool bWinkChg
= nNewStart
!= nStartWink
|| nNewEnd
!= nEndWink
;
1089 if(bKindChg
|| bWinkChg
)
1091 meCircleKind
= eNewKind
;
1092 nStartWink
= nNewStart
;
1095 if(bKindChg
|| (meCircleKind
!= OBJ_CIRC
&& bWinkChg
))
1103 void SdrCircObj::ImpSetCircInfoToAttr()
1105 SdrCircKind eNewKindA
= SDRCIRC_FULL
;
1106 const SfxItemSet
& rSet
= GetObjectItemSet();
1108 if(meCircleKind
== OBJ_SECT
)
1109 eNewKindA
= SDRCIRC_SECT
;
1110 else if(meCircleKind
== OBJ_CARC
)
1111 eNewKindA
= SDRCIRC_ARC
;
1112 else if(meCircleKind
== OBJ_CCUT
)
1113 eNewKindA
= SDRCIRC_CUT
;
1115 SdrCircKind eOldKindA
= ((SdrCircKindItem
&)rSet
.Get(SDRATTR_CIRCKIND
)).GetValue();
1116 sal_Int32 nOldStartWink
= ((SdrCircStartAngleItem
&)rSet
.Get(SDRATTR_CIRCSTARTANGLE
)).GetValue();
1117 sal_Int32 nOldEndWink
= ((SdrCircEndAngleItem
&)rSet
.Get(SDRATTR_CIRCENDANGLE
)).GetValue();
1119 if(eNewKindA
!= eOldKindA
|| nStartWink
!= nOldStartWink
|| nEndWink
!= nOldEndWink
)
1121 // since SetItem() implicitly calls ImpSetAttrToCircInfo()
1122 // setting the item directly is necessary here.
1123 if(eNewKindA
!= eOldKindA
)
1125 GetProperties().SetObjectItemDirect(SdrCircKindItem(eNewKindA
));
1128 if(nStartWink
!= nOldStartWink
)
1130 GetProperties().SetObjectItemDirect(SdrCircStartAngleItem(nStartWink
));
1133 if(nEndWink
!= nOldEndWink
)
1135 GetProperties().SetObjectItemDirect(SdrCircEndAngleItem(nEndWink
));
1139 ImpSetAttrToCircInfo();
1143 SdrObject
* SdrCircObj::DoConvertToPolyObj(sal_Bool bBezier
, bool bAddText
) const
1145 const sal_Bool
bFill(OBJ_CARC
== meCircleKind
? sal_False
: sal_True
);
1146 const basegfx::B2DPolygon
aCircPolygon(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
1147 SdrObject
* pRet
= ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon
), bFill
, bBezier
);
1151 pRet
= ImpConvertAddText(pRet
, bBezier
);
1157 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */