📄 mgctubesurface.cpp
字号:
// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement. The various license agreements may be found at
// the Magic Software web site. This file is subject to the license
//
// RESTRICTED USE SOURCE CODE
// http://www.magic-software.com/License/restricted.pdf
#include "MgcMultipleCurve3.h"
#include "MgcTriMesh.h"
#include "MgcTubeSurface.h"
//----------------------------------------------------------------------------
MgcTubeSurface::MgcTubeSurface (MgcMultipleCurve3* pkMedial,
RadialFunction oRadial, bool bClosed, unsigned int uiMedialSamples,
unsigned int uiSliceSamples, bool bSampleByArcLength, bool bWantNormals,
const MgcVector3* pkUpVector, const MgcVector2& rkTextureMin,
const MgcVector2& rkTextureMax)
{
assert( pkMedial && oRadial );
m_pkMedial = pkMedial;
m_oRadial = oRadial;
m_bClosed = bClosed;
// default tessellation
Tessellate(uiMedialSamples,uiSliceSamples,bSampleByArcLength,bWantNormals,
pkUpVector,rkTextureMin,rkTextureMax);
}
//----------------------------------------------------------------------------
MgcTubeSurface::MgcTubeSurface ()
{
m_pkMedial = 0;
m_oRadial = 0;
m_bClosed = false;
}
//----------------------------------------------------------------------------
MgcTubeSurface::~MgcTubeSurface ()
{
delete m_pkMedial;
}
//----------------------------------------------------------------------------
unsigned int MgcTubeSurface::Index (unsigned short uiS, unsigned short uiM)
{
return uiS + (m_uiSliceSamples+1)*uiM;
}
//----------------------------------------------------------------------------
void MgcTubeSurface::ComputeVertices (unsigned int& ruiVertexQuantity,
MgcVector3*& rakVertex)
{
if ( m_bClosed )
ruiVertexQuantity = (m_uiSliceSamples+1)*(m_uiMedialSamples+1);
else
ruiVertexQuantity = (m_uiSliceSamples+1)*m_uiMedialSamples;
rakVertex = new MgcVector3[ruiVertexQuantity];
// Compute slice vertex coefficients. The first and last coefficients
// are duplicated to allow a closed cross section that has two different
// pairs of texture coordinates at the shared vertex.
MgcReal* afSin = new MgcReal[m_uiSliceSamples + 1];
MgcReal* afCos = new MgcReal[m_uiSliceSamples + 1];
unsigned int uiS;
for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
{
MgcReal fAngle = uiS*MgcMath::TWO_PI/m_uiSliceSamples;
afCos[uiS] = MgcMath::Cos(fAngle);
afSin[uiS] = MgcMath::Sin(fAngle);
}
afSin[m_uiSliceSamples] = afSin[0];
afCos[m_uiSliceSamples] = afCos[0];
// compute vertices
MgcReal fTMin = m_pkMedial->GetMinTime();
MgcReal fTRange = m_pkMedial->GetMaxTime() - fTMin;
MgcReal fTotalLength;
if ( m_bClosed )
fTotalLength = m_pkMedial->GetTotalLength();
else
fTotalLength = 0.0;
for (unsigned int uiM = 0, uiV = 0; uiM < m_uiMedialSamples; uiM++)
{
MgcReal fT;
if ( m_bClosed )
{
if ( m_bSampleByArcLength )
{
fT = m_pkMedial->GetTime(
uiM*fTotalLength/MgcReal(m_uiMedialSamples));
}
else
{
fT = fTMin + uiM*fTRange/MgcReal(m_uiMedialSamples);
}
}
else
{
if ( m_bSampleByArcLength )
{
fT = m_pkMedial->GetTime(
uiM*fTotalLength/MgcReal(m_uiMedialSamples-1));
}
else
{
fT = fTMin + uiM*fTRange/MgcReal(m_uiMedialSamples-1);
}
}
MgcReal fRadius = m_oRadial(fT);
// compute frame (position P, tangent T, normal N, binormal B)
MgcVector3 kP, kT, kN, kB;
if ( m_pkUpVector )
{
// Always use 'up' vector N rather than curve normal. You must
// constrain the curve so that T and N are never parallel. To
// build the frame from this, let
// B = Cross(T,N)/Length(Cross(T,N))
// and replace
// N = Cross(B,T)/Length(Cross(B,T)).
kP = m_pkMedial->GetPosition(fT);
kT = m_pkMedial->GetTangent(fT);
kB = kT.UnitCross(MgcVector3::UNIT_Z);
kN = kB.UnitCross(kT);
}
else
{
// use Frenet frame to create slices
m_pkMedial->GetFrame(fT,kP,kT,kN,kB);
}
// compute slice vertices, duplication at end point as noted earlier
unsigned int uiSave = uiV;
for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
{
rakVertex[uiV] = kP + fRadius*(afCos[uiS]*kN + afSin[uiS]*kB);
uiV++;
}
rakVertex[uiV] = rakVertex[uiSave];
uiV++;
}
if ( m_bClosed )
{
for (uiS = 0; uiS <= m_uiSliceSamples; uiS++)
{
unsigned int uiI1 = Index(uiS,m_uiMedialSamples);
unsigned int uiI0 = Index(uiS,0);
rakVertex[uiI1] = rakVertex[uiI0];
}
}
delete[] afSin;
delete[] afCos;
}
//----------------------------------------------------------------------------
MgcVector3* MgcTubeSurface::ComputeNormals (unsigned int uiVertexQuantity,
MgcVector3* akVertex)
{
MgcVector3* akNormal = new MgcVector3[uiVertexQuantity];
unsigned int uiSm, uiSp, uiMm, uiMp;
MgcVector3 kDir0, kDir1;
unsigned int uiS;
// interior normals (central differences)
for (unsigned int uiM = 1; uiM <= m_uiMedialSamples-2; uiM++)
{
for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
{
uiSm = ( uiS > 0 ? uiS-1 : m_uiSliceSamples-1 );
uiSp = uiS + 1;
uiMm = uiM - 1;
uiMp = uiM + 1;
kDir0 = akVertex[Index(uiSm,uiM)] - akVertex[Index(uiSp,uiM)];
kDir1 = akVertex[Index(uiS,uiMm)] - akVertex[Index(uiS,uiMp)];
akNormal[Index(uiS,uiM)] = kDir0.UnitCross(kDir1);
}
akNormal[Index(m_uiSliceSamples,uiM)] = akNormal[Index(0,uiM)];
}
// boundary normals
if ( m_bClosed )
{
// central differences
for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
{
uiSm = ( uiS > 0 ? uiS-1 : m_uiSliceSamples-1 );
uiSp = uiS + 1;
// m = 0
kDir0 = akVertex[Index(uiSm,0)] - akVertex[Index(uiSp,0)];
kDir1 = akVertex[Index(uiS,m_uiMedialSamples-1)] -
akVertex[Index(uiS,1)];
akNormal[uiS] = kDir0.UnitCross(kDir1);
// m = max
akNormal[Index(uiS,m_uiMedialSamples)] = akNormal[Index(uiS,0)];
}
akNormal[Index(m_uiSliceSamples,0)] = akNormal[Index(0,0)];
akNormal[Index(m_uiSliceSamples,m_uiMedialSamples)] =
akNormal[Index(0,m_uiMedialSamples)];
}
else
{
// one-sided finite differences
// m = 0
for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
{
uiSm = ( uiS > 0 ? uiS-1 : m_uiSliceSamples-1 );
uiSp = uiS + 1;
kDir0 = akVertex[Index(uiSm,0)] - akVertex[Index(uiSp,0)];
kDir1 = akVertex[Index(uiS,0)] - akVertex[Index(uiS,1)];
akNormal[Index(uiS,0)] = kDir0.UnitCross(kDir1);
}
akNormal[Index(m_uiSliceSamples,0)] = akNormal[Index(0,0)];
// m = max-1
for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
{
uiSm = ( uiS > 0 ? uiS-1 : m_uiSliceSamples-1 );
uiSp = uiS + 1;
kDir0 = akVertex[Index(uiSm,m_uiMedialSamples-1)] -
akVertex[Index(uiSp,m_uiMedialSamples-1)];
kDir1 = akVertex[Index(uiS,m_uiMedialSamples-2)] -
akVertex[Index(uiS,m_uiMedialSamples-1)];
akNormal[uiS] = kDir0.UnitCross(kDir1);
}
akNormal[Index(m_uiSliceSamples,m_uiMedialSamples-1)] =
akNormal[Index(0,m_uiMedialSamples-1)];
}
return akNormal;
}
//----------------------------------------------------------------------------
MgcVector2* MgcTubeSurface::ComputeTextures (unsigned int uiVertexQuantity)
{
MgcVector2* akTexture = new MgcVector2[uiVertexQuantity];
MgcVector2 kTextureRange = m_kTextureMax - m_kTextureMin;
unsigned int uiMMax;
if ( m_bClosed )
uiMMax = m_uiMedialSamples;
else
uiMMax = m_uiMedialSamples - 1;
for (unsigned int uiM = 0, uiV = 0; uiM <= uiMMax; uiM++)
{
MgcReal fMRatio = MgcReal(uiM)/MgcReal(uiMMax);
MgcReal fMValue = m_kTextureMin.y + fMRatio*kTextureRange.y;
for (unsigned int uiS = 0; uiS <= m_uiSliceSamples; uiS++)
{
MgcReal fSRatio = MgcReal(uiS)/MgcReal(m_uiSliceSamples);
MgcReal fSValue = m_kTextureMin.x + fSRatio*kTextureRange.x;
akTexture[uiV].x = fSValue;
akTexture[uiV].y = fMValue;
uiV++;
}
}
return akTexture;
}
//----------------------------------------------------------------------------
void MgcTubeSurface::ComputeConnectivity (unsigned int& ruiTriangleQuantity,
unsigned int*& rauiConnect)
{
ruiTriangleQuantity = 2*m_uiSliceSamples*m_uiMedialSamples;
rauiConnect = new unsigned int[3*ruiTriangleQuantity];
unsigned int* puiConnect = rauiConnect;
for (unsigned int uiM = 0, uiMStart = 0; uiM < m_uiMedialSamples; uiM++)
{
unsigned int uiI0 = uiMStart;
unsigned int uiI1 = uiI0 + 1;
uiMStart += m_uiSliceSamples + 1;
unsigned int uiI2 = uiMStart;
unsigned int uiI3 = uiI2 + 1;
for (unsigned int uiS = 0; uiS < m_uiSliceSamples; uiS++)
{
// TO DO. The ordering of the vertices assumes you want to view
// the tube from the inside. If you want a view from the outside
// or if you want a double-sided tube, this function must change.
//
// WARNING. Under Visual C++ 6.0, service pack 2, release build
// optimization set to 'maximize speed', the optimizer incorrectly
// compiles the following block
// *puiConnect++ = uiI0;
// *puiConnect++ = uiI2;
// *puiConnect++ = uiI1;
// *puiConnect++ = uiI1;
// *puiConnect++ = uiI2;
// *puiConnect++ = uiI3;
// uiI0++;
// uiI1++;
// uiI2++;
// uiI3++;
// That is why I have the statements reordered. The source+asm
// listing showed that part of the uiM-loop was being compiled
// twice, really strange...
*puiConnect++ = uiI0;
uiI0++;
*puiConnect++ = uiI2;
*puiConnect++ = uiI1;
*puiConnect++ = uiI1;
uiI1++;
*puiConnect++ = uiI2;
uiI2++;
*puiConnect++ = uiI3;
uiI3++;
}
}
}
//----------------------------------------------------------------------------
void MgcTubeSurface::Tessellate (unsigned int uiMedialSamples,
unsigned int uiSliceSamples, bool bSampleByArcLength, bool bWantNormals,
const MgcVector3* pkUpVector, const MgcVector2& rkTextureMin,
const MgcVector2& rkTextureMax)
{
m_uiMedialSamples = uiMedialSamples;
m_uiSliceSamples = uiSliceSamples;
m_bSampleByArcLength = bSampleByArcLength;
m_bWantNormals = bWantNormals;
m_pkUpVector = pkUpVector;
m_kTextureMin = rkTextureMin;
m_kTextureMax = rkTextureMax;
unsigned int uiVertexQuantity;
MgcVector3* akVertex;
ComputeVertices(uiVertexQuantity,akVertex);
MgcVector3* akNormal;
if ( m_bWantNormals )
akNormal = ComputeNormals(uiVertexQuantity,akVertex);
else
akNormal = 0;
MgcVector2* akTexture = ComputeTextures(uiVertexQuantity);
unsigned int uiTriangleQuantity;
unsigned int* auiConnect;
ComputeConnectivity(uiTriangleQuantity,auiConnect);
// create the triangle mesh for the tube surface
Reconstruct(uiVertexQuantity,akVertex,akNormal,0,akTexture,
uiTriangleQuantity,auiConnect);
UpdateModelBound();
}
//----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -