Просмотр исходного кода

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

Former-commit-id: af19526341083e3c99e20e2dad6fba52ad1aab28
Olga Diamanti 10 лет назад
Родитель
Сommit
44fa3dcc0f

+ 6 - 5
README.md

@@ -19,7 +19,7 @@ header file contains a single function (e.g. `igl/cotmatrix.h` contains
 stored in an n-by-3 matrix of vertex positions V and an m-by-3 matrix of
 stored in an n-by-3 matrix of vertex positions V and an m-by-3 matrix of
 triangle indices F. 
 triangle indices F. 
 
 
-_Optionally_ the library may also be [pre-compiled](build/) into a statically
+_Optionally_ the library may also be [pre-compiled](optional/) into a statically
 linked library, for faster compile times with your projects. This only effects
 linked library, for faster compile times with your projects. This only effects
 compile time (run-time performance and behavior is identical). If in doubt, use
 compile time (run-time performance and behavior is identical). If in doubt, use
 the header-only default mode: (i.e. just include the headers you want to use).
 the header-only default mode: (i.e. just include the headers you want to use).
@@ -65,7 +65,7 @@ If you save this in `hello.cpp`, then you could compile this with (assuming
 Eigen is installed in `/usr/local/include/eigen3`):
 Eigen is installed in `/usr/local/include/eigen3`):
 
 
 ```bash
 ```bash
-gcc -I/usr/local/include/eigen3 -I./libigl/include/ hello.cpp -o hello
+g++ -std=c++11 -I/usr/local/include/eigen3 -I./libigl/include/ hello.cpp -o hello
 ```
 ```
 
 
 Running `./hello` would then produce
 Running `./hello` would then produce
@@ -185,7 +185,8 @@ If you find bugs or have problems please use our [github issue tracking
 page](https://github.com/libigl/libigl/issues).
 page](https://github.com/libigl/libigl/issues).
 
 
 ## Copyright
 ## Copyright
-2015 Alec Jacobson, Daniele Panozzo, Olga Diamanti, Christian Schüller, Kenshi
-Takayama, Leo Sacht, Wenzel Jacob, Nico Pietroni, Amir Vaxman
+2015 Alec Jacobson, Daniele Panozzo, Christian Schüller, Olga Diamanti, Qingnan
+Zhou, Nico Pietroni, Stefan Brugger, Kenshi Takayama, Wenzel Jakob, Nikolas De
+Giorgis, Luigi Rocca, Leonardo Sacht, Olga Sorkine-Hornung, and others.
 
 
-![](tutorial/images/libigl-logo.jpg)
+Please see individual files for appropriate copyright notices.

+ 1 - 1
examples/intersections/Makefile

@@ -2,7 +2,7 @@
 
 
 # Shared flags etc.
 # Shared flags etc.
 include ../Makefile.conf
 include ../Makefile.conf
-LIBIGL_LIB=+liglcgal
+LIBIGL_LIB+=-liglcgal
 
 
 all: example
 all: example
 
 

+ 117 - 0
include/igl/biharmonic_coordinates.cpp

@@ -0,0 +1,117 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "biharmonic_coordinates.h"
+#include "cotmatrix.h"
+#include "massmatrix.h"
+#include "min_quad_with_fixed.h"
+#include "normal_derivative.h"
+#include "on_boundary.h"
+#include <Eigen/Sparse>
+
+template <
+  typename DerivedV,
+  typename DerivedT,
+  typename SType,
+  typename DerivedW>
+IGL_INLINE bool igl::biharmonic_coordinates(
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedT> & T,
+  const std::vector<std::vector<SType> > & S,
+  Eigen::PlainObjectBase<DerivedW> & W)
+{
+  using namespace Eigen;
+  using namespace std;
+  // This is not the most efficient way to build A, but follows "Linear
+  // Subspace Design for Real-Time Shape Deformation" [Wang et al. 2015]. 
+  SparseMatrix<double> A;
+  {
+    SparseMatrix<double> N,Z,L,K,M;
+    normal_derivative(V,T,N);
+    Array<bool,Dynamic,1> I;
+    Array<bool,Dynamic,Dynamic> C;
+    on_boundary(T,I,C);
+    {
+      std::vector<Triplet<double> >ZIJV;
+      for(int t =0;t<T.rows();t++)
+      {
+        for(int f =0;f<T.cols();f++)
+        {
+          if(C(t,f))
+          {
+            const int i = t+f*T.rows();
+            for(int c = 1;c<T.cols();c++)
+            {
+              ZIJV.emplace_back(T(t,(f+c)%T.cols()),i,1);
+            }
+          }
+        }
+      }
+      Z.resize(V.rows(),N.rows());
+      Z.setFromTriplets(ZIJV.begin(),ZIJV.end());
+      N = (Z*N).eval();
+    }
+    cotmatrix(V,T,L);
+    K = N+L;
+    massmatrix(V,T,MASSMATRIX_TYPE_DEFAULT,M);
+    DiagonalMatrix<double,Dynamic> Minv = 
+      ((VectorXd)M.diagonal().array().inverse()).asDiagonal();
+    A = K.transpose() * (Minv * K);
+  }
+  // Vertices in point handles
+  const size_t mp = 
+    count_if(S.begin(),S.end(),[](const vector<int> & h){return h.size()==1;});
+  // number of region handles
+  const size_t r = S.size()-mp;
+  // Vertices in region handles
+  size_t mr = 0;
+  for(const auto & h : S)
+  {
+    if(h.size() > 1)
+    {
+      mr += h.size();
+    }
+  }
+  const size_t dim = T.cols()-1;
+  // Might as well be dense... I think...
+  MatrixXd J = MatrixXd::Zero(mp+mr,mp+r*(dim+1));
+  VectorXi b(mp+mr);
+  MatrixXd H(mp+r*(dim+1),dim);
+  {
+    int v = 0;
+    int c = 0;
+    for(int h = 0;h<S.size();h++)
+    {
+      if(S[h].size()==1)
+      {
+        H.row(c) = V.block(S[h][0],0,1,dim);
+        J(v,c++) = 1;
+        b(v) = S[h][0];
+        v++;
+      }else
+      {
+        assert(S[h].size() >= dim+1);
+        for(int p = 0;p<S[h].size();p++)
+        {
+          for(int d = 0;d<dim;d++)
+          {
+            J(v,c+d) = V(S[h][p],d);
+          }
+          J(v,c+dim) = 1;
+          b(v) = S[h][p];
+          v++;
+        }
+        H.block(c,0,dim+1,dim).setIdentity();
+        c+=dim+1;
+      }
+    }
+  }
+  // minimize    ½ W' A W' 
+  // subject to  W(b,:) = J
+  return min_quad_with_fixed(
+    A,VectorXd::Zero(A.rows()).eval(),b,J,{},VectorXd(),true,W);
+}

+ 77 - 0
include/igl/biharmonic_coordinates.h

@@ -0,0 +1,77 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BIHARMONIC_COORDINATES_H
+#define IGL_BIHARMONIC_COORDINATES_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+#include <vector>
+namespace igl
+{
+  // Compute "discrete biharmonic generalized barycentric coordinates" as
+  // described in "Linear Subspace Design for Real-Time Shape Deformation"
+  // [Wang et al. 2015]. Not to be confused with "Bounded Biharmonic Weights
+  // for Real-Time Deformation" [Jacobson et al. 2011] or "Biharmonic
+  // Coordinates" (2D complex barycentric coordinates) [Weber et al. 2012].
+  // These weights minimize a discrete version of the squared Laplacian energy
+  // subject to positional interpolation constraints at selected vertices
+  // (point handles) and transformation interpolation constraints at regions
+  // (region handles).
+  //
+  // Templates:
+  //   HType  should be a simple index type e.g. `int`,`size_t`
+  // Inputs:
+  //   V  #V by dim list of mesh vertex positions
+  //   T  #T by dim+1 list of / triangle indices into V      if dim=2
+  //                          \ tetrahedron indices into V   if dim=3
+  //   S  #point-handles+#region-handles list of lists of selected vertices for
+  //     each handle. Point handles should have singleton lists and region
+  //     handles should have lists of size at least dim+1 (and these points
+  //     should be in general position).
+  // Outputs:
+  //   W  #V by #points-handles+(#region-handles * dim+1) matrix of weights so
+  //     that columns correspond to each handles generalized barycentric
+  //     coordinates (for point-handles) or animation space weights (for region
+  //     handles).
+  // returns true only on success
+  //
+  // Example:
+  //
+  //     MatrixXd W;
+  //     igl::biharmonic_coordinates(V,F,S,W);
+  //     const size_t dim = T.cols()-1;
+  //     MatrixXd H(W.cols(),dim);
+  //     {
+  //       int c = 0;
+  //       for(int h = 0;h<S.size();h++)
+  //       {
+  //         if(S[h].size()==1)
+  //         {
+  //           H.row(c++) = V.block(S[h][0],0,1,dim);
+  //         }else
+  //         {
+  //           H.block(c,0,dim+1,dim).setIdentity();
+  //           c+=dim+1;
+  //         }
+  //       }
+  //     }
+  //     assert( (V-(W*H)).array().maxCoeff() < 1e-7 );
+  template <
+    typename DerivedV,
+    typename DerivedT,
+    typename SType,
+    typename DerivedW>
+  IGL_INLINE bool biharmonic_coordinates(
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedT> & T,
+    const std::vector<std::vector<SType> > & S,
+    Eigen::PlainObjectBase<DerivedW> & W);
+};
+#  ifndef IGL_STATIC_LIBRARY
+#    include "biharmonic_coordinates.cpp"
+#  endif
+#endif

+ 0 - 1
include/igl/cotmatrix.cpp

@@ -14,7 +14,6 @@
 
 
 // Bug in unsupported/Eigen/SparseExtra needs iostream first
 // Bug in unsupported/Eigen/SparseExtra needs iostream first
 #include <iostream>
 #include <iostream>
-#include <unsupported/Eigen/SparseExtra>
 
 
 template <typename DerivedV, typename DerivedF, typename Scalar>
 template <typename DerivedV, typename DerivedF, typename Scalar>
 IGL_INLINE void igl::cotmatrix(
 IGL_INLINE void igl::cotmatrix(

+ 1 - 1
include/igl/face_occurrences.cpp

@@ -36,7 +36,7 @@ IGL_INLINE void igl::face_occurrences(
     {
     {
       // increment count
       // increment count
       counts[sortedF[i]]++;
       counts[sortedF[i]]++;
-      assert(counts[sortedF[i]] == 2);
+      assert(counts[sortedF[i]] == 2 && "Input should be manifold");
     }
     }
   }
   }
 
 

+ 26 - 0
include/igl/min_quad_with_fixed.cpp

@@ -64,6 +64,7 @@ IGL_INLINE bool igl::min_quad_with_fixed_precompute(
   assert((kr == 0 || known.maxCoeff() < n) && "known indices should be in [0,n)");
   assert((kr == 0 || known.maxCoeff() < n) && "known indices should be in [0,n)");
   assert(neq <= n && "Number of equality constraints should be less than DOFs");
   assert(neq <= n && "Number of equality constraints should be less than DOFs");
 
 
+
   // cache known
   // cache known
   data.known = known;
   data.known = known;
   // get list of unknown indices
   // get list of unknown indices
@@ -539,6 +540,31 @@ IGL_INLINE bool igl::min_quad_with_fixed_solve(
   return min_quad_with_fixed_solve(data,B,Y,Beq,Z,sol);
   return min_quad_with_fixed_solve(data,B,Y,Beq,Z,sol);
 }
 }
 
 
+template <
+  typename T,
+  typename Derivedknown,
+  typename DerivedB,
+  typename DerivedY,
+  typename DerivedBeq,
+  typename DerivedZ>
+IGL_INLINE bool igl::min_quad_with_fixed(
+  const Eigen::SparseMatrix<T>& A,
+  const Eigen::PlainObjectBase<DerivedB> & B,
+  const Eigen::PlainObjectBase<Derivedknown> & known,
+  const Eigen::PlainObjectBase<DerivedY> & Y,
+  const Eigen::SparseMatrix<T>& Aeq,
+  const Eigen::PlainObjectBase<DerivedBeq> & Beq,
+  const bool pd,
+  Eigen::PlainObjectBase<DerivedZ> & Z)
+{
+  min_quad_with_fixed_data<T> data;
+  if(!min_quad_with_fixed_precompute(A,known,Aeq,pd,data))
+  {
+    return false;
+  }
+  return min_quad_with_fixed_solve(data,B,Y,Beq,Z);
+}
+
 #ifdef IGL_STATIC_LIBRARY
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template specialization
 // Explicit template specialization
 template bool igl::min_quad_with_fixed_solve<double, 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::Matrix<double, -1, 1, 0, -1, 1> >(igl::min_quad_with_fixed_data<double> 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> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 template bool igl::min_quad_with_fixed_solve<double, 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::Matrix<double, -1, 1, 0, -1, 1> >(igl::min_quad_with_fixed_data<double> 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> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);

+ 16 - 1
include/igl/min_quad_with_fixed.h

@@ -100,7 +100,22 @@ namespace igl
     const Eigen::PlainObjectBase<DerivedY> & Y,
     const Eigen::PlainObjectBase<DerivedY> & Y,
     const Eigen::PlainObjectBase<DerivedBeq> & Beq,
     const Eigen::PlainObjectBase<DerivedBeq> & Beq,
     Eigen::PlainObjectBase<DerivedZ> & Z);
     Eigen::PlainObjectBase<DerivedZ> & Z);
-
+  template <
+    typename T,
+    typename Derivedknown,
+    typename DerivedB,
+    typename DerivedY,
+    typename DerivedBeq,
+    typename DerivedZ>
+  IGL_INLINE bool min_quad_with_fixed(
+    const Eigen::SparseMatrix<T>& A,
+    const Eigen::PlainObjectBase<DerivedB> & B,
+    const Eigen::PlainObjectBase<Derivedknown> & known,
+    const Eigen::PlainObjectBase<DerivedY> & Y,
+    const Eigen::SparseMatrix<T>& Aeq,
+    const Eigen::PlainObjectBase<DerivedBeq> & Beq,
+    const bool pd,
+    Eigen::PlainObjectBase<DerivedZ> & Z);
 }
 }
 
 
 template <typename T>
 template <typename T>

+ 74 - 32
include/igl/nchoosek.cpp

@@ -1,54 +1,96 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // This file is part of libigl, a simple c++ geometry processing library.
 //
 //
-// Copyright (C) 2014 Olga Diamanti <olga.diam@gmail.com>
+// Copyright (C) 2015 Olga Diamanti, Alec Jacobson
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // 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
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
-
 #include "nchoosek.h"
 #include "nchoosek.h"
+#include <cmath>
+#include <cassert>
 
 
-namespace igl {
-  class CombinationFinder
+IGL_INLINE double igl::nchoosek(const int n, const int k)
+{
+  if(k>n/2)
+  {
+    return nchoosek(n,n-k);
+  }else if(k==1)
   {
   {
-  private:
-    std::vector<int> combinations;
-    void add(const std::vector<int>& v,
-             std::vector<std::vector<int> > &allCombs)
+    return n;
+  }else
+  {
+    double c = 1;
+    for(int i = 1;i<=k;i++)
     {
     {
-      allCombs.push_back(v);
+      c *= (((double)n-k+i)/((double)i));
     }
     }
+    return std::round(c);
+  }
+}
 
 
-  public:
-    void doCombs(int offset,
-                 int k,
-                 int N,
-                 std::vector<std::vector<int> > &allCombs)
+template < typename DerivedV, typename DerivedU>
+IGL_INLINE void igl::nchoosek(
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const int k,
+  Eigen::PlainObjectBase<DerivedU> & U)
+{
+  using namespace Eigen;
+  if(V.size() == 0)
+  {
+    U.resize(0,k);
+    return;
+  }
+  assert((V.cols() == 1 || V.rows() == 1) && "V must be a vector");
+  U.resize(nchoosek(V.size(),k),k);
+  int running_i  = 0;
+  int running_j = 0;
+  Matrix<typename DerivedU::Scalar,1,Dynamic> running(1,k);
+  int N = V.size();
+  const std::function<void(int,int)> doCombs = 
+    [&running,&N,&doCombs,&running_i,&running_j,&U,&V](int offset, int k)
+  {
+    if(k==0)
     {
     {
-      if (k == 0) {
-        add(combinations,allCombs);
-        return;
-      }
-      for (int i = offset; i <= N - k; ++i) {
-        combinations.push_back(i);
-        doCombs(i+1, k-1, N,allCombs);
-        combinations.pop_back();
-      }
+      U.row(running_i) = running;
+      running_i++;
+      return;
+    }
+    for (int i = offset; i <= N - k; ++i) 
+    {
+      running(running_j) = V(i);
+      running_j++;
+      doCombs(i+1,k-1);
+      running_j--;
     }
     }
-
   };
   };
-
-
+  doCombs(0,k);
 }
 }
 
 
-IGL_INLINE void igl::nchoosek(int offset,
-                              int k,
-                              int N,
-                              std::vector<std::vector<int> > &allCombs)
+IGL_INLINE void igl::nchoosek(
+  int offset,
+  int k,
+  int N,
+  std::vector<std::vector<int> > &allCombs)
 {
 {
-  CombinationFinder cmbf;
   allCombs.clear();
   allCombs.clear();
-  cmbf.doCombs(offset,k,N,allCombs);
+  std::vector<int> running;
+  const std::function<void(int,int)> doCombs = 
+    [&allCombs,&running,&N,&doCombs](int offset, int k)
+  {
+    if(k==0)
+    {
+      allCombs.push_back(running);
+      return;
+    }
+    for (int i = offset; i <= N - k; ++i) 
+    {
+      running.push_back(i);
+      doCombs(i+1,k-1);
+      running.pop_back();
+    }
+  };
+  doCombs(offset,k);
+
 }
 }
 
 
 
 

+ 39 - 6
include/igl/nchoosek.h

@@ -1,6 +1,6 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // This file is part of libigl, a simple c++ geometry processing library.
 //
 //
-// Copyright (C) 2014 Olga Diamanti <olga.diam@gmail.com>
+// Copyright (C) 2015 Olga Diamanti, Alec Jacobson
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // 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
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
@@ -9,15 +9,48 @@
 #ifndef IGL_NCHOOSEK
 #ifndef IGL_NCHOOSEK
 #define IGL_NCHOOSEK
 #define IGL_NCHOOSEK
 #include "igl_inline.h"
 #include "igl_inline.h"
+#include "deprecated.h"
 #include <vector>
 #include <vector>
 
 
 #include <Eigen/Core>
 #include <Eigen/Core>
 
 
-namespace igl {
-  IGL_INLINE void nchoosek(int offset,
-                           int k,
-                           int N,
-                           std::vector<std::vector<int> > &allCombs);
+namespace igl 
+{
+  // NCHOOSEK  Like matlab's nchoosek.
+  //
+  // Inputs:
+  //   n  total number elements
+  //   k  size of sub-set to consider
+  // Returns number of k-size combinations out of the set [1,...,n]
+  IGL_INLINE double nchoosek(const int n, const int k);
+  // 
+  // Inputs:
+  //   V  n-long vector of elements
+  //   k  size of sub-set to consider
+  // Outputs:
+  //   U  nchoosek by k long matrix where each row is a unique k-size
+  //     combination
+  template < typename DerivedV, typename DerivedU>
+  IGL_INLINE void nchoosek(
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const int k,
+    Eigen::PlainObjectBase<DerivedU> & U);
+  // This version has a strange interface and confusing parameters. It seems to
+  // reproduce matlab's 
+  //
+  //     nchoosek(3:5,2) 
+  //
+  // Then one should use
+  //
+  //     igl::nchoosek(3,2,6,res);
+  //
+  IGL_INLINE 
+  IGL_DEPRECATED(
+  void nchoosek(
+    int offset,
+    int k,
+    int N,
+    std::vector<std::vector<int> > &allCombs));
 }
 }
 
 
 
 

+ 113 - 0
include/igl/normal_derivative.cpp

@@ -0,0 +1,113 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "normal_derivative.h"
+#include "cotmatrix_entries.h"
+#include "slice.h"
+#include <cassert>
+
+template <
+  typename DerivedV, 
+  typename DerivedEle, 
+  typename Scalar>
+IGL_INLINE void igl::normal_derivative(
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedEle> & Ele,
+  Eigen::SparseMatrix<Scalar>& DD)
+{
+  using namespace Eigen;
+  using namespace std;
+  // Element simplex-size 
+  const size_t ss = Ele.cols();
+  assert( ((ss==3) || (ss==4)) && "Only triangles or tets");
+  // cotangents
+  Matrix<Scalar,Dynamic,Dynamic> C;
+  cotmatrix_entries(V,Ele,C);
+  vector<Triplet<Scalar> > IJV;
+  // Number of elements
+  const size_t m = Ele.rows();
+  // Number of vertices
+  const size_t n = V.rows();
+  switch(ss)
+  {
+    default:
+      assert(false);
+      return;
+    case 4:
+    {
+      const MatrixXi DDJ = 
+        slice(
+          Ele,
+          (VectorXi(24)<<
+            1,0,2,0,3,0,2,1,3,1,0,1,3,2,0,2,1,2,0,3,1,3,2,3).finished(),
+          2);
+      MatrixXi DDI(m,24);
+      for(size_t f = 0;f<4;f++)
+      {
+        const auto & I = (VectorXi::LinSpaced(m,0,m-1).array()+f*m).eval();
+        for(size_t r = 0;r<6;r++)
+        {
+          DDI.col(f*6+r) = I;
+        }
+      }
+      const DiagonalMatrix<Scalar,24,24> S = 
+        (Matrix<Scalar,2,1>(1,-1).template replicate<12,1>()).asDiagonal();
+      Matrix<Scalar,Dynamic,Dynamic> DDV = 
+        slice(
+          C,
+          (VectorXi(24)<<
+            2,2,1,1,3,3,0,0,4,4,2,2,5,5,1,1,0,0,3,3,4,4,5,5).finished(),
+          2);
+      DDV *= S;
+
+      IJV.resize(DDV.size());
+      for(size_t f = 0;f<6*4;f++)
+      {
+        for(size_t e = 0;e<m;e++)
+        {
+          IJV.push_back(Triplet<Scalar>(DDI(e,f),DDJ(e,f),DDV(e,f)));
+        }
+      }
+      DD.resize(m*4,n);
+      DD.setFromTriplets(IJV.begin(),IJV.end());
+      break;
+    }
+    case 3:
+    {
+      const MatrixXi DDJ = 
+        slice(Ele,(VectorXi(12)<<2,0,1,0,0,1,2,1,1,2,0,2).finished(),2);
+      MatrixXi DDI(m,12);
+      for(size_t f = 0;f<3;f++)
+      {
+        const auto & I = (VectorXi::LinSpaced(m,0,m-1).array()+f*m).eval();
+        for(size_t r = 0;r<4;r++)
+        {
+          DDI.col(f*4+r) = I;
+        }
+      }
+      const DiagonalMatrix<Scalar,12,12> S = 
+        (Matrix<Scalar,2,1>(1,-1).template replicate<6,1>()).asDiagonal();
+      Matrix<Scalar,Dynamic,Dynamic> DDV = 
+        slice(C,(VectorXi(12)<<1,1,2,2,2,2,0,0,0,0,1,1).finished(),2);
+      DDV *= S;
+
+      IJV.resize(DDV.size());
+      for(size_t f = 0;f<12;f++)
+      {
+        for(size_t e = 0;e<m;e++)
+        {
+          IJV.push_back(Triplet<Scalar>(DDI(e,f),DDJ(e,f),DDV(e,f)));
+        }
+      }
+      DD.resize(m*3,n);
+      DD.setFromTriplets(IJV.begin(),IJV.end());
+      break;
+    }
+  }
+
+}
+

+ 44 - 0
include/igl/normal_derivative.h

@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_NORMAL_DERIVATIVE_H
+#define IGL_NORMAL_DERIVATIVE_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl 
+{
+  // NORMAL_DERIVATIVE Computes the directional derivative **normal** to
+  // **all** (half-)edges of a triangle mesh (not just boundary edges). These
+  // are integrated along the edge: they're the per-face constant gradient dot
+  // the rotated edge vector (unit rotated edge vector for direction then
+  // magnitude for integration).
+  //
+  // Inputs:
+  //   V  #V by dim list of mesh vertex positions
+  //   F  #F by 3|4 list of triangle|tetrahedron indices into V
+  // Outputs:
+  //   DD  #F*3|4 by #V sparse matrix representing operator to compute
+  //     directional derivative with respect to each facet of each element.
+  //
+  template <
+    typename DerivedV, 
+    typename DerivedEle, 
+    typename Scalar>
+  IGL_INLINE void normal_derivative(
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedEle> & Ele,
+    Eigen::SparseMatrix<Scalar>& DD);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "normal_derivative.cpp"
+#endif
+
+#endif
+

+ 80 - 34
include/igl/on_boundary.cpp

@@ -20,43 +20,89 @@ IGL_INLINE void igl::on_boundary(
   std::vector<std::vector<bool> > & C)
   std::vector<std::vector<bool> > & C)
 {
 {
   using namespace std;
   using namespace std;
-
-  // Get a list of all faces
-  vector<vector<IntegerT> > F(T.size()*4,vector<IntegerT>(3));
-  // Gather faces, loop over tets
-  for(int i = 0; i< (int)T.size();i++)
+  if(T.empty())
   {
   {
-    assert(T[i].size() == 4);
-    // get face in correct order
-    F[i*4+0][0] = T[i][1];
-    F[i*4+0][1] = T[i][3];
-    F[i*4+0][2] = T[i][2];
-    // get face in correct order
-    F[i*4+1][0] = T[i][0];
-    F[i*4+1][1] = T[i][2];
-    F[i*4+1][2] = T[i][3];
-    // get face in correct order
-    F[i*4+2][0] = T[i][0];
-    F[i*4+2][1] = T[i][3];
-    F[i*4+2][2] = T[i][1];
-    // get face in correct order
-    F[i*4+3][0] = T[i][0];
-    F[i*4+3][1] = T[i][1];
-    F[i*4+3][2] = T[i][2];
+    I.clear();
+    C.clear();
+    return;
   }
   }
-  // Counts
-  vector<int> FC;
-  face_occurrences(F,FC);
-  C.resize(T.size(),vector<bool>(4));
-  I.resize(T.size(),false);
-  for(int i = 0; i< (int)T.size();i++)
+
+  switch(T[0].size())
   {
   {
-    for(int j = 0;j<4;j++)
+    case 3:
+    {
+      // Get a list of all faces
+      vector<vector<IntegerT> > F(T.size()*3,vector<IntegerT>(2));
+      // Gather faces, loop over tets
+      for(int i = 0; i< (int)T.size();i++)
+      {
+        assert(T[i].size() == 3);
+        // get face in correct order
+        F[i*3+0][0] = T[i][1];
+        F[i*3+0][1] = T[i][2];
+        F[i*3+1][0] = T[i][2];
+        F[i*3+1][1] = T[i][0];
+        F[i*3+2][0] = T[i][0];
+        F[i*3+2][1] = T[i][1];
+      }
+      // Counts
+      vector<int> FC;
+      face_occurrences(F,FC);
+      C.resize(T.size(),vector<bool>(3));
+      I.resize(T.size(),false);
+      for(int i = 0; i< (int)T.size();i++)
+      {
+        for(int j = 0;j<3;j++)
+        {
+          assert(FC[i*3+j] == 2 || FC[i*3+j] == 1);
+          C[i][j] = FC[i*3+j]==1;
+          // if any are on boundary set to true
+          I[i] = I[i] || C[i][j];
+        }
+      }
+      return;
+    }
+    case 4:
     {
     {
-      assert(FC[i*4+j] == 2 || FC[i*4+j] == 1);
-      C[i][j] = FC[i*4+j]==1;
-      // if any are on boundary set to true
-      I[i] = I[i] || C[i][j];
+      // Get a list of all faces
+      vector<vector<IntegerT> > F(T.size()*4,vector<IntegerT>(3));
+      // Gather faces, loop over tets
+      for(int i = 0; i< (int)T.size();i++)
+      {
+        assert(T[i].size() == 4);
+        // get face in correct order
+        F[i*4+0][0] = T[i][1];
+        F[i*4+0][1] = T[i][3];
+        F[i*4+0][2] = T[i][2];
+        // get face in correct order
+        F[i*4+1][0] = T[i][0];
+        F[i*4+1][1] = T[i][2];
+        F[i*4+1][2] = T[i][3];
+        // get face in correct order
+        F[i*4+2][0] = T[i][0];
+        F[i*4+2][1] = T[i][3];
+        F[i*4+2][2] = T[i][1];
+        // get face in correct order
+        F[i*4+3][0] = T[i][0];
+        F[i*4+3][1] = T[i][1];
+        F[i*4+3][2] = T[i][2];
+      }
+      // Counts
+      vector<int> FC;
+      face_occurrences(F,FC);
+      C.resize(T.size(),vector<bool>(4));
+      I.resize(T.size(),false);
+      for(int i = 0; i< (int)T.size();i++)
+      {
+        for(int j = 0;j<4;j++)
+        {
+          assert(FC[i*4+j] == 2 || FC[i*4+j] == 1);
+          C[i][j] = FC[i*4+j]==1;
+          // if any are on boundary set to true
+          I[i] = I[i] || C[i][j];
+        }
+      }
+      return;
     }
     }
   }
   }
 
 
@@ -73,7 +119,7 @@ IGL_INLINE void igl::on_boundary(
   Eigen::PlainObjectBase<DerivedI>& I,
   Eigen::PlainObjectBase<DerivedI>& I,
   Eigen::PlainObjectBase<DerivedC>& C)
   Eigen::PlainObjectBase<DerivedC>& C)
 {
 {
-  assert(T.cols() == 0 || T.cols() == 4);
+  assert(T.cols() == 0 || T.cols() == 4 || T.cols() == 3);
   using namespace std;
   using namespace std;
   using namespace Eigen;
   using namespace Eigen;
   // Cop out: use vector of vectors version
   // Cop out: use vector of vectors version

+ 4 - 3
include/igl/on_boundary.h

@@ -17,16 +17,17 @@
 
 
 namespace igl
 namespace igl
 {
 {
-  // BOUNDARY_FACES Determine boundary faces of tetrahedra stored in T
+  // ON_BOUNDARY Determine boundary facets of mesh elements stored in T
   //
   //
   // Templates:
   // Templates:
   //   IntegerT  integer-value: i.e. int
   //   IntegerT  integer-value: i.e. int
   //   IntegerF  integer-value: i.e. int
   //   IntegerF  integer-value: i.e. int
   // Input:
   // Input:
-  //  T  tetrahedron index list, m by 4, where m is the number of tetrahedra
+  //  T  triangle|tetrahedron index list, m by 3|4, where m is the number of
+  //    elements
   // Output:
   // Output:
   //  I  m long list of bools whether tet is on boundary
   //  I  m long list of bools whether tet is on boundary
-  //  C  m by 4 list of bools whether opposite face is on boundary
+  //  C  m by 3|4 list of bools whether opposite facet is on boundary
   //
   //
   template <typename IntegerT>
   template <typename IntegerT>
   IGL_INLINE void on_boundary(
   IGL_INLINE void on_boundary(

+ 0 - 3
include/igl/slice.cpp

@@ -9,9 +9,6 @@
 #include "colon.h"
 #include "colon.h"
 
 
 #include <vector>
 #include <vector>
-
-// Bug in unsupported/Eigen/SparseExtra needs iostream first
-#include <iostream>
 #include <unsupported/Eigen/SparseExtra>
 #include <unsupported/Eigen/SparseExtra>
 
 
 template <typename T>
 template <typename T>

+ 1 - 0
include/igl/slice_mask.h

@@ -10,6 +10,7 @@
 #include "igl_inline.h"
 #include "igl_inline.h"
 
 
 #include <Eigen/Sparse>
 #include <Eigen/Sparse>
+#include <Eigen/Core>
 namespace igl
 namespace igl
 {
 {
   // Act like the matlab X(row_mask,col_mask) operator, where
   // Act like the matlab X(row_mask,col_mask) operator, where

+ 6 - 7
index.html

@@ -35,7 +35,7 @@ header file contains a single function (e.g. <code>igl/cotmatrix.h</code> contai
 stored in an n-by&#8211;3 matrix of vertex positions V and an m-by&#8211;3 matrix of
 stored in an n-by&#8211;3 matrix of vertex positions V and an m-by&#8211;3 matrix of
 triangle indices F. </p>
 triangle indices F. </p>
 
 
-<p><em>Optionally</em> the library may also be <a href="build/">pre-compiled</a> into a statically
+<p><em>Optionally</em> the library may also be <a href="optional/">pre-compiled</a> into a statically
 linked library, for faster compile times with your projects. This only effects
 linked library, for faster compile times with your projects. This only effects
 compile time (run-time performance and behavior is identical). If in doubt, use
 compile time (run-time performance and behavior is identical). If in doubt, use
 the header-only default mode: (i.e. just include the headers you want to use).</p>
 the header-only default mode: (i.e. just include the headers you want to use).</p>
@@ -79,7 +79,7 @@ int main()
 <p>If you save this in <code>hello.cpp</code>, then you could compile this with (assuming
 <p>If you save this in <code>hello.cpp</code>, then you could compile this with (assuming
 Eigen is installed in <code>/usr/local/include/eigen3</code>):</p>
 Eigen is installed in <code>/usr/local/include/eigen3</code>):</p>
 
 
-<pre><code class="bash">gcc -I/usr/local/include/eigen3 -I./libigl/include/ hello.cpp -o hello
+<pre><code class="bash">g++ -std=c++11 -I/usr/local/include/eigen3 -I./libigl/include/ hello.cpp -o hello
 </code></pre>
 </code></pre>
 
 
 <p>Running <code>./hello</code> would then produce</p>
 <p>Running <code>./hello</code> would then produce</p>
@@ -204,12 +204,11 @@ page</a>.</p>
 
 
 <h2 id="copyright">Copyright</h2>
 <h2 id="copyright">Copyright</h2>
 
 
-<p>2015 Alec Jacobson, Daniele Panozzo, Olga Diamanti, Christian Schüller, Kenshi
-Takayama, Leo Sacht, Wenzel Jacob, Nico Pietroni, Amir Vaxman</p>
+<p>2015 Alec Jacobson, Daniele Panozzo, Christian Schüller, Olga Diamanti, Qingnan
+Zhou, Nico Pietroni, Stefan Brugger, Kenshi Takayama, Wenzel Jakob, Nikolas De
+Giorgis, Luigi Rocca, Leonardo Sacht, Olga Sorkine-Hornung, and others.</p>
 
 
-<figure>
-<img src="tutorial/images/libigl-logo.jpg" alt="" />
-<figcaption></figcaption></figure>
+<p>Please see individual files for appropriate copyright notices.</p>
 
 
 </body>
 </body>
 </html>
 </html>

+ 1 - 1
libigl-logo.ai.REMOVED.git-id

@@ -1 +1 @@
-f91b6a376761d6f0a5cc97bd4066d17775ba61dc
+1bd069dc597f054c2d4d8c93d9eb6a671b119c86

BIN
libigl-logo.jpg


+ 1 - 1
libigl-teaser.pdf.REMOVED.git-id

@@ -1 +1 @@
-e3cd39bc873032bb79fbeb7608aa1e08aba4eac2
+6d633e0a6c52bd9130db774013a00a5dbe7adeb6

+ 1 - 1
libigl-teaser.png.REMOVED.git-id

@@ -1 +1 @@
-a946fc13d18614f2696a1ed94978ab61e76a722b
+9bcc46445af9bf39049eca841aa080838c2ee837

+ 28 - 26
optional/index.html

@@ -16,9 +16,9 @@
 
 
 <blockquote>
 <blockquote>
 <p>Warning: compiling libigl as a static library is considerably more difficult
 <p>Warning: compiling libigl as a static library is considerably more difficult
-than using it as a header-only library (see <code>../README.md</code> instead). Do it
-only if you are experienced with C++ and you want to improve your compilation
-times.</p>
+than using it as a header-only library (see <a href="../">../README.md</a> instead). Do
+it only if you are experienced with C++, cmake and make, and you want to
+improve your compilation times.</p>
 </blockquote>
 </blockquote>
 
 
 <p>Libigl is developed most often on Mac OS X, though has current users in Linux
 <p>Libigl is developed most often on Mac OS X, though has current users in Linux
@@ -30,36 +30,32 @@ and Windows.</p>
 building a project with libigl, since when used as an header-only library can
 building a project with libigl, since when used as an header-only library can
 slow down compile times.</p>
 slow down compile times.</p>
 
 
-<p>To build the entire libigl library producing <code>lib/libigl.a</code>, issue:</p>
+<p>To build the entire libigl library producing at least <code>libigl/lib/libigl.a</code> and
+possible other (automatically detected) extras, e.g. <code>libigl/lib/libiglcgal.a</code>
+from <em>this current directory</em>: issue:</p>
 
 
-<pre><code>cd build
-make lib
-</code></pre>
-
-<p>You may need to edit <code>Makefile.conf</code> accordingly. Best to give yourself an
-<code>IGL_USERNAME</code> and add a custom install suite for yourself. Then you can enable
-appropriate extras.</p>
-
-<h4 id="extras">Extras</h4>
-
-<p>Once you&#8217;ve set up an <code>IGL_USERNAME</code> and enabled extras within Makefile.conf.
-You can build the extra libraries (into <code>lib/ligiglpng.a</code>, <code>lib/libiglmatlab.a</code>,
-<code>lib/libigltetgen.a</code>, <code>lib/libiglmosek.a</code>, etc.) by issuing:</p>
-
-<pre><code>cd build
-make extras
+<pre><code>mkdir -p ../lib
+cd ../lib
+cmake -DCMAKE_BUILD_TYPE=Release ..
+make
 </code></pre>
 </code></pre>
 
 
 <h4 id="examples">Examples</h4>
 <h4 id="examples">Examples</h4>
 
 
 <p>You can make a slew of examples by issuing:</p>
 <p>You can make a slew of examples by issuing:</p>
 
 
-<pre><code>cd build
-make examples
+<pre><code>cd ../examples
+make
 </code></pre>
 </code></pre>
 
 
 <h4 id="external">External</h4>
 <h4 id="external">External</h4>
 
 
+<blockquote>
+<p><strong>Deprecation notice</strong> All external libraries will be absorbed by libigl or
+moved to separate git sub-repositories in the near future. The following
+instructions are subject to immediate change.</p>
+</blockquote>
+
 <p>Finally there are a number of external libraries that we include in
 <p>Finally there are a number of external libraries that we include in
 <code>./external/</code> because they are either difficult to obtain or they have been
 <code>./external/</code> because they are either difficult to obtain or they have been
 patched for easier use with libigl. Please see the respective readmes in those
 patched for easier use with libigl. Please see the respective readmes in those
@@ -67,7 +63,7 @@ directories.</p>
 
 
 <h5 id="installinganttweakbar">Installing AntTweakBar</h5>
 <h5 id="installinganttweakbar">Installing AntTweakBar</h5>
 
 
-<p>To build the a static AntTweakBar library on Mac OS X issue:</p>
+<p>To build a static AntTweakBar library on Mac OS X issue:</p>
 
 
 <pre><code>cd external/AntTweakBar/src
 <pre><code>cd external/AntTweakBar/src
 make -f Makefile.osx.igl
 make -f Makefile.osx.igl
@@ -132,6 +128,11 @@ installed at <code>/usr/X11/lib</code>.</p>
 
 
 <h3 id="windowsexperimental">Windows (Experimental)</h3>
 <h3 id="windowsexperimental">Windows (Experimental)</h3>
 
 
+<blockquote>
+<p><strong>Deprecation notice</strong> Windows users should run cmake on the <code>CMakeLists.txt</code>
+file in the current directory.</p>
+</blockquote>
+
 <p>To build a static library (.lib) on windows, open Visual Studio 2010.</p>
 <p>To build a static library (.lib) on windows, open Visual Studio 2010.</p>
 
 
 <ul>
 <ul>
@@ -391,9 +392,10 @@ exposing templated functions.</li>
  <code>AntTweakBar</code>, <code>BLAS</code>). However, because all
  <code>AntTweakBar</code>, <code>BLAS</code>). However, because all
  depencies other than Eigen should be encapsulated between
  depencies other than Eigen should be encapsulated between
  <code>#ifndef</code> guards (e.g. <code>#ifndef IGL_NO_OPENGL</code>, it
  <code>#ifndef</code> guards (e.g. <code>#ifndef IGL_NO_OPENGL</code>, it
- is possible to ignore certain functions that have such dependencies.</li>
- <li><strong>Long compile:</strong> Compiling <code>igl.cpp</code> takes a long time and isn&#8217;t easily parallelized (no <code>make -j12</code> equivalent).</li>
- </ul></p></li>
+ is possible to ignore certain functions that have such dependencies.</p></li>
+<li><p><strong>Long compile</strong>:
+ Compiling <code>igl.cpp</code> takes a long time and isn&#8217;t easily parallelized (no <code>make
+  -j12</code> equivalent).</p></li>
 </ul>
 </ul>
 
 
 <p>Here&#8217;s a tiny test example using <code>igl.h</code> and <code>igl.cpp</code>. Save the following in <code>test.cpp</code>:</p>
 <p>Here&#8217;s a tiny test example using <code>igl.h</code> and <code>igl.cpp</code>. Save the following in <code>test.cpp</code>:</p>

+ 3 - 3
scripts/update_gh-pages.sh

@@ -32,8 +32,8 @@ echo "$HEADER" \
   git commit -m "update google-soc/index.html to match google-soc/google-soc.md" google-soc/google-soc.md google-soc/index.html 
   git commit -m "update google-soc/index.html to match google-soc/google-soc.md" google-soc/google-soc.md google-soc/index.html 
 
 
 echo "$HEADER" \
 echo "$HEADER" \
-  | cat - build/README.md | multimarkdown -o build/index.html && \
-  git commit -m "update index.html to match README.md" build/README.md \
-  build/index.html
+  | cat - optional/README.md | multimarkdown -o optional/index.html && \
+  git commit -m "update index.html to match README.md" optional/README.md \
+  optional/index.html
 
 
 git push origin gh-pages && git checkout master && git merge gh-pages && git push
 git push origin gh-pages && git checkout master && git merge gh-pages && git push

BIN
tutorial/images/libigl-logo.jpg


+ 1 - 0
tutorial/images/libigl-logo.jpg.REMOVED.git-id

@@ -0,0 +1 @@
+c55d7d3d54e0d078c021f187cfe0bc8e2c40a526

+ 1 - 1
tutorial/tutorial.md.REMOVED.git-id

@@ -1 +1 @@
-628b770ce18ce0b59a429488ecab9c9363b5be76
+c2c64bc4dca6502cf13e254fa512d9f9feca182f