summaryrefslogtreecommitdiff
path: root/svx/source/svdraw/svdocirc.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/svdraw/svdocirc.cxx')
-rw-r--r--svx/source/svdraw/svdocirc.cxx1169
1 files changed, 1169 insertions, 0 deletions
diff --git a/svx/source/svdraw/svdocirc.cxx b/svx/source/svdraw/svdocirc.cxx
new file mode 100644
index 000000000000..d28039cf1989
--- /dev/null
+++ b/svx/source/svdraw/svdocirc.cxx
@@ -0,0 +1,1169 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svx.hxx"
+#include <svl/style.hxx>
+#include <tools/bigint.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/svdocirc.hxx>
+#include <math.h>
+#include <svx/xpool.hxx>
+#include <svx/svdattr.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdattrx.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdopath.hxx> // fuer die Objektkonvertierung
+#include <svx/svdview.hxx> // Zum Draggen (Ortho)
+#include "svx/svdglob.hxx" // StringCache
+#include "svx/svdstr.hrc" // Objektname
+#include <editeng/eeitem.hxx>
+#include "svdoimp.hxx"
+#include <svx/sdr/properties/circleproperties.hxx>
+#include <svx/sdr/contact/viewcontactofsdrcircobj.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+Point GetWinkPnt(const Rectangle& rR, long nWink)
+{
+ Point aCenter(rR.Center());
+ long nWdt=rR.Right()-rR.Left();
+ long nHgt=rR.Bottom()-rR.Top();
+ long nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
+ double a;
+ a=nWink*nPi180;
+ Point aRetval(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad));
+ if (nWdt==0) aRetval.X()=0;
+ if (nHgt==0) aRetval.Y()=0;
+ if (nWdt!=nHgt) {
+ if (nWdt>nHgt) {
+ if (nWdt!=0) {
+ // eventuelle Ueberlaeufe bei sehr grossen Objekten abfangen (Bug 23384)
+ if (Abs(nHgt)>32767 || Abs(aRetval.Y())>32767) {
+ aRetval.Y()=BigMulDiv(aRetval.Y(),nHgt,nWdt);
+ } else {
+ aRetval.Y()=aRetval.Y()*nHgt/nWdt;
+ }
+ }
+ } else {
+ if (nHgt!=0) {
+ // eventuelle Ueberlaeufe bei sehr grossen Objekten abfangen (Bug 23384)
+ if (Abs(nWdt)>32767 || Abs(aRetval.X())>32767) {
+ aRetval.X()=BigMulDiv(aRetval.X(),nWdt,nHgt);
+ } else {
+ aRetval.X()=aRetval.X()*nWdt/nHgt;
+ }
+ }
+ }
+ }
+ aRetval+=aCenter;
+ return aRetval;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// BaseProperties section
+
+sdr::properties::BaseProperties* SdrCircObj::CreateObjectSpecificProperties()
+{
+ return new sdr::properties::CircleProperties(*this);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// DrawContact section
+
+sdr::contact::ViewContact* SdrCircObj::CreateObjectSpecificViewContact()
+{
+ return new sdr::contact::ViewContactOfSdrCircObj(*this);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+TYPEINIT1(SdrCircObj,SdrRectObj);
+
+SdrCircObj::SdrCircObj(SdrObjKind eNewKind)
+{
+ nStartWink=0;
+ nEndWink=36000;
+ meCircleKind=eNewKind;
+ bClosedObj=eNewKind!=OBJ_CARC;
+}
+
+SdrCircObj::SdrCircObj(SdrObjKind eNewKind, const Rectangle& rRect):
+ SdrRectObj(rRect)
+{
+ nStartWink=0;
+ nEndWink=36000;
+ meCircleKind=eNewKind;
+ bClosedObj=eNewKind!=OBJ_CARC;
+}
+
+SdrCircObj::SdrCircObj(SdrObjKind eNewKind, const Rectangle& rRect, long nNewStartWink, long nNewEndWink):
+ SdrRectObj(rRect)
+{
+ long nWinkDif=nNewEndWink-nNewStartWink;
+ nStartWink=NormAngle360(nNewStartWink);
+ nEndWink=NormAngle360(nNewEndWink);
+ if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis
+ meCircleKind=eNewKind;
+ bClosedObj=eNewKind!=OBJ_CARC;
+}
+
+SdrCircObj::~SdrCircObj()
+{
+}
+
+void SdrCircObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ FASTBOOL bCanConv=!HasText() || ImpCanConvTextToCurve();
+ rInfo.bEdgeRadiusAllowed = FALSE;
+ rInfo.bCanConvToPath=bCanConv;
+ rInfo.bCanConvToPoly=bCanConv;
+ rInfo.bCanConvToContour = !IsFontwork() && (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
+}
+
+UINT16 SdrCircObj::GetObjIdentifier() const
+{
+ return UINT16(meCircleKind);
+}
+
+FASTBOOL SdrCircObj::PaintNeedsXPolyCirc() const
+{
+ // XPoly ist notwendig fuer alle gedrehten Ellipsenobjekte,
+ // fuer alle Kreis- und Ellipsenabschnitte
+ // und wenn nicht WIN dann (erstmal) auch fuer Kreis-/Ellipsenausschnitte
+ // und Kreis-/Ellipsenboegen (wg. Genauigkeit)
+ FASTBOOL bNeed=aGeo.nDrehWink!=0 || aGeo.nShearWink!=0 || meCircleKind==OBJ_CCUT;
+ // Wenn nicht Win, dann fuer alle ausser Vollkreis (erstmal!!!)
+ if (meCircleKind!=OBJ_CIRC) bNeed=TRUE;
+
+ const SfxItemSet& rSet = GetObjectItemSet();
+ if(!bNeed)
+ {
+ // XPoly ist notwendig fuer alles was nicht LineSolid oder LineNone ist
+ XLineStyle eLine = ((XLineStyleItem&)(rSet.Get(XATTR_LINESTYLE))).GetValue();
+ bNeed = eLine != XLINE_NONE && eLine != XLINE_SOLID;
+
+ // XPoly ist notwendig fuer dicke Linien
+ if(!bNeed && eLine != XLINE_NONE)
+ bNeed = ((XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue() != 0;
+
+ // XPoly ist notwendig fuer Kreisboegen mit Linienenden
+ if(!bNeed && meCircleKind == OBJ_CARC)
+ {
+ // Linienanfang ist da, wenn StartPolygon und StartWidth!=0
+ bNeed=((XLineStartItem&)(rSet.Get(XATTR_LINESTART))).GetLineStartValue().count() != 0L &&
+ ((XLineStartWidthItem&)(rSet.Get(XATTR_LINESTARTWIDTH))).GetValue() != 0;
+
+ if(!bNeed)
+ {
+ // Linienende ist da, wenn EndPolygon und EndWidth!=0
+ bNeed = ((XLineEndItem&)(rSet.Get(XATTR_LINEEND))).GetLineEndValue().count() != 0L &&
+ ((XLineEndWidthItem&)(rSet.Get(XATTR_LINEENDWIDTH))).GetValue() != 0;
+ }
+ }
+ }
+
+ // XPoly ist notwendig, wenn Fill !=None und !=Solid
+ if(!bNeed && meCircleKind != OBJ_CARC)
+ {
+ XFillStyle eFill=((XFillStyleItem&)(rSet.Get(XATTR_FILLSTYLE))).GetValue();
+ bNeed = eFill != XFILL_NONE && eFill != XFILL_SOLID;
+ }
+
+ if(!bNeed && meCircleKind != OBJ_CIRC && nStartWink == nEndWink)
+ bNeed=TRUE; // Weil sonst Vollkreis gemalt wird
+
+ return bNeed;
+}
+
+basegfx::B2DPolygon SdrCircObj::ImpCalcXPolyCirc(const SdrObjKind eCicrleKind, const Rectangle& rRect1, long nStart, long nEnd) const
+{
+ const basegfx::B2DRange aRange(rRect1.Left(), rRect1.Top(), rRect1.Right(), rRect1.Bottom());
+ basegfx::B2DPolygon aCircPolygon;
+
+ if(OBJ_CIRC == eCicrleKind)
+ {
+ // create full circle. Do not use createPolygonFromEllipse; it's necessary
+ // to get the start point to the bottom of the circle to keep compatible to
+ // old geometry creation
+ aCircPolygon = basegfx::tools::createPolygonFromUnitCircle(1);
+
+ // needs own scaling and translation from unit circle to target size (same as
+ // would be in createPolygonFromEllipse)
+ const basegfx::B2DPoint aCenter(aRange.getCenter());
+ const basegfx::B2DHomMatrix aMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix(
+ aRange.getWidth() / 2.0, aRange.getHeight() / 2.0,
+ aCenter.getX(), aCenter.getY()));
+ aCircPolygon.transform(aMatrix);
+ }
+ else
+ {
+ // mirror start, end for geometry creation since model coordinate system is mirrored in Y
+ // #i111715# increase numerical correctness by first dividing and not using F_PI1800
+ const double fStart((((36000 - nEnd) % 36000) / 18000.0) * F_PI);
+ const double fEnd((((36000 - nStart) % 36000) / 18000.0) * F_PI);
+
+ // create circle segment. This is not closed by default
+ aCircPolygon = basegfx::tools::createPolygonFromEllipseSegment(
+ aRange.getCenter(), aRange.getWidth() / 2.0, aRange.getHeight() / 2.0,
+ fStart, fEnd);
+
+ // check closing states
+ const bool bCloseSegment(OBJ_CARC != eCicrleKind);
+ const bool bCloseUsingCenter(OBJ_SECT == eCicrleKind);
+
+ if(bCloseSegment)
+ {
+ if(bCloseUsingCenter)
+ {
+ // add center point at start (for historical reasons)
+ basegfx::B2DPolygon aSector;
+ aSector.append(aRange.getCenter());
+ aSector.append(aCircPolygon);
+ aCircPolygon = aSector;
+ }
+
+ // close
+ aCircPolygon.setClosed(true);
+ }
+ }
+
+ // #i76950#
+ if(aGeo.nShearWink || aGeo.nDrehWink)
+ {
+ // translate top left to (0,0)
+ const basegfx::B2DPoint aTopLeft(aRange.getMinimum());
+ basegfx::B2DHomMatrix aMatrix(basegfx::tools::createTranslateB2DHomMatrix(
+ -aTopLeft.getX(), -aTopLeft.getY()));
+
+ // shear, rotate and back to top left (if needed)
+ aMatrix = basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
+ aGeo.nShearWink ? tan((36000 - aGeo.nShearWink) * F_PI18000) : 0.0,
+ aGeo.nDrehWink ? (36000 - aGeo.nDrehWink) * F_PI18000 : 0.0,
+ aTopLeft) * aMatrix;
+
+ // apply transformation
+ aCircPolygon.transform(aMatrix);
+ }
+
+ return aCircPolygon;
+}
+
+void SdrCircObj::RecalcXPoly()
+{
+ const basegfx::B2DPolygon aPolyCirc(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink));
+ mpXPoly = new XPolygon(aPolyCirc);
+}
+
+void SdrCircObj::TakeObjNameSingul(XubString& rName) const
+{
+ USHORT nID=STR_ObjNameSingulCIRC;
+ if (aRect.GetWidth()==aRect.GetHeight() && aGeo.nShearWink==0) {
+ switch (meCircleKind) {
+ case OBJ_CIRC: nID=STR_ObjNameSingulCIRC; break;
+ case OBJ_SECT: nID=STR_ObjNameSingulSECT; break;
+ case OBJ_CARC: nID=STR_ObjNameSingulCARC; break;
+ case OBJ_CCUT: nID=STR_ObjNameSingulCCUT; break;
+ default: break;
+ }
+ } else {
+ switch (meCircleKind) {
+ case OBJ_CIRC: nID=STR_ObjNameSingulCIRCE; break;
+ case OBJ_SECT: nID=STR_ObjNameSingulSECTE; break;
+ case OBJ_CARC: nID=STR_ObjNameSingulCARCE; break;
+ case OBJ_CCUT: nID=STR_ObjNameSingulCCUTE; break;
+ default: break;
+ }
+ }
+ rName=ImpGetResStr(nID);
+
+ String aName( GetName() );
+ if(aName.Len())
+ {
+ rName += sal_Unicode(' ');
+ rName += sal_Unicode('\'');
+ rName += aName;
+ rName += sal_Unicode('\'');
+ }
+}
+
+void SdrCircObj::TakeObjNamePlural(XubString& rName) const
+{
+ USHORT nID=STR_ObjNamePluralCIRC;
+ if (aRect.GetWidth()==aRect.GetHeight() && aGeo.nShearWink==0) {
+ switch (meCircleKind) {
+ case OBJ_CIRC: nID=STR_ObjNamePluralCIRC; break;
+ case OBJ_SECT: nID=STR_ObjNamePluralSECT; break;
+ case OBJ_CARC: nID=STR_ObjNamePluralCARC; break;
+ case OBJ_CCUT: nID=STR_ObjNamePluralCCUT; break;
+ default: break;
+ }
+ } else {
+ switch (meCircleKind) {
+ case OBJ_CIRC: nID=STR_ObjNamePluralCIRCE; break;
+ case OBJ_SECT: nID=STR_ObjNamePluralSECTE; break;
+ case OBJ_CARC: nID=STR_ObjNamePluralCARCE; break;
+ case OBJ_CCUT: nID=STR_ObjNamePluralCCUTE; break;
+ default: break;
+ }
+ }
+ rName=ImpGetResStr(nID);
+}
+
+void SdrCircObj::operator=(const SdrObject& rObj)
+{
+ SdrRectObj::operator=(rObj);
+
+ nStartWink = ((SdrCircObj&)rObj).nStartWink;
+ nEndWink = ((SdrCircObj&)rObj).nEndWink;
+}
+
+basegfx::B2DPolyPolygon SdrCircObj::TakeXorPoly() const
+{
+ const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink));
+ return basegfx::B2DPolyPolygon(aCircPolygon);
+}
+
+struct ImpCircUser : public SdrDragStatUserData
+{
+ Rectangle aR;
+ Point aCenter;
+ Point aRadius;
+ Point aP1;
+ Point aP2;
+ long nMaxRad;
+ long nHgt;
+ long nWdt;
+ long nStart;
+ long nEnd;
+ long nWink;
+ FASTBOOL bRight; // noch nicht implementiert
+
+public:
+ ImpCircUser()
+ : nMaxRad(0),
+ nHgt(0),
+ nWdt(0),
+ nStart(0),
+ nEnd(0),
+ bRight(FALSE)
+ {}
+ void SetCreateParams(SdrDragStat& rStat);
+};
+
+sal_uInt32 SdrCircObj::GetHdlCount() const
+{
+ if(OBJ_CIRC != meCircleKind)
+ {
+ return 10L;
+ }
+ else
+ {
+ return 8L;
+ }
+}
+
+SdrHdl* SdrCircObj::GetHdl(sal_uInt32 nHdlNum) const
+{
+ if (meCircleKind==OBJ_CIRC)
+ {
+ nHdlNum += 2L;
+ }
+
+ SdrHdl* pH = NULL;
+ Point aPnt;
+ SdrHdlKind eLocalKind(HDL_MOVE);
+ sal_uInt32 nPNum(0);
+
+ switch (nHdlNum)
+ {
+ case 0:
+ aPnt = GetWinkPnt(aRect,nStartWink);
+ eLocalKind = HDL_CIRC;
+ nPNum = 1;
+ break;
+ case 1:
+ aPnt = GetWinkPnt(aRect,nEndWink);
+ eLocalKind = HDL_CIRC;
+ nPNum = 2L;
+ break;
+ case 2:
+ aPnt = aRect.TopLeft();
+ eLocalKind = HDL_UPLFT;
+ break;
+ case 3:
+ aPnt = aRect.TopCenter();
+ eLocalKind = HDL_UPPER;
+ break;
+ case 4:
+ aPnt = aRect.TopRight();
+ eLocalKind = HDL_UPRGT;
+ break;
+ case 5:
+ aPnt = aRect.LeftCenter();
+ eLocalKind = HDL_LEFT;
+ break;
+ case 6:
+ aPnt = aRect.RightCenter();
+ eLocalKind = HDL_RIGHT;
+ break;
+ case 7:
+ aPnt = aRect.BottomLeft();
+ eLocalKind = HDL_LWLFT;
+ break;
+ case 8:
+ aPnt = aRect.BottomCenter();
+ eLocalKind = HDL_LOWER;
+ break;
+ case 9:
+ aPnt = aRect.BottomRight();
+ eLocalKind = HDL_LWRGT;
+ break;
+ }
+
+ if (aGeo.nShearWink)
+ {
+ ShearPoint(aPnt,aRect.TopLeft(),aGeo.nTan);
+ }
+
+ if (aGeo.nDrehWink)
+ {
+ RotatePoint(aPnt,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
+ }
+
+ if (eLocalKind != HDL_MOVE)
+ {
+ pH = new SdrHdl(aPnt,eLocalKind);
+ pH->SetPointNum(nPNum);
+ pH->SetObj((SdrObject*)this);
+ pH->SetDrehWink(aGeo.nDrehWink);
+ }
+
+ return pH;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool SdrCircObj::hasSpecialDrag() const
+{
+ return true;
+}
+
+bool SdrCircObj::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
+
+ if(bWink)
+ {
+ if(1 == rDrag.GetHdl()->GetPointNum() || 2 == rDrag.GetHdl()->GetPointNum())
+ {
+ rDrag.SetNoSnap(true);
+ }
+
+ return true;
+ }
+
+ return SdrTextObj::beginSpecialDrag(rDrag);
+}
+
+bool SdrCircObj::applySpecialDrag(SdrDragStat& rDrag)
+{
+ const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
+
+ if(bWink)
+ {
+ Point aPt(rDrag.GetNow());
+
+ if (aGeo.nDrehWink!=0)
+ RotatePoint(aPt,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos);
+
+ if (aGeo.nShearWink!=0)
+ ShearPoint(aPt,aRect.TopLeft(),-aGeo.nTan);
+
+ aPt-=aRect.Center();
+
+ long nWdt=aRect.Right()-aRect.Left();
+ long nHgt=aRect.Bottom()-aRect.Top();
+
+ if(nWdt>=nHgt)
+ {
+ aPt.Y()=BigMulDiv(aPt.Y(),nWdt,nHgt);
+ }
+ else
+ {
+ aPt.X()=BigMulDiv(aPt.X(),nHgt,nWdt);
+ }
+
+ long nWink=NormAngle360(GetAngle(aPt));
+
+ if (rDrag.GetView() && rDrag.GetView()->IsAngleSnapEnabled())
+ {
+ long nSA=rDrag.GetView()->GetSnapAngle();
+
+ if (nSA!=0)
+ {
+ nWink+=nSA/2;
+ nWink/=nSA;
+ nWink*=nSA;
+ nWink=NormAngle360(nWink);
+ }
+ }
+
+ if(1 == rDrag.GetHdl()->GetPointNum())
+ {
+ nStartWink = nWink;
+ }
+ else if(2 == rDrag.GetHdl()->GetPointNum())
+ {
+ nEndWink = nWink;
+ }
+
+ SetRectsDirty();
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+ SetChanged();
+
+ return true;
+ }
+ else
+ {
+ return SdrTextObj::applySpecialDrag(rDrag);
+ }
+}
+
+String SdrCircObj::getSpecialDragComment(const SdrDragStat& rDrag) const
+{
+ const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
+
+ if(bCreateComment)
+ {
+ XubString aStr;
+ ImpTakeDescriptionStr(STR_ViewCreateObj, aStr);
+ const sal_uInt32 nPntAnz(rDrag.GetPointAnz());
+
+ if(OBJ_CIRC != meCircleKind && nPntAnz > 2)
+ {
+ ImpCircUser* pU = (ImpCircUser*)rDrag.GetUser();
+ sal_Int32 nWink;
+
+ aStr.AppendAscii(" (");
+
+ if(3 == nPntAnz)
+ {
+ nWink = pU->nStart;
+ }
+ else
+ {
+ nWink = pU->nEnd;
+ }
+
+ aStr += GetWinkStr(nWink,FALSE);
+ aStr += sal_Unicode(')');
+ }
+
+ return aStr;
+ }
+ else
+ {
+ const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
+
+ if(bWink)
+ {
+ XubString aStr;
+ const sal_Int32 nWink(1 == rDrag.GetHdl()->GetPointNum() ? nStartWink : nEndWink);
+
+ ImpTakeDescriptionStr(STR_DragCircAngle, aStr);
+ aStr.AppendAscii(" (");
+ aStr += GetWinkStr(nWink,FALSE);
+ aStr += sal_Unicode(')');
+
+ return aStr;
+ }
+ else
+ {
+ return SdrTextObj::getSpecialDragComment(rDrag);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void ImpCircUser::SetCreateParams(SdrDragStat& rStat)
+{
+ rStat.TakeCreateRect(aR);
+ aR.Justify();
+ aCenter=aR.Center();
+ nWdt=aR.Right()-aR.Left();
+ nHgt=aR.Bottom()-aR.Top();
+ nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
+ nStart=0;
+ nEnd=36000;
+ if (rStat.GetPointAnz()>2) {
+ Point aP(rStat.GetPoint(2)-aCenter);
+ if (nWdt==0) aP.X()=0;
+ if (nHgt==0) aP.Y()=0;
+ if (nWdt>=nHgt) {
+ if (nHgt!=0) aP.Y()=aP.Y()*nWdt/nHgt;
+ } else {
+ if (nWdt!=0) aP.X()=aP.X()*nHgt/nWdt;
+ }
+ nStart=NormAngle360(GetAngle(aP));
+ if (rStat.GetView()!=NULL && rStat.GetView()->IsAngleSnapEnabled()) {
+ long nSA=rStat.GetView()->GetSnapAngle();
+ if (nSA!=0) { // Winkelfang
+ nStart+=nSA/2;
+ nStart/=nSA;
+ nStart*=nSA;
+ nStart=NormAngle360(nStart);
+ }
+ }
+ aP1 = GetWinkPnt(aR,nStart);
+ nEnd=nStart;
+ aP2=aP1;
+ } else aP1=aCenter;
+ if (rStat.GetPointAnz()>3) {
+ Point aP(rStat.GetPoint(3)-aCenter);
+ if (nWdt>=nHgt) {
+ aP.Y()=BigMulDiv(aP.Y(),nWdt,nHgt);
+ } else {
+ aP.X()=BigMulDiv(aP.X(),nHgt,nWdt);
+ }
+ nEnd=NormAngle360(GetAngle(aP));
+ if (rStat.GetView()!=NULL && rStat.GetView()->IsAngleSnapEnabled()) {
+ long nSA=rStat.GetView()->GetSnapAngle();
+ if (nSA!=0) { // Winkelfang
+ nEnd+=nSA/2;
+ nEnd/=nSA;
+ nEnd*=nSA;
+ nEnd=NormAngle360(nEnd);
+ }
+ }
+ aP2 = GetWinkPnt(aR,nEnd);
+ } else aP2=aCenter;
+}
+
+void SdrCircObj::ImpSetCreateParams(SdrDragStat& rStat) const
+{
+ ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
+ if (pU==NULL) {
+ pU=new ImpCircUser;
+ rStat.SetUser(pU);
+ }
+ pU->SetCreateParams(rStat);
+}
+
+FASTBOOL SdrCircObj::BegCreate(SdrDragStat& rStat)
+{
+ rStat.SetOrtho4Possible();
+ Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
+ aRect1.Justify();
+ rStat.SetActionRect(aRect1);
+ aRect = aRect1;
+ ImpSetCreateParams(rStat);
+ return TRUE;
+}
+
+FASTBOOL SdrCircObj::MovCreate(SdrDragStat& rStat)
+{
+ ImpSetCreateParams(rStat);
+ ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
+ rStat.SetActionRect(pU->aR);
+ aRect=pU->aR; // fuer ObjName
+ ImpJustifyRect(aRect);
+ nStartWink=pU->nStart;
+ nEndWink=pU->nEnd;
+ SetBoundRectDirty();
+ bSnapRectDirty=TRUE;
+ SetXPolyDirty();
+
+ // #i103058# push current angle settings to ItemSet to
+ // allow FullDrag visualisation
+ if(rStat.GetPointAnz() >= 4)
+ {
+ ImpSetCircInfoToAttr();
+ }
+
+ return TRUE;
+}
+
+FASTBOOL SdrCircObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ ImpSetCreateParams(rStat);
+ ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
+ FASTBOOL bRet=FALSE;
+ if (eCmd==SDRCREATE_FORCEEND && rStat.GetPointAnz()<4) meCircleKind=OBJ_CIRC;
+ if (meCircleKind==OBJ_CIRC) {
+ bRet=rStat.GetPointAnz()>=2;
+ if (bRet) {
+ aRect=pU->aR;
+ ImpJustifyRect(aRect);
+ }
+ } else {
+ rStat.SetNoSnap(rStat.GetPointAnz()>=2);
+ rStat.SetOrtho4Possible(rStat.GetPointAnz()<2);
+ bRet=rStat.GetPointAnz()>=4;
+ if (bRet) {
+ aRect=pU->aR;
+ ImpJustifyRect(aRect);
+ nStartWink=pU->nStart;
+ nEndWink=pU->nEnd;
+ }
+ }
+ bClosedObj=meCircleKind!=OBJ_CARC;
+ SetRectsDirty();
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+ if (bRet) {
+ delete pU;
+ rStat.SetUser(NULL);
+ }
+ return bRet;
+}
+
+void SdrCircObj::BrkCreate(SdrDragStat& rStat)
+{
+ ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
+ delete pU;
+ rStat.SetUser(NULL);
+}
+
+FASTBOOL SdrCircObj::BckCreate(SdrDragStat& rStat)
+{
+ rStat.SetNoSnap(rStat.GetPointAnz()>=3);
+ rStat.SetOrtho4Possible(rStat.GetPointAnz()<3);
+ return meCircleKind!=OBJ_CIRC;
+}
+
+basegfx::B2DPolyPolygon SdrCircObj::TakeCreatePoly(const SdrDragStat& rDrag) const
+{
+ ImpCircUser* pU = (ImpCircUser*)rDrag.GetUser();
+
+ if(rDrag.GetPointAnz() < 4L)
+ {
+ // force to OBJ_CIRC to get full visualisation
+ basegfx::B2DPolyPolygon aRetval(ImpCalcXPolyCirc(OBJ_CIRC, pU->aR, pU->nStart, pU->nEnd));
+
+ if(3L == rDrag.GetPointAnz())
+ {
+ // add edge to first point on ellipse
+ basegfx::B2DPolygon aNew;
+
+ aNew.append(basegfx::B2DPoint(pU->aCenter.X(), pU->aCenter.Y()));
+ aNew.append(basegfx::B2DPoint(pU->aP1.X(), pU->aP1.Y()));
+ aRetval.append(aNew);
+ }
+
+ return aRetval;
+ }
+ else
+ {
+ return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind, pU->aR, pU->nStart, pU->nEnd));
+ }
+}
+
+Pointer SdrCircObj::GetCreatePointer() const
+{
+ switch (meCircleKind) {
+ case OBJ_CIRC: return Pointer(POINTER_DRAW_ELLIPSE);
+ case OBJ_SECT: return Pointer(POINTER_DRAW_PIE);
+ case OBJ_CARC: return Pointer(POINTER_DRAW_ARC);
+ case OBJ_CCUT: return Pointer(POINTER_DRAW_CIRCLECUT);
+ default: break;
+ } // switch
+ return Pointer(POINTER_CROSS);
+}
+
+void SdrCircObj::NbcMove(const Size& aSiz)
+{
+ MoveRect(aRect,aSiz);
+ MoveRect(aOutRect,aSiz);
+ MoveRect(maSnapRect,aSiz);
+ SetXPolyDirty();
+ SetRectsDirty(sal_True);
+}
+
+void SdrCircObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ long nWink0=aGeo.nDrehWink;
+ FASTBOOL bNoShearRota=(aGeo.nDrehWink==0 && aGeo.nShearWink==0);
+ SdrTextObj::NbcResize(rRef,xFact,yFact);
+ bNoShearRota|=(aGeo.nDrehWink==0 && aGeo.nShearWink==0);
+ if (meCircleKind!=OBJ_CIRC) {
+ FASTBOOL bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
+ FASTBOOL bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
+ if (bXMirr || bYMirr) {
+ // bei bXMirr!=bYMirr muessten eigentlich noch die beiden
+ // Linienende vertauscht werden. Das ist jedoch mal wieder
+ // schlecht (wg. zwangslaeufiger harter Formatierung).
+ // Alternativ koennte ein bMirrored-Flag eingefuehrt werden
+ // (Vielleicht ja mal grundsaetzlich, auch fuer gepiegelten Text, ...).
+ long nS0=nStartWink;
+ long nE0=nEndWink;
+ if (bNoShearRota) {
+ // Das RectObj spiegelt bei VMirror bereits durch durch 180deg Drehung.
+ if (! (bXMirr && bYMirr)) {
+ long nTmp=nS0;
+ nS0=18000-nE0;
+ nE0=18000-nTmp;
+ }
+ } else { // Spiegeln fuer verzerrte Ellipsen
+ if (bXMirr!=bYMirr) {
+ nS0+=nWink0;
+ nE0+=nWink0;
+ if (bXMirr) {
+ long nTmp=nS0;
+ nS0=18000-nE0;
+ nE0=18000-nTmp;
+ }
+ if (bYMirr) {
+ long nTmp=nS0;
+ nS0=-nE0;
+ nE0=-nTmp;
+ }
+ nS0-=aGeo.nDrehWink;
+ nE0-=aGeo.nDrehWink;
+ }
+ }
+ long nWinkDif=nE0-nS0;
+ nStartWink=NormAngle360(nS0);
+ nEndWink =NormAngle360(nE0);
+ if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis
+ }
+ }
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+}
+
+void SdrCircObj::NbcShear(const Point& rRef, long nWink, double tn, FASTBOOL bVShear)
+{
+ SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+}
+
+void SdrCircObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ //long nWink0=aGeo.nDrehWink;
+ FASTBOOL bFreeMirr=meCircleKind!=OBJ_CIRC;
+ Point aTmpPt1;
+ Point aTmpPt2;
+ if (bFreeMirr) { // bei freier Spiegelachse einige Vorbereitungen Treffen
+ Point aCenter(aRect.Center());
+ long nWdt=aRect.GetWidth()-1;
+ long nHgt=aRect.GetHeight()-1;
+ long nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
+ double a;
+ // Startpunkt
+ a=nStartWink*nPi180;
+ aTmpPt1=Point(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad));
+ if (nWdt==0) aTmpPt1.X()=0;
+ if (nHgt==0) aTmpPt1.Y()=0;
+ aTmpPt1+=aCenter;
+ // Endpunkt
+ a=nEndWink*nPi180;
+ aTmpPt2=Point(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad));
+ if (nWdt==0) aTmpPt2.X()=0;
+ if (nHgt==0) aTmpPt2.Y()=0;
+ aTmpPt2+=aCenter;
+ if (aGeo.nDrehWink!=0) {
+ RotatePoint(aTmpPt1,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
+ RotatePoint(aTmpPt2,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
+ }
+ if (aGeo.nShearWink!=0) {
+ ShearPoint(aTmpPt1,aRect.TopLeft(),aGeo.nTan);
+ ShearPoint(aTmpPt2,aRect.TopLeft(),aGeo.nTan);
+ }
+ }
+ SdrTextObj::NbcMirror(rRef1,rRef2);
+ if (meCircleKind!=OBJ_CIRC) { // Anpassung von Start- und Endwinkel
+ MirrorPoint(aTmpPt1,rRef1,rRef2);
+ MirrorPoint(aTmpPt2,rRef1,rRef2);
+ // Unrotate:
+ if (aGeo.nDrehWink!=0) {
+ RotatePoint(aTmpPt1,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos); // -sin fuer Umkehrung
+ RotatePoint(aTmpPt2,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos); // -sin fuer Umkehrung
+ }
+ // Unshear:
+ if (aGeo.nShearWink!=0) {
+ ShearPoint(aTmpPt1,aRect.TopLeft(),-aGeo.nTan); // -tan fuer Umkehrung
+ ShearPoint(aTmpPt2,aRect.TopLeft(),-aGeo.nTan); // -tan fuer Umkehrung
+ }
+ Point aCenter(aRect.Center());
+ aTmpPt1-=aCenter;
+ aTmpPt2-=aCenter;
+ // Weil gespiegelt sind die Winkel nun auch noch vertauscht
+ nStartWink=GetAngle(aTmpPt2);
+ nEndWink =GetAngle(aTmpPt1);
+ long nWinkDif=nEndWink-nStartWink;
+ nStartWink=NormAngle360(nStartWink);
+ nEndWink =NormAngle360(nEndWink);
+ if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis
+ }
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+}
+
+SdrObjGeoData* SdrCircObj::NewGeoData() const
+{
+ return new SdrCircObjGeoData;
+}
+
+void SdrCircObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrRectObj::SaveGeoData(rGeo);
+ SdrCircObjGeoData& rCGeo=(SdrCircObjGeoData&)rGeo;
+ rCGeo.nStartWink=nStartWink;
+ rCGeo.nEndWink =nEndWink;
+}
+
+void SdrCircObj::RestGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrRectObj::RestGeoData(rGeo);
+ SdrCircObjGeoData& rCGeo=(SdrCircObjGeoData&)rGeo;
+ nStartWink=rCGeo.nStartWink;
+ nEndWink =rCGeo.nEndWink;
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+}
+
+void Union(Rectangle& rR, const Point& rP)
+{
+ if (rP.X()<rR.Left ()) rR.Left ()=rP.X();
+ if (rP.X()>rR.Right ()) rR.Right ()=rP.X();
+ if (rP.Y()<rR.Top ()) rR.Top ()=rP.Y();
+ if (rP.Y()>rR.Bottom()) rR.Bottom()=rP.Y();
+}
+
+void SdrCircObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
+{
+ rRect=aRect;
+ if (meCircleKind!=OBJ_CIRC) {
+ const Point aPntStart(GetWinkPnt(aRect,nStartWink));
+ const Point aPntEnd(GetWinkPnt(aRect,nEndWink));
+ long a=nStartWink;
+ long e=nEndWink;
+ rRect.Left ()=aRect.Right();
+ rRect.Right ()=aRect.Left();
+ rRect.Top ()=aRect.Bottom();
+ rRect.Bottom()=aRect.Top();
+ Union(rRect,aPntStart);
+ Union(rRect,aPntEnd);
+ if ((a<=18000 && e>=18000) || (a>e && (a<=18000 || e>=18000))) {
+ Union(rRect,aRect.LeftCenter());
+ }
+ if ((a<=27000 && e>=27000) || (a>e && (a<=27000 || e>=27000))) {
+ Union(rRect,aRect.BottomCenter());
+ }
+ if (a>e) {
+ Union(rRect,aRect.RightCenter());
+ }
+ if ((a<=9000 && e>=9000) || (a>e && (a<=9000 || e>=9000))) {
+ Union(rRect,aRect.TopCenter());
+ }
+ if (meCircleKind==OBJ_SECT) {
+ Union(rRect,aRect.Center());
+ }
+ if (aGeo.nDrehWink!=0) {
+ Point aDst(rRect.TopLeft());
+ aDst-=aRect.TopLeft();
+ Point aDst0(aDst);
+ RotatePoint(aDst,Point(),aGeo.nSin,aGeo.nCos);
+ aDst-=aDst0;
+ rRect.Move(aDst.X(),aDst.Y());
+ }
+ }
+ if (aGeo.nShearWink!=0) {
+ long nDst=Round((rRect.Bottom()-rRect.Top())*aGeo.nTan);
+ if (aGeo.nShearWink>0) {
+ Point aRef(rRect.TopLeft());
+ rRect.Left()-=nDst;
+ Point aTmpPt(rRect.TopLeft());
+ RotatePoint(aTmpPt,aRef,aGeo.nSin,aGeo.nCos);
+ aTmpPt-=rRect.TopLeft();
+ rRect.Move(aTmpPt.X(),aTmpPt.Y());
+ } else {
+ rRect.Right()-=nDst;
+ }
+ }
+}
+
+void SdrCircObj::RecalcSnapRect()
+{
+ if (PaintNeedsXPolyCirc()) {
+ maSnapRect=GetXPoly().GetBoundRect();
+ } else {
+ TakeUnrotatedSnapRect(maSnapRect);
+ }
+}
+
+void SdrCircObj::NbcSetSnapRect(const Rectangle& rRect)
+{
+ if (aGeo.nDrehWink!=0 || aGeo.nShearWink!=0 || meCircleKind!=OBJ_CIRC) {
+ Rectangle aSR0(GetSnapRect());
+ long nWdt0=aSR0.Right()-aSR0.Left();
+ long nHgt0=aSR0.Bottom()-aSR0.Top();
+ long nWdt1=rRect.Right()-rRect.Left();
+ long nHgt1=rRect.Bottom()-rRect.Top();
+ NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
+ NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
+ } else {
+ aRect=rRect;
+ ImpJustifyRect(aRect);
+ }
+ SetRectsDirty();
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+}
+
+sal_uInt32 SdrCircObj::GetSnapPointCount() const
+{
+ if (meCircleKind==OBJ_CIRC) {
+ return 1L;
+ } else {
+ return 3L;
+ }
+}
+
+Point SdrCircObj::GetSnapPoint(sal_uInt32 i) const
+{
+ switch (i) {
+ case 1 : return GetWinkPnt(aRect,nStartWink);
+ case 2 : return GetWinkPnt(aRect,nEndWink);
+ default: return aRect.Center();
+ }
+}
+
+void __EXPORT SdrCircObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ SetXPolyDirty();
+ SdrRectObj::Notify(rBC,rHint);
+ ImpSetAttrToCircInfo();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void SdrCircObj::ImpSetAttrToCircInfo()
+{
+ const SfxItemSet& rSet = GetObjectItemSet();
+ SdrCircKind eNewKindA = ((SdrCircKindItem&)rSet.Get(SDRATTR_CIRCKIND)).GetValue();
+ SdrObjKind eNewKind = meCircleKind;
+
+ if(eNewKindA == SDRCIRC_FULL)
+ eNewKind = OBJ_CIRC;
+ else if(eNewKindA == SDRCIRC_SECT)
+ eNewKind = OBJ_SECT;
+ else if(eNewKindA == SDRCIRC_ARC)
+ eNewKind = OBJ_CARC;
+ else if(eNewKindA == SDRCIRC_CUT)
+ eNewKind = OBJ_CCUT;
+
+ sal_Int32 nNewStart = ((SdrCircStartAngleItem&)rSet.Get(SDRATTR_CIRCSTARTANGLE)).GetValue();
+ sal_Int32 nNewEnd = ((SdrCircEndAngleItem&)rSet.Get(SDRATTR_CIRCENDANGLE)).GetValue();
+
+ BOOL bKindChg = meCircleKind != eNewKind;
+ BOOL bWinkChg = nNewStart != nStartWink || nNewEnd != nEndWink;
+
+ if(bKindChg || bWinkChg)
+ {
+ meCircleKind = eNewKind;
+ nStartWink = nNewStart;
+ nEndWink = nNewEnd;
+
+ if(bKindChg || (meCircleKind != OBJ_CIRC && bWinkChg))
+ {
+ SetXPolyDirty();
+ SetRectsDirty();
+ }
+ }
+}
+
+void SdrCircObj::ImpSetCircInfoToAttr()
+{
+ SdrCircKind eNewKindA = SDRCIRC_FULL;
+ const SfxItemSet& rSet = GetObjectItemSet();
+
+ if(meCircleKind == OBJ_SECT)
+ eNewKindA = SDRCIRC_SECT;
+ else if(meCircleKind == OBJ_CARC)
+ eNewKindA = SDRCIRC_ARC;
+ else if(meCircleKind == OBJ_CCUT)
+ eNewKindA = SDRCIRC_CUT;
+
+ SdrCircKind eOldKindA = ((SdrCircKindItem&)rSet.Get(SDRATTR_CIRCKIND)).GetValue();
+ sal_Int32 nOldStartWink = ((SdrCircStartAngleItem&)rSet.Get(SDRATTR_CIRCSTARTANGLE)).GetValue();
+ sal_Int32 nOldEndWink = ((SdrCircEndAngleItem&)rSet.Get(SDRATTR_CIRCENDANGLE)).GetValue();
+
+ if(eNewKindA != eOldKindA || nStartWink != nOldStartWink || nEndWink != nOldEndWink)
+ {
+ // #81921# since SetItem() implicitly calls ImpSetAttrToCircInfo()
+ // setting the item directly is necessary here.
+ if(eNewKindA != eOldKindA)
+ {
+ GetProperties().SetObjectItemDirect(SdrCircKindItem(eNewKindA));
+ }
+
+ if(nStartWink != nOldStartWink)
+ {
+ GetProperties().SetObjectItemDirect(SdrCircStartAngleItem(nStartWink));
+ }
+
+ if(nEndWink != nOldEndWink)
+ {
+ GetProperties().SetObjectItemDirect(SdrCircEndAngleItem(nEndWink));
+ }
+
+ SetXPolyDirty();
+ ImpSetAttrToCircInfo();
+ }
+}
+
+SdrObject* SdrCircObj::DoConvertToPolyObj(BOOL bBezier) const
+{
+ const sal_Bool bFill(OBJ_CARC == meCircleKind ? sal_False : sal_True);
+ const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink));
+ SdrObject* pRet = ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon), bFill, bBezier);
+ pRet = ImpConvertAddText(pRet, bBezier);
+
+ return pRet;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// eof