summaryrefslogtreecommitdiff
path: root/binfilter/bf_goodies/source/base3d/goodies_b3dgeom.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'binfilter/bf_goodies/source/base3d/goodies_b3dgeom.cxx')
-rw-r--r--binfilter/bf_goodies/source/base3d/goodies_b3dgeom.cxx852
1 files changed, 852 insertions, 0 deletions
diff --git a/binfilter/bf_goodies/source/base3d/goodies_b3dgeom.cxx b/binfilter/bf_goodies/source/base3d/goodies_b3dgeom.cxx
new file mode 100644
index 000000000000..048f66d17eb3
--- /dev/null
+++ b/binfilter/bf_goodies/source/base3d/goodies_b3dgeom.cxx
@@ -0,0 +1,852 @@
+/* -*- 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.
+ *
+ ************************************************************************/
+
+#include "b3dgeom.hxx"
+
+#include "b3dcompo.hxx"
+
+#include "hmatrix.hxx"
+
+#include "base3d.hxx"
+
+#include <tools/debug.hxx>
+
+#ifndef _INC_MATH
+#include <math.h>
+#endif
+
+namespace binfilter {
+/*************************************************************************
+|*
+|* Bucket fuer Index
+|*
+\************************************************************************/
+
+SV_IMPL_VARARR(GeometryIndexValueBucketMemArr, char*)
+GeometryIndexValueBucket::GeometryIndexValueBucket(UINT16 TheSize) {
+ InitializeSize(TheSize);
+}
+void GeometryIndexValueBucket::InitializeSize(UINT16 TheSize) {
+ UINT16 nSiz;
+ for(nShift=0,nSiz=1;nSiz<sizeof(GeometryIndexValue);nSiz<<=1,nShift++);
+ nBlockShift = TheSize - nShift;
+ nMask = (1L << nBlockShift)-1L;
+ nSlotSize = 1<<nShift;
+ nEntriesPerArray = (UINT16)((1L << TheSize) >> nShift);
+ Empty();
+}
+void GeometryIndexValueBucket::operator=(const GeometryIndexValueBucket& rObj) {
+ Erase();
+ GeometryIndexValueBucket& rSrc = (GeometryIndexValueBucket&)rObj;
+ for(UINT32 a=0;a<rSrc.Count();a++)
+ Append(rSrc[a]);
+}
+void GeometryIndexValueBucket::Empty() {
+ for(UINT16 i=0;i<aMemArray.Count();i++)
+ /*#90353#*/ delete [] aMemArray[i];
+ if(aMemArray.Count())
+ aMemArray.Remove(0, aMemArray.Count());
+ nFreeMemArray = 0;
+ nActMemArray = -1;
+ Erase();
+}
+void GeometryIndexValueBucket::Erase() {
+ nFreeEntry = nEntriesPerArray;
+ nCount = 0;
+ nActMemArray = -1;
+}
+GeometryIndexValueBucket::~GeometryIndexValueBucket() {
+ Empty();
+}
+BOOL GeometryIndexValueBucket::ImplAppend(GeometryIndexValue& rVec) {
+ *((GeometryIndexValue*)(aMemArray[nActMemArray] + (nFreeEntry++ << nShift))) = rVec;
+ nCount++;
+ return TRUE;
+}
+BOOL GeometryIndexValueBucket::ImplCareForSpace() {
+ /* neues array bestimmem */
+ if(nActMemArray + 1 < nFreeMemArray) {
+ /* ist scon allokiert, gehe auf naechstes */
+ nActMemArray++;
+ } else {
+ /* neues muss allokiert werden */
+ char* pNew = new char[nEntriesPerArray << nShift];
+ if(!pNew)
+ return FALSE;
+ aMemArray.Insert((const char*&) pNew, aMemArray.Count());
+ nActMemArray = nFreeMemArray++;
+ }
+ nFreeEntry = 0;
+ return TRUE;
+}
+GeometryIndexValue& GeometryIndexValueBucket::operator[] (UINT32 nPos) {
+ if(nPos >= nCount) {
+ DBG_ERROR("Access to Bucket out of range!");
+ return *((GeometryIndexValue*)aMemArray[0]);
+ }
+ return *((GeometryIndexValue*)(aMemArray[(UINT16)(nPos >> nBlockShift)] + ((nPos & nMask) << nShift)));
+}
+
+/*************************************************************************
+|*
+|* Konstruktor
+|*
+\************************************************************************/
+
+B3dGeometry::B3dGeometry()
+: pComplexPolygon(NULL),
+ aEntityBucket(14), // 16K
+ aIndexBucket(8) // 256Byte
+{
+ Reset();
+}
+
+/*************************************************************************
+|*
+|* Ausgangszustand der Variablen herstellen
+|*
+\************************************************************************/
+
+void B3dGeometry::Reset()
+{
+ bHintIsComplex = FALSE;
+ if(pComplexPolygon)
+ delete pComplexPolygon;
+ pComplexPolygon = NULL;
+
+ // #93136# since #92030# uses bOutline flag now as indication
+ // if the filled object is to be drawn, it MUST be initialized now.
+ bOutline = FALSE;
+}
+
+/*************************************************************************
+|*
+|* Freien Eintrag zum fuellen holen
+|*
+\************************************************************************/
+
+B3dEntity& B3dGeometry::GetFreeEntity()
+{
+ aEntityBucket.Append();
+ return aEntityBucket[aEntityBucket.Count() - 1];
+}
+
+/*************************************************************************
+|*
+|* Inhalte loeschen
+|*
+\************************************************************************/
+
+void B3dGeometry::Erase()
+{
+ aEntityBucket.Erase();
+ aIndexBucket.Erase();
+ Reset();
+}
+
+/*************************************************************************
+|*
+|* Start der Geometriebeschreibung
+|*
+\************************************************************************/
+
+void B3dGeometry::StartDescription()
+{
+ Erase();
+}
+
+/*************************************************************************
+|*
+|* Ende der Geometriebeschreibung
+|*
+\************************************************************************/
+
+void B3dGeometry::EndDescription()
+{
+ if(pComplexPolygon)
+ delete pComplexPolygon;
+ pComplexPolygon = NULL;
+}
+
+/*************************************************************************
+|*
+|* Neues Primitiv beginnen
+|*
+\************************************************************************/
+
+void B3dGeometry::StartObject(BOOL bHintComplex, BOOL bOutl)
+{
+ // Hint uebernehmen
+ bHintIsComplex = bHintComplex;
+ bOutline = bOutl;
+
+ // ComplexPolygon anlegen falls nicht vorhanden
+ if(bHintIsComplex)
+ {
+ if(!pComplexPolygon)
+ pComplexPolygon = new B3dComplexPolygon;
+ pComplexPolygon->StartPrimitive();
+ }
+ else
+ {
+ // Direkt neues Polygon beginnen
+ StartPolygon();
+ }
+}
+
+/*************************************************************************
+|*
+|* Primitiv abschliessen
+|*
+\************************************************************************/
+
+void B3dGeometry::EndObject()
+{
+ // Unteren Index holen
+ UINT32 nLow = 0L;
+ if(aIndexBucket.Count())
+ nLow = aIndexBucket[aIndexBucket.Count()-1].GetIndex();
+
+ if(bHintIsComplex)
+ {
+ pComplexPolygon->EndPrimitive(this);
+ }
+ else
+ {
+ // Polygon abschliessen
+ EndPolygon();
+ }
+
+ // EbenenNormale berechnen und setzen; bei Linien und
+ // Punkten wird PlaneNormal auf (0,0,0) gesetzt
+ UINT32 nHigh = aIndexBucket[aIndexBucket.Count()-1].GetIndex();
+ Vector3D aPlaneNormal = -CalcNormal(nLow, nHigh);
+ while(nLow < nHigh)
+ aEntityBucket[nLow++].PlaneNormal() = aPlaneNormal;
+}
+
+/*************************************************************************
+|*
+|* Geometrieuebergabe
+|*
+\************************************************************************/
+
+void B3dGeometry::AddEdge(const Vector3D& rPoint)
+{
+ if(bHintIsComplex)
+ {
+ B3dEntity& rNew = pComplexPolygon->GetFreeEntity();
+
+ rNew.Reset();
+ rNew.Point() = rPoint;
+ rNew.SetValid();
+ rNew.SetEdgeVisible(TRUE);
+
+ pComplexPolygon->PostAddVertex(rNew);
+ }
+ else
+ {
+ B3dEntity& rNew = GetFreeEntity();
+
+ rNew.Reset();
+ rNew.Point() = rPoint;
+ rNew.SetValid();
+ rNew.SetEdgeVisible(TRUE);
+ }
+}
+
+void B3dGeometry::AddEdge(
+ const Vector3D& rPoint,
+ const Vector3D& rNormal)
+{
+ if(bHintIsComplex)
+ {
+ B3dEntity& rNew = pComplexPolygon->GetFreeEntity();
+
+ rNew.Reset();
+ rNew.Point() = rPoint;
+ rNew.SetValid();
+ rNew.Normal() = rNormal;
+ rNew.SetNormalUsed();
+ rNew.SetEdgeVisible(TRUE);
+
+ pComplexPolygon->PostAddVertex(rNew);
+ }
+ else
+ {
+ B3dEntity& rNew = GetFreeEntity();
+
+ rNew.Reset();
+ rNew.Point() = rPoint;
+ rNew.SetValid();
+ rNew.Normal() = rNormal;
+ rNew.SetNormalUsed();
+ rNew.SetEdgeVisible(TRUE);
+ }
+}
+
+void B3dGeometry::AddEdge(
+ const Vector3D& rPoint,
+ const Vector3D& rNormal,
+ const Vector3D& rTexture)
+{
+ if(bHintIsComplex)
+ {
+ B3dEntity& rNew = pComplexPolygon->GetFreeEntity();
+
+ rNew.Reset();
+ rNew.Point() = rPoint;
+ rNew.SetValid();
+ rNew.Normal() = rNormal;
+ rNew.SetNormalUsed();
+ rNew.TexCoor() = rTexture;
+ rNew.SetTexCoorUsed();
+ rNew.SetEdgeVisible(TRUE);
+
+ pComplexPolygon->PostAddVertex(rNew);
+ }
+ else
+ {
+ B3dEntity& rNew = GetFreeEntity();
+
+ rNew.Reset();
+ rNew.Point() = rPoint;
+ rNew.SetValid();
+ rNew.Normal() = rNormal;
+ rNew.SetNormalUsed();
+ rNew.TexCoor() = rTexture;
+ rNew.SetTexCoorUsed();
+ rNew.SetEdgeVisible(TRUE);
+ }
+}
+
+/*************************************************************************
+|*
+|* Copy-Operator
+|*
+\************************************************************************/
+
+void B3dGeometry::operator=(const B3dGeometry& rObj)
+{
+ // Bucket kopieren
+ aEntityBucket = rObj.aEntityBucket;
+ aIndexBucket = rObj.aIndexBucket;
+
+ // ComplexPolygon nicht kopieren
+ pComplexPolygon = NULL;
+
+ // Hint auch nicht
+ bHintIsComplex = FALSE;
+}
+
+/*************************************************************************
+|*
+|* Callbacks bei komplexen Primitiven
+|*
+\************************************************************************/
+
+void B3dGeometry::StartComplexPrimitive()
+{
+ StartPolygon();
+}
+
+void B3dGeometry::EndComplexPrimitive()
+{
+ EndPolygon();
+}
+
+void B3dGeometry::AddComplexVertex(B3dEntity& rNew, BOOL bIsVisible)
+{
+ // Kopieren
+ B3dEntity& rLocal = GetFreeEntity();
+ rLocal = rNew;
+
+ // EdgeFlag anpassen
+ rLocal.SetEdgeVisible(bIsVisible);
+}
+
+/*************************************************************************
+|*
+|* PolygonStart und -Ende aufzeichnen
+|*
+\************************************************************************/
+
+void B3dGeometry::StartPolygon()
+{
+}
+
+void B3dGeometry::EndPolygon()
+{
+ GeometryIndexValue aNewIndex(aEntityBucket.Count());
+ if(bOutline)
+ aNewIndex.SetMode(B3D_INDEX_MODE_LINE);
+ aIndexBucket.Append(aNewIndex);
+}
+
+/*************************************************************************
+|*
+|* Hittest auf Geometrie
+|* Liegt der angegebene Schnittpunkt innerhalb eines der Polygone?
+|*
+\************************************************************************/
+
+sal_Bool B3dGeometry::CheckHit(const Vector3D& rFront, const Vector3D& rBack, sal_uInt16 nTol)
+{
+ sal_uInt32 nPolyCounter(0L);
+ sal_uInt32 nEntityCounter(0L);
+ sal_uInt32 nUpperBound(0L);
+
+ while(nPolyCounter < aIndexBucket.Count())
+ {
+ // Obergrenze neues Polygon holen
+ nUpperBound = aIndexBucket[nPolyCounter++].GetIndex();
+
+ // Hittest fuer momentanes Polygon
+ Vector3D aCut;
+
+ if(CheckSinglePolygonHit(nEntityCounter, nUpperBound, rFront, rBack, aCut))
+ {
+ return sal_True;
+ }
+
+ // Auf naechstes Polygon
+ nEntityCounter = nUpperBound;
+ }
+
+ return sal_False;
+}
+
+sal_Bool B3dGeometry::CheckSinglePolygonHit(UINT32 nLow, UINT32 nHigh, const Vector3D& rFront,
+ const Vector3D& rBack, Vector3D& rCut) const
+{
+ if(nLow + 2 < nHigh)
+ {
+ // calculate cut with plane
+ if(GetCutPoint(nLow, rCut, rFront, rBack))
+ {
+ // cut exists, is it inside the polygon?
+ if(IsInside(nLow, nHigh, rCut))
+ {
+ return sal_True;
+ }
+ }
+ }
+
+ return sal_False;
+}
+
+sal_Bool B3dGeometry::GetCutPoint(UINT32 nLow, Vector3D& rCut, const Vector3D& rFront, const Vector3D& rBack) const
+{
+ BOOL bCutValid = FALSE;
+
+ // Normale und Skalar der Ebenengleichung ermitteln
+ Vector3D aNormal = ((B3dGeometry*)this)->aEntityBucket[nLow].PlaneNormal();
+ double fScalar = -(((B3dGeometry*)this)->aEntityBucket[nLow + 1].Point().GetVector3D().Scalar(aNormal));
+ Vector3D aLineVec = rFront - rBack;
+ double fZwi = aNormal.Scalar(aLineVec);
+
+ if(fabs(fZwi) > SMALL_DVALUE)
+ {
+ fZwi = (-fScalar - (rBack.Scalar(aNormal))) / fZwi;
+ rCut.X() = rBack.X() + (aLineVec.X() * fZwi);
+ rCut.Y() = rBack.Y() + (aLineVec.Y() * fZwi);
+ rCut.Z() = rBack.Z() + (aLineVec.Z() * fZwi);
+
+ bCutValid = TRUE;
+ }
+ return bCutValid;
+}
+
+sal_Bool B3dGeometry::IsInside(UINT32 nLow, UINT32 nHigh, const Vector3D& rPnt) const
+{
+ BOOL bInside(FALSE);
+ B3dVolume aVolume;
+
+ // Volume von genau dieser Flaeche feststellen
+ for(UINT32 a=nLow;a<nHigh;a++)
+ aVolume.Union(((B3dGeometry*)this)->aEntityBucket[a].Point().GetVector3D());
+
+ // Hier eigentlich ein aVolume.IsInside(rPnt), doch da hier ein
+ // Vergleich mit Epsilon-Umgebung gebraucht wird, vergleiche selbst
+ BOOL bIsInside =
+ (rPnt.X() + SMALL_DVALUE >= aVolume.MinVec().X() && rPnt.X() - SMALL_DVALUE <= aVolume.MaxVec().X()
+ && rPnt.Y() + SMALL_DVALUE >= aVolume.MinVec().Y() && rPnt.Y() - SMALL_DVALUE <= aVolume.MaxVec().Y()
+ && rPnt.Z() + SMALL_DVALUE >= aVolume.MinVec().Z() && rPnt.Z() - SMALL_DVALUE <= aVolume.MaxVec().Z());
+
+ if(bIsInside)
+ {
+ BOOL bInsideXY(FALSE);
+ BOOL bInsideXZ(FALSE);
+ BOOL bInsideYZ(FALSE);
+ const Vector3D* pPrev = &(((B3dGeometry*)this)->aEntityBucket[nHigh - 1].Point().GetVector3D());
+ const Vector3D* pActual;
+ Vector3D aDiffPrev, aDiffActual;
+
+ while(nLow < nHigh)
+ {
+ // Neuen Punkt holen
+ pActual = &(((B3dGeometry*)this)->aEntityBucket[nLow++].Point().GetVector3D());
+
+ // Diffs bilden
+ aDiffPrev = *pPrev - rPnt;
+ aDiffActual = *pActual - rPnt;
+
+ // Ueberschneidung in Y moeglich?
+ if((aDiffPrev.Y() > 0.0 && aDiffActual.Y() <= 0.0) || (aDiffActual.Y() > 0.0 && aDiffPrev.Y() <= 0.0))
+ {
+ // in welchem Bereich liegt X?
+ if(aDiffPrev.X() >= 0.0 && aDiffActual.X() >= 0.0)
+ {
+ // Ueberschneidung
+ bInsideXY = !bInsideXY;
+ }
+ else if((aDiffPrev.X() > 0.0 && aDiffActual.X() <= 0.0) || (aDiffActual.X() > 0.0 && aDiffPrev.X() <= 0.0))
+ {
+ // eventuell Ueberschneidung
+ // wo liegt die X-Koordinate des Schnitts mit der X-Achse?
+ if(aDiffActual.Y() != aDiffPrev.Y())
+ if(aDiffPrev.X() - ((aDiffPrev.Y() * (aDiffActual.X() - aDiffPrev.X())) / (aDiffActual.Y() - aDiffPrev.Y())) >= 0.0)
+ // Ueberschneidung
+ bInsideXY = !bInsideXY;
+ }
+
+ // in welchem Bereich liegt Z?
+ if(aDiffPrev.Z() >= 0.0 && aDiffActual.Z() >= 0.0)
+ {
+ // Ueberschneidung
+ bInsideYZ = !bInsideYZ;
+ }
+ else if((aDiffPrev.Z() > 0.0 && aDiffActual.Z() <= 0.0) || (aDiffActual.Z() > 0.0 && aDiffPrev.Z() <= 0.0))
+ {
+ // eventuell Ueberschneidung
+ // wo liegt die X-Koordinate des Schnitts mit der X-Achse?
+ if(aDiffActual.Y() != aDiffPrev.Y())
+ if(aDiffPrev.Z() - ((aDiffPrev.Y() * (aDiffActual.Z() - aDiffPrev.Z())) / (aDiffActual.Y() - aDiffPrev.Y())) >= 0.0)
+ // Ueberschneidung
+ bInsideYZ = !bInsideYZ;
+ }
+ }
+
+ // Ueberschneidung in X moeglich?
+ if((aDiffPrev.X() > 0.0 && aDiffActual.X() <= 0.0) || (aDiffActual.X() > 0.0 && aDiffPrev.X() <= 0.0))
+ {
+ // in welchem Bereich liegt Z?
+ if(aDiffPrev.Z() >= 0.0 && aDiffActual.Z() >= 0.0)
+ {
+ // Ueberschneidung
+ bInsideXZ = !bInsideXZ;
+ }
+ else if((aDiffPrev.Z() > 0.0 && aDiffActual.Z() <= 0.0) || (aDiffActual.Z() > 0.0 && aDiffPrev.Z() <= 0.0))
+ {
+ // eventuell Ueberschneidung
+ // wo liegt die X-Koordinate des Schnitts mit der X-Achse?
+ if(aDiffActual.X() != aDiffPrev.X())
+ if(aDiffPrev.Z() - ((aDiffPrev.X() * (aDiffActual.Z() - aDiffPrev.Z())) / (aDiffActual.X() - aDiffPrev.X())) >= 0.0)
+ // Ueberschneidung
+ bInsideXZ = !bInsideXZ;
+ }
+ }
+
+ // Punkt als Vorgaenger merken
+ pPrev = pActual;
+ }
+ // Wahrheitswert bilden
+ bInside = bInsideXY || bInsideXZ || bInsideYZ;
+ }
+ return bInside;
+}
+
+/*************************************************************************
+|*
+|* BoundVolume liefern
+|*
+\************************************************************************/
+
+B3dVolume B3dGeometry::GetBoundVolume() const
+{
+ B3dVolume aRetval;
+
+ for(UINT32 a=0;a<((B3dGeometry*)this)->aEntityBucket.Count();a++)
+ aRetval.Union(((B3dGeometry*)this)->aEntityBucket[a].Point().GetVector3D());
+
+ return aRetval;
+}
+
+/*************************************************************************
+|*
+|* Mittelpunkt liefern
+|*
+\************************************************************************/
+
+Vector3D B3dGeometry::GetCenter() const
+{
+ B3dVolume aVolume = GetBoundVolume();
+ return (aVolume.MaxVec() + aVolume.MinVec()) / 2.0;
+}
+
+/*************************************************************************
+|*
+|* Standard - Normalen generieren
+|*
+\************************************************************************/
+
+void B3dGeometry::CreateDefaultNormalsSphere()
+{
+ // Alle Normalen ausgehend vom Zentrum der Geometrie bilden
+ Vector3D aCenter = GetCenter();
+
+ for(UINT32 a=0;a<aEntityBucket.Count();a++)
+ {
+ const Vector3D& aPoint = aEntityBucket[a].Point().GetVector3D();
+ Vector3D aNewNormal = aPoint - aCenter;
+ aNewNormal.Normalize();
+ aEntityBucket[a].Normal() = aNewNormal;
+ aEntityBucket[a].SetNormalUsed(TRUE);
+ }
+}
+
+/*************************************************************************
+|*
+|* Normale ermitteln fuer einzelnes Polygon
+|*
+\************************************************************************/
+
+Vector3D B3dGeometry::CalcNormal(UINT32 nLow, UINT32 nHigh) const
+{
+ const Vector3D* pVec1 = NULL;
+ const Vector3D* pVec2 = NULL;
+ const Vector3D* pVec3 = NULL;
+ Vector3D aNormal;
+
+ while(nLow < nHigh && !(pVec1 && pVec2 && pVec3))
+ {
+ if(!pVec1)
+ {
+ pVec1 = &(((B3dGeometry*)this)->aEntityBucket[nLow++].Point().GetVector3D());
+ }
+ else if(!pVec2)
+ {
+ pVec2 = &(((B3dGeometry*)this)->aEntityBucket[nLow++].Point().GetVector3D());
+ if(*pVec2 == *pVec1)
+ pVec2 = NULL;
+ }
+ else if(!pVec3)
+ {
+ pVec3 = &(((B3dGeometry*)this)->aEntityBucket[nLow++].Point().GetVector3D());
+ if(*pVec3 == *pVec2 || pVec3 == pVec1)
+ pVec3 = NULL;
+ }
+ }
+ if(pVec1 && pVec2 && pVec3)
+ {
+ aNormal = (*pVec2 - *pVec1)|(*pVec2 - *pVec3);
+ aNormal.Normalize();
+ }
+ return aNormal;
+}
+
+/*************************************************************************
+|*
+|* Standard - Texturkoordinaten generieren
+|*
+\************************************************************************/
+
+void B3dGeometry::CreateDefaultTexture(UINT16 nCreateWhat, BOOL bUseSphere)
+{
+ if(nCreateWhat)
+ {
+ if(bUseSphere)
+ {
+ // Texturkoordinaten mittels Kugelprojektion ermitteln,
+ // dazu das Zentrum der Geometrie benutzen
+ // Alle Normalen ausgehend vom Zentrum der Geometrie bilden
+ Vector3D aCenter = GetCenter();
+ UINT32 nPointCounter = 0;
+
+ for(UINT32 a=0;a<aIndexBucket.Count();a++)
+ {
+ // Lokales Zentrum der zu behandelnden Flaeche bilden,
+ // um zu wissen von welcher Seite sich diese Flaeche
+ // dem Winkel F_PI bzw. -F_PI naehert
+ Vector3D aLocalCenter;
+ for(UINT32 b=nPointCounter;b<aIndexBucket[a].GetIndex();b++)
+ aLocalCenter += aEntityBucket[b].Point().GetVector3D();
+ aLocalCenter /= aIndexBucket[a].GetIndex() - nPointCounter;
+
+ // Vektor vom Mittelpunkt zum lokalen Zentrum bilden
+ aLocalCenter = aLocalCenter - aCenter;
+ if(fabs(aLocalCenter.X()) < SMALL_DVALUE)
+ aLocalCenter.X() = 0.0;
+ if(fabs(aLocalCenter.Y()) < SMALL_DVALUE)
+ aLocalCenter.Y() = 0.0;
+ if(fabs(aLocalCenter.Z()) < SMALL_DVALUE)
+ aLocalCenter.Z() = 0.0;
+
+ // X,Y fuer das lokale Zentrum bilden
+ double fXCenter = atan2(aLocalCenter.Z(), aLocalCenter.X());
+ double fYCenter = atan2(aLocalCenter.Y(), aLocalCenter.GetXZLength());
+ fXCenter = 1.0 - ((fXCenter + F_PI) / F_2PI);
+ fYCenter = 1.0 - ((fYCenter + F_PI2) / F_PI);
+
+ // Einzelne Punkte behandeln
+ UINT32 nRememberPointCounter = nPointCounter;
+ while(nPointCounter < aIndexBucket[a].GetIndex())
+ {
+ // Vektor vom Mittelpunkt zum Punkt bilden
+ const Vector3D& aPoint = aEntityBucket[nPointCounter].Point().GetVector3D();
+ Vector3D aDirection = aPoint - aCenter;
+ if(fabs(aDirection.X()) < SMALL_DVALUE)
+ aDirection.X() = 0.0;
+ if(fabs(aDirection.Y()) < SMALL_DVALUE)
+ aDirection.Y() = 0.0;
+ if(fabs(aDirection.Z()) < SMALL_DVALUE)
+ aDirection.Z() = 0.0;
+
+ // X,Y fuer Punkt bilden
+ double fXPoint = atan2(aDirection.Z(), aDirection.X());
+ double fYPoint = atan2(aDirection.Y(), aDirection.GetXZLength());
+ fXPoint = 1.0 - ((fXPoint + F_PI) / F_2PI);
+ fYPoint = 1.0 - ((fYPoint + F_PI2) / F_PI);
+
+ // X,Y des Punktes korrigieren
+ if(fXPoint > fXCenter + 0.5)
+ fXPoint -= 1.0;
+ if(fXPoint < fXCenter - 0.5)
+ fXPoint += 1.0;
+
+ // Polarkoordinaten als Texturkoordinaten zuweisen
+ if(nCreateWhat & B3D_CREATE_DEFAULT_X)
+ aEntityBucket[nPointCounter].TexCoor().X() = fXPoint;
+ if(nCreateWhat & B3D_CREATE_DEFAULT_Y)
+ aEntityBucket[nPointCounter].TexCoor().Y() = fYPoint;
+ if(nCreateWhat & B3D_CREATE_DEFAULT_Z)
+ aEntityBucket[nPointCounter].TexCoor().Z() = 0.0;
+
+ aEntityBucket[nPointCounter++].SetTexCoorUsed(TRUE);
+ }
+
+ // Punkte korrigieren, die direkt in den Polarregionen liegen. Deren
+ // X-Koordinate kann nicht korrekt sein. Die korrekte X-Koordinate
+ // ist diejenige des Punktes, der in den Pol hinein oder aus diesem heraus
+ // fuehrt, auf der Kugel also direkt darauf zu.
+ if(nCreateWhat & B3D_CREATE_DEFAULT_X)
+ {
+ nPointCounter = nRememberPointCounter;
+ while(nPointCounter < aIndexBucket[a].GetIndex())
+ {
+ Vector3D& aCoor = aEntityBucket[nPointCounter].TexCoor();
+ if(fabs(aCoor.Y()) < SMALL_DVALUE || fabs(aCoor.Y() - 1.0) < SMALL_DVALUE)
+ {
+ // Nachfolger finden
+ UINT32 nNextIndex = (nPointCounter + 1 < aIndexBucket[a].GetIndex())
+ ? nPointCounter + 1 : nRememberPointCounter;
+ Vector3D& aNextCoor = aEntityBucket[nNextIndex].TexCoor();
+
+ // Vorgaenger finden
+ UINT32 nPrevIndex = (nPointCounter && nPointCounter - 1 >= nRememberPointCounter)
+ ? nPointCounter - 1 : aIndexBucket[a].GetIndex() - 1;
+ Vector3D& aPrevCoor = aEntityBucket[nPrevIndex].TexCoor();
+
+ // Nachfolger testen: Liegt dieser ausserhalb des Pols?
+ if(fabs(aNextCoor.Y()) > SMALL_DVALUE && fabs(aNextCoor.Y() - 1.0) > SMALL_DVALUE)
+ {
+ // falls ja: X-Koordinate uebernehmen
+ aCoor.X() = aNextCoor.X();
+ }
+ // Vorgaenger testen: Liegt dieser ausserhalb des Pols?
+ else if(fabs(aPrevCoor.Y()) > SMALL_DVALUE && fabs(aPrevCoor.Y() - 1.0) > SMALL_DVALUE)
+ {
+ // falls ja, X-Koordinate uebernehmen
+ aCoor.X() = aPrevCoor.X();
+ }
+ else
+ {
+ // Weder Vorgaenger noch Nachfolger liegen ausserhalb des Pols.
+ // Uebernimm daher wenigstens den bereits korrigierten X-Wert
+ // des Vorgaengers
+ aCoor.X() = aPrevCoor.X();
+ }
+ }
+ // naechster Punkt
+ nPointCounter++;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Texturkoordinaten als Parallelprojektion auf X,Y,Z - Koordinaten
+ // im Bereich 1.0 bis 0.0 der Geometrie abstellen
+ // Gesamtabmessungen holen
+ B3dVolume aVolume = GetBoundVolume();
+
+ for(UINT32 a=0;a<aEntityBucket.Count();a++)
+ {
+ const Vector3D& aPoint = aEntityBucket[a].Point().GetVector3D();
+
+ if(nCreateWhat & B3D_CREATE_DEFAULT_X)
+ {
+ if(aVolume.GetWidth())
+ aEntityBucket[a].TexCoor().X() = (aPoint.X() - aVolume.MinVec().X()) / aVolume.GetWidth();
+ else
+ aEntityBucket[a].TexCoor().X() = 0.0;
+ }
+
+ if(nCreateWhat & B3D_CREATE_DEFAULT_Y)
+ {
+ if(aVolume.GetHeight())
+ aEntityBucket[a].TexCoor().Y() = 1.0 - ((aPoint.Y() - aVolume.MinVec().Y()) / aVolume.GetHeight());
+ else
+ aEntityBucket[a].TexCoor().Y() = 1.0;
+ }
+
+ if(nCreateWhat & B3D_CREATE_DEFAULT_Z)
+ aEntityBucket[a].TexCoor().Z() = 0.0;
+
+ aEntityBucket[a].SetTexCoorUsed(TRUE);
+ }
+ }
+ }
+}
+
+/*************************************************************************
+|*
+|* Normalen invertieren
+|*
+\************************************************************************/
+
+void B3dGeometry::InvertNormals()
+{
+ for(UINT32 a=0;a<aEntityBucket.Count();a++)
+ aEntityBucket[a].Normal() = -aEntityBucket[a].Normal();
+}
+}//end of namespace binfilter
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */