| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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 = sal_False; |
| rInfo.bCanConvToPath=bCanConv; |
| rInfo.bCanConvToPoly=bCanConv; |
| rInfo.bCanConvToContour = !IsFontwork() && (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary()); |
| } |
| |
| sal_uInt16 SdrCircObj::GetObjIdentifier() const |
| { |
| return sal_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=sal_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=sal_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 |
| { |
| sal_uInt16 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 |
| { |
| sal_uInt16 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(sal_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,sal_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,sal_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 sal_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=sal_True; |
| SetXPolyDirty(); |
| |
| // #i103058# push current angle settings to ItemSet to |
| // allow FullDrag visualisation |
| if(rStat.GetPointAnz() >= 4) |
| { |
| ImpSetCircInfoToAttr(); |
| } |
| |
| return sal_True; |
| } |
| |
| FASTBOOL SdrCircObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) |
| { |
| ImpSetCreateParams(rStat); |
| ImpCircUser* pU=(ImpCircUser*)rStat.GetUser(); |
| FASTBOOL bRet=sal_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(); |
| |
| sal_Bool bKindChg = meCircleKind != eNewKind; |
| sal_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(sal_Bool bBezier, bool bAddText) 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); |
| |
| if(bAddText) |
| { |
| pRet = ImpConvertAddText(pRet, bBezier); |
| } |
| |
| return pRet; |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // eof |