/* -*- 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 .
*/
if(pPV && pPV->PageWindowCount())
{ for(size_t a = 0; a < mnCount; ++a)
{
SdrObject* pObject = rMarkList.GetMark(a)->GetMarkedSdrObj();
if(pObject)
{ // use the view-independent primitive representation (without // evtl. GridOffset, that may be applied to the DragEntry individually)
pObject->GetViewContact().getViewIndependentPrimitive2DContainer(maFullOverlay);
}
}
}
} else
{
mpPolygons = new basegfx::B2DPolyPolygon[mnCount];
for(size_t a = 0; a < mnCount; ++a)
{
SdrObject* pObject = rMarkList.GetMark(a)->GetMarkedSdrObj();
mpPolygons[mnCount - (a + 1)] = pObject->TakeXorPoly();
}
}
}
Impl3DMirrorConstructOverlay::~Impl3DMirrorConstructOverlay()
{ // The OverlayObjects are cleared using the destructor of OverlayObjectList. // That destructor calls clear() at the list which removes all objects from the // OverlayManager and deletes them. delete[] mpPolygons;
}
void Impl3DMirrorConstructOverlay::SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB)
{ // get rid of old overlay objects
maObjects.clear();
if(xTargetOverlay.is())
{ // build transformation: translate and rotate so that given edge is // on x axis, them mirror in y and translate back const basegfx::B2DVector aEdge(aMirrorAxisB.X() - aMirrorAxisA.X(), aMirrorAxisB.Y() - aMirrorAxisA.Y());
basegfx::B2DHomMatrix aMatrixTransform(basegfx::utils::createTranslateB2DHomMatrix(
-aMirrorAxisA.X(), -aMirrorAxisA.Y()));
aMatrixTransform.rotate(-atan2(aEdge.getY(), aEdge.getX()));
aMatrixTransform.scale(1.0, -1.0);
aMatrixTransform.rotate(atan2(aEdge.getY(), aEdge.getX()));
aMatrixTransform.translate(aMirrorAxisA.X(), aMirrorAxisA.Y());
if(!aMatrixTransform.isIdentity())
{ // embed in transformation group
aContent = drawinglayer::primitive2d::Primitive2DContainer { new drawinglayer::primitive2d::TransformPrimitive2D(aMatrixTransform, std::move(aContent))
};
}
// if we have full overlay from selected objects, embed with 50% transparence, the // transformation is added to the OverlayPrimitive2DSequenceObject
aContent = drawinglayer::primitive2d::Primitive2DContainer { new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aContent), 0.5)
};
// DrawMarkedObj override, since possibly only a single 3D object is to be // drawn
void E3dView::DrawMarkedObj(OutputDevice& rOut) const
{ // Does 3D objects exist which scenes are not selected? bool bSpecialHandling = false;
E3dScene *pScene = nullptr;
if(bSpecialHandling)
{ // Set selection flag to "not selected" for scenes related to all 3D // objects for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
{
SdrObject *pObj = rMarkList.GetMark(nObjs)->GetMarkedSdrObj(); if(auto pCompoundObject = dynamic_cast<E3dCompoundObject*>(pObj))
{ // related scene
pScene = pCompoundObject->getRootE3dSceneFromE3dObject();
if(!bSpecialHandling) if(auto pCompoundObj = dynamic_cast< const E3dCompoundObject*>(pObj))
{ // if the object is selected, but it's scene not, // we need special handling
pScene = pCompoundObj->getRootE3dSceneFromE3dObject();
// set 3d selection flags at all directly selected objects // and collect SnapRect of selected objects for(size_t nObjs = 0; nObjs < nCount; ++nObjs)
{
SdrObject *pObj = rMarkList.GetMark(nObjs)->GetMarkedSdrObj();
if(auto p3DObj = dynamic_cast<E3dCompoundObject*>(pObj))
{ // mark object, but not scenes
p3DObj->SetSelected(true);
aSelectedSnapRect.Union(p3DObj->GetSnapRect());
}
}
// create new mark list which contains all indirectly selected3d // scenes as selected objects
SdrMarkList aOldML(rMarkList);
SdrMarkList aNewML;
SdrMarkList& rCurrentMarkList = const_cast<E3dView*>(this)->GetMarkedObjectListWriteAccess();
rCurrentMarkList = aNewML;
// call parent. This will copy all scenes and the selection flags at the 3D objects. So // it will be possible to delete all non-selected 3d objects from the cloned 3d scenes
pNewModel = SdrView::CreateMarkedObjModel();
// Copy all objects from E3dScenes and insert them directly for(sal_uInt16 nPg(0); nPg < rMod.GetPageCount(); nPg++)
{ const SdrPage* pSrcPg=rMod.GetPage(nPg);
// calculate offset for paste
tools::Rectangle aR = pSrcPg->GetAllObjBoundRect();
Point aDist(aPos - aR.Center());
// Service routine used from local Clone() and from SdrCreateView::EndCreateObj(...) bool E3dView::ImpCloneAll3DObjectsToDestScene(E3dScene const * pSrcScene, E3dScene* pDstScene, Point /*aOffset*/)
{ bool bRetval(false);
if(pNewCompoundObj)
{ // get dest scene's current range in 3D world coordinates const basegfx::B3DHomMatrix aSceneToWorldTrans(pDstScene->GetFullTransform());
basegfx::B3DRange aSceneRange(pDstScene->GetBoundVolume());
aSceneRange.transform(aSceneToWorldTrans);
// get new object's implied object transformation const basegfx::B3DHomMatrix aNewObjectTrans(pNewCompoundObj->GetTransform());
// get new object's range in 3D world coordinates in dest scene // as if it were already added const basegfx::B3DHomMatrix aObjectToWorldTrans(aSceneToWorldTrans * aNewObjectTrans);
basegfx::B3DRange aObjectRange(pNewCompoundObj->GetBoundVolume());
aObjectRange.transform(aObjectToWorldTrans);
// if new object's size in X,Y or Z is bigger that 80% of dest scene, adapt scale // to not change the scene by the inserted object constdouble fSizeFactor(0.5);
// get translation adaptation const basegfx::B3DPoint aSceneCenter(aSceneRange.getCenter()); const basegfx::B3DPoint aObjectCenter(aObjectRange.getCenter());
// build full modification transform. The object's transformation // shall be modified, so start at object coordinates; transform to 3d world coor
basegfx::B3DHomMatrix aModifyingTransform(aObjectToWorldTrans);
// translate to absolute center in 3d world coor
aModifyingTransform.translate(-aObjectCenter.getX(), -aObjectCenter.getY(), -aObjectCenter.getZ());
// scale to dest size in 3d world coor
aModifyingTransform.scale(fScale, fScale, fScale);
// translate to dest scene center in 3d world coor
aModifyingTransform.translate(aSceneCenter.getX(), aSceneCenter.getY(), aSceneCenter.getZ());
// transform from 3d world to dest object coordinates
basegfx::B3DHomMatrix aWorldToObject(aObjectToWorldTrans);
aWorldToObject.invert();
aModifyingTransform = aWorldToObject * aModifyingTransform;
// correct implied object transform by applying changing one in object coor
pNewCompoundObj->SetTransform(aModifyingTransform * aNewObjectTrans);
// fill and insert new object
pNewCompoundObj->NbcSetLayer(pCompoundObj->GetLayer());
pNewCompoundObj->NbcSetStyleSheet(pCompoundObj->GetStyleSheet(), true);
pDstScene->InsertObject(pNewCompoundObj.get());
bRetval = true;
//For black text objects, the color set to gray if(pObj->getSdrPageFromSdrObject())
{ // if black is only default attribute from // pattern set it hard so that it is used in undo.
pObj->SetMergedItem(SvxColorItem(COL_BLACK, EE_CHAR_COLOR));
// add undo now if (GetModel().IsUndoEnabled())
AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
}
// line style turned off
aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
//Determining if FILL_Attribute is set. if(!pPath->IsClosed() || eFillStyle == drawing::FillStyle_NONE)
{ // This SdrPathObj is not filled, leave the front and rear face out. // Moreover, a two-sided representation necessary.
aDefault.SetDefaultExtrudeCloseFront(false);
aDefault.SetDefaultExtrudeCloseBack(false);
aSet.Put(makeSvx3DDoubleSidedItem(true));
// Set fill attribute
aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
// Fill color must be the color line, because the object was // previously just a line
Color aColorLine = aSet.Get(XATTR_LINECOLOR).GetColorValue();
aSet.Put(XFillColorItem(OUString(), aColorLine));
}
// Create a new extrude object
rtl::Reference<E3dObject> p3DObj; if(bExtrude)
{
p3DObj = new E3dExtrudeObj(pObj->getSdrModelFromSdrObject(), aDefault, pPath->GetPathPoly(), fDepth);
} else
{ // rLatheMat expects coordinates with y-axis up, pPath uses y-axis down
basegfx::B2DHomMatrix aFlipVerticalMat(1.0, 0.0, 0.0, 0.0, -1.0, 0.0);
basegfx::B2DPolyPolygon aPolyPoly2D(pPath->GetPathPoly());
aPolyPoly2D.transform(aFlipVerticalMat);
aPolyPoly2D.transform(rLatheMat); // ctor E3dLatheObj expects coordinates with y-axis down
aPolyPoly2D.transform(aFlipVerticalMat);
p3DObj = new E3dLatheObj(pObj->getSdrModelFromSdrObject(), aDefault, std::move(aPolyPoly2D));
}
// Set attribute
p3DObj->NbcSetLayer(pObj->GetLayer());
// change text color attribute for not so dark colors if(pObj->IsGroupObject())
{
SdrObjListIter aIter(*pObj, SdrIterMode::DeepWithGroups); while(aIter.IsMore())
{
SdrObject* pGroupMember = aIter.Next();
ImpChangeSomeAttributesFor3DConversion(pGroupMember);
}
} else
ImpChangeSomeAttributesFor3DConversion(pObj);
// change text color attribute for not so dark colors if(pNewObj1->IsGroupObject())
{
SdrObjListIter aIter(*pNewObj1, SdrIterMode::DeepWithGroups); while(aIter.IsMore())
{
SdrObject* pGroupMember = aIter.Next();
ImpChangeSomeAttributesFor3DConversion2(pGroupMember);
}
} else
ImpChangeSomeAttributesFor3DConversion2(pNewObj1.get());
// Determine the depth relative to the size of the selection double fDepth = 0.0; double fRot3D = 0.0;
basegfx::B2DHomMatrix aLatheMat;
if(bExtrude)
{
fDepth = std::hypot(aRect.GetWidth(), aRect.GetHeight()) / 6.0;
} if(!bExtrude)
{ // Create transformation for the polygons rotating body if (rPnt1 != rPnt2)
{ // Rotation around control point #1 with set angle // for 3D coordinates
basegfx::B2DPoint aDiff(rPnt1 - rPnt2);
fRot3D = atan2(aDiff.getY(), aDiff.getX()) - M_PI_2;
// Walk through the selection and convert it into 3D, complete with // Conversion to SdrPathObject, also fonts for(size_t a=0; a<rMarkList.GetMarkCount(); ++a)
{
SdrMark* pMark = rMarkList.GetMark(a);
SdrObject* pObj = pMark->GetMarkedSdrObj();
if(pScene->GetSubList() && pScene->GetSubList()->GetObjCount() != 0)
{ // Arrange all created objects by depth if(bExtrude)
DoDepthArrange(pScene.get(), fDepth);
// Center 3D objects in the middle of the overall rectangle
basegfx::B3DPoint aCenter(pScene->GetBoundVolume().getCenter());
basegfx::B3DHomMatrix aMatrix;
// Insert scene instead of the first selected object and throw away // all the old objects
SdrMark* pMark = rMarkList.GetMark(0); if (pMark)
{
SdrObject* pRepObj = pMark->GetMarkedSdrObj();
SdrPageView* pPV = pMark->GetPageView();
MarkObj(pRepObj, pPV, true);
ReplaceObjectAtView(pRepObj, *pPV, pScene.get(), false);
DeleteMarked();
MarkObj(pScene.get(), pPV);
}
// Rotate Rotation body around the axis of rotation if(!bExtrude && fRot3D != 0.0)
{
basegfx::B3DHomMatrix aRotate;
aRotate.rotate(0.0, 0.0, fRot3D);
pScene->SetTransform(aRotate * pScene->GetTransform());
}
// Set default rotation
{
basegfx::B3DHomMatrix aRotate;
aRotate.rotate(basegfx::deg2rad(20.0), 0.0, 0.0); // E3DModifySceneSnapRectUpdater updates the 2D representation of the scene. // It prepares things in ctor and acts in dtor.
E3DModifySceneSnapRectUpdater aUpdater(pScene->getSdrObjectFromSdrObjList());
pScene->SetTransform(aRotate * pScene->GetTransform());
}
} else
pScene.clear();
// sort in ExtrudeObj if(pLayer)
{ // do we have overlap with an object of this layer? bool bOverlap(false);
for(constauto& rAct : pLayer->mvNeighbours)
{ // do rAct.mpObj and pExtrudeObj overlap? Check by // using logical AND clipping const basegfx::B2DPolyPolygon aAndPolyPolygon(
basegfx::utils::solvePolygonOperationAnd(
aExtrudePoly,
rAct.maPreparedPolyPolygon));
if(aAndPolyPolygon.count() != 0)
{ // second criteria: is another fillstyle or color used? const SfxItemSet& rCompareSet = rAct.mpObj->GetMergedItemSet();
if(bOverlap)
{ // yes, start a new layer
pLayer->mpDown = new E3dDepthLayer;
pLayer = pLayer->mpDown;
nNumLayers++;
pLayer->mvNeighbours.emplace_back(pExtrudeObj, aExtrudePoly);
} else
{ // no, add to current layer
pLayer->mvNeighbours.emplace(pLayer->mvNeighbours.begin(), pExtrudeObj, aExtrudePoly);
}
} else
{ // first layer ever
pBaseLayer = new E3dDepthLayer;
pLayer = pBaseLayer;
nNumLayers++;
pLayer->mvNeighbours.emplace_back(pExtrudeObj, aExtrudePoly);
}
}
}
// number of layers is done if(nNumLayers > 1)
{ // need to be arranged double fMinDepth = fDepth * 0.8; double fStep = (fDepth - fMinDepth) / static_cast<double>(nNumLayers);
pLayer = pBaseLayer;
while(pLayer)
{ // move along layer for(auto& rAct : pLayer->mvNeighbours)
{ // adapt extrude value
rAct.mpObj->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH, sal_uInt32(fMinDepth + 0.5)));
}
// next layer
pLayer = pLayer->mpDown;
fMinDepth += fStep;
}
}
case SdrHdlKind::Upper: case SdrHdlKind::Lower:
{
eConstraint = E3dDragConstraint::Y;
} break;
case SdrHdlKind::UpperLeft: case SdrHdlKind::UpperRight: case SdrHdlKind::LowerLeft: case SdrHdlKind::LowerRight:
{
eConstraint = E3dDragConstraint::Z;
} break; default: break;
}
// do not mask the allowed rotations
eConstraint &= E3dDragConstraint::XYZ;
pForcedMeth = new E3dDragRotate(*this, rMarkList, eConstraint, IsSolidDragging());
} break;
case SdrDragMode::Move:
{ if(!bThereAreRootScenes)
{
pForcedMeth = new E3dDragMove(*this, rMarkList, meDragHdl, eConstraint, IsSolidDragging());
}
} break;
// later on case SdrDragMode::Mirror: case SdrDragMode::Crook: case SdrDragMode::Transparence: case SdrDragMode::Gradient: default:
{
} break;
}
}
}
} return SdrView::BegDragObj(rPnt, pOut, pHdl, nMinMov, pForcedMeth);
}
// Set current 3D drawing object, create the scene for this
rtl::Reference<E3dScene> E3dView::SetCurrent3DObj(E3dObject* p3DObj)
{
assert(p3DObj != nullptr && "Who puts in a NULL-pointer here");
// get transformed BoundVolume of the object
basegfx::B3DRange aVolume(p3DObj->GetBoundVolume());
aVolume.transform(p3DObj->GetTransform()); double fW(aVolume.getWidth()); double fH(aVolume.getHeight());
// and then attach the marks at the top and bottom of the object
basegfx::B2DRange aR; for(size_t nMark = 0; nMark < rMarkList.GetMarkCount(); ++nMark)
{
SdrObject* pMark = rMarkList.GetMark(nMark)->GetMarkedSdrObj();
basegfx::B2DPolyPolygon aXPP(pMark->TakeXorPoly());
aR.expand(basegfx::utils::getRange(aXPP));
}
if (pHdl)
{
SdrHdlKind eHdlKind = pHdl->GetKind();
// reacts only due to a mirror axis if ((eHdlKind == SdrHdlKind::Ref1) ||
(eHdlKind == SdrHdlKind::Ref2) ||
(eHdlKind == SdrHdlKind::MirrorAxis))
{ const SdrHdlList &aHdlList = GetHdlList ();
// delete the mirrored polygon, mirrors the original and draws // it anew
SdrView::MovAction (rPnt);
mpMirrorOverlay->SetMirrorAxis(
aHdlList.GetHdl (SdrHdlKind::Ref1)->GetPos(),
aHdlList.GetHdl (SdrHdlKind::Ref2)->GetPos());
}
} else
{
SdrView::MovAction (rPnt);
}
} else
{
SdrView::MovAction (rPnt);
}
}
// The End. Create object and any child objects through ImpCreate3DLathe. // With the parameter value sal_True (SDefault: sal_False) is simply a // rotation body created, without letting the user set the position of the // axis. It is sufficient with this call, if an object is selected. // (No initialization necessary)
ConvertMarkedObjTo3D(false, aPnt1, aPnt2);
} else
{ // Turn off helper overlay // Determine from the handle positions and the displacement of // the points const SdrHdlList &aHdlList = GetHdlList();
Point aMirrorRef1 = aHdlList.GetHdl(SdrHdlKind::Ref1)->GetPos();
Point aMirrorRef2 = aHdlList.GetHdl(SdrHdlKind::Ref2)->GetPos();
// So far: there are two or more of any objects selected. See if // compound objects are involved. If yes, ban grouping. if(m_bGroupPossible && bCompound)
m_bGroupPossible = false;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.