Эх сурвалжийг харах

Merge branch 'dev' into HEAD

Former-commit-id: 5e99913faabff6de18c4f4e9d54b18540a2d6774
Qingnan Zhou 6 жил өмнө
parent
commit
4125afe80f
99 өөрчлөгдсөн 4654 нэмэгдсэн , 627 устгасан
  1. 21 8
      .appveyor.yml
  2. 7 0
      .gitignore
  3. 70 64
      .travis.yml
  4. 2 1
      README.md
  5. 1 0
      include/igl/AABB.cpp
  6. 4 3
      include/igl/Camera.h
  7. 7 11
      include/igl/average_onto_faces.cpp
  8. 7 9
      include/igl/average_onto_faces.h
  9. 3 2
      include/igl/comb_frame_field.cpp
  10. 10 4
      include/igl/combine.cpp
  11. 10 9
      include/igl/compute_frame_field_bisectors.cpp
  12. 38 0
      include/igl/copyleft/cgal/delaunay_triangulation.cpp
  13. 3 2
      include/igl/copyleft/cgal/extract_feature.cpp
  14. 65 0
      include/igl/copyleft/cgal/fast_winding_number.cpp
  15. 79 0
      include/igl/copyleft/cgal/fast_winding_number.h
  16. 5 0
      include/igl/copyleft/cgal/hausdorff.cpp
  17. 25 0
      include/igl/copyleft/cgal/mesh_boolean.cpp
  18. 13 0
      include/igl/copyleft/cgal/mesh_boolean.h
  19. 1 0
      include/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp
  20. 181 0
      include/igl/copyleft/cgal/point_areas.cpp
  21. 78 0
      include/igl/copyleft/cgal/point_areas.h
  22. 1 0
      include/igl/copyleft/cgal/point_mesh_squared_distance.cpp
  23. 2 1
      include/igl/copyleft/cgal/wire_mesh.cpp
  24. 7 7
      include/igl/copyleft/comiso/frame_field.cpp
  25. 1 0
      include/igl/copyleft/comiso/frame_field.h
  26. 9 9
      include/igl/copyleft/comiso/nrosy.cpp
  27. 1 0
      include/igl/copyleft/comiso/nrosy.h
  28. 3 3
      include/igl/copyleft/marching_cubes.cpp
  29. 26 25
      include/igl/copyleft/tetgen/tetrahedralize.cpp
  30. 1 1
      include/igl/cotmatrix.h
  31. 1 0
      include/igl/covariance_scatter_matrix.cpp
  32. 2 1
      include/igl/cross_field_missmatch.cpp
  33. 1 0
      include/igl/cumsum.cpp
  34. 9 15
      include/igl/dirname.cpp
  35. 5 0
      include/igl/dirname.h
  36. 1 2
      include/igl/edges.h
  37. 1 1
      include/igl/exact_geodesic.cpp.REMOVED.git-id
  38. 324 0
      include/igl/fast_winding_number.cpp
  39. 118 0
      include/igl/fast_winding_number.h
  40. 3 2
      include/igl/flip_avoiding_line_search.cpp
  41. 1 0
      include/igl/flip_avoiding_line_search.h
  42. 2 1
      include/igl/grad.cpp
  43. 1 0
      include/igl/hausdorff.cpp
  44. 0 1
      include/igl/is_vertex_manifold.cpp
  45. 105 0
      include/igl/knn.cpp
  46. 52 0
      include/igl/knn.h
  47. 3 2
      include/igl/line_field_missmatch.cpp
  48. 2 1
      include/igl/map_vertices_to_circle.cpp
  49. 1 0
      include/igl/map_vertices_to_circle.h
  50. 1 1
      include/igl/massmatrix.h
  51. 1 0
      include/igl/matrix_to_list.cpp
  52. 180 0
      include/igl/octree.cpp
  53. 62 0
      include/igl/octree.h
  54. 10 13
      include/igl/opengl/MeshGL.cpp
  55. 78 81
      include/igl/opengl/ViewerCore.cpp
  56. 9 19
      include/igl/opengl/ViewerCore.h
  57. 5 5
      include/igl/opengl/glfw/Viewer.cpp
  58. 1 2
      include/igl/opengl/glfw/imgui/ImGuiMenu.cpp
  59. 14 14
      include/igl/per_corner_normals.cpp
  60. 8 8
      include/igl/per_corner_normals.h
  61. 1 0
      include/igl/piecewise_constant_winding_number.cpp
  62. 1 1
      include/igl/point_simplex_squared_distance.cpp
  63. 6 2
      include/igl/qslim.h
  64. 5 4
      include/igl/random_quaternion.cpp
  65. 15 10
      include/igl/ray_box_intersect.cpp
  66. 12 10
      include/igl/ray_mesh_intersect.cpp
  67. 500 0
      include/igl/readMSH.cpp
  68. 38 0
      include/igl/readMSH.h
  69. 1 1
      include/igl/readSTL.h
  70. 6 0
      include/igl/read_triangle_mesh.cpp
  71. 2 2
      include/igl/redux.h
  72. 160 0
      include/igl/remesh_along_isoline.cpp
  73. 81 0
      include/igl/remesh_along_isoline.h
  74. 4 18
      include/igl/setdiff.cpp
  75. 3 2
      include/igl/shapeup.cpp
  76. 1 0
      include/igl/shapeup.h
  77. 4 4
      include/igl/slice_into.cpp
  78. 7 2
      include/igl/sparse_cached.cpp
  79. 76 28
      include/igl/triangle_triangle_adjacency.cpp
  80. 10 10
      include/igl/triangle_triangle_adjacency.h
  81. 54 13
      include/igl/vertex_triangle_adjacency.cpp
  82. 23 4
      include/igl/vertex_triangle_adjacency.h
  83. 3 2
      python/CMakeLists.txt
  84. 10 20
      python/modules/py_igl_opengl_glfw.cpp
  85. 90 0
      python/setup.py
  86. 1 1
      python/tutorial/708_Picking.py
  87. 17 0
      shared/cmake/DownloadProject.CMakeLists.cmake.in
  88. 182 0
      shared/cmake/DownloadProject.cmake
  89. 0 97
      shared/cmake/FindCGAL.cmake
  90. 1540 0
      shared/cmake/FindMATLAB.cmake
  91. 95 50
      shared/cmake/libigl.cmake
  92. 9 8
      tutorial/206_GeodesicDistance/main.cpp
  93. 2 1
      tutorial/504_NRosyDesign/main.cpp
  94. 2 2
      tutorial/505_MIQ/main.cpp
  95. 2 1
      tutorial/506_FrameField/main.cpp
  96. 2 1
      tutorial/701_Statistics/main.cpp
  97. 3 2
      tutorial/707_SweptVolume/main.cpp
  98. 2 2
      tutorial/708_Picking/main.cpp
  99. 2 1
      tutorial/710_SLIM/main.cpp

+ 21 - 8
.appveyor.yml

@@ -8,21 +8,34 @@ branches:
     - alecjacobson
     - cmake
     - cgal
+environment:
+  BOOST_ROOT: C:/Libraries/boost_1_65_1
 install:
   - git submodule update --init --recursive
   - cinstall: python
 build_script:
-  - echo Running cmake...
   - cd c:\projects\libigl
-  - cd external
+  # External libraries (boost)
+  # - cd external
+  # - mkdir build
+  # - cd build
+  # - cmake -G "Visual Studio 15 2017 Win64" -T "host=x64" ..
+  # - msbuild %MSBuildOptions% libigl_external.sln
+  # - cd ../..
+  # Python bindings
+  # - cd python
+  # - mkdir build
+  # - cd build
+  # - cmake -DLIBIGL_WITH_EMBREE=OFF -DLIBIGL_USE_STATIC_LIBRARY=ON ../
+  # - msbuild %MSBuildOptions% pyigl.sln
+  # - cd ../tutorial
+  # - ${PYTHON} 101_FileIO.py
+  # - cd ../../
+  # Tutorials
+  - cd tutorial
   - mkdir build
   - cd build
-  - cmake -G "Visual Studio 15 2017 Win64" -T "host=x64" ..
-  - msbuild %MSBuildOptions% libigl_external.sln
-  - cd ../../tutorial
-  - mkdir build
-  - cd build
-  - cmake -D "LIBIGL_USE_STATIC_LIBRARY=ON" -D "LIBIGL_WITH_ANTTWEAKBAR=OFF" -D "BOOST_ROOT=../external/boost/" -G "Visual Studio 15 2017 Win64" ../
+  - cmake -DLIBIGL_USE_STATIC_LIBRARY=ON -G "Visual Studio 15 2017 Win64" ../
   - set MSBuildLogger="C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
   - set MSBuildOptions=/v:m /p:Configuration=Debug /logger:%MSBuildLogger%
   - msbuild %MSBuildOptions% libigl_tutorials.sln

+ 7 - 0
.gitignore

@@ -28,6 +28,11 @@ external/embree/bin/*
 external/embree/bin
 external/embree/doc/html/*
 external/embree/doc/latex/*
+external/gmp
+external/mpfr
+external/boost
+external/.cache
+external/build
 .DS_Store
 libigl.zip
 *tags
@@ -101,3 +106,5 @@ tutorial/cmake-build-debug
 .vscode/
 .idea/
 site/
+*.egg-info/
+.vs/

+ 70 - 64
.travis.yml

@@ -1,67 +1,73 @@
+dist: trusty
+sudo: true
 language: cpp
-sudo: false
-dist: precise
+cache: ccache
 matrix:
   include:
-    - os: linux
-      compiler: gcc-4.8.1
-      script:
-        - git submodule update --init --recursive
-        - mkdir external/glfw/include/GL
-        - wget --no-check-certificate -P external/glfw/include/GL http://www.opengl.org/registry/api/GL/glcorearb.h
-        - cd python
-        - mkdir build
-        - cd build
-        - 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 ../tutorial
-        - python3 101_FileIO.py || { cd ../; mkdir build2; cd build2; cmake -DCMAKE_CXX_COMPILER=g++-4.8 -DCMAKE_C_COMPILER=gcc-4.8 -DLIBIGL_WITH_EMBREE=OFF -DLIBIGL_USE_STATIC_LIBRARY=ON - DCHECK_UNDEFINED=ON ../; make -j 2; }
-        - cd ../../
-        - cd tutorial
-        - mkdir build
-        - cd build
-        - cmake -DLIBIGL_USE_STATIC_LIBRARY=ON  -DCMAKE_CXX_COMPILER=g++-4.8 -DCMAKE_C_COMPILER=gcc-4.8 -DLIBIGL_WITH_EMBREE=OFF ../
-        - make -j 2
-      addons:
-        apt:
-          sources:
-            - ubuntu-toolchain-r-test
-            - george-edison55-precise-backports
-          packages:
-            - xorg-dev
-            - libglu1-mesa-dev
-            - g++-4.8
-            - cmake
-            - cmake-data
-            - libblas-dev
-            - liblapack-dev
-    #         - binutils
-    #         - libx11-dev
-    #         - mesa-common-dev
-    #         - libgl1-mesa-dev
-    #         - libglu1-mesa-dev
-    #         - libxrandr-dev
-    #         - libxi-dev
-    #         - libxmu-dev
-    #         - libblas-dev
-    #         - xorg-dev
-    - os: osx
-      compiler: clang
-      script:
-        # - brew update
-        # - brew upgrade cmake
-        # - brew upgrade cgal
-        - git submodule update --init --recursive
-        - cd python
-        - mkdir build
-        - cd build
-        - cmake ../
-        - make -j 2
-        - cd ../tutorial
-        - python 101_FileIO.py
-        - cd ../../
-        - cd tutorial
-        - mkdir build
-        - cd build
-        - cmake -DLIBIGL_USE_STATIC_LIBRARY=ON ../
-        - make -j 2
+  - os: linux
+    compiler: gcc # 4.8.4 by default on Trusty
+    addons:
+      apt:
+        sources:
+        - ubuntu-toolchain-r-test
+        packages:
+        - libmpfr-dev
+        - libboost-filesystem-dev
+        - libboost-system-dev
+        - libboost-thread-dev
+        - libblas-dev
+        - liblapack-dev
+        - xorg-dev
+        - libglu1-mesa-dev
+        - python3-setuptools
+        - libpython3-dev
+    env:
+    - MATRIX_EVAL="export CONFIG=Debug && CHECK_UNDEFINED=ON && PYTHON=python3"
+  - os: linux
+    compiler: gcc-7
+    addons:
+      apt:
+        sources:
+        - ubuntu-toolchain-r-test
+        packages:
+        - gcc-7
+        - g++-7
+        - libmpfr-dev
+        - libboost-filesystem-dev
+        - libboost-system-dev
+        - libboost-thread-dev
+        - libblas-dev
+        - liblapack-dev
+        - xorg-dev
+        - libglu1-mesa-dev
+        - python3-setuptools
+        - libpython3-dev
+    env:
+    - MATRIX_EVAL="export CC=gcc-7 && CXX=g++-7 && CONFIG=Debug && CHECK_UNDEFINED=ON && PYTHON=python3"
+  - os: osx
+    compiler: clang
+    env:
+    - MATRIX_EVAL="export CONFIG=Debug && CHECK_UNDEFINED=ON && PYTHON=python3"
+
+install:
+- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache; fi
+- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH="/usr/local/opt/ccache/libexec:$PATH"; fi
+- eval "${MATRIX_EVAL}"
+- ccache --max-size=5.0G
+- ccache -V && ccache --show-stats && ccache --zero-stats
+
+script:
+# Python bindings
+- cd python
+- ${PYTHON} setup.py develop --user -- -DCMAKE_BUILD_TYPE=${CONFIG} -DLIBIGL_WITH_EMBREE=OFF -DLIBIGL_USE_STATIC_LIBRARY=ON -DCHECK_UNDEFINED=${CHECK_UNDEFINED}
+- cd tutorial
+- ${PYTHON} 101_FileIO.py
+- cd ../../
+- rm -rf python/build
+# Tutorials
+- cd tutorial
+- mkdir build
+- cd build
+- cmake -DCMAKE_BUILD_TYPE=$CONFIG -DLIBIGL_USE_STATIC_LIBRARY=ON ../
+- make -j 2
+- ccache --show-stats

+ 2 - 1
README.md

@@ -1,7 +1,7 @@
 # libigl - A simple C++ geometry processing library
 [![Build Status](https://travis-ci.org/libigl/libigl.svg?branch=master)](https://travis-ci.org/libigl/libigl)
 [![Build status](https://ci.appveyor.com/api/projects/status/mf3t9rnhco0vhly8/branch/master?svg=true)](https://ci.appveyor.com/project/danielepanozzo/libigl-6hjk1/branch/master)
-![](libigl-teaser.png)
+![](https://github.com/libigl/libigl/raw/5ff6387765fa85ca46f1a6222728e35e2b8b8961/libigl-teaser.png)
 
 <https://github.com/libigl/libigl/>
 
@@ -229,6 +229,7 @@ few labs/companies/institutions using libigl:
  - [TU Delft](http://www.tudelft.nl/en/), Netherlands
  - [TU Wien](https://www.tuwien.ac.at/en/tuwien_home/), Austria
  - [Telecom ParisTech](http://www.telecom-paristech.fr/en/formation-et-innovation-dans-le-numerique.html), Paris, France
+ - [UBISOFT](https://www.ubisoft.com/en-us/), USA
  - [Utrecht University](http://www.staff.science.uu.nl/~vaxma001/), The Netherlands
  - [Universidade Federal de Santa Catarina](http://mtm.ufsc.br/~leo/), Brazil
  - [University College London](http://vecg.cs.ucl.ac.uk/), England

+ 1 - 0
include/igl/AABB.cpp

@@ -1071,4 +1071,5 @@ template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen
 // generated by autoexplicit.sh
 template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
 template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
+template bool igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::intersect_ray<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, igl::Hit&) const;
 #endif

+ 4 - 3
include/igl/Camera.h

@@ -16,6 +16,7 @@
 
 #include <Eigen/Geometry>
 #include <Eigen/Core>
+#include "PI.h"
 
 #define IGL_CAMERA_MIN_ANGLE 5.0
 namespace igl
@@ -174,7 +175,7 @@ inline Eigen::Matrix4d igl::Camera::projection() const
     const double tx = (right+left)/(right-left);
     const double ty = (top+bottom)/(top-bottom);
     const double tz = (far+near)/(far-near);
-    const double z_fix = 0.5 /m_at_dist / tan(m_angle*0.5 * (M_PI/180.) );
+    const double z_fix = 0.5 /m_at_dist / tan(m_angle*0.5 * (igl::PI/180.) );
     P<<
       z_fix*2./(right-left), 0, 0, -tx,
       0, z_fix*2./(top-bottom), 0, -ty,
@@ -283,8 +284,8 @@ inline void igl::Camera::dolly_zoom(const double da)
     m_angle = min(89.,max(IGL_CAMERA_MIN_ANGLE,m_angle));
     // change in distance
     const double s = 
-      (2.*tan(old_angle/2./180.*M_PI)) /
-      (2.*tan(m_angle/2./180.*M_PI)) ;
+      (2.*tan(old_angle/2./180.*igl::PI)) /
+      (2.*tan(m_angle/2./180.*igl::PI)) ;
     const double old_at_dist = m_at_dist;
     m_at_dist = old_at_dist * s;
     dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));

+ 7 - 11
include/igl/average_onto_faces.cpp

@@ -7,22 +7,18 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "average_onto_faces.h"
 
-template <typename T, typename I>
-IGL_INLINE void igl::average_onto_faces(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
-            const Eigen::Matrix<I, Eigen::Dynamic, Eigen::Dynamic> &F,
-            const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &S,
-            Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &SF)
+template <typename DerivedF, typename DerivedS, typename DerivedSF>
+IGL_INLINE void average_onto_faces(
+  const Eigen::MatrixBase<DerivedF> & F,
+  const Eigen::MatrixBase<DerivedS> & S,
+  Eigen::PlainObjectBase<DerivedSF> & SF)
 {
-  
-  SF = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>::Zero(F.rows(),S.cols());
-
+  SF.setConstant(F.rows(),S.cols(),0);
   for (int i = 0; i <F.rows(); ++i)
     for (int j = 0; j<F.cols(); ++j)
       SF.row(i) += S.row(F(i,j));
-
   SF.array() /= F.cols();
-  
-};
+}
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation

+ 7 - 9
include/igl/average_onto_faces.h

@@ -16,17 +16,15 @@ namespace igl
   // Move a scalar field defined on faces to vertices by averaging
   //
   // Input:
-  // V,F: mesh
-  // S: scalar field defined on vertices, Vx1
-  // 
+  //   F  #F by ss list of simples/faces
+  //   S  #V by dim list of per-vertex values
   // Output:
-  // SV: scalar field defined on faces
-  template <typename T, typename I>
+  //   SF  #F by dim list of per-face values
+  template <typename DerivedF, typename DerivedS, typename DerivedSF>
   IGL_INLINE void average_onto_faces(
-    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
-    const Eigen::Matrix<I, Eigen::Dynamic, Eigen::Dynamic> &F,
-    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &S,
-    Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &SF);
+    const Eigen::MatrixBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedS> & S,
+    Eigen::PlainObjectBase<DerivedSF> & SF);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 3 - 2
include/igl/comb_frame_field.cpp

@@ -13,6 +13,7 @@
 
 #include "comb_frame_field.h"
 #include "local_basis.h"
+#include "PI.h"
 
 template <typename DerivedV, typename DerivedF, typename DerivedP>
 IGL_INLINE void igl::comb_frame_field(const Eigen::PlainObjectBase<DerivedV> &V,
@@ -49,9 +50,9 @@ IGL_INLINE void igl::comb_frame_field(const Eigen::PlainObjectBase<DerivedV> &V,
     {
       a[j] = atan2(B2.row(i).dot(DIRs.row(j)),B1.row(i).dot(DIRs.row(j))) - a_combed;
       //make it positive by adding some multiple of 2pi
-      a[j] += std::ceil (std::max(0., -a[j]) / (M_PI*2.)) * (M_PI*2.);
+      a[j] += std::ceil (std::max(0., -a[j]) / (igl::PI*2.)) * (igl::PI*2.);
       //take modulo 2pi
-      a[j] = fmod(a[j], (M_PI*2.));
+      a[j] = fmod(a[j], (igl::PI*2.));
     }
     // now the max is u and the min is v
 

+ 10 - 4
include/igl/combine.cpp

@@ -39,10 +39,10 @@ IGL_INLINE void igl::combine(
     const auto & Fi = FF[i];
     Vsizes(i) = Vi.rows();
     n+=Vi.rows();
-    assert(dim == Vi.cols() && "All vertex lists should have same #columns");
+    assert((Vi.size()==0 || dim == Vi.cols()) && "All vertex lists should have same #columns");
     Fsizes(i) = Fi.rows();
     m+=Fi.rows();
-    assert(ss == Fi.cols() && "All face lists should have same #columns");
+    assert((Fi.size()==0 || ss == Fi.cols()) && "All face lists should have same #columns");
   }
   V.resize(n,dim);
   F.resize(m,ss);
@@ -55,9 +55,15 @@ IGL_INLINE void igl::combine(
       const int ni = Vi.rows();
       const auto & Fi = FF[i];
       const int mi = Fi.rows();
-      F.block(kf,0,mi,ss) = Fi.array()+kv;
+      if(Fi.size() >0)
+      {
+        F.block(kf,0,mi,ss) = Fi.array()+kv;
+      }
       kf+=mi;
-      V.block(kv,0,ni,dim) = Vi;
+      if(Vi.size() >0)
+      {
+        V.block(kv,0,ni,dim) = Vi;
+      }
       kv+=ni;
     }
     assert(kv == V.rows());

+ 10 - 9
include/igl/compute_frame_field_bisectors.cpp

@@ -13,6 +13,7 @@
 
 #include "compute_frame_field_bisectors.h"
 #include "igl/local_basis.h"
+#include "PI.h"
 
 template <typename DerivedV, typename DerivedF>
 IGL_INLINE void igl::compute_frame_field_bisectors(
@@ -34,26 +35,26 @@ IGL_INLINE void igl::compute_frame_field_bisectors(
     // Convert to angle
     double a1 = atan2(B2.row(i).dot(PD1.row(i)),B1.row(i).dot(PD1.row(i)));
     //make it positive by adding some multiple of 2pi
-    a1 += std::ceil (std::max(0., -a1) / (M_PI*2.)) * (M_PI*2.);
+    a1 += std::ceil (std::max(0., -a1) / (igl::PI*2.)) * (igl::PI*2.);
     //take modulo 2pi
-    a1 = fmod(a1, (M_PI*2.));
+    a1 = fmod(a1, (igl::PI*2.));
     double a2 = atan2(B2.row(i).dot(PD2.row(i)),B1.row(i).dot(PD2.row(i)));
     //make it positive by adding some multiple of 2pi
-    a2 += std::ceil (std::max(0., -a2) / (M_PI*2.)) * (M_PI*2.);
+    a2 += std::ceil (std::max(0., -a2) / (igl::PI*2.)) * (igl::PI*2.);
     //take modulo 2pi
-    a2 = fmod(a2, (M_PI*2.));
+    a2 = fmod(a2, (igl::PI*2.));
 
     double b1 = (a1+a2)/2.0;
     //make it positive by adding some multiple of 2pi
-    b1 += std::ceil (std::max(0., -b1) / (M_PI*2.)) * (M_PI*2.);
+    b1 += std::ceil (std::max(0., -b1) / (igl::PI*2.)) * (igl::PI*2.);
     //take modulo 2pi
-    b1 = fmod(b1, (M_PI*2.));
+    b1 = fmod(b1, (igl::PI*2.));
 
-    double b2 = b1+(M_PI/2.);
+    double b2 = b1+(igl::PI/2.);
     //make it positive by adding some multiple of 2pi
-    b2 += std::ceil (std::max(0., -b2) / (M_PI*2.)) * (M_PI*2.);
+    b2 += std::ceil (std::max(0., -b2) / (igl::PI*2.)) * (igl::PI*2.);
     //take modulo 2pi
-    b2 = fmod(b2, (M_PI*2.));
+    b2 = fmod(b2, (igl::PI*2.));
 
     BIS1.row(i) = cos(b1) * B1.row(i) + sin(b1) * B2.row(i);
     BIS2.row(i) = cos(b2) * B1.row(i) + sin(b2) * B2.row(i);

+ 38 - 0
include/igl/copyleft/cgal/delaunay_triangulation.cpp

@@ -1,5 +1,6 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 //
+// Copyright (C) 2018 Alec Jacobson
 // Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
 //
 // This Source Code Form is subject to the terms of the Mozilla Public License
@@ -20,5 +21,42 @@ IGL_INLINE void igl::copyleft::cgal::delaunay_triangulation(
 {
   typedef typename DerivedV::Scalar Scalar;
   igl::delaunay_triangulation(V, orient2D<Scalar>, incircle<Scalar>, F);
+  // This function really exists to test our igl::delaunay_triangulation
+  // 
+  // It's currently much faster to call cgal's native Delaunay routine
+  //
+//#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+//#include <CGAL/Delaunay_triangulation_2.h>
+//#include <CGAL/Triangulation_vertex_base_with_info_2.h>
+//#include <vector>
+//  const auto delaunay = 
+//    [&](const Eigen::MatrixXd & V,Eigen::MatrixXi & F)
+//  {
+//    typedef CGAL::Exact_predicates_inexact_constructions_kernel            Kernel;
+//    typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
+//    typedef CGAL::Triangulation_data_structure_2<Vb>                       Tds;
+//    typedef CGAL::Delaunay_triangulation_2<Kernel, Tds>                    Delaunay;
+//    typedef Kernel::Point_2                                                Point;
+//    std::vector< std::pair<Point,unsigned> > points(V.rows());
+//    for(int i = 0;i<V.rows();i++)
+//    {
+//      points[i] = std::make_pair(Point(V(i,0),V(i,1)),i);
+//    }
+//    Delaunay triangulation;
+//    triangulation.insert(points.begin(),points.end());
+//    F.resize(triangulation.number_of_faces(),3);
+//    {
+//      int j = 0;
+//      for(Delaunay::Finite_faces_iterator fit = triangulation.finite_faces_begin();
+//          fit != triangulation.finite_faces_end(); ++fit) 
+//      {
+//        Delaunay::Face_handle face = fit;
+//        F(j,0) = face->vertex(0)->info();
+//        F(j,1) = face->vertex(1)->info();
+//        F(j,2) = face->vertex(2)->info();
+//        j++;
+//      }
+//    }
+//  };
 }
 

+ 3 - 2
include/igl/copyleft/cgal/extract_feature.cpp

@@ -7,7 +7,8 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 #include "extract_feature.h"
-#include <igl/unique_edge_map.h>
+#include "../../unique_edge_map.h"
+#include "../../PI.h"
 #include <CGAL/Kernel/global_functions.h>
 #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
 
@@ -55,7 +56,7 @@ IGL_INLINE void igl::copyleft::cgal::extract_feature(
   const size_t num_faces = F.rows();
   // NOTE: CGAL's definition of dihedral angle measures the angle between two
   // facets instead of facet normals.
-  const double cos_tol = cos(M_PI - tol);
+  const double cos_tol = cos(igl::PI - tol);
   std::vector<size_t> result; // Indices into uE
 
   auto is_non_manifold = [&uE2E](size_t ei) -> bool {

+ 65 - 0
include/igl/copyleft/cgal/fast_winding_number.cpp

@@ -0,0 +1,65 @@
+#include "fast_winding_number.h"
+#include "../../fast_winding_number.h"
+#include "../../octree.h"
+#include "../../knn.h"
+#include "../../parallel_for.h"
+#include "point_areas.h"
+#include <vector>
+
+template <
+  typename DerivedP, 
+  typename DerivedN, 
+  typename DerivedQ,
+  typename BetaType, 
+  typename DerivedWN>
+IGL_INLINE void igl::copyleft::cgal::fast_winding_number(
+  const Eigen::MatrixBase<DerivedP>& P,
+  const Eigen::MatrixBase<DerivedN>& N,
+  const Eigen::MatrixBase<DerivedQ>& Q,
+  const int expansion_order,
+  const BetaType beta,
+  Eigen::PlainObjectBase<DerivedWN>& WN)
+{
+  typedef typename DerivedWN::Scalar real;
+  typedef typename Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic>
+    RealMatrix;
+        
+  std::vector<std::vector<int> > point_indices;
+  Eigen::Matrix<int,Eigen::Dynamic,8> CH;
+  Eigen::Matrix<real,Eigen::Dynamic,3> CN;
+  Eigen::Matrix<real,Eigen::Dynamic,1> W;
+  Eigen::MatrixXi I;
+  Eigen::Matrix<real,Eigen::Dynamic,1> A;
+  
+  octree(P,point_indices,CH,CN,W);
+  knn(P,21,point_indices,CH,CN,W,I);
+  point_areas(P,I,N,A);
+  
+  Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic> EC;
+  Eigen::Matrix<real,Eigen::Dynamic,3> CM;
+  Eigen::Matrix<real,Eigen::Dynamic,1> R;
+  
+  igl::fast_winding_number(
+    P,N,A,point_indices,CH,expansion_order,CM,R,EC);
+  igl::fast_winding_number(
+    P,N,A,point_indices,CH,CM,R,EC,Q,beta,WN);
+}
+      
+template <
+  typename DerivedP, 
+  typename DerivedN, 
+  typename DerivedQ, 
+  typename DerivedWN>
+IGL_INLINE void igl::copyleft::cgal::fast_winding_number(
+  const Eigen::MatrixBase<DerivedP>& P,
+  const Eigen::MatrixBase<DerivedN>& N,
+  const Eigen::MatrixBase<DerivedQ>& Q,
+  Eigen::PlainObjectBase<DerivedWN>& WN)
+{
+  fast_winding_number(P,N,Q,2,2.0,WN);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::copyleft::cgal::fast_winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif

+ 79 - 0
include/igl/copyleft/cgal/fast_winding_number.h

@@ -0,0 +1,79 @@
+#ifndef IGL_COPYLEFT_CGAL_FAST_WINDING_NUMBER
+#define IGL_COPYLEFT_CGAL_FAST_WINDING_NUMBER
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+  namespace copyleft
+  {
+    namespace cgal
+    {
+    // Evaluate the fast winding number for point data, without known areas. The
+    // areas are calculated using igl::knn and igl::copyleft::cgal::point_areas.
+    //
+    // This function performes the precomputation and evaluation all in one.
+    // If you need to acess the precomuptation for repeated evaluations, use the
+    // two functions designed for exposed precomputation, which are the first two
+    // functions see in igl/fast_winding_number.h
+    //
+    // Inputs:
+    //   P  #P by 3 list of point locations
+    //   N  #P by 3 list of point normals
+    //   Q  #Q by 3 list of query points for the winding number
+    //   beta  This is a Barnes-Hut style accuracy term that separates near feild
+    //         from far field. The higher the beta, the more accurate and slower
+    //         the evaluation. We reccommend using a beta value of 2.
+    //   expansion_order    the order of the taylor expansion. We support 0,1,2.
+    // Outputs:
+    //   WN  #Q by 1 list of windinng number values at each query point
+    //
+    template <
+      typename DerivedP, 
+      typename DerivedN, 
+      typename DerivedQ,
+      typename BetaType, 
+      typename DerivedWN>
+    IGL_INLINE void fast_winding_number(
+      const Eigen::MatrixBase<DerivedP>& P,
+      const Eigen::MatrixBase<DerivedN>& N,
+      const Eigen::MatrixBase<DerivedQ>& Q,
+      const int expansion_order,
+      const BetaType beta,
+      Eigen::PlainObjectBase<DerivedWN>& WN);
+    
+    // Evaluate the fast winding number for point data, without known areas. The
+    // areas are calculated using igl::knn and
+    // igl::point_areas. This function uses the default expansion
+    // order and beta (both are set to 2).
+    //
+    // This function performes the precomputation and evaluation all in one.
+    // If you need to acess the precomuptation for repeated evaluations, use the
+    // two functions designed for exposed precomputation (described above).
+    
+    // Inputs:
+    //   P  #P by 3 list of point locations
+    //   N  #P by 3 list of point normals
+    //   Q  #Q by 3 list of query points for the winding number
+    // Outputs:
+    //   WN  #Q by 1 list of windinng number values at each query point
+    //
+    template <
+      typename DerivedP, 
+      typename DerivedN, 
+      typename DerivedQ, 
+      typename DerivedWN>
+    IGL_INLINE void fast_winding_number(
+      const Eigen::MatrixBase<DerivedP>& P,
+      const Eigen::MatrixBase<DerivedN>& N,
+      const Eigen::MatrixBase<DerivedQ>& Q,
+      Eigen::PlainObjectBase<DerivedWN>& WN);
+    }
+  }
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "fast_winding_number.cpp"
+#endif
+
+#endif
+

+ 5 - 0
include/igl/copyleft/cgal/hausdorff.cpp

@@ -37,3 +37,8 @@ IGL_INLINE void igl::copyleft::cgal::hausdorff(
   };
   return igl::hausdorff(V,dist_to_B,l,u);
 }
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::copyleft::cgal::hausdorff<Eigen::Matrix<double, -1, -1, 0, -1, -1>, CGAL::Simple_cartesian<double>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Simple_cartesian<double>, CGAL::AABB_triangle_primitive<CGAL::Simple_cartesian<double>, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> > const&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > > const&, double&, double&);
+#endif

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

@@ -145,6 +145,30 @@ IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
   return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J);
 }
 
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedVC,
+  typename DerivedFC,
+  typename DerivedJ>
+IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
+    const std::vector<DerivedV > & Vlist,
+    const std::vector<DerivedF > & Flist,
+    const MeshBooleanType & type,
+    Eigen::PlainObjectBase<DerivedVC > & VC,
+    Eigen::PlainObjectBase<DerivedFC > & FC,
+    Eigen::PlainObjectBase<DerivedJ > & J)
+{
+  DerivedV VV;
+  DerivedF FF;
+  Eigen::Matrix<size_t,Eigen::Dynamic,1> Vsizes,Fsizes;
+  igl::combine(Vlist,Flist,VV,FF,Vsizes,Fsizes);
+  std::function<int(const int, const int)> keep;
+  std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) > wind_num_op;
+  mesh_boolean_type_to_funcs(type,wind_num_op,keep);
+  return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J);
+}
+
 template <
   typename DerivedVV,
   typename DerivedFF,
@@ -435,6 +459,7 @@ template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_n
 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::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<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<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<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&, 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> >&);
 #ifdef WIN32
 template bool igl::copyleft::cgal::mesh_boolean<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, enum igl::MeshBooleanType const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
 #endif

+ 13 - 0
include/igl/copyleft/cgal/mesh_boolean.h

@@ -145,6 +145,19 @@ namespace igl
           Eigen::PlainObjectBase<DerivedVC > & VC,
           Eigen::PlainObjectBase<DerivedFC > & FC,
           Eigen::PlainObjectBase<DerivedJ > & J);
+      template <
+        typename DerivedV,
+        typename DerivedF,
+        typename DerivedVC,
+        typename DerivedFC,
+        typename DerivedJ>
+      IGL_INLINE bool mesh_boolean(
+          const std::vector<DerivedV > & Vlist,
+          const std::vector<DerivedF > & Flist,
+          const MeshBooleanType & type,
+          Eigen::PlainObjectBase<DerivedVC > & VC,
+          Eigen::PlainObjectBase<DerivedFC > & FC,
+          Eigen::PlainObjectBase<DerivedJ > & J);
       // Given a merged mesh (V,F) and list of sizes of inputs
       //
       // Inputs:

+ 1 - 0
include/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp

@@ -73,4 +73,5 @@ template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL
 template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
 template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
 template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Simple_cartesian<double> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >&);
 #endif

+ 181 - 0
include/igl/copyleft/cgal/point_areas.cpp

@@ -0,0 +1,181 @@
+#include "point_areas.h"
+#include "delaunay_triangulation.h"
+
+#include "../../colon.h"
+#include "../../slice.h"
+#include "../../slice_mask.h"
+#include "../../parallel_for.h"
+
+#include "CGAL/Exact_predicates_inexact_constructions_kernel.h"
+#include "CGAL/Triangulation_vertex_base_with_info_2.h"
+#include "CGAL/Triangulation_data_structure_2.h"
+#include "CGAL/Delaunay_triangulation_2.h"
+
+
+
+typedef CGAL::Exact_predicates_inexact_constructions_kernel           Kernel;
+typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
+typedef CGAL::Triangulation_data_structure_2<Vb>                      Tds;
+typedef CGAL::Delaunay_triangulation_2<Kernel, Tds>                   Delaunay;
+typedef Kernel::Point_2                                               Point;
+
+namespace igl {
+  namespace copyleft{
+    namespace cgal{
+      
+      template <typename DerivedP, typename DerivedI, typename DerivedN,
+      typename DerivedA>
+      IGL_INLINE void point_areas(
+                                  const Eigen::MatrixBase<DerivedP>& P,
+                                  const Eigen::MatrixBase<DerivedI>& I,
+                                  const Eigen::MatrixBase<DerivedN>& N,
+                                  Eigen::PlainObjectBase<DerivedA> & A)
+      {
+        Eigen::MatrixXd T;
+        point_areas(P,I,N,A,T);
+      }
+      
+      
+      template <typename DerivedP, typename DerivedI, typename DerivedN,
+      typename DerivedA, typename DerivedT>
+      IGL_INLINE void point_areas(
+                                        const Eigen::MatrixBase<DerivedP>& P,
+                                        const Eigen::MatrixBase<DerivedI>& I,
+                                        const Eigen::MatrixBase<DerivedN>& N,
+                                        Eigen::PlainObjectBase<DerivedA> & A,
+                                        Eigen::PlainObjectBase<DerivedT> & T)
+      {
+        typedef typename DerivedP::Scalar real;
+        typedef typename DerivedN::Scalar scalarN;
+        typedef typename DerivedA::Scalar scalarA;
+        typedef Eigen::Matrix<real,1,3> RowVec3;
+        typedef Eigen::Matrix<real,1,2> RowVec2;
+        
+        typedef Eigen::Matrix<real, Eigen::Dynamic, Eigen::Dynamic> MatrixP;
+        typedef Eigen::Matrix<scalarN, Eigen::Dynamic, Eigen::Dynamic> MatrixN;
+        typedef Eigen::Matrix<typename DerivedN::Scalar,
+                  Eigen::Dynamic, Eigen::Dynamic> VecotorO;
+        typedef Eigen::Matrix<typename DerivedI::Scalar,
+                  Eigen::Dynamic, Eigen::Dynamic> MatrixI;
+        
+        
+        
+        const int n = P.rows();
+        
+        assert(P.cols() == 3 && "P must have exactly 3 columns");
+        assert(P.rows() == N.rows()
+               && "P and N must have the same number of rows");
+        assert(P.rows() == I.rows()
+               && "P and I must have the same number of rows");
+        
+        A.setZero(n,1);
+        T.setZero(n,3);
+        igl::parallel_for(P.rows(),[&](int i)
+        {
+          MatrixI neighbor_index = I.row(i);
+          MatrixP neighbors;
+          igl::slice(P,neighbor_index,1,neighbors);
+          if(N.rows() && neighbors.rows() > 1){
+            MatrixN neighbor_normals;
+            igl::slice(N,neighbor_index,1,neighbor_normals);
+            Eigen::Matrix<scalarN,1,3> poi_normal = neighbor_normals.row(0);
+            Eigen::Matrix<scalarN,Eigen::Dynamic,1> dotprod =
+                            poi_normal(0)*neighbor_normals.col(0)
+            + poi_normal(1)*neighbor_normals.col(1)
+            + poi_normal(2)*neighbor_normals.col(2);
+            Eigen::Array<bool,Eigen::Dynamic,1> keep = dotprod.array() > 0;
+            igl::slice_mask(Eigen::MatrixXd(neighbors),keep,1,neighbors);
+          }
+          if(neighbors.rows() <= 2){
+            A(i) = 0;
+          } else {
+            //subtract the mean from neighbors, then take svd,
+            //the scores will be U*S. This is our pca plane fitting
+            RowVec3 mean = neighbors.colwise().mean();
+            MatrixP mean_centered = neighbors.rowwise() - mean;
+            Eigen::JacobiSVD<MatrixP> svd(mean_centered,
+                                    Eigen::ComputeThinU | Eigen::ComputeThinV);
+            MatrixP scores = svd.matrixU() * svd.singularValues().asDiagonal();
+            
+            T.row(i) = svd.matrixV().col(2).transpose();
+            if(T.row(i).dot(N.row(i)) < 0){
+              T.row(i) *= -1;
+            }
+            
+            MatrixP plane;
+            igl::slice(scores,igl::colon<int>(0,scores.rows()-1),
+                     igl::colon<int>(0,1),plane);
+            
+            std::vector< std::pair<Point,unsigned> > points;
+            //This is where we obtain a delaunay triangulation of the points
+            for(unsigned iter = 0; iter < plane.rows(); iter++){
+              points.push_back( std::make_pair(
+                      Point(plane(iter,0),plane(iter,1)), iter ) );
+            }
+            Delaunay triangulation;
+            triangulation.insert(points.begin(),points.end());
+            Eigen::MatrixXi F(triangulation.number_of_faces(),3);
+            int f_row = 0;
+            for(Delaunay::Finite_faces_iterator fit =
+                triangulation.finite_faces_begin();
+                fit != triangulation.finite_faces_end(); ++fit) {
+              Delaunay::Face_handle face = fit;
+              F.row(f_row) = Eigen::RowVector3i((int)face->vertex(0)->info(),
+                                                (int)face->vertex(1)->info(),
+                                                (int)face->vertex(2)->info());
+              f_row++;
+            }
+            
+            //Here we calculate the voronoi area of the point
+            scalarA area_accumulator = 0;
+            for(int f = 0; f < F.rows(); f++){
+              int X = -1;
+              for(int face_iter = 0; face_iter < 3; face_iter++){
+                if(F(f,face_iter) == 0){
+                  X = face_iter;
+                }
+              }
+              if(X >= 0){
+              //Triangle XYZ with X being the point we want the area of
+                int Y = (X+1)%3;
+                int Z = (X+2)%3;
+                scalarA x = (plane.row(F(f,Y))-plane.row(F(f,Z))).norm();
+                scalarA y = (plane.row(F(f,X))-plane.row(F(f,Z))).norm();
+                scalarA z = (plane.row(F(f,Y))-plane.row(F(f,X))).norm();
+                scalarA cosX = (z*z + y*y - x*x)/(2*y*z);
+                scalarA cosY = (z*z + x*x - y*y)/(2*x*z);
+                scalarA cosZ = (x*x + y*y - z*z)/(2*y*x);
+                Eigen::Matrix<scalarA,1,3> barycentric;
+                barycentric << x*cosX, y*cosY, z*cosZ;
+                barycentric /= (barycentric(0)+barycentric(1)+barycentric(2));
+                
+                //TODO: to make numerically stable, reorder so that x≥y≥z:
+                scalarA full_area = 0.25*std::sqrt(
+                                    (x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z)));
+                Eigen::Matrix<scalarA,1,3> partial_area =
+                                                    barycentric * full_area;
+                if(cosX < 0){
+                  area_accumulator += 0.5*full_area;
+                } else if (cosY < 0 || cosZ < 0){
+                  area_accumulator += 0.25*full_area;
+                } else {
+                  area_accumulator += (partial_area(1) + partial_area(2))/2;
+                }
+              }
+            }
+            
+            if(std::isfinite(area_accumulator)){
+              A(i) = area_accumulator;
+            } else {
+              A(i) = 0;
+            }
+          }
+        },1000);
+      }
+    }
+  }
+}
+
+
+
+

+ 78 - 0
include/igl/copyleft/cgal/point_areas.h

@@ -0,0 +1,78 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Gavin Barill <gavinpcb@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_POINT_AREAS_H
+#define IGL_POINT_AREAS_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  namespace copyleft
+  {
+    namespace cgal
+    {
+    // Given a 3D set of points P, each with a list of k-nearest-neighbours,
+    // estimate the geodesic voronoi area associated with each point.
+    //
+    // The k nearest neighbours may be known from running igl::knn_octree on
+    // the output data from igl::octree. We reccomend using a k value
+    // between 15 and 20 inclusive for accurate area estimation.
+    //
+    // N is used filter the neighbours, to ensure area estimation only occurs
+    // using neighbors that are on the same side of the surface (ie for thin
+    // sheets), as well as to solve the orientation ambiguity of the tangent
+    // plane normal.
+    //
+    // Note: This function *should* be implemented by pre-filtering I, rather
+    // than filtering in this function using N. In this case, the function
+    // would only take P and I as input.
+    //
+    // Inputs:
+    //   P  #P by 3 list of point locations
+    //   I  #P by k list of k-nearest-neighbor indices into P
+    //   N  #P by 3 list of point normals
+    // Outputs:
+    //   A  #P list of estimated areas
+    template <typename DerivedP, typename DerivedI, typename DerivedN,
+      typename DerivedA>
+    IGL_INLINE void point_areas(
+                                        const Eigen::MatrixBase<DerivedP>& P,
+                                        const Eigen::MatrixBase<DerivedI>& I,
+                                        const Eigen::MatrixBase<DerivedN>& N,
+                                        Eigen::PlainObjectBase<DerivedA> & A);
+      
+    // This version can be used to output the tangent plane normal at each
+    // point. Since we area already fitting a plane to each point's neighbour
+    // set, the tangent plane normals come "for free"
+    //
+    // Inputs:
+    //   P  #P by 3 list of point locations
+    //   I  #P by k list of k-nearest-neighbor indices into P
+    //   N  #P by 3 list of point normals
+    // Outputs:
+    //   A  #P list of estimated areas
+    //   T  #P by 3 list of tangent plane normals for each point
+    template <typename DerivedP, typename DerivedI, typename DerivedN,
+    typename DerivedA, typename DerivedT>
+    IGL_INLINE void point_areas(
+                                const Eigen::MatrixBase<DerivedP>& P,
+                                const Eigen::MatrixBase<DerivedI>& I,
+                                const Eigen::MatrixBase<DerivedN>& N,
+                                Eigen::PlainObjectBase<DerivedA> & A,
+                                Eigen::PlainObjectBase<DerivedT> & T);
+      
+    }
+  }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "point_areas.cpp"
+#endif
+
+#endif
+

+ 1 - 0
include/igl/copyleft/cgal/point_mesh_squared_distance.cpp

@@ -135,4 +135,5 @@ IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance(
 // Explicit template instantiation
 template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck,   Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>,   Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1,   -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1>,   Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>   >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3,   0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0,   -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>   > const&,   Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1,   0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&,   Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::point_mesh_squared_distance_precompute<CGAL::Simple_cartesian<double>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Simple_cartesian<double>, CGAL::AABB_triangle_primitive<CGAL::Simple_cartesian<double>, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> >&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >&);
 #endif

+ 2 - 1
include/igl/copyleft/cgal/wire_mesh.cpp

@@ -2,6 +2,7 @@
 
 #include "../../list_to_matrix.h"
 #include "../../slice.h"
+#include "../../PI.h"
 #include "convex_hull.h"
 #include "mesh_boolean.h"
 #include <Eigen/Geometry>
@@ -30,7 +31,7 @@ IGL_INLINE void igl::copyleft::cgal::wire_mesh(
   MatrixX3S PV(poly_size,3);
   for(int p =0;p<PV.rows();p++)
   {
-    const Scalar phi = (Scalar(p)/Scalar(PV.rows()))*2.*M_PI;
+    const Scalar phi = (Scalar(p)/Scalar(PV.rows()))*2.*igl::PI;
     PV(p,0) = 0.5*cos(phi);
     PV(p,1) = 0.5*sin(phi);
     PV(p,2) = 0;

+ 7 - 7
include/igl/copyleft/comiso/frame_field.cpp

@@ -164,25 +164,25 @@ FrameInterpolator::~FrameInterpolator()
 double FrameInterpolator::mod2pi(double d)
 {
   while(d<0)
-    d = d + (2.0*M_PI);
+    d = d + (2.0*igl::PI);
 
-  return fmod(d, (2.0*M_PI));
+  return fmod(d, (2.0*igl::PI));
 }
 
 double FrameInterpolator::modpi2(double d)
 {
   while(d<0)
-    d = d + (M_PI/2.0);
+    d = d + (igl::PI/2.0);
 
-  return fmod(d, (M_PI/2.0));
+  return fmod(d, (igl::PI/2.0));
 }
 
 double FrameInterpolator::modpi(double d)
 {
   while(d<0)
-    d = d + (M_PI);
+    d = d + (igl::PI);
 
-  return fmod(d, (M_PI));
+  return fmod(d, (igl::PI));
 }
 
 
@@ -276,7 +276,7 @@ void FrameInterpolator::compute_edge_consistency()
 
       double r = modpi(theta0-theta1);
 
-      edge_consistency[eid] = r < M_PI/4.0 || r > 3*(M_PI/4.0);
+      edge_consistency[eid] = r < igl::PI/4.0 || r > 3*(igl::PI/4.0);
 
       // Copy it into edge_consistency_TT
       int i1 = -1;

+ 1 - 0
include/igl/copyleft/comiso/frame_field.h

@@ -9,6 +9,7 @@
 #define IGL_COMISO_FRAMEFIELD_H
 
 #include <igl/igl_inline.h>
+#include <igl/PI.h>
 #include <Eigen/Dense>
 #include <vector>
 

+ 9 - 9
include/igl/copyleft/comiso/nrosy.cpp

@@ -297,7 +297,7 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
       row = tag_t[i];
       if (isFixed_i) b(row) += -2               * hard[i]; else T.push_back(Eigen::Triplet<double>(row,tag_t[i]  , 2             ));
       if (isFixed_j) b(row) +=  2               * hard[j]; else T.push_back(Eigen::Triplet<double>(row,tag_t[j]  ,-2             ));
-      if (isFixed_p) b(row) += -((4 * M_PI)/Nd) * p[eid] ; else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],((4 * M_PI)/Nd)));
+      if (isFixed_p) b(row) += -((4 * igl::PI)/Nd) * p[eid] ; else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],((4 * igl::PI)/Nd)));
       b(row) += -2 * k[eid];
       assert(hard[i] == hard[i]);
       assert(hard[j] == hard[j]);
@@ -311,7 +311,7 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
       row = tag_t[j];
       if (isFixed_i) b(row) += 2               * hard[i]; else T.push_back(Eigen::Triplet<double>(row,tag_t[i]  , -2             ));
       if (isFixed_j) b(row) += -2              * hard[j]; else T.push_back(Eigen::Triplet<double>(row,tag_t[j] ,  2              ));
-      if (isFixed_p) b(row) += ((4 * M_PI)/Nd) * p[eid] ; else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],-((4 * M_PI)/Nd)));
+      if (isFixed_p) b(row) += ((4 * igl::PI)/Nd) * p[eid] ; else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],-((4 * igl::PI)/Nd)));
       b(row) += 2 * k[eid];
       assert(k[eid] == k[eid]);
       assert(b(row) == b(row));
@@ -320,10 +320,10 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
     if (!isFixed_p)
     {
       row = tag_p[eid];
-      if (isFixed_i) b(row) += -(4 * M_PI)/Nd              * hard[i]; else T.push_back(Eigen::Triplet<double>(row,tag_t[i] ,   (4 * M_PI)/Nd             ));
-      if (isFixed_j) b(row) +=  (4 * M_PI)/Nd              * hard[j]; else T.push_back(Eigen::Triplet<double>(row,tag_t[j] ,  -(4 * M_PI)/Nd             ));
-      if (isFixed_p) b(row) += -(2 * pow(((2*M_PI)/Nd),2)) * p[eid] ;  else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],  (2 * pow(((2*M_PI)/Nd),2))));
-      b(row) += - (4 * M_PI)/Nd * k[eid];
+      if (isFixed_i) b(row) += -(4 * igl::PI)/Nd              * hard[i]; else T.push_back(Eigen::Triplet<double>(row,tag_t[i] ,   (4 * igl::PI)/Nd             ));
+      if (isFixed_j) b(row) +=  (4 * igl::PI)/Nd              * hard[j]; else T.push_back(Eigen::Triplet<double>(row,tag_t[j] ,  -(4 * igl::PI)/Nd             ));
+      if (isFixed_p) b(row) += -(2 * pow(((2*igl::PI)/Nd),2)) * p[eid] ;  else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],  (2 * pow(((2*igl::PI)/Nd),2))));
+      b(row) += - (4 * igl::PI)/Nd * k[eid];
       assert(k[eid] == k[eid]);
       assert(b(row) == b(row));
     }
@@ -759,7 +759,7 @@ void igl::copyleft::comiso::NRosyField::reduceSpace()
           int fid1 = EF(eid,1);
 
           pFixed[eid] = true;
-          p[eid] = roundl(2.0/M_PI*(hard(fid1) - hard(fid0) - k(eid)));
+          p[eid] = roundl(2.0/igl::PI*(hard(fid1) - hard(fid0) - k(eid)));
         }
       }
     }
@@ -795,7 +795,7 @@ Eigen::Vector3d igl::copyleft::comiso::NRosyField::convertLocalto3D(unsigned fid
 
 Eigen::VectorXd igl::copyleft::comiso::NRosyField::angleDefect()
 {
-  Eigen::VectorXd A = Eigen::VectorXd::Constant(V.rows(),-2*M_PI);
+  Eigen::VectorXd A = Eigen::VectorXd::Constant(V.rows(),-2*igl::PI);
 
   for (unsigned i=0; i < F.rows(); ++i)
   {
@@ -834,7 +834,7 @@ void igl::copyleft::comiso::NRosyField::findCones(int N)
   I0 = I0 + A;
 
   // normalize
-  I0 = I0 / (2*M_PI);
+  I0 = I0 / (2*igl::PI);
 
   // round to integer (remove numerical noise)
   for (unsigned i=0; i < I0.size(); ++i)

+ 1 - 0
include/igl/copyleft/comiso/nrosy.h

@@ -13,6 +13,7 @@
 #include <Eigen/Sparse>
 #include <vector>
 #include "../../igl_inline.h"
+#include "../../PI.h"
 
 namespace igl
 {

+ 3 - 3
include/igl/copyleft/marching_cubes.cpp

@@ -126,7 +126,7 @@ public:
 
       // determine cube type
       for (i=0; i<8; ++i)
-        if (values[corner[i]] > 0.0)
+        if (values(corner[i]) > 0.0)
           cubetype |= (1<<i);
 
 
@@ -202,8 +202,8 @@ public:
     const Eigen::Matrix<typename Derivedpoints::Scalar, 1, 3> & p0 = points.row(i0);
     const Eigen::Matrix<typename Derivedpoints::Scalar, 1, 3> & p1 = points.row(i1);
 
-    typename Derivedvalues::Scalar s0 = fabs(values[i0]);
-    typename Derivedvalues::Scalar s1 = fabs(values[i1]);
+    typename Derivedvalues::Scalar s0 = fabs(values(i0));
+    typename Derivedvalues::Scalar s1 = fabs(values(i1));
     typename Derivedvalues::Scalar t  = s0 / (s0+s1);
 
 

+ 26 - 25
include/igl/copyleft/tetgen/tetrahedralize.cpp

@@ -1,15 +1,15 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 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 
+//
+// 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 "tetrahedralize.h"
 #include "mesh_to_tetgenio.h"
 #include "tetgenio_to_tetmesh.h"
 
-// IGL includes 
+// IGL includes
 #include "../../matrix_to_list.h"
 #include "../../list_to_matrix.h"
 #include "../../boundary_facets.h"
@@ -19,11 +19,11 @@
 #include <iostream>
 
 IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
-  const std::vector<std::vector<REAL > > & V, 
-  const std::vector<std::vector<int> > & F, 
+  const std::vector<std::vector<REAL > > & V,
+  const std::vector<std::vector<int> > & F,
   const std::string switches,
-  std::vector<std::vector<REAL > > & TV, 
-  std::vector<std::vector<int > > & TT, 
+  std::vector<std::vector<REAL > > & TV,
+  std::vector<std::vector<int > > & TT,
   std::vector<std::vector<int> > & TF)
 {
   using namespace std;
@@ -60,10 +60,10 @@ IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
 }
 
 template <
-  typename DerivedV, 
-  typename DerivedF, 
-  typename DerivedTV, 
-  typename DerivedTT, 
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedTV,
+  typename DerivedTT,
   typename DerivedTF>
 IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
   const Eigen::PlainObjectBase<DerivedV>& V,
@@ -101,12 +101,12 @@ IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
 }
 
 template <
-  typename DerivedV, 
-  typename DerivedF, 
-  typename DerivedVM, 
-  typename DerivedFM, 
-  typename DerivedTV, 
-  typename DerivedTT, 
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedVM,
+  typename DerivedFM,
+  typename DerivedTV,
+  typename DerivedTT,
   typename DerivedTF,
   typename DerivedTM>
 IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
@@ -124,7 +124,7 @@ IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
   vector<vector<REAL> > vV,vTV;
   vector<vector<int> > vF,vTT,vTF;
   vector<int> vTM;
-	
+
   matrix_to_list(V,vV);
   matrix_to_list(F,vF);
 	vector<int> vVM = matrix_to_list(VM);
@@ -156,13 +156,13 @@ IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
   return e;
 }
 IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
-  const std::vector<std::vector<REAL > > & V, 
-  const std::vector<std::vector<int> > & F, 
-  const std::vector<int> & VM, 
+  const std::vector<std::vector<REAL > > & V,
+  const std::vector<std::vector<int> > & F,
+  const std::vector<int> & VM,
 	const std::vector<int> & FM,
   const std::string switches,
-  std::vector<std::vector<REAL > > & TV, 
-  std::vector<std::vector<int > > & TT, 
+  std::vector<std::vector<REAL > > & TV,
+  std::vector<std::vector<int > > & TT,
   std::vector<std::vector<int> > & TF,
   std::vector<int> & TM)
 {
@@ -216,4 +216,5 @@ IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
 // Explicit template instantiation
 template int igl::copyleft::tetgen::tetrahedralize<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&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 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 int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1> >(const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &,const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &,const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const std::basic_string<char, std::char_traits<char>, std::allocator<char> >,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> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &);
+template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

+ 1 - 1
include/igl/cotmatrix.h

@@ -32,7 +32,7 @@ namespace igl
   //   Scalar  scalar type for eigen sparse matrix (e.g. double)
   // Inputs:
   //   V  #V by dim list of mesh vertex positions
-  //   F  #F by simplex_size list of mesh faces (must be triangles)
+  //   F  #F by simplex_size list of mesh elements (triangles or tetrahedra)
   // Outputs: 
   //   L  #V by #V cotangent matrix, each row i corresponding to V(i,:)
   //

+ 1 - 0
include/igl/covariance_scatter_matrix.cpp

@@ -13,6 +13,7 @@
 #include "edges.h"
 #include "verbose.h"
 #include "cat.h"
+#include "PI.h"
 
 IGL_INLINE void igl::covariance_scatter_matrix(
   const Eigen::MatrixXd & V, 

+ 2 - 1
include/igl/cross_field_missmatch.cpp

@@ -17,6 +17,7 @@
 #include <igl/vertex_triangle_adjacency.h>
 #include <igl/triangle_triangle_adjacency.h>
 #include <igl/rotation_matrix_from_directions.h>
+#include <igl/PI.h>
 
 namespace igl {
   template <typename DerivedV, typename DerivedF, typename DerivedM>
@@ -65,7 +66,7 @@ namespace igl {
 
       //    std::cerr << "Dani: " << dir0(0) << " " << dir0(1) << " " << dir0(2) << " " << dir1Rot(0) << " " << dir1Rot(1) << " " << dir1Rot(2) << " " << angle_diff << std::endl;
 
-      double step=M_PI/2.0;
+      double step=igl::PI/2.0;
       int i=(int)std::floor((angle_diff/step)+0.5);
       int k=0;
       if (i>=0)

+ 1 - 0
include/igl/cumsum.cpp

@@ -64,6 +64,7 @@ template void igl::cumsum<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<
 template void igl::cumsum<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
 template void igl::cumsum<Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1>, Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1> >(Eigen::MatrixBase<Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1> >&);
 template void igl::cumsum<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1>, Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&);
+template void igl::cumsum<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #ifdef WIN32
 template void igl::cumsum<class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>> const &, int, class Eigen::PlainObjectBase<class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>> &);
 template void igl::cumsum<class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>, class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>> const &, int, class Eigen::PlainObjectBase<class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>> &);

+ 9 - 15
include/igl/dirname.cpp

@@ -1,5 +1,6 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
 // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
 // 
 // This Source Code Form is subject to the terms of the Mozilla Public License 
@@ -16,31 +17,24 @@ IGL_INLINE std::string igl::dirname(const std::string & path)
   {
     return std::string("");
   }
-#if defined (WIN32)
-  char del('\\');
-#else
-  char del('/');
-#endif
-  // http://stackoverflow.com/questions/5077693/dirnamephp-similar-function-in-c
-  std::string::const_reverse_iterator last_slash =
-    std::find(
-      path.rbegin(), 
-      path.rend(),del);
-  if( last_slash == path.rend() )
+  // https://stackoverflow.com/a/3071694/148668
+  size_t found = path.find_last_of("/\\");
+  if(found == std::string::npos)
   {
     // No slashes found
     return std::string(".");
-  }else if(1 == (last_slash.base() - path.begin()))
+  }else if(found == 0)
   {
     // Slash is first char
-    return std::string(&del);
-  }else if(path.end() == last_slash.base() )
+    return std::string(path.begin(),path.begin()+1);
+  }else if(found == path.length()-1)
   {
     // Slash is last char
     std::string redo = std::string(path.begin(),path.end()-1);
     return igl::dirname(redo);
   }
-  return std::string(path.begin(),last_slash.base()-1);
+  // Return everything up to but not including last slash
+  return std::string(path.begin(),path.begin()+found);
 }
 
 

+ 5 - 0
include/igl/dirname.h

@@ -1,5 +1,6 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
 // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
 // 
 // This Source Code Form is subject to the terms of the Mozilla Public License 
@@ -19,6 +20,10 @@ namespace igl
   // Returns string containing dirname (see php's dirname)
   //
   // See also: basename, pathinfo
+  //
+  // **Note:** This function will have undefined behavior if **file names** in
+  // the path contain \ and / characters. This function interprets \ and / as
+  // file path separators.
   IGL_INLINE std::string dirname(const std::string & path);
 }
 

+ 1 - 2
include/igl/edges.h

@@ -14,8 +14,7 @@
 namespace igl
 {
   // Constructs a list of unique edges represented in a given mesh (V,F)
-  // Templates:
-  //   T  should be a eigen sparse matrix primitive type like int or double
+  //
   // Inputs:
   //   F  #F by 3 list of mesh faces (must be triangles)
   //   or

+ 1 - 1
include/igl/exact_geodesic.cpp.REMOVED.git-id

@@ -1 +1 @@
-0ffa8b0392da9471a2fd26ec71effd909d4a75f3
+d962df24e92081e5b1fa2cd25f3123a7b0e03235

+ 324 - 0
include/igl/fast_winding_number.cpp

@@ -0,0 +1,324 @@
+#include "fast_winding_number.h"
+#include "octree.h"
+#include "knn.h"
+#include "parallel_for.h"
+#include "PI.h"
+#include <vector>
+
+namespace igl {
+  template <typename DerivedP, typename DerivedA, typename DerivedN,
+  typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
+  typename DerivedEC>
+  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+                                      const Eigen::MatrixBase<DerivedN>& N,
+                                      const Eigen::MatrixBase<DerivedA>& A,
+                                      const std::vector<std::vector<Index> > & point_indices,
+                                      const Eigen::MatrixBase<DerivedCH>& CH,
+                                      const int expansion_order,
+                                      Eigen::PlainObjectBase<DerivedCM>& CM,
+                                      Eigen::PlainObjectBase<DerivedR>& R,
+                                      Eigen::PlainObjectBase<DerivedEC>& EC)
+  {
+    typedef typename DerivedP::Scalar real_p;
+    typedef typename DerivedN::Scalar real_n;
+    typedef typename DerivedA::Scalar real_a;
+    typedef typename DerivedCM::Scalar real_cm;
+    typedef typename DerivedR::Scalar real_r;
+    typedef typename DerivedEC::Scalar real_ec;
+  
+    typedef Eigen::Matrix<real_p,1,3> RowVec3p;
+  
+    int m = CH.size();
+    int num_terms;
+  
+    assert(expansion_order < 3 && expansion_order >= 0 && "m must be less than n");
+    if(expansion_order == 0){
+        num_terms = 3;
+    } else if(expansion_order ==1){
+        num_terms = 3 + 9;
+    } else if(expansion_order == 2){
+        num_terms = 3 + 9 + 27;
+    }
+  
+    R.resize(m);
+    CM.resize(m,3);
+    EC.resize(m,num_terms);
+    EC.setZero(m,num_terms);
+    std::function< void(const int) > helper;
+    helper = [&helper,
+              &P,&N,&A,&expansion_order,&point_indices,&CH,&EC,&R,&CM]
+    (const int index)-> void
+    {
+        Eigen::Matrix<real_cm,1,3> masscenter;
+        masscenter << 0,0,0;
+        Eigen::Matrix<real_ec,1,3> zeroth_expansion;
+        zeroth_expansion << 0,0,0;
+        real_p areatotal = 0.0;
+        for(int j = 0; j < point_indices.at(index).size(); j++){
+            int curr_point_index = point_indices.at(index).at(j);
+          
+            areatotal += A(curr_point_index);
+            masscenter += A(curr_point_index)*P.row(curr_point_index);
+            zeroth_expansion += A(curr_point_index)*N.row(curr_point_index);
+        }
+      
+        masscenter = masscenter/areatotal;
+        CM.row(index) = masscenter;
+        EC.block(index,0,1,3) = zeroth_expansion;
+      
+        real_r max_norm = 0;
+        real_r curr_norm;
+      
+        for(int i = 0; i < point_indices.at(index).size(); i++){
+            //Get max distance from center of mass:
+            int curr_point_index = point_indices.at(index).at(i);
+            Eigen::Matrix<real_r,1,3> point =
+                P.row(curr_point_index)-masscenter;
+            curr_norm = point.norm();
+            if(curr_norm > max_norm){
+                max_norm = curr_norm;
+            }
+          
+            //Calculate higher order terms if necessary
+            Eigen::Matrix<real_ec,3,3> TempCoeffs;
+            if(EC.cols() >= (3+9)){
+                TempCoeffs = A(curr_point_index)*point.transpose()*
+                                N.row(curr_point_index);
+                EC.block(index,3,1,9) +=
+                Eigen::Map<Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
+                                                        TempCoeffs.size());
+            }
+          
+            if(EC.cols() == (3+9+27)){
+                for(int k = 0; k < 3; k++){
+                    TempCoeffs = 0.5 * point(k) * (A(curr_point_index)*
+                                  point.transpose()*N.row(curr_point_index));
+                    EC.block(index,12+9*k,1,9) += Eigen::Map<
+                      Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
+                                                   TempCoeffs.size());
+                }
+            }
+        }
+      
+        R(index) = max_norm;
+        if(CH(index,0) != -1)
+        {
+            for(int i = 0; i < 8; i++){
+                int child = CH(index,i);
+                helper(child);
+            }
+        }
+    };
+    helper(0);
+  }
+  
+  template <typename DerivedP, typename DerivedA, typename DerivedN,
+  typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
+  typename DerivedEC, typename DerivedQ, typename BetaType,
+  typename DerivedWN>
+  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+                        const Eigen::MatrixBase<DerivedN>& N,
+                        const Eigen::MatrixBase<DerivedA>& A,
+                        const std::vector<std::vector<Index> > & point_indices,
+                        const Eigen::MatrixBase<DerivedCH>& CH,
+                        const Eigen::MatrixBase<DerivedCM>& CM,
+                        const Eigen::MatrixBase<DerivedR>& R,
+                        const Eigen::MatrixBase<DerivedEC>& EC,
+                        const Eigen::MatrixBase<DerivedQ>& Q,
+                        const BetaType beta,
+                        Eigen::PlainObjectBase<DerivedWN>& WN){
+  
+    typedef typename DerivedP::Scalar real_p;
+    typedef typename DerivedN::Scalar real_n;
+    typedef typename DerivedA::Scalar real_a;
+    typedef typename DerivedCM::Scalar real_cm;
+    typedef typename DerivedR::Scalar real_r;
+    typedef typename DerivedEC::Scalar real_ec;
+    typedef typename DerivedQ::Scalar real_q;
+    typedef typename DerivedWN::Scalar real_wn;
+  
+    typedef Eigen::Matrix<real_q,1,3> RowVec;
+    typedef Eigen::Matrix<real_ec,3,3> EC_3by3;
+  
+    auto direct_eval = [](const RowVec & loc,
+                          const Eigen::Matrix<real_ec,1,3> & anorm){
+        real_wn wn = (loc(0)*anorm(0)+loc(1)*anorm(1)+loc(2)*anorm(2))
+                                    /(4.0*igl::PI*std::pow(loc.norm(),3));
+        if(std::isnan(wn)){
+            return 0.5;
+        }else{
+            return wn;
+        }
+    };
+  
+    auto expansion_eval = [&direct_eval](const RowVec & loc,
+                                         const Eigen::RowVectorXd & EC){
+      real_wn wn = direct_eval(loc,EC.head<3>());
+      double r = loc.norm();
+      if(EC.size()>3){
+        Eigen::Matrix<real_ec,3,3> SecondDerivative =
+            Eigen::Matrix<real_ec,3,3>::Identity()/(4.0*igl::PI*std::pow(r,3));
+        SecondDerivative += -3.0*loc.transpose()*loc/(4.0*igl::PI*std::pow(r,5));
+        Eigen::Matrix<real_ec,1,9> derivative_vector =
+          Eigen::Map<Eigen::Matrix<real_ec,1,9> >(SecondDerivative.data(),
+                                                  SecondDerivative.size());
+        wn += derivative_vector.cwiseProduct(EC.segment<9>(3)).sum();
+      }
+      if(EC.size()>3+9){
+          Eigen::Matrix<real_ec,3,3> ThirdDerivative;
+          for(int i = 0; i < 3; i++){
+              ThirdDerivative =
+                  15.0*loc(i)*loc.transpose()*loc/(4.0*igl::PI*std::pow(r,7));
+              Eigen::Matrix<real_ec,3,3> Diagonal;
+              Diagonal << loc(i), 0, 0,
+              0, loc(i), 0,
+              0, 0, loc(i);
+              Eigen::Matrix<real_ec,3,3> RowCol;
+              RowCol.setZero(3,3);
+              RowCol.row(i) = loc;
+              Eigen::Matrix<real_ec,3,3> RowColT = RowCol.transpose();
+              RowCol = RowCol + RowColT;
+              ThirdDerivative +=
+                  -3.0/(4.0*igl::PI*std::pow(r,5))*(RowCol+Diagonal);
+              Eigen::Matrix<real_ec,1,9> derivative_vector =
+                Eigen::Map<Eigen::Matrix<real_ec,1,9> >(ThirdDerivative.data(),
+                                                        ThirdDerivative.size());
+              wn += derivative_vector.cwiseProduct(
+                                              EC.segment<9>(12 + i*9)).sum();
+          }
+      }
+      return wn;
+    };
+  
+    int m = Q.rows();
+    WN.resize(m,1);
+  
+    std::function< real_wn(const RowVec, const std::vector<int>) > helper;
+    helper = [&helper,
+              &P,&N,&A,
+              &point_indices,&CH,
+              &CM,&R,&EC,&beta,
+              &direct_eval,&expansion_eval]
+    (const RowVec query, const std::vector<int> near_indices)-> real_wn
+    {
+      std::vector<int> new_near_indices;
+      real_wn wn = 0;
+      for(int i = 0; i < near_indices.size(); i++){
+        int index = near_indices.at(i);
+        //Leaf Case, Brute force
+        if(CH(index,0) == -1){
+          for(int j = 0; j < point_indices.at(index).size(); j++){
+            int curr_row = point_indices.at(index).at(j);
+            wn += direct_eval(P.row(curr_row)-query,
+                              N.row(curr_row)*A(curr_row));
+          }
+        }
+        //Non-Leaf Case
+        else {
+          for(int child = 0; child < 8; child++){
+              int child_index = CH(index,child);
+              if(point_indices.at(child_index).size() > 0){
+                if((CM.row(child_index)-query).norm() > beta*R(child_index)){
+                  if(CH(child_index,0) == -1){
+                    for(int j=0;j<point_indices.at(child_index).size();j++){
+                      int curr_row = point_indices.at(child_index).at(j);
+                      wn += direct_eval(P.row(curr_row)-query,
+                                        N.row(curr_row)*A(curr_row));
+                    }
+                  }else{
+                    wn += expansion_eval(CM.row(child_index)-query,
+                                         EC.row(child_index));
+                  }
+                }else {
+                  new_near_indices.emplace_back(child_index);
+              }
+            }
+          }
+        }
+      }
+      if(new_near_indices.size() > 0){
+          wn += helper(query,new_near_indices);
+      }
+      return wn;
+    };
+  
+  
+    if(beta > 0){
+      std::vector<int> near_indices_start = {0};
+      igl::parallel_for(m,[&](int iter){
+        WN(iter) = helper(Q.row(iter),near_indices_start);
+      },1000);
+    } else {
+      igl::parallel_for(m,[&](int iter){
+        double wn = 0;
+        for(int j = 0; j <P.rows(); j++){
+          wn += direct_eval(P.row(j)-Q.row(iter),N.row(j)*A(j));
+        }
+        WN(iter) = wn;
+      },1000);
+    }
+  }
+  
+  template <typename DerivedP, typename DerivedA, typename DerivedN,
+    typename DerivedQ, typename BetaType, typename DerivedWN>
+  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+                                      const Eigen::MatrixBase<DerivedN>& N,
+                                      const Eigen::MatrixBase<DerivedA>& A,
+                                      const Eigen::MatrixBase<DerivedQ>& Q,
+                                      const int expansion_order,
+                                      const BetaType beta,
+                                      Eigen::PlainObjectBase<DerivedWN>& WN
+                                      ){
+    typedef typename DerivedWN::Scalar real;
+    
+    std::vector<std::vector<int> > point_indices;
+    Eigen::Matrix<int,Eigen::Dynamic,8> CH;
+    Eigen::Matrix<real,Eigen::Dynamic,3> CN;
+    Eigen::Matrix<real,Eigen::Dynamic,1> W;
+  
+    octree(P,point_indices,CH,CN,W);
+  
+    Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic> EC;
+    Eigen::Matrix<real,Eigen::Dynamic,3> CM;
+    Eigen::Matrix<real,Eigen::Dynamic,1> R;
+  
+    fast_winding_number(P,N,A,point_indices,CH,expansion_order,CM,R,EC);
+    fast_winding_number(P,N,A,point_indices,CH,CM,R,EC,Q,beta,WN);
+  }
+  
+  template <typename DerivedP, typename DerivedA, typename DerivedN,
+    typename DerivedQ, typename DerivedWN>
+  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+                                      const Eigen::MatrixBase<DerivedN>& N,
+                                      const Eigen::MatrixBase<DerivedA>& A,
+                                      const Eigen::MatrixBase<DerivedQ>& Q,
+                                      Eigen::PlainObjectBase<DerivedWN>& WN
+                                      ){
+    fast_winding_number(P,N,A,Q,2,2.0,WN);
+  }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 118 - 0
include/igl/fast_winding_number.h

@@ -0,0 +1,118 @@
+#ifndef IGL_FAST_WINDING_NUMBER
+#define IGL_FAST_WINDING_NUMBER
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+  // Generate the precomputation for the fast winding number for point data
+  // [Barill et. al 2018].
+  //
+  // Given a set of 3D points P, with normals N, areas A, along with octree
+  // data, and an expansion order, we define a taylor series expansion at each
+  // octree cell.
+  //
+  // The octree data is designed to come from igl::octree, and the areas
+  // (if not obtained at scan time), may be calculated using
+  // igl::copyleft::cgal::point_areas.
+  //
+  // Inputs:
+  //   P  #P by 3 list of point locations
+  //   N  #P by 3 list of point normals
+  //   A  #P by 1 list of point areas
+  //   point_indices  a vector of vectors, where the ith entry is a vector of
+  //                  the indices into P that are the ith octree cell's points
+  //   CH             #OctreeCells by 8, where the ith row is the indices of
+  //                  the ith octree cell's children
+  //   expansion_order    the order of the taylor expansion. We support 0,1,2.
+  // Outputs:
+  //   CM  #OctreeCells by 3 list of each cell's center of mass
+  //   R   #OctreeCells by 1 list of each cell's maximum distance of any point
+  //       to the center of mass
+  //   EC  #OctreeCells by #TaylorCoefficients list of expansion coefficients.
+  //       (Note that #TaylorCoefficients = ∑_{i=1}^{expansion_order} 3^i)
+  //
+  template <typename DerivedP, typename DerivedA, typename DerivedN,
+    typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
+    typename DerivedEC>
+  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+                                      const Eigen::MatrixBase<DerivedN>& N,
+                                      const Eigen::MatrixBase<DerivedA>& A,
+            const std::vector<std::vector<Index> > & point_indices,
+            const Eigen::MatrixBase<DerivedCH>& CH,
+            const int expansion_order,
+            Eigen::PlainObjectBase<DerivedCM>& CM,
+            Eigen::PlainObjectBase<DerivedR>& R,
+            Eigen::PlainObjectBase<DerivedEC>& EC);
+  
+  // Evaluate the fast winding number for point data, having already done the
+  // the precomputation
+  //
+  // Inputs:
+  //   P  #P by 3 list of point locations
+  //   N  #P by 3 list of point normals
+  //   A  #P by 1 list of point areas
+  //   point_indices  a vector of vectors, where the ith entry is a vector of
+  //                  the indices into P that are the ith octree cell's points
+  //   CH  #OctreeCells by 8, where the ith row is the indices of
+  //       the ith octree cell's children
+  //   CM  #OctreeCells by 3 list of each cell's center of mass
+  //   R   #OctreeCells by 1 list of each cell's maximum distance of any point
+  //       to the center of mass
+  //   EC  #OctreeCells by #TaylorCoefficients list of expansion coefficients.
+  //        (Note that #TaylorCoefficients = ∑_{i=1}^{expansion_order} 3^i)
+  //   Q  #Q by 3 list of query points for the winding number
+  //   beta  This is a Barnes-Hut style accuracy term that separates near feild
+  //         from far field. The higher the beta, the more accurate and slower
+  //         the evaluation. We reccommend using a beta value of 2. Note that
+  //         for a beta value ≤ 0, we use the direct evaluation, rather than
+  //         the fast approximation
+  // Outputs:
+  //   WN  #Q by 1 list of windinng number values at each query point
+  //
+  template <typename DerivedP, typename DerivedA, typename DerivedN,
+    typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
+    typename DerivedEC, typename DerivedQ, typename BetaType,
+    typename DerivedWN>
+  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+                                      const Eigen::MatrixBase<DerivedN>& N,
+                                      const Eigen::MatrixBase<DerivedA>& A,
+            const std::vector<std::vector<Index> > & point_indices,
+            const Eigen::MatrixBase<DerivedCH>& CH,
+            const Eigen::MatrixBase<DerivedCM>& CM,
+            const Eigen::MatrixBase<DerivedR>& R,
+            const Eigen::MatrixBase<DerivedEC>& EC,
+            const Eigen::MatrixBase<DerivedQ>& Q,
+            const BetaType beta,
+            Eigen::PlainObjectBase<DerivedWN>& WN);
+  
+  // Evaluate the fast winding number for point data, with default expansion
+  // order and beta (both are set to 2).
+  //
+  // This function performes the precomputation and evaluation all in one.
+  // If you need to acess the precomuptation for repeated evaluations, use the
+  // two functions designed for exposed precomputation (described above).
+  //
+  // Inputs:
+  //   P  #P by 3 list of point locations
+  //   N  #P by 3 list of point normals
+  //   A  #P by 1 list of point areas
+  //   Q  #Q by 3 list of query points for the winding number
+  // Outputs:
+  //   WN  #Q by 1 list of windinng number values at each query point
+  //
+  template <typename DerivedP, typename DerivedA, typename DerivedN,
+    typename DerivedQ, typename DerivedWN>
+  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+                                      const Eigen::MatrixBase<DerivedN>& N,
+                                      const Eigen::MatrixBase<DerivedA>& A,
+                                      const Eigen::MatrixBase<DerivedQ>& Q,
+                                      Eigen::PlainObjectBase<DerivedWN>& WN
+                                      );
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "fast_winding_number.cpp"
+#endif
+
+#endif
+

+ 3 - 2
include/igl/flip_avoiding_line_search.cpp

@@ -7,6 +7,7 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "flip_avoiding_line_search.h"
 #include "line_search.h"
+#include "PI.h"
 
 #include <Eigen/Dense>
 #include <vector>
@@ -38,8 +39,8 @@ namespace igl
           t=acos(t);
           a/=3; q=-2*sqrt(q);
           x[0]=q*cos(t/3)-a;
-          x[1]=q*cos((t+(2*M_PI))/3)-a;
-          x[2]=q*cos((t-(2*M_PI))/3)-a;
+          x[1]=q*cos((t+(2*igl::PI))/3)-a;
+          x[2]=q*cos((t-(2*igl::PI))/3)-a;
           return(3);
         }
         else

+ 1 - 0
include/igl/flip_avoiding_line_search.h

@@ -8,6 +8,7 @@
 #ifndef IGL_FLIP_AVOIDING_LINE_SEARCH_H
 #define IGL_FLIP_AVOIDING_LINE_SEARCH_H
 #include "igl_inline.h"
+#include "PI.h"
 
 #include <Eigen/Dense>
 

+ 2 - 1
include/igl/grad.cpp

@@ -9,6 +9,7 @@
 #include <Eigen/Geometry>
 #include <vector>
 
+#include "PI.h"
 #include "per_face_normals.h"
 #include "volume.h"
 #include "doublearea.h"
@@ -148,7 +149,7 @@ IGL_INLINE void grad_tri(const Eigen::PlainObjectBase<DerivedV>&V,
       // Abstract equilateral triangle v1=(0,0), v2=(h,0), v3=(h/2, (sqrt(3)/2)*h)
 
       // get h (by the area of the triangle)
-      double h = sqrt( (dblA)/sin(M_PI / 3.0)); // (h^2*sin(60))/2. = Area => h = sqrt(2*Area/sin_60)
+      double h = sqrt( (dblA)/sin(igl::PI / 3.0)); // (h^2*sin(60))/2. = Area => h = sqrt(2*Area/sin_60)
 
       Eigen::Matrix<typename DerivedV::Scalar, 3, 1> v1,v2,v3;
       v1 << 0,0,0;

+ 1 - 0
include/igl/hausdorff.cpp

@@ -86,4 +86,5 @@ IGL_INLINE void igl::hausdorff(
 
 #ifdef IGL_STATIC_LIBRARY
 template void igl::hausdorff<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>, double>(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&, double&);
+template void igl::hausdorff<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::function<double (double const&, double const&, double const&)> const&, double&, double&);
 #endif

+ 0 - 1
include/igl/is_vertex_manifold.cpp

@@ -97,6 +97,5 @@ IGL_INLINE bool igl::is_vertex_manifold(
 
 #ifdef IGL_STATIC_LIBRARY
 template bool igl::is_vertex_manifold<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> >&);
-template bool igl::is_vertex_manifold<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template bool igl::is_vertex_manifold<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> >&);
 #endif

+ 105 - 0
include/igl/knn.cpp

@@ -0,0 +1,105 @@
+#include "knn.h"
+#include "parallel_for.h"
+
+#include <cmath>
+#include <queue>
+
+namespace igl {
+  template <typename DerivedP, typename KType, typename IndexType,
+  typename DerivedCH, typename DerivedCN, typename DerivedW,
+  typename DerivedI>
+  IGL_INLINE void knn(const Eigen::MatrixBase<DerivedP>& P,
+                      const KType & k,
+                      const std::vector<std::vector<IndexType> > & point_indices,
+                      const Eigen::MatrixBase<DerivedCH>& CH,
+                      const Eigen::MatrixBase<DerivedCN>& CN,
+                      const Eigen::MatrixBase<DerivedW>& W,
+                      Eigen::PlainObjectBase<DerivedI> & I)
+  {
+    typedef typename DerivedCN::Scalar CentersType;
+    typedef typename DerivedW::Scalar WidthsType;
+    
+    typedef Eigen::Matrix<typename DerivedP::Scalar, 1, 3> RowVector3PType;
+    
+    int n = P.rows();
+    const KType real_k = std::min(n,k);
+    
+    auto distance_to_width_one_cube = [](RowVector3PType point){
+      return std::sqrt(std::pow(std::max(std::abs(point(0))-1,0.0),2)
+                       + std::pow(std::max(std::abs(point(1))-1,0.0),2)
+                       + std::pow(std::max(std::abs(point(2))-1,0.0),2));
+    };
+    
+    auto distance_to_cube = [&distance_to_width_one_cube]
+              (RowVector3PType point,
+               Eigen::Matrix<CentersType,1,3> cube_center,
+               WidthsType cube_width){
+      RowVector3PType transformed_point = (point-cube_center)/cube_width;
+      return cube_width*distance_to_width_one_cube(transformed_point);
+    };
+    
+    I.resize(n,real_k);
+    
+    igl::parallel_for(n,[&](int i)
+    {
+      int points_found = 0;
+      RowVector3PType point_of_interest = P.row(i);
+      
+      //To make my priority queue take both points and octree cells,
+      //I use the indices 0 to n-1 for the n points,
+      // and the indices n to n+m-1 for the m octree cells
+      
+      // Using lambda to compare elements.
+      auto cmp = [&point_of_interest, &P, &CN, &W,
+                  &n, &distance_to_cube](int left, int right) {
+        double leftdistance, rightdistance;
+        if(left < n){ //left is a point index
+          leftdistance = (P.row(left) - point_of_interest).norm();
+        } else { //left is an octree cell
+          leftdistance = distance_to_cube(point_of_interest,
+                                            CN.row(left-n),
+                                            W(left-n));
+        }
+      
+        if(right < n){ //left is a point index
+          rightdistance = (P.row(right) - point_of_interest).norm();
+        } else { //left is an octree cell
+          rightdistance = distance_to_cube(point_of_interest,
+                                             CN.row(right-n),
+                                             W(right-n));
+        }
+        return leftdistance >= rightdistance;
+      };
+      
+      std::priority_queue<IndexType, std::vector<IndexType>,
+        decltype(cmp)> queue(cmp);
+      
+      queue.push(n); //This is the 0th octree cell (ie the root)
+      while(points_found < real_k){
+        IndexType curr_cell_or_point = queue.top();
+        queue.pop();
+        if(curr_cell_or_point < n){ //current index is for is a point
+          I(i,points_found) = curr_cell_or_point;
+          points_found++;
+        } else {
+          IndexType curr_cell = curr_cell_or_point - n;
+          if(CH(curr_cell,0) == -1){ //In the case of a leaf
+            if(point_indices.at(curr_cell).size() > 0){
+              //Assumption: Leaves either have one point, or none
+              queue.push(point_indices.at(curr_cell).at(0));
+            }
+          } else { //Not a leaf
+            for(int j = 0; j < 8; j++){
+              //+n to adjust for the octree cells
+              queue.push(CH(curr_cell,j)+n);
+            }
+          }
+        }
+      }
+    },1000);
+  }
+}
+
+
+
+

+ 52 - 0
include/igl/knn.h

@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Gavin Barill <gavinpcb@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_KNN
+#define IGL_KNN
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+  // Given a 3D set of points P, an whole number k, and an octree
+  // find the indicies of the k nearest neighbors for each point in P.
+  // Note that each point is its own neighbor.
+  //
+  // The octree data structures used in this function are intended to be the
+  // same ones output from igl::octree
+  //
+  // Inputs:
+  //   P  #P by 3 list of point locations
+  //   k  number of neighbors to find
+  //   point_indices  a vector of vectors, where the ith entry is a vector of
+  //                  the indices into P that are the ith octree cell's points
+  //   CH     #OctreeCells by 8, where the ith row is the indices of
+  //          the ith octree cell's children
+  //   CN     #OctreeCells by 3, where the ith row is a 3d row vector
+  //          representing the position of the ith cell's center
+  //   W      #OctreeCells, a vector where the ith entry is the width
+  //          of the ith octree cell
+  // Outputs:
+  //   I  #P by k list of k-nearest-neighbor indices into P
+  template <typename DerivedP, typename KType, typename IndexType,
+    typename DerivedCH, typename DerivedCN, typename DerivedW,
+    typename DerivedI>
+  IGL_INLINE void knn(const Eigen::MatrixBase<DerivedP>& P,
+    const KType & k,
+    const std::vector<std::vector<IndexType> > & point_indices,
+    const Eigen::MatrixBase<DerivedCH>& CH,
+    const Eigen::MatrixBase<DerivedCN>& CN,
+    const Eigen::MatrixBase<DerivedW>& W,
+    Eigen::PlainObjectBase<DerivedI> & I);
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "knn.cpp"
+#endif
+#endif
+

+ 3 - 2
include/igl/line_field_missmatch.cpp

@@ -20,6 +20,7 @@
 #include <igl/triangle_triangle_adjacency.h>
 #include <igl/rotation_matrix_from_directions.h>
 #include <igl/local_basis.h>
+#include <igl/PI.h>
 
 namespace igl {
 template <typename DerivedV, typename DerivedF, typename DerivedO>
@@ -65,7 +66,7 @@ private:
 
         double angle_diff = atan2(dir1Rot.dot(PD2.row(f0)),dir1Rot.dot(PD1.row(f0)));
 
-        double step=M_PI;
+        double step=igl::PI;
         int i=(int)std::floor((angle_diff/step)+0.5);
         assert((i>=-2)&&(i<=2));
         int k=0;
@@ -133,7 +134,7 @@ IGL_INLINE void igl::line_field_missmatch(const Eigen::PlainObjectBase<DerivedV>
     }
     Eigen::MatrixXd B1,B2,B3;
     igl::local_basis(V,F,B1,B2,B3);
-    PD2_combed = igl::rotate_vectors(PD1_combed, Eigen::VectorXd::Constant(1,M_PI/2), B1, B2);
+    PD2_combed = igl::rotate_vectors(PD1_combed, Eigen::VectorXd::Constant(1,igl::PI/2), B1, B2);
     igl::MissMatchCalculatorLine<DerivedV, DerivedF, DerivedO> sf(V, F, PD1_combed, PD2_combed);
     sf.calculateMissmatchLine(missmatch);
 }

+ 2 - 1
include/igl/map_vertices_to_circle.cpp

@@ -7,6 +7,7 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 #include "map_vertices_to_circle.h"
+#include "PI.h"
 
 IGL_INLINE void igl::map_vertices_to_circle(
   const Eigen::MatrixXd& V,
@@ -46,7 +47,7 @@ IGL_INLINE void igl::map_vertices_to_circle(
   UV.resize(bnd.size(),2);
   for (int i = 0; i < bnd.size(); i++)
   {
-    double frac = len[i] * 2. * M_PI / total_len;
+    double frac = len[i] * 2. * igl::PI / total_len;
     UV.row(map_ij[bnd[i]]) << cos(frac), sin(frac);
   }
 

+ 1 - 0
include/igl/map_vertices_to_circle.h

@@ -8,6 +8,7 @@
 #ifndef IGL_MAP_VERTICES_TO_CIRCLE_H
 #define IGL_MAP_VERTICES_TO_CIRCLE_H
 #include "igl_inline.h"
+#include "PI.h"
 
 #include <Eigen/Dense>
 #include <vector>

+ 1 - 1
include/igl/massmatrix.h

@@ -35,7 +35,7 @@ namespace igl
   //   Scalar  scalar type for eigen sparse matrix (e.g. double)
   // Inputs:
   //   V  #V by dim list of mesh vertex positions
-  //   F  #F by simplex_size list of mesh faces (must be triangles)
+  //   F  #F by simplex_size list of mesh elements (triangles or tetrahedra)
   //   type  one of the following ints:
   //     MASSMATRIX_TYPE_BARYCENTRIC  barycentric
   //     MASSMATRIX_TYPE_VORONOI voronoi-hybrid {default}

+ 1 - 0
include/igl/matrix_to_list.cpp

@@ -75,4 +75,5 @@ template void igl::matrix_to_list<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::D
 template void igl::matrix_to_list<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar, std::allocator<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar> >, std::allocator<std::vector<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar, std::allocator<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar> > > >&);
 template void igl::matrix_to_list<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar> >&);
 template void igl::matrix_to_list<Eigen::Matrix<int, 1, -1, 1, 1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, 1, -1, 1, 1, -1> > const&, std::vector<Eigen::Matrix<int, 1, -1, 1, 1, -1>::Scalar, std::allocator<Eigen::Matrix<int, 1, -1, 1, 1, -1>::Scalar> >&);
+template std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar> > igl::matrix_to_list<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
 #endif

+ 180 - 0
include/igl/octree.cpp

@@ -0,0 +1,180 @@
+#include "octree.h"
+#include <vector>
+#include <queue>
+
+namespace igl {
+  template <typename DerivedP, typename IndexType, typename DerivedCH,
+    typename DerivedCN, typename DerivedW>
+  IGL_INLINE void octree(const Eigen::MatrixBase<DerivedP>& P,
+                         std::vector<std::vector<IndexType> > & point_indices,
+                         Eigen::PlainObjectBase<DerivedCH>& CH,
+                         Eigen::PlainObjectBase<DerivedCN>& CN,
+                         Eigen::PlainObjectBase<DerivedW>& W)
+  {
+    
+    
+    
+    const int MAX_DEPTH = 30000;
+
+    typedef typename DerivedCH::Scalar ChildrenType;
+    typedef typename DerivedCN::Scalar CentersType;
+    typedef typename DerivedW::Scalar WidthsType;
+    typedef Eigen::Matrix<ChildrenType,8,1> Vector8i;
+    typedef Eigen::Matrix<typename DerivedP::Scalar, 1, 3> RowVector3PType;
+    typedef Eigen::Matrix<CentersType, 1, 3>       RowVector3CentersType;
+    
+    std::vector<Eigen::Matrix<ChildrenType,8,1>,
+        Eigen::aligned_allocator<Eigen::Matrix<ChildrenType,8,1> > > children;
+    std::vector<Eigen::Matrix<CentersType,1,3>,
+        Eigen::aligned_allocator<Eigen::Matrix<CentersType,1,3> > > centers;
+    std::vector<WidthsType> widths;
+    
+    auto get_octant = [](RowVector3PType location,
+                         RowVector3CentersType center){
+      // We use a binary numbering of children. Treating the parent cell's
+      // center as the origin, we number the octants in the following manner:
+      // The first bit is 1 iff the octant's x coordinate is positive
+      // The second bit is 1 iff the octant's y coordinate is positive
+      // The third bit is 1 iff the octant's z coordinate is positive
+      //
+      // For example, the octant with negative x, positive y, positive z is:
+      // 110 binary = 6 decimal
+      IndexType index = 0;
+      if( location(0) >= center(0)){
+        index = index + 1;
+      }
+      if( location(1) >= center(1)){
+        index = index + 2;
+      }
+      if( location(2) >= center(2)){
+        index = index + 4;
+      }
+      return index;
+    };
+
+    
+    std::function< RowVector3CentersType(const RowVector3CentersType,
+                                         const CentersType,
+                                         const ChildrenType) >
+    translate_center =
+        [](const RowVector3CentersType & parent_center,
+           const CentersType h,
+           const ChildrenType child_index){
+      RowVector3CentersType change_vector;
+      change_vector << -h,-h,-h;
+          
+      //positive x chilren are 1,3,4,7
+      if(child_index % 2){
+        change_vector(0) = h;
+      }
+      //positive y children are 2,3,6,7
+      if(child_index == 2 || child_index == 3 ||
+        child_index == 6 || child_index == 7){
+        change_vector(1) = h;
+      }
+      //positive z children are 4,5,6,7
+      if(child_index > 3){
+        change_vector(2) = h;
+      }
+      RowVector3CentersType output = parent_center + change_vector;
+      return output;
+    };
+  
+    // How many cells do we have so far?
+    IndexType m = 0;
+  
+    // Useful list of number 0..7
+    const Vector8i zero_to_seven = (Vector8i()<<0,1,2,3,4,5,6,7).finished();
+    const Vector8i neg_ones = (Vector8i()<<-1,-1,-1,-1,-1,-1,-1,-1).finished();
+  
+    std::function< void(const ChildrenType, const int) > helper;
+    helper = [&helper,&translate_center,&get_octant,&m,
+              &zero_to_seven,&neg_ones,&P,
+              &point_indices,&children,&centers,&widths,&MAX_DEPTH]
+    (const ChildrenType index, const int depth)-> void
+    {
+      if(point_indices.at(index).size() > 1 && depth < MAX_DEPTH){
+        //give the parent access to the children
+        children.at(index) = zero_to_seven.array() + m;
+        //make the children's data in our arrays
+      
+        //Add the children to the lists, as default children
+        CentersType h = widths.at(index)/2;
+        RowVector3CentersType curr_center = centers.at(index);
+        
+
+        for(ChildrenType i = 0; i < 8; i++){
+          children.emplace_back(neg_ones);
+          point_indices.emplace_back(std::vector<IndexType>());
+          centers.emplace_back(translate_center(curr_center,h,i));
+          widths.emplace_back(h);
+        }
+
+      
+        //Split up the points into the corresponding children
+        for(int j = 0; j < point_indices.at(index).size(); j++){
+          IndexType curr_point_index = point_indices.at(index).at(j);
+          IndexType cell_of_curr_point =
+            get_octant(P.row(curr_point_index),curr_center)+m;
+          point_indices.at(cell_of_curr_point).emplace_back(curr_point_index);
+        }
+      
+        //Now increase m
+        m += 8;
+        
+
+        // Look ma, I'm calling myself.
+        for(int i = 0; i < 8; i++){
+          helper(children.at(index)(i),depth+1);
+        }
+      }
+    };
+  
+    {
+      std::vector<IndexType> all(P.rows());
+      for(IndexType i = 0;i<all.size();i++) all[i]=i;
+      point_indices.emplace_back(all);
+    }
+    children.emplace_back(neg_ones);
+  
+    //Get the minimum AABB for the points
+    RowVector3PType backleftbottom(P.col(0).minCoeff(),
+                                   P.col(1).minCoeff(),
+                                   P.col(2).minCoeff());
+    RowVector3PType frontrighttop(P.col(0).maxCoeff(),
+                                  P.col(1).maxCoeff(),
+                                  P.col(2).maxCoeff());
+    RowVector3CentersType aabb_center = (backleftbottom+frontrighttop)/2.0;
+    WidthsType aabb_width = std::max(std::max(
+                                          frontrighttop(0) - backleftbottom(0),
+                                          frontrighttop(1) - backleftbottom(1)),
+                                          frontrighttop(2) - backleftbottom(2));
+    centers.emplace_back( aabb_center );
+  
+    //Widths are the side length of the cube, (not half the side length):
+    widths.emplace_back( aabb_width );
+    m++;
+    // then you have to actually call the function
+    helper(0,0);
+    
+    //Now convert from vectors to Eigen matricies:
+    CH.resize(children.size(),8);
+    CN.resize(centers.size(),3);
+    W.resize(widths.size(),1);
+    
+    for(int i = 0; i < children.size(); i++){
+      CH.row(i) = children.at(i);
+    }
+    for(int i = 0; i < centers.size(); i++){
+      CN.row(i) = centers.at(i);
+    }
+    for(int i = 0; i < widths.size(); i++){
+      W(i) = widths.at(i);
+    }
+  }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::octree<Eigen::Matrix<double, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, 8, 0, -1, 8>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 8, 0, -1, 8> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif

+ 62 - 0
include/igl/octree.h

@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Gavin Barill <gavinpcb@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_OCTREE
+#define IGL_OCTREE
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+
+
+
+namespace igl
+{
+  // Given a set of 3D points P, generate data structures for a pointerless
+  // octree. Each cell stores its points, children, center location and width.
+  // Our octree is not dense. We use the following rule: if the current cell
+  // has any number of points, it will have all 8 children. A leaf cell will
+  // have -1's as its list of child indices.
+  //
+  // We use a binary numbering of children. Treating the parent cell's center
+  // as the origin, we number the octants in the following manner:
+  // The first bit is 1 iff the octant's x coordinate is positive
+  // The second bit is 1 iff the octant's y coordinate is positive
+  // The third bit is 1 iff the octant's z coordinate is positive
+  //
+  // For example, the octant with negative x, positive y, positive z is:
+  // 110 binary = 6 decimal
+  //
+  // Inputs:
+  //   P  #P by 3 list of point locations
+  //
+  // Outputs:
+  //   point_indices  a vector of vectors, where the ith entry is a vector of
+  //                  the indices into P that are the ith octree cell's points
+  //   CH     #OctreeCells by 8, where the ith row is the indices of
+  //          the ith octree cell's children
+  //   CN     #OctreeCells by 3, where the ith row is a 3d row vector
+  //          representing the position of the ith cell's center
+  //   W      #OctreeCells, a vector where the ith entry is the width
+  //          of the ith octree cell
+  //
+  template <typename DerivedP, typename IndexType, typename DerivedCH,
+  typename DerivedCN, typename DerivedW>
+  IGL_INLINE void octree(const Eigen::MatrixBase<DerivedP>& P,
+    std::vector<std::vector<IndexType> > & point_indices,
+    Eigen::PlainObjectBase<DerivedCH>& CH,
+    Eigen::PlainObjectBase<DerivedCN>& CN,
+    Eigen::PlainObjectBase<DerivedW>& W);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "octree.cpp"
+#endif
+
+#endif
+

+ 10 - 13
include/igl/opengl/MeshGL.cpp

@@ -166,9 +166,9 @@ IGL_INLINE void igl::opengl::MeshGL::init()
   is_initialized = true;
   std::string mesh_vertex_shader_string =
 R"(#version 150
-  uniform mat4 model;
   uniform mat4 view;
   uniform mat4 proj;
+  uniform mat4 normal_matrix;
   in vec3 position;
   in vec3 normal;
   out vec3 position_eye;
@@ -184,10 +184,10 @@ R"(#version 150
 
   void main()
   {
-    position_eye = vec3 (view * model * vec4 (position, 1.0));
-    normal_eye = vec3 (view * model * vec4 (normal, 0.0));
+    position_eye = vec3 (view * vec4 (position, 1.0));
+    normal_eye = vec3 (normal_matrix * vec4 (normal, 0.0));
     normal_eye = normalize(normal_eye);
-    gl_Position = proj * vec4 (position_eye, 1.0); //proj * view * model * vec4(position, 1.0);
+    gl_Position = proj * vec4 (position_eye, 1.0); //proj * view * vec4(position, 1.0);"
     Kai = Ka;
     Kdi = Kd;
     Ksi = Ks;
@@ -195,15 +195,14 @@ R"(#version 150
   }
 )";
 
-  std::string mesh_fragment_shader_string = 
+  std::string mesh_fragment_shader_string =
 R"(#version 150
-  uniform mat4 model;
   uniform mat4 view;
   uniform mat4 proj;
   uniform vec4 fixed_color;
   in vec3 position_eye;
   in vec3 normal_eye;
-  uniform vec3 light_position_world;
+  uniform vec3 light_position_eye;
   vec3 Ls = vec3 (1, 1, 1);
   vec3 Ld = vec3 (1, 1, 1);
   vec3 La = vec3 (1, 1, 1);
@@ -220,14 +219,13 @@ R"(#version 150
   {
     vec3 Ia = La * vec3(Kai);    // ambient intensity
 
-    vec3 light_position_eye = vec3 (view * vec4 (light_position_world, 1.0));
     vec3 vector_to_light_eye = light_position_eye - position_eye;
     vec3 direction_to_light_eye = normalize (vector_to_light_eye);
-    float dot_prod = dot (direction_to_light_eye, normal_eye);
+    float dot_prod = dot (direction_to_light_eye, normalize(normal_eye));
     float clamped_dot_prod = max (dot_prod, 0.0);
     vec3 Id = Ld * vec3(Kdi) * clamped_dot_prod;    // Diffuse intensity
 
-    vec3 reflection_eye = reflect (-direction_to_light_eye, normal_eye);
+    vec3 reflection_eye = reflect (-direction_to_light_eye, normalize(normal_eye));
     vec3 surface_to_viewer_eye = normalize (-position_eye);
     float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);
     dot_prod_specular = float(abs(dot_prod)==dot_prod) * max (dot_prod_specular, 0.0);
@@ -237,11 +235,10 @@ R"(#version 150
     outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;
     if (fixed_color != vec4(0.0)) outColor = fixed_color;
   }
-  )";
+)";
 
   std::string overlay_vertex_shader_string =
 R"(#version 150
-  uniform mat4 model;
   uniform mat4 view;
   uniform mat4 proj;
   in vec3 position;
@@ -250,7 +247,7 @@ R"(#version 150
 
   void main()
   {
-    gl_Position = proj * view * model * vec4 (position, 1.0);
+    gl_Position = proj * view * vec4 (position, 1.0);
     color_frag = color;
   }
 )";

+ 78 - 81
include/igl/opengl/ViewerCore.cpp

@@ -26,7 +26,7 @@ IGL_INLINE void igl::opengl::ViewerCore::align_camera_center(
   if(V.rows() == 0)
     return;
 
-  get_scale_and_shift_to_fit_mesh(V,F,model_zoom,model_translation);
+  get_scale_and_shift_to_fit_mesh(V,F,camera_base_zoom,camera_base_translation);
   // Rather than crash on empty mesh...
   if(V.size() > 0)
   {
@@ -60,7 +60,7 @@ IGL_INLINE void igl::opengl::ViewerCore::align_camera_center(
   if(V.rows() == 0)
     return;
 
-  get_scale_and_shift_to_fit_mesh(V,model_zoom,model_translation);
+  get_scale_and_shift_to_fit_mesh(V,camera_base_zoom,camera_base_translation);
   // Rather than crash on empty mesh...
   if(V.size() > 0)
   {
@@ -90,7 +90,7 @@ IGL_INLINE void igl::opengl::ViewerCore::clear_framebuffers()
   glClearColor(background_color[0],
                background_color[1],
                background_color[2],
-               1.0f);
+               background_color[3]);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 }
 
@@ -122,15 +122,20 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
 
   if(update_matrices)
   {
-    model = Eigen::Matrix4f::Identity();
-    view  = Eigen::Matrix4f::Identity();
-    proj  = Eigen::Matrix4f::Identity();
+    view = Eigen::Matrix4f::Identity();
+    proj = Eigen::Matrix4f::Identity();
+    norm = Eigen::Matrix4f::Identity();
+
+    float width  = viewport(2);
+    float height = viewport(3);
 
     // Set view
     look_at( camera_eye, camera_center, camera_up, view);
+    view = view
+      * (trackball_angle * Eigen::Scaling(camera_zoom * camera_base_zoom)
+      * Eigen::Translation3f(camera_translation + camera_base_translation)).matrix();
 
-    float width  = viewport(2);
-    float height = viewport(3);
+    norm = view.inverse().transpose();
 
     // Set projection
     if (orthographic)
@@ -145,40 +150,25 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
       float fW = fH * (double)width/(double)height;
       frustum(-fW, fW, -fH, fH, camera_dnear, camera_dfar,proj);
     }
-    // end projection
-
-    // Set model transformation
-    float mat[16];
-    igl::quat_to_mat(trackball_angle.coeffs().data(), mat);
-
-    for (unsigned i=0;i<4;++i)
-      for (unsigned j=0;j<4;++j)
-        model(i,j) = mat[i+4*j];
-
-    // Why not just use Eigen::Transform<double,3,Projective> for model...?
-    model.topLeftCorner(3,3)*=camera_zoom;
-    model.topLeftCorner(3,3)*=model_zoom;
-    model.col(3).head(3) += model.topLeftCorner(3,3)*model_translation;
   }
 
   // Send transformations to the GPU
-  GLint modeli = glGetUniformLocation(data.meshgl.shader_mesh,"model");
   GLint viewi  = glGetUniformLocation(data.meshgl.shader_mesh,"view");
   GLint proji  = glGetUniformLocation(data.meshgl.shader_mesh,"proj");
-  glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
+  GLint normi  = glGetUniformLocation(data.meshgl.shader_mesh,"normal_matrix");
   glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
   glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
+  glUniformMatrix4fv(normi, 1, GL_FALSE, norm.data());
 
   // Light parameters
   GLint specular_exponenti    = glGetUniformLocation(data.meshgl.shader_mesh,"specular_exponent");
-  GLint light_position_worldi = glGetUniformLocation(data.meshgl.shader_mesh,"light_position_world");
+  GLint light_position_eyei = glGetUniformLocation(data.meshgl.shader_mesh,"light_position_eye");
   GLint lighting_factori      = glGetUniformLocation(data.meshgl.shader_mesh,"lighting_factor");
   GLint fixed_colori          = glGetUniformLocation(data.meshgl.shader_mesh,"fixed_color");
   GLint texture_factori       = glGetUniformLocation(data.meshgl.shader_mesh,"texture_factor");
 
   glUniform1f(specular_exponenti, data.shininess);
-  Vector3f rev_light = -1.*light_position;
-  glUniform3fv(light_position_worldi, 1, rev_light.data());
+  glUniform3fv(light_position_eyei, 1, light_position.data());
   glUniform1f(lighting_factori, lighting_factor); // enables lighting
   glUniform4f(fixed_colori, 0.0, 0.0, 0.0, 0.0);
 
@@ -197,8 +187,8 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
     if (data.show_lines)
     {
       glLineWidth(data.line_width);
-      glUniform4f(fixed_colori, 
-        data.line_color[0], 
+      glUniform4f(fixed_colori,
+        data.line_color[0],
         data.line_color[1],
         data.line_color[2], 1.0f);
       data.meshgl.draw_mesh(false);
@@ -216,11 +206,9 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
     if (data.lines.rows() > 0)
     {
       data.meshgl.bind_overlay_lines();
-      modeli = glGetUniformLocation(data.meshgl.shader_overlay_lines,"model");
       viewi  = glGetUniformLocation(data.meshgl.shader_overlay_lines,"view");
       proji  = glGetUniformLocation(data.meshgl.shader_overlay_lines,"proj");
 
-      glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
       glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
       glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
       // This must be enabled, otherwise glLineWidth has no effect
@@ -233,11 +221,9 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
     if (data.points.rows() > 0)
     {
       data.meshgl.bind_overlay_points();
-      modeli = glGetUniformLocation(data.meshgl.shader_overlay_points,"model");
       viewi  = glGetUniformLocation(data.meshgl.shader_overlay_points,"view");
       proji  = glGetUniformLocation(data.meshgl.shader_overlay_points,"proj");
 
-      glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
       glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
       glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
       glPointSize(data.point_size);
@@ -260,64 +246,81 @@ IGL_INLINE void igl::opengl::ViewerCore::draw_buffer(ViewerData& data,
   assert(R.rows() == G.rows() && G.rows() == B.rows() && B.rows() == A.rows());
   assert(R.cols() == G.cols() && G.cols() == B.cols() && B.cols() == A.cols());
 
-  unsigned x = R.rows();
-  unsigned y = R.cols();
-
-  // Create frame buffer
-  GLuint frameBuffer;
-  glGenFramebuffers(1, &frameBuffer);
-  glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
-
-  // Create texture to hold color buffer
-  GLuint texColorBuffer;
-  glGenTextures(1, &texColorBuffer);
-  glBindTexture(GL_TEXTURE_2D, texColorBuffer);
-
-  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+  unsigned width = R.rows();
+  unsigned height = R.cols();
+
+  // https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing
+  unsigned int framebuffer;
+  glGenFramebuffers(1, &framebuffer);
+  glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+  // create a multisampled color attachment texture
+  unsigned int textureColorBufferMultiSampled;
+  glGenTextures(1, &textureColorBufferMultiSampled);
+  glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled);
+  glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, width, height, GL_TRUE);
+  glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
+  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);
+  // create a (also multisampled) renderbuffer object for depth and stencil attachments
+  unsigned int rbo;
+  glGenRenderbuffers(1, &rbo);
+  glBindRenderbuffer(GL_RENDERBUFFER, rbo);
+  glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
+  glBindRenderbuffer(GL_RENDERBUFFER, 0);
+  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
+  assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+  glBindFramebuffer(GL_FRAMEBUFFER, 0);
 
+  // configure second post-processing framebuffer
+  unsigned int intermediateFBO;
+  glGenFramebuffers(1, &intermediateFBO);
+  glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
+  // create a color attachment texture
+  unsigned int screenTexture;
+  glGenTextures(1, &screenTexture);
+  glBindTexture(GL_TEXTURE_2D, screenTexture);
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);
-
-  // Create Renderbuffer Object to hold depth and stencil buffers
-  GLuint rboDepthStencil;
-  glGenRenderbuffers(1, &rboDepthStencil);
-  glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil);
-  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, x, y);
-  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rboDepthStencil);
-
+  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0);	// we only need a color buffer
   assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+  glBindFramebuffer(GL_FRAMEBUFFER, 0);
 
-  glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
+  glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
 
   // Clear the buffer
   glClearColor(background_color(0), background_color(1), background_color(2), 0.f);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
   // Save old viewport
   Eigen::Vector4f viewport_ori = viewport;
-  viewport << 0,0,x,y;
-
+  viewport << 0,0,width,height;
   // Draw
   draw(data,update_matrices);
-
   // Restore viewport
   viewport = viewport_ori;
 
+  glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
+  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
+  glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+  glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
   // Copy back in the given Eigen matrices
-  GLubyte* pixels = (GLubyte*)calloc(x*y*4,sizeof(GLubyte));
-  glReadPixels
-  (
-   0, 0,
-   x, y,
-   GL_RGBA, GL_UNSIGNED_BYTE, pixels
-   );
+  GLubyte* pixels = (GLubyte*)calloc(width*height*4,sizeof(GLubyte));
+  glReadPixels(0, 0,width, height,GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+  // Clean up
+  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+  glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+  glBindFramebuffer(GL_FRAMEBUFFER, 0);
+  glDeleteTextures(1, &screenTexture);
+  glDeleteTextures(1, &textureColorBufferMultiSampled);
+  glDeleteFramebuffers(1, &framebuffer);
+  glDeleteFramebuffers(1, &intermediateFBO);
+  glDeleteRenderbuffers(1, &rbo);
 
   int count = 0;
-  for (unsigned j=0; j<y; ++j)
+  for (unsigned j=0; j<height; ++j)
   {
-    for (unsigned i=0; i<x; ++i)
+    for (unsigned i=0; i<width; ++i)
     {
       R(i,j) = pixels[count*4+0];
       G(i,j) = pixels[count*4+1];
@@ -326,13 +329,8 @@ IGL_INLINE void igl::opengl::ViewerCore::draw_buffer(ViewerData& data,
       ++count;
     }
   }
-
   // Clean up
   free(pixels);
-  glBindFramebuffer(GL_FRAMEBUFFER, 0);
-  glDeleteRenderbuffers(1, &rboDepthStencil);
-  glDeleteTextures(1, &texColorBuffer);
-  glDeleteFramebuffers(1, &frameBuffer);
 }
 
 IGL_INLINE void igl::opengl::ViewerCore::set_rotation_type(
@@ -356,23 +354,22 @@ IGL_INLINE igl::opengl::ViewerCore::ViewerCore()
   background_color << 0.3f, 0.3f, 0.5f, 1.0f;
 
   // Default lights settings
-  light_position << 0.0f, -0.30f, -5.0f;
+  light_position << 0.0f, 0.3f, 0.0f;
   lighting_factor = 1.0f; //on
 
   // Default trackball
   trackball_angle = Eigen::Quaternionf::Identity();
   set_rotation_type(ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP);
 
-  // Defalut model viewing parameters
-  model_zoom = 1.0f;
-  model_translation << 0,0,0;
-
   // Camera parameters
+  camera_base_zoom = 1.0f;
   camera_zoom = 1.0f;
   orthographic = false;
   camera_view_angle = 45.0;
   camera_dnear = 1.0;
   camera_dfar = 100.0;
+  camera_base_translation << 0, 0, 0;
+  camera_translation << 0, 0, 0;
   camera_eye << 0, 0, 5;
   camera_center << 0, 0, 0;
   camera_up << 0, 1, 0;

+ 9 - 19
include/igl/opengl/ViewerCore.h

@@ -101,20 +101,14 @@ public:
   float lighting_factor;
 
   RotationType rotation_type;
-
   Eigen::Quaternionf trackball_angle;
 
-  // Model viewing parameters
-  float model_zoom;
-  Eigen::Vector3f model_translation;
-
-  // Model viewing parameters (uv coordinates)
-  float model_zoom_uv;
-  Eigen::Vector3f model_translation_uv;
-
   // Camera parameters
+  float camera_base_zoom;
   float camera_zoom;
   bool orthographic;
+  Eigen::Vector3f camera_base_translation;
+  Eigen::Vector3f camera_translation;
   Eigen::Vector3f camera_eye;
   Eigen::Vector3f camera_up;
   Eigen::Vector3f camera_center;
@@ -134,11 +128,10 @@ public:
   // Viewport size
   Eigen::Vector4f viewport;
 
-  // Save the OpenGL transformation matrices used for the previous rendering
-  // pass
+  // Save the OpenGL transformation matrices used for the previous rendering pass
   Eigen::Matrix4f view;
-  Eigen::Matrix4f model;
   Eigen::Matrix4f proj;
+  Eigen::Matrix4f norm;
   public:
       EIGEN_MAKE_ALIGNED_OPERATOR_NEW
 };
@@ -161,14 +154,11 @@ namespace igl {
       SERIALIZE_MEMBER(trackball_angle);
       SERIALIZE_MEMBER(rotation_type);
 
-      SERIALIZE_MEMBER(model_zoom);
-      SERIALIZE_MEMBER(model_translation);
-
-      SERIALIZE_MEMBER(model_zoom_uv);
-      SERIALIZE_MEMBER(model_translation_uv);
-
+      SERIALIZE_MEMBER(camera_base_zoom);
       SERIALIZE_MEMBER(camera_zoom);
       SERIALIZE_MEMBER(orthographic);
+      SERIALIZE_MEMBER(camera_base_translation);
+      SERIALIZE_MEMBER(camera_translation);
       SERIALIZE_MEMBER(camera_view_angle);
       SERIALIZE_MEMBER(camera_dnear);
       SERIALIZE_MEMBER(camera_dfar);
@@ -184,8 +174,8 @@ namespace igl {
 
       SERIALIZE_MEMBER(viewport);
       SERIALIZE_MEMBER(view);
-      SERIALIZE_MEMBER(model);
       SERIALIZE_MEMBER(proj);
+      SERIALIZE_MEMBER(norm);
     }
 
     template<>

+ 5 - 5
include/igl/opengl/glfw/Viewer.cpp

@@ -601,7 +601,7 @@ namespace glfw
 
     down = true;
 
-    down_translation = core.model_translation;
+    down_translation = core.camera_translation;
 
 
     // Initialization code for the trackball
@@ -617,7 +617,7 @@ namespace glfw
     Eigen::Vector3f coord =
       igl::project(
         Eigen::Vector3f(center(0),center(1),center(2)),
-        (core.view * core.model).eval(),
+        core.view,
         core.proj,
         core.viewport);
     down_mouse_z = coord[2];
@@ -724,11 +724,11 @@ namespace glfw
         case MouseMode::Translation:
         {
           //translation
-          Eigen::Vector3f pos1 = igl::unproject(Eigen::Vector3f(mouse_x, core.viewport[3] - mouse_y, down_mouse_z), (core.view * core.model).eval(), core.proj, core.viewport);
-          Eigen::Vector3f pos0 = igl::unproject(Eigen::Vector3f(down_mouse_x, core.viewport[3] - down_mouse_y, down_mouse_z), (core.view * core.model).eval(), core.proj, core.viewport);
+          Eigen::Vector3f pos1 = igl::unproject(Eigen::Vector3f(mouse_x, core.viewport[3] - mouse_y, down_mouse_z), core.view, core.proj, core.viewport);
+          Eigen::Vector3f pos0 = igl::unproject(Eigen::Vector3f(down_mouse_x, core.viewport[3] - down_mouse_y, down_mouse_z), core.view, core.proj, core.viewport);
 
           Eigen::Vector3f diff = pos1 - pos0;
-          core.model_translation = down_translation + Eigen::Vector3f(diff[0],diff[1],diff[2]);
+          core.camera_translation = down_translation + Eigen::Vector3f(diff[0],diff[1],diff[2]);
 
           break;
         }

+ 1 - 2
include/igl/opengl/glfw/imgui/ImGuiMenu.cpp

@@ -347,10 +347,9 @@ IGL_INLINE void ImGuiMenu::draw_labels(const igl::opengl::ViewerData &data)
 
 IGL_INLINE void ImGuiMenu::draw_text(Eigen::Vector3d pos, Eigen::Vector3d normal, const std::string &text)
 {
-  Eigen::Matrix4f view_matrix = viewer->core.view * viewer->core.model;
   pos += normal * 0.005f * viewer->core.object_scale;
   Eigen::Vector3f coord = igl::project(Eigen::Vector3f(pos.cast<float>()),
-    view_matrix, viewer->core.proj, viewer->core.viewport);
+    viewer->core.view, viewer->core.proj, viewer->core.viewport);
 
   // Draw text labels slightly bigger than normal text
   ImDrawList* drawList = ImGui::GetWindowDrawList();

+ 14 - 14
include/igl/per_corner_normals.cpp

@@ -13,8 +13,8 @@
 
 template <typename DerivedV, typename DerivedF, typename DerivedCN>
 IGL_INLINE void igl::per_corner_normals(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
   const double corner_threshold,
   Eigen::PlainObjectBase<DerivedCN> & CN)
 {
@@ -23,7 +23,7 @@ IGL_INLINE void igl::per_corner_normals(
   Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> FN;
   per_face_normals(V,F,FN);
   vector<vector<int> > VF,VFi;
-  vertex_triangle_adjacency(V,F,VF,VFi);
+  vertex_triangle_adjacency(V.rows(),F,VF,VFi);
   return per_corner_normals(V,F,FN,VF,corner_threshold,CN);
 }
 
@@ -33,16 +33,16 @@ template <
   typename DerivedFN, 
   typename DerivedCN>
 IGL_INLINE void igl::per_corner_normals(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedF>& F,
-  const Eigen::PlainObjectBase<DerivedFN>& FN,
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedFN>& FN,
   const double corner_threshold,
   Eigen::PlainObjectBase<DerivedCN> & CN)
 {
   using namespace Eigen;
   using namespace std;
   vector<vector<int> > VF,VFi;
-  vertex_triangle_adjacency(V,F,VF,VFi);
+  vertex_triangle_adjacency(V.rows(),F,VF,VFi);
   return per_corner_normals(V,F,FN,VF,corner_threshold,CN);
 }
 
@@ -53,9 +53,9 @@ template <
   typename IndexType,
   typename DerivedCN>
 IGL_INLINE void igl::per_corner_normals(
-  const Eigen::PlainObjectBase<DerivedV>& /*V*/,
-  const Eigen::PlainObjectBase<DerivedF>& F,
-  const Eigen::PlainObjectBase<DerivedFN>& FN,
+  const Eigen::MatrixBase<DerivedV>& /*V*/,
+  const Eigen::MatrixBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedFN>& FN,
   const std::vector<std::vector<IndexType> >& VF,
   const double corner_threshold,
   Eigen::PlainObjectBase<DerivedCN> & CN)
@@ -104,8 +104,8 @@ IGL_INLINE void igl::per_corner_normals(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
-template void igl::per_corner_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
-template void igl::per_corner_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
-template void igl::per_corner_normals<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
-template void igl::per_corner_normals<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::per_corner_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_corner_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_corner_normals<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::per_corner_normals<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
 #endif

+ 8 - 8
include/igl/per_corner_normals.h

@@ -23,8 +23,8 @@ namespace igl
   //     for corner F(i,j) is at CN(i*3+j,:) 
   template <typename DerivedV, typename DerivedF, typename DerivedCN>
   IGL_INLINE void per_corner_normals(
-    const Eigen::PlainObjectBase<DerivedV>& V,
-    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
     const double corner_threshold,
     Eigen::PlainObjectBase<DerivedCN> & CN);
   // Other Inputs:
@@ -35,9 +35,9 @@ namespace igl
     typename DerivedFN, 
     typename DerivedCN>
   IGL_INLINE void per_corner_normals(
-    const Eigen::PlainObjectBase<DerivedV>& V,
-    const Eigen::PlainObjectBase<DerivedF>& F,
-    const Eigen::PlainObjectBase<DerivedFN>& FN,
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedFN>& FN,
     const double corner_threshold,
     Eigen::PlainObjectBase<DerivedCN> & CN);
   // Other Inputs:
@@ -49,9 +49,9 @@ namespace igl
     typename IndexType,
     typename DerivedCN>
   IGL_INLINE void per_corner_normals(
-    const Eigen::PlainObjectBase<DerivedV>& V,
-    const Eigen::PlainObjectBase<DerivedF>& F,
-    const Eigen::PlainObjectBase<DerivedFN>& FN,
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedFN>& FN,
     const std::vector<std::vector<IndexType> >& VF,
     const double corner_threshold,
     Eigen::PlainObjectBase<DerivedCN> & CN);

+ 1 - 0
include/igl/piecewise_constant_winding_number.cpp

@@ -7,6 +7,7 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "piecewise_constant_winding_number.h"
 #include "unique_edge_map.h"
+#include "PI.h"
 
 template <
   typename DerivedF,

+ 1 - 1
include/igl/point_simplex_squared_distance.cpp

@@ -117,7 +117,7 @@ IGL_INLINE void igl::point_simplex_squared_distance(
   assert((Derivedb::RowsAtCompileTime == 1 || Derivedb::ColsAtCompileTime == 1) && "bary must be Eigen Vector or Eigen RowVector");
   assert(
     ((Derivedb::RowsAtCompileTime == -1 || Derivedb::ColsAtCompileTime == -1) ||
-      (Derivedb::RowsAtCompileTime == Ele.cols() || Derivedb::ColsAtCompileTime == -Ele.cols())
+      (Derivedb::RowsAtCompileTime == Ele.cols() || Derivedb::ColsAtCompileTime == Ele.cols())
     ) && "bary must be Dynamic or size of Ele.cols()");
 
   BaryPoint tmp_bary;

+ 6 - 2
include/igl/qslim.h

@@ -18,12 +18,16 @@ namespace igl
   // mesh can have open boundaries but should be edge-manifold.
   //
   // Inputs:
-  //   V  #V by dim list of vertex positions. Assumes that vertices w
+  //   V  #V by dim list of vertex positions. Assumes that vertices with
+  //     infinite coordinates are "points at infinity" being used to close up
+  //     boundary edges with faces. This allows special subspace quadrice for
+  //     boundary edges: There should never be more than one "point at
+  //     infinity" in a single triangle.
   //   F  #F by 3 list of triangle 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)
+  //   G  #G by 3 list of output face indices into U (can be same ref as F)
   //   J  #G list of indices into F of birth face
   //   I  #U list of indices into V of birth vertices
   IGL_INLINE bool qslim(

+ 5 - 4
include/igl/random_quaternion.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 "random_quaternion.h"
+#include "PI.h"
 
 template <typename Scalar>
 IGL_INLINE Eigen::Quaternion<Scalar> igl::random_quaternion()
@@ -16,9 +17,9 @@ IGL_INLINE Eigen::Quaternion<Scalar> igl::random_quaternion()
   };
 #ifdef false
   // http://mathproofs.blogspot.com/2005/05/uniformly-distributed-random-unit.html
-  const Scalar t0 = 2.*M_PI*unit_rand();
+  const Scalar t0 = 2.*igl::PI*unit_rand();
   const Scalar t1 = acos(1.-2.*unit_rand());
-  const Scalar t2 = 0.5*(M_PI*unit_rand() + acos(unit_rand()));
+  const Scalar t2 = 0.5*(igl::PI*unit_rand() + acos(unit_rand()));
   return Eigen::Quaternion<Scalar>(
     1.*sin(t0)*sin(t1)*sin(t2),
     1.*cos(t0)*sin(t1)*sin(t2),
@@ -63,8 +64,8 @@ IGL_INLINE Eigen::Quaternion<Scalar> igl::random_quaternion()
   const Scalar x2 = unit_rand();
   const Scalar r1 = sqrt(1.0 - x0);
   const Scalar r2 = sqrt(x0);
-  const Scalar t1 = 2.*M_PI*x1;
-  const Scalar t2 = 2.*M_PI*x2;
+  const Scalar t1 = 2.*igl::PI*x1;
+  const Scalar t2 = 2.*igl::PI*x2;
   const Scalar c1 = cos(t1);
   const Scalar s1 = sin(t1);
   const Scalar c2 = cos(t2);

+ 15 - 10
include/igl/ray_box_intersect.cpp

@@ -1,9 +1,9 @@
 // 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 
+//
+// 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 "ray_box_intersect.h"
 #include <vector>
@@ -27,7 +27,7 @@ IGL_INLINE bool igl::ray_box_intersect(
     const Eigen::Vector3f& rayo,
     const Eigen::Vector3f& rayd,
     const Eigen::Vector3f& bmin,
-    const Eigen::Vector3f& bmax, 
+    const Eigen::Vector3f& bmax,
     float & tnear,
     float & tfar
     )->bool
@@ -35,12 +35,12 @@ IGL_INLINE bool igl::ray_box_intersect(
     Eigen::Vector3f bnear;
     Eigen::Vector3f bfar;
     // Checks for intersection testing on each direction coordinate
-    // Computes 
+    // Computes
     float t1, t2;
     tnear = -1e+6f, tfar = 1e+6f; //, tCube;
     bool intersectFlag = true;
     for (int i = 0; i < 3; ++i) {
-  //    std::cout << "coordinate " << i << ": bmin " << bmin(i) << ", bmax " << bmax(i) << std::endl; 
+  //    std::cout << "coordinate " << i << ": bmin " << bmin(i) << ", bmax " << bmax(i) << std::endl;
       assert(bmin(i) <= bmax(i));
       if (::fabs(rayd(i)) < 1e-6) {   // Ray parallel to axis i-th
         if (rayo(i) < bmin(i) || rayo(i) > bmax(i)) {
@@ -59,12 +59,12 @@ IGL_INLINE bool igl::ray_box_intersect(
         }
   //      std::cout << "  bnear " << bnear(i) << ", bfar " << bfar(i) << std::endl;
         // Finds the distance parameters t1 and t2 of the two ray-box intersections:
-        // t1 must be the closest to the ray origin rayo. 
+        // t1 must be the closest to the ray origin rayo.
         t1 = (bnear(i) - rayo(i)) / rayd(i);
         t2 = (bfar(i) - rayo(i)) / rayd(i);
         if (t1 > t2) {
           std::swap(t1,t2);
-        } 
+        }
         // The two intersection values are used to saturate tnear and tfar
         if (t1 > tnear) {
           tnear = t1;
@@ -72,7 +72,7 @@ IGL_INLINE bool igl::ray_box_intersect(
         if (t2 < tfar) {
           tfar = t2;
         }
-  //      std::cout << "  t1 " << t1 << ", t2 " << t2 << ", tnear " << tnear << ", tfar " << tfar 
+  //      std::cout << "  t1 " << t1 << ", t2 " << t2 << ", tnear " << tnear << ", tfar " << tfar
   //        << "  tnear > tfar? " << (tnear > tfar) << ", tfar < 0? " << (tfar < 0) << std::endl;
         if(tnear > tfar) {
           intersectFlag = false;
@@ -143,3 +143,8 @@ IGL_INLINE bool igl::ray_box_intersect(
   return true;
 #endif
 }
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::ray_box_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<double, 3> const&, double const&, double const&, double&, double&);
+#endif

+ 12 - 10
include/igl/ray_mesh_intersect.cpp

@@ -1,9 +1,9 @@
 // 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 
+//
+// 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 "ray_mesh_intersect.h"
 
@@ -15,8 +15,8 @@ extern "C"
 template <
   typename Derivedsource,
   typename Deriveddir,
-  typename DerivedV, 
-  typename DerivedF> 
+  typename DerivedV,
+  typename DerivedF>
 IGL_INLINE bool igl::ray_mesh_intersect(
   const Eigen::MatrixBase<Derivedsource> & s,
   const Eigen::MatrixBase<Deriveddir> & dir,
@@ -26,14 +26,14 @@ IGL_INLINE bool igl::ray_mesh_intersect(
 {
   using namespace Eigen;
   using namespace std;
-  // Should be but can't be const 
+  // Should be but can't be const
   Vector3d s_d = s.template cast<double>();
   Vector3d dir_d = dir.template cast<double>();
   hits.clear();
   // loop over all triangles
   for(int f = 0;f<F.rows();f++)
   {
-    // Should be but can't be const 
+    // Should be but can't be const
     RowVector3d v0 = V.row(F(f,0)).template cast<double>();
     RowVector3d v1 = V.row(F(f,1)).template cast<double>();
     RowVector3d v2 = V.row(F(f,2)).template cast<double>();
@@ -57,8 +57,8 @@ IGL_INLINE bool igl::ray_mesh_intersect(
 template <
   typename Derivedsource,
   typename Deriveddir,
-  typename DerivedV, 
-  typename DerivedF> 
+  typename DerivedV,
+  typename DerivedF>
 IGL_INLINE bool igl::ray_mesh_intersect(
   const Eigen::MatrixBase<Derivedsource> & source,
   const Eigen::MatrixBase<Deriveddir> & dir,
@@ -81,4 +81,6 @@ IGL_INLINE bool igl::ray_mesh_intersect(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 template bool igl::ray_mesh_intersect<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
+template bool igl::ray_mesh_intersect<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::Hit&);
+template bool igl::ray_mesh_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Block<Eigen::Matrix<int, -1, -1, 0, -1, -1> const, 1, -1, false> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<int, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, igl::Hit&);
 #endif

+ 500 - 0
include/igl/readMSH.cpp

@@ -0,0 +1,500 @@
+
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 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 "readMSH.h"
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <vector>
+#include <map>
+
+template <
+  typename DerivedV,
+  typename DerivedT>
+IGL_INLINE bool igl::readMSH(
+  const std::string & filename,
+  Eigen::PlainObjectBase<DerivedV> & V,
+  Eigen::PlainObjectBase<DerivedT> & T)
+{
+  // https://github.com/Yixin-Hu/TetWild/blob/master/pymesh/MshSaver.cpp
+  // Original copyright: /* This file is part of PyMesh. Copyright (c) 2015 by Qingnan Zhou */
+  typedef typename DerivedV::Scalar Float;
+  typedef Eigen::Matrix<Float,Eigen::Dynamic,1> VectorF;
+  typedef Eigen::Matrix<int,Eigen::Dynamic,1> VectorI;
+  typedef std::map<std::string, VectorF> FieldMap;
+  typedef std::vector<std::string> FieldNames;
+  VectorF m_nodes;
+  VectorI m_elements;
+  FieldMap m_node_fields;
+  FieldMap m_element_fields;
+
+  bool m_binary;
+  size_t m_data_size;
+  size_t m_nodes_per_element;
+  size_t m_element_type;
+  std::ifstream fin(filename.c_str(), std::ios::in | std::ios::binary);
+  if (!fin.is_open())
+  {
+    std::stringstream err_msg;
+    err_msg << "failed to open file \"" << filename << "\"";
+    return false;
+  }
+  // Parse header
+  std::string buf;
+  double version;
+  int type;
+  fin >> buf;
+  const auto invalid_format = []()->bool
+  {
+    assert(false && "Invalid format");
+    return false;
+  };
+  const auto not_implemented = []()->bool
+  {
+    assert(false && "Not implemented");
+    return false;
+  };
+  if (buf != "$MeshFormat") { return invalid_format(); }
+
+  fin >> version >> type >> m_data_size;
+  m_binary = (type == 1);
+
+  // Some sanity check.
+  if (m_data_size != 8) {
+      std::cerr << "Error: data size must be 8 bytes." << std::endl;
+      return not_implemented();
+  }
+  if (sizeof(int) != 4) {
+      std::cerr << "Error: code must be compiled with int size 4 bytes." << std::endl;
+      return not_implemented();
+  }
+  const auto eat_white_space = [](std::ifstream& fin)
+  {
+    char next = fin.peek();
+    while (next == '\n' || next == ' ' || next == '\t' || next == '\r') 
+    {
+      fin.get();
+      next = fin.peek();
+    }
+  };
+
+  // Read in extra info from binary header.
+  if (m_binary) {
+      int one;
+      eat_white_space(fin);
+      fin.read(reinterpret_cast<char*>(&one), sizeof(int));
+      if (one != 1) {
+          std::cerr << "Warning: binary msh file " << filename
+              << " is saved with different endianness than this machine."
+              << std::endl;
+          return not_implemented();
+      }
+  }
+
+  fin >> buf;
+  if (buf != "$EndMeshFormat") { return not_implemented(); }
+
+  const auto num_nodes_per_elem_type = [](int elem_type)->int 
+  {
+    size_t nodes_per_element = 0;
+    switch (elem_type) {
+        case 2:
+            nodes_per_element = 3; // Triangle
+            break;
+        case 3:
+            nodes_per_element = 4; // Quad
+            break;
+        case 4:
+            nodes_per_element = 4; // Tet
+            break;
+        case 5:
+            nodes_per_element = 8; // hexahedron
+            break;
+        default:
+            assert(false && "not implemented");
+            nodes_per_element = -1;
+            break;
+    }
+    return nodes_per_element;
+  };
+
+  const auto parse_nodes = [&](std::ifstream& fin) 
+  {
+    size_t num_nodes;
+    fin >> num_nodes;
+    m_nodes.resize(num_nodes*3);
+
+    if (m_binary) {
+        size_t num_bytes = (4+3*m_data_size) * num_nodes;
+        char* data = new char[num_bytes];
+        eat_white_space(fin);
+        fin.read(data, num_bytes);
+
+        for (size_t i=0; i<num_nodes; i++) {
+            int node_idx          = *reinterpret_cast<int*>  (&data[i*(4+3*m_data_size)]) - 1;
+            m_nodes[node_idx*3]   = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4]);
+            m_nodes[node_idx*3+1] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4 + m_data_size]);
+            m_nodes[node_idx*3+2] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4 + 2*m_data_size]);
+        }
+
+        delete [] data;
+    } else {
+        int node_idx;
+        for (size_t i=0; i<num_nodes; i++) {
+            fin >> node_idx;
+            node_idx -= 1;
+            fin >> m_nodes[node_idx*3]
+                >> m_nodes[node_idx*3+1]
+                >> m_nodes[node_idx*3+2];
+        }
+    }
+  };
+
+  const auto parse_elements = [&](std::ifstream& fin) 
+  {
+    size_t num_elements;
+    fin >> num_elements;
+
+    // Tmp storage of elements;
+    std::vector<int> triangle_element_idx;
+    std::vector<int> triangle_elements;
+    std::vector<int> quad_element_idx;
+    std::vector<int> quad_elements;
+    std::vector<int> tet_element_idx;
+    std::vector<int> tet_elements;
+    std::vector<int> hex_element_idx;
+    std::vector<int> hex_elements;
+
+    auto get_element_storage = [&](int elem_type) -> std::vector<int>* {
+        switch (elem_type) {
+            default:
+                assert(false && "Unsupported element type encountered");
+            case 2:
+                return &triangle_elements;
+            case 3:
+                return &quad_elements;
+            case 4:
+                return &tet_elements;
+            case 5:
+                return &hex_elements;
+        };
+    };
+
+    auto get_element_idx_storage = [&](int elem_type) -> std::vector<int>* {
+        switch (elem_type) {
+            default:
+                assert(false && "Unsupported element type encountered");
+            case 2:
+                return &triangle_element_idx;
+            case 3:
+                return &quad_element_idx;
+            case 4:
+                return &tet_element_idx;
+            case 5:
+                return &hex_element_idx;
+        };
+    };
+
+    size_t nodes_per_element;
+    int glob_elem_type = -1;
+
+
+  if (m_binary) 
+  {
+    eat_white_space(fin);
+    int elem_read = 0;
+    while (elem_read < num_elements) {
+        // Parse element header.
+        int elem_type, num_elems, num_tags;
+        fin.read((char*)&elem_type, sizeof(int));
+        fin.read((char*)&num_elems, sizeof(int));
+        fin.read((char*)&num_tags, sizeof(int));
+        nodes_per_element = num_nodes_per_elem_type(elem_type);
+        std::vector<int>& elements = *get_element_storage(elem_type);
+        std::vector<int>& element_idx = *get_element_idx_storage(elem_type);
+
+        for (size_t i=0; i<num_elems; i++) {
+            int elem_idx;
+            fin.read((char*)&elem_idx, sizeof(int));
+            elem_idx -= 1;
+            element_idx.push_back(elem_idx);
+
+            // Eat up tags.
+            for (size_t j=0; j<num_tags; j++) {
+                int tag;
+                fin.read((char*)&tag, sizeof(int));
+            }
+
+            // Element values.
+            for (size_t j=0; j<nodes_per_element; j++) {
+                int idx;
+                fin.read((char*)&idx, sizeof(int));
+                elements.push_back(idx-1);
+            }
+        }
+
+        elem_read += num_elems;
+    }
+  } else 
+  {
+        for (size_t i=0; i<num_elements; i++) {
+            // Parse per element header
+            int elem_num, elem_type, num_tags;
+            fin >> elem_num >> elem_type >> num_tags;
+            for (size_t j=0; j<num_tags; j++) {
+                int tag;
+                fin >> tag;
+            }
+            nodes_per_element = num_nodes_per_elem_type(elem_type);
+            std::vector<int>& elements = *get_element_storage(elem_type);
+            std::vector<int>& element_idx = *get_element_idx_storage(elem_type);
+
+            elem_num -= 1;
+            element_idx.push_back(elem_num);
+
+            // Parse node idx.
+            for (size_t j=0; j<nodes_per_element; j++) {
+                int idx;
+                fin >> idx;
+                elements.push_back(idx-1); // msh index starts from 1.
+            }
+        }
+    }
+
+    auto copy_to_array = [&](
+            const std::vector<int>& elements,
+            const int nodes_per_element) {
+        const size_t num_elements = elements.size() / nodes_per_element;
+        if (elements.size() % nodes_per_element != 0) {
+            assert(false && "parsing element failed");
+            return;
+        }
+        m_elements.resize(elements.size());
+        std::copy(elements.begin(), elements.end(), m_elements.data());
+        m_nodes_per_element = nodes_per_element;
+    };
+
+    if (!tet_elements.empty()) {
+        copy_to_array(tet_elements, 4);
+        m_element_type = 4;
+    } else if (!hex_elements.empty()) {
+        copy_to_array(hex_elements, 8);
+        m_element_type = 5;
+    } else if (!triangle_elements.empty()) {
+        copy_to_array(triangle_elements, 3);
+        m_element_type = 2;
+    } else if (!quad_elements.empty()) {
+        copy_to_array(quad_elements, 4);
+        m_element_type = 3;
+    } else {
+        // 0 elements, use triangle by default.
+        m_element_type = 2;
+    }
+  };
+  const auto parse_element_field = [&](std::ifstream& fin) 
+  {
+    size_t num_string_tags;
+    size_t num_real_tags;
+    size_t num_int_tags;
+
+    fin >> num_string_tags;
+    std::string* str_tags = new std::string[num_string_tags];
+    for (size_t i=0; i<num_string_tags; i++) {
+        eat_white_space(fin);
+        if (fin.peek() == '\"') {
+            // Handle field name between quoates.
+            char buf[128];
+            fin.get(); // remove the quote at the beginning.
+            fin.getline(buf, 128, '\"');
+            str_tags[i] = std::string(buf);
+        } else {
+            fin >> str_tags[i];
+        }
+    }
+
+    fin >> num_real_tags;
+    Float* real_tags = new Float[num_real_tags];
+    for (size_t i=0; i<num_real_tags; i++)
+        fin >> real_tags[i];
+
+    fin >> num_int_tags;
+    int* int_tags = new int[num_int_tags];
+    for (size_t i=0; i<num_int_tags; i++)
+        fin >> int_tags[i];
+
+    if (num_string_tags <= 0 || num_int_tags <= 2) { assert(false && "invalid format"); return; }
+    std::string fieldname = str_tags[0];
+    int num_components = int_tags[1];
+    int num_entries = int_tags[2];
+    VectorF field(num_entries * num_components);
+
+    delete [] str_tags;
+    delete [] real_tags;
+    delete [] int_tags;
+
+    if (m_binary) {
+        size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
+        char* data = new char[num_bytes];
+        eat_white_space(fin);
+        fin.read(data, num_bytes);
+        for (size_t i=0; i<num_entries; i++) {
+            int elem_idx = *reinterpret_cast<int*>(&data[i*(4+num_components*m_data_size)]);
+            elem_idx -= 1;
+            size_t base_idx = i*(4+num_components*m_data_size) + 4;
+            for (size_t j=0; j<num_components; j++) {
+                field[elem_idx * num_components + j] = *reinterpret_cast<Float*>(&data[base_idx+j*m_data_size]);
+            }
+        }
+        delete [] data;
+    } else {
+        int elem_idx;
+        for (size_t i=0; i<num_entries; i++) {
+            fin >> elem_idx;
+            elem_idx -= 1;
+            for (size_t j=0; j<num_components; j++) {
+                fin >> field[elem_idx * num_components + j];
+            }
+        }
+    }
+
+    m_element_fields[fieldname] = field;
+  };
+
+  const auto parse_node_field = [&](std::ifstream& fin) 
+  {
+    size_t num_string_tags;
+    size_t num_real_tags;
+    size_t num_int_tags;
+
+    fin >> num_string_tags;
+    std::string* str_tags = new std::string[num_string_tags];
+    for (size_t i=0; i<num_string_tags; i++) {
+        eat_white_space(fin);
+        if (fin.peek() == '\"') {
+            // Handle field name between quoates.
+            char buf[128];
+            fin.get(); // remove the quote at the beginning.
+            fin.getline(buf, 128, '\"');
+            str_tags[i] = std::string(buf);
+        } else {
+            fin >> str_tags[i];
+        }
+    }
+
+    fin >> num_real_tags;
+    Float* real_tags = new Float[num_real_tags];
+    for (size_t i=0; i<num_real_tags; i++)
+        fin >> real_tags[i];
+
+    fin >> num_int_tags;
+    int* int_tags = new int[num_int_tags];
+    for (size_t i=0; i<num_int_tags; i++)
+        fin >> int_tags[i];
+
+    if (num_string_tags <= 0 || num_int_tags <= 2) { assert(false && "invalid format"); return; }
+    std::string fieldname = str_tags[0];
+    int num_components = int_tags[1];
+    int num_entries = int_tags[2];
+    VectorF field(num_entries * num_components);
+
+    delete [] str_tags;
+    delete [] real_tags;
+    delete [] int_tags;
+
+    if (m_binary) {
+        size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
+        char* data = new char[num_bytes];
+        eat_white_space(fin);
+        fin.read(data, num_bytes);
+        for (size_t i=0; i<num_entries; i++) {
+            int node_idx = *reinterpret_cast<int*>(&data[i*(4+num_components*m_data_size)]);
+            node_idx -= 1;
+            size_t base_idx = i*(4+num_components*m_data_size) + 4;
+            for (size_t j=0; j<num_components; j++) {
+                field[node_idx * num_components + j] = *reinterpret_cast<Float*>(&data[base_idx+j*m_data_size]);
+            }
+        }
+        delete [] data;
+    } else {
+        int node_idx;
+        for (size_t i=0; i<num_entries; i++) {
+            fin >> node_idx;
+            node_idx -= 1;
+            for (size_t j=0; j<num_components; j++) {
+                fin >> field[node_idx * num_components + j];
+            }
+        }
+    }
+
+    m_node_fields[fieldname] = field;
+  };
+  const auto parse_unknown_field = [](std::ifstream& fin,
+        const std::string& fieldname) 
+  {
+    std::cerr << "Warning: \"" << fieldname << "\" not supported yet.  Ignored." << std::endl;
+    std::string endmark = fieldname.substr(0,1) + "End"
+        + fieldname.substr(1,fieldname.size()-1);
+
+    std::string buf("");
+    while (buf != endmark && !fin.eof()) {
+        fin >> buf;
+    }
+  };
+
+
+  while (!fin.eof()) {
+      buf.clear();
+      fin >> buf;
+      if (buf == "$Nodes") {
+          parse_nodes(fin);
+          fin >> buf;
+          if (buf != "$EndNodes") { return invalid_format(); }
+      } else if (buf == "$Elements") {
+          parse_elements(fin);
+          fin >> buf;
+          if (buf != "$EndElements") { return invalid_format(); }
+      } else if (buf == "$NodeData") {
+          parse_node_field(fin);
+          fin >> buf;
+          if (buf != "$EndNodeData") { return invalid_format(); }
+      } else if (buf == "$ElementData") {
+          parse_element_field(fin);
+          fin >> buf;
+          if (buf != "$EndElementData") { return invalid_format(); }
+      } else if (fin.eof()) {
+          break;
+      } else {
+          parse_unknown_field(fin, buf);
+      }
+  }
+  fin.close();
+  V.resize(m_nodes.rows()/3,3);
+  for (int i = 0; i < m_nodes.rows() / 3; i++) 
+  {
+    for (int j = 0; j < 3; j++)
+    {
+      V(i,j) = m_nodes(i * 3 + j);
+    }
+  }
+  int ss = num_nodes_per_elem_type(m_element_type);
+  T.resize(m_elements.rows()/ss,ss);
+  for (int i = 0; i < m_elements.rows() / ss; i++) 
+  {
+    for (int j = 0; j < ss; j++)
+    {
+      T(i, j) = m_elements(i * ss + j);
+    }
+  }
+  return true;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif

+ 38 - 0
include/igl/readMSH.h

@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 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_READMSH_H
+#define IGL_READMSH_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <string>
+
+namespace igl
+{
+  // Read a mesh (e.g., tet mesh) from a gmsh .msh file
+  // 
+  // Inputs:
+  //   filename  path to .msh file
+  // Outputs:
+  //    V  #V by 3 list of 3D mesh vertex positions
+  //    T  #T by ss list of 3D ss-element indices into V (e.g., ss=4 for tets)
+  // Returns true on success
+  template <
+    typename DerivedV,
+    typename DerivedT>
+  IGL_INLINE bool readMSH(
+    const std::string & filename,
+    Eigen::PlainObjectBase<DerivedV> & V,
+    Eigen::PlainObjectBase<DerivedT> & T);
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "readMSH.cpp"
+#endif
+#endif

+ 1 - 1
include/igl/readSTL.h

@@ -28,7 +28,7 @@ namespace igl
   // Outputs:
   //   V  double matrix of vertex positions  #V*3 by 3
   //   F  index matrix of triangle indices #F by 3
-  //   N  double matrix of vertex positions  #F by 3
+  //   N  double matrix of surface normals #F by 3
   // Returns true on success, false on errors
   //
   // Example:

+ 6 - 0
include/igl/read_triangle_mesh.cpp

@@ -85,6 +85,12 @@ IGL_INLINE bool igl::read_triangle_mesh(
   // Convert extension to lower case
   transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
   FILE * fp = fopen(filename.c_str(),"rb");
+  if(NULL==fp)
+  {
+    fprintf(stderr,"IOError: %s could not be opened...\n",
+            filename.c_str());
+    return false;
+  }
   return read_triangle_mesh(ext,fp,V,F);
 }
 

+ 2 - 2
include/igl/redux.h

@@ -34,7 +34,6 @@ namespace igl
 
 // Implementation
 
-#include "redux.h"
 #include "for_each.h"
 
 template <typename AType, typename Func, typename DerivedB>
@@ -44,13 +43,14 @@ inline void igl::redux(
   const Func & func,
   Eigen::PlainObjectBase<DerivedB> & B)
 {
+  typedef typename Eigen::SparseMatrix<AType>::StorageIndex Index;
   assert((dim == 1 || dim == 2) && "dim must be 2 or 1");
   // Get size of input
   int m = A.rows();
   int n = A.cols();
   // resize output
   B = DerivedB::Zero(dim==1?n:m);
-  const auto func_wrap = [&func,&B,&dim](const int i, const int j, const int v)
+  const auto func_wrap = [&func,&B,&dim](const Index i, const Index j, const AType v)
   {
     if(dim == 1)
     {

+ 160 - 0
include/igl/remesh_along_isoline.cpp

@@ -0,0 +1,160 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "remesh_along_isoline.h"
+#include "list_to_matrix.h"
+
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedS,
+  typename DerivedU,
+  typename DerivedG,
+  typename DerivedJ,
+  typename BCtype,
+  typename DerivedSU,
+  typename DerivedL>
+  IGL_INLINE void igl::remesh_along_isoline(
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedS> & S,
+    const typename DerivedS::Scalar val,
+    Eigen::PlainObjectBase<DerivedU> & U,
+    Eigen::PlainObjectBase<DerivedG> & G,
+    Eigen::PlainObjectBase<DerivedSU> & SU,
+    Eigen::PlainObjectBase<DerivedJ> & J,
+    Eigen::SparseMatrix<BCtype> & BC,
+    Eigen::PlainObjectBase<DerivedL> & L)
+{
+  igl::remesh_along_isoline(V.rows(),F,S,val,G,SU,J,BC,L);
+  U = BC * V;
+}
+
+template <
+  typename DerivedF,
+  typename DerivedS,
+  typename DerivedG,
+  typename DerivedJ,
+  typename BCtype,
+  typename DerivedSU,
+  typename DerivedL>
+  IGL_INLINE void igl::remesh_along_isoline(
+    const int num_vertices,
+    const Eigen::MatrixBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedS> & S,
+    const typename DerivedS::Scalar val,
+    Eigen::PlainObjectBase<DerivedG> & G,
+    Eigen::PlainObjectBase<DerivedSU> & SU,
+    Eigen::PlainObjectBase<DerivedJ> & J,
+    Eigen::SparseMatrix<BCtype> & BC,
+    Eigen::PlainObjectBase<DerivedL> & L)
+{
+  // Lazy implementation using vectors
+
+  //assert(val.size() == 1);
+  const int isoval_i = 0;
+  //auto isoval = val(isoval_i);
+  auto isoval = val;
+  std::vector<std::vector<typename DerivedG::Scalar> > vG;
+  std::vector<typename DerivedJ::Scalar> vJ;
+  std::vector<typename DerivedL::Scalar> vL;
+  std::vector<Eigen::Triplet<BCtype> > vBC;
+  int Ucount = 0;
+  for(int i = 0;i<num_vertices;i++)
+  {
+    vBC.emplace_back(Ucount,i,1.0);
+    Ucount++;
+  }
+
+  // Loop over each face
+  for(int f = 0;f<F.rows();f++)
+  {
+    bool Psign[2];
+    int P[2];
+    int count = 0;
+    for(int p = 0;p<3;p++)
+    {
+      const bool psign = S(F(f,p)) > isoval;
+      // Find crossings
+      const int n = (p+1)%3;
+      const bool nsign = S(F(f,n)) > isoval;
+      if(psign != nsign)
+      {
+        P[count] = p;
+        Psign[count] = psign;
+        // record crossing
+        count++;
+      }
+    }
+
+    assert(count == 0  || count == 2);
+    switch(count)
+    {
+      case 0:
+      {
+        // Easy case
+        std::vector<typename DerivedG::Scalar> row = {F(f,0),F(f,1),F(f,2)};
+        vG.push_back(row);
+        vJ.push_back(f);
+        vL.push_back( S(F(f,0))>isoval ? isoval_i+1 : isoval_i );
+        break;
+      }
+      case 2:
+      {
+        // Cut case
+        // flip so that P[1] is the one-off vertex
+        if(P[0] == 0 && P[1] == 2)
+        {
+          std::swap(P[0],P[1]);
+          std::swap(Psign[0],Psign[1]);
+        }
+        assert(Psign[0] != Psign[1]);
+        // Create two new vertices
+        for(int i = 0;i<2;i++)
+        {
+          const double bci = (isoval - S(F(f,(P[i]+1)%3)))/
+            (S(F(f,P[i]))-S(F(f,(P[i]+1)%3)));
+          vBC.emplace_back(Ucount,F(f,P[i]),bci);
+          vBC.emplace_back(Ucount,F(f,(P[i]+1)%3),1.0-bci);
+          Ucount++;
+        }
+        const int v0 = F(f,P[0]);
+        const int v01 = Ucount-2;
+        assert(((P[0]+1)%3) == P[1]);
+        const int v1 = F(f,P[1]);
+        const int v12 = Ucount-1;
+        const int v2 = F(f,(P[1]+1)%3);
+        // v0
+        // |  \
+        // |   \
+        // |    \
+        // v01   \
+        // |      \
+        // |       \
+        // |        \
+        // v1--v12---v2
+        typedef std::vector<typename DerivedG::Scalar> Row;
+        {Row row = {v01,v1,v12}; vG.push_back(row);vJ.push_back(f);vL.push_back(Psign[0]?isoval_i:isoval_i+1);}
+        {Row row = {v12,v2,v01}; vG.push_back(row);vJ.push_back(f);vL.push_back(Psign[1]?isoval_i:isoval_i+1);}
+        {Row row = {v2,v0,v01}; vG.push_back(row) ;vJ.push_back(f);vL.push_back(Psign[1]?isoval_i:isoval_i+1);}
+        break;
+      }
+      default: assert(false);
+    }
+  }
+  igl::list_to_matrix(vG,G);
+  igl::list_to_matrix(vJ,J);
+  igl::list_to_matrix(vL,L);
+  BC.resize(Ucount,num_vertices);
+  BC.setFromTriplets(vBC.begin(),vBC.end());
+  SU = BC * S;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::remesh_along_isoline<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<double, -1, 1, 0, -1, 1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif

+ 81 - 0
include/igl/remesh_along_isoline.h

@@ -0,0 +1,81 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 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_REMESH_ALONG_ISOLINE_H
+#define IGL_REMESH_ALONG_ISOLINE_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl 
+{
+  // Given a triangle mesh and a scalar field, remesh so that a given isovalue
+  // of the scalar field follows (new) edges of the output mesh. Effectively
+  // running "marching triangles" on mesh, but not in any coherent order. The
+  // output mesh should be as manifold as the input.
+  //
+  // Inputs:
+  //   V  #V by dim list of mesh vertex positions
+  //   F  #F by 3 list of mesh triangle indices into V
+  //   S  #V by 1 list of scalar field
+  //   val  value of S to remesh along
+  // Outputs:
+  //  U  #U by dim list of mesh vertex positions #U>=#V
+  //  G  #G by 3 list of mesh triangle indices into U, #G>=#F
+  //  SU  #U list of scalar field values over new mesh
+  //  J  #G list of indices into G revealing birth triangles
+  //  BC  #U by #V sparse matrix of barycentric coordinates so that U = BC*V
+  //  L  #G list of bools whether scalar field in triangle below or above val
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedS,
+    typename DerivedU,
+    typename DerivedG,
+    typename DerivedJ,
+    typename BCtype,
+    typename DerivedSU,
+    typename DerivedL>
+    IGL_INLINE void remesh_along_isoline(
+      const Eigen::MatrixBase<DerivedV> & V,
+      const Eigen::MatrixBase<DerivedF> & F,
+      const Eigen::MatrixBase<DerivedS> & S,
+      const typename DerivedS::Scalar val,
+      Eigen::PlainObjectBase<DerivedU> & U,
+      Eigen::PlainObjectBase<DerivedG> & G,
+      Eigen::PlainObjectBase<DerivedSU> & SU,
+      Eigen::PlainObjectBase<DerivedJ> & J,
+      Eigen::SparseMatrix<BCtype> & BC,
+      Eigen::PlainObjectBase<DerivedL> & L);
+  // Input:
+  //   n  number of vertices (#V)
+  template <
+    typename DerivedF,
+    typename DerivedS,
+    typename DerivedG,
+    typename DerivedJ,
+    typename BCtype,
+    typename DerivedSU,
+    typename DerivedL>
+    IGL_INLINE void remesh_along_isoline(
+      const int n,
+      const Eigen::MatrixBase<DerivedF> & F,
+      const Eigen::MatrixBase<DerivedS> & S,
+      const typename DerivedS::Scalar val,
+      Eigen::PlainObjectBase<DerivedG> & G,
+      Eigen::PlainObjectBase<DerivedSU> & SU,
+      Eigen::PlainObjectBase<DerivedJ> & J,
+      Eigen::SparseMatrix<BCtype> & BC,
+      Eigen::PlainObjectBase<DerivedL> & L);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "remesh_along_isoline.h"
+#endif
+
+#endif

+ 4 - 18
include/igl/setdiff.cpp

@@ -29,22 +29,7 @@ IGL_INLINE void igl::setdiff(
   {
     C.resize(0,1);
     IA.resize(0,1);
-  }
-  if(B.size() == 0)
-  {
-    C.resize(A.size(),1);
-    int k = 0;
-    for(int j = 0;j<A.cols();j++)
-    {
-      for(int i = 0;i<A.rows();i++)
-      {
-        C(k++) = A(i,j);
-      }
-    }
-    assert(k == C.size());
-    // Have to use << instead of = because Eigen's PlainObjectBase is annoying
-    IA << igl::LinSpaced<Eigen::Matrix<typename DerivedIA::Scalar,Eigen::Dynamic,1> >(
-      C.size(),0,C.size()-1);
+    return;
   }
 
   // Get rid of any duplicates
@@ -69,14 +54,15 @@ IGL_INLINE void igl::setdiff(
   int bi = 0;
   // loop over sA
   bool past = false;
+  bool sBempty = sB.size()==0;
   for(int a = 0;a<sA.size();a++)
   {
-    while(!past && sA(a)>sB(bi))
+    while(!sBempty && !past && sA(a)>sB(bi))
     {
       bi++;
       past = bi>=sB.size();
     }
-    if(past || sA(a)<sB(bi))
+    if(sBempty || past || sA(a)<sB(bi))
     {
       // then sA(a) did not appear in sB
       vC.push_back(sA(a));

+ 3 - 2
include/igl/shapeup.cpp

@@ -11,6 +11,7 @@
 #include <igl/igl_inline.h>
 #include <igl/setdiff.h>
 #include <igl/cat.h>
+#include <igl/PI.h>
 #include <Eigen/Core>
 #include <vector>
 
@@ -50,7 +51,7 @@ namespace igl
   
       //creating perfectly regular source polygon
       for (int j=0;j<N;j++)
-        sourcePolygon.row(j)<<cos(2*M_PI*(double)j/(double(N))), sin(2*M_PI*(double)j/(double(N))),0.0;
+        sourcePolygon.row(j)<<cos(2*igl::PI*(double)j/(double(N))), sin(2*igl::PI*(double)j/(double(N))),0.0;
   
       //finding closest similarity transformation between source and target
       Eigen::MatrixXd corrMat=sourcePolygon.transpose()*targetPolygon;
@@ -206,7 +207,7 @@ namespace igl
         for (int j=0;j<sudata.SC(i);j++)
           rhs.row(currRow++)=projP.block(i, 3*j, 1,3);
       
-      Eigen::PlainObjectBase<DerivedP> lsrhs=-sudata.At*sudata.W*rhs;
+      DerivedP lsrhs=-sudata.At*sudata.W*rhs;
       MatrixXd Y(0,3), Beq(0,3);  //We do not use the min_quad_solver fixed variables mechanism; they are treated with the closeness energy of ShapeUp.
       min_quad_with_fixed_solve(sudata.solver_data, lsrhs,Y,Beq,currP);
       

+ 1 - 0
include/igl/shapeup.h

@@ -14,6 +14,7 @@
 #include <igl/cat.h>
 #include <Eigen/Core>
 #include <vector>
+#include <igl/PI.h>
 
 
 //This file implements the following algorithm:

+ 4 - 4
include/igl/slice_into.cpp

@@ -25,8 +25,8 @@ IGL_INLINE void igl::slice_into(
   int xn = X.cols();
   assert(R.size() == xm);
   assert(C.size() == xn);
-  int ym = Y.size();
-  int yn = Y.size();
+  int ym = Y.rows();
+  int yn = Y.cols();
   assert(R.minCoeff() >= 0);
   assert(R.maxCoeff() < ym);
   assert(C.minCoeff() >= 0);
@@ -60,8 +60,8 @@ IGL_INLINE void igl::slice_into(
 #ifndef NDEBUG
   assert(R.size() == xm);
   assert(C.size() == xn);
-  int ym = Y.size();
-  int yn = Y.size();
+  int ym = Y.rows();
+  int yn = Y.cols();
   assert(R.minCoeff() >= 0);
   assert(R.maxCoeff() < ym);
   assert(C.minCoeff() >= 0);

+ 7 - 2
include/igl/sparse_cached.cpp

@@ -117,6 +117,11 @@ IGL_INLINE void igl::sparse_cached(
 
 
 #ifdef IGL_STATIC_LIBRARY
-template void igl::sparse_cached<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&);
-template void igl::sparse_cached_precompute<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&, Eigen::SparseMatrix<double, 0, int>&);
+#if EIGEN_VERSION_AT_LEAST(3,3,0)
+  template void igl::sparse_cached<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::StorageIndex>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::StorageIndex> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&);
+  template void igl::sparse_cached_precompute<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::StorageIndex>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::StorageIndex> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&, Eigen::SparseMatrix<double, 0, int>&);
+#else
+  template void igl::sparse_cached<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&);
+  template void igl::sparse_cached_precompute<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
 #endif

+ 76 - 28
include/igl/triangle_triangle_adjacency.cpp

@@ -1,11 +1,13 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 //
+// Copyright (C) 2018 Alec Jacobson, Marc Alexa
 // Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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 "triangle_triangle_adjacency.h"
+#include "vertex_triangle_adjacency.h"
 #include "parallel_for.h"
 #include "unique_edge_map.h"
 #include <algorithm>
@@ -14,7 +16,7 @@
 // Extract the face adjacencies
 template <typename DerivedF, typename TTT_type, typename DerivedTT>
 IGL_INLINE void igl::triangle_triangle_adjacency_extractTT(
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedF>& F,
   std::vector<std::vector<TTT_type> >& TTT,
   Eigen::PlainObjectBase<DerivedTT>& TT)
 {
@@ -34,16 +36,43 @@ IGL_INLINE void igl::triangle_triangle_adjacency_extractTT(
 
 template <typename DerivedF, typename DerivedTT>
 IGL_INLINE void igl::triangle_triangle_adjacency(
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedF>& F,
   Eigen::PlainObjectBase<DerivedTT>& TT)
 {
-  DerivedTT TTi;
-  return triangle_triangle_adjacency(F,TT,TTi);
+  const int n = F.maxCoeff()+1;
+  typedef Eigen::Matrix<typename DerivedTT::Scalar,Eigen::Dynamic,1> VectorXI;
+  VectorXI VF,NI;
+  vertex_triangle_adjacency(F,n,VF,NI);
+  TT = DerivedTT::Constant(F.rows(),3,-1);
+  // Loop over faces
+  igl::parallel_for(F.rows(),[&](int f)
+  {
+    // Loop over corners
+    for (int k = 0; k < 3; k++)
+    {
+      int vi = F(f,k), vin = F(f,(k+1)%3);
+      // Loop over face neighbors incident on this corner
+      for (int j = NI[vi]; j < NI[vi+1]; j++)
+      {
+        int fn = VF[j];
+        // Not this face
+        if (fn != f)
+        {
+          // Face neighbor also has [vi,vin] edge
+          if (F(fn,0) == vin || F(fn,1) == vin || F(fn,2) == vin)
+          {
+            TT(f,k) = fn;
+            break;
+          }
+        }
+      }
+    }
+  });
 }
 
 template <typename DerivedF, typename TTT_type>
 IGL_INLINE void igl::triangle_triangle_adjacency_preprocess(
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedF>& F,
   std::vector<std::vector<TTT_type> >& TTT)
 {
   for(int f=0;f<F.rows();++f)
@@ -64,7 +93,7 @@ IGL_INLINE void igl::triangle_triangle_adjacency_preprocess(
 // Extract the face adjacencies indices (needed for fast traversal)
 template <typename DerivedF, typename TTT_type, typename DerivedTTi>
 IGL_INLINE void igl::triangle_triangle_adjacency_extractTTi(
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedF>& F,
   std::vector<std::vector<TTT_type> >& TTT,
   Eigen::PlainObjectBase<DerivedTTi>& TTi)
 {
@@ -85,14 +114,33 @@ IGL_INLINE void igl::triangle_triangle_adjacency_extractTTi(
 // Compute triangle-triangle adjacency with indices
 template <typename DerivedF, typename DerivedTT, typename DerivedTTi>
 IGL_INLINE void igl::triangle_triangle_adjacency(
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedF>& F,
   Eigen::PlainObjectBase<DerivedTT>& TT,
   Eigen::PlainObjectBase<DerivedTTi>& TTi)
 {
-  std::vector<std::vector<int> > TTT;
-  triangle_triangle_adjacency_preprocess(F,TTT);
-  triangle_triangle_adjacency_extractTT(F,TTT,TT);
-  triangle_triangle_adjacency_extractTTi(F,TTT,TTi);
+  triangle_triangle_adjacency(F,TT);
+  TTi = DerivedTTi::Constant(TT.rows(),TT.cols(),-1);
+  //for(int f = 0; f<F.rows(); f++)
+  igl::parallel_for(F.rows(),[&](int f)
+  {
+    for(int k = 0;k<3;k++)
+    {
+      int vi = F(f,k), vj = F(f,(k+1)%3);
+      int fn = TT(f,k);
+      if(fn >= 0)
+      {
+        for(int kn = 0;kn<3;kn++)
+        {
+          int vin = F(fn,kn), vjn = F(fn,(kn+1)%3);
+          if(vi == vjn && vin == vj)
+          {
+            TTi(f,k) = kn;
+            break;
+          }
+        }
+      }
+    }
+  });
 }
 
 template <
@@ -100,7 +148,7 @@ template <
   typename TTIndex,
   typename TTiIndex>
   IGL_INLINE void igl::triangle_triangle_adjacency(
-    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedF> & F,
     std::vector<std::vector<std::vector<TTIndex> > > & TT,
     std::vector<std::vector<std::vector<TTiIndex> > > & TTi)
 {
@@ -111,7 +159,7 @@ template <
   typename DerivedF,
   typename TTIndex>
   IGL_INLINE void igl::triangle_triangle_adjacency(
-    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedF> & F,
     std::vector<std::vector<std::vector<TTIndex> > > & TT)
 {
   std::vector<std::vector<std::vector<TTIndex> > > not_used;
@@ -123,7 +171,7 @@ template <
   typename TTIndex,
   typename TTiIndex>
   IGL_INLINE void igl::triangle_triangle_adjacency(
-    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedF> & F,
     const bool construct_TTi,
     std::vector<std::vector<std::vector<TTIndex> > > & TT,
     std::vector<std::vector<std::vector<TTiIndex> > > & TTi)
@@ -149,8 +197,8 @@ template <
   typename TTIndex,
   typename TTiIndex>
   IGL_INLINE void igl::triangle_triangle_adjacency(
-    const Eigen::PlainObjectBase<DerivedE> & E,
-    const Eigen::PlainObjectBase<DerivedEMAP> & EMAP,
+    const Eigen::MatrixBase<DerivedE> & E,
+    const Eigen::MatrixBase<DerivedEMAP> & EMAP,
     const std::vector<std::vector<uE2EType> > & uE2E,
     const bool construct_TTi,
     std::vector<std::vector<std::vector<TTIndex> > > & TT,
@@ -206,21 +254,21 @@ template <
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
-template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 // generated by autoexplicit.sh
-template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&);
 // generated by autoexplicit.sh
-template void igl::triangle_triangle_adjacency<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> >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 // generated by autoexplicit.sh
-template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-template void igl::triangle_triangle_adjacency<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::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, long, long>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, bool, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&);
-template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long, int, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, bool, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&);
-template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, long, long>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&);
-template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::triangle_triangle_adjacency<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::MatrixBase<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::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, long, long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&);
 #ifdef WIN32
-template void igl::triangle_triangle_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, __int64, __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>, class std::allocator<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>>> &, class std::vector<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>, class std::allocator<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>>> &);
-template void igl::triangle_triangle_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64, int, int>(class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, bool, class std::vector<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>, class std::allocator<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>>> &, class std::vector<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>, class std::allocator<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>>> &);
+template void igl::triangle_triangle_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, __int64, __int64>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>, class std::allocator<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>>> &, class std::vector<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>, class std::allocator<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>>> &);
+template void igl::triangle_triangle_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64, int, int>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, bool, class std::vector<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>, class std::allocator<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>>> &, class std::vector<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>, class std::allocator<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>>> &);
 #endif
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, long, long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, bool, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long, int, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, bool, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&);
 #endif

+ 10 - 10
include/igl/triangle_triangle_adjacency.h

@@ -28,28 +28,28 @@ namespace igl
   //       [2,3].  this convention is DIFFERENT from cotmatrix_entries.h
   template <typename DerivedF, typename DerivedTT, typename DerivedTTi>
   IGL_INLINE void triangle_triangle_adjacency(
-    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedF>& F,
     Eigen::PlainObjectBase<DerivedTT>& TT,
     Eigen::PlainObjectBase<DerivedTTi>& TTi);
   template <typename DerivedF, typename DerivedTT>
   IGL_INLINE void triangle_triangle_adjacency(
-    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedF>& F,
     Eigen::PlainObjectBase<DerivedTT>& TT);
   // Preprocessing
   template <typename DerivedF, typename TTT_type>
   IGL_INLINE void triangle_triangle_adjacency_preprocess(
-    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedF>& F,
     std::vector<std::vector<TTT_type> >& TTT);
   // Extract the face adjacencies
   template <typename DerivedF, typename TTT_type, typename DerivedTT>
   IGL_INLINE void triangle_triangle_adjacency_extractTT(
-    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedF>& F,
     std::vector<std::vector<TTT_type> >& TTT,
     Eigen::PlainObjectBase<DerivedTT>& TT);
   // Extract the face adjacencies indices (needed for fast traversal)
   template <typename DerivedF, typename TTT_type, typename DerivedTTi>
   IGL_INLINE void triangle_triangle_adjacency_extractTTi(
-    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedF>& F,
     std::vector<std::vector<TTT_type> >& TTT,
     Eigen::PlainObjectBase<DerivedTTi>& TTi);
   // Adjacency list version, which works with non-manifold meshes
@@ -68,12 +68,12 @@ namespace igl
     typename TTIndex, 
     typename TTiIndex>
     IGL_INLINE void triangle_triangle_adjacency(
-      const Eigen::PlainObjectBase<DerivedF> & F,
+      const Eigen::MatrixBase<DerivedF> & F,
       std::vector<std::vector<std::vector<TTIndex> > > & TT,
       std::vector<std::vector<std::vector<TTiIndex> > > & TTi);
   template < typename DerivedF, typename TTIndex>
     IGL_INLINE void triangle_triangle_adjacency(
-      const Eigen::PlainObjectBase<DerivedF> & F,
+      const Eigen::MatrixBase<DerivedF> & F,
       std::vector<std::vector<std::vector<TTIndex> > > & TT);
   // Wrapper with bool to choose whether to compute TTi (this prototype should
   // be "hidden").
@@ -82,7 +82,7 @@ namespace igl
     typename TTIndex, 
     typename TTiIndex>
     IGL_INLINE void triangle_triangle_adjacency(
-      const Eigen::PlainObjectBase<DerivedF> & F,
+      const Eigen::MatrixBase<DerivedF> & F,
       const bool construct_TTi,
       std::vector<std::vector<std::vector<TTIndex> > > & TT,
       std::vector<std::vector<std::vector<TTiIndex> > > & TTi);
@@ -100,8 +100,8 @@ namespace igl
     typename TTIndex, 
     typename TTiIndex>
     IGL_INLINE void triangle_triangle_adjacency(
-      const Eigen::PlainObjectBase<DerivedE> & E,
-      const Eigen::PlainObjectBase<DerivedEMAP> & EMAP,
+      const Eigen::MatrixBase<DerivedE> & E,
+      const Eigen::MatrixBase<DerivedEMAP> & EMAP,
       const std::vector<std::vector<uE2EType > > & uE2E,
       const bool construct_TTi,
       std::vector<std::vector<std::vector<TTIndex> > > & TT,

+ 54 - 13
include/igl/vertex_triangle_adjacency.cpp

@@ -6,11 +6,12 @@
 // 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 "vertex_triangle_adjacency.h"
+#include "cumsum.h"
 
 template <typename DerivedF, typename VFType, typename VFiType>
 IGL_INLINE void igl::vertex_triangle_adjacency(
   const typename DerivedF::Scalar n,
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedF>& F,
   std::vector<std::vector<VFType> >& VF,
   std::vector<std::vector<VFiType> >& VFi)
 {
@@ -34,28 +35,68 @@ IGL_INLINE void igl::vertex_triangle_adjacency(
 
 template <typename DerivedV, typename DerivedF, typename IndexType>
 IGL_INLINE void igl::vertex_triangle_adjacency(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
   std::vector<std::vector<IndexType> >& VF,
   std::vector<std::vector<IndexType> >& VFi)
 {
   return vertex_triangle_adjacency(V.rows(),F,VF,VFi);
 }
 
+template <
+  typename DerivedF,
+  typename DerivedVF,
+  typename DerivedNI>
+IGL_INLINE void igl::vertex_triangle_adjacency(
+  const Eigen::MatrixBase<DerivedF> & F,
+  const int n,
+  Eigen::PlainObjectBase<DerivedVF> & VF,
+  Eigen::PlainObjectBase<DerivedNI> & NI)
+{
+  typedef Eigen::Matrix<typename DerivedVF::Scalar,Eigen::Dynamic,1> VectorXI;
+  // vfd  #V list so that vfd(i) contains the vertex-face degree (number of
+  // faces incident on vertex i)
+  VectorXI vfd = VectorXI::Zero(n);
+  for (int i = 0; i < F.rows(); i++)
+  {
+    for (int j = 0; j < 3; j++)
+    {
+      vfd[F(i,j)]++;
+    }
+  }
+  igl::cumsum(vfd,1,NI);
+  // Prepend a zero
+  NI = (DerivedNI(n+1)<<0,NI).finished();
+  // vfd now acts as a counter
+  vfd = NI;
+
+  VF.derived()= Eigen::VectorXi(3*F.rows());
+  for (int i = 0; i < F.rows(); i++)
+  {
+    for (int j = 0; j < 3; j++)
+    {
+      VF[vfd[F(i,j)]] = i;
+      vfd[F(i,j)]++;
+    }
+  }
+}
+
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
-template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, 3, 1, -1, 3>, unsigned long, unsigned long>(Eigen::Matrix<int, -1, 3, 1, -1, 3>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, 3, 1, -1, 3>, unsigned long, unsigned long>(Eigen::Matrix<int, -1, 3, 1, -1, 3>::Scalar, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&);
 // generated by autoexplicit.sh
-template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
-template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, unsigned int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, std::vector<std::vector<unsigned int, std::allocator<unsigned int> >, std::allocator<std::vector<unsigned int, std::allocator<unsigned int> > > >&, std::vector<std::vector<unsigned int, std::allocator<unsigned int> >, std::allocator<std::vector<unsigned int, std::allocator<unsigned int> > > >&);
-template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
-template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, -1, 0, -1, -1>, long, long>(Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
-template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, long, long>(Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
-template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, unsigned long>(Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&);
-template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, unsigned int>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, std::vector<std::vector<unsigned int, std::allocator<unsigned int> >, std::allocator<std::vector<unsigned int, std::allocator<unsigned int> > > >&, std::vector<std::vector<unsigned int, std::allocator<unsigned int> >, std::allocator<std::vector<unsigned int, std::allocator<unsigned int> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, -1, 0, -1, -1>, long, long>(Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, long, long>(Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, unsigned long>(Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::vertex_triangle_adjacency<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::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #ifdef WIN32
-template void igl::vertex_triangle_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, unsigned __int64>(int, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &);
-template void igl::vertex_triangle_adjacency<class Eigen::Matrix<int, -1, 3, 1, -1, 3>, unsigned __int64, unsigned __int64>(int, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &);
+template void igl::vertex_triangle_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, unsigned __int64>(int, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &);
+template void igl::vertex_triangle_adjacency<class Eigen::Matrix<int, -1, 3, 1, -1, 3>, unsigned __int64, unsigned __int64>(int, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &);
 #endif
 #endif

+ 23 - 4
include/igl/vertex_triangle_adjacency.h

@@ -7,7 +7,7 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #ifndef IGL_VERTEX_TRIANGLE_ADJACENCY_H
 #define IGL_VERTEX_TRIANGLE_ADJACENCY_H
-#include <igl/igl_inline.h>
+#include "igl_inline.h"
 
 #include <Eigen/Dense>
 #include <vector>
@@ -34,15 +34,34 @@ namespace igl
   template <typename DerivedF, typename VFType, typename VFiType>
   IGL_INLINE void vertex_triangle_adjacency(
     const typename DerivedF::Scalar n,
-    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedF>& F,
     std::vector<std::vector<VFType> >& VF,
     std::vector<std::vector<VFiType> >& VFi);
   template <typename DerivedV, typename DerivedF, typename IndexType>
   IGL_INLINE void vertex_triangle_adjacency(
-    const Eigen::PlainObjectBase<DerivedV>& V,
-    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
     std::vector<std::vector<IndexType> >& VF,
     std::vector<std::vector<IndexType> >& VFi);
+  // Inputs:
+  //   F  #F by 3 list of triangle indices into some vertex list V
+  //   n  number of vertices, #V (e.g., F.maxCoeff()+1)
+  // Outputs:
+  //   VF  3*#F list  List of faces indice on each vertex, so that VF(NI(i)+j) =
+  //     f, means that face f is the jth face (in no particular order) incident
+  //     on vertex i.
+  //   NI  #V+1 list  cumulative sum of vertex-triangle degrees with a
+  //     preceeding zero. "How many faces" have been seen before visiting this
+  //     vertex and its incident faces.
+  template <
+    typename DerivedF,
+    typename DerivedVF,
+    typename DerivedNI>
+  IGL_INLINE void vertex_triangle_adjacency(
+    const Eigen::MatrixBase<DerivedF> & F,
+    const int n,
+    Eigen::PlainObjectBase<DerivedVF> & VF,
+    Eigen::PlainObjectBase<DerivedNI> & NI);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 3 - 2
python/CMakeLists.txt

@@ -10,8 +10,9 @@ project(pyigl)
 # set(PYTHON_INCLUDE_DIR "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/include/python3.5m")
 
 set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6)
-find_package(PythonLibs REQUIRED)
 find_package(PythonInterp REQUIRED)
+find_package(PythonLibs REQUIRED)
+
 
 string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
 if(UNIX)
@@ -144,7 +145,7 @@ elseif(UNIX)
   # .SO file extension on Linux/Mac OS
   set_target_properties(pyigl PROPERTIES SUFFIX ".so")
 
-  #Enable flag if undefined symbols appear on pyigl module import to get notified about the missing symbols at link time
+  # Enable flag if undefined symbols appear on pyigl module import to get notified about the missing symbols at link time
   option(CHECK_UNDEFINED        "Check for undefined symbols"    OFF)
 
   # Strip unnecessary sections of the binary on Linux/Mac OS

+ 10 - 20
python/modules/py_igl_opengl_glfw.cpp

@@ -241,7 +241,6 @@ py::class_<igl::opengl::ViewerCore> viewercore_class(me, "ViewerCore");
     })
 
     .def_readwrite("lighting_factor",&igl::opengl::ViewerCore::lighting_factor)
-    .def_readwrite("model_zoom",&igl::opengl::ViewerCore::model_zoom)
 
     .def_property("trackball_angle",
     [](const igl::opengl::ViewerCore& core) {return Eigen::Quaterniond(core.trackball_angle.cast<double>());},
@@ -250,24 +249,23 @@ py::class_<igl::opengl::ViewerCore> viewercore_class(me, "ViewerCore");
       core.trackball_angle = Eigen::Quaternionf(q.cast<float>());
     })
 
-    .def_property("model_translation",
-    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.model_translation.cast<double>());},
+    .def_property("camera_base_translation",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.camera_base_translation.cast<double>());},
     [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
     {
-      assert_is_Vector3("model_translation",v);
-      core.model_translation = Eigen::Vector3f(v.cast<float>());
+      assert_is_Vector3("camera_base_translation",v);
+      core.camera_base_translation = Eigen::Vector3f(v.cast<float>());
     })
 
-    .def_readwrite("model_zoom_uv",&igl::opengl::ViewerCore::model_zoom_uv)
-
-    .def_property("model_translation_uv",
-    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.model_translation_uv.cast<double>());},
+    .def_property("camera_translation",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.camera_translation.cast<double>());},
     [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
     {
-      assert_is_Vector3("model_translation_uv",v);
-      core.model_translation_uv = Eigen::Vector3f(v.cast<float>());
+      assert_is_Vector3("camera_translation",v);
+      core.camera_translation = Eigen::Vector3f(v.cast<float>());
     })
 
+    .def_readwrite("camera_base_zoom",&igl::opengl::ViewerCore::camera_base_zoom)
     .def_readwrite("camera_zoom",&igl::opengl::ViewerCore::camera_zoom)
     .def_readwrite("orthographic",&igl::opengl::ViewerCore::orthographic)
 
@@ -323,14 +321,6 @@ py::class_<igl::opengl::ViewerCore> viewercore_class(me, "ViewerCore");
       core.view = Eigen::Matrix4f(v.cast<float>());
     })
 
-    .def_property("model",
-    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.model.cast<double>());},
-    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Matrix4("model",v);
-      core.model = Eigen::Matrix4f(v.cast<float>());
-    })
-
     .def_property("proj",
     [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.proj.cast<double>());},
     [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
@@ -380,7 +370,7 @@ py::class_<igl::opengl::ViewerCore> viewercore_class(me, "ViewerCore");
     viewer_class
     .def(py::init<>())
     //.def_readwrite("data", &igl::opengl::glfw::Viewer::data)
-   
+
     // .def_property("data",
     // [](igl::opengl::glfw::Viewer& viewer) {return viewer.data();},
     // [](igl::opengl::glfw::Viewer& viewer, const igl::opengl::ViewerData& data)

+ 90 - 0
python/setup.py

@@ -0,0 +1,90 @@
+import os
+import re
+import sys
+import platform
+import subprocess
+
+from setuptools import setup, Extension
+from setuptools.command.build_ext import build_ext
+from distutils.version import LooseVersion
+from distutils.sysconfig import get_config_var
+from distutils.sysconfig import get_python_inc
+
+CMAKE_ADDITIONAL_OPT = []
+if '--' in sys.argv:
+    i = sys.argv.index('--')
+    CMAKE_ADDITIONAL_OPT = sys.argv[i+1:]
+    sys.argv = sys.argv[:i]
+
+class CMakeExtension(Extension):
+
+    def __init__(self, name, sourcedir=''):
+        Extension.__init__(self, name, sources=[])
+        self.sourcedir = os.path.abspath(sourcedir)
+
+
+class CMakeBuild(build_ext):
+
+    def run(self):
+        try:
+            out = subprocess.check_output(['cmake', '--version'])
+        except OSError:
+            raise RuntimeError("CMake must be installed to build the following extensions: " +
+                               ", ".join(e.name for e in self.extensions))
+
+        if platform.system() == "Windows":
+            cmake_version = LooseVersion(
+                re.search(r'version\s*([\d.]+)', out.decode()).group(1))
+            if cmake_version < '3.1.0':
+                raise RuntimeError("CMake >= 3.1.0 is required on Windows")
+
+        for ext in self.extensions:
+            self.build_extension(ext)
+
+    def build_extension(self, ext):
+        extdir = os.path.abspath(os.path.dirname(
+            self.get_ext_fullpath(ext.name)))
+
+        python_library = str(get_config_var('LIBDIR'))
+        python_include_directory = str(get_python_inc())
+
+        cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir,
+                      '-DPYTHON_EXECUTABLE=' + sys.executable,
+                      '-DPYTHON_INCLUDE_DIR=' + python_include_directory, ]
+
+        cfg = 'Debug' if self.debug else 'Release'
+        build_args = ['--config', cfg]
+
+        if platform.system() == "Windows":
+            cmake_args += [
+                '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)]
+            if sys.maxsize > 2**32:
+                cmake_args += ['-A', 'x64']
+            build_args += ['--', '/m']
+        else:
+            cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
+            build_args += ['--', '-j2']
+        cmake_args += CMAKE_ADDITIONAL_OPT
+
+        env = os.environ.copy()
+        env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''),
+                                                              self.distribution.get_version())
+        if not os.path.exists(self.build_temp):
+            os.makedirs(self.build_temp)
+
+        subprocess.check_call(['cmake', ext.sourcedir] +
+                              cmake_args, cwd=self.build_temp, env=env)
+        subprocess.check_call(['cmake', '--build', '.'] +
+                              build_args, cwd=self.build_temp)
+
+setup(
+    name='pyigl',
+    version='0.0.1',
+    author='Geometric Computing Lab @ NYU',
+    author_email='info@geometriccomputing.org',
+    description='',
+    long_description='',
+    ext_modules=[CMakeExtension('pyigl')],
+    cmdclass=dict(build_ext=CMakeBuild),
+    zip_safe=False,
+)

+ 1 - 1
python/tutorial/708_Picking.py

@@ -24,7 +24,7 @@ def mouse_down(viewer, a, b):
     # Cast a ray in the view direction starting from the mouse position
     fid = igl.eigen.MatrixXi(np.array([-1]))
     coord = igl.eigen.MatrixXd([viewer.current_mouse_x, viewer.core.viewport[3] - viewer.current_mouse_y])
-    hit = igl.unproject_onto_mesh(coord, viewer.core.view * viewer.core.model,
+    hit = igl.unproject_onto_mesh(coord, viewer.core.view,
       viewer.core.proj, viewer.core.viewport, V, F, fid, bc)
     if hit:
         # paint hit red

+ 17 - 0
shared/cmake/DownloadProject.CMakeLists.cmake.in

@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved MIT License.  See accompanying
+# file LICENSE or https://github.com/Crascit/DownloadProject for details.
+
+cmake_minimum_required(VERSION 2.8.2)
+
+project(${DL_ARGS_PROJ}-download NONE)
+
+include(ExternalProject)
+ExternalProject_Add(${DL_ARGS_PROJ}-download
+                    ${DL_ARGS_UNPARSED_ARGUMENTS}
+                    SOURCE_DIR          "${DL_ARGS_SOURCE_DIR}"
+                    BINARY_DIR          "${DL_ARGS_BINARY_DIR}"
+                    CONFIGURE_COMMAND   ""
+                    BUILD_COMMAND       ""
+                    INSTALL_COMMAND     ""
+                    TEST_COMMAND        ""
+)

+ 182 - 0
shared/cmake/DownloadProject.cmake

@@ -0,0 +1,182 @@
+# Distributed under the OSI-approved MIT License.  See accompanying
+# file LICENSE or https://github.com/Crascit/DownloadProject for details.
+#
+# MODULE:   DownloadProject
+#
+# PROVIDES:
+#   download_project( PROJ projectName
+#                    [PREFIX prefixDir]
+#                    [DOWNLOAD_DIR downloadDir]
+#                    [SOURCE_DIR srcDir]
+#                    [BINARY_DIR binDir]
+#                    [QUIET]
+#                    ...
+#   )
+#
+#       Provides the ability to download and unpack a tarball, zip file, git repository,
+#       etc. at configure time (i.e. when the cmake command is run). How the downloaded
+#       and unpacked contents are used is up to the caller, but the motivating case is
+#       to download source code which can then be included directly in the build with
+#       add_subdirectory() after the call to download_project(). Source and build
+#       directories are set up with this in mind.
+#
+#       The PROJ argument is required. The projectName value will be used to construct
+#       the following variables upon exit (obviously replace projectName with its actual
+#       value):
+#
+#           projectName_SOURCE_DIR
+#           projectName_BINARY_DIR
+#
+#       The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically
+#       need to be provided. They can be specified if you want the downloaded source
+#       and build directories to be located in a specific place. The contents of
+#       projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the
+#       locations used whether you provide SOURCE_DIR/BINARY_DIR or not.
+#
+#       The DOWNLOAD_DIR argument does not normally need to be set. It controls the
+#       location of the temporary CMake build used to perform the download.
+#
+#       The PREFIX argument can be provided to change the base location of the default
+#       values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments
+#       are provided, then PREFIX will have no effect. The default value for PREFIX is
+#       CMAKE_BINARY_DIR.
+#
+#       The QUIET option can be given if you do not want to show the output associated
+#       with downloading the specified project.
+#
+#       In addition to the above, any other options are passed through unmodified to
+#       ExternalProject_Add() to perform the actual download, patch and update steps.
+#       The following ExternalProject_Add() options are explicitly prohibited (they
+#       are reserved for use by the download_project() command):
+#
+#           CONFIGURE_COMMAND
+#           BUILD_COMMAND
+#           INSTALL_COMMAND
+#           TEST_COMMAND
+#
+#       Only those ExternalProject_Add() arguments which relate to downloading, patching
+#       and updating of the project sources are intended to be used. Also note that at
+#       least one set of download-related arguments are required.
+#
+#       If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to
+#       prevent a check at the remote end for changes every time CMake is run
+#       after the first successful download. See the documentation of the ExternalProject
+#       module for more information. It is likely you will want to use this option if it
+#       is available to you. Note, however, that the ExternalProject implementation contains
+#       bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when
+#       using the URL download method or when specifying a SOURCE_DIR with no download
+#       method. Fixes for these have been created, the last of which is scheduled for
+#       inclusion in CMake 3.8.0. Details can be found here:
+#
+#           https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c
+#           https://gitlab.kitware.com/cmake/cmake/issues/16428
+#
+#       If you experience build errors related to the update step, consider avoiding
+#       the use of UPDATE_DISCONNECTED.
+#
+# EXAMPLE USAGE:
+#
+#   include(DownloadProject)
+#   download_project(PROJ                googletest
+#                    GIT_REPOSITORY      https://github.com/google/googletest.git
+#                    GIT_TAG             master
+#                    UPDATE_DISCONNECTED 1
+#                    QUIET
+#   )
+#
+#   add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
+#
+#========================================================================================
+
+
+set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}")
+
+include(CMakeParseArguments)
+
+function(download_project)
+
+    set(options QUIET)
+    set(oneValueArgs
+        PROJ
+        PREFIX
+        DOWNLOAD_DIR
+        SOURCE_DIR
+        BINARY_DIR
+        # Prevent the following from being passed through
+        CONFIGURE_COMMAND
+        BUILD_COMMAND
+        INSTALL_COMMAND
+        TEST_COMMAND
+    )
+    set(multiValueArgs "")
+
+    cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+    # Hide output if requested
+    if (DL_ARGS_QUIET)
+        set(OUTPUT_QUIET "OUTPUT_QUIET")
+    else()
+        unset(OUTPUT_QUIET)
+        message(STATUS "Downloading/updating ${DL_ARGS_PROJ}")
+    endif()
+
+    # Set up where we will put our temporary CMakeLists.txt file and also
+    # the base point below which the default source and binary dirs will be.
+    # The prefix must always be an absolute path.
+    if (NOT DL_ARGS_PREFIX)
+        set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}")
+    else()
+        get_filename_component(DL_ARGS_PREFIX "${DL_ARGS_PREFIX}" ABSOLUTE
+                               BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+    endif()
+    if (NOT DL_ARGS_DOWNLOAD_DIR)
+        set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download")
+    endif()
+
+    # Ensure the caller can know where to find the source and build directories
+    if (NOT DL_ARGS_SOURCE_DIR)
+        set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src")
+    endif()
+    if (NOT DL_ARGS_BINARY_DIR)
+        set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build")
+    endif()
+    set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE)
+    set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE)
+
+    # The way that CLion manages multiple configurations, it causes a copy of
+    # the CMakeCache.txt to be copied across due to it not expecting there to
+    # be a project within a project.  This causes the hard-coded paths in the
+    # cache to be copied and builds to fail.  To mitigate this, we simply
+    # remove the cache if it exists before we configure the new project.  It
+    # is safe to do so because it will be re-generated.  Since this is only
+    # executed at the configure step, it should not cause additional builds or
+    # downloads.
+    file(REMOVE "${DL_ARGS_DOWNLOAD_DIR}/CMakeCache.txt")
+
+    # Create and build a separate CMake project to carry out the download.
+    # If we've already previously done these steps, they will not cause
+    # anything to be updated, so extra rebuilds of the project won't occur.
+    # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
+    # has this set to something not findable on the PATH.
+    configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in"
+                   "${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt")
+    execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
+                        -D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}"
+                        .
+                    RESULT_VARIABLE result
+                    ${OUTPUT_QUIET}
+                    WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}"
+    )
+    if(result)
+        message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}")
+    endif()
+    execute_process(COMMAND ${CMAKE_COMMAND} --build .
+                    RESULT_VARIABLE result
+                    ${OUTPUT_QUIET}
+                    WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}"
+    )
+    if(result)
+        message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}")
+    endif()
+
+endfunction()

+ 0 - 97
shared/cmake/FindCGAL.cmake

@@ -1,97 +0,0 @@
-#
-# The following module is based on FindVTK.cmake
-#
-
-# - Find a CGAL installation or binary tree.
-# The following variables are set if CGAL is found.  If CGAL is not
-# found, CGAL_FOUND is set to false.
-#
-#  CGAL_FOUND         - Set to true when CGAL is found.
-#  CGAL_USE_FILE      - CMake file to use CGAL.
-#
-
-# Construct consitent error messages for use below.
-set(CGAL_DIR_DESCRIPTION "directory containing CGALConfig.cmake. This is either the binary directory where CGAL was configured or PREFIX/lib/CGAL for an installation.")
-set(CGAL_DIR_MESSAGE     "CGAL not found.  Set the CGAL_DIR cmake variable or environment variable to the ${CGAL_DIR_DESCRIPTION}")
-
-set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
-
-if ( NOT CGAL_DIR )
-
-  # Get the system search path as a list.
-  if(UNIX)
-    string(REGEX MATCHALL "[^:]+" CGAL_DIR_SEARCH1 "$ENV{PATH}")
-  else()
-    string(REGEX REPLACE "\\\\" "/" CGAL_DIR_SEARCH1 "$ENV{PATH}")
-  endif()
-
-  string(REGEX REPLACE "/;" ";" CGAL_DIR_SEARCH2 "${CGAL_DIR_SEARCH1}")
-
-  # Construct a set of paths relative to the system search path.
-  set(CGAL_DIR_SEARCH "")
-
-  foreach(dir ${CGAL_DIR_SEARCH2})
-
-    set(CGAL_DIR_SEARCH ${CGAL_DIR_SEARCH} ${dir}/../lib/CGAL )
-
-  endforeach()
-
-
-  #
-  # Look for an installation or build tree.
-  #
-  find_path(CGAL_DIR CGALConfig.cmake
-    # Look for CGAL in 'external/' folder
-    "${CMAKE_CURRENT_LIST_DIR}/../../external/cgal/lib/CGAL"
-
-    # Look for an environment variable CGAL_DIR.
-    $ENV{CGAL_DIR}
-
-    # Look in places relative to the system executable search path.
-    ${CGAL_DIR_SEARCH}
-
-    # Look in standard UNIX install locations.
-    /usr/lib/x86_64-linux-gnu/cmake/CGAL
-    /opt/local/share/CGAL/cmake
-    /usr/local/lib/CGAL
-    /usr/lib/CGAL
-
-    # Read from the CMakeSetup registry entries.  It is likely that
-    # CGAL will have been recently built.
-    [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild1]
-    [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild2]
-    [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild3]
-    [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild4]
-    [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild5]
-    [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild6]
-    [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild7]
-    [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild8]
-    [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild9]
-    [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild10]
-
-    # Help the user find it if we cannot.
-    DOC "The ${CGAL_DIR_DESCRIPTION}"
-  )
-
-endif()
-
-if ( CGAL_DIR )
-
-  if ( EXISTS "${CGAL_DIR}/CGALConfig.cmake" )
-    include( "${CGAL_DIR}/CGALConfig.cmake" )
-    set( CGAL_FOUND TRUE )
-  endif()
-
-endif()
-
-if(CGAL_FOUND)
-  MESSAGE(STATUS "Found CGAL: ${CGAL_DIR}")
-else()
-  if(CGAL_FIND_REQUIRED)
-    MESSAGE(FATAL_ERROR ${CGAL_DIR_MESSAGE})
-  else()
-    if(NOT CGAL_FIND_QUIETLY)
-      MESSAGE(STATUS ${CGAL_DIR_MESSAGE})
-    endif()
-  endif()
-endif()

+ 1540 - 0
shared/cmake/FindMATLAB.cmake

@@ -0,0 +1,1540 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#.rst:
+# FindMatlab
+# ----------
+#
+# Finds Matlab installations and provides Matlab tools and libraries to cmake.
+#
+# This package first intention is to find the libraries associated with Matlab
+# in order to be able to build Matlab extensions (mex files). It can also be
+# used:
+#
+# * run specific commands in Matlab
+# * declare Matlab unit test
+# * retrieve various information from Matlab (mex extensions, versions and
+#   release queries, ...)
+#
+# The module supports the following components:
+#
+# * ``MX_LIBRARY``, ``ENG_LIBRARY`` and ``MAT_LIBRARY``: respectively the MX,
+#   ENG and MAT libraries of Matlab
+# * ``MAIN_PROGRAM`` the Matlab binary program.
+# * ``MEX_COMPILER`` the MEX compiler.
+# * ``SIMULINK`` the Simulink environment.
+#
+# .. note::
+#
+#   The version given to the :command:`find_package` directive is the Matlab
+#   **version**, which should not be confused with the Matlab *release* name
+#   (eg. `R2014`).
+#   The :command:`matlab_get_version_from_release_name` and
+#   :command:`matlab_get_release_name_from_version` allow a mapping
+#   from the release name to the version.
+#
+# The variable :variable:`Matlab_ROOT_DIR` may be specified in order to give
+# the path of the desired Matlab version. Otherwise, the behaviour is platform
+# specific:
+#
+# * Windows: The installed versions of Matlab are retrieved from the
+#   Windows registry
+# * OS X: The installed versions of Matlab are given by the MATLAB
+#   paths in ``/Application``. If no such application is found, it falls back
+#   to the one that might be accessible from the PATH.
+# * Unix: The desired Matlab should be accessible from the PATH.
+#
+# Additional information is provided when :variable:`MATLAB_FIND_DEBUG` is set.
+# When a Matlab binary is found automatically and the ``MATLAB_VERSION``
+# is not given, the version is queried from Matlab directly.
+# On Windows, it can make a window running Matlab appear.
+#
+# The mapping of the release names and the version of Matlab is performed by
+# defining pairs (name, version).  The variable
+# :variable:`MATLAB_ADDITIONAL_VERSIONS` may be provided before the call to
+# the :command:`find_package` in order to handle additional versions.
+#
+# A Matlab scripts can be added to the set of tests using the
+# :command:`matlab_add_unit_test`. By default, the Matlab unit test framework
+# will be used (>= 2013a) to run this script, but regular ``.m`` files
+# returning an exit code can be used as well (0 indicating a success).
+#
+# Module Input Variables
+# ^^^^^^^^^^^^^^^^^^^^^^
+#
+# Users or projects may set the following variables to configure the module
+# behaviour:
+#
+# :variable:`Matlab_ROOT_DIR`
+#   the root of the Matlab installation.
+# :variable:`MATLAB_FIND_DEBUG`
+#   outputs debug information
+# :variable:`MATLAB_ADDITIONAL_VERSIONS`
+#   additional versions of Matlab for the automatic retrieval of the installed
+#   versions.
+#
+# Variables defined by the module
+# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+#
+# Result variables
+# """"""""""""""""
+#
+# ``Matlab_FOUND``
+#   ``TRUE`` if the Matlab installation is found, ``FALSE``
+#   otherwise. All variable below are defined if Matlab is found.
+# ``Matlab_ROOT_DIR``
+#   the final root of the Matlab installation determined by the FindMatlab
+#   module.
+# ``Matlab_MAIN_PROGRAM``
+#   the Matlab binary program. Available only if the component ``MAIN_PROGRAM``
+#   is given in the :command:`find_package` directive.
+# ``Matlab_INCLUDE_DIRS``
+#  the path of the Matlab libraries headers
+# ``Matlab_MEX_LIBRARY``
+#   library for mex, always available.
+# ``Matlab_MX_LIBRARY``
+#   mx library of Matlab (arrays). Available only if the component
+#   ``MX_LIBRARY`` has been requested.
+# ``Matlab_ENG_LIBRARY``
+#   Matlab engine library. Available only if the component ``ENG_LIBRARY``
+#   is requested.
+# ``Matlab_MAT_LIBRARY``
+#   Matlab matrix library. Available only if the component ``MAT_LIBRARY``
+#   is requested.
+# ``Matlab_LIBRARIES``
+#   the whole set of libraries of Matlab
+# ``Matlab_MEX_COMPILER``
+#   the mex compiler of Matlab. Currently not used.
+#   Available only if the component ``MEX_COMPILER`` is asked
+#
+# Cached variables
+# """"""""""""""""
+#
+# ``Matlab_MEX_EXTENSION``
+#   the extension of the mex files for the current platform (given by Matlab).
+# ``Matlab_ROOT_DIR``
+#   the location of the root of the Matlab installation found. If this value
+#   is changed by the user, the result variables are recomputed.
+#
+# Provided macros
+# ^^^^^^^^^^^^^^^
+#
+# :command:`matlab_get_version_from_release_name`
+#   returns the version from the release name
+# :command:`matlab_get_release_name_from_version`
+#   returns the release name from the Matlab version
+#
+# Provided functions
+# ^^^^^^^^^^^^^^^^^^
+#
+# :command:`matlab_add_mex`
+#   adds a target compiling a MEX file.
+# :command:`matlab_add_unit_test`
+#   adds a Matlab unit test file as a test to the project.
+# :command:`matlab_extract_all_installed_versions_from_registry`
+#   parses the registry for all Matlab versions. Available on Windows only.
+#   The part of the registry parsed is dependent on the host processor
+# :command:`matlab_get_all_valid_matlab_roots_from_registry`
+#   returns all the possible Matlab paths, according to a previously
+#   given list. Only the existing/accessible paths are kept. This is mainly
+#   useful for the searching all possible Matlab installation.
+# :command:`matlab_get_mex_suffix`
+#   returns the suffix to be used for the mex files
+#   (platform/architecture dependent)
+# :command:`matlab_get_version_from_matlab_run`
+#   returns the version of Matlab, given the full directory of the Matlab
+#   program.
+#
+#
+# Known issues
+# ^^^^^^^^^^^^
+#
+# **Symbol clash in a MEX target**
+#   By default, every symbols inside a MEX
+#   file defined with the command :command:`matlab_add_mex` have hidden
+#   visibility, except for the entry point. This is the default behaviour of
+#   the MEX compiler, which lowers the risk of symbol collision between the
+#   libraries shipped with Matlab, and the libraries to which the MEX file is
+#   linking to. This is also the default on Windows platforms.
+#
+#   However, this is not sufficient in certain case, where for instance your
+#   MEX file is linking against libraries that are already loaded by Matlab,
+#   even if those libraries have different SONAMES.
+#   A possible solution is to hide the symbols of the libraries to which the
+#   MEX target is linking to. This can be achieved in GNU GCC compilers with
+#   the linker option ``-Wl,--exclude-libs,ALL``.
+#
+# **Tests using GPU resources**
+#   in case your MEX file is using the GPU and
+#   in order to be able to run unit tests on this MEX file, the GPU resources
+#   should be properly released by Matlab. A possible solution is to make
+#   Matlab aware of the use of the GPU resources in the session, which can be
+#   performed by a command such as ``D = gpuDevice()`` at the beginning of
+#   the test script (or via a fixture).
+#
+#
+# Reference
+# ^^^^^^^^^
+#
+# .. variable:: Matlab_ROOT_DIR
+#
+#    The root folder of the Matlab installation. If set before the call to
+#    :command:`find_package`, the module will look for the components in that
+#    path. If not set, then an automatic search of Matlab
+#    will be performed. If set, it should point to a valid version of Matlab.
+#
+# .. variable:: MATLAB_FIND_DEBUG
+#
+#    If set, the lookup of Matlab and the intermediate configuration steps are
+#    outputted to the console.
+#
+# .. variable:: MATLAB_ADDITIONAL_VERSIONS
+#
+#   If set, specifies additional versions of Matlab that may be looked for.
+#   The variable should be a list of strings, organised by pairs of release
+#   name and versions, such as follows::
+#
+#     set(MATLAB_ADDITIONAL_VERSIONS
+#         "release_name1=corresponding_version1"
+#         "release_name2=corresponding_version2"
+#         ...
+#         )
+#
+#   Example::
+#
+#     set(MATLAB_ADDITIONAL_VERSIONS
+#         "R2013b=8.2"
+#         "R2013a=8.1"
+#         "R2012b=8.0")
+#
+#   The order of entries in this list matters when several versions of
+#   Matlab are installed. The priority is set according to the ordering in
+#   this list.
+
+set(_FindMatlab_SELF_DIR "${CMAKE_CURRENT_LIST_DIR}")
+
+include(FindPackageHandleStandardArgs)
+include(CheckCXXCompilerFlag)
+include(CheckCCompilerFlag)
+
+
+# The currently supported versions. Other version can be added by the user by
+# providing MATLAB_ADDITIONAL_VERSIONS
+if(NOT MATLAB_ADDITIONAL_VERSIONS)
+  set(MATLAB_ADDITIONAL_VERSIONS)
+endif()
+
+set(MATLAB_VERSIONS_MAPPING
+  "R2018a=9.4"
+  "R2017b=9.3"
+  "R2017a=9.2"
+  "R2016b=9.1"
+  "R2016a=9.0"
+  "R2015b=8.6"
+  "R2015a=8.5"
+  "R2014b=8.4"
+  "R2014a=8.3"
+  "R2013b=8.2"
+  "R2013a=8.1"
+  "R2012b=8.0"
+  "R2012a=7.14"
+  "R2011b=7.13"
+  "R2011a=7.12"
+  "R2010b=7.11"
+
+  ${MATLAB_ADDITIONAL_VERSIONS}
+  )
+
+
+# temporary folder for all Matlab runs
+set(_matlab_temporary_folder ${CMAKE_BINARY_DIR}/Matlab)
+
+if(NOT EXISTS "${_matlab_temporary_folder}")
+  file(MAKE_DIRECTORY "${_matlab_temporary_folder}")
+endif()
+
+#.rst:
+# .. command:: matlab_get_version_from_release_name
+#
+#   Returns the version of Matlab (17.58) from a release name (R2017k)
+macro (matlab_get_version_from_release_name release_name version_name)
+
+  string(REGEX MATCHALL "${release_name}=([0-9]+\\.?[0-9]*)" _matched ${MATLAB_VERSIONS_MAPPING})
+
+  set(${version_name} "")
+  if(NOT _matched STREQUAL "")
+    set(${version_name} ${CMAKE_MATCH_1})
+  else()
+    message(WARNING "The release name ${release_name} is not registered")
+  endif()
+  unset(_matched)
+
+endmacro()
+
+
+
+
+
+#.rst:
+# .. command:: matlab_get_release_name_from_version
+#
+#   Returns the release name (R2017k) from the version of Matlab (17.58)
+macro (matlab_get_release_name_from_version version release_name)
+
+  set(${release_name} "")
+  foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING)
+    string(REGEX MATCHALL "(.+)=${version}" _matched ${_var})
+    if(NOT _matched STREQUAL "")
+      set(${release_name} ${CMAKE_MATCH_1})
+      break()
+    endif()
+  endforeach(_var)
+
+  unset(_var)
+  unset(_matched)
+  if(${release_name} STREQUAL "")
+    message(WARNING "The version ${version} is not registered")
+  endif()
+
+endmacro()
+
+
+
+
+
+# extracts all the supported release names (R2017k...) of Matlab
+# internal use
+macro(matlab_get_supported_releases list_releases)
+  set(${list_releases})
+  foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING)
+    string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var})
+    if(NOT _matched STREQUAL "")
+      list(APPEND ${list_releases} ${CMAKE_MATCH_1})
+    endif()
+    unset(_matched)
+    unset(CMAKE_MATCH_1)
+  endforeach(_var)
+  unset(_var)
+endmacro()
+
+
+
+# extracts all the supported versions of Matlab
+# internal use
+macro(matlab_get_supported_versions list_versions)
+  set(${list_versions})
+  foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING)
+    string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var})
+    if(NOT _matched STREQUAL "")
+      list(APPEND ${list_versions} ${CMAKE_MATCH_2})
+    endif()
+    unset(_matched)
+    unset(CMAKE_MATCH_1)
+  endforeach(_var)
+  unset(_var)
+endmacro()
+
+
+#.rst:
+# .. command:: matlab_extract_all_installed_versions_from_registry
+#
+#   This function parses the registry and founds the Matlab versions that are
+#   installed. The found versions are returned in `matlab_versions`.
+#   Set `win64` to `TRUE` if the 64 bit version of Matlab should be looked for
+#   The returned list contains all versions under
+#   ``HKLM\\SOFTWARE\\Mathworks\\MATLAB`` or an empty list in case an error
+#   occurred (or nothing found).
+#
+#   .. note::
+#
+#     Only the versions are provided. No check is made over the existence of the
+#     installation referenced in the registry,
+#
+function(matlab_extract_all_installed_versions_from_registry win64 matlab_versions)
+
+  if(NOT CMAKE_HOST_WIN32)
+    message(FATAL_ERROR "This macro can only be called by a windows host (call to reg.exe")
+  endif()
+
+
+  if(${win64} AND ${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "64")
+    set(APPEND_REG "/reg:64")
+  else()
+    set(APPEND_REG "/reg:32")
+  endif()
+
+  # /reg:64 should be added on 64 bits capable OSs in order to enable the
+  # redirection of 64 bits applications
+  execute_process(
+    COMMAND reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Mathworks\\MATLAB /f * /k ${APPEND_REG}
+    RESULT_VARIABLE resultMatlab
+    OUTPUT_VARIABLE varMatlab
+    ERROR_VARIABLE errMatlab
+    INPUT_FILE NUL
+    )
+
+
+  set(matlabs_from_registry)
+  if(${resultMatlab} EQUAL 0)
+
+    string(
+      REGEX MATCHALL "MATLAB\\\\([0-9]+(\\.[0-9]+)?)"
+      matlab_versions_regex ${varMatlab})
+
+    foreach(match IN LISTS matlab_versions_regex)
+      string(
+        REGEX MATCH "MATLAB\\\\(([0-9]+)(\\.([0-9]+))?)"
+        current_match ${match})
+
+      set(_matlab_current_version ${CMAKE_MATCH_1})
+      set(current_matlab_version_major ${CMAKE_MATCH_2})
+      set(current_matlab_version_minor ${CMAKE_MATCH_4})
+      if(NOT current_matlab_version_minor)
+        set(current_matlab_version_minor "0")
+      endif()
+
+      list(APPEND matlabs_from_registry ${_matlab_current_version})
+      unset(_matlab_current_version)
+    endforeach(match)
+
+  endif()
+
+  if(matlabs_from_registry)
+    list(REMOVE_DUPLICATES matlabs_from_registry)
+    list(SORT matlabs_from_registry)
+    list(REVERSE matlabs_from_registry)
+  endif()
+
+  set(${matlab_versions} ${matlabs_from_registry} PARENT_SCOPE)
+
+endfunction()
+
+
+
+# (internal)
+macro(extract_matlab_versions_from_registry_brute_force matlab_versions)
+  # get the supported versions
+  set(matlab_supported_versions)
+  matlab_get_supported_versions(matlab_supported_versions)
+
+
+  # this is a manual population of the versions we want to look for
+  # this can be done as is, but preferably with the call to
+  # matlab_get_supported_versions and variable
+
+  # populating the versions we want to look for
+  # set(matlab_supported_versions)
+
+  # # Matlab 7
+  # set(matlab_major 7)
+  # foreach(current_matlab_minor RANGE 4 20)
+    # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}")
+  # endforeach(current_matlab_minor)
+
+  # # Matlab 8
+  # set(matlab_major 8)
+  # foreach(current_matlab_minor RANGE 0 5)
+    # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}")
+  # endforeach(current_matlab_minor)
+
+  # # taking into account the possible additional versions provided by the user
+  # if(DEFINED MATLAB_ADDITIONAL_VERSIONS)
+    # list(APPEND matlab_supported_versions MATLAB_ADDITIONAL_VERSIONS)
+  # endif()
+
+
+  # we order from more recent to older
+  if(matlab_supported_versions)
+    list(REMOVE_DUPLICATES matlab_supported_versions)
+    list(SORT matlab_supported_versions)
+    list(REVERSE matlab_supported_versions)
+  endif()
+
+
+  set(${matlab_versions} ${matlab_supported_versions})
+
+
+endmacro()
+
+
+
+
+#.rst:
+# .. command:: matlab_get_all_valid_matlab_roots_from_registry
+#
+#   Populates the Matlab root with valid versions of Matlab.
+#   The returned matlab_roots is organized in pairs
+#   ``(version_number,matlab_root_path)``.
+#
+#   ::
+#
+#     matlab_get_all_valid_matlab_roots_from_registry(
+#         matlab_versions
+#         matlab_roots)
+#
+#   ``matlab_versions``
+#     the versions of each of the Matlab installations
+#   ``matlab_roots``
+#     the location of each of the Matlab installations
+function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_roots)
+
+  # The matlab_versions comes either from
+  # extract_matlab_versions_from_registry_brute_force or
+  # matlab_extract_all_installed_versions_from_registry.
+
+
+  set(_matlab_roots_list )
+  foreach(_matlab_current_version ${matlab_versions})
+    get_filename_component(
+      current_MATLAB_ROOT
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]"
+      ABSOLUTE)
+
+    if(EXISTS ${current_MATLAB_ROOT})
+      list(APPEND _matlab_roots_list ${_matlab_current_version} ${current_MATLAB_ROOT})
+    endif()
+
+  endforeach(_matlab_current_version)
+  unset(_matlab_current_version)
+  set(${matlab_roots} ${_matlab_roots_list} PARENT_SCOPE)
+  unset(_matlab_roots_list)
+endfunction()
+
+#.rst:
+# .. command:: matlab_get_mex_suffix
+#
+#   Returns the extension of the mex files (the suffixes).
+#   This function should not be called before the appropriate Matlab root has
+#   been found.
+#
+#   ::
+#
+#     matlab_get_mex_suffix(
+#         matlab_root
+#         mex_suffix)
+#
+#   ``matlab_root``
+#     the root of the Matlab installation
+#   ``mex_suffix``
+#     the variable name in which the suffix will be returned.
+function(matlab_get_mex_suffix matlab_root mex_suffix)
+
+  # todo setup the extension properly. Currently I do not know if this is
+  # sufficient for all win32 distributions.
+  # there is also CMAKE_EXECUTABLE_SUFFIX that could be tweaked
+  set(mexext_suffix "")
+  if(WIN32)
+    list(APPEND mexext_suffix ".bat")
+  endif()
+
+  # we first try without suffix, since cmake does not understand a list with
+  # one empty string element
+  find_program(
+    Matlab_MEXEXTENSIONS_PROG
+    NAMES mexext
+    PATHS ${matlab_root}/bin
+    DOC "Matlab MEX extension provider"
+    NO_DEFAULT_PATH
+  )
+
+  foreach(current_mexext_suffix IN LISTS mexext_suffix)
+    if(NOT DEFINED Matlab_MEXEXTENSIONS_PROG OR NOT Matlab_MEXEXTENSIONS_PROG)
+      # this call should populate the cache automatically
+      find_program(
+        Matlab_MEXEXTENSIONS_PROG
+        "mexext${current_mexext_suffix}"
+        PATHS ${matlab_root}/bin
+        DOC "Matlab MEX extension provider"
+        NO_DEFAULT_PATH
+      )
+    endif()
+  endforeach(current_mexext_suffix)
+
+
+  # the program has been found?
+  if((NOT Matlab_MEXEXTENSIONS_PROG) OR (NOT EXISTS ${Matlab_MEXEXTENSIONS_PROG}))
+    if(MATLAB_FIND_DEBUG)
+      message(WARNING "[MATLAB] Cannot found mexext program. Matlab root is ${matlab_root}")
+    endif()
+    unset(Matlab_MEXEXTENSIONS_PROG CACHE)
+    return()
+  endif()
+
+  set(_matlab_mex_extension)
+
+  set(devnull)
+  if(UNIX)
+    set(devnull INPUT_FILE /dev/null)
+  elseif(WIN32)
+    set(devnull INPUT_FILE NUL)
+  endif()
+
+  execute_process(
+    COMMAND ${Matlab_MEXEXTENSIONS_PROG}
+    OUTPUT_VARIABLE _matlab_mex_extension
+    ERROR_VARIABLE _matlab_mex_extension_error
+    ${devnull})
+  string(STRIP ${_matlab_mex_extension} _matlab_mex_extension)
+
+  unset(Matlab_MEXEXTENSIONS_PROG CACHE)
+  set(${mex_suffix} ${_matlab_mex_extension} PARENT_SCOPE)
+endfunction()
+
+
+
+
+#.rst:
+# .. command:: matlab_get_version_from_matlab_run
+#
+#   This function runs Matlab program specified on arguments and extracts its
+#   version.
+#
+#   ::
+#
+#     matlab_get_version_from_matlab_run(
+#         matlab_binary_path
+#         matlab_list_versions)
+#
+#   ``matlab_binary_path``
+#     the location of the `matlab` binary executable
+#   ``matlab_list_versions``
+#     the version extracted from Matlab
+function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_versions)
+
+  set(${matlab_list_versions} "" PARENT_SCOPE)
+
+
+  if(MATLAB_FIND_DEBUG)
+    message(STATUS "[MATLAB] Determining the version of Matlab from ${matlab_binary_program}")
+  endif()
+
+  if(EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
+    if(MATLAB_FIND_DEBUG)
+      message(STATUS "[MATLAB] Removing previous ${_matlab_temporary_folder}/matlabVersionLog.cmaketmp file")
+    endif()
+    file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
+  endif()
+
+
+  # the log file is needed since on windows the command executes in a new
+  # window and it is not possible to get back the answer of Matlab
+  # the -wait command is needed on windows, otherwise the call returns
+  # immediately after the program launches itself.
+  if(WIN32)
+    set(_matlab_additional_commands "-wait")
+  endif()
+
+  set(devnull)
+  if(UNIX)
+    set(devnull INPUT_FILE /dev/null)
+  elseif(WIN32)
+    set(devnull INPUT_FILE NUL)
+  endif()
+
+  # timeout set to 120 seconds, in case it does not start
+  # note as said before OUTPUT_VARIABLE cannot be used in a platform
+  # independent manner however, not setting it would flush the output of Matlab
+  # in the current console (unix variant)
+  execute_process(
+    COMMAND "${matlab_binary_program}" -nosplash -nojvm ${_matlab_additional_commands} -logfile "matlabVersionLog.cmaketmp" -nodesktop -nodisplay -r "version, exit"
+    OUTPUT_VARIABLE _matlab_version_from_cmd_dummy
+    RESULT_VARIABLE _matlab_result_version_call
+    ERROR_VARIABLE _matlab_result_version_call_error
+    TIMEOUT 120
+    WORKING_DIRECTORY "${_matlab_temporary_folder}"
+    ${devnull}
+    )
+
+  if("${_matlab_result_version_call}" MATCHES "timeout")
+    if(MATLAB_FIND_DEBUG)
+      message(WARNING "[MATLAB] Unable to determine the version of Matlab."
+        " Matlab call timed out after 120 seconds.")
+    endif()
+    return()
+  endif()
+
+  if(${_matlab_result_version_call})
+    if(MATLAB_FIND_DEBUG)
+      message(WARNING "[MATLAB] Unable to determine the version of Matlab. Matlab call returned with error ${_matlab_result_version_call}.")
+    endif()
+    return()
+  elseif(NOT EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
+    if(MATLAB_FIND_DEBUG)
+      message(WARNING "[MATLAB] Unable to determine the version of Matlab. The log file does not exist.")
+    endif()
+    return()
+  endif()
+
+  # if successful, read back the log
+  file(READ "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp" _matlab_version_from_cmd)
+  file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
+
+  set(index -1)
+  string(FIND ${_matlab_version_from_cmd} "ans" index)
+  if(index EQUAL -1)
+
+    if(MATLAB_FIND_DEBUG)
+      message(WARNING "[MATLAB] Cannot find the version of Matlab returned by the run.")
+    endif()
+
+  else()
+    set(matlab_list_of_all_versions_tmp)
+
+    string(SUBSTRING ${_matlab_version_from_cmd} ${index} -1 substring_ans)
+    string(
+      REGEX MATCHALL "ans[\r\n\t ]*=[\r\n\t ]*'?([0-9]+(\\.[0-9]+)?)"
+      matlab_versions_regex
+      ${substring_ans})
+    foreach(match IN LISTS matlab_versions_regex)
+      string(
+        REGEX MATCH "ans[\r\n\t ]*=[\r\n\t ]*'?(([0-9]+)(\\.([0-9]+))?)"
+        current_match ${match})
+
+      list(APPEND matlab_list_of_all_versions_tmp ${CMAKE_MATCH_1})
+    endforeach()
+    if(matlab_list_of_all_versions_tmp)
+      list(REMOVE_DUPLICATES matlab_list_of_all_versions_tmp)
+    endif()
+    set(${matlab_list_versions} ${matlab_list_of_all_versions_tmp} PARENT_SCOPE)
+
+  endif()
+
+endfunction()
+
+#.rst:
+# .. command:: matlab_add_unit_test
+#
+#   Adds a Matlab unit test to the test set of cmake/ctest.
+#   This command requires the component ``MAIN_PROGRAM``.
+#   The unit test uses the Matlab unittest framework (default, available
+#   starting Matlab 2013b+) except if the option ``NO_UNITTEST_FRAMEWORK``
+#   is given.
+#
+#   The function expects one Matlab test script file to be given.
+#   In the case ``NO_UNITTEST_FRAMEWORK`` is given, the unittest script file
+#   should contain the script to be run, plus an exit command with the exit
+#   value. This exit value will be passed to the ctest framework (0 success,
+#   non 0 failure). Additional arguments accepted by :command:`add_test` can be
+#   passed through ``TEST_ARGS`` (eg. ``CONFIGURATION <config> ...``).
+#
+#   ::
+#
+#     matlab_add_unit_test(
+#         NAME <name>
+#         UNITTEST_FILE matlab_file_containing_unittest.m
+#         [CUSTOM_TEST_COMMAND matlab_command_to_run_as_test]
+#         [UNITTEST_PRECOMMAND matlab_command_to_run]
+#         [TIMEOUT timeout]
+#         [ADDITIONAL_PATH path1 [path2 ...]]
+#         [MATLAB_ADDITIONAL_STARTUP_OPTIONS option1 [option2 ...]]
+#         [TEST_ARGS arg1 [arg2 ...]]
+#         [NO_UNITTEST_FRAMEWORK]
+#         )
+#
+#   The function arguments are:
+#
+#   ``NAME``
+#     name of the unittest in ctest.
+#   ``UNITTEST_FILE``
+#     the matlab unittest file. Its path will be automatically
+#     added to the Matlab path.
+#   ``CUSTOM_TEST_COMMAND``
+#     Matlab script command to run as the test.
+#     If this is not set, then the following is run:
+#     ``runtests('matlab_file_name'), exit(max([ans(1,:).Failed]))``
+#     where ``matlab_file_name`` is the ``UNITTEST_FILE`` without the extension.
+#   ``UNITTEST_PRECOMMAND``
+#     Matlab script command to be ran before the file
+#     containing the test (eg. GPU device initialisation based on CMake
+#     variables).
+#   ``TIMEOUT``
+#     the test timeout in seconds. Defaults to 180 seconds as the
+#     Matlab unit test may hang.
+#   ``ADDITIONAL_PATH``
+#     a list of paths to add to the Matlab path prior to
+#     running the unit test.
+#   ``MATLAB_ADDITIONAL_STARTUP_OPTIONS``
+#     a list of additional option in order
+#     to run Matlab from the command line.
+#     ``-nosplash -nodesktop -nodisplay`` are always added.
+#   ``TEST_ARGS``
+#     Additional options provided to the add_test command. These
+#     options are added to the default options (eg. "CONFIGURATIONS Release")
+#   ``NO_UNITTEST_FRAMEWORK``
+#     when set, indicates that the test should not
+#     use the unittest framework of Matlab (available for versions >= R2013a).
+#   ``WORKING_DIRECTORY``
+#     This will be the working directory for the test. If specified it will
+#     also be the output directory used for the log file of the test run.
+#     If not specifed the temporary directory ``${CMAKE_BINARY_DIR}/Matlab`` will
+#     be used as the working directory and the log location.
+#
+function(matlab_add_unit_test)
+
+  if(NOT Matlab_MAIN_PROGRAM)
+    message(FATAL_ERROR "[MATLAB] This functionality needs the MAIN_PROGRAM component (not default)")
+  endif()
+
+  set(options NO_UNITTEST_FRAMEWORK)
+  set(oneValueArgs NAME UNITTEST_FILE TIMEOUT WORKING_DIRECTORY
+    UNITTEST_PRECOMMAND CUSTOM_TEST_COMMAND)
+  set(multiValueArgs ADDITIONAL_PATH MATLAB_ADDITIONAL_STARTUP_OPTIONS TEST_ARGS)
+
+  set(prefix _matlab_unittest_prefix)
+  cmake_parse_arguments(PARSE_ARGV 0 ${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" )
+
+  if(NOT ${prefix}_NAME)
+    message(FATAL_ERROR "[MATLAB] The Matlab test name cannot be empty")
+  endif()
+
+  add_test(NAME ${${prefix}_NAME}
+           COMMAND ${CMAKE_COMMAND}
+            "-Dtest_name=${${prefix}_NAME}"
+            "-Dadditional_paths=${${prefix}_ADDITIONAL_PATH}"
+            "-Dtest_timeout=${${prefix}_TIMEOUT}"
+            "-Doutput_directory=${_matlab_temporary_folder}"
+            "-Dworking_directory=${${prefix}_WORKING_DIRECTORY}"
+            "-DMatlab_PROGRAM=${Matlab_MAIN_PROGRAM}"
+            "-Dno_unittest_framework=${${prefix}_NO_UNITTEST_FRAMEWORK}"
+            "-DMatlab_ADDITIONAL_STARTUP_OPTIONS=${${prefix}_MATLAB_ADDITIONAL_STARTUP_OPTIONS}"
+            "-Dunittest_file_to_run=${${prefix}_UNITTEST_FILE}"
+            "-Dcustom_Matlab_test_command=${${prefix}_CUSTOM_TEST_COMMAND}"
+            "-Dcmd_to_run_before_test=${${prefix}_UNITTEST_PRECOMMAND}"
+            -P ${_FindMatlab_SELF_DIR}/MatlabTestsRedirect.cmake
+           ${${prefix}_TEST_ARGS}
+           ${${prefix}_UNPARSED_ARGUMENTS}
+           )
+endfunction()
+
+
+#.rst:
+# .. command:: matlab_add_mex
+#
+#   Adds a Matlab MEX target.
+#   This commands compiles the given sources with the current tool-chain in
+#   order to produce a MEX file. The final name of the produced output may be
+#   specified, as well as additional link libraries, and a documentation entry
+#   for the MEX file. Remaining arguments of the call are passed to the
+#   :command:`add_library` or :command:`add_executable` command.
+#
+#   ::
+#
+#      matlab_add_mex(
+#          NAME <name>
+#          [EXECUTABLE | MODULE | SHARED]
+#          SRC src1 [src2 ...]
+#          [OUTPUT_NAME output_name]
+#          [DOCUMENTATION file.txt]
+#          [LINK_TO target1 target2 ...]
+#          [...]
+#      )
+#
+#   ``NAME``
+#     name of the target.
+#   ``SRC``
+#     list of source files.
+#   ``LINK_TO``
+#     a list of additional link dependencies.  The target links to ``libmex``
+#     by default. If ``Matlab_MX_LIBRARY`` is defined, it also
+#     links to ``libmx``.
+#   ``OUTPUT_NAME``
+#     if given, overrides the default name. The default name is
+#     the name of the target without any prefix and
+#     with ``Matlab_MEX_EXTENSION`` suffix.
+#   ``DOCUMENTATION``
+#     if given, the file ``file.txt`` will be considered as
+#     being the documentation file for the MEX file. This file is copied into
+#     the same folder without any processing, with the same name as the final
+#     mex file, and with extension `.m`. In that case, typing ``help <name>``
+#     in Matlab prints the documentation contained in this file.
+#   ``MODULE`` or ``SHARED`` may be given to specify the type of library to be
+#     created. ``EXECUTABLE`` may be given to create an executable instead of
+#     a library. If no type is given explicitly, the type is ``SHARED``.
+#
+#   The documentation file is not processed and should be in the following
+#   format:
+#
+#   ::
+#
+#     % This is the documentation
+#     function ret = mex_target_output_name(input1)
+#
+function(matlab_add_mex)
+
+  if(NOT WIN32)
+    # we do not need all this on Windows
+    # pthread options
+    if(CMAKE_CXX_COMPILER_LOADED)
+      check_cxx_compiler_flag(-pthread HAS_MINUS_PTHREAD)
+    elseif(CMAKE_C_COMPILER_LOADED)
+      check_c_compiler_flag(-pthread HAS_MINUS_PTHREAD)
+    endif()
+    # we should use try_compile instead, the link flags are discarded from
+    # this compiler_flag function.
+    #check_cxx_compiler_flag(-Wl,--exclude-libs,ALL HAS_SYMBOL_HIDING_CAPABILITY)
+
+  endif()
+
+  set(options EXECUTABLE MODULE SHARED)
+  set(oneValueArgs NAME DOCUMENTATION OUTPUT_NAME)
+  set(multiValueArgs LINK_TO SRC)
+
+  set(prefix _matlab_addmex_prefix)
+  cmake_parse_arguments(${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+  if(NOT ${prefix}_NAME)
+    message(FATAL_ERROR "[MATLAB] The MEX target name cannot be empty")
+  endif()
+
+  if(NOT ${prefix}_OUTPUT_NAME)
+    set(${prefix}_OUTPUT_NAME ${${prefix}_NAME})
+  endif()
+
+  if(${prefix}_EXECUTABLE)
+    add_executable(${${prefix}_NAME}
+      ${${prefix}_SRC}
+      ${${prefix}_DOCUMENTATION}
+      ${${prefix}_UNPARSED_ARGUMENTS})
+  else()
+    if(${prefix}_MODULE)
+      set(type MODULE)
+    else()
+      set(type SHARED)
+    endif()
+
+    add_library(${${prefix}_NAME}
+      ${type}
+      ${${prefix}_SRC}
+      ${${prefix}_DOCUMENTATION}
+      ${${prefix}_UNPARSED_ARGUMENTS})
+  endif()
+
+  target_include_directories(${${prefix}_NAME} PRIVATE ${Matlab_INCLUDE_DIRS})
+
+  if(DEFINED Matlab_MX_LIBRARY)
+    target_link_libraries(${${prefix}_NAME} ${Matlab_MX_LIBRARY})
+  endif()
+
+  target_link_libraries(${${prefix}_NAME} ${Matlab_MEX_LIBRARY} ${${prefix}_LINK_TO})
+  set_target_properties(${${prefix}_NAME}
+      PROPERTIES
+        PREFIX ""
+        OUTPUT_NAME ${${prefix}_OUTPUT_NAME}
+        SUFFIX ".${Matlab_MEX_EXTENSION}")
+
+
+  # documentation
+  if(NOT ${${prefix}_DOCUMENTATION} STREQUAL "")
+    get_target_property(output_name ${${prefix}_NAME} OUTPUT_NAME)
+    add_custom_command(
+      TARGET ${${prefix}_NAME}
+      PRE_BUILD
+      COMMAND ${CMAKE_COMMAND} -E copy_if_different ${${prefix}_DOCUMENTATION} $<TARGET_FILE_DIR:${${prefix}_NAME}>/${output_name}.m
+      COMMENT "Copy ${${prefix}_NAME} documentation file into the output folder"
+    )
+  endif() # documentation
+
+  # entry point in the mex file + taking care of visibility and symbol clashes.
+  if(WIN32)
+    set_target_properties(${${prefix}_NAME}
+      PROPERTIES
+        DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)")
+  else()
+
+    if(HAS_MINUS_PTHREAD AND NOT APPLE)
+      # Apparently, compiling with -pthread generated the proper link flags
+      # and some defines at compilation
+      target_compile_options(${${prefix}_NAME} PRIVATE "-pthread")
+    endif()
+
+
+    # if we do not do that, the symbols linked from eg. boost remain weak and
+    # then clash with the ones defined in the matlab process. So by default
+    # the symbols are hidden.
+    # This also means that for shared libraries (like MEX), the entry point
+    # should be explicitly declared with default visibility, otherwise Matlab
+    # cannot find the entry point.
+    # Note that this is particularly meaningful if the MEX wrapper itself
+    # contains symbols that are clashing with Matlab (that are compiled in the
+    # MEX file). In order to propagate the visibility options to the libraries
+    # to which the MEX file is linked against, the -Wl,--exclude-libs,ALL
+    # option should also be specified.
+
+    set_target_properties(${${prefix}_NAME}
+      PROPERTIES
+        CXX_VISIBILITY_PRESET "hidden"
+        C_VISIBILITY_PRESET "hidden"
+        VISIBILITY_INLINES_HIDDEN ON
+    )
+
+    #  get_target_property(
+    #    _previous_link_flags
+    #    ${${prefix}_NAME}
+    #    LINK_FLAGS)
+    #  if(NOT _previous_link_flags)
+    #    set(_previous_link_flags)
+    #  endif()
+
+    #  if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+    #    set_target_properties(${${prefix}_NAME}
+    #      PROPERTIES
+    #        LINK_FLAGS "${_previous_link_flags} -Wl,--exclude-libs,ALL"
+    #        # -Wl,--version-script=${_FindMatlab_SELF_DIR}/MatlabLinuxVisibility.map"
+    #    )
+    #  elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+    #    # in this case, all other symbols become hidden.
+    #    set_target_properties(${${prefix}_NAME}
+    #      PROPERTIES
+    #        LINK_FLAGS "${_previous_link_flags} -Wl,-exported_symbol,_mexFunction"
+    #        #-Wl,-exported_symbols_list,${_FindMatlab_SELF_DIR}/MatlabOSXVisilibity.map"
+    #    )
+    #  endif()
+
+
+
+    set_target_properties(${${prefix}_NAME}
+      PROPERTIES
+        DEFINE_SYMBOL "DLL_EXPORT_SYM=__attribute__ ((visibility (\"default\")))"
+    )
+
+
+  endif()
+
+endfunction()
+
+
+# (internal)
+# Used to get the version of matlab, using caching. This basically transforms the
+# output of the root list, with possible unknown version, to a version
+#
+function(_Matlab_get_version_from_root matlab_root matlab_known_version matlab_final_version)
+
+  # if the version is not trivial, we query matlab for that
+  # we keep track of the location of matlab that induced this version
+  #if(NOT DEFINED Matlab_PROG_VERSION_STRING_AUTO_DETECT)
+  #  set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version")
+  #endif()
+
+  if(NOT ${matlab_known_version} STREQUAL "NOTFOUND")
+    # the version is known, we just return it
+    set(${matlab_final_version} ${matlab_known_version} PARENT_SCOPE)
+    set(Matlab_VERSION_STRING_INTERNAL ${matlab_known_version} CACHE INTERNAL "Matlab version (automatically determined)" FORCE)
+    return()
+  endif()
+
+  #
+  set(_matlab_current_program ${Matlab_MAIN_PROGRAM})
+
+  # do we already have a matlab program?
+  if(NOT _matlab_current_program)
+
+    set(_find_matlab_options)
+    if(matlab_root AND EXISTS ${matlab_root})
+      set(_find_matlab_options PATHS ${matlab_root} ${matlab_root}/bin NO_DEFAULT_PATH)
+    endif()
+
+    find_program(
+        _matlab_current_program
+        matlab
+        ${_find_matlab_options}
+        DOC "Matlab main program"
+      )
+  endif()
+
+  if(NOT _matlab_current_program OR NOT EXISTS ${_matlab_current_program})
+    # if not found, clear the dependent variables
+    if(MATLAB_FIND_DEBUG)
+      message(WARNING "[MATLAB] Cannot find the main matlab program under ${matlab_root}")
+    endif()
+    set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE)
+    set(Matlab_VERSION_STRING_INTERNAL "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE)
+    unset(_matlab_current_program)
+    unset(_matlab_current_program CACHE)
+    return()
+  endif()
+
+  # full real path for path comparison
+  get_filename_component(_matlab_main_real_path_tmp "${_matlab_current_program}" REALPATH)
+  unset(_matlab_current_program)
+  unset(_matlab_current_program CACHE)
+
+  # is it the same as the previous one?
+  if(_matlab_main_real_path_tmp STREQUAL Matlab_PROG_VERSION_STRING_AUTO_DETECT)
+    set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE)
+    return()
+  endif()
+
+  # update the location of the program
+  set(Matlab_PROG_VERSION_STRING_AUTO_DETECT ${_matlab_main_real_path_tmp} CACHE INTERNAL "internal matlab location for the discovered version" FORCE)
+
+  set(matlab_list_of_all_versions)
+  matlab_get_version_from_matlab_run("${Matlab_PROG_VERSION_STRING_AUTO_DETECT}" matlab_list_of_all_versions)
+
+  list(LENGTH matlab_list_of_all_versions list_of_all_versions_length)
+  if(${list_of_all_versions_length} GREATER 0)
+    list(GET matlab_list_of_all_versions 0 _matlab_version_tmp)
+  else()
+    set(_matlab_version_tmp "unknown")
+  endif()
+
+  # set the version into the cache
+  set(Matlab_VERSION_STRING_INTERNAL ${_matlab_version_tmp} CACHE INTERNAL "Matlab version (automatically determined)" FORCE)
+
+  # warning, just in case several versions found (should not happen)
+  if((${list_of_all_versions_length} GREATER 1) AND MATLAB_FIND_DEBUG)
+    message(WARNING "[MATLAB] Found several versions, taking the first one (versions found ${matlab_list_of_all_versions})")
+  endif()
+
+  # return the updated value
+  set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE)
+
+endfunction()
+
+
+
+
+
+
+
+# ###################################
+# Exploring the possible Matlab_ROOTS
+
+# this variable will get all Matlab installations found in the current system.
+set(_matlab_possible_roots)
+
+
+
+if(Matlab_ROOT_DIR)
+  # if the user specifies a possible root, we keep this one
+
+  if(NOT EXISTS ${Matlab_ROOT_DIR})
+    # if Matlab_ROOT_DIR specified but erroneous
+    if(MATLAB_FIND_DEBUG)
+      message(WARNING "[MATLAB] the specified path for Matlab_ROOT_DIR does not exist (${Matlab_ROOT_DIR})")
+    endif()
+  else()
+    # NOTFOUND indicates the code below to search for the version automatically
+    if("${Matlab_VERSION_STRING_INTERNAL}" STREQUAL "")
+      list(APPEND _matlab_possible_roots "NOTFOUND" ${Matlab_ROOT_DIR}) # empty version
+    else()
+      list(APPEND _matlab_possible_roots ${Matlab_VERSION_STRING_INTERNAL} ${Matlab_ROOT_DIR}) # cached version
+    endif()
+  endif()
+
+
+else()
+
+  # if the user does not specify the possible installation root, we look for
+  # one installation using the appropriate heuristics
+
+  if(WIN32)
+
+    # On WIN32, we look for Matlab installation in the registry
+    # if unsuccessful, we look for all known revision and filter the existing
+    # ones.
+
+    # testing if we are able to extract the needed information from the registry
+    set(_matlab_versions_from_registry)
+
+    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+      set(_matlab_win64 ON)
+    else()
+      set(_matlab_win64 OFF)
+    endif()
+
+    matlab_extract_all_installed_versions_from_registry(_matlab_win64 _matlab_versions_from_registry)
+
+    # the returned list is empty, doing the search on all known versions
+    if(NOT _matlab_versions_from_registry)
+
+      if(MATLAB_FIND_DEBUG)
+        message(STATUS "[MATLAB] Search for Matlab from the registry unsuccessful, testing all supported versions")
+      endif()
+
+      extract_matlab_versions_from_registry_brute_force(_matlab_versions_from_registry)
+    endif()
+
+    # filtering the results with the registry keys
+    matlab_get_all_valid_matlab_roots_from_registry("${_matlab_versions_from_registry}" _matlab_possible_roots)
+    unset(_matlab_versions_from_registry)
+
+  elseif(APPLE)
+
+    # on mac, we look for the /Application paths
+    # this corresponds to the behaviour on Windows. On Linux, we do not have
+    # any other guess.
+    matlab_get_supported_releases(_matlab_releases)
+    if(MATLAB_FIND_DEBUG)
+      message(STATUS "[MATLAB] Matlab supported versions ${_matlab_releases}. If more version should be supported "
+                   "the variable MATLAB_ADDITIONAL_VERSIONS can be set according to the documentation")
+    endif()
+
+    foreach(_matlab_current_release IN LISTS _matlab_releases)
+      set(_matlab_full_string "/Applications/MATLAB_${_matlab_current_release}.app")
+      if(EXISTS ${_matlab_full_string})
+        set(_matlab_current_version)
+        matlab_get_version_from_release_name("${_matlab_current_release}" _matlab_current_version)
+        if(MATLAB_FIND_DEBUG)
+          message(STATUS "[MATLAB] Found version ${_matlab_current_release} (${_matlab_current_version}) in ${_matlab_full_string}")
+        endif()
+        list(APPEND _matlab_possible_roots ${_matlab_current_version} ${_matlab_full_string})
+        unset(_matlab_current_version)
+      endif()
+
+      unset(_matlab_full_string)
+    endforeach(_matlab_current_release)
+
+    unset(_matlab_current_release)
+    unset(_matlab_releases)
+
+  endif()
+
+endif()
+
+
+
+list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots)
+if(_numbers_of_matlab_roots EQUAL 0)
+  # if we have not found anything, we fall back on the PATH
+
+
+  # At this point, we have no other choice than trying to find it from PATH.
+  # If set by the user, this wont change
+  find_program(
+    _matlab_main_tmp
+    NAMES matlab)
+
+
+  if(_matlab_main_tmp)
+    # we then populate the list of roots, with empty version
+    if(MATLAB_FIND_DEBUG)
+      message(STATUS "[MATLAB] matlab found from PATH: ${_matlab_main_tmp}")
+    endif()
+
+    # resolve symlinks
+    get_filename_component(_matlab_current_location "${_matlab_main_tmp}" REALPATH)
+
+    # get the directory (the command below has to be run twice)
+    # this will be the matlab root
+    get_filename_component(_matlab_current_location "${_matlab_current_location}" DIRECTORY)
+    get_filename_component(_matlab_current_location "${_matlab_current_location}" DIRECTORY) # Matlab should be in bin
+
+    list(APPEND _matlab_possible_roots "NOTFOUND" ${_matlab_current_location})
+
+    unset(_matlab_current_location)
+
+  endif()
+  unset(_matlab_main_tmp CACHE)
+
+endif()
+
+
+
+
+
+if(MATLAB_FIND_DEBUG)
+  message(STATUS "[MATLAB] Matlab root folders are ${_matlab_possible_roots}")
+endif()
+
+
+
+
+
+# take the first possible Matlab root
+list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots)
+set(Matlab_VERSION_STRING "NOTFOUND")
+if(_numbers_of_matlab_roots GREATER 0)
+  list(GET _matlab_possible_roots 0 Matlab_VERSION_STRING)
+  list(GET _matlab_possible_roots 1 Matlab_ROOT_DIR)
+
+  # adding a warning in case of ambiguity
+  if(_numbers_of_matlab_roots GREATER 2 AND MATLAB_FIND_DEBUG)
+    message(WARNING "[MATLAB] Found several distributions of Matlab. Setting the current version to ${Matlab_VERSION_STRING} (located ${Matlab_ROOT_DIR})."
+                    " If this is not the desired behaviour, provide the -DMatlab_ROOT_DIR=... on the command line")
+  endif()
+endif()
+
+
+# check if the root changed wrt. the previous defined one, if so
+# clear all the cached variables for being able to reconfigure properly
+if(DEFINED Matlab_ROOT_DIR_LAST_CACHED)
+
+  if(NOT Matlab_ROOT_DIR_LAST_CACHED STREQUAL Matlab_ROOT_DIR)
+    set(_Matlab_cached_vars
+        Matlab_INCLUDE_DIRS
+        Matlab_MEX_LIBRARY
+        Matlab_MEX_COMPILER
+        Matlab_MAIN_PROGRAM
+        Matlab_MX_LIBRARY
+        Matlab_ENG_LIBRARY
+        Matlab_MAT_LIBRARY
+        Matlab_MEX_EXTENSION
+        Matlab_SIMULINK_INCLUDE_DIR
+
+        # internal
+        Matlab_MEXEXTENSIONS_PROG
+        Matlab_ROOT_DIR_LAST_CACHED
+        #Matlab_PROG_VERSION_STRING_AUTO_DETECT
+        Matlab_VERSION_STRING_INTERNAL
+        )
+    foreach(_var IN LISTS _Matlab_cached_vars)
+      if(DEFINED ${_var})
+        unset(${_var} CACHE)
+      endif()
+    endforeach()
+  endif()
+endif()
+
+set(Matlab_ROOT_DIR_LAST_CACHED ${Matlab_ROOT_DIR} CACHE INTERNAL "last Matlab root dir location")
+set(Matlab_ROOT_DIR ${Matlab_ROOT_DIR} CACHE PATH "Matlab installation root path" FORCE)
+
+# Fix the version, in case this one is NOTFOUND
+_Matlab_get_version_from_root(
+  "${Matlab_ROOT_DIR}"
+  ${Matlab_VERSION_STRING}
+  Matlab_VERSION_STRING
+)
+
+
+
+
+if(MATLAB_FIND_DEBUG)
+  message(STATUS "[MATLAB] Current version is ${Matlab_VERSION_STRING} located ${Matlab_ROOT_DIR}")
+endif()
+
+
+
+if(Matlab_ROOT_DIR)
+  file(TO_CMAKE_PATH ${Matlab_ROOT_DIR} Matlab_ROOT_DIR)
+endif()
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+  set(_matlab_64Build FALSE)
+else()
+  set(_matlab_64Build TRUE)
+endif()
+
+if(APPLE)
+  set(_matlab_bin_prefix "mac") # i should be for intel
+  set(_matlab_bin_suffix_32bits "i")
+  set(_matlab_bin_suffix_64bits "i64")
+elseif(UNIX)
+  set(_matlab_bin_prefix "gln")
+  set(_matlab_bin_suffix_32bits "x86")
+  set(_matlab_bin_suffix_64bits "xa64")
+else()
+  set(_matlab_bin_prefix "win")
+  set(_matlab_bin_suffix_32bits "32")
+  set(_matlab_bin_suffix_64bits "64")
+endif()
+
+
+
+set(MATLAB_INCLUDE_DIR_TO_LOOK ${Matlab_ROOT_DIR}/extern/include)
+if(_matlab_64Build)
+  set(_matlab_current_suffix ${_matlab_bin_suffix_64bits})
+else()
+  set(_matlab_current_suffix ${_matlab_bin_suffix_32bits})
+endif()
+
+set(Matlab_BINARIES_DIR
+    ${Matlab_ROOT_DIR}/bin/${_matlab_bin_prefix}${_matlab_current_suffix})
+set(Matlab_EXTERN_LIBRARY_DIR
+    ${Matlab_ROOT_DIR}/extern/lib/${_matlab_bin_prefix}${_matlab_current_suffix})
+
+if(WIN32)
+  if(MINGW)
+    set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/mingw64)
+  else()
+    set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/microsoft)
+  endif()
+  set(_matlab_lib_prefix_for_search "lib")
+else()
+  set(_matlab_lib_dir_for_search ${Matlab_BINARIES_DIR})
+  set(_matlab_lib_prefix_for_search "lib")
+endif()
+
+unset(_matlab_64Build)
+
+
+if(NOT DEFINED Matlab_MEX_EXTENSION)
+  set(_matlab_mex_extension "")
+  matlab_get_mex_suffix("${Matlab_ROOT_DIR}" _matlab_mex_extension)
+
+  # This variable goes to the cache.
+  set(Matlab_MEX_EXTENSION ${_matlab_mex_extension} CACHE STRING "Extensions for the mex targets (automatically given by Matlab)")
+  unset(_matlab_mex_extension)
+endif()
+
+
+if(MATLAB_FIND_DEBUG)
+  message(STATUS "[MATLAB] [DEBUG]_matlab_lib_prefix_for_search = ${_matlab_lib_prefix_for_search} | _matlab_lib_dir_for_search = ${_matlab_lib_dir_for_search}")
+endif()
+
+
+
+# internal
+# This small stub around find_library is to prevent any pollution of CMAKE_FIND_LIBRARY_PREFIXES in the global scope.
+# This is the function to be used below instead of the find_library directives.
+function(_Matlab_find_library _matlab_library_prefix)
+  set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} ${_matlab_library_prefix})
+  find_library(${ARGN})
+endfunction()
+
+
+set(_matlab_required_variables)
+
+
+# the MEX library/header are required
+find_path(
+  Matlab_INCLUDE_DIRS
+  mex.h
+  PATHS ${MATLAB_INCLUDE_DIR_TO_LOOK}
+  NO_DEFAULT_PATH
+  )
+list(APPEND _matlab_required_variables Matlab_INCLUDE_DIRS)
+
+_Matlab_find_library(
+  ${_matlab_lib_prefix_for_search}
+  Matlab_MEX_LIBRARY
+  mex
+  PATHS ${_matlab_lib_dir_for_search}
+  NO_DEFAULT_PATH
+)
+
+list(APPEND _matlab_required_variables Matlab_MEX_LIBRARY)
+
+# the MEX extension is required
+list(APPEND _matlab_required_variables Matlab_MEX_EXTENSION)
+
+# the matlab root is required
+list(APPEND _matlab_required_variables Matlab_ROOT_DIR)
+
+# component Mex Compiler
+list(FIND Matlab_FIND_COMPONENTS MEX_COMPILER _matlab_find_mex_compiler)
+if(_matlab_find_mex_compiler GREATER -1)
+  find_program(
+    Matlab_MEX_COMPILER
+    "mex"
+    PATHS ${Matlab_BINARIES_DIR}
+    DOC "Matlab MEX compiler"
+    NO_DEFAULT_PATH
+  )
+  if(Matlab_MEX_COMPILER)
+    set(Matlab_MEX_COMPILER_FOUND TRUE)
+  endif()
+endif()
+unset(_matlab_find_mex_compiler)
+
+# component Matlab program
+list(FIND Matlab_FIND_COMPONENTS MAIN_PROGRAM _matlab_find_matlab_program)
+if(_matlab_find_matlab_program GREATER -1)
+  find_program(
+    Matlab_MAIN_PROGRAM
+    matlab
+    PATHS ${Matlab_ROOT_DIR} ${Matlab_ROOT_DIR}/bin
+    DOC "Matlab main program"
+    NO_DEFAULT_PATH
+  )
+  if(Matlab_MAIN_PROGRAM)
+    set(Matlab_MAIN_PROGRAM_FOUND TRUE)
+  endif()
+endif()
+unset(_matlab_find_matlab_program)
+
+# Component MX library
+list(FIND Matlab_FIND_COMPONENTS MX_LIBRARY _matlab_find_mx)
+if(_matlab_find_mx GREATER -1)
+  _Matlab_find_library(
+    ${_matlab_lib_prefix_for_search}
+    Matlab_MX_LIBRARY
+    mx
+    PATHS ${_matlab_lib_dir_for_search}
+    NO_DEFAULT_PATH
+  )
+  if(Matlab_MX_LIBRARY)
+    set(Matlab_MX_LIBRARY_FOUND TRUE)
+  endif()
+endif()
+unset(_matlab_find_mx)
+
+# Component ENG library
+list(FIND Matlab_FIND_COMPONENTS ENG_LIBRARY _matlab_find_eng)
+if(_matlab_find_eng GREATER -1)
+  _Matlab_find_library(
+    ${_matlab_lib_prefix_for_search}
+    Matlab_ENG_LIBRARY
+    eng
+    PATHS ${_matlab_lib_dir_for_search}
+    NO_DEFAULT_PATH
+  )
+  if(Matlab_ENG_LIBRARY)
+    set(Matlab_ENG_LIBRARY_FOUND TRUE)
+  endif()
+endif()
+unset(_matlab_find_eng)
+
+# Component MAT library
+list(FIND Matlab_FIND_COMPONENTS MAT_LIBRARY _matlab_find_mat)
+if(_matlab_find_mat GREATER -1)
+  _Matlab_find_library(
+    ${_matlab_lib_prefix_for_search}
+    Matlab_MAT_LIBRARY
+    mat
+    PATHS ${_matlab_lib_dir_for_search}
+    NO_DEFAULT_PATH
+  )
+  if(Matlab_MAT_LIBRARY)
+    set(Matlab_MAT_LIBRARY_FOUND TRUE)
+  endif()
+endif()
+unset(_matlab_find_mat)
+
+# Component Simulink
+list(FIND Matlab_FIND_COMPONENTS SIMULINK _matlab_find_simulink)
+if(_matlab_find_simulink GREATER -1)
+  find_path(
+    Matlab_SIMULINK_INCLUDE_DIR
+    simstruc.h
+    PATHS "${Matlab_ROOT_DIR}/simulink/include"
+    NO_DEFAULT_PATH
+    )
+  if(Matlab_SIMULINK_INCLUDE_DIR)
+    set(Matlab_SIMULINK_FOUND TRUE)
+    list(APPEND Matlab_INCLUDE_DIRS "${Matlab_SIMULINK_INCLUDE_DIR}")
+  endif()
+endif()
+unset(_matlab_find_simulink)
+
+unset(_matlab_lib_dir_for_search)
+
+set(Matlab_LIBRARIES ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY} ${Matlab_ENG_LIBRARY} ${Matlab_MAT_LIBRARY})
+
+find_package_handle_standard_args(
+  Matlab
+  FOUND_VAR Matlab_FOUND
+  REQUIRED_VARS ${_matlab_required_variables}
+  VERSION_VAR Matlab_VERSION_STRING
+  HANDLE_COMPONENTS)
+
+unset(_matlab_required_variables)
+unset(_matlab_bin_prefix)
+unset(_matlab_bin_suffix_32bits)
+unset(_matlab_bin_suffix_64bits)
+unset(_matlab_current_suffix)
+unset(_matlab_lib_dir_for_search)
+unset(_matlab_lib_prefix_for_search)
+
+if(Matlab_INCLUDE_DIRS AND Matlab_LIBRARIES)
+  mark_as_advanced(
+    Matlab_MEX_LIBRARY
+    Matlab_MX_LIBRARY
+    Matlab_ENG_LIBRARY
+    Matlab_MAT_LIBRARY
+    Matlab_INCLUDE_DIRS
+    Matlab_FOUND
+    Matlab_MAIN_PROGRAM
+    Matlab_MEXEXTENSIONS_PROG
+    Matlab_MEX_EXTENSION
+  )
+endif()

+ 95 - 50
shared/cmake/libigl.cmake

@@ -1,21 +1,34 @@
 cmake_minimum_required(VERSION 3.1)
 
+# https://github.com/libigl/libigl/issues/751
+# http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20160425/351643.html
+if(APPLE)
+  if(NOT CMAKE_LIBTOOL)
+    find_program(CMAKE_LIBTOOL NAMES libtool)
+  endif()
+  if(CMAKE_LIBTOOL)
+    set(CMAKE_LIBTOOL ${CMAKE_LIBTOOL} CACHE PATH "libtool executable")
+    message(STATUS "Found libtool - ${CMAKE_LIBTOOL}")
+    get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+    foreach(lang ${languages})
+      # Added -c 
+      set(CMAKE_${lang}_CREATE_STATIC_LIBRARY
+        "${CMAKE_LIBTOOL} -c -static -o <TARGET> <LINK_FLAGS> <OBJECTS> ")
+    endforeach()
+  endif()
+endif()
+
 ### Find packages to populate default options ###
 #
 # COMPONENTS should match subsequent calls
-find_package(CGAL COMPONENTS Core) # --> CGAL_FOUND
-find_package(Boost 1.48 COMPONENTS thread system) # --> BOOST_FOUND
-if(CGAL_FOUND AND BOOST_FOUND)
-  set(CGAL_AND_BOOST_FOUND TRUE)
-endif()
 find_package(Matlab COMPONENTS MEX_COMPILER MX_LIBRARY ENG_LIBRARY) # --> Matlab_FOUND
 find_package(MOSEK) # --> MOSEK_FOUND
 find_package(OpenGL) # --> OPENGL_FOUND
 
 ### Available options ###
-option(LIBIGL_USE_STATIC_LIBRARY     "Use libigl as static library" OFF)
+option(LIBIGL_USE_STATIC_LIBRARY     "Use libigl as static library" ON)
 option(LIBIGL_WITH_ANTTWEAKBAR       "Use AntTweakBar"    OFF)
-option(LIBIGL_WITH_CGAL              "Use CGAL"           "${CGAL_AND_BOOST_FOUND}")
+option(LIBIGL_WITH_CGAL              "Use CGAL"           ON)
 option(LIBIGL_WITH_COMISO            "Use CoMiso"         ON)
 option(LIBIGL_WITH_CORK              "Use Cork"           OFF)
 option(LIBIGL_WITH_EMBREE            "Use Embree"         OFF)
@@ -68,9 +81,6 @@ target_compile_features(igl_common INTERFACE ${CXX11_FEATURES})
 if(MSVC)
   # Enable parallel compilation for Visual Studio
   target_compile_options(igl_common INTERFACE /MP /bigobj)
-  if(LIBIGL_WITH_CGAL)
-    target_compile_options(igl_common INTERFACE "/MD$<$<CONFIG:Debug>:d>")
-  endif()
 endif()
 
 if(BUILD_SHARED_LIBS)
@@ -92,30 +102,67 @@ target_link_libraries(igl_common INTERFACE ${CMAKE_THREAD_LIBS_INIT})
 
 ################################################################################
 
+include(DownloadProject)
+
+# Shortcut function
+function(igl_download_project name)
+  download_project(
+    PROJ         ${name}
+    SOURCE_DIR   ${LIBIGL_EXTERNAL}/${name}
+    DOWNLOAD_DIR ${LIBIGL_EXTERNAL}/.cache/${name}
+    ${ARGN}
+  )
+endfunction()
+
+################################################################################
+
+## CGAL dependencies on Windows: GMP & MPFR
+function(igl_download_cgal_deps)
+  if(WIN32)
+    igl_download_project(gmp
+        URL     https://cgal.geometryfactory.com/CGAL/precompiled_libs/auxiliary/x64/GMP/5.0.1/gmp-all-CGAL-3.9.zip
+        URL_MD5 508c1292319c832609329116a8234c9f
+    )
+    igl_download_project(mpfr
+        URL https://cgal.geometryfactory.com/CGAL/precompiled_libs/auxiliary/x64/MPFR/3.0.0/mpfr-all-CGAL-3.9.zip
+        URL_MD5 48840454eef0ff18730050c05028734b
+    )
+    set(ENV{GMP_DIR} "${LIBIGL_EXTERNAL}/gmp")
+    set(ENV{MPFR_DIR} "${LIBIGL_EXTERNAL}/mpfr")
+  endif()
+endfunction()
+
+################################################################################
+
 function(compile_igl_module module_dir)
   string(REPLACE "/" "_" module_name "${module_dir}")
+  if(module_name STREQUAL "core")
+    set(module_libname "igl")
+  else()
+    set(module_libname "igl_${module_name}")
+  endif()
   if(LIBIGL_USE_STATIC_LIBRARY)
     file(GLOB SOURCES_IGL_${module_name}
       "${LIBIGL_SOURCE_DIR}/igl/${module_dir}/*.cpp"
       "${LIBIGL_SOURCE_DIR}/igl/copyleft/${module_dir}/*.cpp")
-    add_library(igl_${module_name} STATIC ${SOURCES_IGL_${module_name}} ${ARGN})
+    add_library(${module_libname} STATIC ${SOURCES_IGL_${module_name}} ${ARGN})
     if(MSVC)
-      target_compile_options(igl_${module_name} PRIVATE /w) # disable all warnings (not ideal but...)
+      target_compile_options(${module_libname} PRIVATE /w) # disable all warnings (not ideal but...)
     else()
-      #target_compile_options(igl_${module_name} PRIVATE -w) # disable all warnings (not ideal but...)
+      #target_compile_options(${module_libname} PRIVATE -w) # disable all warnings (not ideal but...)
     endif()
   else()
-    add_library(igl_${module_name} INTERFACE)
+    add_library(${module_libname} INTERFACE)
   endif()
 
