Selaa lähdekoodia

Merge branch 'master' of https://github.com/libigl/libigl

Former-commit-id: 863a0ec763b5de2b10172ccf5d8ee792bc074287
Daniele Panozzo 9 vuotta sitten
vanhempi
commit
fbed46c763

+ 2 - 0
include/igl/cgal/RemeshSelfIntersectionsParam.h

@@ -19,6 +19,8 @@ namespace igl
       bool detect_only;
       bool first_only;
       RemeshSelfIntersectionsParam():detect_only(false),first_only(false){};
+      RemeshSelfIntersectionsParam(bool _detect_only, bool _first_only):
+        detect_only(_detect_only),first_only(_first_only){};
     };
   }
 }

+ 166 - 499
include/igl/cgal/SelfIntersectMesh.h

@@ -89,13 +89,13 @@ namespace igl
         typedef typename DerivedF::Index Index;
         Index count;
         typedef std::vector<CGAL::Object> ObjectList;
-        std::vector<ObjectList > F_objects;
+        // Using a vector here makes this **not** output sensitive
         Triangles T;
         typedef std::vector<Index> IndexList;
         IndexList lIF;
-        std::vector<bool> offensive;
-        std::vector<Index> offending_index;
-        std::vector<Index> offending;
+        // #F-long list of faces with intersections mapping to the order in
+        // which they were first found
+        std::map<Index,std::pair<Index,ObjectList> > offending;
         // Make a short name for the edge map's key
         typedef std::pair<Index,Index> EMK;
         // Make a short name for the type stored at each edge, the edge map's
@@ -103,6 +103,7 @@ namespace igl
         typedef std::vector<Index> EMV;
         // Make a short name for the edge map
         typedef std::map<EMK,EMV> EdgeMap;
+        // Maps edges of offending faces to all incident offending faces
         EdgeMap edge2faces;
       public:
         RemeshSelfIntersectionsParam params;
@@ -139,8 +140,8 @@ namespace igl
         // Inputs:
         //   A  triangle in 3D
         //   B  triangle in 3D
-        //   fa  index of A in F (and F_objects)
-        //   fb  index of A in F (and F_objects)
+        //   fa  index of A in F (and key into offending)
+        //   fb  index of A in F (and key into offending)
         // Returns true only if A intersects B
         //
         inline bool intersect(
@@ -156,10 +157,10 @@ namespace igl
         // Inputs:
         //   A  triangle in 3D
         //   B  triangle in 3D
-        //   fa  index of A in F (and F_objects)
-        //   fb  index of B in F (and F_objects)
-        //   va  index of shared vertex in A (and F_objects)
-        //   vb  index of shared vertex in B (and F_objects)
+        //   fa  index of A in F (and key into offending)
+        //   fb  index of B in F (and key into offending)
+        //   va  index of shared vertex in A (and key into offending)
+        //   vb  index of shared vertex in B (and key into offending)
         //// Returns object of intersection (should be Segment or point)
         //   Returns true if intersection (besides shared point)
         //
@@ -185,7 +186,8 @@ namespace igl
             const Triangle_3 & A,
             const Triangle_3 & B,
             const Index fa,
-            const Index fb);
+            const Index fb,
+            const std::vector<std::pair<Index,Index> > shared);
   
       public:
         // Callback function called during box self intersections test. Means
@@ -208,22 +210,13 @@ namespace igl
         //   A_objects_3  updated list of intersection objects for A
         // Outputs:
         //   cdt  Contrained delaunay triangulation in projected 2D plane
-        inline void projected_delaunay(
-            const Triangle_3 & A,
-            const ObjectList & A_objects_3,
-            CDT_plus_2 & cdt);
-        // Getters:
       public:
+        // Getters:
         //const IndexList& get_lIF() const{ return lIF;}
         static inline void box_intersect_static(
           SelfIntersectMesh * SIM, 
           const Box &a, 
           const Box &b);
-        // Annoying wrappers to conver from cgal to double or cgal
-        static inline void to_output_type(const typename Kernel::FT & cgal,double & d);
-        static inline void to_output_type(
-          const typename CGAL::Epeck::FT & cgal,
-          CGAL::Epeck::FT & d);
     };
   }
 }
@@ -231,6 +224,7 @@ namespace igl
 // Implementation
 
 #include "mesh_to_cgal_triangle_list.h"
+#include "remesh_intersections.h"
 
 #include <igl/REDRUM.h>
 #include <igl/get_seconds.h>
@@ -322,11 +316,8 @@ inline igl::cgal::SelfIntersectMesh<
   V(V),
   F(F),
   count(0),
-  F_objects(F.rows()),
   T(),
   lIF(),
-  offensive(F.rows(),false),
-  offending_index(F.rows(),-1),
   offending(),
   edge2faces(),
   params(params)
@@ -413,241 +404,7 @@ inline igl::cgal::SelfIntersectMesh<
     return;
   }
 
-  int NF_count = 0;
-  // list of new faces, we'll fix F later
-  vector<
-    typename Eigen::Matrix<typename DerivedFF::Scalar,Dynamic,Dynamic>
-    > NF(offending.size());
-  // list of new vertices
-  typedef vector<Point_3> Point_3List;
-  Point_3List NV;
-  Index NV_count = 0;
-  vector<CDT_plus_2> cdt(offending.size());
-  vector<Plane_3> P(offending.size());
-  // Use map for *all* faces
-  map<typename CDT_plus_2::Vertex_handle,Index> v2i;
-  // Loop over offending triangles
-  const size_t noff = offending.size();
-#ifdef IGL_SELFINTERSECTMESH_DEBUG
-  double t_proj_del = 0;
-#endif
-  // Unfortunately it looks like CGAL has trouble allocating memory when
-  // multiple openmp threads are running. Crashes durring CDT...
-//# pragma omp parallel for if (noff>1000)
-  for(Index o = 0;o<(Index)noff;o++)
-  {
-    // index in F
-    const Index f = offending[o];
-    {
-#ifdef IGL_SELFINTERSECTMESH_DEBUG
-      const double t_before = get_seconds();
-#endif
-      projected_delaunay(T[f],F_objects[f],cdt[o]);
-#ifdef IGL_SELFINTERSECTMESH_DEBUG
-      t_proj_del += (get_seconds()-t_before);
-#endif
-    }
-    // Q: Is this also delaunay in 3D?
-    // A: No, because the projection is affine and delaunay is not affine
-    // invariant.
-    // Q: Then, can't we first get the 2D delaunay triangulation, then lift it
-    // to 3D and flip any offending edges?
-    // Plane of projection (also used by projected_delaunay)
-    P[o] = Plane_3(T[f].vertex(0),T[f].vertex(1),T[f].vertex(2));
-    // Build index map
-    {
-      Index i=0;
-      for(
-        typename CDT_plus_2::Finite_vertices_iterator vit = cdt[o].finite_vertices_begin();
-        vit != cdt[o].finite_vertices_end();
-        ++vit)
-      {
-        if(i<3)
-        {
-          //cout<<T[f].vertex(i)<<
-          //  (T[f].vertex(i) == P[o].to_3d(vit->point())?" == ":" != ")<<
-          //  P[o].to_3d(vit->point())<<endl;
-#ifndef NDEBUG
-          // I want to be sure that the original corners really show up as the
-          // original corners of the CDT. I.e. I don't trust CGAL to maintain
-          // the order
-          assert(T[f].vertex(i) == P[o].to_3d(vit->point()));
-#endif
-          // For first three, use original index in F
-//#   pragma omp critical
-          v2i[vit] = F(f,i);
-        }else
-        {
-          const Point_3 vit_point_3 = P[o].to_3d(vit->point());
-          // First look up each edge's neighbors to see if exact point has
-          // already been added (This makes everything a bit quadratic)
-          bool found = false;
-          for(int e = 0; e<3 && !found;e++)
-          {
-            // Index of F's eth edge in V
-            Index i = F(f,(e+1)%3);
-            Index j = F(f,(e+2)%3);
-            // Be sure that i<j
-            if(i>j)
-            {
-              swap(i,j);
-            }
-            assert(edge2faces.count(EMK(i,j))==1);
-            // loop over neighbors
-            for(
-              typename IndexList::const_iterator nit = edge2faces[EMK(i,j)].begin();
-              nit != edge2faces[EMK(i,j)].end() && !found;
-              nit++)
-            {
-              // don't consider self
-              if(*nit == f)
-              {
-                continue;
-              }
-              // index of neighbor in offending (to find its cdt)
-              Index no = offending_index[*nit];
-              // Loop over vertices of that neighbor's cdt (might not have been
-              // processed yet, but then it's OK because it'll just be empty)
-              for(
-                  typename CDT_plus_2::Finite_vertices_iterator uit = cdt[no].finite_vertices_begin();
-                  uit != cdt[no].finite_vertices_end() && !found;
-                  ++uit)
-              {
-                if(vit_point_3 == P[no].to_3d(uit->point()))
-                {
-                  assert(v2i.count(uit) == 1);
-//#   pragma omp critical
-                  v2i[vit] = v2i[uit];
-                  found = true;
-                }
-              }
-            }
-          }
-          if(!found)
-          {
-//#   pragma omp critical
-            {
-              v2i[vit] = V.rows()+NV_count;
-              NV.push_back(vit_point_3);
-              NV_count++;
-            }
-          }
-        }
-        i++;
-      }
-    }
-    {
-      Index i = 0;
-      // Resize to fit new number of triangles
-      NF[o].resize(cdt[o].number_of_faces(),3);
-//#   pragma omp atomic
-      NF_count+=NF[o].rows();
-      // Append new faces to NF
-      for(
-        typename CDT_plus_2::Finite_faces_iterator fit = cdt[o].finite_faces_begin();
-        fit != cdt[o].finite_faces_end();
-        ++fit)
-      {
-        NF[o](i,0) = v2i[fit->vertex(0)];
-        NF[o](i,1) = v2i[fit->vertex(1)];
-        NF[o](i,2) = v2i[fit->vertex(2)];
-        i++;
-      }
-    }
-  }
-#ifdef IGL_SELFINTERSECTMESH_DEBUG
-  cout<<"CDT: "<<tictoc()<<"  "<<t_proj_del<<endl;
-#endif
-
-  assert(NV_count == (Index)NV.size());
-  // Build output
-#ifndef NDEBUG
-  {
-    Index off_count = 0;
-    for(Index f = 0;f<F.rows();f++)
-    {
-      off_count+= (offensive[f]?1:0);
-    }
-    assert(off_count==(Index)offending.size());
-  }
-#endif
-  // Append faces
-  FF.resize(F.rows()-offending.size()+NF_count,3);
-  J.resize(FF.rows());
-  // First append non-offending original faces
-  // There's an Eigen way to do this in one line but I forget
-  Index off = 0;
-  for(Index f = 0;f<F.rows();f++)
-  {
-    if(!offensive[f])
-    {
-      FF.row(off) = F.row(f);
-      J(off) = f;
-      off++;
-    }
-  }
-  assert(off == (Index)(F.rows()-offending.size()));
-  // Now append replacement faces for offending faces
-  for(Index o = 0;o<(Index)offending.size();o++)
-  {
-    FF.block(off,0,NF[o].rows(),3) = NF[o];
-    J.block(off,0,NF[o].rows(),1).setConstant(offending[o]);
-    off += NF[o].rows();
-  }
-  // Append vertices
-  VV.resize(V.rows()+NV_count,3);
-  VV.block(0,0,V.rows(),3) = V.template cast<typename DerivedVV::Scalar>();
-  {
-    Index i = 0;
-    for(
-      typename Point_3List::const_iterator nvit = NV.begin();
-      nvit != NV.end();
-      nvit++)
-    {
-      for(Index d = 0;d<3;d++)
-      {
-        const Point_3 & p = *nvit;
-        // Don't convert via double if output type is same as Kernel
-        to_output_type(p[d], VV(V.rows()+i,d));
-      }
-      i++;
-    }
-  }
-  IM.resize(VV.rows(),1);
-  map<Point_3,Index> vv2i;
-  // Safe to check for duplicates using double for original vertices: if
-  // incoming reps are different then the points are unique.
-  for(Index v = 0;v<V.rows();v++)
-  {
-    const Point_3 p(V(v,0),V(v,1),V(v,2));
-    if(vv2i.count(p)==0)
-    {
-      vv2i[p] = v;
-    }
-    assert(vv2i.count(p) == 1);
-    IM(v) = vv2i[p];
-  }
-  // Must check for duplicates of new vertices using exact.
-  {
-    Index v = V.rows();
-    for(
-      typename Point_3List::const_iterator nvit = NV.begin();
-      nvit != NV.end();
-      nvit++)
-    {
-      const Point_3 & p = *nvit;
-      if(vv2i.count(p)==0)
-      {
-        vv2i[p] = v;
-      }
-      assert(vv2i.count(p) == 1);
-      IM(v) = vv2i[p];
-      v++;
-    }
-  }
-#ifdef IGL_SELFINTERSECTMESH_DEBUG
-  cout<<"Output + dupes: "<<tictoc()<<endl;
-#endif
+  remesh_intersections(V,F,T,offending,edge2faces,VV,FF,J,IM);
 
   // Q: Does this give the same result as TETGEN?
   // A: For the cow and beast, yes.
