wmlextractsurfacetetra.cpp
来自「3D Game Engine Design Source Code非常棒」· C++ 代码 · 共 1,297 行 · 第 1/3 页
CPP
1,297 行
// Magic Software, Inc.
// http://www.magic-software.com
// http://www.wild-magic.com
// Copyright (c) 2003. All Rights Reserved
//
// The Wild Magic Library (WML) source code is supplied under the terms of
// the license agreement http://www.magic-software.com/License/WildMagic.pdf
// and may not be copied or disclosed except in accordance with the terms of
// that agreement.
#include "WmlExtractSurfaceTetra.h"
#include "WmlVETMesh.h"
using namespace Wml;
#include <algorithm>
using namespace std;
typedef map<Vector3f,int> VMap;
typedef VMap::iterator VMapIterator;
typedef map<TriangleKey,int> TMap;
typedef TMap::iterator TMapIterator;
//----------------------------------------------------------------------------
ExtractSurfaceTetra::ExtractSurfaceTetra (int iXBound, int iYBound,
int iZBound, int* aiData)
{
assert( iXBound > 0 && iYBound > 0 && iZBound > 0 && aiData );
m_iXBound = iXBound;
m_iYBound = iYBound;
m_iZBound = iZBound;
m_iXYBound = iXBound*iYBound;
m_iXYZBound = m_iXYBound*iZBound;
m_aiData = aiData;
}
//----------------------------------------------------------------------------
float ExtractSurfaceTetra::GetFunction (const Vector3f& rkP) const
{
int iX = (int) rkP.X();
if ( iX < 0 || iX >= m_iXBound-1 )
return 0.0f;
int iY = (int) rkP.Y();
if ( iY < 0 || iY >= m_iYBound-1 )
return 0.0f;
int iZ = (int) rkP.Z();
if ( iZ < 0 || iZ >= m_iZBound-1 )
return 0.0f;
float fDX = rkP.X() - iX, fDY = rkP.Y() - iY, fDZ = rkP.Z() - iZ;
int i000 = iX + m_iXBound*(iY + m_iYBound*iZ);
int i100 = i000 + 1;
int i010 = i000 + m_iXBound;
int i110 = i100 + m_iXBound;
int i001 = i000 + m_iXYBound;
int i101 = i100 + m_iXYBound;
int i011 = i010 + m_iXYBound;
int i111 = i110 + m_iXYBound;
float fF000 = (float) m_aiData[i000];
float fF100 = (float) m_aiData[i100];
float fF010 = (float) m_aiData[i010];
float fF110 = (float) m_aiData[i110];
float fF001 = (float) m_aiData[i001];
float fF101 = (float) m_aiData[i101];
float fF011 = (float) m_aiData[i011];
float fF111 = (float) m_aiData[i111];
float fC0, fC1, fC2, fInterp;
if ( (iX & 1) ^ (iY & 1) ^ (iZ & 1) )
{
if ( fDX - fDY - fDZ >= 0.0f )
{
// 1205
fInterp =
(1.0f-(1.0f-fDX)-fDY-fDZ)*fF100 +
(1.0f-fDX)*fF000 +
fDY*fF110 +
fDZ*fF101;
}
else if ( fDX - fDY + fDZ <= 0.0f )
{
// 3027
fInterp =
(1.0f-fDX-(1.0f-fDY)-fDZ)*fF010 +
fDX*fF110 +
(1.0f-fDY)*fF000 +
fDZ*fF011;
}
else if ( fDX + fDY - fDZ <= 0.0f )
{
// 4750
fInterp =
(1.0f-fDX-fDY-(1-fDZ))*fF001 +
fDX*fF101 +
fDY*fF011 +
(1.0f-fDZ)*fF000;
}
else if ( fDX + fDY + fDZ >= 2.0f )
{
// 6572
fInterp =
(1.0f-(1.0f-fDX)-(1.0f-fDY)-(1.0f-fDZ))*fF111 +
(1.0f-fDX)*fF011 +
(1.0f-fDY)*fF101 +
(1.0f-fDZ)*fF110;
}
else
{
// 0752
fC0 = 0.5f*(-fDX+fDY+fDZ);
fC1 = 0.5f*(fDX-fDY+fDZ);
fC2 = 0.5f*(fDX+fDY-fDZ);
fInterp =
(1.0f-fC0-fC1-fC2)*fF000 +
fC0*fF011 +
fC1*fF101 +
fC2*fF110;
}
}
else
{
if ( fDX + fDY + fDZ <= 1.0f )
{
// 0134
fInterp =
(1.0f-fDX-fDY-fDZ)*fF000 +
fDX*fF100 +
fDY*fF010 +
fDZ*fF001;
}
else if ( fDX + fDY - fDZ >= 1.0f )
{
// 2316
fInterp =
(1.0f-(1.0f-fDX)-(1.0f-fDY)-fDZ)*fF110 +
(1.0f-fDX)*fF010 +
(1.0f-fDY)*fF100 +
fDZ*fF111;
}
else if ( fDX - fDY + fDZ >= 1.0f )
{
// 5461
fInterp =
(1.0f-(1.0f-fDX)-fDY-(1.0f-fDZ))*fF101 +
(1.0f-fDX)*fF001 +
fDY*fF111 +
(1.0f-fDZ)*fF100;
}
else if ( -fDX + fDY + fDZ >= 1.0f )
{
// 7643
fInterp =
(1.0f-fDX-(1.0f-fDY)-(1.0f-fDZ))*fF011 +
fDX*fF111 +
(1.0f-fDY)*fF001 +
(1.0f-fDZ)*fF010;
}
else
{
// 6314
fC0 = 0.5f*((1.0f-fDX)-(1.0f-fDY)+(1.0f-fDZ));
fC1 = 0.5f*(-(1.0f-fDX)+(1.0f-fDY)+(1.0f-fDZ));
fC2 = 0.5f*((1.0f-fDX)+(1.0f-fDY)-(1.0f-fDZ));
fInterp =
(1.0f-fC0-fC1-fC2)*fF111 +
fC0*fF010 +
fC1*fF100 +
fC2*fF001;
}
}
return fInterp;
}
//----------------------------------------------------------------------------
Vector3f ExtractSurfaceTetra::GetGradient (const Vector3f& rkP) const
{
int iX = (int) rkP.X();
if ( iX < 0 || iX >= m_iXBound-1 )
return Vector3f::ZERO;
int iY = (int) rkP.Y();
if ( iY < 0 || iY >= m_iYBound-1 )
return Vector3f::ZERO;
int iZ = (int) rkP.Z();
if ( iZ < 0 || iZ >= m_iZBound-1 )
return Vector3f::ZERO;
float fDX = rkP.X() - iX, fDY = rkP.Y() - iY, fDZ = rkP.Z() - iZ;
int i000 = iX + m_iXBound*(iY + m_iYBound*iZ);
int i100 = i000 + 1;
int i010 = i000 + m_iXBound;
int i110 = i100 + m_iXBound;
int i001 = i000 + m_iXYBound;
int i101 = i100 + m_iXYBound;
int i011 = i010 + m_iXYBound;
int i111 = i110 + m_iXYBound;
float fF000 = (float) m_aiData[i000];
float fF100 = (float) m_aiData[i100];
float fF010 = (float) m_aiData[i010];
float fF110 = (float) m_aiData[i110];
float fF001 = (float) m_aiData[i001];
float fF101 = (float) m_aiData[i101];
float fF011 = (float) m_aiData[i011];
float fF111 = (float) m_aiData[i111];
Vector3f kInterp;
if ( (iX & 1) ^ (iY & 1) ^ (iZ & 1) )
{
if ( fDX - fDY - fDZ >= 0.0f )
{
// 1205
kInterp.X() = + fF100 - fF000;
kInterp.Y() = - fF100 + fF110;
kInterp.Z() = - fF100 + fF101;
}
else if ( fDX - fDY + fDZ <= 0.0f )
{
// 3027
kInterp.X() = - fF010 + fF110;
kInterp.Y() = + fF010 - fF000;
kInterp.Z() = - fF010 + fF011;
}
else if ( fDX + fDY - fDZ <= 0.0f )
{
// 4750
kInterp.X() = - fF001 + fF101;
kInterp.Y() = - fF001 + fF011;
kInterp.Z() = + fF001 - fF000;
}
else if ( fDX + fDY + fDZ >= 2.0f )
{
// 6572
kInterp.X() = + fF111 - fF011;
kInterp.Y() = + fF111 - fF101;
kInterp.Z() = + fF111 - fF110;
}
else
{
// 0752
kInterp.X() = 0.5f*(-fF000-fF011+fF101+fF110);
kInterp.Y() = 0.5f*(-fF000+fF011-fF101+fF110);
kInterp.Z() = 0.5f*(-fF000+fF011+fF101-fF110);
}
}
else
{
if ( fDX + fDY + fDZ <= 1.0f )
{
// 0134
kInterp.X() = - fF000 + fF100;
kInterp.Y() = - fF000 + fF010;
kInterp.Z() = - fF000 + fF001;
}
else if ( fDX + fDY - fDZ >= 1.0f )
{
// 2316
kInterp.X() = + fF110 - fF010;
kInterp.Y() = + fF110 - fF100;
kInterp.Z() = - fF110 + fF111;
}
else if ( fDX - fDY + fDZ >= 1.0f )
{
// 5461
kInterp.X() = + fF101 - fF001;
kInterp.Y() = - fF101 + fF111;
kInterp.Z() = + fF101 - fF100;
}
else if ( -fDX + fDY + fDZ >= 1.0f )
{
// 7643
kInterp.X() = - fF011 + fF111;
kInterp.Y() = + fF011 - fF001;
kInterp.Z() = + fF011 - fF010;
}
else
{
// 6314
kInterp.X() = 0.5f*(fF111-fF010+fF100-fF001);
kInterp.Y() = 0.5f*(fF111+fF010-fF100-fF001);
kInterp.Z() = 0.5f*(fF111-fF010-fF100+fF001);
}
}
return kInterp;
}
//----------------------------------------------------------------------------
void ExtractSurfaceTetra::ExtractContour (int iLevel, vector<Vector3f>& rkVA,
vector<TriangleKey>& rkTA)
{
// NOTE: Isolated edges are computed, but not reported to the caller.
// You can modify the code to return these if so desired.
VtxMap kVMap;
ESet kESet;
TSet kTSet;
m_iNextIndex = 0;
// adjust image so level set is F(x,y,z) = 0
int i;
for (i = 0; i < m_iXYZBound; i++)
m_aiData[i] = m_aiData[i] - iLevel;
int iXBoundM1 = m_iXBound - 1;
int iYBoundM1 = m_iYBound - 1;
int iZBoundM1 = m_iZBound - 1;
for (int iZ = 0, iZP = 1; iZ < iZBoundM1; iZ++, iZP++)
{
int iZParity = (iZ & 1);
for (int iY = 0, iYP = 1; iY < iYBoundM1; iY++, iYP++)
{
int iYParity = (iY & 1);
for (int iX = 0, iXP = 1; iX < iXBoundM1; iX++, iXP++)
{
int iXParity = (iX & 1);
int i000 = iX + m_iXBound*(iY + m_iYBound*iZ);
int i100 = i000 + 1;
int i010 = i000 + m_iXBound;
int i110 = i100 + m_iXBound;
int i001 = i000 + m_iXYBound;
int i101 = i100 + m_iXYBound;
int i011 = i010 + m_iXYBound;
int i111 = i110 + m_iXYBound;
int iF000 = m_aiData[i000];
int iF100 = m_aiData[i100];
int iF010 = m_aiData[i010];
int iF110 = m_aiData[i110];
int iF001 = m_aiData[i001];
int iF101 = m_aiData[i101];
int iF011 = m_aiData[i011];
int iF111 = m_aiData[i111];
if ( iXParity ^ iYParity ^ iZParity )
{
// 1205
ProcessTetrahedron(kVMap,kESet,kTSet,
iXP,iY,iZ,iF100,iXP,iYP,iZ,iF110,iX,iY,iZ,iF000,iXP,
iY,iZP,iF101);
// 3027
ProcessTetrahedron(kVMap,kESet,kTSet,
iX,iYP,iZ,iF010,iX,iY,iZ,iF000,iXP,iYP,iZ,iF110,iX,
iYP,iZP,iF011);
// 4750
ProcessTetrahedron(kVMap,kESet,kTSet,
iX,iY,iZP,iF001,iX,iYP,iZP,iF011,iXP,iY,iZP,iF101,iX,
iY,iZ,iF000);
// 6572
ProcessTetrahedron(kVMap,kESet,kTSet,
iXP,iYP,iZP,iF111,iXP,iY,iZP,iF101,iX,iYP,iZP,iF011,
iXP,iYP,iZ,iF110);
// 0752
ProcessTetrahedron(kVMap,kESet,kTSet,
iX,iY,iZ,iF000,iX,iYP,iZP,iF011,iXP,iY,iZP,iF101,iXP,
iYP,iZ,iF110);
}
else
{
// 0134
ProcessTetrahedron(kVMap,kESet,kTSet,
iX,iY,iZ,iF000,iXP,iY,iZ,iF100,iX,iYP,iZ,iF010,iX,iY,
iZP,iF001);
// 2316
ProcessTetrahedron(kVMap,kESet,kTSet,
iXP,iYP,iZ,iF110,iX,iYP,iZ,iF010,iXP,iY,iZ,iF100,iXP,
iYP,iZP,iF111);
// 5461
ProcessTetrahedron(kVMap,kESet,kTSet,
iXP,iY,iZP,iF101,iX,iY,iZP,iF001,iXP,iYP,iZP,iF111,
iXP,iY,iZ,iF100);
// 7643
ProcessTetrahedron(kVMap,kESet,kTSet,
iX,iYP,iZP,iF011,iXP,iYP,iZP,iF111,iX,iY,iZP,iF001,iX,
iYP,iZ,iF010);
// 6314
ProcessTetrahedron(kVMap,kESet,kTSet,
iXP,iYP,iZP,iF111,iX,iYP,iZ,iF010,iXP,iY,iZ,iF100,iX,
iY,iZP,iF001);
}
}
}
}
// readjust image so level set is F(x,y,z) = L
for (i = 0; i < m_iXYZBound; i++)
m_aiData[i] = m_aiData[i] + iLevel;
// pack vertices into an array
rkVA.resize(kVMap.size());
if ( rkVA.size() > 0 )
{
VtxMapIterator pkVIter;
for (pkVIter = kVMap.begin(); pkVIter != kVMap.end(); pkVIter++)
{
const Vertex& rkV = pkVIter->first;
rkV.GetTriple(rkVA[pkVIter->second]);
}
}
// pack edges into an array (computed, but not reported to caller)
vector<EdgeKey> kEA;
kEA.resize(kESet.size());
if ( kEA.size() > 0 )
copy(kESet.begin(),kESet.end(),&kEA.front());
// pack triangles into an array
rkTA.resize(kTSet.size());
if ( rkTA.size() > 0 )
copy(kTSet.begin(),kTSet.end(),&rkTA.front());
}
//----------------------------------------------------------------------------
void ExtractSurfaceTetra::MakeUnique (vector<Vector3f>& rkVA,
vector<TriangleKey>& rkTA)
{
int iVQuantity = (int)rkVA.size();
int iTQuantity = (int)rkTA.size();
if ( iVQuantity == 0 || iTQuantity == 0 )
return;
// use a hash table to generate unique storage
VMap kVMap;
VMapIterator pkVIter;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?