Browse Source

implementation of integrable polyvector fields (+some templates)

Former-commit-id: 2dc539a4b2aec4a079146f4e836c88c2ce098e30
Olga Diamanti 10 years ago
parent
commit
5f795771d7

+ 14 - 14
include/igl/HalfEdgeIterator.h

@@ -24,14 +24,14 @@ namespace igl
   public:
     // Init the HalfEdgeIterator by specifying Face,Edge Index and Orientation
     IGL_INLINE HalfEdgeIterator(
-        const Eigen::PlainObjectBase<DerivedF>* F,
-        const Eigen::PlainObjectBase<DerivedF>* FF,
-        const Eigen::PlainObjectBase<DerivedF>* FFi,
-        int fi,
-        int ei,
-        bool reverse = false
+        const Eigen::PlainObjectBase<DerivedF>& _F,
+        const Eigen::PlainObjectBase<DerivedF>& _FF,
+        const Eigen::PlainObjectBase<DerivedF>& _FFi,
+        int _fi,
+        int _ei,
+        bool _reverse = false
         )
-    : F(F), FF(FF), FFi(FFi), fi(fi), ei(ei), reverse(reverse)
+    : fi(_fi), ei(_ei), reverse(_reverse), F(_F), FF(_FF), FFi(_FFi)
     {}
 
     // Change Face
@@ -40,8 +40,8 @@ namespace igl
       if (isBorder())
         return;
 
-      int fin = (*FF)(fi,ei);
-      int ein = (*FFi)(fi,ei);
+      int fin = (FF)(fi,ei);
+      int ein = (FFi)(fi,ei);
       int reversen = !reverse;
 
       fi = fin;
@@ -68,7 +68,7 @@ namespace igl
 
     IGL_INLINE bool isBorder()
     {
-      return (*FF)(fi,ei) == -1;
+      return (FF)(fi,ei) == -1;
     }
 
     /*!
@@ -106,7 +106,7 @@ namespace igl
     IGL_INLINE int Vi()
     {
       assert(fi >= 0);
-      assert(fi < F->rows());
+      assert(fi < F.rows());
       assert(ei >= 0);
       assert(ei <= 2);
 
@@ -147,9 +147,9 @@ namespace igl
     int ei;
     bool reverse;
 
-    const Eigen::PlainObjectBase<DerivedF>* F;
-    const Eigen::PlainObjectBase<DerivedF>* FF;
-    const Eigen::PlainObjectBase<DerivedF>* FFi;
+    const Eigen::PlainObjectBase<DerivedF>& F;
+    const Eigen::PlainObjectBase<DerivedF>& FF;
+    const Eigen::PlainObjectBase<DerivedF>& FFi;
   };
 
 }

+ 322 - 0
include/igl/cut_mesh.cpp

@@ -0,0 +1,322 @@
+#include <igl/cut_mesh.h>
+#include <igl/vertex_triangle_adjacency.h>
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/is_border_vertex.h>
+#include <igl/HalfEdgeIterator.h>
+#include <set>
+
+
+namespace igl {
+
+
+  template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+  class MeshCutterMini
+  {
+  public:
+    // Input
+    //mesh
+    const Eigen::PlainObjectBase<DerivedV> &V;
+    const Eigen::PlainObjectBase<DerivedF> &F;
+    const Eigen::PlainObjectBase<DerivedTT> &TT;
+    const Eigen::PlainObjectBase<DerivedTT> &TTi;
+    const std::vector<std::vector<VFType> >& VF;
+    const std::vector<std::vector<VFType> >& VFi;
+    const std::vector<bool> &V_border; // bool
+    //edges to cut
+    const Eigen::PlainObjectBase<DerivedC> &Handle_Seams; // 3 bool
+
+    // total number of scalar variables
+    int num_scalar_variables;
+
+    // per face indexes of vertex in the solver
+    Eigen::PlainObjectBase<DerivedF> HandleS_Index;
+
+    // per vertex variable indexes
+    std::vector<std::vector<int> > HandleV_Integer;
+
+    IGL_INLINE MeshCutterMini(const Eigen::PlainObjectBase<DerivedV> &_V,
+                              const Eigen::PlainObjectBase<DerivedF> &_F,
+                              const Eigen::PlainObjectBase<DerivedTT> &_TT,
+                              const Eigen::PlainObjectBase<DerivedTT> &_TTi,
+                              const std::vector<std::vector<VFType> > &_VF,
+                              const std::vector<std::vector<VFType> > &_VFi,
+                              const std::vector<bool> &_V_border,
+                              const Eigen::PlainObjectBase<DerivedC> &_Handle_Seams);
+
+    // vertex to variable mapping
+    // initialize the mapping for a given sampled mesh
+    IGL_INLINE void InitMappingSeam();
+
+  private:
+
+    IGL_INLINE void FirstPos(const int v, int &f, int &edge);
+
+    IGL_INLINE int AddNewIndex(const int v0);
+
+    IGL_INLINE bool IsSeam(const int f0, const int f1);
+
+    // find initial position of the pos to
+    // assing face to vert inxex correctly
+    IGL_INLINE void FindInitialPos(const int vert, int &edge, int &face);
+
+
+    // intialize the mapping given an initial pos
+    // whih must be initialized with FindInitialPos
+    IGL_INLINE void MapIndexes(const int  vert, const int edge_init, const int f_init);
+
+    // intialize the mapping for a given vertex
+    IGL_INLINE void InitMappingSeam(const int vert);
+
+  };
+}
+
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+MeshCutterMini(const Eigen::PlainObjectBase<DerivedV> &_V,
+               const Eigen::PlainObjectBase<DerivedF> &_F,
+               const Eigen::PlainObjectBase<DerivedTT> &_TT,
+               const Eigen::PlainObjectBase<DerivedTT> &_TTi,
+               const std::vector<std::vector<VFType> > &_VF,
+               const std::vector<std::vector<VFType> > &_VFi,
+               const std::vector<bool> &_V_border,
+               const Eigen::PlainObjectBase<DerivedC> &_Handle_Seams):
+V(_V),
+F(_F),
+TT(_TT),
+TTi(_TTi),
+VF(_VF),
+VFi(_VFi),
+V_border(_V_border),
+Handle_Seams(_Handle_Seams)
+{
+  num_scalar_variables=0;
+
+  HandleS_Index.setConstant(F.rows(),3,-1);
+
+  HandleV_Integer.resize(V.rows());
+}
+
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+FirstPos(const int v, int &f, int &edge)
+{
+  f    = VF[v][0];  // f=v->cVFp();
+  edge = VFi[v][0]; // edge=v->cVFi();
+}
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE int igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+AddNewIndex(const int v0)
+{
+  num_scalar_variables++;
+  HandleV_Integer[v0].push_back(num_scalar_variables);
+  return num_scalar_variables;
+}
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE bool igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+IsSeam(const int f0, const int f1)
+{
+  for (int i=0;i<3;i++)
+  {
+    int f_clos = TT(f0,i);
+
+    if (f_clos == -1)
+      continue; ///border
+
+    if (f_clos == f1)
+      return(Handle_Seams(f0,i));
+  }
+  assert(0);
+  return false;
+}
+
+///find initial position of the pos to
+// assing face to vert inxex correctly
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+FindInitialPos(const int vert,
+               int &edge,
+               int &face)
+{
+  int f_init;
+  int edge_init;
+  FirstPos(vert,f_init,edge_init); // todo manually the function
+  igl::HalfEdgeIterator<DerivedF> VFI(F,TT,TTi,f_init,edge_init);
+
+  bool vertexB = V_border[vert];
+  bool possible_split=false;
+  bool complete_turn=false;
+  do
+  {
+    int curr_f = VFI.Fi();
+    int curr_edge=VFI.Ei();
+    VFI.NextFE();
+    int next_f=VFI.Fi();
+    ///test if I've just crossed a border
+    bool on_border=(TT(curr_f,curr_edge)==-1);
+    //bool mismatch=false;
+    bool seam=false;
+
+    ///or if I've just crossed a seam
+    ///if I'm on a border I MUST start from the one next t othe border
+    if (!vertexB)
+      //seam=curr_f->IsSeam(next_f);
+      seam=IsSeam(curr_f,next_f);
+    //    if (vertexB)
+    //      assert(!Handle_Singular(vert));
+    //    ;
+    //assert(!vert->IsSingular());
+    possible_split=((on_border)||(seam));
+    complete_turn = next_f == f_init;
+  } while ((!possible_split)&&(!complete_turn));
+  face=VFI.Fi();
+  edge=VFI.Ei();
+}
+
+
+
+///intialize the mapping given an initial pos
+///whih must be initialized with FindInitialPos
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+MapIndexes(const int  vert,
+           const int edge_init,
+           const int f_init)
+{
+  ///check that is not on border..
+  ///in such case maybe it's non manyfold
+  ///insert an initial index
+  int curr_index=AddNewIndex(vert);
+  ///and initialize the jumping pos
+  igl::HalfEdgeIterator<DerivedF> VFI(F,TT,TTi,f_init,edge_init);
+  bool complete_turn=false;
+  do
+  {
+    int curr_f = VFI.Fi();
+    int curr_edge = VFI.Ei();
+    ///assing the current index
+    HandleS_Index(curr_f,curr_edge) = curr_index;
+    VFI.NextFE();
+    int next_f = VFI.Fi();
+    ///test if I've finiseh with the face exploration
+    complete_turn = (next_f==f_init);
+    ///or if I've just crossed a mismatch
+    if (!complete_turn)
+    {
+      bool seam=false;
+      //seam=curr_f->IsSeam(next_f);
+      seam=IsSeam(curr_f,next_f);
+      if (seam)
+      {
+        ///then add a new index
+        curr_index=AddNewIndex(vert);
+      }
+    }
+  } while (!complete_turn);
+}
+
+///initialize the mapping for a given vertex
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+InitMappingSeam(const int vert)
+{
+  ///first rotate until find the first pos after a mismatch
+  ///or a border or return to the first position...
+  int f_init = VF[vert][0];
+  int indexE = VFi[vert][0];
+
+  igl::HalfEdgeIterator<DerivedF> VFI(F,TT,TTi,f_init,indexE);
+
+  int edge_init;
+  int face_init;
+  FindInitialPos(vert,edge_init,face_init);
+  MapIndexes(vert,edge_init,face_init);
+}
+
+///vertex to variable mapping
+///initialize the mapping for a given sampled mesh
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+InitMappingSeam()
+{
+  num_scalar_variables=-1;
+  for (unsigned int i=0;i<V.rows();i++)
+    InitMappingSeam(i);
+
+  for (unsigned int j=0;j<V.rows();j++)
+    assert(HandleV_Integer[j].size()>0);
+}
+
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::cut_mesh(
+                                                                  const Eigen::PlainObjectBase<DerivedV> &V,
+                                                                  const Eigen::PlainObjectBase<DerivedF> &F,
+                                                                  const std::vector<std::vector<VFType> >& VF,
+                                                                  const std::vector<std::vector<VFType> >& VFi,
+                                                                  const Eigen::PlainObjectBase<DerivedTT>& TT,
+                                                                  const Eigen::PlainObjectBase<DerivedTT>& TTi,
+                                                                  const std::vector<bool> &V_border,
+                                                                  const Eigen::PlainObjectBase<DerivedC> &cuts,
+                                                                  Eigen::PlainObjectBase<DerivedV> &Vcut,
+                                                                  Eigen::PlainObjectBase<DerivedF> &Fcut)
+{
+  //finding the cuts is done, now we need to actually generate a cut mesh
+  igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC> mc(V, F, TT, TTi, VF, VFi, V_border, cuts);
+  mc.InitMappingSeam();
+
+  Fcut = mc.HandleS_Index;
+  //we have the faces, we need the vertices;
+  int newNumV = Fcut.maxCoeff()+1;
+  Vcut.setZero(newNumV,3);
+  for (int vi=0; vi<V.rows(); ++vi)
+    for (int i=0; i<mc.HandleV_Integer[vi].size();++i)
+      Vcut.row(mc.HandleV_Integer[vi][i]) = V.row(vi);
+
+  //ugly hack to fix some problematic cases (border vertex that is also on the boundary of the hole
+  for (int fi =0; fi<Fcut.rows(); ++fi)
+    for (int k=0; k<3; ++k)
+      if (Fcut(fi,k)==-1)
+      {
+        //we need to add a vertex
+        Fcut(fi,k) = newNumV;
+        newNumV ++;
+        Vcut.conservativeResize(newNumV, Eigen::NoChange);
+        Vcut.row(newNumV-1) = V.row(F(fi,k));
+      }
+
+
+}
+
+
+//Wrapper of the above with only vertices and faces as mesh input
+template <typename DerivedV, typename DerivedF, typename DerivedC>
+IGL_INLINE void igl::cut_mesh(
+                                                                  const Eigen::PlainObjectBase<DerivedV> &V,
+                                                                  const Eigen::PlainObjectBase<DerivedF> &F,
+                                                                  const Eigen::PlainObjectBase<DerivedC> &cuts,
+                                                                  Eigen::PlainObjectBase<DerivedV> &Vcut,
+                                                                  Eigen::PlainObjectBase<DerivedF> &Fcut)
+{
+
+  std::vector<std::vector<int> > VF, VFi;
+  igl::vertex_triangle_adjacency(V,F,VF,VFi);
+
+  Eigen::MatrixXi TT, TTi;
+  igl::triangle_triangle_adjacency(V,F,TT,TTi);
+
+  std::vector<bool> V_border = igl::is_border_vertex(V,F);
+
+  igl::cut_mesh(V, F, VF, VFi, TT, TTi, V_border, cuts, Vcut, Fcut);
+
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > > const&, std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::__1::vector<bool, std::__1::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(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<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif

+ 72 - 0
include/igl/cut_mesh.h

@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_CUT_MESH
+#define IGL_CUT_MESH
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl {
+  // Given a mesh and a list of edges that are to be cut, the function generates a
+  // new disk-topology mesh that has the cuts at its boundary.
+  // Inputs:
+  //   V                #V by 3 list of the vertex positions
+  //   F                #F by 3 list of the faces (must be triangles)
+  //   VF               #V list of lists of incident faces (adjacency list), e.g.
+  //                    as returned by igl::vertex_triangle_adjacency
+  //   VFi               #V list of lists of index of incidence within incident faces listed
+  //                    in VF, e.g. as returned by igl::vertex_triangle_adjacency
+  //   TT               #F by 3 triangle to triangle adjacent matrix (e.g. computed
+  //                    via igl:triangle_triangle_adjacency)
+  //   TTi              #F by 3 adjacent matrix, the element i,j is the id of edge of the
+  //                    triangle TT(i,j) that is adjacent with triangle i (e.g. computed
+  //                    via igl:triangle_triangle_adjacency)
+  //   V_border         #V by 1 list of booleans, indicating if the corresponging vertex is
+  //                    at the mesh boundary, e.g. as returned by igl::is_border_vertex
+  //   cuts             #F by 3 list of boolean flags, indicating the edges that need to be cut
+  // Outputs:
+  //                    (has 1 at the face edges that are to be cut, 0 otherwise)
+  //   Vcut             #V by 3 list of the vertex positions of the cut mesh. This matrix will be
+  //                    similar to the original vertices except some rows will be duplicated.
+  //   Fcut             #F by 3 list of the faces of the cut mesh(must be triangles). This matrix
+  //                    will be similar to the original face matrix except some indices will be
+  //                    redirected to point to the newly duplicated vertices.
+  //
+  template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+  IGL_INLINE void cut_mesh(const Eigen::PlainObjectBase<DerivedV> &V,
+                           const Eigen::PlainObjectBase<DerivedF> &F,
+                           const std::vector<std::vector<VFType> >& VF,
+                           const std::vector<std::vector<VFType> >& VFi,
+                           const Eigen::PlainObjectBase<DerivedTT>& TT,
+                           const Eigen::PlainObjectBase<DerivedTT>& TTi,
+                           const std::vector<bool> &V_border,
+                           const Eigen::PlainObjectBase<DerivedC> &cuts,
+                           Eigen::PlainObjectBase<DerivedV> &Vcut,
+                           Eigen::PlainObjectBase<DerivedF> &Fcut);
+  
+  
+  //Wrapper of the above with only vertices and faces as mesh input
+  template <typename DerivedV, typename DerivedF, typename DerivedC>
+  IGL_INLINE void cut_mesh(
+                           const Eigen::PlainObjectBase<DerivedV> &V,
+                           const Eigen::PlainObjectBase<DerivedF> &F,
+                           const Eigen::PlainObjectBase<DerivedC> &cuts,
+                           Eigen::PlainObjectBase<DerivedV> &Vcut,
+                           Eigen::PlainObjectBase<DerivedF> &Fcut);
+  
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "cut_mesh.cpp"
+#endif
+
+
+#endif /* defined(IGL_CUT_MESH) */

+ 1 - 0
include/igl/cut_mesh_from_singularities.cpp

