1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <svx/svdpoev.hxx>
22 #include <math.h>
23 #include <svx/svdpagv.hxx>
24 #include <svx/svdpage.hxx>
25 #include <svx/svdopath.hxx>
26 #include <svx/svdundo.hxx>
27 #include <svx/strings.hrc>
28 #include <svx/dialmgr.hxx>
29 #include <svx/svdtrans.hxx>
30 #include <basegfx/polygon/b2dpolygon.hxx>
31 #include <basegfx/polygon/b2dpolygontools.hxx>
32 #include <tools/debug.hxx>
33 #include <tools/helpers.hxx>
34 
35 #include <svx/polypolygoneditor.hxx>
36 
37 using namespace sdr;
38 
39 
ImpResetPolyPossibilityFlags()40 void SdrPolyEditView::ImpResetPolyPossibilityFlags()
41 {
42     eMarkedPointsSmooth=SdrPathSmoothKind::DontCare;
43     eMarkedSegmentsKind=SdrPathSegmentKind::DontCare;
44     bSetMarkedPointsSmoothPossible=false;
45     bSetMarkedSegmentsKindPossible=false;
46 }
47 
SdrPolyEditView(SdrModel & rSdrModel,OutputDevice * pOut)48 SdrPolyEditView::SdrPolyEditView(
49     SdrModel& rSdrModel,
50     OutputDevice* pOut)
51 :   SdrEditView(rSdrModel, pOut)
52 {
53     ImpResetPolyPossibilityFlags();
54 }
55 
~SdrPolyEditView()56 SdrPolyEditView::~SdrPolyEditView()
57 {
58 }
59 
ImpCheckPolyPossibilities()60 void SdrPolyEditView::ImpCheckPolyPossibilities()
61 {
62     ImpResetPolyPossibilityFlags();
63     const size_t nMarkCount(GetMarkedObjectCount());
64 
65     if(!nMarkCount || ImpIsFrameHandles())
66         return;
67 
68     bool b1stSmooth(true);
69     bool b1stSegm(true);
70     bool bCurve(false);
71     bool bSmoothFuz(false);
72     bool bSegmFuz(false);
73     basegfx::B2VectorContinuity eSmooth = basegfx::B2VectorContinuity::NONE;
74 
75     for(size_t nMarkNum = 0; nMarkNum < nMarkCount; ++nMarkNum)
76     {
77         SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
78         CheckPolyPossibilitiesHelper( pM, b1stSmooth, b1stSegm, bCurve, bSmoothFuz, bSegmFuz, eSmooth );
79     }
80 }
81 
CheckPolyPossibilitiesHelper(SdrMark * pM,bool & b1stSmooth,bool & b1stSegm,bool & bCurve,bool & bSmoothFuz,bool & bSegmFuz,basegfx::B2VectorContinuity & eSmooth)82 void SdrPolyEditView::CheckPolyPossibilitiesHelper( SdrMark* pM, bool& b1stSmooth, bool& b1stSegm, bool& bCurve, bool& bSmoothFuz, bool& bSegmFuz, basegfx::B2VectorContinuity& eSmooth )
83 {
84     SdrObject* pObj = pM->GetMarkedSdrObj();
85     SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pObj );
86 
87     if (!pPath)
88         return;
89 
90     SdrUShortCont& rPts = pM->GetMarkedPoints();
91     if (rPts.empty())
92         return;
93 
94     const bool bClosed(pPath->IsClosed());
95     bSetMarkedPointsSmoothPossible = true;
96 
97     if (bClosed)
98     {
99         bSetMarkedSegmentsKindPossible = true;
100     }
101 
102     for (const auto& rPt : rPts)
103     {
104         sal_uInt32 nNum(rPt);
105         sal_uInt32 nPolyNum, nPntNum;
106 
107         if(PolyPolygonEditor::GetRelativePolyPoint(pPath->GetPathPoly(), nNum, nPolyNum, nPntNum))
108         {
109             const basegfx::B2DPolygon aLocalPolygon(pPath->GetPathPoly().getB2DPolygon(nPolyNum));
110             bool bCanSegment(bClosed || nPntNum < aLocalPolygon.count() - 1);
111 
112             if(!bSetMarkedSegmentsKindPossible && bCanSegment)
113             {
114                 bSetMarkedSegmentsKindPossible = true;
115             }
116 
117             if(!bSmoothFuz)
118             {
119                 if (b1stSmooth)
120                 {
121                     b1stSmooth = false;
122                     eSmooth = basegfx::utils::getContinuityInPoint(aLocalPolygon, nPntNum);
123                 }
124                 else
125                 {
126                     bSmoothFuz = (eSmooth != basegfx::utils::getContinuityInPoint(aLocalPolygon, nPntNum));
127                 }
128             }
129 
130             if(!bSegmFuz && bCanSegment)
131             {
132                 bool bCrv(aLocalPolygon.isNextControlPointUsed(nPntNum));
133 
134                 if(b1stSegm)
135                 {
136                     b1stSegm = false;
137                     bCurve = bCrv;
138                 }
139                 else
140                 {
141                     bSegmFuz = (bCrv != bCurve);
142                 }
143             }
144         }
145     }
146 
147     if(!b1stSmooth && !bSmoothFuz)
148     {
149         if(basegfx::B2VectorContinuity::NONE == eSmooth)
150         {
151             eMarkedPointsSmooth = SdrPathSmoothKind::Angular;
152         }
153 
154         if(basegfx::B2VectorContinuity::C1 == eSmooth)
155         {
156             eMarkedPointsSmooth = SdrPathSmoothKind::Asymmetric;
157         }
158 
159         if(basegfx::B2VectorContinuity::C2 == eSmooth)
160         {
161             eMarkedPointsSmooth = SdrPathSmoothKind::Symmetric;
162         }
163     }
164 
165     if(!b1stSegm && !bSegmFuz)
166     {
167         eMarkedSegmentsKind = bCurve ? SdrPathSegmentKind::Curve : SdrPathSegmentKind::Line;
168     }
169 }
170 
SetMarkedPointsSmooth(SdrPathSmoothKind eKind)171 void SdrPolyEditView::SetMarkedPointsSmooth(SdrPathSmoothKind eKind)
172 {
173     basegfx::B2VectorContinuity eFlags;
174 
175     if(SdrPathSmoothKind::Angular == eKind)
176     {
177         eFlags = basegfx::B2VectorContinuity::NONE;
178     }
179     else if(SdrPathSmoothKind::Asymmetric == eKind)
180     {
181         eFlags = basegfx::B2VectorContinuity::C1;
182     }
183     else if(SdrPathSmoothKind::Symmetric == eKind)
184     {
185         eFlags = basegfx::B2VectorContinuity::C2;
186     }
187     else
188     {
189         return;
190     }
191 
192     if(!HasMarkedPoints())
193         return;
194 
195     SortMarkedObjects();
196 
197     const bool bUndo = IsUndoEnabled();
198     if( bUndo )
199         BegUndo(SvxResId(STR_EditSetPointsSmooth), GetDescriptionOfMarkedPoints());
200     const size_t nMarkCount(GetMarkedObjectCount());
201 
202     for(size_t nMarkNum(nMarkCount); nMarkNum > 0;)
203     {
204         --nMarkNum;
205         SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
206         SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
207         if (!pPath)
208             continue;
209 
210         SdrUShortCont& rPts = pM->GetMarkedPoints();
211         PolyPolygonEditor aEditor(pPath->GetPathPoly());
212         if (aEditor.SetPointsSmooth(eFlags, rPts))
213         {
214             if( bUndo )
215                 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath));
216             pPath->SetPathPoly(aEditor.GetPolyPolygon());
217         }
218     }
219 
220     if( bUndo )
221         EndUndo();
222 }
223 
SetMarkedSegmentsKind(SdrPathSegmentKind eKind)224 void SdrPolyEditView::SetMarkedSegmentsKind(SdrPathSegmentKind eKind)
225 {
226     if(!HasMarkedPoints())
227         return;
228 
229     SortMarkedObjects();
230 
231     const bool bUndo = IsUndoEnabled();
232     if( bUndo )
233         BegUndo(SvxResId(STR_EditSetSegmentsKind), GetDescriptionOfMarkedPoints());
234     const size_t nMarkCount(GetMarkedObjectCount());
235 
236     for(size_t nMarkNum=nMarkCount; nMarkNum > 0;)
237     {
238         --nMarkNum;
239         SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
240         SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
241         if (!pPath)
242             continue;
243         SdrUShortCont& rPts = pM->GetMarkedPoints();
244         PolyPolygonEditor aEditor( pPath->GetPathPoly());
245         if (aEditor.SetSegmentsKind(eKind, rPts))
246         {
247             if( bUndo )
248                 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath));
249             pPath->SetPathPoly(aEditor.GetPolyPolygon());
250         }
251     }
252 
253     if( bUndo )
254         EndUndo();
255 }
256 
IsSetMarkedPointsSmoothPossible() const257 bool SdrPolyEditView::IsSetMarkedPointsSmoothPossible() const
258 {
259     ForcePossibilities();
260     return bSetMarkedPointsSmoothPossible;
261 }
262 
GetMarkedPointsSmooth() const263 SdrPathSmoothKind SdrPolyEditView::GetMarkedPointsSmooth() const
264 {
265     ForcePossibilities();
266     return eMarkedPointsSmooth;
267 }
268 
IsSetMarkedSegmentsKindPossible() const269 bool SdrPolyEditView::IsSetMarkedSegmentsKindPossible() const
270 {
271     ForcePossibilities();
272     return bSetMarkedSegmentsKindPossible;
273 }
274 
GetMarkedSegmentsKind() const275 SdrPathSegmentKind SdrPolyEditView::GetMarkedSegmentsKind() const
276 {
277     ForcePossibilities();
278     return eMarkedSegmentsKind;
279 }
280 
IsDeleteMarkedPointsPossible() const281 bool SdrPolyEditView::IsDeleteMarkedPointsPossible() const
282 {
283     return HasMarkedPoints();
284 }
285 
DeleteMarkedPoints()286 void SdrPolyEditView::DeleteMarkedPoints()
287 {
288     if (!HasMarkedPoints())
289         return;
290 
291     BrkAction();
292     SortMarkedObjects();
293     const size_t nMarkCount=GetMarkedObjectCount();
294 
295     const bool bUndo = IsUndoEnabled();
296     if( bUndo )
297     {
298         // Description
299         BegUndo(SvxResId(STR_EditDelete),GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Delete);
300     }
301 
302     for (size_t nMarkNum=nMarkCount; nMarkNum>0;)
303     {
304         --nMarkNum;
305         SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
306         SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
307         if (!pPath)
308             continue;
309 
310         SdrUShortCont& rPts = pM->GetMarkedPoints();
311         PolyPolygonEditor aEditor( pPath->GetPathPoly());
312         if (aEditor.DeletePoints(rPts))
313         {
314             if( aEditor.GetPolyPolygon().count() )
315             {
316                 if( bUndo )
317                     AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath ));
318                 pPath->SetPathPoly( aEditor.GetPolyPolygon() );
319             }
320             else
321             {
322                 if( bUndo )
323                     AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pPath ) );
324                 pM->GetPageView()->GetObjList()->RemoveObject(pPath->GetOrdNum());
325                 if( !bUndo )
326                 {
327                     SdrObject* pObj = pPath;
328                     SdrObject::Free(pObj);
329                 }
330             }
331         }
332     }
333 
334     if( bUndo )
335         EndUndo();
336     UnmarkAllPoints();
337     MarkListHasChanged();
338 }
339 
RipUpAtMarkedPoints()340 void SdrPolyEditView::RipUpAtMarkedPoints()
341 {
342     if(!HasMarkedPoints())
343         return;
344 
345     SortMarkedObjects();
346     const size_t nMarkCount(GetMarkedObjectCount());
347 
348     const bool bUndo = IsUndoEnabled();
349     if( bUndo )
350         BegUndo(SvxResId(STR_EditRipUp), GetDescriptionOfMarkedPoints());
351 
352     for(size_t nMarkNum = nMarkCount; nMarkNum > 0;)
353     {
354         --nMarkNum;
355         SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
356         SdrPathObj* pObj = dynamic_cast<SdrPathObj*>( pM->GetMarkedSdrObj() );
357         if (!pObj)
358             continue;
359 
360         SdrUShortCont& rPts = pM->GetMarkedPoints();
361 
362         if( bUndo )
363             AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
364         bool bCorrectionFlag(false);
365         sal_uInt32 nMax(pObj->GetHdlCount());
366 
367         for(SdrUShortCont::const_reverse_iterator it = rPts.rbegin(); it != rPts.rend(); ++it)
368         {
369             sal_uInt32 nNewPt0Idx(0);
370             SdrObject* pNewObj = pObj->RipPoint(*it, nNewPt0Idx);
371 
372             if(pNewObj)
373             {
374                 pM->GetPageView()->GetObjList()->InsertObject(pNewObj, pObj->GetOrdNum() + 1);
375                 if( bUndo )
376                     AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewObj));
377                 MarkObj(pNewObj, pM->GetPageView(), false, true);
378             }
379 
380             if(nNewPt0Idx)
381             {
382                 // correction necessary?
383                 DBG_ASSERT(!bCorrectionFlag,"Multiple index corrections at SdrPolyEditView::RipUp().");
384                 if(!bCorrectionFlag)
385                 {
386                     bCorrectionFlag = true;
387 
388                     SdrUShortCont aReplaceSet;
389                     for(const auto& rPt : rPts)
390                     {
391                         sal_uInt32 nPntNum(rPt);
392                         nPntNum += nNewPt0Idx;
393 
394                         if(nPntNum >= nMax)
395                         {
396                             nPntNum -= nMax;
397                         }
398 
399                         aReplaceSet.insert( static_cast<sal_uInt16>(nPntNum) );
400                     }
401                     rPts.swap(aReplaceSet);
402 
403                     it = rPts.rbegin();
404                 }
405             }
406         }
407     }
408 
409     UnmarkAllPoints();
410     if( bUndo )
411         EndUndo();
412     MarkListHasChanged();
413 }
414 
IsRipUpAtMarkedPointsPossible() const415 bool SdrPolyEditView::IsRipUpAtMarkedPointsPossible() const
416 {
417     bool bRetval(false);
418     const size_t nMarkCount(GetMarkedObjectCount());
419 
420     for(size_t a = 0; a < nMarkCount; ++a)
421     {
422         const SdrMark* pMark = GetSdrMarkByIndex(a);
423         const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
424 
425         if (!pMarkedPathObject)
426             continue;
427 
428         const SdrUShortCont& rSelectedPoints = pMark->GetMarkedPoints();
429         if (rSelectedPoints.empty())
430             continue;
431 
432         const basegfx::B2DPolyPolygon& rPathPolyPolygon = pMarkedPathObject->GetPathPoly();
433 
434         if(1 == rPathPolyPolygon.count())
435         {
436             // #i76617# Do not yet use basegfx::B2DPolygon since curve definitions
437             // are different and methods need to be changed thoroughly with interaction rework
438             const tools::Polygon aPathPolygon(rPathPolyPolygon.getB2DPolygon(0));
439             const sal_uInt16 nPointCount(aPathPolygon.GetSize());
440 
441             if(nPointCount >= 3)
442             {
443                 bRetval = pMarkedPathObject->IsClosedObj() // #i76617#
444                     || std::any_of(rSelectedPoints.begin(), rSelectedPoints.end(),
445                         [nPointCount](const sal_uInt16 nMarkedPointNum) {
446                             return nMarkedPointNum > 0 && nMarkedPointNum < nPointCount - 1;
447                         });
448             }
449         }
450     }
451 
452     return bRetval;
453 }
454 
IsOpenCloseMarkedObjectsPossible() const455 bool SdrPolyEditView::IsOpenCloseMarkedObjectsPossible() const
456 {
457     bool bRetval(false);
458     const size_t nMarkCount(GetMarkedObjectCount());
459 
460     for(size_t a = 0; a < nMarkCount; ++a)
461     {
462         const SdrMark* pMark = GetSdrMarkByIndex(a);
463         const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
464 
465         if(pMarkedPathObject)
466         {
467             // #i76617# Do not yet use basegfx::B2DPolygon since curve definitions
468             // are different and methods need to be changed thoroughly with interaction rework
469             const tools::PolyPolygon aPathPolyPolygon(pMarkedPathObject->GetPathPoly());
470             const sal_uInt16 nPolygonCount(aPathPolyPolygon.Count());
471 
472             for(sal_uInt16 b(0); !bRetval && b < nPolygonCount; b++)
473             {
474                 const tools::Polygon& rPathPolygon = aPathPolyPolygon[b];
475                 const sal_uInt16 nPointCount(rPathPolygon.GetSize());
476 
477                 bRetval = (nPointCount >= 3);
478             }
479         }
480     }
481 
482     return bRetval;
483 }
484 
GetMarkedObjectsClosedState() const485 SdrObjClosedKind SdrPolyEditView::GetMarkedObjectsClosedState() const
486 {
487     bool bOpen(false);
488     bool bClosed(false);
489     const size_t nMarkCount(GetMarkedObjectCount());
490 
491     for(size_t a = 0; !(bOpen && bClosed) && a < nMarkCount; ++a)
492     {
493         const SdrMark* pMark = GetSdrMarkByIndex(a);
494         const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
495 
496         if(pMarkedPathObject)
497         {
498             if(pMarkedPathObject->IsClosedObj())
499             {
500                 bClosed = true;
501             }
502             else
503             {
504                 bOpen = true;
505             }
506         }
507     }
508 
509     if(bOpen && bClosed)
510     {
511         return SdrObjClosedKind::DontCare;
512     }
513     else if(bOpen)
514     {
515         return SdrObjClosedKind::Open;
516     }
517     else
518     {
519         return SdrObjClosedKind::Closed;
520     }
521 }
522 
ImpTransformMarkedPoints(PPolyTrFunc pTrFunc,const void * p1,const void * p2,const void * p3,const void * p4)523 void SdrPolyEditView::ImpTransformMarkedPoints(PPolyTrFunc pTrFunc, const void* p1, const void* p2, const void* p3, const void* p4)
524 {
525     const bool bUndo = IsUndoEnabled();
526 
527     const size_t nMarkCount=GetMarkedObjectCount();
528     for (size_t nm=0; nm<nMarkCount; ++nm)
529     {
530         SdrMark* pM=GetSdrMarkByIndex(nm);
531         SdrObject* pObj=pM->GetMarkedSdrObj();
532         SdrPathObj* pPath=dynamic_cast<SdrPathObj*>( pObj );
533         if (!pPath)
534             continue;
535 
536         const SdrUShortCont& rPts = pM->GetMarkedPoints();
537         if (rPts.empty())
538             continue;
539 
540         if( bUndo )
541             AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
542 
543         basegfx::B2DPolyPolygon aXPP(pPath->GetPathPoly());
544 
545         for (const auto& rPt : rPts)
546         {
547             sal_uInt32 nPt = rPt;
548             sal_uInt32 nPolyNum, nPointNum;
549 
550             if(PolyPolygonEditor::GetRelativePolyPoint(aXPP, nPt, nPolyNum, nPointNum))
551             {
552                 //#i83671# used nLocalPointNum (which was the polygon point count)
553                 // instead of the point index (nPointNum). This of course led
554                 // to a wrong point access to the B2DPolygon.
555                 basegfx::B2DPolygon aNewXP(aXPP.getB2DPolygon(nPolyNum));
556                 Point aPos, aC1, aC2;
557                 bool bC1(false);
558                 bool bC2(false);
559 
560                 const basegfx::B2DPoint aB2DPos(aNewXP.getB2DPoint(nPointNum));
561                 aPos = Point(FRound(aB2DPos.getX()), FRound(aB2DPos.getY()));
562 
563                 if(aNewXP.isPrevControlPointUsed(nPointNum))
564                 {
565                     const basegfx::B2DPoint aB2DC1(aNewXP.getPrevControlPoint(nPointNum));
566                     aC1 = Point(FRound(aB2DC1.getX()), FRound(aB2DC1.getY()));
567                     bC1 = true;
568                 }
569 
570                 if(aNewXP.isNextControlPointUsed(nPointNum))
571                 {
572                     const basegfx::B2DPoint aB2DC2(aNewXP.getNextControlPoint(nPointNum));
573                     aC2 = Point(FRound(aB2DC2.getX()), FRound(aB2DC2.getY()));
574                     bC2 = true;
575                 }
576 
577                 (*pTrFunc)(aPos,&aC1,&aC2,p1,p2,p3,p4);
578                 aNewXP.setB2DPoint(nPointNum, basegfx::B2DPoint(aPos.X(), aPos.Y()));
579 
580                 if (bC1)
581                 {
582                     aNewXP.setPrevControlPoint(nPointNum, basegfx::B2DPoint(aC1.X(), aC1.Y()));
583                 }
584 
585                 if (bC2)
586                 {
587                     aNewXP.setNextControlPoint(nPointNum, basegfx::B2DPoint(aC2.X(), aC2.Y()));
588                 }
589 
590                 aXPP.setB2DPolygon(nPolyNum, aNewXP);
591             }
592         }
593 
594         pPath->SetPathPoly(aXPP);
595     }
596 }
597 
598 
ImpMove(Point & rPt,Point * pC1,Point * pC2,const void * p1,const void *,const void *,const void *)599 static void ImpMove(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* /*p2*/, const void* /*p3*/, const void* /*p4*/)
600 {
601     rPt.Move(*static_cast<const Size*>(p1));
602     if (pC1!=nullptr) pC1->Move(*static_cast<const Size*>(p1));
603     if (pC2!=nullptr) pC2->Move(*static_cast<const Size*>(p1));
604 }
605 
MoveMarkedPoints(const Size & rSiz)606 void SdrPolyEditView::MoveMarkedPoints(const Size& rSiz)
607 {
608     ForceUndirtyMrkPnt();
609     OUString aStr(SvxResId(STR_EditMove));
610     BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Move);
611     ImpTransformMarkedPoints(ImpMove,&rSiz);
612     EndUndo();
613     AdjustMarkHdl();
614 }
615 
ImpResize(Point & rPt,Point * pC1,Point * pC2,const void * p1,const void * p2,const void * p3,const void *)616 static void ImpResize(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* p2, const void* p3, const void* /*p4*/)
617 {
618     ResizePoint(rPt,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
619     if (pC1!=nullptr) ResizePoint(*pC1,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
620     if (pC2!=nullptr) ResizePoint(*pC2,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
621 }
622 
ResizeMarkedPoints(const Point & rRef,const Fraction & xFact,const Fraction & yFact)623 void SdrPolyEditView::ResizeMarkedPoints(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
624 {
625     ForceUndirtyMrkPnt();
626     OUString aStr(SvxResId(STR_EditResize));
627     BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Resize);
628     ImpTransformMarkedPoints(ImpResize,&rRef,&xFact,&yFact);
629     EndUndo();
630     AdjustMarkHdl();
631 }
632 
ImpRotate(Point & rPt,Point * pC1,Point * pC2,const void * p1,const void *,const void * p3,const void * p4)633 static void ImpRotate(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* /*p2*/, const void* p3, const void* p4)
634 {
635     RotatePoint(rPt,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
636     if (pC1!=nullptr) RotatePoint(*pC1,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
637     if (pC2!=nullptr) RotatePoint(*pC2,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
638 }
639 
RotateMarkedPoints(const Point & rRef,Degree100 nAngle)640 void SdrPolyEditView::RotateMarkedPoints(const Point& rRef, Degree100 nAngle)
641 {
642     ForceUndirtyMrkPnt();
643     OUString aStr(SvxResId(STR_EditResize));
644     BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Rotate);
645     double nSin = sin(nAngle.get() * F_PI18000);
646     double nCos = cos(nAngle.get() * F_PI18000);
647     ImpTransformMarkedPoints(ImpRotate,&rRef,&nAngle,&nSin,&nCos);
648     EndUndo();
649     AdjustMarkHdl();
650 }
651 
652 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
653