Files
odfstudio/svx/source/engine3d/obj3d.cxx
T
Armin Le Grand (collabora) 5519a3d407 Correct StyleSheet handling when cloning to different Model II
Until now the 'local' StyleSheet got set, but that may
not be the same as the original. It was/gets identified just
by searching by name and type, not comparing content.

What to do? We could...

(a) the Style-Friendly way:
 - check if StyleSheet is identical
  - if not, create a new in-between StyleSheet hosting missing Items
  - if yes, use, done.

(b) the pragmatic/practical way:
 - Just hard-attribute the Items that are detected as different
   similar to what BurnInStyleSheetAttributes does/did, but only
   for a view differing Items

(b) is the most simple for now, but will lead to more hard
attributes. The other possibilities will be better in the
long term. For now, I will use (b).

Note that there are more cases in that VERY complex and grown
stuff emerging from SdDrawDocument::PasteBookmarkAsPage. More
things will need to be fixed, see this as a 1st step.

Needed to adapt postProcessAfterCloneToDifferentModel due to
UT testTdf96206 failing, see comment there for details.

That 1st implementation showed weaknesses with those Items
critical and only on MasterPages, so decided to give up on
that and implement ContentCompare to SdPage::Equals. That
was easier than thought: No parameter needed, only used by
InsertBookmarkAsPage_FindDuplicateLayouts::operator(). Thus,
SdPage::Equals needs no change, just SdrObject::Equals.

Due to still problems with Items corrected in Objects on
MasterPages I will for now exclude this.

Could now isolate remaining problems, these are defaults
and/or PresObj things on MasterPages. Important is that I can
completely correct all Items for all Objects in
postProcessAfterCloneToDifferentModel. I can react to these
false-positives in the ContentCompare in SdrObject::Equals.