@@ -198,4 +198,5 @@ IGL_INLINE void igl::cut_mesh_from_singularities(const Eigen::PlainObjectBase<De
 template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -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, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::cut_mesh_from_singularities<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<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::cut_mesh_from_singularities<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<int, -1, 3, 0, -1, 3> >(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> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::cut_mesh_from_singularities<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> >(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> >&);
 #endif

+ 64 - 0
include/igl/dijkstra.cpp

@@ -0,0 +1,64 @@
+#include <igl/dijkstra.h>
+
+template <typename IndexType, typename DerivedD, typename DerivedP>
+IGL_INLINE int igl::dijkstra_compute_paths(const IndexType &source,
+                                           const std::set<IndexType> &targets,
+                                           const std::vector<std::vector<IndexType> >& VV,
+                                           Eigen::PlainObjectBase<DerivedD> &min_distance,
+                                           Eigen::PlainObjectBase<DerivedP> &previous)
+{
+  int numV = VV.size();
+  min_distance.setConstant(numV, 1, std::numeric_limits<typename DerivedD::Scalar>::infinity());
+  min_distance[source] = 0;
+  previous.setConstant(numV, 1, -1);
+  std::set<std::pair<typename DerivedD::Scalar, IndexType> > vertex_queue;
+  vertex_queue.insert(std::make_pair(min_distance[source], source));
+
+  while (!vertex_queue.empty())
+  {
+    typename DerivedD::Scalar dist = vertex_queue.begin()->first;
+    IndexType u = vertex_queue.begin()->second;
+    vertex_queue.erase(vertex_queue.begin());
+
+    if (targets.find(u)!= targets.end())
+      return u;
+
+    // Visit each edge exiting u
+    const std::vector<int> &neighbors = VV[u];
+    for (std::vector<int>::const_iterator neighbor_iter = neighbors.begin();
+         neighbor_iter != neighbors.end();
+         neighbor_iter++)
+    {
+      IndexType v = *neighbor_iter;
+      typename DerivedD::Scalar distance_through_u = dist + 1.;
+      if (distance_through_u < min_distance[v]) {
+        vertex_queue.erase(std::make_pair(min_distance[v], v));
+
+        min_distance[v] = distance_through_u;
+        previous[v] = u;
+        vertex_queue.insert(std::make_pair(min_distance[v], v));
+
+      }
+
+    }
+  }
+  //we should never get here
+  return -1;
+}
+
+template <typename IndexType, typename DerivedP>
+IGL_INLINE void igl::dijkstra_get_shortest_path_to(const IndexType &vertex,
+                                                   const Eigen::PlainObjectBase<DerivedP> &previous,
+                                                   std::vector<IndexType> &path)
+{
+  IndexType source = vertex;
+  path.clear();
+  for ( ; source != -1; source = previous[source])
+    path.push_back(source);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template int igl::dijkstra_compute_paths<int, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, std::__1::set<int, std::__1::less<int>, std::__1::allocator<int> > const&, std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::dijkstra_get_shortest_path_to<int, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::__1::vector<int, std::__1::allocator<int> >&);
+#endif

+ 60 - 0
include/igl/dijkstra.h

@@ -0,0 +1,60 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_DIJKSTRA
+#define IGL_DIJKSTRA
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+#include <set>
+
+namespace igl {
+
+  // Dijstra's algorithm for shortest paths, with multiple targets.
+  // Adapted from http://rosettacode.org/wiki/Dijkstra%27s_algorithm .
+  //
+  // Inputs:
+  //   source           index of source vertex
+  //   targets          target vector set
+  //   VV               #V list of lists of incident vertices (adjacency list), e.g.
+  //                    as returned by igl::adjacency_list
+  //
+  // Output:
+  //   min_distance     #V by 1 list of the minimum distances from source to all vertices
+  //   previous         #V by 1 list of the previous visited vertices (for each vertex) - used for backtracking
+  //
+  template <typename IndexType, typename DerivedD, typename DerivedP>
+  IGL_INLINE int dijkstra_compute_paths(const IndexType &source,
+                                        const std::set<IndexType> &targets,
+                                        const std::vector<std::vector<IndexType> >& VV,
+                                        Eigen::PlainObjectBase<DerivedD> &min_distance,
+                                        Eigen::PlainObjectBase<DerivedP> &previous);
+
+  // Backtracking after Dijstra's algorithm, to find shortest path.
+  //
+  // Inputs:
+  //   vertex           vertex to which we want the shortest path (from same source as above)
+  //   previous         #V by 1 list of the previous visited vertices (for each vertex) - result of Dijkstra's algorithm
+  //
+  // Output:
+  //   path             #P by 1 list of vertex indices in the shortest path from source to vertex
+  //
+  template <typename IndexType, typename DerivedP>
+  IGL_INLINE void dijkstra_get_shortest_path_to(const IndexType &vertex,
+                                                const Eigen::PlainObjectBase<DerivedP> &previous,
+                                                std::vector<IndexType> &path);
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "dijkstra.cpp"
+#endif
+
+
+#endif /* defined(IGL_DIJKSTRA) */

+ 1 - 0
include/igl/false_barycentric_subdivision.cpp

@@ -55,4 +55,5 @@ IGL_INLINE void igl::false_barycentric_subdivision(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template specialization
 template void igl::false_barycentric_subdivision<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::false_barycentric_subdivision<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

+ 49 - 0
include/igl/field_local_global_conversions.cpp

@@ -0,0 +1,49 @@
+#include <igl/field_local_global_conversions.h>
+
+ template <typename DerivedG, typename DerivedL, typename DerivedB>
+IGL_INLINE void igl::global2local(
+const Eigen::PlainObjectBase<DerivedB>& B1,
+const Eigen::PlainObjectBase<DerivedB>& B2,
+const Eigen::PlainObjectBase<DerivedG>& global,
+Eigen::PlainObjectBase<DerivedL>& local)
+{
+
+  int n = global.cols()/3;
+  //get 2D vectors from 3D vectors
+  local.resize(global.rows(), n*2);
+  for (int i =0; i<global.rows(); ++i)
+  {
+    for (int k =0; k<n; k++)
+    {
+      const Eigen::Matrix<typename DerivedG::Scalar,1,3> &g = global.block(i, k*3,1,3);
+      local.block(i, k*2,1,2) << g.dot(B1.row(i).template cast<typename DerivedG::Scalar>()), g.dot(B2.row(i).template cast<typename DerivedG::Scalar>()) ;
+    }
+  }
+}
+
+template <typename DerivedG, typename DerivedL, typename DerivedB>
+IGL_INLINE void igl::local2global(
+const Eigen::PlainObjectBase<DerivedB>& B1,
+const Eigen::PlainObjectBase<DerivedB>& B2,
+const Eigen::PlainObjectBase<DerivedL>& local,
+Eigen::PlainObjectBase<DerivedG>& global)
+{
+  int n = local.cols()/2;
+  //get 3D vectors from 2D vectors
+  global.resize(local.rows(), n*3);
+  for (int i =0; i<global.rows(); ++i)
+  {
+    for (int k =0; k<n; k++)
+    {
+      const Eigen::Matrix<typename DerivedL::Scalar,1,2> &l = local.block(i, k*2,1,2);
+      global.block(i, k*3, 1,3) = l[0]*B1.row(i).template cast<typename DerivedG::Scalar>() + l[1]*B2.row(i).template cast<typename DerivedG::Scalar>() ;
+    }
+  }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template void igl::global2local<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::local2global<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif

+ 65 - 0
include/igl/field_local_global_conversions.h

@@ -0,0 +1,65 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_FIELD_LOCAL_GLOBAL_CONVERSIONS
+#define IGL_FIELD_LOCAL_GLOBAL_CONVERSIONS
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl {
+  // Converts a face-based polyvector field consisting of n vectors per face
+  // from its 3D coordinates to its local 2D representation (with respect to the
+  // local bases of each triangle)
+
+  // Inputs:
+  //   B1               #F by 3 list of the first basis vector of each triangle
+  //   B2               #F by 3 list of the second basis vector of each triangle
+  //   global           #F by 3n list of the 3D coordinates of the per-face vectors
+  //                    (stacked horizontally for each triangle)
+  // Output:
+  //   local            #F by 2n list of the 2D representation of the per-face vectors
+  //                    (stacked horizontally for each triangle)
+  //
+template <typename DerivedG, typename DerivedL, typename DerivedB>
+IGL_INLINE void global2local(
+const Eigen::PlainObjectBase<DerivedB>& B1,
+const Eigen::PlainObjectBase<DerivedB>& B2,
+const Eigen::PlainObjectBase<DerivedG>& global,
+Eigen::PlainObjectBase<DerivedL>& local);
+
+// Converts a face-based polyvector field consisting of n vectors per face
+// from its local 2D representation (with respect to the local bases of each
+// triangle) to its 3D coordinates
+
+// Inputs:
+//   B1               #F by 3 list of the first basis vector of each triangle
+//   B2               #F by 3 list of the second basis vector of each triangle
+//   local            #F by 2n list of the 2D representation of the per-face vectors
+//                    (stacked horizontally for each triangle)
+// Output:
+//   global           #F by 3n list of the 3D coordinates of the per-face vectors
+//                    (stacked horizontally for each triangle)
+//
+template <typename DerivedG, typename DerivedL, typename DerivedB>
+IGL_INLINE void local2global(
+const Eigen::PlainObjectBase<DerivedB>& B1,
+const Eigen::PlainObjectBase<DerivedB>& B2,
+const Eigen::PlainObjectBase<DerivedL>& local,
+Eigen::PlainObjectBase<DerivedG>& global);
+
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "field_local_global_conversions.cpp"
+#endif
+
+
+#endif /* defined(IGL_FIELD_LOCAL_GLOBAL_CONVERSIONS) */

+ 1179 - 0
include/igl/integrable_polyvector_fields.cpp

@@ -0,0 +1,1179 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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 <igl/integrable_polyvector_fields.h>
+#include <igl/field_local_global_conversions.h>
+#include <igl/parallel_transport_angles.h>
+#include <igl/local_basis.h>
+#include <igl/edge_topology.h>
+#include <igl/sparse.h>
+#include <igl/sort.h>
+#include <igl/slice.h>
+#include <igl/slice_into.h>
+#include <igl/sort_vectors_ccw.h>
+#include <iostream>
+
+IGL_INLINE igl::integrable_polyvector_fields_parameters::integrable_polyvector_fields_parameters():
+numIter(5),
+wBarrier(0.1),
+sBarrier(0.9),
+wCurl(10),
+wQuotCurl(10),
+wSmooth(1.),
+wCloseUnconstrained(1e-3),
+wCloseConstrained(100),
+redFactor_wsmooth(.8),
+gamma(0.1),
+tikh_gamma(1e-8),
+do_partial(false)
+{}
+
+
+
+
+namespace igl {
+  template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+  class IntegrableFieldSolver
+  {
+  private:
+    
+    IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &data;
+    //Symbolic calculations
+    IGL_INLINE void rj_barrier_face(const Eigen::RowVectorXd &vec2D_a,
+                                    const double &s,
+                                    Eigen::VectorXd &residuals,
+                                    bool do_jac = false,
+                                    Eigen::MatrixXd &J = *(Eigen::MatrixXd*)NULL);
+    IGL_INLINE void rj_polycurl_edge(const Eigen::RowVectorXd &vec2D_a,
+                                     const Eigen::RowVector2d &ea,
+                                     const Eigen::RowVectorXd &vec2D_b,
+                                     const Eigen::RowVector2d &eb,
+                                     Eigen::VectorXd &residuals,
+                                     bool do_jac = false,
+                                     Eigen::MatrixXd &Jac = *(Eigen::MatrixXd*)NULL);
+    IGL_INLINE void rj_quotcurl_edge_polyversion(const Eigen::RowVectorXd &vec2D_a,
+                                                 const Eigen::RowVector2d &ea,
+                                                 const Eigen::RowVectorXd &vec2D_b,
+                                                 const Eigen::RowVector2d &eb,
+                                                 Eigen::VectorXd &residuals,
+                                                 bool do_jac = false,
+                                                 Eigen::MatrixXd &Jac = *(Eigen::MatrixXd*)NULL);
+    IGL_INLINE void rj_smoothness_edge(const Eigen::RowVectorXd &vec2D_a,
+                                       const Eigen::RowVectorXd &vec2D_b,
+                                       const double &k,
+                                       const int nA,
+                                       const int nB,
+                                       Eigen::VectorXd &residuals,
+                                       bool do_jac = false,
+                                       Eigen::MatrixXd &Jac = *(Eigen::MatrixXd*)NULL);
+    
+  public:
+    IGL_INLINE IntegrableFieldSolver(IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &cffsoldata);
+    
+    IGL_INLINE bool solve(integrable_polyvector_fields_parameters &params,
+                          Eigen::PlainObjectBase<DerivedFF>& current_field,
+                          bool current_field_is_not_ccw);
+    
+    IGL_INLINE void solveGaussNewton(integrable_polyvector_fields_parameters &params,
+                                     const Eigen::VectorXd &x_initial,
+                                     Eigen::VectorXd &x);
+    
+    //Compute residuals and Jacobian for Gauss Newton
+    IGL_INLINE double RJ(const Eigen::VectorXd &x,
+                         const Eigen::VectorXd &x0,
+                         const integrable_polyvector_fields_parameters &params,
+                         bool doJacs = false);
+    
+    IGL_INLINE void RJ_Smoothness(const Eigen::MatrixXd &sol2D,
+                                  const double &wSmoothSqrt,
+                                  const int startRowInJacobian,
+                                  bool doJacs = false,
+                                  const int startIndexInVectors = 0);
+    IGL_INLINE void RJ_Barrier(const Eigen::MatrixXd &sol2D,
+                               const double &s,
+                               const double &wBarrierSqrt,
+                               const int startRowInJacobian,
+                               bool doJacs = false,
+                               const int startIndexInVectors = 0);
+    IGL_INLINE void RJ_Closeness(const Eigen::MatrixXd &sol2D,
+                                 const Eigen::MatrixXd &sol02D,
+                                 const double &wCloseUnconstrainedSqrt,
+                                 const double &wCloseConstrainedSqrt,
+                                 const bool do_partial,
+                                 const int startRowInJacobian,
+                                 bool doJacs = false,
+                                 const int startIndexInVectors = 0);
+    IGL_INLINE void RJ_Curl(const Eigen::MatrixXd &sol2D,
+                            const double &wCASqrt,
+                            const double &wCBSqrt,
+                            const int startRowInJacobian,
+                            bool doJacs = false,
+                            const int startIndexInVectors = 0);
+    IGL_INLINE void RJ_QuotCurl(const Eigen::MatrixXd &sol2D,
+                                const double &wQuotCurlSqrt,
+                                const int startRowInJacobian,
+                                bool doJacs = false,
+                                const int startIndexInVectors = 0);
+    
+    
+  };
+};
+
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::IntegrableFieldSolverData()
+{}
+
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+precomputeMesh(const Eigen::PlainObjectBase<DerivedV> &_V,
+               const Eigen::PlainObjectBase<DerivedF> &_F)
+{
+  numV = _V.rows();
+  numF = _F.rows();
+  numVariables = 2*2*numF;
+  //Mesh stuff
+  igl::edge_topology(_V,_F,E,F2E,E2F);
+  numE = E.rows();
+  igl::local_basis(_V,_F,B1,B2,FN);
+  computeInteriorEdges();
+  igl::parallel_transport_angles(_V, _F, FN, E2F, F2E, K);
+  EVecNorm.setZero(numE,3);
+  for (int k = 0; k<numE; ++k)
+    EVecNorm.row(k) = (_V.row(E(k,1))-_V.row(E(k,0))).normalized();
+}
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+initializeConstraints(const Eigen::VectorXi& b,
+                      const Eigen::PlainObjectBase<DerivedC>& bc,
+                      const Eigen::VectorXi& constraint_level)
+{
+  //save constrained
+  Eigen::VectorXi iSorted, constrained_unsorted;
+  constrained_unsorted.resize(2*2*b.size());
+  is_constrained_face.setZero(numF, 1);
+  int ind = 0;
+  indInConstrained.setConstant(numF,1,-1);
+  for (int k =0; k<b.size(); ++k)
+  {
+    is_constrained_face[b[k]] = constraint_level[k];
+    for (int i=0; i<2;++i)
+    {
+      int xi = 2*2*b[k] + 2*i +0;
+      int yi = 2*2*b[k] + 2*i +1;
+      constrained_unsorted[ind++] = xi;
+      constrained_unsorted[ind++] = yi;
+    }
+    indInConstrained[b[k]] = k;
+  }
+  //sort in descending order (so removing rows will work)
+  igl::sort(constrained_unsorted, 1, false, constrained, iSorted);
+  constrained_vec3 = bc.template cast<double>();
+  
+}
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+makeFieldCCW(Eigen::MatrixXd &sol3D)
+{
+  //sort ccw
+  Eigen::RowVectorXd t;
+  Eigen::RowVectorXd all(1,2*2*3);
+  Eigen::VectorXi order;
+  for (int fi=0; fi<numF; ++fi)
+  {
+    //take all 4 vectors (including opposites) and pick two that are in ccw order
+    all << sol3D.row(fi), -sol3D.row(fi);
+    igl::sort_vectors_ccw(all, FN.row(fi).eval(), order, true, t);
+    //if we are in a constrained face, we need to make sure that the first vector is always the same vector as in the constraints
+    if(is_constrained_face[fi])
+    {
+      const Eigen::RowVector3d &constraint = constrained_vec3.block(indInConstrained[fi], 0, 1, 3);;
+      int best_i = -1; double best_score = std::numeric_limits<double>::max();
+      for (int i = 0; i<2*2; ++i)
+      {
+        double score = (t.segment(i*3,3) - constraint).norm();
+        if (score<best_score)
+        {
+          best_score = score;
+          best_i = i;
+        }
+      }
+      //do a circshift
+      Eigen::RowVectorXd temp = t.segment(0, 3*best_i);
+      int s1 = 3*best_i;
+      int n2 = 3*best_i;
+      int n1 = 3*2*2-n2;
+      t.segment(0,n1) = t.segment(s1,n1);
+      t.segment(n1, n2) = temp;
+      
+    }
+    sol3D.row(fi) = t.segment(0, 2*3);
+  }
+}
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+initializeOriginalVariable(const Eigen::PlainObjectBase<DerivedFF>& original_field)
+{
+  Eigen::MatrixXd sol2D;
+  Eigen::MatrixXd sol3D = original_field.template cast<double>();
+  makeFieldCCW(sol3D);
+  igl::global2local(B1, B2, sol3D, sol2D);
+  xOriginal.setZero(numVariables);
+  for (int i =0; i<numF; i++)
+    xOriginal.segment(i*2*2, 2*2) = sol2D.row(i);
+  
+}
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+computeInteriorEdges()
+{
+  Eigen::VectorXi isBorderEdge;
+  // Flag border edges
+  numInteriorEdges = 0;
+  isBorderEdge.setZero(numE,1);
+  indFullToInterior = -1.*Eigen::VectorXi::Ones(numE,1);
+  
+  for(unsigned i=0; i<numE; ++i)
+  {
+    if ((E2F(i,0) == -1) || ((E2F(i,1) == -1)))
+      isBorderEdge[i] = 1;
+    else
+    {
+      indFullToInterior[i] = numInteriorEdges;
+      numInteriorEdges++;
+    }
+  }
+  
+  E2F_int.resize(numInteriorEdges, 2);
+  indInteriorToFull.setZero(numInteriorEdges,1);
+  int ii = 0;
+  for (int k=0; k<numE; ++k)
+  {
+    if (isBorderEdge[k])
+      continue;
+    E2F_int.row(ii) = E2F.row(k);
+    indInteriorToFull[ii] = k;
+    ii++;
+  }
+  
+}
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+add_Jacobian_to_svector(const int &toplace,
+                        const Eigen::MatrixXd &tJac,
+                        Eigen::VectorXd &SS_Jac)
+{
+  int numInnerRows = tJac.rows();
+  int numInnerCols = tJac.cols();
+  int ind = toplace;
+  for (int j=0; j<numInnerRows; ++j)
+    for (int k=0; k<numInnerCols; ++k, ++ind)
+      SS_Jac(ind) = tJac(j,k);
+}
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+add_jac_indices_face(const int numInnerRows,
+                     const int numInnerCols,
+                     const int startRowInJacobian,
+                     const int startIndexInVectors,
+                     Eigen::VectorXi &Rows,
+                     Eigen::VectorXi &Columns)
+{
+  for (int fi=0; fi<numF; ++fi)
+  {
+    
+    int startRow = startRowInJacobian+numInnerRows*fi;
+    int startIndex = startIndexInVectors+numInnerRows*numInnerCols*fi;
+    face_Jacobian_indices(startRow, startIndex, fi, 2, numInnerRows, numInnerCols, Rows, Columns);
+  }
+}
+
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+face_Jacobian_indices(const int &startRow,
+                      const int &toplace,
+                      const int& fi,
+                      const int& half_degree,
+                      const int &numInnerRows,
+                      const int &numInnerCols,
+                      Eigen::VectorXi &rows,
+                      Eigen::VectorXi &columns)
+{
+  int ind = toplace;
+  for (int j=0; j<numInnerRows; ++j)
+  {
+    for (int k=0; k<numInnerCols; ++k, ++ind)
+    {
+      int iv  = k/2;//which vector (0..half_degree-1) am i at
+      int ixy = k%2;//which part (real/imag) am i at
+      rows(ind) = startRow+j;
+      columns(ind) = 2*half_degree*fi + 2*iv +ixy;
+    }
+  }
+}
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+add_jac_indices_edge(const int numInnerRows,
+                     const int numInnerCols,
+                     const int startRowInJacobian,
+                     const int startIndexInVectors,
+                     Eigen::VectorXi &Rows,
+                     Eigen::VectorXi &Columns)
+{
+  for (int ii=0; ii<numInteriorEdges; ++ii)
+  {
+    // the two faces of the flap
+    int a = E2F_int(ii,0);
+    int b = E2F_int(ii,1);
+    
+    
+    int startRow = startRowInJacobian+numInnerRows*ii;
+    int startIndex = startIndexInVectors+numInnerRows*numInnerCols*ii;
+    
+    edge_Jacobian_indices(startRow, startIndex, a, b, 2, numInnerRows, numInnerCols, Rows, Columns);
+    
+  }
+}
+
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+edge_Jacobian_indices(const int &startRow,
+                      const int &toplace,
+                      const int& a,
+                      const int& b,
+                      const int& half_degree,
+                      const int &numInnerRows,
+                      const int &numInnerCols,
+                      Eigen::VectorXi &rows,
+                      Eigen::VectorXi &columns)
+{
+  int ind = toplace;
+  for (int j=0; j<numInnerRows; ++j)
+  {
+    for (int k=0; k<numInnerCols; ++k, ++ind)
+    {
+      int f   = (k<2*half_degree)?a:b;//which face i am at
+      int iv  = (k%(2*half_degree))/2;//which vector (0..half_degree-1) am i at
+      int ixy = k%2;//which part (real/imag) am i at
+      rows(ind) = startRow+j;
+      columns(ind) = 2*half_degree*f + 2*iv +ixy;
+    }
+  }
+}
+
+template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+computeJacobianPattern()
+{
+  num_residuals_smooth = 4*numInteriorEdges;
+  num_residuals_close = 4*numF;
+  num_residuals_polycurl = 2*numInteriorEdges;
+  num_residuals_quotcurl = numInteriorEdges;
+  num_residuals_barrier = numF;
+  
+  num_residuals = num_residuals_smooth + num_residuals_close + num_residuals_polycurl + num_residuals_quotcurl + num_residuals_barrier;
+  
+  residuals.setZero(num_residuals,1);
+  
+  //per edge
+  numJacElements_smooth = numInteriorEdges*numInnerJacCols_edge*numInnerJacRows_smooth;
+  numJacElements_polycurl = numInteriorEdges*numInnerJacCols_edge*numInnerJacRows_polycurl;
+  numJacElements_quotcurl = numInteriorEdges*numInnerJacCols_edge*numInnerJacRows_quotcurl;
+  
+  //per face
+  numJacElements_barrier = numF*numInnerJacCols_face*numInnerJacRows_barrier;
+  numJacElements_close = numF*numInnerJacCols_face*numInnerJacRows_close;
+  
+  numJacElements = (numJacElements_smooth +numJacElements_polycurl + numJacElements_quotcurl) + (numJacElements_barrier +numJacElements_close);
+  //allocate
+  II_Jac.setZero(numJacElements);
+  JJ_Jac.setZero(numJacElements);
+  SS_Jac.setOnes(numJacElements);
+  
+  //set stuff (attention: order !)
+  int startRowInJacobian = 0;
+  int startIndexInVectors = 0;
+  
+  //smoothness
+  add_jac_indices_edge(numInnerJacRows_smooth,
+                       numInnerJacCols_edge,
+                       startRowInJacobian,
+                       startIndexInVectors,
+                       II_Jac,
+                       JJ_Jac);
+  startRowInJacobian += num_residuals_smooth;
+  startIndexInVectors += numJacElements_smooth;
+  
+  //closeness
+  add_jac_indices_face(numInnerJacRows_close,
+                       numInnerJacCols_face,
+                       startRowInJacobian,
+                       startIndexInVectors,
+                       II_Jac,
+                       JJ_Jac);
+  startRowInJacobian += num_residuals_close;
+  startIndexInVectors += numJacElements_close;
+  
+  //barrier
+  add_jac_indices_face(numInnerJacRows_barrier,
+                       numInnerJacCols_face,
+                       startRowInJacobian,
+                       startIndexInVectors,
+                       II_Jac,
+                       JJ_Jac);
+  startRowInJacobian += num_residuals_barrier;
+  startIndexInVectors += numJacElements_barrier;
+  
+  //polycurl
+  add_jac_indices_edge(numInnerJacRows_polycurl,
+                       numInnerJacCols_edge,
+                       startRowInJacobian,
+                       startIndexInVectors,
+                       II_Jac,
+                       JJ_Jac);
+  startRowInJacobian += num_residuals_polycurl;
+  startIndexInVectors += numJacElements_polycurl;
+  
+  //quotcurl
+  add_jac_indices_edge(numInnerJacRows_quotcurl,
+                       numInnerJacCols_edge,
+                       startRowInJacobian,
+                       startIndexInVectors,
+                       II_Jac,
+                       JJ_Jac);
+  igl::sparse(II_Jac, JJ_Jac, SS_Jac, Jac);
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+computeHessianPattern()
+{
+  //II_Jac is sorted in ascending order already
+  int starti = 0;
+  int currI = II_Jac(0);
+  for (int ii = 0; ii<II_Jac.rows(); ++ii)
+  {
+    if(currI != II_Jac(ii))
+    {
+      starti = ii;
+      currI = II_Jac(ii);
+    }
+    int k1  = II_Jac(ii);
+    for (int jj = starti; jj<II_Jac.rows(); ++jj)
+    {
+      int k2  = II_Jac(jj);
+      if (k1 !=k2)
+        break;
+      indInSS_Hess_1_vec.push_back(ii);
+      indInSS_Hess_2_vec.push_back(jj);
+      Hess_triplets.push_back(Eigen::Triplet<double> (JJ_Jac(ii),
+                                                      JJ_Jac(jj),
+                                                      SS_Jac(ii)*SS_Jac(jj)
+                                                      )
+                              );
+    }
+  }
+  Hess.resize(Jac.cols(),Jac.cols());
+  Hess.setFromTriplets(Hess_triplets.begin(), Hess_triplets.end());
+  Hess.makeCompressed();
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
+computeNewHessValues()
+{
+  for (int i =0; i<Hess_triplets.size(); ++i)
+    Hess_triplets[i] = Eigen::Triplet<double>(Hess_triplets[i].row(),
+                                              Hess_triplets[i].col(),
+                                              SS_Jac(indInSS_Hess_1_vec[i])*SS_Jac(indInSS_Hess_2_vec[i])
+                                              );
+  
+  Hess.setFromTriplets(Hess_triplets.begin(), Hess_triplets.end());
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::IntegrableFieldSolver( IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &cffsoldata):
+data(cffsoldata)
+{ };
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE bool igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+solve(igl::integrable_polyvector_fields_parameters &params,
+      Eigen::PlainObjectBase<DerivedFF>& current_field,
+      bool current_field_is_not_ccw)
+{
+  Eigen::MatrixXd sol2D;
+  Eigen::MatrixXd sol3D = current_field.template cast<double>();
+  if (current_field_is_not_ccw)
+    data.makeFieldCCW(sol3D);
+  
+  igl::global2local(data.B1, data.B2, sol3D, sol2D);
+  Eigen::VectorXd x;
+  x.setZero(data.numVariables);
+  for (int i =0; i<data.numF; i++)
+    x.segment(i*2*2, 2*2) = sol2D.row(i);
+  
+  //get x
+  solveGaussNewton(params, data.xOriginal, x);
+  //get output from x
+  for (int i =0; i<data.numF; i++)
+    sol2D.row(i) = x.segment(i*2*2, 2*2);
+  igl::local2global(data.B1, data.B2, sol2D, sol3D);
+  current_field = sol3D.cast<typename DerivedFF::Scalar>();
+  return true;
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+solveGaussNewton(integrable_polyvector_fields_parameters &params,
+                 const Eigen::VectorXd &x_initial,
+                 Eigen::VectorXd &x)
+{
+  bool converged = false;
+  
+  double F;
+  Eigen::VectorXd xprev = x;
+  Eigen::VectorXd xc = igl::slice(x_initial, data.constrained, 1);
+  //  double ESmooth, EClose, ECurl, EQuotCurl, EBarrier;
+  for (int innerIter = 0; innerIter<params.numIter; ++innerIter)
+  {
+    
+    //set constrained entries to those of the initial
+    igl::slice_into(xc, data.constrained, 1, xprev);
+    
+    
+    //get function, gradients and Hessians
+    F = RJ(x, xprev, params, true);
+    
+    printf("IntegrableFieldSolver -- Iteration %d\n", innerIter);
+    
+    if((data.residuals.array() == std::numeric_limits<double>::infinity()).any())
+    {
+      std::cerr<<"IntegrableFieldSolver -- residuals: got infinity somewhere"<<std::endl;
+      exit(1);
+    };
+    if((data.residuals.array() != data.residuals.array()).any())
+    {
+      std::cerr<<"IntegrableFieldSolver -- residuals: got infinity somewhere"<<std::endl;
+      exit(1);
+    };
+    
+    converged = false;
+    
+    Eigen::VectorXd rhs = data.Jac.transpose()*data.residuals;
+    
+    bool success;
+    data.solver.factorize(data.Hess);
+    success = data.solver.info() == Eigen::Success;
+    
+    if(!success)
+      std::cerr<<"IntegrableFieldSolver -- Could not do LU"<<std::endl;
+    
+    Eigen::VectorXd direction;
+    
+    double error;
+    direction = data.solver.solve(rhs);
+    error = (data.Hess*direction - rhs).cwiseAbs().maxCoeff();
+    if(error> 1e-4)
+    {
+      std::cerr<<"IntegrableFieldSolver -- Could not solve"<<std::endl;
+    }
+    
+    // adaptive backtracking
+    bool repeat = true;
+    int run = 0;
+    Eigen::VectorXd cx;
+    Eigen::VectorXd tRes;
+    double newF;
+    while(repeat)
+    {
+      cx = x - params.gamma*direction;
+      newF = RJ(cx, xprev, params);
+      if(newF < F)
+      {
+        repeat = false;
+        if(run == 0)
+          params.gamma *= 2;
+      }
+      else
+      {
+        params.gamma *= 0.5f;
+        if(params.gamma<1e-30)
+        {
+          repeat = false;
+          converged = true;
+        }
+      }
+      run++;
+    }
+    
+    
+    if (!converged)
+    {
+      xprev = x;
+      x = cx;
+    }
+    else
+    {
+      std::cerr<<"IntegrableFieldSolver -- Converged"<<std::endl;
+      break;
+    }
+  }
+  
+  
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE double igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+RJ(const Eigen::VectorXd &x,
+   const Eigen::VectorXd &x0,
+   const integrable_polyvector_fields_parameters &params,
+   bool doJacs)
+{
+  Eigen::MatrixXd sol2D(data.numF,4), sol02D(data.numF,4);
+  for (int i =0; i<data.numF; i++)
+    sol2D.row(i) = x.segment(i*2*2, 2*2);
+  for (int i =0; i<data.numF; i++)
+    sol02D.row(i) = x0.segment(i*2*2, 2*2);
+  
+  data.SS_Jac.setZero(data.numJacElements);
+  
+  //set stuff (attention: order !)
+  int startRowInJacobian = 0;
+  int startIndexInVectors = 0;
+  
+  //smoothness
+  RJ_Smoothness(sol2D, sqrt(params.wSmooth), startRowInJacobian, doJacs, startIndexInVectors);
+  startRowInJacobian += data.num_residuals_smooth;
+  startIndexInVectors += data.numJacElements_smooth;
+  
+  //closeness
+  RJ_Closeness(sol2D, sol02D, sqrt(params.wCloseUnconstrained), sqrt(params.wCloseConstrained), params.do_partial, startRowInJacobian, doJacs, startIndexInVectors);
+  startRowInJacobian += data.num_residuals_close;
+  startIndexInVectors += data.numJacElements_close;
+  
+  //barrier
+  RJ_Barrier(sol2D, params.sBarrier, sqrt(params.wBarrier), startRowInJacobian, doJacs, startIndexInVectors);
+  startRowInJacobian += data.num_residuals_barrier;
+  startIndexInVectors += data.numJacElements_barrier;
+  
+  //polycurl
+  RJ_Curl(sol2D, params.wCurl, powl(params.wCurl, 2), startRowInJacobian, doJacs, startIndexInVectors);
+  startRowInJacobian += data.num_residuals_polycurl;
+  startIndexInVectors += data.numJacElements_polycurl;
+  
+  //quotcurl
+  RJ_QuotCurl(sol2D, sqrt(params.wQuotCurl), startRowInJacobian, doJacs, startIndexInVectors);
+  
+  if(doJacs)
+  {
+    for (int i =0; i<data.numJacElements; ++i)
+      data.Jac.coeffRef(data.II_Jac(i), data.JJ_Jac(i)) = data.SS_Jac(i);
+    data.computeNewHessValues();
+  }
+  
+  return data.residuals.transpose()*data.residuals;
+}
+
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+rj_smoothness_edge(const Eigen::RowVectorXd &vec2D_a,
+                   const Eigen::RowVectorXd &vec2D_b,
+                   const double &k,
+                   const int nA,
+                   const int nB,
+                   Eigen::VectorXd &residuals,
+                   bool do_jac,
+                   Eigen::MatrixXd &Jac)
+{
+  const Eigen::RowVector2d &ua = vec2D_a.segment(0, 2);
+  const Eigen::RowVector2d &va = vec2D_a.segment(2, 2);
+  const Eigen::RowVector2d &ub = vec2D_b.segment(0, 2);
+  const Eigen::RowVector2d &vb = vec2D_b.segment(2, 2);
+  const double &xua=ua[0], &yua=ua[1], &xva=va[0], &yva=va[1];
+  const double &xub=ub[0], &yub=ub[1], &xvb=vb[0], &yvb=vb[1];
+  
+  double xua_2 = xua*xua;
+  double xva_2 = xva*xva;
+  double yua_2 = yua*yua;
+  double yva_2 = yva*yva;
+  double xub_2 = xub*xub;
+  double xvb_2 = xvb*xvb;
+  double yub_2 = yub*yub;
+  double yvb_2 = yvb*yvb;
+  
+  double sA = sin(nA*k);
+  double cA = cos(nA*k);
+  double sB = sin(nB*k);
+  double cB = cos(nB*k);
+  
+  double t1 = xua*yua;
+  double t2 = xva*yva;
+  double t3 = xub*xvb;
+  double t4 = yub*yvb;
+  double t5 = xua*xva;
+  double t6 = xub*yub;
+  double t7 = yua*yva;
+  double t8 = xvb*yvb;
+  
+  double t9  = xva_2 - yva_2;
+  double t10 = xua_2 - yua_2;
+  double t11 = xvb_2 - yvb_2;
+  double t12 = xub_2 - yub_2;
+  
+  double t13 = 2*t1 + 2*t2;
+  
+  double t17 = (2*t1*t9 + 2*t2*t10);
+  double t19 = (t10*t9 - 4*t5*t7);
+  
+  
+  residuals.resize(4, 1);
+  residuals <<
+  cA*(t10 + t9) - sA*(t13) - t12 - t11,
+  sA*(t10 + t9) - 2*t8 - 2*t6 + cA*(t13),
+  cB*t19 - (t12)*(t11) - sB*t17 + 4*t3*t4,
+  cB*t17 + sB*t19 - 2*t6*(t11) - 2*t8*(t12);
+  
+  
+  if (do_jac)
+  {
+    double t20 = 2*yua*t9 + 4*xua*t2;
+    double t21 = 2*xua*t9 - 4*xva*t7;
+    double t22 = 2*yva*t10 + 4*t5*yua;
+    double t23 = 2*xva*t10 - 4*t1*yva;
+    
+    Jac.resize(4,8);
+    Jac <<                                                                     2*xua*cA - 2*yua*sA,                                                                     - 2*yua*cA - 2*xua*sA,                                                                     2*xva*cA - 2*yva*sA,                                                                     - 2*yva*cA - 2*xva*sA,                                  -2*xub,                                 2*yub,                                  -2*xvb,                                 2*yvb,
+    2*yua*cA + 2*xua*sA,                                                                       2*xua*cA - 2*yua*sA,                                                                     2*yva*cA + 2*xva*sA,                                                                       2*xva*cA - 2*yva*sA,                                  -2*yub,                                -2*xub,                                  -2*yvb,                                -2*xvb,
+    cB*(t21) - sB*(t20), - cB*(t20) - sB*(t21), cB*(t23) - sB*(t22), - cB*(t22) - sB*(t23),   4*xvb*t4 - 2*xub*t11, 2*yub*t11 + 4*t3*yvb,   4*xub*t4 - 2*xvb*t12, 2*yvb*t12 + 4*t3*yub,
+    cB*(t20) + sB*(t21),   cB*(t21) - sB*(t20), cB*(t22) + sB*(t23),   cB*(t23) - sB*(t22), - 2*yub*t11 - 4*t3*yvb, 4*xvb*t4 - 2*xub*t11, - 2*yvb*t12 - 4*t3*yub, 4*xub*t4 - 2*xvb*t12;
+  }
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+RJ_Smoothness(const Eigen::MatrixXd &sol2D,
+              const double &wSmoothSqrt,
+              const int startRowInJacobian,
+              bool doJacs,
+              const int startIndexInVectors)
+{
+  if (wSmoothSqrt ==0)
+    return;
+  for (int ii=0; ii<data.numInteriorEdges; ++ii)
+  {
+    // the two faces of the flap
+    int a = data.E2F_int(ii,0);
+    int b = data.E2F_int(ii,1);
+    
+    int k = data.indInteriorToFull[ii];
+    
+    Eigen::MatrixXd tJac;
+    Eigen::VectorXd tRes;
+    rj_smoothness_edge(sol2D.row(a),
+                       sol2D.row(b),
+                       data.K[k],
+                       2*(0+1), //degree of first coefficient
+                       2*(1+1), //degree of second coefficient
+                       tRes,
+                       doJacs,
+                       tJac);
+    
+    int startRow = startRowInJacobian+data.numInnerJacRows_smooth*ii;
+    data.residuals.segment(startRow,data.numInnerJacRows_smooth) = wSmoothSqrt*tRes;
+    
+    if(doJacs)
+    {
+      int startIndex = startIndexInVectors+data.numInnerJacRows_smooth*data.numInnerJacCols_edge*ii;
+      data.add_Jacobian_to_svector(startIndex, wSmoothSqrt*tJac,data.SS_Jac);
+    }
+  }
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+rj_barrier_face(const Eigen::RowVectorXd &vec2D_a,
+                const double &s,
+                Eigen::VectorXd &residuals,
+                bool do_jac,
+                Eigen::MatrixXd &Jac)
+{
+  
+  const Eigen::RowVector2d &ua = vec2D_a.segment(0, 2);
+  const Eigen::RowVector2d &va = vec2D_a.segment(2, 2);
+  const double &xua=ua[0], &yua=ua[1], &xva=va[0], &yva=va[1];
+  
+  
+  double xva_2 = xva*xva;
+  double yua_2 = yua*yua;
+  double xua_2 = xua*xua;
+  double yva_2 = yva*yva;
+  
+  double s_2 = s*s;
+  double s_3 = s*s_2;
+  
+  double t00 = xua*yva;
+  double t01 = xva*yua;
+  double t05 = t00 - t01;
+  double t05_2 = t05*t05;
+  double t05_3 = t05*t05_2;
+  
+  if (do_jac)
+    Jac.setZero(1,4);
+  residuals.resize(1, 1);
+  if (t05>=s)
+    residuals << 0;
+  else if (t05<0)
+    residuals << std::numeric_limits<double>::infinity();
+  else
+  {
+    residuals << 1/((3*t00 - 3*t01)/s - (3*t05_2)/s_2 + t05_3/s_3) - 1;
+    double t03 = (s - t05)*(s - t05);
+    double t06 = (3*s_2 - 3*s*t00 + 3*s*t01 + xua_2*yva_2 - 2*xua*t01*yva + xva_2*yua_2);
+    double t04 = t06*t06;
+    if (do_jac)
+      Jac<<
+      -(3*s_3*yva*t03)/(t05_2*t04),
+      (3*s_3*xva*t03)/(t05_2*t04),
+      (3*s_3*yua*t03)/(t05_2*t04),
+      -(3*s_3*xua*t03)/(t05_2*t04);
+  }
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+RJ_Barrier(const Eigen::MatrixXd &sol2D,
+           const double &s,
+           const double &wBarrierSqrt,
+           const int startRowInJacobian,
+           bool doJacs,
+           const int startIndexInVectors)
+{
+  if (wBarrierSqrt ==0)
+    return;
+  
+  for (int fi=0; fi<data.numF; ++fi)
+  {
+    Eigen::MatrixXd tJac;
+    Eigen::VectorXd tRes;
+    rj_barrier_face(sol2D.row(fi),
+                    s,
+                    tRes,
+                    doJacs,
+                    tJac);
+    
+    int startRow = startRowInJacobian+ data.numInnerJacRows_barrier * fi;
+    data.residuals.segment(startRow,data.numInnerJacRows_barrier) = wBarrierSqrt*tRes;
+    
+    if(doJacs)
+    {
+      int startIndex = startIndexInVectors+data.numInnerJacRows_barrier*data.numInnerJacCols_face*fi;
+      data.add_Jacobian_to_svector(startIndex, wBarrierSqrt*tJac,data.SS_Jac);
+    }
+  }
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+RJ_Closeness(const Eigen::MatrixXd &sol2D,
+             const Eigen::MatrixXd &sol02D,
+             const double &wCloseUnconstrainedSqrt,
+             const double &wCloseConstrainedSqrt,
+             const bool do_partial,
+             const int startRowInJacobian,
+             bool doJacs,
+             const int startIndexInVectors)
+{
+  if (wCloseUnconstrainedSqrt ==0 && wCloseConstrainedSqrt ==0)
+    return;
+  for (int fi=0; fi<data.numF; ++fi)
+  {
+    Eigen::Vector4d weights;
+    if (!data.is_constrained_face[fi])
+      weights.setConstant(wCloseUnconstrainedSqrt);
+    else
+    {
+      if (do_partial&&data.is_constrained_face[fi]==1)
+        //only constrain the first vector
+        weights<<wCloseConstrainedSqrt,wCloseConstrainedSqrt,wCloseUnconstrainedSqrt,wCloseUnconstrainedSqrt;
+      else
+        //either not partial, or partial with 2 constraints
+        weights.setConstant(wCloseConstrainedSqrt);
+    }
+    
+    Eigen::MatrixXd tJac;
+    Eigen::VectorXd tRes;
+    tJac = Eigen::MatrixXd::Identity(4,4);
+    tRes.resize(4, 1); tRes<<(sol2D.row(fi)-sol02D.row(fi)).transpose();
+    int startRow = startRowInJacobian+data.numInnerJacRows_close*fi;
+    data.residuals.segment(startRow,data.numInnerJacRows_close) = weights.array()*tRes.array();
+    
+    if(doJacs)
+    {
+      int startIndex = startIndexInVectors+data.numInnerJacRows_close*data.numInnerJacCols_face*fi;
+      data.add_Jacobian_to_svector(startIndex, weights.asDiagonal()*tJac,data.SS_Jac);
+    }
+    
+  }
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+rj_polycurl_edge(const Eigen::RowVectorXd &vec2D_a,
+                 const Eigen::RowVector2d &ea,
+                 const Eigen::RowVectorXd &vec2D_b,
+                 const Eigen::RowVector2d &eb,
+                 Eigen::VectorXd &residuals,
+                 bool do_jac,
+                 Eigen::MatrixXd &Jac)
+{
+  const Eigen::RowVector2d &ua = vec2D_a.segment(0, 2);
+  const Eigen::RowVector2d &va = vec2D_a.segment(2, 2);
+  const Eigen::RowVector2d &ub = vec2D_b.segment(0, 2);
+  const Eigen::RowVector2d &vb = vec2D_b.segment(2, 2);
+  const double &xua=ua[0], &yua=ua[1], &xva=va[0], &yva=va[1];
+  const double &xub=ub[0], &yub=ub[1], &xvb=vb[0], &yvb=vb[1];
+  const double &xea=ea[0], &yea=ea[1];
+  const double &xeb=eb[0], &yeb=eb[1];
+  
+  const double dua = (xea*xua + yea*yua);
+  const double dub = (xeb*xub + yeb*yub);
+  const double dva = (xea*xva + yea*yva);
+  const double dvb = (xeb*xvb + yeb*yvb);
+  
+  const double dua_2 = dua*dua;
+  const double dva_2 = dva*dva;
+  const double dub_2 = dub*dub;
+  const double dvb_2 = dvb*dvb;
+  
+  residuals.resize(2, 1);
+  residuals << dua_2 - dub_2 + dva_2 - dvb_2,
+  dua_2*dva_2 - dub_2*dvb_2 ;
+  
+  
+  
+  if (do_jac)
+  {
+    
+    Jac.resize(2,8);
+    Jac << 2*xea*dua,                       2*yea*dua,                       2*xea*dva,                       2*yea*dva,                       -2*xeb*dub,                       -2*yeb*dub,                       -2*xeb*dvb,                       -2*yeb*dvb,
+    2*xea*dua*dva_2, 2*yea*dua*dva_2, 2*xea*dua_2*dva, 2*yea*dua_2*dva, -2*xeb*dub*dvb_2, -2*yeb*dub*dvb_2, -2*xeb*dub_2*dvb, -2*yeb*dub_2*dvb;
+  }
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+RJ_Curl(const Eigen::MatrixXd &sol2D,
+        const double &wCASqrt,
+        const double &wCBSqrt,
+        const int startRowInJacobian,
+        bool doJacs,
+        const int startIndexInVectors)
+{
+  if((wCASqrt==0) &&(wCBSqrt==0))
+    return;
+  for (int ii=0; ii<data.numInteriorEdges; ++ii)
+  {
+    // the two faces of the flap
+    int a = data.E2F_int(ii,0);
+    int b = data.E2F_int(ii,1);
+    
+    int k = data.indInteriorToFull[ii];
+    
+    // the common edge, a 3 vector
+    const Eigen::RowVector3d &ce = data.EVecNorm.row(k);
+    
+    // the common edge expressed in local coordinates in the two faces
+    // x/y denotes real/imaginary
+    double xea = data.B1.row(a).dot(ce);
+    double yea = data.B2.row(a).dot(ce);
+    Eigen::RowVector2d ea; ea<<xea, yea;
+    double xeb = data.B1.row(b).dot(ce);
+    double yeb = data.B2.row(b).dot(ce);
+    Eigen::RowVector2d eb; eb<<xeb, yeb;
+    
+    
+    Eigen::MatrixXd tJac;
+    Eigen::VectorXd tRes;
+    rj_polycurl_edge(sol2D.row(a),
+                     ea,
+                     sol2D.row(b),
+                     eb,
+                     tRes,
+                     doJacs,
+                     tJac);
+    
+    tRes[0] = tRes[0]*wCASqrt;
+    tRes[1] = tRes[1]*wCBSqrt;
+    
+    
+    int startRow = startRowInJacobian+data.numInnerJacRows_polycurl*ii;
+    data.residuals.segment(startRow,data.numInnerJacRows_polycurl) = tRes;
+    
+    if(doJacs)
+    {
+      tJac.row(0) = tJac.row(0)*wCASqrt;
+      tJac.row(1) = tJac.row(1)*wCBSqrt;
+      int startIndex = startIndexInVectors+data.numInnerJacRows_polycurl*data.numInnerJacCols_edge*ii;
+      data.add_Jacobian_to_svector(startIndex, tJac,data.SS_Jac);
+    }
+    
+  }
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+rj_quotcurl_edge_polyversion(const Eigen::RowVectorXd &vec2D_a,
+                             const Eigen::RowVector2d &ea,
+                             const Eigen::RowVectorXd &vec2D_b,
+                             const Eigen::RowVector2d &eb,
+                             Eigen::VectorXd &residuals,
+                             bool do_jac,
+                             Eigen::MatrixXd &Jac)
+{
+  const Eigen::RowVector2d &ua = vec2D_a.segment(0, 2);
+  const Eigen::RowVector2d &va = vec2D_a.segment(2, 2);
+  const Eigen::RowVector2d &ub = vec2D_b.segment(0, 2);
+  const Eigen::RowVector2d &vb = vec2D_b.segment(2, 2);
+  const double &xua=ua[0], &yua=ua[1], &xva=va[0], &yva=va[1];
+  const double &xub=ub[0], &yub=ub[1], &xvb=vb[0], &yvb=vb[1];
+  const double &xea=ea[0], &yea=ea[1];
+  const double &xeb=eb[0], &yeb=eb[1];
+  
+  double dua = (xea*xua + yea*yua);
+  double dva = (xea*xva + yea*yva);
+  double dub = (xeb*xub + yeb*yub);
+  double dvb = (xeb*xvb + yeb*yvb);
+  
+  double dua_2 = dua * dua;
+  double dva_2 = dva * dva;
+  double dub_2 = dub * dub;
+  double dvb_2 = dvb * dvb;
+  double t00 = (dub_2 - dvb_2);
+  double t01 = (dua_2 - dva_2);
+  
+  
+  residuals.resize(1, 1);
+  residuals << dua*dva*t00 - dub*dvb*t01;
+  
+  if (do_jac)
+  {
+    Jac.resize(1,8);
+    Jac <<  xea*dva*t00 - 2*xea*dua*dub*dvb, yea*dva*t00 - 2*yea*dua*dub*dvb, xea*dua*t00 + 2*xea*dub*dva*dvb, yea*dua*t00 + 2*yea*dub*dva*dvb, 2*xeb*dua*dub*dva - xeb*dvb*t01, 2*yeb*dua*dub*dva - yeb*dvb*t01, - xeb*dub*t01 - 2*xeb*dua*dva*dvb, - yeb*dub*t01 - 2*yeb*dua*dva*dvb;
+  }
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
+RJ_QuotCurl(const Eigen::MatrixXd &sol2D,
+            const double &wQuotCurlSqrt,
+            const int startRowInJacobian,
+            bool doJacs,
+            const int startIndexInVectors)
+{
+  for (int ii=0; ii<data.numInteriorEdges; ++ii)
+  {
+    // the two faces of the flap
+    int a = data.E2F_int(ii,0);
+    int b = data.E2F_int(ii,1);
+    
+    int k = data.indInteriorToFull[ii];
+    
+    // the common edge, a 3 vector
+    const Eigen::RowVector3d &ce = data.EVecNorm.row(k);
+    
+    // the common edge expressed in local coordinates in the two faces
+    // x/y denotes real/imaginary
+    double xea = data.B1.row(a).dot(ce);
+    double yea = data.B2.row(a).dot(ce);
+    Eigen::RowVector2d ea; ea<<xea, yea;
+    double xeb = data.B1.row(b).dot(ce);
+    double yeb = data.B2.row(b).dot(ce);
+    Eigen::RowVector2d eb; eb<<xeb, yeb;
+    
+    
+    Eigen::MatrixXd tJac;
+    Eigen::VectorXd tRes;
+    rj_quotcurl_edge_polyversion(sol2D.row(a),
+                                 ea,
+                                 sol2D.row(b),
+                                 eb,
+                                 tRes,
+                                 doJacs,
+                                 tJac);
+    
+    int startRow = startRowInJacobian+ data.numInnerJacRows_quotcurl*ii;
+    data.residuals.segment(startRow,data.numInnerJacRows_quotcurl) = wQuotCurlSqrt*tRes;
+    
+    if(doJacs)
+    {
+      int startIndex = startIndexInVectors+data.numInnerJacRows_quotcurl*data.numInnerJacCols_edge*ii;
+      data.add_Jacobian_to_svector(startIndex, wQuotCurlSqrt*tJac,data.SS_Jac);
+    }
+  }
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::integrable_polyvector_fields_precompute(
+                                                             const Eigen::PlainObjectBase<DerivedV>& V,
+                                                             const Eigen::PlainObjectBase<DerivedF>& F,
+                                                             const Eigen::VectorXi& b,
+                                                             const Eigen::PlainObjectBase<DerivedC>& bc,
+                                                             const Eigen::VectorXi& constraint_level,
+                                                             const Eigen::PlainObjectBase<DerivedFF>& original_field,
+                                                             igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &data)
+{
+  data.precomputeMesh(V,F);
+  
+  data.computeJacobianPattern();
+  data.computeHessianPattern();
+  data.solver.analyzePattern(data.Hess);
+  
+  data.initializeConstraints(b,bc,constraint_level);
+  data.initializeOriginalVariable(original_field);
+};
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::integrable_polyvector_fields_solve(igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &cffsoldata,
+                                                        integrable_polyvector_fields_parameters &params,
+                                                        Eigen::PlainObjectBase<DerivedFF>& current_field,
+                                                        bool current_field_is_not_ccw)
+{
+  igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC> cffs(cffsoldata);
+  cffs.solve(params, current_field, current_field_is_not_ccw);
+};
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template igl::IntegrableFieldSolverData<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<double, -1, -1, 0, -1, -1> >::IntegrableFieldSolverData();
+template void igl::integrable_polyvector_fields_solve<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<double, -1, -1, 0, -1, -1> >(igl::IntegrableFieldSolverData<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<double, -1, -1, 0, -1, -1> >&, igl::integrable_polyvector_fields_parameters&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, bool);
+template void igl::integrable_polyvector_fields_precompute<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<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::IntegrableFieldSolverData<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<double, -1, -1, 0, -1, -1> >&);
+#endif

+ 234 - 0
include/igl/integrable_polyvector_fields.h

@@ -0,0 +1,234 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_INTEGRABLE_POLYVECTOR_FIELDS
+#define IGL_INTEGRABLE_POLYVECTOR_FIELDS
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+namespace igl {
+  // Compute a curl-free frame field from user constraints, optionally starting
+  // from a gived frame field (assumed to be interpolating the constraints).
+  // Implementation of the paper "Integrable PolyVector Fields", SIGGRAPH 2015.
+
+  // Set of parameters used during solve
+  struct integrable_polyvector_fields_parameters;
+
+  // All data necessary for solving. Gets initialized from the original field
+  //  and gets updated during each solve.
+  template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC> class IntegrableFieldSolverData;
+
+
+  // Precomputes matrices and necessary initial variables from the mesh and the
+  // original field. This function is meant to be called before solve().
+  // Inputs:
+  //   V                 #V by 3 list of mesh vertex coordinates
+  //   F                 #F by 3 list of mesh faces (must be triangles)
+  //   b                 #B by 1 list of constrained face indices
+  //   bc                #B by 6 list of the representative vectors at the constrained faces
+  //   constraint_level  #B by 1 list of "constraint level" flag (level=2 indicates that both directions are constrained,
+  //                     level = 1 indicates a partially constrained face, i.e. only the first vector will be constrained)
+  //   original_field    #F by 6 list of the representative vectors of the frame field to be used as a starting point
+  //                     (up to permutation and sign, stacked horizontally for each face)
+  // Returns:
+  //   data              an IntegrableFieldSolverData object that holds all intermediate
+  //                     data needed by the solve routine, with correctly initialized values.
+  //
+  template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+  IGL_INLINE void integrable_polyvector_fields_precompute(const Eigen::PlainObjectBase<DerivedV>& V,
+                                                    const Eigen::PlainObjectBase<DerivedF>& F,
+                                                    const Eigen::VectorXi& b,
+                                                    const Eigen::PlainObjectBase<DerivedC>& bc,
+                                                    const Eigen::VectorXi& constraint_level,
+                                                    const Eigen::PlainObjectBase<DerivedFF>& original_field,
+                                                    igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &data);
+
+
+  // Given the current estimate of the field, performes one round of optimization
+  // iterations and updates the current estimate. The intermediate data is saved
+  // and returned for the next iteration.
+  // Inputs:
+  //   data                         an IntegrableFieldSolverData object that holds all intermediate
+  //                                data needed by the solve routine, with their values at the current time instance.
+  //   params                       solver parameters (see below)
+  //   current_field                #F by 6 list of the representative vectors of the current frame field to be used as a starting point
+  //   current_field_is_not_ccw     boolean, determines whether the representative vectors in the current field are in
+  //                                non- ccw order - if true, they will be corrected before being passed to the solver.
+  //                                The field returned by this routine is always in ccw order, so this flag typically only
+  //                                needs to be set to true during the first call to solve(). If unsure, set to true.
+  // Returns:
+  //   current_field                updated estimate for the integrable field
+  //
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+  IGL_INLINE void integrable_polyvector_fields_solve(IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &cffsoldata,
+    integrable_polyvector_fields_parameters &params,
+                                               Eigen::PlainObjectBase<DerivedFF>& current_field,
+                                               bool current_field_is_not_ccw);
+
+
+};
+
+
+//parameters
+struct igl::integrable_polyvector_fields_parameters
+{
+  // number of optimization iterations
+  int numIter;
+  //weight for barrier term (ensuring ccw ordering of the vectors per face)
+  double wBarrier;
+  //the s-parameter of the barrier term (see Schüller et al. 2013, Locally Injective Mappings)
+  double sBarrier;
+  //weight for the PolyCurl term of the energy
+  double wCurl;
+  //weight for the PolyQuotient term of the energy
+  double wQuotCurl;
+  //weight for the smoothness term of the energy
+  double wSmooth;
+  //weight for the closeness to the original field, for the unconstrained faces (regularization term)
+  double wCloseUnconstrained;
+  //weight for the closeness to the original field, for the constrained faces
+  double wCloseConstrained;
+  //the per-iteration reduction factor the smoothness weight
+  double redFactor_wsmooth;
+  //the step size for the Gauss-Newton optimization
+  double gamma;
+  //tikhonov regularization term (typically not needed, default value should suffice)
+  double tikh_gamma;
+  //boolean, determines whether the frames at the constrained faces should be treated
+  //as partial constraints (i.e. only one of the vectors is preserved in the result)
+  bool do_partial;
+
+  IGL_INLINE integrable_polyvector_fields_parameters();
+
+};
+
+//solver data
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
+class igl::IntegrableFieldSolverData
+{
+public:
+  //Original field
+  Eigen::VectorXd xOriginal;
+
+  //Constraints
+  Eigen::VectorXi constrained;
+  Eigen::VectorXi is_constrained_face;//0 for unconstrained, 1 for constrained once (partial) and 2 for fully constrained
+  Eigen::VectorXi indInConstrained;
+  Eigen::MatrixXd constrained_vec3;
+
+  //Mesh data
+  //edges and normalized edge vectors
+  Eigen::MatrixXd EVecNorm;
+  Eigen::MatrixXi E, E2F, F2E;
+  int numV, numF, numE;
+  //interior edge data
+  int numInteriorEdges;
+  Eigen::Matrix<int,Eigen::Dynamic,2> E2F_int;
+  Eigen::VectorXi indInteriorToFull;
+  Eigen::VectorXi indFullToInterior;
+  //per-edge angles (for parallel transport)
+  Eigen::VectorXd K;
+  //local bases
+  Eigen::PlainObjectBase<DerivedV> B1, B2, FN;
+
+  //Solver Data
+  Eigen::VectorXd residuals;
+  Eigen::SparseMatrix<double> Jac;
+  Eigen::VectorXi II_Jac, JJ_Jac;
+  Eigen::VectorXd SS_Jac;
+  int numVariables;
+  int num_residuals;
+  int num_residuals_smooth;
+  int num_residuals_close;
+  int num_residuals_polycurl;
+  int num_residuals_quotcurl;
+  int num_residuals_barrier;
+  const int numInnerJacCols_edge = 8;
+  const int numInnerJacCols_face = 4;
+  const int numInnerJacRows_smooth = 4;
+  const int numInnerJacRows_polycurl = 2;
+  const int numInnerJacRows_quotcurl = 1;
+  const int numInnerJacRows_barrier = 1;
+  const int numInnerJacRows_close = 4;
+  int numJacElements_smooth;
+  int numJacElements_polycurl;
+  int numJacElements_quotcurl;
+  int numJacElements_barrier;
+  int numJacElements_close;
+  int numJacElements;
+  IGL_INLINE void add_jac_indices_face(const int numInnerRows,
+                                       const int numInnerCols,
+                                       const int startRowInJacobian,
+                                       const int startIndexInVectors,
+                                       Eigen::VectorXi &Rows,
+                                       Eigen::VectorXi &Columns);
+  IGL_INLINE void face_Jacobian_indices(const int &startRow,
+                                        const int &toplace,
+                                        const int& fi,
+                                        const int& half_degree,
+                                        const int &numInnerRows,
+                                        const int &numInnerCols,
+                                        Eigen::VectorXi &rows,
+                                        Eigen::VectorXi &columns);
+  IGL_INLINE void add_Jacobian_to_svector(const int &toplace,
+                                          const Eigen::MatrixXd &tJac,
+                                          Eigen::VectorXd &SS_Jac);
+
+  IGL_INLINE void add_jac_indices_edge(const int numInnerRows,
+                                       const int numInnerCols,
+                                       const int startRowInJacobian,
+                                       const int startIndexInVectors,
+                                       Eigen::VectorXi &Rows,
+                                       Eigen::VectorXi &Columns);
+  IGL_INLINE void edge_Jacobian_indices(const int &startRow,
+                                        const int &toplace,
+                                        const int& a,
+                                        const int& b,
+                                        const int& half_degree,
+                                        const int &numInnerRows,
+                                        const int &numInnerCols,
+                                        Eigen::VectorXi &rows,
+                                        Eigen::VectorXi &columns);
+  std::vector<int> indInSS_Hess_1_vec;
+  std::vector<int> indInSS_Hess_2_vec;
+  Eigen::SparseMatrix<double> Hess;
+  std::vector<Eigen::Triplet<double> > Hess_triplets;
+  Eigen::SimplicialLDLT<Eigen::SparseMatrix<double> > solver;
+
+  IGL_INLINE void precomputeMesh(const Eigen::PlainObjectBase<DerivedV> &_V,
+                                 const Eigen::PlainObjectBase<DerivedF> &_F);
+  IGL_INLINE void computeInteriorEdges();
+  IGL_INLINE void computeJacobianPattern();
+  IGL_INLINE void computeHessianPattern();
+  IGL_INLINE void computeNewHessValues();
+  IGL_INLINE void initializeOriginalVariable(const Eigen::PlainObjectBase<DerivedFF>& original_field);
+  IGL_INLINE void initializeConstraints(const Eigen::VectorXi& b,
+                                        const Eigen::PlainObjectBase<DerivedC>& bc,
+                                        const Eigen::VectorXi& constraint_level);
+  IGL_INLINE void makeFieldCCW(Eigen::MatrixXd &sol3D);
+
+public:
+  IGL_INLINE IntegrableFieldSolverData();
+
+  IGL_INLINE IntegrableFieldSolverData(
+                                     const Eigen::PlainObjectBase<DerivedV> &_V,
+                                     const Eigen::PlainObjectBase<DerivedF> &_F,
+                                     const Eigen::VectorXi& b,
+                                     const Eigen::VectorXi& constraint_level,
+                                     const Eigen::PlainObjectBase<DerivedFF>& original_field);
+
+};
+
+#ifndef IGL_STATIC_LIBRARY
+#include "integrable_polyvector_fields.cpp"
+#endif
+
+
+#endif /* defined(IGL_INTEGRABLE_POLYVECTOR_FIELDS) */

+ 1 - 0
include/igl/jet.cpp

@@ -135,4 +135,5 @@ template void igl::jet<Eigen::Array<double, -1, 1, 0, -1, 1>, Eigen::Matrix<doub
 template void igl::jet<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::jet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::jet<float>(float, float&, float&, float&);
+template void igl::jet<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 1 - 0
include/igl/matlab_format.cpp

@@ -127,4 +127,5 @@ template Eigen::WithFormat<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const igl::matl
 template Eigen::WithFormat<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const igl::matlab_format<Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
 template Eigen::WithFormat<Eigen::Matrix<double, 2, 3, 0, 2, 3> > const igl::matlab_format<Eigen::Matrix<double, 2, 3, 0, 2, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >);
 template Eigen::WithFormat<Eigen::Matrix<double, 3, 2, 0, 3, 2> > const igl::matlab_format<Eigen::Matrix<double, 3, 2, 0, 3, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 2, 0, 3, 2> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const igl::matlab_format<Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >);
 #endif

+ 121 - 0
include/igl/parallel_transport_angles.cpp

@@ -0,0 +1,121 @@
+#include <igl/parallel_transport_angles.h>
+#include <Eigen/Geometry>
+
+template <typename DerivedV, typename DerivedF, typename DerivedK>
+IGL_INLINE void igl::parallel_transport_angles(
+const Eigen::PlainObjectBase<DerivedV>& V,
+const Eigen::PlainObjectBase<DerivedF>& F,
+const Eigen::PlainObjectBase<DerivedV>& FN,
+const Eigen::MatrixXi &E2F,
+const Eigen::MatrixXi &F2E,
+Eigen::PlainObjectBase<DerivedK> &K)
+{
+  int numE = E2F.rows();
+
+  Eigen::VectorXi isBorderEdge;
+  isBorderEdge.setZero(numE,1);
+  for(unsigned i=0; i<numE; ++i)
+  {
+    if ((E2F(i,0) == -1) || ((E2F(i,1) == -1)))
+      isBorderEdge[i] = 1;
+  }
+
+  K.setZero(numE);
+  // For every non-border edge
+  for (unsigned eid=0; eid<numE; ++eid)
+  {
+    if (!isBorderEdge[eid])
+    {
+      int fid0 = E2F(eid,0);
+      int fid1 = E2F(eid,1);
+
+      Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N0 = FN.row(fid0);
+//      Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N1 = FN.row(fid1);
+
+      // find common edge on triangle 0 and 1
+      int fid0_vc = -1;
+      int fid1_vc = -1;
+      for (unsigned i=0;i<3;++i)
+      {
+        if (F2E(fid0,i) == eid)
+          fid0_vc = i;
+        if (F2E(fid1,i) == eid)
+          fid1_vc = i;
+      }
+      assert(fid0_vc != -1);
+      assert(fid1_vc != -1);
+
+      Eigen::Matrix<typename DerivedV::Scalar, 1, 3> common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc));
+      common_edge.normalize();
+
+      // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis
+      Eigen::Matrix<typename DerivedV::Scalar, 3, 3> P;
+      Eigen::Matrix<typename DerivedV::Scalar, 1, 3> o = V.row(F(fid0,fid0_vc));
+      Eigen::Matrix<typename DerivedV::Scalar, 1, 3> tmp = -N0.cross(common_edge);
+      P << common_edge, tmp, N0;
+      //      P.transposeInPlace();
+
+
+      Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V0;
+      V0.row(0) = V.row(F(fid0,0)) -o;
+      V0.row(1) = V.row(F(fid0,1)) -o;
+      V0.row(2) = V.row(F(fid0,2)) -o;
+
+      V0 = (P*V0.transpose()).transpose();
+
+      //      assert(V0(0,2) < 1e-10);
+      //      assert(V0(1,2) < 1e-10);
+      //      assert(V0(2,2) < 1e-10);
+
+      Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V1;
+      V1.row(0) = V.row(F(fid1,0)) -o;
+      V1.row(1) = V.row(F(fid1,1)) -o;
+      V1.row(2) = V.row(F(fid1,2)) -o;
+      V1 = (P*V1.transpose()).transpose();
+
+      //      assert(V1(fid1_vc,2) < 10e-10);
+      //      assert(V1((fid1_vc+1)%3,2) < 10e-10);
+
+      // compute rotation R such that R * N1 = N0
+      // i.e. map both triangles to the same plane
+      double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1));
+
+      Eigen::Matrix<typename DerivedV::Scalar, 3, 3> R;
+      R << 1,          0,            0,
+      0, cos(alpha), -sin(alpha) ,
+      0, sin(alpha),  cos(alpha);
+      V1 = (R*V1.transpose()).transpose();
+
+      //      assert(V1(0,2) < 1e-10);
+      //      assert(V1(1,2) < 1e-10);
+      //      assert(V1(2,2) < 1e-10);
+
+      // measure the angle between the reference frames
+      // k_ij is the angle between the triangle on the left and the one on the right
+      Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref0 = V0.row(1) - V0.row(0);
+      Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref1 = V1.row(1) - V1.row(0);
+
+      ref0.normalize();
+      ref1.normalize();
+
+      double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0));
+
+      // just to be sure, rotate ref0 using angle ktemp...
+      Eigen::Matrix<typename DerivedV::Scalar,2,2> R2;
+      R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp);
+
+//      Eigen::Matrix<typename DerivedV::Scalar, 1, 2> tmp1 = R2*(ref0.head(2)).transpose();
+
+      //      assert(tmp1(0) - ref1(0) < 1e-10);
+      //      assert(tmp1(1) - ref1(1) < 1e-10);
+
+      K[eid] = ktemp;
+    }
+  }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template void igl::parallel_transport_angles<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::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::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif

+ 51 - 0
include/igl/parallel_transport_angles.h

@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_PARALLEL_TRANSPORT_ANGLE
+#define IGL_PARALLEL_TRANSPORT_ANGLE
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl {
+  // Given the per-face local bases computed via igl::local_basis, this function
+  // computes the angle between the two reference frames across each edge.
+  // Any two vectors across the edge whose 2D representation only differs by
+  // this angle are considered to be parallel.
+
+  // Inputs:
+  //   V               #V by 3 list of mesh vertex coordinates
+  //   F               #F by 3 list of mesh faces (must be triangles)
+  //   FN              #F by 3 list of face normals
+  //   E2F             #E by 2 list of the edge-to-face relation (e.g. computed
+  //                   via igl::edge_topology)
+  //   F2E             #F by 3 list of the face-to-edge relation (e.g. computed
+  //                   via igl::edge_topology)
+  // Output:
+  //   K               #E by 1 list of the parallel transport angles (zero
+  //                   for all boundary edges)
+  //
+template <typename DerivedV, typename DerivedF, typename DerivedK>
+IGL_INLINE void parallel_transport_angles(
+const Eigen::PlainObjectBase<DerivedV>&V,
+const Eigen::PlainObjectBase<DerivedF>&F,
+const Eigen::PlainObjectBase<DerivedV>&FN,
+const Eigen::MatrixXi &E2F,
+const Eigen::MatrixXi &F2E,
+Eigen::PlainObjectBase<DerivedK>&K);
+
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "parallel_transport_angles.cpp"
+#endif
+
+
+#endif /* defined(IGL_PARALLEL_TRANSPORT_ANGLE) */

+ 112 - 0
include/igl/polyvector_field_comb_from_matchings_and_cuts.cpp

@@ -0,0 +1,112 @@
+#include <igl/colon.h>
+#include <algorithm>
+#include <deque>
+#include <igl/polyvector_field_comb_from_matchings_and_cuts.h>
+#include <igl/edge_topology.h>
+#include <igl/triangle_triangle_adjacency.h>
+
+template <typename DerivedV, typename DerivedF, typename DerivedTT, typename DerivedS, typename DerivedM, typename DerivedC>
+IGL_INLINE void igl::polyvector_field_comb_from_matchings_and_cuts(
+  const Eigen::PlainObjectBase<DerivedV> &V,
+  const Eigen::PlainObjectBase<DerivedF> &F,
+  const Eigen::PlainObjectBase<DerivedTT> &TT,
+  const Eigen::MatrixXi &E2F,
+  const Eigen::MatrixXi &F2E,
+  const Eigen::PlainObjectBase<DerivedS> &sol3D,
+  const Eigen::PlainObjectBase<DerivedM> &match_ab,
+  const Eigen::PlainObjectBase<DerivedM> &match_ba,
+  const Eigen::PlainObjectBase<DerivedC> &cuts,
+  Eigen::PlainObjectBase<DerivedS> &sol3D_combed)
+{
+
+  int half_degree = sol3D.cols()/3;
+  int full_degree = 2*half_degree;
+
+  Eigen::MatrixXi used; used.setConstant(F.rows(),half_degree,-1);
+
+  //  Eigen::VectorXi mark;
+  std::deque<int> d;
+  sol3D_combed.setZero(sol3D.rows(), sol3D.cols());
+
+  int start = 0;
+  d.push_back(start);
+  used.row(start) = igl::colon<int>(0, half_degree-1);
+  sol3D_combed.row(start) = sol3D.row(start);
+  while (!d.empty())
+  {
+    int f0 = d.at(0);
+    d.pop_front();
+    for (int k=0; k<3; k++)
+    {
+      int f1 = TT(f0,k);
+      if (f1==-1) continue;
+      //do not comb across cuts
+      if ((used.row(f1).array()!=-1).any()||cuts(f0,k))
+        continue;
+
+
+      // look at the edge between the two faces
+      const int &current_edge = F2E(f0,k);
+
+      // check its orientation to determine whether match_ab or match_ba should be used
+      if ((E2F(current_edge,0) == f0) &&
+          (E2F(current_edge,1) == f1) )
+      {
+        //look at match_ab
+        for(int i=0; i<half_degree; ++i)
+        {
+          int ii = used(f0,i);
+          used(f1,i) = (match_ab(current_edge,ii%half_degree) + (ii>=half_degree)*half_degree)%full_degree;
+        }
+      }
+      else
+      {
+        assert((E2Fcut(current_edge,1) == f0) &&
+               (E2Fcut(current_edge,0) == f1));
+        //look at match_ba
+        for(int i=0; i<half_degree; ++i)
+        {
+          int ii = used(f0,i);
+          used(f1,i) = (match_ba(current_edge,ii%half_degree)+ (ii>=half_degree)*half_degree)%full_degree;
+        }
+      }
+
+      for (int i = 0; i<half_degree; ++i)
+      {
+        int sign = (used(f1,i)<half_degree)?1:-1;
+        sol3D_combed.block(f1,i*3,1,3) = sign*sol3D.block(f1,(used(f1,i)%half_degree)*3,1,3);
+      }
+      d.push_back(f1);
+    }
+  }
+
+  // everything should be marked
+  assert((used.rowwise().minCoeff().array()>=0).all());
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedS, typename DerivedM, typename DerivedC>
+IGL_INLINE void igl::polyvector_field_comb_from_matchings_and_cuts(
+  const Eigen::PlainObjectBase<DerivedV> &V,
+  const Eigen::PlainObjectBase<DerivedF> &F,
+  const Eigen::PlainObjectBase<DerivedS> &sol3D,
+  const Eigen::PlainObjectBase<DerivedM> &match_ab,
+  const Eigen::PlainObjectBase<DerivedM> &match_ba,
+  const Eigen::PlainObjectBase<DerivedC> &cuts,
+  Eigen::PlainObjectBase<DerivedS> &sol3D_combed)
+  {
+    Eigen::MatrixXi TT, TTi;
+    igl::triangle_triangle_adjacency(V,F,TT,TTi);
+
+    Eigen::MatrixXi E, E2F, F2E;
+    igl::edge_topology(V,F,E,F2E,E2F);
+
+    igl::polyvector_field_comb_from_matchings_and_cuts(V, F, TT, E2F, F2E, sol3D, match_ab, match_ba, cuts, sol3D_combed);
+  }
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template void igl::polyvector_field_comb_from_matchings_and_cuts<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -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>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(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<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, 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&, Eigen::PlainObjectBase<Eigen::Matrix<int, -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> >&);
+template void igl::polyvector_field_comb_from_matchings_and_cuts<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>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(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&, Eigen::PlainObjectBase<Eigen::Matrix<int, -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> >&);
+#endif

+ 78 - 0
include/igl/polyvector_field_comb_from_matchings_and_cuts.h

@@ -0,0 +1,78 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_POLYVECTOR_FIELD_COMB_FROM_MATCHINGS_AND_CUTS
+#define IGL_POLYVECTOR_FIELD_COMB_FROM_MATCHINGS_AND_CUTS
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl {
+  // Given an mesh, an N- polyvector field with given matchings between
+  // the vector sets across interior edges, and corresponding mesh cuts,
+  // compute a "combed" polyvector field, i.e.
+  // separate the vector set field into N vector fields, where the separation is defined
+  // by the matchings. The cuts have previously been generated based on the field
+  // singularities, see igl::polyvector_field_cut_mesh_with_singularities.
+  // Inputs:
+  //   V                #V by 3 list of the vertex positions
+  //   F                #F by 3 list of the faces (must be triangles)
+  //   TT               #F by 3 triangle to triangle adjacent matrix (e.g. computed
+  //                    via igl:triangle_triangle_adjacency).
+  //   E2F              #E by 2 list of the edge-to-face relation (e.g. computed
+  //                    via igl::edge_topology)
+  //   F2E              #F by 3 list of the face-to-edge relation (e.g. computed
+  //                    via igl::edge_topology)
+  //   sol3D            #F by 3n list of the 3D coordinates of the per-face vectors of the input vector set field
+  //                    (stacked horizontally for each triangle). Vector #1 in one face does not necessarily match
+  //                    vector #1 in the adjacent face.
+  //   match_ab         #E by N matrix, describing for each edge the matching a->b, where a
+  //                    and b are the faces adjacent to the edge (i.e. vector #i of
+  //                    the vector set in a is matched to vector #mab[i] in b)
+  //   match_ba         #E by N matrix, describing for each edge the matching b->a, where a
+  //                    and b are the faces adjacent to the edge (i.e. vector #mba[i] of
+  //                    the vector set in a is matched to vector #i in b)
+  //   cuts             #F by 3 list of boolean flags, indicating the edges that need to be cut
+  // Outputs:
+  //   sol3D_combed     #F by 3n list of the 3D coordinates of the per-face vectors of the combed vector set field
+  //                    (stacked horizontally for each triangle). Vector #1 in one face will match vector #1 in
+  //                    the adjacent face.
+  //
+  template <typename DerivedV, typename DerivedF, typename DerivedTT, typename DerivedS, typename DerivedM, typename DerivedC>
+  IGL_INLINE void polyvector_field_comb_from_matchings_and_cuts(
+                                                                const Eigen::PlainObjectBase<DerivedV> &V,
+                                                                const Eigen::PlainObjectBase<DerivedF> &F,
+                                                                const Eigen::PlainObjectBase<DerivedTT> &TT,
+                                                                const Eigen::MatrixXi &E2F,
+                                                                const Eigen::MatrixXi &F2E,
+                                                                const Eigen::PlainObjectBase<DerivedS> &sol3D,
+                                                                const Eigen::PlainObjectBase<DerivedM> &match_ab,
+                                                                const Eigen::PlainObjectBase<DerivedM> &match_ba,
+                                                                const Eigen::PlainObjectBase<DerivedC> &cuts,
+                                                                Eigen::PlainObjectBase<DerivedS> &sol3D_combed);
+  
+  //Wrapper with only the mesh as input
+  template <typename DerivedV, typename DerivedF, typename DerivedS, typename DerivedM, typename DerivedC>
+  IGL_INLINE void polyvector_field_comb_from_matchings_and_cuts(
+                                                                const Eigen::PlainObjectBase<DerivedV> &V,
+                                                                const Eigen::PlainObjectBase<DerivedF> &F,
+                                                                const Eigen::PlainObjectBase<DerivedS> &sol3D,
+                                                                const Eigen::PlainObjectBase<DerivedM> &match_ab,
+                                                                const Eigen::PlainObjectBase<DerivedM> &match_ba,
+                                                                const Eigen::PlainObjectBase<DerivedC> &cuts,
+                                                                Eigen::PlainObjectBase<DerivedS> &sol3D_combed);
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "polyvector_field_comb_from_matchings_and_cuts.cpp"
+#endif
+
+
+#endif /* defined(IGL_POLYVECTOR_FIELD_COMB_FROM_MATCHINGS_AND_CUTS) */

+ 105 - 0
include/igl/polyvector_field_cut_mesh_with_singularities.cpp

@@ -0,0 +1,105 @@
+#include <igl/polyvector_field_cut_mesh_with_singularities.h>
+#include <igl/dijkstra.h>
+#include <igl/vertex_triangle_adjacency.h>
+#include <igl/adjacency_list.h>
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/is_border_vertex.h>
+#include <igl/cut_mesh_from_singularities.h>
+#include <set>
+
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename VVType, typename DerivedTT, typename DerivedC, typename DerivedS>
+IGL_INLINE void igl::polyvector_field_cut_mesh_with_singularities(
+                                                                  const Eigen::PlainObjectBase<DerivedV> &V,
+                                                                  const Eigen::PlainObjectBase<DerivedF> &F,
+                                                                  const std::vector<std::vector<VFType> >& VF,
+                                                                  const std::vector<std::vector<VVType> >& VV,
+                                                                  const Eigen::PlainObjectBase<DerivedTT>& TT,
+                                                                  const Eigen::PlainObjectBase<DerivedTT>& TTi,
+                                                                  const Eigen::PlainObjectBase<DerivedS> &singularities,
+                                                                  Eigen::PlainObjectBase<DerivedC> &cuts)
+{
+
+  //first, get a spanning tree for the mesh (no missmatch needed)
+  igl::cut_mesh_from_singularities(V, F, Eigen::MatrixXd::Zero(F.rows(), 3).eval(), cuts);
+
+  std::set<int> vertices_in_cut;
+  for (int i =0; i< cuts.rows(); ++i)
+    for (int j =0;j< cuts.cols(); ++j)
+      if (cuts(i,j))
+        vertices_in_cut.insert(F(i,j));
+
+  //then, add all singularities one by one by using Dijkstra's algorithm
+  for (int i = 0; i<singularities.rows(); ++i)
+  {
+    std::vector<int> path;
+    Eigen::VectorXd min_distance;
+    Eigen::VectorXi previous;
+    int vertex_found = igl::dijkstra_compute_paths(singularities[i], vertices_in_cut, VV, min_distance, previous);
+    if(vertex_found ==-1)
+      // this means that there are no cuts
+      path.push_back(singularities[i]);
+    else
+      igl::dijkstra_get_shortest_path_to(vertex_found, previous, path);
+
+    vertices_in_cut.insert(path.begin(), path.end());
+
+    //insert to cut
+    for (int ii = 0; ii<path.size()-1; ++ii)
+    {
+      const int &v0 = path[ii];
+      const int &v1 = path[ii+1];
+
+      std::vector<int> vf0 = VF[v0];
+      std::sort(vf0.begin(), vf0.end());
+      std::vector<int> vf1 = VF[v1];
+      std::sort(vf1.begin(), vf1.end());
+      std::vector<int> common_face_v(std::max(vf0.size(),vf1.size()));
+      std::vector<int>::iterator it;
+      it=std::set_intersection (vf0.begin(), vf0.end(), vf1.begin(), vf1.end(), common_face_v.begin());
+      common_face_v.resize(it-common_face_v.begin());
+      assert(common_face_v.size() == 2);
+
+      const int &fi = common_face_v[0];
+      int j=-1;
+      for (unsigned z=0; z<3; ++z)
+        if (((F(fi,z) == v0) && (F(fi,(z+1)%3) == v1)) ||((F(fi,z) == v1) && (F(fi,(z+1)%3) == v0)))
+          j=z;
+      assert(j!=-1);
+      cuts(fi,j) = 1;
+      cuts(TT(fi,j), TTi(fi,j)) = 1;
+
+    }
+  }
+
+}
+
+
+//Wrapper of the above with only vertices and faces as mesh input
+template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedS>
+IGL_INLINE void igl::polyvector_field_cut_mesh_with_singularities(
+                                                                  const Eigen::PlainObjectBase<DerivedV> &V,
+                                                                  const Eigen::PlainObjectBase<DerivedF> &F,
+                                                                  const Eigen::PlainObjectBase<DerivedS> &singularities,
+                                                                  Eigen::PlainObjectBase<DerivedC> &cuts)
+{
+
+  std::vector<std::vector<int> > VF, VFi;
+  igl::vertex_triangle_adjacency(V,F,VF,VFi);
+
+  std::vector<std::vector<int> > VV;
+  igl::adjacency_list(F, VV);
+
+  Eigen::MatrixXi TT, TTi;
+  igl::triangle_triangle_adjacency(V,F,TT,TTi);
+
+  igl::polyvector_field_cut_mesh_with_singularities(V, F, VF, VV, TT, TTi, singularities, cuts);
+
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template void igl::polyvector_field_cut_mesh_with_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > > const&, std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::polyvector_field_cut_mesh_with_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(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<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif

+ 66 - 0
include/igl/polyvector_field_cut_mesh_with_singularities.h

@@ -0,0 +1,66 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_POLYVECTOR_FIELD_CUT_MESH_WITH_SINGULARITIES
+#define IGL_POLYVECTOR_FIELD_CUT_MESH_WITH_SINGULARITIES
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl {
+  // Given a mesh and the singularities of a polyvector field, cut the mesh
+  // to disk topology in such a way that the singularities lie at the boundary of
+  // the disk, as described in the paper "Mixed Integer Quadrangulation" by
+  // Bommes et al. 2009.
+  // Inputs:
+  //   V                #V by 3 list of the vertex positions
+  //   F                #F by 3 list of the faces (must be triangles)
+  //   VF               #V list of lists of incident faces (adjacency list), e.g.
+  //                    as returned by igl::vertex_triangle_adjacency
+  //   VV               #V list of lists of incident vertices (adjacency list), e.g.
+  //                    as returned by igl::adjacency_list
+  //   TT               #F by 3 triangle to triangle adjacent matrix (e.g. computed
+  //                    via igl:triangle_triangle_adjacency)
+  //   TTi              #F by 3 adjacent matrix, the element i,j is the id of edge of the
+  //                    triangle TT(i,j) that is adjacent with triangle i (e.g. computed
+  //                    via igl:triangle_triangle_adjacency)
+  //   singularities    #S by 1 list of the indices of the singular vertices
+  // Outputs:
+  //   cuts             #F by 3 list of boolean flags, indicating the edges that need to be cut
+  //                    (has 1 at the face edges that are to be cut, 0 otherwise)
+  //
+  template <typename DerivedV, typename DerivedF, typename VFType, typename VVType, typename DerivedTT, typename DerivedC, typename DerivedS>
+  IGL_INLINE void polyvector_field_cut_mesh_with_singularities(
+                                                               const Eigen::PlainObjectBase<DerivedV> &V,
+                                                               const Eigen::PlainObjectBase<DerivedF> &F,
+                                                               const std::vector<std::vector<VFType> >& VF,
+                                                               const std::vector<std::vector<VVType> >& VV,
+                                                               const Eigen::PlainObjectBase<DerivedTT>& TT,
+                                                               const Eigen::PlainObjectBase<DerivedTT>& TTi,
+                                                               const Eigen::PlainObjectBase<DerivedS> &singularities,
+                                                               Eigen::PlainObjectBase<DerivedC> &cuts);
+  
+  
+  //Wrapper of the above with only vertices and faces as mesh input
+  template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedS>
+  IGL_INLINE void polyvector_field_cut_mesh_with_singularities(
+                                                               const Eigen::PlainObjectBase<DerivedV> &V,
+                                                               const Eigen::PlainObjectBase<DerivedF> &F,
+                                                               const Eigen::PlainObjectBase<DerivedS> &singularities,
+                                                               Eigen::PlainObjectBase<DerivedC> &cuts);
+  
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "polyvector_field_cut_mesh_with_singularities.cpp"
+#endif
+
+
+#endif /* defined(IGL_POLYVECTOR_FIELD_CUT_MESH_WITH_SINGULARITIES) */

+ 180 - 0
include/igl/polyvector_field_matchings.cpp

@@ -0,0 +1,180 @@
+#include <igl/polyvector_field_matchings.h>
+#include <igl/edge_topology.h>
+#include <igl/per_face_normals.h>
+#include <igl/sort_vectors_ccw.h>
+#include <igl/rotation_matrix_from_directions.h>
+
+template <typename DerivedS, typename DerivedV, typename DerivedM>
+IGL_INLINE void igl::polyvector_field_matching(
+                                               const Eigen::PlainObjectBase<DerivedS>& _ua,
+                                               const Eigen::PlainObjectBase<DerivedS>& _ub,
+                                               const Eigen::PlainObjectBase<DerivedV>& na,
+                                               const Eigen::PlainObjectBase<DerivedV>& nb,
+                                               const Eigen::PlainObjectBase<DerivedV>& e,
+                                               bool match_with_curl,
+                                               Eigen::PlainObjectBase<DerivedM>& mab,
+                                               Eigen::PlainObjectBase<DerivedM>& mba)
+{
+  // make sure the matching preserve ccw order of the vectors across the edge
+  // 1) order vectors in a, ccw  e.g. (0,1,2,3)_a not ccw --> (0,3,2,1)_a ccw
+  // 2) order vectors in b, ccw  e.g. (0,1,2,3)_b not ccw --> (0,2,1,3)_b ccw
+  // 3) the vectors in b that match the ordered vectors in a (in this case  (0,3,2,1)_a ) must be a circular shift of the ccw ordered vectors in b  - so we need to explicitely check only these matchings to find the best ccw one, there are N of them
+  int hN = _ua.cols()/3;
+  int N = 2*hN;
+  Eigen::Matrix<typename DerivedS::Scalar,1,Eigen::Dynamic> ua (1,N*3); ua <<_ua, -_ua;
+  Eigen::Matrix<typename DerivedS::Scalar,1,Eigen::Dynamic> ub (1,N*3); ub <<_ub, -_ub;
+  Eigen::Matrix<typename DerivedM::Scalar,Eigen::Dynamic,1> order_a, order_b;
+  igl::sort_vectors_ccw(ua, na, order_a);
+  igl::sort_vectors_ccw(ub, nb, order_b);
+
+  //checking all possible circshifts of order_b as matches for order_a
+  Eigen::Matrix<typename DerivedM::Scalar,Eigen::Dynamic,Eigen::Dynamic> all_matches(N,N);
+  Eigen::Matrix<typename DerivedS::Scalar,1,Eigen::Dynamic> all_scores(1,N);
+  for (int s =0; s< N; ++s)
+  {
+    all_matches.row(s) = order_b;
+    typename DerivedS::Scalar current_score=0;
+    for (int i=0; i< N; ++i)
+    {
+      if (match_with_curl)
+        current_score += fabs(ua.segment(order_a[i]*3, 3).dot(e) - ub.segment(order_b[i]*3, 3).dot(e));
+      else
+      {
+        Eigen::Matrix<typename DerivedS::Scalar,3,1> na_ = na.transpose();
+        Eigen::Matrix<typename DerivedS::Scalar,3,1> nb_ = nb.transpose();
+
+        Eigen::Matrix<typename DerivedS::Scalar,1,3> uaRot = igl::rotation_matrix_from_directions(na_, nb_)*ua.segment(order_a[i]*3, 3).transpose();
+        current_score += (uaRot-ub.segment(order_b[i]*3, 3)).norm();
+      }
+    }
+    all_scores[s] = current_score;
+    // do a circshift on order_b to check the next preserving matching
+    int temp = order_b[0];
+    for (int i =0; i< N-1; ++i)
+      order_b[i] = order_b[i+1];
+    order_b(N-1) = temp;
+  }
+  Eigen::Matrix<typename DerivedM::Scalar,1,Eigen::Dynamic> best_matching_for_sorted_a;
+  int best_i;
+  all_scores.minCoeff(&best_i);
+  best_matching_for_sorted_a = all_matches.row(best_i);
+  // best_matching_for_sorted_a is the matching for the sorted vectors in a
+  // get the matching for the initial (unsorted) vectors
+  mab.resize(1,N);
+  for (int i=0; i< N; ++i)
+    mab[order_a[i]] = best_matching_for_sorted_a[i];
+
+  //mab contains the best matching a->b, get the opposite too
+  mba.resize(1, N);
+  for (int i=0; i< N; ++i)
+    mba[mab[i]] = i;
+
+  mab = mab.head(hN);
+  mba = mba.head(hN);
+
+}
+
+
+template <typename DerivedS, typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedM, typename DerivedC>
+IGL_INLINE typename DerivedC::Scalar igl::polyvector_field_matchings(
+                                                                     const Eigen::PlainObjectBase<DerivedS>& sol3D,
+                                                                     const Eigen::PlainObjectBase<DerivedV>&V,
+                                                                     const Eigen::PlainObjectBase<DerivedF>&F,
+                                                                     const Eigen::PlainObjectBase<DerivedE>&E,
+                                                                     const Eigen::PlainObjectBase<DerivedV>& FN,
+                                                                     const Eigen::MatrixXi &E2F,
+                                                                     bool match_with_curl,
+                                                                     Eigen::PlainObjectBase<DerivedM>& match_ab,
+                                                                     Eigen::PlainObjectBase<DerivedM>& match_ba,
+                                                                     Eigen::PlainObjectBase<DerivedC>& curl)
+{
+  int numEdges = E.rows();
+  int half_degree = sol3D.cols()/3;
+
+  Eigen::VectorXi isBorderEdge;
+  isBorderEdge.setZero(numEdges,1);
+  for(unsigned i=0; i<numEdges; ++i)
+  {
+    if ((E2F(i,0) == -1) || ((E2F(i,1) == -1)))
+      isBorderEdge[i] = 1;
+  }
+
+  curl.setZero(numEdges,1);
+  match_ab.setZero(numEdges, half_degree);
+  match_ba.setZero(numEdges, half_degree);
+
+  typename DerivedC::Scalar meanCurl = 0;
+  for (int ei=0; ei<numEdges; ++ei)
+  {
+    if (isBorderEdge[ei])
+      continue;
+    // the two faces of the flap
+    int a = E2F(ei,0);
+    int b = E2F(ei,1);
+
+    Eigen::Matrix<typename DerivedV::Scalar, 1, Eigen::Dynamic> ce = (V.row(E(ei,1))-V.row(E(ei,0))).normalized().template cast<typename DerivedV::Scalar>();
+
+    Eigen::Matrix<typename DerivedM::Scalar, 1, Eigen::Dynamic> mab, mba;
+    igl::polyvector_field_matching(sol3D.row(a).eval(),
+                                   sol3D.row(b).eval(),
+                                   FN.row(a).eval(),
+                                   FN.row(b).eval(),
+                                   ce,
+                                   match_with_curl,
+                                   mab,
+                                   mba);
+
+    match_ab.row(ei) = mab;
+    match_ba.row(ei) = mba;
+    Eigen::Matrix<typename DerivedS::Scalar, 1, Eigen::Dynamic> matched;
+    matched.resize(1, 3*half_degree);
+    for (int i = 0; i<half_degree; ++i)
+    {
+      int sign = (mab[i]<half_degree)?1:-1;
+      matched.segment(i*3, 3) = sign*sol3D.row(b).segment((mab[i]%half_degree)*3, 3);
+    }
+
+    typename DerivedC::Scalar avgCurl = 0;
+    for (int i = 0; i<half_degree; ++i)
+      avgCurl += fabs(sol3D.row(a).segment(i*3, 3).dot(ce) - matched.segment(i*3, 3).dot(ce));
+
+    avgCurl = avgCurl/half_degree;
+
+
+    curl[ ei ] = avgCurl;
+
+    meanCurl+= avgCurl;
+
+  }
+
+  meanCurl /= 1.*(numEdges - isBorderEdge.sum());
+  return meanCurl;
+}
+
+
+
+template <typename DerivedS, typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedC>
+IGL_INLINE typename DerivedC::Scalar igl::polyvector_field_matchings(
+                                                                     const Eigen::PlainObjectBase<DerivedS>& sol3D,
+                                                                     const Eigen::PlainObjectBase<DerivedV>&V,
+                                                                     const Eigen::PlainObjectBase<DerivedF>&F,
+                                                                     bool match_with_curl,
+                                                                     Eigen::PlainObjectBase<DerivedM>& match_ab,
+                                                                     Eigen::PlainObjectBase<DerivedM>& match_ba,
+                                                                     Eigen::PlainObjectBase<DerivedC>& curl)
+{
+  Eigen::MatrixXi E, E2F, F2E;
+  igl::edge_topology(V,F,E,F2E,E2F);
+
+  Eigen::PlainObjectBase<DerivedV> FN;
+  igl::per_face_normals(V,F,FN);
+
+  return igl::polyvector_field_matchings(sol3D, V, F, E, FN, E2F, match_with_curl, match_ab, match_ba, curl);
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template Eigen::Matrix<float, -1, 1, 0, -1, 1>::Scalar igl::polyvector_field_matchings<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -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&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+template Eigen::Matrix<double, -1, 1, 0, -1, 1>::Scalar igl::polyvector_field_matchings<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -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&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif

+ 105 - 0
include/igl/polyvector_field_matchings.h

@@ -0,0 +1,105 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_POLYVECTOR_FIELD_MATCHINGS
+#define IGL_POLYVECTOR_FIELD_MATCHINGS
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl {
+  // Given a pair of adjacent faces a and b, and a set of N unordered vectors
+  // of a vector set defined on each face, the function computes the best order-preserving
+  // matching between them, where "best" means "minimum curl", or "smoothest".
+  // Inputs:
+  //   _ua              1 by 3N row vector of the vectors on face a, stacked horizontally
+  //   _ub              1 by 3N row vector of the vectors on face b, stacked horizontally
+  //   na               1 by 3, normal of face a
+  //   nb               1 by 3, normal of face b
+  //   e                1 by 3, the vector corresponding to the shared edge between a and b
+  //   match_with_curl  boolean flag, determines whether a curl or a smoothness matching will
+  //                    be computed
+  // Outputs:
+  //   mab              1 by N row vector, describing the matching a->b (i.e. vector #i of the
+  //                    vector set in a is matched to vector #mab[i] in b)
+  //   mba              1 by N row vector, describing the matching b->a (i.e. vector #mba[i]
+  //                    of the vector set in a is matched to vector #i in b)
+  //
+  template <typename DerivedS, typename DerivedV, typename DerivedM>
+  IGL_INLINE void polyvector_field_matching(
+                                            const Eigen::PlainObjectBase<DerivedS>& _ua,
+                                            const Eigen::PlainObjectBase<DerivedS>& _ub,
+                                            const Eigen::PlainObjectBase<DerivedV>& na,
+                                            const Eigen::PlainObjectBase<DerivedV>& nb,
+                                            const Eigen::PlainObjectBase<DerivedV>& e,
+                                            bool match_with_curl,
+                                            Eigen::PlainObjectBase<DerivedM>& mab,
+                                            Eigen::PlainObjectBase<DerivedM>& mba);
+
+
+  // Given a mesh and a vector set field consisting of unordered N-vector sets defined
+  // on the faces of the mesh, the function computes, for each (non-boundary) edge
+  // the best order-preserving matching between the vector sets of the faces across
+  // the edge, where "best" means to "with minimum curl", or "smoothest"
+  // Inputs:
+  //   sol3D            #F by 3n list of the 3D coordinates of the per-face vectors
+  //                    (stacked horizontally for each triangle)
+  //   V                #V by 3 list of mesh vertex coordinates
+  //   F                #F by 3 list of mesh faces
+  //   E                #E by 2 list of mesh edges (pairs of vertex indices)
+  //   FN               #F by 3 list of face normals
+  //   E2F              #E by 2 list of the edge-to-face relation (e.g. computed
+  //                    via igl::edge_topology)
+  //   match_with_curl  boolean flag, determines whether curl or smoothness matchings will
+  //                    be computed
+  // Outputs:
+  //   match_ab         #E by N matrix, describing for each edge the matching a->b, where a
+  //                    and b are the faces adjacent to the edge (i.e. vector #i of
+  //                    the vector set in a is matched to vector #mab[i] in b)
+  //   match_ba         #E by N matrix, describing for each edge the matching b->a, where a
+  //                    and b are the faces adjacent to the edge (i.e. vector #mba[i] of
+  //                    the vector set in a is matched to vector #i in b)
+  //   curl             the per-edge curl of the matchings (zero for boundary edges)
+  // Returns:
+  //   meanCurl         the average of the per-edge curl values (only non-boundary edges are counted)
+  //
+  template <typename DerivedS, typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedM, typename DerivedC>
+  IGL_INLINE typename DerivedC::Scalar polyvector_field_matchings(
+                                                                  const Eigen::PlainObjectBase<DerivedS>& sol3D,
+                                                                  const Eigen::PlainObjectBase<DerivedV>&V,
+                                                                  const Eigen::PlainObjectBase<DerivedF>&F,
+                                                                  const Eigen::PlainObjectBase<DerivedE>&E,
+                                                                  const Eigen::PlainObjectBase<DerivedV>& FN,
+                                                                  const Eigen::MatrixXi &E2F,
+                                                                  bool match_with_curl,
+                                                                  Eigen::PlainObjectBase<DerivedM>& match_ab,
+                                                                  Eigen::PlainObjectBase<DerivedM>& match_ba,
+                                                                  Eigen::PlainObjectBase<DerivedC>& curl);
+
+
+  //Wrapper of the above with only vertices and faces as mesh input
+  template <typename DerivedS, typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedC>
+  IGL_INLINE typename DerivedC::Scalar polyvector_field_matchings(
+                                                                  const Eigen::PlainObjectBase<DerivedS>& sol3D,
+                                                                  const Eigen::PlainObjectBase<DerivedV>&V,
+                                                                  const Eigen::PlainObjectBase<DerivedF>&F,
+                                                                  bool match_with_curl,
+                                                                  Eigen::PlainObjectBase<DerivedM>& match_ab,
+                                                                  Eigen::PlainObjectBase<DerivedM>& match_ba,
+                                                                  Eigen::PlainObjectBase<DerivedC>& curl);
+
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "polyvector_field_matchings.cpp"
+#endif
+
+
+#endif /* defined(IGL_POLYVECTOR_FIELD_MATCHINGS) */

+ 97 - 0
include/igl/polyvector_field_poisson_reconstruction.cpp

@@ -0,0 +1,97 @@
+#include <igl/polyvector_field_poisson_reconstruction.h>
+#include <igl/grad.h>
+#include <igl/doublearea.h>
+#include <igl/sparse.h>
+#include <igl/repdiag.h>
+#include <igl/slice.h>
+#include <igl/slice_into.h>
+#include <igl/colon.h>
+
+#include <Eigen/Sparse>
+
+template <typename DerivedV, typename DerivedF, typename DerivedSF, typename DerivedS, typename DerivedE>
+IGL_INLINE double igl::polyvector_field_poisson_reconstruction(
+  const Eigen::PlainObjectBase<DerivedV> &Vcut,
+  const Eigen::PlainObjectBase<DerivedF> &Fcut,
+  const Eigen::PlainObjectBase<DerivedS> &sol3D_combed,
+  Eigen::PlainObjectBase<DerivedSF> &scalars,
+  Eigen::PlainObjectBase<DerivedS> &sol3D_recon,
+  Eigen::PlainObjectBase<DerivedE> &max_error )
+  {
+    Eigen::SparseMatrix<typename DerivedV::Scalar> gradMatrix;
+    igl::grad(Vcut, Fcut, gradMatrix);
+
+    Eigen::VectorXd FAreas;
+    igl::doublearea(Vcut, Fcut, FAreas);
+    FAreas = FAreas.array() * .5;
+
+    int nf = FAreas.rows();
+    Eigen::SparseMatrix<typename DerivedV::Scalar> M,M1;
+    Eigen::VectorXi II = igl::colon<int>(0, nf-1);
+
+    igl::sparse(II, II, FAreas, M1);
+    igl::repdiag(M1, 3, M) ;
+
+    int half_degree = sol3D_combed.cols()/3;
+
+    sol3D_recon.setZero(sol3D_combed.rows(),sol3D_combed.cols());
+
+    int numF = Fcut.rows();
+    scalars.setZero(Vcut.rows(),half_degree);
+
+    Eigen::SparseMatrix<typename DerivedV::Scalar> Q = gradMatrix.transpose()* M *gradMatrix;
+
+    //fix one point at Ik=fix, value at fixed xk=0
+    int fix = 0;
+    Eigen::VectorXi Ik(1);Ik<<fix;
+    Eigen::VectorXd xk(1);xk<<0;
+
+    //unknown indices
+    Eigen::VectorXi Iu(Vcut.rows()-1,1);
+    Iu<<igl::colon<int>(0, fix-1),  igl::colon<int>(fix+1,Vcut.rows()-1);
+
+    Eigen::SparseMatrix<typename DerivedV::Scalar> Quu, Quk;
+    igl::slice(Q, Iu, Iu, Quu);
+    igl::slice(Q, Iu, Ik, Quk);
+    Eigen::SimplicialLDLT<Eigen::SparseMatrix<typename DerivedV::Scalar> > solver;
+    solver.compute(Quu);
+
+
+    Eigen::VectorXd vec; vec.setZero(3*numF,1);
+    for (int i =0; i<half_degree; ++i)
+    {
+      vec<<sol3D_combed.col(i*3+0),sol3D_combed.col(i*3+1),sol3D_combed.col(i*3+2);
+      Eigen::VectorXd b = gradMatrix.transpose()* M * vec;
+      Eigen::VectorXd bu = igl::slice(b, Iu);
+
+      Eigen::VectorXd rhs = bu-Quk*xk;
+      Eigen::MatrixXd yu = solver.solve(rhs);
+
+      Eigen::VectorXi index = i*Eigen::VectorXi::Ones(Iu.rows(),1);
+      igl::slice_into(yu, Iu, index, scalars);scalars(Ik[0],i)=xk[0];
+    }
+
+    //    evaluate gradient of found scalar function
+    for (int i =0; i<half_degree; ++i)
+    {
+      Eigen::VectorXd vec_poisson = gradMatrix*scalars.col(i);
+      sol3D_recon.col(i*3+0) = vec_poisson.segment(0*numF, numF);
+      sol3D_recon.col(i*3+1) = vec_poisson.segment(1*numF, numF);
+      sol3D_recon.col(i*3+2) = vec_poisson.segment(2*numF, numF);
+    }
+
+    max_error.setZero(numF,1);
+    for (int i =0; i<half_degree; ++i)
+    {
+      Eigen::VectorXd diff = (sol3D_recon.block(0, i*3, numF, 3)-sol3D_combed.block(0, i*3, numF, 3)).rowwise().norm();
+      diff = diff.array() / sol3D_combed.block(0, i*3, numF, 3).rowwise().norm().array();
+      max_error = max_error.cwiseMax(diff.cast<typename DerivedE::Scalar>());
+    }
+
+    return max_error.mean();
+  }
+
+  #ifdef IGL_STATIC_LIBRARY
+  // Explicit template specialization
+  template double igl::polyvector_field_poisson_reconstruction<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<double, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(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<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+  #endif

+ 54 - 0
include/igl/polyvector_field_poisson_reconstruction.h

@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_POLYVECTOR_FIELD_POISSON_RECONSTRUCTION
+#define IGL_POLYVECTOR_FIELD_POISSON_RECONSTRUCTION
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl {
+  // Poisson integration on a combed n-polyvector field, defined on a cut mesh.
+  // The function finds n new integrable vector fields that are as close as possible to the
+  // N-vector fields of the original combed polyvector field. Integrable means
+  // that the vector fields are gradients of scalar functions. The deviation from the input
+  // field measures how much the input field deviates from integrability.
+  // Inputs:
+  //   Vcut             #V by 3 list of the vertex positions
+  //   Fcut             #F by 3 list of the faces (must be triangles)
+  //   sol3D_combed     #F by 3n list of the 3D coordinates of the per-face vectors of the combed vector set field
+  //                    (stacked horizontally for each triangle). Vector #1 in one face will match vector #1 in
+  //                    the adjacent face.
+  // Outputs:
+  //   scalars          #V by n list of the per-vertex scalar functions of which the input field
+  //                    is approximately the gradients
+  //   sol3D_recon      #F by 3n list of the 3D coordinates of the per-face vectors of the reconstructed
+  //                    vector set fields (stacked horizontally for each triangle). The fields are the
+  //                    gradients of the scalar functions sF.
+  //   max_error        #V by 1 list of the maximal (across the n vector fields) reconstruction error.
+  //
+  template <typename DerivedV, typename DerivedF, typename DerivedSF, typename DerivedS, typename DerivedE>
+  IGL_INLINE double polyvector_field_poisson_reconstruction(
+                                                            const Eigen::PlainObjectBase<DerivedV> &Vcut,
+                                                            const Eigen::PlainObjectBase<DerivedF> &Fcut,
+                                                            const Eigen::PlainObjectBase<DerivedS> &sol3D_combed,
+                                                            Eigen::PlainObjectBase<DerivedSF> &scalars,
+                                                            Eigen::PlainObjectBase<DerivedS> &sol3D_recon,
+                                                            Eigen::PlainObjectBase<DerivedE> &max_error );
+
+
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "polyvector_field_poisson_reconstruction.cpp"
+#endif
+
+
+#endif /* defined(IGL_POLYVECTOR_FIELD_POISSON_RECONSTRUCTION) */

+ 136 - 0
include/igl/polyvector_field_singularities_from_matchings.cpp

@@ -0,0 +1,136 @@
+#include <igl/polyvector_field_singularities_from_matchings.h>
+#include <igl/is_border_vertex.h>
+#include <igl/vertex_triangle_adjacency.h>
+#include <igl/list_to_matrix.h>
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/edge_topology.h>
+
+template <typename DerivedV, typename DerivedF, typename DerivedM, typename VFType, typename DerivedTT>
+void igl::polyvector_field_one_ring_matchings(const Eigen::PlainObjectBase<DerivedV> &V,
+                                              const Eigen::PlainObjectBase<DerivedF> &F,
+                                              const std::vector<std::vector<VFType> >& VF,
+                                              const Eigen::MatrixXi& E2F,
+                                              const Eigen::MatrixXi& F2E,
+                                              const Eigen::PlainObjectBase<DerivedTT>& TT,
+                                              const Eigen::PlainObjectBase<DerivedM> &match_ab,
+                                              const Eigen::PlainObjectBase<DerivedM> &match_ba,
+                                              const int vi,
+                                              const int vector_to_match,
+                                              Eigen::VectorXi &mvi,
+                                              Eigen::VectorXi &fi)
+{
+  int half_degree = match_ab.cols();
+  mvi.resize(VF[vi].size()+1,1);
+  fi.resize(VF[vi].size()+1,1);
+  //start from one face
+  const int &fstart = VF[vi][0];
+  int current_face = fstart;
+  int i =0;
+  mvi[i] = vector_to_match;
+  fi[i] = current_face;
+  int next_face = -1;
+  while (next_face != fstart)
+  {
+    // look for the vertex
+    int j=-1;
+    for (unsigned z=0; z<3; ++z)
+      if (F(current_face,z) == vi)
+        j=z;
+    assert(j!=-1);
+
+    next_face = TT(current_face, j);
+    ++i;
+
+    // look at the edge between the two faces
+    const int &current_edge = F2E(current_face,j);
+
+    // check its orientation to determine whether match_ab or match_ba should be used
+    if ((E2F(current_edge,0) == current_face) &&
+        (E2F(current_edge,1) == next_face) )
+    {
+      //look at match_ab
+      mvi[i] = match_ab(current_edge,(mvi[i-1])%half_degree);
+    }
+    else
+    {
+      assert((E2F(current_edge,1) == current_face) &&
+             (E2F(current_edge,0) == next_face));
+      //look at match_ba
+      mvi[i] = match_ba(current_edge,(mvi[i-1])%half_degree);
+    }
+    if (mvi[i-1]>=half_degree)
+      mvi[i] = (mvi[i]+half_degree)%(2*half_degree);
+
+    current_face = next_face;
+    fi[i] = current_face;
+  }
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedS>
+IGL_INLINE void igl::polyvector_field_singularities_from_matchings(
+                                                                   const Eigen::PlainObjectBase<DerivedV> &V,
+                                                                   const Eigen::PlainObjectBase<DerivedF> &F,
+                                                                   const Eigen::PlainObjectBase<DerivedM> &match_ab,
+                                                                   const Eigen::PlainObjectBase<DerivedM> &match_ba,
+                                                                   Eigen::PlainObjectBase<DerivedS> &singularities)
+{
+
+  std::vector<bool> V_border = igl::is_border_vertex(V,F);
+  std::vector<std::vector<int> > VF, VFi;
+  igl::vertex_triangle_adjacency(V,F,VF,VFi);
+
+  Eigen::MatrixXi TT, TTi;
+  igl::triangle_triangle_adjacency(V,F,TT,TTi);
+
+  Eigen::MatrixXi E, E2F, F2E;
+  igl::edge_topology(V,F,E,F2E,E2F);
+
+  igl::polyvector_field_singularities_from_matchings(V, F, V_border, VF, TT, E2F, F2E, match_ab, match_ba, singularities);
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedM, typename VFType, typename DerivedS>
+IGL_INLINE void igl::polyvector_field_singularities_from_matchings(
+                                                                   const Eigen::PlainObjectBase<DerivedV> &V,
+                                                                   const Eigen::PlainObjectBase<DerivedF> &F,
+                                                                   const std::vector<bool> &V_border,
+                                                                   const std::vector<std::vector<VFType> > &VF,
+                                                                   const Eigen::MatrixXi &TT,
+                                                                   const Eigen::MatrixXi &E2F,
+                                                                   const Eigen::MatrixXi &F2E,
+                                                                   const Eigen::PlainObjectBase<DerivedM> &match_ab,
+                                                                   const Eigen::PlainObjectBase<DerivedM> &match_ba,
+                                                                   Eigen::PlainObjectBase<DerivedS> &singularities)
+{
+
+  int numV = V.rows();
+
+  std::vector<int> singularities_v;
+  int half_degree = match_ab.cols();
+  //pick one of the vectors to check for singularities
+  for (int vector_to_match = 0; vector_to_match < half_degree; ++vector_to_match)
+  {
+    for (int vi =0; vi<numV; ++vi)
+    {
+      ///check that is on border..
+      if (V_border[vi])
+        continue;
+      Eigen::VectorXi mvi,fi;
+
+      igl::polyvector_field_one_ring_matchings(V, F, VF, E2F, F2E, TT, match_ab, match_ba, vi, vector_to_match, mvi, fi);
+
+      if(mvi.tail(1) != mvi.head(1))
+        singularities_v.push_back(vi);
+    }
+  }
+  std::sort(singularities_v.begin(), singularities_v.end());
+  auto last = std::unique(singularities_v.begin(), singularities_v.end());
+  singularities_v.erase(last, singularities_v.end());
+
+  igl::list_to_matrix(singularities_v, singularities);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template void igl::polyvector_field_singularities_from_matchings<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::__1::vector<bool, std::__1::allocator<bool> > const&, std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::polyvector_field_singularities_from_matchings<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(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<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif

+ 126 - 0
include/igl/polyvector_field_singularities_from_matchings.h

@@ -0,0 +1,126 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_POLYVECTOR_FIELD_SINGULARITIES_FROM_MATCHINGS
+#define IGL_POLYVECTOR_FIELD_SINGULARITIES_FROM_MATCHINGS
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl {
+  
+  // We are given a polyvector field on a mesh (with N vectors per face), and matchings between the vector sets
+  // across all non-boundary edges.  The function computes, for the one-ring
+  // neighborhood of a given vertex, and for the selected vector of the vector set,
+  // the sequence of the vectors that match to it around the one-ring. If the vector that
+  // we land on by following the matchings is not the original vector that we started from,
+  // the vertex is a singularity.
+  //
+  // Inputs:
+  //   V                #V by 3 list of the vertex positions
+  //   F                #F by 3 list of the faces (must be triangles)
+  //   VF               #V list of lists of incident faces (adjacency list), e.g.
+  //                    as returned by igl::vertex_triangle_adjacency
+  //   E2F              #E by 2 list of the edge-to-face relation (e.g. computed
+  //                    via igl::edge_topology)
+  //   F2E              #F by 3 list of the face-to-edge relation (e.g. computed
+  //                    via igl::edge_topology)
+  //   TT               #F by 3 triangle to triangle adjacent matrix (e.g. computed
+  //                    via igl:triangle_triangle_adjacency)
+  //   match_ab         #E by N matrix, describing for each edge the matching a->b, where a
+  //                    and b are the faces adjacent to the edge (i.e. vector #i of
+  //                    the vector set in a is matched to vector #mab[i] in b)
+  //   match_ba         #E by N matrix, describing for each edge the matching b->a, where a
+  //                    and b are the faces adjacent to the edge (i.e. vector #mba[i] of
+  //                    the vector set in a is matched to vector #i in b)
+  //   vi               the selected one ring
+  //   vector_id        the selected vector of the polyvector
+  //
+  // Output:
+  //   mvi              #numOneRingFaces by 1 list of the indices of the sequentially matching vectors
+  //                    in the faces of the one ring (first enty is always vector_id, then the vector matching
+  //                    vector_id in the next face, then the vector matching that in the third face etc.)
+  //   fi               #numOneRingFaces by 1 list of the sequentially visited faces in the one ring neighborhood
+  //
+  template <typename DerivedV, typename DerivedF, typename DerivedM, typename VFType, typename DerivedTT>
+  void polyvector_field_one_ring_matchings(const Eigen::PlainObjectBase<DerivedV> &V,
+                                           const Eigen::PlainObjectBase<DerivedF> &F,
+                                           const std::vector<std::vector<VFType> >& VF,
+                                           const Eigen::MatrixXi& E2F,
+                                           const Eigen::MatrixXi& F2E,
+                                           const Eigen::PlainObjectBase<DerivedTT>& TT,
+                                           const Eigen::PlainObjectBase<DerivedM> &match_ab,
+                                           const Eigen::PlainObjectBase<DerivedM> &match_ba,
+                                           const int vi,
+                                           const int vector_id,
+                                           Eigen::VectorXi &mvi,
+                                           Eigen::VectorXi &fi);
+  
+  
+  // Given a polyvector field on a mesh, and matchings between the vector sets
+  // across all non-boundary edges, the function computes the singularities of the
+  // polyvector field, by computing the one ring matchings.
+  //
+  // Inputs:
+  //   V                #V by 3 list of the vertex positions
+  //   F                #F by 3 list of the faces (must be triangles)
+  //   V_border         #V by 1 list of booleans, indicating if the corresponging vertex is
+  //                    at the mesh boundary, e.g. as returned by igl::is_border_vertex
+  //   VF               #V list of lists of incident faces (adjacency list), e.g.
+  //                    as returned by igl::vertex_triangle_adjacency
+  //   TT               #F by 3 triangle to triangle adjacent matrix (e.g. computed
+  //                    via igl:triangle_triangle_adjacency)
+  //   E2F              #E by 2 list of the edge-to-face relation (e.g. computed
+  //                    via igl::edge_topology)
+  //   F2E              #F by 3 list of the face-to-edge relation (e.g. computed
+  //                    via igl::edge_topology)
+  //   match_ab         #E by N matrix, describing for each edge the matching a->b, where a
+  //                    and b are the faces adjacent to the edge (i.e. vector #i of
+  //                    the vector set in a is matched to vector #mab[i] in b)
+  //   match_ba         #E by N matrix, describing for each edge the matching b->a, where a
+  //                    and b are the faces adjacent to the edge (i.e. vector #mba[i] of
+  //                    the vector set in a is matched to vector #i in b)
+  //
+  // Output:
+  //   singularities    #S by 1 list of the indices of the singular vertices
+  //
+  template <typename DerivedV, typename DerivedF, typename DerivedM, typename VFType, typename DerivedS>
+  IGL_INLINE void polyvector_field_singularities_from_matchings(
+                                                                const Eigen::PlainObjectBase<DerivedV> &V,
+                                                                const Eigen::PlainObjectBase<DerivedF> &F,
+                                                                const std::vector<bool> &V_border,
+                                                                const std::vector<std::vector<VFType> > &VF,
+                                                                const Eigen::MatrixXi &TT,
+                                                                const Eigen::MatrixXi &E2F,
+                                                                const Eigen::MatrixXi &F2E,
+                                                                const Eigen::PlainObjectBase<DerivedM> &match_ab,
+                                                                const Eigen::PlainObjectBase<DerivedM> &match_ba,
+                                                                Eigen::PlainObjectBase<DerivedS> &singularities);
+  
+  
+  // Wrapper with only V,F and the matchings as input
+  template <typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedS>
+  IGL_INLINE void polyvector_field_singularities_from_matchings(
+                                                                const Eigen::PlainObjectBase<DerivedV> &V,
+                                                                const Eigen::PlainObjectBase<DerivedF> &F,
+                                                                const Eigen::PlainObjectBase<DerivedM> &match_ab,
+                                                                const Eigen::PlainObjectBase<DerivedM> &match_ba,
+                                                                Eigen::PlainObjectBase<DerivedS> &singularities);
+  
+  
+  
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "polyvector_field_singularities_from_matchings.cpp"
+#endif
+
+
+#endif /* defined(IGL_POLYVECTOR_FIELD_SINGULARITIES_FROM_MATCHINGS) */

+ 68 - 0
include/igl/sort_vectors_ccw.cpp

@@ -0,0 +1,68 @@
+#include <igl/sort_vectors_ccw.h>
+#include <igl/sort.h>
+#include <Eigen/Dense>
+
+template <typename DerivedS, typename DerivedI>
+IGL_INLINE void igl::sort_vectors_ccw(
+  const Eigen::PlainObjectBase<DerivedS>& P,
+  const Eigen::PlainObjectBase<DerivedS>& N,
+  Eigen::PlainObjectBase<DerivedI> &order,
+  const bool do_sorted,
+  Eigen::PlainObjectBase<DerivedS> &sorted,
+  const bool do_inv_order,
+  Eigen::PlainObjectBase<DerivedI> &inv_order)
+{
+  int half_degree = P.cols()/3;
+
+  //local frame
+  Eigen::Matrix<typename DerivedS::Scalar,1,3> e1 = P.head(3).normalized();
+  Eigen::Matrix<typename DerivedS::Scalar,1,3> e3 = N.normalized();
+  Eigen::Matrix<typename DerivedS::Scalar,1,3> e2 = e3.cross(e1);
+
+  Eigen::Matrix<typename DerivedS::Scalar,3,3> F; F<<e1.transpose(),e2.transpose(),e3.transpose();
+
+  Eigen::Matrix<typename DerivedS::Scalar,Eigen::Dynamic,1> angles(half_degree,1);
+  for (int i=0; i<half_degree; ++i)
+  {
+    Eigen::Matrix<typename DerivedS::Scalar,1,3> Pl = F.colPivHouseholderQr().solve(P.segment(i*3,3).transpose()).transpose();
+    assert(fabs(Pl(2))/Pl.cwiseAbs().maxCoeff() <1e-5);
+    angles[i] = atan2(Pl(1),Pl(0));
+  }
+
+  igl::sort( angles, 1, true, angles, order);
+  //make sure that the first element is always  at the top
+  while (order[0] != 0)
+  {
+    //do a circshift
+    int temp = order[0];
+    for (int i =0; i< half_degree-1; ++i)
+      order[i] = order[i+1];
+    order(half_degree-1) = temp;
+  }
+  if (do_sorted)
+  {
+    sorted.resize(1,half_degree*3);
+    for (int i=0; i<half_degree; ++i)
+      sorted.segment(i*3,3) = P.segment(order[i]*3,3);
+  }
+  if (do_inv_order)
+  {
+    inv_order.resize(half_degree,1);
+    for (int i=0; i<half_degree; ++i)
+    {
+      for (int j=0; j<half_degree; ++j)
+        if (order[j] ==i)
+        {
+          inv_order(i) = j;
+          break;
+        }
+    }
+    assert(inv_order[0] == 0);
+  }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template void igl::sort_vectors_ccw<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> >&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif

+ 50 - 0
include/igl/sort_vectors_ccw.h

@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@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_SORT_VECTORS_CCW
+#define IGL_SORT_VECTORS_CCW
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+
+namespace igl {
+  // Sorts a set of N coplanar vectors in a ccw order, and returns their order.
+  // Optionally it also returns a copy of the ordered vector set, or the indices,
+  // in the original unordered set, of the vectors in the ordered set (called here
+  // the "inverse" set of indices).
+  
+  // Inputs:
+  //   P               1 by 3N row vector of the vectors to be sorted, stacked horizontally
+  //   N               #1 by 3 normal of the plane where the vectors lie
+  //   do_sorted       boolean flag, determines whether to return the sorted vector set
+  //   do_inv_order    boolean flag, determines whether to return the "inverse" set of indices
+  // Output:
+  //   order           N by 1 order of the vectors (indices of the unordered vectors into
+  //                   the ordered vector set)
+  //   sorted          1 by 3N row vector of the ordered vectors, stacked horizontally
+  //   inv_order       N by 1 "inverse" order of the vectors (the indices of the ordered
+  //                   vectors into the unordered vector set)
+  //
+  template <typename DerivedS, typename DerivedI>
+  IGL_INLINE void sort_vectors_ccw(
+                                   const Eigen::PlainObjectBase<DerivedS>& P,
+                                   const Eigen::PlainObjectBase<DerivedS>& N,
+                                   Eigen::PlainObjectBase<DerivedI> &order,
+                                   const bool do_sorted = false,
+                                   Eigen::PlainObjectBase<DerivedS> &sorted = *(Eigen::PlainObjectBase<DerivedS>*)NULL,
+                                   const bool do_inv_order = false,
+                                   Eigen::PlainObjectBase<DerivedI> &inv_order = *(Eigen::PlainObjectBase<DerivedI> *)NULL);
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "sort_vectors_ccw.cpp"
+#endif
+
+
+#endif /* defined(IGL_FIELD_LOCAL_GLOBAL_CONVERSIONS) */