Эх сурвалжийг харах

Merge commit '5d1f1cf7374c4ad6f20581a558c0f8a967dc1076 [formerly ac7818e87545767f3c5e5375d5f84d43f71dee16]'

Former-commit-id: 9586e074d2f95ff96c4a9de8e159de37e90b51ea
Daniele Panozzo 10 жил өмнө
parent
commit
2a8c8b45fb

+ 1 - 1
README.md

@@ -6,7 +6,7 @@
 
 libigl is a simple C++ geometry processing library. We have a wide
 functionality including construction of sparse discrete differential geometry
-operators and finite-elements matrices such as the contangent Laplacian and
+operators and finite-elements matrices such as the cotangent Laplacian and
 diagonalized mass matrix, simple facet and edge-based topology data structures,
 mesh-viewing utilities for OpenGL and GLSL, and many core functions for matrix
 manipulation which make [Eigen](http://eigen.tuxfamily.org) feel a lot more

+ 1 - 0
google-soc/collapse-split-flip.ai.REMOVED.git-id

@@ -0,0 +1 @@
+df9f72b3e478619e1ea66fe679d1c5b4cfa13fb2

+ 1 - 0
google-soc/collapse-split-flip.jpg.REMOVED.git-id

@@ -0,0 +1 @@
+4a6e9ced0bd70bfe81d27bc663e0205225d1ab51

+ 46 - 0
google-soc/google-soc.md

@@ -0,0 +1,46 @@
+# [libigl](./index.html) - Google Summer of Code 2015 Project Ideas
+
+## Automatic Generation of Python/MATLAB bindings
+
+![](./libigl-logo-python-matlab.jpg)
+
+Libigl is a C++ library, but its functional interface make it very friendly to
+wrapping individual functions for popular scripting languages like Python or
+MATLAB. Since many libigl functions have the form "mesh in" --> "mesh out" or
+"mesh with scalar field in" --> "scalar field out", we would like to develop an
+_automatic_ routine for generating Python and MATLAB bindings for libigl
+functions. This project has three parts: 1) determining the necessary mark up
+(e.g. comments) inside libigl header files to determine the Python interface,
+2) writing a program to parse this mark up and generate valid Python bindings
+and compilation instructions, and 3) validating and testing these results on a
+variety of functions in the library.
+
+Student: [apply](https://www.google-melange.com/gsoc/homepage/google/gsoc2015)
+
+Mentors: Alec Jacobson & Daniele Panozzo
+
+## Topological Mesh Operations
+
+![](./collapse-split-flip.jpg)
+
+Libigl avoids complicated mesh data-structures to ensure that its interface is
+clean and easy to port into users' existing projects. Our mesh format is a
+simple list of vertices and list of face indices to those vertices: `V` and
+`F`.  We have a number of functions for _deforming_ a mesh: that is, modifying
+the entries in `V`, but currently lack functions for _modifying_ the mesh's
+topology: that is, modifying `F` and/or modifying the _size_ of `V`. This
+project entails implementing _efficient_ routines for: edge collapse, edge
+splitting, and edge flipping. The project will culminate in a routine combining
+these core functions for surface remeshing.
+
+Student: [apply](https://www.google-melange.com/gsoc/homepage/google/gsoc2015)
+
+Mentors: Alec Jacobson & Daniele Panozzo
+
+## Contact
+
+Google Summer of Code projects with libigl are mentored by [Alec
+Jacobson](http://www.cs.columbia.edu/~jacobson/) and [Daniele
+Panozzo](http://www.inf.ethz.ch/personal/dpanozzo/). Please [contact
+us](mailto:alecjacobson@gmail.com,daniele.panozzo@gmail.com) if you have
+questions, comments or other ideas for a fun summer of hacking on libigl.

+ 67 - 0
google-soc/index.html

@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<meta charset="utf-8"/>
+	<title>libigl</title>
+	<meta name="author" content="Alec Jacobson and Daniele Panozzo and others"/>
+	<link type="text/css" rel="stylesheet" href="../tutorial/style.css"/>
+<script type='text/javascript' src='http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'></script>
+<link rel='stylesheet' href='http://yandex.st/highlightjs/7.3/styles/default.min.css'>
+<script src='http://yandex.st/highlightjs/7.3/highlight.min.js'></script>
+<script>hljs.initHighlightingOnLoad();</script>
+</head>
+<body>
+
+<h1 id="libigl-googlesummerofcode2015projectideas"><a href="./index.html">libigl</a> - Google Summer of Code 2015 Project Ideas</h1>
+
+<h2 id="automaticgenerationofpythonmatlabbindings">Automatic Generation of Python/MATLAB bindings</h2>
+
+<figure>
+<img src="./libigl-logo-python-matlab.jpg" alt="" />
+<figcaption></figcaption></figure>
+
+<p>Libigl is a C++ library, but its functional interface make it very friendly to
+wrapping individual functions for popular scripting languages like Python or
+MATLAB. Since many libigl functions have the form &#8220;mesh in&#8221; &#8211;&gt; &#8220;mesh out&#8221; or
+&#8220;mesh with scalar field in&#8221; &#8211;&gt; &#8220;scalar field out&#8221;, we would like to develop an
+<em>automatic</em> routine for generating Python and MATLAB bindings for libigl
+functions. This project has three parts: 1) determining the necessary mark up
+(e.g. comments) inside libigl header files to determine the Python interface,
+2) writing a program to parse this mark up and generate valid Python bindings
+and compilation instructions, and 3) validating and testing these results on a
+variety of functions in the library.</p>
+
+<p>Student: <a href="https://www.google-melange.com/gsoc/homepage/google/gsoc2015">apply</a></p>
+
+<p>Mentors: Alec Jacobson &amp; Daniele Panozzo</p>
+
+<h2 id="topologicalmeshoperations">Topological Mesh Operations</h2>
+
+<figure>
+<img src="./collapse-split-flip.jpg" alt="" />
+<figcaption></figcaption></figure>
+
+<p>Libigl avoids complicated mesh data-structures to ensure that its interface is
+clean and easy to port into users&#8217; existing projects. Our mesh format is a
+simple list of vertices and list of face indices to those vertices: <code>V</code> and
+<code>F</code>. We have a number of functions for <em>deforming</em> a mesh: that is, modifying
+the entries in <code>V</code>, but currently lack functions for <em>modifying</em> the mesh&#8217;s
+topology: that is, modifying <code>F</code> and/or modifying the <em>size</em> of <code>V</code>. This
+project entails implementing <em>efficient</em> routines for: edge collapse, edge
+splitting, and edge flipping. The project will culminate in a routine combining
+these core functions for surface remeshing.</p>
+
+<p>Student: <a href="https://www.google-melange.com/gsoc/homepage/google/gsoc2015">apply</a></p>
+
+<p>Mentors: Alec Jacobson &amp; Daniele Panozzo</p>
+
+<h2 id="contact">Contact</h2>
+
+<p>Google Summer of Code projects with libigl are mentored by <a href="http://www.cs.columbia.edu/~jacobson/">Alec
+Jacobson</a> and <a href="http://www.inf.ethz.ch/personal/dpanozzo/">Daniele
+Panozzo</a>. Please <a href="&#109;&#97;&#105;&#108;&#x74;&#111;&#x3a;&#x61;&#x6c;&#101;&#x63;&#x6a;&#x61;&#x63;&#111;&#98;&#115;&#111;&#110;&#64;&#103;&#109;&#x61;&#105;&#108;&#x2e;&#x63;&#x6f;&#x6d;&#44;&#x64;&#x61;&#110;&#105;&#101;&#x6c;&#101;&#x2e;&#x70;&#x61;&#110;&#x6f;&#122;&#x7a;&#x6f;&#64;&#x67;&#x6d;&#x61;&#x69;&#x6c;&#x2e;&#99;&#x6f;&#x6d;">&#99;&#x6f;&#x6e;&#116;&#x61;&#99;&#x74;
+&#117;&#115;</a> if you have
+questions, comments or other ideas for a fun summer of hacking on libigl.</p>
+
+</body>
+</html>

+ 1 - 0
google-soc/libigl-logo-python-matlab.ai.REMOVED.git-id

@@ -0,0 +1 @@
+3aee7373f24e4e55c0e9996326581446109ddbaa

+ 1 - 0
google-soc/libigl-logo-python-matlab.jpg.REMOVED.git-id

@@ -0,0 +1 @@
+f8623f70e91e4bbc5ed229da96191cb7bce86765

+ 9 - 1
include/igl/boolean/mesh_boolean.cpp

@@ -1,5 +1,6 @@
 #include "mesh_boolean.h"
 #include <igl/peel_outer_hull_layers.h>
+#include <igl/per_face_normals.h>
 #include <igl/cgal/remesh_self_intersections.h>
 #include <igl/remove_unreferenced.h>
 #include <igl/unique_simplices.h>
@@ -167,6 +168,13 @@ IGL_INLINE void igl::mesh_boolean(
     J = CJ;
     return;
   }
+  MatrixX3S N,CN;
+  per_face_normals(V,F,N);
+  CN.resize(CF.rows(),3);
+  for(size_t f = 0;f<(size_t)CN.rows();f++)
+  {
+    CN.row(f) = N.row(CJ(f));
+  }
 
 #ifdef IGL_MESH_BOOLEAN_DEBUG
   cout<<"peel..."<<endl;
@@ -175,7 +183,7 @@ IGL_INLINE void igl::mesh_boolean(
   // peel layers keeping track of odd and even flips
   Matrix<bool,Dynamic,1> odd;
   Matrix<bool,Dynamic,1> flip;
-  peel_outer_hull_layers(CV,CF,odd,flip);
+  peel_outer_hull_layers(CV,CF,CN,odd,flip);
 
 #ifdef IGL_MESH_BOOLEAN_DEBUG
   cout<<"categorize..."<<endl;

+ 2 - 1
include/igl/cgal/CGAL_includes.hpp

@@ -33,7 +33,8 @@
 
 // Boolean operations
 #include <CGAL/Polyhedron_3.h>
-#include <CGAL/Nef_polyhedron_3.h>
+// Is this actually used?
+//#include <CGAL/Nef_polyhedron_3.h>
 
 // Delaunay Triangulation in 3D
 #include <CGAL/Delaunay_triangulation_3.h>

+ 12 - 8
include/igl/cgal/SelfIntersectMesh.h

@@ -212,10 +212,10 @@ namespace igl
       // Getters:
     public:
       //const IndexList& get_lIF() const{ return lIF;}
-      static inline void box_intersect(
+      static inline void box_intersect_static(
         SelfIntersectMesh * SIM, 
-        const SelfIntersectMesh::Box &a, 
-        const SelfIntersectMesh::Box &b);
+        const Box &a, 
+        const Box &b);
   };
 }
 
@@ -227,9 +227,8 @@ namespace igl
 #include <igl/get_seconds.h>
 #include <igl/C_STR.h>
 
-#include <boost/function.hpp>
-#include <boost/bind.hpp>
 
+#include <functional>
 #include <algorithm>
 #include <exception>
 #include <cassert>
@@ -277,7 +276,7 @@ inline void igl::SelfIntersectMesh<
   DerivedFF,
   DerivedIF,
   DerivedJ,
-  DerivedIM>::box_intersect(
+  DerivedIM>::box_intersect_static(
   Self * SIM, 
   const typename Self::Box &a, 
   const typename Self::Box &b)
@@ -350,8 +349,12 @@ inline igl::SelfIntersectMesh<
     boxes.push_back(Box(tit->bbox(), tit));
   }
   // Leapfrog callback
