update dev300-m58
[ooovba.git] / svx / source / svdraw / svdocirc.cxx
blobb37e327ed1f43cc7d1f07bcf7086612e7855c8f6
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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>
41 #include <math.h>
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;
73 double a;
74 a=nWink*nPi180;
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;
78 if (nWdt!=nHgt) {
79 if (nWdt>nHgt) {
80 if (nWdt!=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);
84 } else {
85 aRetval.Y()=aRetval.Y()*nHgt/nWdt;
88 } else {
89 if (nHgt!=0) {
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);
93 } else {
94 aRetval.X()=aRetval.X()*nWdt/nHgt;
99 aRetval+=aCenter;
100 return aRetval;
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)
125 nStartWink=0;
126 nEndWink=36000;
127 meCircleKind=eNewKind;
128 bClosedObj=eNewKind!=OBJ_CARC;
131 SdrCircObj::SdrCircObj(SdrObjKind eNewKind, const Rectangle& rRect):
132 SdrRectObj(rRect)
134 nStartWink=0;
135 nEndWink=36000;
136 meCircleKind=eNewKind;
137 bClosedObj=eNewKind!=OBJ_CARC;
140 SdrCircObj::SdrCircObj(SdrObjKind eNewKind, const Rectangle& rRect, long nNewStartWink, long nNewEndWink):
141 SdrRectObj(rRect)
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;
176 #ifndef WIN
177 // Wenn nicht Win, dann fuer alle ausser Vollkreis (erstmal!!!)
178 if (meCircleKind!=OBJ_CIRC) bNeed=TRUE;
179 #endif
181 const SfxItemSet& rSet = GetObjectItemSet();
182 if(!bNeed)
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;
199 if(!bNeed)
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
218 return bNeed;
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);
248 else
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);
261 if(bCloseSegment)
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;
272 // close
273 aCircPolygon.setClosed(true);
277 // #i76950#
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());
286 // shear (if needed)
287 if(aGeo.nShearWink)
289 aMatrix.shearX(tan((36000 - aGeo.nShearWink) * F_PI18000));
292 // rotate (if needed)
293 if(aGeo.nDrehWink)
295 aMatrix.rotate((36000 - aGeo.nDrehWink) * F_PI18000);
298 // back to top left
299 aMatrix.translate(aTopLeft.getX(), aTopLeft.getY());
301 // apply transformation
302 aCircPolygon.transform(aMatrix);
305 return aCircPolygon;
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;
323 default: break;
325 } else {
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;
331 default: break;
334 rName=ImpGetResStr(nID);
336 String aName( GetName() );
337 if(aName.Len())
339 rName += sal_Unicode(' ');
340 rName += sal_Unicode('\'');
341 rName += aName;
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;
355 default: break;
357 } else {
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;
363 default: 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
385 Rectangle aR;
386 Point aCenter;
387 Point aRadius;
388 Point aP1;
389 Point aP2;
390 long nMaxRad;
391 long nHgt;
392 long nWdt;
393 long nStart;
394 long nEnd;
395 long nWink;
396 FASTBOOL bRight; // noch nicht implementiert
398 public:
399 ImpCircUser()
400 : nMaxRad(0),
401 nHgt(0),
402 nWdt(0),
403 nStart(0),
404 nEnd(0),
405 bRight(FALSE)
407 void SetCreateParams(SdrDragStat& rStat);
410 sal_uInt32 SdrCircObj::GetHdlCount() const
412 if(OBJ_CIRC != meCircleKind)
414 return 10L;
416 else
418 return 8L;
422 SdrHdl* SdrCircObj::GetHdl(sal_uInt32 nHdlNum) const
424 if (meCircleKind==OBJ_CIRC)
426 nHdlNum += 2L;
429 SdrHdl* pH = NULL;
430 Point aPnt;
431 SdrHdlKind eLocalKind(HDL_MOVE);
432 sal_uInt32 nPNum(0);
434 switch (nHdlNum)
436 case 0:
437 aPnt = GetWinkPnt(aRect,nStartWink);
438 eLocalKind = HDL_CIRC;
439 nPNum = 1;
440 break;
441 case 1:
442 aPnt = GetWinkPnt(aRect,nEndWink);
443 eLocalKind = HDL_CIRC;
444 nPNum = 2L;
445 break;
446 case 2:
447 aPnt = aRect.TopLeft();
448 eLocalKind = HDL_UPLFT;
449 break;
450 case 3:
451 aPnt = aRect.TopCenter();
452 eLocalKind = HDL_UPPER;
453 break;
454 case 4:
455 aPnt = aRect.TopRight();
456 eLocalKind = HDL_UPRGT;
457 break;
458 case 5:
459 aPnt = aRect.LeftCenter();
460 eLocalKind = HDL_LEFT;
461 break;
462 case 6:
463 aPnt = aRect.RightCenter();
464 eLocalKind = HDL_RIGHT;
465 break;
466 case 7:
467 aPnt = aRect.BottomLeft();
468 eLocalKind = HDL_LWLFT;
469 break;
470 case 8:
471 aPnt = aRect.BottomCenter();
472 eLocalKind = HDL_LOWER;
473 break;
474 case 9:
475 aPnt = aRect.BottomRight();
476 eLocalKind = HDL_LWRGT;
477 break;
480 if (aGeo.nShearWink)
482 ShearPoint(aPnt,aRect.TopLeft(),aGeo.nTan);
485 if (aGeo.nDrehWink)
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);
498 return pH;
501 ////////////////////////////////////////////////////////////////////////////////////////////////////
503 bool SdrCircObj::hasSpecialDrag() const
505 return true;
508 bool SdrCircObj::beginSpecialDrag(SdrDragStat& rDrag) const
510 const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
512 if(bWink)
514 if(1 == rDrag.GetHdl()->GetPointNum() || 2 == rDrag.GetHdl()->GetPointNum())
516 rDrag.SetNoSnap(true);
519 return true;
522 return SdrTextObj::beginSpecialDrag(rDrag);
525 bool SdrCircObj::applySpecialDrag(SdrDragStat& rDrag)
527 const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
529 if(bWink)
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);
539 aPt-=aRect.Center();
541 long nWdt=aRect.Right()-aRect.Left();
542 long nHgt=aRect.Bottom()-aRect.Top();
544 if(nWdt>=nHgt)
546 aPt.Y()=BigMulDiv(aPt.Y(),nWdt,nHgt);
548 else
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();
559 if (nSA!=0)
561 nWink+=nSA/2;
562 nWink/=nSA;
563 nWink*=nSA;
564 nWink=NormAngle360(nWink);
568 if(1 == rDrag.GetHdl()->GetPointNum())
570 nStartWink = nWink;
572 else if(2 == rDrag.GetHdl()->GetPointNum())
574 nEndWink = nWink;
577 SetRectsDirty();
578 SetXPolyDirty();
579 ImpSetCircInfoToAttr();
580 SetChanged();
582 return true;
584 else
586 return SdrTextObj::applySpecialDrag(rDrag);
590 String SdrCircObj::getSpecialDragComment(const SdrDragStat& rDrag) const
592 const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
594 if(bWink)
596 XubString aStr;
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(')');
604 return aStr;
606 else
608 return SdrTextObj::getSpecialDragComment(rDrag);
612 ////////////////////////////////////////////////////////////////////////////////////////////////////
614 void ImpCircUser::SetCreateParams(SdrDragStat& rStat)
616 rStat.TakeCreateRect(aR);
617 aR.Justify();
618 aCenter=aR.Center();
619 nWdt=aR.Right()-aR.Left();
620 nHgt=aR.Bottom()-aR.Top();
621 nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
622 nStart=0;
623 nEnd=36000;
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;
628 if (nWdt>=nHgt) {
629 if (nHgt!=0) aP.Y()=aP.Y()*nWdt/nHgt;
630 } else {
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
637 nStart+=nSA/2;
638 nStart/=nSA;
639 nStart*=nSA;
640 nStart=NormAngle360(nStart);
643 aP1 = GetWinkPnt(aR,nStart);
644 nEnd=nStart;
645 aP2=aP1;
646 } else aP1=aCenter;
647 if (rStat.GetPointAnz()>3) {
648 Point aP(rStat.GetPoint(3)-aCenter);
649 if (nWdt>=nHgt) {
650 aP.Y()=BigMulDiv(aP.Y(),nWdt,nHgt);
651 } else {
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
658 nEnd+=nSA/2;
659 nEnd/=nSA;
660 nEnd*=nSA;
661 nEnd=NormAngle360(nEnd);
664 aP2 = GetWinkPnt(aR,nEnd);
665 } else aP2=aCenter;
668 void SdrCircObj::ImpSetCreateParams(SdrDragStat& rStat) const
670 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
671 if (pU==NULL) {
672 pU=new ImpCircUser;
673 rStat.SetUser(pU);
675 pU->SetCreateParams(rStat);
678 FASTBOOL SdrCircObj::BegCreate(SdrDragStat& rStat)
680 rStat.SetOrtho4Possible();
681 Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
682 aRect1.Justify();
683 rStat.SetActionRect(aRect1);
684 aRect = aRect1;
685 ImpSetCreateParams(rStat);
686 return TRUE;
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;
697 nEndWink=pU->nEnd;
698 SetBoundRectDirty();
699 bSnapRectDirty=TRUE;
700 SetXPolyDirty();
701 return TRUE;
704 FASTBOOL SdrCircObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
706 ImpSetCreateParams(rStat);
707 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
708 FASTBOOL bRet=FALSE;
709 if (eCmd==SDRCREATE_FORCEEND && rStat.GetPointAnz()<4) meCircleKind=OBJ_CIRC;
710 if (meCircleKind==OBJ_CIRC) {
711 bRet=rStat.GetPointAnz()>=2;
712 if (bRet) {
713 aRect=pU->aR;
714 ImpJustifyRect(aRect);
716 } else {
717 rStat.SetNoSnap(rStat.GetPointAnz()>=2);
718 rStat.SetOrtho4Possible(rStat.GetPointAnz()<2);
719 bRet=rStat.GetPointAnz()>=4;
720 if (bRet) {
721 aRect=pU->aR;
722 ImpJustifyRect(aRect);
723 nStartWink=pU->nStart;
724 nEndWink=pU->nEnd;
727 bClosedObj=meCircleKind!=OBJ_CARC;
728 SetRectsDirty();
729 SetXPolyDirty();
730 ImpSetCircInfoToAttr();
731 if (bRet) {
732 delete pU;
733 rStat.SetUser(NULL);
735 return bRet;
738 void SdrCircObj::BrkCreate(SdrDragStat& rStat)
740 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
741 delete pU;
742 rStat.SetUser(NULL);
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);
771 return aRetval;
773 else
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);
786 default: break;
787 } // switch
788 return Pointer(POINTER_CROSS);
791 void SdrCircObj::NbcMove(const Size& aSiz)
793 MoveRect(aRect,aSiz);
794 MoveRect(aOutRect,aSiz);
795 MoveRect(maSnapRect,aSiz);
796 SetXPolyDirty();
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, ...).
815 long nS0=nStartWink;
816 long nE0=nEndWink;
817 if (bNoShearRota) {
818 // Das RectObj spiegelt bei VMirror bereits durch durch 180deg Drehung.
819 if (! (bXMirr && bYMirr)) {
820 long nTmp=nS0;
821 nS0=18000-nE0;
822 nE0=18000-nTmp;
824 } else { // Spiegeln fuer verzerrte Ellipsen
825 if (bXMirr!=bYMirr) {
826 nS0+=nWink0;
827 nE0+=nWink0;
828 if (bXMirr) {
829 long nTmp=nS0;
830 nS0=18000-nE0;
831 nE0=18000-nTmp;
833 if (bYMirr) {
834 long nTmp=nS0;
835 nS0=-nE0;
836 nE0=-nTmp;
838 nS0-=aGeo.nDrehWink;
839 nE0-=aGeo.nDrehWink;
842 long nWinkDif=nE0-nS0;
843 nStartWink=NormAngle360(nS0);
844 nEndWink =NormAngle360(nE0);
845 if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis
848 SetXPolyDirty();
849 ImpSetCircInfoToAttr();
852 void SdrCircObj::NbcShear(const Point& rRef, long nWink, double tn, FASTBOOL bVShear)
854 SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
855 SetXPolyDirty();
856 ImpSetCircInfoToAttr();
859 void SdrCircObj::NbcMirror(const Point& rRef1, const Point& rRef2)
861 //long nWink0=aGeo.nDrehWink;
862 FASTBOOL bFreeMirr=meCircleKind!=OBJ_CIRC;
863 Point aTmpPt1;
864 Point aTmpPt2;
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;
870 double a;
871 // Startpunkt
872 a=nStartWink*nPi180;
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;
876 aTmpPt1+=aCenter;
877 // Endpunkt
878 a=nEndWink*nPi180;
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;
882 aTmpPt2+=aCenter;
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);
896 // Unrotate:
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
901 // Unshear:
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());
907 aTmpPt1-=aCenter;
908 aTmpPt2-=aCenter;
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
917 SetXPolyDirty();
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;
940 SetXPolyDirty();
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
954 rRect=aRect;
955 if (meCircleKind!=OBJ_CIRC) {
956 const Point aPntStart(GetWinkPnt(aRect,nStartWink));
957 const Point aPntEnd(GetWinkPnt(aRect,nEndWink));
958 long a=nStartWink;
959 long e=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());
972 if (a>e) {
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();
984 Point aDst0(aDst);
985 RotatePoint(aDst,Point(),aGeo.nSin,aGeo.nCos);
986 aDst-=aDst0;
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());
994 rRect.Left()-=nDst;
995 Point aTmpPt(rRect.TopLeft());
996 RotatePoint(aTmpPt,aRef,aGeo.nSin,aGeo.nCos);
997 aTmpPt-=rRect.TopLeft();
998 rRect.Move(aTmpPt.X(),aTmpPt.Y());
999 } else {
1000 rRect.Right()-=nDst;
1005 void SdrCircObj::RecalcSnapRect()
1007 if (PaintNeedsXPolyCirc()) {
1008 maSnapRect=GetXPoly().GetBoundRect();
1009 } else {
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()));
1024 } else {
1025 aRect=rRect;
1026 ImpJustifyRect(aRect);
1028 SetRectsDirty();
1029 SetXPolyDirty();
1030 ImpSetCircInfoToAttr();
1033 sal_uInt32 SdrCircObj::GetSnapPointCount() const
1035 if (meCircleKind==OBJ_CIRC) {
1036 return 1L;
1037 } else {
1038 return 3L;
1042 Point SdrCircObj::GetSnapPoint(sal_uInt32 i) const
1044 switch (i) {
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)
1053 SetXPolyDirty();
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;
1085 nEndWink = nNewEnd;
1087 if(bKindChg || (meCircleKind != OBJ_CIRC && bWinkChg))
1089 SetXPolyDirty();
1090 SetRectsDirty();
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));
1130 SetXPolyDirty();
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);
1142 return pRet;
1145 //////////////////////////////////////////////////////////////////////////////
1146 // eof