git-svn-id: https://free-cad.svn.sourceforge.net/svnroot/free-cad/trunk@5000 e8eeb9e2-ec13-0410-a4a9-efa5cf37419d
194 lines
7.0 KiB
C++
194 lines
7.0 KiB
C++
// Wild Magic Source Code
|
|
// David Eberly
|
|
// http://www.geometrictools.com
|
|
// Copyright (c) 1998-2007
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation; either version 2.1 of the License, or (at
|
|
// your option) any later version. The license is available for reading at
|
|
// either of the locations:
|
|
// http://www.gnu.org/copyleft/lgpl.html
|
|
// http://www.geometrictools.com/License/WildMagicLicense.pdf
|
|
// The license applies to versions 0 through 4 of Wild Magic.
|
|
//
|
|
// Version: 4.0.0 (2006/06/28)
|
|
|
|
#include "Wm4FoundationPCH.h"
|
|
#include "Wm4ParametricSurface.h"
|
|
#include "Wm4Matrix2.h"
|
|
|
|
namespace Wm4
|
|
{
|
|
//----------------------------------------------------------------------------
|
|
template <class Real>
|
|
ParametricSurface<Real>::ParametricSurface (Real fUMin, Real fUMax,
|
|
Real fVMin, Real fVMax, bool bRectangular)
|
|
{
|
|
assert(fUMin < fUMax && fVMin < fVMax);
|
|
|
|
m_fUMin = fUMin;
|
|
m_fUMax = fUMax;
|
|
m_fVMin = fVMin;
|
|
m_fVMax = fVMax;
|
|
m_bRectangular = bRectangular;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
template <class Real>
|
|
ParametricSurface<Real>::~ParametricSurface ()
|
|
{
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
template <class Real>
|
|
Real ParametricSurface<Real>::GetUMin () const
|
|
{
|
|
return m_fUMin;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
template <class Real>
|
|
Real ParametricSurface<Real>::GetUMax () const
|
|
{
|
|
return m_fUMax;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
template <class Real>
|
|
Real ParametricSurface<Real>::GetVMin () const
|
|
{
|
|
return m_fVMin;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
template <class Real>
|
|
Real ParametricSurface<Real>::GetVMax () const
|
|
{
|
|
return m_fVMax;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
template <class Real>
|
|
bool ParametricSurface<Real>::IsRectangular () const
|
|
{
|
|
return m_bRectangular;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
template <class Real>
|
|
void ParametricSurface<Real>::GetFrame (Real fU, Real fV,
|
|
Vector3<Real>& rkPosition, Vector3<Real>& rkTangent0,
|
|
Vector3<Real>& rkTangent1, Vector3<Real>& rkNormal) const
|
|
{
|
|
rkPosition = P(fU,fV);
|
|
|
|
rkTangent0 = PU(fU,fV);
|
|
rkTangent1 = PV(fU,fV);
|
|
rkTangent0.Normalize(); // T0
|
|
rkTangent1.Normalize(); // temporary T1 just to compute N
|
|
rkNormal = rkTangent0.UnitCross(rkTangent1); // N
|
|
|
|
// The normalized first derivatives are not necessarily orthogonal.
|
|
// Recompute T1 so that {T0,T1,N} is an orthonormal set.
|
|
rkTangent1 = rkNormal.Cross(rkTangent0);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
template <class Real>
|
|
void ParametricSurface<Real>::ComputePrincipalCurvatureInfo (Real fU, Real fV,
|
|
Real& rfCurv0, Real& rfCurv1, Vector3<Real>& rkDir0,
|
|
Vector3<Real>& rkDir1)
|
|
{
|
|
// Tangents: T0 = (x_u,y_u,z_u), T1 = (x_v,y_v,z_v)
|
|
// Normal: N = Cross(T0,T1)/Length(Cross(T0,T1))
|
|
// Metric Tensor: G = +- -+
|
|
// | Dot(T0,T0) Dot(T0,T1) |
|
|
// | Dot(T1,T0) Dot(T1,T1) |
|
|
// +- -+
|
|
//
|
|
// Curvature Tensor: B = +- -+
|
|
// | -Dot(N,T0_u) -Dot(N,T0_v) |
|
|
// | -Dot(N,T1_u) -Dot(N,T1_v) |
|
|
// +- -+
|
|
//
|
|
// Principal curvatures k are the generalized eigenvalues of
|
|
//
|
|
// Bw = kGw
|
|
//
|
|
// If k is a curvature and w=(a,b) is the corresponding solution to
|
|
// Bw = kGw, then the principal direction as a 3D vector is d = a*U+b*V.
|
|
//
|
|
// Let k1 and k2 be the principal curvatures. The mean curvature
|
|
// is (k1+k2)/2 and the Gaussian curvature is k1*k2.
|
|
|
|
// derivatives
|
|
Vector3<Real> kDerU = PU(fU,fV);
|
|
Vector3<Real> kDerV = PV(fU,fV);
|
|
Vector3<Real> kDerUU = PUU(fU,fV);
|
|
Vector3<Real> kDerUV = PUV(fU,fV);
|
|
Vector3<Real> kDerVV = PVV(fU,fV);
|
|
|
|
// metric tensor
|
|
Matrix2<Real> kMetricTensor;
|
|
kMetricTensor[0][0] = kDerU.Dot(kDerU);
|
|
kMetricTensor[0][1] = kDerU.Dot(kDerV);
|
|
kMetricTensor[1][0] = kMetricTensor[0][1];
|
|
kMetricTensor[1][1] = kDerV.Dot(kDerV);
|
|
|
|
// curvature tensor
|
|
Vector3<Real> kNormal = kDerU.UnitCross(kDerV);
|
|
Matrix2<Real> kCurvatureTensor;
|
|
kCurvatureTensor[0][0] = -kNormal.Dot(kDerUU);
|
|
kCurvatureTensor[0][1] = -kNormal.Dot(kDerUV);
|
|
kCurvatureTensor[1][0] = kCurvatureTensor[0][1];
|
|
kCurvatureTensor[1][1] = -kNormal.Dot(kDerVV);
|
|
|
|
// characteristic polynomial is 0 = det(B-kG) = c2*k^2+c1*k+c0
|
|
Real fC0 = kCurvatureTensor.Determinant();
|
|
Real fC1 = ((Real)2.0)*kCurvatureTensor[0][1]* kMetricTensor[0][1] -
|
|
kCurvatureTensor[0][0]*kMetricTensor[1][1] -
|
|
kCurvatureTensor[1][1]*kMetricTensor[0][0];
|
|
Real fC2 = kMetricTensor.Determinant();
|
|
|
|
// principal curvatures are roots of characteristic polynomial
|
|
Real fTemp = Math<Real>::Sqrt(Math<Real>::FAbs(fC1*fC1 -
|
|
((Real)4.0)*fC0*fC2));
|
|
Real fMult = ((Real)0.5)/fC2;
|
|
rfCurv0 = -fMult*(fC1+fTemp);
|
|
rfCurv1 = fMult*(-fC1+fTemp);
|
|
|
|
// principal directions are solutions to (B-kG)w = 0
|
|
// w1 = (b12-k1*g12,-(b11-k1*g11)) OR (b22-k1*g22,-(b12-k1*g12))
|
|
Real fA0 = kCurvatureTensor[0][1] - rfCurv0*kMetricTensor[0][1];
|
|
Real fA1 = rfCurv0*kMetricTensor[0][0] - kCurvatureTensor[0][0];
|
|
Real fLength = Math<Real>::Sqrt(fA0*fA0+fA1*fA1);
|
|
if (fLength >= Math<Real>::ZERO_TOLERANCE)
|
|
{
|
|
rkDir0 = fA0*kDerU + fA1*kDerV;
|
|
}
|
|
else
|
|
{
|
|
fA0 = kCurvatureTensor[1][1] - rfCurv0*kMetricTensor[1][1];
|
|
fA1 = rfCurv0*kMetricTensor[0][1] - kCurvatureTensor[0][1];
|
|
fLength = Math<Real>::Sqrt(fA0*fA0+fA1*fA1);
|
|
if (fLength >= Math<Real>::ZERO_TOLERANCE)
|
|
{
|
|
rkDir0 = fA0*kDerU + fA1*kDerV;
|
|
}
|
|
else
|
|
{
|
|
// umbilic (surface is locally sphere, any direction principal)
|
|
rkDir0 = kDerU;
|
|
}
|
|
}
|
|
rkDir0.Normalize();
|
|
|
|
// second tangent is cross product of first tangent and normal
|
|
rkDir1 = rkDir0.Cross(kNormal);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// explicit instantiation
|
|
//----------------------------------------------------------------------------
|
|
template WM4_FOUNDATION_ITEM
|
|
class ParametricSurface<float>;
|
|
|
|
template WM4_FOUNDATION_ITEM
|
|
class ParametricSurface<double>;
|
|
//----------------------------------------------------------------------------
|
|
}
|