浏览代码

Merge remote-tracking branch 'GitHubLibigl/master'

Former-commit-id: aa6b76fd2a4e27a94945600806e732f79561f679
Wesley Ranger 9 年之前
父节点
当前提交
9c76e328c2

+ 1 - 0
.gitignore

@@ -94,3 +94,4 @@ python/build3
 *.pyc
 python/build4
 python/scripts/generated
+python/builddebug

+ 1 - 1
.travis.yml

@@ -11,7 +11,7 @@ matrix:
         - cd python
         - mkdir build
         - cd build
-        - cmake -DCMAKE_CXX_COMPILER=g++-4.8 -DCMAKE_C_COMPILER=gcc-4.8 -DLIBIGL_WITH_EMBREE=OFF ../
+        - cmake -DCMAKE_CXX_COMPILER=g++-4.8 -DCMAKE_C_COMPILER=gcc-4.8 -DLIBIGL_WITH_EMBREE=OFF -DLIBIGL_USE_STATIC_LIBRARY=ON ../
         - make -j 2
         - cd ../../
         - cd tutorial

+ 2 - 2
README.md

@@ -23,8 +23,8 @@ It is **a header-only library**. You do not need to compile anything to use,
 just include igl headers (e.g. `#include <igl/cotmatrix.h>`) and run.  Each
 header file contains a single function (e.g. `igl/cotmatrix.h` contains
 `igl::cotmatrix()`). Most are tailored to operate on a generic triangle mesh
-stored in an n-by-3 matrix of vertex positions V and an m-by-3 matrix of
-triangle indices F.
+stored in an n-by-3 matrix of vertex positions `V` and an m-by-3 matrix of
+triangle indices `F`.
 
 _Optionally_ the library may also be [pre-compiled](optional/) into a statically
 linked library, for faster compile times with your projects. This only effects

+ 19 - 32
include/igl/ambient_occlusion.cpp

@@ -10,7 +10,7 @@
 #include "ray_mesh_intersect.h"
 #include "EPS.h"
 #include "Hit.h"
-#include <thread>
+#include "parallel_for.h"
 #include <functional>
 #include <vector>
 #include <algorithm>
@@ -38,40 +38,27 @@ IGL_INLINE void igl::ambient_occlusion(
   // Embree seems to be parallel when constructing but not when tracing rays
   const MatrixXf D = random_dir_stratified(num_samples).cast<float>();
 
-  const size_t nthreads = n<1000?1:std::thread::hardware_concurrency();
+  const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p)
   {
-    std::vector<std::thread> threads(nthreads);
-    for(int t = 0;t<nthreads;t++)
+    const Vector3f origin = P.row(p).template cast<float>();
+    const Vector3f normal = N.row(p).template cast<float>();
+    int num_hits = 0;
+    for(int s = 0;s<num_samples;s++)
     {
-      threads[t] = std::thread(std::bind(
-        [&P,&N,&shoot_ray,&S,&num_samples,&D](const int bi, const int ei, const int t)
-        {
-          // loop over mesh vertices in this chunk
-          for(int p = bi;p<ei;p++)
-          {
-            const Vector3f origin = P.row(p).template cast<float>();
-            const Vector3f normal = N.row(p).template cast<float>();
-            int num_hits = 0;
-            for(int s = 0;s<num_samples;s++)
-            {
-              Vector3f d = D.row(s);
-              if(d.dot(normal) < 0)
-              {
-                // reverse ray
-                d *= -1;
-              }
-              if(shoot_ray(origin,d))
-              {
-                num_hits++;
-              }
-            }
-            S(p) = (double)num_hits/(double)num_samples;
-          }
-        },t*n/nthreads,(t+1)==nthreads?n:(t+1)*n/nthreads,t));
+      Vector3f d = D.row(s);
+      if(d.dot(normal) < 0)
+      {
+        // reverse ray
+        d *= -1;
+      }
+      if(shoot_ray(origin,d))
+      {
+        num_hits++;
+      }
     }
-    std::for_each(threads.begin(),threads.end(),[](std::thread& x){x.join();});
-  }
-
+    S(p) = (double)num_hits/(double)num_samples;
+  };
+  parallel_for(n,inner,1000);
 }
 
 template <

+ 2 - 0
include/igl/copyleft/cgal/mesh_boolean.cpp

@@ -443,6 +443,8 @@ template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_n
 template bool igl::copyleft::cgal::mesh_boolean<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> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, std::function<int (Eigen::Matrix<int, 1, -1, 1, 1, -1>)> const&, std::function<int (int, int)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, 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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<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<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&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<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<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&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #undef IGL_STATIC_LIBRARY
 #include "../../remove_unreferenced.cpp"
 template void igl::remove_unreferenced<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);

+ 16 - 22
include/igl/doublearea.cpp

@@ -7,6 +7,7 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "doublearea.h"
 #include "edge_lengths.h"
+#include "parallel_for.h"
 #include "sort.h"
 #include <cassert>
 #include <iostream>
@@ -148,28 +149,21 @@ IGL_INLINE void igl::doublearea(
   assert((Index)s.rows() == m);
   // resize output
   dblA.resize(l.rows(),1);
-  // Minimum number of iterms per openmp thread
-  #ifndef IGL_OMP_MIN_VALUE
-  #  define IGL_OMP_MIN_VALUE 1000
-  #endif
-  #pragma omp parallel for if (m>IGL_OMP_MIN_VALUE)
-  for(Index i = 0;i<m;i++)
-  {
-    //// Heron's formula for area
-    //const typename Derivedl::Scalar arg =
-    //  s(i)*(s(i)-l(i,0))*(s(i)-l(i,1))*(s(i)-l(i,2));
-    //assert(arg>=0);
-    //dblA(i) = 2.0*sqrt(arg);
-    // Kahan's Heron's formula
-    const typename Derivedl::Scalar arg =
-      (l(i,0)+(l(i,1)+l(i,2)))*
-      (l(i,2)-(l(i,0)-l(i,1)))*
-      (l(i,2)+(l(i,0)-l(i,1)))*
-      (l(i,0)+(l(i,1)-l(i,2)));
-    dblA(i) = 2.0*0.25*sqrt(arg);
-    assert( l(i,2) - (l(i,0)-l(i,1)) && "FAILED KAHAN'S ASSERTION");
-    assert(dblA(i) == dblA(i) && "DOUBLEAREA() PRODUCED NaN");
-  }
+  parallel_for(
+    m,
+    [&l,&dblA](const int i)
+    {
+      // Kahan's Heron's formula
+      const typename Derivedl::Scalar arg =
+        (l(i,0)+(l(i,1)+l(i,2)))*
+        (l(i,2)-(l(i,0)-l(i,1)))*
+        (l(i,2)+(l(i,0)-l(i,1)))*
+        (l(i,0)+(l(i,1)-l(i,2)));
+      dblA(i) = 2.0*0.25*sqrt(arg);
+      assert( l(i,2) - (l(i,0)-l(i,1)) && "FAILED KAHAN'S ASSERTION");
+      assert(dblA(i) == dblA(i) && "DOUBLEAREA() PRODUCED NaN");
+    },
+    1000l);
 }
 
 template <typename DerivedV, typename DerivedF, typename DeriveddblA>

+ 22 - 21
include/igl/edge_lengths.cpp

@@ -6,6 +6,7 @@
 // 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 "edge_lengths.h"
+#include "parallel_for.h"
 #include <iostream>
 
 template <typename DerivedV, typename DerivedF, typename DerivedL>
@@ -16,10 +17,6 @@ IGL_INLINE void igl::edge_lengths(
 {
   using namespace std;
   const int m = F.rows();
-  // Minimum number of iterms per openmp thread
-#ifndef IGL_OMP_MIN_VALUE
-#  define IGL_OMP_MIN_VALUE 1000
-#endif
   switch(F.cols())
   {
     case 2:
@@ -35,29 +32,33 @@ IGL_INLINE void igl::edge_lengths(
     {
       L.resize(m,3);
       // loop over faces
-      #pragma omp parallel for if (m>IGL_OMP_MIN_VALUE)
-      for(int i = 0;i<m;i++)
-      {
-        L(i,0) = (V.row(F(i,1))-V.row(F(i,2))).norm();
-        L(i,1) = (V.row(F(i,2))-V.row(F(i,0))).norm();
-        L(i,2) = (V.row(F(i,0))-V.row(F(i,1))).norm();
-      }
+      parallel_for(
+        m,
+        [&V,&F,&L](const int i)
+        {
+          L(i,0) = (V.row(F(i,1))-V.row(F(i,2))).norm();
+          L(i,1) = (V.row(F(i,2))-V.row(F(i,0))).norm();
+          L(i,2) = (V.row(F(i,0))-V.row(F(i,1))).norm();
+        },
+        1000);
       break;
     }
     case 4:
     {
       L.resize(m,6);
       // loop over faces
-      #pragma omp parallel for if (m>IGL_OMP_MIN_VALUE)
-      for(int i = 0;i<m;i++)
-      {
-        L(i,0) = (V.row(F(i,3))-V.row(F(i,0))).norm();
-        L(i,1) = (V.row(F(i,3))-V.row(F(i,1))).norm();
-        L(i,2) = (V.row(F(i,3))-V.row(F(i,2))).norm();
-        L(i,3) = (V.row(F(i,1))-V.row(F(i,2))).norm();
-        L(i,4) = (V.row(F(i,2))-V.row(F(i,0))).norm();
-        L(i,5) = (V.row(F(i,0))-V.row(F(i,1))).norm();
-      }
+      parallel_for(
+        m,
+        [&V,&F,&L](const int i)
+        {
+          L(i,0) = (V.row(F(i,3))-V.row(F(i,0))).norm();
+          L(i,1) = (V.row(F(i,3))-V.row(F(i,1))).norm();
+          L(i,2) = (V.row(F(i,3))-V.row(F(i,2))).norm();
+          L(i,3) = (V.row(F(i,1))-V.row(F(i,2))).norm();
+          L(i,4) = (V.row(F(i,2))-V.row(F(i,0))).norm();
+          L(i,5) = (V.row(F(i,0))-V.row(F(i,1))).norm();
+        },
+        1000);
       break;
     }
     default:

+ 13 - 21
include/igl/internal_angles.cpp

@@ -8,6 +8,7 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "internal_angles.h"
 #include "edge_lengths.h"
+#include "parallel_for.h"
 #include "get_seconds.h"
 
 template <typename DerivedV, typename DerivedF, typename DerivedK>
@@ -70,28 +71,19 @@ IGL_INLINE void igl::internal_angles(
   assert(L.cols() == 3 && "Edge-lengths should come from triangles");
   const Index m = L.rows();
   K.resize(m,3);
-  //for(int d = 0;d<3;d++)
-  //{
-  //  const auto & s1 = L.col(d).array();
-  //  const auto & s2 = L.col((d+1)%3).array();
-  //  const auto & s3 = L.col((d+2)%3).array();
-  //  K.col(d) = ((s3.square() + s2.square() - s1.square())/(2.*s3*s2)).acos();
-  //}
-  // Minimum number of iterms per openmp thread
-  #ifndef IGL_OMP_MIN_VALUE
-  #  define IGL_OMP_MIN_VALUE 1000
-  #endif
-  #pragma omp parallel for if (m>IGL_OMP_MIN_VALUE)
-  for(Index f = 0;f<m;f++)
-  {
-    for(size_t d = 0;d<3;d++)
+  parallel_for(
+    m,
+    [&L,&K](const Index f)
     {
-      const auto & s1 = L(f,d);
-      const auto & s2 = L(f,(d+1)%3);
-      const auto & s3 = L(f,(d+2)%3);
-      K(f,d) = acos((s3*s3 + s2*s2 - s1*s1)/(2.*s3*s2));
-    }
-  }
+      for(size_t d = 0;d<3;d++)
+      {
+        const auto & s1 = L(f,d);
+        const auto & s2 = L(f,(d+1)%3);
+        const auto & s3 = L(f,(d+2)%3);
+        K(f,d) = acos((s3*s3 + s2*s2 - s1*s1)/(2.*s3*s2));
+      }
+    },
+    1000l);
 }
 
 #ifdef IGL_STATIC_LIBRARY

+ 180 - 0
include/igl/parallel_for.h

@@ -0,0 +1,180 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2016 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_PARALLEL_FOR_H
+#define IGL_PARALLEL_FOR_H
+#include "igl_inline.h"
+#include <functional>
+
+namespace igl
+{
+  // PARALLEL_FOR Functional implementation of a basic, open-mp style, parallel
+  // for loop. If the inner block of a for-loop can be rewritten/encapsulated in
+  // a single (anonymous/lambda) function call `func` so that the serial code
+  // looks like:
+  // 
+  //     for(int i = 0;i<loop_size;i++)
+  //     {
+  //       func(i);
+  //     }
+  //
+  // then `parallel_for(loop_size,func,min_parallel)` will use as many threads as
+  // available on the current hardware to parallelize this for loop so long as
+  // loop_size<min_parallel, otherwise it will just use a serial for loop.
+  //
+  // Inputs:
+  //   loop_size  number of iterations. I.e. for(int i = 0;i<loop_size;i++) ...
+  //   func  function handle taking iteration index as only arguement to compute
+  //     inner block of for loop I.e. for(int i ...){ func(i); }
+  //   min_parallel  min size of loop_size such that parallel (non-serial)
+  //     thread pooling should be attempted {0}
+  // Returns true iff thread pool was invoked
+  template<typename Index, typename FunctionType >
+  inline bool parallel_for(
+    const Index loop_size, 
+    const FunctionType & func,
+    const size_t min_parallel=0);
+  // PARALLEL_FOR Functional implementation of an open-mp style, parallel for
+  // loop with accumulation. For example, serial code separated into n chunks
+  // (each to be parallelized with a thread) might look like:
+  //     
+  //     Eigen::VectorXd S;
+  //     const auto & prep_func = [&S](int n){ S = Eigen:VectorXd::Zero(n); };
+  //     const auto & func = [&X,&S](int i, int t){ S(t) += X(i); };
+  //     const auto & accum_func = [&S,&sum](int t){ sum += S(t); };
+  //     prep_func(n);
+  //     for(int i = 0;i<loop_size;i++)
+  //     {
+  //       func(i,i%n);
+  //     }
+  //     double sum = 0;
+  //     for(int t = 0;t<n;t++)
+  //     {
+  //       accum_func(t);
+  //     }
+  // 
+  // Inputs:
+  //   loop_size  number of iterations. I.e. for(int i = 0;i<loop_size;i++) ...
+  //   prep_func function handle taking n >= number of threads as only
+  //     argument 
+  //   func  function handle taking iteration index i and thread id t as only
+  //     arguements to compute inner block of for loop I.e. 
+  //     for(int i ...){ func(i,t); }
+  //   accum_func  function handle taking thread index as only argument, to be
+  //     called after all calls of func, e.g., for serial accumulation across
+  //     all n (potential) threads, see n in description of prep_func.
+  //   min_parallel  min size of loop_size such that parallel (non-serial)
+  //     thread pooling should be attempted {0}
+  // Returns true iff thread pool was invoked
+  template<
+    typename Index, 
+    typename PrepFunctionType, 
+    typename FunctionType, 
+    typename AccumFunctionType 
+    >
+  inline bool parallel_for(
+    const Index loop_size, 
+    const PrepFunctionType & prep_func,
+    const FunctionType & func,
+    const AccumFunctionType & accum_func,
+    const size_t min_parallel=0);
+}
+
+// Implementation
+
+#include <cmath>
+#include <cassert>
+#include <thread>
+#include <vector>
+#include <algorithm>
+
+template<typename Index, typename FunctionType >
+inline bool igl::parallel_for(
+  const Index loop_size, 
+  const FunctionType & func,
+  const size_t min_parallel)
+{
+  using namespace std;
+  // no op preparation/accumulation
+  const auto & no_op = [](const size_t /*n/t*/){};
+  // two-parameter wrapper ignoring thread id
+  const auto & wrapper = [&func](Index i,size_t /*t*/){ func(i); };
+  return parallel_for(loop_size,no_op,wrapper,no_op,min_parallel);
+}
+
+template<
+  typename Index, 
+  typename PreFunctionType,
+  typename FunctionType, 
+  typename AccumFunctionType>
+inline bool igl::parallel_for(
+  const Index loop_size, 
+  const PreFunctionType & prep_func,
+  const FunctionType & func,
+  const AccumFunctionType & accum_func,
+  const size_t min_parallel)
+{
+  assert(loop_size>=0);
+  if(loop_size==0) return false;
+  // Estimate number of threads in the pool
+  // http://ideone.com/Z7zldb
+  const static size_t sthc = std::thread::hardware_concurrency();
+  const size_t nthreads = loop_size<min_parallel?0:(sthc==0?8:sthc);
+  if(nthreads==0)
+  {
+    // serial
+    prep_func(1);
+    for(Index i = 0;i<loop_size;i++) func(i,0);
+    accum_func(0);
+    return false;
+  }else
+  {
+    // Size of a slice for the range functions
+    Index slice = 
+      std::max(
+        (Index)std::round((loop_size+1)/static_cast<double>(nthreads)),(Index)1);
+ 
+    // [Helper] Inner loop
+    const auto & range = [&func](const Index k1, const Index k2, const size_t t)
+    {
+      for(Index k = k1; k < k2; k++) func(k,t);
+    };
+    prep_func(nthreads);
+    // Create pool and launch jobs
+    std::vector<std::thread> pool;
+    pool.reserve(nthreads);
+    // Inner range extents
+    Index i1 = 0;
+    Index i2 = std::min(0 + slice, loop_size);
+    {
+      size_t t = 0;
+      for (; t+1 < nthreads && i1 < loop_size; ++t)
+      {
+        pool.emplace_back(range, i1, i2, t);
+        i1 = i2;
+        i2 = std::min(i2 + slice, loop_size);
+      }
+      if (i1 < loop_size)
+      {
+        pool.emplace_back(range, i1, loop_size, t);
+      }
+    }
+    // Wait for jobs to finish
+    for (std::thread &t : pool) if (t.joinable()) t.join();
+    // Accumulate across threads
+    for(size_t t = 0;t<nthreads;t++)
+    {
+      accum_func(t);
+    }
+    return true;
+  }
+}
+ 
+//#ifndef IGL_STATIC_LIBRARY
+//#include "parallel_for.cpp"
+//#endif
+#endif

+ 23 - 11
include/igl/per_vertex_normals.cpp

@@ -10,6 +10,7 @@
 #include "get_seconds.h"
 #include "per_face_normals.h"
 #include "doublearea.h"
+#include "parallel_for.h"
 #include "internal_angles.h"
 
 template <typename DerivedV, typename DerivedF>
@@ -68,23 +69,34 @@ IGL_INLINE void igl::per_vertex_normals(
   }
 
   // loop over faces
-  const int Frows = F.rows();
-//// Minimum number of iterms per openmp thread
-//#ifndef IGL_OMP_MIN_VALUE
-//#  define IGL_OMP_MIN_VALUE 1000
-//#endif
-//#pragma omp parallel for if (Frows>IGL_OMP_MIN_VALUE)
-  for(int i = 0; i < Frows;i++)
+  for(int i = 0;i<F.rows();i++)
   {
     // throw normal at each corner
     for(int j = 0; j < 3;j++)
     {
-      // Q: Does this need to be critical?
-      // A: Yes. Different (i,j)'s could produce the same F(i,j)
-//#pragma omp critical
-      N.row(F(i,j)) += W(i,j)*FN.row(i);
+      N.row(F(i,j)) += W(i,j) * FN.row(i);
     }
   }
+
+  //// loop over faces
+  //std::mutex critical;
+  //std::vector<DerivedN> NN;
+  //parallel_for(
+  //  F.rows(),
+  //  [&NN,&N](const size_t n){ NN.resize(n,DerivedN::Zero(N.rows(),3));},
+  //  [&F,&W,&FN,&NN,&critical](const int i, const size_t t)
+  //  {
+  //    // throw normal at each corner
+  //    for(int j = 0; j < 3;j++)
+  //    {
+  //      // Q: Does this need to be critical?
+  //      // A: Yes. Different (i,j)'s could produce the same F(i,j)
+  //      NN[t].row(F(i,j)) += W(i,j) * FN.row(i);
+  //    }
+  //  },
+  //  [&N,&NN](const size_t t){ N += NN[t]; },
+  //  1000l);
+
   // take average via normalization
   N.rowwise().normalize();
 }

+ 1 - 0
include/igl/resolve_duplicated_faces.cpp

@@ -86,4 +86,5 @@ IGL_INLINE void igl::resolve_duplicated_faces(
 #ifdef IGL_STATIC_LIBRARY
 template void igl::resolve_duplicated_faces<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<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::resolve_duplicated_faces<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::resolve_duplicated_faces<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<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

+ 1 - 0
include/igl/slice.cpp

@@ -280,4 +280,5 @@ template void igl::slice<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<in
 template void igl::slice<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::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::slice<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<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> >&);
 template void igl::slice<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> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

+ 66 - 87
include/igl/sort.cpp

@@ -11,12 +11,11 @@
 #include "reorder.h"
 #include "IndexComparison.h"
 #include "colon.h"
+#include "parallel_for.h"
 
 #include <cassert>
 #include <algorithm>
 #include <iostream>
-#include <thread>
-#include <functional>
 
 template <typename DerivedX, typename DerivedY, typename DerivedIX>
 IGL_INLINE void igl::sort(
@@ -223,106 +222,86 @@ IGL_INLINE void igl::sort3(
     IX.col(2).setConstant(2);// = Eigen::PlainObjectBase<DerivedIX>::Ones (IX.rows(),1);
   }
 
-  const int n = num_outer;
-  const size_t nthreads = n<8000?1:std::thread::hardware_concurrency();
+
+  const auto & inner = [&IX,&Y,&dim,&ascending](const Index & i)
   {
-    std::vector<std::thread> threads(nthreads<=1?0:nthreads);
-    for(int t = 0;t<nthreads;t++)
+    YScalar & a = (dim==1 ? Y(0,i) : Y(i,0));
+    YScalar & b = (dim==1 ? Y(1,i) : Y(i,1));
+    YScalar & c = (dim==1 ? Y(2,i) : Y(i,2));
+    Index & ai = (dim==1 ? IX(0,i) : IX(i,0));
+    Index & bi = (dim==1 ? IX(1,i) : IX(i,1));
+    Index & ci = (dim==1 ? IX(2,i) : IX(i,2));
+    if(ascending)
     {
-      const auto & inner =  
-        [&X,&Y,&IX,&dim,&ascending](const int bi, const int ei, const int t)
+      // 123 132 213 231 312 321
+      if(a > b)
+      {
+        std::swap(a,b);
+        std::swap(ai,bi);
+      }
+      // 123 132 123 231 132 231
+      if(b > c)
       {
-        // loop over columns (or rows)
-        for(int i = bi;i<ei;i++)
+        std::swap(b,c);
+        std::swap(bi,ci);
+        // 123 123 123 213 123 213
+        if(a > b)
         {
-          YScalar & a = (dim==1 ? Y(0,i) : Y(i,0));
-          YScalar & b = (dim==1 ? Y(1,i) : Y(i,1));
-          YScalar & c = (dim==1 ? Y(2,i) : Y(i,2));
-          Index & ai = (dim==1 ? IX(0,i) : IX(i,0));
-          Index & bi = (dim==1 ? IX(1,i) : IX(i,1));
-          Index & ci = (dim==1 ? IX(2,i) : IX(i,2));
-          if(ascending)
-          {
-            // 123 132 213 231 312 321
-            if(a > b)
-            {
-              std::swap(a,b);
-              std::swap(ai,bi);
-            }
-            // 123 132 123 231 132 231
-            if(b > c)
-            {
-              std::swap(b,c);
-              std::swap(bi,ci);
-              // 123 123 123 213 123 213
-              if(a > b)
-              {
-                std::swap(a,b);
-                std::swap(ai,bi);
-              }
-              // 123 123 123 123 123 123
-            }
-          }else
-          {
-            // 123 132 213 231 312 321
-            if(a < b)
-            {
-              std::swap(a,b);
-              std::swap(ai,bi);
-            }
-            // 213 312 213 321 312 321
-            if(b < c)
-            {
-              std::swap(b,c);
-              std::swap(bi,ci);
-              // 231 321 231 321 321 321
-              if(a < b)
-              {
-                std::swap(a,b);
-                std::swap(ai,bi);
-              }
-              // 321 321 321 321 321 321
-            }
-          }
+          std::swap(a,b);
+          std::swap(ai,bi);
         }
-      };
-      if(nthreads == 1)
+        // 123 123 123 123 123 123
+      }
+    }else
+    {
+      // 123 132 213 231 312 321
+      if(a < b)
       {
-        inner(0,n,0);
-      }else
+        std::swap(a,b);
+        std::swap(ai,bi);
+      }
+      // 213 312 213 321 312 321
+      if(b < c)
       {
-        threads[t] = std::thread(
-          std::bind(inner,t*n/nthreads,(t+1)==nthreads?n:(t+1)*n/nthreads,t));
+        std::swap(b,c);
+        std::swap(bi,ci);
+        // 231 321 231 321 321 321
+        if(a < b)
+        {
+          std::swap(a,b);
+          std::swap(ai,bi);
+        }
+        // 321 321 321 321 321 321
       }
     }
-    std::for_each(threads.begin(),threads.end(),[](std::thread& x){x.join();});
-  }
+  };
+  parallel_for(num_outer,inner,16000);
 }
 
 template <class T>
 IGL_INLINE void igl::sort(
-  const std::vector<T> & unsorted,
-  const bool ascending,
-  std::vector<T> & sorted,
-  std::vector<size_t> & index_map)
+const std::vector<T> & unsorted,
+const bool ascending,
+std::vector<T> & sorted,
+std::vector<size_t> & index_map)
 {
-  // Original unsorted index map
-  index_map.resize(unsorted.size());
-  for(size_t i=0;i<unsorted.size();i++)
-  {
-    index_map[i] = i;
-  }
-  // Sort the index map, using unsorted for comparison
-  std::sort(
-    index_map.begin(),
-    index_map.end(),
-    igl::IndexLessThan<const std::vector<T>& >(unsorted));
+// Original unsorted index map
+index_map.resize(unsorted.size());
+for(size_t i=0;i<unsorted.size();i++)
+{
+  index_map[i] = i;
+}
+// Sort the index map, using unsorted for comparison
+std::sort(
+  index_map.begin(),
+  index_map.end(),
+  igl::IndexLessThan<const std::vector<T>& >(unsorted));
 
-  // if not ascending then reverse
-  if(!ascending)
-  {
-    std::reverse(index_map.begin(),index_map.end());
-  }
+// if not ascending then reverse
+if(!ascending)
+{
+  std::reverse(index_map.begin(),index_map.end());
+}
   // make space for output without clobbering
   sorted.resize(unsorted.size());
   // reorder unsorted into sorted using index map

+ 23 - 21
include/igl/triangle_triangle_adjacency.cpp

@@ -9,6 +9,7 @@
 #include "is_edge_manifold.h"
 #include "all_edges.h"
 #include "unique_simplices.h"
+#include "parallel_for.h"
 #include "unique_edge_map.h"
 #include <algorithm>
 #include <iostream>
@@ -172,36 +173,37 @@ template <
   }
 
   // No race conditions because TT*[f][c]'s are in bijection with e's
-  // Minimum number of iterms per openmp thread
+  // Minimum number of items per thread
   //const size_t num_e = E.rows();
-# ifndef IGL_OMP_MIN_VALUE
-#   define IGL_OMP_MIN_VALUE 1000
-# endif
-# pragma omp parallel for if (m>IGL_OMP_MIN_VALUE)
   // Slightly better memory access than loop over E
-  for(Index f = 0;f<(Index)m;f++)
-  {
-    for(Index c = 0;c<3;c++)
+  igl::parallel_for(
+    m,
+    [&](const Index & f)
     {
-      const Index e = f + m*c;
-      //const Index c = e/m;
-      const vector<uE2EType> & N = uE2E[EMAP(e)];
-      for(const auto & ne : N)
+      for(Index c = 0;c<3;c++)
       {
-        const Index nf = ne%m;
-        // don't add self
-        if(nf != f)
+        const Index e = f + m*c;
+        //const Index c = e/m;
+        const vector<uE2EType> & N = uE2E[EMAP(e)];
+        for(const auto & ne : N)
         {
-          TT[f][c].push_back(nf);
-          if(construct_TTi)
+          const Index nf = ne%m;
+          // don't add self
+          if(nf != f)
           {
-            const Index nc = ne/m;
-            TTi[f][c].push_back(nc);
+            TT[f][c].push_back(nf);
+            if(construct_TTi)
+            {
+              const Index nc = ne/m;
+              TTi[f][c].push_back(nc);
+            }
           }
         }
       }
-    }
-  }
+    },
+    1000ul);
+
+
 }
 
 #ifdef IGL_STATIC_LIBRARY

