bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / engine3d / view3d.cxx
blob7f4ce943d9c1bb687a4e672764ef73ad761467f9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <vcl/wrkwin.hxx>
22 #include <svx/svdogrp.hxx>
23 #include <svx/svdopath.hxx>
24 #include "svx/svditer.hxx"
25 #include <svx/svdpool.hxx>
26 #include <svx/svdorect.hxx>
27 #include <svx/svdmodel.hxx>
28 #include <svx/svdpagv.hxx>
29 #include <svx/svxids.hrc>
30 #include <editeng/colritem.hxx>
31 #include <svx/xtable.hxx>
32 #include <svx/svdview.hxx>
33 #include <svx/dialogs.hrc>
34 #include <svx/dialmgr.hxx>
35 #include "svx/globl3d.hxx"
36 #include <svx/obj3d.hxx>
37 #include <svx/lathe3d.hxx>
38 #include <svx/sphere3d.hxx>
39 #include <svx/extrud3d.hxx>
40 #include <svx/cube3d.hxx>
41 #include <svx/polysc3d.hxx>
42 #include "dragmt3d.hxx"
43 #include <svx/view3d.hxx>
44 #include <svx/svdundo.hxx>
45 #include <svx/xflclit.hxx>
46 #include <svx/xlnclit.hxx>
47 #include <svx/svdograf.hxx>
48 #include <svx/xbtmpit.hxx>
49 #include <svx/xflbmtit.hxx>
50 #include <basegfx/range/b2drange.hxx>
51 #include <basegfx/polygon/b2dpolygontools.hxx>
52 #include <basegfx/polygon/b2dpolypolygontools.hxx>
53 #include <svx/xlnwtit.hxx>
54 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
55 #include <svx/sdr/overlay/overlaymanager.hxx>
56 #include <svx/sdrpaintwindow.hxx>
57 #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
58 #include <drawinglayer/geometry/viewinformation3d.hxx>
59 #include <svx/sdrpagewindow.hxx>
60 #include <svx/sdr/contact/displayinfo.hxx>
61 #include <svx/sdr/contact/objectcontact.hxx>
62 #include <svx/sdr/contact/viewobjectcontact.hxx>
63 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
64 #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
65 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
66 #include <basegfx/matrix/b2dhommatrixtools.hxx>
67 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
69 using namespace com::sun::star;
71 #define ITEMVALUE(ItemSet,Id,Cast) (static_cast<const Cast&>((ItemSet).Get(Id))).GetValue()
73 TYPEINIT1(E3dView, SdrView);
76 // Migrate Marking
78 class Impl3DMirrorConstructOverlay
80 // The OverlayObjects
81 sdr::overlay::OverlayObjectList maObjects;
83 // the view
84 const E3dView& mrView;
86 // the object count
87 size_t mnCount;
89 // the unmirrored polygons
90 basegfx::B2DPolyPolygon* mpPolygons;
92 // the overlay geometry from selected objects
93 drawinglayer::primitive2d::Primitive2DSequence maFullOverlay;
95 public:
96 Impl3DMirrorConstructOverlay(const E3dView& rView);
97 ~Impl3DMirrorConstructOverlay();
99 void SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB);
102 Impl3DMirrorConstructOverlay::Impl3DMirrorConstructOverlay(const E3dView& rView)
103 : maObjects(),
104 mrView(rView),
105 mnCount(rView.GetMarkedObjectCount()),
106 mpPolygons(0),
107 maFullOverlay()
109 if(mnCount)
111 if(mrView.IsSolidDragging())
113 SdrPageView* pPV = rView.GetSdrPageView();
115 if(pPV && pPV->PageWindowCount())
117 sdr::contact::ObjectContact& rOC = pPV->GetPageWindow(0)->GetObjectContact();
118 sdr::contact::DisplayInfo aDisplayInfo;
120 // Do not use the last ViewPort set at the OC at the last ProcessDisplay()
121 rOC.resetViewPort();
123 for(size_t a = 0; a < mnCount; ++a)
125 SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
127 if(pObject)
129 sdr::contact::ViewContact& rVC = pObject->GetViewContact();
130 sdr::contact::ViewObjectContact& rVOC = rVC.GetViewObjectContact(rOC);
132 const drawinglayer::primitive2d::Primitive2DSequence aNewSequence(rVOC.getPrimitive2DSequenceHierarchy(aDisplayInfo));
133 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(maFullOverlay, aNewSequence);
138 else
140 mpPolygons = new basegfx::B2DPolyPolygon[mnCount];
142 for(size_t a = 0; a < mnCount; ++a)
144 SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
145 mpPolygons[mnCount - (a + 1)] = pObject->TakeXorPoly();
151 Impl3DMirrorConstructOverlay::~Impl3DMirrorConstructOverlay()
153 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
154 // That destructor calls clear() at the list which removes all objects from the
155 // OverlayManager and deletes them.
156 if(!mrView.IsSolidDragging())
158 delete[] mpPolygons;
162 void Impl3DMirrorConstructOverlay::SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB)
164 // get rid of old overlay objects
165 maObjects.clear();
167 // create new ones
168 for(sal_uInt32 a(0); a < mrView.PaintWindowCount(); a++)
170 SdrPaintWindow* pCandidate = mrView.GetPaintWindow(a);
171 rtl::Reference< sdr::overlay::OverlayManager > xTargetOverlay = pCandidate->GetOverlayManager();
173 if(xTargetOverlay.is())
175 // buld transfoprmation: translate and rotate so that given edge is
176 // on x axis, them mirror in y and translate back
177 const basegfx::B2DVector aEdge(aMirrorAxisB.X() - aMirrorAxisA.X(), aMirrorAxisB.Y() - aMirrorAxisA.Y());
178 basegfx::B2DHomMatrix aMatrixTransform(basegfx::tools::createTranslateB2DHomMatrix(
179 -aMirrorAxisA.X(), -aMirrorAxisA.Y()));
180 aMatrixTransform.rotate(-atan2(aEdge.getY(), aEdge.getX()));
181 aMatrixTransform.scale(1.0, -1.0);
182 aMatrixTransform.rotate(atan2(aEdge.getY(), aEdge.getX()));
183 aMatrixTransform.translate(aMirrorAxisA.X(), aMirrorAxisA.Y());
185 if(mrView.IsSolidDragging())
187 if(maFullOverlay.hasElements())
189 drawinglayer::primitive2d::Primitive2DSequence aContent(maFullOverlay);
191 if(!aMatrixTransform.isIdentity())
193 // embed in transformation group
194 drawinglayer::primitive2d::Primitive2DReference aTransformPrimitive2D(new drawinglayer::primitive2d::TransformPrimitive2D(aMatrixTransform, aContent));
195 aContent = drawinglayer::primitive2d::Primitive2DSequence(&aTransformPrimitive2D, 1);
198 // if we have full overlay from selected objects, embed with 50% transparence, the
199 // transformation is added to the OverlayPrimitive2DSequenceObject
200 drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(aContent, 0.5));
201 aContent = drawinglayer::primitive2d::Primitive2DSequence(&aUnifiedTransparencePrimitive2D, 1);
203 sdr::overlay::OverlayPrimitive2DSequenceObject* pNew = new sdr::overlay::OverlayPrimitive2DSequenceObject(aContent);
205 xTargetOverlay->add(*pNew);
206 maObjects.append(*pNew);
209 else
211 for(size_t b = 0; b < mnCount; ++b)
213 // apply to polygon
214 basegfx::B2DPolyPolygon aPolyPolygon(mpPolygons[b]);
215 aPolyPolygon.transform(aMatrixTransform);
217 sdr::overlay::OverlayPolyPolygonStripedAndFilled* pNew = new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
218 aPolyPolygon);
219 xTargetOverlay->add(*pNew);
220 maObjects.append(*pNew);
227 E3dView::E3dView(SdrModel* pModel, OutputDevice* pOut) :
228 SdrView(pModel, pOut)
230 InitView ();
233 // DrawMarkedObj override, since possibly only a single 3D object is to be
234 // drawn
236 void E3dView::DrawMarkedObj(OutputDevice& rOut) const
238 // Does 3D objects exist which scenes are not selected?
239 bool bSpecialHandling = false;
240 E3dScene *pScene = NULL;
242 const size_t nCnt = GetMarkedObjectCount();
243 for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
245 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
246 if(pObj && pObj->ISA(E3dCompoundObject))
248 // related scene
249 pScene = static_cast<E3dCompoundObject*>(pObj)->GetScene();
250 if(pScene && !IsObjMarked(pScene))
251 bSpecialHandling = true;
253 // Reset all selection flags
254 if(pObj && pObj->ISA(E3dObject))
256 pScene = static_cast<E3dObject*>(pObj)->GetScene();
257 if(pScene)
258 pScene->SetSelected(false);
262 if(bSpecialHandling)
264 // Set selection flag to "not selected" for scenes related to all 3D
265 // objects
266 for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
268 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
269 if(pObj && pObj->ISA(E3dCompoundObject))
271 // relatated scene
272 pScene = static_cast<E3dCompoundObject*>(pObj)->GetScene();
273 if(pScene)
274 pScene->SetSelected(false);
278 for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
280 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
281 if(pObj && pObj->ISA(E3dObject))
283 // Select object
284 E3dObject* p3DObj = static_cast<E3dObject*>(pObj);
285 p3DObj->SetSelected(true);
286 pScene = p3DObj->GetScene();
290 if(pScene)
292 // code from parent
293 SortMarkedObjects();
295 pScene->SetDrawOnlySelected(true);
296 pScene->SingleObjectPainter(rOut);
297 pScene->SetDrawOnlySelected(false);
300 // Reset selection flag
301 for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
303 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
304 if(pObj && pObj->ISA(E3dCompoundObject))
306 // releated scene
307 pScene = static_cast<E3dCompoundObject*>(pObj)->GetScene();
308 if(pScene)
309 pScene->SetSelected(false);
313 else
315 // call parent
316 SdrExchangeView::DrawMarkedObj(rOut);
320 // override get model, since in some 3D objects an additional scene
321 // must be pushed in
323 SdrModel* E3dView::GetMarkedObjModel() const
325 // Does 3D objects exist which scenes are not selected?
326 bool bSpecialHandling(false);
327 const size_t nCount(GetMarkedObjectCount());
328 E3dScene *pScene = 0;
330 for(size_t nObjs = 0; nObjs < nCount; ++nObjs)
332 const SdrObject* pObj = GetMarkedObjectByIndex(nObjs);
334 if(!bSpecialHandling && pObj && pObj->ISA(E3dCompoundObject))
336 // if the object is selected, but it's scene not,
337 // we need special handling
338 pScene = static_cast<const E3dCompoundObject*>(pObj)->GetScene();
340 if(pScene && !IsObjMarked(pScene))
342 bSpecialHandling = true;
346 if(pObj && pObj->ISA(E3dObject))
348 // reset all selection flags at 3D objects
349 pScene = static_cast<const E3dObject*>(pObj)->GetScene();
351 if(pScene)
353 pScene->SetSelected(false);
358 if(!bSpecialHandling)
360 // call parent
361 return SdrView::GetMarkedObjModel();
364 SdrModel* pNewModel = 0;
365 Rectangle aSelectedSnapRect;
367 // set 3d selection flags at all directly selected objects
368 // and collect SnapRect of selected objects
369 for(size_t nObjs = 0; nObjs < nCount; ++nObjs)
371 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
373 if(pObj && pObj->ISA(E3dCompoundObject))
375 // mark object, but not scenes
376 E3dCompoundObject* p3DObj = static_cast<E3dCompoundObject*>(pObj);
377 p3DObj->SetSelected(true);
378 aSelectedSnapRect.Union(p3DObj->GetSnapRect());
382 // create new mark list which contains all indirectly selected3d
383 // scenes as selected objects
384 SdrMarkList aOldML(GetMarkedObjectList());
385 SdrMarkList aNewML;
386 SdrMarkList& rCurrentMarkList = const_cast<E3dView*>(this)->GetMarkedObjectListWriteAccess();
387 rCurrentMarkList = aNewML;
389 for(size_t nObjs = 0; nObjs < nCount; ++nObjs)
391 SdrObject *pObj = aOldML.GetMark(nObjs)->GetMarkedSdrObj();
393 if(pObj && pObj->ISA(E3dObject))
395 pScene = static_cast<E3dObject*>(pObj)->GetScene();
397 if(pScene && !IsObjMarked(pScene) && GetSdrPageView())
399 const_cast<E3dView*>(this)->MarkObj(pScene, GetSdrPageView(), false, true);
404 // call parent. This will copy all scenes and the selection flags at the 3d objectss. So
405 // it will be possible to delete all non-selected 3d objects from the cloned 3d scenes
406 pNewModel = SdrView::GetMarkedObjModel();
408 if(pNewModel)
410 for(sal_uInt16 nPg(0); nPg < pNewModel->GetPageCount(); nPg++)
412 const SdrPage* pSrcPg=pNewModel->GetPage(nPg);
413 const size_t nObjCount(pSrcPg->GetObjCount());
415 for(size_t nOb = 0; nOb < nObjCount; ++nOb)
417 const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
419 if(pSrcOb->ISA(E3dScene))
421 pScene = const_cast<E3dScene*>(static_cast<const E3dScene*>(pSrcOb));
423 // delete all not intentionally cloned 3d objects
424 pScene->removeAllNonSelectedObjects();
426 // reset select flags and set SnapRect of all selected objects
427 pScene->SetSelected(false);
428 pScene->SetSnapRect(aSelectedSnapRect);
434 // restore old selection
435 rCurrentMarkList = aOldML;
437 return pNewModel;
440 // When pasting objects have to integrated if a scene is inserted, but
441 // not the scene itself
443 bool E3dView::Paste(
444 const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions,
445 const OUString& rSrcShellID, const OUString& rDestShellID )
447 bool bRetval = false;
449 // Get list
450 Point aPos(rPos);
451 SdrObjList* pDstList = pLst;
452 ImpGetPasteObjList(aPos, pDstList);
454 if(!pDstList)
455 return false;
457 // Get owner of the list
458 SdrObject* pOwner = pDstList->GetOwnerObj();
459 if(pOwner && pOwner->ISA(E3dScene))
461 E3dScene* pDstScene = static_cast<E3dScene*>(pOwner);
462 BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_EXCHANGE_PASTE));
464 // Copy all objects from E3dScenes and insert them directly
465 for(sal_uInt16 nPg(0); nPg < rMod.GetPageCount(); nPg++)
467 const SdrPage* pSrcPg=rMod.GetPage(nPg);
468 const size_t nObjCount(pSrcPg->GetObjCount());
470 // calculate offset for paste
471 Rectangle aR = pSrcPg->GetAllObjBoundRect();
472 Point aDist(aPos - aR.Center());
474 // Insert sub-objects for scenes
475 for(size_t nOb = 0; nOb < nObjCount; ++nOb)
477 const SdrObject* pSrcOb = pSrcPg->GetObj(nOb);
478 if(pSrcOb->ISA(E3dScene))
480 E3dScene* pSrcScene = const_cast<E3dScene*>(static_cast<const E3dScene*>(pSrcOb));
481 ImpCloneAll3DObjectsToDestScene(pSrcScene, pDstScene, aDist);
485 EndUndo();
487 else
489 // call parent
490 bRetval = SdrView::Paste(rMod, rPos, pLst, nOptions, rSrcShellID, rDestShellID);
493 return bRetval;
496 // Service routine used from local Clone() and from SdrCreateView::EndCreateObj(...)
497 bool E3dView::ImpCloneAll3DObjectsToDestScene(E3dScene* pSrcScene, E3dScene* pDstScene, Point /*aOffset*/)
499 bool bRetval(false);
501 if(pSrcScene && pDstScene)
503 const sdr::contact::ViewContactOfE3dScene& rVCSceneDst = static_cast< sdr::contact::ViewContactOfE3dScene& >(pDstScene->GetViewContact());
504 const drawinglayer::geometry::ViewInformation3D aViewInfo3DDst(rVCSceneDst.getViewInformation3D());
505 const sdr::contact::ViewContactOfE3dScene& rVCSceneSrc = static_cast< sdr::contact::ViewContactOfE3dScene& >(pSrcScene->GetViewContact());
506 const drawinglayer::geometry::ViewInformation3D aViewInfo3DSrc(rVCSceneSrc.getViewInformation3D());
508 for(size_t i = 0; i < pSrcScene->GetSubList()->GetObjCount(); ++i)
510 E3dCompoundObject* pCompoundObj = dynamic_cast< E3dCompoundObject* >(pSrcScene->GetSubList()->GetObj(i));
512 if(pCompoundObj)
514 E3dCompoundObject* pNewCompoundObj = dynamic_cast< E3dCompoundObject* >(pCompoundObj->Clone());
516 if(pNewCompoundObj)
518 // get dest scene's current range in 3D world coordinates
519 const basegfx::B3DHomMatrix aSceneToWorldTrans(pDstScene->GetFullTransform());
520 basegfx::B3DRange aSceneRange(pDstScene->GetBoundVolume());
521 aSceneRange.transform(aSceneToWorldTrans);
523 // get new object's implied object transformation
524 const basegfx::B3DHomMatrix aNewObjectTrans(pNewCompoundObj->GetTransform());
526 // get new object's range in 3D world coordinates in dest scene
527 // as if it were already added
528 const basegfx::B3DHomMatrix aObjectToWorldTrans(aSceneToWorldTrans * aNewObjectTrans);
529 basegfx::B3DRange aObjectRange(pNewCompoundObj->GetBoundVolume());
530 aObjectRange.transform(aObjectToWorldTrans);
532 // get scale adaption
533 const basegfx::B3DVector aSceneScale(aSceneRange.getRange());
534 const basegfx::B3DVector aObjectScale(aObjectRange.getRange());
535 double fScale(1.0);
537 // if new object's size in X,Y or Z is bigger that 80% of dest scene, adapt scale
538 // to not change the scene by the inserted object
539 const double fSizeFactor(0.5);
541 if(aObjectScale.getX() * fScale > aSceneScale.getX() * fSizeFactor)
543 const double fObjSize(aObjectScale.getX() * fScale);
544 const double fFactor((aSceneScale.getX() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
545 fScale *= fFactor;
548 if(aObjectScale.getY() * fScale > aSceneScale.getY() * fSizeFactor)
550 const double fObjSize(aObjectScale.getY() * fScale);
551 const double fFactor((aSceneScale.getY() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
552 fScale *= fFactor;
555 if(aObjectScale.getZ() * fScale > aSceneScale.getZ() * fSizeFactor)
557 const double fObjSize(aObjectScale.getZ() * fScale);
558 const double fFactor((aSceneScale.getZ() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
559 fScale *= fFactor;
562 // get translation adaption
563 const basegfx::B3DPoint aSceneCenter(aSceneRange.getCenter());
564 const basegfx::B3DPoint aObjectCenter(aObjectRange.getCenter());
566 // build full modification transform. The object's transformation
567 // shall be modified, so start at object coordinates; transform to 3d world coor
568 basegfx::B3DHomMatrix aModifyingTransform(aObjectToWorldTrans);
570 // translate to absolute center in 3d world coor
571 aModifyingTransform.translate(-aObjectCenter.getX(), -aObjectCenter.getY(), -aObjectCenter.getZ());
573 // scale to dest size in 3d world coor
574 aModifyingTransform.scale(fScale, fScale, fScale);
576 // translate to dest scene center in 3d world coor
577 aModifyingTransform.translate(aSceneCenter.getX(), aSceneCenter.getY(), aSceneCenter.getZ());
579 // transform from 3d world to dest object coordinates
580 basegfx::B3DHomMatrix aWorldToObject(aObjectToWorldTrans);
581 aWorldToObject.invert();
582 aModifyingTransform = aWorldToObject * aModifyingTransform;
584 // correct implied object transform by applying changing one in object coor
585 pNewCompoundObj->SetTransform(aModifyingTransform * aNewObjectTrans);
587 // fill and insert new object
588 pNewCompoundObj->SetModel(pDstScene->GetModel());
589 pNewCompoundObj->SetPage(pDstScene->GetPage());
590 pNewCompoundObj->NbcSetLayer(pCompoundObj->GetLayer());
591 pNewCompoundObj->NbcSetStyleSheet(pCompoundObj->GetStyleSheet(), true);
592 pDstScene->Insert3DObj(pNewCompoundObj);
593 bRetval = true;
595 // Create undo
596 if( GetModel()->IsUndoEnabled() )
597 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewCompoundObj));
603 return bRetval;
606 bool E3dView::IsConvertTo3DObjPossible() const
608 bool bAny3D(false);
609 bool bGroupSelected(false);
610 bool bRetval(true);
612 for(size_t a=0; !bAny3D && a<GetMarkedObjectCount(); ++a)
614 SdrObject *pObj = GetMarkedObjectByIndex(a);
615 if(pObj)
617 ImpIsConvertTo3DPossible(pObj, bAny3D, bGroupSelected);
621 bRetval = !bAny3D
622 && (
623 IsConvertToPolyObjPossible(false)
624 || IsConvertToPathObjPossible(false)
625 || IsImportMtfPossible());
626 return bRetval;
629 void E3dView::ImpIsConvertTo3DPossible(SdrObject* pObj, bool& rAny3D,
630 bool& rGroupSelected) const
632 if(pObj)
634 if(pObj->ISA(E3dObject))
636 rAny3D = true;
638 else
640 if(pObj->IsGroupObject())
642 SdrObjListIter aIter(*pObj, IM_DEEPNOGROUPS);
643 while(aIter.IsMore())
645 SdrObject* pNewObj = aIter.Next();
646 ImpIsConvertTo3DPossible(pNewObj, rAny3D, rGroupSelected);
648 rGroupSelected = true;
654 #include <editeng/eeitem.hxx>
656 void E3dView::ImpChangeSomeAttributesFor3DConversion(SdrObject* pObj)
658 if(pObj->ISA(SdrTextObj))
660 const SfxItemSet& rSet = pObj->GetMergedItemSet();
661 const SvxColorItem& rTextColorItem = static_cast<const SvxColorItem&>(rSet.Get(EE_CHAR_COLOR));
662 if(rTextColorItem.GetValue() == RGB_Color(COL_BLACK))
664 //For black text objects, the color set to gray
665 if(pObj->GetPage())
667 // if black is only default attribute from
668 // pattern set it hard so that it is used in undo.
669 pObj->SetMergedItem(SvxColorItem(RGB_Color(COL_BLACK), EE_CHAR_COLOR));
671 // add undo now
672 if( GetModel()->IsUndoEnabled() )
673 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj, false, false));
676 pObj->SetMergedItem(SvxColorItem(RGB_Color(COL_GRAY), EE_CHAR_COLOR));
681 void E3dView::ImpChangeSomeAttributesFor3DConversion2(SdrObject* pObj)
683 if(pObj->ISA(SdrPathObj))
685 const SfxItemSet& rSet = pObj->GetMergedItemSet();
686 sal_Int32 nLineWidth = static_cast<const XLineWidthItem&>(rSet.Get(XATTR_LINEWIDTH)).GetValue();
687 drawing::LineStyle eLineStyle = (drawing::LineStyle)static_cast<const XLineStyleItem&>(rSet.Get(XATTR_LINESTYLE)).GetValue();
688 drawing::FillStyle eFillStyle = ITEMVALUE(rSet, XATTR_FILLSTYLE, XFillStyleItem);
690 if(static_cast<SdrPathObj*>(pObj)->IsClosed()
691 && eLineStyle == drawing::LineStyle_SOLID
692 && !nLineWidth
693 && eFillStyle != drawing::FillStyle_NONE)
695 if(pObj->GetPage() && GetModel()->IsUndoEnabled() )
696 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj, false, false));
697 pObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
698 pObj->SetMergedItem(XLineWidthItem(0L));
703 void E3dView::ImpCreateSingle3DObjectFlat(E3dScene* pScene, SdrObject* pObj, bool bExtrude, double fDepth, basegfx::B2DHomMatrix& rLatheMat)
705 // Single PathObject, transform this
706 SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj);
708 if(pPath)
710 E3dDefaultAttributes aDefault = Get3DDefaultAttributes();
711 if(bExtrude)
712 aDefault.SetDefaultExtrudeCharacterMode(true);
713 else
714 aDefault.SetDefaultLatheCharacterMode(true);
716 // Get Itemset of the original object
717 SfxItemSet aSet(pObj->GetMergedItemSet());
719 drawing::FillStyle eFillStyle = ITEMVALUE(aSet, XATTR_FILLSTYLE, XFillStyleItem);
721 // line style turned off
722 aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
724 //Determining if FILL_Attribut is set.
725 if(!pPath->IsClosed() || eFillStyle == drawing::FillStyle_NONE)
727 // This SdrPathObj is not filled, leave the front and rear face out.
728 // Moreover, a two-sided representation necessary.
729 aDefault.SetDefaultExtrudeCloseFront(false);
730 aDefault.SetDefaultExtrudeCloseBack(false);
732 aSet.Put(makeSvx3DDoubleSidedItem(true));
734 // Set fill attribute
735 aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
737 // Fill color must be the color line, because the object was
738 // previously just a line
739 Color aColorLine = static_cast<const XLineColorItem&>(aSet.Get(XATTR_LINECOLOR)).GetColorValue();
740 aSet.Put(XFillColorItem(OUString(), aColorLine));
743 // Create a new extrude object
744 E3dObject* p3DObj = NULL;
745 if(bExtrude)
747 p3DObj = new E3dExtrudeObj(aDefault, pPath->GetPathPoly(), fDepth);
749 else
751 basegfx::B2DPolyPolygon aPolyPoly2D(pPath->GetPathPoly());
752 aPolyPoly2D.transform(rLatheMat);
753 p3DObj = new E3dLatheObj(aDefault, aPolyPoly2D);
756 // Set attribute
757 if(p3DObj)
759 p3DObj->NbcSetLayer(pObj->GetLayer());
761 p3DObj->SetMergedItemSet(aSet);
763 p3DObj->NbcSetStyleSheet(pObj->GetStyleSheet(), true);
765 // Insert a new extrude object
766 pScene->Insert3DObj(p3DObj);
771 void E3dView::ImpCreate3DObject(E3dScene* pScene, SdrObject* pObj, bool bExtrude, double fDepth, basegfx::B2DHomMatrix& rLatheMat)
773 if(pObj)
775 // change text color attribute for not so dark colors
776 if(pObj->IsGroupObject())
778 SdrObjListIter aIter(*pObj, IM_DEEPWITHGROUPS);
779 while(aIter.IsMore())
781 SdrObject* pGroupMember = aIter.Next();
782 ImpChangeSomeAttributesFor3DConversion(pGroupMember);
785 else
786 ImpChangeSomeAttributesFor3DConversion(pObj);
788 // convert completely to path objects
789 SdrObject* pNewObj1 = pObj->ConvertToPolyObj(false, false);
791 if(pNewObj1)
793 // change text color attribute for not so dark colors
794 if(pNewObj1->IsGroupObject())
796 SdrObjListIter aIter(*pNewObj1, IM_DEEPWITHGROUPS);
797 while(aIter.IsMore())
799 SdrObject* pGroupMember = aIter.Next();
800 ImpChangeSomeAttributesFor3DConversion2(pGroupMember);
803 else
804 ImpChangeSomeAttributesFor3DConversion2(pNewObj1);
806 // convert completely to path objects
807 SdrObject* pNewObj2 = pObj->ConvertToContourObj(pNewObj1, true);
809 if(pNewObj2)
811 // add all to flat scene
812 if(pNewObj2->IsGroupObject())
814 SdrObjListIter aIter(*pNewObj2, IM_DEEPWITHGROUPS);
815 while(aIter.IsMore())
817 SdrObject* pGroupMember = aIter.Next();
818 ImpCreateSingle3DObjectFlat(pScene, pGroupMember, bExtrude, fDepth, rLatheMat);
821 else
822 ImpCreateSingle3DObjectFlat(pScene, pNewObj2, bExtrude, fDepth, rLatheMat);
824 // delete object in between
825 if(pNewObj2 != pObj && pNewObj2 != pNewObj1 && pNewObj2)
826 SdrObject::Free( pNewObj2 );
829 // delete object in between
830 if(pNewObj1 != pObj && pNewObj1)
831 SdrObject::Free( pNewObj1 );
836 void E3dView::ConvertMarkedObjTo3D(bool bExtrude, const basegfx::B2DPoint& rPnt1, const basegfx::B2DPoint& rPnt2)
838 if(AreObjectsMarked())
840 // Create undo
841 if(bExtrude)
842 BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_EXTRUDE));
843 else
844 BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_LATHE));
846 // Create a new scene for the created 3D object
847 E3dScene* pScene = new E3dPolyScene(Get3DDefaultAttributes());
849 // Determine rectangle and possibly correct it
850 Rectangle aRect = GetAllMarkedRect();
851 if(aRect.GetWidth() <= 1)
852 aRect.SetSize(Size(500, aRect.GetHeight()));
853 if(aRect.GetHeight() <= 1)
854 aRect.SetSize(Size(aRect.GetWidth(), 500));
856 // Determine the depth relative to the size of the selection
857 double fDepth = 0.0;
858 double fRot3D = 0.0;
859 basegfx::B2DHomMatrix aLatheMat;
861 if(bExtrude)
863 double fW = (double)aRect.GetWidth();
864 double fH = (double)aRect.GetHeight();
865 fDepth = sqrt(fW*fW + fH*fH) / 6.0;
867 if(!bExtrude)
869 // Create transformation for the polygons rotating body
870 if (rPnt1 != rPnt2)
872 // Rotation around control point #1 with set angle
873 // for 3D coordinates
874 basegfx::B2DPoint aDiff(rPnt1 - rPnt2);
875 fRot3D = atan2(aDiff.getY(), aDiff.getX()) - F_PI2;
877 if(basegfx::fTools::equalZero(fabs(fRot3D)))
878 fRot3D = 0.0;
880 if(fRot3D != 0.0)
882 aLatheMat = basegfx::tools::createRotateAroundPoint(rPnt2, -fRot3D)
883 * aLatheMat;
887 if (rPnt2.getX() != 0.0)
889 // Translation to Y=0 - axis
890 aLatheMat.translate(-rPnt2.getX(), 0.0);
892 else
894 aLatheMat.translate((double)-aRect.Left(), 0.0);
897 // Form the inverse matrix to determine the target expansion
898 basegfx::B2DHomMatrix aInvLatheMat(aLatheMat);
899 aInvLatheMat.invert();
901 // SnapRect extension enables mirroring in the axis of rotation
902 for(size_t a=0; a<GetMarkedObjectCount(); ++a)
904 SdrMark* pMark = GetSdrMarkByIndex(a);
905 SdrObject* pObj = pMark->GetMarkedSdrObj();
906 Rectangle aTurnRect = pObj->GetSnapRect();
907 basegfx::B2DPoint aRot;
908 Point aRotPnt;
910 aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Top());
911 aRot *= aLatheMat;
912 aRot.setX(-aRot.getX());
913 aRot *= aInvLatheMat;
914 aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
915 aRect.Union(Rectangle(aRotPnt, aRotPnt));
917 aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Bottom());
918 aRot *= aLatheMat;
919 aRot.setX(-aRot.getX());
920 aRot *= aInvLatheMat;
921 aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
922 aRect.Union(Rectangle(aRotPnt, aRotPnt));
924 aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Top());
925 aRot *= aLatheMat;
926 aRot.setX(-aRot.getX());
927 aRot *= aInvLatheMat;
928 aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
929 aRect.Union(Rectangle(aRotPnt, aRotPnt));
931 aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Bottom());
932 aRot *= aLatheMat;
933 aRot.setX(-aRot.getX());
934 aRot *= aInvLatheMat;
935 aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
936 aRect.Union(Rectangle(aRotPnt, aRotPnt));
940 // Walk through the selection and convert it into 3D, complete with
941 // Conversion to SdrPathObject, also fonts
942 for(size_t a=0; a<GetMarkedObjectCount(); ++a)
944 SdrMark* pMark = GetSdrMarkByIndex(a);
945 SdrObject* pObj = pMark->GetMarkedSdrObj();
947 ImpCreate3DObject(pScene, pObj, bExtrude, fDepth, aLatheMat);
950 if(pScene->GetSubList() && pScene->GetSubList()->GetObjCount() != 0)
952 // Arrange all created objects by depth
953 if(bExtrude)
954 DoDepthArrange(pScene, fDepth);
956 // Center 3D objects in the middle of the overall rectangle
957 basegfx::B3DPoint aCenter(pScene->GetBoundVolume().getCenter());
958 basegfx::B3DHomMatrix aMatrix;
960 aMatrix.translate(-aCenter.getX(), -aCenter.getY(), -aCenter.getZ());
961 pScene->SetTransform(aMatrix * pScene->GetTransform());
963 // Initialize scene
964 pScene->NbcSetSnapRect(aRect);
965 basegfx::B3DRange aBoundVol = pScene->GetBoundVolume();
966 InitScene(pScene, (double)aRect.GetWidth(), (double)aRect.GetHeight(), aBoundVol.getDepth());
968 // Insert scene instead of the first selected object and throw away
969 // all the old objects
970 SdrObject* pRepObj = GetMarkedObjectByIndex(0);
971 SdrPageView* pPV = GetSdrPageViewOfMarkedByIndex(0);
972 MarkObj(pRepObj, pPV, true);
973 ReplaceObjectAtView(pRepObj, *pPV, pScene, false);
974 DeleteMarked();
975 MarkObj(pScene, pPV);
977 // Rotate Rotation body around the axis of rotation
978 basegfx::B3DHomMatrix aRotate;
980 if(!bExtrude && fRot3D != 0.0)
982 aRotate.rotate(0.0, 0.0, fRot3D);
985 // Set default rotation
987 double XRotateDefault = 20;
988 aRotate.rotate(DEG2RAD(XRotateDefault), 0.0, 0.0);
991 if(!aRotate.isIdentity())
993 pScene->SetTransform(aRotate * pScene->GetTransform());
996 // Invalid SnapRects of objects
997 pScene->SetSnapRect(aRect);
999 else
1001 // No 3D object was created, throw away everything
1002 delete pScene;
1005 EndUndo();
1009 //Arrange all created extrude objects by depth
1011 struct E3dDepthNeighbour
1013 E3dDepthNeighbour* mpNext;
1014 E3dExtrudeObj* mpObj;
1015 basegfx::B2DPolyPolygon maPreparedPolyPolygon;
1017 E3dDepthNeighbour()
1018 : mpNext(0),
1019 mpObj(0),
1020 maPreparedPolyPolygon()
1025 struct E3dDepthLayer
1027 E3dDepthLayer* mpDown;
1028 E3dDepthNeighbour* mpNext;
1030 E3dDepthLayer()
1031 : mpDown(0),
1032 mpNext(0)
1036 ~E3dDepthLayer()
1038 while(mpNext)
1040 E3dDepthNeighbour* pSucc = mpNext->mpNext;
1041 delete mpNext;
1042 mpNext = pSucc;
1047 void E3dView::DoDepthArrange(E3dScene* pScene, double fDepth)
1049 if(pScene && pScene->GetSubList() && pScene->GetSubList()->GetObjCount() > 1)
1051 SdrObjList* pSubList = pScene->GetSubList();
1052 SdrObjListIter aIter(*pSubList, IM_FLAT);
1053 E3dDepthLayer* pBaseLayer = NULL;
1054 E3dDepthLayer* pLayer = NULL;
1055 sal_Int32 nNumLayers = 0;
1057 while(aIter.IsMore())
1059 E3dExtrudeObj* pExtrudeObj = dynamic_cast< E3dExtrudeObj* >(aIter.Next());
1061 if(pExtrudeObj)
1063 const basegfx::B2DPolyPolygon aExtrudePoly(
1064 basegfx::tools::prepareForPolygonOperation(pExtrudeObj->GetExtrudePolygon()));
1065 const SfxItemSet& rLocalSet = pExtrudeObj->GetMergedItemSet();
1066 const drawing::FillStyle eLocalFillStyle = ITEMVALUE(rLocalSet, XATTR_FILLSTYLE, XFillStyleItem);
1067 const Color aLocalColor = static_cast<const XFillColorItem&>(rLocalSet.Get(XATTR_FILLCOLOR)).GetColorValue();
1069 // sort in ExtrudeObj
1070 if(pLayer)
1072 // do we have overlap with an object of this layer?
1073 bool bOverlap(false);
1074 E3dDepthNeighbour* pAct = pLayer->mpNext;
1076 while(!bOverlap && pAct)
1078 // do pAct->mpObj and pExtrudeObj overlap? Check by
1079 // using logical AND clipping
1080 const basegfx::B2DPolyPolygon aAndPolyPolygon(
1081 basegfx::tools::solvePolygonOperationAnd(
1082 aExtrudePoly,
1083 pAct->maPreparedPolyPolygon));
1085 bOverlap = (0 != aAndPolyPolygon.count());
1087 if(bOverlap)
1089 // second ciriteria: is another fillstyle or color used?
1090 const SfxItemSet& rCompareSet = pAct->mpObj->GetMergedItemSet();
1092 drawing::FillStyle eCompareFillStyle = ITEMVALUE(rCompareSet, XATTR_FILLSTYLE, XFillStyleItem);
1094 if(eLocalFillStyle == eCompareFillStyle)
1096 if(eLocalFillStyle == drawing::FillStyle_SOLID)
1098 Color aCompareColor = static_cast<const XFillColorItem&>(rCompareSet.Get(XATTR_FILLCOLOR)).GetColorValue();
1100 if(aCompareColor == aLocalColor)
1102 bOverlap = false;
1105 else if(eLocalFillStyle == drawing::FillStyle_NONE)
1107 bOverlap = false;
1112 pAct = pAct->mpNext;
1115 if(bOverlap)
1117 // yes, start a new layer
1118 pLayer->mpDown = new E3dDepthLayer;
1119 pLayer = pLayer->mpDown;
1120 nNumLayers++;
1121 pLayer->mpNext = new E3dDepthNeighbour;
1122 pLayer->mpNext->mpObj = pExtrudeObj;
1123 pLayer->mpNext->maPreparedPolyPolygon = aExtrudePoly;
1125 else
1127 // no, add to current layer
1128 E3dDepthNeighbour* pNewNext = new E3dDepthNeighbour;
1129 pNewNext->mpObj = pExtrudeObj;
1130 pNewNext->maPreparedPolyPolygon = aExtrudePoly;
1131 pNewNext->mpNext = pLayer->mpNext;
1132 pLayer->mpNext = pNewNext;
1135 else
1137 // first layer ever
1138 pBaseLayer = new E3dDepthLayer;
1139 pLayer = pBaseLayer;
1140 nNumLayers++;
1141 pLayer->mpNext = new E3dDepthNeighbour;
1142 pLayer->mpNext->mpObj = pExtrudeObj;
1143 pLayer->mpNext->maPreparedPolyPolygon = aExtrudePoly;
1148 // number of layers is done
1149 if(nNumLayers > 1)
1151 // need to be arranged
1152 double fMinDepth = fDepth * 0.8;
1153 double fStep = (fDepth - fMinDepth) / (double)nNumLayers;
1154 pLayer = pBaseLayer;
1156 while(pLayer)
1158 // move along layer
1159 E3dDepthNeighbour* pAct = pLayer->mpNext;
1161 while(pAct)
1163 // adapt extrude value
1164 pAct->mpObj->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH, sal_uInt32(fMinDepth + 0.5)));
1166 // next
1167 pAct = pAct->mpNext;
1170 // next layer
1171 pLayer = pLayer->mpDown;
1172 fMinDepth += fStep;
1176 // cleanup
1177 while(pBaseLayer)
1179 pLayer = pBaseLayer->mpDown;
1180 delete pBaseLayer;
1181 pBaseLayer = pLayer;
1186 // Start drag, create for 3D objects before possibly drag method
1188 bool E3dView::BegDragObj(const Point& rPnt, OutputDevice* pOut,
1189 SdrHdl* pHdl, short nMinMov,
1190 SdrDragMethod* pForcedMeth)
1192 if(Is3DRotationCreationActive() && GetMarkedObjectCount())
1194 // Determine all selected polygons and return the mirrored helper overlay
1195 mpMirrorOverlay->SetMirrorAxis(aRef1, aRef2);
1197 else
1199 bool bOwnActionNecessary;
1200 if (pHdl == NULL)
1202 bOwnActionNecessary = true;
1204 else if (pHdl->IsVertexHdl() || pHdl->IsCornerHdl())
1206 bOwnActionNecessary = true;
1208 else
1210 bOwnActionNecessary = false;
1213 if(bOwnActionNecessary && GetMarkedObjectCount() > 0)
1215 E3dDragConstraint eConstraint = E3DDRAG_CONSTR_XYZ;
1216 bool bThereAreRootScenes = false;
1217 bool bThereAre3DObjects = false;
1218 const size_t nCnt = GetMarkedObjectCount();
1219 for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
1221 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
1222 if(pObj)
1224 if(pObj->ISA(E3dScene) && static_cast<E3dScene*>(pObj)->GetScene() == pObj)
1225 bThereAreRootScenes = true;
1226 if(pObj->ISA(E3dObject))
1227 bThereAre3DObjects = true;
1230 if( bThereAre3DObjects )
1232 eDragHdl = ( pHdl == NULL ? HDL_MOVE : pHdl->GetKind() );
1233 switch ( eDragMode )
1235 case SDRDRAG_ROTATE:
1236 case SDRDRAG_SHEAR:
1238 switch ( eDragHdl )
1240 case HDL_LEFT:
1241 case HDL_RIGHT:
1243 eConstraint = E3DDRAG_CONSTR_X;
1245 break;
1247 case HDL_UPPER:
1248 case HDL_LOWER:
1250 eConstraint = E3DDRAG_CONSTR_Y;
1252 break;
1254 case HDL_UPLFT:
1255 case HDL_UPRGT:
1256 case HDL_LWLFT:
1257 case HDL_LWRGT:
1259 eConstraint = E3DDRAG_CONSTR_Z;
1261 break;
1262 default: break;
1265 // do not mask the allowed rotations
1266 eConstraint = E3dDragConstraint(eConstraint& eDragConstraint);
1267 pForcedMeth = new E3dDragRotate(*this, GetMarkedObjectList(), eConstraint, IsSolidDragging());
1269 break;
1271 case SDRDRAG_MOVE:
1273 if(!bThereAreRootScenes)
1275 pForcedMeth = new E3dDragMove(*this, GetMarkedObjectList(), eDragHdl, eConstraint, IsSolidDragging());
1278 break;
1280 // later on
1281 case SDRDRAG_MIRROR:
1282 case SDRDRAG_CROOK:
1283 case SDRDRAG_DISTORT:
1284 case SDRDRAG_TRANSPARENCE:
1285 case SDRDRAG_GRADIENT:
1286 default:
1289 break;
1294 return SdrView::BegDragObj(rPnt, pOut, pHdl, nMinMov, pForcedMeth);
1297 // Set current 3D drawing object, create the scene for this
1299 E3dScene* E3dView::SetCurrent3DObj(E3dObject* p3DObj)
1301 DBG_ASSERT(p3DObj != NULL, "Who puts in a NULL-pointer here");
1302 E3dScene* pScene = NULL;
1304 // get transformed BoundVolume of the object
1305 basegfx::B3DRange aVolume(p3DObj->GetBoundVolume());
1306 aVolume.transform(p3DObj->GetTransform());
1307 double fW(aVolume.getWidth());
1308 double fH(aVolume.getHeight());
1310 Rectangle aRect(0,0, (long) fW, (long) fH);
1312 pScene = new E3dPolyScene(Get3DDefaultAttributes());
1314 InitScene(pScene, fW, fH, aVolume.getMaxZ() + ((fW + fH) / 4.0));
1316 pScene->Insert3DObj(p3DObj);
1317 pScene->NbcSetSnapRect(aRect);
1319 return pScene;
1322 void E3dView::InitScene(E3dScene* pScene, double fW, double fH, double fCamZ)
1324 Camera3D aCam(pScene->GetCamera());
1326 aCam.SetAutoAdjustProjection(false);
1327 aCam.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
1328 basegfx::B3DPoint aLookAt;
1330 double fDefaultCamPosZ = GetDefaultCamPosZ();
1331 basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
1333 aCam.SetPosAndLookAt(aCamPos, aLookAt);
1334 aCam.SetFocalLength(GetDefaultCamFocal());
1335 aCam.SetDefaults(basegfx::B3DPoint(0.0, 0.0, fDefaultCamPosZ), aLookAt, GetDefaultCamFocal());
1336 pScene->SetCamera(aCam);
1339 void E3dView::Start3DCreation()
1341 if (GetMarkedObjectCount())
1343 //positioned
1344 long nOutMin = 0;
1345 long nOutMax = 0;
1346 long nMinLen = 0;
1347 long nObjDst = 0;
1348 long nOutHgt = 0;
1349 OutputDevice* pOut = GetFirstOutputDevice();
1351 // first determine representation boundaries
1352 if (pOut != NULL)
1354 nMinLen = pOut->PixelToLogic(Size(0,50)).Height();
1355 nObjDst = pOut->PixelToLogic(Size(0,20)).Height();
1357 long nDst = pOut->PixelToLogic(Size(0,10)).Height();
1359 nOutMin = -pOut->GetMapMode().GetOrigin().Y();
1360 nOutMax = pOut->GetOutputSize().Height() - 1 + nOutMin;
1361 nOutMin += nDst;
1362 nOutMax -= nDst;
1364 if (nOutMax - nOutMin < nDst)
1366 nOutMin += nOutMax + 1;
1367 nOutMin /= 2;
1368 nOutMin -= (nDst + 1) / 2;
1369 nOutMax = nOutMin + nDst;
1372 nOutHgt = nOutMax - nOutMin;
1374 long nTemp = nOutHgt / 4;
1375 if (nTemp > nMinLen) nMinLen = nTemp;
1378 // and then attach the marks at the top and bottom of the object
1379 basegfx::B2DRange aR;
1380 for(size_t nMark = 0; nMark < GetMarkedObjectCount(); ++nMark)
1382 SdrObject* pMark = GetMarkedObjectByIndex(nMark);
1383 basegfx::B2DPolyPolygon aXPP(pMark->TakeXorPoly());
1384 aR.expand(basegfx::tools::getRange(aXPP));
1387 basegfx::B2DPoint aCenter(aR.getCenter());
1388 long nMarkHgt = basegfx::fround(aR.getHeight()) - 1;
1389 long nHgt = nMarkHgt + nObjDst * 2;
1391 if (nHgt < nMinLen) nHgt = nMinLen;
1393 long nY1 = basegfx::fround(aCenter.getY()) - (nHgt + 1) / 2;
1394 long nY2 = nY1 + nHgt;
1396 if (pOut && (nMinLen > nOutHgt)) nMinLen = nOutHgt;
1397 if (pOut)
1399 if (nY1 < nOutMin)
1401 nY1 = nOutMin;
1402 if (nY2 < nY1 + nMinLen) nY2 = nY1 + nMinLen;
1404 if (nY2 > nOutMax)
1406 nY2 = nOutMax;
1407 if (nY1 > nY2 - nMinLen) nY1 = nY2 - nMinLen;
1411 aRef1.X() = basegfx::fround(aR.getMinX()); // Initial move axis 2/100mm to the left
1412 aRef1.Y() = nY1;
1413 aRef2.X() = aRef1.X();
1414 aRef2.Y() = nY2;
1416 // Turn on marks
1417 SetMarkHandles();
1419 //HMHif (bVis) ShowMarkHdl();
1420 if (AreObjectsMarked()) MarkListHasChanged();
1422 // Show mirror polygon IMMEDIATELY
1423 const SdrHdlList &aHdlList = GetHdlList();
1424 mpMirrorOverlay = new Impl3DMirrorConstructOverlay(*this);
1425 mpMirrorOverlay->SetMirrorAxis(aHdlList.GetHdl(HDL_REF1)->GetPos(), aHdlList.GetHdl(HDL_REF2)->GetPos());
1429 // what happens with a mouse movement when the object is created?
1431 void E3dView::MovAction(const Point& rPnt)
1433 if(Is3DRotationCreationActive())
1435 SdrHdl* pHdl = GetDragHdl();
1437 if (pHdl)
1439 SdrHdlKind eHdlKind = pHdl->GetKind();
1441 // reacts only due to a mirror axis
1442 if ((eHdlKind == HDL_REF1) ||
1443 (eHdlKind == HDL_REF2) ||
1444 (eHdlKind == HDL_MIRX))
1446 const SdrHdlList &aHdlList = GetHdlList ();
1448 // delete the mirroed polygon, mirrors the original and draws
1449 // it anew
1450 SdrView::MovAction (rPnt);
1451 mpMirrorOverlay->SetMirrorAxis(
1452 aHdlList.GetHdl (HDL_REF1)->GetPos(),
1453 aHdlList.GetHdl (HDL_REF2)->GetPos());
1456 else
1458 SdrView::MovAction (rPnt);
1461 else
1463 SdrView::MovAction (rPnt);
1467 // The End. Create object and any child objects through ImpCreate3DLathe.
1468 // With the parameter value sal_True (SDefault: sal_False) is simply a
1469 // rotation body created, without letting the user set the position of the
1470 // axis. It is sufficient with this call, if an object is selected.
1471 // (No initialization necessary)
1473 void E3dView::End3DCreation(bool bUseDefaultValuesForMirrorAxes)
1475 ResetCreationActive();
1477 if(AreObjectsMarked())
1479 if(bUseDefaultValuesForMirrorAxes)
1481 Rectangle aRect = GetAllMarkedRect();
1482 if(aRect.GetWidth() <= 1)
1483 aRect.SetSize(Size(500, aRect.GetHeight()));
1484 if(aRect.GetHeight() <= 1)
1485 aRect.SetSize(Size(aRect.GetWidth(), 500));
1487 basegfx::B2DPoint aPnt1(aRect.Left(), -aRect.Top());
1488 basegfx::B2DPoint aPnt2(aRect.Left(), -aRect.Bottom());
1490 ConvertMarkedObjTo3D(false, aPnt1, aPnt2);
1492 else
1494 // Turn off helper overlay
1495 // Determine from the handle positions and the displacement of
1496 // the points
1497 const SdrHdlList &aHdlList = GetHdlList();
1498 Point aMirrorRef1 = aHdlList.GetHdl(HDL_REF1)->GetPos();
1499 Point aMirrorRef2 = aHdlList.GetHdl(HDL_REF2)->GetPos();
1501 basegfx::B2DPoint aPnt1(aMirrorRef1.X(), -aMirrorRef1.Y());
1502 basegfx::B2DPoint aPnt2(aMirrorRef2.X(), -aMirrorRef2.Y());
1504 ConvertMarkedObjTo3D(false, aPnt1, aPnt2);
1509 E3dView::~E3dView ()
1513 void E3dView::ResetCreationActive ()
1515 if(mpMirrorOverlay)
1517 delete mpMirrorOverlay;
1518 mpMirrorOverlay = 0L;
1522 void E3dView::InitView ()
1524 eDragConstraint = E3DDRAG_CONSTR_XYZ;
1525 fDefaultScaleX =
1526 fDefaultScaleY =
1527 fDefaultScaleZ = 1.0;
1528 fDefaultRotateX =
1529 fDefaultRotateY =
1530 fDefaultRotateZ = 0.0;
1531 fDefaultExtrusionDeepth = 1000; // old: 2000;
1532 fDefaultLightIntensity = 0.8; // old: 0.6;
1533 fDefaultAmbientIntensity = 0.4;
1534 nHDefaultSegments = 12;
1535 nVDefaultSegments = 12;
1536 aDefaultLightColor = RGB_Color(COL_WHITE);
1537 aDefaultAmbientColor = RGB_Color(COL_BLACK);
1538 bDoubleSided = false;
1539 mpMirrorOverlay = 0L;
1542 bool E3dView::IsBreak3DObjPossible() const
1544 const size_t nCount = GetMarkedObjectCount();
1546 if (nCount > 0)
1548 for (size_t i = 0; i < nCount; ++i)
1550 SdrObject* pObj = GetMarkedObjectByIndex(i);
1552 if (pObj && pObj->ISA(E3dObject))
1554 if(!(static_cast<E3dObject*>(pObj)->IsBreakObjPossible()))
1555 return false;
1557 else
1559 return false;
1563 else
1565 return false;
1568 return true;
1571 void E3dView::Break3DObj()
1573 if(IsBreak3DObjPossible())
1575 // ALL selected objects are changed
1576 const size_t nCount = GetMarkedObjectCount();
1578 BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_BREAK_LATHE));
1579 for(size_t a=0; a<nCount; ++a)
1581 E3dObject* pObj = static_cast<E3dObject*>(GetMarkedObjectByIndex(a));
1582 BreakSingle3DObj(pObj);
1584 DeleteMarked();
1585 EndUndo();
1589 void E3dView::BreakSingle3DObj(E3dObject* pObj)
1591 if(pObj->ISA(E3dScene))
1593 SdrObjList* pSubList = pObj->GetSubList();
1594 SdrObjListIter aIter(*pSubList, IM_FLAT);
1596 while(aIter.IsMore())
1598 E3dObject* pSubObj = static_cast<E3dObject*>(aIter.Next());
1599 BreakSingle3DObj(pSubObj);
1602 else
1604 SdrAttrObj* pNewObj = pObj->GetBreakObj();
1605 if(pNewObj)
1607 InsertObjectAtView(pNewObj, *GetSdrPageView(), SdrInsertFlags::DONTMARK);
1608 pNewObj->SetChanged();
1609 pNewObj->BroadcastObjectChange();
1614 void E3dView::CheckPossibilities()
1616 // call parent
1617 SdrView::CheckPossibilities();
1619 // Set other flags
1620 if(bGroupPossible || bUnGroupPossible || bGrpEnterPossible)
1622 const size_t nMarkCnt = GetMarkedObjectCount();
1623 bool bCoumpound = false;
1624 bool b3DObject = false;
1625 for(size_t nObjs = 0; (nObjs < nMarkCnt) && !bCoumpound; ++nObjs)
1627 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
1628 if(pObj && pObj->ISA(E3dCompoundObject))
1629 bCoumpound = true;
1630 if(pObj && pObj->ISA(E3dObject))
1631 b3DObject = true;
1634 // So far: there are two or more of any objects selected. See if
1635 // compound objects are involved. If yes, ban grouping.
1636 if(bGroupPossible && bCoumpound)
1637 bGroupPossible = false;
1639 if(bUnGroupPossible && b3DObject)
1640 bUnGroupPossible = false;
1642 if(bGrpEnterPossible && bCoumpound)
1643 bGrpEnterPossible = false;
1647 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */