1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: svdocirc.cxx,v $
10 * $Revision: 1.37.18.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include <svtools/style.hxx>
34 #include <tools/bigint.hxx>
35 #include <svx/xlnwtit.hxx>
36 #include <svx/xlnedwit.hxx>
37 #include <svx/xlnstwit.hxx>
38 #include <svx/xlnstit.hxx>
39 #include <svx/xlnedit.hxx>
40 #include <svx/svdocirc.hxx>
42 #include <svx/xpool.hxx>
43 #include <svx/svdattr.hxx>
44 #include <svx/svdpool.hxx>
45 #include <svx/svdattrx.hxx>
46 #include <svx/svdtrans.hxx>
47 #include <svx/svdetc.hxx>
48 #include <svx/svddrag.hxx>
49 #include <svx/svdmodel.hxx>
50 #include <svx/svdpage.hxx>
51 #include <svx/svdopath.hxx> // fuer die Objektkonvertierung
52 #include <svx/svdview.hxx> // Zum Draggen (Ortho)
53 #include "svdglob.hxx" // StringCache
54 #include "svdstr.hrc" // Objektname
55 #include <svx/eeitem.hxx>
56 #include "svdoimp.hxx"
57 #include <svx/sdr/properties/circleproperties.hxx>
58 #include <svx/sdr/contact/viewcontactofsdrcircobj.hxx>
59 #include <basegfx/point/b2dpoint.hxx>
60 #include <basegfx/polygon/b2dpolygon.hxx>
61 #include <basegfx/polygon/b2dpolygontools.hxx>
62 #include <basegfx/matrix/b2dhommatrix.hxx>
63 #include <basegfx/polygon/b2dpolygontools.hxx>
65 //////////////////////////////////////////////////////////////////////////////
67 Point
GetWinkPnt(const Rectangle
& rR
, long nWink
)
69 Point
aCenter(rR
.Center());
70 long nWdt
=rR
.Right()-rR
.Left();
71 long nHgt
=rR
.Bottom()-rR
.Top();
72 long nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
75 Point
aRetval(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
76 if (nWdt
==0) aRetval
.X()=0;
77 if (nHgt
==0) aRetval
.Y()=0;
81 // eventuelle Ueberlaeufe bei sehr grossen Objekten abfangen (Bug 23384)
82 if (Abs(nHgt
)>32767 || Abs(aRetval
.Y())>32767) {
83 aRetval
.Y()=BigMulDiv(aRetval
.Y(),nHgt
,nWdt
);
85 aRetval
.Y()=aRetval
.Y()*nHgt
/nWdt
;
90 // eventuelle Ueberlaeufe bei sehr grossen Objekten abfangen (Bug 23384)
91 if (Abs(nWdt
)>32767 || Abs(aRetval
.X())>32767) {
92 aRetval
.X()=BigMulDiv(aRetval
.X(),nWdt
,nHgt
);
94 aRetval
.X()=aRetval
.X()*nWdt
/nHgt
;
103 //////////////////////////////////////////////////////////////////////////////
104 // BaseProperties section
106 sdr::properties::BaseProperties
* SdrCircObj::CreateObjectSpecificProperties()
108 return new sdr::properties::CircleProperties(*this);
111 //////////////////////////////////////////////////////////////////////////////
112 // DrawContact section
114 sdr::contact::ViewContact
* SdrCircObj::CreateObjectSpecificViewContact()
116 return new sdr::contact::ViewContactOfSdrCircObj(*this);
119 //////////////////////////////////////////////////////////////////////////////
121 TYPEINIT1(SdrCircObj
,SdrRectObj
);
123 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
)
127 meCircleKind
=eNewKind
;
128 bClosedObj
=eNewKind
!=OBJ_CARC
;
131 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
, const Rectangle
& rRect
):
136 meCircleKind
=eNewKind
;
137 bClosedObj
=eNewKind
!=OBJ_CARC
;
140 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
, const Rectangle
& rRect
, long nNewStartWink
, long nNewEndWink
):
143 long nWinkDif
=nNewEndWink
-nNewStartWink
;
144 nStartWink
=NormAngle360(nNewStartWink
);
145 nEndWink
=NormAngle360(nNewEndWink
);
146 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // Vollkreis
147 meCircleKind
=eNewKind
;
148 bClosedObj
=eNewKind
!=OBJ_CARC
;
151 SdrCircObj::~SdrCircObj()
155 void SdrCircObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
157 FASTBOOL bCanConv
=!HasText() || ImpCanConvTextToCurve();
158 rInfo
.bEdgeRadiusAllowed
= FALSE
;
159 rInfo
.bCanConvToPath
=bCanConv
;
160 rInfo
.bCanConvToPoly
=bCanConv
;
161 rInfo
.bCanConvToContour
= !IsFontwork() && (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
164 UINT16
SdrCircObj::GetObjIdentifier() const
166 return UINT16(meCircleKind
);
169 FASTBOOL
SdrCircObj::PaintNeedsXPolyCirc() const
171 // XPoly ist notwendig fuer alle gedrehten Ellipsenobjekte,
172 // fuer alle Kreis- und Ellipsenabschnitte
173 // und wenn nicht WIN dann (erstmal) auch fuer Kreis-/Ellipsenausschnitte
174 // und Kreis-/Ellipsenboegen (wg. Genauigkeit)
175 FASTBOOL bNeed
=aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0 || meCircleKind
==OBJ_CCUT
;
177 // Wenn nicht Win, dann fuer alle ausser Vollkreis (erstmal!!!)
178 if (meCircleKind
!=OBJ_CIRC
) bNeed
=TRUE
;
181 const SfxItemSet
& rSet
= GetObjectItemSet();
184 // XPoly ist notwendig fuer alles was nicht LineSolid oder LineNone ist
185 XLineStyle eLine
= ((XLineStyleItem
&)(rSet
.Get(XATTR_LINESTYLE
))).GetValue();
186 bNeed
= eLine
!= XLINE_NONE
&& eLine
!= XLINE_SOLID
;
188 // XPoly ist notwendig fuer dicke Linien
189 if(!bNeed
&& eLine
!= XLINE_NONE
)
190 bNeed
= ((XLineWidthItem
&)(rSet
.Get(XATTR_LINEWIDTH
))).GetValue() != 0;
192 // XPoly ist notwendig fuer Kreisboegen mit Linienenden
193 if(!bNeed
&& meCircleKind
== OBJ_CARC
)
195 // Linienanfang ist da, wenn StartPolygon und StartWidth!=0
196 bNeed
=((XLineStartItem
&)(rSet
.Get(XATTR_LINESTART
))).GetLineStartValue().count() != 0L &&
197 ((XLineStartWidthItem
&)(rSet
.Get(XATTR_LINESTARTWIDTH
))).GetValue() != 0;
201 // Linienende ist da, wenn EndPolygon und EndWidth!=0
202 bNeed
= ((XLineEndItem
&)(rSet
.Get(XATTR_LINEEND
))).GetLineEndValue().count() != 0L &&
203 ((XLineEndWidthItem
&)(rSet
.Get(XATTR_LINEENDWIDTH
))).GetValue() != 0;
208 // XPoly ist notwendig, wenn Fill !=None und !=Solid
209 if(!bNeed
&& meCircleKind
!= OBJ_CARC
)
211 XFillStyle eFill
=((XFillStyleItem
&)(rSet
.Get(XATTR_FILLSTYLE
))).GetValue();
212 bNeed
= eFill
!= XFILL_NONE
&& eFill
!= XFILL_SOLID
;
215 if(!bNeed
&& meCircleKind
!= OBJ_CIRC
&& nStartWink
== nEndWink
)
216 bNeed
=TRUE
; // Weil sonst Vollkreis gemalt wird
221 basegfx::B2DPolygon
SdrCircObj::ImpCalcXPolyCirc(const SdrObjKind eCicrleKind
, const Rectangle
& rRect1
, long nStart
, long nEnd
) const
223 const basegfx::B2DRange
aRange(rRect1
.Left(), rRect1
.Top(), rRect1
.Right(), rRect1
.Bottom());
224 basegfx::B2DPolygon aCircPolygon
;
226 if(OBJ_CIRC
== eCicrleKind
)
228 // create full circle. Do not use createPolygonFromEllipse, but the single
229 // calls to appendUnitCircleQuadrant() to get the start point to the bottom of the
230 // circle to keep compatible to old geometry creation
231 basegfx::tools::appendUnitCircleQuadrant(aCircPolygon
, 1);
232 basegfx::tools::appendUnitCircleQuadrant(aCircPolygon
, 2);
233 basegfx::tools::appendUnitCircleQuadrant(aCircPolygon
, 3);
234 basegfx::tools::appendUnitCircleQuadrant(aCircPolygon
, 0);
235 aCircPolygon
.setClosed(true);
237 // remove double points between segments created by segmented creation
238 aCircPolygon
.removeDoublePoints();
240 // needs own scaling and translation from unit circle to target size
241 basegfx::B2DHomMatrix aMatrix
;
242 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
244 aMatrix
.scale(aRange
.getWidth() / 2.0, aRange
.getHeight() / 2.0);
245 aMatrix
.translate(aCenter
.getX(), aCenter
.getY());
246 aCircPolygon
.transform(aMatrix
);
250 // mirror start, end for geometry creation since model coordinate system is mirrored in Y
251 const double fStart(((36000 - nEnd
) % 36000) * F_PI18000
);
252 const double fEnd(((36000 - nStart
) % 36000) * F_PI18000
);
254 // create circle segment. This is not closed by default
255 aCircPolygon
= basegfx::tools::createPolygonFromEllipseSegment(aRange
.getCenter(), aRange
.getWidth() / 2.0, aRange
.getHeight() / 2.0, fStart
, fEnd
);
257 // check closing states
258 const bool bCloseSegment(OBJ_CARC
!= eCicrleKind
);
259 const bool bCloseUsingCenter(OBJ_SECT
== eCicrleKind
);
263 if(bCloseUsingCenter
)
265 // add center point at start (for historical reasons)
266 basegfx::B2DPolygon aSector
;
267 aSector
.append(aRange
.getCenter());
268 aSector
.append(aCircPolygon
);
269 aCircPolygon
= aSector
;
273 aCircPolygon
.setClosed(true);
278 if(aGeo
.nShearWink
|| aGeo
.nDrehWink
)
280 const basegfx::B2DPoint
aTopLeft(aRange
.getMinimum());
281 basegfx::B2DHomMatrix aMatrix
;
283 // translate top left to (0,0)
284 aMatrix
.translate(-aTopLeft
.getX(), -aTopLeft
.getY());
289 aMatrix
.shearX(tan((36000 - aGeo
.nShearWink
) * F_PI18000
));
292 // rotate (if needed)
295 aMatrix
.rotate((36000 - aGeo
.nDrehWink
) * F_PI18000
);
299 aMatrix
.translate(aTopLeft
.getX(), aTopLeft
.getY());
301 // apply transformation
302 aCircPolygon
.transform(aMatrix
);
308 void SdrCircObj::RecalcXPoly()
310 const basegfx::B2DPolygon
aPolyCirc(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
311 mpXPoly
= new XPolygon(aPolyCirc
);
314 void SdrCircObj::TakeObjNameSingul(XubString
& rName
) const
316 USHORT nID
=STR_ObjNameSingulCIRC
;
317 if (aRect
.GetWidth()==aRect
.GetHeight() && aGeo
.nShearWink
==0) {
318 switch (meCircleKind
) {
319 case OBJ_CIRC
: nID
=STR_ObjNameSingulCIRC
; break;
320 case OBJ_SECT
: nID
=STR_ObjNameSingulSECT
; break;
321 case OBJ_CARC
: nID
=STR_ObjNameSingulCARC
; break;
322 case OBJ_CCUT
: nID
=STR_ObjNameSingulCCUT
; break;
326 switch (meCircleKind
) {
327 case OBJ_CIRC
: nID
=STR_ObjNameSingulCIRCE
; break;
328 case OBJ_SECT
: nID
=STR_ObjNameSingulSECTE
; break;
329 case OBJ_CARC
: nID
=STR_ObjNameSingulCARCE
; break;
330 case OBJ_CCUT
: nID
=STR_ObjNameSingulCCUTE
; break;
334 rName
=ImpGetResStr(nID
);
336 String
aName( GetName() );
339 rName
+= sal_Unicode(' ');
340 rName
+= sal_Unicode('\'');
342 rName
+= sal_Unicode('\'');
346 void SdrCircObj::TakeObjNamePlural(XubString
& rName
) const
348 USHORT nID
=STR_ObjNamePluralCIRC
;
349 if (aRect
.GetWidth()==aRect
.GetHeight() && aGeo
.nShearWink
==0) {
350 switch (meCircleKind
) {
351 case OBJ_CIRC
: nID
=STR_ObjNamePluralCIRC
; break;
352 case OBJ_SECT
: nID
=STR_ObjNamePluralSECT
; break;
353 case OBJ_CARC
: nID
=STR_ObjNamePluralCARC
; break;
354 case OBJ_CCUT
: nID
=STR_ObjNamePluralCCUT
; break;
358 switch (meCircleKind
) {
359 case OBJ_CIRC
: nID
=STR_ObjNamePluralCIRCE
; break;
360 case OBJ_SECT
: nID
=STR_ObjNamePluralSECTE
; break;
361 case OBJ_CARC
: nID
=STR_ObjNamePluralCARCE
; break;
362 case OBJ_CCUT
: nID
=STR_ObjNamePluralCCUTE
; break;
366 rName
=ImpGetResStr(nID
);
369 void SdrCircObj::operator=(const SdrObject
& rObj
)
371 SdrRectObj::operator=(rObj
);
373 nStartWink
= ((SdrCircObj
&)rObj
).nStartWink
;
374 nEndWink
= ((SdrCircObj
&)rObj
).nEndWink
;
377 basegfx::B2DPolyPolygon
SdrCircObj::TakeXorPoly() const
379 const basegfx::B2DPolygon
aCircPolygon(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
380 return basegfx::B2DPolyPolygon(aCircPolygon
);
383 struct ImpCircUser
: public SdrDragStatUserData
396 FASTBOOL bRight
; // noch nicht implementiert
407 void SetCreateParams(SdrDragStat
& rStat
);
410 sal_uInt32
SdrCircObj::GetHdlCount() const
412 if(OBJ_CIRC
!= meCircleKind
)
422 SdrHdl
* SdrCircObj::GetHdl(sal_uInt32 nHdlNum
) const
424 if (meCircleKind
==OBJ_CIRC
)
431 SdrHdlKind
eLocalKind(HDL_MOVE
);
437 aPnt
= GetWinkPnt(aRect
,nStartWink
);
438 eLocalKind
= HDL_CIRC
;
442 aPnt
= GetWinkPnt(aRect
,nEndWink
);
443 eLocalKind
= HDL_CIRC
;
447 aPnt
= aRect
.TopLeft();
448 eLocalKind
= HDL_UPLFT
;
451 aPnt
= aRect
.TopCenter();
452 eLocalKind
= HDL_UPPER
;
455 aPnt
= aRect
.TopRight();
456 eLocalKind
= HDL_UPRGT
;
459 aPnt
= aRect
.LeftCenter();
460 eLocalKind
= HDL_LEFT
;
463 aPnt
= aRect
.RightCenter();
464 eLocalKind
= HDL_RIGHT
;
467 aPnt
= aRect
.BottomLeft();
468 eLocalKind
= HDL_LWLFT
;
471 aPnt
= aRect
.BottomCenter();
472 eLocalKind
= HDL_LOWER
;
475 aPnt
= aRect
.BottomRight();
476 eLocalKind
= HDL_LWRGT
;
482 ShearPoint(aPnt
,aRect
.TopLeft(),aGeo
.nTan
);
487 RotatePoint(aPnt
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
490 if (eLocalKind
!= HDL_MOVE
)
492 pH
= new SdrHdl(aPnt
,eLocalKind
);
493 pH
->SetPointNum(nPNum
);
494 pH
->SetObj((SdrObject
*)this);
495 pH
->SetDrehWink(aGeo
.nDrehWink
);
501 ////////////////////////////////////////////////////////////////////////////////////////////////////
503 bool SdrCircObj::hasSpecialDrag() const
508 bool SdrCircObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
510 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
514 if(1 == rDrag
.GetHdl()->GetPointNum() || 2 == rDrag
.GetHdl()->GetPointNum())
516 rDrag
.SetNoSnap(true);
522 return SdrTextObj::beginSpecialDrag(rDrag
);
525 bool SdrCircObj::applySpecialDrag(SdrDragStat
& rDrag
)
527 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
531 Point
aPt(rDrag
.GetNow());
533 if (aGeo
.nDrehWink
!=0)
534 RotatePoint(aPt
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
);
536 if (aGeo
.nShearWink
!=0)
537 ShearPoint(aPt
,aRect
.TopLeft(),-aGeo
.nTan
);
541 long nWdt
=aRect
.Right()-aRect
.Left();
542 long nHgt
=aRect
.Bottom()-aRect
.Top();
546 aPt
.Y()=BigMulDiv(aPt
.Y(),nWdt
,nHgt
);
550 aPt
.X()=BigMulDiv(aPt
.X(),nHgt
,nWdt
);
553 long nWink
=NormAngle360(GetAngle(aPt
));
555 if (rDrag
.GetView() && rDrag
.GetView()->IsAngleSnapEnabled())
557 long nSA
=rDrag
.GetView()->GetSnapAngle();
564 nWink
=NormAngle360(nWink
);
568 if(1 == rDrag
.GetHdl()->GetPointNum())
572 else if(2 == rDrag
.GetHdl()->GetPointNum())
579 ImpSetCircInfoToAttr();
586 return SdrTextObj::applySpecialDrag(rDrag
);
590 String
SdrCircObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
592 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
597 ImpTakeDescriptionStr(STR_ViewCreateObj
, aStr
);
598 const sal_uInt32
nPntAnz(rDrag
.GetPointAnz());
600 if(OBJ_CIRC
!= meCircleKind
&& nPntAnz
> 2)
602 ImpCircUser
* pU
= (ImpCircUser
*)rDrag
.GetUser();
605 aStr
.AppendAscii(" (");
616 aStr
+= GetWinkStr(nWink
,FALSE
);
617 aStr
+= sal_Unicode(')');
624 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
629 const sal_Int32
nWink(1 == rDrag
.GetHdl()->GetPointNum() ? nStartWink
: nEndWink
);
631 ImpTakeDescriptionStr(STR_DragCircAngle
, aStr
);
632 aStr
.AppendAscii(" (");
633 aStr
+= GetWinkStr(nWink
,FALSE
);
634 aStr
+= sal_Unicode(')');
640 return SdrTextObj::getSpecialDragComment(rDrag
);
645 ////////////////////////////////////////////////////////////////////////////////////////////////////
647 void ImpCircUser::SetCreateParams(SdrDragStat
& rStat
)
649 rStat
.TakeCreateRect(aR
);
652 nWdt
=aR
.Right()-aR
.Left();
653 nHgt
=aR
.Bottom()-aR
.Top();
654 nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
657 if (rStat
.GetPointAnz()>2) {
658 Point
aP(rStat
.GetPoint(2)-aCenter
);
659 if (nWdt
==0) aP
.X()=0;
660 if (nHgt
==0) aP
.Y()=0;
662 if (nHgt
!=0) aP
.Y()=aP
.Y()*nWdt
/nHgt
;
664 if (nWdt
!=0) aP
.X()=aP
.X()*nHgt
/nWdt
;
666 nStart
=NormAngle360(GetAngle(aP
));
667 if (rStat
.GetView()!=NULL
&& rStat
.GetView()->IsAngleSnapEnabled()) {
668 long nSA
=rStat
.GetView()->GetSnapAngle();
669 if (nSA
!=0) { // Winkelfang
673 nStart
=NormAngle360(nStart
);
676 aP1
= GetWinkPnt(aR
,nStart
);
680 if (rStat
.GetPointAnz()>3) {
681 Point
aP(rStat
.GetPoint(3)-aCenter
);
683 aP
.Y()=BigMulDiv(aP
.Y(),nWdt
,nHgt
);
685 aP
.X()=BigMulDiv(aP
.X(),nHgt
,nWdt
);
687 nEnd
=NormAngle360(GetAngle(aP
));
688 if (rStat
.GetView()!=NULL
&& rStat
.GetView()->IsAngleSnapEnabled()) {
689 long nSA
=rStat
.GetView()->GetSnapAngle();
690 if (nSA
!=0) { // Winkelfang
694 nEnd
=NormAngle360(nEnd
);
697 aP2
= GetWinkPnt(aR
,nEnd
);
701 void SdrCircObj::ImpSetCreateParams(SdrDragStat
& rStat
) const
703 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
708 pU
->SetCreateParams(rStat
);
711 FASTBOOL
SdrCircObj::BegCreate(SdrDragStat
& rStat
)
713 rStat
.SetOrtho4Possible();
714 Rectangle
aRect1(rStat
.GetStart(), rStat
.GetNow());
716 rStat
.SetActionRect(aRect1
);
718 ImpSetCreateParams(rStat
);
722 FASTBOOL
SdrCircObj::MovCreate(SdrDragStat
& rStat
)
724 ImpSetCreateParams(rStat
);
725 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
726 rStat
.SetActionRect(pU
->aR
);
727 aRect
=pU
->aR
; // fuer ObjName
728 ImpJustifyRect(aRect
);
729 nStartWink
=pU
->nStart
;
735 // #i103058# push current angle settings to ItemSet to
736 // allow FullDrag visualisation
737 if(rStat
.GetPointAnz() >= 4)
739 ImpSetCircInfoToAttr();
745 FASTBOOL
SdrCircObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
747 ImpSetCreateParams(rStat
);
748 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
750 if (eCmd
==SDRCREATE_FORCEEND
&& rStat
.GetPointAnz()<4) meCircleKind
=OBJ_CIRC
;
751 if (meCircleKind
==OBJ_CIRC
) {
752 bRet
=rStat
.GetPointAnz()>=2;
755 ImpJustifyRect(aRect
);
758 rStat
.SetNoSnap(rStat
.GetPointAnz()>=2);
759 rStat
.SetOrtho4Possible(rStat
.GetPointAnz()<2);
760 bRet
=rStat
.GetPointAnz()>=4;
763 ImpJustifyRect(aRect
);
764 nStartWink
=pU
->nStart
;
768 bClosedObj
=meCircleKind
!=OBJ_CARC
;
771 ImpSetCircInfoToAttr();
779 void SdrCircObj::BrkCreate(SdrDragStat
& rStat
)
781 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
786 FASTBOOL
SdrCircObj::BckCreate(SdrDragStat
& rStat
)
788 rStat
.SetNoSnap(rStat
.GetPointAnz()>=3);
789 rStat
.SetOrtho4Possible(rStat
.GetPointAnz()<3);
790 return meCircleKind
!=OBJ_CIRC
;
793 basegfx::B2DPolyPolygon
SdrCircObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
795 ImpCircUser
* pU
= (ImpCircUser
*)rDrag
.GetUser();
797 if(rDrag
.GetPointAnz() < 4L)
799 // force to OBJ_CIRC to get full visualisation
800 basegfx::B2DPolyPolygon
aRetval(ImpCalcXPolyCirc(OBJ_CIRC
, pU
->aR
, pU
->nStart
, pU
->nEnd
));
802 if(3L == rDrag
.GetPointAnz())
804 // add edge to first point on ellipse
805 basegfx::B2DPolygon aNew
;
807 aNew
.append(basegfx::B2DPoint(pU
->aCenter
.X(), pU
->aCenter
.Y()));
808 aNew
.append(basegfx::B2DPoint(pU
->aP1
.X(), pU
->aP1
.Y()));
809 aRetval
.append(aNew
);
816 return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind
, pU
->aR
, pU
->nStart
, pU
->nEnd
));
820 Pointer
SdrCircObj::GetCreatePointer() const
822 switch (meCircleKind
) {
823 case OBJ_CIRC
: return Pointer(POINTER_DRAW_ELLIPSE
);
824 case OBJ_SECT
: return Pointer(POINTER_DRAW_PIE
);
825 case OBJ_CARC
: return Pointer(POINTER_DRAW_ARC
);
826 case OBJ_CCUT
: return Pointer(POINTER_DRAW_CIRCLECUT
);
829 return Pointer(POINTER_CROSS
);
832 void SdrCircObj::NbcMove(const Size
& aSiz
)
834 MoveRect(aRect
,aSiz
);
835 MoveRect(aOutRect
,aSiz
);
836 MoveRect(maSnapRect
,aSiz
);
838 SetRectsDirty(sal_True
);
841 void SdrCircObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
843 long nWink0
=aGeo
.nDrehWink
;
844 FASTBOOL bNoShearRota
=(aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0);
845 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
846 bNoShearRota
|=(aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0);
847 if (meCircleKind
!=OBJ_CIRC
) {
848 FASTBOOL bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
849 FASTBOOL bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
850 if (bXMirr
|| bYMirr
) {
851 // bei bXMirr!=bYMirr muessten eigentlich noch die beiden
852 // Linienende vertauscht werden. Das ist jedoch mal wieder
853 // schlecht (wg. zwangslaeufiger harter Formatierung).
854 // Alternativ koennte ein bMirrored-Flag eingefuehrt werden
855 // (Vielleicht ja mal grundsaetzlich, auch fuer gepiegelten Text, ...).
859 // Das RectObj spiegelt bei VMirror bereits durch durch 180deg Drehung.
860 if (! (bXMirr
&& bYMirr
)) {
865 } else { // Spiegeln fuer verzerrte Ellipsen
866 if (bXMirr
!=bYMirr
) {
883 long nWinkDif
=nE0
-nS0
;
884 nStartWink
=NormAngle360(nS0
);
885 nEndWink
=NormAngle360(nE0
);
886 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // Vollkreis
890 ImpSetCircInfoToAttr();
893 void SdrCircObj::NbcShear(const Point
& rRef
, long nWink
, double tn
, FASTBOOL bVShear
)
895 SdrTextObj::NbcShear(rRef
,nWink
,tn
,bVShear
);
897 ImpSetCircInfoToAttr();
900 void SdrCircObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
902 //long nWink0=aGeo.nDrehWink;
903 FASTBOOL bFreeMirr
=meCircleKind
!=OBJ_CIRC
;
906 if (bFreeMirr
) { // bei freier Spiegelachse einige Vorbereitungen Treffen
907 Point
aCenter(aRect
.Center());
908 long nWdt
=aRect
.GetWidth()-1;
909 long nHgt
=aRect
.GetHeight()-1;
910 long nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
914 aTmpPt1
=Point(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
915 if (nWdt
==0) aTmpPt1
.X()=0;
916 if (nHgt
==0) aTmpPt1
.Y()=0;
920 aTmpPt2
=Point(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
921 if (nWdt
==0) aTmpPt2
.X()=0;
922 if (nHgt
==0) aTmpPt2
.Y()=0;
924 if (aGeo
.nDrehWink
!=0) {
925 RotatePoint(aTmpPt1
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
926 RotatePoint(aTmpPt2
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
928 if (aGeo
.nShearWink
!=0) {
929 ShearPoint(aTmpPt1
,aRect
.TopLeft(),aGeo
.nTan
);
930 ShearPoint(aTmpPt2
,aRect
.TopLeft(),aGeo
.nTan
);
933 SdrTextObj::NbcMirror(rRef1
,rRef2
);
934 if (meCircleKind
!=OBJ_CIRC
) { // Anpassung von Start- und Endwinkel
935 MirrorPoint(aTmpPt1
,rRef1
,rRef2
);
936 MirrorPoint(aTmpPt2
,rRef1
,rRef2
);
938 if (aGeo
.nDrehWink
!=0) {
939 RotatePoint(aTmpPt1
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
); // -sin fuer Umkehrung
940 RotatePoint(aTmpPt2
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
); // -sin fuer Umkehrung
943 if (aGeo
.nShearWink
!=0) {
944 ShearPoint(aTmpPt1
,aRect
.TopLeft(),-aGeo
.nTan
); // -tan fuer Umkehrung
945 ShearPoint(aTmpPt2
,aRect
.TopLeft(),-aGeo
.nTan
); // -tan fuer Umkehrung
947 Point
aCenter(aRect
.Center());
950 // Weil gespiegelt sind die Winkel nun auch noch vertauscht
951 nStartWink
=GetAngle(aTmpPt2
);
952 nEndWink
=GetAngle(aTmpPt1
);
953 long nWinkDif
=nEndWink
-nStartWink
;
954 nStartWink
=NormAngle360(nStartWink
);
955 nEndWink
=NormAngle360(nEndWink
);
956 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // Vollkreis
959 ImpSetCircInfoToAttr();
962 SdrObjGeoData
* SdrCircObj::NewGeoData() const
964 return new SdrCircObjGeoData
;
967 void SdrCircObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
969 SdrRectObj::SaveGeoData(rGeo
);
970 SdrCircObjGeoData
& rCGeo
=(SdrCircObjGeoData
&)rGeo
;
971 rCGeo
.nStartWink
=nStartWink
;
972 rCGeo
.nEndWink
=nEndWink
;
975 void SdrCircObj::RestGeoData(const SdrObjGeoData
& rGeo
)
977 SdrRectObj::RestGeoData(rGeo
);
978 SdrCircObjGeoData
& rCGeo
=(SdrCircObjGeoData
&)rGeo
;
979 nStartWink
=rCGeo
.nStartWink
;
980 nEndWink
=rCGeo
.nEndWink
;
982 ImpSetCircInfoToAttr();
985 void Union(Rectangle
& rR
, const Point
& rP
)
987 if (rP
.X()<rR
.Left ()) rR
.Left ()=rP
.X();
988 if (rP
.X()>rR
.Right ()) rR
.Right ()=rP
.X();
989 if (rP
.Y()<rR
.Top ()) rR
.Top ()=rP
.Y();
990 if (rP
.Y()>rR
.Bottom()) rR
.Bottom()=rP
.Y();
993 void SdrCircObj::TakeUnrotatedSnapRect(Rectangle
& rRect
) const
996 if (meCircleKind
!=OBJ_CIRC
) {
997 const Point
aPntStart(GetWinkPnt(aRect
,nStartWink
));
998 const Point
aPntEnd(GetWinkPnt(aRect
,nEndWink
));
1001 rRect
.Left ()=aRect
.Right();
1002 rRect
.Right ()=aRect
.Left();
1003 rRect
.Top ()=aRect
.Bottom();
1004 rRect
.Bottom()=aRect
.Top();
1005 Union(rRect
,aPntStart
);
1006 Union(rRect
,aPntEnd
);
1007 if ((a
<=18000 && e
>=18000) || (a
>e
&& (a
<=18000 || e
>=18000))) {
1008 Union(rRect
,aRect
.LeftCenter());
1010 if ((a
<=27000 && e
>=27000) || (a
>e
&& (a
<=27000 || e
>=27000))) {
1011 Union(rRect
,aRect
.BottomCenter());
1014 Union(rRect
,aRect
.RightCenter());
1016 if ((a
<=9000 && e
>=9000) || (a
>e
&& (a
<=9000 || e
>=9000))) {
1017 Union(rRect
,aRect
.TopCenter());
1019 if (meCircleKind
==OBJ_SECT
) {
1020 Union(rRect
,aRect
.Center());
1022 if (aGeo
.nDrehWink
!=0) {
1023 Point
aDst(rRect
.TopLeft());
1024 aDst
-=aRect
.TopLeft();
1026 RotatePoint(aDst
,Point(),aGeo
.nSin
,aGeo
.nCos
);
1028 rRect
.Move(aDst
.X(),aDst
.Y());
1031 if (aGeo
.nShearWink
!=0) {
1032 long nDst
=Round((rRect
.Bottom()-rRect
.Top())*aGeo
.nTan
);
1033 if (aGeo
.nShearWink
>0) {
1034 Point
aRef(rRect
.TopLeft());
1036 Point
aTmpPt(rRect
.TopLeft());
1037 RotatePoint(aTmpPt
,aRef
,aGeo
.nSin
,aGeo
.nCos
);
1038 aTmpPt
-=rRect
.TopLeft();
1039 rRect
.Move(aTmpPt
.X(),aTmpPt
.Y());
1041 rRect
.Right()-=nDst
;
1046 void SdrCircObj::RecalcSnapRect()
1048 if (PaintNeedsXPolyCirc()) {
1049 maSnapRect
=GetXPoly().GetBoundRect();
1051 TakeUnrotatedSnapRect(maSnapRect
);
1055 void SdrCircObj::NbcSetSnapRect(const Rectangle
& rRect
)
1057 if (aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0 || meCircleKind
!=OBJ_CIRC
) {
1058 Rectangle
aSR0(GetSnapRect());
1059 long nWdt0
=aSR0
.Right()-aSR0
.Left();
1060 long nHgt0
=aSR0
.Bottom()-aSR0
.Top();
1061 long nWdt1
=rRect
.Right()-rRect
.Left();
1062 long nHgt1
=rRect
.Bottom()-rRect
.Top();
1063 NbcResize(maSnapRect
.TopLeft(),Fraction(nWdt1
,nWdt0
),Fraction(nHgt1
,nHgt0
));
1064 NbcMove(Size(rRect
.Left()-aSR0
.Left(),rRect
.Top()-aSR0
.Top()));
1067 ImpJustifyRect(aRect
);
1071 ImpSetCircInfoToAttr();
1074 sal_uInt32
SdrCircObj::GetSnapPointCount() const
1076 if (meCircleKind
==OBJ_CIRC
) {
1083 Point
SdrCircObj::GetSnapPoint(sal_uInt32 i
) const
1086 case 1 : return GetWinkPnt(aRect
,nStartWink
);
1087 case 2 : return GetWinkPnt(aRect
,nEndWink
);
1088 default: return aRect
.Center();
1092 void __EXPORT
SdrCircObj::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
1095 SdrRectObj::Notify(rBC
,rHint
);
1096 ImpSetAttrToCircInfo();
1099 ////////////////////////////////////////////////////////////////////////////////////////////////////
1101 void SdrCircObj::ImpSetAttrToCircInfo()
1103 const SfxItemSet
& rSet
= GetObjectItemSet();
1104 SdrCircKind eNewKindA
= ((SdrCircKindItem
&)rSet
.Get(SDRATTR_CIRCKIND
)).GetValue();
1105 SdrObjKind eNewKind
= meCircleKind
;
1107 if(eNewKindA
== SDRCIRC_FULL
)
1108 eNewKind
= OBJ_CIRC
;
1109 else if(eNewKindA
== SDRCIRC_SECT
)
1110 eNewKind
= OBJ_SECT
;
1111 else if(eNewKindA
== SDRCIRC_ARC
)
1112 eNewKind
= OBJ_CARC
;
1113 else if(eNewKindA
== SDRCIRC_CUT
)
1114 eNewKind
= OBJ_CCUT
;
1116 sal_Int32 nNewStart
= ((SdrCircStartAngleItem
&)rSet
.Get(SDRATTR_CIRCSTARTANGLE
)).GetValue();
1117 sal_Int32 nNewEnd
= ((SdrCircEndAngleItem
&)rSet
.Get(SDRATTR_CIRCENDANGLE
)).GetValue();
1119 BOOL bKindChg
= meCircleKind
!= eNewKind
;
1120 BOOL bWinkChg
= nNewStart
!= nStartWink
|| nNewEnd
!= nEndWink
;
1122 if(bKindChg
|| bWinkChg
)
1124 meCircleKind
= eNewKind
;
1125 nStartWink
= nNewStart
;
1128 if(bKindChg
|| (meCircleKind
!= OBJ_CIRC
&& bWinkChg
))
1136 void SdrCircObj::ImpSetCircInfoToAttr()
1138 SdrCircKind eNewKindA
= SDRCIRC_FULL
;
1139 const SfxItemSet
& rSet
= GetObjectItemSet();
1141 if(meCircleKind
== OBJ_SECT
)
1142 eNewKindA
= SDRCIRC_SECT
;
1143 else if(meCircleKind
== OBJ_CARC
)
1144 eNewKindA
= SDRCIRC_ARC
;
1145 else if(meCircleKind
== OBJ_CCUT
)
1146 eNewKindA
= SDRCIRC_CUT
;
1148 SdrCircKind eOldKindA
= ((SdrCircKindItem
&)rSet
.Get(SDRATTR_CIRCKIND
)).GetValue();
1149 sal_Int32 nOldStartWink
= ((SdrCircStartAngleItem
&)rSet
.Get(SDRATTR_CIRCSTARTANGLE
)).GetValue();
1150 sal_Int32 nOldEndWink
= ((SdrCircEndAngleItem
&)rSet
.Get(SDRATTR_CIRCENDANGLE
)).GetValue();
1152 if(eNewKindA
!= eOldKindA
|| nStartWink
!= nOldStartWink
|| nEndWink
!= nOldEndWink
)
1154 // #81921# since SetItem() implicitly calls ImpSetAttrToCircInfo()
1155 // setting the item directly is necessary here.
1156 if(eNewKindA
!= eOldKindA
)
1158 GetProperties().SetObjectItemDirect(SdrCircKindItem(eNewKindA
));
1161 if(nStartWink
!= nOldStartWink
)
1163 GetProperties().SetObjectItemDirect(SdrCircStartAngleItem(nStartWink
));
1166 if(nEndWink
!= nOldEndWink
)
1168 GetProperties().SetObjectItemDirect(SdrCircEndAngleItem(nEndWink
));
1172 ImpSetAttrToCircInfo();
1176 SdrObject
* SdrCircObj::DoConvertToPolyObj(BOOL bBezier
) const
1178 const sal_Bool
bFill(OBJ_CARC
== meCircleKind
? sal_False
: sal_True
);
1179 const basegfx::B2DPolygon
aCircPolygon(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
1180 SdrObject
* pRet
= ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon
), bFill
, bBezier
);
1181 pRet
= ImpConvertAddText(pRet
, bBezier
);
1186 //////////////////////////////////////////////////////////////////////////////