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 <dragmt3d.hxx>
22 #include <o3tl/numeric.hxx>
23 #include <svx/svdpagv.hxx>
24 #include <svx/dialmgr.hxx>
25 #include <svx/svddrgmt.hxx>
26 #include <svx/svdtrans.hxx>
27 #include <svx/obj3d.hxx>
28 #include <svx/e3dundo.hxx>
29 #include <svx/strings.hrc>
30 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
31 #include <svx/sdr/overlay/overlaymanager.hxx>
32 #include <basegfx/polygon/b2dpolypolygontools.hxx>
33 #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
34 #include <drawinglayer/geometry/viewinformation3d.hxx>
35 #include <svx/e3dsceneupdater.hxx>
36 #include <vcl/ptrstyle.hxx>
37 #include <comphelper/lok.hxx>
38 
39 
E3dDragMethod(SdrDragView & _rView,const SdrMarkList & rMark,E3dDragConstraint eConstr,bool bFull)40 E3dDragMethod::E3dDragMethod (
41     SdrDragView &_rView,
42     const SdrMarkList& rMark,
43     E3dDragConstraint eConstr,
44     bool bFull)
45 :   SdrDragMethod(_rView),
46     meConstraint(eConstr),
47     mbMoveFull(bFull),
48     mbMovedAtAll(false)
49 {
50     // Create a unit for all the 3D objects present in the selection
51     const size_t nCnt(rMark.GetMarkCount());
52 
53     if(mbMoveFull)
54     {
55         // for non-visible 3D objects fallback to wireframe interaction
56         for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
57         {
58             E3dObject* pE3dObj = dynamic_cast< E3dObject* >(rMark.GetMark(nObjs)->GetMarkedSdrObj());
59 
60             if(pE3dObj)
61             {
62                 if(!pE3dObj->HasFillStyle() && !pE3dObj->HasLineStyle())
63                 {
64                     mbMoveFull = false;
65                     break;
66                 }
67             }
68         }
69     }
70 
71     for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
72     {
73         E3dObject* pE3dObj = dynamic_cast< E3dObject* >(rMark.GetMark(nObjs)->GetMarkedSdrObj());
74 
75         if(pE3dObj)
76         {
77             // fill new interaction unit
78             E3dDragMethodUnit aNewUnit(*pE3dObj);
79 
80             // get transformations
81             aNewUnit.maInitTransform = aNewUnit.maTransform = pE3dObj->GetTransform();
82 
83             if(nullptr != pE3dObj->getParentE3dSceneFromE3dObject())
84             {
85                 // get transform between object and world, normally scene transform
86                 aNewUnit.maInvDisplayTransform = aNewUnit.maDisplayTransform = pE3dObj->getParentE3dSceneFromE3dObject()->GetFullTransform();
87                 aNewUnit.maInvDisplayTransform.invert();
88             }
89 
90             if(!mbMoveFull)
91             {
92                 // create wireframe visualisation for parent coordinate system
93                 aNewUnit.maWireframePoly.clear();
94                 aNewUnit.maWireframePoly = pE3dObj->CreateWireframe();
95                 aNewUnit.maWireframePoly.transform(aNewUnit.maTransform);
96             }
97 
98             // Determine FullBound
99             maFullBound.Union(pE3dObj->GetSnapRect());
100 
101             // Insert Unit
102             maGrp.push_back(aNewUnit);
103         }
104     }
105 }
106 
GetSdrDragComment() const107 OUString E3dDragMethod::GetSdrDragComment() const
108 {
109     return OUString();
110 }
111 
112 // Create the wireframe model for all actions
113 
BeginSdrDrag()114 bool E3dDragMethod::BeginSdrDrag()
115 {
116     if(E3dDragConstraint::Z == meConstraint)
117     {
118         const sal_uInt32 nCnt(maGrp.size());
119         DragStat().SetRef1( maFullBound.Center() );
120 
121         for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
122         {
123             E3dDragMethodUnit& rCandidate = maGrp[nOb];
124             rCandidate.mnStartAngle = GetAngle(DragStat().GetStart() - DragStat().GetRef1());
125             rCandidate.mnLastAngle = 0_deg100;
126         }
127     }
128     else
129     {
130         maLastPos = DragStat().GetStart();
131     }
132 
133     if(!mbMoveFull)
134     {
135         Show();
136     }
137 
138     return true;
139 }
140 
EndSdrDrag(bool)141 bool E3dDragMethod::EndSdrDrag(bool /*bCopy*/)
142 {
143     const sal_uInt32 nCnt(maGrp.size());
144 
145     if(!mbMoveFull)
146     {
147         // Hide wireframe
148         Hide();
149     }
150 
151     // Apply all transformations and create undo's
152     if(mbMovedAtAll)
153     {
154         const bool bUndo = getSdrDragView().IsUndoEnabled();
155         if( bUndo )
156             getSdrDragView().BegUndo(SvxResId(RID_SVX_3D_UNDO_ROTATE));
157         sal_uInt32 nOb(0);
158 
159         for(nOb=0;nOb<nCnt;nOb++)
160         {
161             E3dDragMethodUnit& rCandidate = maGrp[nOb];
162             E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
163             rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
164             if( bUndo )
165             {
166                 getSdrDragView().AddUndo(
167                     std::make_unique<E3dRotateUndoAction>(
168                         rCandidate.mr3DObj,
169                         rCandidate.maInitTransform,
170                         rCandidate.maTransform));
171             }
172         }
173         if( bUndo )
174             getSdrDragView().EndUndo();
175     }
176 
177     return true;
178 }
179 
CancelSdrDrag()180 void E3dDragMethod::CancelSdrDrag()
181 {
182     if(mbMoveFull)
183     {
184         if(mbMovedAtAll)
185         {
186             const sal_uInt32 nCnt(maGrp.size());
187 
188             for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
189             {
190                 // Restore transformation
191                 E3dDragMethodUnit& rCandidate = maGrp[nOb];
192                 E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
193                 rCandidate.mr3DObj.SetTransform(rCandidate.maInitTransform);
194             }
195         }
196     }
197     else
198     {
199         // Hide WireFrame
200         Hide();
201     }
202 }
203 
204 // Common MoveSdrDrag()
205 
MoveSdrDrag(const Point &)206 void E3dDragMethod::MoveSdrDrag(const Point& /*rPnt*/)
207 {
208     mbMovedAtAll = true;
209 }
210 
211 // Draw the wire frame model
212 
213 // for migration from XOR to overlay
CreateOverlayGeometry(sdr::overlay::OverlayManager & rOverlayManager,const sdr::contact::ObjectContact & rObjectContact)214 void E3dDragMethod::CreateOverlayGeometry(
215     sdr::overlay::OverlayManager& rOverlayManager,
216     const sdr::contact::ObjectContact& rObjectContact)
217 {
218     // We do client-side object manipulation with the Kit API
219     if (comphelper::LibreOfficeKit::isActive())
220         return;
221 
222     const sal_uInt32 nCnt(maGrp.size());
223     basegfx::B2DPolyPolygon aResult;
224 
225     for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
226     {
227         E3dDragMethodUnit& rCandidate = maGrp[nOb];
228         SdrPageView* pPV = getSdrDragView().GetSdrPageView();
229 
230         if(pPV && pPV->HasMarkedObjPageView())
231         {
232             const basegfx::B3DPolyPolygon aCandidate(rCandidate.maWireframePoly);
233             const sal_uInt32 nPlyCnt(aCandidate.count());
234 
235             if(nPlyCnt)
236             {
237                 const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
238 
239                 if(nullptr != pScene)
240                 {
241                     const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
242                     const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
243                     const basegfx::B3DHomMatrix aWorldToView(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection() * aViewInfo3D.getOrientation());
244                     const basegfx::B3DHomMatrix aTransform(aWorldToView * rCandidate.maDisplayTransform);
245 
246                     // transform to relative scene coordinates
247                     basegfx::B2DPolyPolygon aPolyPolygon(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aCandidate, aTransform));
248 
249                     // transform to 2D view coordinates
250                     aPolyPolygon.transform(rVCScene.getObjectTransformation());
251 
252                     aResult.append(aPolyPolygon);
253                 }
254             }
255         }
256     }
257 
258     if(aResult.count())
259     {
260         std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(
261             new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
262                 aResult));
263 
264         insertNewlyCreatedOverlayObjectForSdrDragMethod(
265             std::move(pNew),
266             rObjectContact,
267             rOverlayManager);
268     }
269 }
270 
271 
E3dDragRotate(SdrDragView & _rView,const SdrMarkList & rMark,E3dDragConstraint eConstr,bool bFull)272 E3dDragRotate::E3dDragRotate(SdrDragView &_rView,
273     const SdrMarkList& rMark,
274     E3dDragConstraint eConstr,
275     bool bFull)
276 :   E3dDragMethod(_rView, rMark, eConstr, bFull)
277 {
278     // Get center of all selected objects in eye coordinates
279     const sal_uInt32 nCnt(maGrp.size());
280 
281     if(!nCnt)
282         return;
283 
284     const E3dScene* pScene(maGrp[0].mr3DObj.getRootE3dSceneFromE3dObject());
285 
286     if(nullptr == pScene)
287         return;
288 
289     const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
290     const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
291 
292     for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
293     {
294         E3dDragMethodUnit& rCandidate = maGrp[nOb];
295         basegfx::B3DPoint aObjCenter = rCandidate.mr3DObj.GetBoundVolume().getCenter();
296         const basegfx::B3DHomMatrix aTransform(aViewInfo3D.getOrientation() * rCandidate.maDisplayTransform * rCandidate.maInitTransform);
297 
298         aObjCenter = aTransform * aObjCenter;
299         maGlobalCenter += aObjCenter;
300     }
301 
302     // Divide by the number
303     if(nCnt > 1)
304     {
305         maGlobalCenter /= static_cast<double>(nCnt);
306     }
307 
308     // get rotate center and transform to 3D eye coordinates
309     basegfx::B2DPoint aRotCenter2D(Ref1().X(), Ref1().Y());
310 
311     // from world to relative scene using inverse getObjectTransformation()
312     basegfx::B2DHomMatrix aInverseObjectTransform(rVCScene.getObjectTransformation());
313     aInverseObjectTransform.invert();
314     aRotCenter2D = aInverseObjectTransform * aRotCenter2D;
315 
316     // from 3D view to 3D eye
317     basegfx::B3DPoint aRotCenter3D(aRotCenter2D.getX(), aRotCenter2D.getY(), 0.0);
318     basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
319     aInverseViewToEye.invert();
320     aRotCenter3D = aInverseViewToEye * aRotCenter3D;
321 
322 // Use X,Y of the RotCenter and depth of the common object centre
323 // as rotation point in the space
324     maGlobalCenter.setX(aRotCenter3D.getX());
325     maGlobalCenter.setY(aRotCenter3D.getY());
326 }
327 
328 
329 //The object is moved, determine the angle
330 
MoveSdrDrag(const Point & rPnt)331 void E3dDragRotate::MoveSdrDrag(const Point& rPnt)
332 {
333     // call parent
334     E3dDragMethod::MoveSdrDrag(rPnt);
335 
336     if(!DragStat().CheckMinMoved(rPnt))
337         return;
338 
339     // Get modifier
340     sal_uInt16 nModifier = 0;
341     if(auto pDragView = dynamic_cast<const E3dView*>(&getSdrDragView()))
342     {
343         const MouseEvent& rLastMouse = pDragView->GetMouseEvent();
344         nModifier = rLastMouse.GetModifier();
345     }
346 
347     // Rotate all objects
348     const sal_uInt32 nCnt(maGrp.size());
349 
350     for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
351     {
352         // Determine rotation angle
353         double fWAngle, fHAngle;
354         E3dDragMethodUnit& rCandidate = maGrp[nOb];
355 
356         if(E3dDragConstraint::Z == meConstraint)
357         {
358             Degree100 lastAngle = NormAngle36000(GetAngle(rPnt - DragStat().GetRef1()) -
359                 rCandidate.mnStartAngle) - rCandidate.mnLastAngle;
360             rCandidate.mnLastAngle = lastAngle + rCandidate.mnLastAngle;
361             fWAngle = toDegrees(lastAngle);
362             fHAngle = 0.0;
363         }
364         else
365         {
366             if ((maFullBound.GetWidth() == 0) || (maFullBound.GetHeight() == 0))
367                 throw o3tl::divide_by_zero();
368             fWAngle = 90.0 * static_cast<double>(rPnt.X() - maLastPos.X())
369                 / static_cast<double>(maFullBound.GetWidth());
370             fHAngle = 90.0 * static_cast<double>(rPnt.Y() - maLastPos.Y())
371                 / static_cast<double>(maFullBound.GetHeight());
372         }
373         tools::Long nSnap = 0;
374 
375         if(!getSdrDragView().IsRotateAllowed())
376             nSnap = 90;
377 
378         if(nSnap != 0)
379         {
380             fWAngle = static_cast<double>((static_cast<tools::Long>(fWAngle) + nSnap/2) / nSnap * nSnap);
381             fHAngle = static_cast<double>((static_cast<tools::Long>(fHAngle) + nSnap/2) / nSnap * nSnap);
382         }
383 
384         // to radians
385         fWAngle = basegfx::deg2rad(fWAngle);
386         fHAngle = basegfx::deg2rad(fHAngle);
387 
388         // Determine transformation
389         basegfx::B3DHomMatrix aRotMat;
390         if(E3dDragConstraint::Y & meConstraint)
391         {
392             if(nModifier & KEY_MOD2)
393                 aRotMat.rotate(0.0, 0.0, fWAngle);
394             else
395                 aRotMat.rotate(0.0, fWAngle, 0.0);
396         }
397         else if(E3dDragConstraint::Z & meConstraint)
398         {
399             if(nModifier & KEY_MOD2)
400                 aRotMat.rotate(0.0, fWAngle, 0.0);
401             else
402                 aRotMat.rotate(0.0, 0.0, fWAngle);
403         }
404         if(E3dDragConstraint::X & meConstraint)
405         {
406             aRotMat.rotate(fHAngle, 0.0, 0.0);
407         }
408 
409         const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
410 
411         if(nullptr != pScene)
412         {
413             // Transformation in eye coordinates, there rotate then and back
414             const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
415             const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
416             basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
417             aInverseOrientation.invert();
418 
419             basegfx::B3DHomMatrix aTransMat(rCandidate.maDisplayTransform);
420             aTransMat *= aViewInfo3D.getOrientation();
421             aTransMat.translate(-maGlobalCenter.getX(), -maGlobalCenter.getY(), -maGlobalCenter.getZ());
422             aTransMat *= aRotMat;
423             aTransMat.translate(maGlobalCenter.getX(), maGlobalCenter.getY(), maGlobalCenter.getZ());
424             aTransMat *= aInverseOrientation;
425             aTransMat *= rCandidate.maInvDisplayTransform;
426 
427             // ...and apply
428             rCandidate.maTransform *= aTransMat;
429 
430             if(mbMoveFull)
431             {
432                 E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
433                 rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
434             }
435             else
436             {
437                 Hide();
438                 rCandidate.maWireframePoly.transform(aTransMat);
439                 Show();
440             }
441         }
442     }
443     maLastPos = rPnt;
444     DragStat().NextMove(rPnt);
445 }
446 
GetSdrDragPointer() const447 PointerStyle E3dDragRotate::GetSdrDragPointer() const
448 {
449     return PointerStyle::Rotate;
450 }
451 
452 // E3dDragMove. This drag method is only required for translations inside
453 // 3D scenes. If a 3D-scene itself moved, then this drag method will drag
454 // not be used.
455 
456 
E3dDragMove(SdrDragView & _rView,const SdrMarkList & rMark,SdrHdlKind eDrgHdl,E3dDragConstraint eConstr,bool bFull)457 E3dDragMove::E3dDragMove(SdrDragView &_rView,
458     const SdrMarkList& rMark,
459     SdrHdlKind eDrgHdl,
460     E3dDragConstraint eConstr,
461     bool bFull)
462 :   E3dDragMethod(_rView, rMark, eConstr, bFull),
463     meWhatDragHdl(eDrgHdl)
464 {
465     switch(meWhatDragHdl)
466     {
467         case SdrHdlKind::Left:
468             maScaleFixPos = maFullBound.RightCenter();
469             break;
470         case SdrHdlKind::Right:
471             maScaleFixPos = maFullBound.LeftCenter();
472             break;
473         case SdrHdlKind::Upper:
474             maScaleFixPos = maFullBound.BottomCenter();
475             break;
476         case SdrHdlKind::Lower:
477             maScaleFixPos = maFullBound.TopCenter();
478             break;
479         case SdrHdlKind::UpperLeft:
480             maScaleFixPos = maFullBound.BottomRight();
481             break;
482         case SdrHdlKind::UpperRight:
483             maScaleFixPos = maFullBound.BottomLeft();
484             break;
485         case SdrHdlKind::LowerLeft:
486             maScaleFixPos = maFullBound.TopRight();
487             break;
488         case SdrHdlKind::LowerRight:
489             maScaleFixPos = maFullBound.TopLeft();
490             break;
491         default:
492             // Moving the object, SdrHdlKind::Move
493             break;
494     }
495 
496     // Override when IsResizeAtCenter()
497     if(getSdrDragView().IsResizeAtCenter())
498     {
499         meWhatDragHdl = SdrHdlKind::User;
500         maScaleFixPos = maFullBound.Center();
501     }
502 }
503 
504 // The object is moved, determine the translations
505 
MoveSdrDrag(const Point & rPnt)506 void E3dDragMove::MoveSdrDrag(const Point& rPnt)
507 {
508     // call parent
509     E3dDragMethod::MoveSdrDrag(rPnt);
510 
511     if(!DragStat().CheckMinMoved(rPnt))
512         return;
513 
514     if(SdrHdlKind::Move == meWhatDragHdl)
515     {
516         // Translation
517         // Determine the motion vector
518         const sal_uInt32 nCnt(maGrp.size());
519 
520         // Get modifier
521         sal_uInt16 nModifier(0);
522 
523         if(auto pDragView = dynamic_cast<const E3dView*>(&getSdrDragView()))
524         {
525             const MouseEvent& rLastMouse = pDragView->GetMouseEvent();
526             nModifier = rLastMouse.GetModifier();
527         }
528 
529         for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
530         {
531             E3dDragMethodUnit& rCandidate = maGrp[nOb];
532             const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
533 
534             if(nullptr != pScene)
535             {
536                 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
537                 const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
538 
539                 // move coor from 2d world to 3d Eye
540                 basegfx::B2DPoint aGlobalMoveHead2D(static_cast<double>(rPnt.X() - maLastPos.X()), static_cast<double>(rPnt.Y() - maLastPos.Y()));
541                 basegfx::B2DPoint aGlobalMoveTail2D(0.0, 0.0);
542                 basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
543 
544                 aInverseSceneTransform.invert();
545                 aGlobalMoveHead2D = aInverseSceneTransform * aGlobalMoveHead2D;
546                 aGlobalMoveTail2D = aInverseSceneTransform * aGlobalMoveTail2D;
547 
548                 basegfx::B3DPoint aMoveHead3D(aGlobalMoveHead2D.getX(), aGlobalMoveHead2D.getY(), 0.5);
549                 basegfx::B3DPoint aMoveTail3D(aGlobalMoveTail2D.getX(), aGlobalMoveTail2D.getY(), 0.5);
550                 basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
551                 aInverseViewToEye.invert();
552 
553                 aMoveHead3D = aInverseViewToEye * aMoveHead3D;
554                 aMoveTail3D = aInverseViewToEye * aMoveTail3D;
555 
556                 // eventually switch movement from XY to XZ plane
557                 if(nModifier & KEY_MOD2)
558                 {
559                     double fZwi = aMoveHead3D.getY();
560                     aMoveHead3D.setY(aMoveHead3D.getZ());
561                     aMoveHead3D.setZ(fZwi);
562 
563                     fZwi = aMoveTail3D.getY();
564                     aMoveTail3D.setY(aMoveTail3D.getZ());
565                     aMoveTail3D.setZ(fZwi);
566                 }
567 
568                 // Motion vector from eye coordinates to parent coordinates
569                 basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
570                 aInverseOrientation.invert();
571                 basegfx::B3DHomMatrix aCompleteTrans(rCandidate.maInvDisplayTransform * aInverseOrientation);
572 
573                 aMoveHead3D = aCompleteTrans * aMoveHead3D;
574                 aMoveTail3D = aCompleteTrans* aMoveTail3D;
575 
576                 // build transformation
577                 basegfx::B3DHomMatrix aTransMat;
578                 basegfx::B3DPoint aTranslate(aMoveHead3D - aMoveTail3D);
579                 aTransMat.translate(aTranslate.getX(), aTranslate.getY(), aTranslate.getZ());
580 
581                 // ...and apply
582                 rCandidate.maTransform *= aTransMat;
583 
584                 if(mbMoveFull)
585                 {
586                     E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
587                     rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
588                 }
589                 else
590                 {
591                     Hide();
592                     rCandidate.maWireframePoly.transform(aTransMat);
593                     Show();
594                 }
595             }
596         }
597     }
598     else
599     {
600         // Scaling
601         // Determine scaling vector
602         Point aStartPos = DragStat().GetStart();
603         const sal_uInt32 nCnt(maGrp.size());
604 
605         for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
606         {
607             E3dDragMethodUnit& rCandidate = maGrp[nOb];
608             const basegfx::B3DPoint aObjectCenter(rCandidate.mr3DObj.GetBoundVolume().getCenter());
609             const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
610 
611             if(nullptr != pScene)
612             {
613                 // transform from 2D world view to 3D eye
614                 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
615                 const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
616 
617                 basegfx::B2DPoint aGlobalScaleStart2D(static_cast<double>(aStartPos.X()), static_cast<double>(aStartPos.Y()));
618                 basegfx::B2DPoint aGlobalScaleNext2D(static_cast<double>(rPnt.X()), static_cast<double>(rPnt.Y()));
619                 basegfx::B2DPoint aGlobalScaleFixPos2D(static_cast<double>(maScaleFixPos.X()), static_cast<double>(maScaleFixPos.Y()));
620                 basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
621 
622                 aInverseSceneTransform.invert();
623                 aGlobalScaleStart2D = aInverseSceneTransform * aGlobalScaleStart2D;
624                 aGlobalScaleNext2D = aInverseSceneTransform * aGlobalScaleNext2D;
625                 aGlobalScaleFixPos2D = aInverseSceneTransform * aGlobalScaleFixPos2D;
626 
627                 basegfx::B3DPoint aGlobalScaleStart3D(aGlobalScaleStart2D.getX(), aGlobalScaleStart2D.getY(), aObjectCenter.getZ());
628                 basegfx::B3DPoint aGlobalScaleNext3D(aGlobalScaleNext2D.getX(), aGlobalScaleNext2D.getY(), aObjectCenter.getZ());
629                 basegfx::B3DPoint aGlobalScaleFixPos3D(aGlobalScaleFixPos2D.getX(), aGlobalScaleFixPos2D.getY(), aObjectCenter.getZ());
630                 basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
631 
632                 aInverseViewToEye.invert();
633                 basegfx::B3DPoint aScStart(aInverseViewToEye * aGlobalScaleStart3D);
634                 basegfx::B3DPoint aScNext(aInverseViewToEye * aGlobalScaleNext3D);
635                 basegfx::B3DPoint aScFixPos(aInverseViewToEye * aGlobalScaleFixPos3D);
636 
637                 // constraints?
638                 switch(meWhatDragHdl)
639                 {
640                     case SdrHdlKind::Left:
641                     case SdrHdlKind::Right:
642                         // to constrain on X -> Y equal
643                         aScNext.setY(aScFixPos.getY());
644                         break;
645                     case SdrHdlKind::Upper:
646                     case SdrHdlKind::Lower:
647                         // constrain to Y -> X equal
648                         aScNext.setX(aScFixPos.getX());
649                         break;
650                     default:
651                         break;
652                 }
653 
654                 // get scale vector in eye coordinates
655                 basegfx::B3DPoint aScaleVec(aScStart - aScFixPos);
656                 aScaleVec.setZ(1.0);
657 
658                 if(aScaleVec.getX() != 0.0)
659                 {
660                     aScaleVec.setX((aScNext.getX() - aScFixPos.getX()) / aScaleVec.getX());
661                 }
662                 else
663                 {
664                     aScaleVec.setX(1.0);
665                 }
666 
667                 if(aScaleVec.getY() != 0.0)
668                 {
669                     aScaleVec.setY((aScNext.getY() - aScFixPos.getY()) / aScaleVec.getY());
670                 }
671                 else
672                 {
673                     aScaleVec.setY(1.0);
674                 }
675 
676                 // SHIFT-key used?
677                 if(getSdrDragView().IsOrtho())
678                 {
679                     if(fabs(aScaleVec.getX()) > fabs(aScaleVec.getY()))
680                     {
681                         // X is biggest
682                         aScaleVec.setY(aScaleVec.getX());
683                     }
684                     else
685                     {
686                         // Y is biggest
687                         aScaleVec.setX(aScaleVec.getY());
688                     }
689                 }
690 
691                 // build transformation
692                 basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
693                 aInverseOrientation.invert();
694 
695                 basegfx::B3DHomMatrix aNewTrans = rCandidate.maInitTransform;
696                 aNewTrans *= rCandidate.maDisplayTransform;
697                 aNewTrans *= aViewInfo3D.getOrientation();
698                 aNewTrans.translate(-aScFixPos.getX(), -aScFixPos.getY(), -aScFixPos.getZ());
699                 aNewTrans.scale(aScaleVec.getX(), aScaleVec.getY(), aScaleVec.getZ());
700                 aNewTrans.translate(aScFixPos.getX(), aScFixPos.getY(), aScFixPos.getZ());
701                 aNewTrans *= aInverseOrientation;
702                 aNewTrans *= rCandidate.maInvDisplayTransform;
703 
704                 // ...and apply
705                 rCandidate.maTransform = aNewTrans;
706 
707                 if(mbMoveFull)
708                 {
709                     E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
710                     rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
711                 }
712                 else
713                 {
714                     Hide();
715                     rCandidate.maWireframePoly.clear();
716                     rCandidate.maWireframePoly = rCandidate.mr3DObj.CreateWireframe();
717                     rCandidate.maWireframePoly.transform(rCandidate.maTransform);
718                     Show();
719                 }
720             }
721         }
722     }
723     maLastPos = rPnt;
724     DragStat().NextMove(rPnt);
725 }
726 
GetSdrDragPointer() const727 PointerStyle E3dDragMove::GetSdrDragPointer() const
728 {
729     return PointerStyle::Move;
730 }
731 
732 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
733