summaryrefslogtreecommitdiffstats
path: root/svx/source/svdraw/svdpoev.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--svx/source/svdraw/svdpoev.cxx652
1 files changed, 652 insertions, 0 deletions
diff --git a/svx/source/svdraw/svdpoev.cxx b/svx/source/svdraw/svdpoev.cxx
new file mode 100644
index 000000000..117aa71f7
--- /dev/null
+++ b/svx/source/svdraw/svdpoev.cxx
@@ -0,0 +1,652 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+
+#include <svx/svdpoev.hxx>
+#include <math.h>
+#include <svx/svdpagv.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svdtrans.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <tools/debug.hxx>
+#include <tools/helpers.hxx>
+
+#include <svx/polypolygoneditor.hxx>
+
+using namespace sdr;
+
+
+void SdrPolyEditView::ImpResetPolyPossibilityFlags()
+{
+ eMarkedPointsSmooth=SdrPathSmoothKind::DontCare;
+ eMarkedSegmentsKind=SdrPathSegmentKind::DontCare;
+ bSetMarkedPointsSmoothPossible=false;
+ bSetMarkedSegmentsKindPossible=false;
+}
+
+SdrPolyEditView::SdrPolyEditView(
+ SdrModel& rSdrModel,
+ OutputDevice* pOut)
+: SdrEditView(rSdrModel, pOut)
+{
+ ImpResetPolyPossibilityFlags();
+}
+
+SdrPolyEditView::~SdrPolyEditView()
+{
+}
+
+void SdrPolyEditView::ImpCheckPolyPossibilities()
+{
+ ImpResetPolyPossibilityFlags();
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ if(nMarkCount && !ImpIsFrameHandles())
+ {
+ bool b1stSmooth(true);
+ bool b1stSegm(true);
+ bool bCurve(false);
+ bool bSmoothFuz(false);
+ bool bSegmFuz(false);
+ basegfx::B2VectorContinuity eSmooth = basegfx::B2VectorContinuity::NONE;
+
+ for(size_t nMarkNum = 0; nMarkNum < nMarkCount; ++nMarkNum)
+ {
+ SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
+ CheckPolyPossibilitiesHelper( pM, b1stSmooth, b1stSegm, bCurve, bSmoothFuz, bSegmFuz, eSmooth );
+ }
+ }
+}
+
+void SdrPolyEditView::CheckPolyPossibilitiesHelper( SdrMark* pM, bool& b1stSmooth, bool& b1stSegm, bool& bCurve, bool& bSmoothFuz, bool& bSegmFuz, basegfx::B2VectorContinuity& eSmooth )
+{
+ SdrObject* pObj = pM->GetMarkedSdrObj();
+ SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pObj );
+
+ if (!pPath)
+ return;
+
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+ if (rPts.empty())
+ return;
+
+ const bool bClosed(pPath->IsClosed());
+ bSetMarkedPointsSmoothPossible = true;
+
+ if (bClosed)
+ {
+ bSetMarkedSegmentsKindPossible = true;
+ }
+
+ for (const auto& rPt : rPts)
+ {
+ sal_uInt32 nNum(rPt);
+ sal_uInt32 nPolyNum, nPntNum;
+
+ if(PolyPolygonEditor::GetRelativePolyPoint(pPath->GetPathPoly(), nNum, nPolyNum, nPntNum))
+ {
+ const basegfx::B2DPolygon aLocalPolygon(pPath->GetPathPoly().getB2DPolygon(nPolyNum));
+ bool bCanSegment(bClosed || nPntNum < aLocalPolygon.count() - 1);
+
+ if(!bSetMarkedSegmentsKindPossible && bCanSegment)
+ {
+ bSetMarkedSegmentsKindPossible = true;
+ }
+
+ if(!bSmoothFuz)
+ {
+ if (b1stSmooth)
+ {
+ b1stSmooth = false;
+ eSmooth = basegfx::utils::getContinuityInPoint(aLocalPolygon, nPntNum);
+ }
+ else
+ {
+ bSmoothFuz = (eSmooth != basegfx::utils::getContinuityInPoint(aLocalPolygon, nPntNum));
+ }
+ }
+
+ if(!bSegmFuz && bCanSegment)
+ {
+ bool bCrv(aLocalPolygon.isNextControlPointUsed(nPntNum));
+
+ if(b1stSegm)
+ {
+ b1stSegm = false;
+ bCurve = bCrv;
+ }
+ else
+ {
+ bSegmFuz = (bCrv != bCurve);
+ }
+ }
+ }
+ }
+
+ if(!b1stSmooth && !bSmoothFuz)
+ {
+ if(basegfx::B2VectorContinuity::NONE == eSmooth)
+ {
+ eMarkedPointsSmooth = SdrPathSmoothKind::Angular;
+ }
+
+ if(basegfx::B2VectorContinuity::C1 == eSmooth)
+ {
+ eMarkedPointsSmooth = SdrPathSmoothKind::Asymmetric;
+ }
+
+ if(basegfx::B2VectorContinuity::C2 == eSmooth)
+ {
+ eMarkedPointsSmooth = SdrPathSmoothKind::Symmetric;
+ }
+ }
+
+ if(!b1stSegm && !bSegmFuz)
+ {
+ eMarkedSegmentsKind = bCurve ? SdrPathSegmentKind::Curve : SdrPathSegmentKind::Line;
+ }
+}
+
+void SdrPolyEditView::SetMarkedPointsSmooth(SdrPathSmoothKind eKind)
+{
+ basegfx::B2VectorContinuity eFlags;
+
+ if(SdrPathSmoothKind::Angular == eKind)
+ {
+ eFlags = basegfx::B2VectorContinuity::NONE;
+ }
+ else if(SdrPathSmoothKind::Asymmetric == eKind)
+ {
+ eFlags = basegfx::B2VectorContinuity::C1;
+ }
+ else if(SdrPathSmoothKind::Symmetric == eKind)
+ {
+ eFlags = basegfx::B2VectorContinuity::C2;
+ }
+ else
+ {
+ return;
+ }
+
+ if(HasMarkedPoints())
+ {
+ SortMarkedObjects();
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditSetPointsSmooth), GetDescriptionOfMarkedPoints());
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t nMarkNum(nMarkCount); nMarkNum > 0;)
+ {
+ --nMarkNum;
+ SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
+ SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
+ if (!pPath)
+ continue;
+
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+ PolyPolygonEditor aEditor(pPath->GetPathPoly());
+ if (aEditor.SetPointsSmooth(eFlags, rPts))
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath));
+ pPath->SetPathPoly(aEditor.GetPolyPolygon());
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+ }
+}
+
+void SdrPolyEditView::SetMarkedSegmentsKind(SdrPathSegmentKind eKind)
+{
+ if(HasMarkedPoints())
+ {
+ SortMarkedObjects();
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditSetSegmentsKind), GetDescriptionOfMarkedPoints());
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t nMarkNum=nMarkCount; nMarkNum > 0;)
+ {
+ --nMarkNum;
+ SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
+ SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
+ if (!pPath)
+ continue;
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+ PolyPolygonEditor aEditor( pPath->GetPathPoly());
+ if (aEditor.SetSegmentsKind(eKind, rPts))
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath));
+ pPath->SetPathPoly(aEditor.GetPolyPolygon());
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+ }
+}
+
+bool SdrPolyEditView::IsSetMarkedPointsSmoothPossible() const
+{
+ ForcePossibilities();
+ return bSetMarkedPointsSmoothPossible;
+}
+
+SdrPathSmoothKind SdrPolyEditView::GetMarkedPointsSmooth() const
+{
+ ForcePossibilities();
+ return eMarkedPointsSmooth;
+}
+
+bool SdrPolyEditView::IsSetMarkedSegmentsKindPossible() const
+{
+ ForcePossibilities();
+ return bSetMarkedSegmentsKindPossible;
+}
+
+SdrPathSegmentKind SdrPolyEditView::GetMarkedSegmentsKind() const
+{
+ ForcePossibilities();
+ return eMarkedSegmentsKind;
+}
+
+bool SdrPolyEditView::IsDeleteMarkedPointsPossible() const
+{
+ return HasMarkedPoints();
+}
+
+void SdrPolyEditView::DeleteMarkedPoints()
+{
+ if (HasMarkedPoints())
+ {
+ BrkAction();
+ SortMarkedObjects();
+ const size_t nMarkCount=GetMarkedObjectCount();
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ {
+ // Description
+ BegUndo(SvxResId(STR_EditDelete),GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Delete);
+ }
+
+ for (size_t nMarkNum=nMarkCount; nMarkNum>0;)
+ {
+ --nMarkNum;
+ SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
+ if (!pPath)
+ continue;
+
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+ PolyPolygonEditor aEditor( pPath->GetPathPoly());
+ if (aEditor.DeletePoints(rPts))
+ {
+ if( aEditor.GetPolyPolygon().count() )
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath ));
+ pPath->SetPathPoly( aEditor.GetPolyPolygon() );
+ }
+ else
+ {
+ if( bUndo )
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pPath ) );
+ pM->GetPageView()->GetObjList()->RemoveObject(pPath->GetOrdNum());
+ if( !bUndo )
+ {
+ SdrObject* pObj = pPath;
+ SdrObject::Free(pObj);
+ }
+ }
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+ UnmarkAllPoints();
+ MarkListHasChanged();
+ }
+}
+
+void SdrPolyEditView::RipUpAtMarkedPoints()
+{
+ if(HasMarkedPoints())
+ {
+ SortMarkedObjects();
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditRipUp), GetDescriptionOfMarkedPoints());
+
+ for(size_t nMarkNum = nMarkCount; nMarkNum > 0;)
+ {
+ --nMarkNum;
+ SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
+ SdrPathObj* pObj = dynamic_cast<SdrPathObj*>( pM->GetMarkedSdrObj() );
+ if (!pObj)
+ continue;
+
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+ bool bCorrectionFlag(false);
+ sal_uInt32 nMax(pObj->GetHdlCount());
+
+ for(SdrUShortCont::const_reverse_iterator it = rPts.rbegin(); it != rPts.rend(); ++it)
+ {
+ sal_uInt32 nNewPt0Idx(0);
+ SdrObject* pNewObj = pObj->RipPoint(*it, nNewPt0Idx);
+
+ if(pNewObj)
+ {
+ pM->GetPageView()->GetObjList()->InsertObject(pNewObj, pObj->GetOrdNum() + 1);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewObj));
+ MarkObj(pNewObj, pM->GetPageView(), false, true);
+ }
+
+ if(nNewPt0Idx)
+ {
+ // correction necessary?
+ DBG_ASSERT(!bCorrectionFlag,"Multiple index corrections at SdrPolyEditView::RipUp().");
+ if(!bCorrectionFlag)
+ {
+ bCorrectionFlag = true;
+
+ SdrUShortCont aReplaceSet;
+ for(const auto& rPt : rPts)
+ {
+ sal_uInt32 nPntNum(rPt);
+ nPntNum += nNewPt0Idx;
+
+ if(nPntNum >= nMax)
+ {
+ nPntNum -= nMax;
+ }
+
+ aReplaceSet.insert( static_cast<sal_uInt16>(nPntNum) );
+ }
+ rPts.swap(aReplaceSet);
+
+ it = rPts.rbegin();
+ }
+ }
+ }
+ }
+
+ UnmarkAllPoints();
+ if( bUndo )
+ EndUndo();
+ MarkListHasChanged();
+ }
+}
+
+bool SdrPolyEditView::IsRipUpAtMarkedPointsPossible() const
+{
+ bool bRetval(false);
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t a = 0; a < nMarkCount; ++a)
+ {
+ const SdrMark* pMark = GetSdrMarkByIndex(a);
+ const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
+
+ if (!pMarkedPathObject)
+ continue;
+
+ const SdrUShortCont& rSelectedPoints = pMark->GetMarkedPoints();
+ if (rSelectedPoints.empty())
+ continue;
+
+ const basegfx::B2DPolyPolygon& rPathPolyPolygon = pMarkedPathObject->GetPathPoly();
+
+ if(1 == rPathPolyPolygon.count())
+ {
+ // #i76617# Do not yet use basegfx::B2DPolygon since curve definitions
+ // are different and methods need to be changed thoroughly with interaction rework
+ const tools::Polygon aPathPolygon(rPathPolyPolygon.getB2DPolygon(0));
+ const sal_uInt16 nPointCount(aPathPolygon.GetSize());
+
+ if(nPointCount >= 3)
+ {
+ bRetval = pMarkedPathObject->IsClosedObj() // #i76617#
+ || std::any_of(rSelectedPoints.begin(), rSelectedPoints.end(),
+ [nPointCount](const sal_uInt16 nMarkedPointNum) {
+ return nMarkedPointNum > 0 && nMarkedPointNum < nPointCount - 1;
+ });
+ }
+ }
+ }
+
+ return bRetval;
+}
+
+bool SdrPolyEditView::IsOpenCloseMarkedObjectsPossible() const
+{
+ bool bRetval(false);
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t a = 0; a < nMarkCount; ++a)
+ {
+ const SdrMark* pMark = GetSdrMarkByIndex(a);
+ const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
+
+ if(pMarkedPathObject)
+ {
+ // #i76617# Do not yet use basegfx::B2DPolygon since curve definitions
+ // are different and methods need to be changed thoroughly with interaction rework
+ const tools::PolyPolygon aPathPolyPolygon(pMarkedPathObject->GetPathPoly());
+ const sal_uInt16 nPolygonCount(aPathPolyPolygon.Count());
+
+ for(sal_uInt16 b(0); !bRetval && b < nPolygonCount; b++)
+ {
+ const tools::Polygon& rPathPolygon = aPathPolyPolygon[b];
+ const sal_uInt16 nPointCount(rPathPolygon.GetSize());
+
+ bRetval = (nPointCount >= 3);
+ }
+ }
+ }
+
+ return bRetval;
+}
+
+SdrObjClosedKind SdrPolyEditView::GetMarkedObjectsClosedState() const
+{
+ bool bOpen(false);
+ bool bClosed(false);
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t a = 0; !(bOpen && bClosed) && a < nMarkCount; ++a)
+ {
+ const SdrMark* pMark = GetSdrMarkByIndex(a);
+ const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
+
+ if(pMarkedPathObject)
+ {
+ if(pMarkedPathObject->IsClosedObj())
+ {
+ bClosed = true;
+ }
+ else
+ {
+ bOpen = true;
+ }
+ }
+ }
+
+ if(bOpen && bClosed)
+ {
+ return SdrObjClosedKind::DontCare;
+ }
+ else if(bOpen)
+ {
+ return SdrObjClosedKind::Open;
+ }
+ else
+ {
+ return SdrObjClosedKind::Closed;
+ }
+}
+
+void SdrPolyEditView::ImpTransformMarkedPoints(PPolyTrFunc pTrFunc, const void* p1, const void* p2, const void* p3, const void* p4)
+{
+ const bool bUndo = IsUndoEnabled();
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrPathObj* pPath=dynamic_cast<SdrPathObj*>( pObj );
+ if (!pPath)
+ continue;
+
+ const SdrUShortCont& rPts = pM->GetMarkedPoints();
+ if (rPts.empty())
+ continue;
+
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+
+ basegfx::B2DPolyPolygon aXPP(pPath->GetPathPoly());
+
+ for (const auto& rPt : rPts)
+ {
+ sal_uInt32 nPt = rPt;
+ sal_uInt32 nPolyNum, nPointNum;
+
+ if(PolyPolygonEditor::GetRelativePolyPoint(aXPP, nPt, nPolyNum, nPointNum))
+ {
+ //#i83671# used nLocalPointNum (which was the polygon point count)
+ // instead of the point index (nPointNum). This of course led
+ // to a wrong point access to the B2DPolygon.
+ basegfx::B2DPolygon aNewXP(aXPP.getB2DPolygon(nPolyNum));
+ Point aPos, aC1, aC2;
+ bool bC1(false);
+ bool bC2(false);
+
+ const basegfx::B2DPoint aB2DPos(aNewXP.getB2DPoint(nPointNum));
+ aPos = Point(FRound(aB2DPos.getX()), FRound(aB2DPos.getY()));
+
+ if(aNewXP.isPrevControlPointUsed(nPointNum))
+ {
+ const basegfx::B2DPoint aB2DC1(aNewXP.getPrevControlPoint(nPointNum));
+ aC1 = Point(FRound(aB2DC1.getX()), FRound(aB2DC1.getY()));
+ bC1 = true;
+ }
+
+ if(aNewXP.isNextControlPointUsed(nPointNum))
+ {
+ const basegfx::B2DPoint aB2DC2(aNewXP.getNextControlPoint(nPointNum));
+ aC2 = Point(FRound(aB2DC2.getX()), FRound(aB2DC2.getY()));
+ bC2 = true;
+ }
+
+ (*pTrFunc)(aPos,&aC1,&aC2,p1,p2,p3,p4);
+ aNewXP.setB2DPoint(nPointNum, basegfx::B2DPoint(aPos.X(), aPos.Y()));
+
+ if (bC1)
+ {
+ aNewXP.setPrevControlPoint(nPointNum, basegfx::B2DPoint(aC1.X(), aC1.Y()));
+ }
+
+ if (bC2)
+ {
+ aNewXP.setNextControlPoint(nPointNum, basegfx::B2DPoint(aC2.X(), aC2.Y()));
+ }
+
+ aXPP.setB2DPolygon(nPolyNum, aNewXP);
+ }
+ }
+
+ pPath->SetPathPoly(aXPP);
+ }
+}
+
+
+static void ImpMove(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* /*p2*/, const void* /*p3*/, const void* /*p4*/)
+{
+ rPt.Move(*static_cast<const Size*>(p1));
+ if (pC1!=nullptr) pC1->Move(*static_cast<const Size*>(p1));
+ if (pC2!=nullptr) pC2->Move(*static_cast<const Size*>(p1));
+}
+
+void SdrPolyEditView::MoveMarkedPoints(const Size& rSiz)
+{
+ ForceUndirtyMrkPnt();
+ OUString aStr(SvxResId(STR_EditMove));
+ BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Move);
+ ImpTransformMarkedPoints(ImpMove,&rSiz);
+ EndUndo();
+ AdjustMarkHdl();
+}
+
+static void ImpResize(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* p2, const void* p3, const void* /*p4*/)
+{
+ ResizePoint(rPt,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
+ if (pC1!=nullptr) ResizePoint(*pC1,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
+ if (pC2!=nullptr) ResizePoint(*pC2,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
+}
+
+void SdrPolyEditView::ResizeMarkedPoints(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ ForceUndirtyMrkPnt();
+ OUString aStr(SvxResId(STR_EditResize));
+ BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Resize);
+ ImpTransformMarkedPoints(ImpResize,&rRef,&xFact,&yFact);
+ EndUndo();
+ AdjustMarkHdl();
+}
+
+static void ImpRotate(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* /*p2*/, const void* p3, const void* p4)
+{
+ RotatePoint(rPt,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
+ if (pC1!=nullptr) RotatePoint(*pC1,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
+ if (pC2!=nullptr) RotatePoint(*pC2,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
+}
+
+void SdrPolyEditView::RotateMarkedPoints(const Point& rRef, long nAngle)
+{
+ ForceUndirtyMrkPnt();
+ OUString aStr(SvxResId(STR_EditResize));
+ BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Rotate);
+ double nSin = sin(nAngle * F_PI18000);
+ double nCos = cos(nAngle * F_PI18000);
+ ImpTransformMarkedPoints(ImpRotate,&rRef,&nAngle,&nSin,&nCos);
+ EndUndo();
+ AdjustMarkHdl();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */