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
)
93 const SdrMarkList
& rMarkList
= mrView
.GetMarkedObjectList();
94 mnCount
= rMarkList
.GetMarkCount();
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
= rMarkList
.GetMark(a
)->GetMarkedSdrObj();
110 // use the view-independent primitive representation (without
111 // evtl. GridOffset, that may be applied to the DragEntry individually)
112 pObject
->GetViewContact().getViewIndependentPrimitive2DContainer(maFullOverlay
);
119 mpPolygons
= new basegfx::B2DPolyPolygon
[mnCount
];
121 for(size_t a
= 0; a
< mnCount
; ++a
)
123 SdrObject
* pObject
= rMarkList
.GetMark(a
)->GetMarkedSdrObj();
124 mpPolygons
[mnCount
- (a
+ 1)] = pObject
->TakeXorPoly();
129 Impl3DMirrorConstructOverlay::~Impl3DMirrorConstructOverlay()
131 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
132 // That destructor calls clear() at the list which removes all objects from the
133 // OverlayManager and deletes them.
137 void Impl3DMirrorConstructOverlay::SetMirrorAxis(Point aMirrorAxisA
, Point aMirrorAxisB
)
139 // get rid of old overlay objects
143 for(sal_uInt32
a(0); a
< mrView
.PaintWindowCount(); a
++)
145 SdrPaintWindow
* pCandidate
= mrView
.GetPaintWindow(a
);
146 const rtl::Reference
< sdr::overlay::OverlayManager
>& xTargetOverlay
= pCandidate
->GetOverlayManager();
148 if(xTargetOverlay
.is())
150 // build transformation: translate and rotate so that given edge is
151 // on x axis, them mirror in y and translate back
152 const basegfx::B2DVector
aEdge(aMirrorAxisB
.X() - aMirrorAxisA
.X(), aMirrorAxisB
.Y() - aMirrorAxisA
.Y());
153 basegfx::B2DHomMatrix
aMatrixTransform(basegfx::utils::createTranslateB2DHomMatrix(
154 -aMirrorAxisA
.X(), -aMirrorAxisA
.Y()));
155 aMatrixTransform
.rotate(-atan2(aEdge
.getY(), aEdge
.getX()));
156 aMatrixTransform
.scale(1.0, -1.0);
157 aMatrixTransform
.rotate(atan2(aEdge
.getY(), aEdge
.getX()));
158 aMatrixTransform
.translate(aMirrorAxisA
.X(), aMirrorAxisA
.Y());
160 if(mrView
.IsSolidDragging())
162 if(!maFullOverlay
.empty())
164 drawinglayer::primitive2d::Primitive2DContainer
aContent(maFullOverlay
);
166 if(!aMatrixTransform
.isIdentity())
168 // embed in transformation group
169 aContent
= drawinglayer::primitive2d::Primitive2DContainer
{
170 new drawinglayer::primitive2d::TransformPrimitive2D(aMatrixTransform
, std::move(aContent
))
174 // if we have full overlay from selected objects, embed with 50% transparence, the
175 // transformation is added to the OverlayPrimitive2DSequenceObject
176 aContent
= drawinglayer::primitive2d::Primitive2DContainer
{
177 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aContent
), 0.5)
180 std::unique_ptr
<sdr::overlay::OverlayPrimitive2DSequenceObject
> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(std::move(aContent
)));
182 xTargetOverlay
->add(*pNew
);
183 maObjects
.append(std::move(pNew
));
188 for(size_t b
= 0; b
< mnCount
; ++b
)
191 basegfx::B2DPolyPolygon
aPolyPolygon(mpPolygons
[b
]);
192 aPolyPolygon
.transform(aMatrixTransform
);
194 std::unique_ptr
<sdr::overlay::OverlayPolyPolygonStripedAndFilled
> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
195 std::move(aPolyPolygon
)));
196 xTargetOverlay
->add(*pNew
);
197 maObjects
.append(std::move(pNew
));
207 : SdrView(rSdrModel
, pOut
)
212 // DrawMarkedObj override, since possibly only a single 3D object is to be
215 void E3dView::DrawMarkedObj(OutputDevice
& rOut
) const
217 // Does 3D objects exist which scenes are not selected?
218 bool bSpecialHandling
= false;
219 E3dScene
*pScene
= nullptr;
221 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
222 const size_t nCnt
= rMarkList
.GetMarkCount();
223 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
225 SdrObject
*pObj
= rMarkList
.GetMark(nObjs
)->GetMarkedSdrObj();
226 if(auto pCompoundObject
= dynamic_cast<E3dCompoundObject
*>(pObj
))
229 pScene
= pCompoundObject
->getRootE3dSceneFromE3dObject();
231 if(nullptr != pScene
&& !IsObjMarked(pScene
))
233 bSpecialHandling
= true;
236 // Reset all selection flags
237 if(auto p3dObject
= DynCastE3dObject(pObj
))
239 pScene
= p3dObject
->getRootE3dSceneFromE3dObject();
241 if(nullptr != pScene
)
243 pScene
->SetSelected(false);
250 // Set selection flag to "not selected" for scenes related to all 3D
252 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
254 SdrObject
*pObj
= rMarkList
.GetMark(nObjs
)->GetMarkedSdrObj();
255 if(auto pCompoundObject
= dynamic_cast<E3dCompoundObject
*>(pObj
))
258 pScene
= pCompoundObject
->getRootE3dSceneFromE3dObject();
260 if(nullptr != pScene
)
262 pScene
->SetSelected(false);
267 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
269 SdrObject
*pObj
= rMarkList
.GetMark(nObjs
)->GetMarkedSdrObj();
270 if(auto p3DObj
= DynCastE3dObject(pObj
))
273 p3DObj
->SetSelected(true);
274 pScene
= p3DObj
->getRootE3dSceneFromE3dObject();
278 if(nullptr != pScene
)
281 rMarkList
.ForceSort();
283 pScene
->SetDrawOnlySelected(true);
284 pScene
->SingleObjectPainter(rOut
);
285 pScene
->SetDrawOnlySelected(false);
288 // Reset selection flag
289 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
291 SdrObject
*pObj
= rMarkList
.GetMark(nObjs
)->GetMarkedSdrObj();
292 if(auto pCompoundObject
= dynamic_cast<E3dCompoundObject
*>(pObj
))
295 pScene
= pCompoundObject
->getRootE3dSceneFromE3dObject();
297 if(nullptr != pScene
)
299 pScene
->SetSelected(false);
307 SdrExchangeView::DrawMarkedObj(rOut
);
311 // override get model, since in some 3D objects an additional scene
314 std::unique_ptr
<SdrModel
> E3dView::CreateMarkedObjModel() const
316 // Does 3D objects exist which scenes are not selected?
317 bool bSpecialHandling(false);
318 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
319 const size_t nCount(rMarkList
.GetMarkCount());
320 E3dScene
*pScene
= nullptr;
322 for(size_t nObjs
= 0; nObjs
< nCount
; ++nObjs
)
324 const SdrObject
* pObj
= rMarkList
.GetMark(nObjs
)->GetMarkedSdrObj();
326 if(!bSpecialHandling
)
327 if(auto pCompoundObj
= dynamic_cast< const E3dCompoundObject
*>(pObj
))
329 // if the object is selected, but it's scene not,
330 // we need special handling
331 pScene
= pCompoundObj
->getRootE3dSceneFromE3dObject();
333 if(nullptr != pScene
&& !IsObjMarked(pScene
))
335 bSpecialHandling
= true;
339 if(auto p3dObject
= DynCastE3dObject(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
= rMarkList
.GetMark(nObjs
)->GetMarkedSdrObj();
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(rMarkList
);
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
= DynCastE3dObject(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
);
406 for (const rtl::Reference
<SdrObject
>& pSrcOb
: *pSrcPg
)
408 if(const E3dScene
* p3dscene
= DynCastE3dScene( pSrcOb
.get()))
410 pScene
= const_cast<E3dScene
*>(p3dscene
);
412 // delete all not intentionally cloned 3d objects
413 pScene
->removeAllNonSelectedObjects();
415 // reset select flags and set SnapRect of all selected objects
416 pScene
->SetSelected(false);
417 pScene
->SetSnapRect(aSelectedSnapRect
);
423 // restore old selection
424 rCurrentMarkList
= aOldML
;
429 // When pasting objects have to integrated if a scene is inserted, but
430 // not the scene itself
433 const SdrModel
& rMod
, const Point
& rPos
, SdrObjList
* pLst
, SdrInsertFlags nOptions
)
435 bool bRetval
= false;
439 SdrObjList
* pDstList
= pLst
;
440 ImpGetPasteObjList(aPos
, pDstList
);
445 // Get owner of the list
446 E3dScene
* pDstScene(DynCastE3dScene(pDstList
->getSdrObjectFromSdrObjList()));
448 if(nullptr != pDstScene
)
450 BegUndo(SvxResId(RID_SVX_3D_UNDO_EXCHANGE_PASTE
));
452 // Copy all objects from E3dScenes and insert them directly
453 for(sal_uInt16
nPg(0); nPg
< rMod
.GetPageCount(); nPg
++)
455 const SdrPage
* pSrcPg
=rMod
.GetPage(nPg
);
457 // calculate offset for paste
458 tools::Rectangle aR
= pSrcPg
->GetAllObjBoundRect();
459 Point
aDist(aPos
- aR
.Center());
461 // Insert sub-objects for scenes
462 for (const rtl::Reference
<SdrObject
>& pSrcOb
: *pSrcPg
)
464 if(const E3dScene
* p3dscene
= DynCastE3dScene(pSrcOb
.get()))
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 (const rtl::Reference
<SdrObject
>& pObj
: *pSrcScene
->GetSubList())
491 E3dCompoundObject
* pCompoundObj
= dynamic_cast< E3dCompoundObject
* >(pObj
.get());
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 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
592 for(size_t a
=0; !bAny3D
&& a
<rMarkList
.GetMarkCount(); ++a
)
594 SdrObject
*pObj
= rMarkList
.GetMark(a
)->GetMarkedSdrObj();
597 ImpIsConvertTo3DPossible(pObj
, bAny3D
, bGroupSelected
);
603 IsConvertToPolyObjPossible()
604 || IsConvertToPathObjPossible()
605 || IsImportMtfPossible());
609 void E3dView::ImpIsConvertTo3DPossible(SdrObject
const * pObj
, bool& rAny3D
,
610 bool& rGroupSelected
) const
615 if(DynCastE3dObject(pObj
))
621 if(pObj
->IsGroupObject())
623 SdrObjListIter
aIter(*pObj
, SdrIterMode::DeepNoGroups
);
624 while(aIter
.IsMore())
626 SdrObject
* pNewObj
= aIter
.Next();
627 ImpIsConvertTo3DPossible(pNewObj
, rAny3D
, rGroupSelected
);
629 rGroupSelected
= true;
634 void E3dView::ImpChangeSomeAttributesFor3DConversion(SdrObject
* pObj
)
636 if(DynCastSdrTextObj( pObj
) == nullptr)
639 const SfxItemSet
& rSet
= pObj
->GetMergedItemSet();
640 const SvxColorItem
& rTextColorItem
= rSet
.Get(EE_CHAR_COLOR
);
641 if(rTextColorItem
.GetValue() != COL_BLACK
)
644 //For black text objects, the color set to gray
645 if(pObj
->getSdrPageFromSdrObject())
647 // if black is only default attribute from
648 // pattern set it hard so that it is used in undo.
649 pObj
->SetMergedItem(SvxColorItem(COL_BLACK
, EE_CHAR_COLOR
));
652 if (GetModel().IsUndoEnabled())
653 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj
));
656 pObj
->SetMergedItem(SvxColorItem(COL_GRAY
, EE_CHAR_COLOR
));
659 void E3dView::ImpChangeSomeAttributesFor3DConversion2(SdrObject
* pObj
)
661 auto pPathObj
= dynamic_cast<const SdrPathObj
*>( pObj
);
665 const SfxItemSet
& rSet
= pObj
->GetMergedItemSet();
666 sal_Int32 nLineWidth
= rSet
.Get(XATTR_LINEWIDTH
).GetValue();
667 drawing::LineStyle eLineStyle
= rSet
.Get(XATTR_LINESTYLE
).GetValue();
668 drawing::FillStyle eFillStyle
= rSet
.Get(XATTR_FILLSTYLE
).GetValue();
670 if(pPathObj
->IsClosed()
671 && eLineStyle
== drawing::LineStyle_SOLID
673 && eFillStyle
!= drawing::FillStyle_NONE
)
675 if (pObj
->getSdrPageFromSdrObject() && GetModel().IsUndoEnabled())
677 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj
));
680 pObj
->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE
));
681 pObj
->SetMergedItem(XLineWidthItem(0));
685 void E3dView::ImpCreateSingle3DObjectFlat(E3dScene
* pScene
, SdrObject
* pObj
, bool bExtrude
, double fDepth
, basegfx::B2DHomMatrix
const & rLatheMat
)
687 // Single PathObject, transform this
688 SdrPathObj
* pPath
= dynamic_cast<SdrPathObj
*>( pObj
);
693 E3dDefaultAttributes aDefault
= Get3DDefaultAttributes();
697 aDefault
.SetDefaultExtrudeCharacterMode(true);
701 aDefault
.SetDefaultLatheCharacterMode(true);
704 // Get Itemset of the original object
705 SfxItemSet
aSet(pObj
->GetMergedItemSet());
707 drawing::FillStyle eFillStyle
= aSet
.Get(XATTR_FILLSTYLE
).GetValue();
709 // line style turned off
710 aSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
712 //Determining if FILL_Attribute is set.
713 if(!pPath
->IsClosed() || eFillStyle
== drawing::FillStyle_NONE
)
715 // This SdrPathObj is not filled, leave the front and rear face out.
716 // Moreover, a two-sided representation necessary.
717 aDefault
.SetDefaultExtrudeCloseFront(false);
718 aDefault
.SetDefaultExtrudeCloseBack(false);
720 aSet
.Put(makeSvx3DDoubleSidedItem(true));
722 // Set fill attribute
723 aSet
.Put(XFillStyleItem(drawing::FillStyle_SOLID
));
725 // Fill color must be the color line, because the object was
726 // previously just a line
727 Color aColorLine
= aSet
.Get(XATTR_LINECOLOR
).GetColorValue();
728 aSet
.Put(XFillColorItem(OUString(), aColorLine
));
731 // Create a new extrude object
732 rtl::Reference
<E3dObject
> p3DObj
;
735 p3DObj
= new E3dExtrudeObj(pObj
->getSdrModelFromSdrObject(), aDefault
, pPath
->GetPathPoly(), fDepth
);
739 // rLatheMat expects coordinates with y-axis up, pPath uses y-axis down
740 basegfx::B2DHomMatrix
aFlipVerticalMat(1.0, 0.0, 0.0, 0.0, -1.0, 0.0);
741 basegfx::B2DPolyPolygon
aPolyPoly2D(pPath
->GetPathPoly());
742 aPolyPoly2D
.transform(aFlipVerticalMat
);
743 aPolyPoly2D
.transform(rLatheMat
);
744 // ctor E3dLatheObj expects coordinates with y-axis down
745 aPolyPoly2D
.transform(aFlipVerticalMat
);
746 p3DObj
= new E3dLatheObj(pObj
->getSdrModelFromSdrObject(), aDefault
, std::move(aPolyPoly2D
));
750 p3DObj
->NbcSetLayer(pObj
->GetLayer());
752 p3DObj
->SetMergedItemSet(aSet
);
754 p3DObj
->NbcSetStyleSheet(pObj
->GetStyleSheet(), true);
756 // Insert a new extrude object
757 pScene
->InsertObject(p3DObj
.get());
760 void E3dView::ImpCreate3DObject(E3dScene
* pScene
, SdrObject
* pObj
, bool bExtrude
, double fDepth
, basegfx::B2DHomMatrix
const & rLatheMat
)
765 // change text color attribute for not so dark colors
766 if(pObj
->IsGroupObject())
768 SdrObjListIter
aIter(*pObj
, SdrIterMode::DeepWithGroups
);
769 while(aIter
.IsMore())
771 SdrObject
* pGroupMember
= aIter
.Next();
772 ImpChangeSomeAttributesFor3DConversion(pGroupMember
);
776 ImpChangeSomeAttributesFor3DConversion(pObj
);
778 // convert completely to path objects
779 rtl::Reference
<SdrObject
> pNewObj1
= pObj
->ConvertToPolyObj(false, false);
784 // change text color attribute for not so dark colors
785 if(pNewObj1
->IsGroupObject())
787 SdrObjListIter
aIter(*pNewObj1
, SdrIterMode::DeepWithGroups
);
788 while(aIter
.IsMore())
790 SdrObject
* pGroupMember
= aIter
.Next();
791 ImpChangeSomeAttributesFor3DConversion2(pGroupMember
);
795 ImpChangeSomeAttributesFor3DConversion2(pNewObj1
.get());
797 // convert completely to path objects
798 rtl::Reference
<SdrObject
> pNewObj2
= pObj
->ConvertToContourObj(pNewObj1
.get(), true);
802 // add all to flat scene
803 if(pNewObj2
->IsGroupObject())
805 SdrObjListIter
aIter(*pNewObj2
, SdrIterMode::DeepWithGroups
);
806 while(aIter
.IsMore())
808 SdrObject
* pGroupMember
= aIter
.Next();
809 ImpCreateSingle3DObjectFlat(pScene
, pGroupMember
, bExtrude
, fDepth
, rLatheMat
);
813 ImpCreateSingle3DObjectFlat(pScene
, pNewObj2
.get(), bExtrude
, fDepth
, rLatheMat
);
817 void E3dView::ConvertMarkedObjTo3D(bool bExtrude
, const basegfx::B2DPoint
& rPnt1
, const basegfx::B2DPoint
& rPnt2
)
819 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
820 if(rMarkList
.GetMarkCount() == 0)
825 BegUndo(SvxResId(RID_SVX_3D_UNDO_EXTRUDE
));
827 BegUndo(SvxResId(RID_SVX_3D_UNDO_LATHE
));
829 SdrModel
& rSdrModel(rMarkList
.GetMark(0)->GetMarkedSdrObj()->getSdrModelFromSdrObject());
831 // Create a new scene for the created 3D object
832 rtl::Reference
<E3dScene
> pScene
= new E3dScene(rSdrModel
);
834 // Determine rectangle and possibly correct it
835 tools::Rectangle aRect
= GetAllMarkedRect();
836 if(aRect
.GetWidth() <= 1)
837 aRect
.SetSize(Size(500, aRect
.GetHeight()));
838 if(aRect
.GetHeight() <= 1)
839 aRect
.SetSize(Size(aRect
.GetWidth(), 500));
841 // Determine the depth relative to the size of the selection
844 basegfx::B2DHomMatrix aLatheMat
;
848 fDepth
= std::hypot(aRect
.GetWidth(), aRect
.GetHeight()) / 6.0;
852 // Create transformation for the polygons rotating body
855 // Rotation around control point #1 with set angle
856 // for 3D coordinates
857 basegfx::B2DPoint
aDiff(rPnt1
- rPnt2
);
858 fRot3D
= atan2(aDiff
.getY(), aDiff
.getX()) - M_PI_2
;
860 if(basegfx::fTools::equalZero(fabs(fRot3D
)))
865 aLatheMat
= basegfx::utils::createRotateAroundPoint(rPnt2
, -fRot3D
)
870 if (rPnt2
.getX() != 0.0)
872 // Translation to Y=0 - axis
873 aLatheMat
.translate(-rPnt2
.getX(), 0.0);
877 aLatheMat
.translate(static_cast<double>(-aRect
.Left()), 0.0);
880 // Form the inverse matrix to determine the target expansion
881 basegfx::B2DHomMatrix
aInvLatheMat(aLatheMat
);
882 aInvLatheMat
.invert();
884 // SnapRect extension enables mirroring in the axis of rotation
885 for(size_t a
=0; a
<rMarkList
.GetMarkCount(); ++a
)
887 SdrMark
* pMark
= rMarkList
.GetMark(a
);
888 SdrObject
* pObj
= pMark
->GetMarkedSdrObj();
889 tools::Rectangle aTurnRect
= pObj
->GetSnapRect();
890 basegfx::B2DPoint aRot
;
893 aRot
= basegfx::B2DPoint(aTurnRect
.Left(), -aTurnRect
.Top());
895 aRot
.setX(-aRot
.getX());
896 aRot
*= aInvLatheMat
;
897 aRotPnt
= Point(static_cast<tools::Long
>(aRot
.getX() + 0.5), static_cast<tools::Long
>(-aRot
.getY() - 0.5));
898 aRect
.Union(tools::Rectangle(aRotPnt
, aRotPnt
));
900 aRot
= basegfx::B2DPoint(aTurnRect
.Left(), -aTurnRect
.Bottom());
902 aRot
.setX(-aRot
.getX());
903 aRot
*= aInvLatheMat
;
904 aRotPnt
= Point(static_cast<tools::Long
>(aRot
.getX() + 0.5), static_cast<tools::Long
>(-aRot
.getY() - 0.5));
905 aRect
.Union(tools::Rectangle(aRotPnt
, aRotPnt
));
907 aRot
= basegfx::B2DPoint(aTurnRect
.Right(), -aTurnRect
.Top());
909 aRot
.setX(-aRot
.getX());
910 aRot
*= aInvLatheMat
;
911 aRotPnt
= Point(static_cast<tools::Long
>(aRot
.getX() + 0.5), static_cast<tools::Long
>(-aRot
.getY() - 0.5));
912 aRect
.Union(tools::Rectangle(aRotPnt
, aRotPnt
));
914 aRot
= basegfx::B2DPoint(aTurnRect
.Right(), -aTurnRect
.Bottom());
916 aRot
.setX(-aRot
.getX());
917 aRot
*= aInvLatheMat
;
918 aRotPnt
= Point(static_cast<tools::Long
>(aRot
.getX() + 0.5), static_cast<tools::Long
>(-aRot
.getY() - 0.5));
919 aRect
.Union(tools::Rectangle(aRotPnt
, aRotPnt
));
923 // Walk through the selection and convert it into 3D, complete with
924 // Conversion to SdrPathObject, also fonts
925 for(size_t a
=0; a
<rMarkList
.GetMarkCount(); ++a
)
927 SdrMark
* pMark
= rMarkList
.GetMark(a
);
928 SdrObject
* pObj
= pMark
->GetMarkedSdrObj();
930 ImpCreate3DObject(pScene
.get(), pObj
, bExtrude
, fDepth
, aLatheMat
);
933 if(pScene
->GetSubList() && pScene
->GetSubList()->GetObjCount() != 0)
935 // Arrange all created objects by depth
937 DoDepthArrange(pScene
.get(), fDepth
);
939 // Center 3D objects in the middle of the overall rectangle
940 basegfx::B3DPoint
aCenter(pScene
->GetBoundVolume().getCenter());
941 basegfx::B3DHomMatrix aMatrix
;
943 aMatrix
.translate(-aCenter
.getX(), -aCenter
.getY(), -aCenter
.getZ());
944 pScene
->SetTransform(aMatrix
* pScene
->GetTransform());
947 pScene
->NbcSetSnapRect(aRect
);
948 basegfx::B3DRange aBoundVol
= pScene
->GetBoundVolume();
949 InitScene(pScene
.get(), static_cast<double>(aRect
.GetWidth()), static_cast<double>(aRect
.GetHeight()), aBoundVol
.getDepth());
951 // Insert scene instead of the first selected object and throw away
952 // all the old objects
953 SdrMark
* pMark
= rMarkList
.GetMark(0);
956 SdrObject
* pRepObj
= pMark
->GetMarkedSdrObj();
957 SdrPageView
* pPV
= pMark
->GetPageView();
958 MarkObj(pRepObj
, pPV
, true);
959 ReplaceObjectAtView(pRepObj
, *pPV
, pScene
.get(), false);
961 MarkObj(pScene
.get(), pPV
);
964 // Rotate Rotation body around the axis of rotation
965 if(!bExtrude
&& fRot3D
!= 0.0)
967 basegfx::B3DHomMatrix aRotate
;
968 aRotate
.rotate(0.0, 0.0, fRot3D
);
969 pScene
->SetTransform(aRotate
* pScene
->GetTransform());
972 // Set default rotation
974 basegfx::B3DHomMatrix aRotate
;
975 aRotate
.rotate(basegfx::deg2rad(20.0), 0.0, 0.0);
976 // E3DModifySceneSnapRectUpdater updates the 2D representation of the scene.
977 // It prepares things in ctor and acts in dtor.
978 E3DModifySceneSnapRectUpdater
aUpdater(pScene
->getSdrObjectFromSdrObjList());
979 pScene
->SetTransform(aRotate
* pScene
->GetTransform());
988 //Arrange all created extrude objects by depth
992 struct E3dDepthNeighbour
994 E3dExtrudeObj
* mpObj
;
995 basegfx::B2DPolyPolygon maPreparedPolyPolygon
;
997 E3dDepthNeighbour(E3dExtrudeObj
* pObj
, basegfx::B2DPolyPolygon aPreparedPolyPolygon
)
999 maPreparedPolyPolygon(std::move(aPreparedPolyPolygon
))
1004 struct E3dDepthLayer
1006 E3dDepthLayer
* mpDown
;
1007 std::vector
<E3dDepthNeighbour
> mvNeighbours
;
1017 void E3dView::DoDepthArrange(E3dScene
const * pScene
, double fDepth
)
1019 if(!(pScene
&& pScene
->GetSubList() && pScene
->GetSubList()->GetObjCount() > 1))
1022 SdrObjList
* pSubList
= pScene
->GetSubList();
1023 SdrObjListIter
aIter(pSubList
, SdrIterMode::Flat
);
1024 E3dDepthLayer
* pBaseLayer
= nullptr;
1025 E3dDepthLayer
* pLayer
= nullptr;
1026 sal_Int32 nNumLayers
= 0;
1028 while(aIter
.IsMore())
1030 E3dExtrudeObj
* pExtrudeObj
= dynamic_cast< E3dExtrudeObj
* >(aIter
.Next());
1034 const basegfx::B2DPolyPolygon
aExtrudePoly(
1035 basegfx::utils::prepareForPolygonOperation(pExtrudeObj
->GetExtrudePolygon()));
1036 const SfxItemSet
& rLocalSet
= pExtrudeObj
->GetMergedItemSet();
1037 const drawing::FillStyle eLocalFillStyle
= rLocalSet
.Get(XATTR_FILLSTYLE
).GetValue();
1038 const Color aLocalColor
= rLocalSet
.Get(XATTR_FILLCOLOR
).GetColorValue();
1040 // sort in ExtrudeObj
1043 // do we have overlap with an object of this layer?
1044 bool bOverlap(false);
1046 for(const auto& rAct
: pLayer
->mvNeighbours
)
1048 // do rAct.mpObj and pExtrudeObj overlap? Check by
1049 // using logical AND clipping
1050 const basegfx::B2DPolyPolygon
aAndPolyPolygon(
1051 basegfx::utils::solvePolygonOperationAnd(
1053 rAct
.maPreparedPolyPolygon
));
1055 if(aAndPolyPolygon
.count() != 0)
1057 // second criteria: is another fillstyle or color used?
1058 const SfxItemSet
& rCompareSet
= rAct
.mpObj
->GetMergedItemSet();
1060 drawing::FillStyle eCompareFillStyle
= rCompareSet
.Get(XATTR_FILLSTYLE
).GetValue();
1062 if(eLocalFillStyle
== eCompareFillStyle
)
1064 if(eLocalFillStyle
== drawing::FillStyle_SOLID
)
1066 Color aCompareColor
= rCompareSet
.Get(XATTR_FILLCOLOR
).GetColorValue();
1068 if(aCompareColor
== aLocalColor
)
1073 else if(eLocalFillStyle
== drawing::FillStyle_NONE
)
1086 // yes, start a new layer
1087 pLayer
->mpDown
= new E3dDepthLayer
;
1088 pLayer
= pLayer
->mpDown
;
1090 pLayer
->mvNeighbours
.emplace_back(pExtrudeObj
, aExtrudePoly
);
1094 // no, add to current layer
1095 pLayer
->mvNeighbours
.emplace(pLayer
->mvNeighbours
.begin(), pExtrudeObj
, aExtrudePoly
);
1101 pBaseLayer
= new E3dDepthLayer
;
1102 pLayer
= pBaseLayer
;
1104 pLayer
->mvNeighbours
.emplace_back(pExtrudeObj
, aExtrudePoly
);
1109 // number of layers is done
1112 // need to be arranged
1113 double fMinDepth
= fDepth
* 0.8;
1114 double fStep
= (fDepth
- fMinDepth
) / static_cast<double>(nNumLayers
);
1115 pLayer
= pBaseLayer
;
1120 for(auto& rAct
: pLayer
->mvNeighbours
)
1122 // adapt extrude value
1123 rAct
.mpObj
->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH
, sal_uInt32(fMinDepth
+ 0.5)));
1127 pLayer
= pLayer
->mpDown
;
1135 pLayer
= pBaseLayer
->mpDown
;
1137 pBaseLayer
= pLayer
;
1141 // Start drag, create for 3D objects before possibly drag method
1143 bool E3dView::BegDragObj(const Point
& rPnt
, OutputDevice
* pOut
,
1144 SdrHdl
* pHdl
, short nMinMov
,
1145 SdrDragMethod
* pForcedMeth
)
1147 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1148 if(Is3DRotationCreationActive() && rMarkList
.GetMarkCount())
1150 // Determine all selected polygons and return the mirrored helper overlay
1151 mpMirrorOverlay
->SetMirrorAxis(maRef1
, maRef2
);
1155 bool bOwnActionNecessary
;
1156 if (pHdl
== nullptr)
1158 bOwnActionNecessary
= true;
1160 else if (pHdl
->IsVertexHdl() || pHdl
->IsCornerHdl())
1162 bOwnActionNecessary
= true;
1166 bOwnActionNecessary
= false;
1169 if(bOwnActionNecessary
&& rMarkList
.GetMarkCount() > 0)
1171 E3dDragConstraint eConstraint
= E3dDragConstraint::XYZ
;
1172 bool bThereAreRootScenes
= false;
1173 bool bThereAre3DObjects
= false;
1174 const size_t nCnt
= rMarkList
.GetMarkCount();
1175 for(size_t nObjs
= 0; nObjs
< nCnt
; ++nObjs
)
1177 SdrObject
*pObj
= rMarkList
.GetMark(nObjs
)->GetMarkedSdrObj();
1180 if( const E3dScene
* pScene
= DynCastE3dScene(pObj
) )
1181 if( pScene
->getRootE3dSceneFromE3dObject() == pObj
)
1182 bThereAreRootScenes
= true;
1184 if(DynCastE3dObject(pObj
))
1186 bThereAre3DObjects
= true;
1190 if( bThereAre3DObjects
)
1192 meDragHdl
= ( pHdl
== nullptr ? SdrHdlKind::Move
: pHdl
->GetKind() );
1193 switch ( meDragMode
)
1195 case SdrDragMode::Rotate
:
1196 case SdrDragMode::Shear
:
1198 switch ( meDragHdl
)
1200 case SdrHdlKind::Left
:
1201 case SdrHdlKind::Right
:
1203 eConstraint
= E3dDragConstraint::X
;
1207 case SdrHdlKind::Upper
:
1208 case SdrHdlKind::Lower
:
1210 eConstraint
= E3dDragConstraint::Y
;
1214 case SdrHdlKind::UpperLeft
:
1215 case SdrHdlKind::UpperRight
:
1216 case SdrHdlKind::LowerLeft
:
1217 case SdrHdlKind::LowerRight
:
1219 eConstraint
= E3dDragConstraint::Z
;
1225 // do not mask the allowed rotations
1226 eConstraint
&= E3dDragConstraint::XYZ
;
1227 pForcedMeth
= new E3dDragRotate(*this, rMarkList
, eConstraint
, IsSolidDragging());
1231 case SdrDragMode::Move
:
1233 if(!bThereAreRootScenes
)
1235 pForcedMeth
= new E3dDragMove(*this, rMarkList
, meDragHdl
, eConstraint
, IsSolidDragging());
1241 case SdrDragMode::Mirror
:
1242 case SdrDragMode::Crook
:
1243 case SdrDragMode::Transparence
:
1244 case SdrDragMode::Gradient
:
1253 return SdrView::BegDragObj(rPnt
, pOut
, pHdl
, nMinMov
, pForcedMeth
);
1256 // Set current 3D drawing object, create the scene for this
1257 rtl::Reference
<E3dScene
> E3dView::SetCurrent3DObj(E3dObject
* p3DObj
)
1259 assert(p3DObj
!= nullptr && "Who puts in a NULL-pointer here");
1261 // get transformed BoundVolume of the object
1262 basegfx::B3DRange
aVolume(p3DObj
->GetBoundVolume());
1263 aVolume
.transform(p3DObj
->GetTransform());
1264 double fW(aVolume
.getWidth());
1265 double fH(aVolume
.getHeight());
1267 tools::Rectangle
aRect(0,0, static_cast<tools::Long
>(fW
), static_cast<tools::Long
>(fH
));
1269 rtl::Reference
<E3dScene
> pScene
= new E3dScene(p3DObj
->getSdrModelFromSdrObject());
1271 InitScene(pScene
.get(), fW
, fH
, aVolume
.getMaxZ() + ((fW
+ fH
) / 4.0));
1273 pScene
->InsertObject(p3DObj
);
1274 pScene
->NbcSetSnapRect(aRect
);
1279 void E3dView::InitScene(E3dScene
* pScene
, double fW
, double fH
, double fCamZ
)
1281 Camera3D
aCam(pScene
->GetCamera());
1283 aCam
.SetAutoAdjustProjection(false);
1284 aCam
.SetViewWindow(- fW
/ 2, - fH
/ 2, fW
, fH
);
1285 basegfx::B3DPoint aLookAt
;
1287 double fDefaultCamPosZ
= GetDefaultCamPosZ();
1288 basegfx::B3DPoint
aCamPos(0.0, 0.0, fCamZ
< fDefaultCamPosZ
? fDefaultCamPosZ
: fCamZ
);
1290 aCam
.SetPosAndLookAt(aCamPos
, aLookAt
);
1291 aCam
.SetFocalLength(GetDefaultCamFocal());
1292 pScene
->SetCamera(aCam
);
1295 void E3dView::Start3DCreation()
1297 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1298 if (!rMarkList
.GetMarkCount())
1302 tools::Long nOutMin
= 0;
1303 tools::Long nOutMax
= 0;
1304 tools::Long nMinLen
= 0;
1305 tools::Long nObjDst
= 0;
1306 tools::Long nOutHgt
= 0;
1307 OutputDevice
* pOut
= GetFirstOutputDevice();
1309 // first determine representation boundaries
1310 if (pOut
!= nullptr)
1312 nMinLen
= pOut
->PixelToLogic(Size(0,50)).Height();
1313 nObjDst
= pOut
->PixelToLogic(Size(0,20)).Height();
1315 tools::Long nDst
= pOut
->PixelToLogic(Size(0,10)).Height();
1317 nOutMin
= -pOut
->GetMapMode().GetOrigin().Y();
1318 nOutMax
= pOut
->GetOutputSize().Height() - 1 + nOutMin
;
1322 if (nOutMax
- nOutMin
< nDst
)
1324 nOutMin
+= nOutMax
+ 1;
1326 nOutMin
-= (nDst
+ 1) / 2;
1327 nOutMax
= nOutMin
+ nDst
;
1330 nOutHgt
= nOutMax
- nOutMin
;
1332 tools::Long nTemp
= nOutHgt
/ 4;
1333 if (nTemp
> nMinLen
) nMinLen
= nTemp
;
1336 // and then attach the marks at the top and bottom of the object
1337 basegfx::B2DRange aR
;
1338 for(size_t nMark
= 0; nMark
< rMarkList
.GetMarkCount(); ++nMark
)
1340 SdrObject
* pMark
= rMarkList
.GetMark(nMark
)->GetMarkedSdrObj();
1341 basegfx::B2DPolyPolygon
aXPP(pMark
->TakeXorPoly());
1342 aR
.expand(basegfx::utils::getRange(aXPP
));
1345 basegfx::B2DPoint
aCenter(aR
.getCenter());
1346 tools::Long nMarkHgt
= basegfx::fround
<tools::Long
>(aR
.getHeight()) - 1;
1347 tools::Long nHgt
= nMarkHgt
+ nObjDst
* 2;
1349 if (nHgt
< nMinLen
) nHgt
= nMinLen
;
1351 tools::Long nY1
= basegfx::fround
<tools::Long
>(aCenter
.getY()) - (nHgt
+ 1) / 2;
1352 tools::Long nY2
= nY1
+ nHgt
;
1354 if (pOut
&& (nMinLen
> nOutHgt
)) nMinLen
= nOutHgt
;
1360 if (nY2
< nY1
+ nMinLen
) nY2
= nY1
+ nMinLen
;
1365 if (nY1
> nY2
- nMinLen
) nY1
= nY2
- nMinLen
;
1369 maRef1
.setX( basegfx::fround
<tools::Long
>(aR
.getMinX()) ); // Initial move axis 2/100mm to the left
1371 maRef2
.setX( maRef1
.X() );
1375 SetMarkHandles(nullptr);
1377 //HMHif (bVis) ShowMarkHdl();
1378 if (rMarkList
.GetMarkCount() != 0) MarkListHasChanged();
1380 // Show mirror polygon IMMEDIATELY
1381 const SdrHdlList
&aHdlList
= GetHdlList();
1382 mpMirrorOverlay
.reset(new Impl3DMirrorConstructOverlay(*this));
1383 mpMirrorOverlay
->SetMirrorAxis(aHdlList
.GetHdl(SdrHdlKind::Ref1
)->GetPos(), aHdlList
.GetHdl(SdrHdlKind::Ref2
)->GetPos());
1386 // what happens with a mouse movement when the object is created?
1388 void E3dView::MovAction(const Point
& rPnt
)
1390 if(Is3DRotationCreationActive())
1392 SdrHdl
* pHdl
= GetDragHdl();
1396 SdrHdlKind eHdlKind
= pHdl
->GetKind();
1398 // reacts only due to a mirror axis
1399 if ((eHdlKind
== SdrHdlKind::Ref1
) ||
1400 (eHdlKind
== SdrHdlKind::Ref2
) ||
1401 (eHdlKind
== SdrHdlKind::MirrorAxis
))
1403 const SdrHdlList
&aHdlList
= GetHdlList ();
1405 // delete the mirrored polygon, mirrors the original and draws
1407 SdrView::MovAction (rPnt
);
1408 mpMirrorOverlay
->SetMirrorAxis(
1409 aHdlList
.GetHdl (SdrHdlKind::Ref1
)->GetPos(),
1410 aHdlList
.GetHdl (SdrHdlKind::Ref2
)->GetPos());
1415 SdrView::MovAction (rPnt
);
1420 SdrView::MovAction (rPnt
);
1424 // The End. Create object and any child objects through ImpCreate3DLathe.
1425 // With the parameter value sal_True (SDefault: sal_False) is simply a
1426 // rotation body created, without letting the user set the position of the
1427 // axis. It is sufficient with this call, if an object is selected.
1428 // (No initialization necessary)
1430 void E3dView::End3DCreation(bool bUseDefaultValuesForMirrorAxes
)
1432 ResetCreationActive();
1434 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1435 if(rMarkList
.GetMarkCount() == 0)
1438 if(bUseDefaultValuesForMirrorAxes
)
1440 tools::Rectangle aRect
= GetAllMarkedRect();
1441 if(aRect
.GetWidth() <= 1)
1442 aRect
.SetSize(Size(500, aRect
.GetHeight()));
1443 if(aRect
.GetHeight() <= 1)
1444 aRect
.SetSize(Size(aRect
.GetWidth(), 500));
1446 basegfx::B2DPoint
aPnt1(aRect
.Left(), -aRect
.Top());
1447 basegfx::B2DPoint
aPnt2(aRect
.Left(), -aRect
.Bottom());
1449 ConvertMarkedObjTo3D(false, aPnt1
, aPnt2
);
1453 // Turn off helper overlay
1454 // Determine from the handle positions and the displacement of
1456 const SdrHdlList
&aHdlList
= GetHdlList();
1457 Point aMirrorRef1
= aHdlList
.GetHdl(SdrHdlKind::Ref1
)->GetPos();
1458 Point aMirrorRef2
= aHdlList
.GetHdl(SdrHdlKind::Ref2
)->GetPos();
1460 basegfx::B2DPoint
aPnt1(aMirrorRef1
.X(), -aMirrorRef1
.Y());
1461 basegfx::B2DPoint
aPnt2(aMirrorRef2
.X(), -aMirrorRef2
.Y());
1463 ConvertMarkedObjTo3D(false, aPnt1
, aPnt2
);
1467 E3dView::~E3dView ()
1471 void E3dView::ResetCreationActive ()
1473 mpMirrorOverlay
.reset();
1476 void E3dView::InitView ()
1478 mpMirrorOverlay
= nullptr;
1481 bool E3dView::IsBreak3DObjPossible() const
1483 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1484 const size_t nCount
= rMarkList
.GetMarkCount();
1488 for (size_t i
= 0; i
< nCount
; ++i
)
1490 SdrObject
* pObj
= rMarkList
.GetMark(i
)->GetMarkedSdrObj();
1492 if (auto p3dObject
= DynCastE3dObject(pObj
))
1494 if(!p3dObject
->IsBreakObjPossible())
1511 void E3dView::Break3DObj()
1513 if(!IsBreak3DObjPossible())
1516 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1517 // ALL selected objects are changed
1518 const size_t nCount
= rMarkList
.GetMarkCount();
1520 BegUndo(SvxResId(RID_SVX_3D_UNDO_BREAK_LATHE
));
1521 for(size_t a
=0; a
<nCount
; ++a
)
1523 E3dObject
* pObj
= static_cast<E3dObject
*>(rMarkList
.GetMark(a
)->GetMarkedSdrObj());
1524 BreakSingle3DObj(pObj
);
1530 void E3dView::BreakSingle3DObj(E3dObject
* pObj
)
1532 if(DynCastE3dScene(pObj
))
1534 SdrObjList
* pSubList
= pObj
->GetSubList();
1535 SdrObjListIter
aIter(pSubList
, SdrIterMode::Flat
);
1537 while(aIter
.IsMore())
1539 E3dObject
* pSubObj
= static_cast<E3dObject
*>(aIter
.Next());
1540 BreakSingle3DObj(pSubObj
);
1545 rtl::Reference
<SdrAttrObj
> pNewObj
= pObj
->GetBreakObj();
1548 if (InsertObjectAtView(pNewObj
.get(), *GetSdrPageView(), SdrInsertFlags::DONTMARK
))
1550 pNewObj
->SetChanged();
1551 pNewObj
->BroadcastObjectChange();
1557 void E3dView::CheckPossibilities()
1560 SdrView::CheckPossibilities();
1563 if(!(m_bGroupPossible
|| m_bUnGroupPossible
|| m_bGrpEnterPossible
))
1566 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1567 const size_t nMarkCnt
= rMarkList
.GetMarkCount();
1568 bool bCompound
= false;
1569 bool b3DObject
= false;
1570 for(size_t nObjs
= 0; (nObjs
< nMarkCnt
) && !bCompound
; ++nObjs
)
1572 SdrObject
*pObj
= rMarkList
.GetMark(nObjs
)->GetMarkedSdrObj();
1573 if(dynamic_cast< const E3dCompoundObject
* >(pObj
))
1575 if(DynCastE3dObject(pObj
))
1579 // So far: there are two or more of any objects selected. See if
1580 // compound objects are involved. If yes, ban grouping.
1581 if(m_bGroupPossible
&& bCompound
)
1582 m_bGroupPossible
= false;
1584 if(m_bUnGroupPossible
&& b3DObject
)
1585 m_bUnGroupPossible
= false;
1587 if(m_bGrpEnterPossible
&& bCompound
)
1588 m_bGrpEnterPossible
= false;
1591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */