/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#define ITEMID_COLOR            SID_ATTR_3D_LIGHTCOLOR

#include "svdstr.hrc"
#include "svdview.hxx"
#include "globl3d.hxx"
#include "polyob3d.hxx"
#include "polysc3d.hxx"
#include "xoutx.hxx"
#include "xlnwtit.hxx"
#include "svdio.hxx"
#include "svxids.hrc"
#include "eeitem.hxx"

namespace binfilter {

#define ITEMVALUE(ItemSet,Id,Cast)  ((const Cast&)(ItemSet).Get(Id)).GetValue()

/*************************************************************************
|*
|* Liste fuer 3D-Objekte
|*
\************************************************************************/

/*N*/ TYPEINIT1(E3dObjList, SdrObjList);

/*N*/ E3dObjList::E3dObjList(SdrModel* pNewModel, SdrPage* pNewPage, E3dObjList* pNewUpList)
/*N*/ : SdrObjList(pNewModel, pNewPage, pNewUpList)
/*N*/ {
/*N*/ }

/*?*/ E3dObjList::E3dObjList(const E3dObjList& rSrcList)
/*?*/ : SdrObjList(rSrcList)
/*?*/ {
/*?*/ }

/*N*/ E3dObjList::~E3dObjList()
/*N*/ {
/*N*/ }

/*N*/ void E3dObjList::NbcInsertObject(SdrObject* pObj, ULONG nPos, const SdrInsertReason* pReason)
/*N*/ {
/*N*/   // Owner holen
/*N*/   DBG_ASSERT(GetOwnerObj()->ISA(E3dObject), "AW: Einfuegen 3DObject in Parent != 3DObject");
/*N*/
/*N*/   // Ist es ueberhaupt ein 3D-Objekt?
/*N*/   if(pObj && pObj->ISA(E3dObject))
/*N*/   {
/*N*/       // Normales 3D Objekt, einfuegen mittels
/*N*/       // call parent
/*N*/       SdrObjList::NbcInsertObject(pObj, nPos, pReason);
/*N*/   }
/*N*/   else
/*N*/   {
/*?*/       // Kein 3D Objekt, fuege in Seite statt in Szene ein...
/*?*/       GetOwnerObj()->GetPage()->InsertObject(pObj, nPos);
/*N*/   }
/*N*/ }


/*N*/ SdrObject* E3dObjList::RemoveObject(ULONG nObjNum)
/*N*/ {
/*N*/   // Owner holen
/*N*/   DBG_ASSERT(GetOwnerObj()->ISA(E3dObject), "AW: Entfernen 3DObject aus Parent != 3DObject");
/*N*/   /*E3dObject* pOwner =*/ (E3dObject*)GetOwnerObj();
/*N*/
/*N*/   // call parent
/*N*/   SdrObject* pRetval = SdrObjList::RemoveObject(nObjNum);
/*N*/
/*N*/   // FitSnapRectToBoundVol vorbereiten
/*N*/   if(GetOwnerObj() && GetOwnerObj()->ISA(E3dScene))
/*N*/       ((E3dScene*)GetOwnerObj())->CorrectSceneDimensions();
/*N*/
/*N*/   return pRetval;
/*N*/ }

/*************************************************************************
|*
|* Konstruktor
|*
\************************************************************************/

/*N*/ TYPEINIT1(E3dObject, SdrAttrObj);

/*N*/ E3dObject::E3dObject() :
/*N*/   nLogicalGroup(0),
/*N*/   nObjTreeLevel(0),
/*N*/   nPartOfParent(0),
/*N*/   eDragDetail(E3DDETAIL_ONEBOX),
/*N*/   bTfHasChanged(TRUE),
/*N*/   bBoundVolValid(TRUE),
/*N*/   bIsSelected(FALSE)
/*N*/ {
/*N*/   bIs3DObj = TRUE;
/*N*/   pSub = new E3dObjList(NULL, NULL);
/*N*/   pSub->SetOwnerObj(this);
/*N*/   pSub->SetListKind(SDROBJLIST_GROUPOBJ);
/*N*/   bClosedObj = TRUE;
/*N*/ }

/*************************************************************************
|*
|* Destruktor
|*
\************************************************************************/

/*N*/ E3dObject::~E3dObject()
/*N*/ {
/*N*/   delete pSub;
/*N*/   pSub = NULL;
/*N*/ }

/*************************************************************************
|*
|* SetRectsDirty muss ueber die lokale SdrSubList gehen
|*
\************************************************************************/

/*N*/ void E3dObject::SetRectsDirty(bool bNotMyself)
/*N*/ {
/*N*/   // call parent
/*N*/   SdrAttrObj::SetRectsDirty(bNotMyself);
/*N*/
/*N*/   // Eigene SubListe AUCH behandeln
/*N*/   if(pSub && pSub->GetObjCount())
/*N*/   {
/*N*/       for (ULONG i = 0; i < pSub->GetObjCount(); i++)
/*N*/       {
/*N*/           SdrObject* pObj = pSub->GetObj(i);
/*N*/           DBG_ASSERT(pObj->ISA(E3dObject), "AW: In E3dObject sind nur 3D-Objekte erlaubt!");
/*N*/           ((E3dObject*)pObj)->SetRectsDirty(bNotMyself);
/*N*/       }
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* Inventor zurueckgeben
|*
\************************************************************************/

/*N*/ UINT32 E3dObject::GetObjInventor() const
/*N*/ {
/*N*/   return E3dInventor;
/*N*/ }

/*************************************************************************
|*
|* Identifier zurueckgeben
|*
\************************************************************************/

/*N*/ UINT16 E3dObject::GetObjIdentifier() const
/*N*/ {
/*N*/   return E3D_OBJECT_ID;
/*N*/ }

/*************************************************************************
|*
|* Layer abfragen
|*
\************************************************************************/

/*N*/ SdrLayerID E3dObject::GetLayer() const
/*N*/ {
/*N*/   bool bFirst = TRUE;
/*N*/   E3dObjList* pOL = pSub;
/*N*/   ULONG       nObjCnt = pOL->GetObjCount();
/*N*/   SdrLayerID  nLayer = SdrLayerID(nLayerID);
/*N*/
/*N*/   for ( ULONG i = 0; i < nObjCnt; i++ )
/*N*/   {
/*N*/       SdrLayerID nObjLayer;
/*N*/       if(pOL->GetObj(i)->ISA(E3dPolyObj))
/*N*/           nObjLayer = SdrLayerID(nLayerID);
/*N*/       else
/*N*/           nObjLayer = pOL->GetObj(i)->GetLayer();
/*N*/
/*N*/       if (bFirst)
/*N*/       {
/*N*/           nLayer = nObjLayer;
/*N*/           bFirst = FALSE;
/*N*/       }
/*N*/       else if ( nObjLayer != nLayer )
/*N*/           return 0;
/*N*/   }
/*N*/   return nLayer;
/*N*/ }

/*************************************************************************
|*
|* Layer setzen
|*
\************************************************************************/

/*N*/ void E3dObject::NbcSetLayer(SdrLayerID nLayer)
/*N*/ {
/*N*/   SdrAttrObj::NbcSetLayer(nLayer);
/*N*/
/*N*/   E3dObjList* pOL = pSub;
/*N*/   ULONG nObjCnt = pOL->GetObjCount();
/*N*/   ULONG i;
/*N*/   for ( i = 0; i < nObjCnt; i++ )
/*N*/       pOL->GetObj(i)->NbcSetLayer(nLayer);
/*N*/ }

/*************************************************************************
|*
|* ObjList auch an SubList setzen
|*
\************************************************************************/

/*N*/ void E3dObject::SetObjList(SdrObjList* pNewObjList)
/*N*/ {
/*N*/   SdrObject::SetObjList(pNewObjList);
/*N*/   pSub->SetUpList(pNewObjList);
/*N*/ }

/*************************************************************************
|*
|* Layer setzen
|*
\************************************************************************/

/*N*/ void E3dObject::SetPage(SdrPage* pNewPage)
/*N*/ {
/*N*/   SdrAttrObj::SetPage(pNewPage);
/*N*/   pSub->SetPage(pNewPage);
/*N*/ }

/*************************************************************************
|*
|* Layer setzen
|*
\************************************************************************/

/*N*/ void E3dObject::SetModel(SdrModel* pNewModel)
/*N*/ {
/*N*/   SdrAttrObj::SetModel(pNewModel);
/*N*/   pSub->SetModel(pNewModel);
/*N*/ }

/*************************************************************************
|*
|* resize object, used from old 2d interfaces, e.g. in Move/Scale dialog
|* (F4)
|*
\************************************************************************/
/*N*/ void E3dObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
/*N*/ {
/*N*/ #ifndef SVX_LIGHT
/*N*/   // SdrAttrObj::NbcResize(rRef, xFact, yFact);
/*N*/
/*N*/   // Bewegung in X,Y im Augkoordinatensystem
/*N*/   E3dScene* pScene = GetScene();
/*N*/
/*N*/   if(pScene)
/*N*/   {
/*N*/       // pos ermitteln
/*N*/       B3dTransformationSet& rTransSet = pScene->GetCameraSet();
/*N*/       Vector3D aScaleCenter((double)rRef.X(), (double)rRef.Y(), 32768.0);
/*N*/       aScaleCenter = rTransSet.ViewToEyeCoor(aScaleCenter);
/*N*/
/*N*/       // scale-faktoren holen
/*N*/       double fScaleX = xFact;
/*N*/       double fScaleY = yFact;
/*N*/
/*N*/       // build transform
/*N*/       Matrix4D mFullTransform(GetFullTransform());
/*N*/       Matrix4D mTrans(mFullTransform);
/*N*/
/*N*/       mTrans *= rTransSet.GetOrientation();
/*N*/       mTrans.Translate(-aScaleCenter);
/*N*/       mTrans.Scale(fScaleX, fScaleY, 1.0);
/*N*/       mTrans.Translate(aScaleCenter);
/*N*/       mTrans *= rTransSet.GetInvOrientation();
/*N*/       mFullTransform.Invert();
/*N*/       mTrans *= mFullTransform;
/*N*/
/*N*/       // anwenden
/*N*/       Matrix4D mObjTrans(GetTransform());
/*N*/       mObjTrans *= mTrans;
/*N*/       SetTransform(mObjTrans);
/*N*/
/*N*/       // force new camera and SnapRect on scene, geometry may have really
/*N*/       // changed
/*N*/       pScene->CorrectSceneDimensions();
/*N*/   }
/*N*/ #endif
/*N*/ }

/*************************************************************************
|*
|* liefere die Sublist, aber nur dann, wenn darin Objekte enthalten sind !
|*
\************************************************************************/

/*N*/ SdrObjList* E3dObject::GetSubList() const
/*N*/ {
/*N*/   return pSub;
/*N*/ }

/*************************************************************************
|*
|* SnapRect berechnen
|*
\************************************************************************/

/*N*/ void E3dObject::RecalcSnapRect()
/*N*/ {
/*N*/   maSnapRect = Rectangle();
/*N*/   if(pSub && pSub->GetObjCount())
/*N*/   {
/*N*/       for (ULONG i = 0; i < pSub->GetObjCount(); i++)
/*N*/       {
/*N*/           SdrObject* pObj = pSub->GetObj(i);
/*N*/           DBG_ASSERT(pObj->ISA(E3dObject), "AW: In E3dObject sind nur 3D-Objekte erlaubt!");
/*N*/           Rectangle aSubRect = ((E3dObject*)pObj)->GetSnapRect();
/*N*/           maSnapRect.Union(aSubRect);
/*N*/       }
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* BoundRect berechnen
|*
\************************************************************************/

/*N*/ void E3dObject::RecalcBoundRect()
/*N*/ {
/*N*/   // BoundRect aus SnapRect berechnen
/*N*/   aOutRect = GetSnapRect();
/*N*/
/*N*/   if(pSub && pSub->GetObjCount())
/*N*/   {
/*N*/       for (ULONG i = 0; i < pSub->GetObjCount(); i++)
/*N*/       {
/*N*/           SdrObject* pObj = pSub->GetObj(i);
/*N*/           DBG_ASSERT(pObj->ISA(E3dObject), "AW: In E3dObject sind nur 3D-Objekte erlaubt!");
/*N*/           Rectangle aSubRect = ((E3dObject*)pObj)->GetBoundRect();
/*N*/           aOutRect.Union(aSubRect);
/*N*/       }
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* Einfuegen eines 3D-Objekts an den Parent weitermelden, damit dieser
|* ggf. eine Sonderbehandlung fuer spezielle Objekte durchfuehren kann
|* (z.B. Light/Label in E3dScene)
|*
\************************************************************************/

/*N*/ void E3dObject::NewObjectInserted(const E3dObject* p3DObj)
/*N*/ {
/*N*/   if(GetParentObj())
/*N*/       GetParentObj()->NewObjectInserted(p3DObj);
/*N*/ }

/*************************************************************************
|*
|* Parent ueber Aenderung der Struktur (z.B. durch Transformation)
|* informieren; dabei wird das Objekt, in welchem die Aenderung
|* aufgetreten ist, uebergeben
|*
\************************************************************************/

/*N*/ void E3dObject::StructureChanged(const E3dObject* p3DObj)
/*N*/ {
/*N*/   if ( GetParentObj() )
/*N*/   {
/*N*/       // Wenn sich im Child das BoundVolume geaendert hat, muessen
/*N*/       // auch die der Parents angepasst werden
/*N*/       if ( !p3DObj->bBoundVolValid )
/*N*/           GetParentObj()->bBoundVolValid = FALSE;
/*N*/
/*N*/       GetParentObj()->StructureChanged(p3DObj);
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* 3D-Objekt einfuegen
|*
\************************************************************************/

/*N*/ void E3dObject::Insert3DObj(E3dObject* p3DObj)
/*N*/ {
/*N*/   DBG_ASSERT(p3DObj, "Insert3DObj mit NULL-Zeiger!");
/*N*/   p3DObj->SetObjTreeLevel(nObjTreeLevel + 1);
/*N*/   SdrPage* pPg = pPage;
/*N*/   pSub->InsertObject(p3DObj);
/*N*/   pPage = pPg;
/*N*/   bBoundVolValid = FALSE;
/*N*/   NewObjectInserted(p3DObj);
/*N*/   StructureChanged(this);
/*N*/ }

/*N*/ void E3dObject::Remove3DObj(E3dObject* p3DObj)
/*N*/ {
/*N*/   DBG_ASSERT(p3DObj, "Remove3DObj mit NULL-Zeiger!");
/*N*/
/*N*/   if(p3DObj->GetParentObj() == this)
/*N*/   {
/*N*/       SdrPage* pPg = pPage;
/*N*/       pSub->RemoveObject(p3DObj->GetOrdNum());
/*N*/       pPage = pPg;
/*N*/
/*N*/       bBoundVolValid = FALSE;
/*N*/       StructureChanged(this);
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* Parent holen
|*
\************************************************************************/

/*N*/ E3dObject* E3dObject::GetParentObj() const
/*N*/ {
/*N*/   E3dObject* pRetval = NULL;
/*N*/
/*N*/   if(GetObjList()
/*N*/       && GetObjList()->GetOwnerObj()
/*N*/       && GetObjList()->GetOwnerObj()->ISA(E3dObject))
/*N*/       pRetval = ((E3dObject*)GetObjList()->GetOwnerObj());
/*N*/   return pRetval;
/*N*/ }

/*************************************************************************
|*
|* Uebergeordnetes Szenenobjekt bestimmen
|*
\************************************************************************/

/*N*/ E3dScene* E3dObject::GetScene() const
/*N*/ {
/*N*/   if(GetParentObj())
/*N*/       return GetParentObj()->GetScene();
/*N*/   return NULL;
/*N*/ }

/*************************************************************************
|*
|* umschliessendes Volumen inklusive aller Kindobjekte berechnen
|*
\************************************************************************/

/*N*/ void E3dObject::RecalcBoundVolume()
/*N*/ {
/*N*/   E3dObjList* pOL = pSub;
/*N*/   ULONG nObjCnt = pOL->GetObjCount();
/*N*/
/*N*/   if(nObjCnt)
/*N*/   {
/*N*/       aBoundVol = Volume3D();
/*N*/
/*N*/       for (ULONG i = 0; i < nObjCnt; i++)
/*N*/       {
/*N*/           SdrObject* pObj = pOL->GetObj(i);
/*N*/
/*N*/           DBG_ASSERT(pObj->ISA(E3dObject), "In E3dObject sind nur 3D-Objekte erlaubt!");
/*N*/           // Bei den Kindobjekten auch die lokalen Transformationen
/*N*/           // beruecksichtigen
/*N*/           E3dObject* p3DObj = (E3dObject*) pObj;
/*N*/           const Volume3D& rVol = p3DObj->GetBoundVolume();
/*N*/           const Matrix4D& rTf  = p3DObj->GetTransform();
/*N*/           aBoundVol.Union(rVol.GetTransformVolume(rTf));
/*N*/       }
/*N*/
/*N*/       aLocalBoundVol = aBoundVol;
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       aBoundVol = aLocalBoundVol;
/*N*/   }
/*N*/
/*N*/   bBoundVolValid = TRUE;
/*N*/ }

/*************************************************************************
|*
|* umschliessendes Volumen zurueckgeben und ggf. neu berechnen
|*
\************************************************************************/

/*N*/ const Volume3D& E3dObject::GetBoundVolume()
/*N*/ {
/*N*/   if ( !bBoundVolValid )
/*N*/       RecalcBoundVolume();
/*N*/
/*N*/   if(!aBoundVol.IsValid())
/*N*/       aBoundVol = Volume3D(Vector3D(), Vector3D());
/*N*/
/*N*/   return aBoundVol;
/*N*/ }

/*************************************************************************
|*
|* Mittelpunkt liefern
|*
\************************************************************************/

/*N*/ Vector3D E3dObject::GetCenter()
/*N*/ {
/*N*/   Volume3D aVolume = GetBoundVolume();
/*N*/   return (aVolume.MaxVec() + aVolume.MinVec()) / 2.0;
/*N*/ }

/*************************************************************************
|*
|* Aederung des BoundVolumes an alle Kindobjekte weitergeben
|*
\************************************************************************/

/*N*/ void E3dObject::SetBoundVolInvalid()
/*N*/ {
/*N*/   bBoundVolValid = FALSE;
/*N*/
/*N*/   E3dObjList* pOL = pSub;
/*N*/   ULONG nObjCnt = pOL->GetObjCount();
/*N*/
/*N*/   for (ULONG i = 0; i < nObjCnt; i++)
/*N*/   {
/*N*/       SdrObject* pObj = pOL->GetObj(i);
/*N*/       DBG_ASSERT(pObj->ISA(E3dObject), "In E3dObject sind nur 3D-Objekte erlaubt!");
/*N*/
/*N*/       ((E3dObject*) pObj)->SetBoundVolInvalid();
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* Aederung der Transformation an alle Kindobjekte weitergeben
|*
\************************************************************************/

/*N*/ void E3dObject::SetTransformChanged()
/*N*/ {
/*N*/   bTfHasChanged = TRUE;
/*N*/   bBoundVolValid = FALSE;
/*N*/
/*N*/   E3dObjList* pOL = pSub;
/*N*/   ULONG nObjCnt = pOL->GetObjCount();
/*N*/
/*N*/   for (ULONG i = 0; i < nObjCnt; i++)
/*N*/   {
/*N*/       SdrObject* pObj = pOL->GetObj(i);
/*N*/       DBG_ASSERT(pObj->ISA(E3dObject), "In E3dObject sind nur 3D-Objekte erlaubt!");
/*N*/
/*N*/       ((E3dObject*) pObj)->SetTransformChanged();
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* hierarchische Transformation ueber alle Parents bestimmen, in
|* aFullTfMatrix ablegen und diese zurueckgeben
|*
\************************************************************************/

/*N*/ const Matrix4D& E3dObject::GetFullTransform()
/*N*/ {
/*N*/   if ( bTfHasChanged )
/*N*/   {
/*N*/       aFullTfMatrix = aTfMatrix;
/*N*/
/*N*/       if ( GetParentObj() )
/*N*/           aFullTfMatrix *= GetParentObj()->GetFullTransform();
/*N*/
/*N*/       bTfHasChanged = FALSE;
/*N*/   }
/*N*/
/*N*/   return aFullTfMatrix;
/*N*/ }

/*************************************************************************
|*
|* Transformationsmatrix abfragen
|*
\************************************************************************/

/*N*/ const Matrix4D& E3dObject::GetTransform() const
/*N*/ {
/*N*/   return aTfMatrix;
/*N*/ }

/*************************************************************************
|*
|* Transformationsmatrix setzen
|*
\************************************************************************/

/*N*/ void E3dObject::NbcSetTransform(const Matrix4D& rMatrix)
/*N*/ {
/*N*/   aTfMatrix = rMatrix;
/*N*/   SetTransformChanged();
/*N*/   StructureChanged(this);
/*N*/ }

/*************************************************************************
|*
|* Transformationsmatrix auf Einheitsmatrix zuruecksetzen
|*
\************************************************************************/

/*N*/ void E3dObject::NbcResetTransform()
/*N*/ {
/*N*/   aTfMatrix.Identity();
/*N*/   SetTransformChanged();
/*N*/   StructureChanged(this);
/*N*/ }

/*************************************************************************
|*
|* Transformationsmatrix setzen mit Repaint-Broadcast
|*
\************************************************************************/

/*N*/ void E3dObject::SetTransform(const Matrix4D& rMatrix)
/*N*/ {
/*N*/   SendRepaintBroadcast();
/*N*/   NbcSetTransform(rMatrix);
/*N*/   SetChanged();
/*N*/   SendRepaintBroadcast();
/*N*/   if (pUserCall != NULL) pUserCall->Changed(*this, SDRUSERCALL_RESIZE, Rectangle());
/*N*/ }

/*************************************************************************
|*
|* Objektbaum-Ebene des Objekts und aller Children setzen
|*
\************************************************************************/

/*N*/ void E3dObject::SetObjTreeLevel(USHORT nNewLevel)
/*N*/ {
/*N*/   nObjTreeLevel = nNewLevel;
/*N*/   nNewLevel++;
/*N*/
/*N*/   E3dObjList* pOL = pSub;
/*N*/   ULONG nObjCnt = pOL->GetObjCount();
/*N*/
/*N*/   for (ULONG i = 0; i < nObjCnt; i++)
/*N*/   {
/*N*/       SdrObject* pObj = pOL->GetObj(i);
/*N*/       DBG_ASSERT(pObj->ISA(E3dObject), "In E3dObject sind nur 3D-Objekte erlaubt!");
/*N*/
/*N*/       ((E3dObject*) pObj)->SetObjTreeLevel(nNewLevel);
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* Zuweisungsoperator
|*
\************************************************************************/


//////////////////////////////////////////////////////////////////////////////
// ItemSet access

/*N*/ const SfxItemSet& E3dObject::GetItemSet() const
/*N*/ {
/*N*/   // include Items of scene this object belongs to
/*N*/   E3dScene* pScene = GetScene();
/*N*/   if(pScene && pScene != this)
/*N*/   {
/*N*/       SfxItemSet& rSet = (SfxItemSet&)SdrAttrObj::GetItemSet();
/*N*/       SfxItemSet aSet(*rSet.GetPool(), SDRATTR_3DSCENE_FIRST, SDRATTR_3DSCENE_LAST);
/*N*/       aSet.Put(pScene->E3dObject::GetItemSet());
/*N*/       rSet.Put(aSet);
/*N*/   }
/*N*/
/*N*/   return SdrAttrObj::GetItemSet();
/*N*/ }

/*N*/ SfxItemSet* E3dObject::CreateNewItemSet(SfxItemPool& rPool)
/*N*/ {
/*N*/   // include ALL items, 2D and 3D
/*N*/   return new SfxItemSet(rPool,
/*N*/       // ranges from SdrAttrObj
/*N*/       SDRATTR_START, SDRATTRSET_SHADOW,
/*N*/       SDRATTRSET_OUTLINER, SDRATTRSET_MISC,
/*N*/
/*N*/       // ranges for 3D (object and scene)
/*N*/       SDRATTR_3D_FIRST, SDRATTR_3D_LAST,
/*N*/
/*N*/       // outliner and end
/*N*/       EE_ITEMS_START, EE_ITEMS_END,
/*N*/       0, 0);
/*N*/ }

// private support routines for ItemSet access. NULL pointer means clear item.
/*N*/ void E3dObject::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
/*N*/ {
/*N*/   // propagate item changes to scene
/*N*/   if(!nWhich || (nWhich >= SDRATTR_3DSCENE_FIRST && nWhich <= SDRATTR_3DSCENE_LAST))
/*N*/   {
/*N*/       E3dScene* pScene = GetScene();
/*N*/       if(pScene && pScene != this)
/*N*/           pScene->E3dObject::ItemChange(nWhich, pNewItem);
/*N*/   }
/*N*/
/*N*/   // call parent
/*N*/   SdrAttrObj::ItemChange(nWhich, pNewItem);
/*N*/ }

// #107770# Like propagating ItemChange to the scene if scene items are changed,
// do the same with the PostItemChange calls.
/*N*/ void E3dObject::PostItemChange(const sal_uInt16 nWhich)
/*N*/ {
/*N*/   // propagate item changes to scene
/*N*/   if(!nWhich || (nWhich >= SDRATTR_3DSCENE_FIRST && nWhich <= SDRATTR_3DSCENE_LAST))
/*N*/   {
/*N*/       E3dScene* pScene = GetScene();
/*N*/       if(pScene && pScene != this)
/*N*/           pScene->PostItemChange(nWhich);
/*N*/   }
/*N*/
/*N*/   // call parent
/*N*/   SdrAttrObj::PostItemChange(nWhich);
/*N*/ }

/*N*/ void E3dObject::ItemSetChanged( const SfxItemSet& rSet )
/*N*/ {
/*N*/   // call parent
/*N*/   SdrAttrObj::ItemSetChanged( rSet );
/*N*/
/*N*/   // local changes
/*N*/   StructureChanged(this);
/*N*/ }

/*************************************************************************
|*
|* StyleSheet setzen
|*
\************************************************************************/

/*N*/ void E3dObject::NbcSetStyleSheet(SfxStyleSheet* pNewStyleSheet,
/*N*/   bool bDontRemoveHardAttr)
/*N*/ {
/*N*/   // call parent
/*N*/   SdrAttrObj::NbcSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
/*N*/
/*N*/   E3dObjList* pOL = pSub;
/*N*/   ULONG nObjCnt = pOL->GetObjCount();
/*N*/   for ( ULONG i = 0; i < nObjCnt; i++ )
/*?*/       pOL->GetObj(i)->NbcSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
/*N*/ }

/*************************************************************************
|*
|* Objektdaten aus Stream laden
|*
\************************************************************************/

/*N*/ void E3dObject::ReadData(const SdrObjIOHeader& rHead, SvStream& rIn)
/*N*/ {
/*N*/   if (ImpCheckSubRecords (rHead, rIn))
/*N*/   {
/*N*/       SdrAttrObj::ReadData(rHead, rIn);
/*N*/       // Fuer Abwaertskompatibilitaet (Lesen neuer Daten mit altem Code)
/*N*/       SdrDownCompat aCompat(rIn, STREAM_READ);
/*N*/ #ifdef DBG_UTIL
/*N*/       aCompat.SetID("E3dObject");
/*N*/ #endif
/*N*/       pSub->Load(rIn, *pPage);
/*N*/
/*N*/       if ((rIn.GetVersion() < 3560) || (rHead.GetVersion() <= 12))
/*N*/       {
/*N*/           UINT16  nTmp16;
/*N*/
/*N*/           rIn >> aLocalBoundVol;
/*N*/
/*N*/           Old_Matrix3D aMat3D;
/*N*/           rIn >> aMat3D;
/*N*/           aTfMatrix = Matrix4D(aMat3D);
/*N*/
/*N*/           rIn >> nLogicalGroup;
/*N*/           rIn >> nObjTreeLevel;
/*N*/           rIn >> nPartOfParent;
/*N*/           rIn >> nTmp16; eDragDetail = E3dDragDetail(nTmp16);
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           ReadOnlyOwnMembers(rHead, rIn);
/*N*/       }
/*N*/
/*N*/       // Wie ein veraendertes Objekt behandeln
/*N*/       SetTransformChanged();
/*N*/       StructureChanged(this);
/*N*/
/*N*/       // BoundVolume muss neu berechnet werden
/*N*/       bBoundVolValid = FALSE;
/*N*/
/*N*/       // SnapRect auch
/*N*/       bSnapRectDirty = TRUE;
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* Nur die Daten des E3dObject aus Stream laden (nicht der Sublisten und
|* der Basisklassen). Wird von E3dSphere auch genutzt. (FileFormat-Optimierung)
|*
\************************************************************************/

/*N*/ void E3dObject::ReadOnlyOwnMembers(const SdrObjIOHeader& /*rHead*/, SvStream& rIn)
/*N*/ {
/*N*/   // Fuer Abwaertskompatibilitaet (Lesen neuer Daten mit altem Code)
/*N*/   SdrDownCompat aCompat(rIn, STREAM_READ);
/*N*/ #ifdef DBG_UTIL
/*N*/   aCompat.SetID("E3dObjectOwnMembers");
/*N*/ #endif
/*N*/   UINT16  nTmp16;
/*N*/
/*N*/   rIn >> aLocalBoundVol;
/*N*/
/*N*/   Old_Matrix3D aMat3D;
/*N*/   rIn >> aMat3D;
/*N*/   aTfMatrix = Matrix4D(aMat3D);
/*N*/
/*N*/   rIn >> nLogicalGroup;
/*N*/   rIn >> nObjTreeLevel;
/*N*/   rIn >> nPartOfParent;
/*N*/   rIn >> nTmp16; eDragDetail = E3dDragDetail(nTmp16);
/*N*/
/*N*/   bBoundVolValid = FALSE;
/*N*/ }


/*************************************************************************
|*
|* nach dem Laden...
|*
\************************************************************************/

/*N*/ void E3dObject::AfterRead()
/*N*/ {
/*N*/   SdrAttrObj::AfterRead();
/*N*/   if (pSub)
/*N*/       pSub->AfterRead();
/*N*/ }

/*************************************************************************
|*
|* erstelle neues GeoData-Objekt
|*
\************************************************************************/

/*N*/ SdrObjGeoData *E3dObject::NewGeoData() const
/*N*/ {
/*N*/   // Theoretisch duerfen auch nur Szenen ihre GeoDatas erstellen und verwalten !!
/*N*/   // AW: Dies stimmt nicht mehr, diese Stelle ist mit der neuen Engine OK!
/*N*/   return new E3DObjGeoData;
/*N*/ }

/*************************************************************************
|*
|* uebergebe aktuelle werte an das GeoData-Objekt
|*
\************************************************************************/

/*N*/ void E3dObject::SaveGeoData(SdrObjGeoData& rGeo) const
/*N*/ {
/*N*/   SdrAttrObj::SaveGeoData (rGeo);
/*N*/
/*N*/   ((E3DObjGeoData &) rGeo).aLocalBoundVol  = aLocalBoundVol;
/*N*/   ((E3DObjGeoData &) rGeo).aTfMatrix       = aTfMatrix;
/*N*/ }

/*************************************************************************
|*
|* uebernehme werte aus dem GeoData-Objekt
|*
\************************************************************************/

/*N*/ void E3dObject::RestGeoData(const SdrObjGeoData& rGeo)
/*N*/ {
/*N*/   aLocalBoundVol = ((E3DObjGeoData &) rGeo).aLocalBoundVol;
/*N*/   NbcSetTransform (((E3DObjGeoData &) rGeo).aTfMatrix);
/*N*/
/*N*/   SdrAttrObj::RestGeoData (rGeo);
/*N*/   GetScene()->FitSnapRectToBoundVol();
/*N*/ }

/*************************************************************************
|*
|* Pruefe, ob die SubRecords ok sind und mit der Factory gelesen werden
|* koennen.
|*
\************************************************************************/

/*N*/ BOOL E3dObject::ImpCheckSubRecords (const SdrObjIOHeader& rHead,
/*N*/                                   SvStream&             rIn)
/*N*/ {
/*N*/   BOOL bDoRead = FALSE;
/*N*/
/*N*/   if ( rIn.GetError() == SVSTREAM_OK )
/*N*/   {
/*N*/       if (rHead.GetVersion () <= 12)
/*N*/       {
/*N*/           ULONG nPos0 = rIn.Tell();
/*N*/           // Einen SubRecord ueberspringen (SdrObject)
/*N*/           { SdrDownCompat aCompat(rIn,STREAM_READ); }
/*N*/           // Nocheinen SubRecord ueberspringen (SdrAttrObj)
/*N*/           { SdrDownCompat aCompat(rIn,STREAM_READ); }
/*N*/           // Und nun muesste meiner kommen
/*N*/           bDoRead = rHead.GetBytesLeft() != 0;
/*N*/           rIn.Seek (nPos0); // FilePos wieder restaurieren
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           bDoRead = TRUE;
/*N*/       }
/*N*/   }
/*N*/
/*N*/   return bDoRead;
/*N*/ }

/*************************************************************************
|*
|* Keine DefaultAttr, zu langsam
|*
\************************************************************************/

/*N*/ void E3dObject::ForceDefaultAttr()
/*N*/ {
/*N*/ }

/*************************************************************************/

/*N*/ TYPEINIT1(E3dCompoundObject, E3dObject);

/*************************************************************************
|*
|* Konstruktor
|*
\************************************************************************/

/*N*/ E3dCompoundObject::E3dCompoundObject() : E3dObject()
/*N*/ {
/*N*/   // Defaults setzen
/*N*/   E3dDefaultAttributes aDefault;
/*N*/   SetDefaultAttributes(aDefault);
/*N*/
/*N*/   bBytesLeft = FALSE;
/*N*/   bCreateE3dPolyObj = FALSE;
/*N*/   bGeometryValid = FALSE;
/*N*/ }

/*N*/ E3dCompoundObject::E3dCompoundObject(E3dDefaultAttributes& rDefault) : E3dObject()
/*N*/ {
/*N*/   // Defaults setzen
/*N*/   SetDefaultAttributes(rDefault);
/*N*/
/*N*/   bBytesLeft = FALSE;
/*N*/   bCreateE3dPolyObj = FALSE;
/*N*/   bGeometryValid = FALSE;
/*N*/ }

/*N*/ void E3dCompoundObject::SetDefaultAttributes(E3dDefaultAttributes& rDefault)
/*N*/ {
/*N*/   // Defaults setzen
/*N*/   aMaterialAmbientColor = rDefault.GetDefaultAmbientColor();
/*N*/
//is always default, so it needs not to be set /*N*/    aBackMaterial = rDefault.GetDefaultBackMaterial();
/*N*/   bCreateNormals = rDefault.GetDefaultCreateNormals();
/*N*/   bCreateTexture = rDefault.GetDefaultCreateTexture();
/*N*/   bUseDifferentBackMaterial = rDefault.GetDefaultUseDifferentBackMaterial();
/*N*/ }

/*************************************************************************
|*
|* Destruktor
|*
\************************************************************************/

/*N*/ E3dCompoundObject::~E3dCompoundObject ()
/*N*/ {
/*N*/ }

/*************************************************************************
|*
|* Start der Geometrieerzeugung ankuendigen
|*
\************************************************************************/

/*N*/ void E3dCompoundObject::StartCreateGeometry()
/*N*/ {
/*N*/   // Geometriestart mitteilen
/*N*/   aDisplayGeometry.StartDescription();
/*N*/
/*N*/   // Lokales Volumen reset
/*N*/   aLocalBoundVol = Volume3D();
/*N*/
/*N*/   // Geometrie ist ab jetzt gueltig, um ein rekursives weiteres
/*N*/   // Erzeugen zu verhindern
/*N*/   bGeometryValid = TRUE;
/*N*/ }

/*************************************************************************
|*
|* Identifier zurueckgeben
|*
\************************************************************************/

/*N*/ UINT16 E3dCompoundObject::GetObjIdentifier() const
/*N*/ {
/*N*/   return E3D_COMPOUNDOBJ_ID;
/*N*/ }

/*************************************************************************
|*
|* Compounds brauchen Defaults
|*
\************************************************************************/

/*N*/ void E3dCompoundObject::ForceDefaultAttr()
/*N*/ {
/*N*/   SdrAttrObj::ForceDefaultAttr();
/*N*/ }

/*************************************************************************
|*
|* SnapRect berechnen
|*
\************************************************************************/

/*N*/ void E3dCompoundObject::RecalcSnapRect()
/*N*/ {
/*N*/   E3dScene* pScene = GetScene();
/*N*/   if(pScene)
/*N*/   {
/*N*/       // Objekttransformation uebernehmen
/*N*/       const Volume3D& rBoundVol = GetBoundVolume();
/*N*/       maSnapRect = Rectangle();
/*N*/
/*N*/       if(rBoundVol.IsValid())
/*N*/       {
/*N*/           const Matrix4D& rTrans = GetFullTransform();
/*N*/           Vol3DPointIterator aIter(rBoundVol, &rTrans);
/*N*/           Vector3D aTfVec;
/*N*/           while ( aIter.Next(aTfVec) )
/*N*/           {
/*N*/               aTfVec = pScene->GetCameraSet().WorldToViewCoor(aTfVec);
/*N*/               Point aPoint((long)(aTfVec.X() + 0.5), (long)(aTfVec.Y() + 0.5));
/*N*/               maSnapRect.Union(Rectangle(aPoint, aPoint));
/*N*/           }
/*N*/       }
/*N*/       bSnapRectDirty = FALSE;
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* BoundRect berechnen und evtl. Schatten einbeziehen
|* Dazu muss ein eventueller Schatten des einzelnen 3D-Objektes
|* beruecksichtigt werden
|*
\************************************************************************/

/*N*/ void E3dCompoundObject::RecalcBoundRect()
/*N*/ {
/*N*/   // BoundRect aus SnapRect berechnen
/*N*/   aOutRect = GetSnapRect();
/*N*/
/*N*/   E3dScene* pScene = GetScene();
/*N*/   if(pScene)
/*N*/   {
            // Linienbreite beruecksichtigen
/*N*/       INT32 nLineWidth = ((const XLineWidthItem&)(GetItem(XATTR_LINEWIDTH))).GetValue();
/*N*/       if(nLineWidth)
/*N*/       {
/*?*/           Rectangle aShadowRect = aOutRect;
/*?*/           aShadowRect.Left() -= nLineWidth;
/*?*/           aShadowRect.Right() += nLineWidth;
/*?*/           aShadowRect.Top() -= nLineWidth;
/*?*/           aShadowRect.Bottom() += nLineWidth;
/*?*/           aOutRect.Union(aShadowRect);
/*N*/       }
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* BoundVolume holen. Falls die Geometrie ungueltig ist, diese neu
|* erzeugen und das BoundVol neu berechnen
|*
\************************************************************************/

/*N*/ const Volume3D& E3dCompoundObject::GetBoundVolume()
/*N*/ {
/*N*/   // Geometrie aktuell?
/*N*/   if(!bGeometryValid)
/*N*/   {
/*N*/       // Neu erzeugen und eine Neubestimmung des BoundVol erzwingen
/*N*/       ReCreateGeometry();
/*N*/       bBoundVolValid = FALSE;
/*N*/   }
/*N*/
/*N*/   // call parent
/*N*/   return E3dObject::GetBoundVolume();
/*N*/ }

/*************************************************************************
|*
|* Einlesen der Datenmember eines E3dCompounds
|*
\************************************************************************/

/*N*/ void E3dCompoundObject::ReadData(const SdrObjIOHeader& rHead, SvStream& rIn)
/*N*/ {
/*N*/   if ( rIn.GetError() != SVSTREAM_OK )
/*N*/       return;
/*N*/
/*N*/   E3dObject::ReadData(rHead, rIn);
/*N*/
/*N*/     // Vor der Filerevision 13 wurde das Objekt nie geschrieben.
/*N*/     // auch kein Kompatibilitaetsrecord.
/*N*/   if ((rHead.GetVersion() < 13) || (rIn.GetVersion() < 3560))
/*N*/   {
/*N*/       return;
/*N*/   }
/*N*/
/*N*/   SdrDownCompat aCompat(rIn, STREAM_READ);
/*N*/ #ifdef DBG_UTIL
/*N*/   aCompat.SetID("E3dCompoundObject");
/*N*/ #endif
/*N*/
/*N*/   bBytesLeft = FALSE;
/*N*/   if (aCompat.GetBytesLeft () >= sizeof (BOOL))
/*N*/   {
/*N*/       BOOL bTmp, bTmp2;
/*N*/
/*N*/       rIn >> bTmp;
/*N*/       mpObjectItemSet->Put(Svx3DDoubleSidedItem(bTmp));
/*N*/
/*N*/       // neue Parameter zur Geometrieerzeugung
/*N*/       if (aCompat.GetBytesLeft () >= sizeof (BOOL))
/*N*/       {
/*N*/           sal_uInt16 nTmp;
/*N*/
/*N*/           rIn >> bTmp;
/*N*/           bCreateNormals = bTmp;
/*N*/
/*N*/           rIn >> bTmp;
/*N*/           bCreateTexture = bTmp;
/*N*/
/*N*/           rIn >> bTmp;
/*N*/           rIn >> bTmp2;
/*N*/           if(bTmp == FALSE && bTmp2 == FALSE)
/*N*/               nTmp = 0;
/*N*/           else if(bTmp == TRUE && bTmp2 == FALSE)
/*N*/               nTmp = 1;
/*N*/           else
/*N*/               nTmp = 2;
/*N*/           mpObjectItemSet->Put(Svx3DNormalsKindItem(nTmp));
/*N*/
/*N*/           rIn >> bTmp;
/*N*/           rIn >> bTmp2;
/*N*/           if(bTmp == FALSE && bTmp2 == FALSE)
/*N*/               nTmp = 0;
/*N*/           else if(bTmp == TRUE && bTmp2 == FALSE)
/*N*/               nTmp = 1;
/*N*/           else
/*N*/               nTmp = 2;
/*N*/           mpObjectItemSet->Put(Svx3DTextureProjectionXItem(nTmp));
/*N*/
/*N*/           rIn >> bTmp;
/*N*/           rIn >> bTmp2;
/*N*/           if(bTmp == FALSE && bTmp2 == FALSE)
/*N*/               nTmp = 0;
/*N*/           else if(bTmp == TRUE && bTmp2 == FALSE)
/*N*/               nTmp = 1;
/*N*/           else
/*N*/               nTmp = 2;
/*N*/           mpObjectItemSet->Put(Svx3DTextureProjectionYItem(nTmp));
/*N*/
/*N*/           rIn >> bTmp;
/*N*/           mpObjectItemSet->Put(Svx3DShadow3DItem(bTmp));
/*N*/
/*N*/           // Setze ein Flag fuer den Aufrufer, dass neues Format
/*N*/           // zu lesen ist
/*N*/           bBytesLeft = TRUE;
/*N*/       }
/*N*/
/*N*/       // neu al 384:
/*N*/       if (aCompat.GetBytesLeft () >= sizeof (B3dMaterial))
/*N*/       {
/*N*/           UINT16 nTmp;
/*N*/
/*N*/           Color aCol;
/*N*/
/*N*/           rIn >> aCol;
/*N*/           SetMaterialAmbientColor(aCol);
/*N*/
/*N*/           rIn >> aCol;
/*N*/           // do NOT use, this is the old 3D-Color(!)
/*N*/           // SetItem(XFillColorItem(String(), aCol));
/*N*/
/*N*/           rIn >> aCol;
/*N*/           mpObjectItemSet->Put(Svx3DMaterialSpecularItem(aCol));
/*N*/
/*N*/           rIn >> aCol;
/*N*/           mpObjectItemSet->Put(Svx3DMaterialEmissionItem(aCol));
/*N*/
/*N*/           rIn >> nTmp;
/*N*/           mpObjectItemSet->Put(Svx3DMaterialSpecularIntensityItem(nTmp));
/*N*/
/*N*/           aBackMaterial.ReadData(rIn);
/*N*/
/*N*/           rIn >> nTmp;
/*N*/           mpObjectItemSet->Put(Svx3DTextureKindItem(nTmp));
/*N*/
/*N*/           rIn >> nTmp;
/*N*/           mpObjectItemSet->Put(Svx3DTextureModeItem(nTmp));
/*N*/
/*N*/           rIn >> bTmp;
/*N*/           mpObjectItemSet->Put(Svx3DNormalsInvertItem(bTmp));
/*N*/       }
/*N*/
/*N*/       // neu ab 534: (hat noch gefehlt)
/*N*/       if (aCompat.GetBytesLeft () >= sizeof (BOOL))
/*N*/       {
/*N*/           rIn >> bTmp;
/*N*/           mpObjectItemSet->Put(Svx3DTextureFilterItem(bTmp));
/*N*/       }
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* Geometrieerzeugung
|*
\************************************************************************/

/*N*/ void E3dCompoundObject::DestroyGeometry()
/*N*/ {
/*N*/   // Alle Objekte in der Sub-Liste zerstoeren. Dies sind die
/*N*/   // zur Visualisierung des Objektes verwendeten Hilfsobjekte
/*N*/   pSub->Clear();
/*N*/   delete pSub;
/*N*/   pSub = new E3dObjList(NULL, NULL);
/*N*/   pSub->SetOwnerObj(this);
/*N*/   pSub->SetListKind(SDROBJLIST_GROUPOBJ);
/*N*/
/*N*/   // Neue Geometrie zerstoeren
/*N*/   aDisplayGeometry.Erase();
/*N*/
/*N*/   // BoundVols resetten
/*N*/   aLocalBoundVol  = Volume3D();
/*N*/   bBoundVolValid = FALSE;
/*N*/   StructureChanged(this);
/*N*/
/*N*/   // Geometrie ist ungueltig
/*N*/   bGeometryValid = FALSE;
/*N*/ }

/*N*/ void E3dCompoundObject::CreateGeometry()
/*N*/ {
/*N*/   // Geometrie ist gueltig, um rekursion zu verhindern
/*N*/   bGeometryValid = TRUE;
/*N*/
/*N*/   // Eventuell entstandene Geometrie noch korrigieren
/*N*/   // und Default -Normalen oder -Texturkoordinaten erzeugen
/*N*/   if(bCreateNormals)
/*N*/   {
/*N*/       if(GetNormalsKind() > 1)
/*?*/           GetDisplayGeometry().CreateDefaultNormalsSphere();
/*N*/       if(GetNormalsInvert())
/*?*/           GetDisplayGeometry().InvertNormals();
/*N*/   }
/*N*/
/*N*/   if(bCreateTexture)
/*N*/   {
/*N*/       GetDisplayGeometry().CreateDefaultTexture(
/*N*/           ((GetTextureProjectionX() > 0) ? B3D_CREATE_DEFAULT_X : FALSE)
/*N*/           |((GetTextureProjectionY() > 0) ? B3D_CREATE_DEFAULT_Y : FALSE),
/*N*/           GetTextureProjectionX() > 1);
/*N*/   }
/*N*/
/*N*/   // Am Ende der Geometrieerzeugung das model an den erzeugten
/*N*/   // PolyObj's setzen, d.h. beim ueberladen dieser Funktion
/*N*/   // den parent am Ende rufen.
/*N*/   if(bCreateE3dPolyObj)
/*N*/       SetModel(pModel);
/*N*/
/*N*/   // Das Ende der Geometrieerzeugung anzeigen
/*N*/   aDisplayGeometry.EndDescription();
/*N*/ }

/*N*/ void E3dCompoundObject::ReCreateGeometry(BOOL bCreateOldGeometry)
/*N*/ {
/*N*/   // Geometrie zerstoeren
/*N*/   DestroyGeometry();
/*N*/
/*N*/   // Flag fuer Geometrieerzeugung setzen
/*N*/   bCreateE3dPolyObj = bCreateOldGeometry;
/*N*/
/*N*/   // ... und neu erzeugen
/*N*/   CreateGeometry();
/*N*/ }

/*************************************************************************
|*
|* Geometrieerzeugung
|*
\************************************************************************/

/*N*/ void E3dCompoundObject::AddGeometry(const PolyPolygon3D& rPolyPolygon3D,
/*N*/   BOOL bHintIsComplex, BOOL bOutline)
/*N*/ {
/*N*/   if(rPolyPolygon3D.Count())
/*N*/   {
/*N*/       // eventuell alte Geometrie erzeugen (z.B. zum speichern)
/*N*/       if(bCreateE3dPolyObj)
/*N*/       {
/*N*/           E3dPolyObj* pObj = new E3dPolyObj(
/*N*/               rPolyPolygon3D, GetDoubleSided(), TRUE);
/*N*/           pObj->SetPartOfParent();
/*N*/           Insert3DObj(pObj);
/*N*/       }
/*N*/
/*N*/       // neue Geometrie erzeugen
/*N*/       for(USHORT a = 0; a < rPolyPolygon3D.Count(); a++ )
/*N*/       {
/*N*/           const Polygon3D& rPoly3D = rPolyPolygon3D[a];
/*N*/           aDisplayGeometry.StartObject(bHintIsComplex, bOutline);
/*N*/           for(USHORT b = 0; b < rPoly3D.GetPointCount(); b++ )
/*N*/               aDisplayGeometry.AddEdge(rPoly3D[b]);
/*N*/       }
/*N*/       aDisplayGeometry.EndObject();
/*N*/
/*N*/       // LocalBoundVolume pflegen
/*N*/       aLocalBoundVol.Union(rPolyPolygon3D.GetPolySize());
/*N*/
/*N*/       // Eigenes BoundVol nicht mehr gueltig
/*N*/       SetBoundVolInvalid();
/*N*/       SetRectsDirty();
/*N*/   }
/*N*/ }

/*?*/ void E3dCompoundObject::AddGeometry(
/*?*/   const PolyPolygon3D& rPolyPolygon3D,
/*?*/   const PolyPolygon3D& rPolyNormal3D,
/*?*/   BOOL bHintIsComplex, BOOL bOutline)
/*?*/ {
/*?*/   if(rPolyPolygon3D.Count())
/*?*/   {
/*?*/       // eventuell alte Geometrie erzeugen (z.B. zum speichern)
/*?*/       if(bCreateE3dPolyObj)
/*?*/       {
/*?*/           E3dPolyObj* pObj = new E3dPolyObj(
/*?*/               rPolyPolygon3D, rPolyNormal3D, GetDoubleSided(), TRUE);
/*?*/           pObj->SetPartOfParent();
/*?*/           Insert3DObj(pObj);
/*?*/       }
/*?*/
/*?*/       // neue Geometrie erzeugen
/*?*/       for(USHORT a = 0; a < rPolyPolygon3D.Count(); a++ )
/*?*/       {
/*?*/           const Polygon3D& rPoly3D = rPolyPolygon3D[a];
/*?*/           const Polygon3D& rNormal3D = rPolyNormal3D[a];
/*?*/           aDisplayGeometry.StartObject(bHintIsComplex, bOutline);
/*?*/           for(USHORT b = 0; b < rPoly3D.GetPointCount(); b++ )
/*?*/               aDisplayGeometry.AddEdge(rPoly3D[b], rNormal3D[b]);
/*?*/       }
/*?*/       aDisplayGeometry.EndObject();
/*?*/
/*?*/       // LocalBoundVolume pflegen
/*?*/       aLocalBoundVol.Union(rPolyPolygon3D.GetPolySize());
/*?*/
/*?*/       // Eigenes BoundVol nicht mehr gueltig
/*?*/       SetBoundVolInvalid();
/*?*/       SetRectsDirty();
/*?*/   }
/*?*/ }

/*N*/ void E3dCompoundObject::AddGeometry(
/*N*/   const PolyPolygon3D& rPolyPolygon3D,
/*N*/   const PolyPolygon3D& rPolyNormal3D,
/*N*/   const PolyPolygon3D& rPolyTexture3D,
/*N*/   BOOL bHintIsComplex, BOOL bOutline)
/*N*/ {
/*N*/   if(rPolyPolygon3D.Count())
/*N*/   {
/*N*/       // eventuell alte Geometrie erzeugen (z.B. zum speichern)
/*N*/       if(bCreateE3dPolyObj)
/*N*/       {
/*N*/           E3dPolyObj* pObj = new E3dPolyObj(
/*N*/               rPolyPolygon3D, rPolyNormal3D,
/*N*/               rPolyTexture3D, GetDoubleSided(), TRUE);
/*N*/           pObj->SetPartOfParent();
/*N*/           Insert3DObj(pObj);
/*N*/       }
/*N*/
/*N*/       // neue Geometrie erzeugen
/*N*/       for(USHORT a = 0; a < rPolyPolygon3D.Count(); a++ )
/*N*/       {
/*N*/           const Polygon3D& rPoly3D = rPolyPolygon3D[a];
/*N*/           const Polygon3D& rNormal3D = rPolyNormal3D[a];
/*N*/           const Polygon3D& rTexture3D = rPolyTexture3D[a];
/*N*/           aDisplayGeometry.StartObject(bHintIsComplex, bOutline);
/*N*/           for(USHORT b = 0; b < rPoly3D.GetPointCount(); b++ )
/*N*/               aDisplayGeometry.AddEdge(rPoly3D[b], rNormal3D[b], rTexture3D[b]);
/*N*/       }
/*N*/       aDisplayGeometry.EndObject();
/*N*/
/*N*/       // LocalBoundVolume pflegen
/*N*/       aLocalBoundVol.Union(rPolyPolygon3D.GetPolySize());
/*N*/
/*N*/       // Eigenes BoundVol nicht mehr gueltig
/*N*/       SetBoundVolInvalid();
/*N*/       SetRectsDirty();
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* Hilfsfunktionen zur Geometrieerzeugung
|*
\************************************************************************/

/*N*/ void E3dCompoundObject::RotatePoly(
/*N*/   PolyPolygon3D& rPolyPolyRotate,
/*N*/   Matrix4D& rRotMat)
/*N*/ {
/*N*/   USHORT nPolyCnt = rPolyPolyRotate.Count();
/*N*/
/*N*/   for(UINT16 a=0;a<nPolyCnt;a++)
/*N*/   {
/*N*/       Polygon3D& rPolyRotate = rPolyPolyRotate[a];
/*N*/       USHORT nPntCnt = rPolyRotate.GetPointCount();
/*N*/
/*N*/       for(UINT16 b=0;b<nPntCnt;b++)
/*N*/           rPolyRotate[b] *= rRotMat;
/*N*/   }
/*N*/ }

/*N*/ void E3dCompoundObject::GrowPoly(
/*N*/   PolyPolygon3D& rPolyPolyGrow,
/*N*/   PolyPolygon3D& rPolyPolyNormals,
/*N*/   double fFactor)
/*N*/ {
/*N*/   USHORT nPolyCnt = rPolyPolyGrow.Count();
/*N*/
/*N*/   for(UINT16 a=0;a<nPolyCnt;a++)
/*N*/   {
/*N*/       Polygon3D& rPolyGrow = rPolyPolyGrow[a];
/*N*/       const Polygon3D& rPolyNormals = rPolyPolyNormals[a];
/*N*/       USHORT nPntCnt = rPolyGrow.GetPointCount();
/*N*/
/*N*/       for(UINT16 b=0;b<nPntCnt;b++)
/*N*/           rPolyGrow[b] += rPolyNormals[b] * fFactor;
/*N*/   }
/*N*/ }


/*N*/ void E3dCompoundObject::ScalePoly(
/*N*/   PolyPolygon3D& rPolyPolyScale,
/*N*/   double fFactor)
/*N*/ {
/*N*/   USHORT nPolyCnt = rPolyPolyScale.Count();
/*N*/   Vector3D aMiddle = rPolyPolyScale.GetMiddle();
/*N*/
/*N*/   for(UINT16 a=0;a<nPolyCnt;a++)
/*N*/   {
/*N*/       Polygon3D& rPolyScale = rPolyPolyScale[a];
/*N*/       USHORT nPntCnt = rPolyScale.GetPointCount();
/*N*/
/*N*/       for(UINT16 b=0;b<nPntCnt;b++)
/*N*/           rPolyScale[b] = ((rPolyScale[b] - aMiddle) * fFactor) + aMiddle;
/*N*/   }
/*N*/ }

/*N*/ void E3dCompoundObject::CreateFront(
/*N*/   const PolyPolygon3D& rPolyPoly3D,
/*N*/   const PolyPolygon3D& rFrontNormals,
/*N*/   BOOL bInCreateNormals,
/*N*/   BOOL bInCreateTexture)
/*N*/ {
/*N*/   // Vorderseite
/*N*/   if(bInCreateNormals)
/*N*/   {
/*N*/       if(bInCreateTexture)
/*N*/       {
/*N*/           // Polygon fuer die Textur erzeugen
/*N*/           PolyPolygon3D aPolyTexture = rPolyPoly3D;
/*N*/           Volume3D aSize = aPolyTexture.GetPolySize();
/*N*/           Matrix4D aTrans;
/*N*/
/*N*/           aTrans.Identity();
/*N*/           aTrans.Translate(-aSize.MinVec());
/*N*/           aPolyTexture.Transform(aTrans);
/*N*/
/*N*/           double fFactorX(1.0), fFactorY(1.0), fFactorZ(1.0);
/*N*/
/*N*/           if(aSize.GetWidth() != 0.0)
/*N*/               fFactorX = 1.0 / aSize.GetWidth();
/*N*/
/*N*/           if(aSize.GetHeight() != 0.0)
/*N*/               fFactorY = 1.0 / aSize.GetHeight();
/*N*/
/*N*/           if(aSize.GetDepth() != 0.0)
/*N*/               fFactorZ = 1.0 / aSize.GetDepth();
/*N*/
/*N*/           aTrans.Identity();
/*N*/           aTrans.Scale(fFactorX, -fFactorY, fFactorZ);
/*N*/           aTrans.Translate(Vector3D(0.0, 1.0, 0.0));
/*N*/           aPolyTexture.Transform(aTrans);
/*N*/
/*N*/           AddGeometry(rPolyPoly3D, rFrontNormals, aPolyTexture, TRUE);
/*N*/       }
/*N*/       else
/*N*/           AddGeometry(rPolyPoly3D, rFrontNormals, TRUE);
/*N*/   }
/*N*/   else
/*N*/       AddGeometry(rPolyPoly3D, TRUE);
/*N*/ }

/*N*/ void E3dCompoundObject::AddFrontNormals(
/*N*/   const PolyPolygon3D& rPolyPoly3D,
/*N*/   PolyPolygon3D& rNormalsFront,
/*N*/   Vector3D &rOffset)
/*N*/ {
/*N*/   Vector3D aFrontNormal = -rOffset;
/*N*/   aFrontNormal.Normalize();
/*N*/   USHORT nPolyCnt = rPolyPoly3D.Count();
/*N*/
/*N*/   for(UINT16 a=0;a<nPolyCnt;a++)
/*N*/   {
/*N*/       const Polygon3D& rPoly3D = rPolyPoly3D[a];
/*N*/       Polygon3D& rNormalPoly = rNormalsFront[a];
/*N*/       USHORT nPntCnt = rPoly3D.GetPointCount();
/*N*/
/*N*/       for(UINT16 b=0;b<nPntCnt;b++)
/*N*/       {
/*N*/           rNormalPoly[b] += aFrontNormal;
/*N*/           rNormalPoly[b].Normalize();
/*N*/       }
/*N*/   }
/*N*/ }

/*N*/ void E3dCompoundObject::CreateBack(
/*N*/   const PolyPolygon3D& rPolyPoly3D,
/*N*/   const PolyPolygon3D& rBackNormals,
/*N*/   BOOL bInCreateNormals,
/*N*/   BOOL bInCreateTexture)
/*N*/ {
/*N*/   // PolyPolygon umdrehen
/*N*/   PolyPolygon3D aLocalPoly = rPolyPoly3D;
/*N*/   aLocalPoly.FlipDirections();
/*N*/
/*N*/   // Rueckseite
/*N*/   if(bInCreateNormals)
/*N*/   {
/*N*/       PolyPolygon3D aLocalNormals = rBackNormals;
/*N*/       aLocalNormals.FlipDirections();
/*N*/       if(bInCreateTexture)
/*N*/       {
/*N*/           // Polygon fuer die Textur erzeugen
/*N*/           PolyPolygon3D aPolyTexture(aLocalPoly);
/*N*/           Volume3D aSize = aPolyTexture.GetPolySize();
/*N*/           Matrix4D aTrans;
/*N*/
/*N*/           aTrans.Identity();
/*N*/           aTrans.Translate(-aSize.MinVec());
/*N*/           aPolyTexture.Transform(aTrans);
/*N*/
/*N*/           double fFactorX(1.0), fFactorY(1.0), fFactorZ(1.0);
/*N*/
/*N*/           if(aSize.GetWidth() != 0.0)
/*N*/               fFactorX = 1.0 / aSize.GetWidth();
/*N*/
/*N*/           if(aSize.GetHeight() != 0.0)
/*N*/               fFactorY = 1.0 / aSize.GetHeight();
/*N*/
/*N*/           if(aSize.GetDepth() != 0.0)
/*N*/               fFactorZ = 1.0 / aSize.GetDepth();
/*N*/
/*N*/           aTrans.Identity();
/*N*/           aTrans.Scale(fFactorX, -fFactorY, fFactorZ);
/*N*/           aTrans.Translate(Vector3D(0.0, 1.0, 0.0));
/*N*/           aPolyTexture.Transform(aTrans);
/*N*/
/*N*/           AddGeometry(aLocalPoly, aLocalNormals, aPolyTexture, TRUE);
/*N*/       }
/*N*/       else
/*N*/           AddGeometry(aLocalPoly, aLocalNormals, TRUE);
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       AddGeometry(aLocalPoly, TRUE);
/*N*/   }
/*N*/ }

/*N*/ void E3dCompoundObject::AddBackNormals(
/*N*/   const PolyPolygon3D& rPolyPoly3D,
/*N*/   PolyPolygon3D& rNormalsBack,
/*N*/   Vector3D& rOffset)
/*N*/ {
/*N*/   Vector3D aBackNormal = rOffset;
/*N*/   aBackNormal.Normalize();
/*N*/   USHORT nPolyCnt = rPolyPoly3D.Count();
/*N*/
/*N*/   for(UINT16 a=0;a<nPolyCnt;a++)
/*N*/   {
/*N*/       const Polygon3D& rPoly3D = rPolyPoly3D[a];
/*N*/       Polygon3D& rNormalPoly = rNormalsBack[a];
/*N*/       USHORT nPntCnt = rPoly3D.GetPointCount();
/*N*/
/*N*/       for(UINT16 b=0;b<nPntCnt;b++)
/*N*/       {
/*N*/           rNormalPoly[b] += aBackNormal;
/*N*/           rNormalPoly[b].Normalize();
/*N*/       }
/*N*/   }
/*N*/ }

/*N*/ void E3dCompoundObject::CreateInBetween(
/*N*/   const PolyPolygon3D& rPolyPolyFront,
/*N*/   const PolyPolygon3D& rPolyPolyBack,
/*N*/   const PolyPolygon3D& rFrontNormals,
/*N*/   const PolyPolygon3D& rBackNormals,
/*N*/   BOOL bInCreateNormals,
/*N*/   double fSurroundFactor,
/*N*/   double fTextureStart,
/*N*/   double fTextureDepth,
/*N*/   BOOL bRotateTexture90)
/*N*/ {
/*N*/   USHORT nPolyCnt = rPolyPolyFront.Count();
/*N*/   BOOL bLclCreateTexture = (fTextureDepth == 0.0) ? FALSE : TRUE;
/*N*/   double fPolyLength(0.0), fPolyPos(0.0);
/*N*/   USHORT nLastIndex(0);
/*N*/
/*N*/   // Verbindungsstuecke
/*N*/   if(bInCreateNormals)
/*N*/   {
/*N*/       for(UINT16 a=0;a<nPolyCnt;a++)
/*N*/       {
/*N*/           const Polygon3D& rPoly3DFront = rPolyPolyFront[a];
/*N*/           const Polygon3D& rPoly3DBack = rPolyPolyBack[a];
/*N*/
/*N*/           const Polygon3D& rPolyNormalsFront = rFrontNormals[a];
/*N*/           const Polygon3D& rPolyNormalsBack = rBackNormals[a];
/*N*/
/*N*/           Polygon3D   aRect3D(4);
/*N*/           Polygon3D   aNormal3D(4);
/*N*/           Polygon3D   aTexture3D(4);
/*N*/           USHORT nPntCnt = rPoly3DFront.GetPointCount();
/*N*/           USHORT nPrefillIndex = rPoly3DFront.IsClosed() ? nPntCnt - 1 : 0;
/*N*/
/*N*/           aRect3D[3] = rPoly3DFront[nPrefillIndex];
/*N*/           aRect3D[2] = rPoly3DBack[nPrefillIndex];
/*N*/           aNormal3D[3] = rPolyNormalsFront[nPrefillIndex];
/*N*/           aNormal3D[2] = rPolyNormalsBack[nPrefillIndex];
/*N*/
/*N*/           if(bLclCreateTexture)
/*N*/           {
/*N*/               fPolyLength = rPoly3DFront.GetLength();
/*N*/               fPolyPos = 0.0;
/*N*/               nLastIndex = rPoly3DFront.IsClosed() ? nPntCnt - 1 : 0;
/*N*/
/*N*/               if(bRotateTexture90)
/*N*/               {
/*N*/                   // X,Y vertauschen
/*N*/                   aTexture3D[3].X() = fTextureStart;
/*N*/                   aTexture3D[3].Y() = (1.0 - fPolyPos) * fSurroundFactor;
/*N*/
/*N*/                   aTexture3D[2].X() = fTextureStart + fTextureDepth;
/*N*/                   aTexture3D[2].Y() = (1.0 - fPolyPos) * fSurroundFactor;
/*N*/               }
/*N*/               else
/*N*/               {
/*N*/                   aTexture3D[3].X() = fPolyPos * fSurroundFactor;
/*N*/                   aTexture3D[3].Y() = fTextureStart;
/*N*/
/*N*/                   aTexture3D[2].X() = fPolyPos * fSurroundFactor;
/*N*/                   aTexture3D[2].Y() = fTextureStart + fTextureDepth;
/*N*/               }
/*N*/           }
/*N*/
/*N*/           for (USHORT i = rPoly3DFront.IsClosed() ? 0 : 1; i < nPntCnt; i++)
/*N*/           {
/*N*/               aRect3D[0] = aRect3D[3];
/*N*/               aRect3D[1] = aRect3D[2];
/*N*/
/*N*/               aRect3D[3] = rPoly3DFront[i];
/*N*/               aRect3D[2] = rPoly3DBack[i];
/*N*/
/*N*/               aNormal3D[0] = aNormal3D[3];
/*N*/               aNormal3D[1] = aNormal3D[2];
/*N*/
/*N*/               aNormal3D[3] = rPolyNormalsFront[i];
/*N*/               aNormal3D[2] = rPolyNormalsBack[i];
/*N*/
/*N*/               if(bLclCreateTexture)
/*N*/               {
/*N*/                   // Texturkoordinaten ermitteln
/*N*/                   Vector3D aPart = rPoly3DFront[i] - rPoly3DFront[nLastIndex];
/*N*/                   fPolyPos += aPart.GetLength() / fPolyLength;
/*N*/                   nLastIndex = i;
/*N*/
/*N*/                   // Der Abschnitt am Polygon entspricht dem Teil
/*N*/                   // von fPolyPos bis fPolyPos+fPartLength
/*N*/
/*N*/                   aTexture3D[0] = aTexture3D[3];
/*N*/                   aTexture3D[1] = aTexture3D[2];
/*N*/
/*N*/                   if(bRotateTexture90)
/*N*/                   {
/*N*/                       // X,Y vertauschen
/*N*/                       aTexture3D[3].X() = fTextureStart;
/*N*/                       aTexture3D[3].Y() = (1.0 - fPolyPos) * fSurroundFactor;
/*N*/
/*N*/                       aTexture3D[2].X() = fTextureStart + fTextureDepth;
/*N*/                       aTexture3D[2].Y() = (1.0 - fPolyPos) * fSurroundFactor;
/*N*/                   }
/*N*/                   else
/*N*/                   {
/*N*/                       aTexture3D[3].X() = fPolyPos * fSurroundFactor;
/*N*/                       aTexture3D[3].Y() = fTextureStart;
/*N*/
/*N*/                       aTexture3D[2].X() = fPolyPos * fSurroundFactor;
/*N*/                       aTexture3D[2].Y() = fTextureStart + fTextureDepth;
/*N*/                   }
/*N*/
/*N*/                   AddGeometry(aRect3D, aNormal3D, aTexture3D, FALSE);
/*N*/               }
/*N*/               else
/*N*/                   AddGeometry(aRect3D, aNormal3D, FALSE);
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       for(UINT16 a=0;a<nPolyCnt;a++)
/*N*/       {
/*N*/           const Polygon3D& rPoly3DFront = rPolyPolyFront[a];
/*N*/           const Polygon3D& rPoly3DBack = rPolyPolyBack[a];
/*N*/           Polygon3D   aRect3D(4);
/*N*/           USHORT nPntCnt = rPoly3DFront.GetPointCount();
/*N*/           USHORT nPrefillIndex = rPoly3DFront.IsClosed() ? nPntCnt - 1 : 0;
/*N*/
/*N*/           aRect3D[3] = rPoly3DFront[nPrefillIndex];
/*N*/           aRect3D[2] = rPoly3DBack[nPrefillIndex];
/*N*/
/*N*/           for (USHORT i = rPoly3DFront.IsClosed() ? 0 : 1; i < nPntCnt; i++)
/*N*/           {
/*N*/               aRect3D[0] = aRect3D[3];
/*N*/               aRect3D[1] = aRect3D[2];
/*N*/
/*N*/               aRect3D[3] = rPoly3DFront[i];
/*N*/               aRect3D[2] = rPoly3DBack[i];
/*N*/
/*N*/               AddGeometry(aRect3D, FALSE);
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/ }

/*N*/ void E3dCompoundObject::AddInBetweenNormals(
/*N*/   const PolyPolygon3D& rPolyPolyFront,
/*N*/   const PolyPolygon3D& rPolyPolyBack,
/*N*/   PolyPolygon3D& rNormals,
/*N*/   BOOL bSmoothed)
/*N*/ {
/*N*/   USHORT nPolyCnt = rPolyPolyFront.Count();
/*N*/
/*N*/   // Verbindungsstuecke
/*N*/   for(UINT16 a=0;a<nPolyCnt;a++)
/*N*/   {
/*N*/       const Polygon3D& rPoly3DFront = rPolyPolyFront[a];
/*N*/       const Polygon3D& rPoly3DBack = rPolyPolyBack[a];
/*N*/       Polygon3D& rNormalPoly = rNormals[a];
/*N*/       USHORT nPntCnt = rPoly3DFront.GetPointCount();
/*N*/
/*N*/       if(rPoly3DBack.IsClosed())
/*N*/       {
/*N*/           Vector3D aNormal = (rPoly3DBack[nPntCnt - 1] - rPoly3DFront[nPntCnt - 1])
/*N*/                     |(rPoly3DFront[0] - rPoly3DFront[nPntCnt - 1]);
/*N*/           aNormal.Normalize();
/*N*/           for (USHORT i = 0; i < nPntCnt; i++)
/*N*/           {
/*N*/               Vector3D aNextNormal = (rPoly3DBack[i] - rPoly3DFront[i])
/*N*/                   |(rPoly3DFront[(i+1 == nPntCnt) ? 0 : i+1] - rPoly3DFront[i]);
/*N*/               aNextNormal.Normalize();
/*N*/               if(bSmoothed)
/*N*/               {
/*N*/                   Vector3D aMidNormal = aNormal + aNextNormal;
/*N*/                   aMidNormal.Normalize();
/*N*/                   rNormalPoly[i] += aMidNormal;
/*N*/               }
/*N*/               else
/*N*/                   rNormalPoly[i] += aNormal;
/*N*/               rNormalPoly[i].Normalize();
/*N*/               aNormal = aNextNormal;
/*N*/           }
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           Vector3D aNormal;
/*N*/           if(rPoly3DBack[0] == rPoly3DFront[0])
/*N*/           {
/*N*/               aNormal = (rPoly3DBack[1] - rPoly3DFront[1])
/*N*/                     |(rPoly3DFront[1] - rPoly3DFront[0]);
/*N*/           }
/*N*/           else
/*N*/           {
/*N*/               aNormal = (rPoly3DBack[0] - rPoly3DFront[0])
/*N*/                     |(rPoly3DFront[1] - rPoly3DFront[0]);
/*N*/           }
/*N*/           aNormal.Normalize();
/*N*/           rNormalPoly[0] += aNormal; rNormalPoly[0].Normalize();
/*N*/           for (USHORT i = 1; i < nPntCnt; i++)
/*N*/           {
/*N*/               Vector3D aNextNormal;
/*N*/               if(i+1 == nPntCnt)
/*N*/               {
/*N*/                   aNextNormal = aNormal;
/*N*/               }
/*N*/               else
/*N*/               {
/*N*/                   aNextNormal = (rPoly3DBack[i] - rPoly3DFront[i])
/*N*/                       |(rPoly3DFront[i+1] - rPoly3DFront[i]);
/*N*/               }
/*N*/               aNextNormal.Normalize();
/*N*/               if(bSmoothed)
/*N*/               {
/*N*/                   Vector3D aMidNormal = aNormal + aNextNormal;
/*N*/                   aMidNormal.Normalize();
/*N*/                   rNormalPoly[i] += aMidNormal;
/*N*/               }
/*N*/               else
/*N*/                   rNormalPoly[i] += aNormal;
/*N*/               rNormalPoly[i].Normalize();
/*N*/               aNormal = aNextNormal;
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* Hittest fuer 3D-Objekte, wird an Geometrie weitergegeben
|*
\************************************************************************/

/*N*/ SdrObject* E3dCompoundObject::CheckHit(const Point& rPnt, USHORT nTol,
/*N*/   const SetOfByte* /*pVisiLayer*/) const
/*N*/ {
/*N*/   E3dPolyScene* pScene = (E3dPolyScene*)GetScene();
/*N*/   if(pScene)
/*N*/   {
/*N*/       // HitLine holen in ObjektKoordinaten
/*N*/       // ObjectTrans setzen
/*N*/       Matrix4D mTransform = ((E3dCompoundObject*)this)->GetFullTransform();
/*N*/       pScene->GetCameraSet().SetObjectTrans(mTransform);
/*N*/
/*N*/       // HitPoint Front und Back erzeugen und umrechnen
/*N*/       Vector3D aFront(rPnt.X(), rPnt.Y(), 0.0);
/*N*/       Vector3D aBack(rPnt.X(), rPnt.Y(), ZBUFFER_DEPTH_RANGE);
/*N*/       aFront = pScene->GetCameraSet().ViewToObjectCoor(aFront);
/*N*/       aBack = pScene->GetCameraSet().ViewToObjectCoor(aBack);
/*N*/
/*N*/       const Volume3D& rBoundVol = ((E3dCompoundObject*)this)->GetBoundVolume();
/*N*/       if(rBoundVol.IsValid())
/*N*/       {
/*N*/           double fXMax = aFront.X();
/*N*/           double fXMin = aBack.X();
/*N*/
/*N*/           if(fXMax < fXMin)
/*N*/           {
/*N*/               fXMax = aBack.X();
/*N*/               fXMin = aFront.X();
/*N*/           }
/*N*/
/*N*/           if(rBoundVol.MinVec().X() <= fXMax && rBoundVol.MaxVec().X() >= fXMin)
/*N*/           {
/*N*/               double fYMax = aFront.Y();
/*N*/               double fYMin = aBack.Y();
/*N*/
/*N*/               if(fYMax < fYMin)
/*N*/               {
/*N*/                   fYMax = aBack.Y();
/*N*/                   fYMin = aFront.Y();
/*N*/               }
/*N*/
/*N*/               if(rBoundVol.MinVec().Y() <= fYMax && rBoundVol.MaxVec().Y() >= fYMin)
/*N*/               {
/*N*/                   double fZMax = aFront.Z();
/*N*/                   double fZMin = aBack.Z();
/*N*/
/*N*/                   if(fZMax < fZMin)
/*N*/                   {
/*N*/                       fZMax = aBack.Z();
/*N*/                       fZMin = aFront.Z();
/*N*/                   }
/*N*/
/*N*/                   if(rBoundVol.MinVec().Z() <= fZMax && rBoundVol.MaxVec().Z() >= fZMin)
/*N*/                   {
/*N*/                       // Geometrie herstellen
/*N*/                       if(!bGeometryValid)
/*?*/                           ((E3dCompoundObject*)this)->ReCreateGeometry();
/*N*/
/*N*/                       // 3D Volumes schneiden sich, teste in der Geometrie
/*N*/                       // auf Basis der Projektion weiter
/*N*/                       if(((E3dCompoundObject*)this)->aDisplayGeometry.CheckHit(aFront, aBack, nTol) == sal_True)
/*?*/                           return ((E3dCompoundObject*)this);
/*N*/                   }
/*N*/               }
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/   return NULL;
/*N*/ }

/*************************************************************************
|*
|* Create vertical polygons for line polygon
|*
\************************************************************************/

// #78972#
/*N*/ void E3dCompoundObject::ImpCompleteLinePolygon(PolyPolygon3D& rLinePolyPoly,
/*N*/   sal_uInt16 nPolysPerRun, BOOL bClosed)
/*N*/ {
/*N*/   if(rLinePolyPoly.Count() && nPolysPerRun)
/*N*/   {
/*N*/       // get number of layers
/*N*/       sal_uInt16 nLayers(rLinePolyPoly.Count() / nPolysPerRun);
/*N*/       sal_uInt16 a, b, c;
/*N*/
/*N*/       // add vertical Polygons if at least two horizontal ones exist
/*N*/       if(nLayers > 1)
/*N*/       {
/*N*/           for(a = 0; a < nPolysPerRun; a++)
/*N*/           {
/*N*/               const sal_uInt16 nPntCnt = rLinePolyPoly[a].GetPointCount();
/*N*/
/*N*/               for(b = 0; b < nPntCnt; b++)
/*N*/               {
/*N*/                   Polygon3D aNewVerPoly(bClosed ? nLayers + 1 : nLayers);
/*N*/
/*N*/                   for(c = 0; c < nLayers; c++)
/*N*/                       aNewVerPoly[c] = rLinePolyPoly[(c * nPolysPerRun) + a][b];
/*N*/
/*N*/                   // evtl. set first point again to close polygon
/*N*/                   if(bClosed)
/*N*/                       aNewVerPoly[aNewVerPoly.GetPointCount()] = aNewVerPoly[0];
/*N*/
/*N*/                   // insert
/*N*/                   rLinePolyPoly.Insert(aNewVerPoly);
/*N*/               }
/*N*/           }
/*N*/       }
/*N*/
/*N*/       // open closed polygons
/*N*/       for(a = 0; a < rLinePolyPoly.Count(); a++)
/*N*/       {
/*N*/           if(rLinePolyPoly[a].IsClosed())
/*N*/           {
/*N*/               rLinePolyPoly[a][rLinePolyPoly[a].GetPointCount()] = rLinePolyPoly[a][0];
/*N*/               rLinePolyPoly[a].SetClosed(FALSE);
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/ }
/*N*/
/*************************************************************************
|*
|* Ein Segment fuer Extrude oder Lathe erzeugen
|*
\************************************************************************/

/*N*/ void E3dCompoundObject::ImpCreateSegment(
/*N*/   const PolyPolygon3D& rFront,        // vorderes Polygon
/*N*/   const PolyPolygon3D& rBack,         // hinteres Polygon
/*N*/   const PolyPolygon3D* pPrev,         // smooth uebergang zu Vorgaenger
/*N*/   const PolyPolygon3D* pNext,         // smooth uebergang zu Nachfolger
/*N*/   BOOL bCreateFront,                  // vorderen Deckel erzeugen
/*N*/   BOOL bCreateBack,                   // hinteren Deckel erzeugen
/*N*/   double fPercentDiag,                // Anteil des Deckels an der Tiefe
/*N*/   BOOL bSmoothLeft,                   // Glaetten der umlaufenden Normalen links
/*N*/   BOOL bSmoothRight,                  // Glaetten der umlaufenden Normalen rechts
/*N*/   BOOL bSmoothFrontBack,              // Glaetten der Abschlussflaechen
/*N*/   double fSurroundFactor,             // Wertebereich der Texturkoordinaten im Umlauf
/*N*/   double fTextureStart,               // TexCoor ueber Extrude-Tiefe
/*N*/   double fTextureDepth,               // TexCoor ueber Extrude-Tiefe
/*N*/   BOOL bInCreateTexture,
/*N*/   BOOL bInCreateNormals,
/*N*/   BOOL bCharacterExtrude,             // FALSE=exakt, TRUE=ohne Ueberschneidungen
/*N*/   BOOL bRotateTexture90,              // Textur der Seitenflaechen um 90 Grad kippen
/*N*/   PolyPolygon3D* pLineGeometry        // For creation of line geometry
/*N*/   )
/*N*/ {
/*N*/   PolyPolygon3D aNormalsLeft, aNormalsRight;
/*N*/   AddInBetweenNormals(rFront, rBack, aNormalsLeft, bSmoothLeft);
/*N*/   AddInBetweenNormals(rFront, rBack, aNormalsRight, bSmoothRight);
/*N*/   Vector3D aOffset = rBack.GetMiddle() - rFront.GetMiddle();
/*N*/
/*N*/   // Ausnahmen: Nicht geschlossen
/*N*/   if(!rFront.IsClosed())
/*N*/   {
/*N*/       bCreateFront = FALSE;
/*N*/   }
/*N*/   if(!rBack.IsClosed())
/*N*/   {
/*N*/       bCreateBack = FALSE;
/*N*/   }
/*N*/
/*N*/   // Ausnahmen: Einfache Linie
/*N*/   if(rFront[0].GetPointCount() < 3 || (!bCreateFront && !bCreateBack))
/*N*/   {
/*N*/       fPercentDiag = 0.0;
/*N*/   }
/*N*/
/*N*/   if(fPercentDiag == 0.0)
/*N*/   {
/*N*/       // Ohne Schraegen, Vorderseite
/*N*/       if(bCreateFront)
/*N*/       {
/*N*/           PolyPolygon3D aNormalsFront;
/*N*/           AddFrontNormals(rFront, aNormalsFront, aOffset);
/*N*/
/*N*/           if(!bSmoothFrontBack)
/*N*/               CreateFront(rFront, aNormalsFront, bInCreateNormals, bInCreateTexture);
/*N*/           if(bSmoothLeft)
/*N*/               AddFrontNormals(rFront, aNormalsLeft, aOffset);
/*N*/           if(bSmoothFrontBack)
/*?*/               CreateFront(rFront, aNormalsLeft, bInCreateNormals, bInCreateTexture);
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           if(pPrev)
/*N*/               AddInBetweenNormals(*pPrev, rFront, aNormalsLeft, bSmoothLeft);
/*N*/       }
/*N*/
/*N*/       // Ohne Schraegen, Rueckseite
/*N*/       if(bCreateBack)
/*N*/       {
/*N*/           PolyPolygon3D aNormalsBack;
/*N*/           AddBackNormals(rBack, aNormalsBack, aOffset);
/*N*/
/*N*/           if(!bSmoothFrontBack)
/*N*/               CreateBack(rBack, aNormalsBack, bInCreateNormals, bInCreateTexture);
/*N*/           if(bSmoothRight)
/*N*/               AddBackNormals(rBack, aNormalsRight, aOffset);
/*N*/           if(bSmoothFrontBack)
/*?*/               CreateBack(rBack, aNormalsRight, bInCreateNormals, bInCreateTexture);
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           if(pNext)
/*N*/               AddInBetweenNormals(rBack, *pNext, aNormalsRight, bSmoothRight);
/*N*/       }
/*N*/
/*N*/       // eigentliches Zwischenstueck
/*N*/       CreateInBetween(rFront, rBack,
/*N*/           aNormalsLeft, aNormalsRight,
/*N*/           bInCreateNormals,
/*N*/           fSurroundFactor,
/*N*/           fTextureStart,
/*N*/           fTextureDepth,
/*N*/           bRotateTexture90);
/*N*/
/*N*/       // #78972#
/*N*/       if(pLineGeometry)
/*N*/       {
/*N*/           pLineGeometry->Insert(rFront);
/*N*/           if(bCreateBack)
/*N*/               pLineGeometry->Insert(rBack);
/*N*/       }
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       // Mit Scraegen, Vorderseite
/*N*/       PolyPolygon3D aLocalFront = rFront;
/*N*/       PolyPolygon3D aLocalBack = rBack;
/*N*/       double fExtrudeDepth, fDiagLen = 0.0;
/*N*/       double fTexMidStart = fTextureStart;
/*N*/       double fTexMidDepth = fTextureDepth;
/*N*/
/*N*/       if(bCreateFront || bCreateBack)
/*N*/       {
/*N*/           fExtrudeDepth = aOffset.GetLength();
/*N*/           fDiagLen = fPercentDiag * fExtrudeDepth;
/*N*/       }
/*N*/
/*N*/       PolyPolygon3D aOuterFront;
/*N*/       PolyPolygon3D aOuterBack;
/*N*/
/*N*/       if(bCreateFront)
/*N*/       {
/*N*/           PolyPolygon3D aNormalsOuterFront;
/*N*/           AddFrontNormals(aLocalFront, aNormalsOuterFront, aOffset);
/*N*/
/*N*/           if(bCharacterExtrude)
/*N*/           {
/*N*/               // Polygon kopieren
/*N*/               aOuterFront = aLocalFront;
/*N*/
/*N*/               // notwendige Normalen erzeugen
/*N*/               PolyPolygon3D aGrowDirection;
/*N*/               AddInBetweenNormals(aLocalFront, aLocalBack, aGrowDirection, bSmoothLeft);
/*N*/
/*N*/               // Groesse inneres Polygon merken
/*N*/               Volume3D aOldSize(aLocalFront.GetPolySize());
/*N*/
/*N*/               // Inneres Polygon vergroessern
/*N*/               GrowPoly(aLocalFront, aGrowDirection, fDiagLen);
/*N*/
/*N*/               // Inneres Polygon nach innen verschieben
/*N*/               //GrowPoly(aLocalFront, aNormalsOuterFront, -fDiagLen);
/*N*/
/*N*/               // Neue Groesse inneres Polygon feststellen
/*N*/               Volume3D aNewSize(aLocalFront.GetPolySize());
/*N*/
/*N*/               // Skalierung feststellen (nur X,Y)
/*N*/               Vector3D aScaleVec(
/*N*/                   (aNewSize.GetWidth() != 0.0) ? aOldSize.GetWidth() / aNewSize.GetWidth() : 1.0,
/*N*/                   (aNewSize.GetHeight() != 0.0) ? aOldSize.GetHeight() / aNewSize.GetHeight() : 1.0,
/*N*/                   (aNewSize.GetDepth() != 0.0) ? aOldSize.GetDepth() / aNewSize.GetDepth() : 1.0);
/*N*/
/*N*/               // Transformation bilden
/*N*/               Matrix4D aTransMat;
/*N*/               aTransMat.Scale(aScaleVec);
/*N*/
/*N*/               // aeusseres und inneres Polygon skalieren
/*N*/               aLocalFront.Transform(aTransMat);
/*N*/               aOuterFront.Transform(aTransMat);
/*N*/
/*N*/               // Neue Groesse aktualisieren
/*N*/               aNewSize = aLocalFront.GetPolySize();
/*N*/
/*N*/               // Translation feststellen
/*N*/               Vector3D aTransVec(
/*N*/                   aOldSize.MinVec().X() - aNewSize.MinVec().X(),
/*N*/                   aOldSize.MinVec().Y() - aNewSize.MinVec().Y(),
/*N*/                   aOldSize.MinVec().Z() - aNewSize.MinVec().Z());
/*N*/
/*N*/               // Transformation bilden
/*N*/               aTransMat.Identity();
/*N*/               aTransMat.Translate(aTransVec);
/*N*/
/*N*/               // aeusseres und inneres Polygon skalieren
/*N*/               aLocalFront.Transform(aTransMat);
/*N*/               aOuterFront.Transform(aTransMat);
/*N*/
/*N*/               // move aLocalFront again, scale and translate has moved it back
/*N*/               GrowPoly(aLocalFront, aNormalsOuterFront, -fDiagLen);
/*N*/           }
/*N*/           else
/*N*/           {
/*N*/               // Polygon kopieren
/*N*/               aOuterFront = aLocalFront;
/*N*/
/*N*/               // notwendige Normalen erzeugen
/*N*/               PolyPolygon3D aGrowDirection;
/*N*/               AddInBetweenNormals(aLocalFront, aLocalBack, aGrowDirection, bSmoothLeft);
/*N*/
/*N*/               // Aeusseres Polygon verkleinern
/*N*/               GrowPoly(aOuterFront, aGrowDirection, -fDiagLen);
/*N*/               aOuterFront.CorrectGrownPoly(aLocalFront);
/*N*/
/*N*/               // Inneres Polygon nach innen verschieben
/*N*/               GrowPoly(aLocalFront, aNormalsOuterFront, -fDiagLen);
/*N*/           }
/*N*/
/*N*/           // eventuell noch glaetten
/*N*/           if(bSmoothLeft)
/*N*/           {
/*N*/               if(bSmoothFrontBack)
/*?*/                   AddInBetweenNormals(aOuterFront, aLocalFront, aNormalsOuterFront, bSmoothLeft);
/*N*/               AddInBetweenNormals(aOuterFront, aLocalFront, aNormalsLeft, bSmoothLeft);
/*N*/           }
/*N*/
/*N*/           // vordere Zwischenstuecke erzeugen
/*N*/           CreateInBetween(aOuterFront, aLocalFront,
/*N*/               aNormalsOuterFront, aNormalsLeft,
/*N*/               bInCreateNormals,
/*N*/               fSurroundFactor,
/*N*/               fTextureStart,
/*N*/               fTextureDepth * fPercentDiag,
/*N*/               bRotateTexture90);
/*N*/
/*N*/           // Vorderseite erzeugen
/*N*/           CreateFront(aOuterFront, aNormalsOuterFront, bInCreateNormals, bInCreateTexture);
/*N*/
/*N*/           // Weitere Texturwerte setzen
/*N*/           fTexMidStart += fTextureDepth * fPercentDiag;
/*N*/           fTexMidDepth -= fTextureDepth * fPercentDiag;
/*N*/       }
/*N*/       else
/*N*/       {
/*?*/           if(pPrev)
/*?*/               AddInBetweenNormals(*pPrev, rFront, aNormalsLeft, bSmoothLeft);
/*N*/       }
/*N*/
/*N*/       // Mit Scraegen, Rueckseite
/*N*/       if(bCreateBack)
/*N*/       {
/*N*/           PolyPolygon3D aNormalsOuterBack;
/*N*/           AddBackNormals(aLocalBack, aNormalsOuterBack, aOffset);
/*N*/
/*N*/           if(bCharacterExtrude)
/*N*/           {
/*N*/               // Polygon kopieren
/*N*/               aOuterBack = aLocalBack;
/*N*/
/*N*/               // notwendige Normalen erzeugen
/*N*/               PolyPolygon3D aGrowDirection;
/*N*/               AddInBetweenNormals(aLocalFront, aLocalBack, aGrowDirection, bSmoothRight);
/*N*/
/*N*/               // Groesse inneres Polygon merken
/*N*/               Volume3D aOldSize(aLocalBack.GetPolySize());
/*N*/
/*N*/               // Inneres Polygon vergroessern
/*N*/               GrowPoly(aLocalBack, aGrowDirection, fDiagLen);
/*N*/
/*N*/               // Inneres Polygon nach innen verschieben
/*N*/               //GrowPoly(aLocalBack, aNormalsOuterBack, -fDiagLen);
/*N*/
/*N*/               // Neue Groesse inneres Polygon feststellen
/*N*/               Volume3D aNewSize(aLocalBack.GetPolySize());
/*N*/
/*N*/               // Skalierung feststellen (nur X,Y)
/*N*/               Vector3D aScaleVec(
/*N*/                   (aNewSize.GetWidth() != 0.0) ? aOldSize.GetWidth() / aNewSize.GetWidth() : 1.0,
/*N*/                   (aNewSize.GetHeight() != 0.0) ? aOldSize.GetHeight() / aNewSize.GetHeight() : 1.0,
/*N*/                   (aNewSize.GetDepth() != 0.0) ? aOldSize.GetDepth() / aNewSize.GetDepth() : 1.0);
/*N*/
/*N*/               // Transformation bilden
/*N*/               Matrix4D aTransMat;
/*N*/               aTransMat.Scale(aScaleVec);
/*N*/
/*N*/               // aeusseres und inneres Polygon skalieren
/*N*/               aLocalBack.Transform(aTransMat);
/*N*/               aOuterBack.Transform(aTransMat);
/*N*/
/*N*/               // Neue Groesse aktualisieren
/*N*/               aNewSize = aLocalBack.GetPolySize();
/*N*/
/*N*/               // Translation feststellen
/*N*/               Vector3D aTransVec(
/*N*/                   aOldSize.MinVec().X() - aNewSize.MinVec().X(),
/*N*/                   aOldSize.MinVec().Y() - aNewSize.MinVec().Y(),
/*N*/                   aOldSize.MinVec().Z() - aNewSize.MinVec().Z());
/*N*/
/*N*/               // Transformation bilden
/*N*/               aTransMat.Identity();
/*N*/               aTransMat.Translate(aTransVec);
/*N*/
/*N*/               // aeusseres und inneres Polygon skalieren
/*N*/               aLocalBack.Transform(aTransMat);
/*N*/               aOuterBack.Transform(aTransMat);
/*N*/
/*N*/               // move aLocalBack again, scale and translate has moved it back
/*N*/               GrowPoly(aLocalBack, aNormalsOuterBack, -fDiagLen);
/*N*/           }
/*N*/           else
/*N*/           {
/*N*/               // Polygon kopieren
/*N*/               aOuterBack = aLocalBack;
/*N*/
/*N*/               // notwendige Normalen erzeugen
/*N*/               PolyPolygon3D aGrowDirection;
/*N*/               AddInBetweenNormals(aLocalFront, aLocalBack, aGrowDirection, bSmoothRight);
/*N*/
/*N*/               // Aeusseres Polygon verkleinern
/*N*/               GrowPoly(aOuterBack, aGrowDirection, -fDiagLen);
/*N*/               aOuterBack.CorrectGrownPoly(aLocalBack);
/*N*/
/*N*/               // Inneres Polygon nach innen verschieben
/*N*/               GrowPoly(aLocalBack, aNormalsOuterBack, -fDiagLen);
/*N*/           }
/*N*/
/*N*/           // eventuell noch glaetten
/*N*/           if(bSmoothRight)
/*N*/           {
/*N*/               if(bSmoothFrontBack)
/*?*/                   AddInBetweenNormals(aLocalBack, aOuterBack, aNormalsOuterBack, bSmoothRight);
/*N*/               AddInBetweenNormals(aLocalBack, aOuterBack, aNormalsRight, bSmoothRight);
/*N*/           }
/*N*/
/*N*/           // vordere Zwischenstuecke erzeugen
/*N*/           // hintere Zwischenstuecke erzeugen
/*N*/           CreateInBetween(aLocalBack, aOuterBack,
/*N*/               aNormalsRight, aNormalsOuterBack,
/*N*/               bInCreateNormals,
/*N*/               fSurroundFactor,
/*N*/               fTextureStart + (fTextureDepth * (1.0 - fPercentDiag)),
/*N*/               fTextureDepth * fPercentDiag,
/*N*/               bRotateTexture90);
/*N*/
/*N*/           // Rueckseite erzeugen
/*N*/           CreateBack(aOuterBack, aNormalsOuterBack, bInCreateNormals, bInCreateTexture);
/*N*/
/*N*/           // Weitere Texturwerte setzen
/*N*/           fTexMidDepth -= fTextureDepth * fPercentDiag;
/*N*/       }
/*N*/       else
/*N*/       {
/*?*/           if(pNext)
/*?*/               AddInBetweenNormals(rBack, *pNext, aNormalsRight, bSmoothRight);
/*?*/       }
/*N*/
/*N*/       // eigentliches Zwischenstueck
/*N*/       CreateInBetween(aLocalFront, aLocalBack,
/*N*/           aNormalsLeft, aNormalsRight,
/*N*/           bInCreateNormals,
/*N*/           fSurroundFactor,
/*N*/           fTexMidStart,
/*N*/           fTexMidDepth,
/*N*/           bRotateTexture90);
/*N*/
/*N*/       // #78972#
/*N*/       if(pLineGeometry)
/*N*/       {
/*N*/           if(bCreateFront)
/*N*/               pLineGeometry->Insert(aOuterFront);
/*N*/           pLineGeometry->Insert(aLocalFront);
/*N*/           if(bCreateBack)
/*N*/           {
/*N*/               pLineGeometry->Insert(aLocalBack);
/*N*/               pLineGeometry->Insert(aOuterBack);
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* DisplayGeometry rausruecken
|*
\************************************************************************/

/*N*/ B3dGeometry& E3dCompoundObject::GetDisplayGeometry()
/*N*/ {
/*N*/   // Geometrie herstellen
/*N*/   if(!bGeometryValid)
/*?*/       ReCreateGeometry();
/*N*/
/*N*/   return aDisplayGeometry;
/*N*/ }

/*************************************************************************
|*
|* Material des Objektes
|*
\************************************************************************/

/*N*/ void E3dCompoundObject::SetMaterialAmbientColor(const Color& rColor)
/*N*/ {
/*N*/   if(aMaterialAmbientColor != rColor)
/*N*/   {
/*?*/       aMaterialAmbientColor = rColor;
/*N*/   }
/*N*/ }

/*************************************************************************
|*
|* Attribute setzen
|*
\************************************************************************/

// private support routines for ItemSet access. NULL pointer means clear item.
/*N*/ void E3dCompoundObject::PostItemChange(const sal_uInt16 nWhich)
/*N*/ {
/*N*/   // call parent
/*N*/   E3dObject::PostItemChange(nWhich);
/*N*/
/*N*/   // handle value change
/*N*/   switch(nWhich)
/*N*/   {
/*N*/       case SDRATTR_3DOBJ_DOUBLE_SIDED:
/*N*/       {
/*N*/           bGeometryValid = FALSE;
/*N*/           break;
/*N*/       }
/*N*/       case SDRATTR_3DOBJ_NORMALS_KIND:
/*N*/       {
/*N*/           bGeometryValid = FALSE;
/*N*/           break;
/*N*/       }
/*N*/       case SDRATTR_3DOBJ_NORMALS_INVERT:
/*N*/       {
/*N*/           bGeometryValid = FALSE;
/*N*/           break;
/*N*/       }
/*N*/       case SDRATTR_3DOBJ_TEXTURE_PROJ_X:
/*N*/       {
/*N*/           bGeometryValid = FALSE;
/*N*/           break;
/*N*/       }
/*N*/       case SDRATTR_3DOBJ_TEXTURE_PROJ_Y:
/*N*/       {
/*N*/           bGeometryValid = FALSE;
/*N*/           break;
/*N*/       }
/*N*/   }
/*N*/ }

// EOF
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