@@ -659,6 +416,7 @@ inline igl::cgal::SelfIntersectMesh<
   // CGAL implementation on the beast takes 98 seconds but tetgen detection
   // takes 14 seconds
 
+
 }
 
 
@@ -683,28 +441,16 @@ inline void igl::cgal::SelfIntersectMesh<
 {
   using namespace std;
   lIF.push_back(f);
-  if(!offensive[f])
+  if(offending.count(f) == 0)
   {
-    offensive[f]=true;
-    offending_index[f]=offending.size();
-    offending.push_back(f);
-    // Add to edge map
+    // first time marking, initialize with new id and empty list
+    const Index id = offending.size();
+    offending[f] = {id,{}};
     for(Index e = 0; e<3;e++)
     {
-      // Index of F's eth edge in V
-      Index i = F(f,(e+1)%3);
-      Index j = F(f,(e+2)%3);
-      // Be sure that i<j
-      if(i>j)
-      {
-        swap(i,j);
-      }
-      // Create new list if there is no entry
-      if(edge2faces.count(EMK(i,j))==0)
-      {
-        edge2faces[EMK(i,j)] = EMV();
-      }
-      // append to list
+      // append face to edge's list
+      Index i = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+1)%3) : F(f,(e+2)%3);
+      Index j = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+2)%3) : F(f,(e+1)%3);
       edge2faces[EMK(i,j)].push_back(f);
     }
   }
@@ -769,14 +515,14 @@ inline bool igl::cgal::SelfIntersectMesh<
   {
     return false;
   }
+  count_intersection(fa,fb);
   if(!params.detect_only)
   {
     // Construct intersection
     CGAL::Object result = CGAL::intersection(A,B);
-    F_objects[fa].push_back(result);
-    F_objects[fb].push_back(result);
+    offending[fa].second.push_back(result);
+    offending[fb].second.push_back(result);
   }
-  count_intersection(fa,fb);
   return true;
 }
 
@@ -858,43 +604,41 @@ inline bool igl::cgal::SelfIntersectMesh<
 
   if(CGAL::do_intersect(sa,B))
   {
+    // can't put count_intersection(fa,fb) here since we use intersect below
+    // and then it will be counted twice.
+    if(params.detect_only)
+    {
+      count_intersection(fa,fb);
+      return true;
+    }
     CGAL::Object result = CGAL::intersection(sa,B);
     if(const Point_3 * p = CGAL::object_cast<Point_3 >(&result))
     {
-      if(!params.detect_only)
-      {
-        // Single intersection --> segment from shared point to intersection
-        CGAL::Object seg = CGAL::make_object(Segment_3(
-          A.vertex(va),
-          *p));
-        F_objects[fa].push_back(seg);
-        F_objects[fb].push_back(seg);
-      }
+      // Single intersection --> segment from shared point to intersection
+      CGAL::Object seg = CGAL::make_object(Segment_3(
+        A.vertex(va),
+        *p));
       count_intersection(fa,fb);
+      offending[fa].second.push_back(seg);
+      offending[fb].second.push_back(seg);
       return true;
     }else if(CGAL::object_cast<Segment_3 >(&result))
     {
       //cerr<<REDRUM("Coplanar at: "<<fa<<" & "<<fb<<" (single shared).")<<endl;
       // Must be coplanar
-      if(params.detect_only)
-      {
-        count_intersection(fa,fb);
-      }else
-      {
-        // WRONG:
-        //// Segment intersection --> triangle from shared point to intersection
-        //CGAL::Object tri = CGAL::make_object(Triangle_3(
-        //  A.vertex(va),
-        //  s->vertex(0),
-        //  s->vertex(1)));
-        //F_objects[fa].push_back(tri);
-        //F_objects[fb].push_back(tri);
-        //count_intersection(fa,fb);
-        // Need to do full test. Intersection could be a general poly.
-        bool test = intersect(A,B,fa,fb);
-        ((void)test);
-        assert(test);
-      }
+      // WRONG:
+      //// Segment intersection --> triangle from shared point to intersection
+      //CGAL::Object tri = CGAL::make_object(Triangle_3(
+      //  A.vertex(va),
+      //  s->vertex(0),
+      //  s->vertex(1)));
+      //F_objects[fa].push_back(tri);
+      //F_objects[fb].push_back(tri);
+      //count_intersection(fa,fb);
+      // Need to do full test. Intersection could be a general poly.
+      bool test = intersect(A,B,fa,fb);
+      ((void)test);
+      assert(test && "intersect should agree with do_intersect");
       return true;
     }else
     {
@@ -928,60 +672,122 @@ inline bool igl::cgal::SelfIntersectMesh<
   const Triangle_3 & A,
   const Triangle_3 & B,
   const Index fa,
-  const Index fb)
+  const Index fb,
+  const std::vector<std::pair<Index,Index> > shared)
 {
   using namespace std;
-  // Cheaper way to do this than calling do_intersect?
+
+  // must be co-planar
   if(
-    // Can only have an intersection if co-planar
-    (A.supporting_plane() == B.supporting_plane() ||
-    A.supporting_plane() == B.supporting_plane().opposite()) &&
-    CGAL::do_intersect(A,B))
+    A.supporting_plane() != B.supporting_plane() &&
+    A.supporting_plane() != B.supporting_plane().opposite())
   {
-    // Construct intersection
-    try
+    return false;
+  }
+  // Since A and B are non-degenerate the intersection must be a polygon
+  // (triangle). Either
+  //   - the vertex of A (B) opposite the shared edge of lies on B (A), or
+  //   - an edge of A intersects and edge of B without sharing a vertex
+
+
+
+  // Determine if the vertex opposite edge (a0,a1) in triangle A lies in
+  // (intersects) triangle B
+  const auto & opposite_point_inside = [](
+    const Triangle_3 & A, const Index a0, const Index a1, const Triangle_3 & B) 
+    -> bool
+  {
+    // get opposite index
+    Index a2 = -1;
+    for(int c = 0;c<3;c++)
     {
-      // This can fail for Epick but not Epeck
-      CGAL::Object result = CGAL::intersection(A,B);
-      if(!result.empty())
+      if(c != a0 && c != a1)
       {
-        if(CGAL::object_cast<Segment_3 >(&result))
-        {
-          // not coplanar
-          return false;
-        } else if(CGAL::object_cast<Point_3 >(&result))
-        {
-          // this "shouldn't" happen but does for inexact
-          return false;
-        } else
-        {
-          if(!params.detect_only)
-          {
-            // Triangle object
-            F_objects[fa].push_back(result);
-            F_objects[fb].push_back(result);
-          }
-          count_intersection(fa,fb);
-          //cerr<<REDRUM("Coplanar at: "<<fa<<" & "<<fb<<" (double shared).")<<endl;
-          return true;
-        }
-      }else
+        a2 = c;
+        break;
+      }
+    }
+    assert(a2 != -1);
+    bool ret = CGAL::do_intersect(A.vertex(a2),B);
+    //cout<<"opposite_point_inside: "<<ret<<endl;
+    return ret;
+  };
+
+  // Determine if edge opposite vertex va in triangle A intersects edge
+  // opposite vertex vb in triangle B.
+  const auto & opposite_edges_intersect = [](
+    const Triangle_3 & A, const Index va,
+    const Triangle_3 & B, const Index vb) -> bool
+  {
+    Segment_3 sa( A.vertex((va+1)%3), A.vertex((va+2)%3));
+    Segment_3 sb( B.vertex((vb+1)%3), B.vertex((vb+2)%3));
+    //cout<<sa<<endl;
+    //cout<<sb<<endl;
+    bool ret = CGAL::do_intersect(sa,sb);
+    //cout<<"opposite_edges_intersect: "<<ret<<endl;
+    return ret;
+  };
+
+
+  if( 
+    !opposite_point_inside(A,shared[0].first,shared[1].first,B) &&
+    !opposite_point_inside(B,shared[0].second,shared[1].second,A) &&
+    !opposite_edges_intersect(A,shared[0].first,B,shared[1].second) && 
+    !opposite_edges_intersect(A,shared[1].first,B,shared[0].second))
+  {
+    return false;
+  }
+
+  // there is an intersection indeed
+  count_intersection(fa,fb);
+  if(params.detect_only)
+  {
+    return true;
+  }
+  // Construct intersection
+  try
+  {
+    // This can fail for Epick but not Epeck
+    CGAL::Object result = CGAL::intersection(A,B);
+    if(!result.empty())
+    {
+      if(CGAL::object_cast<Segment_3 >(&result))
+      {
+        // not coplanar
+        assert(false && 
+          "Co-planar non-degenerate triangles should intersect over triangle");
+        return false;
+      } else if(CGAL::object_cast<Point_3 >(&result))
       {
-        // CGAL::intersection is disagreeing with do_intersect
+        // this "shouldn't" happen but does for inexact
+        assert(false && 
+          "Co-planar non-degenerate triangles should intersect over triangle");
         return false;
+      } else
+      {
+        // Triangle object
+        offending[fa].second.push_back(result);
+        offending[fb].second.push_back(result);
+        //cerr<<REDRUM("Coplanar at: "<<fa<<" & "<<fb<<" (double shared).")<<endl;
+        return true;
       }
-    }catch(...)
+    }else
     {
-      // This catches some cgal assertion:
-      //     CGAL error: assertion violation!
-      //     Expression : is_finite(d)
-      //     File       : /opt/local/include/CGAL/GMP/Gmpq_type.h
-      //     Line       : 132
-      //     Explanation: 
-      // But only if NDEBUG is not defined, otherwise there's an uncaught
-      // "Floating point exception: 8" SIGFPE
+      // CGAL::intersection is disagreeing with do_intersect
+      assert(false && "CGAL::intersection should agree with predicate tests");
       return false;
     }
+  }catch(...)
+  {
+    // This catches some cgal assertion:
+    //     CGAL error: assertion violation!
+    //     Expression : is_finite(d)
+    //     File       : /opt/local/include/CGAL/GMP/Gmpq_type.h
+    //     Line       : 132
+    //     Explanation: 
+    // But only if NDEBUG is not defined, otherwise there's an uncaught
+    // "Floating point exception: 8" SIGFPE
+    return false;
   }
   // No intersection.
   return false;
@@ -1030,9 +836,8 @@ inline void igl::cgal::SelfIntersectMesh<
   // Number of geometrically shared vertices (*not* including combinatorially
   // shared)
   Index geo_shared_vertices = 0;
-  // Keep track of shared vertex indices (we only handles single shared
-  // vertices as a special case, so just need last/first/only ones)
-  Index va=-1,vb=-1;
+  // Keep track of shared vertex indices
+  std::vector<std::pair<Index,Index> > shared;
   Index ea,eb;
   for(ea=0;ea<3;ea++)
   {
@@ -1041,25 +846,25 @@ inline void igl::cgal::SelfIntersectMesh<
       if(F(fa,ea) == F(fb,eb))
       {
         comb_shared_vertices++;
-        va = ea;
-        vb = eb;
+        shared.emplace_back(ea,eb);
       }else if(A.vertex(ea) == B.vertex(eb))
       {
         geo_shared_vertices++;
-        va = ea;
-        vb = eb;
+        shared.emplace_back(ea,eb);
       }
     }
   }
   const Index total_shared_vertices = comb_shared_vertices + geo_shared_vertices;
   if(comb_shared_vertices== 3)
   {
+    assert(shared.size() == 3);
     //// Combinatorially duplicate face, these should be removed by preprocessing
     //cerr<<REDRUM("Facets "<<fa<<" and "<<fb<<" are combinatorial duplicates")<<endl;
     goto done;
   }
   if(total_shared_vertices== 3)
   {
+    assert(shared.size() == 3);
     //// Geometrically duplicate face, these should be removed by preprocessing
     //cerr<<REDRUM("Facets "<<fa<<" and "<<fb<<" are geometrical duplicates")<<endl;
     goto done;
@@ -1081,6 +886,7 @@ inline void igl::cgal::SelfIntersectMesh<
 
   if(total_shared_vertices == 2)
   {
+    assert(shared.size() == 2);
     // Q: What about coplanar?
     //
     // o    o
@@ -1089,19 +895,17 @@ inline void igl::cgal::SelfIntersectMesh<
     // | /\ |
     // |/  \|
     // o----o
-    double_shared_vertex(A,B,fa,fb);
+    double_shared_vertex(A,B,fa,fb,shared);
 
     goto done;
   }
   assert(total_shared_vertices<=1);
   if(total_shared_vertices==1)
   {
-    assert(va>=0 && va<3);
-    assert(vb>=0 && vb<3);
 //#ifndef NDEBUG
 //    CGAL::Object result =
 //#endif
-    single_shared_vertex(A,B,fa,fb,va,vb);
+    single_shared_vertex(A,B,fa,fb,shared[0].first,shared[0].second);
 //#ifndef NDEBUG
 //    if(!CGAL::object_cast<Segment_3 >(&result))
 //    {
@@ -1130,142 +934,5 @@ done:
   return;
 }
 
-// Compute 2D delaunay triangulation of a given 3d triangle and a list of
-// intersection objects (points,segments,triangles). CGAL uses an affine
-// projection rather than an isometric projection, so we're not guaranteed
-// that the 2D delaunay triangulation here will be a delaunay triangulation
-// in 3D.
-//
-// Inputs:
-//   A  triangle in 3D
-//   A_objects_3  updated list of intersection objects for A
-// Outputs:
-//   cdt  Contrained delaunay triangulation in projected 2D plane
-template <
-  typename Kernel,
-  typename DerivedV,
-  typename DerivedF,
-  typename DerivedVV,
-  typename DerivedFF,
-  typename DerivedIF,
-  typename DerivedJ,
-  typename DerivedIM>
-inline void igl::cgal::SelfIntersectMesh<
-  Kernel,
-  DerivedV,
-  DerivedF,
-  DerivedVV,
-  DerivedFF,
-  DerivedIF,
-  DerivedJ,
-  DerivedIM>::projected_delaunay(
-  const Triangle_3 & A,
-  const ObjectList & A_objects_3,
-  CDT_plus_2 & cdt)
-{
-  using namespace std;
-  // http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Triangulation_2/Chapter_main.html#Section_2D_Triangulations_Constrained_Plus
-  // Plane of triangle A
-  Plane_3 P(A.vertex(0),A.vertex(1),A.vertex(2));
-  // Insert triangle into vertices
-  typename CDT_plus_2::Vertex_handle corners[3];
-  for(Index i = 0;i<3;i++)
-  {
-    corners[i] = cdt.insert(P.to_2d(A.vertex(i)));
-  }
-  // Insert triangle edges as constraints
-  for(Index i = 0;i<3;i++)
-  {
-    cdt.insert_constraint( corners[(i+1)%3], corners[(i+2)%3]);
-  }
-  // Insert constraints for intersection objects
-  for( const auto & obj : A_objects_3)
-  {
-    if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
-    {
-      // Add segment constraint
-      cdt.insert_constraint(P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
-    }else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
-    {
-      // Add point
-      cdt.insert(P.to_2d(*ipoint));
-    } else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
-    {
-      // Add 3 segment constraints
-      cdt.insert_constraint(P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
-      cdt.insert_constraint(P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
-      cdt.insert_constraint(P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
-    } else if(const std::vector<Point_3 > *polyp = 
-        CGAL::object_cast< std::vector<Point_3 > >(&obj))
-    {
-      //cerr<<REDRUM("Poly...")<<endl;
-      const std::vector<Point_3 > & poly = *polyp;
-      const Index m = poly.size();
-      assert(m>=2);
-      for(Index p = 0;p<m;p++)
-      {
-        const Index np = (p+1)%m;
-        cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
-      }
-    }else
-    {
-      cerr<<REDRUM("What is this object?!")<<endl;
-      assert(false);
-    }
-  }
-}
-
-template <
-  typename Kernel,
-  typename DerivedV,
-  typename DerivedF,
-  typename DerivedVV,
-  typename DerivedFF,
-  typename DerivedIF,
-  typename DerivedJ,
-  typename DerivedIM>
-inline 
-void 
-igl::cgal::SelfIntersectMesh<
-  Kernel,
-  DerivedV,
-  DerivedF,
-  DerivedVV,
-  DerivedFF,
-  DerivedIF,
-  DerivedJ,
-  DerivedIM>::to_output_type(
-    const typename Kernel::FT & cgal,
-    double & d)
-{
-  d = CGAL::to_double(cgal);
-}
-
-template <
-  typename Kernel,
-  typename DerivedV,
-  typename DerivedF,
-  typename DerivedVV,
-  typename DerivedFF,
-  typename DerivedIF,
-  typename DerivedJ,
-  typename DerivedIM>
-inline 
-void 
-igl::cgal::SelfIntersectMesh<
-  Kernel,
-  DerivedV,
-  DerivedF,
-  DerivedVV,
-  DerivedFF,
-  DerivedIF,
-  DerivedJ,
-  DerivedIM>::to_output_type(
-    const typename CGAL::Epeck::FT & cgal,
-    CGAL::Epeck::FT & d)
-{
-  d = cgal;
-}
-
 #endif
 

+ 22 - 0
include/igl/cgal/assign_scalar.cpp

@@ -0,0 +1,22 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "assign_scalar.h"
+
+IGL_INLINE void igl::cgal::assign_scalar(
+  const typename CGAL::Epeck::FT & cgal,
+  CGAL::Epeck::FT & d)
+{
+  d = cgal;
+}
+
+IGL_INLINE void igl::cgal::assign_scalar(
+  const typename CGAL::Epeck::FT & cgal,
+  double & d)
+{
+  d = CGAL::to_double(cgal);
+}

+ 31 - 0
include/igl/cgal/assign_scalar.h

@@ -0,0 +1,31 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CGAL_ASSIGN_SCALAR_H
+#define IGL_CGAL_ASSIGN_SCALAR_H
+#include "../igl_inline.h"
+#include "CGAL_includes.hpp"
+namespace igl
+{
+  namespace cgal
+  {
+    // Inputs:
+    //   cgal  cgal scalar
+    // Outputs:
+    //   d  output scalar
+    IGL_INLINE void assign_scalar(
+      const typename CGAL::Epeck::FT & cgal,
+      CGAL::Epeck::FT & d);
+    IGL_INLINE void assign_scalar(
+      const typename CGAL::Epeck::FT & cgal,
+      double & d);
+  }
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "assign_scalar.cpp"
+#endif
+#endif

+ 237 - 99
include/igl/cgal/intersect_other.cpp

@@ -8,123 +8,261 @@
 #include "intersect_other.h"
 #include "CGAL_includes.hpp"
 #include "mesh_to_cgal_triangle_list.h"
+#include "remesh_intersections.h"
 
 #ifndef IGL_FIRST_HIT_EXCEPTION
 #define IGL_FIRST_HIT_EXCEPTION 10
 #endif
 
-IGL_INLINE void igl::cgal::intersect_other(
-  const Eigen::MatrixXd & V,
-  const Eigen::MatrixXi & F,
-  const Eigen::MatrixXd & U,
-  const Eigen::MatrixXi & G,
-  const bool first_only,
-  Eigen::MatrixXi & IF)
+// Un-exposed helper functions
+namespace igl
 {
-  using namespace std;
-  using namespace Eigen;
-
-
-  typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
-  // 3D Primitives
-  typedef CGAL::Point_3<Kernel>    Point_3;
-  typedef CGAL::Segment_3<Kernel>  Segment_3; 
-  typedef CGAL::Triangle_3<Kernel> Triangle_3; 
-  typedef CGAL::Plane_3<Kernel>    Plane_3;
-  typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3; 
-  // 2D Primitives
-  typedef CGAL::Point_2<Kernel>    Point_2;
-  typedef CGAL::Segment_2<Kernel>  Segment_2; 
-  typedef CGAL::Triangle_2<Kernel> Triangle_2; 
-  // 2D Constrained Delaunay Triangulation types
-  typedef CGAL::Triangulation_vertex_base_2<Kernel>  TVB_2;
-  typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
-  typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
-  typedef CGAL::Exact_intersections_tag Itag;
-  typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag> 
-    CDT_2;
-  typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
-  // Axis-align boxes for all-pairs self-intersection detection
-  typedef std::vector<Triangle_3> Triangles;
-  typedef typename Triangles::iterator TrianglesIterator;
-  typedef typename Triangles::const_iterator TrianglesConstIterator;
-  typedef 
-    CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator> 
-    Box;
-
-  Triangles TF,TG;
-  // Compute and process self intersections
-  mesh_to_cgal_triangle_list(V,F,TF);
-  mesh_to_cgal_triangle_list(U,G,TG);
-  // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5 
-  // Create the corresponding vector of bounding boxes
-  std::vector<Box> F_boxes,G_boxes;
-  const auto box_up = [](Triangles & T, std::vector<Box> & boxes)
+  namespace cgal
   {
-    boxes.reserve(T.size());
-    for ( 
-      TrianglesIterator tit = T.begin(); 
-      tit != T.end(); 
-      ++tit)
+    template <typename DerivedF>
+    static IGL_INLINE void push_result(
+      const Eigen::PlainObjectBase<DerivedF> & F,
+      const int f,
+      const CGAL::Object & result,
+      std::map<
+        typename DerivedF::Index,
+        std::pair<typename DerivedF::Index,
+          std::vector<CGAL::Object> > > & offending,
+      std::map<
+        std::pair<typename DerivedF::Index,typename DerivedF::Index>,
+        std::vector<typename DerivedF::Index> > & edge2faces)
     {
-      boxes.push_back(Box(tit->bbox(), tit));
-    }
-  };
-  box_up(TF,F_boxes);
-  box_up(TG,G_boxes);
-  std::list<int> lIF;
-  const auto cb = [&](const Box &a, const Box &b)
-  {
-    using namespace std;
-    // index in F and T
-    int fa = a.handle()-TF.begin();
-    int fb = b.handle()-TG.begin();
-    const Triangle_3 & A = *a.handle();
-    const Triangle_3 & B = *b.handle();
-    if(CGAL::do_intersect(A,B))
-    {
-      // There was an intersection
-      lIF.push_back(fa);
-      lIF.push_back(fb);
-      if(first_only)
+      typedef typename DerivedF::Index Index;
+      typedef std::pair<Index,Index> EMK;
+      if(offending.count(f) == 0)
       {
-        throw IGL_FIRST_HIT_EXCEPTION;
+        // first time marking, initialize with new id and empty list
+        Index id = offending.size();
+        offending[f] = {id,{}};
+        for(Index e = 0; e<3;e++)
+        {
+          // append face to edge's list
+          Index i = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+1)%3) : F(f,(e+2)%3);
+          Index j = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+2)%3) : F(f,(e+1)%3);
+          edge2faces[EMK(i,j)].push_back(f);
+        }
       }
+      offending[f].second.push_back(result);
     }
-  };
-  try{
-    CGAL::box_intersection_d(
-      F_boxes.begin(), F_boxes.end(),
-      G_boxes.begin(), G_boxes.end(),
-      cb);
-  }catch(int e)
-  {
-    // Rethrow if not FIRST_HIT_EXCEPTION
-    if(e != IGL_FIRST_HIT_EXCEPTION)
+    template <
+      typename Kernel,
+      typename DerivedVA,
+      typename DerivedFA,
+      typename DerivedVB,
+      typename DerivedFB,
+      typename DerivedIF,
+      typename DerivedVVA,
+      typename DerivedFFA,
+      typename DerivedJA,
+      typename DerivedIMA,
+      typename DerivedVVB,
+      typename DerivedFFB,
+      typename DerivedJB,
+      typename DerivedIMB>
+    static IGL_INLINE bool intersect_other_helper(
+      const Eigen::PlainObjectBase<DerivedVA> & VA,
+      const Eigen::PlainObjectBase<DerivedFA> & FA,
+      const Eigen::PlainObjectBase<DerivedVB> & VB,
+      const Eigen::PlainObjectBase<DerivedFB> & FB,
+      const RemeshSelfIntersectionsParam & params,
+      Eigen::PlainObjectBase<DerivedIF> & IF,
+      Eigen::PlainObjectBase<DerivedVVA> & VVA,
+      Eigen::PlainObjectBase<DerivedFFA> & FFA,
+      Eigen::PlainObjectBase<DerivedJA>  & JA,
+      Eigen::PlainObjectBase<DerivedIMA> & IMA,
+      Eigen::PlainObjectBase<DerivedVVB> & VVB,
+      Eigen::PlainObjectBase<DerivedFFB> & FFB,
+      Eigen::PlainObjectBase<DerivedJB>  & JB,
+      Eigen::PlainObjectBase<DerivedIMB> & IMB)
     {
-      throw e;
+
+      using namespace std;
+      using namespace Eigen;
+
+      typedef typename DerivedFA::Index Index;
+      // 3D Primitives
+      typedef CGAL::Point_3<Kernel>    Point_3;
+      typedef CGAL::Segment_3<Kernel>  Segment_3; 
+      typedef CGAL::Triangle_3<Kernel> Triangle_3; 
+      typedef CGAL::Plane_3<Kernel>    Plane_3;
+      typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3; 
+      // 2D Primitives
+      typedef CGAL::Point_2<Kernel>    Point_2;
+      typedef CGAL::Segment_2<Kernel>  Segment_2; 
+      typedef CGAL::Triangle_2<Kernel> Triangle_2; 
+      // 2D Constrained Delaunay Triangulation types
+      typedef CGAL::Triangulation_vertex_base_2<Kernel>  TVB_2;
+      typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTAB_2;
+      typedef CGAL::Triangulation_data_structure_2<TVB_2,CTAB_2> TDS_2;
+      typedef CGAL::Exact_intersections_tag Itag;
+      typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag> 
+        CDT_2;
+      typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
+      // Axis-align boxes for all-pairs self-intersection detection
+      typedef std::vector<Triangle_3> Triangles;
+      typedef typename Triangles::iterator TrianglesIterator;
+      typedef typename Triangles::const_iterator TrianglesConstIterator;
+      typedef 
+        CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator> 
+        Box;
+      typedef 
+        std::map<Index,std::pair<Index,std::vector<CGAL::Object> > > 
+        OffendingMap;
+      typedef std::map<std::pair<Index,Index>,std::vector<Index> >  EdgeMap;
+      typedef std::pair<Index,Index> EMK;
+
+      Triangles TA,TB;
+      // Compute and process self intersections
+      mesh_to_cgal_triangle_list(VA,FA,TA);
+      mesh_to_cgal_triangle_list(VB,FB,TB);
+      // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5 
+      // Create the corresponding vector of bounding boxes
+      std::vector<Box> A_boxes,B_boxes;
+      const auto box_up = [](Triangles & T, std::vector<Box> & boxes)
+      {
+        boxes.reserve(T.size());
+        for ( 
+          TrianglesIterator tit = T.begin(); 
+          tit != T.end(); 
+          ++tit)
+        {
+          boxes.push_back(Box(tit->bbox(), tit));
+        }
+      };
+      box_up(TA,A_boxes);
+      box_up(TB,B_boxes);
+      OffendingMap offendingA,offendingB;
+      EdgeMap edge2facesA,edge2facesB;
+
+      std::list<int> lIF;
+      const auto cb = [&](const Box &a, const Box &b)
+      {
+        using namespace std;
+        // index in F and T
+        int fa = a.handle()-TA.begin();
+        int fb = b.handle()-TB.begin();
+        const Triangle_3 & A = *a.handle();
+        const Triangle_3 & B = *b.handle();
+        if(CGAL::do_intersect(A,B))
+        {
+          // There was an intersection
+          lIF.push_back(fa);
+          lIF.push_back(fb);
+          if(params.first_only)
+          {
+            throw IGL_FIRST_HIT_EXCEPTION;
+          }
+          if(!params.detect_only)
+          {
+            CGAL::Object result = CGAL::intersection(A,B);
+
+            push_result(FA,fa,result,offendingA,edge2facesA);
+            push_result(FB,fb,result,offendingB,edge2facesB);
+          }
+        }
+      };
+      try{
+        CGAL::box_intersection_d(
+          A_boxes.begin(), A_boxes.end(),
+          B_boxes.begin(), B_boxes.end(),
+          cb);
+      }catch(int e)
+      {
+        // Rethrow if not FIRST_HIT_EXCEPTION
+        if(e != IGL_FIRST_HIT_EXCEPTION)
+        {
+          throw e;
+        }
+        // Otherwise just fall through
+      }
+
+      // Convert lIF to Eigen matrix
+      assert(lIF.size()%2 == 0);
+      IF.resize(lIF.size()/2,2);
+      {
+        int i=0;
+        for(
+          list<int>::const_iterator ifit = lIF.begin();
+          ifit!=lIF.end();
+          )
+        {
+          IF(i,0) = (*ifit);
+          ifit++; 
+          IF(i,1) = (*ifit);
+          ifit++;
+          i++;
+        }
+      }
+      if(!params.detect_only)
+      {
+        remesh_intersections(VA,FA,TA,offendingA,edge2facesA,VVA,FFA,JA,IMA);
+        remesh_intersections(VB,FB,TB,offendingB,edge2facesB,VVB,FFB,JB,IMB);
+      }
+
+      return IF.rows() > 0;
     }
-    // Otherwise just fall through
   }
+}
 
-  // Convert lIF to Eigen matrix
-  assert(lIF.size()%2 == 0);
-  IF.resize(lIF.size()/2,2);
+template <
+  typename DerivedVA,
+  typename DerivedFA,
+  typename DerivedVB,
+  typename DerivedFB,
+  typename DerivedIF,
+  typename DerivedVVA,
+  typename DerivedFFA,
+  typename DerivedJA,
+  typename DerivedIMA,
+  typename DerivedVVB,
+  typename DerivedFFB,
+  typename DerivedJB,
+  typename DerivedIMB>
+IGL_INLINE bool igl::cgal::intersect_other(
+  const Eigen::PlainObjectBase<DerivedVA> & VA,
+  const Eigen::PlainObjectBase<DerivedFA> & FA,
+  const Eigen::PlainObjectBase<DerivedVB> & VB,
+  const Eigen::PlainObjectBase<DerivedFB> & FB,
+  const RemeshSelfIntersectionsParam & params,
+  Eigen::PlainObjectBase<DerivedIF> & IF,
+  Eigen::PlainObjectBase<DerivedVVA> & VVA,
+  Eigen::PlainObjectBase<DerivedFFA> & FFA,
+  Eigen::PlainObjectBase<DerivedJA>  & JA,
+  Eigen::PlainObjectBase<DerivedIMA> & IMA,
+  Eigen::PlainObjectBase<DerivedVVB> & VVB,
+  Eigen::PlainObjectBase<DerivedFFB> & FFB,
+  Eigen::PlainObjectBase<DerivedJB>  & JB,
+  Eigen::PlainObjectBase<DerivedIMB> & IMB)
+{
+  if(params.detect_only)
   {
-    int i=0;
-    for(
-      list<int>::const_iterator ifit = lIF.begin();
-      ifit!=lIF.end();
-      )
-    {
-      IF(i,0) = (*ifit);
-      ifit++; 
-      IF(i,1) = (*ifit);
-      ifit++;
-      i++;
-    }
+    return intersect_other_helper<CGAL::Epick>
+      (VA,FA,VB,FB,params,IF,VVA,FFA,JA,IMA,VVB,FFB,JB,IMB);
+  }else
+  {
+    return intersect_other_helper<CGAL::Epeck>
+      (VA,FA,VB,FB,params,IF,VVA,FFA,JA,IMA,VVB,FFB,JB,IMB);
   }
+}
 
+IGL_INLINE bool igl::cgal::intersect_other(
+  const Eigen::MatrixXd & VA,
+  const Eigen::MatrixXi & FA,
+  const Eigen::MatrixXd & VB,
+  const Eigen::MatrixXi & FB,
+  const bool first_only,
+  Eigen::MatrixXi & IF)
+{
+  Eigen::MatrixXd VVA,VVB;
+  Eigen::MatrixXi FFA,FFB;
+  Eigen::VectorXi JA,JB,IMA,IMB;
+  return intersect_other(
+    VA,FA,VB,FB,{true,first_only},IF,VVA,FFA,JA,IMA,VVB,FFB,JB,IMB);
 }
 
 #ifdef IGL_STATIC_LIBRARY

+ 66 - 16
include/igl/cgal/intersect_other.h

@@ -1,13 +1,14 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // 
-// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+// Copyright (C) 2015 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 
 // obtain one at http://mozilla.org/MPL/2.0/.
 #ifndef IGL_CGAL_INTERSECT_OTHER_H
 #define IGL_CGAL_INTERSECT_OTHER_H
-#include <igl/igl_inline.h>
+#include "../igl_inline.h"
+#include "RemeshSelfIntersectionsParam.h"
 
 #include <Eigen/Dense>
 
@@ -22,27 +23,76 @@ namespace igl
 {
   namespace cgal
   {
-    // INTERSECT Given a triangle mesh (V,F) and another mesh (U,G) find all pairs
-    // of intersecting faces. Note that self-intersections are ignored.
+    // INTERSECT_OTHER Given a triangle mesh (VA,FA) and another mesh (VB,FB)
+    // find all pairs of intersecting faces. Note that self-intersections are
+    // ignored.
     // 
-    // [VV,FF,IF] = selfintersect(V,F,'ParameterName',ParameterValue, ...)
+    // Inputs:
+    //   VA  #V by 3 list of vertex positions
+    //   FA  #F by 3 list of triangle indices into VA
+    //   VB  #V by 3 list of vertex positions
+    //   FB  #F by 3 list of triangle indices into VB
+    //   params   whether to detect only and then whether to only find first
+    //     intersection
+    // Outputs:
+    //   IF  #intersecting face pairs by 2 list of intersecting face pairs,
+    //     indexing FA and FB
+    //   VVA  #VVA by 3 list of vertex positions
+    //   FFA  #FFA by 3 list of triangle indices into VVA
+    //   JA  #FFA list of indices into FA denoting birth triangle
+    //   IMA  #VVA list of indices into VVA of unique vertices.
+    //   VVB  #VVB by 3 list of vertex positions
+    //   FFB  #FFB by 3 list of triangle indices into VVB
+    //   JB  #FFB list of indices into FB denoting birth triangle
+    //   IMB  #VVB list of indices into VVB of unique vertices.
+    template <
+      typename DerivedVA,
+      typename DerivedFA,
+      typename DerivedVB,
+      typename DerivedFB,
+      typename DerivedIF,
+      typename DerivedVVA,
+      typename DerivedFFA,
+      typename DerivedJA,
+      typename DerivedIMA,
+      typename DerivedVVB,
+      typename DerivedFFB,
+      typename DerivedJB,
+      typename DerivedIMB>
+    IGL_INLINE bool intersect_other(
+      const Eigen::PlainObjectBase<DerivedVA> & VA,
+      const Eigen::PlainObjectBase<DerivedFA> & FA,
+      const Eigen::PlainObjectBase<DerivedVB> & VB,
+      const Eigen::PlainObjectBase<DerivedFB> & FB,
+      const RemeshSelfIntersectionsParam & params,
+      Eigen::PlainObjectBase<DerivedIF> & IF,
+      Eigen::PlainObjectBase<DerivedVVA> & VVA,
+      Eigen::PlainObjectBase<DerivedFFA> & FFA,
+      Eigen::PlainObjectBase<DerivedJA>  & JA,
+      Eigen::PlainObjectBase<DerivedIMA> & IMA,
+      Eigen::PlainObjectBase<DerivedVVB> & VVB,
+      Eigen::PlainObjectBase<DerivedFFB> & FFB,
+      Eigen::PlainObjectBase<DerivedJB>  & JB,
+      Eigen::PlainObjectBase<DerivedIMB> & IMB);
+    // Legacy wrapper for detect only using common types.
     //
     // Inputs:
-    //   V  #V by 3 list of vertex positions
-    //   F  #F by 3 list of triangle indices into V
-    //   U  #U by 3 list of vertex positions
-    //   G  #G by 3 list of triangle indices into U
+    //   VA  #V by 3 list of vertex positions
+    //   FA  #F by 3 list of triangle indices into VA
+    //   VB  #V by 3 list of vertex positions
+    //   FB  #F by 3 list of triangle indices into VB
     //   first_only  whether to only detect the first intersection.
     // Outputs:
     //   IF  #intersecting face pairs by 2 list of intersecting face pairs,
-    //     indexing F and G
+    //     indexing FA and FB
+    // Returns true if any intersections were found
     //
-    // See also: selfintersect
-    IGL_INLINE void intersect_other(
-      const Eigen::MatrixXd & V,
-      const Eigen::MatrixXi & F,
-      const Eigen::MatrixXd & U,
-      const Eigen::MatrixXi & G,
+    // See also: remesh_self_intersections
+    IGL_INLINE bool intersect_other(
+      const Eigen::MatrixXd & VA,
+      const Eigen::MatrixXi & FA,
+      const Eigen::MatrixXd & VB,
+      const Eigen::MatrixXi & FB,
       const bool first_only,
       Eigen::MatrixXi & IF);
   }

+ 8 - 8
include/igl/cgal/outer_hull.cpp

@@ -7,7 +7,7 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "outer_hull.h"
 #include "order_facets_around_edges.h"
-#include "../outer_facet.h"
+#include "../outer_element.h"
 #include "../sortrows.h"
 #include "../facet_components.h"
 #include "../winding_number.h"
@@ -163,9 +163,9 @@ IGL_INLINE void igl::cgal::outer_hull(
     outer_facet(V,F,N,IM,f,f_flip);
 #ifdef IGL_OUTER_HULL_DEBUG
   cout<<"outer facet: "<<f<<endl;
-  cout << V.row(F(f, 0)) << std::endl;
-  cout << V.row(F(f, 1)) << std::endl;
-  cout << V.row(F(f, 2)) << std::endl;
+  //cout << V.row(F(f, 0)) << std::endl;
+  //cout << V.row(F(f, 1)) << std::endl;
+  //cout << V.row(F(f, 2)) << std::endl;
 #endif
     int FHcount = 1;
     FH[f] = true;
@@ -209,9 +209,9 @@ IGL_INLINE void igl::cgal::outer_hull(
       // edge valence
       const size_t val = uE2E[EMAP(e)].size();
 #ifdef IGL_OUTER_HULL_DEBUG
-      std::cout << "vd: " << V.row(fd) << std::endl;
-      std::cout << "vs: " << V.row(fs) << std::endl;
-      std::cout << "edge: " << V.row(fd) - V.row(fs) << std::endl;
+      //std::cout << "vd: " << V.row(fd) << std::endl;
+      //std::cout << "vs: " << V.row(fs) << std::endl;
+      //std::cout << "edge: " << V.row(fd) - V.row(fs) << std::endl;
       for (size_t i=0; i<val; i++) {
           if (i == diIM(e)) {
               std::cout << "* ";
@@ -536,7 +536,7 @@ IGL_INLINE void igl::cgal::outer_hull(
 // Explicit template specialization
 #undef IGL_STATIC_LIBRARY
 #include <igl/barycenter.cpp>
-#include <igl/outer_facet.cpp>
+#include <igl/outer_element.cpp>
 #include <igl/cgal/order_facets_around_edges.cpp>
 #define IGL_STATIC_LIBRARY
 template void igl::cgal::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> >&);

+ 96 - 0
include/igl/cgal/projected_delaunay.cpp

@@ -0,0 +1,96 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "projected_delaunay.h"
+#include "../REDRUM.h"
+#include <iostream>
+#include <cassert>
+
+template <typename Kernel>
+IGL_INLINE void igl::cgal::projected_delaunay(
+  const CGAL::Triangle_3<Kernel> & A,
+  const std::vector<CGAL::Object> & A_objects_3,
+  CGAL::Constrained_triangulation_plus_2<
+    CGAL::Constrained_Delaunay_triangulation_2<
+      Kernel,
+      CGAL::Triangulation_data_structure_2<
+        CGAL::Triangulation_vertex_base_2<Kernel>,
+        CGAL::Constrained_triangulation_face_base_2<Kernel> >,
+      CGAL::Exact_intersections_tag> > & cdt)
+{
+  using namespace std;
+  // 3D Primitives
+  typedef CGAL::Point_3<Kernel>    Point_3;
+  typedef CGAL::Segment_3<Kernel>  Segment_3; 
+  typedef CGAL::Triangle_3<Kernel> Triangle_3; 
+  typedef CGAL::Plane_3<Kernel>    Plane_3;
+  typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3; 
+  typedef CGAL::Point_2<Kernel>    Point_2;
+  typedef CGAL::Segment_2<Kernel>  Segment_2; 
+  typedef CGAL::Triangle_2<Kernel> Triangle_2; 
+  typedef CGAL::Triangulation_vertex_base_2<Kernel>  TVB_2;
+  typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
+  typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
+  typedef CGAL::Exact_intersections_tag Itag;
+  typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag> 
+    CDT_2;
+  typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
+
+  // http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Triangulation_2/Chapter_main.html#Section_2D_Triangulations_Constrained_Plus
+  // Plane of triangle A
+  Plane_3 P(A.vertex(0),A.vertex(1),A.vertex(2));
+  // Insert triangle into vertices
+  typename CDT_plus_2::Vertex_handle corners[3];
+  typedef size_t Index;
+  for(Index i = 0;i<3;i++)
+  {
+    const Point_3 & p3 = A.vertex(i);
+    const Point_2 & p2 = P.to_2d(p3);
+    typename CDT_plus_2::Vertex_handle corner = cdt.insert(p2);
+    corners[i] = corner;
+  }
+  // Insert triangle edges as constraints
+  for(Index i = 0;i<3;i++)
+  {
+    cdt.insert_constraint( corners[(i+1)%3], corners[(i+2)%3]);
+  }
+  // Insert constraints for intersection objects
+  for( const auto & obj : A_objects_3)
+  {
+    if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
+    {
+      // Add segment constraint
+      cdt.insert_constraint(P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
+    }else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
+    {
+      // Add point
+      cdt.insert(P.to_2d(*ipoint));
+    } else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
+    {
+      // Add 3 segment constraints
+      cdt.insert_constraint(P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
+      cdt.insert_constraint(P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
+      cdt.insert_constraint(P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
+    } else if(const std::vector<Point_3 > *polyp = 
+        CGAL::object_cast< std::vector<Point_3 > >(&obj))
+    {
+      //cerr<<REDRUM("Poly...")<<endl;
+      const std::vector<Point_3 > & poly = *polyp;
+      const Index m = poly.size();
+      assert(m>=2);
+      for(Index p = 0;p<m;p++)
+      {
+        const Index np = (p+1)%m;
+        cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
+      }
+    }else
+    {
+      cerr<<REDRUM("What is this object?!")<<endl;
+      assert(false);
+    }
+  }
+}

+ 43 - 0
include/igl/cgal/projected_delaunay.h

@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CGAL_PROJECTED_DELAUNAY_H
+#define IGL_CGAL_PROJECTED_DELAUNAY_H
+#include "../igl_inline.h"
+#include "CGAL_includes.hpp"
+namespace igl
+{
+  namespace cgal
+  {
+    // Compute 2D delaunay triangulation of a given 3d triangle and a list of
+    // intersection objects (points,segments,triangles). CGAL uses an affine
+    // projection rather than an isometric projection, so we're not guaranteed
+    // that the 2D delaunay triangulation here will be a delaunay triangulation
+    // in 3D.
+    //
+    // Inputs:
+    //   A  triangle in 3D
+    //   A_objects_3  updated list of intersection objects for A
+    // Outputs:
+    //   cdt  Contrained delaunay triangulation in projected 2D plane
+    template <typename Kernel>
+    IGL_INLINE void projected_delaunay(
+      const CGAL::Triangle_3<Kernel> & A,
+      const std::vector<CGAL::Object> & A_objects_3,
+      CGAL::Constrained_triangulation_plus_2<
+        CGAL::Constrained_Delaunay_triangulation_2<
+          Kernel,
+          CGAL::Triangulation_data_structure_2<
+            CGAL::Triangulation_vertex_base_2<Kernel>,
+            CGAL::Constrained_triangulation_face_base_2<Kernel> >,
+          CGAL::Exact_intersections_tag> > & cdt);
+  }
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "projected_delaunay.cpp"
+#endif
+#endif

+ 306 - 0
include/igl/cgal/remesh_intersections.cpp

@@ -0,0 +1,306 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "remesh_intersections.h"
+#include "SelfIntersectMesh.h"
+#include "assign_scalar.h"
+#include "projected_delaunay.h"
+#include <iostream>
+#include <cassert>
+
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename Kernel,
+  typename DerivedVV,
+  typename DerivedFF,
+  typename DerivedJ,
+  typename DerivedIM>
+IGL_INLINE void igl::cgal::remesh_intersections(
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  const std::vector<CGAL::Triangle_3<Kernel> > & T,
+  const std::map<
+    typename DerivedF::Index,
+    std::pair<typename DerivedF::Index,
+      std::vector<CGAL::Object> > > & offending,
+  const std::map<
+    std::pair<typename DerivedF::Index,typename DerivedF::Index>,
+    std::vector<typename DerivedF::Index> > & edge2faces,
+  Eigen::PlainObjectBase<DerivedVV> & VV,
+  Eigen::PlainObjectBase<DerivedFF> & FF,
+  Eigen::PlainObjectBase<DerivedJ> & J,
+  Eigen::PlainObjectBase<DerivedIM> & IM)
+{
+  using namespace std;
+  using namespace Eigen;
+  typedef typename DerivedF::Index          Index;
+  typedef CGAL::Point_3<Kernel>    Point_3;
+  typedef CGAL::Segment_3<Kernel>  Segment_3; 
+  typedef CGAL::Triangle_3<Kernel> Triangle_3; 
+  typedef CGAL::Plane_3<Kernel>    Plane_3;
+  typedef CGAL::Point_2<Kernel>    Point_2;
+  typedef CGAL::Segment_2<Kernel>  Segment_2; 
+  typedef CGAL::Triangle_2<Kernel> Triangle_2; 
+  typedef CGAL::Triangulation_vertex_base_2<Kernel>  TVB_2;
+  typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
+  typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
+  typedef CGAL::Exact_intersections_tag Itag;
+  typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag> 
+    CDT_2;
+  typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
+  typedef std::pair<Index,Index> EMK;
+  typedef std::vector<Index> EMV;
+  typedef std::map<EMK,EMV> EdgeMap;
+  typedef std::pair<Index,Index> EMK;
+  typedef std::vector<CGAL::Object> ObjectList;
+  typedef std::vector<Index> IndexList;
+
+  int NF_count = 0;
+  // list of new faces, we'll fix F later
+  vector<
+    typename Eigen::Matrix<typename DerivedFF::Scalar,Dynamic,Dynamic>
+    > NF(offending.size());
+  // list of new vertices
+  typedef vector<Point_3> Point_3List;
+  Point_3List NV;
+  Index NV_count = 0;
+  vector<CDT_plus_2> cdt(offending.size());
+  vector<Plane_3> P(offending.size());
+  // Use map for *all* faces
+  map<typename CDT_plus_2::Vertex_handle,Index> v2i;
+  // Loop over offending triangles
+  const size_t noff = offending.size();
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+  double t_proj_del = 0;
+#endif
+  // Unfortunately it looks like CGAL has trouble allocating memory when
+  // multiple openmp threads are running. Crashes durring CDT...
+//# pragma omp parallel for if (noff>1000)
+  for(const auto & okv : offending)
+  {
+    // index in F
+    const Index f = okv.first;
+    const Index o = okv.second.first;
+    {
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+      const double t_before = get_seconds();
+#endif
+      CDT_plus_2 cdt_o;
+      projected_delaunay(T[f],okv.second.second,cdt_o);
+      cdt[o] = cdt_o;
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+      t_proj_del += (get_seconds()-t_before);
+#endif
+    }
+    // Q: Is this also delaunay in 3D?
+    // A: No, because the projection is affine and delaunay is not affine
+    // invariant.
+    // Q: Then, can't we first get the 2D delaunay triangulation, then lift it
+    // to 3D and flip any offending edges?
+    // Plane of projection (also used by projected_delaunay)
+    P[o] = Plane_3(T[f].vertex(0),T[f].vertex(1),T[f].vertex(2));
+    // Build index map
+    {
+      Index i=0;
+      for(
+        typename CDT_plus_2::Finite_vertices_iterator vit = cdt[o].finite_vertices_begin();
+        vit != cdt[o].finite_vertices_end();
+        ++vit)
+      {
+        if(i<3)
+        {
+          //cout<<T[f].vertex(i)<<
+          //  (T[f].vertex(i) == P[o].to_3d(vit->point())?" == ":" != ")<<
+          //  P[o].to_3d(vit->point())<<endl;
+#ifndef NDEBUG
+          // I want to be sure that the original corners really show up as the
+          // original corners of the CDT. I.e. I don't trust CGAL to maintain
+          // the order
+          assert(T[f].vertex(i) == P[o].to_3d(vit->point()));
+#endif
+          // For first three, use original index in F
+//#   pragma omp critical
+          v2i[vit] = F(f,i);
+        }else
+        {
+          const Point_3 vit_point_3 = P[o].to_3d(vit->point());
+          // First look up each edge's neighbors to see if exact point has
+          // already been added (This makes everything a bit quadratic)
+          bool found = false;
+          for(int e = 0; e<3 && !found;e++)
+          {
+            // Index of F's eth edge in V
+            Index i = F(f,(e+1)%3);
+            Index j = F(f,(e+2)%3);
+            // Be sure that i<j
+            if(i>j)
+            {
+              swap(i,j);
+            }
+            assert(edge2faces.count(EMK(i,j))==1);
+            const EMV & facesij = edge2faces.find(EMK(i,j))->second;
+            // loop over neighbors
+            for(
+              typename IndexList::const_iterator nit = facesij.begin();
+              nit != facesij.end() && !found;
+              nit++)
+            {
+              // don't consider self
+              if(*nit == f)
+              {
+                continue;
+              }
+              // index of neighbor in offending (to find its cdt)
+              assert(offending.count(*nit) == 1);
+              Index no = offending.find(*nit)->second.first;
+              // Loop over vertices of that neighbor's cdt (might not have been
+              // processed yet, but then it's OK because it'll just be empty)
+              for(
+                  typename CDT_plus_2::Finite_vertices_iterator uit = cdt[no].finite_vertices_begin();
+                  uit != cdt[no].finite_vertices_end() && !found;
+                  ++uit)
+              {
+                if(vit_point_3 == P[no].to_3d(uit->point()))
+                {
+                  assert(v2i.count(uit) == 1);
+//#   pragma omp critical
+                  v2i[vit] = v2i[uit];
+                  found = true;
+                }
+              }
+            }
+          }
+          if(!found)
+          {
+//#   pragma omp critical
+            {
+              v2i[vit] = V.rows()+NV_count;
+              NV.push_back(vit_point_3);
+              NV_count++;
+            }
+          }
+        }
+        i++;
+      }
+    }
+    {
+      Index i = 0;
+      // Resize to fit new number of triangles
+      NF[o].resize(cdt[o].number_of_faces(),3);
+//#   pragma omp atomic
+      NF_count+=NF[o].rows();
+      // Append new faces to NF
+      for(
+        typename CDT_plus_2::Finite_faces_iterator fit = cdt[o].finite_faces_begin();
+        fit != cdt[o].finite_faces_end();
+        ++fit)
+      {
+        NF[o](i,0) = v2i[fit->vertex(0)];
+        NF[o](i,1) = v2i[fit->vertex(1)];
+        NF[o](i,2) = v2i[fit->vertex(2)];
+        i++;
+      }
+    }
+  }
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+  cout<<"CDT: "<<tictoc()<<"  "<<t_proj_del<<endl;
+#endif
+
+  assert(NV_count == (Index)NV.size());
+  // Build output
+#ifndef NDEBUG
+  //{
+  //  Index off_count = 0;
+  //  for(Index f = 0;f<F.rows();f++)
+  //  {
+  //    off_count+= (offensive[f]?1:0);
+  //  }
+  //  assert(off_count==(Index)offending.size());
+  //}
+#endif
+  // Append faces
+  FF.resize(F.rows()-offending.size()+NF_count,3);
+  J.resize(FF.rows());
+  // First append non-offending original faces
+  // There's an Eigen way to do this in one line but I forget
+  Index off = 0;
+  for(Index f = 0;f<F.rows();f++)
+  {
+    if(!offending.count(f))
+    {
+      FF.row(off) = F.row(f);
+      J(off) = f;
+      off++;
+    }
+  }
+  assert(off == (Index)(F.rows()-offending.size()));
+  // Now append replacement faces for offending faces
+  for(const auto & okv : offending)
+  {
+    // index in F
+    const Index f = okv.first;
+    const Index o = okv.second.first;
+    FF.block(off,0,NF[o].rows(),3) = NF[o];
+    J.block(off,0,NF[o].rows(),1).setConstant(f);
+    off += NF[o].rows();
+  }
+  // Append vertices
+  VV.resize(V.rows()+NV_count,3);
+  VV.block(0,0,V.rows(),3) = V.template cast<typename DerivedVV::Scalar>();
+  {
+    Index i = 0;
+    for(
+      typename Point_3List::const_iterator nvit = NV.begin();
+      nvit != NV.end();
+      nvit++)
+    {
+      for(Index d = 0;d<3;d++)
+      {
+        const Point_3 & p = *nvit;
+        // Don't convert via double if output type is same as Kernel
+        assign_scalar(p[d], VV(V.rows()+i,d));
+      }
+      i++;
+    }
+  }
+  IM.resize(VV.rows(),1);
+  map<Point_3,Index> vv2i;
+  // Safe to check for duplicates using double for original vertices: if
+  // incoming reps are different then the points are unique.
+  for(Index v = 0;v<V.rows();v++)
+  {
+    const Point_3 p(V(v,0),V(v,1),V(v,2));
+    if(vv2i.count(p)==0)
+    {
+      vv2i[p] = v;
+    }
+    assert(vv2i.count(p) == 1);
+    IM(v) = vv2i[p];
+  }
+  // Must check for duplicates of new vertices using exact.
+  {
+    Index v = V.rows();
+    for(
+      typename Point_3List::const_iterator nvit = NV.begin();
+      nvit != NV.end();
+      nvit++)
+    {
+      const Point_3 & p = *nvit;
+      if(vv2i.count(p)==0)
+      {
+        vv2i[p] = v;
+      }
+      assert(vv2i.count(p) == 1);
+      IM(v) = vv2i[p];
+      v++;
+    }
+  }
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+  cout<<"Output + dupes: "<<tictoc()<<endl;
+#endif
+}

+ 77 - 0
include/igl/cgal/remesh_intersections.h

@@ -0,0 +1,77 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CGAL_REMESH_INTERSECTIONS_H
+#define IGL_CGAL_REMESH_INTERSECTIONS_H
+#include <igl/igl_inline.h>
+
+#include <Eigen/Dense>
+#include "CGAL_includes.hpp"
+
+#ifdef MEX
+#  include <mex.h>
+#  include <cassert>
+#  undef assert
+#  define assert( isOK ) ( (isOK) ? (void)0 : (void) mexErrMsgTxt(C_STR(__FILE__<<":"<<__LINE__<<": failed assertion `"<<#isOK<<"'"<<std::endl) ) )
+#endif
+  
+namespace igl
+{
+  namespace cgal
+  {
+    // Remesh faces according to results of intersection detection and
+    // construction (e.g. from `igl::cgal::intersect_other` or
+    // `igl::cgal::SelfIntersectMesh`)
+    //
+    // Inputs:
+    //   V  #V by 3 list of vertex positions
+    //   F  #F by 3 list of triangle indices into V
+    //   T  #F list of cgal triangles
+    //   offending #offending map taking face indices into F to pairs of order
+    //     of first finding and list of intersection objects from all
+    //     intersections
+    //   edge2faces  #edges <= #offending*3 to incident offending faces 
+    // Outputs:
+    //   VV  #VV by 3 list of vertex positions
+    //   FF  #FF by 3 list of triangle indices into V
+    //   IF  #intersecting face pairs by 2  list of intersecting face pairs,
+    //     indexing F
+    //   J  #FF list of indices into F denoting birth triangle
+    //   IM  #VV list of indices into VV of unique vertices.
+    //
+    template <
+      typename DerivedV,
+      typename DerivedF,
+      typename Kernel,
+      typename DerivedVV,
+      typename DerivedFF,
+      typename DerivedJ,
+      typename DerivedIM>
+    IGL_INLINE void remesh_intersections(
+      const Eigen::PlainObjectBase<DerivedV> & V,
+      const Eigen::PlainObjectBase<DerivedF> & F,
+      const std::vector<CGAL::Triangle_3<Kernel> > & T,
+      const std::map<
+        typename DerivedF::Index,
+        std::pair<typename DerivedF::Index,
+          std::vector<CGAL::Object> > > & offending,
+      const std::map<
+        std::pair<typename DerivedF::Index,typename DerivedF::Index>,
+        std::vector<typename DerivedF::Index> > & edge2faces,
+      Eigen::PlainObjectBase<DerivedVV> & VV,
+      Eigen::PlainObjectBase<DerivedFF> & FF,
+      Eigen::PlainObjectBase<DerivedJ> & J,
+      Eigen::PlainObjectBase<DerivedIM> & IM);
+  }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "remesh_intersections.cpp"
+#endif
+  
+#endif
+

+ 1 - 1
include/igl/cgal/remesh_self_intersections.h

@@ -37,7 +37,7 @@ namespace igl
     //   params  struct of optional parameters
     // Outputs:
     //   VV  #VV by 3 list of vertex positions
-    //   FF  #FF by 3 list of triangle indices into V
+    //   FF  #FF by 3 list of triangle indices into VV
     //   IF  #intersecting face pairs by 2  list of intersecting face pairs,
     //     indexing F
     //   J  #FF list of indices into F denoting birth triangle

+ 1 - 0
include/igl/facet_components.h

@@ -27,6 +27,7 @@ namespace igl
   //   triangle_triangle_adjacency.h)
   // Ouputs:
   //   C  #F list of connected component ids
+  //   counts #C list of number of facets in each components
   template <
     typename TTIndex, 
     typename DerivedC,

+ 17 - 13
include/igl/lscm.h

@@ -1,6 +1,7 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 //
 // Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//               2015 Alec Jacobson
 //
 // 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
@@ -12,14 +13,17 @@
 #include <Eigen/Dense>
 #include <Eigen/Sparse>
 
-namespace igl
+namespace igl 
 {
-  // Compute a Least-squares conformal map parametrization following the
-  // algorithm presented in: Spectral Conformal Parameterization, Patrick
-  // Mullen, Yiying Tong, Pierre Alliez and Mathieu Desbrun. Input should be a
-  // manifold mesh (also no unreferenced vertices) and "boundary" `b` should
-  // contain at least two vertices per connected component.
-  //
+  // Compute a Least-squares conformal map parametrization (equivalently
+  // derived in "Intrinsic Parameterizations of Surface Meshes" [Desbrun et al.
+  // 2002] and "Least Squares Conformal Maps for Automatic Texture Atlas
+  // Generation" [Lévy et al. 2002]), though this implementation follows the
+  // derivation in: "Spectral Conformal Parameterization" [Mullen et al. 2008]
+  // (note, this does **not** implement the Eigen-decomposition based method in
+  // [Mullen et al. 2008], which is not equivalent). Input should be a manifold
+  // mesh (also no unreferenced vertices) and "boundary" (fixed vertices) `b`
+  // should contain at least two vertices per connected component.
   //
   // Inputs:
   //   V  #V by 3 list of mesh vertex positions
@@ -30,12 +34,12 @@ namespace igl
   //   UV #V by 2 list of 2D mesh vertex positions in UV space
   // Returns true only on solver success.
   //
-  IGL_INLINE bool lscm(
-    const Eigen::MatrixXd& V,
-    const Eigen::MatrixXi& F,
-    const Eigen::VectorXi& b,
-    const Eigen::MatrixXd& bc,
-    Eigen::MatrixXd& V_uv);
+  IGL_INLINE bool lscm( 
+      const Eigen::MatrixXd& V, 
+      const Eigen::MatrixXi& F,
+      const Eigen::VectorXi& b, 
+      const Eigen::MatrixXd& bc, 
+      Eigen::MatrixXd& V_uv);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 65 - 50
include/igl/mosek/mosek_quadprog.h

@@ -10,7 +10,7 @@
 #include "../igl_inline.h"
 #include <vector>
 #include <map>
-#include "mosek.h"
+#include <mosek.h>
 
 
 #define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
@@ -42,10 +42,10 @@ namespace igl
     //
     // Note: Q⁰ must be symmetric and the ½ is a convention of MOSEK
     //
-    // Note: Because of how MOSEK accepts different parts of the system, Q should
-    // be stored in IJV (aka Coordinate) format and should only include entries in
-    // the lower triangle. A should be stored in Column compressed (aka Harwell
-    // Boeing) format. As described:
+    // Note: Because of how MOSEK accepts different parts of the system, Q
+    // should be stored in IJV (aka Coordinate) format and should only include
+    // entries in the lower triangle. A should be stored in Column compressed
+    // (aka Harwell Boeing) format. As described:
     // http://netlib.org/linalg/html_templates/node92.html
     // or
     // http://en.wikipedia.org/wiki/Sparse_matrix
@@ -57,24 +57,27 @@ namespace igl
     //   Scalar  type for floating point variables (gets cast to double?)
     // Input:
     //   n  number of variables, i.e. size of x
-    //   Qi  vector of qnnz row indices of non-zeros in LOWER TRIANGLE ONLY of Q⁰
-    //   Qj  vector of qnnz column indices of non-zeros in LOWER TRIANGLE ONLY of 
-    //     Q⁰
+    //   Qi  vector of qnnz row indices of non-zeros in LOWER TRIANGLE ONLY of
+    //       Q⁰
+    //   Qj  vector of qnnz column indices of non-zeros in LOWER TRIANGLE ONLY
+    //       of Q⁰
     //   Qv  vector of qnnz values of non-zeros in LOWER TRIANGLE ONLY of Q⁰, 
-    //     such that:
-    //     Q⁰(Qi[k],Qj[k]) = Qv[k] for k ∈ [0,Qnnz-1], where Qnnz is the number of
-    //     non-zeros in Q⁰
-    //   c   (optional) vector of n values of c, transpose of coefficient row vector
-    //     of linear terms, EMPTY means c == 0
-    //   cf  (optional) value of constant term in objective, 0 means cf == 0, so
-    //     optional only in the sense that it is mandatory
+    //       such that:
+    //
+    //           Q⁰(Qi[k],Qj[k]) = Qv[k] for k ∈ [0,Qnnz-1], where Qnnz is the
+    // 
+    //       number of non-zeros in Q⁰
+    //   c   (optional) vector of n values of c, transpose of coefficient row
+    //       vector of linear terms, EMPTY means c == 0
+    //   cf  (ignored) value of constant term in objective, 0 means cf == 0, so
+    //       optional only in the sense that it is mandatory
     //   m  number of constraints, therefore also number of rows in linear
-    //     constraint coefficient matrix A, and in linear constraint bound vectors 
-    //     lc and uc
+    //      constraint coefficient matrix A, and in linear constraint bound
+    //      vectors lc and uc
     //   Av  vector of non-zero values of A, in column compressed order
     //   Ari  vector of row indices corresponding to non-zero values of A,
-    //   Acp  vector of indices into Ari and Av of the first entry for each column
-    //     of A, size(Acp) = (# columns of A) + 1 = n + 1
+    //   Acp  vector of indices into Ari and Av of the first entry for each
+    //        column of A, size(Acp) = (# columns of A) + 1 = n + 1
     //   lc  vector of m linear constraint lower bounds
     //   uc  vector of m linear constraint upper bounds
     //   lx  vector of n constant lower bounds
@@ -87,39 +90,51 @@ namespace igl
     // Note: All indices are 0-based
     //
     template <typename Index, typename Scalar>
-      IGL_INLINE bool mosek_quadprog(
-          const Index n,
-          /* mosek won't allow this to be const*/ std::vector<Index> & Qi,
-          /* mosek won't allow this to be const*/ std::vector<Index> & Qj,
-          /* mosek won't allow this to be const*/ std::vector<Scalar> & Qv,
-          const std::vector<Scalar> & c,
-          const Scalar cf,
-          const Index m,
-          /* mosek won't allow this to be const*/ std::vector<Scalar> & Av,
-          /* mosek won't allow this to be const*/ std::vector<Index> & Ari,
-          const std::vector<Index> & Acp,
-          const std::vector<Scalar> & lc,
-          const std::vector<Scalar> & uc,
-          const std::vector<Scalar> & lx,
-          const std::vector<Scalar> & ux,
-          MosekData & mosek_data,
-          std::vector<Scalar> & x);
-
+    IGL_INLINE bool mosek_quadprog(
+      const Index n,
+      /* mosek won't allow this to be const*/ std::vector<Index> & Qi,
+      /* mosek won't allow this to be const*/ std::vector<Index> & Qj,
+      /* mosek won't allow this to be const*/ std::vector<Scalar> & Qv,
+      const std::vector<Scalar> & c,
+      const Scalar cf,
+      const Index m,
+      /* mosek won't allow this to be const*/ std::vector<Scalar> & Av,
+      /* mosek won't allow this to be const*/ std::vector<Index> & Ari,
+      const std::vector<Index> & Acp,
+      const std::vector<Scalar> & lc,
+      const std::vector<Scalar> & uc,
+      const std::vector<Scalar> & lx,
+      const std::vector<Scalar> & ux,
+      MosekData & mosek_data,
+      std::vector<Scalar> & x);
     // Wrapper with Eigen elements
-    //// Templates:
-    ////   Scalar  Scalar type for sparse matrix  (e.g. double)
-    ////   Derived  dervied type from matrix/vector (e.g. VectorXd)
+    //
+    // Inputs:
+    //   Q  n by n square quadratic coefficients matrix **only lower triangle
+    //      is used**.
+    //   c  n-long vector of linear coefficients
+    //   cf  constant coefficient
+    //   A  m by n square linear coefficienst matrix of inequality constraints
+    //   lc  m-long vector of lower bounds for linear inequality constraints
+    //   uc  m-long vector of upper bounds for linear inequality constraints
+    //   lx  n-long vector of lower bounds
+    //   ux  n-long vector of upper bounds
+    //   mosek_data  parameters struct
+    // Outputs:
+    //   x  n-long solution vector
+    // Returns true only if optimization finishes without error
+    //
     IGL_INLINE bool mosek_quadprog(
-        const Eigen::SparseMatrix<double> & Q,
-        const Eigen::VectorXd & c,
-        const double cf,
-        const Eigen::SparseMatrix<double> & A,
-        const Eigen::VectorXd & lc,
-        const Eigen::VectorXd & uc,
-        const Eigen::VectorXd & lx,
-        const Eigen::VectorXd & ux,
-        MosekData & mosek_data,
-        Eigen::VectorXd & x);
+      const Eigen::SparseMatrix<double> & Q,
+      const Eigen::VectorXd & c,
+      const double cf,
+      const Eigen::SparseMatrix<double> & A,
+      const Eigen::VectorXd & lc,
+      const Eigen::VectorXd & uc,
+      const Eigen::VectorXd & lx,
+      const Eigen::VectorXd & ux,
+      MosekData & mosek_data,
+      Eigen::VectorXd & x);
   }
 }
 

+ 238 - 0
include/igl/outer_element.cpp

@@ -0,0 +1,238 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@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 "outer_element.h"
+#include <iostream>
+#include <vector>
+
+template <
+     typename DerivedV,
+     typename DerivedF,
+     typename DerivedI,
+     typename IndexType,
+     typename DerivedA
+     >
+IGL_INLINE void igl::outer_vertex(
+        const Eigen::PlainObjectBase<DerivedV> & V,
+        const Eigen::PlainObjectBase<DerivedF> & F,
+        const Eigen::PlainObjectBase<DerivedI> & I,
+        IndexType & v_index,
+        Eigen::PlainObjectBase<DerivedA> & A) {
+    // Algorithm: 
+    //    Find an outer vertex (i.e. vertex reachable from infinity)
+    //    Return the vertex with the largest X value.
+    //    If there is a tie, pick the one with largest Y value.
+    //    If there is still a tie, pick the one with the largest Z value.
+    //    If there is still a tie, then there are duplicated vertices within the
+    //    mesh, which violates the precondition.
+    const size_t INVALID = std::numeric_limits<size_t>::max();
+    const size_t num_selected_faces = I.rows();
+    std::vector<size_t> candidate_faces;
+    size_t outer_vid = INVALID;
+    typename DerivedV::Scalar outer_val = 0;
+    for (size_t i=0; i<num_selected_faces; i++) {
+        size_t f = I(i);
+        for (size_t j=0; j<3; j++) {
+            auto v = F(f, j);
+            auto vx = V(v, 0);
+            if (outer_vid == INVALID || vx > outer_val) {
+                outer_val = vx;
+                outer_vid = v;
+                candidate_faces = {f};
+            } else if (v == outer_vid) {
+                candidate_faces.push_back(f);
+            } else if (vx == outer_val) {
+                // Break tie.
+                auto vy = V(v,1);
+                auto vz = V(v, 2);
+                auto outer_y = V(outer_vid, 1);
+                auto outer_z = V(outer_vid, 2);
+                assert(!(vy == outer_y && vz == outer_z));
+                bool replace = (vy > outer_y) ||
+                    ((vy == outer_y) && (vz > outer_z));
+                if (replace) {
+                    outer_val = vx;
+                    outer_vid = v;
+                    candidate_faces = {f};
+                }
+            }
+        }
+    }
+
+    assert(outer_vid != INVALID);
+    assert(candidate_faces.size() > 0);
+    v_index = outer_vid;
+    A.resize(candidate_faces.size());
+    std::copy(candidate_faces.begin(), candidate_faces.end(), A.data());
+}
+
+template<
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedI,
+    typename IndexType,
+    typename DerivedA
+    >
+IGL_INLINE void igl::outer_edge(
+        const Eigen::PlainObjectBase<DerivedV> & V,
+        const Eigen::PlainObjectBase<DerivedF> & F,
+        const Eigen::PlainObjectBase<DerivedI> & I,
+        IndexType & v1,
+        IndexType & v2,
+        Eigen::PlainObjectBase<DerivedA> & A) {
+    // Algorithm:
+    //    Find an outer vertex first.
+    //    Find the incident edge with largest slope when projected onto XY plane.
+    //    If there is still a tie, break it using the projected slope onto ZX plane.
+    //    If there is still a tie, then there are multiple overlapping edges,
+    //    which violates the precondition.
+    typedef typename DerivedV::Scalar Scalar;
+    typedef typename DerivedV::Index Index;
+    typedef typename Eigen::Matrix<Scalar, 3, 1> ScalarArray3;
+    typedef typename Eigen::Matrix<typename DerivedF::Scalar, 3, 1> IndexArray3;
+    const size_t INVALID = std::numeric_limits<size_t>::max();
+
+    Index outer_vid;
+    Eigen::Matrix<Index,Eigen::Dynamic,1> candidate_faces;
+    outer_vertex(V, F, I, outer_vid, candidate_faces);
+    const ScalarArray3& outer_v = V.row(outer_vid);
+    assert(candidate_faces.size() > 0);
+
+    auto get_vertex_index = [&](const IndexArray3& f, Index vid) -> Index 
+    {
+        if (f[0] == vid) return 0;
+        if (f[1] == vid) return 1;
+        if (f[2] == vid) return 2;
+        assert(false);
+        return -1;
+    };
+
+    Scalar outer_slope_YX = 0;
+    Scalar outer_slope_ZX = 0;
+    size_t outer_opp_vid = INVALID;
+    bool infinite_slope_detected = false;
+    std::vector<Index> incident_faces;
+    auto check_and_update_outer_edge = [&](Index opp_vid, Index fid) {
+        if (opp_vid == outer_opp_vid) {
+            incident_faces.push_back(fid);
+            return;
+        }
+
+        const ScalarArray3 opp_v = V.row(opp_vid);
+        if (!infinite_slope_detected && outer_v[0] != opp_v[0]) {
+            // Finite slope
+            const ScalarArray3 diff = opp_v - outer_v;
+            const Scalar slope_YX = diff[1] / diff[0];
+            const Scalar slope_ZX = diff[2] / diff[0];
+            if (outer_opp_vid == INVALID ||
+                    slope_YX > outer_slope_YX ||
+                    (slope_YX == outer_slope_YX &&
+                     slope_ZX > outer_slope_ZX)) {
+                outer_opp_vid = opp_vid;
+                outer_slope_YX = slope_YX;
+                outer_slope_ZX = slope_ZX;
+                incident_faces = {fid};
+            }
+        } else if (!infinite_slope_detected) {
+            // Infinite slope
+            outer_opp_vid = opp_vid;
+            infinite_slope_detected = true;
+            incident_faces = {fid};
+        }
+    };
+
+    const auto num_candidate_faces = candidate_faces.size();
+    for (size_t i=0; i<num_candidate_faces; i++) {
+        const Index fid = candidate_faces(i);
+        const IndexArray3& f = F.row(fid);
+        size_t id = get_vertex_index(f, outer_vid);
+        Index next_vid = f((id+1)%3);
+        Index prev_vid = f((id+2)%3);
+        check_and_update_outer_edge(next_vid, fid);
+        check_and_update_outer_edge(prev_vid, fid);
+    }
+
+    v1 = outer_vid;
+    v2 = outer_opp_vid;
+    A.resize(incident_faces.size());
+    std::copy(incident_faces.begin(), incident_faces.end(), A.data());
+}
+
+template<
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedN,
+    typename DerivedI,
+    typename IndexType
+    >
+IGL_INLINE void igl::outer_facet(
+        const Eigen::PlainObjectBase<DerivedV> & V,
+        const Eigen::PlainObjectBase<DerivedF> & F,
+        const Eigen::PlainObjectBase<DerivedN> & N,
+        const Eigen::PlainObjectBase<DerivedI> & I,
+        IndexType & f,
+        bool & flipped) {
+    // Algorithm:
+    //    Find an outer edge.
+    //    Find the incident facet with the largest absolute X normal component.
+    //    If there is a tie, keep the one with positive X component.
+    //    If there is still a tie, pick the face with the larger signed index
+    //    (flipped face has negative index).
+    typedef typename DerivedV::Scalar Scalar;
+    typedef typename DerivedV::Index Index;
+    const size_t INVALID = std::numeric_limits<size_t>::max();
+
+    Index v1,v2;
+    Eigen::Matrix<Index,Eigen::Dynamic,1> incident_faces;
+    outer_edge(V, F, I, v1, v2, incident_faces);
+    assert(incident_faces.size() > 0);
+
+    auto generic_fabs = [&](const Scalar& val) -> const Scalar {
+        if (val >= 0) return val;
+        else return -val;
+    };
+
+    Scalar max_nx = 0;
+    size_t outer_fid = INVALID;
+    const size_t num_incident_faces = incident_faces.size();
+    for (size_t i=0; i<num_incident_faces; i++) 
+    {
+        const auto& fid = incident_faces(i);
+        const Scalar nx = N(fid, 0);
+        if (outer_fid == INVALID) {
+            max_nx = nx;
+            outer_fid = fid;
+        } else {
+            if (generic_fabs(nx) > generic_fabs(max_nx)) {
+                max_nx = nx;
+                outer_fid = fid;
+            } else if (nx == -max_nx && nx > 0) {
+                max_nx = nx;
+                outer_fid = fid;
+            } else if (nx == max_nx) {
+                if ((max_nx >= 0 && outer_fid < fid) ||
+                    (max_nx <  0 && outer_fid > fid)) {
+                    max_nx = nx;
+                    outer_fid = fid;
+                }
+            }
+        }
+    }
+
+    assert(outer_fid != INVALID);
+    f = outer_fid;
+    flipped = max_nx < 0;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template void igl::outer_facet<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<long, -1, 1, 0, -1, 1>, int>(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<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::outer_facet<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, unsigned long&, bool&);
+template void igl::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
+#endif

+ 110 - 0
include/igl/outer_element.h

@@ -0,0 +1,110 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 Qingan Zhou <qnzhou@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_OUTER_ELEMENT_H
+#define IGL_OUTER_ELEMENT_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  // Find a vertex that is reachable from infinite without crossing any faces.
+  // Such vertex is called "outer vertex."
+  //
+  // Precondition: The input mesh must have all self-intersection resolved and
+  // no duplicated vertices.  See cgal::remesh_self_intersections.h for how to
+  // obtain such input.
+  //
+  // Inputs:
+  //   V  #V by 3 list of vertex positions
+  //   F  #F by 3 list of triangle indices into V
+  //   I  #I list of facets to consider
+  // Outputs:
+  //   v_index  index of outer vertex
+  //   A  #A list of facets incident to the outer vertex
+  template <
+      typename DerivedV,
+      typename DerivedF,
+      typename DerivedI,
+      typename IndexType,
+      typename DerivedA
+      >
+  IGL_INLINE void outer_vertex(
+          const Eigen::PlainObjectBase<DerivedV> & V,
+          const Eigen::PlainObjectBase<DerivedF> & F,
+          const Eigen::PlainObjectBase<DerivedI> & I,
+          IndexType & v_index,
+          Eigen::PlainObjectBase<DerivedA> & A);
+
+
+  // Find an edge that is reachable from infinity without crossing any faces.
+  // Such edge is called "outer edge."
+  //
+  // Precondition: The input mesh must have all self-intersection resolved and
+  // no duplicated vertices.  The correctness of the output depends on the fact
+  // that there is no edge overlap.  See cgal::remesh_self_intersections.h for
+  // how to obtain such input.
+  //
+  // Inputs:
+  //   V  #V by 3 list of vertex positions
+  //   F  #F by 3 list of triangle indices into V
+  //   I  #I list of facets to consider
+  // Outputs:
+  //   v1 index of the first end point of outer edge
+  //   v2 index of the second end point of outer edge
+  //   A  #A list of facets incident to the outer edge
+  template<
+      typename DerivedV,
+      typename DerivedF,
+      typename DerivedI,
+      typename IndexType,
+      typename DerivedA
+      >
+  IGL_INLINE void outer_edge(
+          const Eigen::PlainObjectBase<DerivedV> & V,
+          const Eigen::PlainObjectBase<DerivedF> & F,
+          const Eigen::PlainObjectBase<DerivedI> & I,
+          IndexType & v1,
+          IndexType & v2,
+          Eigen::PlainObjectBase<DerivedA> & A);
+
+
+  // Find a facet that is reachable from infinity without crossing any faces.
+  // Such facet is called "outer facet."
+  //
+  // Precondition: The input mesh must have all self-intersection resolved.  I.e
+  // there is no duplicated vertices, no overlapping edge and no intersecting
+  // faces (the only exception is there could be topologically duplicated faces).
+  // See cgal::remesh_self_intersections.h for how to obtain such input.
+  //
+  // Inputs:
+  //   V  #V by 3 list of vertex positions
+  //   F  #F by 3 list of triangle indices into V
+  //   N  #N by 3 list of face normals
+  //   I  #I list of facets to consider
+  // Outputs:
+  //   f  Index of the outer facet.
+  //   flipped  true iff the normal of f points inwards.
+  template<
+      typename DerivedV,
+      typename DerivedF,
+      typename DerivedN,
+      typename DerivedI,
+      typename IndexType
+      >
+  IGL_INLINE void outer_facet(
+          const Eigen::PlainObjectBase<DerivedV> & V,
+          const Eigen::PlainObjectBase<DerivedF> & F,
+          const Eigen::PlainObjectBase<DerivedN> & N,
+          const Eigen::PlainObjectBase<DerivedI> & I,
+          IndexType & f,
+          bool & flipped);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "outer_element.cpp"
+#endif
+#endif

+ 0 - 122
include/igl/outer_facet.cpp

@@ -1,122 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2015 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 
-// obtain one at http://mozilla.org/MPL/2.0/.
-#include "outer_facet.h"
-#include "sort.h"
-#include "vertex_triangle_adjacency.h"
-#include <iostream>
-#define IGL_OUTER_FACET_DEBUG
-
-template <
-  typename DerivedV,
-  typename DerivedF,
-  typename DerivedN,
-  typename DerivedI,
-  typename f_type>
-IGL_INLINE void igl::outer_facet(
-  const Eigen::PlainObjectBase<DerivedV> & V,
-  const Eigen::PlainObjectBase<DerivedF> & F,
-  const Eigen::PlainObjectBase<DerivedN> & N,
-  const Eigen::PlainObjectBase<DerivedI> & I,
-  f_type & max_f,
-  bool & flip)
-{
-  using namespace std;
-  typedef typename DerivedV::Scalar Scalar;
-  typedef typename DerivedV::Index Index;
-  typedef 
-    typename Eigen::Matrix<Index, DerivedV::RowsAtCompileTime,1> VectorXI;
-  typedef 
-    typename Eigen::Matrix<Scalar, DerivedV::RowsAtCompileTime,1> VectorXS;
-  // "Direct repair of self-intersecting meshes" [Attene 14]
-  const Index mi = I.size();
-  assert(V.cols() == 3);
-  assert(N.cols() == 3);
-  Index max_v = -1;
-  auto generic_fabs = [&](Scalar val) { 
-      if (val >= 0) return val;
-      else return -val;
-  };
-  for(size_t d = 0;d<(size_t)V.cols();d++)
-  {
-    Scalar max_d = -1e26;
-    Scalar max_nd = -1e26;
-    for(Index i = 0;i<mi;i++)
-    {
-      const Index f = I(i);
-      const Scalar nd = N(f,d);
-      if(generic_fabs(nd)>0)
-      {
-        for(Index c = 0;c<3;c++)
-        {
-          const Index v = F(f,c);
-          if(v == max_v)
-          {
-            if(generic_fabs(nd) > max_nd)
-            {
-              // Just update max face and normal
-              max_f = f;
-              max_nd = generic_fabs(nd);
-              flip = nd<0;
-            } else if (generic_fabs(nd) == max_nd) {
-                if (nd == max_nd) {
-                    if (flip) {
-                        max_f = f;
-                        max_nd = nd;
-                        flip = false;
-                    } else if (f > (Index)max_f){
-                        max_f = f;
-                        max_nd = nd;
-                        flip = false;
-                    }
-                } else {
-                    if (flip && f < (Index)max_f) {
-                        max_f = f;
-                        max_nd = generic_fabs(nd);
-                        flip = true;
-                    }
-                }
-            }
-          }else
-          {
-            const Scalar vd = V(v,d);
-            if(vd>max_d)
-            {
-              // update max vertex, face and normal
-              max_v = v;
-              max_d = vd;
-              max_f = f;
-              max_nd = generic_fabs(nd);
-              flip = nd<0;
-            }
-          }
-        }
-      }
-    }
-    if(max_v >= 0)
-    {
-      break;
-    }
-    // if we get here and max_v is still -1 then there were no faces with
-    // |N(d)| > 0
-  }
-#ifdef IGL_OUTER_FACET_DEBUG
-  if(max_v <0)
-  {
-    cerr<<"Very degenerate case, no suitable face found."<<endl;
-  }
-#endif
-  assert(max_v >=0 && "Very degenerate case, no suitable face found.");
-}
-
-#ifdef IGL_STATIC_LIBRARY
-// Explicit template specialization
-template void igl::outer_facet<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<long, -1, 1, 0, -1, 1>, int>(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<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
-template void igl::outer_facet<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, unsigned long&, bool&);
-template void igl::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
-template void igl::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
-#endif

+ 0 - 46
include/igl/outer_facet.h

@@ -1,46 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2015 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 
-// obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef IGL_OUTER_FACET_H
-#define IGL_OUTER_FACET_H
-#include "igl_inline.h"
-#include <Eigen/Core>
-namespace igl
-{
-  // Compute a single facet which is guaranteed to be part of the "outer hull of
-  // a mesh (V,F). This implementation follows Section 3.6 of "Direct repair of
-  // self-intersecting meshes" [Attene 2014].
-  //
-  // 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 face normals
-  //   I  #I list of facets to actually consider
-  // Outputs:
-  //   f  index of facet into V
-  //   flip  whether facet's orientation should be flipped so that
-  //     counter-clockwise normal points outward.
-  //
-  // See also: cgal/outer_hull.h
-  template <
-    typename DerivedV,
-    typename DerivedF,
-    typename DerivedN,
-    typename DerivedI,
-    typename f_type>
-  IGL_INLINE void outer_facet(
-    const Eigen::PlainObjectBase<DerivedV> & V,
-    const Eigen::PlainObjectBase<DerivedF> & F,
-    const Eigen::PlainObjectBase<DerivedN> & N,
-    const Eigen::PlainObjectBase<DerivedI> & I,
-    f_type & f,
-    bool & flip);
-}
-#ifndef IGL_STATIC_LIBRARY
-#  include "outer_facet.cpp"
-#endif
-#endif

+ 1 - 1
include/igl/png/render_to_png.cpp

@@ -52,4 +52,4 @@ IGL_INLINE bool igl::png::render_to_png(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template specialization
-#endif;
+#endif

+ 2 - 1
include/igl/readDMAT.cpp

@@ -45,7 +45,8 @@ static inline int readDMAT_read_header(FILE * fp, int & num_rows, int & num_cols
   }
   // finish reading header
   char lf;
-  if(fread(&lf, sizeof(char), 1, fp)!=1 || lf != '\n')
+
+  if(fread(&lf, sizeof(char), 1, fp)!=1 || !(lf == '\n' || lf == '\r'))
   {
     fprintf(stderr,"IOError: bad line ending in header\n");
     return 4;

+ 1 - 1
tutorial/CMakeLists.txt

@@ -12,7 +12,7 @@ endif(LIBIGL_USE_STATIC_LIBRARY)
 SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
 
 IF(MSVC)
-  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") ### Enable parallel compilation for Visual Studio
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /bigobj") ### Enable parallel compilation for Visual Studio
   SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} )
   SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} )
 ELSE(MSVC)