1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <svx/svdopath.hxx>
22 #include <svx/svditer.hxx>
23 #include <svx/svdmodel.hxx>
24 #include <svx/svdpagv.hxx>
25 #include <editeng/colritem.hxx>
26 #include <editeng/eeitem.hxx>
27 #include <svx/svdview.hxx>
28 #include <svx/strings.hrc>
29 #include <svx/dialmgr.hxx>
30 #include <svx/obj3d.hxx>
31 #include <svx/lathe3d.hxx>
32 #include <extrud3d.hxx>
33 #include <dragmt3d.hxx>
34 #include <svx/scene3d.hxx>
35 #include <svx/view3d.hxx>
36 #include <svx/svdundo.hxx>
37 #include <svx/xflclit.hxx>
38 #include <svx/xlnclit.hxx>
39 #include <svx/xfillit0.hxx>
40 #include <svx/xlineit0.hxx>
41 #include <basegfx/range/b2drange.hxx>
42 #include <basegfx/polygon/b2dpolypolygontools.hxx>
43 #include <svx/xlnwtit.hxx>
44 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
45 #include <svx/sdr/overlay/overlaymanager.hxx>
46 #include <svx/sdrpaintwindow.hxx>
47 #include <svx/sdr/contact/viewcontact.hxx>
48 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
49 #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
50 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
51 #include <basegfx/matrix/b2dhommatrixtools.hxx>
52 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
53 #include <svx/e3dsceneupdater.hxx>
55 using namespace com::sun::star
;
60 class Impl3DMirrorConstructOverlay
63 sdr::overlay::OverlayObjectList maObjects
;
66 const E3dView
& mrView
;
71 // the unmirrored polygons
72 basegfx::B2DPolyPolygon
* mpPolygons
;
74 // the overlay geometry from selected objects
75 drawinglayer::primitive2d::Primitive2DContainer maFullOverlay
;
77 // Copy assignment is forbidden and not implemented.
78 Impl3DMirrorConstructOverlay (const Impl3DMirrorConstructOverlay
&) = delete;
79 Impl3DMirrorConstructOverlay
& operator= (const Impl3DMirrorConstructOverlay
&) = delete;
82 explicit Impl3DMirrorConstructOverlay(const E3dView
& rView
);
83 ~Impl3DMirrorConstructOverlay();
85 void SetMirrorAxis(Point aMirrorAxisA
, Point aMirrorAxisB
);
88 Impl3DMirrorConstructOverlay::Impl3DMirrorConstructOverlay(const E3dView
& rView
)
91 mnCount(rView
.GetMarkedObjectCount()),
98 if(mrView
.IsSolidDragging())
100 SdrPageView
* pPV
= rView
.GetSdrPageView();
102 if(pPV
&& pPV
->PageWindowCount())
104 for(size_t a
= 0; a
< mnCount
; ++a
)
106 SdrObject
* pObject
= mrView
.GetMarkedObjectByIndex(a
);
110 // use the view-independent primitive representation (without
111 // evtl. GridOffset, that may be applied to the DragEntry individually)
112 const drawinglayer::primitive2d::Primitive2DContainer
& aNewSequence(
113 pObject
->GetViewContact().getViewIndependentPrimitive2DContainer());
114 maFullOverlay
.append(aNewSequence
);
121 mpPolygons
= new basegfx::B2DPolyPolygon
[mnCount
];
123 for(size_t a
= 0; a
< mnCount
; ++a
)
125 SdrObject
* pObject
= mrView
.GetMarkedObjectByIndex(a
);
126 mpPolygons
[mnCount
- (a
+ 1)] = pObject
->TakeXorPoly();
131 Impl3DMirrorConstructOverlay::~Impl3DMirrorConstructOverlay()
133 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
134 // That destructor calls clear() at the list which removes all objects from the
135 // OverlayManager and deletes them.
136 if(!mrView
.IsSolidDragging())
142 void Impl3DMirrorConstructOverlay::SetMirrorAxis(Point aMirrorAxisA
, Point aMirrorAxisB
)
144 // get rid of old overlay objects
148 for(sal_uInt32
a(0); a
< mrView
.PaintWindowCount(); a
++)
150 SdrPaintWindow
* pCandidate
= mrView
.GetPaintWindow(a
);
151 const rtl::Reference
< sdr::overlay::OverlayManager
>& xTargetOverlay
= pCandidate
->GetOverlayManager();
153 if(xTargetOverlay
.is())
155 // build transformation: translate and rotate so that given edge is
156 // on x axis, them mirror in y and translate back
157 const basegfx::B2DVector
aEdge(aMirrorAxisB
.X() - aMirrorAxisA
.X(), aMirrorAxisB
.Y() - aMirrorAxisA
.Y());
158 basegfx::B2DHomMatrix
aMatrixTransform(basegfx::utils::createTranslateB2DHomMatrix(
159 -aMirrorAxisA
.X(), -aMirrorAxisA
.Y()));
160 aMatrixTransform
.rotate(-atan2(aEdge
.getY(), aEdge
.getX()));
161 aMatrixTransform
.scale(1.0, -1.0);
162 aMatrixTransform
.rotate(atan2(aEdge
.getY(), aEdge
.getX()));
163 aMatrixTransform
.translate(aMirrorAxisA
.X(), aMirrorAxisA
.Y());
165 if(mrView
.IsSolidDragging())
167 if(!maFullOverlay
.empty())
169 drawinglayer::primitive2d::Primitive2DContainer
aContent(maFullOverlay
);
171 if(!aMatrixTransform
.isIdentity())
173 // embed in transformation group
174 drawinglayer::primitive2d::Primitive2DReference
aTransformPrimitive2D(new drawinglayer::primitive2d::TransformPrimitive2D(aMatrixTransform
, aContent
));
175 aContent
= drawinglayer::primitive2d::Primitive2DContainer
{ aTransformPrimitive2D
};
178 // if we have full overlay from selected objects, embed with 50% transparence, the
179 // transformation is added to the OverlayPrimitive2DSequenceObject
180 drawinglayer::primitive2d::Primitive2DReference
aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(aContent
, 0.5));
181 aContent
= drawinglayer::primitive2d::Primitive2DContainer
{ aUnifiedTransparencePrimitive2D
};
183 std::unique_ptr
<sdr::overlay::OverlayPrimitive2DSequenceObject
> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(aContent
));
185 xTargetOverlay
->add(*pNew
);
186 maObjects
.append(std::move(pNew
));
191 for(size_t b
= 0; b
< mnCount
; ++b
)
194 basegfx::B2DPolyPolygon
aPolyPolygon(mpPolygons
[b
]);
195 aPolyPolygon
.transform(aMatrixTransform
);
197 std::unique_ptr
<sdr::overlay::OverlayPolyPolygonStripedAndFilled
> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
199 xTargetOverlay
->add(*pNew
);
200 maObjects
.append(std::move(pNew
));
210 : SdrView(rSdrModel
, pOut
)
215 // DrawMarkedObj override, since possibly only a single 3D object is to be
218 void E3dView::DrawMarkedObj(OutputDevice
& rOut
) const
220 // Does 3D objects exist which scenes are not selected?
221 bool bSpecialHandling
= false;
222 E3dScene
*pScene
= nullptr;
224 const size_t nCnt
= GetMarkedObjectCount();
225 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
227 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
228 if(auto pCompoundObject
= dynamic_cast<E3dCompoundObject
*>(pObj
))
231 pScene
= pCompoundObject
->getRootE3dSceneFromE3dObject();
233 if(nullptr != pScene
&& !IsObjMarked(pScene
))
235 bSpecialHandling
= true;
238 // Reset all selection flags
239 if(auto p3dObject
= dynamic_cast< const E3dObject
*>(pObj
))
241 pScene
= p3dObject
->getRootE3dSceneFromE3dObject();
243 if(nullptr != pScene
)
245 pScene
->SetSelected(false);
252 // Set selection flag to "not selected" for scenes related to all 3D
254 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
256 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
257 if(auto pCompoundObject
= dynamic_cast<E3dCompoundObject
*>(pObj
))
260 pScene
= pCompoundObject
->getRootE3dSceneFromE3dObject();
262 if(nullptr != pScene
)
264 pScene
->SetSelected(false);
269 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
271 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
272 if(auto p3DObj
= dynamic_cast<E3dObject
*>(pObj
))
275 p3DObj
->SetSelected(true);
276 pScene
= p3DObj
->getRootE3dSceneFromE3dObject();
280 if(nullptr != pScene
)
285 pScene
->SetDrawOnlySelected(true);
286 pScene
->SingleObjectPainter(rOut
);
287 pScene
->SetDrawOnlySelected(false);
290 // Reset selection flag
291 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
293 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
294 if(auto pCompoundObject
= dynamic_cast<E3dCompoundObject
*>(pObj
))
297 pScene
= pCompoundObject
->getRootE3dSceneFromE3dObject();
299 if(nullptr != pScene
)
301 pScene
->SetSelected(false);
309 SdrExchangeView::DrawMarkedObj(rOut
);
313 // override get model, since in some 3D objects an additional scene
316 std::unique_ptr
<SdrModel
> E3dView::CreateMarkedObjModel() const
318 // Does 3D objects exist which scenes are not selected?
319 bool bSpecialHandling(false);
320 const size_t nCount(GetMarkedObjectCount());
321 E3dScene
*pScene
= nullptr;
323 for(size_t nObjs
= 0; nObjs
< nCount
; ++nObjs
)
325 const SdrObject
* pObj
= GetMarkedObjectByIndex(nObjs
);
327 if(!bSpecialHandling
&& dynamic_cast< const E3dCompoundObject
*>(pObj
))
329 // if the object is selected, but it's scene not,
330 // we need special handling
331 pScene
= static_cast<const E3dCompoundObject
*>(pObj
)->getRootE3dSceneFromE3dObject();
333 if(nullptr != pScene
&& !IsObjMarked(pScene
))
335 bSpecialHandling
= true;
339 if(auto p3dObject
= dynamic_cast< const E3dObject
*>(pObj
))
341 // reset all selection flags at 3D objects
342 pScene
= p3dObject
->getRootE3dSceneFromE3dObject();
344 if(nullptr != pScene
)
346 pScene
->SetSelected(false);
351 if(!bSpecialHandling
)
354 return SdrView::CreateMarkedObjModel();
357 std::unique_ptr
<SdrModel
> pNewModel
;
358 tools::Rectangle aSelectedSnapRect
;
360 // set 3d selection flags at all directly selected objects
361 // and collect SnapRect of selected objects
362 for(size_t nObjs
= 0; nObjs
< nCount
; ++nObjs
)
364 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
366 if(auto p3DObj
= dynamic_cast<E3dCompoundObject
*>(pObj
))
368 // mark object, but not scenes
369 p3DObj
->SetSelected(true);
370 aSelectedSnapRect
.Union(p3DObj
->GetSnapRect());
374 // create new mark list which contains all indirectly selected3d
375 // scenes as selected objects
376 SdrMarkList
aOldML(GetMarkedObjectList());
378 SdrMarkList
& rCurrentMarkList
= const_cast<E3dView
*>(this)->GetMarkedObjectListWriteAccess();
379 rCurrentMarkList
= aNewML
;
381 for(size_t nObjs
= 0; nObjs
< nCount
; ++nObjs
)
383 SdrObject
*pObj
= aOldML
.GetMark(nObjs
)->GetMarkedSdrObj();
385 if(auto p3dObject
= dynamic_cast< E3dObject
* >(pObj
))
387 pScene
= p3dObject
->getRootE3dSceneFromE3dObject();
389 if(nullptr != pScene
&& !IsObjMarked(pScene
) && GetSdrPageView())
391 const_cast<E3dView
*>(this)->MarkObj(pScene
, GetSdrPageView(), false, true);
396 // call parent. This will copy all scenes and the selection flags at the 3D objects. So
397 // it will be possible to delete all non-selected 3d objects from the cloned 3d scenes
398 pNewModel
= SdrView::CreateMarkedObjModel();
402 for(sal_uInt16
nPg(0); nPg
< pNewModel
->GetPageCount(); nPg
++)
404 const SdrPage
* pSrcPg
=pNewModel
->GetPage(nPg
);
405 const size_t nObjCount(pSrcPg
->GetObjCount());
407 for(size_t nOb
= 0; nOb
< nObjCount
; ++nOb
)
409 const SdrObject
* pSrcOb
=pSrcPg
->GetObj(nOb
);
411 if(auto p3dscene
= dynamic_cast< const E3dScene
* >( pSrcOb
))
413 pScene
= const_cast<E3dScene
*>(p3dscene
);
415 // delete all not intentionally cloned 3d objects
416 pScene
->removeAllNonSelectedObjects();
418 // reset select flags and set SnapRect of all selected objects
419 pScene
->SetSelected(false);
420 pScene
->SetSnapRect(aSelectedSnapRect
);
426 // restore old selection
427 rCurrentMarkList
= aOldML
;
432 // When pasting objects have to integrated if a scene is inserted, but
433 // not the scene itself
436 const SdrModel
& rMod
, const Point
& rPos
, SdrObjList
* pLst
, SdrInsertFlags nOptions
)
438 bool bRetval
= false;
442 SdrObjList
* pDstList
= pLst
;
443 ImpGetPasteObjList(aPos
, pDstList
);
448 // Get owner of the list
449 E3dScene
* pDstScene(dynamic_cast< E3dScene
* >(pDstList
->getSdrObjectFromSdrObjList()));
451 if(nullptr != pDstScene
)
453 BegUndo(SvxResId(RID_SVX_3D_UNDO_EXCHANGE_PASTE
));
455 // Copy all objects from E3dScenes and insert them directly
456 for(sal_uInt16
nPg(0); nPg
< rMod
.GetPageCount(); nPg
++)
458 const SdrPage
* pSrcPg
=rMod
.GetPage(nPg
);
459 const size_t nObjCount(pSrcPg
->GetObjCount());
461 // calculate offset for paste
462 tools::Rectangle aR
= pSrcPg
->GetAllObjBoundRect();
463 Point
aDist(aPos
- aR
.Center());
465 // Insert sub-objects for scenes
466 for(size_t nOb
= 0; nOb
< nObjCount
; ++nOb
)
468 const SdrObject
* pSrcOb
= pSrcPg
->GetObj(nOb
);
469 if(auto p3dscene
= dynamic_cast< const E3dScene
* >(pSrcOb
))
471 E3dScene
* pSrcScene
= const_cast<E3dScene
*>(p3dscene
);
472 ImpCloneAll3DObjectsToDestScene(pSrcScene
, pDstScene
, aDist
);
481 bRetval
= SdrView::Paste(rMod
, rPos
, pLst
, nOptions
);
487 // Service routine used from local Clone() and from SdrCreateView::EndCreateObj(...)
488 bool E3dView::ImpCloneAll3DObjectsToDestScene(E3dScene
const * pSrcScene
, E3dScene
* pDstScene
, Point
/*aOffset*/)
492 if(pSrcScene
&& pDstScene
)
494 for(size_t i
= 0; i
< pSrcScene
->GetSubList()->GetObjCount(); ++i
)
496 E3dCompoundObject
* pCompoundObj
= dynamic_cast< E3dCompoundObject
* >(pSrcScene
->GetSubList()->GetObj(i
));
500 E3dCompoundObject
* pNewCompoundObj(pCompoundObj
->CloneSdrObject(pDstScene
->getSdrModelFromSdrObject()));
504 // get dest scene's current range in 3D world coordinates
505 const basegfx::B3DHomMatrix
aSceneToWorldTrans(pDstScene
->GetFullTransform());
506 basegfx::B3DRange
aSceneRange(pDstScene
->GetBoundVolume());
507 aSceneRange
.transform(aSceneToWorldTrans
);
509 // get new object's implied object transformation
510 const basegfx::B3DHomMatrix
aNewObjectTrans(pNewCompoundObj
->GetTransform());
512 // get new object's range in 3D world coordinates in dest scene
513 // as if it were already added
514 const basegfx::B3DHomMatrix
aObjectToWorldTrans(aSceneToWorldTrans
* aNewObjectTrans
);
515 basegfx::B3DRange
aObjectRange(pNewCompoundObj
->GetBoundVolume());
516 aObjectRange
.transform(aObjectToWorldTrans
);
518 // get scale adaptation
519 const basegfx::B3DVector
aSceneScale(aSceneRange
.getRange());
520 const basegfx::B3DVector
aObjectScale(aObjectRange
.getRange());
523 // if new object's size in X,Y or Z is bigger that 80% of dest scene, adapt scale
524 // to not change the scene by the inserted object
525 const double fSizeFactor(0.5);
527 if(aObjectScale
.getX() * fScale
> aSceneScale
.getX() * fSizeFactor
)
529 const double fObjSize(aObjectScale
.getX() * fScale
);
530 const double fFactor((aSceneScale
.getX() * fSizeFactor
) / (basegfx::fTools::equalZero(fObjSize
) ? 1.0 : fObjSize
));
534 if(aObjectScale
.getY() * fScale
> aSceneScale
.getY() * fSizeFactor
)
536 const double fObjSize(aObjectScale
.getY() * fScale
);
537 const double fFactor((aSceneScale
.getY() * fSizeFactor
) / (basegfx::fTools::equalZero(fObjSize
) ? 1.0 : fObjSize
));
541 if(aObjectScale
.getZ() * fScale
> aSceneScale
.getZ() * fSizeFactor
)
543 const double fObjSize(aObjectScale
.getZ() * fScale
);
544 const double fFactor((aSceneScale
.getZ() * fSizeFactor
) / (basegfx::fTools::equalZero(fObjSize
) ? 1.0 : fObjSize
));
548 // get translation adaptation
549 const basegfx::B3DPoint
aSceneCenter(aSceneRange
.getCenter());
550 const basegfx::B3DPoint
aObjectCenter(aObjectRange
.getCenter());
552 // build full modification transform. The object's transformation
553 // shall be modified, so start at object coordinates; transform to 3d world coor
554 basegfx::B3DHomMatrix
aModifyingTransform(aObjectToWorldTrans
);
556 // translate to absolute center in 3d world coor
557 aModifyingTransform
.translate(-aObjectCenter
.getX(), -aObjectCenter
.getY(), -aObjectCenter
.getZ());
559 // scale to dest size in 3d world coor
560 aModifyingTransform
.scale(fScale
, fScale
, fScale
);
562 // translate to dest scene center in 3d world coor
563 aModifyingTransform
.translate(aSceneCenter
.getX(), aSceneCenter
.getY(), aSceneCenter
.getZ());
565 // transform from 3d world to dest object coordinates
566 basegfx::B3DHomMatrix
aWorldToObject(aObjectToWorldTrans
);
567 aWorldToObject
.invert();
568 aModifyingTransform
= aWorldToObject
* aModifyingTransform
;
570 // correct implied object transform by applying changing one in object coor
571 pNewCompoundObj
->SetTransform(aModifyingTransform
* aNewObjectTrans
);
573 // fill and insert new object
574 pNewCompoundObj
->NbcSetLayer(pCompoundObj
->GetLayer());
575 pNewCompoundObj
->NbcSetStyleSheet(pCompoundObj
->GetStyleSheet(), true);
576 pDstScene
->InsertObject(pNewCompoundObj
);
580 if( GetModel()->IsUndoEnabled() )
581 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewCompoundObj
));
590 bool E3dView::IsConvertTo3DObjPossible() const
593 bool bGroupSelected(false);
596 for(size_t a
=0; !bAny3D
&& a
<GetMarkedObjectCount(); ++a
)
598 SdrObject
*pObj
= GetMarkedObjectByIndex(a
);
601 ImpIsConvertTo3DPossible(pObj
, bAny3D
, bGroupSelected
);
607 IsConvertToPolyObjPossible()
608 || IsConvertToPathObjPossible()
609 || IsImportMtfPossible());
613 void E3dView::ImpIsConvertTo3DPossible(SdrObject
const * pObj
, bool& rAny3D
,
614 bool& rGroupSelected
) const
619 if(dynamic_cast< const E3dObject
* >(pObj
) != nullptr)
625 if(pObj
->IsGroupObject())
627 SdrObjListIter
aIter(*pObj
, SdrIterMode::DeepNoGroups
);
628 while(aIter
.IsMore())
630 SdrObject
* pNewObj
= aIter
.Next();
631 ImpIsConvertTo3DPossible(pNewObj
, rAny3D
, rGroupSelected
);
633 rGroupSelected
= true;
638 void E3dView::ImpChangeSomeAttributesFor3DConversion(SdrObject
* pObj
)
640 if(dynamic_cast<const SdrTextObj
*>( pObj
) == nullptr)
643 const SfxItemSet
& rSet
= pObj
->GetMergedItemSet();
644 const SvxColorItem
& rTextColorItem
= rSet
.Get(EE_CHAR_COLOR
);
645 if(rTextColorItem
.GetValue() != COL_BLACK
)
648 //For black text objects, the color set to gray
649 if(pObj
->getSdrPageFromSdrObject())
651 // if black is only default attribute from
652 // pattern set it hard so that it is used in undo.
653 pObj
->SetMergedItem(SvxColorItem(COL_BLACK
, EE_CHAR_COLOR
));
656 if( GetModel()->IsUndoEnabled() )
657 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj
));
660 pObj
->SetMergedItem(SvxColorItem(COL_GRAY
, EE_CHAR_COLOR
));
663 void E3dView::ImpChangeSomeAttributesFor3DConversion2(SdrObject
* pObj
)
665 if(dynamic_cast<const SdrPathObj
*>( pObj
) == nullptr)
668 const SfxItemSet
& rSet
= pObj
->GetMergedItemSet();
669 sal_Int32 nLineWidth
= rSet
.Get(XATTR_LINEWIDTH
).GetValue();
670 drawing::LineStyle eLineStyle
= rSet
.Get(XATTR_LINESTYLE
).GetValue();
671 drawing::FillStyle eFillStyle
= rSet
.Get(XATTR_FILLSTYLE
).GetValue();
673 if(static_cast<SdrPathObj
*>(pObj
)->IsClosed()
674 && eLineStyle
== drawing::LineStyle_SOLID
676 && eFillStyle
!= drawing::FillStyle_NONE
)
678 if(pObj
->getSdrPageFromSdrObject() && GetModel()->IsUndoEnabled() )
680 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj
));
683 pObj
->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE
));
684 pObj
->SetMergedItem(XLineWidthItem(0));
688 void E3dView::ImpCreateSingle3DObjectFlat(E3dScene
* pScene
, SdrObject
* pObj
, bool bExtrude
, double fDepth
, basegfx::B2DHomMatrix
const & rLatheMat
)
690 // Single PathObject, transform this
691 SdrPathObj
* pPath
= dynamic_cast<SdrPathObj
*>( pObj
);
696 E3dDefaultAttributes aDefault
= Get3DDefaultAttributes();
700 aDefault
.SetDefaultExtrudeCharacterMode(true);
704 aDefault
.SetDefaultLatheCharacterMode(true);
707 // Get Itemset of the original object
708 SfxItemSet
aSet(pObj
->GetMergedItemSet());
710 drawing::FillStyle eFillStyle
= aSet
.Get(XATTR_FILLSTYLE
).GetValue();
712 // line style turned off
713 aSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
715 //Determining if FILL_Attribute is set.
716 if(!pPath
->IsClosed() || eFillStyle
== drawing::FillStyle_NONE
)
718 // This SdrPathObj is not filled, leave the front and rear face out.
719 // Moreover, a two-sided representation necessary.
720 aDefault
.SetDefaultExtrudeCloseFront(false);
721 aDefault
.SetDefaultExtrudeCloseBack(false);
723 aSet
.Put(makeSvx3DDoubleSidedItem(true));
725 // Set fill attribute
726 aSet
.Put(XFillStyleItem(drawing::FillStyle_SOLID
));
728 // Fill color must be the color line, because the object was
729 // previously just a line
730 Color aColorLine
= aSet
.Get(XATTR_LINECOLOR
).GetColorValue();
731 aSet
.Put(XFillColorItem(OUString(), aColorLine
));
734 // Create a new extrude object
735 E3dObject
* p3DObj
= nullptr;
738 p3DObj
= new E3dExtrudeObj(pObj
->getSdrModelFromSdrObject(), aDefault
, pPath
->GetPathPoly(), fDepth
);
742 // rLatheMat expects coordinates with y-axis up, pPath uses y-axis down
743 basegfx::B2DHomMatrix
aFlipVerticalMat(1.0, 0.0, 0.0, 0.0, -1.0, 0.0);
744 basegfx::B2DPolyPolygon
aPolyPoly2D(pPath
->GetPathPoly());
745 aPolyPoly2D
.transform(aFlipVerticalMat
);
746 aPolyPoly2D
.transform(rLatheMat
);
747 // ctor E3dLatheObj expects coordinates with y-axis down
748 aPolyPoly2D
.transform(aFlipVerticalMat
);
749 p3DObj
= new E3dLatheObj(pObj
->getSdrModelFromSdrObject(), aDefault
, aPolyPoly2D
);
753 p3DObj
->NbcSetLayer(pObj
->GetLayer());
755 p3DObj
->SetMergedItemSet(aSet
);
757 p3DObj
->NbcSetStyleSheet(pObj
->GetStyleSheet(), true);
759 // Insert a new extrude object
760 pScene
->InsertObject(p3DObj
);
763 void E3dView::ImpCreate3DObject(E3dScene
* pScene
, SdrObject
* pObj
, bool bExtrude
, double fDepth
, basegfx::B2DHomMatrix
const & rLatheMat
)
768 // change text color attribute for not so dark colors
769 if(pObj
->IsGroupObject())
771 SdrObjListIter
aIter(*pObj
, SdrIterMode::DeepWithGroups
);
772 while(aIter
.IsMore())
774 SdrObject
* pGroupMember
= aIter
.Next();
775 ImpChangeSomeAttributesFor3DConversion(pGroupMember
);
779 ImpChangeSomeAttributesFor3DConversion(pObj
);
781 // convert completely to path objects
782 SdrObject
* pNewObj1
= pObj
->ConvertToPolyObj(false, false).release();
787 // change text color attribute for not so dark colors
788 if(pNewObj1
->IsGroupObject())
790 SdrObjListIter
aIter(*pNewObj1
, SdrIterMode::DeepWithGroups
);
791 while(aIter
.IsMore())
793 SdrObject
* pGroupMember
= aIter
.Next();
794 ImpChangeSomeAttributesFor3DConversion2(pGroupMember
);
798 ImpChangeSomeAttributesFor3DConversion2(pNewObj1
);
800 // convert completely to path objects
801 SdrObject
* pNewObj2
= pObj
->ConvertToContourObj(pNewObj1
, true);
805 // add all to flat scene
806 if(pNewObj2
->IsGroupObject())
808 SdrObjListIter
aIter(*pNewObj2
, SdrIterMode::DeepWithGroups
);
809 while(aIter
.IsMore())
811 SdrObject
* pGroupMember
= aIter
.Next();
812 ImpCreateSingle3DObjectFlat(pScene
, pGroupMember
, bExtrude
, fDepth
, rLatheMat
);
816 ImpCreateSingle3DObjectFlat(pScene
, pNewObj2
, bExtrude
, fDepth
, rLatheMat
);
818 // delete object in between
819 if (pNewObj2
!= pObj
&& pNewObj2
!= pNewObj1
)
820 SdrObject::Free( pNewObj2
);
823 // delete object in between
824 if (pNewObj1
!= pObj
)
825 SdrObject::Free( pNewObj1
);
828 void E3dView::ConvertMarkedObjTo3D(bool bExtrude
, const basegfx::B2DPoint
& rPnt1
, const basegfx::B2DPoint
& rPnt2
)
830 if(!AreObjectsMarked())
835 BegUndo(SvxResId(RID_SVX_3D_UNDO_EXTRUDE
));
837 BegUndo(SvxResId(RID_SVX_3D_UNDO_LATHE
));
839 SdrModel
& rSdrModel(GetSdrMarkByIndex(0)->GetMarkedSdrObj()->getSdrModelFromSdrObject());
841 // Create a new scene for the created 3D object
842 E3dScene
* pScene
= new E3dScene(rSdrModel
);
844 // Determine rectangle and possibly correct it
845 tools::Rectangle aRect
= GetAllMarkedRect();
846 if(aRect
.GetWidth() <= 1)
847 aRect
.SetSize(Size(500, aRect
.GetHeight()));
848 if(aRect
.GetHeight() <= 1)
849 aRect
.SetSize(Size(aRect
.GetWidth(), 500));
851 // Determine the depth relative to the size of the selection
854 basegfx::B2DHomMatrix aLatheMat
;
858 double fW
= static_cast<double>(aRect
.GetWidth());
859 double fH
= static_cast<double>(aRect
.GetHeight());
860 fDepth
= sqrt(fW
*fW
+ fH
*fH
) / 6.0;
864 // Create transformation for the polygons rotating body
867 // Rotation around control point #1 with set angle
868 // for 3D coordinates
869 basegfx::B2DPoint
aDiff(rPnt1
- rPnt2
);
870 fRot3D
= atan2(aDiff
.getY(), aDiff
.getX()) - F_PI2
;
872 if(basegfx::fTools::equalZero(fabs(fRot3D
)))
877 aLatheMat
= basegfx::utils::createRotateAroundPoint(rPnt2
, -fRot3D
)
882 if (rPnt2
.getX() != 0.0)
884 // Translation to Y=0 - axis
885 aLatheMat
.translate(-rPnt2
.getX(), 0.0);
889 aLatheMat
.translate(static_cast<double>(-aRect
.Left()), 0.0);
892 // Form the inverse matrix to determine the target expansion
893 basegfx::B2DHomMatrix
aInvLatheMat(aLatheMat
);
894 aInvLatheMat
.invert();
896 // SnapRect extension enables mirroring in the axis of rotation
897 for(size_t a
=0; a
<GetMarkedObjectCount(); ++a
)
899 SdrMark
* pMark
= GetSdrMarkByIndex(a
);
900 SdrObject
* pObj
= pMark
->GetMarkedSdrObj();
901 tools::Rectangle aTurnRect
= pObj
->GetSnapRect();
902 basegfx::B2DPoint aRot
;
905 aRot
= basegfx::B2DPoint(aTurnRect
.Left(), -aTurnRect
.Top());
907 aRot
.setX(-aRot
.getX());
908 aRot
*= aInvLatheMat
;
909 aRotPnt
= Point(static_cast<tools::Long
>(aRot
.getX() + 0.5), static_cast<tools::Long
>(-aRot
.getY() - 0.5));
910 aRect
.Union(tools::Rectangle(aRotPnt
, aRotPnt
));
912 aRot
= basegfx::B2DPoint(aTurnRect
.Left(), -aTurnRect
.Bottom());
914 aRot
.setX(-aRot
.getX());
915 aRot
*= aInvLatheMat
;
916 aRotPnt
= Point(static_cast<tools::Long
>(aRot
.getX() + 0.5), static_cast<tools::Long
>(-aRot
.getY() - 0.5));
917 aRect
.Union(tools::Rectangle(aRotPnt
, aRotPnt
));
919 aRot
= basegfx::B2DPoint(aTurnRect
.Right(), -aTurnRect
.Top());
921 aRot
.setX(-aRot
.getX());
922 aRot
*= aInvLatheMat
;
923 aRotPnt
= Point(static_cast<tools::Long
>(aRot
.getX() + 0.5), static_cast<tools::Long
>(-aRot
.getY() - 0.5));
924 aRect
.Union(tools::Rectangle(aRotPnt
, aRotPnt
));
926 aRot
= basegfx::B2DPoint(aTurnRect
.Right(), -aTurnRect
.Bottom());
928 aRot
.setX(-aRot
.getX());
929 aRot
*= aInvLatheMat
;
930 aRotPnt
= Point(static_cast<tools::Long
>(aRot
.getX() + 0.5), static_cast<tools::Long
>(-aRot
.getY() - 0.5));
931 aRect
.Union(tools::Rectangle(aRotPnt
, aRotPnt
));
935 // Walk through the selection and convert it into 3D, complete with
936 // Conversion to SdrPathObject, also fonts
937 for(size_t a
=0; a
<GetMarkedObjectCount(); ++a
)
939 SdrMark
* pMark
= GetSdrMarkByIndex(a
);
940 SdrObject
* pObj
= pMark
->GetMarkedSdrObj();
942 ImpCreate3DObject(pScene
, pObj
, bExtrude
, fDepth
, aLatheMat
);
945 if(pScene
->GetSubList() && pScene
->GetSubList()->GetObjCount() != 0)
947 // Arrange all created objects by depth
949 DoDepthArrange(pScene
, fDepth
);
951 // Center 3D objects in the middle of the overall rectangle
952 basegfx::B3DPoint
aCenter(pScene
->GetBoundVolume().getCenter());
953 basegfx::B3DHomMatrix aMatrix
;
955 aMatrix
.translate(-aCenter
.getX(), -aCenter
.getY(), -aCenter
.getZ());
956 pScene
->SetTransform(aMatrix
* pScene
->GetTransform());
959 pScene
->NbcSetSnapRect(aRect
);
960 basegfx::B3DRange aBoundVol
= pScene
->GetBoundVolume();
961 InitScene(pScene
, static_cast<double>(aRect
.GetWidth()), static_cast<double>(aRect
.GetHeight()), aBoundVol
.getDepth());
963 // Insert scene instead of the first selected object and throw away
964 // all the old objects
965 SdrObject
* pRepObj
= GetMarkedObjectByIndex(0);
966 SdrPageView
* pPV
= GetSdrPageViewOfMarkedByIndex(0);
967 MarkObj(pRepObj
, pPV
, true);
968 ReplaceObjectAtView(pRepObj
, *pPV
, pScene
, false);
970 MarkObj(pScene
, pPV
);
972 // Rotate Rotation body around the axis of rotation
973 if(!bExtrude
&& fRot3D
!= 0.0)
975 basegfx::B3DHomMatrix aRotate
;
976 aRotate
.rotate(0.0, 0.0, fRot3D
);
977 pScene
->SetTransform(aRotate
* pScene
->GetTransform());
980 // Set default rotation
982 basegfx::B3DHomMatrix aRotate
;
983 aRotate
.rotate(DEG2RAD(20.0), 0.0, 0.0);
984 // E3DModifySceneSnapRectUpdater updates the 2D representation of the scene.
985 // It prepares things in ctor and acts in dtor.
986 E3DModifySceneSnapRectUpdater
aUpdater(pScene
->getSdrObjectFromSdrObjList());
987 pScene
->SetTransform(aRotate
* pScene
->GetTransform());
992 // No 3D object was created, throw away everything
993 // always use SdrObject::Free(...) for SdrObjects (!)
994 SdrObject
* pTemp(pScene
);
995 SdrObject::Free(pTemp
);
1001 //Arrange all created extrude objects by depth
1005 struct E3dDepthNeighbour
1007 E3dExtrudeObj
* mpObj
;
1008 basegfx::B2DPolyPolygon maPreparedPolyPolygon
;
1010 E3dDepthNeighbour(E3dExtrudeObj
* pObj
, basegfx::B2DPolyPolygon
const & rPreparedPolyPolygon
)
1012 maPreparedPolyPolygon(rPreparedPolyPolygon
)
1017 struct E3dDepthLayer
1019 E3dDepthLayer
* mpDown
;
1020 std::vector
<E3dDepthNeighbour
> mvNeighbours
;
1030 void E3dView::DoDepthArrange(E3dScene
const * pScene
, double fDepth
)
1032 if(!(pScene
&& pScene
->GetSubList() && pScene
->GetSubList()->GetObjCount() > 1))
1035 SdrObjList
* pSubList
= pScene
->GetSubList();
1036 SdrObjListIter
aIter(pSubList
, SdrIterMode::Flat
);
1037 E3dDepthLayer
* pBaseLayer
= nullptr;
1038 E3dDepthLayer
* pLayer
= nullptr;
1039 sal_Int32 nNumLayers
= 0;
1041 while(aIter
.IsMore())
1043 E3dExtrudeObj
* pExtrudeObj
= dynamic_cast< E3dExtrudeObj
* >(aIter
.Next());
1047 const basegfx::B2DPolyPolygon
aExtrudePoly(
1048 basegfx::utils::prepareForPolygonOperation(pExtrudeObj
->GetExtrudePolygon()));
1049 const SfxItemSet
& rLocalSet
= pExtrudeObj
->GetMergedItemSet();
1050 const drawing::FillStyle eLocalFillStyle
= rLocalSet
.Get(XATTR_FILLSTYLE
).GetValue();
1051 const Color aLocalColor
= rLocalSet
.Get(XATTR_FILLCOLOR
).GetColorValue();
1053 // sort in ExtrudeObj
1056 // do we have overlap with an object of this layer?
1057 bool bOverlap(false);
1059 for(const auto& rAct
: pLayer
->mvNeighbours
)
1061 // do rAct.mpObj and pExtrudeObj overlap? Check by
1062 // using logical AND clipping
1063 const basegfx::B2DPolyPolygon
aAndPolyPolygon(
1064 basegfx::utils::solvePolygonOperationAnd(
1066 rAct
.maPreparedPolyPolygon
));
1068 if(aAndPolyPolygon
.count() != 0)
1070 // second criteria: is another fillstyle or color used?
1071 const SfxItemSet
& rCompareSet
= rAct
.mpObj
->GetMergedItemSet();
1073 drawing::FillStyle eCompareFillStyle
= rCompareSet
.Get(XATTR_FILLSTYLE
).GetValue();
1075 if(eLocalFillStyle
== eCompareFillStyle
)
1077 if(eLocalFillStyle
== drawing::FillStyle_SOLID
)
1079 Color aCompareColor
= rCompareSet
.Get(XATTR_FILLCOLOR
).GetColorValue();
1081 if(aCompareColor
== aLocalColor
)
1086 else if(eLocalFillStyle
== drawing::FillStyle_NONE
)
1099 // yes, start a new layer
1100 pLayer
->mpDown
= new E3dDepthLayer
;
1101 pLayer
= pLayer
->mpDown
;
1103 pLayer
->mvNeighbours
.emplace_back(pExtrudeObj
, aExtrudePoly
);
1107 // no, add to current layer
1108 pLayer
->mvNeighbours
.emplace(pLayer
->mvNeighbours
.begin(), pExtrudeObj
, aExtrudePoly
);
1114 pBaseLayer
= new E3dDepthLayer
;
1115 pLayer
= pBaseLayer
;
1117 pLayer
->mvNeighbours
.emplace_back(pExtrudeObj
, aExtrudePoly
);
1122 // number of layers is done
1125 // need to be arranged
1126 double fMinDepth
= fDepth
* 0.8;
1127 double fStep
= (fDepth
- fMinDepth
) / static_cast<double>(nNumLayers
);
1128 pLayer
= pBaseLayer
;
1133 for(auto& rAct
: pLayer
->mvNeighbours
)
1135 // adapt extrude value
1136 rAct
.mpObj
->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH
, sal_uInt32(fMinDepth
+ 0.5)));
1140 pLayer
= pLayer
->mpDown
;
1148 pLayer
= pBaseLayer
->mpDown
;
1150 pBaseLayer
= pLayer
;
1154 // Start drag, create for 3D objects before possibly drag method
1156 bool E3dView::BegDragObj(const Point
& rPnt
, OutputDevice
* pOut
,
1157 SdrHdl
* pHdl
, short nMinMov
,
1158 SdrDragMethod
* pForcedMeth
)
1160 if(Is3DRotationCreationActive() && GetMarkedObjectCount())
1162 // Determine all selected polygons and return the mirrored helper overlay
1163 mpMirrorOverlay
->SetMirrorAxis(maRef1
, maRef2
);
1167 bool bOwnActionNecessary
;
1168 if (pHdl
== nullptr)
1170 bOwnActionNecessary
= true;
1172 else if (pHdl
->IsVertexHdl() || pHdl
->IsCornerHdl())
1174 bOwnActionNecessary
= true;
1178 bOwnActionNecessary
= false;
1181 if(bOwnActionNecessary
&& GetMarkedObjectCount() > 0)
1183 E3dDragConstraint eConstraint
= E3dDragConstraint::XYZ
;
1184 bool bThereAreRootScenes
= false;
1185 bool bThereAre3DObjects
= false;
1186 const size_t nCnt
= GetMarkedObjectCount();
1187 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
1189 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
1192 if(nullptr != dynamic_cast< const E3dScene
* >(pObj
) && static_cast< E3dScene
* >(pObj
)->getRootE3dSceneFromE3dObject() == pObj
)
1194 bThereAreRootScenes
= true;
1197 if(dynamic_cast< const E3dObject
* >(pObj
) != nullptr)
1199 bThereAre3DObjects
= true;
1203 if( bThereAre3DObjects
)
1205 meDragHdl
= ( pHdl
== nullptr ? SdrHdlKind::Move
: pHdl
->GetKind() );
1206 switch ( meDragMode
)
1208 case SdrDragMode::Rotate
:
1209 case SdrDragMode::Shear
:
1211 switch ( meDragHdl
)
1213 case SdrHdlKind::Left
:
1214 case SdrHdlKind::Right
:
1216 eConstraint
= E3dDragConstraint::X
;
1220 case SdrHdlKind::Upper
:
1221 case SdrHdlKind::Lower
:
1223 eConstraint
= E3dDragConstraint::Y
;
1227 case SdrHdlKind::UpperLeft
:
1228 case SdrHdlKind::UpperRight
:
1229 case SdrHdlKind::LowerLeft
:
1230 case SdrHdlKind::LowerRight
:
1232 eConstraint
= E3dDragConstraint::Z
;
1238 // do not mask the allowed rotations
1239 eConstraint
&= E3dDragConstraint::XYZ
;
1240 pForcedMeth
= new E3dDragRotate(*this, GetMarkedObjectList(), eConstraint
, IsSolidDragging());
1244 case SdrDragMode::Move
:
1246 if(!bThereAreRootScenes
)
1248 pForcedMeth
= new E3dDragMove(*this, GetMarkedObjectList(), meDragHdl
, eConstraint
, IsSolidDragging());
1254 case SdrDragMode::Mirror
:
1255 case SdrDragMode::Crook
:
1256 case SdrDragMode::Transparence
:
1257 case SdrDragMode::Gradient
:
1266 return SdrView::BegDragObj(rPnt
, pOut
, pHdl
, nMinMov
, pForcedMeth
);
1269 // Set current 3D drawing object, create the scene for this
1270 E3dScene
* E3dView::SetCurrent3DObj(E3dObject
* p3DObj
)
1272 DBG_ASSERT(p3DObj
!= nullptr, "Who puts in a NULL-pointer here");
1274 // get transformed BoundVolume of the object
1275 basegfx::B3DRange
aVolume(p3DObj
->GetBoundVolume());
1276 aVolume
.transform(p3DObj
->GetTransform());
1277 double fW(aVolume
.getWidth());
1278 double fH(aVolume
.getHeight());
1280 tools::Rectangle
aRect(0,0, static_cast<tools::Long
>(fW
), static_cast<tools::Long
>(fH
));
1282 E3dScene
* pScene
= new E3dScene(p3DObj
->getSdrModelFromSdrObject());
1284 InitScene(pScene
, fW
, fH
, aVolume
.getMaxZ() + ((fW
+ fH
) / 4.0));
1286 pScene
->InsertObject(p3DObj
);
1287 pScene
->NbcSetSnapRect(aRect
);
1292 void E3dView::InitScene(E3dScene
* pScene
, double fW
, double fH
, double fCamZ
)
1294 Camera3D
aCam(pScene
->GetCamera());
1296 aCam
.SetAutoAdjustProjection(false);
1297 aCam
.SetViewWindow(- fW
/ 2, - fH
/ 2, fW
, fH
);
1298 basegfx::B3DPoint aLookAt
;
1300 double fDefaultCamPosZ
= GetDefaultCamPosZ();
1301 basegfx::B3DPoint
aCamPos(0.0, 0.0, fCamZ
< fDefaultCamPosZ
? fDefaultCamPosZ
: fCamZ
);
1303 aCam
.SetPosAndLookAt(aCamPos
, aLookAt
);
1304 aCam
.SetFocalLength(GetDefaultCamFocal());
1305 pScene
->SetCamera(aCam
);
1308 void E3dView::Start3DCreation()
1310 if (!GetMarkedObjectCount())
1314 tools::Long nOutMin
= 0;
1315 tools::Long nOutMax
= 0;
1316 tools::Long nMinLen
= 0;
1317 tools::Long nObjDst
= 0;
1318 tools::Long nOutHgt
= 0;
1319 OutputDevice
* pOut
= GetFirstOutputDevice();
1321 // first determine representation boundaries
1322 if (pOut
!= nullptr)
1324 nMinLen
= pOut
->PixelToLogic(Size(0,50)).Height();
1325 nObjDst
= pOut
->PixelToLogic(Size(0,20)).Height();
1327 tools::Long nDst
= pOut
->PixelToLogic(Size(0,10)).Height();
1329 nOutMin
= -pOut
->GetMapMode().GetOrigin().Y();
1330 nOutMax
= pOut
->GetOutputSize().Height() - 1 + nOutMin
;
1334 if (nOutMax
- nOutMin
< nDst
)
1336 nOutMin
+= nOutMax
+ 1;
1338 nOutMin
-= (nDst
+ 1) / 2;
1339 nOutMax
= nOutMin
+ nDst
;
1342 nOutHgt
= nOutMax
- nOutMin
;
1344 tools::Long nTemp
= nOutHgt
/ 4;
1345 if (nTemp
> nMinLen
) nMinLen
= nTemp
;
1348 // and then attach the marks at the top and bottom of the object
1349 basegfx::B2DRange aR
;
1350 for(size_t nMark
= 0; nMark
< GetMarkedObjectCount(); ++nMark
)
1352 SdrObject
* pMark
= GetMarkedObjectByIndex(nMark
);
1353 basegfx::B2DPolyPolygon
aXPP(pMark
->TakeXorPoly());
1354 aR
.expand(basegfx::utils::getRange(aXPP
));
1357 basegfx::B2DPoint
aCenter(aR
.getCenter());
1358 tools::Long nMarkHgt
= basegfx::fround(aR
.getHeight()) - 1;
1359 tools::Long nHgt
= nMarkHgt
+ nObjDst
* 2;
1361 if (nHgt
< nMinLen
) nHgt
= nMinLen
;
1363 tools::Long nY1
= basegfx::fround(aCenter
.getY()) - (nHgt
+ 1) / 2;
1364 tools::Long nY2
= nY1
+ nHgt
;
1366 if (pOut
&& (nMinLen
> nOutHgt
)) nMinLen
= nOutHgt
;
1372 if (nY2
< nY1
+ nMinLen
) nY2
= nY1
+ nMinLen
;
1377 if (nY1
> nY2
- nMinLen
) nY1
= nY2
- nMinLen
;
1381 maRef1
.setX( basegfx::fround(aR
.getMinX()) ); // Initial move axis 2/100mm to the left
1383 maRef2
.setX( maRef1
.X() );
1387 SetMarkHandles(nullptr);
1389 //HMHif (bVis) ShowMarkHdl();
1390 if (AreObjectsMarked()) MarkListHasChanged();
1392 // Show mirror polygon IMMEDIATELY
1393 const SdrHdlList
&aHdlList
= GetHdlList();
1394 mpMirrorOverlay
.reset(new Impl3DMirrorConstructOverlay(*this));
1395 mpMirrorOverlay
->SetMirrorAxis(aHdlList
.GetHdl(SdrHdlKind::Ref1
)->GetPos(), aHdlList
.GetHdl(SdrHdlKind::Ref2
)->GetPos());
1398 // what happens with a mouse movement when the object is created?
1400 void E3dView::MovAction(const Point
& rPnt
)
1402 if(Is3DRotationCreationActive())
1404 SdrHdl
* pHdl
= GetDragHdl();
1408 SdrHdlKind eHdlKind
= pHdl
->GetKind();
1410 // reacts only due to a mirror axis
1411 if ((eHdlKind
== SdrHdlKind::Ref1
) ||
1412 (eHdlKind
== SdrHdlKind::Ref2
) ||
1413 (eHdlKind
== SdrHdlKind::MirrorAxis
))
1415 const SdrHdlList
&aHdlList
= GetHdlList ();
1417 // delete the mirrored polygon, mirrors the original and draws
1419 SdrView::MovAction (rPnt
);
1420 mpMirrorOverlay
->SetMirrorAxis(
1421 aHdlList
.GetHdl (SdrHdlKind::Ref1
)->GetPos(),
1422 aHdlList
.GetHdl (SdrHdlKind::Ref2
)->GetPos());
1427 SdrView::MovAction (rPnt
);
1432 SdrView::MovAction (rPnt
);
1436 // The End. Create object and any child objects through ImpCreate3DLathe.
1437 // With the parameter value sal_True (SDefault: sal_False) is simply a
1438 // rotation body created, without letting the user set the position of the
1439 // axis. It is sufficient with this call, if an object is selected.
1440 // (No initialization necessary)
1442 void E3dView::End3DCreation(bool bUseDefaultValuesForMirrorAxes
)
1444 ResetCreationActive();
1446 if(!AreObjectsMarked())
1449 if(bUseDefaultValuesForMirrorAxes
)
1451 tools::Rectangle aRect
= GetAllMarkedRect();
1452 if(aRect
.GetWidth() <= 1)
1453 aRect
.SetSize(Size(500, aRect
.GetHeight()));
1454 if(aRect
.GetHeight() <= 1)
1455 aRect
.SetSize(Size(aRect
.GetWidth(), 500));
1457 basegfx::B2DPoint
aPnt1(aRect
.Left(), -aRect
.Top());
1458 basegfx::B2DPoint
aPnt2(aRect
.Left(), -aRect
.Bottom());
1460 ConvertMarkedObjTo3D(false, aPnt1
, aPnt2
);
1464 // Turn off helper overlay
1465 // Determine from the handle positions and the displacement of
1467 const SdrHdlList
&aHdlList
= GetHdlList();
1468 Point aMirrorRef1
= aHdlList
.GetHdl(SdrHdlKind::Ref1
)->GetPos();
1469 Point aMirrorRef2
= aHdlList
.GetHdl(SdrHdlKind::Ref2
)->GetPos();
1471 basegfx::B2DPoint
aPnt1(aMirrorRef1
.X(), -aMirrorRef1
.Y());
1472 basegfx::B2DPoint
aPnt2(aMirrorRef2
.X(), -aMirrorRef2
.Y());
1474 ConvertMarkedObjTo3D(false, aPnt1
, aPnt2
);
1478 E3dView::~E3dView ()
1482 void E3dView::ResetCreationActive ()
1484 mpMirrorOverlay
.reset();
1487 void E3dView::InitView ()
1489 mpMirrorOverlay
= nullptr;
1492 bool E3dView::IsBreak3DObjPossible() const
1494 const size_t nCount
= GetMarkedObjectCount();
1498 for (size_t i
= 0; i
< nCount
; ++i
)
1500 SdrObject
* pObj
= GetMarkedObjectByIndex(i
);
1502 if (auto p3dObject
= dynamic_cast< E3dObject
* >(pObj
))
1504 if(!p3dObject
->IsBreakObjPossible())
1521 void E3dView::Break3DObj()
1523 if(!IsBreak3DObjPossible())
1526 // ALL selected objects are changed
1527 const size_t nCount
= GetMarkedObjectCount();
1529 BegUndo(SvxResId(RID_SVX_3D_UNDO_BREAK_LATHE
));
1530 for(size_t a
=0; a
<nCount
; ++a
)
1532 E3dObject
* pObj
= static_cast<E3dObject
*>(GetMarkedObjectByIndex(a
));
1533 BreakSingle3DObj(pObj
);
1539 void E3dView::BreakSingle3DObj(E3dObject
* pObj
)
1541 if(dynamic_cast< const E3dScene
* >(pObj
) != nullptr)
1543 SdrObjList
* pSubList
= pObj
->GetSubList();
1544 SdrObjListIter
aIter(pSubList
, SdrIterMode::Flat
);
1546 while(aIter
.IsMore())
1548 E3dObject
* pSubObj
= static_cast<E3dObject
*>(aIter
.Next());
1549 BreakSingle3DObj(pSubObj
);
1554 SdrAttrObj
* pNewObj
= pObj
->GetBreakObj().release();
1557 if (InsertObjectAtView(pNewObj
, *GetSdrPageView(), SdrInsertFlags::DONTMARK
))
1559 pNewObj
->SetChanged();
1560 pNewObj
->BroadcastObjectChange();
1566 void E3dView::CheckPossibilities()
1569 SdrView::CheckPossibilities();
1572 if(!(m_bGroupPossible
|| m_bUnGroupPossible
|| m_bGrpEnterPossible
))
1575 const size_t nMarkCnt
= GetMarkedObjectCount();
1576 bool bCompound
= false;
1577 bool b3DObject
= false;
1578 for(size_t nObjs
= 0; (nObjs
< nMarkCnt
) && !bCompound
; ++nObjs
)
1580 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
1581 if(dynamic_cast< const E3dCompoundObject
* >(pObj
))
1583 if(dynamic_cast< const E3dObject
* >(pObj
))
1587 // So far: there are two or more of any objects selected. See if
1588 // compound objects are involved. If yes, ban grouping.
1589 if(m_bGroupPossible
&& bCompound
)
1590 m_bGroupPossible
= false;
1592 if(m_bUnGroupPossible
&& b3DObject
)
1593 m_bUnGroupPossible
= false;
1595 if(m_bGrpEnterPossible
&& bCompound
)
1596 m_bGrpEnterPossible
= false;
1599 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */