Update ooo320-m1
[ooovba.git] / svx / source / svdraw / svdocirc.cxx
blob363fa04a3c5045797279c5f05ea272558fd8a3cb
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 bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
594 if(bCreateComment)
596 XubString aStr;
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();
603 sal_Int32 nWink;
605 aStr.AppendAscii(" (");
607 if(3 == nPntAnz)
609 nWink = pU->nStart;
611 else
613 nWink = pU->nEnd;
616 aStr += GetWinkStr(nWink,FALSE);
617 aStr += sal_Unicode(')');
620 return aStr;
622 else
624 const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
626 if(bWink)
628 XubString aStr;
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(')');
636 return aStr;
638 else
640 return SdrTextObj::getSpecialDragComment(rDrag);
645 ////////////////////////////////////////////////////////////////////////////////////////////////////
647 void ImpCircUser::SetCreateParams(SdrDragStat& rStat)
649 rStat.TakeCreateRect(aR);
650 aR.Justify();
651 aCenter=aR.Center();
652 nWdt=aR.Right()-aR.Left();
653 nHgt=aR.Bottom()-aR.Top();
654 nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
655 nStart=0;
656 nEnd=36000;
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;
661 if (nWdt>=nHgt) {
662 if (nHgt!=0) aP.Y()=aP.Y()*nWdt/nHgt;
663 } else {
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
670 nStart+=nSA/2;
671 nStart/=nSA;
672 nStart*=nSA;
673 nStart=NormAngle360(nStart);
676 aP1 = GetWinkPnt(aR,nStart);
677 nEnd=nStart;
678 aP2=aP1;
679 } else aP1=aCenter;
680 if (rStat.GetPointAnz()>3) {
681 Point aP(rStat.GetPoint(3)-aCenter);
682 if (nWdt>=nHgt) {
683 aP.Y()=BigMulDiv(aP.Y(),nWdt,nHgt);
684 } else {
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
691 nEnd+=nSA/2;
692 nEnd/=nSA;
693 nEnd*=nSA;
694 nEnd=NormAngle360(nEnd);
697 aP2 = GetWinkPnt(aR,nEnd);
698 } else aP2=aCenter;
701 void SdrCircObj::ImpSetCreateParams(SdrDragStat& rStat) const
703 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
704 if (pU==NULL) {
705 pU=new ImpCircUser;
706 rStat.SetUser(pU);
708 pU->SetCreateParams(rStat);
711 FASTBOOL SdrCircObj::BegCreate(SdrDragStat& rStat)
713 rStat.SetOrtho4Possible();
714 Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
715 aRect1.Justify();
716 rStat.SetActionRect(aRect1);
717 aRect = aRect1;
718 ImpSetCreateParams(rStat);
719 return TRUE;
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;
730 nEndWink=pU->nEnd;
731 SetBoundRectDirty();
732 bSnapRectDirty=TRUE;
733 SetXPolyDirty();
735 // #i103058# push current angle settings to ItemSet to
736 // allow FullDrag visualisation
737 if(rStat.GetPointAnz() >= 4)
739 ImpSetCircInfoToAttr();
742 return TRUE;
745 FASTBOOL SdrCircObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
747 ImpSetCreateParams(rStat);
748 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
749 FASTBOOL bRet=FALSE;
750 if (eCmd==SDRCREATE_FORCEEND && rStat.GetPointAnz()<4) meCircleKind=OBJ_CIRC;
751 if (meCircleKind==OBJ_CIRC) {
752 bRet=rStat.GetPointAnz()>=2;
753 if (bRet) {
754 aRect=pU->aR;
755 ImpJustifyRect(aRect);
757 } else {
758 rStat.SetNoSnap(rStat.GetPointAnz()>=2);
759 rStat.SetOrtho4Possible(rStat.GetPointAnz()<2);
760 bRet=rStat.GetPointAnz()>=4;
761 if (bRet) {
762 aRect=pU->aR;
763 ImpJustifyRect(aRect);
764 nStartWink=pU->nStart;
765 nEndWink=pU->nEnd;
768 bClosedObj=meCircleKind!=OBJ_CARC;
769 SetRectsDirty();
770 SetXPolyDirty();
771 ImpSetCircInfoToAttr();
772 if (bRet) {
773 delete pU;
774 rStat.SetUser(NULL);
776 return bRet;
779 void SdrCircObj::BrkCreate(SdrDragStat& rStat)
781 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
782 delete pU;
783 rStat.SetUser(NULL);
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);
812 return aRetval;
814 else
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);
827 default: break;
828 } // switch
829 return Pointer(POINTER_CROSS);
832 void SdrCircObj::NbcMove(const Size& aSiz)
834 MoveRect(aRect,aSiz);
835 MoveRect(aOutRect,aSiz);
836 MoveRect(maSnapRect,aSiz);
837 SetXPolyDirty();
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, ...).
856 long nS0=nStartWink;
857 long nE0=nEndWink;
858 if (bNoShearRota) {
859 // Das RectObj spiegelt bei VMirror bereits durch durch 180deg Drehung.
860 if (! (bXMirr && bYMirr)) {
861 long nTmp=nS0;
862 nS0=18000-nE0;
863 nE0=18000-nTmp;
865 } else { // Spiegeln fuer verzerrte Ellipsen
866 if (bXMirr!=bYMirr) {
867 nS0+=nWink0;
868 nE0+=nWink0;
869 if (bXMirr) {
870 long nTmp=nS0;
871 nS0=18000-nE0;
872 nE0=18000-nTmp;
874 if (bYMirr) {
875 long nTmp=nS0;
876 nS0=-nE0;
877 nE0=-nTmp;
879 nS0-=aGeo.nDrehWink;
880 nE0-=aGeo.nDrehWink;
883 long nWinkDif=nE0-nS0;
884 nStartWink=NormAngle360(nS0);
885 nEndWink =NormAngle360(nE0);
886 if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis
889 SetXPolyDirty();
890 ImpSetCircInfoToAttr();
893 void SdrCircObj::NbcShear(const Point& rRef, long nWink, double tn, FASTBOOL bVShear)
895 SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
896 SetXPolyDirty();
897 ImpSetCircInfoToAttr();
900 void SdrCircObj::NbcMirror(const Point& rRef1, const Point& rRef2)
902 //long nWink0=aGeo.nDrehWink;
903 FASTBOOL bFreeMirr=meCircleKind!=OBJ_CIRC;
904 Point aTmpPt1;
905 Point aTmpPt2;
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;
911 double a;
912 // Startpunkt
913 a=nStartWink*nPi180;
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;
917 aTmpPt1+=aCenter;
918 // Endpunkt
919 a=nEndWink*nPi180;
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;
923 aTmpPt2+=aCenter;
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);
937 // Unrotate:
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
942 // Unshear:
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());
948 aTmpPt1-=aCenter;
949 aTmpPt2-=aCenter;
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
958 SetXPolyDirty();
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;
981 SetXPolyDirty();
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
995 rRect=aRect;
996 if (meCircleKind!=OBJ_CIRC) {
997 const Point aPntStart(GetWinkPnt(aRect,nStartWink));
998 const Point aPntEnd(GetWinkPnt(aRect,nEndWink));
999 long a=nStartWink;
1000 long e=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());
1013 if (a>e) {
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();
1025 Point aDst0(aDst);
1026 RotatePoint(aDst,Point(),aGeo.nSin,aGeo.nCos);
1027 aDst-=aDst0;
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());
1035 rRect.Left()-=nDst;
1036 Point aTmpPt(rRect.TopLeft());
1037 RotatePoint(aTmpPt,aRef,aGeo.nSin,aGeo.nCos);
1038 aTmpPt-=rRect.TopLeft();
1039 rRect.Move(aTmpPt.X(),aTmpPt.Y());
1040 } else {
1041 rRect.Right()-=nDst;
1046 void SdrCircObj::RecalcSnapRect()
1048 if (PaintNeedsXPolyCirc()) {
1049 maSnapRect=GetXPoly().GetBoundRect();
1050 } else {
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()));
1065 } else {
1066 aRect=rRect;
1067 ImpJustifyRect(aRect);
1069 SetRectsDirty();
1070 SetXPolyDirty();
1071 ImpSetCircInfoToAttr();
1074 sal_uInt32 SdrCircObj::GetSnapPointCount() const
1076 if (meCircleKind==OBJ_CIRC) {
1077 return 1L;
1078 } else {
1079 return 3L;
1083 Point SdrCircObj::GetSnapPoint(sal_uInt32 i) const
1085 switch (i) {
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)
1094 SetXPolyDirty();
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;
1126 nEndWink = nNewEnd;
1128 if(bKindChg || (meCircleKind != OBJ_CIRC && bWinkChg))
1130 SetXPolyDirty();
1131 SetRectsDirty();
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));
1171 SetXPolyDirty();
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);
1183 return pRet;
1186 //////////////////////////////////////////////////////////////////////////////
1187 // eof