-  target_link_libraries(igl_${module_name} ${IGL_SCOPE} igl_common)
+  target_link_libraries(${module_libname} ${IGL_SCOPE} igl_common)
   if(NOT module_name STREQUAL "core")
-    target_link_libraries(igl_${module_name} ${IGL_SCOPE} igl_core)
+    target_link_libraries(${module_libname} ${IGL_SCOPE} igl)
   endif()
 
   # Alias target because it looks nicer
-  message(STATUS "Creating target: igl::${module_name}")
-  add_library(igl::${module_name} ALIAS igl_${module_name})
+  message(STATUS "Creating target: igl::${module_name} (${module_libname})")
+  add_library(igl::${module_name} ALIAS ${module_libname})
 endfunction()
 
 ################################################################################
@@ -138,26 +185,29 @@ if(LIBIGL_WITH_ANTTWEAKBAR)
   endif()
   compile_igl_module("anttweakbar")
   target_link_libraries(igl_anttweakbar ${IGL_SCOPE} AntTweakBar)
+  target_include_directories(igl_anttweakbar ${IGL_SCOPE} "${ANTTWEAKBAR_DIR}/include")
 endif()
 
 ################################################################################
-### Compile the cgal parts ###
+### Compile the CGAL part ###
 if(LIBIGL_WITH_CGAL)
+  # Try to find the CGAL library
   # CGAL Core is needed for
   # `Exact_predicates_exact_constructions_kernel_with_sqrt`
-  if(EXISTS ${LIBIGL_EXTERNAL}/boost)
-    set(BOOST_ROOT "${LIBIGL_EXTERNAL}/boost")
+  if(NOT TARGET CGAL::CGAL)
+    set(CGAL_DIR "${LIBIGL_EXTERNAL}/cgal")
+    igl_download_cgal_deps()
+    if(EXISTS ${LIBIGL_EXTERNAL}/boost)
+      set(BOOST_ROOT "${LIBIGL_EXTERNAL}/boost")
+    endif()
+    set(CGAL_Boost_USE_STATIC_LIBS ON CACHE BOOL "" FORCE)
+    find_package(CGAL CONFIG COMPONENTS Core PATHS ${CGAL_DIR} NO_DEFAULT_PATH)
   endif()
-  find_package(CGAL COMPONENTS Core)
-  if(CGAL_FOUND)
+
+  # If CGAL has been found, then build the libigl module
+  if(TARGET CGAL::CGAL AND TARGET CGAL::CGAL_Core)
     compile_igl_module("cgal")
-    if(WIN32)
-      set(Boost_USE_STATIC_LIBS ON) # Favor static Boost libs on Windows
-    endif()
-    target_include_directories(igl_cgal ${IGL_SCOPE} "${GMP_INCLUDE_DIR}" "${MPFR_INCLUDE_DIR}")
-    find_package(Boost 1.48 REQUIRED thread system)
-    target_include_directories(igl_cgal ${IGL_SCOPE} ${CGAL_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
-    target_link_libraries(igl_cgal ${IGL_SCOPE} CGAL::CGAL CGAL::CGAL_Core ${Boost_LIBRARIES})
+    target_link_libraries(igl_cgal ${IGL_SCOPE} CGAL::CGAL CGAL::CGAL_Core)
   else()
     set(LIBIGL_WITH_CGAL OFF CACHE BOOL "" FORCE)
   endif()
@@ -165,19 +215,15 @@ endif()
 
 # Helper function for `igl_copy_cgal_dll()`
 function(igl_copy_imported_dll src_target dst_target)
-  get_target_property(configurations ${src_target} IMPORTED_CONFIGURATIONS)
-  foreach(config ${configurations})
-    get_target_property(main_lib ${src_target} IMPORTED_LOCATION_${config})
-    get_target_property(other_libs ${src_target} IMPORTED_LINK_INTERFACE_LIBRARIES_${config})
-    set(locations)
-    list(APPEND locations ${main_lib} ${other_libs})
-    foreach(location ${locations})
-      string(REGEX MATCH "^(.*)\\.[^.]*$" dummy ${location})
-      set(location "${CMAKE_MATCH_1}.dll")
-      if(EXISTS "${location}" AND location MATCHES "^.*\\.dll$")
-        add_custom_command(TARGET ${dst_target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${location}" $<TARGET_FILE_DIR:${dst_target}>)
-      endif()
-    endforeach()
+  get_target_property(other_libs ${src_target} INTERFACE_LINK_LIBRARIES)
+  set(locations)
+  list(APPEND locations ${main_lib} ${other_libs})
+  foreach(location ${locations})
+    string(REGEX MATCH "^(.*)\\.[^.]*$" dummy ${location})
+    set(location "${CMAKE_MATCH_1}.dll")
+    if(EXISTS "${location}" AND location MATCHES "^.*\\.dll$")
+      add_custom_command(TARGET ${dst_target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${location}" $<TARGET_FILE_DIR:${dst_target}>)
+    endif()
   endforeach()
 endfunction()
 
@@ -190,7 +236,7 @@ function(igl_copy_cgal_dll target)
 endfunction()
 
 ################################################################################
-# Compile CoMISo
+### Compile the CoMISo part ###
 # NOTE: this cmakefile works only with the
 # comiso available here: https://github.com/libigl/CoMISo
 if(LIBIGL_WITH_COMISO)
@@ -202,7 +248,7 @@ if(LIBIGL_WITH_COMISO)
 endif()
 
 ################################################################################
-### Compile the cork parts ###
+### Compile the cork part ###
 if(LIBIGL_WITH_CORK)
   set(CORK_DIR "${LIBIGL_EXTERNAL}/cork")
   if(NOT TARGET cork)
@@ -213,6 +259,7 @@ if(LIBIGL_WITH_CORK)
   compile_igl_module("cork")
   target_include_directories(igl_cork ${IGL_SCOPE} cork)
   target_include_directories(igl_cork ${IGL_SCOPE} "${CORK_DIR}/src")
+  target_link_libraries(igl_cork ${IGL_SCOPE} cork)
 endif()
 
 ################################################################################
@@ -224,6 +271,7 @@ if(LIBIGL_WITH_EMBREE)
   set(EMBREE_TASKING_SYSTEM "INTERNAL" CACHE BOOL " " FORCE)
   set(EMBREE_TUTORIALS OFF CACHE BOOL " " FORCE)
   set(EMBREE_MAX_ISA NONE CACHE STRINGS " " FORCE)
+  set(BUILD_TESTING OFF CACHE BOOL " " FORCE)
 
   # set(ENABLE_INSTALLER OFF CACHE BOOL " " FORCE)
   if(MSVC)
@@ -285,8 +333,7 @@ if(LIBIGL_WITH_MOSEK)
 endif()
 
 ################################################################################
-### Compile the opengl parts ###
-
+### Compile the opengl part ###
 if(LIBIGL_WITH_OPENGL)
   # OpenGL module
   find_package(OpenGL REQUIRED)
@@ -303,7 +350,6 @@ endif()
 
 ################################################################################
 ### Compile the GLFW part ###
-
 if(LIBIGL_WITH_OPENGL_GLFW)
   if(TARGET igl::opengl)
     # GLFW module
@@ -321,7 +367,6 @@ endif()
 
 ################################################################################
 ### Compile the ImGui part ###
-
 if(LIBIGL_WITH_OPENGL_GLFW_IMGUI)
   if(TARGET igl::opengl_glfw)
     # ImGui module
@@ -378,7 +423,6 @@ if(LIBIGL_WITH_XML)
   set(TINYXML2_DIR "${LIBIGL_EXTERNAL}/tinyxml2")
   if(NOT TARGET tinyxml2)
     add_library(tinyxml2 STATIC ${TINYXML2_DIR}/tinyxml2.cpp ${TINYXML2_DIR}/tinyxml2.h)
-    target_include_directories(tinyxml2 PUBLIC ${TINYXML2_DIR})
     set_target_properties(tinyxml2 PROPERTIES
             COMPILE_DEFINITIONS "TINYXML2_EXPORT"
             VERSION "3.0.0"
@@ -386,4 +430,5 @@ if(LIBIGL_WITH_XML)
   endif()
   compile_igl_module("xml")
   target_link_libraries(igl_xml ${IGL_SCOPE} tinyxml2)
+  target_include_directories(igl_xml ${IGL_SCOPE} ${TINYXML2_DIR})
 endif()

+ 9 - 8
tutorial/206_GeodesicDistance/main.cpp

@@ -3,6 +3,7 @@
 #include <igl/exact_geodesic.h>
 #include <igl/colormap.h>
 #include <igl/unproject_onto_mesh.h>
+#include <igl/PI.h>
 #include <iostream>
 #include "tutorial_shared_path.h"
 
@@ -30,7 +31,7 @@ int main(int argc, char *argv[])
     igl::exact_geodesic(V,F,VS,FS,VT,FT,d);
     const double strip_size = 0.05;
     // The function should be 1 on each integer coordinate
-    d = (d/strip_size*M_PI).array().sin().abs().eval();
+    d = (d/strip_size*igl::PI).array().sin().abs().eval();
     // Compute per-vertex colors
     Eigen::MatrixXd C;
     igl::colormap(igl::COLOR_MAP_TYPE_INFERNO,d,false,C);
@@ -49,13 +50,13 @@ int main(int argc, char *argv[])
     double x = viewer.current_mouse_x;
     double y = viewer.core.viewport(3) - viewer.current_mouse_y;
     if(igl::unproject_onto_mesh(
-      Eigen::Vector2f(x,y), 
-      viewer.core.view * viewer.core.model,
-      viewer.core.proj, 
-      viewer.core.viewport, 
-      V, 
-      F, 
-      fid, 
+      Eigen::Vector2f(x,y),
+      viewer.core.view,
+      viewer.core.proj,
+      viewer.core.viewport,
+      V,
+      F,
+      fid,
       bc))
     {
       int max;

+ 2 - 1
tutorial/504_NRosyDesign/main.cpp

@@ -4,6 +4,7 @@
 #include <igl/readOFF.h>
 #include <igl/copyleft/comiso/nrosy.h>
 #include <igl/opengl/glfw/Viewer.h>
+#include <igl/PI.h>
 
 #include "tutorial_shared_path.h"
 
@@ -44,7 +45,7 @@ void representative_to_nrosy(
 
     for (unsigned j=0; j<N;++j)
     {
-      double anglej = angle + 2*M_PI*double(j)/double(N);
+      double anglej = angle + 2*igl::PI*double(j)/double(N);
       double xj = cos(anglej);
       double yj = sin(anglej);
       Y.row(i*N+j) = xj * B1.row(i) + yj * B2.row(i);

+ 2 - 2
tutorial/505_MIQ/main.cpp

@@ -12,6 +12,7 @@
 #include <igl/copyleft/comiso/miq.h>
 #include <igl/copyleft/comiso/nrosy.h>
 #include <igl/opengl/glfw/Viewer.h>
+#include <igl/PI.h>
 #include <sstream>
 
 #include "tutorial_shared_path.h"
@@ -239,7 +240,6 @@ int main(int argc, char *argv[])
   double iter = 0;
   double stiffness = 5.0;
   bool direct_round = 0;
-  std::string filename = "/Users/daniele/x.dat";
 
   // Compute face barycenters
   igl::barycenter(V, F, B);
@@ -260,7 +260,7 @@ int main(int argc, char *argv[])
     // Find the orthogonal vector
     MatrixXd B1, B2, B3;
     igl::local_basis(V, F, B1, B2, B3);
-    X2 = igl::rotate_vectors(X1, VectorXd::Constant(1, M_PI / 2), B1, B2);
+    X2 = igl::rotate_vectors(X1, VectorXd::Constant(1, igl::PI / 2), B1, B2);
 
     // Always work on the bisectors, it is more general
     igl::compute_frame_field_bisectors(V, F, X1, X2, BIS1, BIS2);

+ 2 - 1
tutorial/506_FrameField/main.cpp

@@ -11,6 +11,7 @@
 #include <igl/copyleft/comiso/miq.h>
 #include <igl/copyleft/comiso/frame_field.h>
 #include <igl/opengl/glfw/Viewer.h>
+#include <igl/PI.h>
 
 #include "tutorial_shared_path.h"
 
@@ -231,7 +232,7 @@ int main(int argc, char *argv[])
   MatrixXd B1,B2,B3;
   igl::local_basis(V_deformed,F,B1,B2,B3);
   X2_deformed =
-    igl::rotate_vectors(X1_deformed, VectorXd::Constant(1,M_PI/2), B1, B2);
+    igl::rotate_vectors(X1_deformed, VectorXd::Constant(1,igl::PI/2), B1, B2);
 
   // Global seamless parametrization
   igl::copyleft::comiso::miq(V_deformed,

+ 2 - 1
tutorial/701_Statistics/main.cpp

@@ -2,6 +2,7 @@
 #include <igl/internal_angles.h>
 #include <igl/is_irregular_vertex.h>
 #include <igl/readOBJ.h>
+#include <igl/PI.h>
 #include <Eigen/Core>
 #include <iostream>
 
@@ -44,7 +45,7 @@ int main(int argc, char *argv[])
   // Compute per face angles, min, max and standard deviation
   MatrixXd angles;
   igl::internal_angles(V,F,angles);
-  angles = 360.0 * (angles/(2*M_PI)); // Convert to degrees
+  angles = 360.0 * (angles/(2*igl::PI)); // Convert to degrees
 
   double angle_avg   = angles.mean();
   double angle_min   = angles.minCoeff();

+ 3 - 2
tutorial/707_SweptVolume/main.cpp

@@ -4,6 +4,7 @@
 #include <igl/copyleft/marching_cubes.h>
 #include <igl/copyleft/swept_volume.h>
 #include <igl/opengl/glfw/Viewer.h>
+#include <igl/PI.h>
 #include <Eigen/Core>
 #include <iostream>
 
@@ -20,8 +21,8 @@ int main(int argc, char * argv[])
   const auto & transform = [](const double t)->Eigen::Affine3d
   {
     Eigen::Affine3d T = Eigen::Affine3d::Identity();
-    T.rotate(Eigen::AngleAxisd(t*2.*M_PI,Eigen::Vector3d(0,1,0)));
-    T.translate(Eigen::Vector3d(0,0.125*cos(2.*M_PI*t),0));
+    T.rotate(Eigen::AngleAxisd(t*2.*igl::PI,Eigen::Vector3d(0,1,0)));
+    T.translate(Eigen::Vector3d(0,0.125*cos(2.*igl::PI*t),0));
     return T;
   };
   // Read in inputs as double precision floating point meshes

+ 2 - 2
tutorial/708_Picking/main.cpp

@@ -16,7 +16,7 @@ int main(int argc, char *argv[])
   // Initialize white
   C = Eigen::MatrixXd::Constant(F.rows(),3,1);
   igl::opengl::glfw::Viewer viewer;
-  viewer.callback_mouse_down = 
+  viewer.callback_mouse_down =
     [&V,&F,&C](igl::opengl::glfw::Viewer& viewer, int, int)->bool
   {
     int fid;
@@ -24,7 +24,7 @@ int main(int argc, char *argv[])
     // Cast a ray in the view direction starting from the mouse position
     double x = viewer.current_mouse_x;
     double y = viewer.core.viewport(3) - viewer.current_mouse_y;
-    if(igl::unproject_onto_mesh(Eigen::Vector2f(x,y), viewer.core.view * viewer.core.model,
+    if(igl::unproject_onto_mesh(Eigen::Vector2f(x,y), viewer.core.view,
       viewer.core.proj, viewer.core.viewport, V, F, fid, bc))
     {
       // paint hit red

+ 2 - 1
tutorial/710_SLIM/main.cpp

@@ -20,6 +20,7 @@
 #include <igl/is_edge_manifold.h>
 #include <igl/doublearea.h>
 #include <igl/cat.h>
+#include <igl/PI.h>
 
 #include <stdlib.h>
 
@@ -372,7 +373,7 @@ void get_cube_corner_constraints(Eigen::MatrixXd& V, Eigen::MatrixXi& F, Eigen::
   b = igl::cat(1,b,edge4);
 
   bc.resize(b.rows(),3);
-  Eigen::Matrix3d m; m = Eigen::AngleAxisd(0.3 * M_PI, Eigen::Vector3d(1./sqrt(2.),1./sqrt(2.),0.)/*Eigen::Vector3d::UnitX()*/);
+  Eigen::Matrix3d m; m = Eigen::AngleAxisd(0.3 * igl::PI, Eigen::Vector3d(1./sqrt(2.),1./sqrt(2.),0.)/*Eigen::Vector3d::UnitX()*/);
   int i = 0;
   for (; i < cube_edge1.size(); i++) {
     Eigen::RowVector3d edge_rot_center(min_x,min_y,(min_z+max_z)/2.);