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>
56 using namespace com::sun::star
;
61 class Impl3DMirrorConstructOverlay
64 sdr::overlay::OverlayObjectList maObjects
;
67 const E3dView
& mrView
;
72 // the unmirrored polygons
73 basegfx::B2DPolyPolygon
* mpPolygons
;
75 // the overlay geometry from selected objects
76 drawinglayer::primitive2d::Primitive2DContainer maFullOverlay
;
78 // Copy assignment is forbidden and not implemented.
79 Impl3DMirrorConstructOverlay (const Impl3DMirrorConstructOverlay
&) = delete;
80 Impl3DMirrorConstructOverlay
& operator= (const Impl3DMirrorConstructOverlay
&) = delete;
83 explicit Impl3DMirrorConstructOverlay(const E3dView
& rView
);
84 ~Impl3DMirrorConstructOverlay();
86 void SetMirrorAxis(Point aMirrorAxisA
, Point aMirrorAxisB
);
89 Impl3DMirrorConstructOverlay::Impl3DMirrorConstructOverlay(const E3dView
& rView
)
91 mnCount(rView
.GetMarkedObjectCount()),
97 if(mrView
.IsSolidDragging())
99 SdrPageView
* pPV
= rView
.GetSdrPageView();
101 if(pPV
&& pPV
->PageWindowCount())
103 for(size_t a
= 0; a
< mnCount
; ++a
)
105 SdrObject
* pObject
= mrView
.GetMarkedObjectByIndex(a
);
109 // use the view-independent primitive representation (without
110 // evtl. GridOffset, that may be applied to the DragEntry individually)
111 pObject
->GetViewContact().getViewIndependentPrimitive2DContainer(maFullOverlay
);
118 mpPolygons
= new basegfx::B2DPolyPolygon
[mnCount
];
120 for(size_t a
= 0; a
< mnCount
; ++a
)
122 SdrObject
* pObject
= mrView
.GetMarkedObjectByIndex(a
);
123 mpPolygons
[mnCount
- (a
+ 1)] = pObject
->TakeXorPoly();
128 Impl3DMirrorConstructOverlay::~Impl3DMirrorConstructOverlay()
130 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
131 // That destructor calls clear() at the list which removes all objects from the
132 // OverlayManager and deletes them.
136 void Impl3DMirrorConstructOverlay::SetMirrorAxis(Point aMirrorAxisA
, Point aMirrorAxisB
)
138 // get rid of old overlay objects
142 for(sal_uInt32
a(0); a
< mrView
.PaintWindowCount(); a
++)
144 SdrPaintWindow
* pCandidate
= mrView
.GetPaintWindow(a
);
145 const rtl::Reference
< sdr::overlay::OverlayManager
>& xTargetOverlay
= pCandidate
->GetOverlayManager();
147 if(xTargetOverlay
.is())
149 // build transformation: translate and rotate so that given edge is
150 // on x axis, them mirror in y and translate back
151 const basegfx::B2DVector
aEdge(aMirrorAxisB
.X() - aMirrorAxisA
.X(), aMirrorAxisB
.Y() - aMirrorAxisA
.Y());
152 basegfx::B2DHomMatrix
aMatrixTransform(basegfx::utils::createTranslateB2DHomMatrix(
153 -aMirrorAxisA
.X(), -aMirrorAxisA
.Y()));
154 aMatrixTransform
.rotate(-atan2(aEdge
.getY(), aEdge
.getX()));
155 aMatrixTransform
.scale(1.0, -1.0);
156 aMatrixTransform
.rotate(atan2(aEdge
.getY(), aEdge
.getX()));
157 aMatrixTransform
.translate(aMirrorAxisA
.X(), aMirrorAxisA
.Y());
159 if(mrView
.IsSolidDragging())
161 if(!maFullOverlay
.empty())
163 drawinglayer::primitive2d::Primitive2DContainer
aContent(maFullOverlay
);
165 if(!aMatrixTransform
.isIdentity())
167 // embed in transformation group
168 drawinglayer::primitive2d::Primitive2DReference
aTransformPrimitive2D(new drawinglayer::primitive2d::TransformPrimitive2D(aMatrixTransform
, std::move(aContent
)));
169 aContent
= drawinglayer::primitive2d::Primitive2DContainer
{ aTransformPrimitive2D
};
172 // if we have full overlay from selected objects, embed with 50% transparence, the
173 // transformation is added to the OverlayPrimitive2DSequenceObject
174 drawinglayer::primitive2d::Primitive2DReference
aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aContent
), 0.5));
175 aContent
= drawinglayer::primitive2d::Primitive2DContainer
{ aUnifiedTransparencePrimitive2D
};
177 std::unique_ptr
<sdr::overlay::OverlayPrimitive2DSequenceObject
> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(std::move(aContent
)));
179 xTargetOverlay
->add(*pNew
);
180 maObjects
.append(std::move(pNew
));
185 for(size_t b
= 0; b
< mnCount
; ++b
)
188 basegfx::B2DPolyPolygon
aPolyPolygon(mpPolygons
[b
]);
189 aPolyPolygon
.transform(aMatrixTransform
);
191 std::unique_ptr
<sdr::overlay::OverlayPolyPolygonStripedAndFilled
> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
192 std::move(aPolyPolygon
)));
193 xTargetOverlay
->add(*pNew
);
194 maObjects
.append(std::move(pNew
));
204 : SdrView(rSdrModel
, pOut
)
209 // DrawMarkedObj override, since possibly only a single 3D object is to be
212 void E3dView::DrawMarkedObj(OutputDevice
& rOut
) const
214 // Does 3D objects exist which scenes are not selected?
215 bool bSpecialHandling
= false;
216 E3dScene
*pScene
= nullptr;
218 const size_t nCnt
= GetMarkedObjectCount();
219 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
221 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
222 if(auto pCompoundObject
= dynamic_cast<E3dCompoundObject
*>(pObj
))
225 pScene
= pCompoundObject
->getRootE3dSceneFromE3dObject();
227 if(nullptr != pScene
&& !IsObjMarked(pScene
))
229 bSpecialHandling
= true;
232 // Reset all selection flags
233 if(auto p3dObject
= DynCastE3dObject(pObj
))
235 pScene
= p3dObject
->getRootE3dSceneFromE3dObject();
237 if(nullptr != pScene
)
239 pScene
->SetSelected(false);
246 // Set selection flag to "not selected" for scenes related to all 3D
248 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
250 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
251 if(auto pCompoundObject
= dynamic_cast<E3dCompoundObject
*>(pObj
))
254 pScene
= pCompoundObject
->getRootE3dSceneFromE3dObject();
256 if(nullptr != pScene
)
258 pScene
->SetSelected(false);
263 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
265 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
266 if(auto p3DObj
= DynCastE3dObject(pObj
))
269 p3DObj
->SetSelected(true);
270 pScene
= p3DObj
->getRootE3dSceneFromE3dObject();
274 if(nullptr != pScene
)
279 pScene
->SetDrawOnlySelected(true);
280 pScene
->SingleObjectPainter(rOut
);
281 pScene
->SetDrawOnlySelected(false);
284 // Reset selection flag
285 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
287 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
288 if(auto pCompoundObject
= dynamic_cast<E3dCompoundObject
*>(pObj
))
291 pScene
= pCompoundObject
->getRootE3dSceneFromE3dObject();
293 if(nullptr != pScene
)
295 pScene
->SetSelected(false);
303 SdrExchangeView::DrawMarkedObj(rOut
);
307 // override get model, since in some 3D objects an additional scene
310 std::unique_ptr
<SdrModel
> E3dView::CreateMarkedObjModel() const
312 // Does 3D objects exist which scenes are not selected?
313 bool bSpecialHandling(false);
314 const size_t nCount(GetMarkedObjectCount());
315 E3dScene
*pScene
= nullptr;
317 for(size_t nObjs
= 0; nObjs
< nCount
; ++nObjs
)
319 const SdrObject
* pObj
= GetMarkedObjectByIndex(nObjs
);
321 if(!bSpecialHandling
)
322 if(auto pCompoundObj
= dynamic_cast< const E3dCompoundObject
*>(pObj
))
324 // if the object is selected, but it's scene not,
325 // we need special handling
326 pScene
= pCompoundObj
->getRootE3dSceneFromE3dObject();
328 if(nullptr != pScene
&& !IsObjMarked(pScene
))
330 bSpecialHandling
= true;
334 if(auto p3dObject
= DynCastE3dObject(pObj
))
336 // reset all selection flags at 3D objects
337 pScene
= p3dObject
->getRootE3dSceneFromE3dObject();
339 if(nullptr != pScene
)
341 pScene
->SetSelected(false);
346 if(!bSpecialHandling
)
349 return SdrView::CreateMarkedObjModel();
352 std::unique_ptr
<SdrModel
> pNewModel
;
353 tools::Rectangle aSelectedSnapRect
;
355 // set 3d selection flags at all directly selected objects
356 // and collect SnapRect of selected objects
357 for(size_t nObjs
= 0; nObjs
< nCount
; ++nObjs
)
359 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
361 if(auto p3DObj
= dynamic_cast<E3dCompoundObject
*>(pObj
))
363 // mark object, but not scenes
364 p3DObj
->SetSelected(true);
365 aSelectedSnapRect
.Union(p3DObj
->GetSnapRect());
369 // create new mark list which contains all indirectly selected3d
370 // scenes as selected objects
371 SdrMarkList
aOldML(GetMarkedObjectList());
373 SdrMarkList
& rCurrentMarkList
= const_cast<E3dView
*>(this)->GetMarkedObjectListWriteAccess();
374 rCurrentMarkList
= aNewML
;
376 for(size_t nObjs
= 0; nObjs
< nCount
; ++nObjs
)
378 SdrObject
*pObj
= aOldML
.GetMark(nObjs
)->GetMarkedSdrObj();
380 if(auto p3dObject
= DynCastE3dObject(pObj
))
382 pScene
= p3dObject
->getRootE3dSceneFromE3dObject();
384 if(nullptr != pScene
&& !IsObjMarked(pScene
) && GetSdrPageView())
386 const_cast<E3dView
*>(this)->MarkObj(pScene
, GetSdrPageView(), false, true);
391 // call parent. This will copy all scenes and the selection flags at the 3D objects. So
392 // it will be possible to delete all non-selected 3d objects from the cloned 3d scenes
393 pNewModel
= SdrView::CreateMarkedObjModel();
397 for(sal_uInt16
nPg(0); nPg
< pNewModel
->GetPageCount(); nPg
++)
399 const SdrPage
* pSrcPg
=pNewModel
->GetPage(nPg
);
400 const size_t nObjCount(pSrcPg
->GetObjCount());
402 for(size_t nOb
= 0; nOb
< nObjCount
; ++nOb
)
404 const SdrObject
* pSrcOb
=pSrcPg
->GetObj(nOb
);
406 if(const E3dScene
* p3dscene
= DynCastE3dScene( pSrcOb
))
408 pScene
= const_cast<E3dScene
*>(p3dscene
);
410 // delete all not intentionally cloned 3d objects
411 pScene
->removeAllNonSelectedObjects();
413 // reset select flags and set SnapRect of all selected objects
414 pScene
->SetSelected(false);
415 pScene
->SetSnapRect(aSelectedSnapRect
);
421 // restore old selection
422 rCurrentMarkList
= aOldML
;
427 // When pasting objects have to integrated if a scene is inserted, but
428 // not the scene itself
431 const SdrModel
& rMod
, const Point
& rPos
, SdrObjList
* pLst
, SdrInsertFlags nOptions
)
433 bool bRetval
= false;
437 SdrObjList
* pDstList
= pLst
;
438 ImpGetPasteObjList(aPos
, pDstList
);
443 // Get owner of the list
444 E3dScene
* pDstScene(DynCastE3dScene(pDstList
->getSdrObjectFromSdrObjList()));
446 if(nullptr != pDstScene
)
448 BegUndo(SvxResId(RID_SVX_3D_UNDO_EXCHANGE_PASTE
));
450 // Copy all objects from E3dScenes and insert them directly
451 for(sal_uInt16
nPg(0); nPg
< rMod
.GetPageCount(); nPg
++)
453 const SdrPage
* pSrcPg
=rMod
.GetPage(nPg
);
454 const size_t nObjCount(pSrcPg
->GetObjCount());
456 // calculate offset for paste
457 tools::Rectangle aR
= pSrcPg
->GetAllObjBoundRect();
458 Point
aDist(aPos
- aR
.Center());
460 // Insert sub-objects for scenes
461 for(size_t nOb
= 0; nOb
< nObjCount
; ++nOb
)
463 const SdrObject
* pSrcOb
= pSrcPg
->GetObj(nOb
);
464 if(const E3dScene
* p3dscene
= DynCastE3dScene(pSrcOb
))
466 E3dScene
* pSrcScene
= const_cast<E3dScene
*>(p3dscene
);
467 ImpCloneAll3DObjectsToDestScene(pSrcScene
, pDstScene
, aDist
);
476 bRetval
= SdrView::Paste(rMod
, rPos
, pLst
, nOptions
);
482 // Service routine used from local Clone() and from SdrCreateView::EndCreateObj(...)
483 bool E3dView::ImpCloneAll3DObjectsToDestScene(E3dScene
const * pSrcScene
, E3dScene
* pDstScene
, Point
/*aOffset*/)
487 if(pSrcScene
&& pDstScene
)
489 for(size_t i
= 0; i
< pSrcScene
->GetSubList()->GetObjCount(); ++i
)
491 E3dCompoundObject
* pCompoundObj
= dynamic_cast< E3dCompoundObject
* >(pSrcScene
->GetSubList()->GetObj(i
));
495 rtl::Reference
<E3dCompoundObject
> pNewCompoundObj
= SdrObject::Clone(*pCompoundObj
, pDstScene
->getSdrModelFromSdrObject());
499 // get dest scene's current range in 3D world coordinates
500 const basegfx::B3DHomMatrix
aSceneToWorldTrans(pDstScene
->GetFullTransform());
501 basegfx::B3DRange
aSceneRange(pDstScene
->GetBoundVolume());
502 aSceneRange
.transform(aSceneToWorldTrans
);
504 // get new object's implied object transformation
505 const basegfx::B3DHomMatrix
aNewObjectTrans(pNewCompoundObj
->GetTransform());
507 // get new object's range in 3D world coordinates in dest scene
508 // as if it were already added
509 const basegfx::B3DHomMatrix
aObjectToWorldTrans(aSceneToWorldTrans
* aNewObjectTrans
);
510 basegfx::B3DRange
aObjectRange(pNewCompoundObj
->GetBoundVolume());
511 aObjectRange
.transform(aObjectToWorldTrans
);
513 // get scale adaptation
514 const basegfx::B3DVector
aSceneScale(aSceneRange
.getRange());
515 const basegfx::B3DVector
aObjectScale(aObjectRange
.getRange());
518 // if new object's size in X,Y or Z is bigger that 80% of dest scene, adapt scale
519 // to not change the scene by the inserted object
520 const double fSizeFactor(0.5);
522 if(aObjectScale
.getX() * fScale
> aSceneScale
.getX() * fSizeFactor
)
524 const double fObjSize(aObjectScale
.getX() * fScale
);
525 const double fFactor((aSceneScale
.getX() * fSizeFactor
) / (basegfx::fTools::equalZero(fObjSize
) ? 1.0 : fObjSize
));
529 if(aObjectScale
.getY() * fScale
> aSceneScale
.getY() * fSizeFactor
)
531 const double fObjSize(aObjectScale
.getY() * fScale
);
532 const double fFactor((aSceneScale
.getY() * fSizeFactor
) / (basegfx::fTools::equalZero(fObjSize
) ? 1.0 : fObjSize
));
536 if(aObjectScale
.getZ() * fScale
> aSceneScale
.getZ() * fSizeFactor
)
538 const double fObjSize(aObjectScale
.getZ() * fScale
);
539 const double fFactor((aSceneScale
.getZ() * fSizeFactor
) / (basegfx::fTools::equalZero(fObjSize
) ? 1.0 : fObjSize
));
543 // get translation adaptation
544 const basegfx::B3DPoint
aSceneCenter(aSceneRange
.getCenter());
545 const basegfx::B3DPoint
aObjectCenter(aObjectRange
.getCenter());
547 // build full modification transform. The object's transformation
548 // shall be modified, so start at object coordinates; transform to 3d world coor
549 basegfx::B3DHomMatrix
aModifyingTransform(aObjectToWorldTrans
);
551 // translate to absolute center in 3d world coor
552 aModifyingTransform
.translate(-aObjectCenter
.getX(), -aObjectCenter
.getY(), -aObjectCenter
.getZ());
554 // scale to dest size in 3d world coor
555 aModifyingTransform
.scale(fScale
, fScale
, fScale
);
557 // translate to dest scene center in 3d world coor
558 aModifyingTransform
.translate(aSceneCenter
.getX(), aSceneCenter
.getY(), aSceneCenter
.getZ());
560 // transform from 3d world to dest object coordinates
561 basegfx::B3DHomMatrix
aWorldToObject(aObjectToWorldTrans
);
562 aWorldToObject
.invert();
563 aModifyingTransform
= aWorldToObject
* aModifyingTransform
;
565 // correct implied object transform by applying changing one in object coor
566 pNewCompoundObj
->SetTransform(aModifyingTransform
* aNewObjectTrans
);
568 // fill and insert new object
569 pNewCompoundObj
->NbcSetLayer(pCompoundObj
->GetLayer());
570 pNewCompoundObj
->NbcSetStyleSheet(pCompoundObj
->GetStyleSheet(), true);
571 pDstScene
->InsertObject(pNewCompoundObj
.get());
575 if( GetModel().IsUndoEnabled() )
576 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pNewCompoundObj
));
585 bool E3dView::IsConvertTo3DObjPossible() const
588 bool bGroupSelected(false);
591 for(size_t a
=0; !bAny3D
&& a
<GetMarkedObjectCount(); ++a
)
593 SdrObject
*pObj
= GetMarkedObjectByIndex(a
);
596 ImpIsConvertTo3DPossible(pObj
, bAny3D
, bGroupSelected
);
602 IsConvertToPolyObjPossible()
603 || IsConvertToPathObjPossible()
604 || IsImportMtfPossible());
608 void E3dView::ImpIsConvertTo3DPossible(SdrObject
const * pObj
, bool& rAny3D
,
609 bool& rGroupSelected
) const
614 if(DynCastE3dObject(pObj
))
620 if(pObj
->IsGroupObject())
622 SdrObjListIter
aIter(*pObj
, SdrIterMode::DeepNoGroups
);
623 while(aIter
.IsMore())
625 SdrObject
* pNewObj
= aIter
.Next();
626 ImpIsConvertTo3DPossible(pNewObj
, rAny3D
, rGroupSelected
);
628 rGroupSelected
= true;
633 void E3dView::ImpChangeSomeAttributesFor3DConversion(SdrObject
* pObj
)
635 if(DynCastSdrTextObj( pObj
) == nullptr)
638 const SfxItemSet
& rSet
= pObj
->GetMergedItemSet();
639 const SvxColorItem
& rTextColorItem
= rSet
.Get(EE_CHAR_COLOR
);
640 if(rTextColorItem
.GetValue() != COL_BLACK
)
643 //For black text objects, the color set to gray
644 if(pObj
->getSdrPageFromSdrObject())
646 // if black is only default attribute from
647 // pattern set it hard so that it is used in undo.
648 pObj
->SetMergedItem(SvxColorItem(COL_BLACK
, EE_CHAR_COLOR
));
651 if (GetModel().IsUndoEnabled())
652 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj
));
655 pObj
->SetMergedItem(SvxColorItem(COL_GRAY
, EE_CHAR_COLOR
));
658 void E3dView::ImpChangeSomeAttributesFor3DConversion2(SdrObject
* pObj
)
660 auto pPathObj
= dynamic_cast<const SdrPathObj
*>( pObj
);
664 const SfxItemSet
& rSet
= pObj
->GetMergedItemSet();
665 sal_Int32 nLineWidth
= rSet
.Get(XATTR_LINEWIDTH
).GetValue();
666 drawing::LineStyle eLineStyle
= rSet
.Get(XATTR_LINESTYLE
).GetValue();
667 drawing::FillStyle eFillStyle
= rSet
.Get(XATTR_FILLSTYLE
).GetValue();
669 if(pPathObj
->IsClosed()
670 && eLineStyle
== drawing::LineStyle_SOLID
672 && eFillStyle
!= drawing::FillStyle_NONE
)
674 if (pObj
->getSdrPageFromSdrObject() && GetModel().IsUndoEnabled())
676 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj
));
679 pObj
->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE
));
680 pObj
->SetMergedItem(XLineWidthItem(0));
684 void E3dView::ImpCreateSingle3DObjectFlat(E3dScene
* pScene
, SdrObject
* pObj
, bool bExtrude
, double fDepth
, basegfx::B2DHomMatrix
const & rLatheMat
)
686 // Single PathObject, transform this
687 SdrPathObj
* pPath
= dynamic_cast<SdrPathObj
*>( pObj
);
692 E3dDefaultAttributes aDefault
= Get3DDefaultAttributes();
696 aDefault
.SetDefaultExtrudeCharacterMode(true);
700 aDefault
.SetDefaultLatheCharacterMode(true);
703 // Get Itemset of the original object
704 SfxItemSet
aSet(pObj
->GetMergedItemSet());
706 drawing::FillStyle eFillStyle
= aSet
.Get(XATTR_FILLSTYLE
).GetValue();
708 // line style turned off
709 aSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
711 //Determining if FILL_Attribute is set.
712 if(!pPath
->IsClosed() || eFillStyle
== drawing::FillStyle_NONE
)
714 // This SdrPathObj is not filled, leave the front and rear face out.
715 // Moreover, a two-sided representation necessary.
716 aDefault
.SetDefaultExtrudeCloseFront(false);
717 aDefault
.SetDefaultExtrudeCloseBack(false);
719 aSet
.Put(makeSvx3DDoubleSidedItem(true));
721 // Set fill attribute
722 aSet
.Put(XFillStyleItem(drawing::FillStyle_SOLID
));
724 // Fill color must be the color line, because the object was
725 // previously just a line
726 Color aColorLine
= aSet
.Get(XATTR_LINECOLOR
).GetColorValue();
727 aSet
.Put(XFillColorItem(OUString(), aColorLine
));
730 // Create a new extrude object
731 rtl::Reference
<E3dObject
> p3DObj
;
734 p3DObj
= new E3dExtrudeObj(pObj
->getSdrModelFromSdrObject(), aDefault
, pPath
->GetPathPoly(), fDepth
);
738 // rLatheMat expects coordinates with y-axis up, pPath uses y-axis down
739 basegfx::B2DHomMatrix
aFlipVerticalMat(1.0, 0.0, 0.0, 0.0, -1.0, 0.0);
740 basegfx::B2DPolyPolygon
aPolyPoly2D(pPath
->GetPathPoly());
741 aPolyPoly2D
.transform(aFlipVerticalMat
);
742 aPolyPoly2D
.transform(rLatheMat
);
743 // ctor E3dLatheObj expects coordinates with y-axis down
744 aPolyPoly2D
.transform(aFlipVerticalMat
);
745 p3DObj
= new E3dLatheObj(pObj
->getSdrModelFromSdrObject(), aDefault
, std::move(aPolyPoly2D
));
749 p3DObj
->NbcSetLayer(pObj
->GetLayer());
751 p3DObj
->SetMergedItemSet(aSet
);
753 p3DObj
->NbcSetStyleSheet(pObj
->GetStyleSheet(), true);
755 // Insert a new extrude object
756 pScene
->InsertObject(p3DObj
.get());
759 void E3dView::ImpCreate3DObject(E3dScene
* pScene
, SdrObject
* pObj
, bool bExtrude
, double fDepth
, basegfx::B2DHomMatrix
const & rLatheMat
)
764 // change text color attribute for not so dark colors
765 if(pObj
->IsGroupObject())
767 SdrObjListIter
aIter(*pObj
, SdrIterMode::DeepWithGroups
);
768 while(aIter
.IsMore())
770 SdrObject
* pGroupMember
= aIter
.Next();
771 ImpChangeSomeAttributesFor3DConversion(pGroupMember
);
775 ImpChangeSomeAttributesFor3DConversion(pObj
);
777 // convert completely to path objects
778 rtl::Reference
<SdrObject
> pNewObj1
= pObj
->ConvertToPolyObj(false, false);
783 // change text color attribute for not so dark colors
784 if(pNewObj1
->IsGroupObject())
786 SdrObjListIter
aIter(*pNewObj1
, SdrIterMode::DeepWithGroups
);
787 while(aIter
.IsMore())
789 SdrObject
* pGroupMember
= aIter
.Next();
790 ImpChangeSomeAttributesFor3DConversion2(pGroupMember
);
794 ImpChangeSomeAttributesFor3DConversion2(pNewObj1
.get());
796 // convert completely to path objects
797 rtl::Reference
<SdrObject
> pNewObj2
= pObj
->ConvertToContourObj(pNewObj1
.get(), true);
801 // add all to flat scene
802 if(pNewObj2
->IsGroupObject())
804 SdrObjListIter
aIter(*pNewObj2
, SdrIterMode::DeepWithGroups
);
805 while(aIter
.IsMore())
807 SdrObject
* pGroupMember
= aIter
.Next();
808 ImpCreateSingle3DObjectFlat(pScene
, pGroupMember
, bExtrude
, fDepth
, rLatheMat
);
812 ImpCreateSingle3DObjectFlat(pScene
, pNewObj2
.get(), bExtrude
, fDepth
, rLatheMat
);
816 void E3dView::ConvertMarkedObjTo3D(bool bExtrude
, const basegfx::B2DPoint
& rPnt1
, const basegfx::B2DPoint
& rPnt2
)
818 if(!AreObjectsMarked())
823 BegUndo(SvxResId(RID_SVX_3D_UNDO_EXTRUDE
));
825 BegUndo(SvxResId(RID_SVX_3D_UNDO_LATHE
));
827 SdrModel
& rSdrModel(GetSdrMarkByIndex(0)->GetMarkedSdrObj()->getSdrModelFromSdrObject());
829 // Create a new scene for the created 3D object
830 rtl::Reference
<E3dScene
> pScene
= new E3dScene(rSdrModel
);
832 // Determine rectangle and possibly correct it
833 tools::Rectangle aRect
= GetAllMarkedRect();
834 if(aRect
.GetWidth() <= 1)
835 aRect
.SetSize(Size(500, aRect
.GetHeight()));
836 if(aRect
.GetHeight() <= 1)
837 aRect
.SetSize(Size(aRect
.GetWidth(), 500));
839 // Determine the depth relative to the size of the selection
842 basegfx::B2DHomMatrix aLatheMat
;
846 fDepth
= std::hypot(aRect
.GetWidth(), aRect
.GetHeight()) / 6.0;
850 // Create transformation for the polygons rotating body
853 // Rotation around control point #1 with set angle
854 // for 3D coordinates
855 basegfx::B2DPoint
aDiff(rPnt1
- rPnt2
);
856 fRot3D
= atan2(aDiff
.getY(), aDiff
.getX()) - M_PI_2
;
858 if(basegfx::fTools::equalZero(fabs(fRot3D
)))
863 aLatheMat
= basegfx::utils::createRotateAroundPoint(rPnt2
, -fRot3D
)
868 if (rPnt2
.getX() != 0.0)
870 // Translation to Y=0 - axis
871 aLatheMat
.translate(-rPnt2
.getX(), 0.0);
875 aLatheMat
.translate(static_cast<double>(-aRect
.Left()), 0.0);
878 // Form the inverse matrix to determine the target expansion
879 basegfx::B2DHomMatrix
aInvLatheMat(aLatheMat
);
880 aInvLatheMat
.invert();
882 // SnapRect extension enables mirroring in the axis of rotation
883 for(size_t a
=0; a
<GetMarkedObjectCount(); ++a
)
885 SdrMark
* pMark
= GetSdrMarkByIndex(a
);
886 SdrObject
* pObj
= pMark
->GetMarkedSdrObj();
887 tools::Rectangle aTurnRect
= pObj
->GetSnapRect();
888 basegfx::B2DPoint aRot
;
891 aRot
= basegfx::B2DPoint(aTurnRect
.Left(), -aTurnRect
.Top());
893 aRot
.setX(-aRot
.getX());
894 aRot
*= aInvLatheMat
;
895 aRotPnt
= Point(static_cast<tools::Long
>(aRot
.getX() + 0.5), static_cast<tools::Long
>(-aRot
.getY() - 0.5));
896 aRect
.Union(tools::Rectangle(aRotPnt
, aRotPnt
));
898 aRot
= basegfx::B2DPoint(aTurnRect
.Left(), -aTurnRect
.Bottom());
900 aRot
.setX(-aRot
.getX());
901 aRot
*= aInvLatheMat
;
902 aRotPnt
= Point(static_cast<tools::Long
>(aRot
.getX() + 0.5), static_cast<tools::Long
>(-aRot
.getY() - 0.5));
903 aRect
.Union(tools::Rectangle(aRotPnt
, aRotPnt
));
905 aRot
= basegfx::B2DPoint(aTurnRect
.Right(), -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
.Right(), -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
));
921 // Walk through the selection and convert it into 3D, complete with
922 // Conversion to SdrPathObject, also fonts
923 for(size_t a
=0; a
<GetMarkedObjectCount(); ++a
)
925 SdrMark
* pMark
= GetSdrMarkByIndex(a
);
926 SdrObject
* pObj
= pMark
->GetMarkedSdrObj();
928 ImpCreate3DObject(pScene
.get(), pObj
, bExtrude
, fDepth
, aLatheMat
);
931 if(pScene
->GetSubList() && pScene
->GetSubList()->GetObjCount() != 0)
933 // Arrange all created objects by depth
935 DoDepthArrange(pScene
.get(), fDepth
);
937 // Center 3D objects in the middle of the overall rectangle
938 basegfx::B3DPoint
aCenter(pScene
->GetBoundVolume().getCenter());
939 basegfx::B3DHomMatrix aMatrix
;
941 aMatrix
.translate(-aCenter
.getX(), -aCenter
.getY(), -aCenter
.getZ());
942 pScene
->SetTransform(aMatrix
* pScene
->GetTransform());
945 pScene
->NbcSetSnapRect(aRect
);
946 basegfx::B3DRange aBoundVol
= pScene
->GetBoundVolume();
947 InitScene(pScene
.get(), static_cast<double>(aRect
.GetWidth()), static_cast<double>(aRect
.GetHeight()), aBoundVol
.getDepth());
949 // Insert scene instead of the first selected object and throw away
950 // all the old objects
951 SdrObject
* pRepObj
= GetMarkedObjectByIndex(0);
952 SdrPageView
* pPV
= GetSdrPageViewOfMarkedByIndex(0);
953 MarkObj(pRepObj
, pPV
, true);
954 ReplaceObjectAtView(pRepObj
, *pPV
, pScene
.get(), false);
956 MarkObj(pScene
.get(), pPV
);
958 // Rotate Rotation body around the axis of rotation
959 if(!bExtrude
&& fRot3D
!= 0.0)
961 basegfx::B3DHomMatrix aRotate
;
962 aRotate
.rotate(0.0, 0.0, fRot3D
);
963 pScene
->SetTransform(aRotate
* pScene
->GetTransform());
966 // Set default rotation
968 basegfx::B3DHomMatrix aRotate
;
969 aRotate
.rotate(basegfx::deg2rad(20.0), 0.0, 0.0);
970 // E3DModifySceneSnapRectUpdater updates the 2D representation of the scene.
971 // It prepares things in ctor and acts in dtor.
972 E3DModifySceneSnapRectUpdater
aUpdater(pScene
->getSdrObjectFromSdrObjList());
973 pScene
->SetTransform(aRotate
* pScene
->GetTransform());
982 //Arrange all created extrude objects by depth
986 struct E3dDepthNeighbour
988 E3dExtrudeObj
* mpObj
;
989 basegfx::B2DPolyPolygon maPreparedPolyPolygon
;
991 E3dDepthNeighbour(E3dExtrudeObj
* pObj
, basegfx::B2DPolyPolygon aPreparedPolyPolygon
)
993 maPreparedPolyPolygon(std::move(aPreparedPolyPolygon
))
1000 E3dDepthLayer
* mpDown
;
1001 std::vector
<E3dDepthNeighbour
> mvNeighbours
;
1011 void E3dView::DoDepthArrange(E3dScene
const * pScene
, double fDepth
)
1013 if(!(pScene
&& pScene
->GetSubList() && pScene
->GetSubList()->GetObjCount() > 1))
1016 SdrObjList
* pSubList
= pScene
->GetSubList();
1017 SdrObjListIter
aIter(pSubList
, SdrIterMode::Flat
);
1018 E3dDepthLayer
* pBaseLayer
= nullptr;
1019 E3dDepthLayer
* pLayer
= nullptr;
1020 sal_Int32 nNumLayers
= 0;
1022 while(aIter
.IsMore())
1024 E3dExtrudeObj
* pExtrudeObj
= dynamic_cast< E3dExtrudeObj
* >(aIter
.Next());
1028 const basegfx::B2DPolyPolygon
aExtrudePoly(
1029 basegfx::utils::prepareForPolygonOperation(pExtrudeObj
->GetExtrudePolygon()));
1030 const SfxItemSet
& rLocalSet
= pExtrudeObj
->GetMergedItemSet();
1031 const drawing::FillStyle eLocalFillStyle
= rLocalSet
.Get(XATTR_FILLSTYLE
).GetValue();
1032 const Color aLocalColor
= rLocalSet
.Get(XATTR_FILLCOLOR
).GetColorValue();
1034 // sort in ExtrudeObj
1037 // do we have overlap with an object of this layer?
1038 bool bOverlap(false);
1040 for(const auto& rAct
: pLayer
->mvNeighbours
)
1042 // do rAct.mpObj and pExtrudeObj overlap? Check by
1043 // using logical AND clipping
1044 const basegfx::B2DPolyPolygon
aAndPolyPolygon(
1045 basegfx::utils::solvePolygonOperationAnd(
1047 rAct
.maPreparedPolyPolygon
));
1049 if(aAndPolyPolygon
.count() != 0)
1051 // second criteria: is another fillstyle or color used?
1052 const SfxItemSet
& rCompareSet
= rAct
.mpObj
->GetMergedItemSet();
1054 drawing::FillStyle eCompareFillStyle
= rCompareSet
.Get(XATTR_FILLSTYLE
).GetValue();
1056 if(eLocalFillStyle
== eCompareFillStyle
)
1058 if(eLocalFillStyle
== drawing::FillStyle_SOLID
)
1060 Color aCompareColor
= rCompareSet
.Get(XATTR_FILLCOLOR
).GetColorValue();
1062 if(aCompareColor
== aLocalColor
)
1067 else if(eLocalFillStyle
== drawing::FillStyle_NONE
)
1080 // yes, start a new layer
1081 pLayer
->mpDown
= new E3dDepthLayer
;
1082 pLayer
= pLayer
->mpDown
;
1084 pLayer
->mvNeighbours
.emplace_back(pExtrudeObj
, aExtrudePoly
);
1088 // no, add to current layer
1089 pLayer
->mvNeighbours
.emplace(pLayer
->mvNeighbours
.begin(), pExtrudeObj
, aExtrudePoly
);
1095 pBaseLayer
= new E3dDepthLayer
;
1096 pLayer
= pBaseLayer
;
1098 pLayer
->mvNeighbours
.emplace_back(pExtrudeObj
, aExtrudePoly
);
1103 // number of layers is done
1106 // need to be arranged
1107 double fMinDepth
= fDepth
* 0.8;
1108 double fStep
= (fDepth
- fMinDepth
) / static_cast<double>(nNumLayers
);
1109 pLayer
= pBaseLayer
;
1114 for(auto& rAct
: pLayer
->mvNeighbours
)
1116 // adapt extrude value
1117 rAct
.mpObj
->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH
, sal_uInt32(fMinDepth
+ 0.5)));
1121 pLayer
= pLayer
->mpDown
;
1129 pLayer
= pBaseLayer
->mpDown
;
1131 pBaseLayer
= pLayer
;
1135 // Start drag, create for 3D objects before possibly drag method
1137 bool E3dView::BegDragObj(const Point
& rPnt
, OutputDevice
* pOut
,
1138 SdrHdl
* pHdl
, short nMinMov
,
1139 SdrDragMethod
* pForcedMeth
)
1141 if(Is3DRotationCreationActive() && GetMarkedObjectCount())
1143 // Determine all selected polygons and return the mirrored helper overlay
1144 mpMirrorOverlay
->SetMirrorAxis(maRef1
, maRef2
);
1148 bool bOwnActionNecessary
;
1149 if (pHdl
== nullptr)
1151 bOwnActionNecessary
= true;
1153 else if (pHdl
->IsVertexHdl() || pHdl
->IsCornerHdl())
1155 bOwnActionNecessary
= true;
1159 bOwnActionNecessary
= false;
1162 if(bOwnActionNecessary
&& GetMarkedObjectCount() > 0)
1164 E3dDragConstraint eConstraint
= E3dDragConstraint::XYZ
;
1165 bool bThereAreRootScenes
= false;
1166 bool bThereAre3DObjects
= false;
1167 const size_t nCnt
= GetMarkedObjectCount();
1168 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
1170 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
1173 if( const E3dScene
* pScene
= DynCastE3dScene(pObj
) )
1174 if( pScene
->getRootE3dSceneFromE3dObject() == pObj
)
1175 bThereAreRootScenes
= true;
1177 if(DynCastE3dObject(pObj
))
1179 bThereAre3DObjects
= true;
1183 if( bThereAre3DObjects
)
1185 meDragHdl
= ( pHdl
== nullptr ? SdrHdlKind::Move
: pHdl
->GetKind() );
1186 switch ( meDragMode
)
1188 case SdrDragMode::Rotate
:
1189 case SdrDragMode::Shear
:
1191 switch ( meDragHdl
)
1193 case SdrHdlKind::Left
:
1194 case SdrHdlKind::Right
:
1196 eConstraint
= E3dDragConstraint::X
;
1200 case SdrHdlKind::Upper
:
1201 case SdrHdlKind::Lower
:
1203 eConstraint
= E3dDragConstraint::Y
;
1207 case SdrHdlKind::UpperLeft
:
1208 case SdrHdlKind::UpperRight
:
1209 case SdrHdlKind::LowerLeft
:
1210 case SdrHdlKind::LowerRight
:
1212 eConstraint
= E3dDragConstraint::Z
;
1218 // do not mask the allowed rotations
1219 eConstraint
&= E3dDragConstraint::XYZ
;
1220 pForcedMeth
= new E3dDragRotate(*this, GetMarkedObjectList(), eConstraint
, IsSolidDragging());
1224 case SdrDragMode::Move
:
1226 if(!bThereAreRootScenes
)
1228 pForcedMeth
= new E3dDragMove(*this, GetMarkedObjectList(), meDragHdl
, eConstraint
, IsSolidDragging());
1234 case SdrDragMode::Mirror
:
1235 case SdrDragMode::Crook
:
1236 case SdrDragMode::Transparence
:
1237 case SdrDragMode::Gradient
:
1246 return SdrView::BegDragObj(rPnt
, pOut
, pHdl
, nMinMov
, pForcedMeth
);
1249 // Set current 3D drawing object, create the scene for this
1250 rtl::Reference
<E3dScene
> E3dView::SetCurrent3DObj(E3dObject
* p3DObj
)
1252 DBG_ASSERT(p3DObj
!= nullptr, "Who puts in a NULL-pointer here");
1254 // get transformed BoundVolume of the object
1255 basegfx::B3DRange
aVolume(p3DObj
->GetBoundVolume());
1256 aVolume
.transform(p3DObj
->GetTransform());
1257 double fW(aVolume
.getWidth());
1258 double fH(aVolume
.getHeight());
1260 tools::Rectangle
aRect(0,0, static_cast<tools::Long
>(fW
), static_cast<tools::Long
>(fH
));
1262 rtl::Reference
<E3dScene
> pScene
= new E3dScene(p3DObj
->getSdrModelFromSdrObject());
1264 InitScene(pScene
.get(), fW
, fH
, aVolume
.getMaxZ() + ((fW
+ fH
) / 4.0));
1266 pScene
->InsertObject(p3DObj
);
1267 pScene
->NbcSetSnapRect(aRect
);
1272 void E3dView::InitScene(E3dScene
* pScene
, double fW
, double fH
, double fCamZ
)
1274 Camera3D
aCam(pScene
->GetCamera());
1276 aCam
.SetAutoAdjustProjection(false);
1277 aCam
.SetViewWindow(- fW
/ 2, - fH
/ 2, fW
, fH
);
1278 basegfx::B3DPoint aLookAt
;
1280 double fDefaultCamPosZ
= GetDefaultCamPosZ();
1281 basegfx::B3DPoint
aCamPos(0.0, 0.0, fCamZ
< fDefaultCamPosZ
? fDefaultCamPosZ
: fCamZ
);
1283 aCam
.SetPosAndLookAt(aCamPos
, aLookAt
);
1284 aCam
.SetFocalLength(GetDefaultCamFocal());
1285 pScene
->SetCamera(aCam
);
1288 void E3dView::Start3DCreation()
1290 if (!GetMarkedObjectCount())
1294 tools::Long nOutMin
= 0;
1295 tools::Long nOutMax
= 0;
1296 tools::Long nMinLen
= 0;
1297 tools::Long nObjDst
= 0;
1298 tools::Long nOutHgt
= 0;
1299 OutputDevice
* pOut
= GetFirstOutputDevice();
1301 // first determine representation boundaries
1302 if (pOut
!= nullptr)
1304 nMinLen
= pOut
->PixelToLogic(Size(0,50)).Height();
1305 nObjDst
= pOut
->PixelToLogic(Size(0,20)).Height();
1307 tools::Long nDst
= pOut
->PixelToLogic(Size(0,10)).Height();
1309 nOutMin
= -pOut
->GetMapMode().GetOrigin().Y();
1310 nOutMax
= pOut
->GetOutputSize().Height() - 1 + nOutMin
;
1314 if (nOutMax
- nOutMin
< nDst
)
1316 nOutMin
+= nOutMax
+ 1;
1318 nOutMin
-= (nDst
+ 1) / 2;
1319 nOutMax
= nOutMin
+ nDst
;
1322 nOutHgt
= nOutMax
- nOutMin
;
1324 tools::Long nTemp
= nOutHgt
/ 4;
1325 if (nTemp
> nMinLen
) nMinLen
= nTemp
;
1328 // and then attach the marks at the top and bottom of the object
1329 basegfx::B2DRange aR
;
1330 for(size_t nMark
= 0; nMark
< GetMarkedObjectCount(); ++nMark
)
1332 SdrObject
* pMark
= GetMarkedObjectByIndex(nMark
);
1333 basegfx::B2DPolyPolygon
aXPP(pMark
->TakeXorPoly());
1334 aR
.expand(basegfx::utils::getRange(aXPP
));
1337 basegfx::B2DPoint
aCenter(aR
.getCenter());
1338 tools::Long nMarkHgt
= basegfx::fround(aR
.getHeight()) - 1;
1339 tools::Long nHgt
= nMarkHgt
+ nObjDst
* 2;
1341 if (nHgt
< nMinLen
) nHgt
= nMinLen
;
1343 tools::Long nY1
= basegfx::fround(aCenter
.getY()) - (nHgt
+ 1) / 2;
1344 tools::Long nY2
= nY1
+ nHgt
;
1346 if (pOut
&& (nMinLen
> nOutHgt
)) nMinLen
= nOutHgt
;
1352 if (nY2
< nY1
+ nMinLen
) nY2
= nY1
+ nMinLen
;
1357 if (nY1
> nY2
- nMinLen
) nY1
= nY2
- nMinLen
;
1361 maRef1
.setX( basegfx::fround(aR
.getMinX()) ); // Initial move axis 2/100mm to the left
1363 maRef2
.setX( maRef1
.X() );
1367 SetMarkHandles(nullptr);
1369 //HMHif (bVis) ShowMarkHdl();
1370 if (AreObjectsMarked()) MarkListHasChanged();
1372 // Show mirror polygon IMMEDIATELY
1373 const SdrHdlList
&aHdlList
= GetHdlList();
1374 mpMirrorOverlay
.reset(new Impl3DMirrorConstructOverlay(*this));
1375 mpMirrorOverlay
->SetMirrorAxis(aHdlList
.GetHdl(SdrHdlKind::Ref1
)->GetPos(), aHdlList
.GetHdl(SdrHdlKind::Ref2
)->GetPos());
1378 // what happens with a mouse movement when the object is created?
1380 void E3dView::MovAction(const Point
& rPnt
)
1382 if(Is3DRotationCreationActive())
1384 SdrHdl
* pHdl
= GetDragHdl();
1388 SdrHdlKind eHdlKind
= pHdl
->GetKind();
1390 // reacts only due to a mirror axis
1391 if ((eHdlKind
== SdrHdlKind::Ref1
) ||
1392 (eHdlKind
== SdrHdlKind::Ref2
) ||
1393 (eHdlKind
== SdrHdlKind::MirrorAxis
))
1395 const SdrHdlList
&aHdlList
= GetHdlList ();
1397 // delete the mirrored polygon, mirrors the original and draws
1399 SdrView::MovAction (rPnt
);
1400 mpMirrorOverlay
->SetMirrorAxis(
1401 aHdlList
.GetHdl (SdrHdlKind::Ref1
)->GetPos(),
1402 aHdlList
.GetHdl (SdrHdlKind::Ref2
)->GetPos());
1407 SdrView::MovAction (rPnt
);
1412 SdrView::MovAction (rPnt
);
1416 // The End. Create object and any child objects through ImpCreate3DLathe.
1417 // With the parameter value sal_True (SDefault: sal_False) is simply a
1418 // rotation body created, without letting the user set the position of the
1419 // axis. It is sufficient with this call, if an object is selected.
1420 // (No initialization necessary)
1422 void E3dView::End3DCreation(bool bUseDefaultValuesForMirrorAxes
)
1424 ResetCreationActive();
1426 if(!AreObjectsMarked())
1429 if(bUseDefaultValuesForMirrorAxes
)
1431 tools::Rectangle aRect
= GetAllMarkedRect();
1432 if(aRect
.GetWidth() <= 1)
1433 aRect
.SetSize(Size(500, aRect
.GetHeight()));
1434 if(aRect
.GetHeight() <= 1)
1435 aRect
.SetSize(Size(aRect
.GetWidth(), 500));
1437 basegfx::B2DPoint
aPnt1(aRect
.Left(), -aRect
.Top());
1438 basegfx::B2DPoint
aPnt2(aRect
.Left(), -aRect
.Bottom());
1440 ConvertMarkedObjTo3D(false, aPnt1
, aPnt2
);
1444 // Turn off helper overlay
1445 // Determine from the handle positions and the displacement of
1447 const SdrHdlList
&aHdlList
= GetHdlList();
1448 Point aMirrorRef1
= aHdlList
.GetHdl(SdrHdlKind::Ref1
)->GetPos();
1449 Point aMirrorRef2
= aHdlList
.GetHdl(SdrHdlKind::Ref2
)->GetPos();
1451 basegfx::B2DPoint
aPnt1(aMirrorRef1
.X(), -aMirrorRef1
.Y());
1452 basegfx::B2DPoint
aPnt2(aMirrorRef2
.X(), -aMirrorRef2
.Y());
1454 ConvertMarkedObjTo3D(false, aPnt1
, aPnt2
);
1458 E3dView::~E3dView ()
1462 void E3dView::ResetCreationActive ()
1464 mpMirrorOverlay
.reset();
1467 void E3dView::InitView ()
1469 mpMirrorOverlay
= nullptr;
1472 bool E3dView::IsBreak3DObjPossible() const
1474 const size_t nCount
= GetMarkedObjectCount();
1478 for (size_t i
= 0; i
< nCount
; ++i
)
1480 SdrObject
* pObj
= GetMarkedObjectByIndex(i
);
1482 if (auto p3dObject
= DynCastE3dObject(pObj
))
1484 if(!p3dObject
->IsBreakObjPossible())
1501 void E3dView::Break3DObj()
1503 if(!IsBreak3DObjPossible())
1506 // ALL selected objects are changed
1507 const size_t nCount
= GetMarkedObjectCount();
1509 BegUndo(SvxResId(RID_SVX_3D_UNDO_BREAK_LATHE
));
1510 for(size_t a
=0; a
<nCount
; ++a
)
1512 E3dObject
* pObj
= static_cast<E3dObject
*>(GetMarkedObjectByIndex(a
));
1513 BreakSingle3DObj(pObj
);
1519 void E3dView::BreakSingle3DObj(E3dObject
* pObj
)
1521 if(DynCastE3dScene(pObj
))
1523 SdrObjList
* pSubList
= pObj
->GetSubList();
1524 SdrObjListIter
aIter(pSubList
, SdrIterMode::Flat
);
1526 while(aIter
.IsMore())
1528 E3dObject
* pSubObj
= static_cast<E3dObject
*>(aIter
.Next());
1529 BreakSingle3DObj(pSubObj
);
1534 rtl::Reference
<SdrAttrObj
> pNewObj
= pObj
->GetBreakObj();
1537 if (InsertObjectAtView(pNewObj
.get(), *GetSdrPageView(), SdrInsertFlags::DONTMARK
))
1539 pNewObj
->SetChanged();
1540 pNewObj
->BroadcastObjectChange();
1546 void E3dView::CheckPossibilities()
1549 SdrView::CheckPossibilities();
1552 if(!(m_bGroupPossible
|| m_bUnGroupPossible
|| m_bGrpEnterPossible
))
1555 const size_t nMarkCnt
= GetMarkedObjectCount();
1556 bool bCompound
= false;
1557 bool b3DObject
= false;
1558 for(size_t nObjs
= 0; (nObjs
< nMarkCnt
) && !bCompound
; ++nObjs
)
1560 SdrObject
*pObj
= GetMarkedObjectByIndex(nObjs
);
1561 if(dynamic_cast< const E3dCompoundObject
* >(pObj
))
1563 if(DynCastE3dObject(pObj
))
1567 // So far: there are two or more of any objects selected. See if
1568 // compound objects are involved. If yes, ban grouping.
1569 if(m_bGroupPossible
&& bCompound
)
1570 m_bGroupPossible
= false;
1572 if(m_bUnGroupPossible
&& b3DObject
)
1573 m_bUnGroupPossible
= false;
1575 if(m_bGrpEnterPossible
&& bCompound
)
1576 m_bGrpEnterPossible
= false;
1579 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */