瀏覽代碼

- added tutorial for principal curvature directions
- fixed bug in viewer for line rendering
- renamed draw overlay functions to add


Former-commit-id: 0a556f42c9062433eccb99592eb46f16f69f94e4

Daniele Panozzo 11 年之前
父節點
當前提交
f692781ff9

+ 132 - 122
include/igl/principal_curvature.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "principal_curvature.h"
 #include <iostream>
@@ -51,12 +51,12 @@ public:
   class Quadric
   {
   public:
-    
+
     IGL_INLINE Quadric ()
     {
       a() = b() = c() = d() = e() = 1.0;
     }
-    
+
     IGL_INLINE Quadric(double av, double bv, double cv, double dv, double ev)
     {
       a() = av;
@@ -65,46 +65,46 @@ public:
       d() = dv;
       e() = ev;
     }
-    
+
     IGL_INLINE double& a() { return data[0];}
     IGL_INLINE double& b() { return data[1];}
     IGL_INLINE double& c() { return data[2];}
     IGL_INLINE double& d() { return data[3];}
     IGL_INLINE double& e() { return data[4];}
-    
+
     double data[5];
-    
+
     IGL_INLINE double evaluate(double u, double v)
     {
       return a()*u*u + b()*u*v + c()*v*v + d()*u + e()*v;
     }
-    
+
     IGL_INLINE double du(double u, double v)
     {
       return 2.0*a()*u + b()*v + d();
     }
-    
+
     IGL_INLINE double dv(double u, double v)
     {
       return 2.0*c()*v + b()*u + e();
     }
-    
+
     IGL_INLINE double duv(double u, double v)
     {
       return b();
     }
-    
+
     IGL_INLINE double duu(double u, double v)
     {
       return 2.0*a();
     }
-    
+
     IGL_INLINE double dvv(double u, double v)
     {
       return 2.0*c();
     }
-    
-    
+
+
     IGL_INLINE static Quadric fit(std::vector<Eigen::Vector3d> &VV, bool zeroDetCheck, bool svd)
     {
       using namespace std;
@@ -118,67 +118,67 @@ public:
       Eigen::MatrixXd A(VV.size(),5);
       Eigen::MatrixXd b(VV.size(),1);
       Eigen::MatrixXd sol(5,1);
-      
+
       for(unsigned int c=0; c < VV.size(); ++c)
       {
         double u = VV[c][0];
         double v = VV[c][1];
         double n = VV[c][2];
-        
+
         A(c,0) = u*u;
         A(c,1) = u*v;
         A(c,2) = v*v;
         A(c,3) = u;
         A(c,4) = v;
-        
+
         b(c) = n;
       }
-      
+
       sol=A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
 
       return Quadric(sol(0),sol(1),sol(2),sol(3),sol(4));
     }
   };
-  
+
 public:
-  
+
   Eigen::MatrixXd vertices;
   // Face list of current mesh    (#F x 3) or (#F x 4)
   // The i-th row contains the indices of the vertices that forms the i-th face in ccw order
   Eigen::MatrixXi faces;
-  
+
   std::vector<std::vector<int> > vertex_to_vertices;
   std::vector<std::vector<int> > vertex_to_faces;
   std::vector<std::vector<int> > vertex_to_faces_index;
   Eigen::MatrixXd face_normals;
   Eigen::MatrixXd vertex_normals;
-  
+
   /* Size of the neighborhood */
   double sphereRadius;
   int kRing;
-  
+
   bool localMode; /* Use local mode */
   bool projectionPlaneCheck; /* Check collected vertices on tangent plane */
   bool montecarlo;
   bool svd; /* Use svd calculation instead of pseudoinverse */
   bool zeroDetCheck; /* Check if the determinant is close to zero */
   unsigned int montecarloN;
-  
+
   searchType st; /* Use either a sphere search or a k-ring search */
   normalType nt;
-  
+
   double lastRadius;
   double scaledRadius;
   std::string lastMeshName;
