void ParametricSurface<Real>::GetFrame (Real fU, Real fV,
    Vector3<Real>& kPosition, Vector3<Real>& kTangent0,
    Vector3<Real>& kTangent1, Vector3<Real>& kNormal) const
{
    kPosition = GetPosition(fU,fV);
    kTangent0 = GetDerivativeU(fU,fV);
    kTangent1 = GetDerivativeV(fU,fV);
    kTangent0.Normalize();
    kTangent1.Normalize();
    kNormal = kTangent0.UnitCross(kTangent1);
}
void ParametricSurface<Real>::GetFrame (Real u, Real v,
                                        Vector3<Real>& position, Vector3<Real>& tangent0,
                                        Vector3<Real>& tangent1, Vector3<Real>& normal) const
{
	position = P(u, v);

	tangent0 = PU(u, v);
	tangent1 = PV(u, v);
	tangent0.Normalize();  // T0
	tangent1.Normalize();  // temporary T1 just to compute N
	normal = tangent0.UnitCross(tangent1);  // N

	// The normalized first derivatives are not necessarily orthogonal.
	// Recompute T1 so that {T0,T1,N} is an orthonormal set.
	tangent1 = normal.Cross(tangent0);
}
bool ImplicitSurface<Real>::ComputePrincipalCurvatureInfo (
    const Vector3<Real>& rkP, Real& rfCurv0, Real& rfCurv1,
    Vector3<Real>& rkDir0, Vector3<Real>& rkDir1)
{
    // Principal curvatures and directions for implicitly defined surfaces
    // F(x,y,z) = 0.
    //
    // DF = (Fx,Fy,Fz), L = Length(DF)
    //
    // D^2 F = +-           -+
    //         | Fxx Fxy Fxz |
    //         | Fxy Fyy Fyz |
    //         | Fxz Fyz Fzz |
    //         +-           -+
    //
    // adj(D^2 F) = +-                                                 -+
    //              | Fyy*Fzz-Fyz*Fyz  Fyz*Fxz-Fxy*Fzz  Fxy*Fyz-Fxz*Fyy |
    //              | Fyz*Fxz-Fxy*Fzz  Fxx*Fzz-Fxz*Fxz  Fxy*Fxz-Fxx*Fyz |
    //              | Fxy*Fyz-Fxz*Fyy  Fxy*Fxz-Fxx*Fyz  Fxx*Fyy-Fxy*Fxy |
    //              +-                                                 -+
    //
    // Gaussian curvature = [DF^t adj(D^2 F) DF]/L^4
    // 
    // Mean curvature = 0.5*[trace(D^2 F)/L - (DF^t D^2 F DF)/L^3]

    // first derivatives
    Real fFX = FX(rkP);
    Real fFY = FY(rkP);
    Real fFZ = FZ(rkP);
    Real fL = Math<Real>::Sqrt(fFX*fFX + fFY*fFY + fFZ*fFZ);
    if (fL <= Math<Real>::ZERO_TOLERANCE)
    {
        return false;
    }

    Real fFXFX = fFX*fFX;
    Real fFXFY = fFX*fFY;
    Real fFXFZ = fFX*fFZ;
    Real fFYFY = fFY*fFY;
    Real fFYFZ = fFY*fFZ;
    Real fFZFZ = fFZ*fFZ;

    Real fInvL = ((Real)1.0)/fL;
    Real fInvL2 = fInvL*fInvL;
    Real fInvL3 = fInvL*fInvL2;
    Real fInvL4 = fInvL2*fInvL2;

    // second derivatives
    Real fFXX = FXX(rkP);
    Real fFXY = FXY(rkP);
    Real fFXZ = FXZ(rkP);
    Real fFYY = FYY(rkP);
    Real fFYZ = FYZ(rkP);
    Real fFZZ = FZZ(rkP);

    // mean curvature
    Real fMCurv = ((Real)0.5)*fInvL3*(fFXX*(fFYFY+fFZFZ) + fFYY*(fFXFX+fFZFZ)
        + fFZZ*(fFXFX+fFYFY)
        - ((Real)2.0)*(fFXY*fFXFY+fFXZ*fFXFZ+fFYZ*fFYFZ));

    // Gaussian curvature
    Real fGCurv = fInvL4*(fFXFX*(fFYY*fFZZ-fFYZ*fFYZ)
        + fFYFY*(fFXX*fFZZ-fFXZ*fFXZ) + fFZFZ*(fFXX*fFYY-fFXY*fFXY)
        + ((Real)2.0)*(fFXFY*(fFXZ*fFYZ-fFXY*fFZZ)
        + fFXFZ*(fFXY*fFYZ-fFXZ*fFYY)
        + fFYFZ*(fFXY*fFXZ-fFXX*fFYZ)));

    // solve for principal curvatures
    Real fDiscr = Math<Real>::Sqrt(Math<Real>::FAbs(fMCurv*fMCurv-fGCurv));
    rfCurv0 = fMCurv - fDiscr;
    rfCurv1 = fMCurv + fDiscr;

    Real fM00 = ((-(Real)1.0 + fFXFX*fInvL2)*fFXX)*fInvL + (fFXFY*fFXY)*fInvL3
        + (fFXFZ*fFXZ)*fInvL3;
    Real fM01 = ((-(Real)1.0 + fFXFX*fInvL2)*fFXY)*fInvL + (fFXFY*fFYY)*fInvL3
        + (fFXFZ*fFYZ)*fInvL3;
    Real fM02 = ((-(Real)1.0 + fFXFX*fInvL2)*fFXZ)*fInvL + (fFXFY*fFYZ)*fInvL3
        + (fFXFZ*fFZZ)*fInvL3;
    Real fM10 = (fFXFY*fFXX)*fInvL3 + ((-(Real)1.0 + fFYFY*fInvL2)*fFXY)*fInvL
        + (fFYFZ*fFXZ)*fInvL3;
    Real fM11 = (fFXFY*fFXY)*fInvL3 + ((-(Real)1.0 + fFYFY*fInvL2)*fFYY)*fInvL
        + (fFYFZ*fFYZ)*fInvL3;
    Real fM12 = (fFXFY*fFXZ)*fInvL3 + ((-(Real)1.0 + fFYFY*fInvL2)*fFYZ)*fInvL
        + (fFYFZ*fFZZ)*fInvL3;
    Real fM20 = (fFXFZ*fFXX)*fInvL3 + (fFYFZ*fFXY)*fInvL3 + ((-(Real)1.0
        + fFZFZ*fInvL2)*fFXZ)*fInvL;
    Real fM21 = (fFXFZ*fFXY)*fInvL3 + (fFYFZ*fFYY)*fInvL3 + ((-(Real)1.0
        + fFZFZ*fInvL2)*fFYZ)*fInvL;
    Real fM22 = (fFXFZ*fFXZ)*fInvL3 + (fFYFZ*fFYZ)*fInvL3 + ((-(Real)1.0
        + fFZFZ*fInvL2)*fFZZ)*fInvL;

    // solve for principal directions
    Real fTmp1 = fM00 + rfCurv0;
    Real fTmp2 = fM11 + rfCurv0;
    Real fTmp3 = fM22 + rfCurv0;

    Vector3<Real> akU[3];
    Real afLength[3];

    akU[0].X() = fM01*fM12-fM02*fTmp2;
    akU[0].Y() = fM02*fM10-fM12*fTmp1;
    akU[0].Z() = fTmp1*fTmp2-fM01*fM10;
    afLength[0] = akU[0].Length();

    akU[1].X() = fM01*fTmp3-fM02*fM21;
    akU[1].Y() = fM02*fM20-fTmp1*fTmp3;
    akU[1].Z() = fTmp1*fM21-fM01*fM20;
    afLength[1] = akU[1].Length();

    akU[2].X() = fTmp2*fTmp3-fM12*fM21;
    akU[2].Y() = fM12*fM20-fM10*fTmp3;
    akU[2].Z() = fM10*fM21-fM20*fTmp2;
    afLength[2] = akU[2].Length();

    int iMaxIndex = 0;
    Real fMax = afLength[0];
    if (afLength[1] > fMax)
    {
        iMaxIndex = 1;
        fMax = afLength[1];
    }
    if (afLength[2] > fMax)
    {
        iMaxIndex = 2;
    }

    Real fInvLength = ((Real)1.0)/afLength[iMaxIndex];
    akU[iMaxIndex] *= fInvLength;

    rkDir1 = akU[iMaxIndex];
    rkDir0 = rkDir1.UnitCross(Vector3<Real>(fFX,fFY,fFZ));

    return true;
}
Example #4
0
bool ImplicitSurface<Real>::ComputePrincipalCurvatureInfo (
    const Vector3<Real>& pos, Real& curv0, Real& curv1, Vector3<Real>& dir0,
    Vector3<Real>& dir1)
{
    // Principal curvatures and directions for implicitly defined surfaces
    // F(x,y,z) = 0.
    //
    // DF = (Fx,Fy,Fz), L = Length(DF)
    //
    // D^2 F = +-           -+
    //         | Fxx Fxy Fxz |
    //         | Fxy Fyy Fyz |
    //         | Fxz Fyz Fzz |
    //         +-           -+
    //
    // adj(D^2 F) = +-                                                 -+
    //              | Fyy*Fzz-Fyz*Fyz  Fyz*Fxz-Fxy*Fzz  Fxy*Fyz-Fxz*Fyy |
    //              | Fyz*Fxz-Fxy*Fzz  Fxx*Fzz-Fxz*Fxz  Fxy*Fxz-Fxx*Fyz |
    //              | Fxy*Fyz-Fxz*Fyy  Fxy*Fxz-Fxx*Fyz  Fxx*Fyy-Fxy*Fxy |
    //              +-                                                 -+
    //
    // Gaussian curvature = [DF^t adj(D^2 F) DF]/L^4
    // 
    // Mean curvature = 0.5*[trace(D^2 F)/L - (DF^t D^2 F DF)/L^3]

    // first derivatives
    Real fx = FX(pos);
    Real fy = FY(pos);
    Real fz = FZ(pos);
    Real fLength = Math<Real>::Sqrt(fx*fx + fy*fy + fz*fz);
    if (fLength <= Math<Real>::ZERO_TOLERANCE)
    {
        return false;
    }

    Real fxfx = fx*fx;
    Real fxfy = fx*fy;
    Real fxfz = fx*fz;
    Real fyfy = fy*fy;
    Real fyfz = fy*fz;
    Real fzfz = fz*fz;

    Real invLength = ((Real)1)/fLength;
    Real invLength2 = invLength*invLength;
    Real invLength3 = invLength*invLength2;
    Real invLength4 = invLength2*invLength2;

    // second derivatives
    Real fxx = FXX(pos);
    Real fxy = FXY(pos);
    Real fxz = FXZ(pos);
    Real fyy = FYY(pos);
    Real fyz = FYZ(pos);
    Real fzz = FZZ(pos);

    // mean curvature
    Real meanCurv = ((Real)0.5)*invLength3*(fxx*(fyfy + fzfz) +
        fyy*(fxfx + fzfz) + fzz*(fxfx + fyfy) - ((Real)2)*(fxy*fxfy + fxz*fxfz +
        fyz*fyfz));

    // Gaussian curvature
    Real gaussCurv = invLength4*(fxfx*(fyy*fzz - fyz*fyz)
        + fyfy*(fxx*fzz - fxz*fxz) + fzfz*(fxx*fyy - fxy*fxy)
        + ((Real)2)*(fxfy*(fxz*fyz - fxy*fzz) + fxfz*(fxy*fyz - fxz*fyy)
        + fyfz*(fxy*fxz - fxx*fyz)));

    // solve for principal curvatures
    Real discr = Math<Real>::Sqrt(Math<Real>::FAbs(meanCurv*meanCurv-gaussCurv));
    curv0 = meanCurv - discr;
    curv1 = meanCurv + discr;

    Real m00 = ((-(Real)1 + fxfx*invLength2)*fxx)*invLength +
        (fxfy*fxy)*invLength3 + (fxfz*fxz)*invLength3;
    Real m01 = ((-(Real)1 + fxfx*invLength2)*fxy)*invLength +
        (fxfy*fyy)*invLength3 + (fxfz*fyz)*invLength3;
    Real m02 = ((-(Real)1 + fxfx*invLength2)*fxz)*invLength +
        (fxfy*fyz)*invLength3 + (fxfz*fzz)*invLength3;
    Real m10 = (fxfy*fxx)*invLength3 +
        ((-(Real)1 + fyfy*invLength2)*fxy)*invLength + (fyfz*fxz)*invLength3;
    Real m11 = (fxfy*fxy)*invLength3 +
        ((-(Real)1 + fyfy*invLength2)*fyy)*invLength + (fyfz*fyz)*invLength3;
    Real m12 = (fxfy*fxz)*invLength3 +
        ((-(Real)1 + fyfy*invLength2)*fyz)*invLength + (fyfz*fzz)*invLength3;
    Real m20 = (fxfz*fxx)*invLength3 + (fyfz*fxy)*invLength3 +
        ((-(Real)1 + fzfz*invLength2)*fxz)*invLength;
    Real m21 = (fxfz*fxy)*invLength3 + (fyfz*fyy)*invLength3 +
        ((-(Real)1 + fzfz*invLength2)*fyz)*invLength;
    Real m22 = (fxfz*fxz)*invLength3 + (fyfz*fyz)*invLength3 +
        ((-(Real)1 + fzfz*invLength2)*fzz)*invLength;

    // solve for principal directions
    Real tmp1 = m00 + curv0;
    Real tmp2 = m11 + curv0;
    Real tmp3 = m22 + curv0;

    Vector3<Real> U[3];
    Real lengths[3];

    U[0].X() = m01*m12-m02*tmp2;
    U[0].Y() = m02*m10-m12*tmp1;
    U[0].Z() = tmp1*tmp2-m01*m10;
    lengths[0] = U[0].Length();

    U[1].X() = m01*tmp3-m02*m21;
    U[1].Y() = m02*m20-tmp1*tmp3;
    U[1].Z() = tmp1*m21-m01*m20;
    lengths[1] = U[1].Length();

    U[2].X() = tmp2*tmp3-m12*m21;
    U[2].Y() = m12*m20-m10*tmp3;
    U[2].Z() = m10*m21-m20*tmp2;
    lengths[2] = U[2].Length();

    int maxIndex = 0;
    Real maxValue = lengths[0];
    if (lengths[1] > maxValue)
    {
        maxIndex = 1;
        maxValue = lengths[1];
    }
    if (lengths[2] > maxValue)
    {
        maxIndex = 2;
    }

    invLength = ((Real)1)/lengths[maxIndex];
    U[maxIndex] *= invLength;

    dir1 = U[maxIndex];
    dir0 = dir1.UnitCross(Vector3<Real>(fx, fy, fz));

    return true;
}
void ParametricSurface<Real>::ComputePrincipalCurvatureInfo (Real u, Real v,
        Real& curv0, Real& curv1, Vector3<Real>& dir0,
        Vector3<Real>& dir1)
{
	// 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.

	// Compute derivatives.
	Vector3<Real> derU = PU(u,v);
	Vector3<Real> derV = PV(u,v);
	Vector3<Real> derUU = PUU(u,v);
	Vector3<Real> derUV = PUV(u,v);
	Vector3<Real> derVV = PVV(u,v);

	// Compute the metric tensor.
	Matrix2<Real> metricTensor;
	metricTensor[0][0] = derU.Dot(derU);
	metricTensor[0][1] = derU.Dot(derV);
	metricTensor[1][0] = metricTensor[0][1];
	metricTensor[1][1] = derV.Dot(derV);

	// Compute the curvature tensor.
	Vector3<Real> normal = derU.UnitCross(derV);
	Matrix2<Real> curvatureTensor;
	curvatureTensor[0][0] = -normal.Dot(derUU);
	curvatureTensor[0][1] = -normal.Dot(derUV);
	curvatureTensor[1][0] = curvatureTensor[0][1];
	curvatureTensor[1][1] = -normal.Dot(derVV);

	// Characteristic polynomial is 0 = det(B-kG) = c2*k^2+c1*k+c0.
	Real c0 = curvatureTensor.Determinant();
	Real c1 = ((Real)2)*curvatureTensor[0][1]* metricTensor[0][1] -
	          curvatureTensor[0][0]*metricTensor[1][1] -
	          curvatureTensor[1][1]*metricTensor[0][0];
	Real c2 = metricTensor.Determinant();

	// Principal curvatures are roots of characteristic polynomial.
	Real temp = Math<Real>::Sqrt(Math<Real>::FAbs(c1*c1 - ((Real)4)*c0*c2));
	Real mult = ((Real)0.5)/c2;
	curv0 = -mult*(c1+temp);
	curv1 = mult*(-c1+temp);

	// Principal directions are solutions to (B-kG)w = 0,
	// w1 = (b12-k1*g12,-(b11-k1*g11)) OR (b22-k1*g22,-(b12-k1*g12)).
	Real a0 = curvatureTensor[0][1] - curv0*metricTensor[0][1];
	Real a1 = curv0*metricTensor[0][0] - curvatureTensor[0][0];
	Real length = Math<Real>::Sqrt(a0*a0 + a1*a1);
	if (length >= Math<Real>::ZERO_TOLERANCE)
	{
		dir0 = a0*derU + a1*derV;
	}
	else
	{
		a0 = curvatureTensor[1][1] - curv0*metricTensor[1][1];
		a1 = curv0*metricTensor[0][1] - curvatureTensor[0][1];
		length = Math<Real>::Sqrt(a0*a0 + a1*a1);
		if (length >= Math<Real>::ZERO_TOLERANCE)
		{
			dir0 = a0*derU + a1*derV;
		}
		else
		{
			// Umbilic (surface is locally sphere, any direction principal).
			dir0 = derU;
		}
	}
	dir0.Normalize();

	// Second tangent is cross product of first tangent and normal.
	dir1 = dir0.Cross(normal);
}
void ParametricSurface<Real>::ComputePrincipalCurvatureInfo (Real fU, Real fV,
    Real& rfCurv0, Real& rfCurv1, Vector3<Real>& rkDir0,
    Vector3<Real>& rkDir1)
{
    // Tangents:  U = (x_s,y_s,z_s), V = (x_t,y_t,z_t)
    // Normal:    N = Cross(U,V)/Length(Cross(U,V))
    // Metric Tensor:    G = +-                  -+
    //                       | Dot(U,U)  Dot(U,V) |
    //                       | Dot(V,U)  Dot(V,V) |
    //                       +-                  -+
    //
    // Curvature Tensor:  B = +-                        -+
    //                        | -Dot(N,U_s)  -Dot(N,U_t) |
    //                        | -Dot(N,V_s)  -Dot(N,V_t) |
    //                        +-                        -+
    //
    // 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 = GetDerivativeU(fU,fV);
    Vector3<Real> kDerV = GetDerivativeV(fU,fV);
    Vector3<Real> kDerUU = GetDerivativeUU(fU,fV);
    Vector3<Real> kDerUV = GetDerivativeUV(fU,fV);
    Vector3<Real> kDerVV = GetDerivativeVV(fU,fV);

    // metric tensor
    Matrix3<Real> kMetricTensor;
    kMetricTensor[0][0] = kDerU.Dot(kDerU);
    kMetricTensor[0][1] = kDerU.Dot(kDerV);
    kMetricTensor[1][0] = kMetricTensor[1][0];
    kMetricTensor[1][1] = kDerV.Dot(kDerV);

    // curvature tensor
    Vector3<Real> kNormal = kDerU.UnitCross(kDerV);
    Matrix3<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));
    rfCurv0 = -((Real)0.5)*(fC1+fTemp);
    rfCurv1 = ((Real)0.5)*(-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>::EPSILON )
    {
        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>::EPSILON )
        {
            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);
}