Browse Source

create copyleft, mc, quadprog, prog hulls

Former-commit-id: 98ec122c45483f22038db21d90b3142efad8d84d
Alec Jacobson 9 years ago
parent
commit
0c4d3c823c

+ 14 - 0
include/igl/copyleft/README.md

@@ -0,0 +1,14 @@
+## IGL copyleft subdirectory
+
+Functions in the `include/igl/copyleft/` subdirectory are in the
+`igl::copyleft::` namespace to indicate that they are under a more aggressive
+[copyleft](https://en.wikipedia.org/wiki/Copyleft) than
+[MPL2](https://en.wikipedia.org/wiki/Mozilla_Public_License) used for the main
+`include/igl` directory and `igl::` namespace. Most notably, this subdirectory
+includes code that is under
+[GPL](https://en.wikipedia.org/wiki/GNU_General_Public_License).
+
+Typically a company planning on developing software without releasing its
+source code will avoid or purchase licenses for such dependencies. If you do
+obtain such a license for the dependencies employed here, you are free to use
+the libigl functions here as per their MPL2 license.

+ 13 - 12
include/igl/marching_cubes.cpp → include/igl/copyleft/marching_cubes.cpp

@@ -220,13 +220,14 @@ public:
 
 
 template <typename DerivedV, typename DerivedF>
-IGL_INLINE void igl::marching_cubes(const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &values,
-                                    const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 3> &points,
-                                    const unsigned x_res,
-                                    const unsigned y_res,
-                                    const unsigned z_res,
-                                    Eigen::PlainObjectBase<DerivedV> &vertices,
-                                    Eigen::PlainObjectBase<DerivedF> &faces)
+IGL_INLINE void igl::copyleft::marching_cubes(
+  const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &values,
+  const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 3> &points,
+  const unsigned x_res,
+  const unsigned y_res,
+  const unsigned z_res,
+  Eigen::PlainObjectBase<DerivedV> &vertices,
+  Eigen::PlainObjectBase<DerivedF> &faces)
 {
   MarchingCubes<DerivedV, DerivedF> mc(values, 
                                        points, 
@@ -238,9 +239,9 @@ IGL_INLINE void igl::marching_cubes(const Eigen::Matrix<typename DerivedV::Scala
 }
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template specialization
-template void igl::marching_cubes<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, -1, 1, 0, -1, 1> const&, Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, -1, 3, 0, -1, 3> const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-template void igl::marching_cubes<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::Matrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, -1, 1, 0, -1, 1> const&, Eigen::Matrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, -1, 3, 0, -1, 3> const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-template void igl::marching_cubes<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 0, -1, 3> >(Eigen::Matrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, -1, 1, 0, -1, 1> const&, Eigen::Matrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, -1, 3, 0, -1, 3> const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 0, -1, 3> >&);
-template void igl::marching_cubes<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 0, -1, 3> >(Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, -1, 1, 0, -1, 1> const&, Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, -1, 3, 0, -1, 3> const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 0, -1, 3> >&);
-template void igl::marching_cubes<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::Matrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, -1, 1, 0, -1, 1> const&, Eigen::Matrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, -1, 3, 0, -1, 3> const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::marching_cubes<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, -1, 1, 0, -1, 1> const&, Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, -1, 3, 0, -1, 3> const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::marching_cubes<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::Matrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, -1, 1, 0, -1, 1> const&, Eigen::Matrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, -1, 3, 0, -1, 3> const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::marching_cubes<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 0, -1, 3> >(Eigen::Matrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, -1, 1, 0, -1, 1> const&, Eigen::Matrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, -1, 3, 0, -1, 3> const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::marching_cubes<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 0, -1, 3> >(Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, -1, 1, 0, -1, 1> const&, Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, -1, 3, 0, -1, 3> const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::marching_cubes<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::Matrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, -1, 1, 0, -1, 1> const&, Eigen::Matrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, -1, 3, 0, -1, 3> const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

+ 57 - 0
include/igl/copyleft/marching_cubes.h

@@ -0,0 +1,57 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 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_COPYLEFT_MARCHINGCUBES_H
+#define IGL_COPYLEFT_MARCHINGCUBES_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+namespace igl 
+{
+  namespace copyleft
+  {
+    // marching_cubes( values, points, x_res, y_res, z_res, vertices, faces )
+    //
+    // performs marching cubes reconstruction on the grid defined by values, and
+    // points, and generates vertices and faces
+    //
+    // Input:
+    //  values  #number_of_grid_points x 1 array -- the scalar values of an
+    //    implicit function defined on the grid points (<0 in the inside of the
+    //    surface, 0 on the border, >0 outside)
+    //  points  #number_of_grid_points x 3 array -- 3-D positions of the grid
+    //    points, ordered in x,y,z order:
+    //      points[index] = the point at (x,y,z) where :
+    //      x = (index % (xres -1), 
+    //      y = (index / (xres-1)) %(yres-1),
+    //      z = index / (xres -1) / (yres -1) ).
+    //      where x,y,z index x, y, z dimensions
+    //      i.e. index = x + y*xres + z*xres*yres
+    //  xres  resolutions of the grid in x dimension
+    //  yres  resolutions of the grid in y dimension
+    //  zres  resolutions of the grid in z dimension
+    // Output:
+    //   vertices  #V by 3 list of mesh vertex positions
+    //   faces  #F by 3 list of mesh triangle indices
+    //
+    template <typename DerivedV, typename DerivedF>
+      IGL_INLINE void marching_cubes(
+        const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &values,
+        const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 3> &points,
+        const unsigned x_res,
+        const unsigned y_res,
+        const unsigned z_res,
+        Eigen::PlainObjectBase<DerivedV> &vertices,
+        Eigen::PlainObjectBase<DerivedF> &faces);
+  }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "marching_cubes.cpp"
+#endif
+
+#endif

+ 0 - 0
include/igl/marching_cubes_tables.h → include/igl/copyleft/marching_cubes_tables.h


+ 27 - 0
include/igl/copyleft/progressive_hulls.cpp

@@ -0,0 +1,27 @@
+// 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 "progressive_hulls.h"
+#include "progressive_hulls_cost_and_placement.h"
+#include "../decimate.h"
+#include "../max_faces_stopping_condition.h"
+IGL_INLINE bool igl::copyleft::progressive_hulls(
+  const Eigen::MatrixXd & V,
+  const Eigen::MatrixXi & F,
+  const size_t max_m,
+  Eigen::MatrixXd & U,
+  Eigen::MatrixXi & G)
+{
+  int m = F.rows();
+  return decimate(
+    V,
+    F,
+    progressive_hulls_cost_and_placement,
+    max_faces_stopping_condition(m,max_m),
+    U,
+    G);
+}

+ 41 - 0
include/igl/copyleft/progressive_hulls.h

@@ -0,0 +1,41 @@
+// 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_COPYLEFT_PROGRESSIVE_HULLS_H
+#define IGL_COPYLEFT_PROGRESSIVE_HULLS_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+  namespace copyleft
+  {
+    // Assumes (V,F) is a closed manifold mesh 
+    // Collapses edges until desired number of faces is achieved but ensures
+    // that new vertices are placed outside all previous meshes as per
+    // "progressive hulls" in "Silhouette clipping" [Sander et al. 2000].
+    //
+    // Inputs:
+    //   V  #V by dim list of vertex positions
+    //   F  #F by 3 list of face indices into V.
+    //   max_m  desired number of output faces
+    // Outputs:
+    //   U  #U by dim list of output vertex posistions (can be same ref as V)
+    //   G  #G by 3 list of output face indices into U (can be same ref as G)
+    // Returns true if m was reached (otherwise #G > m)
+    IGL_INLINE bool progressive_hulls(
+      const Eigen::MatrixXd & V,
+      const Eigen::MatrixXi & F,
+      const size_t max_m,
+      Eigen::MatrixXd & U,
+      Eigen::MatrixXi & G);
+  }
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "progressive_hulls.cpp"
+#endif
+#endif

+ 107 - 0
include/igl/copyleft/progressive_hulls_cost_and_placement.cpp

@@ -0,0 +1,107 @@
+// 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 "progressive_hulls_cost_and_placement.h"
+#include "quadprog.h"
+#include "../unique.h"
+#include "../circulation.h"
+#include <cassert>
+#include <vector>
+#include <limits>
+
+IGL_INLINE void igl::copyleft::progressive_hulls_cost_and_placement(
+  const int e,
+  const Eigen::MatrixXd & V,
+  const Eigen::MatrixXi & F,
+  const Eigen::MatrixXi & E,
+  const Eigen::VectorXi & EMAP,
+  const Eigen::MatrixXi & EF,
+  const Eigen::MatrixXi & EI,
+  double & cost,
+  Eigen::RowVectorXd & p)
+{
+  using namespace Eigen;
+  using namespace std;
+  // Controls the amount of quadratic energy to add (too small will introduce
+  // instabilities and flaps)
+  const double w = 0.1;
+
+  assert(V.cols() == 3 && "V.cols() should be 3");
+  // Gather list of unique face neighbors
+  vector<int> Nall =  circulation(e, true,F,E,EMAP,EF,EI);
+  vector<int> Nother= circulation(e,false,F,E,EMAP,EF,EI);
+  Nall.insert(Nall.end(),Nother.begin(),Nother.end());
+  vector<int> N;
+  igl::unique(Nall,N);
+  // Gather:
+  //   A  #N by 3 normals scaled by area,
+  //   D  #N determinants of matrix formed by points as columns
+  //   B  #N point on plane dot normal
+  MatrixXd A(N.size(),3);
+  VectorXd D(N.size());
+  VectorXd B(N.size());
+  //cout<<"N=[";
+  for(int i = 0;i<N.size();i++)
+  {
+    const int f = N[i];
+    //cout<<(f+1)<<" ";
+    const RowVector3d & v01 = V.row(F(f,1))-V.row(F(f,0));
+    const RowVector3d & v20 = V.row(F(f,2))-V.row(F(f,0));
+    A.row(i) = v01.cross(v20);
+    B(i) = V.row(F(f,0)).dot(A.row(i));
+    D(i) = 
+      (Matrix3d()<< V.row(F(f,0)), V.row(F(f,1)), V.row(F(f,2)))
+      .finished().determinant();
+  }
+  //cout<<"];"<<endl;
+  // linear objective
+  Vector3d f = A.colwise().sum().transpose();
+  VectorXd x;
+  //bool success = linprog(f,-A,-B,MatrixXd(0,A.cols()),VectorXd(0,1),x);
+  //VectorXd _;
+  //bool success = mosek_linprog(f,A.sparseView(),B,_,_,_,env,x);
+  //if(success)
+  //{
+  //  cost  = (1./6.)*(x.dot(f) - D.sum());
+  //}
+  bool success = false;
+  {
+    RowVectorXd mid = 0.5*(V.row(E(e,0))+V.row(E(e,1)));
+    MatrixXd G =  w*Matrix3d::Identity(3,3);
+    VectorXd g0 = (1.-w)*f - w*mid.transpose();
+    const int n = A.cols();
+    success = quadprog(
+        G,g0,
+        MatrixXd(n,0),VectorXd(0,1),
+        A.transpose(),-B,x);
+    cost  = (1.-w)*(1./6.)*(x.dot(f) - D.sum()) + 
+      w*(x.transpose()-mid).squaredNorm() +
+      w*(V.row(E(e,0))-V.row(E(e,1))).norm();
+  }
+
+  // A x >= B
+  // A x - B >=0
+  // This is annoyingly necessary. Seems the solver is letting some garbage
+  // slip by.
+  success = success && ((A*x-B).minCoeff()>-1e-10);
+  if(success)
+  {
+    p = x.transpose();
+    //assert(cost>=0 && "Cost should be positive");
+  }else
+  {
+    cost = std::numeric_limits<double>::infinity();
+    //VectorXi NM;
+    //igl::list_to_matrix(N,NM);
+    //cout<<matlab_format((NM.array()+1).eval(),"N")<<endl;
+    //cout<<matlab_format(f,"f")<<endl;
+    //cout<<matlab_format(A,"A")<<endl;
+    //cout<<matlab_format(B,"B")<<endl;
+    //exit(-1);
+    p = RowVectorXd::Constant(1,3,std::nan("inf-cost"));
+  }
+}

+ 54 - 0
include/igl/copyleft/progressive_hulls_cost_and_placement.h

@@ -0,0 +1,54 @@
+// 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_COPYLEFT_PROGRESSIVE_HULLS_COST_AND_PLACEMENT_H
+#define IGL_COPYLEFT_PROGRESSIVE_HULLS_COST_AND_PLACEMENT_H
+#include <Eigen/Core>
+#include "../igl_inline.h"
+namespace igl
+{
+  namespace copyleft
+  {
+    // A "cost and placement" compatible with `igl::decimate` implementing the
+    // "progressive hulls" algorithm in "Silhouette clipping" [Sander et al.
+    // 2000]. This implementation fixes an issue that the original linear
+    // program becomes unstable for flat patches by introducing a small
+    // quadratic energy term pulling the collapsed edge toward its midpoint.
+    // This function is not really meant to be called directly but rather
+    // passed to `igl::decimate` as a handle.
+    //
+    // Inputs:
+    //   e  index of edge to be collapsed
+    //   V  #V by 3 list of vertex positions
+    //   F  #F by 3 list of faces indices into V
+    //   E  #E by 3 list of edges indices into V
+    //   EMAP #F*3 list of indices into E, mapping each directed edge to unique
+    //     unique edge in E
+    //   EF  #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
+    //     F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
+    //     e=(j->i)
+    //   EI  #E by 2 list of edge flap corners (see above).
+    // Outputs:
+    //   cost  cost of collapsing edge e
+    //   p  position to place collapsed vertex
+    //
+    IGL_INLINE void progressive_hulls_cost_and_placement(
+      const int e,
+      const Eigen::MatrixXd & V,
+      const Eigen::MatrixXi & F,
+      const Eigen::MatrixXi & E,
+      const Eigen::VectorXi & EMAP,
+      const Eigen::MatrixXi & EF,
+      const Eigen::MatrixXi & EI,
+      double & cost,
+      Eigen::RowVectorXd & p);
+  }
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "progressive_hulls_cost_and_placement.cpp"
+#endif
+#endif

+ 606 - 0
include/igl/copyleft/quadprog.cpp

@@ -0,0 +1,606 @@
+// 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 "quadprog.h"
+
+/*
+ FILE eiquadprog.hh
+ 
+ NOTE: this is a modified of uQuadProg++ package, working with Eigen data structures. 
+       uQuadProg++ is itself a port made by Angelo Furfaro of QuadProg++ originally developed by 
+       Luca Di Gaspero, working with ublas data structures. 
+
+ The quadprog_solve() function implements the algorithm of Goldfarb and Idnani 
+ for the solution of a (convex) Quadratic Programming problem
+by means of a dual method.
+	 
+The problem is in the form:
+
+min 0.5 * x G x + g0 x
+s.t.
+    CE^T x + ce0 = 0
+    CI^T x + ci0 >= 0
+	 
+ The matrix and vectors dimensions are as follows:
+     G: n * n
+		g0: n
+				
+		CE: n * p
+	 ce0: p
+				
+	  CI: n * m
+   ci0: m
+
+     x: n
+ 
+ The function will return the cost of the solution written in the x vector or
+ std::numeric_limits::infinity() if the problem is infeasible. In the latter case
+ the value of the x vector is not correct.
+ 
+ References: D. Goldfarb, A. Idnani. A numerically stable dual method for solving
+             strictly convex quadratic programs. Mathematical Programming 27 (1983) pp. 1-33.
+
+ Notes:
+  1. pay attention in setting up the vectors ce0 and ci0. 
+	   If the constraints of your problem are specified in the form 
+	   A^T x = b and C^T x >= d, then you should set ce0 = -b and ci0 = -d.
+  2. The matrix G is modified within the function since it is used to compute
+     the G = L^T L cholesky factorization for further computations inside the function. 
+     If you need the original matrix G you should make a copy of it and pass the copy
+     to the function.
+    
+ 
+ The author will be grateful if the researchers using this software will
+ acknowledge the contribution of this modified function and of Di Gaspero's
+ original version in their research papers.
+
+
+LICENSE
+
+Copyright (2010) Gael Guennebaud
+Copyright (2008) Angelo Furfaro
+Copyright (2006) Luca Di Gaspero
+
+
+This file is a porting of QuadProg++ routine, originally developed
+by Luca Di Gaspero, exploiting uBlas data structures for vectors and
+matrices instead of native C++ array.
+
+uquadprog is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+uquadprog is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with uquadprog; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <Eigen/Dense>
+
+IGL_INLINE bool igl::copyleft::quadprog(
+  const Eigen::MatrixXd & G,  
+  const Eigen::VectorXd & g0,  
+  const Eigen::MatrixXd & CE, 
+  const Eigen::VectorXd & ce0,  
+  const Eigen::MatrixXd & CI, 
+  const Eigen::VectorXd & ci0, 
+  Eigen::VectorXd& x)
+{
+  using namespace Eigen;
+  typedef double Scalar;
+  const auto distance = [](Scalar a, Scalar b)->Scalar
+  {
+  	Scalar a1, b1, t;
+  	a1 = std::abs(a);
+  	b1 = std::abs(b);
+  	if (a1 > b1) 
+  	{
+  		t = (b1 / a1);
+  		return a1 * std::sqrt(1.0 + t * t);
+  	}
+  	else
+  		if (b1 > a1)
+  		{
+  			t = (a1 / b1);
+  			return b1 * std::sqrt(1.0 + t * t);
+  		}
+  	return a1 * std::sqrt(2.0);
+  };
+  const auto compute_d = [](VectorXd &d, const MatrixXd& J, const VectorXd& np)
+  {
+    d = J.adjoint() * np;
+  };
+
+  const auto update_z = 
+    [](VectorXd& z, const MatrixXd& J, const VectorXd& d,  int iq)
+  {
+    z = J.rightCols(z.size()-iq) * d.tail(d.size()-iq);
+  };
+
+  const auto update_r = 
+    [](const MatrixXd& R, VectorXd& r, const VectorXd& d, int iq) 
+  {
+    r.head(iq) = 
+      R.topLeftCorner(iq,iq).triangularView<Upper>().solve(d.head(iq));
+  };
+
+  const auto add_constraint = [&distance](
+    MatrixXd& R, 
+    MatrixXd& J, 
+    VectorXd& d, 
+    int& iq, 
+    double& R_norm)->bool
+  {
+    int n=J.rows();
+#ifdef TRACE_SOLVER
+    std::cerr << "Add constraint " << iq << '/';
+#endif
+    int i, j, k;
+    double cc, ss, h, t1, t2, xny;
+    
+    /* we have to find the Givens rotation which will reduce the element
+      d(j) to zero.
+      if it is already zero we don't have to do anything, except of
+      decreasing j */  
+    for (j = n - 1; j >= iq + 1; j--)
+    {
+      /* The Givens rotation is done with the matrix (cc cs, cs -cc).
+        If cc is one, then element (j) of d is zero compared with element
+        (j - 1). Hence we don't have to do anything. 
+        If cc is zero, then we just have to switch column (j) and column (j - 1) 
+        of J. Since we only switch columns in J, we have to be careful how we
+        update d depending on the sign of gs.
+        Otherwise we have to apply the Givens rotation to these columns.
+        The i - 1 element of d has to be updated to h. */
+      cc = d(j - 1);
+      ss = d(j);
+      h = distance(cc, ss);
+      if (h == 0.0)
+        continue;
+      d(j) = 0.0;
+      ss = ss / h;
+      cc = cc / h;
+      if (cc < 0.0)
+      {
+        cc = -cc;
+        ss = -ss;
+        d(j - 1) = -h;
+      }
+      else
+        d(j - 1) = h;
+      xny = ss / (1.0 + cc);
+      for (k = 0; k < n; k++)
+      {
+        t1 = J(k,j - 1);
+        t2 = J(k,j);
+        J(k,j - 1) = t1 * cc + t2 * ss;
+        J(k,j) = xny * (t1 + J(k,j - 1)) - t2;
+      }
+    }
+    /* update the number of constraints added*/
+    iq++;
+    /* To update R we have to put the iq components of the d vector
+      into column iq - 1 of R
+      */
+    R.col(iq-1).head(iq) = d.head(iq);
+#ifdef TRACE_SOLVER
+    std::cerr << iq << std::endl;
+#endif
+    
+    if (std::abs(d(iq - 1)) <= std::numeric_limits<double>::epsilon() * R_norm)
+    {
+      // problem degenerate
+      return false;
+    }
+    R_norm = std::max<double>(R_norm, std::abs(d(iq - 1)));
+    return true;
+  };
+
+  const auto delete_constraint = [&distance](
+      MatrixXd& R, 
+      MatrixXd& J, 
+      VectorXi& A, 
+      VectorXd& u, 
+      int p, 
+      int& iq, 
+      int l)
+  {
+    int n = R.rows();
+#ifdef TRACE_SOLVER
+    std::cerr << "Delete constraint " << l << ' ' << iq;
+#endif
+    int i, j, k, qq;
+    double cc, ss, h, xny, t1, t2;
+
+    /* Find the index qq for active constraint l to be removed */
+    for (i = p; i < iq; i++)
+      if (A(i) == l)
+      {
+        qq = i;
+        break;
+      }
+
+    /* remove the constraint from the active set and the duals */
+    for (i = qq; i < iq - 1; i++)
+    {
+      A(i) = A(i + 1);
+      u(i) = u(i + 1);
+      R.col(i) = R.col(i+1);
+    }
+
+    A(iq - 1) = A(iq);
+    u(iq - 1) = u(iq);
+    A(iq) = 0; 
+    u(iq) = 0.0;
+    for (j = 0; j < iq; j++)
+      R(j,iq - 1) = 0.0;
+    /* constraint has been fully removed */
+    iq--;
+#ifdef TRACE_SOLVER
+    std::cerr << '/' << iq << std::endl;
+#endif 
+
+    if (iq == 0)
+      return;
+
+    for (j = qq; j < iq; j++)
+    {
+      cc = R(j,j);
+      ss = R(j + 1,j);
+      h = distance(cc, ss);
+      if (h == 0.0)
+        continue;
+      cc = cc / h;
+      ss = ss / h;
+      R(j + 1,j) = 0.0;
+      if (cc < 0.0)
+      {
+        R(j,j) = -h;
+        cc = -cc;
+        ss = -ss;
+      }
+      else
+        R(j,j) = h;
+
+      xny = ss / (1.0 + cc);
+      for (k = j + 1; k < iq; k++)
+      {
+        t1 = R(j,k);
+        t2 = R(j + 1,k);
+        R(j,k) = t1 * cc + t2 * ss;
+        R(j + 1,k) = xny * (t1 + R(j,k)) - t2;
+      }
+      for (k = 0; k < n; k++)
+      {
+        t1 = J(k,j);
+        t2 = J(k,j + 1);
+        J(k,j) = t1 * cc + t2 * ss;
+        J(k,j + 1) = xny * (J(k,j) + t1) - t2;
+      }
+    }
+  };
+
+  int i, j, k, l; /* indices */
+  int ip, me, mi;
+  int n=g0.size();  int p=ce0.size();  int m=ci0.size();  
+  MatrixXd R(G.rows(),G.cols()), J(G.rows(),G.cols());
+  
+  LLT<MatrixXd,Lower> chol(G.cols());
+ 
+  VectorXd s(m+p), z(n), r(m + p), d(n),  np(n), u(m + p);
+  VectorXd x_old(n), u_old(m + p);
+  double f_value, psi, c1, c2, sum, ss, R_norm;
+  const double inf = std::numeric_limits<double>::infinity();
+  double t, t1, t2; /* t is the step length, which is the minimum of the partial step length t1 
+    * and the full step length t2 */
+  VectorXi A(m + p), A_old(m + p), iai(m + p);
+  int q;
+  int iq, iter = 0;
+  bool iaexcl[m + p];
+ 	
+  me = p; /* number of equality constraints */
+  mi = m; /* number of inequality constraints */
+  q = 0;  /* size of the active set A (containing the indices of the active constraints) */
+  
+  /*
+   * Preprocessing phase
+   */
+	
+  /* compute the trace of the original matrix G */
+  c1 = G.trace();
+	
+	/* decompose the matrix G in the form LL^T */
+  chol.compute(G);
+ 
+  /* initialize the matrix R */
+  d.setZero();
+  R.setZero();
+	R_norm = 1.0; /* this variable will hold the norm of the matrix R */
+  
+	/* compute the inverse of the factorized matrix G^-1, this is the initial value for H */
+  // J = L^-T
+  J.setIdentity();
+  J = chol.matrixU().solve(J);
+	c2 = J.trace();
+#ifdef TRACE_SOLVER
+ print_matrix("J", J, n);
+#endif
+  
+	/* c1 * c2 is an estimate for cond(G) */
+  
+	/* 
+   * Find the unconstrained minimizer of the quadratic form 0.5 * x G x + g0 x 
+   * this is a feasible point in the dual space
+	 * x = G^-1 * g0
+   */
+  x = chol.solve(g0);
+  x = -x;
+	/* and compute the current solution value */ 
+	f_value = 0.5 * g0.dot(x);
+#ifdef TRACE_SOLVER
+  std::cerr << "Unconstrained solution: " << f_value << std::endl;
+  print_vector("x", x, n);
+#endif
+  
+	/* Add equality constraints to the working set A */
+  iq = 0;
+	for (i = 0; i < me; i++)
+	{
+    np = CE.col(i);
+    compute_d(d, J, np);
+		update_z(z, J, d,  iq);
+		update_r(R, r, d,  iq);
+#ifdef TRACE_SOLVER
+		print_matrix("R", R, iq);
+		print_vector("z", z, n);
+		print_vector("r", r, iq);
+		print_vector("d", d, n);
+#endif
+    
+    /* compute full step length t2: i.e., the minimum step in primal space s.t. the contraint 
+      becomes feasible */
+    t2 = 0.0;
+    if (std::abs(z.dot(z)) > std::numeric_limits<double>::epsilon()) // i.e. z != 0
+      t2 = (-np.dot(x) - ce0(i)) / z.dot(np);
+    
+    x += t2 * z;
+
+    /* set u = u+ */
+    u(iq) = t2;
+    u.head(iq) -= t2 * r.head(iq);
+    
+    /* compute the new solution value */
+    f_value += 0.5 * (t2 * t2) * z.dot(np);
+    A(i) = -i - 1;
+    
+    if (!add_constraint(R, J, d, iq, R_norm))
+    {
+      // FIXME: it should raise an error
+      // Equality constraints are linearly dependent
+      return false;
+    }
+  }
+  
+	/* set iai = K \ A */
+	for (i = 0; i < mi; i++)
+		iai(i) = i;
+  
+l1:	iter++;
+#ifdef TRACE_SOLVER
+  print_vector("x", x, n);
+#endif
+  /* step 1: choose a violated constraint */
+	for (i = me; i < iq; i++)
+	{
+	  ip = A(i);
+		iai(ip) = -1;
+	}
+	
+	/* compute s(x) = ci^T * x + ci0 for all elements of K \ A */
+	ss = 0.0;
+	psi = 0.0; /* this value will contain the sum of all infeasibilities */
+	ip = 0; /* ip will be the index of the chosen violated constraint */
+	for (i = 0; i < mi; i++)
+	{
+		iaexcl[i] = true;
+		sum = CI.col(i).dot(x) + ci0(i);
+		s(i) = sum;
+		psi += std::min(0.0, sum);
+	}
+#ifdef TRACE_SOLVER
+  print_vector("s", s, mi);
+#endif
+
+    
+	if (std::abs(psi) <= mi * std::numeric_limits<double>::epsilon() * c1 * c2* 100.0)
+	{
+    /* numerically there are not infeasibilities anymore */
+    q = iq;
+		return true;
+  }
+    
+  /* save old values for u, x and A */
+   u_old.head(iq) = u.head(iq);
+   A_old.head(iq) = A.head(iq);
+   x_old = x;
+    
+l2: /* Step 2: check for feasibility and determine a new S-pair */
+	for (i = 0; i < mi; i++)
+	{
+		if (s(i) < ss && iai(i) != -1 && iaexcl[i])
+		{
+			ss = s(i);
+			ip = i;
+		}
+	}
+  if (ss >= 0.0)
+  {
+    q = iq;
+    return true;
+  }
+    
+  /* set np = n(ip) */
+  np = CI.col(ip);
+  /* set u = (u 0)^T */
+  u(iq) = 0.0;
+  /* add ip to the active set A */
+  A(iq) = ip;
+
+#ifdef TRACE_SOLVER
+	std::cerr << "Trying with constraint " << ip << std::endl;
+	print_vector("np", np, n);
+#endif
+    
+l2a:/* Step 2a: determine step direction */
+  /* compute z = H np: the step direction in the primal space (through J, see the paper) */
+  compute_d(d, J, np);
+  update_z(z, J, d, iq);
+  /* compute N* np (if q > 0): the negative of the step direction in the dual space */
+  update_r(R, r, d, iq);
+#ifdef TRACE_SOLVER
+  std::cerr << "Step direction z" << std::endl;
+		print_vector("z", z, n);
+		print_vector("r", r, iq + 1);
+    print_vector("u", u, iq + 1);
+    print_vector("d", d, n);
+    print_ivector("A", A, iq + 1);
+#endif
+    
+  /* Step 2b: compute step length */
+  l = 0;
+  /* Compute t1: partial step length (maximum step in dual space without violating dual feasibility */
+  t1 = inf; /* +inf */
+  /* find the index l s.t. it reaches the minimum of u+(x) / r */
+  for (k = me; k < iq; k++)
+  {
+    double tmp;
+    if (r(k) > 0.0 && ((tmp = u(k) / r(k)) < t1) )
+    {
+      t1 = tmp;
+      l = A(k);
+    }
+  }
+  /* Compute t2: full step length (minimum step in primal space such that the constraint ip becomes feasible */
+  if (std::abs(z.dot(z))  > std::numeric_limits<double>::epsilon()) // i.e. z != 0
+    t2 = -s(ip) / z.dot(np);
+  else
+    t2 = inf; /* +inf */
+
+  /* the step is chosen as the minimum of t1 and t2 */
+  t = std::min(t1, t2);
+#ifdef TRACE_SOLVER
+  std::cerr << "Step sizes: " << t << " (t1 = " << t1 << ", t2 = " << t2 << ") ";
+#endif
+  
+  /* Step 2c: determine new S-pair and take step: */
+  
+  /* case (i): no step in primal or dual space */
+  if (t >= inf)
+  {
+    /* QPP is infeasible */
+    // FIXME: unbounded to raise
+    q = iq;
+    return false;
+  }
+  /* case (ii): step in dual space */
+  if (t2 >= inf)
+  {
+    /* set u = u +  t * [-r 1) and drop constraint l from the active set A */
+    u.head(iq) -= t * r.head(iq);
+    u(iq) += t;
+    iai(l) = l;
+    delete_constraint(R, J, A, u, p, iq, l);
+#ifdef TRACE_SOLVER
+    std::cerr << " in dual space: " 
+      << f_value << std::endl;
+    print_vector("x", x, n);
+    print_vector("z", z, n);
+		print_ivector("A", A, iq + 1);
+#endif
+    goto l2a;
+  }
+  
+  /* case (iii): step in primal and dual space */
+  
+  x += t * z;
+  /* update the solution value */
+  f_value += t * z.dot(np) * (0.5 * t + u(iq));
+  
+  u.head(iq) -= t * r.head(iq);
+  u(iq) += t;
+#ifdef TRACE_SOLVER
+  std::cerr << " in both spaces: " 
+    << f_value << std::endl;
+	print_vector("x", x, n);
+	print_vector("u", u, iq + 1);
+	print_vector("r", r, iq + 1);
+	print_ivector("A", A, iq + 1);
+#endif
+  
+  if (t == t2)
+  {
+#ifdef TRACE_SOLVER
+    std::cerr << "Full step has taken " << t << std::endl;
+    print_vector("x", x, n);
+#endif
+    /* full step has taken */
+    /* add constraint ip to the active set*/
+		if (!add_constraint(R, J, d, iq, R_norm))
+		{
+			iaexcl[ip] = false;
+			delete_constraint(R, J, A, u, p, iq, ip);
+#ifdef TRACE_SOLVER
+      print_matrix("R", R, n);
+      print_ivector("A", A, iq);
+#endif
+			for (i = 0; i < m; i++)
+				iai(i) = i;
+			for (i = 0; i < iq; i++)
+			{
+				A(i) = A_old(i);
+				iai(A(i)) = -1;
+				u(i) = u_old(i);
+			}
+			x = x_old;
+      goto l2; /* go to step 2 */
+		}    
+    else
+      iai(ip) = -1;
+#ifdef TRACE_SOLVER
+    print_matrix("R", R, n);
+    print_ivector("A", A, iq);
+#endif
+    goto l1;
+  }
+  
+  /* a patial step has taken */
+#ifdef TRACE_SOLVER
+  std::cerr << "Partial step has taken " << t << std::endl;
+  print_vector("x", x, n);
+#endif
+  /* drop constraint l */
+	iai(l) = l;
+	delete_constraint(R, J, A, u, p, iq, l);
+#ifdef TRACE_SOLVER
+  print_matrix("R", R, n);
+  print_ivector("A", A, iq);
+#endif
+  
+  s(ip) = CI.col(ip).dot(x) + ci0(ip);
+
+#ifdef TRACE_SOLVER
+  print_vector("s", s, mi);
+#endif
+  goto l2a;
+}

+ 48 - 0
include/igl/copyleft/quadprog.h

@@ -0,0 +1,48 @@
+// 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_COPYLEFT_QUADPROG_H
+#define IGL_COPYLEFT_QUADPROG_H
+
+#include "../igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+  namespace copyleft
+  {
+    // Solve a (dense) quadratric program of the form:
+    //
+    //   min  0.5 x G x + g0 x
+    //   s.t. CE' x + ce0  = 0
+    //   and  CI' x + ci0 >= 0
+    //
+    // Inputs:
+    //   G  #x by #x matrix of quadratic coefficients
+    //   g0  #x vector of linear coefficients
+    //   CE #x by #CE list of linear equality coefficients
+    //   ce0 #CE list of linear equality right-hand sides
+    //   CI #x by #CI list of linear equality coefficients
+    //   ci0 #CI list of linear equality right-hand sides
+    // Outputs:
+    //   x  #x vector of solution values
+    // Returns true iff success
+    IGL_INLINE bool quadprog(
+      const Eigen::MatrixXd & G,  
+      const Eigen::VectorXd & g0,  
+      const Eigen::MatrixXd & CE, 
+      const Eigen::VectorXd & ce0,  
+      const Eigen::MatrixXd & CI, 
+      const Eigen::VectorXd & ci0, 
+      Eigen::VectorXd& x);
+  }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "quadprog.cpp"
+#endif
+
+#endif

+ 8 - 21
include/igl/decimate.cpp

@@ -9,6 +9,7 @@
 #include "collapse_edge.h"
 #include "edge_flaps.h"
 #include "remove_unreferenced.h"
+#include "max_faces_stopping_condition.h"
 #include <iostream>
 
 IGL_INLINE bool igl::decimate(
@@ -19,26 +20,6 @@ IGL_INLINE bool igl::decimate(
   Eigen::MatrixXi & G)
 {
   int m = F.rows();
-  const auto & max_m_faces = 
-    [&max_m,&m](
-    const Eigen::MatrixXd &,
-    const Eigen::MatrixXi &,
-    const Eigen::MatrixXi &,
-    const Eigen::VectorXi &,
-    const Eigen::MatrixXi &,
-    const Eigen::MatrixXi &,
-    const std::set<std::pair<double,int> > &,
-    const std::vector<std::set<std::pair<double,int> >::iterator > &,
-    const Eigen::MatrixXd &,
-    const int,
-    const int,
-    const int,
-    const int,
-    const int)->bool
-    {
-      m-=2;
-      return m<=(int)max_m;
-    };
   const auto & shortest_edge_and_midpoint = [](
     const int e,
     const Eigen::MatrixXd & V,
@@ -53,7 +34,13 @@ IGL_INLINE bool igl::decimate(
     cost = (V.row(E(e,0))-V.row(E(e,1))).norm();
     p = 0.5*(V.row(E(e,0))+V.row(E(e,1)));
   };
-  return decimate(V,F,shortest_edge_and_midpoint,max_m_faces,U,G);
+  return decimate(
+    V,
+    F,
+    shortest_edge_and_midpoint,
+    max_faces_stopping_condition(m,max_m),
+    U,
+    G);
 }
 
 IGL_INLINE bool igl::decimate(

+ 0 - 54
include/igl/marching_cubes.h

@@ -1,54 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2014 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_MARCHINGCUBES_H
-#define IGL_MARCHINGCUBES_H
-#include "igl_inline.h"
-
-#include <Eigen/Core>
-namespace igl 
-{
-  // marching_cubes( values, points, x_res, y_res, z_res, vertices, faces )
-  //
-  // performs marching cubes reconstruction on the grid defined by values, and
-  // points, and generates vertices and faces
-  //
-  // Input:
-  //  values  #number_of_grid_points x 1 array -- the scalar values of an
-  //    implicit function defined on the grid points (<0 in the inside of the
-  //    surface, 0 on the border, >0 outside)
-  //  points  #number_of_grid_points x 3 array -- 3-D positions of the grid
-  //    points, ordered in x,y,z order:
-  //      points[index] = the point at (x,y,z) where :
-  //      x = (index % (xres -1), 
-  //      y = (index / (xres-1)) %(yres-1),
-  //      z = index / (xres -1) / (yres -1) ).
-  //      where x,y,z index x, y, z dimensions
-  //      i.e. index = x + y*xres + z*xres*yres
-  //  xres  resolutions of the grid in x dimension
-  //  yres  resolutions of the grid in y dimension
-  //  zres  resolutions of the grid in z dimension
-  // Output:
-  //   vertices  #V by 3 list of mesh vertex positions
-  //   faces  #F by 3 list of mesh triangle indices
-  //
-  template <typename DerivedV, typename DerivedF>
-  IGL_INLINE void marching_cubes(
-    const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &values,
-    const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 3> &points,
-    const unsigned x_res,
-    const unsigned y_res,
-    const unsigned z_res,
-    Eigen::PlainObjectBase<DerivedV> &vertices,
-    Eigen::PlainObjectBase<DerivedF> &faces);
-}
-
-#ifndef IGL_STATIC_LIBRARY
-#  include "marching_cubes.cpp"
-#endif
-
-#endif

+ 82 - 0
include/igl/max_faces_stopping_condition.cpp

@@ -0,0 +1,82 @@
+#include "max_faces_stopping_condition.h"
+
+IGL_INLINE void igl::max_faces_stopping_condition(
+  int & m,
+  const int max_m,
+  std::function<bool(
+    const Eigen::MatrixXd &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::VectorXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const std::set<std::pair<double,int> > &,
+    const std::vector<std::set<std::pair<double,int> >::iterator > &,
+    const Eigen::MatrixXd &,
+    const int,
+    const int,
+    const int,
+    const int,
+    const int)> & stopping_condition)
+{
+  stopping_condition = 
+    [&max_m,&m](
+    const Eigen::MatrixXd &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::VectorXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const std::set<std::pair<double,int> > &,
+    const std::vector<std::set<std::pair<double,int> >::iterator > &,
+    const Eigen::MatrixXd &,
+    const int,
+    const int,
+    const int,
+    const int,
+    const int)->bool
+    {
+      m-=2;
+      return m<=(int)max_m;
+    };
+}
+
+IGL_INLINE 
+  std::function<bool(
+    const Eigen::MatrixXd &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::VectorXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const std::set<std::pair<double,int> > &,
+    const std::vector<std::set<std::pair<double,int> >::iterator > &,
+    const Eigen::MatrixXd &,
+    const int,
+    const int,
+    const int,
+    const int,
+    const int)> 
+  igl::max_faces_stopping_condition(
+    int & m,
+    const int max_m)
+{
+  std::function<bool(
+    const Eigen::MatrixXd &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::VectorXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const std::set<std::pair<double,int> > &,
+    const std::vector<std::set<std::pair<double,int> >::iterator > &,
+    const Eigen::MatrixXd &,
+    const int,
+    const int,
+    const int,
+    const int,
+    const int)> stopping_condition;
+  max_faces_stopping_condition(
+      m,max_m,stopping_condition);
+  return stopping_condition;
+}

+ 70 - 0
include/igl/max_faces_stopping_condition.h

@@ -0,0 +1,70 @@
+// 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_MAX_FACES_STOPPING_CONDITION_H
+#define IGL_MAX_FACES_STOPPING_CONDITION_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+#include <set>
+#include <functional>
+namespace igl
+{
+  // Stopping condition function compatible with igl::decimate. The outpute
+  // function handle will return true if number of faces is less than max_m
+  //
+  // Inputs:
+  //   m  reference to working variable initially should be set to current
+  //    number of faces.
+  //   max_m  maximum number of faces
+  // Outputs:
+  //   stopping_condition
+  //
+  IGL_INLINE void max_faces_stopping_condition(
+    int & m,
+    const int max_m,
+    std::function<bool(
+      const Eigen::MatrixXd &,
+      const Eigen::MatrixXi &,
+      const Eigen::MatrixXi &,
+      const Eigen::VectorXi &,
+      const Eigen::MatrixXi &,
+      const Eigen::MatrixXi &,
+      const std::set<std::pair<double,int> > &,
+      const std::vector<std::set<std::pair<double,int> >::iterator > &,
+      const Eigen::MatrixXd &,
+      const int,
+      const int,
+      const int,
+      const int,
+      const int)> & stopping_condition);
+  IGL_INLINE 
+    std::function<bool(
+      const Eigen::MatrixXd &,
+      const Eigen::MatrixXi &,
+      const Eigen::MatrixXi &,
+      const Eigen::VectorXi &,
+      const Eigen::MatrixXi &,
+      const Eigen::MatrixXi &,
+      const std::set<std::pair<double,int> > &,
+      const std::vector<std::set<std::pair<double,int> >::iterator > &,
+      const Eigen::MatrixXd &,
+      const int,
+      const int,
+      const int,
+      const int,
+      const int)> 
+    max_faces_stopping_condition(
+      int & m,
+      const int max_m);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "max_faces_stopping_condition.cpp"
+#endif
+#endif
+