Signed-off-by: Armin Le Grand (collabora) <Armin.LeGrand@collabora.com>
Change-Id: I10e17c8d6a893dbe92ab716182f07bafce1f3284
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/6595
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Armin Le Grand <armin.legrand@collabora.com>
(cherry picked from commit 92ffaeac04c5c8586006b026f29ce12fba3674f1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211729
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-10-05 08:52:54 +02:00

621 lines
21 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <o3tl/numeric.hxx>
#include <svx/strings.hrc>
#include <svx/dialmgr.hxx>
#include <svx/svdhdl.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdobjkind.hxx>
#include <svx/scene3d.hxx>
#include <svx/obj3d.hxx>
#include <sdr/properties/e3dproperties.hxx>
#include <sdr/properties/e3dcompoundproperties.hxx>
#include <basegfx/polygon/b3dpolypolygontools.hxx>
#include <basegfx/point/b3dpoint.hxx>
#include <basegfx/matrix/b3dhommatrix.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <svx/helperhittest3d.hxx>
#include <sdr/contact/viewcontactofe3d.hxx>
#include <drawinglayer/geometry/viewinformation3d.hxx>
#include <com/sun/star/uno/Sequence.h>
#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
#include <svx/e3dsceneupdater.hxx>
#include <comphelper/configuration.hxx>
using namespace com::sun::star;
std::unique_ptr<sdr::properties::BaseProperties> E3dObject::CreateObjectSpecificProperties()
{
return std::make_unique<sdr::properties::E3dProperties>(*this);
}
E3dObject::E3dObject(SdrModel& rSdrModel)
: SdrAttrObj(rSdrModel),
mbTfHasChanged(true),
mbIsSelected(false)
{
m_bIs3DObj = true;
m_bClosedObj = true;
}
E3dObject::E3dObject(SdrModel& rSdrModel, E3dObject const & rSource)
: SdrAttrObj(rSdrModel, rSource),
mbTfHasChanged(true),
mbIsSelected(false)
{
m_bIs3DObj = true;
m_bClosedObj = true;
// BoundVol can be copied since also the children are copied
maLocalBoundVol = rSource.maLocalBoundVol;
maTransformation = rSource.maTransformation;
// Because the parent may have changed, definitely redefine the total
// transformation next time
SetTransformChanged();
// Copy selection status
mbIsSelected = rSource.mbIsSelected;
}
E3dObject::~E3dObject()
{
}
void E3dObject::SetSelected(bool bNew)
{
if(mbIsSelected != bNew)
{
mbIsSelected = bNew;
}
}
// Break, default implementations
bool E3dObject::IsBreakObjPossible()
{
return false;
}
rtl::Reference<SdrAttrObj> E3dObject::GetBreakObj()
{
return nullptr;
}
SdrInventor E3dObject::GetObjInventor() const
{
return SdrInventor::E3d;
}
SdrObjKind E3dObject::GetObjIdentifier() const
{
return SdrObjKind::E3D_Object;
}
// Determine the capabilities of the object
void E3dObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
{
rInfo.bResizeFreeAllowed = true;
rInfo.bResizePropAllowed = true;
rInfo.bRotateFreeAllowed = true;
rInfo.bRotate90Allowed = true;
rInfo.bMirrorFreeAllowed = false;
rInfo.bMirror45Allowed = false;
rInfo.bMirror90Allowed = false;
rInfo.bShearAllowed = false;
rInfo.bEdgeRadiusAllowed = false;
rInfo.bCanConvToPath = false;
// no transparence for 3d objects
rInfo.bTransparenceAllowed = false;
// 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
// coordinates were an unsolved problem.
rInfo.bCanConvToPoly = false;
rInfo.bCanConvToContour = false;
rInfo.bCanConvToPathLineToArea = false;
rInfo.bCanConvToPolyLineToArea = false;
}
// resize object, used from old 2d interfaces, e.g. in Move/Scale dialog (F4)
void E3dObject::NbcResize(const Point& rRef, double xFact, double yFact)
{
// Movement in X, Y in the eye coordinate system
E3dScene* pScene(getRootE3dSceneFromE3dObject());
if(nullptr == pScene)
{
return;
}
// 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(static_cast<double>(rRef.X()), static_cast<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 aFullTransform(GetFullTransform());
basegfx::B3DHomMatrix aTrans(aFullTransform);
aTrans *= aViewInfo3D.getOrientation();
aTrans.translate(-aScaleCenter3D.getX(), -aScaleCenter3D.getY(), -aScaleCenter3D.getZ());
aTrans.scale(fScaleX, fScaleY, 1.0);
aTrans.translate(aScaleCenter3D.getX(), aScaleCenter3D.getY(), aScaleCenter3D.getZ());
aTrans *= aInverseOrientation;
aFullTransform.invert();
aTrans *= aFullTransform;
// Apply
basegfx::B3DHomMatrix aObjTrans(GetTransform());
aObjTrans *= aTrans;
E3DModifySceneSnapRectUpdater aUpdater(this);
SetTransform(aObjTrans);
}
// 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(getRootE3dSceneFromE3dObject());
if(nullptr == pScene)
{
return;
}
//Dimensions of the scene in 3D and 2D for comparison
tools::Rectangle aRect = pScene->GetSnapRect();
basegfx::B3DHomMatrix aInvDispTransform;
E3dScene* pParent(getParentE3dSceneFromE3dObject());
if(nullptr != pParent)
{
aInvDispTransform = pParent->GetFullTransform();
aInvDispTransform.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());
if ((aRect.GetWidth() == 0) || (aRect.GetHeight() == 0))
throw o3tl::divide_by_zero();
// build relative movement vector in eye coordinates
basegfx::B3DPoint aMove(
static_cast<double>(rSize.Width()) * aEyeVol.getWidth() / static_cast<double>(aRect.GetWidth()),
static_cast<double>(-rSize.Height()) * aEyeVol.getHeight() / static_cast<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(aInvDispTransform * 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());
}
void E3dObject::RecalcSnapRect()
{
maSnapRect = tools::Rectangle();
}
// 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()
{
E3dScene* pParent(getParentE3dSceneFromE3dObject());
if(nullptr != pParent)
{
pParent->InvalidateBoundVolume();
pParent->StructureChanged();
}
}
E3dScene* E3dObject::getParentE3dSceneFromE3dObject() const
{
return DynCastE3dScene(getParentSdrObjectFromSdrObject());
}
// Determine the top-level scene object
E3dScene* E3dObject::getRootE3dSceneFromE3dObject() const
{
E3dScene* pParent(getParentE3dSceneFromE3dObject());
if(nullptr != pParent)
{
return pParent->getRootE3dSceneFromE3dObject();
}
return nullptr;
}
// Calculate enclosed volume, including all child objects
basegfx::B3DRange E3dObject::RecalcBoundVolume() const
{
basegfx::B3DRange aRetval;
if (comphelper::IsFuzzing()) // skip slow path for fuzzing
return aRetval;
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::Primitive3DContainer& xLocalSequence(pVCOfE3D->getVIP3DSWithoutObjectTransform());
if(!xLocalSequence.empty())
{
const uno::Sequence< beans::PropertyValue > aEmptyParameters;
const drawinglayer::geometry::ViewInformation3D aLocalViewInformation3D(aEmptyParameters);
aRetval = xLocalSequence.getB3DRange(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 in transformation to all child objects
void E3dObject::SetTransformChanged()
{
InvalidateBoundVolume();
mbTfHasChanged = true;
}
// 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);
E3dScene* pParent(getParentE3dSceneFromE3dObject());
if(nullptr != pParent)
{
aNewFullTransformation = pParent->GetFullTransform() * aNewFullTransformation;
}
const_cast< E3dObject* >(this)->maFullTransform = std::move(aNewFullTransformation);
const_cast< E3dObject* >(this)->mbTfHasChanged = false;
}
return maFullTransform;
}
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 (m_pUserCall != nullptr) m_pUserCall->Changed(*this, SdrUserCallType::Resize, tools::Rectangle());
}
}
basegfx::B3DPolyPolygon E3dObject::CreateWireframe() const
{
const basegfx::B3DRange aBoundVolume(GetBoundVolume());
return basegfx::utils::createCubePolyPolygonFromB3DRange(aBoundVolume);
}
// Get the name of the object (singular)
OUString E3dObject::TakeObjNameSingul() const
{
OUString sName = SvxResId(STR_ObjNameSingulObj3d);
OUString aName(GetName());
if (!aName.isEmpty())
{
sName += " '" + aName + "'";
}
return sName;
}
// Get the name of the object (plural)
OUString E3dObject::TakeObjNamePlural() const
{
return SvxResId(STR_ObjNamePluralObj3d);
}
rtl::Reference<SdrObject> E3dObject::implCloneSdrObject(SdrModel& rTargetModel) const
{
return new E3dObject(rTargetModel, *this);
}
std::unique_ptr<SdrObjGeoData> E3dObject::NewGeoData() const
{
return std::make_unique<E3DObjGeoData>();
}
void E3dObject::SaveGeoData(SdrObjGeoData& rGeo) const
{
SdrAttrObj::SaveGeoData (rGeo);
static_cast<E3DObjGeoData &>(rGeo).maLocalBoundVol = maLocalBoundVol;
static_cast<E3DObjGeoData &>(rGeo).maTransformation = maTransformation;
}
void E3dObject::RestoreGeoData(const SdrObjGeoData& rGeo)
{
maLocalBoundVol = static_cast<const E3DObjGeoData &>(rGeo).maLocalBoundVol;
E3DModifySceneSnapRectUpdater aUpdater(this);
NbcSetTransform(static_cast<const E3DObjGeoData &>(rGeo).maTransformation);
SdrAttrObj::RestoreGeoData (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, Degree100 nAngle, double sn, double cs)
{
// So currently the gluepoints are defined relative to the scene aOutRect.
// Before turning the gluepoints 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 fAngleInRad = toRadians(nAngle);
basegfx::B3DHomMatrix aRotateZ;
aRotateZ.rotate(0.0, 0.0, fAngleInRad);
NbcSetTransform(aRotateZ * GetTransform());
SetBoundAndSnapRectsDirty(); // This forces a recalculation of all BoundRects
NbcRotateGluePoints(rRef,nAngle,sn,cs); // Rotate the gluepoints (who still
// have coordinates relative to the
// original page)
SetGlueReallyAbsolute(false); // from now they are again relative to BoundRect (that is defined as aOutRect)
}
std::unique_ptr<sdr::properties::BaseProperties> E3dCompoundObject::CreateObjectSpecificProperties()
{
return std::make_unique<sdr::properties::E3dCompoundProperties>(*this);
}
E3dCompoundObject::E3dCompoundObject(SdrModel& rSdrModel)
: E3dObject(rSdrModel)
{
}
E3dCompoundObject::E3dCompoundObject(SdrModel& rSdrModel, E3dCompoundObject const & rSource)
: E3dObject(rSdrModel, rSource)
{
}
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::utils::createB2DPolyPolygonFromB3DPolyPolygon(aCubePolyPolygon,
aViewInfo3D.getObjectToView() * GetTransform());
aRetval.transform(rVCScene.getObjectTransformation());
}
return aRetval;
}
sal_uInt32 E3dCompoundObject::GetHdlCount() const
{
// 8 corners + 1 E3dVolumeMarker (= Wireframe representation)
return 9;
}
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(std::make_unique<SdrHdl>(Point(basegfx::fround<tools::Long>(aPos2D.getX()), basegfx::fround<tools::Long>(aPos2D.getY())), SdrHdlKind::BezierWeight));
}
}
}
const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());
if(aPolyPolygon.count())
{
rHdlList.AddHdl(std::make_unique<E3dVolumeMarker>(aPolyPolygon));
}
}
SdrObjKind E3dCompoundObject::GetObjIdentifier() const
{
return SdrObjKind::E3D_CompoundObject;
}
void E3dCompoundObject::RecalcSnapRect()
{
if (comphelper::IsFuzzing()) // skip slow path for fuzzing
return;
const uno::Sequence< beans::PropertyValue > aEmptyParameters;
drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
maSnapRect = tools::Rectangle();
if(!pRootScene)
return;
// get VC of 3D candidate
const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
if(!pVCOfE3D)
return;
// get 3D primitive sequence
const drawinglayer::primitive3d::Primitive3DContainer xLocalSequence(pVCOfE3D->getViewIndependentPrimitive3DContainer());
if(xLocalSequence.empty())
return;
// get BoundVolume
basegfx::B3DRange aBoundVolume(xLocalSequence.getB3DRange(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 coordinates
const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
aSnapRange.transform(rVCScene.getObjectTransformation());
// snap to integer
maSnapRect = tools::Rectangle(
sal_Int32(floor(aSnapRange.getMinX())), sal_Int32(floor(aSnapRange.getMinY())),
sal_Int32(ceil(aSnapRange.getMaxX())), sal_Int32(ceil(aSnapRange.getMaxY())));
}
rtl::Reference<SdrObject> E3dCompoundObject::implCloneSdrObject(SdrModel& rTargetModel) const
{
return new E3dCompoundObject(rTargetModel, *this);
}
// convert given basegfx::B3DPolyPolygon to screen coor
basegfx::B2DPolyPolygon E3dCompoundObject::TransformToScreenCoor(const basegfx::B3DPolyPolygon& rCandidate) const
{
const uno::Sequence< beans::PropertyValue > aEmptyParameters;
drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
basegfx::B2DPolyPolygon aRetval;
if(pRootScene)
{
aRetval = basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(rCandidate,
aViewInfo3D.getObjectToView() * GetTransform());
const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
aRetval.transform(rVCScene.getObjectTransformation());
}
return aRetval;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */