bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / engine3d / obj3d.cxx
blobef50b3da671f384df4791b5a2adc874203c0a63c
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 .
20 #include <o3tl/numeric.hxx>
22 #include "svx/svdstr.hrc"
23 #include "svdglob.hxx"
24 #include <svx/svdview.hxx>
25 #include <svx/svdattr.hxx>
26 #include <svx/svdpage.hxx>
27 #include <svx/svdmodel.hxx>
28 #include "svx/svditer.hxx"
29 #include "svx/globl3d.hxx"
30 #include <svx/camera3d.hxx>
31 #include <svx/scene3d.hxx>
32 #include <svx/polysc3d.hxx>
33 #include <svx/cube3d.hxx>
34 #include <svx/lathe3d.hxx>
35 #include <svx/sphere3d.hxx>
36 #include <svx/extrud3d.hxx>
37 #include <svx/obj3d.hxx>
38 #include <svx/xtable.hxx>
39 #include <svx/xflclit.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/settings.hxx>
42 #include <svx/xlnclit.hxx>
43 #include <svl/metitem.hxx>
44 #include <svx/xfillit.hxx>
45 #include <svx/xlnwtit.hxx>
46 #include <vcl/virdev.hxx>
47 #include <tools/poly.hxx>
48 #include <tools/b3dtrans.hxx>
49 #include <svx/svxids.hrc>
50 #include <editeng/colritem.hxx>
51 #include <svx/e3ditem.hxx>
52 #include <svx/xlntrit.hxx>
53 #include <svx/xfltrit.hxx>
54 #include <svx/svdpagv.hxx>
55 #include <vcl/gradient.hxx>
56 #include <vcl/metaact.hxx>
57 #include <svx/svx3ditems.hxx>
58 #include <svl/whiter.hxx>
59 #include <svtools/colorcfg.hxx>
60 #include <editeng/eeitem.hxx>
61 #include <svx/xgrscit.hxx>
62 #include <sdr/properties/e3dproperties.hxx>
63 #include <sdr/properties/e3dcompoundproperties.hxx>
64 #include <basegfx/polygon/b3dpolypolygontools.hxx>
65 #include <basegfx/point/b3dpoint.hxx>
66 #include <basegfx/vector/b3dvector.hxx>
67 #include <svx/xlndsit.hxx>
68 #include <basegfx/matrix/b3dhommatrix.hxx>
69 #include <basegfx/polygon/b3dpolygon.hxx>
70 #include <basegfx/matrix/b2dhommatrix.hxx>
71 #include <basegfx/polygon/b2dpolypolygontools.hxx>
72 #include <basegfx/polygon/b3dpolygontools.hxx>
73 #include <svx/helperhittest3d.hxx>
74 #include <svx/sdr/contact/viewcontactofe3d.hxx>
75 #include <drawinglayer/geometry/viewinformation3d.hxx>
76 #include <com/sun/star/uno/Sequence.h>
77 #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
78 #include <svx/e3dsceneupdater.hxx>
82 using namespace com::sun::star;
85 // List for 3D-Objects
87 TYPEINIT1(E3dObjList, SdrObjList);
89 E3dObjList::E3dObjList(SdrModel* pNewModel, SdrPage* pNewPage, E3dObjList* pNewUpList)
90 : SdrObjList(pNewModel, pNewPage, pNewUpList)
94 E3dObjList::E3dObjList(const E3dObjList&)
95 : SdrObjList()
99 E3dObjList* E3dObjList::Clone() const
101 E3dObjList* const pObjList = new E3dObjList(*this);
102 pObjList->lateInit(*this);
103 return pObjList;
106 E3dObjList::~E3dObjList()
110 void E3dObjList::NbcInsertObject(SdrObject* pObj, size_t nPos, const SdrInsertReason* pReason)
112 // Get owner
113 DBG_ASSERT(GetOwnerObj()->ISA(E3dObject), "Insert 3D object in parent != 3DObject");
115 // Is it even a 3D object?
116 if(pObj && pObj->ISA(E3dObject))
118 // Normal 3D object, insert means
119 // call parent
120 SdrObjList::NbcInsertObject(pObj, nPos, pReason);
122 else
124 // No 3D object, inserted a page in place in a scene ...
125 GetOwnerObj()->GetPage()->InsertObject(pObj, nPos);
129 void E3dObjList::InsertObject(SdrObject* pObj, size_t nPos, const SdrInsertReason* pReason)
131 OSL_ENSURE(GetOwnerObj()->ISA(E3dObject), "Insert 3D object in non-3D Parent");
133 // call parent
134 SdrObjList::InsertObject(pObj, nPos, pReason);
136 E3dScene* pScene = static_cast<E3dObject*>(GetOwnerObj())->GetScene();
137 if(pScene)
139 pScene->Cleanup3DDepthMapper();
143 SdrObject* E3dObjList::NbcRemoveObject(size_t nObjNum)
145 DBG_ASSERT(GetOwnerObj()->ISA(E3dObject), "Remove 3D object from Parent != 3DObject");
147 // call parent
148 SdrObject* pRetval = SdrObjList::NbcRemoveObject(nObjNum);
150 E3dScene* pScene = static_cast<E3dObject*>(GetOwnerObj())->GetScene();
151 if(pScene)
153 pScene->Cleanup3DDepthMapper();
156 return pRetval;
159 SdrObject* E3dObjList::RemoveObject(size_t nObjNum)
161 OSL_ENSURE(GetOwnerObj()->ISA(E3dObject), "3D object is removed from non-3D Parent");
163 // call parent
164 SdrObject* pRetval = SdrObjList::RemoveObject(nObjNum);
166 E3dScene* pScene = static_cast<E3dObject*>(GetOwnerObj())->GetScene();
167 if(pScene)
169 pScene->Cleanup3DDepthMapper();
172 return pRetval;
177 sdr::properties::BaseProperties* E3dObject::CreateObjectSpecificProperties()
179 return new sdr::properties::E3dProperties(*this);
184 TYPEINIT1(E3dObject, SdrAttrObj);
186 E3dObject::E3dObject()
187 : maSubList(),
188 maLocalBoundVol(),
189 maTransformation(),
190 maFullTransform(),
191 mbTfHasChanged(true),
192 mbIsSelected(false)
194 bIs3DObj = true;
195 maSubList.SetOwnerObj(this);
196 maSubList.SetListKind(SDROBJLIST_GROUPOBJ);
197 bClosedObj = true;
200 E3dObject::~E3dObject()
204 void E3dObject::SetSelected(bool bNew)
206 if((bool)mbIsSelected != bNew)
208 mbIsSelected = bNew;
211 for(size_t a = 0; a < maSubList.GetObjCount(); ++a)
213 E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
215 if(pCandidate)
217 pCandidate->SetSelected(bNew);
222 // Break, default implementations
224 bool E3dObject::IsBreakObjPossible()
226 return false;
229 SdrAttrObj* E3dObject::GetBreakObj()
231 return 0L;
234 // SetRectsDirty must be done through the local SdrSubList
236 void E3dObject::SetRectsDirty(bool bNotMyself)
238 // call parent
239 SdrAttrObj::SetRectsDirty(bNotMyself);
241 for(size_t a = 0; a < maSubList.GetObjCount(); ++a)
243 E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
245 if(pCandidate)
247 pCandidate->SetRectsDirty(bNotMyself);
252 sal_uInt32 E3dObject::GetObjInventor() const
254 return E3dInventor;
257 sal_uInt16 E3dObject::GetObjIdentifier() const
259 return E3D_OBJECT_ID;
262 // Determine the capabilities of the object
264 void E3dObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
266 rInfo.bResizeFreeAllowed = true;
267 rInfo.bResizePropAllowed = true;
268 rInfo.bRotateFreeAllowed = true;
269 rInfo.bRotate90Allowed = true;
270 rInfo.bMirrorFreeAllowed = false;
271 rInfo.bMirror45Allowed = false;
272 rInfo.bMirror90Allowed = false;
273 rInfo.bShearAllowed = false;
274 rInfo.bEdgeRadiusAllowed = false;
275 rInfo.bCanConvToPath = false;
277 // no transparence for 3d objects
278 rInfo.bTransparenceAllowed = false;
280 // gradient depends on fillstyle
281 // BM *** check if SetItem is NULL ***
282 drawing::FillStyle eFillStyle = static_cast<const XFillStyleItem&>(GetMergedItem(XATTR_FILLSTYLE)).GetValue();
283 rInfo.bGradientAllowed = (eFillStyle == drawing::FillStyle_GRADIENT);
285 // Convert 3D objects in a group of polygons:
286 // At first not only possible, because the creation of a group of
287 // 2D polygons would be required which need to be sorted by depth,
288 // ie at intersections be cut relative to each other. Also the texture
289 // coorinates were an unsolved problem.
290 rInfo.bCanConvToPoly = false;
291 rInfo.bCanConvToContour = false;
292 rInfo.bCanConvToPathLineToArea = false;
293 rInfo.bCanConvToPolyLineToArea = false;
296 void E3dObject::NbcSetLayer(SdrLayerID nLayer)
298 SdrAttrObj::NbcSetLayer(nLayer);
300 for(size_t a = 0; a < maSubList.GetObjCount(); ++a)
302 E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
304 if(pCandidate)
306 pCandidate->NbcSetLayer(nLayer);
311 // Set ObjList also on SubList
313 void E3dObject::SetObjList(SdrObjList* pNewObjList)
315 SdrObject::SetObjList(pNewObjList);
316 maSubList.SetUpList(pNewObjList);
319 void E3dObject::SetPage(SdrPage* pNewPage)
321 SdrAttrObj::SetPage(pNewPage);
322 maSubList.SetPage(pNewPage);
325 void E3dObject::SetModel(SdrModel* pNewModel)
327 SdrAttrObj::SetModel(pNewModel);
328 maSubList.SetModel(pNewModel);
331 // resize object, used from old 2d interfaces, e.g. in Move/Scale dialog (F4)
333 void E3dObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
335 // Movement in X, Y in the eye coordinate system
336 E3dScene* pScene = GetScene();
338 if(pScene)
340 // transform pos from 2D world to 3D eye
341 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
342 const drawinglayer::geometry::ViewInformation3D aViewInfo3D(rVCScene.getViewInformation3D());
343 basegfx::B2DPoint aScaleCenter2D((double)rRef.X(), (double)rRef.Y());
344 basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
346 aInverseSceneTransform.invert();
347 aScaleCenter2D = aInverseSceneTransform * aScaleCenter2D;
349 basegfx::B3DPoint aScaleCenter3D(aScaleCenter2D.getX(), aScaleCenter2D.getY(), 0.5);
350 basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
352 aInverseViewToEye.invert();
353 aScaleCenter3D = aInverseViewToEye * aScaleCenter3D;
355 // Get scale factors
356 double fScaleX(xFact);
357 double fScaleY(yFact);
359 // build transform
360 basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
361 aInverseOrientation.invert();
362 basegfx::B3DHomMatrix mFullTransform(GetFullTransform());
363 basegfx::B3DHomMatrix mTrans(mFullTransform);
365 mTrans *= aViewInfo3D.getOrientation();
366 mTrans.translate(-aScaleCenter3D.getX(), -aScaleCenter3D.getY(), -aScaleCenter3D.getZ());
367 mTrans.scale(fScaleX, fScaleY, 1.0);
368 mTrans.translate(aScaleCenter3D.getX(), aScaleCenter3D.getY(), aScaleCenter3D.getZ());
369 mTrans *= aInverseOrientation;
370 mFullTransform.invert();
371 mTrans *= mFullTransform;
373 // Apply
374 basegfx::B3DHomMatrix mObjTrans(GetTransform());
375 mObjTrans *= mTrans;
377 E3DModifySceneSnapRectUpdater aUpdater(this);
378 SetTransform(mObjTrans);
383 // Move object in 2D is needed when using cursor keys
385 void E3dObject::NbcMove(const Size& rSize)
387 // Movement in X, Y in the eye coordinate system
388 E3dScene* pScene = GetScene();
390 if(pScene)
392 //Dimensions of the scene in 3D and 2D for comparison
393 Rectangle aRect = pScene->GetSnapRect();
395 basegfx::B3DHomMatrix mInvDispTransform;
396 if(GetParentObj())
398 mInvDispTransform = GetParentObj()->GetFullTransform();
399 mInvDispTransform.invert();
402 // BoundVolume from 3d world to 3d eye
403 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
404 const drawinglayer::geometry::ViewInformation3D aViewInfo3D(rVCScene.getViewInformation3D());
405 basegfx::B3DRange aEyeVol(pScene->GetBoundVolume());
406 aEyeVol.transform(aViewInfo3D.getOrientation());
408 if ((aRect.GetWidth() == 0) || (aRect.GetHeight() == 0))
409 throw o3tl::divide_by_zero();
411 // build relative movement vector in eye coordinates
412 basegfx::B3DPoint aMove(
413 (double)rSize.Width() * aEyeVol.getWidth() / (double)aRect.GetWidth(),
414 (double)-rSize.Height() * aEyeVol.getHeight() / (double)aRect.GetHeight(),
415 0.0);
416 basegfx::B3DPoint aPos(0.0, 0.0, 0.0);
418 // movement vector to local coordinates of objects' parent
419 basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
420 aInverseOrientation.invert();
421 basegfx::B3DHomMatrix aCompleteTrans(mInvDispTransform * aInverseOrientation);
423 aMove = aCompleteTrans * aMove;
424 aPos = aCompleteTrans * aPos;
426 // build transformation and apply
427 basegfx::B3DHomMatrix aTranslate;
428 aTranslate.translate(aMove.getX() - aPos.getX(), aMove.getY() - aPos.getY(), aMove.getZ() - aPos.getZ());
430 E3DModifySceneSnapRectUpdater aUpdater(pScene);
431 SetTransform(aTranslate * GetTransform());
435 // Return the sublist, but only if it contains objects!
437 SdrObjList* E3dObject::GetSubList() const
439 return &(const_cast< E3dObjList& >(maSubList));
442 void E3dObject::RecalcSnapRect()
444 maSnapRect = Rectangle();
446 for(size_t a = 0; a < maSubList.GetObjCount(); ++a)
448 E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
450 if(pCandidate)
452 maSnapRect.Union(pCandidate->GetSnapRect());
457 // Inform the parent about insertion of a 3D object, so that the parent is able
458 // treat the particualar objects in a special way (eg Light / Label in E3dScene)
460 void E3dObject::NewObjectInserted(const E3dObject* p3DObj)
462 if(GetParentObj())
463 GetParentObj()->NewObjectInserted(p3DObj);
466 // Inform parent of changes in the structure (eg by transformation), in this
467 // process the object in which the change has occurred is returned.
469 void E3dObject::StructureChanged()
471 if ( GetParentObj() )
473 GetParentObj()->InvalidateBoundVolume();
474 GetParentObj()->StructureChanged();
478 void E3dObject::Insert3DObj(E3dObject* p3DObj)
480 DBG_ASSERT(p3DObj, "Insert3DObj with NULL-pointer!");
481 SdrPage* pPg = pPage;
482 maSubList.InsertObject(p3DObj);
483 pPage = pPg;
484 InvalidateBoundVolume();
485 NewObjectInserted(p3DObj);
486 StructureChanged();
489 void E3dObject::Remove3DObj(E3dObject* p3DObj)
491 DBG_ASSERT(p3DObj, "Remove3DObj with NULL-pointer!");
493 if(p3DObj->GetParentObj() == this)
495 SdrPage* pPg = pPage;
496 maSubList.RemoveObject(p3DObj->GetOrdNum());
497 pPage = pPg;
499 InvalidateBoundVolume();
500 StructureChanged();
504 E3dObject* E3dObject::GetParentObj() const
506 E3dObject* pRetval = NULL;
508 if(GetObjList()
509 && GetObjList()->GetOwnerObj()
510 && GetObjList()->GetOwnerObj()->ISA(E3dObject))
511 pRetval = static_cast<E3dObject*>(GetObjList()->GetOwnerObj());
512 return pRetval;
515 // Determine the top-level scene object
517 E3dScene* E3dObject::GetScene() const
519 if(GetParentObj())
520 return GetParentObj()->GetScene();
521 return NULL;
524 // Calculate enclosed volume, including all child objects
526 basegfx::B3DRange E3dObject::RecalcBoundVolume() const
528 basegfx::B3DRange aRetval;
529 const size_t nObjCnt(maSubList.GetObjCount());
531 if(nObjCnt)
533 for(size_t a = 0; a < nObjCnt; ++a)
535 const E3dObject* p3DObject = dynamic_cast< const E3dObject* >(maSubList.GetObj(a));
537 if(p3DObject)
539 basegfx::B3DRange aLocalRange(p3DObject->GetBoundVolume());
540 aLocalRange.transform(p3DObject->GetTransform());
541 aRetval.expand(aLocalRange);
545 else
547 // single 3D object
548 const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
550 if(pVCOfE3D)
552 // BoundVolume is without 3D object transformation, use correct sequence
553 const drawinglayer::primitive3d::Primitive3DSequence xLocalSequence(pVCOfE3D->getVIP3DSWithoutObjectTransform());
555 if(xLocalSequence.hasElements())
557 const uno::Sequence< beans::PropertyValue > aEmptyParameters;
558 const drawinglayer::geometry::ViewInformation3D aLocalViewInformation3D(aEmptyParameters);
560 aRetval = drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(
561 xLocalSequence, aLocalViewInformation3D);
566 return aRetval;
569 // Get enclosed volume and possibly recalculate it
571 const basegfx::B3DRange& E3dObject::GetBoundVolume() const
573 if(maLocalBoundVol.isEmpty())
575 const_cast< E3dObject* >(this)->maLocalBoundVol = RecalcBoundVolume();
578 return maLocalBoundVol;
581 void E3dObject::InvalidateBoundVolume()
583 maLocalBoundVol.reset();
586 // Pass on the changes of the BoundVolumes to all child objects
588 void E3dObject::SetBoundVolInvalid()
590 InvalidateBoundVolume();
592 for(size_t a = 0; a < maSubList.GetObjCount(); ++a)
594 E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
596 if(pCandidate)
598 pCandidate->SetBoundVolInvalid();
603 // Pass on the changes in transformation to all child objects
605 void E3dObject::SetTransformChanged()
607 InvalidateBoundVolume();
608 mbTfHasChanged = true;
610 for(size_t a = 0; a < maSubList.GetObjCount(); ++a)
612 E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
614 if(pCandidate)
616 pCandidate->SetTransformChanged();
621 // Define the hierarchical transformation over all Parents, store in
622 // maFullTransform and return them
624 const basegfx::B3DHomMatrix& E3dObject::GetFullTransform() const
626 if(mbTfHasChanged)
628 basegfx::B3DHomMatrix aNewFullTransformation(maTransformation);
630 if ( GetParentObj() )
632 aNewFullTransformation = GetParentObj()->GetFullTransform() * aNewFullTransformation;
635 const_cast< E3dObject* >(this)->maFullTransform = aNewFullTransformation;
636 const_cast< E3dObject* >(this)->mbTfHasChanged = false;
639 return maFullTransform;
643 void E3dObject::NbcSetTransform(const basegfx::B3DHomMatrix& rMatrix)
645 if(maTransformation != rMatrix)
647 maTransformation = rMatrix;
648 SetTransformChanged();
649 StructureChanged();
653 // Set transformation matrix with repaint broadcast
655 void E3dObject::SetTransform(const basegfx::B3DHomMatrix& rMatrix)
657 if(rMatrix != maTransformation)
659 NbcSetTransform(rMatrix);
660 SetChanged();
661 BroadcastObjectChange();
662 if (pUserCall != NULL) pUserCall->Changed(*this, SDRUSERCALL_RESIZE, Rectangle());
666 basegfx::B3DPolyPolygon E3dObject::CreateWireframe() const
668 const basegfx::B3DRange aBoundVolume(GetBoundVolume());
669 return basegfx::tools::createCubePolyPolygonFromB3DRange(aBoundVolume);
672 // Get the name of the object (singular)
674 OUString E3dObject::TakeObjNameSingul() const
676 OUStringBuffer sName(ImpGetResStr(STR_ObjNameSingulObj3d));
678 OUString aName(GetName());
679 if (!aName.isEmpty())
681 sName.append(' ');
682 sName.append('\'');
683 sName.append(aName);
684 sName.append('\'');
686 return sName.makeStringAndClear();
689 // Get the name of the object (plural)
691 OUString E3dObject::TakeObjNamePlural() const
693 return ImpGetResStr(STR_ObjNamePluralObj3d);
696 E3dObject* E3dObject::Clone() const
698 return CloneHelper< E3dObject >();
701 E3dObject& E3dObject::operator=(const E3dObject& rObj)
703 if( this == &rObj )
704 return *this;
705 SdrObject::operator=(rObj);
707 const E3dObject& r3DObj = (const E3dObject&) rObj;
708 if (r3DObj.GetSubList())
710 maSubList.CopyObjects(*r3DObj.GetSubList());
713 // BoundVol can be copied since also the children are copied
714 maLocalBoundVol = r3DObj.maLocalBoundVol;
715 maTransformation = r3DObj.maTransformation;
717 // Because the parent may have changed, definitely redefine the total
718 // transformation next time
719 SetTransformChanged();
721 // Copy selection status
722 mbIsSelected = r3DObj.mbIsSelected;
723 return *this;
726 SdrObjGeoData *E3dObject::NewGeoData() const
728 return new E3DObjGeoData;
731 void E3dObject::SaveGeoData(SdrObjGeoData& rGeo) const
733 SdrAttrObj::SaveGeoData (rGeo);
735 static_cast<E3DObjGeoData &>(rGeo).maLocalBoundVol = maLocalBoundVol;
736 static_cast<E3DObjGeoData &>(rGeo).maTransformation = maTransformation;
739 void E3dObject::RestGeoData(const SdrObjGeoData& rGeo)
741 maLocalBoundVol = static_cast<const E3DObjGeoData &>(rGeo).maLocalBoundVol;
742 E3DModifySceneSnapRectUpdater aUpdater(this);
743 NbcSetTransform(static_cast<const E3DObjGeoData &>(rGeo).maTransformation);
744 SdrAttrObj::RestGeoData (rGeo);
747 // 2D-rotation of a 3D-body, normally this is done by the scene itself.
748 // This is however a correct implementation, because everything that has
749 // happened is a rotation around the axis perpendicular to the screen and that
750 // is regardless of how the scene has been rotated up until now.
752 void E3dObject::NbcRotate(const Point& rRef, long nAngle, double sn, double cs)
754 // So currently the glue points are defined relative to the scene aOutRect.
755 // Before turning the glue points are defined relative to the page. They
756 // take no part in the rotation of the scene. To ensure this, there is the
757 // SetGlueReallyAbsolute(sal_True);
759 double fWinkelInRad = nAngle/100.0 * F_PI180;
761 basegfx::B3DHomMatrix aRotateZ;
762 aRotateZ.rotate(0.0, 0.0, fWinkelInRad);
763 NbcSetTransform(aRotateZ * GetTransform());
765 SetRectsDirty(); // This forces a recalculation of all BoundRects
766 NbcRotateGluePoints(rRef,nAngle,sn,cs); // Rotate the glue points (who still
767 // have coordinates relative to the
768 // original page)
769 SetGlueReallyAbsolute(false); // from now they are again relative to BoundRect (that is defined as aOutRect)
772 sdr::properties::BaseProperties* E3dCompoundObject::CreateObjectSpecificProperties()
774 return new sdr::properties::E3dCompoundProperties(*this);
779 TYPEINIT1(E3dCompoundObject, E3dObject);
781 E3dCompoundObject::E3dCompoundObject()
782 : E3dObject(),
783 aMaterialAmbientColor(),
784 bCreateNormals(false),
785 bCreateTexture(false)
787 // Set defaults
788 E3dDefaultAttributes aDefault;
789 SetDefaultAttributes(aDefault);
792 E3dCompoundObject::E3dCompoundObject(E3dDefaultAttributes& rDefault)
793 : E3dObject(),
794 aMaterialAmbientColor(),
795 bCreateNormals(false),
796 bCreateTexture(false)
798 // Set defaults
799 SetDefaultAttributes(rDefault);
802 void E3dCompoundObject::SetDefaultAttributes(E3dDefaultAttributes& rDefault)
804 // Set defaults
805 aMaterialAmbientColor = rDefault.GetDefaultAmbientColor();
807 bCreateNormals = rDefault.GetDefaultCreateNormals();
808 bCreateTexture = rDefault.GetDefaultCreateTexture();
811 E3dCompoundObject::~E3dCompoundObject ()
815 basegfx::B2DPolyPolygon E3dCompoundObject::TakeXorPoly() const
817 basegfx::B2DPolyPolygon aRetval;
818 const uno::Sequence< beans::PropertyValue > aEmptyParameters;
819 drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
820 E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
822 if(pRootScene)
824 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
825 const basegfx::B3DPolyPolygon aCubePolyPolygon(CreateWireframe());
826 aRetval = basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(aCubePolyPolygon,
827 aViewInfo3D.getObjectToView() * GetTransform());
828 aRetval.transform(rVCScene.getObjectTransformation());
831 return aRetval;
834 sal_uInt32 E3dCompoundObject::GetHdlCount() const
836 // 8 corners + 1 E3dVolumeMarker (= Wireframe representation)
837 return 9L;
840 void E3dCompoundObject::AddToHdlList(SdrHdlList& rHdlList) const
842 const uno::Sequence< beans::PropertyValue > aEmptyParameters;
843 drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
844 E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
846 if(pRootScene)
848 const basegfx::B3DRange aBoundVolume(GetBoundVolume());
850 if(!aBoundVolume.isEmpty())
852 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
854 for(sal_uInt32 a(0); a < 8; a++)
856 basegfx::B3DPoint aPos3D;
858 switch(a)
860 case 0 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
861 case 1 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
862 case 2 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
863 case 3 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
864 case 4 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
865 case 5 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
866 case 6 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
867 case 7 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
870 // to 3d view coor
871 aPos3D *= aViewInfo3D.getObjectToView() * GetTransform();
873 // create 2d relative scene
874 basegfx::B2DPoint aPos2D(aPos3D.getX(), aPos3D.getY());
876 // to 2d world coor
877 aPos2D *= rVCScene.getObjectTransformation();
879 rHdlList.AddHdl(new SdrHdl(Point(basegfx::fround(aPos2D.getX()), basegfx::fround(aPos2D.getY())), HDL_BWGT));
884 const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());
886 if(aPolyPolygon.count())
888 E3dVolumeMarker* pVolMarker = new E3dVolumeMarker(aPolyPolygon);
889 rHdlList.AddHdl(pVolMarker);
893 sal_uInt16 E3dCompoundObject::GetObjIdentifier() const
895 return E3D_COMPOUNDOBJ_ID;
898 void E3dCompoundObject::RecalcSnapRect()
900 const uno::Sequence< beans::PropertyValue > aEmptyParameters;
901 drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
902 E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
903 maSnapRect = Rectangle();
905 if(pRootScene)
907 // get VC of 3D candidate
908 const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
910 if(pVCOfE3D)
912 // get 3D primitive sequence
913 const drawinglayer::primitive3d::Primitive3DSequence xLocalSequence(pVCOfE3D->getViewIndependentPrimitive3DSequence());
915 if(xLocalSequence.hasElements())
917 // get BoundVolume
918 basegfx::B3DRange aBoundVolume(drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(
919 xLocalSequence, aViewInfo3D));
921 // transform bound volume to relative scene coordinates
922 aBoundVolume.transform(aViewInfo3D.getObjectToView());
924 // build 2d relative scene range
925 basegfx::B2DRange aSnapRange(
926 aBoundVolume.getMinX(), aBoundVolume.getMinY(),
927 aBoundVolume.getMaxX(), aBoundVolume.getMaxY());
929 // transform to 2D world coordiantes
930 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
931 aSnapRange.transform(rVCScene.getObjectTransformation());
933 // snap to integer
934 maSnapRect = Rectangle(
935 sal_Int32(floor(aSnapRange.getMinX())), sal_Int32(floor(aSnapRange.getMinY())),
936 sal_Int32(ceil(aSnapRange.getMaxX())), sal_Int32(ceil(aSnapRange.getMaxY())));
942 E3dCompoundObject* E3dCompoundObject::Clone() const
944 return CloneHelper< E3dCompoundObject >();
947 // convert given basegfx::B3DPolyPolygon to screen coor
949 basegfx::B2DPolyPolygon E3dCompoundObject::TransformToScreenCoor(const basegfx::B3DPolyPolygon& rCandidate)
951 const uno::Sequence< beans::PropertyValue > aEmptyParameters;
952 drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
953 E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
954 basegfx::B2DPolyPolygon aRetval;
956 if(pRootScene)
958 aRetval = basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(rCandidate,
959 aViewInfo3D.getObjectToView() * GetTransform());
960 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
961 aRetval.transform(rVCScene.getObjectTransformation());
964 return aRetval;
967 bool E3dCompoundObject::IsAOrdNumRemapCandidate(E3dScene*& prScene) const
969 if(GetObjList()
970 && GetObjList()->GetOwnerObj()
971 && GetObjList()->GetOwnerObj()->ISA(E3dScene))
973 prScene = static_cast<E3dScene*>(GetObjList()->GetOwnerObj());
974 return true;
977 return false;
980 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */