fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / svx / source / engine3d / view3d.cxx
blob5f856ed538a84a538284b008b3e9c40b05b17eaf
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 <tools/shl.hxx>
25 #include "svx/svditer.hxx"
26 #include <svx/svdpool.hxx>
27 #include <svx/svdorect.hxx>
28 #include <svx/svdmodel.hxx>
29 #include <svx/svdpagv.hxx>
30 #include <svx/svxids.hrc>
31 #include <editeng/colritem.hxx>
32 #include <svx/xtable.hxx>
33 #include <svx/svdview.hxx>
34 #include <svx/dialogs.hrc>
35 #include <svx/dialmgr.hxx>
36 #include "svx/globl3d.hxx"
37 #include <svx/obj3d.hxx>
38 #include <svx/lathe3d.hxx>
39 #include <svx/sphere3d.hxx>
40 #include <svx/extrud3d.hxx>
41 #include <svx/cube3d.hxx>
42 #include <svx/polysc3d.hxx>
43 #include "dragmt3d.hxx"
44 #include <svx/view3d.hxx>
45 #include <svx/svdundo.hxx>
46 #include <svx/xflclit.hxx>
47 #include <svx/xlnclit.hxx>
48 #include <svx/svdograf.hxx>
49 #include <svx/xbtmpit.hxx>
50 #include <svx/xflbmtit.hxx>
51 #include <basegfx/range/b2drange.hxx>
52 #include <basegfx/polygon/b2dpolygontools.hxx>
53 #include <basegfx/polygon/b2dpolypolygontools.hxx>
54 #include <svx/xlnwtit.hxx>
55 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
56 #include <svx/sdr/overlay/overlaymanager.hxx>
57 #include <svx/sdrpaintwindow.hxx>
58 #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
59 #include <drawinglayer/geometry/viewinformation3d.hxx>
60 #include <svx/sdrpagewindow.hxx>
61 #include <svx/sdr/contact/displayinfo.hxx>
62 #include <svx/sdr/contact/objectcontact.hxx>
63 #include <svx/sdr/contact/viewobjectcontact.hxx>
64 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
65 #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
66 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
67 #include <basegfx/matrix/b2dhommatrixtools.hxx>
68 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
70 #define ITEMVALUE(ItemSet,Id,Cast) ((const Cast&)(ItemSet).Get(Id)).GetValue()
72 TYPEINIT1(E3dView, SdrView);
74 //////////////////////////////////////////////////////////////////////////////
75 // Migrate Marking
77 class Impl3DMirrorConstructOverlay
79 // The OverlayObjects
80 ::sdr::overlay::OverlayObjectList maObjects;
82 // the view
83 const E3dView& mrView;
85 // the object count
86 sal_uInt32 mnCount;
88 // the unmirrored polygons
89 basegfx::B2DPolyPolygon* mpPolygons;
91 // the overlay geometry from selected objects
92 drawinglayer::primitive2d::Primitive2DSequence maFullOverlay;
94 public:
95 Impl3DMirrorConstructOverlay(const E3dView& rView);
96 ~Impl3DMirrorConstructOverlay();
98 void SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB);
101 Impl3DMirrorConstructOverlay::Impl3DMirrorConstructOverlay(const E3dView& rView)
102 : maObjects(),
103 mrView(rView),
104 mnCount(rView.GetMarkedObjectCount()),
105 mpPolygons(0),
106 maFullOverlay()
108 if(mnCount)
110 if(mrView.IsSolidDragging())
112 SdrPageView* pPV = rView.GetSdrPageView();
114 if(pPV && pPV->PageWindowCount())
116 sdr::contact::ObjectContact& rOC = pPV->GetPageWindow(0)->GetObjectContact();
117 sdr::contact::DisplayInfo aDisplayInfo;
119 // Do not use the last ViewPort set at the OC at the last ProcessDisplay()
120 rOC.resetViewPort();
122 for(sal_uInt32 a(0);a < mnCount;a++)
124 SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
126 if(pObject)
128 sdr::contact::ViewContact& rVC = pObject->GetViewContact();
129 sdr::contact::ViewObjectContact& rVOC = rVC.GetViewObjectContact(rOC);
131 const drawinglayer::primitive2d::Primitive2DSequence aNewSequence(rVOC.getPrimitive2DSequenceHierarchy(aDisplayInfo));
132 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(maFullOverlay, aNewSequence);
137 else
139 mpPolygons = new basegfx::B2DPolyPolygon[mnCount];
141 for(sal_uInt32 a(0); a < mnCount; a++)
143 SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
144 mpPolygons[mnCount - (a + 1)] = pObject->TakeXorPoly();
150 Impl3DMirrorConstructOverlay::~Impl3DMirrorConstructOverlay()
152 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
153 // That destructor calls clear() at the list which removes all objects from the
154 // OverlayManager and deletes them.
155 if(!mrView.IsSolidDragging())
157 delete[] mpPolygons;
161 void Impl3DMirrorConstructOverlay::SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB)
163 // get rid of old overlay objects
164 maObjects.clear();
166 // create new ones
167 for(sal_uInt32 a(0); a < mrView.PaintWindowCount(); a++)
169 SdrPaintWindow* pCandidate = mrView.GetPaintWindow(a);
170 rtl::Reference< ::sdr::overlay::OverlayManager > xTargetOverlay = pCandidate->GetOverlayManager();
172 if(xTargetOverlay.is())
174 // buld transfoprmation: translate and rotate so that given edge is
175 // on x axis, them mirror in y and translate back
176 const basegfx::B2DVector aEdge(aMirrorAxisB.X() - aMirrorAxisA.X(), aMirrorAxisB.Y() - aMirrorAxisA.Y());
177 basegfx::B2DHomMatrix aMatrixTransform(basegfx::tools::createTranslateB2DHomMatrix(
178 -aMirrorAxisA.X(), -aMirrorAxisA.Y()));
179 aMatrixTransform.rotate(-atan2(aEdge.getY(), aEdge.getX()));
180 aMatrixTransform.scale(1.0, -1.0);
181 aMatrixTransform.rotate(atan2(aEdge.getY(), aEdge.getX()));
182 aMatrixTransform.translate(aMirrorAxisA.X(), aMirrorAxisA.Y());
184 if(mrView.IsSolidDragging())
186 if(maFullOverlay.hasElements())
188 drawinglayer::primitive2d::Primitive2DSequence aContent(maFullOverlay);
190 if(!aMatrixTransform.isIdentity())
192 // embed in transformation group
193 drawinglayer::primitive2d::Primitive2DReference aTransformPrimitive2D(new drawinglayer::primitive2d::TransformPrimitive2D(aMatrixTransform, aContent));
194 aContent = drawinglayer::primitive2d::Primitive2DSequence(&aTransformPrimitive2D, 1);
197 // if we have full overlay from selected objects, embed with 50% transparence, the
198 // transformation is added to the OverlayPrimitive2DSequenceObject
199 drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(aContent, 0.5));
200 aContent = drawinglayer::primitive2d::Primitive2DSequence(&aUnifiedTransparencePrimitive2D, 1);
202 sdr::overlay::OverlayPrimitive2DSequenceObject* pNew = new sdr::overlay::OverlayPrimitive2DSequenceObject(aContent);
204 xTargetOverlay->add(*pNew);
205 maObjects.append(*pNew);
208 else
210 for(sal_uInt32 b(0); b < mnCount; b++)
212 // apply to polygon
213 basegfx::B2DPolyPolygon aPolyPolygon(mpPolygons[b]);
214 aPolyPolygon.transform(aMatrixTransform);
216 ::sdr::overlay::OverlayPolyPolygonStriped* pNew = new ::sdr::overlay::OverlayPolyPolygonStriped(aPolyPolygon);
217 xTargetOverlay->add(*pNew);
218 maObjects.append(*pNew);
225 E3dView::E3dView(SdrModel* pModel, OutputDevice* pOut) :
226 SdrView(pModel, pOut)
228 InitView ();
231 // DrawMarkedObj overloaded, since possibly only a single 3D object is to be
232 // drawn
234 void E3dView::DrawMarkedObj(OutputDevice& rOut) const
236 // Does 3D objects exist which scenes are not selected?
237 bool bSpecialHandling = false;
238 E3dScene *pScene = NULL;
240 long nCnt = GetMarkedObjectCount();
241 for(long nObjs = 0;nObjs < nCnt;nObjs++)
243 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
244 if(pObj && pObj->ISA(E3dCompoundObject))
246 // related scene
247 pScene = ((E3dCompoundObject*)pObj)->GetScene();
248 if(pScene && !IsObjMarked(pScene))
249 bSpecialHandling = true;
251 // Reset all selection flags
252 if(pObj && pObj->ISA(E3dObject))
254 pScene = ((E3dObject*)pObj)->GetScene();
255 if(pScene)
256 pScene->SetSelected(sal_False);
260 if(bSpecialHandling)
262 // Set selection flag to "not selected" for scenes related to all 3D
263 // objects
264 long nObjs;
265 for(nObjs = 0;nObjs < nCnt;nObjs++)
267 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
268 if(pObj && pObj->ISA(E3dCompoundObject))
270 // relatated scene
271 pScene = ((E3dCompoundObject*)pObj)->GetScene();
272 if(pScene)
273 pScene->SetSelected(sal_False);
277 for(nObjs = 0;nObjs < nCnt;nObjs++)
279 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
280 if(pObj && pObj->ISA(E3dObject))
282 // Select object
283 E3dObject* p3DObj = (E3dObject*)pObj;
284 p3DObj->SetSelected(sal_True);
285 pScene = p3DObj->GetScene();
289 if(pScene)
291 // code from parent
292 SortMarkedObjects();
294 pScene->SetDrawOnlySelected(sal_True);
295 pScene->SingleObjectPainter(rOut);
296 pScene->SetDrawOnlySelected(sal_False);
299 // Reset selection flag
300 for(nObjs = 0;nObjs < nCnt;nObjs++)
302 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
303 if(pObj && pObj->ISA(E3dCompoundObject))
305 // releated scene
306 pScene = ((E3dCompoundObject*)pObj)->GetScene();
307 if(pScene)
308 pScene->SetSelected(sal_False);
312 else
314 // call parent
315 SdrExchangeView::DrawMarkedObj(rOut);
319 // Get overloaded model, since in some 3D objects an additional scene
320 // must be pushed in
322 SdrModel* E3dView::GetMarkedObjModel() const
324 // Does 3D objects exist which scenes are not selected?
325 bool bSpecialHandling(false);
326 const sal_uInt32 nCount(GetMarkedObjectCount());
327 sal_uInt32 nObjs(0);
328 E3dScene *pScene = 0;
330 for(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 = ((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 = ((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(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 = (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 = ((E3dView*)this)->GetMarkedObjectListWriteAccess();
387 rCurrentMarkList = aNewML;
389 for(nObjs = 0; nObjs < nCount; nObjs++)
391 SdrObject *pObj = aOldML.GetMark(nObjs)->GetMarkedSdrObj();
393 if(pObj && pObj->ISA(E3dObject))
395 pScene = ((E3dObject*)pObj)->GetScene();
397 if(pScene && !IsObjMarked(pScene) && GetSdrPageView())
399 ((E3dView*)this)->MarkObj(pScene, GetSdrPageView(), sal_False, sal_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 sal_uInt32 nObAnz(pSrcPg->GetObjCount());
415 for(sal_uInt32 nOb(0); nOb < nObAnz; nOb++)
417 const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
419 if(pSrcOb->ISA(E3dScene))
421 pScene = (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 sal_Bool E3dView::Paste(const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, sal_uInt32 nOptions)
445 sal_Bool bRetval = sal_False;
447 // Get list
448 Point aPos(rPos);
449 SdrObjList* pDstList = pLst;
450 ImpGetPasteObjList(aPos, pDstList);
452 if(!pDstList)
453 return sal_False;
455 // Get owner of the list
456 SdrObject* pOwner = pDstList->GetOwnerObj();
457 if(pOwner && pOwner->ISA(E3dScene))
459 E3dScene* pDstScene = (E3dScene*)pOwner;
460 BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_EXCHANGE_PASTE));
462 // Copy all objects from E3dScenes and insert them directly
463 for(sal_uInt16 nPg(0); nPg < rMod.GetPageCount(); nPg++)
465 const SdrPage* pSrcPg=rMod.GetPage(nPg);
466 sal_uInt32 nObAnz(pSrcPg->GetObjCount());
468 // calculate offset for paste
469 Rectangle aR = pSrcPg->GetAllObjBoundRect();
470 Point aDist(aPos - aR.Center());
472 // Insert sub-objects for scenes
473 for(sal_uInt32 nOb(0); nOb < nObAnz; nOb++)
475 const SdrObject* pSrcOb = pSrcPg->GetObj(nOb);
476 if(pSrcOb->ISA(E3dScene))
478 E3dScene* pSrcScene = (E3dScene*)pSrcOb;
479 ImpCloneAll3DObjectsToDestScene(pSrcScene, pDstScene, aDist);
483 EndUndo();
485 else
487 // call parent
488 bRetval = SdrView::Paste(rMod, rPos, pLst, nOptions);
491 return bRetval;
494 // Service routine used from local Clone() and from SdrCreateView::EndCreateObj(...)
495 bool E3dView::ImpCloneAll3DObjectsToDestScene(E3dScene* pSrcScene, E3dScene* pDstScene, Point /*aOffset*/)
497 bool bRetval(false);
499 if(pSrcScene && pDstScene)
501 const sdr::contact::ViewContactOfE3dScene& rVCSceneDst = static_cast< sdr::contact::ViewContactOfE3dScene& >(pDstScene->GetViewContact());
502 const drawinglayer::geometry::ViewInformation3D aViewInfo3DDst(rVCSceneDst.getViewInformation3D());
503 const sdr::contact::ViewContactOfE3dScene& rVCSceneSrc = static_cast< sdr::contact::ViewContactOfE3dScene& >(pSrcScene->GetViewContact());
504 const drawinglayer::geometry::ViewInformation3D aViewInfo3DSrc(rVCSceneSrc.getViewInformation3D());
506 for(sal_uInt32 i(0); i < pSrcScene->GetSubList()->GetObjCount(); i++)
508 E3dCompoundObject* pCompoundObj = dynamic_cast< E3dCompoundObject* >(pSrcScene->GetSubList()->GetObj(i));
510 if(pCompoundObj)
512 E3dCompoundObject* pNewCompoundObj = dynamic_cast< E3dCompoundObject* >(pCompoundObj->Clone());
514 if(pNewCompoundObj)
516 // get dest scene's current range in 3D world coordinates
517 const basegfx::B3DHomMatrix aSceneToWorldTrans(pDstScene->GetFullTransform());
518 basegfx::B3DRange aSceneRange(pDstScene->GetBoundVolume());
519 aSceneRange.transform(aSceneToWorldTrans);
521 // get new object's implied object transformation
522 const basegfx::B3DHomMatrix aNewObjectTrans(pNewCompoundObj->GetTransform());
524 // get new object's range in 3D world coordinates in dest scene
525 // as if it were already added
526 const basegfx::B3DHomMatrix aObjectToWorldTrans(aSceneToWorldTrans * aNewObjectTrans);
527 basegfx::B3DRange aObjectRange(pNewCompoundObj->GetBoundVolume());
528 aObjectRange.transform(aObjectToWorldTrans);
530 // get scale adaption
531 const basegfx::B3DVector aSceneScale(aSceneRange.getRange());
532 const basegfx::B3DVector aObjectScale(aObjectRange.getRange());
533 double fScale(1.0);
535 // if new object's size in X,Y or Z is bigger that 80% of dest scene, adapt scale
536 // to not change the scene by the inserted object
537 const double fSizeFactor(0.5);
539 if(aObjectScale.getX() * fScale > aSceneScale.getX() * fSizeFactor)
541 const double fObjSize(aObjectScale.getX() * fScale);
542 const double fFactor((aSceneScale.getX() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
543 fScale *= fFactor;
546 if(aObjectScale.getY() * fScale > aSceneScale.getY() * fSizeFactor)
548 const double fObjSize(aObjectScale.getY() * fScale);
549 const double fFactor((aSceneScale.getY() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
550 fScale *= fFactor;
553 if(aObjectScale.getZ() * fScale > aSceneScale.getZ() * fSizeFactor)
555 const double fObjSize(aObjectScale.getZ() * fScale);
556 const double fFactor((aSceneScale.getZ() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
557 fScale *= fFactor;
560 // get translation adaption
561 const basegfx::B3DPoint aSceneCenter(aSceneRange.getCenter());
562 const basegfx::B3DPoint aObjectCenter(aObjectRange.getCenter());
564 // build full modification transform. The object's transformation
565 // shall be modified, so start at object coordinates; transform to 3d world coor
566 basegfx::B3DHomMatrix aModifyingTransform(aObjectToWorldTrans);
568 // translate to absolute center in 3d world coor
569 aModifyingTransform.translate(-aObjectCenter.getX(), -aObjectCenter.getY(), -aObjectCenter.getZ());
571 // scale to dest size in 3d world coor
572 aModifyingTransform.scale(fScale, fScale, fScale);
574 // translate to dest scene center in 3d world coor
575 aModifyingTransform.translate(aSceneCenter.getX(), aSceneCenter.getY(), aSceneCenter.getZ());
577 // transform from 3d world to dest object coordinates
578 basegfx::B3DHomMatrix aWorldToObject(aObjectToWorldTrans);
579 aWorldToObject.invert();
580 aModifyingTransform = aWorldToObject * aModifyingTransform;
582 // correct implied object transform by applying changing one in object coor
583 pNewCompoundObj->SetTransform(aModifyingTransform * aNewObjectTrans);
585 // fill and insert new object
586 pNewCompoundObj->SetModel(pDstScene->GetModel());
587 pNewCompoundObj->SetPage(pDstScene->GetPage());
588 pNewCompoundObj->NbcSetLayer(pCompoundObj->GetLayer());
589 pNewCompoundObj->NbcSetStyleSheet(pCompoundObj->GetStyleSheet(), sal_True);
590 pDstScene->Insert3DObj(pNewCompoundObj);
591 bRetval = true;
593 // Create undo
594 if( GetModel()->IsUndoEnabled() )
595 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewCompoundObj));
601 return bRetval;
604 bool E3dView::IsConvertTo3DObjPossible() const
606 bool bAny3D(false);
607 bool bGroupSelected(false);
608 bool bRetval(true);
610 for(sal_uInt32 a=0;!bAny3D && a<GetMarkedObjectCount();a++)
612 SdrObject *pObj = GetMarkedObjectByIndex(a);
613 if(pObj)
615 ImpIsConvertTo3DPossible(pObj, bAny3D, bGroupSelected);
619 bRetval = !bAny3D
620 && (
621 IsConvertToPolyObjPossible(sal_False)
622 || IsConvertToPathObjPossible(sal_False)
623 || IsImportMtfPossible());
624 return bRetval;
627 void E3dView::ImpIsConvertTo3DPossible(SdrObject* pObj, bool& rAny3D,
628 bool& rGroupSelected) const
630 if(pObj)
632 if(pObj->ISA(E3dObject))
634 rAny3D = true;
636 else
638 if(pObj->IsGroupObject())
640 SdrObjListIter aIter(*pObj, IM_DEEPNOGROUPS);
641 while(aIter.IsMore())
643 SdrObject* pNewObj = aIter.Next();
644 ImpIsConvertTo3DPossible(pNewObj, rAny3D, rGroupSelected);
646 rGroupSelected = true;
652 #include <editeng/eeitem.hxx>
654 void E3dView::ImpChangeSomeAttributesFor3DConversion(SdrObject* pObj)
656 if(pObj->ISA(SdrTextObj))
658 const SfxItemSet& rSet = pObj->GetMergedItemSet();
659 const SvxColorItem& rTextColorItem = (const SvxColorItem&)rSet.Get(EE_CHAR_COLOR);
660 if(rTextColorItem.GetValue() == RGB_Color(COL_BLACK))
662 //For black text objects, the color set to gray
663 if(pObj->GetPage())
665 // if black is only default attribute from
666 // pattern set it hard so that it is used in undo.
667 pObj->SetMergedItem(SvxColorItem(RGB_Color(COL_BLACK), EE_CHAR_COLOR));
669 // add undo now
670 if( GetModel()->IsUndoEnabled() )
671 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj, false, false));
674 pObj->SetMergedItem(SvxColorItem(RGB_Color(COL_GRAY), EE_CHAR_COLOR));
679 void E3dView::ImpChangeSomeAttributesFor3DConversion2(SdrObject* pObj)
681 if(pObj->ISA(SdrPathObj))
683 const SfxItemSet& rSet = pObj->GetMergedItemSet();
684 sal_Int32 nLineWidth = ((const XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue();
685 XLineStyle eLineStyle = (XLineStyle)((const XLineStyleItem&)rSet.Get(XATTR_LINESTYLE)).GetValue();
686 XFillStyle eFillStyle = ITEMVALUE(rSet, XATTR_FILLSTYLE, XFillStyleItem);
688 if(((SdrPathObj*)pObj)->IsClosed()
689 && eLineStyle == XLINE_SOLID
690 && !nLineWidth
691 && eFillStyle != XFILL_NONE)
693 if(pObj->GetPage() && GetModel()->IsUndoEnabled() )
694 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj, false, false));
695 pObj->SetMergedItem(XLineStyleItem(XLINE_NONE));
696 pObj->SetMergedItem(XLineWidthItem(0L));
701 void E3dView::ImpCreateSingle3DObjectFlat(E3dScene* pScene, SdrObject* pObj, bool bExtrude, double fDepth, basegfx::B2DHomMatrix& rLatheMat)
703 // Single PathObject, transform this
704 SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj);
706 if(pPath)
708 E3dDefaultAttributes aDefault = Get3DDefaultAttributes();
709 if(bExtrude)
710 aDefault.SetDefaultExtrudeCharacterMode(sal_True);
711 else
712 aDefault.SetDefaultLatheCharacterMode(sal_True);
714 // Get Itemset of the original object
715 SfxItemSet aSet(pObj->GetMergedItemSet());
717 XFillStyle eFillStyle = ITEMVALUE(aSet, XATTR_FILLSTYLE, XFillStyleItem);
719 // line style turned off
720 aSet.Put(XLineStyleItem(XLINE_NONE));
722 //Determining if FILL_Attribut is set.
723 if(!pPath->IsClosed() || eFillStyle == XFILL_NONE)
725 // This SdrPathObj is not filled, leave the front and rear face out.
726 // Moreover, a two-sided representation necessary.
727 aDefault.SetDefaultExtrudeCloseFront(sal_False);
728 aDefault.SetDefaultExtrudeCloseBack(sal_False);
730 aSet.Put(Svx3DDoubleSidedItem(sal_True));
732 // Set fill attribute
733 aSet.Put(XFillStyleItem(XFILL_SOLID));
735 // Fill color must be the color line, because the object was
736 // previously just a line
737 Color aColorLine = ((const XLineColorItem&)(aSet.Get(XATTR_LINECOLOR))).GetColorValue();
738 aSet.Put(XFillColorItem(String(), aColorLine));
741 // Create a new extrude object
742 E3dObject* p3DObj = NULL;
743 if(bExtrude)
745 p3DObj = new E3dExtrudeObj(aDefault, pPath->GetPathPoly(), fDepth);
747 else
749 basegfx::B2DPolyPolygon aPolyPoly2D(pPath->GetPathPoly());
750 aPolyPoly2D.transform(rLatheMat);
751 p3DObj = new E3dLatheObj(aDefault, aPolyPoly2D);
754 // Set attribute
755 if(p3DObj)
757 p3DObj->NbcSetLayer(pObj->GetLayer());
759 p3DObj->SetMergedItemSet(aSet);
761 p3DObj->NbcSetStyleSheet(pObj->GetStyleSheet(), sal_True);
763 // Insert a new extrude object
764 pScene->Insert3DObj(p3DObj);
769 void E3dView::ImpCreate3DObject(E3dScene* pScene, SdrObject* pObj, bool bExtrude, double fDepth, basegfx::B2DHomMatrix& rLatheMat)
771 if(pObj)
773 // change text color attribute for not so dark colors
774 if(pObj->IsGroupObject())
776 SdrObjListIter aIter(*pObj, IM_DEEPWITHGROUPS);
777 while(aIter.IsMore())
779 SdrObject* pGroupMember = aIter.Next();
780 ImpChangeSomeAttributesFor3DConversion(pGroupMember);
783 else
784 ImpChangeSomeAttributesFor3DConversion(pObj);
786 // convert completely to path objects
787 SdrObject* pNewObj1 = pObj->ConvertToPolyObj(sal_False, sal_False);
789 if(pNewObj1)
791 // change text color attribute for not so dark colors
792 if(pNewObj1->IsGroupObject())
794 SdrObjListIter aIter(*pNewObj1, IM_DEEPWITHGROUPS);
795 while(aIter.IsMore())
797 SdrObject* pGroupMember = aIter.Next();
798 ImpChangeSomeAttributesFor3DConversion2(pGroupMember);
801 else
802 ImpChangeSomeAttributesFor3DConversion2(pNewObj1);
804 // convert completely to path objects
805 SdrObject* pNewObj2 = pObj->ConvertToContourObj(pNewObj1, sal_True);
807 if(pNewObj2)
809 // add all to flat scene
810 if(pNewObj2->IsGroupObject())
812 SdrObjListIter aIter(*pNewObj2, IM_DEEPWITHGROUPS);
813 while(aIter.IsMore())
815 SdrObject* pGroupMember = aIter.Next();
816 ImpCreateSingle3DObjectFlat(pScene, pGroupMember, bExtrude, fDepth, rLatheMat);
819 else
820 ImpCreateSingle3DObjectFlat(pScene, pNewObj2, bExtrude, fDepth, rLatheMat);
822 // delete object in between
823 if(pNewObj2 != pObj && pNewObj2 != pNewObj1 && pNewObj2)
824 SdrObject::Free( pNewObj2 );
827 // delete object in between
828 if(pNewObj1 != pObj && pNewObj1)
829 SdrObject::Free( pNewObj1 );
834 void E3dView::ConvertMarkedObjTo3D(bool bExtrude, basegfx::B2DPoint aPnt1, basegfx::B2DPoint aPnt2)
836 if(AreObjectsMarked())
838 // Create undo
839 if(bExtrude)
840 BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_EXTRUDE));
841 else
842 BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_LATHE));
844 // Create a new scene for the created 3D object
845 E3dScene* pScene = new E3dPolyScene(Get3DDefaultAttributes());
847 // Determine rectangle and possibly correct it
848 Rectangle aRect = GetAllMarkedRect();
849 if(aRect.GetWidth() <= 1)
850 aRect.SetSize(Size(500, aRect.GetHeight()));
851 if(aRect.GetHeight() <= 1)
852 aRect.SetSize(Size(aRect.GetWidth(), 500));
854 // Determine the depth relative to the size of the selection
855 double fDepth = 0.0;
856 double fRot3D = 0.0;
857 basegfx::B2DHomMatrix aLatheMat;
859 if(bExtrude)
861 double fW = (double)aRect.GetWidth();
862 double fH = (double)aRect.GetHeight();
863 fDepth = sqrt(fW*fW + fH*fH) / 6.0;
865 if(!bExtrude)
867 // Create transformation for the polygons rotating body
868 if(aPnt1 != aPnt2)
870 // Rotation around control point #1 with set angle
871 // for 3D coordinates
872 basegfx::B2DPoint aDiff(aPnt1 - aPnt2);
873 fRot3D = atan2(aDiff.getY(), aDiff.getX()) - F_PI2;
875 if(basegfx::fTools::equalZero(fabs(fRot3D)))
876 fRot3D = 0.0;
878 if(fRot3D != 0.0)
880 aLatheMat = basegfx::tools::createRotateAroundPoint(aPnt2, -fRot3D)
881 * aLatheMat;
885 if(aPnt2.getX() != 0.0)
887 // Translation to Y=0 - axis
888 aLatheMat.translate(-aPnt2.getX(), 0.0);
890 else
892 aLatheMat.translate((double)-aRect.Left(), 0.0);
895 // Form the inverse matrix to determine the target expansion
896 basegfx::B2DHomMatrix aInvLatheMat(aLatheMat);
897 aInvLatheMat.invert();
899 // SnapRect extension enables mirroring in the axis of rotation
900 for(sal_uInt32 a=0;a<GetMarkedObjectCount();a++)
902 SdrMark* pMark = GetSdrMarkByIndex(a);
903 SdrObject* pObj = pMark->GetMarkedSdrObj();
904 Rectangle aTurnRect = pObj->GetSnapRect();
905 basegfx::B2DPoint aRot;
906 Point aRotPnt;
908 aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Top());
909 aRot *= aLatheMat;
910 aRot.setX(-aRot.getX());
911 aRot *= aInvLatheMat;
912 aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
913 aRect.Union(Rectangle(aRotPnt, aRotPnt));
915 aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Bottom());
916 aRot *= aLatheMat;
917 aRot.setX(-aRot.getX());
918 aRot *= aInvLatheMat;
919 aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
920 aRect.Union(Rectangle(aRotPnt, aRotPnt));
922 aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Top());
923 aRot *= aLatheMat;
924 aRot.setX(-aRot.getX());
925 aRot *= aInvLatheMat;
926 aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
927 aRect.Union(Rectangle(aRotPnt, aRotPnt));
929 aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Bottom());
930 aRot *= aLatheMat;
931 aRot.setX(-aRot.getX());
932 aRot *= aInvLatheMat;
933 aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
934 aRect.Union(Rectangle(aRotPnt, aRotPnt));
938 // Walk throguh the selection and convert it into 3D, complete with
939 // Convertion to SdrPathObject, also fonts
940 for(sal_uInt32 a=0;a<GetMarkedObjectCount();a++)
942 SdrMark* pMark = GetSdrMarkByIndex(a);
943 SdrObject* pObj = pMark->GetMarkedSdrObj();
945 ImpCreate3DObject(pScene, pObj, bExtrude, fDepth, aLatheMat);
948 if(pScene->GetSubList() && pScene->GetSubList()->GetObjCount() != 0)
950 // Arrange all created objects by depth
951 if(bExtrude)
952 DoDepthArrange(pScene, fDepth);
954 // Center 3D objects in the middle of the overall rectangle
955 basegfx::B3DPoint aCenter(pScene->GetBoundVolume().getCenter());
956 basegfx::B3DHomMatrix aMatrix;
958 aMatrix.translate(-aCenter.getX(), -aCenter.getY(), -aCenter.getZ());
959 pScene->SetTransform(aMatrix * pScene->GetTransform());
961 // Initialize scene
962 pScene->NbcSetSnapRect(aRect);
963 basegfx::B3DRange aBoundVol = pScene->GetBoundVolume();
964 InitScene(pScene, (double)aRect.GetWidth(), (double)aRect.GetHeight(), aBoundVol.getDepth());
966 // Insert scene instead of the first selected object and throw away
967 // all the old objects
968 SdrObject* pRepObj = GetMarkedObjectByIndex(0);
969 SdrPageView* pPV = GetSdrPageViewOfMarkedByIndex(0);
970 MarkObj(pRepObj, pPV, sal_True);
971 ReplaceObjectAtView(pRepObj, *pPV, pScene, sal_False);
972 DeleteMarked();
973 MarkObj(pScene, pPV);
975 // Rotate Rotation body around the axis of rotation
976 basegfx::B3DHomMatrix aRotate;
978 if(!bExtrude && fRot3D != 0.0)
980 aRotate.rotate(0.0, 0.0, fRot3D);
983 // Set default rotation
985 double XRotateDefault = 20;
986 aRotate.rotate(DEG2RAD(XRotateDefault), 0.0, 0.0);
989 if(!aRotate.isIdentity())
991 pScene->SetTransform(aRotate * pScene->GetTransform());
994 // Invalid SnapRects of objects
995 pScene->SetSnapRect(aRect);
997 else
999 // No 3D object was created, throw away everything
1000 delete pScene;
1003 EndUndo();
1007 //Arrange all created extrude objects by depth
1009 struct E3dDepthNeighbour
1011 E3dDepthNeighbour* mpNext;
1012 E3dExtrudeObj* mpObj;
1013 basegfx::B2DPolyPolygon maPreparedPolyPolygon;
1015 E3dDepthNeighbour()
1016 : mpNext(0),
1017 mpObj(0),
1018 maPreparedPolyPolygon()
1023 struct E3dDepthLayer
1025 E3dDepthLayer* mpDown;
1026 E3dDepthNeighbour* mpNext;
1028 E3dDepthLayer()
1029 : mpDown(0),
1030 mpNext(0)
1034 ~E3dDepthLayer()
1036 while(mpNext)
1038 E3dDepthNeighbour* pSucc = mpNext->mpNext;
1039 delete mpNext;
1040 mpNext = pSucc;
1045 void E3dView::DoDepthArrange(E3dScene* pScene, double fDepth)
1047 if(pScene && pScene->GetSubList() && pScene->GetSubList()->GetObjCount() > 1)
1049 SdrObjList* pSubList = pScene->GetSubList();
1050 SdrObjListIter aIter(*pSubList, IM_FLAT);
1051 E3dDepthLayer* pBaseLayer = NULL;
1052 E3dDepthLayer* pLayer = NULL;
1053 sal_Int32 nNumLayers = 0;
1055 while(aIter.IsMore())
1057 E3dExtrudeObj* pExtrudeObj = dynamic_cast< E3dExtrudeObj* >(aIter.Next());
1059 if(pExtrudeObj)
1061 const basegfx::B2DPolyPolygon aExtrudePoly(
1062 basegfx::tools::prepareForPolygonOperation(pExtrudeObj->GetExtrudePolygon()));
1063 const SfxItemSet& rLocalSet = pExtrudeObj->GetMergedItemSet();
1064 const XFillStyle eLocalFillStyle = ITEMVALUE(rLocalSet, XATTR_FILLSTYLE, XFillStyleItem);
1065 const Color aLocalColor = ((const XFillColorItem&)(rLocalSet.Get(XATTR_FILLCOLOR))).GetColorValue();
1067 // sort in ExtrudeObj
1068 if(pLayer)
1070 // do we have overlap with an object of this layer?
1071 bool bOverlap(false);
1072 E3dDepthNeighbour* pAct = pLayer->mpNext;
1074 while(!bOverlap && pAct)
1076 // do pAct->mpObj and pExtrudeObj overlap? Check by
1077 // using logical AND clipping
1078 const basegfx::B2DPolyPolygon aAndPolyPolygon(
1079 basegfx::tools::solvePolygonOperationAnd(
1080 aExtrudePoly,
1081 pAct->maPreparedPolyPolygon));
1083 bOverlap = (0 != aAndPolyPolygon.count());
1085 if(bOverlap)
1087 // second ciriteria: is another fillstyle or color used?
1088 const SfxItemSet& rCompareSet = pAct->mpObj->GetMergedItemSet();
1090 XFillStyle eCompareFillStyle = ITEMVALUE(rCompareSet, XATTR_FILLSTYLE, XFillStyleItem);
1092 if(eLocalFillStyle == eCompareFillStyle)
1094 if(eLocalFillStyle == XFILL_SOLID)
1096 Color aCompareColor = ((const XFillColorItem&)(rCompareSet.Get(XATTR_FILLCOLOR))).GetColorValue();
1098 if(aCompareColor == aLocalColor)
1100 bOverlap = false;
1103 else if(eLocalFillStyle == XFILL_NONE)
1105 bOverlap = false;
1110 pAct = pAct->mpNext;
1113 if(bOverlap)
1115 // yes, start a new layer
1116 pLayer->mpDown = new E3dDepthLayer;
1117 pLayer = pLayer->mpDown;
1118 nNumLayers++;
1119 pLayer->mpNext = new E3dDepthNeighbour;
1120 pLayer->mpNext->mpObj = pExtrudeObj;
1121 pLayer->mpNext->maPreparedPolyPolygon = aExtrudePoly;
1123 else
1125 // no, add to current layer
1126 E3dDepthNeighbour* pNewNext = new E3dDepthNeighbour;
1127 pNewNext->mpObj = pExtrudeObj;
1128 pNewNext->maPreparedPolyPolygon = aExtrudePoly;
1129 pNewNext->mpNext = pLayer->mpNext;
1130 pLayer->mpNext = pNewNext;
1133 else
1135 // first layer ever
1136 pBaseLayer = new E3dDepthLayer;
1137 pLayer = pBaseLayer;
1138 nNumLayers++;
1139 pLayer->mpNext = new E3dDepthNeighbour;
1140 pLayer->mpNext->mpObj = pExtrudeObj;
1141 pLayer->mpNext->maPreparedPolyPolygon = aExtrudePoly;
1146 // number of layers is done
1147 if(nNumLayers > 1)
1149 // need to be arranged
1150 double fMinDepth = fDepth * 0.8;
1151 double fStep = (fDepth - fMinDepth) / (double)nNumLayers;
1152 pLayer = pBaseLayer;
1154 while(pLayer)
1156 // move along layer
1157 E3dDepthNeighbour* pAct = pLayer->mpNext;
1159 while(pAct)
1161 // adapt extrude value
1162 pAct->mpObj->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH, sal_uInt32(fMinDepth + 0.5)));
1164 // next
1165 pAct = pAct->mpNext;
1168 // next layer
1169 pLayer = pLayer->mpDown;
1170 fMinDepth += fStep;
1174 // cleanup
1175 while(pBaseLayer)
1177 pLayer = pBaseLayer->mpDown;
1178 delete pBaseLayer;
1179 pBaseLayer = pLayer;
1184 // Start drag, create for 3D objects before possibly drag method
1186 sal_Bool E3dView::BegDragObj(const Point& rPnt, OutputDevice* pOut,
1187 SdrHdl* pHdl, short nMinMov,
1188 SdrDragMethod* pForcedMeth)
1190 if(Is3DRotationCreationActive() && GetMarkedObjectCount())
1192 // Determine all selected polygons and return rhe mirrored helper overlay
1193 mpMirrorOverlay->SetMirrorAxis(aRef1, aRef2);
1195 else
1197 bool bOwnActionNecessary;
1198 if (pHdl == NULL)
1200 bOwnActionNecessary = true;
1202 else if (pHdl->IsVertexHdl() || pHdl->IsCornerHdl())
1204 bOwnActionNecessary = true;
1206 else
1208 bOwnActionNecessary = false;
1211 if(bOwnActionNecessary && GetMarkedObjectCount() >= 1)
1213 E3dDragConstraint eConstraint = E3DDRAG_CONSTR_XYZ;
1214 bool bThereAreRootScenes = false;
1215 bool bThereAre3DObjects = false;
1216 long nCnt = GetMarkedObjectCount();
1217 for(long nObjs = 0;nObjs < nCnt;nObjs++)
1219 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
1220 if(pObj)
1222 if(pObj->ISA(E3dScene) && ((E3dScene*)pObj)->GetScene() == pObj)
1223 bThereAreRootScenes = true;
1224 if(pObj->ISA(E3dObject))
1225 bThereAre3DObjects = true;
1228 if( bThereAre3DObjects )
1230 eDragHdl = ( pHdl == NULL ? HDL_MOVE : pHdl->GetKind() );
1231 switch ( eDragMode )
1233 case SDRDRAG_ROTATE:
1234 case SDRDRAG_SHEAR:
1236 switch ( eDragHdl )
1238 case HDL_LEFT:
1239 case HDL_RIGHT:
1241 eConstraint = E3DDRAG_CONSTR_X;
1243 break;
1245 case HDL_UPPER:
1246 case HDL_LOWER:
1248 eConstraint = E3DDRAG_CONSTR_Y;
1250 break;
1252 case HDL_UPLFT:
1253 case HDL_UPRGT:
1254 case HDL_LWLFT:
1255 case HDL_LWRGT:
1257 eConstraint = E3DDRAG_CONSTR_Z;
1259 break;
1260 default: break;
1263 // do not mask the allowed rotations
1264 eConstraint = E3dDragConstraint(eConstraint& eDragConstraint);
1265 pForcedMeth = new E3dDragRotate(*this, GetMarkedObjectList(), eConstraint, IsSolidDragging());
1267 break;
1269 case SDRDRAG_MOVE:
1271 if(!bThereAreRootScenes)
1273 pForcedMeth = new E3dDragMove(*this, GetMarkedObjectList(), eDragHdl, eConstraint, IsSolidDragging());
1276 break;
1278 // later on
1279 case SDRDRAG_MIRROR:
1280 case SDRDRAG_CROOK:
1281 case SDRDRAG_DISTORT:
1282 case SDRDRAG_TRANSPARENCE:
1283 case SDRDRAG_GRADIENT:
1284 default:
1287 break;
1292 return SdrView::BegDragObj(rPnt, pOut, pHdl, nMinMov, pForcedMeth);
1295 // Set current 3D drawing object, create the scene for this
1297 E3dScene* E3dView::SetCurrent3DObj(E3dObject* p3DObj)
1299 DBG_ASSERT(p3DObj != NULL, "Who puts in a NULL-pointer here");
1300 E3dScene* pScene = NULL;
1302 // get transformed BoundVolume of the object
1303 basegfx::B3DRange aVolume(p3DObj->GetBoundVolume());
1304 aVolume.transform(p3DObj->GetTransform());
1305 double fW(aVolume.getWidth());
1306 double fH(aVolume.getHeight());
1308 Rectangle aRect(0,0, (long) fW, (long) fH);
1310 pScene = new E3dPolyScene(Get3DDefaultAttributes());
1312 InitScene(pScene, fW, fH, aVolume.getMaxZ() + ((fW + fH) / 4.0));
1314 pScene->Insert3DObj(p3DObj);
1315 pScene->NbcSetSnapRect(aRect);
1317 return pScene;
1320 void E3dView::InitScene(E3dScene* pScene, double fW, double fH, double fCamZ)
1322 Camera3D aCam(pScene->GetCamera());
1324 aCam.SetAutoAdjustProjection(sal_False);
1325 aCam.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
1326 basegfx::B3DPoint aLookAt;
1328 double fDefaultCamPosZ = GetDefaultCamPosZ();
1329 basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
1331 aCam.SetPosAndLookAt(aCamPos, aLookAt);
1332 aCam.SetFocalLength(GetDefaultCamFocal());
1333 aCam.SetDefaults(basegfx::B3DPoint(0.0, 0.0, fDefaultCamPosZ), aLookAt, GetDefaultCamFocal());
1334 pScene->SetCamera(aCam);
1337 void E3dView::Start3DCreation()
1339 if (GetMarkedObjectCount())
1341 //positioned
1342 long nOutMin = 0;
1343 long nOutMax = 0;
1344 long nMinLen = 0;
1345 long nObjDst = 0;
1346 long nOutHgt = 0;
1347 OutputDevice* pOut = GetFirstOutputDevice();
1349 // first determine representation boundaries
1350 if (pOut != NULL)
1352 nMinLen = pOut->PixelToLogic(Size(0,50)).Height();
1353 nObjDst = pOut->PixelToLogic(Size(0,20)).Height();
1355 long nDst = pOut->PixelToLogic(Size(0,10)).Height();
1357 nOutMin = -pOut->GetMapMode().GetOrigin().Y();
1358 nOutMax = pOut->GetOutputSize().Height() - 1 + nOutMin;
1359 nOutMin += nDst;
1360 nOutMax -= nDst;
1362 if (nOutMax - nOutMin < nDst)
1364 nOutMin += nOutMax + 1;
1365 nOutMin /= 2;
1366 nOutMin -= (nDst + 1) / 2;
1367 nOutMax = nOutMin + nDst;
1370 nOutHgt = nOutMax - nOutMin;
1372 long nTemp = nOutHgt / 4;
1373 if (nTemp > nMinLen) nMinLen = nTemp;
1376 // and then attach the marks at the top and bottom of the object
1377 basegfx::B2DRange aR;
1378 for(sal_uInt32 nMark(0L); nMark < GetMarkedObjectCount(); nMark++)
1380 SdrObject* pMark = GetMarkedObjectByIndex(nMark);
1381 basegfx::B2DPolyPolygon aXPP(pMark->TakeXorPoly());
1382 aR.expand(basegfx::tools::getRange(aXPP));
1385 basegfx::B2DPoint aCenter(aR.getCenter());
1386 long nMarkHgt = basegfx::fround(aR.getHeight()) - 1;
1387 long nHgt = nMarkHgt + nObjDst * 2;
1389 if (nHgt < nMinLen) nHgt = nMinLen;
1391 long nY1 = basegfx::fround(aCenter.getY()) - (nHgt + 1) / 2;
1392 long nY2 = nY1 + nHgt;
1394 if (pOut && (nMinLen > nOutHgt)) nMinLen = nOutHgt;
1395 if (pOut)
1397 if (nY1 < nOutMin)
1399 nY1 = nOutMin;
1400 if (nY2 < nY1 + nMinLen) nY2 = nY1 + nMinLen;
1402 if (nY2 > nOutMax)
1404 nY2 = nOutMax;
1405 if (nY1 > nY2 - nMinLen) nY1 = nY2 - nMinLen;
1409 aRef1.X() = basegfx::fround(aR.getMinX()); // Initial move axis 2/100mm to the left
1410 aRef1.Y() = nY1;
1411 aRef2.X() = aRef1.X();
1412 aRef2.Y() = nY2;
1414 // Turn on marks
1415 SetMarkHandles();
1417 //HMHif (bVis) ShowMarkHdl();
1418 if (AreObjectsMarked()) MarkListHasChanged();
1420 // Show mirror polygon IMMEDIATELY
1421 const SdrHdlList &aHdlList = GetHdlList();
1422 mpMirrorOverlay = new Impl3DMirrorConstructOverlay(*this);
1423 mpMirrorOverlay->SetMirrorAxis(aHdlList.GetHdl(HDL_REF1)->GetPos(), aHdlList.GetHdl(HDL_REF2)->GetPos());
1427 // what happens with a mouse movement when the object is created?
1429 void E3dView::MovAction(const Point& rPnt)
1431 if(Is3DRotationCreationActive())
1433 SdrHdl* pHdl = GetDragHdl();
1435 if (pHdl)
1437 SdrHdlKind eHdlKind = pHdl->GetKind();
1439 // reacts only due to a mirror axis
1440 if ((eHdlKind == HDL_REF1) ||
1441 (eHdlKind == HDL_REF2) ||
1442 (eHdlKind == HDL_MIRX))
1444 const SdrHdlList &aHdlList = GetHdlList ();
1446 // delete the mirroed polygon, mirrors the original and draws
1447 // it anew
1448 SdrView::MovAction (rPnt);
1449 mpMirrorOverlay->SetMirrorAxis(
1450 aHdlList.GetHdl (HDL_REF1)->GetPos(),
1451 aHdlList.GetHdl (HDL_REF2)->GetPos());
1454 else
1456 SdrView::MovAction (rPnt);
1459 else
1461 SdrView::MovAction (rPnt);
1465 // The End. Create object and any child objects through ImpCreate3DLathe.
1466 // With the parameter value sal_True (SDefault: sal_False) is simply a
1467 // rotation body created, without letting the user set the position of the
1468 // axis. It is sufficient with this call, if an object is selected.
1469 // (No initialization necessary)
1471 void E3dView::End3DCreation(bool bUseDefaultValuesForMirrorAxes)
1473 ResetCreationActive();
1475 if(AreObjectsMarked())
1477 if(bUseDefaultValuesForMirrorAxes)
1479 Rectangle aRect = GetAllMarkedRect();
1480 if(aRect.GetWidth() <= 1)
1481 aRect.SetSize(Size(500, aRect.GetHeight()));
1482 if(aRect.GetHeight() <= 1)
1483 aRect.SetSize(Size(aRect.GetWidth(), 500));
1485 basegfx::B2DPoint aPnt1(aRect.Left(), -aRect.Top());
1486 basegfx::B2DPoint aPnt2(aRect.Left(), -aRect.Bottom());
1488 ConvertMarkedObjTo3D(false, aPnt1, aPnt2);
1490 else
1492 // Turn off helper overlay
1493 // Determine from the handle positions and the displacement of
1494 // the points
1495 const SdrHdlList &aHdlList = GetHdlList();
1496 Point aMirrorRef1 = aHdlList.GetHdl(HDL_REF1)->GetPos();
1497 Point aMirrorRef2 = aHdlList.GetHdl(HDL_REF2)->GetPos();
1499 basegfx::B2DPoint aPnt1(aMirrorRef1.X(), -aMirrorRef1.Y());
1500 basegfx::B2DPoint aPnt2(aMirrorRef2.X(), -aMirrorRef2.Y());
1502 ConvertMarkedObjTo3D(false, aPnt1, aPnt2);
1507 E3dView::~E3dView ()
1511 void E3dView::ResetCreationActive ()
1513 if(mpMirrorOverlay)
1515 delete mpMirrorOverlay;
1516 mpMirrorOverlay = 0L;
1520 void E3dView::InitView ()
1522 eDragConstraint = E3DDRAG_CONSTR_XYZ;
1523 fDefaultScaleX =
1524 fDefaultScaleY =
1525 fDefaultScaleZ = 1.0;
1526 fDefaultRotateX =
1527 fDefaultRotateY =
1528 fDefaultRotateZ = 0.0;
1529 fDefaultExtrusionDeepth = 1000; // old: 2000;
1530 fDefaultLightIntensity = 0.8; // old: 0.6;
1531 fDefaultAmbientIntensity = 0.4;
1532 nHDefaultSegments = 12;
1533 nVDefaultSegments = 12;
1534 aDefaultLightColor = RGB_Color(COL_WHITE);
1535 aDefaultAmbientColor = RGB_Color(COL_BLACK);
1536 bDoubleSided = sal_False;
1537 mpMirrorOverlay = 0L;
1540 bool E3dView::IsBreak3DObjPossible() const
1542 sal_uIntPtr nCount = GetMarkedObjectCount();
1544 if (nCount > 0)
1546 sal_uIntPtr i = 0;
1548 while (i < nCount)
1550 SdrObject* pObj = GetMarkedObjectByIndex(i);
1552 if (pObj && pObj->ISA(E3dObject))
1554 if(!(((E3dObject*)pObj)->IsBreakObjPossible()))
1555 return false;
1557 else
1559 return false;
1562 i++;
1565 else
1567 return false;
1570 return true;
1573 void E3dView::Break3DObj()
1575 if(IsBreak3DObjPossible())
1577 // ALL selected objects are changed
1578 sal_uInt32 nCount = GetMarkedObjectCount();
1580 BegUndo(String(SVX_RESSTR(RID_SVX_3D_UNDO_BREAK_LATHE)));
1581 for(sal_uInt32 a=0;a<nCount;a++)
1583 E3dObject* pObj = (E3dObject*)GetMarkedObjectByIndex(a);
1584 BreakSingle3DObj(pObj);
1586 DeleteMarked();
1587 EndUndo();
1591 void E3dView::BreakSingle3DObj(E3dObject* pObj)
1593 if(pObj->ISA(E3dScene))
1595 SdrObjList* pSubList = pObj->GetSubList();
1596 SdrObjListIter aIter(*pSubList, IM_FLAT);
1598 while(aIter.IsMore())
1600 E3dObject* pSubObj = (E3dObject*)aIter.Next();
1601 BreakSingle3DObj(pSubObj);
1604 else
1606 SdrAttrObj* pNewObj = pObj->GetBreakObj();
1607 if(pNewObj)
1609 InsertObjectAtView(pNewObj, *GetSdrPageView(), SDRINSERT_DONTMARK);
1610 pNewObj->SetChanged();
1611 pNewObj->BroadcastObjectChange();
1616 void E3dView::CheckPossibilities()
1618 // call parent
1619 SdrView::CheckPossibilities();
1621 // Set other flags
1622 if(bGroupPossible || bUnGroupPossible || bGrpEnterPossible)
1624 sal_Int32 nMarkCnt = GetMarkedObjectCount();
1625 bool bCoumpound = false;
1626 bool b3DObject = false;
1627 for(sal_Int32 nObjs = 0L; (nObjs < nMarkCnt) && !bCoumpound; nObjs++)
1629 SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
1630 if(pObj && pObj->ISA(E3dCompoundObject))
1631 bCoumpound = true;
1632 if(pObj && pObj->ISA(E3dObject))
1633 b3DObject = true;
1636 // So far: there are two or more of any objects selected. See if
1637 // compound objects are involved. If yes, ban grouping.
1638 if(bGroupPossible && bCoumpound)
1639 bGroupPossible = sal_False;
1641 if(bUnGroupPossible && b3DObject)
1642 bUnGroupPossible = sal_False;
1644 if(bGrpEnterPossible && bCoumpound)
1645 bGrpEnterPossible = sal_False;
1649 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */