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 bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
597 const sal_Int32
nWink(1 == rDrag
.GetHdl()->GetPointNum() ? nStartWink
: nEndWink
);
599 ImpTakeDescriptionStr(STR_DragCircAngle
, aStr
);
600 aStr
.AppendAscii(" (");
601 aStr
+= GetWinkStr(nWink
,FALSE
);
602 aStr
+= sal_Unicode(')');
608 return SdrTextObj::getSpecialDragComment(rDrag
);
612 ////////////////////////////////////////////////////////////////////////////////////////////////////
614 void ImpCircUser::SetCreateParams(SdrDragStat
& rStat
)
616 rStat
.TakeCreateRect(aR
);
619 nWdt
=aR
.Right()-aR
.Left();
620 nHgt
=aR
.Bottom()-aR
.Top();
621 nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
624 if (rStat
.GetPointAnz()>2) {
625 Point
aP(rStat
.GetPoint(2)-aCenter
);
626 if (nWdt
==0) aP
.X()=0;
627 if (nHgt
==0) aP
.Y()=0;
629 if (nHgt
!=0) aP
.Y()=aP
.Y()*nWdt
/nHgt
;
631 if (nWdt
!=0) aP
.X()=aP
.X()*nHgt
/nWdt
;
633 nStart
=NormAngle360(GetAngle(aP
));
634 if (rStat
.GetView()!=NULL
&& rStat
.GetView()->IsAngleSnapEnabled()) {
635 long nSA
=rStat
.GetView()->GetSnapAngle();
636 if (nSA
!=0) { // Winkelfang
640 nStart
=NormAngle360(nStart
);
643 aP1
= GetWinkPnt(aR
,nStart
);
647 if (rStat
.GetPointAnz()>3) {
648 Point
aP(rStat
.GetPoint(3)-aCenter
);
650 aP
.Y()=BigMulDiv(aP
.Y(),nWdt
,nHgt
);
652 aP
.X()=BigMulDiv(aP
.X(),nHgt
,nWdt
);
654 nEnd
=NormAngle360(GetAngle(aP
));
655 if (rStat
.GetView()!=NULL
&& rStat
.GetView()->IsAngleSnapEnabled()) {
656 long nSA
=rStat
.GetView()->GetSnapAngle();
657 if (nSA
!=0) { // Winkelfang
661 nEnd
=NormAngle360(nEnd
);
664 aP2
= GetWinkPnt(aR
,nEnd
);
668 void SdrCircObj::ImpSetCreateParams(SdrDragStat
& rStat
) const
670 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
675 pU
->SetCreateParams(rStat
);
678 FASTBOOL
SdrCircObj::BegCreate(SdrDragStat
& rStat
)
680 rStat
.SetOrtho4Possible();
681 Rectangle
aRect1(rStat
.GetStart(), rStat
.GetNow());
683 rStat
.SetActionRect(aRect1
);
685 ImpSetCreateParams(rStat
);
689 FASTBOOL
SdrCircObj::MovCreate(SdrDragStat
& rStat
)
691 ImpSetCreateParams(rStat
);
692 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
693 rStat
.SetActionRect(pU
->aR
);
694 aRect
=pU
->aR
; // fuer ObjName
695 ImpJustifyRect(aRect
);
696 nStartWink
=pU
->nStart
;
704 FASTBOOL
SdrCircObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
706 ImpSetCreateParams(rStat
);
707 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
709 if (eCmd
==SDRCREATE_FORCEEND
&& rStat
.GetPointAnz()<4) meCircleKind
=OBJ_CIRC
;
710 if (meCircleKind
==OBJ_CIRC
) {
711 bRet
=rStat
.GetPointAnz()>=2;
714 ImpJustifyRect(aRect
);
717 rStat
.SetNoSnap(rStat
.GetPointAnz()>=2);
718 rStat
.SetOrtho4Possible(rStat
.GetPointAnz()<2);
719 bRet
=rStat
.GetPointAnz()>=4;
722 ImpJustifyRect(aRect
);
723 nStartWink
=pU
->nStart
;
727 bClosedObj
=meCircleKind
!=OBJ_CARC
;
730 ImpSetCircInfoToAttr();
738 void SdrCircObj::BrkCreate(SdrDragStat
& rStat
)
740 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
745 FASTBOOL
SdrCircObj::BckCreate(SdrDragStat
& rStat
)
747 rStat
.SetNoSnap(rStat
.GetPointAnz()>=3);
748 rStat
.SetOrtho4Possible(rStat
.GetPointAnz()<3);
749 return meCircleKind
!=OBJ_CIRC
;
752 basegfx::B2DPolyPolygon
SdrCircObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
754 ImpCircUser
* pU
= (ImpCircUser
*)rDrag
.GetUser();
756 if(rDrag
.GetPointAnz() < 4L)
758 // force to OBJ_CIRC to get full visualisation
759 basegfx::B2DPolyPolygon
aRetval(ImpCalcXPolyCirc(OBJ_CIRC
, pU
->aR
, pU
->nStart
, pU
->nEnd
));
761 if(3L == rDrag
.GetPointAnz())
763 // add edge to first point on ellipse
764 basegfx::B2DPolygon aNew
;
766 aNew
.append(basegfx::B2DPoint(pU
->aCenter
.X(), pU
->aCenter
.Y()));
767 aNew
.append(basegfx::B2DPoint(pU
->aP1
.X(), pU
->aP1
.Y()));
768 aRetval
.append(aNew
);
775 return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind
, pU
->aR
, pU
->nStart
, pU
->nEnd
));
779 Pointer
SdrCircObj::GetCreatePointer() const
781 switch (meCircleKind
) {
782 case OBJ_CIRC
: return Pointer(POINTER_DRAW_ELLIPSE
);
783 case OBJ_SECT
: return Pointer(POINTER_DRAW_PIE
);
784 case OBJ_CARC
: return Pointer(POINTER_DRAW_ARC
);
785 case OBJ_CCUT
: return Pointer(POINTER_DRAW_CIRCLECUT
);
788 return Pointer(POINTER_CROSS
);
791 void SdrCircObj::NbcMove(const Size
& aSiz
)
793 MoveRect(aRect
,aSiz
);
794 MoveRect(aOutRect
,aSiz
);
795 MoveRect(maSnapRect
,aSiz
);
797 SetRectsDirty(sal_True
);
800 void SdrCircObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
802 long nWink0
=aGeo
.nDrehWink
;
803 FASTBOOL bNoShearRota
=(aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0);
804 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
805 bNoShearRota
|=(aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0);
806 if (meCircleKind
!=OBJ_CIRC
) {
807 FASTBOOL bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
808 FASTBOOL bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
809 if (bXMirr
|| bYMirr
) {
810 // bei bXMirr!=bYMirr muessten eigentlich noch die beiden
811 // Linienende vertauscht werden. Das ist jedoch mal wieder
812 // schlecht (wg. zwangslaeufiger harter Formatierung).
813 // Alternativ koennte ein bMirrored-Flag eingefuehrt werden
814 // (Vielleicht ja mal grundsaetzlich, auch fuer gepiegelten Text, ...).
818 // Das RectObj spiegelt bei VMirror bereits durch durch 180deg Drehung.
819 if (! (bXMirr
&& bYMirr
)) {
824 } else { // Spiegeln fuer verzerrte Ellipsen
825 if (bXMirr
!=bYMirr
) {
842 long nWinkDif
=nE0
-nS0
;
843 nStartWink
=NormAngle360(nS0
);
844 nEndWink
=NormAngle360(nE0
);
845 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // Vollkreis
849 ImpSetCircInfoToAttr();
852 void SdrCircObj::NbcShear(const Point
& rRef
, long nWink
, double tn
, FASTBOOL bVShear
)
854 SdrTextObj::NbcShear(rRef
,nWink
,tn
,bVShear
);
856 ImpSetCircInfoToAttr();
859 void SdrCircObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
861 //long nWink0=aGeo.nDrehWink;
862 FASTBOOL bFreeMirr
=meCircleKind
!=OBJ_CIRC
;
865 if (bFreeMirr
) { // bei freier Spiegelachse einige Vorbereitungen Treffen
866 Point
aCenter(aRect
.Center());
867 long nWdt
=aRect
.GetWidth()-1;
868 long nHgt
=aRect
.GetHeight()-1;
869 long nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
873 aTmpPt1
=Point(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
874 if (nWdt
==0) aTmpPt1
.X()=0;
875 if (nHgt
==0) aTmpPt1
.Y()=0;
879 aTmpPt2
=Point(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
880 if (nWdt
==0) aTmpPt2
.X()=0;
881 if (nHgt
==0) aTmpPt2
.Y()=0;
883 if (aGeo
.nDrehWink
!=0) {
884 RotatePoint(aTmpPt1
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
885 RotatePoint(aTmpPt2
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
887 if (aGeo
.nShearWink
!=0) {
888 ShearPoint(aTmpPt1
,aRect
.TopLeft(),aGeo
.nTan
);
889 ShearPoint(aTmpPt2
,aRect
.TopLeft(),aGeo
.nTan
);
892 SdrTextObj::NbcMirror(rRef1
,rRef2
);
893 if (meCircleKind
!=OBJ_CIRC
) { // Anpassung von Start- und Endwinkel
894 MirrorPoint(aTmpPt1
,rRef1
,rRef2
);
895 MirrorPoint(aTmpPt2
,rRef1
,rRef2
);
897 if (aGeo
.nDrehWink
!=0) {
898 RotatePoint(aTmpPt1
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
); // -sin fuer Umkehrung
899 RotatePoint(aTmpPt2
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
); // -sin fuer Umkehrung
902 if (aGeo
.nShearWink
!=0) {
903 ShearPoint(aTmpPt1
,aRect
.TopLeft(),-aGeo
.nTan
); // -tan fuer Umkehrung
904 ShearPoint(aTmpPt2
,aRect
.TopLeft(),-aGeo
.nTan
); // -tan fuer Umkehrung
906 Point
aCenter(aRect
.Center());
909 // Weil gespiegelt sind die Winkel nun auch noch vertauscht
910 nStartWink
=GetAngle(aTmpPt2
);
911 nEndWink
=GetAngle(aTmpPt1
);
912 long nWinkDif
=nEndWink
-nStartWink
;
913 nStartWink
=NormAngle360(nStartWink
);
914 nEndWink
=NormAngle360(nEndWink
);
915 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // Vollkreis
918 ImpSetCircInfoToAttr();
921 SdrObjGeoData
* SdrCircObj::NewGeoData() const
923 return new SdrCircObjGeoData
;
926 void SdrCircObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
928 SdrRectObj::SaveGeoData(rGeo
);
929 SdrCircObjGeoData
& rCGeo
=(SdrCircObjGeoData
&)rGeo
;
930 rCGeo
.nStartWink
=nStartWink
;
931 rCGeo
.nEndWink
=nEndWink
;
934 void SdrCircObj::RestGeoData(const SdrObjGeoData
& rGeo
)
936 SdrRectObj::RestGeoData(rGeo
);
937 SdrCircObjGeoData
& rCGeo
=(SdrCircObjGeoData
&)rGeo
;
938 nStartWink
=rCGeo
.nStartWink
;
939 nEndWink
=rCGeo
.nEndWink
;
941 ImpSetCircInfoToAttr();
944 void Union(Rectangle
& rR
, const Point
& rP
)
946 if (rP
.X()<rR
.Left ()) rR
.Left ()=rP
.X();
947 if (rP
.X()>rR
.Right ()) rR
.Right ()=rP
.X();
948 if (rP
.Y()<rR
.Top ()) rR
.Top ()=rP
.Y();
949 if (rP
.Y()>rR
.Bottom()) rR
.Bottom()=rP
.Y();
952 void SdrCircObj::TakeUnrotatedSnapRect(Rectangle
& rRect
) const
955 if (meCircleKind
!=OBJ_CIRC
) {
956 const Point
aPntStart(GetWinkPnt(aRect
,nStartWink
));
957 const Point
aPntEnd(GetWinkPnt(aRect
,nEndWink
));
960 rRect
.Left ()=aRect
.Right();
961 rRect
.Right ()=aRect
.Left();
962 rRect
.Top ()=aRect
.Bottom();
963 rRect
.Bottom()=aRect
.Top();
964 Union(rRect
,aPntStart
);
965 Union(rRect
,aPntEnd
);
966 if ((a
<=18000 && e
>=18000) || (a
>e
&& (a
<=18000 || e
>=18000))) {
967 Union(rRect
,aRect
.LeftCenter());
969 if ((a
<=27000 && e
>=27000) || (a
>e
&& (a
<=27000 || e
>=27000))) {
970 Union(rRect
,aRect
.BottomCenter());
973 Union(rRect
,aRect
.RightCenter());
975 if ((a
<=9000 && e
>=9000) || (a
>e
&& (a
<=9000 || e
>=9000))) {
976 Union(rRect
,aRect
.TopCenter());
978 if (meCircleKind
==OBJ_SECT
) {
979 Union(rRect
,aRect
.Center());
981 if (aGeo
.nDrehWink
!=0) {
982 Point
aDst(rRect
.TopLeft());
983 aDst
-=aRect
.TopLeft();
985 RotatePoint(aDst
,Point(),aGeo
.nSin
,aGeo
.nCos
);
987 rRect
.Move(aDst
.X(),aDst
.Y());
990 if (aGeo
.nShearWink
!=0) {
991 long nDst
=Round((rRect
.Bottom()-rRect
.Top())*aGeo
.nTan
);
992 if (aGeo
.nShearWink
>0) {
993 Point
aRef(rRect
.TopLeft());
995 Point
aTmpPt(rRect
.TopLeft());
996 RotatePoint(aTmpPt
,aRef
,aGeo
.nSin
,aGeo
.nCos
);
997 aTmpPt
-=rRect
.TopLeft();
998 rRect
.Move(aTmpPt
.X(),aTmpPt
.Y());
1000 rRect
.Right()-=nDst
;
1005 void SdrCircObj::RecalcSnapRect()
1007 if (PaintNeedsXPolyCirc()) {
1008 maSnapRect
=GetXPoly().GetBoundRect();
1010 TakeUnrotatedSnapRect(maSnapRect
);
1014 void SdrCircObj::NbcSetSnapRect(const Rectangle
& rRect
)
1016 if (aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0 || meCircleKind
!=OBJ_CIRC
) {
1017 Rectangle
aSR0(GetSnapRect());
1018 long nWdt0
=aSR0
.Right()-aSR0
.Left();
1019 long nHgt0
=aSR0
.Bottom()-aSR0
.Top();
1020 long nWdt1
=rRect
.Right()-rRect
.Left();
1021 long nHgt1
=rRect
.Bottom()-rRect
.Top();
1022 NbcResize(maSnapRect
.TopLeft(),Fraction(nWdt1
,nWdt0
),Fraction(nHgt1
,nHgt0
));
1023 NbcMove(Size(rRect
.Left()-aSR0
.Left(),rRect
.Top()-aSR0
.Top()));
1026 ImpJustifyRect(aRect
);
1030 ImpSetCircInfoToAttr();
1033 sal_uInt32
SdrCircObj::GetSnapPointCount() const
1035 if (meCircleKind
==OBJ_CIRC
) {
1042 Point
SdrCircObj::GetSnapPoint(sal_uInt32 i
) const
1045 case 1 : return GetWinkPnt(aRect
,nStartWink
);
1046 case 2 : return GetWinkPnt(aRect
,nEndWink
);
1047 default: return aRect
.Center();
1051 void __EXPORT
SdrCircObj::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
1054 SdrRectObj::Notify(rBC
,rHint
);
1055 ImpSetAttrToCircInfo();
1058 ////////////////////////////////////////////////////////////////////////////////////////////////////
1060 void SdrCircObj::ImpSetAttrToCircInfo()
1062 const SfxItemSet
& rSet
= GetObjectItemSet();
1063 SdrCircKind eNewKindA
= ((SdrCircKindItem
&)rSet
.Get(SDRATTR_CIRCKIND
)).GetValue();
1064 SdrObjKind eNewKind
= meCircleKind
;
1066 if(eNewKindA
== SDRCIRC_FULL
)
1067 eNewKind
= OBJ_CIRC
;
1068 else if(eNewKindA
== SDRCIRC_SECT
)
1069 eNewKind
= OBJ_SECT
;
1070 else if(eNewKindA
== SDRCIRC_ARC
)
1071 eNewKind
= OBJ_CARC
;
1072 else if(eNewKindA
== SDRCIRC_CUT
)
1073 eNewKind
= OBJ_CCUT
;
1075 sal_Int32 nNewStart
= ((SdrCircStartAngleItem
&)rSet
.Get(SDRATTR_CIRCSTARTANGLE
)).GetValue();
1076 sal_Int32 nNewEnd
= ((SdrCircEndAngleItem
&)rSet
.Get(SDRATTR_CIRCENDANGLE
)).GetValue();
1078 BOOL bKindChg
= meCircleKind
!= eNewKind
;
1079 BOOL bWinkChg
= nNewStart
!= nStartWink
|| nNewEnd
!= nEndWink
;
1081 if(bKindChg
|| bWinkChg
)
1083 meCircleKind
= eNewKind
;
1084 nStartWink
= nNewStart
;
1087 if(bKindChg
|| (meCircleKind
!= OBJ_CIRC
&& bWinkChg
))
1095 void SdrCircObj::ImpSetCircInfoToAttr()
1097 SdrCircKind eNewKindA
= SDRCIRC_FULL
;
1098 const SfxItemSet
& rSet
= GetObjectItemSet();
1100 if(meCircleKind
== OBJ_SECT
)
1101 eNewKindA
= SDRCIRC_SECT
;
1102 else if(meCircleKind
== OBJ_CARC
)
1103 eNewKindA
= SDRCIRC_ARC
;
1104 else if(meCircleKind
== OBJ_CCUT
)
1105 eNewKindA
= SDRCIRC_CUT
;
1107 SdrCircKind eOldKindA
= ((SdrCircKindItem
&)rSet
.Get(SDRATTR_CIRCKIND
)).GetValue();
1108 sal_Int32 nOldStartWink
= ((SdrCircStartAngleItem
&)rSet
.Get(SDRATTR_CIRCSTARTANGLE
)).GetValue();
1109 sal_Int32 nOldEndWink
= ((SdrCircEndAngleItem
&)rSet
.Get(SDRATTR_CIRCENDANGLE
)).GetValue();
1111 if(eNewKindA
!= eOldKindA
|| nStartWink
!= nOldStartWink
|| nEndWink
!= nOldEndWink
)
1113 // #81921# since SetItem() implicitly calls ImpSetAttrToCircInfo()
1114 // setting the item directly is necessary here.
1115 if(eNewKindA
!= eOldKindA
)
1117 GetProperties().SetObjectItemDirect(SdrCircKindItem(eNewKindA
));
1120 if(nStartWink
!= nOldStartWink
)
1122 GetProperties().SetObjectItemDirect(SdrCircStartAngleItem(nStartWink
));
1125 if(nEndWink
!= nOldEndWink
)
1127 GetProperties().SetObjectItemDirect(SdrCircEndAngleItem(nEndWink
));
1131 ImpSetAttrToCircInfo();
1135 SdrObject
* SdrCircObj::DoConvertToPolyObj(BOOL bBezier
) const
1137 const sal_Bool
bFill(OBJ_CARC
== meCircleKind
? sal_False
: sal_True
);
1138 const basegfx::B2DPolygon
aCircPolygon(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
1139 SdrObject
* pRet
= ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon
), bFill
, bBezier
);
1140 pRet
= ImpConvertAddText(pRet
, bBezier
);
1145 //////////////////////////////////////////////////////////////////////////////