993 lines
30 KiB
C++
993 lines
30 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
#include "svx/svdstr.hrc"
|
|
#include "svx/svdglob.hxx"
|
|
#include <svx/svdview.hxx>
|
|
#include <svx/svdattr.hxx>
|
|
#include <svx/svdpage.hxx>
|
|
#include <svx/svdmodel.hxx>
|
|
#include "svx/svditer.hxx"
|
|
#include "svx/globl3d.hxx"
|
|
#include <svx/camera3d.hxx>
|
|
#include <svx/scene3d.hxx>
|
|
#include <svx/polysc3d.hxx>
|
|
#include <svx/cube3d.hxx>
|
|
#include <svx/lathe3d.hxx>
|
|
#include <svx/sphere3d.hxx>
|
|
#include <svx/extrud3d.hxx>
|
|
#include <svx/obj3d.hxx>
|
|
#include <svx/xtable.hxx>
|
|
#include <svx/xflclit.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <svx/xlnclit.hxx>
|
|
#include <svl/metitem.hxx>
|
|
#include <svx/xtable.hxx>
|
|
#include <svx/xfillit.hxx>
|
|
#include <svx/xlnwtit.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <tools/poly.hxx>
|
|
#include <tools/b3dtrans.hxx>
|
|
#include <svx/svxids.hrc>
|
|
#include <editeng/colritem.hxx>
|
|
#include <svx/e3ditem.hxx>
|
|
#include <svx/xlntrit.hxx>
|
|
#include <svx/xfltrit.hxx>
|
|
#include <svx/svdpagv.hxx>
|
|
#include <vcl/gradient.hxx>
|
|
#include <vcl/metaact.hxx>
|
|
#include <svx/svx3ditems.hxx>
|
|
#include <svl/whiter.hxx>
|
|
#include <svtools/colorcfg.hxx>
|
|
#include <editeng/eeitem.hxx>
|
|
#include <svx/xgrscit.hxx>
|
|
#include <svx/sdr/properties/e3dproperties.hxx>
|
|
#include <svx/sdr/properties/e3dcompoundproperties.hxx>
|
|
#include <basegfx/polygon/b3dpolypolygontools.hxx>
|
|
#include <basegfx/point/b3dpoint.hxx>
|
|
#include <basegfx/vector/b3dvector.hxx>
|
|
#include <svx/xlndsit.hxx>
|
|
#include <basegfx/matrix/b3dhommatrix.hxx>
|
|
#include <basegfx/polygon/b3dpolygon.hxx>
|
|
#include <basegfx/matrix/b2dhommatrix.hxx>
|
|
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
|
#include <basegfx/polygon/b3dpolygontools.hxx>
|
|
#include <svx/helperhittest3d.hxx>
|
|
#include <svx/sdr/contact/viewcontactofe3d.hxx>
|
|
#include <drawinglayer/geometry/viewinformation3d.hxx>
|
|
#include <com/sun/star/uno/Sequence.h>
|
|
#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
|
|
#include <basegfx/polygon/b3dpolypolygontools.hxx>
|
|
#include <svx/e3dsceneupdater.hxx>
|
|
|
|
#define ITEMVALUE(ItemSet,Id,Cast) ((const Cast&)(ItemSet).Get(Id)).GetValue()
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
using namespace com::sun::star;
|
|
|
|
|
|
// List for 3D-Objects
|
|
|
|
TYPEINIT1(E3dObjList, SdrObjList);
|
|
|
|
E3dObjList::E3dObjList(SdrModel* pNewModel, SdrPage* pNewPage, E3dObjList* pNewUpList)
|
|
: SdrObjList(pNewModel, pNewPage, pNewUpList)
|
|
{
|
|
}
|
|
|
|
E3dObjList::E3dObjList(const E3dObjList& rSrcList)
|
|
: SdrObjList(rSrcList)
|
|
{
|
|
}
|
|
|
|
E3dObjList::~E3dObjList()
|
|
{
|
|
}
|
|
|
|
void E3dObjList::NbcInsertObject(SdrObject* pObj, sal_uIntPtr nPos, const SdrInsertReason* pReason)
|
|
{
|
|
// Get owner
|
|
DBG_ASSERT(GetOwnerObj()->ISA(E3dObject), "Insert 3D object in parent != 3DObject");
|
|
|
|
// Is it even a 3D object?
|
|
if(pObj && pObj->ISA(E3dObject))
|
|
{
|
|
// Normal 3D object, insert means
|
|
// call parent
|
|
SdrObjList::NbcInsertObject(pObj, nPos, pReason);
|
|
}
|
|
else
|
|
{
|
|
// No 3D object, inserted a page in place in a scene ...
|
|
GetOwnerObj()->GetPage()->InsertObject(pObj, nPos);
|
|
}
|
|
}
|
|
|
|
void E3dObjList::InsertObject(SdrObject* pObj, sal_uIntPtr nPos, const SdrInsertReason* pReason)
|
|
{
|
|
OSL_ENSURE(GetOwnerObj()->ISA(E3dObject), "Insert 3D object in non-3D Parent");
|
|
|
|
// call parent
|
|
SdrObjList::InsertObject(pObj, nPos, pReason);
|
|
|
|
E3dScene* pScene = ((E3dObject*)GetOwnerObj())->GetScene();
|
|
if(pScene)
|
|
{
|
|
pScene->Cleanup3DDepthMapper();
|
|
}
|
|
}
|
|
|
|
SdrObject* E3dObjList::NbcRemoveObject(sal_uIntPtr nObjNum)
|
|
{
|
|
DBG_ASSERT(GetOwnerObj()->ISA(E3dObject), "Remove 3D object from Parent != 3DObject");
|
|
|
|
// call parent
|
|
SdrObject* pRetval = SdrObjList::NbcRemoveObject(nObjNum);
|
|
|
|
E3dScene* pScene = ((E3dObject*)GetOwnerObj())->GetScene();
|
|
if(pScene)
|
|
{
|
|
pScene->Cleanup3DDepthMapper();
|
|
}
|
|
|
|
return pRetval;
|
|
}
|
|
|
|
SdrObject* E3dObjList::RemoveObject(sal_uIntPtr nObjNum)
|
|
{
|
|
OSL_ENSURE(GetOwnerObj()->ISA(E3dObject), "3D object is removed from non-3D Parent");
|
|
|
|
// call parent
|
|
SdrObject* pRetval = SdrObjList::RemoveObject(nObjNum);
|
|
|
|
E3dScene* pScene = ((E3dObject*)GetOwnerObj())->GetScene();
|
|
if(pScene)
|
|
{
|
|
pScene->Cleanup3DDepthMapper();
|
|
}
|
|
|
|
return pRetval;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
sdr::properties::BaseProperties* E3dObject::CreateObjectSpecificProperties()
|
|
{
|
|
return new sdr::properties::E3dProperties(*this);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
TYPEINIT1(E3dObject, SdrAttrObj);
|
|
|
|
E3dObject::E3dObject()
|
|
: maSubList(),
|
|
maLocalBoundVol(),
|
|
maTransformation(),
|
|
maFullTransform(),
|
|
mbTfHasChanged(true),
|
|
mbIsSelected(false)
|
|
{
|
|
bIs3DObj = true;
|
|
maSubList.SetOwnerObj(this);
|
|
maSubList.SetListKind(SDROBJLIST_GROUPOBJ);
|
|
bClosedObj = true;
|
|
}
|
|
|
|
E3dObject::~E3dObject()
|
|
{
|
|
}
|
|
|
|
void E3dObject::SetSelected(bool bNew)
|
|
{
|
|
if((bool)mbIsSelected != bNew)
|
|
{
|
|
mbIsSelected = bNew;
|
|
}
|
|
|
|
for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
|
|
{
|
|
E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
|
|
|
|
if(pCandidate)
|
|
{
|
|
pCandidate->SetSelected(bNew);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Break, default implementations
|
|
|
|
sal_Bool E3dObject::IsBreakObjPossible()
|
|
{
|
|
return sal_False;
|
|
}
|
|
|
|
SdrAttrObj* E3dObject::GetBreakObj()
|
|
{
|
|
return 0L;
|
|
}
|
|
|
|
// SetRectsDirty must be done through the local SdrSubList
|
|
|
|
void E3dObject::SetRectsDirty(sal_Bool bNotMyself)
|
|
{
|
|
// call parent
|
|
SdrAttrObj::SetRectsDirty(bNotMyself);
|
|
|
|
for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
|
|
{
|
|
E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
|
|
|
|
if(pCandidate)
|
|
{
|
|
pCandidate->SetRectsDirty(bNotMyself);
|
|
}
|
|
}
|
|
}
|
|
|
|
sal_uInt32 E3dObject::GetObjInventor() const
|
|
{
|
|
return E3dInventor;
|
|
}
|
|
|
|
sal_uInt16 E3dObject::GetObjIdentifier() const
|
|
{
|
|
return E3D_OBJECT_ID;
|
|
}
|
|
|
|
// Determine the capabilities of the object
|
|
|
|
void E3dObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
|
|
{
|
|
rInfo.bResizeFreeAllowed = sal_True;
|
|
rInfo.bResizePropAllowed = sal_True;
|
|
rInfo.bRotateFreeAllowed = sal_True;
|
|
rInfo.bRotate90Allowed = sal_True;
|
|
rInfo.bMirrorFreeAllowed = sal_False;
|
|
rInfo.bMirror45Allowed = sal_False;
|
|
rInfo.bMirror90Allowed = sal_False;
|
|
rInfo.bShearAllowed = sal_False;
|
|
rInfo.bEdgeRadiusAllowed = sal_False;
|
|
rInfo.bCanConvToPath = sal_False;
|
|
|
|
// no transparence for 3d objects
|
|
rInfo.bTransparenceAllowed = sal_False;
|
|
|
|
// gradient depends on fillstyle
|
|
// BM *** check if SetItem is NULL ***
|
|
XFillStyle eFillStyle = ((XFillStyleItem&)(GetMergedItem(XATTR_FILLSTYLE))).GetValue();
|
|
rInfo.bGradientAllowed = (eFillStyle == XFILL_GRADIENT);
|
|
|
|
// Convert 3D objects in a group of polygons:
|
|
// At first not only possible, because the creation of a group of
|
|
// 2D polygons would be required which need to be sorted by depth,
|
|
// ie at intersections be cut relative to each other. Also the texture
|
|
// coorinates were an unsolved problem.
|
|
rInfo.bCanConvToPoly = sal_False;
|
|
rInfo.bCanConvToContour = sal_False;
|
|
rInfo.bCanConvToPathLineToArea = sal_False;
|
|
rInfo.bCanConvToPolyLineToArea = sal_False;
|
|
}
|
|
|
|
void E3dObject::NbcSetLayer(SdrLayerID nLayer)
|
|
{
|
|
SdrAttrObj::NbcSetLayer(nLayer);
|
|
|
|
for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
|
|
{
|
|
E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
|
|
|
|
if(pCandidate)
|
|
{
|
|
pCandidate->NbcSetLayer(nLayer);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set ObjList also on SubList
|
|
|
|
void E3dObject::SetObjList(SdrObjList* pNewObjList)
|
|
{
|
|
SdrObject::SetObjList(pNewObjList);
|
|
maSubList.SetUpList(pNewObjList);
|
|
}
|
|
|
|
void E3dObject::SetPage(SdrPage* pNewPage)
|
|
{
|
|
SdrAttrObj::SetPage(pNewPage);
|
|
maSubList.SetPage(pNewPage);
|
|
}
|
|
|
|
void E3dObject::SetModel(SdrModel* pNewModel)
|
|
{
|
|
SdrAttrObj::SetModel(pNewModel);
|
|
maSubList.SetModel(pNewModel);
|
|
}
|
|
|
|
// resize object, used from old 2d interfaces, e.g. in Move/Scale dialog (F4)
|
|
|
|
void E3dObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
|
|
{
|
|
// Movement in X, Y in the eye coordinate system
|
|
E3dScene* pScene = GetScene();
|
|
|
|
if(pScene)
|
|
{
|
|
// transform pos from 2D world to 3D eye
|
|
const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
|
|
const drawinglayer::geometry::ViewInformation3D aViewInfo3D(rVCScene.getViewInformation3D());
|
|
basegfx::B2DPoint aScaleCenter2D((double)rRef.X(), (double)rRef.Y());
|
|
basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
|
|
|
|
aInverseSceneTransform.invert();
|
|
aScaleCenter2D = aInverseSceneTransform * aScaleCenter2D;
|
|
|
|
basegfx::B3DPoint aScaleCenter3D(aScaleCenter2D.getX(), aScaleCenter2D.getY(), 0.5);
|
|
basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
|
|
|
|
aInverseViewToEye.invert();
|
|
aScaleCenter3D = aInverseViewToEye * aScaleCenter3D;
|
|
|
|
// Get scale factors
|
|
double fScaleX(xFact);
|
|
double fScaleY(yFact);
|
|
|
|
// build transform
|
|
basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
|
|
aInverseOrientation.invert();
|
|
basegfx::B3DHomMatrix mFullTransform(GetFullTransform());
|
|
basegfx::B3DHomMatrix mTrans(mFullTransform);
|
|
|
|
mTrans *= aViewInfo3D.getOrientation();
|
|
mTrans.translate(-aScaleCenter3D.getX(), -aScaleCenter3D.getY(), -aScaleCenter3D.getZ());
|
|
mTrans.scale(fScaleX, fScaleY, 1.0);
|
|
mTrans.translate(aScaleCenter3D.getX(), aScaleCenter3D.getY(), aScaleCenter3D.getZ());
|
|
mTrans *= aInverseOrientation;
|
|
mFullTransform.invert();
|
|
mTrans *= mFullTransform;
|
|
|
|
// Apply
|
|
basegfx::B3DHomMatrix mObjTrans(GetTransform());
|
|
mObjTrans *= mTrans;
|
|
|
|
E3DModifySceneSnapRectUpdater aUpdater(this);
|
|
SetTransform(mObjTrans);
|
|
}
|
|
}
|
|
|
|
|
|
// Move object in 2D is needed when using cursor keys
|
|
|
|
void E3dObject::NbcMove(const Size& rSize)
|
|
{
|
|
// Movement in X, Y in the eye coordinate system
|
|
E3dScene* pScene = GetScene();
|
|
|
|
if(pScene)
|
|
{
|
|
//Dimensions of the scene in 3D and 2D for comparison
|
|
Rectangle aRect = pScene->GetSnapRect();
|
|
|
|
basegfx::B3DHomMatrix mInvDispTransform;
|
|
if(GetParentObj())
|
|
{
|
|
mInvDispTransform = GetParentObj()->GetFullTransform();
|
|
mInvDispTransform.invert();
|
|
}
|
|
|
|
// BoundVolume from 3d world to 3d eye
|
|
const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
|
|
const drawinglayer::geometry::ViewInformation3D aViewInfo3D(rVCScene.getViewInformation3D());
|
|
basegfx::B3DRange aEyeVol(pScene->GetBoundVolume());
|
|
aEyeVol.transform(aViewInfo3D.getOrientation());
|
|
|
|
// build relative movement vector in eye coordinates
|
|
basegfx::B3DPoint aMove(
|
|
(double)rSize.Width() * aEyeVol.getWidth() / (double)aRect.GetWidth(),
|
|
(double)-rSize.Height() * aEyeVol.getHeight() / (double)aRect.GetHeight(),
|
|
0.0);
|
|
basegfx::B3DPoint aPos(0.0, 0.0, 0.0);
|
|
|
|
// movement vector to local coordinates of objects' parent
|
|
basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
|
|
aInverseOrientation.invert();
|
|
basegfx::B3DHomMatrix aCompleteTrans(mInvDispTransform * aInverseOrientation);
|
|
|
|
aMove = aCompleteTrans * aMove;
|
|
aPos = aCompleteTrans * aPos;
|
|
|
|
// build transformation and apply
|
|
basegfx::B3DHomMatrix aTranslate;
|
|
aTranslate.translate(aMove.getX() - aPos.getX(), aMove.getY() - aPos.getY(), aMove.getZ() - aPos.getZ());
|
|
|
|
E3DModifySceneSnapRectUpdater aUpdater(pScene);
|
|
SetTransform(aTranslate * GetTransform());
|
|
}
|
|
}
|
|
|
|
// Return the sublist, but only if it contains objects!
|
|
|
|
SdrObjList* E3dObject::GetSubList() const
|
|
{
|
|
return &(const_cast< E3dObjList& >(maSubList));
|
|
}
|
|
|
|
void E3dObject::RecalcSnapRect()
|
|
{
|
|
maSnapRect = Rectangle();
|
|
|
|
for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
|
|
{
|
|
E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
|
|
|
|
if(pCandidate)
|
|
{
|
|
maSnapRect.Union(pCandidate->GetSnapRect());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Inform the parent about insertion of a 3D object, so that the parent is able
|
|
// treat the particualar objects in a special way (eg Light / Label in E3dScene)
|
|
|
|
void E3dObject::NewObjectInserted(const E3dObject* p3DObj)
|
|
{
|
|
if(GetParentObj())
|
|
GetParentObj()->NewObjectInserted(p3DObj);
|
|
}
|
|
|
|
// Inform parent of changes in the structure (eg by transformation), in this
|
|
// process the object in which the change has occurred is returned.
|
|
|
|
void E3dObject::StructureChanged()
|
|
{
|
|
if ( GetParentObj() )
|
|
{
|
|
GetParentObj()->InvalidateBoundVolume();
|
|
GetParentObj()->StructureChanged();
|
|
}
|
|
}
|
|
|
|
void E3dObject::Insert3DObj(E3dObject* p3DObj)
|
|
{
|
|
DBG_ASSERT(p3DObj, "Insert3DObj with NULL-pointer!");
|
|
SdrPage* pPg = pPage;
|
|
maSubList.InsertObject(p3DObj);
|
|
pPage = pPg;
|
|
InvalidateBoundVolume();
|
|
NewObjectInserted(p3DObj);
|
|
StructureChanged();
|
|
}
|
|
|
|
void E3dObject::Remove3DObj(E3dObject* p3DObj)
|
|
{
|
|
DBG_ASSERT(p3DObj, "Remove3DObj with NULL-pointer!");
|
|
|
|
if(p3DObj->GetParentObj() == this)
|
|
{
|
|
SdrPage* pPg = pPage;
|
|
maSubList.RemoveObject(p3DObj->GetOrdNum());
|
|
pPage = pPg;
|
|
|
|
InvalidateBoundVolume();
|
|
StructureChanged();
|
|
}
|
|
}
|
|
|
|
E3dObject* E3dObject::GetParentObj() const
|
|
{
|
|
E3dObject* pRetval = NULL;
|
|
|
|
if(GetObjList()
|
|
&& GetObjList()->GetOwnerObj()
|
|
&& GetObjList()->GetOwnerObj()->ISA(E3dObject))
|
|
pRetval = ((E3dObject*)GetObjList()->GetOwnerObj());
|
|
return pRetval;
|
|
}
|
|
|
|
// Determine the top-level scene object
|
|
|
|
E3dScene* E3dObject::GetScene() const
|
|
{
|
|
if(GetParentObj())
|
|
return GetParentObj()->GetScene();
|
|
return NULL;
|
|
}
|
|
|
|
// Calculate enclosed volume, including all child objects
|
|
|
|
basegfx::B3DRange E3dObject::RecalcBoundVolume() const
|
|
{
|
|
basegfx::B3DRange aRetval;
|
|
const sal_uInt32 nObjCnt(maSubList.GetObjCount());
|
|
|
|
if(nObjCnt)
|
|
{
|
|
for(sal_uInt32 a(0); a < nObjCnt; a++)
|
|
{
|
|
const E3dObject* p3DObject = dynamic_cast< const E3dObject* >(maSubList.GetObj(a));
|
|
|
|
if(p3DObject)
|
|
{
|
|
basegfx::B3DRange aLocalRange(p3DObject->GetBoundVolume());
|
|
aLocalRange.transform(p3DObject->GetTransform());
|
|
aRetval.expand(aLocalRange);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// single 3D object
|
|
const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
|
|
|
|
if(pVCOfE3D)
|
|
{
|
|
// BoundVolume is without 3D object transformation, use correct sequence
|
|
const drawinglayer::primitive3d::Primitive3DSequence xLocalSequence(pVCOfE3D->getVIP3DSWithoutObjectTransform());
|
|
|
|
if(xLocalSequence.hasElements())
|
|
{
|
|
const uno::Sequence< beans::PropertyValue > aEmptyParameters;
|
|
const drawinglayer::geometry::ViewInformation3D aLocalViewInformation3D(aEmptyParameters);
|
|
|
|
aRetval = drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(
|
|
xLocalSequence, aLocalViewInformation3D);
|
|
}
|
|
}
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
|
|
// Get enclosed volume and possibly recalculate it
|
|
|
|
const basegfx::B3DRange& E3dObject::GetBoundVolume() const
|
|
{
|
|
if(maLocalBoundVol.isEmpty())
|
|
{
|
|
const_cast< E3dObject* >(this)->maLocalBoundVol = RecalcBoundVolume();
|
|
}
|
|
|
|
return maLocalBoundVol;
|
|
}
|
|
|
|
void E3dObject::InvalidateBoundVolume()
|
|
{
|
|
maLocalBoundVol.reset();
|
|
}
|
|
|
|
// Pass on the changes of the BoundVolumes to all child objects
|
|
|
|
void E3dObject::SetBoundVolInvalid()
|
|
{
|
|
InvalidateBoundVolume();
|
|
|
|
for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
|
|
{
|
|
E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
|
|
|
|
if(pCandidate)
|
|
{
|
|
pCandidate->SetBoundVolInvalid();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pass on the changes in transformation to all child objects
|
|
|
|
void E3dObject::SetTransformChanged()
|
|
{
|
|
InvalidateBoundVolume();
|
|
mbTfHasChanged = true;
|
|
|
|
for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
|
|
{
|
|
E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
|
|
|
|
if(pCandidate)
|
|
{
|
|
pCandidate->SetTransformChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Define the hierarchical transformation over all Parents, store in
|
|
// maFullTransform and return them
|
|
|
|
const basegfx::B3DHomMatrix& E3dObject::GetFullTransform() const
|
|
{
|
|
if(mbTfHasChanged)
|
|
{
|
|
basegfx::B3DHomMatrix aNewFullTransformation(maTransformation);
|
|
|
|
if ( GetParentObj() )
|
|
{
|
|
aNewFullTransformation = GetParentObj()->GetFullTransform() * aNewFullTransformation;
|
|
}
|
|
|
|
const_cast< E3dObject* >(this)->maFullTransform = aNewFullTransformation;
|
|
const_cast< E3dObject* >(this)->mbTfHasChanged = false;
|
|
}
|
|
|
|
return maFullTransform;
|
|
}
|
|
|
|
const basegfx::B3DHomMatrix& E3dObject::GetTransform() const
|
|
{
|
|
return maTransformation;
|
|
}
|
|
|
|
void E3dObject::NbcSetTransform(const basegfx::B3DHomMatrix& rMatrix)
|
|
{
|
|
if(maTransformation != rMatrix)
|
|
{
|
|
maTransformation = rMatrix;
|
|
SetTransformChanged();
|
|
StructureChanged();
|
|
}
|
|
}
|
|
|
|
// Set transformation matrix with repaint broadcast
|
|
|
|
void E3dObject::SetTransform(const basegfx::B3DHomMatrix& rMatrix)
|
|
{
|
|
if(rMatrix != maTransformation)
|
|
{
|
|
NbcSetTransform(rMatrix);
|
|
SetChanged();
|
|
BroadcastObjectChange();
|
|
if (pUserCall != NULL) pUserCall->Changed(*this, SDRUSERCALL_RESIZE, Rectangle());
|
|
}
|
|
}
|
|
|
|
basegfx::B3DPolyPolygon E3dObject::CreateWireframe() const
|
|
{
|
|
const basegfx::B3DRange aBoundVolume(GetBoundVolume());
|
|
return basegfx::tools::createCubePolyPolygonFromB3DRange(aBoundVolume);
|
|
}
|
|
|
|
// Get the name of the object (singular)
|
|
|
|
void E3dObject::TakeObjNameSingul(XubString& rName) const
|
|
{
|
|
rName=ImpGetResStr(STR_ObjNameSingulObj3d);
|
|
|
|
String aName( GetName() );
|
|
if(aName.Len())
|
|
{
|
|
rName += sal_Unicode(' ');
|
|
rName += sal_Unicode('\'');
|
|
rName += aName;
|
|
rName += sal_Unicode('\'');
|
|
}
|
|
}
|
|
|
|
// Get the name of the object (plural)
|
|
|
|
void E3dObject::TakeObjNamePlural(XubString& rName) const
|
|
{
|
|
rName=ImpGetResStr(STR_ObjNamePluralObj3d);
|
|
}
|
|
|
|
E3dObject* E3dObject::Clone() const
|
|
{
|
|
return CloneHelper< E3dObject >();
|
|
}
|
|
|
|
E3dObject& E3dObject::operator=(const E3dObject& rObj)
|
|
{
|
|
if( this == &rObj )
|
|
return *this;
|
|
SdrObject::operator=(rObj);
|
|
|
|
const E3dObject& r3DObj = (const E3dObject&) rObj;
|
|
if (r3DObj.GetSubList())
|
|
{
|
|
maSubList.CopyObjects(*r3DObj.GetSubList());
|
|
}
|
|
|
|
// BoundVol can be copied since also the children are copied
|
|
maLocalBoundVol = r3DObj.maLocalBoundVol;
|
|
maTransformation = r3DObj.maTransformation;
|
|
|
|
// Because the parent may have changed, definitely redefine the total
|
|
// transformation next time
|
|
SetTransformChanged();
|
|
|
|
// Copy selection status
|
|
mbIsSelected = r3DObj.mbIsSelected;
|
|
return *this;
|
|
}
|
|
|
|
SdrObjGeoData *E3dObject::NewGeoData() const
|
|
{
|
|
return new E3DObjGeoData;
|
|
}
|
|
|
|
void E3dObject::SaveGeoData(SdrObjGeoData& rGeo) const
|
|
{
|
|
SdrAttrObj::SaveGeoData (rGeo);
|
|
|
|
((E3DObjGeoData &) rGeo).maLocalBoundVol = maLocalBoundVol;
|
|
((E3DObjGeoData &) rGeo).maTransformation = maTransformation;
|
|
}
|
|
|
|
void E3dObject::RestGeoData(const SdrObjGeoData& rGeo)
|
|
{
|
|
maLocalBoundVol = ((E3DObjGeoData &) rGeo).maLocalBoundVol;
|
|
E3DModifySceneSnapRectUpdater aUpdater(this);
|
|
NbcSetTransform(((E3DObjGeoData &) rGeo).maTransformation);
|
|
SdrAttrObj::RestGeoData (rGeo);
|
|
}
|
|
|
|
// 2D-rotation of a 3D-body, normally this is done by the scene itself.
|
|
// This is however a correct implementation, because everything that has
|
|
// happened is a rotation around the axis perpendicular to the screen and that
|
|
// is regardless of how the scene has been rotated up until now.
|
|
|
|
void E3dObject::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
|
|
{
|
|
// So currently the glue points are defined relative to the scene aOutRect.
|
|
// Before turning the glue points are defined relative to the page. They
|
|
// take no part in the rotation of the scene. To ensure this, there is the
|
|
// SetGlueReallyAbsolute(sal_True);
|
|
|
|
double fWinkelInRad = nWink/100 * F_PI180;
|
|
|
|
basegfx::B3DHomMatrix aRotateZ;
|
|
aRotateZ.rotate(0.0, 0.0, fWinkelInRad);
|
|
NbcSetTransform(aRotateZ * GetTransform());
|
|
|
|
SetRectsDirty(); // This forces a recalculation of all BoundRects
|
|
NbcRotateGluePoints(rRef,nWink,sn,cs); // Rotate the glue points (who still
|
|
// have coordinates relative to the
|
|
// original page)
|
|
SetGlueReallyAbsolute(sal_False); // from now they are again relative to BoundRect (that is defined as aOutRect)
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
sdr::properties::BaseProperties* E3dCompoundObject::CreateObjectSpecificProperties()
|
|
{
|
|
return new sdr::properties::E3dCompoundProperties(*this);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
TYPEINIT1(E3dCompoundObject, E3dObject);
|
|
|
|
E3dCompoundObject::E3dCompoundObject()
|
|
: E3dObject(),
|
|
aMaterialAmbientColor(),
|
|
bCreateNormals(false),
|
|
bCreateTexture(false)
|
|
{
|
|
// Set defaults
|
|
E3dDefaultAttributes aDefault;
|
|
SetDefaultAttributes(aDefault);
|
|
}
|
|
|
|
E3dCompoundObject::E3dCompoundObject(E3dDefaultAttributes& rDefault)
|
|
: E3dObject(),
|
|
aMaterialAmbientColor(),
|
|
bCreateNormals(false),
|
|
bCreateTexture(false)
|
|
{
|
|
// Set defaults
|
|
SetDefaultAttributes(rDefault);
|
|
}
|
|
|
|
void E3dCompoundObject::SetDefaultAttributes(E3dDefaultAttributes& rDefault)
|
|
{
|
|
// Set defaults
|
|
aMaterialAmbientColor = rDefault.GetDefaultAmbientColor();
|
|
|
|
bCreateNormals = rDefault.GetDefaultCreateNormals();
|
|
bCreateTexture = rDefault.GetDefaultCreateTexture();
|
|
}
|
|
|
|
E3dCompoundObject::~E3dCompoundObject ()
|
|
{
|
|
}
|
|
|
|
basegfx::B2DPolyPolygon E3dCompoundObject::TakeXorPoly() const
|
|
{
|
|
basegfx::B2DPolyPolygon aRetval;
|
|
const uno::Sequence< beans::PropertyValue > aEmptyParameters;
|
|
drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
|
|
E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
|
|
|
|
if(pRootScene)
|
|
{
|
|
const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
|
|
const basegfx::B3DPolyPolygon aCubePolyPolygon(CreateWireframe());
|
|
aRetval = basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(aCubePolyPolygon,
|
|
aViewInfo3D.getObjectToView() * GetTransform());
|
|
aRetval.transform(rVCScene.getObjectTransformation());
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
|
|
sal_uInt32 E3dCompoundObject::GetHdlCount() const
|
|
{
|
|
// 8 corners + 1 E3dVolumeMarker (= Wireframe representation)
|
|
return 9L;
|
|
}
|
|
|
|
void E3dCompoundObject::AddToHdlList(SdrHdlList& rHdlList) const
|
|
{
|
|
const uno::Sequence< beans::PropertyValue > aEmptyParameters;
|
|
drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
|
|
E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
|
|
|
|
if(pRootScene)
|
|
{
|
|
const basegfx::B3DRange aBoundVolume(GetBoundVolume());
|
|
|
|
if(!aBoundVolume.isEmpty())
|
|
{
|
|
const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
|
|
|
|
for(sal_uInt32 a(0); a < 8; a++)
|
|
{
|
|
basegfx::B3DPoint aPos3D;
|
|
|
|
switch(a)
|
|
{
|
|
case 0 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
|
|
case 1 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
|
|
case 2 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
|
|
case 3 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
|
|
case 4 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
|
|
case 5 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
|
|
case 6 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
|
|
case 7 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
|
|
}
|
|
|
|
// to 3d view coor
|
|
aPos3D *= aViewInfo3D.getObjectToView() * GetTransform();
|
|
|
|
// create 2d relative scene
|
|
basegfx::B2DPoint aPos2D(aPos3D.getX(), aPos3D.getY());
|
|
|
|
// to 2d world coor
|
|
aPos2D *= rVCScene.getObjectTransformation();
|
|
|
|
rHdlList.AddHdl(new SdrHdl(Point(basegfx::fround(aPos2D.getX()), basegfx::fround(aPos2D.getY())), HDL_BWGT));
|
|
}
|
|
}
|
|
}
|
|
|
|
const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());
|
|
|
|
if(aPolyPolygon.count())
|
|
{
|
|
E3dVolumeMarker* pVolMarker = new E3dVolumeMarker(aPolyPolygon);
|
|
rHdlList.AddHdl(pVolMarker);
|
|
}
|
|
}
|
|
|
|
sal_uInt16 E3dCompoundObject::GetObjIdentifier() const
|
|
{
|
|
return E3D_COMPOUNDOBJ_ID;
|
|
}
|
|
|
|
void E3dCompoundObject::RecalcSnapRect()
|
|
{
|
|
const uno::Sequence< beans::PropertyValue > aEmptyParameters;
|
|
drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
|
|
E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
|
|
maSnapRect = Rectangle();
|
|
|
|
if(pRootScene)
|
|
{
|
|
// get VC of 3D candidate
|
|
const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
|
|
|
|
if(pVCOfE3D)
|
|
{
|
|
// get 3D primitive sequence
|
|
const drawinglayer::primitive3d::Primitive3DSequence xLocalSequence(pVCOfE3D->getViewIndependentPrimitive3DSequence());
|
|
|
|
if(xLocalSequence.hasElements())
|
|
{
|
|
// get BoundVolume
|
|
basegfx::B3DRange aBoundVolume(drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(
|
|
xLocalSequence, aViewInfo3D));
|
|
|
|
// transform bound volume to relative scene coordinates
|
|
aBoundVolume.transform(aViewInfo3D.getObjectToView());
|
|
|
|
// build 2d relative scene range
|
|
basegfx::B2DRange aSnapRange(
|
|
aBoundVolume.getMinX(), aBoundVolume.getMinY(),
|
|
aBoundVolume.getMaxX(), aBoundVolume.getMaxY());
|
|
|
|
// transform to 2D world coordiantes
|
|
const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
|
|
aSnapRange.transform(rVCScene.getObjectTransformation());
|
|
|
|
// snap to integer
|
|
maSnapRect = Rectangle(
|
|
sal_Int32(floor(aSnapRange.getMinX())), sal_Int32(floor(aSnapRange.getMinY())),
|
|
sal_Int32(ceil(aSnapRange.getMaxX())), sal_Int32(ceil(aSnapRange.getMaxY())));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
E3dCompoundObject* E3dCompoundObject::Clone() const
|
|
{
|
|
return CloneHelper< E3dCompoundObject >();
|
|
}
|
|
|
|
// convert given basegfx::B3DPolyPolygon to screen coor
|
|
|
|
basegfx::B2DPolyPolygon E3dCompoundObject::TransformToScreenCoor(const basegfx::B3DPolyPolygon& rCandidate)
|
|
{
|
|
const uno::Sequence< beans::PropertyValue > aEmptyParameters;
|
|
drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
|
|
E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
|
|
basegfx::B2DPolyPolygon aRetval;
|
|
|
|
if(pRootScene)
|
|
{
|
|
aRetval = basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(rCandidate,
|
|
aViewInfo3D.getObjectToView() * GetTransform());
|
|
const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
|
|
aRetval.transform(rVCScene.getObjectTransformation());
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
|
|
sal_Bool E3dCompoundObject::IsAOrdNumRemapCandidate(E3dScene*& prScene) const
|
|
{
|
|
if(GetObjList()
|
|
&& GetObjList()->GetOwnerObj()
|
|
&& GetObjList()->GetOwnerObj()->ISA(E3dScene))
|
|
{
|
|
prScene = (E3dScene*)GetObjList()->GetOwnerObj();
|
|
return sal_True;
|
|
}
|
|
|
|
return sal_False;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// eof
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|