-  
+
   /* Benchmark related variables */
   bool expStep; /* True if we want the radius to increase exponentially */
   int step;  /* If expStep==false, by how much rhe radius increases on every step */
   int maxSize; /* The maximum limit of the radius in the benchmark */
-  
+
   IGL_INLINE CurvatureCalculator();
   IGL_INLINE void init(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
-  
+
   IGL_INLINE void finalEigenStuff (int, std::vector<Eigen::Vector3d>, Quadric );
   IGL_INLINE void fitQuadric (Eigen::Vector3d, std::vector<Eigen::Vector3d> ref, const  std::vector<int>& , Quadric *);
   IGL_INLINE void applyProjOnPlane(Eigen::Vector3d, std::vector<int>, std::vector<int>&);
@@ -192,48 +192,48 @@ public:
   IGL_INLINE void computeCurvature();
   IGL_INLINE void printCurvature(std::string outpath);
   IGL_INLINE double getAverageEdge();
-  
+
   IGL_INLINE static int rotateForward (float *v0, float *v1, float *v2)
   {
     float t;
-    
+
     if (abs(*v2) >= abs(*v1) && abs(*v2) >= abs(*v0))
       return 0;
-    
+
     t = *v0;
     *v0 = *v2;
     *v2 = *v1;
     *v1 = t;
-    
+
     return 1 + rotateForward (v0, v1, v2);
   }
-  
+
   IGL_INLINE static void rotateBackward (int nr, float *v0, float *v1, float *v2)
   {
     float t;
-    
+
     if (nr == 0)
       return;
-    
+
     t = *v2;
     *v2 = *v0;
     *v0 = *v1;
     *v1 = t;
-    
+
     rotateBackward (nr - 1, v0, v1, v2);
   }
-  
+
   IGL_INLINE static Eigen::Vector3d chooseMax (Eigen::Vector3d n, Eigen::Vector3d abc, float ab)
   {
     int i, max_i;
     float max_sp;
     Eigen::Vector3d nt[8];
-    
+
     n.normalize ();
     abc.normalize ();
-    
+
     max_sp = - std::numeric_limits<float>::max();
-    
+
     for (i = 0; i < 4; i++)
     {
       nt[i] = n;
@@ -243,16 +243,16 @@ public:
         {
           case 0:
             break;
-            
+
           case 1:
             nt[i][2] = -n[2];
             break;
-            
+
           case 2:
             nt[i][0] = -n[0];
             nt[i][1] = -n[1];
             break;
-            
+
           case 3:
             nt[i][0] = -n[0];
             nt[i][1] = -n[1];
@@ -267,33 +267,33 @@ public:
           case 0:
             nt[i][0] = -n[0];
             break;
-            
+
           case 1:
             nt[i][1] = -n[1];
             break;
-            
+
           case 2:
             nt[i][0] = -n[0];
             nt[i][2] = -n[2];
             break;
-            
+
           case 3:
             nt[i][1] = -n[1];
             nt[i][2] = -n[2];
             break;
         }
       }
-      
+
       if (nt[i].dot(abc) > max_sp)
       {
         max_sp = nt[i].dot(abc);
         max_i = i;
       }
     }
-    
+
     return nt[max_i];
   }
-  
+
 };
 
 class comparer
