blob: 00632a3a72c3bebd9a3eb830638b6a69f2cc43fd [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"
#include <vcl/wrkwin.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdopath.hxx>
#include <tools/shl.hxx>
#include "svx/svditer.hxx"
#include <svx/svdpool.hxx>
#include <svx/svdorect.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svxids.hrc>
#include <editeng/colritem.hxx>
#include <svx/xtable.hxx>
#include <svx/svdview.hxx>
#include <svx/dialogs.hrc>
#include <svx/dialmgr.hxx>
#include "svx/globl3d.hxx"
#include <svx/obj3d.hxx>
#include <svx/lathe3d.hxx>
#include <svx/sphere3d.hxx>
#include <svx/extrud3d.hxx>
#include <svx/cube3d.hxx>
#include <svx/polysc3d.hxx>
#include "dragmt3d.hxx"
#include <svx/view3d.hxx>
#include <svx/svdundo.hxx>
#include <svx/xflclit.hxx>
#include <svx/xlnclit.hxx>
#include <svx/svdograf.hxx>
#include <svx/xbtmpit.hxx>
#include <svx/xflbmtit.hxx>
#include <basegfx/range/b2drange.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <svx/xlnwtit.hxx>
#include <svx/sdr/overlay/overlaypolypolygon.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
#include <drawinglayer/geometry/viewinformation3d.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <svx/sdr/contact/objectcontact.hxx>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
#define ITEMVALUE(ItemSet,Id,Cast) ((const Cast&)(ItemSet).Get(Id)).GetValue()
TYPEINIT1(E3dView, SdrView);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Migrate Marking
class Impl3DMirrorConstructOverlay
{
// The OverlayObjects
::sdr::overlay::OverlayObjectList maObjects;
// the view
const E3dView& mrView;
// the object count
sal_uInt32 mnCount;
// the unmirrored polygons
basegfx::B2DPolyPolygon* mpPolygons;
// the overlay geometry from selected objects
drawinglayer::primitive2d::Primitive2DSequence maFullOverlay;
public:
Impl3DMirrorConstructOverlay(const E3dView& rView);
~Impl3DMirrorConstructOverlay();
void SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB);
};
Impl3DMirrorConstructOverlay::Impl3DMirrorConstructOverlay(const E3dView& rView)
: maObjects(),
mrView(rView),
mnCount(rView.GetMarkedObjectCount()),
mpPolygons(0),
maFullOverlay()
{
if(mnCount)
{
if(mrView.IsSolidDragging())
{
SdrPageView* pPV = rView.GetSdrPageView();
if(pPV && pPV->PageWindowCount())
{
sdr::contact::ObjectContact& rOC = pPV->GetPageWindow(0)->GetObjectContact();
sdr::contact::DisplayInfo aDisplayInfo;
// Do not use the last ViewPort set at the OC at the last ProcessDisplay()
rOC.resetViewPort();
for(sal_uInt32 a(0);a < mnCount;a++)
{
SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
if(pObject)
{
sdr::contact::ViewContact& rVC = pObject->GetViewContact();
sdr::contact::ViewObjectContact& rVOC = rVC.GetViewObjectContact(rOC);
const drawinglayer::primitive2d::Primitive2DSequence aNewSequence(rVOC.getPrimitive2DSequenceHierarchy(aDisplayInfo));
drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(maFullOverlay, aNewSequence);
}
}
}
}
else
{
mpPolygons = new basegfx::B2DPolyPolygon[mnCount];
for(sal_uInt32 a(0); a < mnCount; a++)
{
SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
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.
if(!mrView.IsSolidDragging())
{
delete[] mpPolygons;
}
}
void Impl3DMirrorConstructOverlay::SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB)
{
// get rid of old overlay objects
maObjects.clear();
// create new ones
for(sal_uInt32 a(0); a < mrView.PaintWindowCount(); a++)
{
SdrPaintWindow* pCandidate = mrView.GetPaintWindow(a);
::sdr::overlay::OverlayManager* pTargetOverlay = pCandidate->GetOverlayManager();
if(pTargetOverlay)
{
// buld transfoprmation: 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::tools::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(mrView.IsSolidDragging())
{
if(maFullOverlay.hasElements())
{
drawinglayer::primitive2d::Primitive2DSequence aContent(maFullOverlay);
if(!aMatrixTransform.isIdentity())
{
// embed in transformation group
drawinglayer::primitive2d::Primitive2DReference aTransformPrimitive2D(new drawinglayer::primitive2d::TransformPrimitive2D(aMatrixTransform, aContent));
aContent = drawinglayer::primitive2d::Primitive2DSequence(&aTransformPrimitive2D, 1);
}
// if we have full overlay from selected objects, embed with 50% transparence, the
// transformation is added to the OverlayPrimitive2DSequenceObject
drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(aContent, 0.5));
aContent = drawinglayer::primitive2d::Primitive2DSequence(&aUnifiedTransparencePrimitive2D, 1);
sdr::overlay::OverlayPrimitive2DSequenceObject* pNew = new sdr::overlay::OverlayPrimitive2DSequenceObject(aContent);
pTargetOverlay->add(*pNew);
maObjects.append(*pNew);
}
}
else
{
for(sal_uInt32 b(0); b < mnCount; b++)
{
// apply to polygon
basegfx::B2DPolyPolygon aPolyPolygon(mpPolygons[b]);
aPolyPolygon.transform(aMatrixTransform);
::sdr::overlay::OverlayPolyPolygonStripedAndFilled* pNew = new ::sdr::overlay::OverlayPolyPolygonStripedAndFilled(
aPolyPolygon);
pTargetOverlay->add(*pNew);
maObjects.append(*pNew);
}
}
}
}
}
/*************************************************************************
|*
|* Konstruktor 1
|*
\************************************************************************/
E3dView::E3dView(SdrModel* pModel, OutputDevice* pOut) :
SdrView(pModel, pOut)
{
InitView ();
}
/*************************************************************************
|*
|* DrawMarkedObj ueberladen, da eventuell nur einzelne 3D-Objekte
|* gezeichnet werden sollen
|*
\************************************************************************/
void E3dView::DrawMarkedObj(OutputDevice& rOut) const
{
// Existieren 3D-Objekte, deren Szenen nicht selektiert sind?
sal_Bool bSpecialHandling = sal_False;
E3dScene *pScene = NULL;
long nCnt = GetMarkedObjectCount();
for(long nObjs = 0;nObjs < nCnt;nObjs++)
{
SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
if(pObj && pObj->ISA(E3dCompoundObject))
{
// zugehoerige Szene
pScene = ((E3dCompoundObject*)pObj)->GetScene();
if(pScene && !IsObjMarked(pScene))
bSpecialHandling = sal_True;
}
// Alle SelectionFlags zuruecksetzen
if(pObj && pObj->ISA(E3dObject))
{
pScene = ((E3dObject*)pObj)->GetScene();
if(pScene)
pScene->SetSelected(sal_False);
}
}
if(bSpecialHandling)
{
// SelectionFlag bei allen zu 3D Objekten gehoerigen
// Szenen und deren Objekten auf nicht selektiert setzen
long nObjs;
for(nObjs = 0;nObjs < nCnt;nObjs++)
{
SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
if(pObj && pObj->ISA(E3dCompoundObject))
{
// zugehoerige Szene
pScene = ((E3dCompoundObject*)pObj)->GetScene();
if(pScene)
pScene->SetSelected(sal_False);
}
}
// bei allen direkt selektierten Objekten auf selektiert setzen
SdrMark* pM = NULL;
for(nObjs = 0;nObjs < nCnt;nObjs++)
{
SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
if(pObj && pObj->ISA(E3dObject))
{
// Objekt markieren
E3dObject* p3DObj = (E3dObject*)pObj;
p3DObj->SetSelected(sal_True);
pScene = p3DObj->GetScene();
pM = GetSdrMarkByIndex(nObjs);
}
}
if(pScene)
{
// code from parent
SortMarkedObjects();
pScene->SetDrawOnlySelected(sal_True);
pScene->SingleObjectPainter(rOut); // #110094#-17
pScene->SetDrawOnlySelected(sal_False);
}
// SelectionFlag zuruecksetzen
for(nObjs = 0;nObjs < nCnt;nObjs++)
{
SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
if(pObj && pObj->ISA(E3dCompoundObject))
{
// zugehoerige Szene
pScene = ((E3dCompoundObject*)pObj)->GetScene();
if(pScene)
pScene->SetSelected(sal_False);
}
}
}
else
{
// call parent
SdrExchangeView::DrawMarkedObj(rOut);
}
}
/*************************************************************************
|*
|* Model holen ueberladen, da bei einzelnen 3D Objekten noch eine Szene
|* untergeschoben werden muss
|*
\************************************************************************/
SdrModel* E3dView::GetMarkedObjModel() const
{
// Existieren 3D-Objekte, deren Szenen nicht selektiert sind?
bool bSpecialHandling(false);
const sal_uInt32 nCount(GetMarkedObjectCount());
sal_uInt32 nObjs(0);
E3dScene *pScene = 0;
for(nObjs = 0; nObjs < nCount; nObjs++)
{
const SdrObject* pObj = GetMarkedObjectByIndex(nObjs);
if(!bSpecialHandling && pObj && pObj->ISA(E3dCompoundObject))
{
// if the object is selected, but it's scene not,
// we need special handling
pScene = ((E3dCompoundObject*)pObj)->GetScene();
if(pScene && !IsObjMarked(pScene))
{
bSpecialHandling = true;
}
}
if(pObj && pObj->ISA(E3dObject))
{
// reset all selection flags at 3D objects
pScene = ((E3dObject*)pObj)->GetScene();
if(pScene)
{
pScene->SetSelected(false);
}
}
}
if(!bSpecialHandling)
{
// call parent
return SdrView::GetMarkedObjModel();
}
SdrModel* pNewModel = 0;
Rectangle aSelectedSnapRect;
// set 3d selection flags at all directly selected objects
// and collect SnapRect of selected objects
for(nObjs = 0; nObjs < nCount; nObjs++)
{
SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
if(pObj && pObj->ISA(E3dCompoundObject))
{
// mark object, but not scenes
E3dCompoundObject* p3DObj = (E3dCompoundObject*)pObj;
p3DObj->SetSelected(true);
aSelectedSnapRect.Union(p3DObj->GetSnapRect());
}
}
// create new mark list which contains all indirectly selected3d
// scenes as selected objects
SdrMarkList aOldML(GetMarkedObjectList());
SdrMarkList aNewML;
SdrMarkList& rCurrentMarkList = ((E3dView*)this)->GetMarkedObjectListWriteAccess();
rCurrentMarkList = aNewML;
for(nObjs = 0; nObjs < nCount; nObjs++)
{
SdrObject *pObj = aOldML.GetMark(nObjs)->GetMarkedSdrObj();
if(pObj && pObj->ISA(E3dObject))
{
pScene = ((E3dObject*)pObj)->GetScene();
if(pScene && !IsObjMarked(pScene) && GetSdrPageView())
{
((E3dView*)this)->MarkObj(pScene, GetSdrPageView(), sal_False, sal_True);
}
}
}
// call parent. This will copy all scenes and the selection flags at the 3d objectss. So
// it will be possible to delete all non-selected 3d objects from the cloned 3d scenes
pNewModel = SdrView::GetMarkedObjModel();
if(pNewModel)
{
for(sal_uInt16 nPg(0); nPg < pNewModel->GetPageCount(); nPg++)
{
const SdrPage* pSrcPg=pNewModel->GetPage(nPg);
const sal_uInt32 nObAnz(pSrcPg->GetObjCount());
for(sal_uInt32 nOb(0); nOb < nObAnz; nOb++)
{
const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
if(pSrcOb->ISA(E3dScene))
{
pScene = (E3dScene*)pSrcOb;
// delete all not intentionally cloned 3d objects
pScene->removeAllNonSelectedObjects();
// reset select flags and set SnapRect of all selected objects
pScene->SetSelected(false);
pScene->SetSnapRect(aSelectedSnapRect);
}
}
}
}
// restore old selection
rCurrentMarkList = aOldML;
// model zurueckgeben
return pNewModel;
}
/*************************************************************************
|*
|* Bei Paste muss - falls in eine Scene eingefuegt wird - die
|* Objekte der Szene eingefuegt werden, die Szene selbst aber nicht
|*
\************************************************************************/
sal_Bool E3dView::Paste(const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, sal_uInt32 nOptions)
{
sal_Bool bRetval = sal_False;
// Liste holen
Point aPos(rPos);
SdrObjList* pDstList = pLst;
ImpGetPasteObjList(aPos, pDstList);
if(!pDstList)
return sal_False;
// Owner der Liste holen
SdrObject* pOwner = pDstList->GetOwnerObj();
if(pOwner && pOwner->ISA(E3dScene))
{
E3dScene* pDstScene = (E3dScene*)pOwner;
BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_EXCHANGE_PASTE));
// Alle Objekte aus E3dScenes kopieren und direkt einfuegen
for(sal_uInt16 nPg(0); nPg < rMod.GetPageCount(); nPg++)
{
const SdrPage* pSrcPg=rMod.GetPage(nPg);
sal_uInt32 nObAnz(pSrcPg->GetObjCount());
// calculate offset for paste
Rectangle aR = pSrcPg->GetAllObjBoundRect();
Point aDist(aPos - aR.Center());
// Unterobjekte von Szenen einfuegen
for(sal_uInt32 nOb(0); nOb < nObAnz; nOb++)
{
const SdrObject* pSrcOb = pSrcPg->GetObj(nOb);
if(pSrcOb->ISA(E3dScene))
{
E3dScene* pSrcScene = (E3dScene*)pSrcOb;
ImpCloneAll3DObjectsToDestScene(pSrcScene, pDstScene, aDist);
}
}
}
EndUndo();
}
else
{
// call parent
bRetval = SdrView::Paste(rMod, rPos, pLst, nOptions);
}
// und Rueckgabewert liefern
return bRetval;
}
// #83403# Service routine used from local Clone() and from SdrCreateView::EndCreateObj(...)
sal_Bool E3dView::ImpCloneAll3DObjectsToDestScene(E3dScene* pSrcScene, E3dScene* pDstScene, Point /*aOffset*/)
{
sal_Bool bRetval(sal_False);
if(pSrcScene && pDstScene)
{
const sdr::contact::ViewContactOfE3dScene& rVCSceneDst = static_cast< sdr::contact::ViewContactOfE3dScene& >(pDstScene->GetViewContact());
const drawinglayer::geometry::ViewInformation3D aViewInfo3DDst(rVCSceneDst.getViewInformation3D());
const sdr::contact::ViewContactOfE3dScene& rVCSceneSrc = static_cast< sdr::contact::ViewContactOfE3dScene& >(pSrcScene->GetViewContact());
const drawinglayer::geometry::ViewInformation3D aViewInfo3DSrc(rVCSceneSrc.getViewInformation3D());
for(sal_uInt32 i(0); i < pSrcScene->GetSubList()->GetObjCount(); i++)
{
E3dCompoundObject* pCompoundObj = dynamic_cast< E3dCompoundObject* >(pSrcScene->GetSubList()->GetObj(i));
if(pCompoundObj)
{
// #116235#
E3dCompoundObject* pNewCompoundObj = dynamic_cast< E3dCompoundObject* >(pCompoundObj->Clone());
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);
// get scale adaption
const basegfx::B3DVector aSceneScale(aSceneRange.getRange());
const basegfx::B3DVector aObjectScale(aObjectRange.getRange());
double fScale(1.0);
// 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
const double fSizeFactor(0.5);
if(aObjectScale.getX() * fScale > aSceneScale.getX() * fSizeFactor)
{
const double fObjSize(aObjectScale.getX() * fScale);
const double fFactor((aSceneScale.getX() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
fScale *= fFactor;
}
if(aObjectScale.getY() * fScale > aSceneScale.getY() * fSizeFactor)
{
const double fObjSize(aObjectScale.getY() * fScale);
const double fFactor((aSceneScale.getY() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
fScale *= fFactor;
}
if(aObjectScale.getZ() * fScale > aSceneScale.getZ() * fSizeFactor)
{
const double fObjSize(aObjectScale.getZ() * fScale);
const double fFactor((aSceneScale.getZ() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
fScale *= fFactor;
}
// get translation adaption
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->SetModel(pDstScene->GetModel());
pNewCompoundObj->SetPage(pDstScene->GetPage());
pNewCompoundObj->NbcSetLayer(pCompoundObj->GetLayer());
pNewCompoundObj->NbcSetStyleSheet(pCompoundObj->GetStyleSheet(), sal_True);
pDstScene->Insert3DObj(pNewCompoundObj);
bRetval = sal_True;
// Undo anlegen
if( GetModel()->IsUndoEnabled() )
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewCompoundObj));
}
}
}
}
return bRetval;
}
/*************************************************************************
|*
|* 3D-Konvertierung moeglich?
|*
\************************************************************************/
sal_Bool E3dView::IsConvertTo3DObjPossible() const
{
sal_Bool bAny3D(sal_False);
sal_Bool bGroupSelected(sal_False);
sal_Bool bRetval(sal_True);
for(sal_uInt32 a=0;!bAny3D && a<GetMarkedObjectCount();a++)
{
SdrObject *pObj = GetMarkedObjectByIndex(a);
if(pObj)
{
ImpIsConvertTo3DPossible(pObj, bAny3D, bGroupSelected);
}
}
bRetval = !bAny3D
&& (
IsConvertToPolyObjPossible(sal_False)
|| IsConvertToPathObjPossible(sal_False)
|| IsImportMtfPossible());
return bRetval;
}
void E3dView::ImpIsConvertTo3DPossible(SdrObject* pObj, sal_Bool& rAny3D,
sal_Bool& rGroupSelected) const
{
if(pObj)
{
if(pObj->ISA(E3dObject))
{
rAny3D = sal_True;
}
else
{
if(pObj->IsGroupObject())
{
SdrObjListIter aIter(*pObj, IM_DEEPNOGROUPS);
while(aIter.IsMore())
{
SdrObject* pNewObj = aIter.Next();
ImpIsConvertTo3DPossible(pNewObj, rAny3D, rGroupSelected);
}
rGroupSelected = sal_True;
}
}
}
}
/*************************************************************************
|*
|* 3D-Konvertierung zu Extrude ausfuehren
|*
\************************************************************************/
#include <editeng/eeitem.hxx>
void E3dView::ImpChangeSomeAttributesFor3DConversion(SdrObject* pObj)
{
if(pObj->ISA(SdrTextObj))
{
const SfxItemSet& rSet = pObj->GetMergedItemSet();
const SvxColorItem& rTextColorItem = (const SvxColorItem&)rSet.Get(EE_CHAR_COLOR);
if(rTextColorItem.GetValue() == RGB_Color(COL_BLACK))
{
// Bei schwarzen Textobjekten wird die Farbe auf grau gesetzt
if(pObj->GetPage())
{
// #84864# if black is only default attribute from
// pattern set it hard so that it is used in undo.
pObj->SetMergedItem(SvxColorItem(RGB_Color(COL_BLACK), EE_CHAR_COLOR));
// add undo now
if( GetModel()->IsUndoEnabled() )
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj, false, false));
}
pObj->SetMergedItem(SvxColorItem(RGB_Color(COL_GRAY), EE_CHAR_COLOR));
}
}
}
void E3dView::ImpChangeSomeAttributesFor3DConversion2(SdrObject* pObj)
{
if(pObj->ISA(SdrPathObj))
{
const SfxItemSet& rSet = pObj->GetMergedItemSet();
sal_Int32 nLineWidth = ((const XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue();
XLineStyle eLineStyle = (XLineStyle)((const XLineStyleItem&)rSet.Get(XATTR_LINESTYLE)).GetValue();
XFillStyle eFillStyle = ITEMVALUE(rSet, XATTR_FILLSTYLE, XFillStyleItem);
if(((SdrPathObj*)pObj)->IsClosed()
&& eLineStyle == XLINE_SOLID
&& !nLineWidth
&& eFillStyle != XFILL_NONE)
{
if(pObj->GetPage() && GetModel()->IsUndoEnabled() )
AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj, false, false));
pObj->SetMergedItem(XLineStyleItem(XLINE_NONE));
pObj->SetMergedItem(XLineWidthItem(0L));
}
}
}
void E3dView::ImpCreateSingle3DObjectFlat(E3dScene* pScene, SdrObject* pObj, sal_Bool bExtrude, double fDepth, basegfx::B2DHomMatrix& rLatheMat)
{
// Einzelnes PathObject, dieses umwanden
SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj);
if(pPath)
{
E3dDefaultAttributes aDefault = Get3DDefaultAttributes();
if(bExtrude)
aDefault.SetDefaultExtrudeCharacterMode(sal_True);
else
aDefault.SetDefaultLatheCharacterMode(sal_True);
// ItemSet des Ursprungsobjektes holen
SfxItemSet aSet(pObj->GetMergedItemSet());
XFillStyle eFillStyle = ITEMVALUE(aSet, XATTR_FILLSTYLE, XFillStyleItem);
// Linienstil ausschalten
aSet.Put(XLineStyleItem(XLINE_NONE));
// Feststellen, ob ein FILL_Attribut gesetzt ist.
if(!pPath->IsClosed() || eFillStyle == XFILL_NONE)
{
// Das SdrPathObj ist nicht gefuellt, lasse die
// vordere und hintere Flaeche weg. Ausserdem ist
// eine beidseitige Darstellung notwendig.
aDefault.SetDefaultExtrudeCloseFront(sal_False);
aDefault.SetDefaultExtrudeCloseBack(sal_False);
aSet.Put(Svx3DDoubleSidedItem(sal_True));
// Fuellattribut setzen
aSet.Put(XFillStyleItem(XFILL_SOLID));
// Fuellfarbe muss auf Linienfarbe, da das Objekt vorher
// nur eine Linie war
Color aColorLine = ((const XLineColorItem&)(aSet.Get(XATTR_LINECOLOR))).GetColorValue();
aSet.Put(XFillColorItem(String(), aColorLine));
}
// Neues Extrude-Objekt erzeugen
E3dObject* p3DObj = NULL;
if(bExtrude)
{
p3DObj = new E3dExtrudeObj(aDefault, pPath->GetPathPoly(), fDepth);
}
else
{
basegfx::B2DPolyPolygon aPolyPoly2D(pPath->GetPathPoly());
aPolyPoly2D.transform(rLatheMat);
p3DObj = new E3dLatheObj(aDefault, aPolyPoly2D);
}
// Attribute setzen
if(p3DObj)
{
p3DObj->NbcSetLayer(pObj->GetLayer());
p3DObj->SetMergedItemSet(aSet);
p3DObj->NbcSetStyleSheet(pObj->GetStyleSheet(), sal_True);
// Neues 3D-Objekt einfuegen
pScene->Insert3DObj(p3DObj);
}
}
}
void E3dView::ImpCreate3DObject(E3dScene* pScene, SdrObject* pObj, sal_Bool bExtrude, double fDepth, basegfx::B2DHomMatrix& rLatheMat)
{
if(pObj)
{
// change text color attribute for not so dark colors
if(pObj->IsGroupObject())
{
SdrObjListIter aIter(*pObj, IM_DEEPWITHGROUPS);
while(aIter.IsMore())
{
SdrObject* pGroupMember = aIter.Next();
ImpChangeSomeAttributesFor3DConversion(pGroupMember);
}
}
else
ImpChangeSomeAttributesFor3DConversion(pObj);
// convert completely to path objects
SdrObject* pNewObj1 = pObj->ConvertToPolyObj(sal_False, sal_False);
if(pNewObj1)
{
// change text color attribute for not so dark colors
if(pNewObj1->IsGroupObject())
{
SdrObjListIter aIter(*pNewObj1, IM_DEEPWITHGROUPS);
while(aIter.IsMore())
{
SdrObject* pGroupMember = aIter.Next();
ImpChangeSomeAttributesFor3DConversion2(pGroupMember);
}
}
else
ImpChangeSomeAttributesFor3DConversion2(pNewObj1);
// convert completely to path objects
SdrObject* pNewObj2 = pObj->ConvertToContourObj(pNewObj1, sal_True);
if(pNewObj2)
{
// add all to flat scene
if(pNewObj2->IsGroupObject())
{
SdrObjListIter aIter(*pNewObj2, IM_DEEPWITHGROUPS);
while(aIter.IsMore())
{
SdrObject* pGroupMember = aIter.Next();
ImpCreateSingle3DObjectFlat(pScene, pGroupMember, bExtrude, fDepth, rLatheMat);
}
}
else
ImpCreateSingle3DObjectFlat(pScene, pNewObj2, bExtrude, fDepth, rLatheMat);
// delete zwi object
if(pNewObj2 != pObj && pNewObj2 != pNewObj1 && pNewObj2)
SdrObject::Free( pNewObj2 );
}
// delete zwi object
if(pNewObj1 != pObj && pNewObj1)
SdrObject::Free( pNewObj1 );
}
}
}
/*************************************************************************
|*
|* 3D-Konvertierung zu Extrude steuern
|*
\************************************************************************/
void E3dView::ConvertMarkedObjTo3D(sal_Bool bExtrude, basegfx::B2DPoint aPnt1, basegfx::B2DPoint aPnt2)
{
if(AreObjectsMarked())
{
// Undo anlegen
if(bExtrude)
BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_EXTRUDE));
else
BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_LATHE));
// Neue Szene fuer zu erzeugende 3D-Objekte anlegen
E3dScene* pScene = new E3dPolyScene(Get3DDefaultAttributes());
// Rechteck bestimmen und evtl. korrigieren
Rectangle aRect = GetAllMarkedRect();
if(aRect.GetWidth() <= 1)
aRect.SetSize(Size(500, aRect.GetHeight()));
if(aRect.GetHeight() <= 1)
aRect.SetSize(Size(aRect.GetWidth(), 500));
// Tiefe relativ zur Groesse der Selektion bestimmen
double fDepth = 0.0;
double fRot3D = 0.0;
basegfx::B2DHomMatrix aLatheMat;
if(bExtrude)
{
double fW = (double)aRect.GetWidth();
double fH = (double)aRect.GetHeight();
fDepth = sqrt(fW*fW + fH*fH) / 6.0;
}
if(!bExtrude)
{
// Transformation fuer Polygone Rotationskoerper erstellen
if(aPnt1 != aPnt2)
{
// Rotation um Kontrollpunkt1 mit eigestelltem Winkel
// fuer 3D Koordinaten
basegfx::B2DPoint aDiff(aPnt1 - aPnt2);
fRot3D = atan2(aDiff.getY(), aDiff.getX()) - F_PI2;
if(basegfx::fTools::equalZero(fabs(fRot3D)))
fRot3D = 0.0;
if(fRot3D != 0.0)
{
aLatheMat = basegfx::tools::createRotateAroundPoint(aPnt2, -fRot3D)
* aLatheMat;
}
}
if(aPnt2.getX() != 0.0)
{
// Translation auf Y=0 - Achse
aLatheMat.translate(-aPnt2.getX(), 0.0);
}
else
{
aLatheMat.translate((double)-aRect.Left(), 0.0);
}
// Inverse Matrix bilden, um die Zielausdehnung zu bestimmen
basegfx::B2DHomMatrix aInvLatheMat(aLatheMat);
aInvLatheMat.invert();
// SnapRect Ausdehnung mittels Spiegelung an der Rotationsachse
// erweitern
for(sal_uInt32 a=0;a<GetMarkedObjectCount();a++)
{
SdrMark* pMark = GetSdrMarkByIndex(a);
SdrObject* pObj = pMark->GetMarkedSdrObj();
Rectangle aTurnRect = pObj->GetSnapRect();
basegfx::B2DPoint aRot;
Point aRotPnt;
aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Top());
aRot *= aLatheMat;
aRot.setX(-aRot.getX());
aRot *= aInvLatheMat;
aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
aRect.Union(Rectangle(aRotPnt, aRotPnt));
aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Bottom());
aRot *= aLatheMat;
aRot.setX(-aRot.getX());
aRot *= aInvLatheMat;
aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
aRect.Union(Rectangle(aRotPnt, aRotPnt));
aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Top());
aRot *= aLatheMat;
aRot.setX(-aRot.getX());
aRot *= aInvLatheMat;
aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
aRect.Union(Rectangle(aRotPnt, aRotPnt));
aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Bottom());
aRot *= aLatheMat;
aRot.setX(-aRot.getX());
aRot *= aInvLatheMat;
aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
aRect.Union(Rectangle(aRotPnt, aRotPnt));
}
}
// Ueber die Selektion gehen und in 3D wandeln, komplett mit
// Umwandeln in SdrPathObject, auch Schriften
for(sal_uInt32 a=0;a<GetMarkedObjectCount();a++)
{
SdrMark* pMark = GetSdrMarkByIndex(a);
SdrObject* pObj = pMark->GetMarkedSdrObj();
ImpCreate3DObject(pScene, pObj, bExtrude, fDepth, aLatheMat);
}
if(pScene->GetSubList() && pScene->GetSubList()->GetObjCount() != 0)
{
// Alle angelegten Objekte Tiefenarrangieren
if(bExtrude)
DoDepthArrange(pScene, fDepth);
// 3D-Objekte auf die Mitte des Gesamtrechtecks zentrieren
basegfx::B3DPoint aCenter(pScene->GetBoundVolume().getCenter());
basegfx::B3DHomMatrix aMatrix;
aMatrix.translate(-aCenter.getX(), -aCenter.getY(), -aCenter.getZ());
pScene->SetTransform(aMatrix * pScene->GetTransform()); // #112587#
// Szene initialisieren
pScene->NbcSetSnapRect(aRect);
basegfx::B3DRange aBoundVol = pScene->GetBoundVolume();
InitScene(pScene, (double)aRect.GetWidth(), (double)aRect.GetHeight(), aBoundVol.getDepth());
// Szene anstelle des ersten selektierten Objektes einfuegen
// und alle alten Objekte weghauen
SdrObject* pRepObj = GetMarkedObjectByIndex(0);
SdrPageView* pPV = GetSdrPageViewOfMarkedByIndex(0);
MarkObj(pRepObj, pPV, sal_True);
ReplaceObjectAtView(pRepObj, *pPV, pScene, sal_False);
DeleteMarked();
MarkObj(pScene, pPV);
// Rotationskoerper um Rotationsachse drehen
basegfx::B3DHomMatrix aRotate;
if(!bExtrude && fRot3D != 0.0)
{
aRotate.rotate(0.0, 0.0, fRot3D);
}
// Default-Rotation setzen
{
double XRotateDefault = 20;
aRotate.rotate(DEG2RAD(XRotateDefault), 0.0, 0.0);
}
if(!aRotate.isIdentity())
{
pScene->SetTransform(aRotate * pScene->GetTransform());
}
// SnapRects der Objekte ungueltig
pScene->SetSnapRect(aRect);
}
else
{
// Es wurden keine 3D Objekte erzeugt, schmeiss alles weg
delete pScene;
}
// Undo abschliessen
EndUndo();
}
}
/*************************************************************************
|*
|* Alle enthaltenen Extrude-Objekte Tiefenarrangieren
|*
\************************************************************************/
struct E3dDepthNeighbour
{
E3dDepthNeighbour* mpNext;
E3dExtrudeObj* mpObj;
basegfx::B2DPolyPolygon maPreparedPolyPolygon;
E3dDepthNeighbour()
: mpNext(0),
mpObj(0),
maPreparedPolyPolygon()
{
}
};
struct E3dDepthLayer
{
E3dDepthLayer* mpDown;
E3dDepthNeighbour* mpNext;
E3dDepthLayer()
: mpDown(0),
mpNext(0)
{
}
~E3dDepthLayer()
{
while(mpNext)
{
E3dDepthNeighbour* pSucc = mpNext->mpNext;
delete mpNext;
mpNext = pSucc;
}
}
};
void E3dView::DoDepthArrange(E3dScene* pScene, double fDepth)
{
if(pScene && pScene->GetSubList() && pScene->GetSubList()->GetObjCount() > 1)
{
SdrObjList* pSubList = pScene->GetSubList();
SdrObjListIter aIter(*pSubList, IM_FLAT);
E3dDepthLayer* pBaseLayer = NULL;
E3dDepthLayer* pLayer = NULL;
sal_Int32 nNumLayers = 0;
while(aIter.IsMore())
{
E3dExtrudeObj* pExtrudeObj = dynamic_cast< E3dExtrudeObj* >(aIter.Next());
if(pExtrudeObj)
{
const basegfx::B2DPolyPolygon aExtrudePoly(
basegfx::tools::prepareForPolygonOperation(pExtrudeObj->GetExtrudePolygon()));
const SfxItemSet& rLocalSet = pExtrudeObj->GetMergedItemSet();
const XFillStyle eLocalFillStyle = ITEMVALUE(rLocalSet, XATTR_FILLSTYLE, XFillStyleItem);
const Color aLocalColor = ((const XFillColorItem&)(rLocalSet.Get(XATTR_FILLCOLOR))).GetColorValue();
// sort in ExtrudeObj
if(pLayer)
{
// do we have overlap with an object of this layer?
bool bOverlap(false);
E3dDepthNeighbour* pAct = pLayer->mpNext;
while(!bOverlap && pAct)
{
// do pAct->mpObj and pExtrudeObj overlap? Check by
// using logical AND clipping
const basegfx::B2DPolyPolygon aAndPolyPolygon(
basegfx::tools::solvePolygonOperationAnd(
aExtrudePoly,
pAct->maPreparedPolyPolygon));
bOverlap = (0 != aAndPolyPolygon.count());
if(bOverlap)
{
// second ciriteria: is another fillstyle or color used?
const SfxItemSet& rCompareSet = pAct->mpObj->GetMergedItemSet();
XFillStyle eCompareFillStyle = ITEMVALUE(rCompareSet, XATTR_FILLSTYLE, XFillStyleItem);
if(eLocalFillStyle == eCompareFillStyle)
{
if(eLocalFillStyle == XFILL_SOLID)
{
Color aCompareColor = ((const XFillColorItem&)(rCompareSet.Get(XATTR_FILLCOLOR))).GetColorValue();
if(aCompareColor == aLocalColor)
{
bOverlap = sal_False;
}
}
else if(eLocalFillStyle == XFILL_NONE)
{
bOverlap = sal_False;
}
}
}
pAct = pAct->mpNext;
}
if(bOverlap)
{
// yes, start a new layer
pLayer->mpDown = new E3dDepthLayer;
pLayer = pLayer->mpDown;
nNumLayers++;
pLayer->mpNext = new E3dDepthNeighbour;
pLayer->mpNext->mpObj = pExtrudeObj;
pLayer->mpNext->maPreparedPolyPolygon = aExtrudePoly;
}
else
{
// no, add to current layer
E3dDepthNeighbour* pNewNext = new E3dDepthNeighbour;
pNewNext->mpObj = pExtrudeObj;
pNewNext->maPreparedPolyPolygon = aExtrudePoly;
pNewNext->mpNext = pLayer->mpNext;
pLayer->mpNext = pNewNext;
}
}
else
{
// first layer ever
pBaseLayer = new E3dDepthLayer;
pLayer = pBaseLayer;
nNumLayers++;
pLayer->mpNext = new E3dDepthNeighbour;
pLayer->mpNext->mpObj = pExtrudeObj;
pLayer->mpNext->maPreparedPolyPolygon = aExtrudePoly;
}
}
}
// number of layers is done
if(nNumLayers > 1)
{
// need to be arranged
double fMinDepth = fDepth * 0.8;
double fStep = (fDepth - fMinDepth) / (double)nNumLayers;
pLayer = pBaseLayer;
while(pLayer)
{
// move along layer
E3dDepthNeighbour* pAct = pLayer->mpNext;
while(pAct)
{
// adapt extrude value
pAct->mpObj->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH, sal_uInt32(fMinDepth + 0.5)));
// next
pAct = pAct->mpNext;
}
// next layer
pLayer = pLayer->mpDown;
fMinDepth += fStep;
}
}
// cleanup
while(pBaseLayer)
{
pLayer = pBaseLayer->mpDown;
delete pBaseLayer;
pBaseLayer = pLayer;
}
}
}
/*************************************************************************
|*
|* Drag beginnen, vorher ggf. Drag-Methode fuer 3D-Objekte erzeugen
|*
\************************************************************************/
sal_Bool E3dView::BegDragObj(const Point& rPnt, OutputDevice* pOut,
SdrHdl* pHdl, short nMinMov,
SdrDragMethod* pForcedMeth)
{
if(Is3DRotationCreationActive() && GetMarkedObjectCount())
{
// bestimme alle selektierten Polygone und gebe die gespiegelte Hilfsfigur aus
mpMirrorOverlay->SetMirrorAxis(aRef1, aRef2);
}
else
{
sal_Bool bOwnActionNecessary;
if (pHdl == NULL)
{
bOwnActionNecessary = sal_True;
}
else if (pHdl->IsVertexHdl() || pHdl->IsCornerHdl())
{
bOwnActionNecessary = sal_True;
}
else
{
bOwnActionNecessary = sal_False;
}
if(bOwnActionNecessary && GetMarkedObjectCount() >= 1)
{
E3dDragConstraint eConstraint = E3DDRAG_CONSTR_XYZ;
sal_Bool bThereAreRootScenes = sal_False;
sal_Bool bThereAre3DObjects = sal_False;
long nCnt = GetMarkedObjectCount();
for(long nObjs = 0;nObjs < nCnt;nObjs++)
{
SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
if(pObj)
{
if(pObj->ISA(E3dScene) && ((E3dScene*)pObj)->GetScene() == pObj)
bThereAreRootScenes = sal_True;
if(pObj->ISA(E3dObject))
bThereAre3DObjects = sal_True;
}
}
if( bThereAre3DObjects )
{
eDragHdl = ( pHdl == NULL ? HDL_MOVE : pHdl->GetKind() );
switch ( eDragMode )
{
case SDRDRAG_ROTATE:
case SDRDRAG_SHEAR:
{
switch ( eDragHdl )
{
case HDL_LEFT:
case HDL_RIGHT:
{
eConstraint = E3DDRAG_CONSTR_X;
}
break;
case HDL_UPPER:
case HDL_LOWER:
{
eConstraint = E3DDRAG_CONSTR_Y;
}
break;
case HDL_UPLFT:
case HDL_UPRGT:
case HDL_LWLFT:
case HDL_LWRGT:
{
eConstraint = E3DDRAG_CONSTR_Z;
}
break;
default: break;
}
// die nicht erlaubten Rotationen ausmaskieren
eConstraint = E3dDragConstraint(eConstraint& eDragConstraint);
pForcedMeth = new E3dDragRotate(*this, GetMarkedObjectList(), eConstraint, IsSolidDragging());
}
break;
case SDRDRAG_MOVE:
{
if(!bThereAreRootScenes)
{
pForcedMeth = new E3dDragMove(*this, GetMarkedObjectList(), eDragHdl, eConstraint, IsSolidDragging());
}
}
break;
// spaeter mal
case SDRDRAG_MIRROR:
case SDRDRAG_CROOK:
case SDRDRAG_DISTORT:
case SDRDRAG_TRANSPARENCE:
case SDRDRAG_GRADIENT:
default:
{
}
break;
}
}
}
}
return SdrView::BegDragObj(rPnt, pOut, pHdl, nMinMov, pForcedMeth);
}
/*************************************************************************
|*
|* Pruefen, obj 3D-Szene markiert ist
|*
\************************************************************************/
sal_Bool E3dView::HasMarkedScene()
{
return (GetMarkedScene() != NULL);
}
/*************************************************************************
|*
|* Pruefen, obj 3D-Szene markiert ist
|*
\************************************************************************/
E3dScene* E3dView::GetMarkedScene()
{
sal_uIntPtr nCnt = GetMarkedObjectCount();
for ( sal_uIntPtr i = 0; i < nCnt; i++ )
if ( GetMarkedObjectByIndex(i)->ISA(E3dScene) )
return (E3dScene*) GetMarkedObjectByIndex(i);
return NULL;
}
/*************************************************************************
|*
|* aktuelles 3D-Zeichenobjekt setzen, dafuer Szene erzeugen
|*
\************************************************************************/
E3dScene* E3dView::SetCurrent3DObj(E3dObject* p3DObj)
{
DBG_ASSERT(p3DObj != NULL, "Nana, wer steckt denn hier 'nen NULL-Zeiger rein?");
E3dScene* pScene = NULL;
// get transformed BoundVolume of the object
basegfx::B3DRange aVolume(p3DObj->GetBoundVolume());
aVolume.transform(p3DObj->GetTransform());
double fW(aVolume.getWidth());
double fH(aVolume.getHeight());
Rectangle aRect(0,0, (long) fW, (long) fH);
pScene = new E3dPolyScene(Get3DDefaultAttributes());
InitScene(pScene, fW, fH, aVolume.getMaxZ() + ((fW + fH) / 4.0));
pScene->Insert3DObj(p3DObj);
pScene->NbcSetSnapRect(aRect);
return pScene;
}
/*************************************************************************
|*
|* neu erzeugte Szene initialisieren
|*
\************************************************************************/
void E3dView::InitScene(E3dScene* pScene, double fW, double fH, double fCamZ)
{
Camera3D aCam(pScene->GetCamera());
aCam.SetAutoAdjustProjection(sal_False);
aCam.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
basegfx::B3DPoint aLookAt;
double fDefaultCamPosZ = GetDefaultCamPosZ();
basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
aCam.SetPosAndLookAt(aCamPos, aLookAt);
aCam.SetFocalLength(GetDefaultCamFocal());
aCam.SetDefaults(basegfx::B3DPoint(0.0, 0.0, fDefaultCamPosZ), aLookAt, GetDefaultCamFocal());
pScene->SetCamera(aCam);
}
/*************************************************************************
|*
|* startsequenz fuer die erstellung eines 3D-Rotationskoerpers
|*
\************************************************************************/
void E3dView::Start3DCreation()
{
if (GetMarkedObjectCount())
{
// irgendwelche Markierungen ermitteln und ausschalten
//HMHBOOL bVis = IsMarkHdlShown();
//HMHif (bVis) HideMarkHdl();
// bestimme die koordinaten fuer JOEs Mirrorachse
// entgegen der normalen Achse wird diese an die linke Seite des Objektes
// positioniert
long nOutMin = 0;
long nOutMax = 0;
long nMinLen = 0;
long nObjDst = 0;
long nOutHgt = 0;
OutputDevice* pOut = GetFirstOutputDevice(); //GetWin(0);
// erstmal Darstellungsgrenzen bestimmen
if (pOut != NULL)
{
nMinLen = pOut->PixelToLogic(Size(0,50)).Height();
nObjDst = pOut->PixelToLogic(Size(0,20)).Height();
long nDst = pOut->PixelToLogic(Size(0,10)).Height();
nOutMin = -pOut->GetMapMode().GetOrigin().Y();
nOutMax = pOut->GetOutputSize().Height() - 1 + nOutMin;
nOutMin += nDst;
nOutMax -= nDst;
if (nOutMax - nOutMin < nDst)
{
nOutMin += nOutMax + 1;
nOutMin /= 2;
nOutMin -= (nDst + 1) / 2;
nOutMax = nOutMin + nDst;
}
nOutHgt = nOutMax - nOutMin;
long nTemp = nOutHgt / 4;
if (nTemp > nMinLen) nMinLen = nTemp;
}
// und dann die Markierungen oben und unten an das Objekt heften
basegfx::B2DRange aR;
for(sal_uInt32 nMark(0L); nMark < GetMarkedObjectCount(); nMark++)
{
SdrObject* pMark = GetMarkedObjectByIndex(nMark);
basegfx::B2DPolyPolygon aXPP(pMark->TakeXorPoly());
aR.expand(basegfx::tools::getRange(aXPP));
}
basegfx::B2DPoint aCenter(aR.getCenter());
long nMarkHgt = basegfx::fround(aR.getHeight()) - 1;
long nHgt = nMarkHgt + nObjDst * 2;
if (nHgt < nMinLen) nHgt = nMinLen;
long nY1 = basegfx::fround(aCenter.getY()) - (nHgt + 1) / 2;
long nY2 = nY1 + nHgt;
if (pOut && (nMinLen > nOutHgt)) nMinLen = nOutHgt;
if (pOut)
{
if (nY1 < nOutMin)
{
nY1 = nOutMin;
if (nY2 < nY1 + nMinLen) nY2 = nY1 + nMinLen;
}
if (nY2 > nOutMax)
{
nY2 = nOutMax;
if (nY1 > nY2 - nMinLen) nY1 = nY2 - nMinLen;
}
}
aRef1.X() = basegfx::fround(aR.getMinX()); // Initial Achse um 2/100mm nach links
aRef1.Y() = nY1;
aRef2.X() = aRef1.X();
aRef2.Y() = nY2;
// Markierungen einschalten
SetMarkHandles();
//HMHif (bVis) ShowMarkHdl();
if (AreObjectsMarked()) MarkListHasChanged();
// SpiegelPolygone SOFORT zeigen
const SdrHdlList &aHdlList = GetHdlList();
mpMirrorOverlay = new Impl3DMirrorConstructOverlay(*this);
mpMirrorOverlay->SetMirrorAxis(aHdlList.GetHdl(HDL_REF1)->GetPos(), aHdlList.GetHdl(HDL_REF2)->GetPos());
//CreateMirrorPolygons ();
//ShowMirrorPolygons (aHdlList.GetHdl (HDL_REF1)->GetPos (),
// aHdlList.GetHdl (HDL_REF2)->GetPos ());
}
}
/*************************************************************************
|*
|* was passiert bei einer Mausbewegung, wenn das Objekt erstellt wird ?
|*
\************************************************************************/
void E3dView::MovAction(const Point& rPnt)
{
if(Is3DRotationCreationActive())
{
SdrHdl* pHdl = GetDragHdl();
if (pHdl)
{
SdrHdlKind eHdlKind = pHdl->GetKind();
// reagiere nur bei einer spiegelachse
if ((eHdlKind == HDL_REF1) ||
(eHdlKind == HDL_REF2) ||
(eHdlKind == HDL_MIRX))
{
const SdrHdlList &aHdlList = GetHdlList ();
// loesche das gespiegelte Polygon, spiegele das Original und zeichne es neu
//ShowMirrored ();
SdrView::MovAction (rPnt);
mpMirrorOverlay->SetMirrorAxis(
aHdlList.GetHdl (HDL_REF1)->GetPos(),
aHdlList.GetHdl (HDL_REF2)->GetPos());
}
}
else
{
SdrView::MovAction (rPnt);
}
}
else
{
SdrView::MovAction (rPnt);
}
}
/*************************************************************************
|*
|* Schluss. Objekt und evtl. Unterobjekte ueber ImpCreate3DLathe erstellen
|* [FG] Mit dem Parameterwert sal_True (SDefault: sal_False) wird einfach ein
|* Rotationskoerper erzeugt, ohne den Benutzer die Lage der
|* Achse fetlegen zu lassen. Es reicht dieser Aufruf, falls
|* ein Objekt selektiert ist. (keine Initialisierung noetig)
|*
\************************************************************************/
void E3dView::End3DCreation(sal_Bool bUseDefaultValuesForMirrorAxes)
{
ResetCreationActive();
if(AreObjectsMarked())
{
if(bUseDefaultValuesForMirrorAxes)
{
Rectangle aRect = GetAllMarkedRect();
if(aRect.GetWidth() <= 1)
aRect.SetSize(Size(500, aRect.GetHeight()));
if(aRect.GetHeight() <= 1)
aRect.SetSize(Size(aRect.GetWidth(), 500));
basegfx::B2DPoint aPnt1(aRect.Left(), -aRect.Top());
basegfx::B2DPoint aPnt2(aRect.Left(), -aRect.Bottom());
ConvertMarkedObjTo3D(sal_False, aPnt1, aPnt2);
}
else
{
// Hilfsfigur ausschalten
// bestimme aus den Handlepositionen und den Versatz der Punkte
const SdrHdlList &aHdlList = GetHdlList();
Point aMirrorRef1 = aHdlList.GetHdl(HDL_REF1)->GetPos();
Point aMirrorRef2 = aHdlList.GetHdl(HDL_REF2)->GetPos();
basegfx::B2DPoint aPnt1(aMirrorRef1.X(), -aMirrorRef1.Y());
basegfx::B2DPoint aPnt2(aMirrorRef2.X(), -aMirrorRef2.Y());
ConvertMarkedObjTo3D(sal_False, aPnt1, aPnt2);
}
}
}
/*************************************************************************
|*
|* Destruktor
|*
\************************************************************************/
E3dView::~E3dView ()
{
}
/*************************************************************************
|*
|* beende das erzeugen und loesche die polygone
|*
\************************************************************************/
void E3dView::ResetCreationActive ()
{
if(mpMirrorOverlay)
{
delete mpMirrorOverlay;
mpMirrorOverlay = 0L;
}
}
/*************************************************************************
|*
|* Klasse initialisieren
|*
\************************************************************************/
void E3dView::InitView ()
{
eDragConstraint = E3DDRAG_CONSTR_XYZ;
fDefaultScaleX =
fDefaultScaleY =
fDefaultScaleZ = 1.0;
fDefaultRotateX =
fDefaultRotateY =
fDefaultRotateZ = 0.0;
fDefaultExtrusionDeepth = 1000; // old: 2000;
fDefaultLightIntensity = 0.8; // old: 0.6;
fDefaultAmbientIntensity = 0.4;
nHDefaultSegments = 12;
nVDefaultSegments = 12;
aDefaultLightColor = RGB_Color(COL_WHITE);
aDefaultAmbientColor = RGB_Color(COL_BLACK);
bDoubleSided = sal_False;
mpMirrorOverlay = 0L;
}
/*************************************************************************
|*
|* Koennen die selektierten Objekte aufgebrochen werden?
|*
\************************************************************************/
sal_Bool E3dView::IsBreak3DObjPossible() const
{
sal_uIntPtr nCount = GetMarkedObjectCount();
if (nCount > 0)
{
sal_uIntPtr i = 0;
while (i < nCount)
{
SdrObject* pObj = GetMarkedObjectByIndex(i);
if (pObj && pObj->ISA(E3dObject))
{
if(!(((E3dObject*)pObj)->IsBreakObjPossible()))
return sal_False;
}
else
{
return sal_False;
}
i++;
}
}
else
{
return sal_False;
}
return sal_True;
}
/*************************************************************************
|*
|* Selektierte Lathe-Objekte aufbrechen
|*
\************************************************************************/
void E3dView::Break3DObj()
{
if(IsBreak3DObjPossible())
{
// ALLE selektierten Objekte werden gewandelt
sal_uInt32 nCount = GetMarkedObjectCount();
BegUndo(String(SVX_RESSTR(RID_SVX_3D_UNDO_BREAK_LATHE)));
for(sal_uInt32 a=0;a<nCount;a++)
{
E3dObject* pObj = (E3dObject*)GetMarkedObjectByIndex(a);
BreakSingle3DObj(pObj);
}
DeleteMarked();
EndUndo();
}
}
void E3dView::BreakSingle3DObj(E3dObject* pObj)
{
if(pObj->ISA(E3dScene))
{
SdrObjList* pSubList = pObj->GetSubList();
SdrObjListIter aIter(*pSubList, IM_FLAT);
while(aIter.IsMore())
{
E3dObject* pSubObj = (E3dObject*)aIter.Next();
BreakSingle3DObj(pSubObj);
}
}
else
{
SdrAttrObj* pNewObj = pObj->GetBreakObj();
if(pNewObj)
{
InsertObjectAtView(pNewObj, *GetSdrPageView(), SDRINSERT_DONTMARK);
pNewObj->SetChanged();
pNewObj->BroadcastObjectChange();
}
}
}
/*************************************************************************
|*
|* Szenen mischen
|*
\************************************************************************/
void E3dView::MergeScenes ()
{
sal_uIntPtr nCount = GetMarkedObjectCount();
if (nCount > 0)
{
sal_uIntPtr nObj = 0;
SdrObject *pObj = GetMarkedObjectByIndex(nObj);
E3dScene *pScene = new E3dPolyScene(Get3DDefaultAttributes());
basegfx::B3DRange aBoundVol;
Rectangle aAllBoundRect (GetMarkedObjBoundRect ());
Point aCenter (aAllBoundRect.Center());
while (pObj)
{
if (pObj->ISA(E3dScene))
{
/**********************************************************
* Es ist eine 3D-Scene oder 3D-PolyScene
**********************************************************/
SdrObjList* pSubList = ((E3dObject*) pObj)->GetSubList();
SdrObjListIter aIter(*pSubList, IM_FLAT);
while (aIter.IsMore())
{
/******************************************************
* LatheObjekte suchen
******************************************************/
SdrObject* pSubObj = aIter.Next();
E3dObject *pNewObj = 0;
switch (pSubObj->GetObjIdentifier())
{
case E3D_CUBEOBJ_ID :
pNewObj = new E3dCubeObj;
*(E3dCubeObj*)pNewObj = *(E3dCubeObj*)pSubObj;
break;
case E3D_SPHEREOBJ_ID:
pNewObj = new E3dSphereObj;
*(E3dSphereObj*)pNewObj = *(E3dSphereObj*)pSubObj;
break;
case E3D_EXTRUDEOBJ_ID:
pNewObj = new E3dExtrudeObj;
*(E3dExtrudeObj*)pNewObj = *(E3dExtrudeObj*)pSubObj;
break;
case E3D_LATHEOBJ_ID:
pNewObj = new E3dLatheObj;
*(E3dLatheObj*)pNewObj = *(E3dLatheObj*)pSubObj;
break;
case E3D_COMPOUNDOBJ_ID:
pNewObj = new E3dCompoundObject;
*(E3dCompoundObject*)pNewObj = *(E3dCompoundObject*)pSubObj;
break;
}
Rectangle aBoundRect = pSubObj->GetCurrentBoundRect();
basegfx::B3DHomMatrix aMatrix;
aMatrix.translate(aBoundRect.Left() - aCenter.getX(), aCenter.getY(), 0.0);
pNewObj->SetTransform(aMatrix * pNewObj->GetTransform()); // #112587#
if (pNewObj) aBoundVol.expand(pNewObj->GetBoundVolume());
pScene->Insert3DObj (pNewObj);
}
}
nObj++;
if (nObj < nCount)
{
pObj = GetMarkedObjectByIndex(nObj);
}
else
{
pObj = NULL;
}
}
double fW = aAllBoundRect.GetWidth();
double fH = aAllBoundRect.GetHeight();
Rectangle aRect(0,0, (long) fW, (long) fH);
InitScene(pScene, fW, fH, aBoundVol.getMaxZ() + + ((fW + fH) / 4.0));
pScene->NbcSetSnapRect(aRect);
Camera3D &aCamera = (Camera3D&) pScene->GetCamera ();
basegfx::B3DPoint aMinVec(aBoundVol.getMinimum());
basegfx::B3DPoint aMaxVec(aBoundVol.getMaximum());
double fDeepth(fabs(aMaxVec.getZ() - aMinVec.getZ()));
aCamera.SetPRP(basegfx::B3DPoint(0.0, 0.0, 1000.0));
double fDefaultCamPosZ(GetDefaultCamPosZ());
aCamera.SetPosition(basegfx::B3DPoint(0.0, 0.0, fDefaultCamPosZ + fDeepth / 2.0));
aCamera.SetFocalLength(GetDefaultCamFocal());
pScene->SetCamera (aCamera);
// SnapRects der Objekte ungueltig
pScene->SetRectsDirty();
InsertObjectAtView(pScene, *(GetSdrPageViewOfMarkedByIndex(0)));
// SnapRects der Objekte ungueltig
pScene->SetRectsDirty();
}
}
/*************************************************************************
|*
|* Possibilities, hauptsaechlich gruppieren/ungruppieren
|*
\************************************************************************/
void E3dView::CheckPossibilities()
{
// call parent
SdrView::CheckPossibilities();
// Weitere Flags bewerten
if(bGroupPossible || bUnGroupPossible || bGrpEnterPossible)
{
sal_Int32 nMarkCnt = GetMarkedObjectCount();
sal_Bool bCoumpound = sal_False;
sal_Bool b3DObject = sal_False;
for(sal_Int32 nObjs = 0L; (nObjs < nMarkCnt) && !bCoumpound; nObjs++)
{
SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
if(pObj && pObj->ISA(E3dCompoundObject))
bCoumpound = sal_True;
if(pObj && pObj->ISA(E3dObject))
b3DObject = sal_True;
}
// Bisher: Es sind ZWEI oder mehr beliebiger Objekte selektiert.
// Nachsehen, ob CompoundObjects beteiligt sind. Falls ja,
// das Gruppieren verbieten.
if(bGroupPossible && bCoumpound)
bGroupPossible = sal_False;
if(bUnGroupPossible && b3DObject)
bUnGroupPossible = sal_False;
if(bGrpEnterPossible && bCoumpound)
bGrpEnterPossible = sal_False;
}
}
// eof