+ 3 - 12
include/igl/unique_simplices.cpp

@@ -1,6 +1,6 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // 
-// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+// Copyright (C) 2016 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 
@@ -8,7 +8,7 @@
 #include "unique_simplices.h"
 #include "sort.h"
 #include "unique.h"
-#include "get_seconds.h"
+#include "parallel_for.h"
 
 template <
   typename DerivedF,
@@ -31,16 +31,7 @@ IGL_INLINE void igl::unique_simplices(
   igl::unique_rows(sortF,C,IA,IC);
   FF.resize(IA.size(),F.cols());
   const size_t mff = FF.rows();
-  // Minimum number of iterms per openmp thread
-  #ifndef IGL_OMP_MIN_VALUE
-  #  define IGL_OMP_MIN_VALUE 1000
-  #endif
-  #pragma omp parallel for if (mff>IGL_OMP_MIN_VALUE)
-  // Copy into output
-  for(size_t i = 0;i<mff;i++)
-  {
-    FF.row(i) = F.row(IA(i));
-  }
+  parallel_for(mff,[&F,&IA,&FF](size_t & i){FF.row(i) = F.row(IA(i));},1000ul);
 }
 
 template <

+ 11 - 2
python/CMakeLists.txt

@@ -62,7 +62,7 @@ option(LIBIGL_WITH_LIM              "Use LIM"            ON)
 option(LIBIGL_WITH_MATLAB           "Use Matlab"         OFF)
 option(LIBIGL_WITH_MOSEK            "Use MOSEK"          OFF)
 option(LIBIGL_WITH_BBW              "Use BBW"            ON)
-option(LIBIGL_WITH_OPENGL_AND_PNG   "Use OpenGL"         ON)
+option(LIBIGL_WITH_PNG              "Use PNG"            ON)
 option(LIBIGL_WITH_TETGEN           "Use Tetgen"         ON)
 option(LIBIGL_WITH_TRIANGLE         "Use Triangle"       ON)
 option(LIBIGL_WITH_XML              "Use XML"            ON)
@@ -107,6 +107,16 @@ if (LIBIGL_WITH_TRIANGLE)
   list(APPEND SHARED_SOURCES "modules/py_igl_triangle.cpp")
 endif ()
 
+if (LIBIGL_WITH_CGAL)
+  add_definitions(-DPY_CGAL)
+  list(APPEND SHARED_SOURCES "modules/copyleft/py_igl_cgal.cpp")
+endif ()
+
+if (LIBIGL_WITH_PNG)
+  add_definitions(-DPY_PNG)
+  list(APPEND SHARED_SOURCES "modules/py_igl_png.cpp")
+endif ()
+
 
 ## Prepare the python library
 add_library(pyigl SHARED
@@ -180,4 +190,3 @@ elseif (UNIX)
     endif()
   endif()
 endif()
-

+ 18 - 0
python/modules/copyleft/py_igl_cgal.cpp

@@ -0,0 +1,18 @@
+//#include <Eigen/Geometry>
+//#include <Eigen/Dense>
+//#include <Eigen/Sparse>
+
+
+#include "../../python_shared.h"
+
+#include <igl/copyleft/cgal/mesh_boolean.h>
+
+
+void python_export_igl_cgal(py::module &me) {
+
+  py::module m = me.def_submodule(
+    "cgal", "Wrappers for libigl functions that use cgal");
+
+  #include "../../py_igl/copyleft/cgal/py_mesh_boolean.cpp"
+
+}

+ 16 - 0
python/modules/py_igl_png.cpp

@@ -0,0 +1,16 @@
+
+#include "../python_shared.h"
+
+#include <igl/png/readPNG.h>
+#include <igl/png/writePNG.h>
+
+
+void python_export_igl_png(py::module &me) {
+
+  py::module m = me.def_submodule(
+    "png", "Wrappers for libigl functions that use png");
+
+  #include "../py_igl/png/py_readPNG.cpp"
+  #include "../py_igl/png/py_writePNG.cpp"
+
+}

+ 12 - 0
python/modules/py_igl_viewer.cpp

@@ -6,6 +6,7 @@
 #include <igl/viewer/Viewer.h>
 #include <igl/viewer/ViewerCore.h>
 #include <igl/viewer/ViewerData.h>
+#include <igl/viewer/OpenGL_state.h>
 #include <igl/serialize.h>
 
 void python_export_igl_viewer(py::module &m)
@@ -118,6 +119,16 @@ py::enum_<igl::viewer::ViewerData::DirtyFlags>(viewerdata_class, "DirtyFlags")
 
     ;
 
+//////////////////////// OPENGL_State
+
+py::class_<igl::viewer::OpenGL_state> opengl_state_class(me, "OpenGL_state");
+
+    opengl_state_class
+    .def(py::init<>())
+    .def("init", &igl::viewer::OpenGL_state::init)
+
+    ;
+
 //////////////////////// CORE
 
 py::class_<igl::viewer::ViewerCore> viewercore_class(me, "ViewerCore");
@@ -311,6 +322,7 @@ py::class_<igl::viewer::ViewerCore> viewercore_class(me, "ViewerCore");
     .def(py::init<>())
     .def_readwrite("data", &igl::viewer::Viewer::data)
     .def_readwrite("core", &igl::viewer::Viewer::core)
+    .def_readwrite("opengl", &igl::viewer::Viewer::opengl)
     .def("launch", &igl::viewer::Viewer::launch, py::arg("resizable") = true, py::arg("fullscreen") = false)
     .def("launch_init", &igl::viewer::Viewer::launch_init, py::arg("resizable") = true, py::arg("fullscreen") = false)
     .def("launch_rendering", &igl::viewer::Viewer::launch_rendering, py::arg("loop") = true)

文件差异内容过多而无法显示
+ 385 - 564
python/py_doc.cpp


+ 65 - 62
python/py_doc.h

@@ -1,77 +1,80 @@
-extern const char *__doc_igl_principal_curvature;
-extern const char *__doc_igl_local_basis;
-extern const char *__doc_igl_signed_distance;
-extern const char *__doc_igl_signed_distance_pseudonormal;
-extern const char *__doc_igl_signed_distance_winding_number;
-extern const char *__doc_igl_triangle_triangulate;
-extern const char *__doc_igl_embree_ambient_occlusion;
-extern const char *__doc_igl_cotmatrix;
-extern const char *__doc_igl_floor;
-extern const char *__doc_igl_slice;
-extern const char *__doc_igl_per_face_normals;
-extern const char *__doc_igl_per_face_normals_stable;
-extern const char *__doc_igl_quad_planarity;
-extern const char *__doc_igl_readOFF;
-extern const char *__doc_igl_per_vertex_normals;
-extern const char *__doc_igl_sortrows;
+extern const char *__doc_igl_active_set;
+extern const char *__doc_igl_arap_precomputation;
+extern const char *__doc_igl_arap_solve;
+extern const char *__doc_igl_avg_edge_length;
 extern const char *__doc_igl_barycenter;
-extern const char *__doc_igl_jet;
+extern const char *__doc_igl_barycentric_coordinates;
+extern const char *__doc_igl_boundary_facets;
+extern const char *__doc_igl_boundary_loop;
 extern const char *__doc_igl_cat;
-extern const char *__doc_igl_eigs;
-extern const char *__doc_igl_per_corner_normals;
-extern const char *__doc_igl_massmatrix;
-extern const char *__doc_igl_unproject_onto_mesh;
 extern const char *__doc_igl_colon;
-extern const char *__doc_igl_fit_rotations;
-extern const char *__doc_igl_fit_rotations_planar;
-extern const char *__doc_igl_fit_rotations_SSE;
-extern const char *__doc_igl_rotate_vectors;
-extern const char *__doc_igl_read_triangle_mesh;
-extern const char *__doc_igl_gaussian_curvature;
-extern const char *__doc_igl_planarize_quad_mesh;
-extern const char *__doc_igl_avg_edge_length;
-extern const char *__doc_igl_barycentric_coordinates;
-extern const char *__doc_igl_lscm;
-extern const char *__doc_igl_find_cross_field_singularities;
-extern const char *__doc_igl_upsample;
-extern const char *__doc_igl_slice_mask;
-extern const char *__doc_igl_point_mesh_squared_distance;
-extern const char *__doc_igl_parula;
-extern const char *__doc_igl_setdiff;
-extern const char *__doc_igl_copyleft_tetgen_tetrahedralize;
+extern const char *__doc_igl_comb_cross_field;
 extern const char *__doc_igl_comb_frame_field;
-extern const char *__doc_igl_map_vertices_to_circle;
-extern const char *__doc_igl_writeOBJ;
-extern const char *__doc_igl_active_set;
-extern const char *__doc_igl_per_edge_normals;
-extern const char *__doc_igl_covariance_scatter_matrix;
-extern const char *__doc_igl_boundary_facets;
 extern const char *__doc_igl_compute_frame_field_bisectors;
-extern const char *__doc_igl_edge_lengths;
-extern const char *__doc_igl_readOBJ;
+extern const char *__doc_igl_copyleft_cgal_mesh_boolean;
+extern const char *__doc_igl_copyleft_comiso_miq;
+extern const char *__doc_igl_copyleft_comiso_nrosy;
+extern const char *__doc_igl_copyleft_tetgen_tetrahedralize;
+extern const char *__doc_igl_cotmatrix;
+extern const char *__doc_igl_covariance_scatter_matrix;
+extern const char *__doc_igl_cross_field_missmatch;
 extern const char *__doc_igl_cut_mesh_from_singularities;
-extern const char *__doc_igl_readDMAT;
 extern const char *__doc_igl_doublearea;
 extern const char *__doc_igl_doublearea_single;
 extern const char *__doc_igl_doublearea_quad;
+extern const char *__doc_igl_edge_lengths;
+extern const char *__doc_igl_eigs;
+extern const char *__doc_igl_embree_ambient_occlusion;
+extern const char *__doc_igl_find_cross_field_singularities;
+extern const char *__doc_igl_fit_rotations;
+extern const char *__doc_igl_fit_rotations_planar;
+extern const char *__doc_igl_fit_rotations_SSE;
+extern const char *__doc_igl_floor;
+extern const char *__doc_igl_gaussian_curvature;
+extern const char *__doc_igl_grad;
+extern const char *__doc_igl_harmonic;
+extern const char *__doc_igl_invert_diag;
+extern const char *__doc_igl_jet;
+extern const char *__doc_igl_local_basis;
+extern const char *__doc_igl_lscm;
+extern const char *__doc_igl_map_vertices_to_circle;
+extern const char *__doc_igl_massmatrix;
 extern const char *__doc_igl_min_quad_with_fixed_precompute;
 extern const char *__doc_igl_min_quad_with_fixed_solve;
 extern const char *__doc_igl_min_quad_with_fixed;
-extern const char *__doc_igl_writeMESH;
-extern const char *__doc_igl_unique;
-extern const char *__doc_igl_unique_rows;
-extern const char *__doc_igl_arap_precomputation;
-extern const char *__doc_igl_arap_solve;
-extern const char *__doc_igl_cross_field_missmatch;
-extern const char *__doc_igl_grad;
-extern const char *__doc_igl_slice_into;
-extern const char *__doc_igl_slice_tets;
 extern const char *__doc_igl_n_polyvector;
-extern const char *__doc_igl_harmonic;
-extern const char *__doc_igl_boundary_loop;
+extern const char *__doc_igl_parula;
+extern const char *__doc_igl_per_corner_normals;
+extern const char *__doc_igl_per_edge_normals;
+extern const char *__doc_igl_per_face_normals;
+extern const char *__doc_igl_per_face_normals_stable;
+extern const char *__doc_igl_per_vertex_normals;
+extern const char *__doc_igl_planarize_quad_mesh;
+extern const char *__doc_igl_png_readPNG;
+extern const char *__doc_igl_png_writePNG;
+extern const char *__doc_igl_point_mesh_squared_distance;
 extern const char *__doc_igl_polar_svd;
-extern const char *__doc_igl_comb_cross_field;
-extern const char *__doc_igl_invert_diag;
+extern const char *__doc_igl_principal_curvature;
+extern const char *__doc_igl_quad_planarity;
+extern const char *__doc_igl_readDMAT;
 extern const char *__doc_igl_readMESH;
-extern const char *__doc_igl_copyleft_comiso_miq;
-extern const char *__doc_igl_copyleft_comiso_nrosy;
+extern const char *__doc_igl_readOBJ;
+extern const char *__doc_igl_readOFF;
+extern const char *__doc_igl_read_triangle_mesh;
+extern const char *__doc_igl_rotate_vectors;
+extern const char *__doc_igl_setdiff;
+extern const char *__doc_igl_signed_distance;
+extern const char *__doc_igl_signed_distance_pseudonormal;
+extern const char *__doc_igl_signed_distance_winding_number;
+extern const char *__doc_igl_slice;
+extern const char *__doc_igl_slice_into;
+extern const char *__doc_igl_slice_mask;
+extern const char *__doc_igl_slice_tets;
+extern const char *__doc_igl_sortrows;
+extern const char *__doc_igl_triangle_triangulate;
+extern const char *__doc_igl_unique;
+extern const char *__doc_igl_unique_rows;
+extern const char *__doc_igl_unproject_onto_mesh;
+extern const char *__doc_igl_upsample;
+extern const char *__doc_igl_writeMESH;
+extern const char *__doc_igl_writeOBJ;

+ 106 - 108
python/py_igl.cpp

@@ -2,141 +2,139 @@
 
 #include "python_shared.h"
 
-#include <igl/readOFF.h>
-#include <igl/writeOBJ.h>
-#include <igl/per_face_normals.h>
-#include <igl/per_corner_normals.h>
-#include <igl/per_vertex_normals.h>
-#include <igl/gaussian_curvature.h>
-#include <igl/jet.h>
-#include <igl/read_triangle_mesh.h>
-#include <igl/cotmatrix.h>
-#include <igl/massmatrix.h>
-#include <igl/invert_diag.h>
-#include <igl/principal_curvature.h>
-#include <igl/parula.h>
-#include <igl/readDMAT.h>
-#include <igl/grad.h>
-#include <igl/avg_edge_length.h>
-#include <igl/barycenter.h>
-#include <igl/doublearea.h>
-#include <igl/floor.h>
-#include <igl/slice.h>
-#include <igl/slice_into.h>
-#include <igl/sortrows.h>
-#include <igl/colon.h>
-#include <igl/boundary_facets.h>
-#include <igl/unique.h>
-#include <igl/setdiff.h>
-#include <igl/min_quad_with_fixed.h>
+#include <igl/AABB.h>
+#include <igl/ARAPEnergyType.h>
+#include <igl/MeshBooleanType.h>
 #include <igl/SolverStatus.h>
 #include <igl/active_set.h>
-#include <igl/eigs.h>
-#include <igl/readOBJ.h>
-#include <igl/harmonic.h>
 #include <igl/arap.h>
-#include <igl/ARAPEnergyType.h>
+#include <igl/avg_edge_length.h>
+#include <igl/barycenter.h>
+#include <igl/barycentric_coordinates.h>
+#include <igl/boundary_facets.h>
 #include <igl/boundary_loop.h>
-#include <igl/map_vertices_to_circle.h>
-#include <igl/lscm.h>
-#include <igl/local_basis.h>
-#include <igl/rotate_vectors.h>
-#include <igl/compute_frame_field_bisectors.h>
+#include <igl/cat.h>
+#include <igl/colon.h>
 #include <igl/comb_cross_field.h>
+#include <igl/comb_frame_field.h>
+#include <igl/compute_frame_field_bisectors.h>
+#include <igl/cotmatrix.h>
+#include <igl/covariance_scatter_matrix.h>
 #include <igl/cross_field_missmatch.h>
-#include <igl/find_cross_field_singularities.h>
 #include <igl/cut_mesh_from_singularities.h>
-#include <igl/comb_frame_field.h>
-#include <igl/n_polyvector.h>
-
-#include <igl/point_mesh_squared_distance.h>
-#include <igl/AABB.h>
-#include <igl/readMESH.h>
-#include <igl/writeMESH.h>
-#include <igl/slice_tets.h>
+#include <igl/doublearea.h>
 #include <igl/edge_lengths.h>
-#include <igl/upsample.h>
-#include <igl/cat.h>
-#include <igl/per_edge_normals.h>
-#include <igl/barycentric_coordinates.h>
+#include <igl/eigs.h>
+#include <igl/find_cross_field_singularities.h>
 #include <igl/fit_rotations.h>
+#include <igl/floor.h>
+#include <igl/gaussian_curvature.h>
+#include <igl/grad.h>
+#include <igl/harmonic.h>
+#include <igl/invert_diag.h>
+#include <igl/jet.h>
+#include <igl/local_basis.h>
+#include <igl/lscm.h>
+#include <igl/map_vertices_to_circle.h>
+#include <igl/massmatrix.h>
+#include <igl/min_quad_with_fixed.h>
+#include <igl/n_polyvector.h>
+#include <igl/parula.h>
+#include <igl/per_corner_normals.h>
+#include <igl/per_edge_normals.h>
+#include <igl/per_face_normals.h>
+#include <igl/per_vertex_normals.h>
+#include <igl/planarize_quad_mesh.h>
+#include <igl/point_mesh_squared_distance.h>
 #include <igl/polar_svd.h>
-#include <igl/covariance_scatter_matrix.h>
-#include <igl/slice_mask.h>
-#include <igl/signed_distance.h>
+#include <igl/principal_curvature.h>
 #include <igl/quad_planarity.h>
-#include <igl/planarize_quad_mesh.h>
+#include <igl/readDMAT.h>
+#include <igl/readMESH.h>
+#include <igl/readOBJ.h>
+#include <igl/readOFF.h>
+#include <igl/read_triangle_mesh.h>
+#include <igl/rotate_vectors.h>
+#include <igl/setdiff.h>
+#include <igl/signed_distance.h>
+#include <igl/slice.h>
+#include <igl/slice_into.h>
+#include <igl/slice_mask.h>
+#include <igl/slice_tets.h>
+#include <igl/sortrows.h>
+#include <igl/unique.h>
 #include <igl/unproject_onto_mesh.h>
-//#include <igl/.h>
+#include <igl/upsample.h>
+#include <igl/writeMESH.h>
+#include <igl/writeOBJ.h>
 
 
 void python_export_igl(py::module &m)
 {
-#include "py_igl/py_readOFF.cpp"
-#include "py_igl/py_writeOBJ.cpp"
-#include "py_igl/py_per_face_normals.cpp"
-#include "py_igl/py_per_corner_normals.cpp"
-#include "py_igl/py_per_vertex_normals.cpp"
-#include "py_igl/py_gaussian_curvature.cpp"
-#include "py_igl/py_jet.cpp"
-#include "py_igl/py_read_triangle_mesh.cpp"
-#include "py_igl/py_cotmatrix.cpp"
-#include "py_igl/py_massmatrix.cpp"
-#include "py_igl/py_invert_diag.cpp"
-#include "py_igl/py_principal_curvature.cpp"
-#include "py_igl/py_parula.cpp"
-#include "py_igl/py_readDMAT.cpp"
-#include "py_igl/py_grad.cpp"
-#include "py_igl/py_avg_edge_length.cpp"
-#include "py_igl/py_barycenter.cpp"
-#include "py_igl/py_doublearea.cpp"
-#include "py_igl/py_floor.cpp"
-#include "py_igl/py_slice.cpp"
-#include "py_igl/py_slice_into.cpp"
-#include "py_igl/py_sortrows.cpp"
-#include "py_igl/py_colon.cpp"
-#include "py_igl/py_boundary_facets.cpp"
-#include "py_igl/py_unique.cpp"
-#include "py_igl/py_setdiff.cpp"
-#include "py_igl/py_min_quad_with_fixed.cpp"
+#include "py_igl/py_AABB.cpp"
+#include "py_igl/py_ARAPEnergyType.cpp"
+#include "py_igl/py_MeshBooleanType.cpp"
 #include "py_igl/py_SolverStatus.cpp"
 #include "py_igl/py_active_set.cpp"
-#include "py_igl/py_eigs.cpp"
-#include "py_igl/py_readOBJ.cpp"
-#include "py_igl/py_harmonic.cpp"
-#include "py_igl/py_ARAPEnergyType.cpp"
 #include "py_igl/py_arap.cpp"
+#include "py_igl/py_avg_edge_length.cpp"
+#include "py_igl/py_barycenter.cpp"
+#include "py_igl/py_barycentric_coordinates.cpp"
+#include "py_igl/py_boundary_facets.cpp"
 #include "py_igl/py_boundary_loop.cpp"
-#include "py_igl/py_map_vertices_to_circle.cpp"
-#include "py_igl/py_lscm.cpp"
-#include "py_igl/py_local_basis.cpp"
-#include "py_igl/py_rotate_vectors.cpp"
-#include "py_igl/py_compute_frame_field_bisectors.cpp"
+#include "py_igl/py_cat.cpp"
+#include "py_igl/py_colon.cpp"
 #include "py_igl/py_comb_cross_field.cpp"
+#include "py_igl/py_comb_frame_field.cpp"
+#include "py_igl/py_compute_frame_field_bisectors.cpp"
+#include "py_igl/py_cotmatrix.cpp"
+#include "py_igl/py_covariance_scatter_matrix.cpp"
 #include "py_igl/py_cross_field_missmatch.cpp"
-#include "py_igl/py_find_cross_field_singularities.cpp"
 #include "py_igl/py_cut_mesh_from_singularities.cpp"
-#include "py_igl/py_comb_frame_field.cpp"
-#include "py_igl/py_n_polyvector.cpp"
-
-#include "py_igl/py_point_mesh_squared_distance.cpp"
-#include "py_igl/py_AABB.cpp"
-#include "py_igl/py_readMESH.cpp"
-#include "py_igl/py_writeMESH.cpp"
-#include "py_igl/py_slice_tets.cpp"
+#include "py_igl/py_doublearea.cpp"
 #include "py_igl/py_edge_lengths.cpp"
-#include "py_igl/py_upsample.cpp"
-#include "py_igl/py_cat.cpp"
-#include "py_igl/py_per_edge_normals.cpp"
-#include "py_igl/py_barycentric_coordinates.cpp"
+#include "py_igl/py_eigs.cpp"
+#include "py_igl/py_find_cross_field_singularities.cpp"
 #include "py_igl/py_fit_rotations.cpp"
+#include "py_igl/py_floor.cpp"
+#include "py_igl/py_gaussian_curvature.cpp"
+#include "py_igl/py_grad.cpp"
+#include "py_igl/py_harmonic.cpp"
+#include "py_igl/py_invert_diag.cpp"
+#include "py_igl/py_jet.cpp"
+#include "py_igl/py_local_basis.cpp"
+#include "py_igl/py_lscm.cpp"
+#include "py_igl/py_map_vertices_to_circle.cpp"
+#include "py_igl/py_massmatrix.cpp"
+#include "py_igl/py_min_quad_with_fixed.cpp"
+#include "py_igl/py_n_polyvector.cpp"
+#include "py_igl/py_parula.cpp"
+#include "py_igl/py_per_corner_normals.cpp"
+#include "py_igl/py_per_edge_normals.cpp"
+#include "py_igl/py_per_face_normals.cpp"
+#include "py_igl/py_per_vertex_normals.cpp"
+#include "py_igl/py_planarize_quad_mesh.cpp"
+#include "py_igl/py_point_mesh_squared_distance.cpp"
 #include "py_igl/py_polar_svd.cpp"
-#include "py_igl/py_covariance_scatter_matrix.cpp"
-#include "py_igl/py_slice_mask.cpp"
-#include "py_igl/py_signed_distance.cpp"
+#include "py_igl/py_principal_curvature.cpp"
 #include "py_igl/py_quad_planarity.cpp"
-#include "py_igl/py_planarize_quad_mesh.cpp"
+#include "py_igl/py_readDMAT.cpp"
+#include "py_igl/py_readMESH.cpp"
+#include "py_igl/py_readOBJ.cpp"
+#include "py_igl/py_readOFF.cpp"
+#include "py_igl/py_read_triangle_mesh.cpp"
+#include "py_igl/py_rotate_vectors.cpp"
+#include "py_igl/py_setdiff.cpp"
+#include "py_igl/py_signed_distance.cpp"
+#include "py_igl/py_slice.cpp"
+#include "py_igl/py_slice_into.cpp"
+#include "py_igl/py_slice_mask.cpp"
+#include "py_igl/py_slice_tets.cpp"
+#include "py_igl/py_sortrows.cpp"
+#include "py_igl/py_unique.cpp"
 #include "py_igl/py_unproject_onto_mesh.cpp"
-//#include "py_igl/py_.cpp"
+#include "py_igl/py_upsample.cpp"
+#include "py_igl/py_writeMESH.cpp"
+#include "py_igl/py_writeOBJ.cpp"
 
 }

+ 107 - 0
python/py_igl/copyleft/cgal/py_mesh_boolean.cpp

@@ -0,0 +1,107 @@
+// COMPLETE BINDINGS ========================
+
+m.def("mesh_boolean", []
+(
+  const Eigen::MatrixXd& VA,
+  const Eigen::MatrixXi& FA,
+  const Eigen::MatrixXd& VB,
+  const Eigen::MatrixXi& FB,
+  igl::MeshBooleanType & type,
+  Eigen::MatrixXd& VC,
+  Eigen::MatrixXi& FC,
+  Eigen::MatrixXi& J
+)
+{
+  return igl::copyleft::cgal::mesh_boolean(VA, FA, VB, FB, type, VC, FC, J);
+}, __doc_igl_copyleft_cgal_mesh_boolean,
+py::arg("VA"), py::arg("FA"), py::arg("VB"), py::arg("FB"), py::arg("type"), py::arg("VC"), py::arg("FC"), py::arg("J"));
+
+
+m.def("mesh_boolean", []
+(
+  const Eigen::MatrixXd& VA,
+  const Eigen::MatrixXi& FA,
+  const Eigen::MatrixXd& VB,
+  const Eigen::MatrixXi& FB,
+  const std::string & type_str,
+  Eigen::MatrixXd& VC,
+  Eigen::MatrixXi& FC,
+  Eigen::MatrixXi& J
+)
+{
+  return igl::copyleft::cgal::mesh_boolean(VA, FA, VB, FB, type_str, VC, FC, J);
+}, __doc_igl_copyleft_cgal_mesh_boolean,
+py::arg("VA"), py::arg("FA"), py::arg("VB"), py::arg("FB"), py::arg("type_str"), py::arg("VC"), py::arg("FC"), py::arg("J"));
+
+m.def("mesh_boolean", []
+(
+  const Eigen::MatrixXd& VA,
+  const Eigen::MatrixXi& FA,
+  const Eigen::MatrixXd& VB,
+  const Eigen::MatrixXi& FB,
+  const igl::MeshBooleanType & type,
+  Eigen::MatrixXd& VC,
+  Eigen::MatrixXi& FC
+)
+{
+  return igl::copyleft::cgal::mesh_boolean(VA, FA, VB, FB, type, VC, FC);
+}, __doc_igl_copyleft_cgal_mesh_boolean,
+py::arg("VA"), py::arg("FA"), py::arg("VB"), py::arg("FB"), py::arg("type"), py::arg("VC"), py::arg("FC"));
+
+
+
+// INCOMPLETE BINDINGS ========================
+
+
+
+
+//m.def("mesh_boolean", []
+//(
+//  const Eigen::MatrixXd& VA,
+//  const Eigen::MatrixXd& FA,
+//  const Eigen::MatrixXd& VB,
+//  const Eigen::MatrixXd& FB,
+//  std::function<int (const Eigen::Matrix<int, 1, Eigen::Dynamic>)> & wind_num_op,
+//  std::function<int (const int, const int)> & keep,
+//  Eigen::MatrixXd& VC,
+//  Eigen::MatrixXd& FC,
+//  Eigen::MatrixXd& J
+//)
+//{
+//  return igl::copyleft::cgal::mesh_boolean(VA, FA, VB, FB, wind_num_op, keep, VC, FC, J);
+//}, __doc_igl_copyleft_cgal_mesh_boolean,
+//py::arg("VA"), py::arg("FA"), py::arg("VB"), py::arg("FB"), py::arg("wind_num_op"), py::arg("keep"), py::arg("VC"), py::arg("FC"), py::arg("J"));
+
+//m.def("mesh_boolean", []
+//(
+//  std::vector<DerivedV> & Vlist,
+//  std::vector<DerivedF> & Flist,
+//  std::function<int (const Eigen::Matrix<int, 1, Eigen::Dynamic>)> & wind_num_op,
+//  std::function<int (const int, const int)> & keep,
+//  Eigen::MatrixXd& VC,
+//  Eigen::MatrixXd& FC,
+//  Eigen::MatrixXd& J
+//)
+//{
+//  return igl::copyleft::cgal::mesh_boolean(Vlist, Flist, wind_num_op, keep, VC, FC, J);
+//}, __doc_igl_copyleft_cgal_mesh_boolean,
+//py::arg("Vlist"), py::arg("Flist"), py::arg("wind_num_op"), py::arg("keep"), py::arg("VC"), py::arg("FC"), py::arg("J"));
+
+//m.def("mesh_boolean", []
+//(
+//  const Eigen::MatrixXd& VV,
+//  const Eigen::MatrixXd& FF,
+//  const Eigen::MatrixXd& sizes,
+//  std::function<int (const Eigen::Matrix<int, 1, Eigen::Dynamic>)> & wind_num_op,
+//  std::function<int (const int, const int)> & keep,
+//  Eigen::MatrixXd& VC,
+//  Eigen::MatrixXd& FC,
+//  Eigen::MatrixXd& J
+//)
+//{
+//  return igl::copyleft::cgal::mesh_boolean(VV, FF, sizes, wind_num_op, keep, VC, FC, J);
+//}, __doc_igl_copyleft_cgal_mesh_boolean,
+//py::arg("VV"), py::arg("FF"), py::arg("sizes"), py::arg("wind_num_op"), py::arg("keep"), py::arg("VC"), py::arg("FC"), py::arg("J"));
+
+
+

+ 14 - 0
python/py_igl/png/py_readPNG.cpp

@@ -0,0 +1,14 @@
+
+m.def("readPNG", []
+(
+  const std::string png_file,
+  Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> & R,
+  Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> & G,
+  Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> & B,
+  Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> & A
+)
+{
+  return igl::png::readPNG(png_file, R, G, B, A);
+}, __doc_igl_png_readPNG,
+py::arg("png_file"), py::arg("R"), py::arg("G"), py::arg("B"), py::arg("A"));
+

+ 15 - 0
python/py_igl/png/py_writePNG.cpp

@@ -0,0 +1,15 @@
+
+
+m.def("writePNG", []
+(
+  const Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> & R,
+  const Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> & G,
+  const Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> & B,
+  const Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> & A,
+  const std::string png_file
+)
+{
+  return igl::png::writePNG(R, G, B, A, png_file);
+}, __doc_igl_png_writePNG,
+py::arg("R"), py::arg("G"), py::arg("B"), py::arg("A"), py::arg("png_file"));
+

+ 10 - 0
python/py_igl/py_MeshBooleanType.cpp

@@ -0,0 +1,10 @@
+py::enum_<igl::MeshBooleanType>(m, "MeshBooleanType")
+    .value("MESH_BOOLEAN_TYPE_UNION", igl::MESH_BOOLEAN_TYPE_UNION)
+    .value("MESH_BOOLEAN_TYPE_INTERSECT", igl::MESH_BOOLEAN_TYPE_INTERSECT)
+    .value("MESH_BOOLEAN_TYPE_MINUS", igl::MESH_BOOLEAN_TYPE_MINUS)
+    .value("MESH_BOOLEAN_TYPE_XOR", igl::MESH_BOOLEAN_TYPE_XOR)
+    .value("MESH_BOOLEAN_TYPE_RESOLVE", igl::MESH_BOOLEAN_TYPE_RESOLVE)
+    .value("NUM_MESH_BOOLEAN_TYPES", igl::NUM_MESH_BOOLEAN_TYPES)
+    .export_values();
+
+

+ 89 - 0
python/python_shared.cpp

@@ -26,6 +26,14 @@ extern void python_export_igl_embree(py::module &);
 extern void python_export_igl_triangle(py::module &);
 #endif
 
+#ifdef PY_CGAL
+extern void python_export_igl_cgal(py::module &);
+#endif
+
+#ifdef PY_PNG
+extern void python_export_igl_png(py::module &);
+#endif
+
 PYBIND11_PLUGIN(pyigl) {
     py::module m("pyigl", R"pyigldoc(
         Python wrappers for libigl
@@ -36,6 +44,79 @@ PYBIND11_PLUGIN(pyigl) {
         .. autosummary::
            :toctree: _generate
 
+           AABB
+           ARAPEnergyType
+           MeshBooleanType
+           SolverStatus
+           active_set
+           arap
+           avg_edge_length
+           barycenter
+           barycentric_coordinates
+           boundary_facets
+           boundary_loop
+           cat
+           colon
+           comb_cross_field
+           comb_frame_field
+           compute_frame_field_bisectors
+           copyleft_cgal_mesh_boolean
+           copyleft_comiso_miq
+           copyleft_comiso_nrosy
+           copyleft_tetgen_tetrahedralize
+           cotmatrix
+           covariance_scatter_matrix
+           cross_field_missmatch
+           cut_mesh_from_singularities
+           doublearea
+           edge_lengths
+           eigs
+           embree_ambient_occlusion
+           find_cross_field_singularities
+           fit_rotations
+           floor
+           gaussian_curvature
+           grad
+           harmonic
+           invert_diag
+           jet
+           local_basis
+           lscm
+           map_vertices_to_circle
+           massmatrix
+           min_quad_with_fixed
+           n_polyvector
+           parula
+           per_corner_normals
+           per_edge_normals
+           per_face_normals
+           per_vertex_normals
+           planarize_quad_mesh
+           png_readPNG
+           png_writePNG
+           point_mesh_squared_distance
+           polar_svd
+           principal_curvature
+           quad_planarity
+           readDMAT
+           readMESH
+           readOBJ
+           readOFF
+           read_triangle_mesh
+           rotate_vectors
+           setdiff
+           signed_distance
+           slice
+           slice_into
+           slice_mask
+           slice_tets
+           sortrows
+           triangle_triangulate
+           unique
+           unproject_onto_mesh
+           upsample
+           writeMESH
+           writeOBJ
 
     )pyigldoc");
 
@@ -63,5 +144,13 @@ PYBIND11_PLUGIN(pyigl) {
     python_export_igl_triangle(m);
     #endif
 
+    #ifdef PY_CGAL
+    python_export_igl_cgal(m);
+    #endif
+
+    #ifdef PY_PNG
+    python_export_igl_png(m);
+    #endif
+
     return m.ptr();
 }

+ 4 - 1
python/scripts/generate_bindings.py

@@ -63,6 +63,9 @@ def map_parameter_types(name, cpp_type, parsed_types, errors, enum_types):
     if cpp_type.startswith("MatY"):
         result.append("Eigen::SparseMatrix<double>&")
         skip_parsing = True
+    if cpp_type.startswith("Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic>"):
+        result.append("Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic>")
+        skip_parsing = True
     if cpp_type == "std::vector<std::vector<Scalar> > &":
         result.append("std::vector<std::vector<double> > &")
         skip_parsing = True
@@ -298,4 +301,4 @@ if __name__ == '__main__':
         for k in l:
             fs.write("%s: %i \n" %(k, len(files[k])))
             fs.writelines("\n".join(files[k]))
-            fs.write("\n\n\n")
+            fs.write("\n\n\n")

+ 19 - 3
python/scripts/generate_docstrings.py

@@ -21,6 +21,7 @@ def get_filepaths(directory):
     it yields a 3-tuple (dirpath, dirnames, filenames).
     """
     file_paths = []  # List which will store all of the full filepaths.
+    root_file_paths = []
 
     # Walk the tree.
     for root, directories, files in os.walk(directory):
@@ -29,7 +30,10 @@ def get_filepaths(directory):
             filepath = os.path.join(root, filename)
             file_paths.append(filepath)  # Add it to the list.
 
-    return file_paths  # Self-explanatory.
+            if root.endswith(directory): # Add only the files in the root directory
+                root_file_paths.append(filepath)
+
+    return file_paths, root_file_paths  # file_paths contains all file paths, core_file_paths only the ones in <directory>
 
 
 def get_name_from_path(path, basepath, prefix, postfix):
@@ -53,8 +57,8 @@ if __name__ == '__main__':
     # List all files in the given folder and subfolders
     cpp_base_path = sys.argv[1]
     py_base_path = sys.argv[2]
-    cpp_file_paths = get_filepaths(cpp_base_path)
-    py_file_paths = get_filepaths(py_base_path)
+    cpp_file_paths, cpp_root_file_paths = get_filepaths(cpp_base_path)
+    py_file_paths, py_root_file_paths = get_filepaths(py_base_path)
 
     # Add all the .h filepaths to a dict
     mapping = {}
@@ -65,10 +69,16 @@ if __name__ == '__main__':
 
     # Add all python binding files to a list
     implemented_names = []
+    core_implemented_names = []
     for f in py_file_paths:
         if f.endswith(".cpp"):
             name = get_name_from_path(f, py_base_path, "py_", ".cpp")
             implemented_names.append(name)
+            if f in py_root_file_paths:
+                core_implemented_names.append(name)
+
+    implemented_names.sort()
+    core_implemented_names.sort()
 
     # Create a list of cpp header files for which a python binding file exists
     files_to_parse = []
@@ -124,3 +134,9 @@ if __name__ == '__main__':
     rendered = tpl.render(functions=implemented_names)
     with open("../python_shared.cpp", 'w') as fs:
         fs.write(rendered)
+
+    # Write py_igl_cpp file with all core library files
+    tpl = Template(filename='py_igl.mako')
+    rendered = tpl.render(functions=core_implemented_names)
+    with open("../py_igl.cpp", 'w') as fs:
+        fs.write(rendered)

+ 16 - 0
python/scripts/py_igl.mako

@@ -0,0 +1,16 @@
+#include <Eigen/Dense>
+
+#include "python_shared.h"
+
+% for f in functions:
+#include <igl/${f}.h>
+% endfor
+
+
+void python_export_igl(py::module &m)
+{
+% for f in functions:
+#include "py_igl/py_${f}.cpp"
+% endfor
+
+}

+ 40 - 0
python/scripts/python_shared.mako

@@ -14,6 +14,26 @@ extern void python_export_igl_viewer(py::module &);
 extern void python_export_igl_comiso(py::module &);
 #endif
 
+#ifdef PY_TETGEN
+extern void python_export_igl_tetgen(py::module &);
+#endif
+
+#ifdef PY_EMBREE
+extern void python_export_igl_embree(py::module &);
+#endif
+
+#ifdef PY_TRIANGLE
+extern void python_export_igl_triangle(py::module &);
+#endif
+
+#ifdef PY_CGAL
+extern void python_export_igl_cgal(py::module &);
+#endif
+
+#ifdef PY_PNG
+extern void python_export_igl_png(py::module &);
+#endif
+
 PYBIND11_PLUGIN(pyigl) {
     py::module m("pyigl", R"pyigldoc(
         Python wrappers for libigl
@@ -42,5 +62,25 @@ PYBIND11_PLUGIN(pyigl) {
     python_export_igl_comiso(m);
     #endif
 
+    #ifdef PY_TETGEN
+    python_export_igl_tetgen(m);
+    #endif
+
+    #ifdef PY_EMBREE
+    python_export_igl_embree(m);
+    #endif
+
+    #ifdef PY_TRIANGLE
+    python_export_igl_triangle(m);
+    #endif
+
+    #ifdef PY_CGAL
+    python_export_igl_cgal(m);
+    #endif
+
+    #ifdef PY_PNG
+    python_export_igl_png(m);
+    #endif
+
     return m.ptr();
 }

+ 78 - 0
python/tutorial/607_ScreenCapture.py

@@ -0,0 +1,78 @@
+import sys, os
+
+# Add the igl library to the modules search path
+sys.path.insert(0, os.getcwd() + "/../")
+import pyigl as igl
+
+from shared import TUTORIAL_SHARED_PATH, check_dependencies
+
+dependencies = ["png", "viewer"]
+check_dependencies(dependencies)
+
+temp_png = os.path.join(os.getcwd(),"out.png")
+
+def key_down(viewer, key, modifier):
+    if key == ord('1'):
+        # Allocate temporary buffers
+        R = igl.eigen.MatrixXuc(1280, 800)
+        G = igl.eigen.MatrixXuc(1280, 800)
+        B = igl.eigen.MatrixXuc(1280, 800)
+        A = igl.eigen.MatrixXuc(1280, 800)
+
+        # Draw the scene in the buffers
+        viewer.core.draw_buffer(viewer.data, viewer.opengl, False, R, G, B, A)
+
+        # Save it to a PNG
+        igl.png.writePNG(R, G, B, A, temp_png)
+    elif key == ord('2'):
+        # Allocate temporary buffers
+        R = igl.eigen.MatrixXuc()
+        G = igl.eigen.MatrixXuc()
+        B = igl.eigen.MatrixXuc()
+        A = igl.eigen.MatrixXuc()
+
+        # Read the PNG
+        igl.png.readPNG(temp_png, R, G, B, A)
+
+        # Replace the mesh with a triangulated square
+        V = igl.eigen.MatrixXd([[-0.5, -0.5, 0],
+                                [0.5, -0.5, 0],
+                                [0.5, 0.5, 0],
+                                [-0.5, 0.5, 0]])
+
+        F = igl.eigen.MatrixXi([[0, 1, 2], [2, 3, 0]])
+
+        UV = igl.eigen.MatrixXd([[0, 0], [1, 0], [1, 1], [0, 1]])
+
+        viewer.data.clear()
+        viewer.data.set_mesh(V, F)
+        viewer.data.set_uv(UV)
+        viewer.core.align_camera_center(V)
+        viewer.core.show_texture = True
+
+        # Use the image as a texture
+        viewer.data.set_texture(R, G, B)
+
+    else:
+        return False
+
+    return True
+
+
+if __name__ == "__main__":
+    V = igl.eigen.MatrixXd()
+    F = igl.eigen.MatrixXi()
+
+    # Load meshes in OFF format
+    igl.readOFF(TUTORIAL_SHARED_PATH + "bunny.off", V, F)
+
+    viewer = igl.viewer.Viewer()
+
+    print(
+        "Usage: Press 1 to render the scene and save it in a png. \nPress 2 to load the saved png and use it as a texture.")
+
+    viewer.callback_key_down = key_down
+    viewer.data.set_mesh(V, F)
+    viewer.launch()
+
+    os.remove(temp_png)

+ 83 - 0
python/tutorial/609_Boolean.py

@@ -0,0 +1,83 @@
+import sys, os
+
+# Add the igl library to the modules search path
+sys.path.insert(0, os.getcwd() + "/../")
+import pyigl as igl
+
+from shared import TUTORIAL_SHARED_PATH, check_dependencies
+
+dependencies = ["cgal", "viewer"]
+check_dependencies(dependencies)
+
+boolean_type_names = {igl.MESH_BOOLEAN_TYPE_UNION: "Union", igl.MESH_BOOLEAN_TYPE_INTERSECT: "Intersect", igl.MESH_BOOLEAN_TYPE_MINUS: "Minus", igl.MESH_BOOLEAN_TYPE_XOR: "XOR", igl.MESH_BOOLEAN_TYPE_RESOLVE: "Resolve"}
+
+boolean_types = list(boolean_type_names.keys())
+
+
+
+
+def update(viewer):
+    print("Calculating A %s B..." % boolean_type_names[boolean_type])
+    igl.cgal.mesh_boolean(VA, FA, VB, FB, boolean_type, VC, FC, J)
+    C = igl.eigen.MatrixXd(FC.rows(), 3)
+
+    for f in range(C.rows()):
+        if J[f] < FA.rows():
+            C.setRow(f, Red)
+        else:
+            C.setRow(f, Green)
+
+    viewer.data.clear()
+    viewer.data.set_mesh(VC, FC)
+    viewer.data.set_colors(C)
+    print("Done.")
+
+
+def key_down(viewer, key, modifier):
+    global boolean_type
+
+    if key == ord('.'):
+        boolean_type = boolean_types[(boolean_types.index(boolean_type) + 1) % (len(boolean_types))]
+    elif key == ord(','):
+        boolean_type = boolean_types[(boolean_types.index(boolean_type) + len(boolean_types) - 1) % len(boolean_types)]
+    elif key == ord('['):
+        viewer.core.camera_dnear -= 0.1
+    elif key == ord(']'):
+        viewer.core.camera_dnear += 0.1
+    else:
+        return False
+
+    update(viewer)
+
+    return False
+
+
+if __name__ == "__main__":
+
+    VA = igl.eigen.MatrixXd()
+    FA = igl.eigen.MatrixXi()
+    VB = igl.eigen.MatrixXd()
+    FB = igl.eigen.MatrixXi()
+    VC = igl.eigen.MatrixXd()
+    FC = igl.eigen.MatrixXi()
+    J = igl.eigen.MatrixXi()
+
+    Red = igl.eigen.MatrixXd([[1, 0, 0]])
+    Green = igl.eigen.MatrixXd([[0, 1, 0]])
+
+    # Load meshes in OFF format
+    igl.readOFF(TUTORIAL_SHARED_PATH + "cheburashka.off", VA, FA)
+    igl.readOFF(TUTORIAL_SHARED_PATH + "decimated-knight.off", VB, FB)
+
+    boolean_type = igl.MESH_BOOLEAN_TYPE_UNION
+
+    viewer = igl.viewer.Viewer()
+    update(viewer)
+
+    print(
+        "Usage: Press '.' to switch to next boolean operation type. \nPress ',' to switch to previous boolean operation type. \nPress ']' to push near cutting plane away from camera. \nPress '[' to pull near cutting plane closer to camera. \nHint: investigate _inside_ the model to see orientation changes. \n")
+
+    viewer.core.show_lines = True
+    viewer.callback_key_down = key_down
+    viewer.core.camera_dnear = 3.9
+    viewer.launch()

+ 1 - 2
tutorial/609_Boolean/main.cpp

@@ -41,6 +41,7 @@ void update(igl::viewer::Viewer &viewer)
   viewer.data.clear();
   viewer.data.set_mesh(VC,FC);
   viewer.data.set_colors(C);
+  std::cout<<"A "<<MESH_BOOLEAN_TYPE_NAMES[boolean_type]<<" B."<<std::endl;
 }
 
 bool key_down(igl::viewer::Viewer &viewer, unsigned char key, int mods)
@@ -67,8 +68,6 @@ bool key_down(igl::viewer::Viewer &viewer, unsigned char key, int mods)
       viewer.core.camera_dnear += 0.1;
       return true;
   }
-  std::cout<<"A "<<MESH_BOOLEAN_TYPE_NAMES[boolean_type]<<" B."<<std::endl;
-  igl::copyleft::cgal::mesh_boolean(VA,FA,VB,FB,boolean_type,VC,FC);
   update(viewer);
   return true;
 }

部分文件因为文件数量过多而无法显示