-  boost::function<void(const Box &a,const Box &b)> cb
-    = boost::bind(&box_intersect, this, _1,_2);
+  std::function<void(const Box &a,const Box &b)> cb = 
+    std::bind(&box_intersect_static, this, 
+      // Explicitly use std namespace to avoid confusion with boost (who puts
+      // _1 etc. in global namespace)
+      std::placeholders::_1,
+      std::placeholders::_2);
   //cout<<"boxes and bind: "<<tictoc()<<endl;
   // Run the self intersection algorithm with all defaults
   try{
@@ -910,6 +913,7 @@ inline bool igl::SelfIntersectMesh<
     // Construct intersection
     try
     {
+      // This can fail for Epick but not Epeck
       CGAL::Object result = CGAL::intersection(A,B);
       if(!result.empty())
       {

+ 1 - 1
include/igl/file_dialog_open.cpp

@@ -35,7 +35,7 @@ IGL_INLINE std::string igl::file_dialog_open()
   while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
   {
   }
-#elif _WIN32
+#elif defined _WIN32
   
   // Use native windows file dialog box
   // (code contributed by Tino Weinkauf)

+ 1 - 1
include/igl/file_dialog_save.cpp

@@ -34,7 +34,7 @@ IGL_INLINE std::string igl::file_dialog_save()
   while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
   {
   }
-#elif _WIN32
+#elif defined _WIN32
 
   // Use native windows file dialog box
   // (code contributed by Tino Weinkauf)

+ 1 - 0
include/igl/list_to_matrix.cpp

@@ -151,4 +151,5 @@ template bool igl::list_to_matrix<double, Eigen::PlainObjectBase<Eigen::Matrix<d
 template bool igl::list_to_matrix<int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
 template bool igl::list_to_matrix<double, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::Matrix<double, 1, -1, 1, 1, -1>&);
 template bool igl::list_to_matrix<unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > >(std::vector<unsigned long, std::allocator<unsigned long> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::list_to_matrix<float, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > >(std::vector<std::vector<float, std::allocator<float> >, std::allocator<std::vector<float, std::allocator<float> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
 #endif

+ 1 - 0
include/igl/max_size.cpp

@@ -31,4 +31,5 @@ template int igl::max_size<std::vector<int, std::allocator<int> > >(std::vector<
 // generated by autoexplicit.sh
 template int igl::max_size<std::vector<double, std::allocator<double> > >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&);
 template int igl::max_size<std::vector<bool, std::allocator<bool> > >(std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > > const&);
+template int igl::max_size<std::vector<float, std::allocator<float> > >(std::vector<std::vector<float, std::allocator<float> >, std::allocator<std::vector<float, std::allocator<float> > > > const&);
 #endif

+ 1 - 0
include/igl/min_size.cpp

@@ -37,4 +37,5 @@ template int igl::min_size<std::vector<int, std::allocator<int> > >(std::vector<
 // generated by autoexplicit.sh
 template int igl::min_size<std::vector<double, std::allocator<double> > >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&);
 template int igl::min_size<std::vector<bool, std::allocator<bool> > >(std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > > const&);
+template int igl::min_size<std::vector<float, std::allocator<float> > >(std::vector<std::vector<float, std::allocator<float> >, std::allocator<std::vector<float, std::allocator<float> > > > const&);
 #endif

+ 154 - 33
include/igl/outer_hull.cpp

@@ -1,5 +1,6 @@
 #include "outer_hull.h"
 #include "outer_facet.h"
+#include "sort.h"
 #include "facet_components.h"
 #include "winding_number.h"
 #include "triangle_triangle_adjacency.h"
@@ -20,12 +21,14 @@
 template <
   typename DerivedV,
   typename DerivedF,
+  typename DerivedN,
   typename DerivedG,
   typename DerivedJ,
   typename Derivedflip>
 IGL_INLINE void igl::outer_hull(
   const Eigen::PlainObjectBase<DerivedV> & V,
   const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::PlainObjectBase<DerivedN> & N,
   Eigen::PlainObjectBase<DerivedG> & G,
   Eigen::PlainObjectBase<DerivedJ> & J,
   Eigen::PlainObjectBase<Derivedflip> & flip)
@@ -55,6 +58,65 @@ IGL_INLINE void igl::outer_hull(
   vector<vector<typename DerivedF::Index> > uE2E;
   unique_edge_map(F,E,uE,EMAP,uE2E);
 
+  // TODO:
+  // uE --> face-edge index, sorted CCW around edge according to normal
+  // uE --> sorted order index 
+  // uE --> bool, whether needed to flip face to make "consistent" with unique
+  //   edge
+  VectorXI diIM(3*m);
+  vector<vector<typename DerivedV::Scalar> > di(uE2E.size());
+  // For each list of face-edges incide on a unique edge
+  for(size_t ui = 0;ui<(size_t)uE.rows();ui++)
+  {
+    const typename DerivedF::Scalar ud = uE(ui,1);
+    const typename DerivedF::Scalar us = uE(ui,0);
+    // Base normal vector to orient against
+    const auto fe0 = uE2E[ui][0];
+    const auto & eVp = N.row(fe0%m);
+    di[ui].resize(uE2E[ui].size());
+
+    const typename DerivedF::Scalar d = F(fe0%m,((fe0/m)+2)%3);
+    const typename DerivedF::Scalar s = F(fe0%m,((fe0/m)+1)%3);
+    // Edge vector
+    //const auto & eV = (V.row(ud)-V.row(us)).normalized();
+    const auto & eV = (V.row(d)-V.row(s)).normalized();
+
+    // Loop over incident face edges
+    for(size_t fei = 0;fei<uE2E[ui].size();fei++)
+    {
+      const auto & fe = uE2E[ui][fei];
+      const auto f = fe % m;
+      const auto c = fe / m;
+      // source should match destination to be consistent
+      const bool cons = (d == F(f,(c+1)%3));
+      assert(cons ||  (d == F(f,(c+2)%3)));
+      assert(!cons || (s == F(f,(c+2)%3)));
+      assert(!cons || (d == F(f,(c+1)%3)));
+      // Angle between n and f
+      const auto & n = N.row(f);
+      di[ui][fei] = M_PI - atan2( eVp.cross(n).dot(eV), eVp.dot(n));
+      if(!cons)
+      {
+        di[ui][fei] = di[ui][fei] + M_PI;
+        if(di[ui][fei]>2.*M_PI)
+        {
+          di[ui][fei] = di[ui][fei] - 2.*M_PI;
+        }
+      }
+    }
+    vector<size_t> IM;
+    igl::sort(di[ui],true,di[ui],IM);
+    // copy old list
+    vector<typename DerivedF::Index> temp = uE2E[ui];
+    for(size_t fei = 0;fei<uE2E[ui].size();fei++)
+    {
+      uE2E[ui][fei] = temp[IM[fei]];
+      const auto & fe = uE2E[ui][fei];
+      diIM(fe) = fei;
+    }
+
+  }
+
   vector<vector<vector<Index > > > TT,_1;
   triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
   VectorXI counts;
@@ -67,15 +129,6 @@ IGL_INLINE void igl::outer_hull(
   G.resize(0,F.cols());
   J.resize(0,1);
   flip.setConstant(m,1,false);
-  // precompute face normals
-  typename Eigen::Matrix<
-    typename DerivedV::Scalar,
-    DerivedF::RowsAtCompileTime,
-    3> N;
-#ifdef IGL_OUTER_HULL_DEBUG
-  cout<<"normals..."<<endl;
-#endif
-  per_face_normals(V,F,N);
 
 #ifdef IGL_OUTER_HULL_DEBUG
   cout<<"reindex..."<<endl;
@@ -107,7 +160,7 @@ IGL_INLINE void igl::outer_hull(
   barycenter(V,F,BC);
 
 #ifdef IGL_OUTER_HULL_DEBUG
-  cout<<"loop over CCs..."<<endl;
+  cout<<"loop over CCs (="<<ncc<<")..."<<endl;
 #endif
   for(Index id = 0;id<(Index)ncc;id++)
   {
@@ -127,6 +180,7 @@ IGL_INLINE void igl::outer_hull(
     Q.push(f+1*m);
     Q.push(f+2*m);
     flip(f) = f_flip;
+    //cout<<"flip("<<f<<") = "<<(flip(f)?"true":"false")<<endl;
 #ifdef IGL_OUTER_HULL_DEBUG
   cout<<"BFS..."<<endl;
 #endif
@@ -153,44 +207,93 @@ IGL_INLINE void igl::outer_hull(
       }
       // find overlapping face-edges
       const auto & neighbors = uE2E[EMAP(e)];
+      // normal after possible flipping 
       const auto & fN = (flip(f)?-1.:1.)*N.row(f);
       // source of edge according to f
       const int fs = flip(f)?F(f,(c+2)%3):F(f,(c+1)%3);
       // destination of edge according to f
       const int fd = flip(f)?F(f,(c+1)%3):F(f,(c+2)%3);
+      // Edge vector according to f's (flipped) orientation.
       const auto & eV = (V.row(fd)-V.row(fs)).normalized();
+      // edge valence
+      const size_t val = uE2E[EMAP(e)].size();
+      const auto ui = EMAP(e);
+      const auto fe0 = uE2E[ui][0];
+      const auto es = F(fe0%m,((fe0/m)+1)%3);
+      const int e_cons = (fs == es?-1:1);
+      const int nfei = (diIM(e) + val + e_cons*(flip(f)?-1:1))%val;
+      const int max_ne_2 = uE2E[EMAP(e)][nfei];
       // Loop over and find max dihedral angle
-      typename DerivedV::Scalar max_di = -1;
       int max_ne = -1;
-      typename Eigen::Matrix< typename DerivedV::Scalar, 1, 3> max_nN;
-      for(const auto & ne : neighbors)
-      {
-        const int nf = ne%m;
-        if(nf == f)
-        {
-          continue;
-        }
-        const int nc = ne/m;
-        // are faces consistently oriented
-        //const int ns = F(nf,(nc+1)%3);
-        const int nd = F(nf,(nc+2)%3);
-        const bool cons = (flip(f)?fd:fs) == nd;
-        const auto & nN = (cons? (flip(f)?-1:1.) : (flip(f)?1.:-1.) )*N.row(nf);
-        const auto & ndi = M_PI - atan2( fN.cross(nN).dot(eV), fN.dot(nN));
-        if(ndi>=max_di)
-        {
-          max_ne = ne;
-          max_di = ndi;
-          max_nN = nN;
-        }
-      }
+      // // SAVE THIS OLD IMPLEMENTATION FOR NOW
+      //typename DerivedV::Scalar max_di = -1;
+      //for(const auto & ne : neighbors)
+      //{
+      //  const int nf = ne%m;
+      //  if(nf == f)
+      //  {
+      //    continue;
+      //  }
+      //  // Corner of neighbor
+      //  const int nc = ne/m;
+      //  // Is neighbor oriented consistently with (flipped) f?
+      //  //const int ns = F(nf,(nc+1)%3);
+      //  const int nd = F(nf,(nc+2)%3);
+      //  const bool cons = (flip(f)?fd:fs) == nd;
+      //  // Normal after possibly flipping to match flip or orientation of f
+      //  const auto & nN = (cons? (flip(f)?-1:1.) : (flip(f)?1.:-1.) )*N.row(nf);
+      //  // Angle between n and f
+      //  const auto & ndi = M_PI - atan2( fN.cross(nN).dot(eV), fN.dot(nN));
+      //  if(ndi>=max_di)
+      //  {
+      //    max_ne = ne;
+      //    max_di = ndi;
+      //  }
+      //}
+      ////cout<<(max_ne != max_ne_2)<<" =?= "<<e_cons<<endl;
+      //if(max_ne != max_ne_2)
+      //{
+      //  cout<<(f+1)<<" ---> "<<(max_ne%m)+1<<" != "<<(max_ne_2%m)+1<<" ... "<<e_cons<<endl;
+      //  typename DerivedV::Scalar max_di = -1;
+      //  for(size_t nei = 0;nei<neighbors.size();nei++)
+      //  {
+      //    const auto & ne = neighbors[nei];
+      //    const int nf = ne%m;
+      //    if(nf == f)
+      //    {
+      //      cout<<"  "<<(ne%m)+1<<": "<<0<<" "<<di[EMAP[e]][nei]<<" "<<diIM(ne)<<endl;
+      //      continue;
+      //    }
+      //    // Corner of neighbor
+      //    const int nc = ne/m;
+      //    // Is neighbor oriented consistently with (flipped) f?
+      //    //const int ns = F(nf,(nc+1)%3);
+      //    const int nd = F(nf,(nc+2)%3);
+      //    const bool cons = (flip(f)?fd:fs) == nd;
+      //    // Normal after possibly flipping to match flip or orientation of f
+      //    const auto & nN = (cons? (flip(f)?-1:1.) : (flip(f)?1.:-1.) )*N.row(nf);
+      //    // Angle between n and f
+      //    const auto & ndi = M_PI - atan2( fN.cross(nN).dot(eV), fN.dot(nN));
+      //    cout<<"  "<<(ne%m)+1<<": "<<ndi<<" "<<di[EMAP[e]][nei]<<" "<<diIM(ne)<<endl;
+      //    if(ndi>=max_di)
+      //    {
+      //      max_ne = ne;
+      //      max_di = ndi;
+      //    }
+      //  }
+      //}
+      max_ne = max_ne_2;
+
       if(max_ne>=0)
       {
+        // face of neighbor
         const int nf = max_ne%m;
+        // corner of neighbor
         const int nc = max_ne/m;
         const int nd = F(nf,(nc+2)%3);
         const bool cons = (flip(f)?fd:fs) == nd;
         flip(nf) = (cons ? flip(f) : !flip(f));
+        //cout<<"flip("<<nf<<") = "<<(flip(nf)?"true":"false")<<endl;
         const int ne1 = nf+((nc+1)%3)*m;
         const int ne2 = nf+((nc+2)%3)*m;
         if(!EH[ne1])
@@ -323,6 +426,24 @@ IGL_INLINE void igl::outer_hull(
     }
   }
 }
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedG,
+  typename DerivedJ,
+  typename Derivedflip>
+IGL_INLINE void igl::outer_hull(
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  Eigen::PlainObjectBase<DerivedG> & G,
+  Eigen::PlainObjectBase<DerivedJ> & J,
+  Eigen::PlainObjectBase<Derivedflip> & flip)
+{
+  Eigen::Matrix<typename DerivedV::Scalar,DerivedF::RowsAtCompileTime,3> N;
+  per_face_normals(V,F,N);
+  return outer_hull(V,F,N,G,J,flip);
+}
+
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template specialization
 template void igl::outer_hull<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);

+ 16 - 0
include/igl/outer_hull.h

@@ -16,11 +16,26 @@ namespace igl
   // Inputs:
   //   V  #V by 3 list of vertex positions
   //   F  #F by 3 list of triangle indices into V
+  //   N  #F by 3 list of per-face normals
   // Outputs:
   //   G  #G by 3 list of output triangle indices into V
   //   J  #G list of indices into F
   //   flip  #F list of whether facet was added to G **and** flipped orientation
   //     (false for faces not added to G)
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedN,
+    typename DerivedG,
+    typename DerivedJ,
+    typename Derivedflip>
+  IGL_INLINE void outer_hull(
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::PlainObjectBase<DerivedN> & N,
+    Eigen::PlainObjectBase<DerivedG> & G,
+    Eigen::PlainObjectBase<DerivedJ> & J,
+    Eigen::PlainObjectBase<Derivedflip> & flip);
   template <
     typename DerivedV,
     typename DerivedF,
@@ -34,6 +49,7 @@ namespace igl
     Eigen::PlainObjectBase<DerivedJ> & J,
     Eigen::PlainObjectBase<Derivedflip> & flip);
 }
+
 #ifndef IGL_STATIC_LIBRARY
 #  include "outer_hull.cpp"
 #endif

+ 27 - 2
include/igl/peel_outer_hull_layers.cpp

@@ -1,21 +1,24 @@
 #include "peel_outer_hull_layers.h"
+#include "per_face_normals.h"
 #include "outer_hull.h"
-#include "writePLY.h"
 #include <vector>
 #include <iostream>
 //#define IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
 #ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+#include "writePLY.h"
 #include "STR.h"
 #endif
 
 template <
   typename DerivedV,
   typename DerivedF,
+  typename DerivedN,
   typename Derivedodd,
   typename Derivedflip>
 IGL_INLINE size_t igl::peel_outer_hull_layers(
   const Eigen::PlainObjectBase<DerivedV > & V,
   const Eigen::PlainObjectBase<DerivedF > & F,
+  const Eigen::PlainObjectBase<DerivedN > & N,
   Eigen::PlainObjectBase<Derivedodd > & odd,
   Eigen::PlainObjectBase<Derivedflip > & flip)
 {
@@ -23,6 +26,7 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
   using namespace std;
   typedef typename DerivedF::Index Index;
   typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
+  typedef Matrix<typename DerivedN::Scalar,Dynamic,DerivedN::ColsAtCompileTime> MatrixXN;
   typedef Matrix<Index,Dynamic,1> MatrixXI;
   typedef Matrix<typename Derivedflip::Scalar,Dynamic,Derivedflip::ColsAtCompileTime> MatrixXflip;
   const Index m = F.rows();
@@ -35,6 +39,7 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
 #endif
   // keep track of iteration parity and whether flipped in hull
   MatrixXF Fr = F;
+  MatrixXN Nr = N;
   odd.resize(m,1);
   flip.resize(m,1);
   // Keep track of index map
@@ -54,7 +59,7 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
   cout<<"calling outer hull..."<<endl;
   writePLY(STR("outer-hull-input-"<<iter<<".ply"),V,Fr);
 #endif
-    outer_hull(V,Fr,Fo,Jo,flipr);
+    outer_hull(V,Fr,Nr,Fo,Jo,flipr);
 #ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
   writePLY(STR("outer-hull-output-"<<iter<<".ply"),V,Fo);
   cout<<"reindex, flip..."<<endl;
@@ -72,8 +77,10 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
     // Fr = Fr - Fo
     // update IM
     MatrixXF prev_Fr = Fr;
+    MatrixXN prev_Nr = Nr;
     MatrixXI prev_IM = IM;
     Fr.resize(prev_Fr.rows() - Fo.rows(),F.cols());
+    Nr.resize(Fr.rows(),3);
     IM.resize(Fr.rows());
     {
       Index g = 0;
@@ -82,6 +89,7 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
         if(!in_outer[f])
         {
           Fr.row(g) = prev_Fr.row(f);
+          Nr.row(g) = prev_Nr.row(f);
           IM(g) = prev_IM(f);
           g++;
         }
@@ -93,8 +101,25 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
   return iter;
 }
 
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename Derivedodd,
+  typename Derivedflip>
+IGL_INLINE size_t igl::peel_outer_hull_layers(
+  const Eigen::PlainObjectBase<DerivedV > & V,
+  const Eigen::PlainObjectBase<DerivedF > & F,
+  Eigen::PlainObjectBase<Derivedodd > & odd,
+  Eigen::PlainObjectBase<Derivedflip > & flip)
+{
+  Eigen::Matrix<typename DerivedV::Scalar,DerivedF::RowsAtCompileTime,3> N;
+  per_face_normals(V,F,N);
+  return peel_outer_hull_layers(V,F,N,odd,flip);
+}
+
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template specialization
 template size_t igl::peel_outer_hull_layers<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);
+template size_t igl::peel_outer_hull_layers<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);
 #endif

+ 13 - 0
include/igl/peel_outer_hull_layers.h

@@ -11,12 +11,25 @@ namespace igl
   // Inputs:
   //   V  #V by 3 list of vertex positions
   //   F  #F by 3 list of triangle indices into V
+  //   N  #F by 3 list of per-face normals
   // Outputs:
   //   odd  #F list of whether facet belongs to an odd iteration peel (otherwise
   //     an even iteration peel)
   //   flip  #F list of whether a facet's orientation was flipped when facet
   //     "peeled" into its associated outer hull layer.
   // Returns number of peels
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedN,
+    typename Derivedodd,
+    typename Derivedflip>
+  IGL_INLINE size_t peel_outer_hull_layers(
+    const Eigen::PlainObjectBase<DerivedV > & V,
+    const Eigen::PlainObjectBase<DerivedF > & F,
+    const Eigen::PlainObjectBase<DerivedN > & N,
+    Eigen::PlainObjectBase<Derivedodd > & odd,
+    Eigen::PlainObjectBase<Derivedflip > & flip);
   template <
     typename DerivedV,
     typename DerivedF,

+ 4 - 4
include/igl/sort.h

@@ -65,10 +65,10 @@ namespace igl
   //   index_map  an index map such that sorted[i] = unsorted[index_map[i]]
   template <class T>
   IGL_INLINE void sort(
-      const std::vector<T> &unsorted,
-      const bool ascending,
-      std::vector<T> &sorted,
-      std::vector<size_t> &index_map);
+    const std::vector<T> &unsorted,
+    const bool ascending,
+    std::vector<T> &sorted,
+    std::vector<size_t> &index_map);
 
 }
 

+ 1 - 1
index.html

@@ -22,7 +22,7 @@
 
 <p>libigl is a simple C++ geometry processing library. We have a wide
 functionality including construction of sparse discrete differential geometry
-operators and finite-elements matrices such as the contangent Laplacian and
+operators and finite-elements matrices such as the cotangent Laplacian and
 diagonalized mass matrix, simple facet and edge-based topology data structures,
 mesh-viewing utilities for OpenGL and GLSL, and many core functions for matrix
 manipulation which make <a href="http://eigen.tuxfamily.org">Eigen</a> feel a lot more

+ 9 - 0
scripts/update_gh-pages.sh

@@ -2,6 +2,7 @@
 # Usage: cd $LIBIGL; scripts/update_gh-pages.sh
 set -o xtrace
 git pull && git checkout gh-pages && git rebase master && git pull
+
 HEADER="title: libigl
 author: Alec Jacobson and Daniele Panozzo and others
 css: tutorial/style.css
@@ -11,9 +12,11 @@ html header:   <script type='text/javascript' src='http://cdn.mathjax.org/mathja
 <script>hljs.initHighlightingOnLoad();</script>
 
 "
+
 echo "$HEADER" \
   | cat - README.md | multimarkdown -o index.html && \
   git commit -m "update index.html to match README.md" README.md index.html
+
 HEADER="title: libigl
 author: Alec Jacobson and Daniele Panozzo and others
 css: ../tutorial/style.css
@@ -23,8 +26,14 @@ html header:   <script type='text/javascript' src='http://cdn.mathjax.org/mathja
 <script>hljs.initHighlightingOnLoad();</script>
 
 "
+
+echo "$HEADER" \
+  | cat - google-soc/google-soc.md | multimarkdown -o google-soc/index.html && \
+  git commit -m "update google-soc/index.html to match google-soc/google-soc.md" google-soc/google-soc.md google-soc/index.html 
+
 echo "$HEADER" \
   | cat - build/README.md | multimarkdown -o build/index.html && \
   git commit -m "update index.html to match README.md" build/README.md \
   build/index.html
+
 git push origin gh-pages && git checkout master && git merge gh-pages && git push