Wm4MeshCurvature.cpp

Go to the documentation of this file.
00001 // Wild Magic Source Code
00002 // David Eberly
00003 // http://www.geometrictools.com
00004 // Copyright (c) 1998-2007
00005 //
00006 // This library is free software; you can redistribute it and/or modify it
00007 // under the terms of the GNU Lesser General Public License as published by
00008 // the Free Software Foundation; either version 2.1 of the License, or (at
00009 // your option) any later version.  The license is available for reading at
00010 // either of the locations:
00011 //     http://www.gnu.org/copyleft/lgpl.html
00012 //     http://www.geometrictools.com/License/WildMagicLicense.pdf
00013 // The license applies to versions 0 through 4 of Wild Magic.
00014 //
00015 // Version: 4.0.1 (2006/07/23)
00016 
00017 #include "Wm4FoundationPCH.h"
00018 #include "Wm4MeshCurvature.h"
00019 
00020 namespace Wm4
00021 {
00022 //----------------------------------------------------------------------------
00023 template <class Real>
00024 MeshCurvature<Real>::MeshCurvature (int iVQuantity,
00025     const Vector3<Real>* akVertex, int iTQuantity, const int* aiIndex)
00026 {
00027     m_iVQuantity = iVQuantity;
00028     m_akVertex = akVertex;
00029     m_iTQuantity = iTQuantity;
00030     m_aiIndex = aiIndex;
00031 
00032     // compute normal vectors
00033     m_akNormal = WM4_NEW Vector3<Real>[m_iVQuantity];
00034     memset(m_akNormal,0,m_iVQuantity*sizeof(Vector3<Real>));
00035     int i, iV0, iV1, iV2;
00036     for (i = 0; i < m_iTQuantity; i++)
00037     {
00038         // get vertex indices
00039         iV0 = *aiIndex++;
00040         iV1 = *aiIndex++;
00041         iV2 = *aiIndex++;
00042 
00043         // compute the normal (length provides a weighted sum)
00044         Vector3<Real> kEdge1 = m_akVertex[iV1] - m_akVertex[iV0];
00045         Vector3<Real> kEdge2 = m_akVertex[iV2] - m_akVertex[iV0];
00046         Vector3<Real> kNormal = kEdge1.Cross(kEdge2);
00047 
00048         m_akNormal[iV0] += kNormal;
00049         m_akNormal[iV1] += kNormal;
00050         m_akNormal[iV2] += kNormal;
00051     }
00052     for (i = 0; i < m_iVQuantity; i++)
00053     {
00054         m_akNormal[i].Normalize();
00055     }
00056 
00057     // compute the matrix of normal derivatives
00058     Matrix3<Real>* akDNormal = WM4_NEW Matrix3<Real>[m_iVQuantity];
00059     Matrix3<Real>* akWWTrn = WM4_NEW Matrix3<Real>[m_iVQuantity];
00060     Matrix3<Real>* akDWTrn = WM4_NEW Matrix3<Real>[m_iVQuantity];
00061     memset(akWWTrn,0,m_iVQuantity*sizeof(Matrix3<Real>));
00062     memset(akDWTrn,0,m_iVQuantity*sizeof(Matrix3<Real>));
00063 
00064     int iRow, iCol;
00065     aiIndex = m_aiIndex;
00066     for (i = 0; i < m_iTQuantity; i++)
00067     {
00068         // get vertex indices
00069         int aiV[3];
00070         aiV[0] = *aiIndex++;
00071         aiV[1] = *aiIndex++;
00072         aiV[2] = *aiIndex++;
00073 
00074         for (int j = 0; j < 3; j++)
00075         {
00076             iV0 = aiV[j];
00077             iV1 = aiV[(j+1)%3];
00078             iV2 = aiV[(j+2)%3];
00079 
00080             // Compute edge from V0 to V1, project to tangent plane of vertex,
00081             // and compute difference of adjacent normals.
00082             Vector3<Real> kE = m_akVertex[iV1] - m_akVertex[iV0];
00083             Vector3<Real> kW = kE - (kE.Dot(m_akNormal[iV0]))*m_akNormal[iV0];
00084             Vector3<Real> kD = m_akNormal[iV1] - m_akNormal[iV0];
00085             for (iRow = 0; iRow < 3; iRow++)
00086             {
00087                 for (iCol = 0; iCol < 3; iCol++)
00088                 {
00089                     akWWTrn[iV0][iRow][iCol] += kW[iRow]*kW[iCol];
00090                     akDWTrn[iV0][iRow][iCol] += kD[iRow]*kW[iCol];
00091                 }
00092             }
00093 
00094             // Compute edge from V0 to V2, project to tangent plane of vertex,
00095             // and compute difference of adjacent normals.
00096             kE = m_akVertex[iV2] - m_akVertex[iV0];
00097             kW = kE - (kE.Dot(m_akNormal[iV0]))*m_akNormal[iV0];
00098             kD = m_akNormal[iV2] - m_akNormal[iV0];
00099             for (iRow = 0; iRow < 3; iRow++)
00100             {
00101                 for (iCol = 0; iCol < 3; iCol++)
00102                 {
00103                     akWWTrn[iV0][iRow][iCol] += kW[iRow]*kW[iCol];
00104                     akDWTrn[iV0][iRow][iCol] += kD[iRow]*kW[iCol];
00105                 }
00106             }
00107         }
00108     }
00109 
00110     // Add in N*N^T to W*W^T for numerical stability.  In theory 0*0^T gets
00111     // added to D*W^T, but of course no update needed in the implementation.
00112     // Compute the matrix of normal derivatives.
00113     for (i = 0; i < m_iVQuantity; i++)
00114     {
00115         for (iRow = 0; iRow < 3; iRow++)
00116         {
00117             for (iCol = 0; iCol < 3; iCol++)
00118             {
00119                 akWWTrn[i][iRow][iCol] = ((Real)0.5)*akWWTrn[i][iRow][iCol] +
00120                     m_akNormal[i][iRow]*m_akNormal[i][iCol];
00121                 akDWTrn[i][iRow][iCol] *= (Real)0.5;
00122             }
00123         }
00124 
00125         akDNormal[i] = akDWTrn[i]*akWWTrn[i].Inverse();
00126     }
00127 
00128     WM4_DELETE[] akWWTrn;
00129     WM4_DELETE[] akDWTrn;
00130 
00131     // If N is a unit-length normal at a vertex, let U and V be unit-length
00132     // tangents so that {U, V, N} is an orthonormal set.  Define the matrix
00133     // J = [U | V], a 3-by-2 matrix whose columns are U and V.  Define J^T
00134     // to be the transpose of J, a 2-by-3 matrix.  Let dN/dX denote the
00135     // matrix of first-order derivatives of the normal vector field.  The
00136     // shape matrix is
00137     //   S = (J^T * J)^{-1} * J^T * dN/dX * J = J^T * dN/dX * J
00138     // where the superscript of -1 denotes the inverse.  (The formula allows
00139     // for J built from non-perpendicular vectors.) The matrix S is 2-by-2.
00140     // The principal curvatures are the eigenvalues of S.  If k is a principal
00141     // curvature and W is the 2-by-1 eigenvector corresponding to it, then
00142     // S*W = k*W (by definition).  The corresponding 3-by-1 tangent vector at
00143     // the vertex is called the principal direction for k, and is J*W.
00144     m_afMinCurvature = WM4_NEW Real[m_iVQuantity];
00145     m_afMaxCurvature = WM4_NEW Real[m_iVQuantity];
00146     m_akMinDirection = WM4_NEW Vector3<Real>[m_iVQuantity];
00147     m_akMaxDirection = WM4_NEW Vector3<Real>[m_iVQuantity];
00148     for (i = 0; i < m_iVQuantity; i++)
00149     {
00150         // compute U and V given N
00151         Vector3<Real> kU, kV;
00152         Vector3<Real>::GenerateComplementBasis(kU,kV,m_akNormal[i]);
00153 
00154         // Compute S = J^T * dN/dX * J.  In theory S is symmetric, but
00155         // because we have estimated dN/dX, we must slightly adjust our
00156         // calculations to make sure S is symmetric.
00157         Real fS01 = kU.Dot(akDNormal[i]*kV);
00158         Real fS10 = kV.Dot(akDNormal[i]*kU);
00159         Real fSAvr = ((Real)0.5)*(fS01+fS10);
00160         Matrix2<Real> kS
00161         (
00162             kU.Dot(akDNormal[i]*kU), fSAvr,
00163             fSAvr, kV.Dot(akDNormal[i]*kV)
00164         );
00165 
00166         // compute the eigenvalues of S (min and max curvatures)
00167         Real fTrace = kS[0][0] + kS[1][1];
00168         Real fDet = kS[0][0]*kS[1][1] - kS[0][1]*kS[1][0];
00169         Real fDiscr = fTrace*fTrace - ((Real)4.0)*fDet;
00170         Real fRootDiscr = Math<Real>::Sqrt(Math<Real>::FAbs(fDiscr));
00171         m_afMinCurvature[i] = ((Real)0.5)*(fTrace - fRootDiscr);
00172         m_afMaxCurvature[i] = ((Real)0.5)*(fTrace + fRootDiscr);
00173 
00174         // compute the eigenvectors of S
00175         Vector2<Real> kW0(kS[0][1],m_afMinCurvature[i]-kS[0][0]);
00176         Vector2<Real> kW1(m_afMinCurvature[i]-kS[1][1],kS[1][0]);
00177         if (kW0.SquaredLength() >= kW1.SquaredLength())
00178         {
00179             kW0.Normalize();
00180             m_akMinDirection[i] = kW0.X()*kU + kW0.Y()*kV;
00181         }
00182         else
00183         {
00184             kW1.Normalize();
00185             m_akMinDirection[i] = kW1.X()*kU + kW1.Y()*kV;
00186         }
00187 
00188         kW0 = Vector2<Real>(kS[0][1],m_afMaxCurvature[i]-kS[0][0]);
00189         kW1 = Vector2<Real>(m_afMaxCurvature[i]-kS[1][1],kS[1][0]);
00190         if (kW0.SquaredLength() >= kW1.SquaredLength())
00191         {
00192             kW0.Normalize();
00193             m_akMaxDirection[i] = kW0.X()*kU + kW0.Y()*kV;
00194         }
00195         else
00196         {
00197             kW1.Normalize();
00198             m_akMaxDirection[i] = kW1.X()*kU + kW1.Y()*kV;
00199         }
00200     }
00201 
00202     WM4_DELETE[] akDNormal;
00203 }
00204 //----------------------------------------------------------------------------
00205 template <class Real>
00206 MeshCurvature<Real>::~MeshCurvature ()
00207 {
00208     WM4_DELETE[] m_akNormal;
00209     WM4_DELETE[] m_afMinCurvature;
00210     WM4_DELETE[] m_afMaxCurvature;
00211     WM4_DELETE[] m_akMinDirection;
00212     WM4_DELETE[] m_akMaxDirection;
00213 }
00214 //----------------------------------------------------------------------------
00215 template <class Real>
00216 int MeshCurvature<Real>::GetVQuantity () const
00217 {
00218     return m_iVQuantity;
00219 }
00220 //----------------------------------------------------------------------------
00221 template <class Real>
00222 const Vector3<Real>* MeshCurvature<Real>::GetVertices () const
00223 {
00224     return m_akVertex;
00225 }
00226 //----------------------------------------------------------------------------
00227 template <class Real>
00228 int MeshCurvature<Real>::GetTQuantity () const
00229 {
00230     return m_iTQuantity;
00231 }
00232 //----------------------------------------------------------------------------
00233 template <class Real>
00234 const int* MeshCurvature<Real>::GetIndices () const
00235 {
00236     return m_aiIndex;
00237 }
00238 //----------------------------------------------------------------------------
00239 template <class Real>
00240 const Vector3<Real>* MeshCurvature<Real>::GetNormals () const
00241 {
00242     return m_akNormal;
00243 }
00244 //----------------------------------------------------------------------------
00245 template <class Real>
00246 const Real* MeshCurvature<Real>::GetMinCurvatures () const
00247 {
00248     return m_afMinCurvature;
00249 }
00250 //----------------------------------------------------------------------------
00251 template <class Real>
00252 const Real* MeshCurvature<Real>::GetMaxCurvatures () const
00253 {
00254     return m_afMaxCurvature;
00255 }
00256 //----------------------------------------------------------------------------
00257 template <class Real>
00258 const Vector3<Real>* MeshCurvature<Real>::GetMinDirections () const
00259 {
00260     return m_akMinDirection;
00261 }
00262 //----------------------------------------------------------------------------
00263 template <class Real>
00264 const Vector3<Real>* MeshCurvature<Real>::GetMaxDirections () const
00265 {
00266     return m_akMaxDirection;
00267 }
00268 //----------------------------------------------------------------------------
00269 
00270 //----------------------------------------------------------------------------
00271 // explicit instantiation
00272 //----------------------------------------------------------------------------
00273 template WM4_FOUNDATION_ITEM
00274 class MeshCurvature<float>;
00275 
00276 template WM4_FOUNDATION_ITEM
00277 class MeshCurvature<double>;
00278 //----------------------------------------------------------------------------
00279 }

Generated on Wed Nov 23 19:01:06 2011 for FreeCAD by  doxygen 1.6.1