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; }
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); }