@@ -325,11 +325,11 @@ IGL_INLINE void CurvatureCalculator::init(const Eigen::MatrixXd& V, const Eigen:
 {
   // Normalize vertices
   vertices = V;
-  
+
 //  vertices = vertices.array() - vertices.minCoeff();
 //  vertices = vertices.array() / vertices.maxCoeff();
 //  vertices = vertices.array() * (1.0/igl::avg_edge_length(V,F));
-  
+
   faces = F;
   igl::adjacency_list(F, vertex_to_vertices);
   igl::vf(V, F, vertex_to_faces, vertex_to_faces_index);
@@ -341,14 +341,14 @@ IGL_INLINE void CurvatureCalculator::fitQuadric (Eigen::Vector3d v, std::vector<
 {
   std::vector<Eigen::Vector3d> points;
   points.reserve (vv.size());
-  
+
   for (unsigned int i = 0; i < vv.size(); ++i) {
-    
+
     Eigen::Vector3d  cp = vertices.row(vv[i]);
-    
+
     // vtang non e` il v tangente!!!
     Eigen::Vector3d  vTang = cp - v;
-    
+
     double x = vTang.dot(ref[0]);
     double y = vTang.dot(ref[1]);
     double z = vTang.dot(ref[2]);
@@ -359,13 +359,13 @@ IGL_INLINE void CurvatureCalculator::fitQuadric (Eigen::Vector3d v, std::vector<
 
 IGL_INLINE void CurvatureCalculator::finalEigenStuff (int i, std::vector<Eigen::Vector3d> ref, Quadric q)
 {
-  
+
   double a = q.a();
   double b = q.b();
   double c = q.c();
   double d = q.d();
   double e = q.e();
-  
+
 //  if (fabs(a) < 10e-8 || fabs(b) < 10e-8)
 //  {
 //    std::cout << "Degenerate quadric: " << i << std::endl;
@@ -374,52 +374,52 @@ IGL_INLINE void CurvatureCalculator::finalEigenStuff (int i, std::vector<Eigen::
   double E = 1.0 + d*d;
   double F = d*e;
   double G = 1.0 + e*e;
-  
+
   Eigen::Vector3d n = Eigen::Vector3d(-d,-e,1.0).normalized();
-  
+
   double L = 2.0 * a * n[2];
   double M = b * n[2];
   double N = 2 * c * n[2];
-  
-  
+
+
   // ----------------- Eigen stuff
   Eigen::Matrix2d m;
   m << L*G - M*F, M*E-L*F, M*E-L*F, N*E-M*F;
   m = m / (E*G-F*F);
   Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eig(m);
-  
+
   Eigen::Vector2d c_val = eig.eigenvalues();
   Eigen::Matrix2d c_vec = eig.eigenvectors();
 
   // std::cerr << "c_val:" << c_val << std::endl;
   // std::cerr << "c_vec:" << c_vec << std::endl;
-  
+
   // std::cerr << "c_vec:" << c_vec(0) << " "  << c_vec(1) << std::endl;
 
   c_val = -c_val;
-  
+
   Eigen::Vector3d v1, v2;
   v1[0] = c_vec(0);
   v1[1] = c_vec(1);
   v1[2] = 0; //d * v1[0] + e * v1[1];
-  
+
   v2[0] = c_vec(2);
   v2[1] = c_vec(3);
   v2[2] = 0; //d * v2[0] + e * v2[1];
-  
-  
+
+
   // v1 = v1.normalized();
   // v2 = v2.normalized();
-  
+
   Eigen::Vector3d v1global = ref[0] * v1[0] + ref[1] * v1[1] + ref[2] * v1[2];
   Eigen::Vector3d v2global = ref[0] * v2[0] + ref[1] * v2[1] + ref[2] * v2[2];
-  
+
   v1global.normalize();
   v2global.normalize();
-  
+
   v1global *= c_val(0);
   v2global *= c_val(1);
-  
+
   if (c_val[0] > c_val[1])
   {
     curv[i]=std::vector<double>(2);
@@ -532,12 +532,12 @@ IGL_INLINE Eigen::Vector3d CurvatureCalculator::project(Eigen::Vector3d v, Eigen
 
 IGL_INLINE void CurvatureCalculator::computeReferenceFrame(int i, Eigen::Vector3d normal, std::vector<Eigen::Vector3d>& ref )
 {
-  
+
   Eigen::Vector3d longest_v=Eigen::Vector3d::Zero();
   longest_v=Eigen::Vector3d(vertices.row(vertex_to_vertices[i][0]));
-  
+
   longest_v=(project(vertices.row(i),longest_v,normal)-Eigen::Vector3d(vertices.row(i))).normalized();
-  
+
   /* L'ultimo asse si ottiene come prodotto vettoriale tra i due
    * calcolati */
   Eigen::Vector3d y_axis=(normal.cross(longest_v)).normalized();
@@ -551,7 +551,7 @@ IGL_INLINE void CurvatureCalculator::getAverageNormal(int j, std::vector<int> vv
   normal=(vertex_normals.row(j)).normalized();
   if (localMode)
     return;
-  
+
   for (unsigned int i=0; i<vv.size(); i++)
   {
     normal+=vertex_normals.row(vv[i]).normalized();
@@ -565,9 +565,9 @@ IGL_INLINE void CurvatureCalculator::getProjPlane(int j, std::vector<int> vv, Ei
   float a, b, c;
   float nx, ny, nz;
   float abcq;
-  
+
   a = b = c = 0;
-  
+
   if (localMode)
   {
     for (unsigned int i=0; i<vertex_to_faces.at(j).size(); ++i)
@@ -594,7 +594,7 @@ IGL_INLINE void CurvatureCalculator::getProjPlane(int j, std::vector<int> vv, Ei
   nz = sqrt (1 - nx*nx - ny*ny);
   rotateBackward (nr, &a, &b, &c);
   rotateBackward (nr, &nx, &ny, &nz);
-  
+
   ppn = chooseMax (Eigen::Vector3d(nx, ny, nz), Eigen::Vector3d (a, b, c), a * b);
   ppn.normalize();
 }
@@ -604,21 +604,21 @@ IGL_INLINE double CurvatureCalculator::getAverageEdge()
 {
   double sum = 0;
   int count = 0;
-  
+
   for (int i = 0; i<faces.rows(); i++)
   {
     for (short unsigned j=0; j<3; j++)
     {
       Eigen::Vector3d p1=vertices.row(faces.row(i)[j]);
       Eigen::Vector3d p2=vertices.row(faces.row(i)[(j+1)%3]);
-      
+
       double l = (p1-p2).norm();
-      
+
       sum+=l;
       ++count;
     }
   }
-  
+
   return (sum/(double)count);
 }
 
@@ -637,7 +637,7 @@ IGL_INLINE void CurvatureCalculator::applyMontecarlo(std::vector<int>& vin, std:
     *vout = vin;
     return;
   }
-  
+
   float p = ((float) montecarloN) / (float) vin.size();
   for (std::vector<int>::iterator vpi = vin.begin(); vpi != vin.end(); ++vpi)
   {
@@ -652,27 +652,27 @@ IGL_INLINE void CurvatureCalculator::applyMontecarlo(std::vector<int>& vin, std:
 IGL_INLINE void CurvatureCalculator::computeCurvature()
 {
   using namespace std;
-  
+
   //CHECK che esista la mesh
   size_t vertices_count=vertices.rows() ;
-  
+
   if (vertices_count <=0)
     return;
-  
+
   curvDir=std::vector< std::vector<Eigen::Vector3d> >(vertices_count);
   curv=std::vector<std::vector<double> >(vertices_count);
-  
-  
-  
+
+
+
   scaledRadius=getAverageEdge()*sphereRadius;
-  
+
   std::vector<int> vv;
   std::vector<int> vvtmp;
   Eigen::Vector3d normal;
-  
+
   //double time_spent;
   //double searchtime=0, ref_time=0, fit_time=0, final_time=0;
-  
+
   for (size_t i=0; i<vertices_count; ++i)
   {
     vv.clear();
@@ -690,7 +690,7 @@ IGL_INLINE void CurvatureCalculator::computeCurvature()
         fprintf(stderr,"Error: search type not recognized");
         return;
     }
-    
+
     std::vector<Eigen::Vector3d> ref(3);
     if (vv.size()<6)
     {
@@ -709,7 +709,7 @@ IGL_INLINE void CurvatureCalculator::computeCurvature()
         fprintf(stderr,"Error: normal type not recognized");
         return;
     }
-    
+
     if (projectionPlaneCheck)
     {
       vvtmp.reserve (vv.size ());
@@ -717,7 +717,7 @@ IGL_INLINE void CurvatureCalculator::computeCurvature()
       if (vvtmp.size() >= 6)
         vv = vvtmp;
     }
-    
+
     if (vv.size()<6)
     {
       std::cerr << "Could not compute curvature of radius " << scaledRadius << endl;
@@ -731,16 +731,16 @@ IGL_INLINE void CurvatureCalculator::computeCurvature()
       applyMontecarlo(vv,&vvtmp);
       vv=vvtmp;
     }
-    
+
     if (vv.size()<6)
       return;
     computeReferenceFrame(i,normal,ref);
-    
+
     Quadric q;
     fitQuadric (me, ref, vv, &q);
     finalEigenStuff(i,ref,q);
   }
-  
+
   lastRadius=sphereRadius;
   curvatureComputed=true;
 }
@@ -750,16 +750,16 @@ IGL_INLINE void CurvatureCalculator::printCurvature(std::string outpath)
   using namespace std;
   if (!curvatureComputed)
     return;
-  
+
   std::ofstream of;
   of.open(outpath.c_str());
-  
+
   if (!of)
   {
     fprintf(stderr, "Error: could not open output file %s\n", outpath.c_str());
     return;
   }
-  
+
   int vertices_count=vertices.rows();
   of << vertices_count << endl;
   for (int i=0; i<vertices_count; i++)
@@ -767,9 +767,9 @@ IGL_INLINE void CurvatureCalculator::printCurvature(std::string outpath)
     of << curv[i][0] << " " << curv[i][1] << " " << curvDir[i][0][0] << " " << curvDir[i][0][1] << " " << curvDir[i][0][2] << " " <<
     curvDir[i][1][0] << " " << curvDir[i][1][1] << " " << curvDir[i][1][2] << endl;
   }
-  
+
   of.close();
-  
+
 }
 
 template <typename DerivedV, typename DerivedF>
@@ -778,51 +778,61 @@ IGL_INLINE void igl::principal_curvature(
                                          const Eigen::PlainObjectBase<DerivedF>& F,
                                          Eigen::PlainObjectBase<DerivedV>& PD1,
                                          Eigen::PlainObjectBase<DerivedV>& PD2,
+                                         Eigen::PlainObjectBase<DerivedV>& PV1,
+                                         Eigen::PlainObjectBase<DerivedV>& PV2,
                                          unsigned radius,
                                          bool useKring
                                          )
 {
   using namespace std;
-  
+
   // Preallocate memory
   PD1.resize(V.rows(),3);
   PD2.resize(V.rows(),3);
-  
+
+  // Preallocate memory
+  PV1.resize(V.rows(),1);
+  PV2.resize(V.rows(),1);
+
   // Precomputation
   CurvatureCalculator cc;
   cc.init(V.template cast<double>(),F.template cast<int>());
   cc.sphereRadius = radius;
-  
+
   if (useKring)
   {
     cc.kRing = radius;
     cc.st = K_RING_SEARCH;
   }
-  
+
   // Compute
   cc.computeCurvature();
-  
+
   // Copy it back
   for (unsigned i=0; i<V.rows(); i++)
   {
     Eigen::Vector3d d1;
     Eigen::Vector3d d2;
-    d1 << cc.curvDir[i][0][0], cc.curvDir[i][0][1], cc.curvDir[i][0][2];
-    d2 << cc.curvDir[i][1][0], cc.curvDir[i][1][1], cc.curvDir[i][1][2];
-    d1.normalize();
-    d2.normalize();
-    d1 *= cc.curv[i][0];
-    d2 *= cc.curv[i][1];
-    PD1.row(i) = d1;
-    PD2.row(i) = d2;
+    PD1.row(i) << cc.curvDir[i][0][0], cc.curvDir[i][0][1], cc.curvDir[i][0][2];
+    PD2.row(i) << cc.curvDir[i][1][0], cc.curvDir[i][1][1], cc.curvDir[i][1][2];
+    PD1.row(i).normalize();
+    PD2.row(i).normalize();
     
+    if (isnan(PD1(i,0)) || isnan(PD1(i,1)) || isnan(PD1(i,2)) || isnan(PD2(i,0)) || isnan(PD2(i,1)) || isnan(PD2(i,2)))
+    {
+      PD1.row(i) << 0,0,0;
+      PD2.row(i) << 0,0,0;
+    }
+
+    PV1(i) = cc.curv[i][0];
+    PV2(i) = cc.curv[i][1];
+
     if (PD1.row(i) * PD2.row(i).transpose() > 10e-6)
     {
-      cerr << "Something is wrong, vertex: i" << endl;
+      cerr << "PRINCIPAL_CURVATURE: Something is wrong with vertex: i" << endl;
       PD1.row(i) *= 0;
       PD2.row(i) *= 0;
     }
   }
-  
-}
 
+}

+ 10 - 7
include/igl/principal_curvature.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #ifndef IGL_PRINCIPAL_CURVATURE_H
 #define IGL_PRINCIPAL_CURVATURE_H
@@ -34,8 +34,9 @@ namespace igl
   //
   // Outputs:
   //   PD1 #V by 3 maximal curvature direction for each vertex.
-  //   PD2 #V by 3 minimal curvature direction for each vertex.  
-  //  Note that to maximal/minimal curvature value is the rowise norm of PD1/PD2
+  //   PD2 #V by 3 minimal curvature direction for each vertex.
+  //   PV1 #V by 1 maximal curvature value for each vertex.
+  //   PV2 #V by 1 minimal curvature value for each vertex.
   //
   // See also: moveVF, moveFV
   //
@@ -51,6 +52,8 @@ IGL_INLINE void principal_curvature(
   const Eigen::PlainObjectBase<DerivedF>& F,
   Eigen::PlainObjectBase<DerivedV>& PD1,
   Eigen::PlainObjectBase<DerivedV>& PD2,
+  Eigen::PlainObjectBase<DerivedV>& PV1,
+  Eigen::PlainObjectBase<DerivedV>& PV2,
   unsigned radius = 5,
   bool useKring = true);
 }

+ 8 - 4
include/igl/viewer/Viewer.cpp

@@ -1616,7 +1616,7 @@ namespace igl
 
   void Viewer::OpenGL_state::draw_overlay_lines()
   {
-    glDrawElements(GL_LINES, 2*lines_F_vbo.cols(), GL_UNSIGNED_INT, 0);
+    glDrawElements(GL_LINES, lines_F_vbo.cols(), GL_UNSIGNED_INT, 0);
   }
 
   void Viewer::OpenGL_state::draw_overlay_points()
@@ -2282,23 +2282,27 @@ namespace igl
     data.dirty |= DIRTY_TEXTURE;
   }
 
-  void Viewer::draw_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C)
+  void Viewer::add_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C)
   {
     int lastid = data.points.rows();
     data.points.conservativeResize(data.points.rows() + P.rows(),6);
     for (unsigned i=0; i<P.rows(); ++i)
       data.points.row(lastid+i) << P.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
+
+    data.dirty |= DIRTY_OVERLAY_POINTS;
   }
 
-  void Viewer::draw_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C)
+  void Viewer::add_edges(const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C)
   {
     int lastid = data.lines.rows();
     data.lines.conservativeResize(data.lines.rows() + P1.rows(),9);
     for (unsigned i=0; i<P1.rows(); ++i)
       data.lines.row(lastid+i) << P1.row(i), P2.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
+
+    data.dirty |= DIRTY_OVERLAY_LINES;
   }
 
-  void Viewer::draw_label (const Eigen::VectorXd& P,  const std::string& str)
+  void Viewer::add_label(const Eigen::VectorXd& P,  const std::string& str)
   {
     int lastid = data.labels_positions.rows();
     data.labels_positions.conservativeResize(lastid+1, 3);

+ 3 - 3
include/igl/viewer/Viewer.h

@@ -363,9 +363,9 @@ namespace igl
                       const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& G,
                       const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B);
 
-    void draw_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C);
-    void draw_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C);
-    void draw_label (const Eigen::VectorXd& P,  const std::string& str);
+    void add_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C);
+    void add_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C);
+    void add_label (const Eigen::VectorXd& P,  const std::string& str);
 
     // Save the OpenGL transformation matrices used for the previous rendering pass
     Eigen::Matrix4f view;

+ 5 - 5
tutorial/106_Overlays/main.cpp

@@ -45,14 +45,14 @@ int main(int argc, char *argv[])
 
   // Plot the mesh
   igl::Viewer viewer;
-  viewer.draw_mesh(V, F);
+  viewer.set_mesh(V, F);
 
   // Plot the corners of the bounding box as points
-  viewer.draw_points(V_box,Eigen::RowVector3d(1,0,0));
+  viewer.add_points(V_box,Eigen::RowVector3d(1,0,0));
 
   // Plot the edges of the bounding box
   for (unsigned i=0;i<E_box.rows(); ++i)
-    viewer.draw_edges
+    viewer.add_edges
     (
       V_box.row(E_box(i,0)),
       V_box.row(E_box(i,1)),
@@ -65,10 +65,10 @@ int main(int argc, char *argv[])
   // Plot labels with the coordinates of bounding box vertices
   std::stringstream l1;
   l1 << m(0) << ", " << m(1) << ", " << m(2);
-  viewer.draw_label(m,l1.str());
+  viewer.add_label(m,l1.str());
   std::stringstream l2;
   l2 << M(0) << ", " << M(1) << ", " << M(2);
-  viewer.draw_label(M,l2.str());
+  viewer.add_label(M,l2.str());
 
   // Launch the viewer
   viewer.launch();

+ 11 - 0
tutorial/203_CurvatureDirections/CMakeLists.txt

@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 2.6)
+project(203_CurvatureDirections)
+
+include("../CMakeLists.shared")
+
+set(SOURCES
+${PROJECT_SOURCE_DIR}/main.cpp
+)
+
+add_executable(${CMAKE_PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${CMAKE_PROJECT_NAME} ${SHARED_LIBRARIES})

+ 37 - 0
tutorial/203_CurvatureDirections/main.cpp

@@ -0,0 +1,37 @@
+#include <igl/readOFF.h>
+#include <igl/viewer/Viewer.h>
+#include <igl/per_vertex_normals.h>
+#include <igl/per_face_normals.h>
+#include <igl/per_corner_normals.h>
+#include <igl/avg_edge_length.h>
+#include <igl/barycenter.h>
+#include <igl/principal_curvature.h>
+
+Eigen::MatrixXd V;
+Eigen::MatrixXi F;
+
+int main(int argc, char *argv[])
+{
+  // Load a mesh in OFF format
+  igl::readOFF("../shared/fertility.off", V, F);
+
+  // Compute curvature directions via quadric fitting
+  Eigen::MatrixXd PD1,PD2,PV1,PV2;
+  igl::principal_curvature(V,F,PD1,PD2,PV1,PV2);
+
+  // Plot the mesh
+  igl::Viewer viewer;
+  viewer.set_mesh(V, F);
+
+  // Find the average edge length
+  double avg = igl::avg_edge_length(V,F);
+  
+  // Draw a red segment on each vertex parallel to the minimal curvature direction
+  viewer.add_edges(V + PD1*avg, V - PD1*avg, Eigen::RowVector3d(0,0,1));
+
+  // Draw a blue segment on each vertex parallel to the maximal curvature direction
+  viewer.add_edges(V + PD2*avg, V - PD2*avg, Eigen::RowVector3d(1,0,0));
+
+  // Launch the viewer
+  viewer.launch();
+}