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>
621 lines
21 KiB
C++
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: */
|