Browse Source

Merge branch 'master' of https://github.com/libigl/libigl into polygon-laplacian

Alec Jacobson 5 years ago
parent
commit
0ac1d696f8
88 changed files with 3370 additions and 1157 deletions
  1. 3 0
      .github/workflows/continuous.yml
  2. 4 1
      .github/workflows/nightly.yml
  3. 1 1
      cmake/DownloadProject.CMakeLists.cmake.in
  4. 1 0
      cmake/FindMOSEK.cmake
  5. 2 2
      cmake/LibiglDownloadExternal.cmake
  6. 151 0
      cmake/OSXFixDylibReferences.cmake
  7. 3 1
      cmake/libigl.cmake
  8. 4 0
      include/igl/AABB.cpp
  9. 7 3
      include/igl/Hit.h
  10. 12 0
      include/igl/WindingNumberAABB.h
  11. 2 0
      include/igl/average_onto_faces.cpp
  12. 2 0
      include/igl/barycenter.cpp
  13. 2 0
      include/igl/copyleft/cgal/assign.cpp
  14. 2 0
      include/igl/copyleft/cgal/convex_hull.cpp
  15. 2 0
      include/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp
  16. 3 0
      include/igl/copyleft/cgal/point_mesh_squared_distance.cpp
  17. 2 0
      include/igl/copyleft/cgal/polyhedron_to_mesh.cpp
  18. 1 0
      include/igl/copyleft/marching_cubes.h
  19. 0 64
      include/igl/copyleft/offset_surface.cpp
  20. 0 54
      include/igl/copyleft/offset_surface.h
  21. 0 41
      include/igl/copyleft/swept_volume.h
  22. 1 1
      include/igl/copyleft/tetgen/tetrahedralize.h
  23. 86 0
      include/igl/embree/EmbreeDevice.h
  24. 396 0
      include/igl/embree/EmbreeIntersector.cpp
  25. 18 445
      include/igl/embree/EmbreeIntersector.h
  26. 423 0
      include/igl/embree/EmbreeRenderer.cpp
  27. 248 0
      include/igl/embree/EmbreeRenderer.h
  28. 9 0
      include/igl/extension.cpp
  29. 29 0
      include/igl/extension.h
  30. 2 0
      include/igl/harmonic.cpp
  31. 451 0
      include/igl/marching_cubes.cpp
  32. 52 0
      include/igl/marching_cubes.h
  33. 1 1
      include/igl/matlab/prepare_lhs.cpp
  34. 2 0
      include/igl/matlab_format.cpp
  35. 2 0
      include/igl/min_quad_with_fixed.cpp
  36. 1 1
      include/igl/mosek/mosek_guarded.h
  37. 4 0
      include/igl/mosek/mosek_linprog.cpp
  38. 18 17
      include/igl/mosek/mosek_quadprog.cpp
  39. 55 0
      include/igl/offset_surface.cpp
  40. 52 0
      include/igl/offset_surface.h
  41. 208 0
      include/igl/opengl/glfw/imgui/SelectionPlugin.cpp
  42. 64 0
      include/igl/opengl/glfw/imgui/SelectionPlugin.h
  43. 2 0
      include/igl/per_edge_normals.cpp
  44. 2 0
      include/igl/point_simplex_squared_distance.cpp
  45. 1 0
      include/igl/project.cpp
  46. 5 0
      include/igl/project.h
  47. 2 1
      include/igl/readDMAT.cpp
  48. 138 416
      include/igl/readMESH.cpp
  49. 2 1
      include/igl/readPLY.cpp
  50. 2 0
      include/igl/readSTL.cpp
  51. 2 0
      include/igl/read_triangle_mesh.cpp
  52. 2 0
      include/igl/remove_duplicate_vertices.cpp
  53. 100 0
      include/igl/screen_space_selection.cpp
  54. 105 0
      include/igl/screen_space_selection.h
  55. 4 0
      include/igl/sharp_edges.cpp
  56. 2 9
      include/igl/signed_angle.cpp
  57. 2 0
      include/igl/slice.cpp
  58. 1 0
      include/igl/slim.cpp
  59. 4 0
      include/igl/solid_angle.cpp
  60. 5 6
      include/igl/swept_volume.cpp
  61. 39 0
      include/igl/swept_volume.h
  62. 113 0
      include/igl/tetrahedralized_grid.cpp
  63. 67 0
      include/igl/tetrahedralized_grid.h
  64. 0 2
      include/igl/triangle/triangulate.cpp
  65. 4 0
      include/igl/unique_rows.cpp
  66. 1 0
      include/igl/unproject.cpp
  67. 6 0
      include/igl/unproject_onto_mesh.h
  68. 25 0
      include/igl/voxel_grid.cpp
  69. 11 0
      include/igl/voxel_grid.h
  70. 2 0
      include/igl/winding_number.cpp
  71. 7 9
      include/igl/writeDMAT.cpp
  72. 1 1
      include/igl/writePLY.cpp
  73. 6 0
      include/igl/xml/writeDAE.cpp
  74. 5 0
      tests/CMakeLists.txt
  75. 32 30
      tests/include/igl/embree/EmbreeIntersector.cpp
  76. 90 0
      tests/include/igl/readMESH.cpp
  77. 17 5
      tests/include/igl/writePLY.cpp
  78. 5 0
      tutorial/112_Selection/CMakeLists.txt
  79. 66 0
      tutorial/112_Selection/main.cpp
  80. 0 3
      tutorial/403_BoundedBiharmonicWeights/CMakeLists.txt
  81. 0 7
      tutorial/403_BoundedBiharmonicWeights/main.cpp
  82. 5 0
      tutorial/608_RayTrace/CMakeLists.txt
  83. 70 0
      tutorial/608_RayTrace/main.cpp
  84. 3 3
      tutorial/705_MarchingCubes/main.cpp
  85. 2 3
      tutorial/707_SweptVolume/main.cpp
  86. 1 1
      tutorial/714_MarchingTets/CMakeLists.txt
  87. 81 28
      tutorial/714_MarchingTets/main.cpp
  88. 4 0
      tutorial/CMakeLists.txt

+ 3 - 0
.github/workflows/continuous.yml

@@ -141,6 +141,9 @@ jobs:
             -DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.static }} ^
             -DLIBIGL_WITH_CGAL=ON ^
             -DLIBIGL_WITH_COMISO=OFF ^
+            -DCMAKE_JOB_POOLS=pool-linking=1;pool-compilation=2 ^
+            -DCMAKE_JOB_POOL_COMPILE:STRING=pool-compilation ^
+            -DCMAKE_JOB_POOL_LINK:STRING=pool-linking ^
             -B build ^
             -S .
           cmake --build build

+ 4 - 1
.github/workflows/nightly.yml

@@ -178,9 +178,12 @@ jobs:
             -DLIBIGL_BUILD_TUTORIALS=${{ matrix.tutorials }} ^
             -DLIBIGL_WITH_CGAL=ON ^
             -DLIBIGL_WITH_COMISO=OFF ^
+            -DCMAKE_JOB_POOLS=pool-linking=1;pool-compilation=2 ^
+            -DCMAKE_JOB_POOL_COMPILE:STRING=pool-compilation ^
+            -DCMAKE_JOB_POOL_LINK:STRING=pool-linking ^
             -B build ^
             -S .
-          cmake --build build -j 2
+          cmake --build build -j 1
 
       - name: Tests
         run: cd build; ctest --verbose

+ 1 - 1
cmake/DownloadProject.CMakeLists.cmake.in

@@ -1,7 +1,7 @@
 # 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)
+cmake_minimum_required(VERSION 3.1)
 
 project(${DL_ARGS_PROJ}-download NONE)
 

+ 1 - 0
cmake/FindMOSEK.cmake

@@ -12,6 +12,7 @@ set(SEARCH_PATHS
   ${CMAKE_SOURCE_DIR}/mosek/9.2/tools/platform/osx64x86/ 
   /usr/local/mosek/7/tools/platform/osx64x86/
   /usr/local/mosek/8/tools/platform/osx64x86/
+  /usr/local/mosek/9.2/tools/platform/osx64x86/
   /opt/mosek/7/tools/platform/linux64x86/
 )
 

+ 2 - 2
cmake/LibiglDownloadExternal.cmake

@@ -77,7 +77,7 @@ endfunction()
 function(igl_download_embree)
 	igl_download_project(embree
 		GIT_REPOSITORY https://github.com/embree/embree.git
-		GIT_TAG        v3.5.2
+		GIT_TAG        v3.12.1
 		${LIBIGL_BRANCH_OPTIONS}
 	)
 endfunction()
@@ -94,7 +94,7 @@ endfunction()
 function(igl_download_glfw)
 	igl_download_project(glfw
 		GIT_REPOSITORY https://github.com/glfw/glfw.git
-		GIT_TAG        3.3
+		GIT_TAG        3327050ca66ad34426a82c217c2d60ced61526b7
 		${LIBIGL_BRANCH_OPTIONS}
 	)
 endfunction()

+ 151 - 0
cmake/OSXFixDylibReferences.cmake

@@ -0,0 +1,151 @@
+# OS X requires a Mach-O dynamic library to have a baked "install name", that is used by other modules to link to it. Depending
+# on how the library is built, the install name is not always an absolute path, nor necessarily the same as the name of the
+# library file itself. This macro takes as input the name of a target, and a list of libraries that it links to (the output of
+# FIND_PACKAGE or FIND_LIBRARY calls), and generates a set of custom, post-build commands that, for each linked dylib, changes
+# the name the target uses to refer to it with a fully-qualified (absolute) version of the library's own install name. This
+# helps ensure that the target can be used from any location while still being able to locate the linked dynamic libraries.
+#
+# Note that this script does NOT handle the case when a linked library itself refers to another library using a non-absolute
+# name (Boost is a notorious example). To avoid such issues, it is recommended to use a static library instead of a shared one
+# in a non-standard location. Alternatively, set DYLD_LIBRARY_PATH to include these non-standard locations when running the
+# program (not recommended).
+#
+# Author: Siddhartha Chaudhuri, 2009.
+#
+
+# Set the minimum required CMake version
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+
+# See cmake --help-policy CMP0011 for details on this one
+IF(POLICY CMP0011)
+  CMAKE_POLICY(SET CMP0011 NEW)
+ENDIF(POLICY CMP0011)
+
+# See cmake --help-policy CMP0026 for details on this one
+IF(POLICY CMP0026)
+  CMAKE_POLICY(SET CMP0026 NEW)
+ENDIF(POLICY CMP0026)
+
+# See cmake --help-policy CMP0045 for details on this one
+IF(POLICY CMP0045)
+  CMAKE_POLICY(SET CMP0045 NEW)
+ENDIF(POLICY CMP0045)
+
+MACRO(OSX_FIX_DYLIB_REFERENCES target libraries)
+
+  IF(APPLE)
+    SET(OFIN_${target}_RPATHS )
+
+    FOREACH(OFIN_${target}_Library ${libraries})
+      IF(${OFIN_${target}_Library} MATCHES "[.]dylib$"
+         OR ${OFIN_${target}_Library} MATCHES "[.]framework/.+")
+
+        # Resolve symlinks and get absolute location
+        GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolute ${OFIN_${target}_Library} ABSOLUTE)
+
+        # Get the baked install name of the library
+        EXECUTE_PROCESS(COMMAND otool -D ${OFIN_${target}_LibraryAbsolute}
+                        OUTPUT_VARIABLE OFIN_${target}_LibraryInstallNameOutput
+                        OUTPUT_STRIP_TRAILING_WHITESPACE)
+        STRING(REGEX REPLACE "[\r\n]" " " OFIN_${target}_LibraryInstallNameOutput ${OFIN_${target}_LibraryInstallNameOutput})
+        SEPARATE_ARGUMENTS(OFIN_${target}_LibraryInstallNameOutput)
+        LIST(GET OFIN_${target}_LibraryInstallNameOutput 1 OFIN_${target}_LibraryInstallName)
+
+        IF(${OFIN_${target}_LibraryInstallName} MATCHES "^[@]rpath/")
+
+          # Ideally, we want to eliminate the longest common suffix of the install name and the absolute path. Whatever's left
+          # will be the desired rpath. But this is difficult to do (especially if there are naming variations, e.g.
+          # "Versions/Current" vs "Versions/5" is a common culprit). So we'll add various candidate rpaths and hope at least one
+          # is correct.
+
+          # Typically, the rpath to a library within a framework looks like this:
+          # @rpath/A.framework/Versions/5/libFoo.dylib
+          #
+          # Hence, we'll extract for the path unit immediately following the @rpath (in this case A.framework) and then look for
+          # it in the library's actual path. Everything before this location will be put in the rpath.
+          SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryInstallName})
+          SET(OFIN_${target}_RpathFirstChild )
+          WHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath")
+            GET_FILENAME_COMPONENT(OFIN_${target}_RpathFirstChild  ${OFIN_${target}_PathPrefix} NAME)
+            GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix       ${OFIN_${target}_PathPrefix} PATH)
+
+            IF(NOT OFIN_${target}_PathPrefix)  # should never happen but just in case
+              BREAK()
+            ENDIF(NOT OFIN_${target}_PathPrefix)
+
+            IF(OFIN_${target}_PathPrefix STREQUAL "/")  # should never happen but just in case
+              BREAK()
+            ENDIF(OFIN_${target}_PathPrefix STREQUAL "/")
+          ENDWHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath")
+
+          IF(OFIN_${target}_RpathFirstChild)
+            SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryAbsolute})
+            SET(OFIN_${target}_PathUnit )
+            WHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild})
+              GET_FILENAME_COMPONENT(OFIN_${target}_PathUnit    ${OFIN_${target}_PathPrefix} NAME)
+              GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix  ${OFIN_${target}_PathPrefix} PATH)
+
+              IF(NOT OFIN_${target}_PathPrefix)
+                BREAK()
+              ENDIF(NOT OFIN_${target}_PathPrefix)
+
+              IF(OFIN_${target}_PathPrefix STREQUAL "/")
+                BREAK()
+              ENDIF(OFIN_${target}_PathPrefix STREQUAL "/")
+            ENDWHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild})
+
+            IF(OFIN_${target}_PathPrefix)
+              SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_PathPrefix}")
+            ENDIF(OFIN_${target}_PathPrefix)
+          ENDIF(OFIN_${target}_RpathFirstChild)
+
+          # Add the directory containing the library
+          GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolutePath ${OFIN_${target}_LibraryAbsolute} PATH)
+          SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_LibraryAbsolutePath}")
+
+          # Add paths specified as library search prefixes
+          FOREACH(prefix ${CMAKE_PREFIX_PATH})
+            SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}")
+            SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}/lib")
+          ENDFOREACH()
+
+        ELSEIF(NOT ${OFIN_${target}_LibraryInstallName} MATCHES "^[@/]")  # just a relative path
+
+          # Replace the unqualified filename, if it appears, with the absolute location, either by directly changing the path or
+          # by editing the rpath
+
+          # -- handle the case when the actual filename is baked in
+          GET_FILENAME_COMPONENT(OFIN_${target}_LibraryFilename ${OFIN_${target}_LibraryAbsolute} NAME)
+          ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
+                             COMMAND install_name_tool
+                             ARGS -change
+                                  ${OFIN_${target}_LibraryFilename}
+                                  ${OFIN_${target}_LibraryAbsolute}
+                                  $<TARGET_FILE:${target}>)
+
+          # -- handle the case when the install name is baked in
+          ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
+                             COMMAND install_name_tool
+                             ARGS -change
+                                  ${OFIN_${target}_LibraryInstallName}
+                                  ${OFIN_${target}_LibraryAbsolute}
+                                  $<TARGET_FILE:${target}>)
+        ENDIF()
+
+      ENDIF()
+    ENDFOREACH(OFIN_${target}_Library)
+
+    # Add the collected rpaths
+    IF(OFIN_${target}_RPATHS)
+      LIST(REMOVE_DUPLICATES OFIN_${target}_RPATHS)
+
+      FOREACH(rpath ${OFIN_${target}_RPATHS})
+        ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
+                           COMMAND bash
+                           ARGS -c "install_name_tool -add_rpath '${rpath}' '$<TARGET_FILE:${target}>' > /dev/null 2>&1 || true"
+                           VERBATIM)
+      ENDFOREACH()
+    ENDIF()
+  ENDIF()
+
+ENDMACRO(OSX_FIX_DYLIB_REFERENCES)

+ 3 - 1
cmake/libigl.cmake

@@ -301,11 +301,12 @@ if(LIBIGL_WITH_EMBREE)
   if(NOT TARGET embree)
     igl_download_embree()
 
+    # Note: On macOS, building embree as a static lib can only be done with a single ISA target.
+    set(EMBREE_MAX_ISA "DEFAULT" CACHE STRING "Selects highest ISA to support.")
     set(EMBREE_TESTING_INTENSITY 0 CACHE STRING "")
     set(EMBREE_ISPC_SUPPORT OFF CACHE BOOL " ")
     set(EMBREE_TASKING_SYSTEM "INTERNAL" CACHE BOOL " ")
     set(EMBREE_TUTORIALS OFF CACHE BOOL " ")
-    set(EMBREE_MAX_ISA "SSE2" CACHE STRING " ")
     set(EMBREE_STATIC_LIB ON CACHE BOOL " ")
     if(MSVC)
       set(EMBREE_STATIC_RUNTIME ${IGL_STATIC_RUNTIME} CACHE BOOL "Use the static version of the C/C++ runtime library.")
@@ -401,6 +402,7 @@ if(LIBIGL_WITH_OPENGL_GLFW_IMGUI)
     if(NOT TARGET imguizmo)
       igl_download_imguizmo()
       add_library(imguizmo ${LIBIGL_EXTERNAL}/imguizmo/ImGuizmo.cpp ${LIBIGL_EXTERNAL}/imguizmo/ImGuizmo.h)
+      target_compile_features(imguizmo PUBLIC cxx_std_11)
       target_link_libraries(imguizmo PUBLIC imgui)
     endif()
     target_link_libraries(igl_opengl_glfw_imgui ${IGL_SCOPE} igl_opengl_glfw imgui imguizmo)

+ 4 - 0
include/igl/AABB.cpp

@@ -1024,6 +1024,10 @@ namespace igl
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > 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, 3, 1, -1, 3> >&) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > 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;
 template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::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, 2, 1, 1, 2> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) 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;

+ 7 - 3
include/igl/Hit.h

@@ -17,9 +17,13 @@ namespace igl
   struct Hit
   {
     int id; // primitive id
-    int gid; // geometry id
-    float u,v; // barycentric coordinates
-    float t; // distance = direction*t to intersection
+    int gid; // geometry id (not used)
+    // barycentric coordinates so that 
+    //   pos = V.row(F(id,0))*(1-u-v)+V.row(F(id,1))*u+V.row(F(id,2))*v;
+    float u,v; 
+    // parametric distance so that
+    //   pos = origin + t * dir
+    float t; 
   };
 }
 #endif 

+ 12 - 0
include/igl/WindingNumberAABB.h

@@ -374,4 +374,16 @@ inline typename DerivedV::Scalar
   return igl::winding_number(BV,PBF,p);
 }
 
+// This is a bullshit template because AABB annoyingly needs templates for bad
+// combinations of 3D V with DIM=2 AABB
+//
+// _Define_ as a no-op rather than monkeying around with the proper code above
+namespace igl
+{
+  template <> inline igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::WindingNumberAABB(const Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2>> & V, const Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2>> & F){};
+  template <> inline void igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::grow(){};
+  template <> inline void igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::init(){};
+
+}
+
 #endif

+ 2 - 0
include/igl/average_onto_faces.cpp

@@ -22,4 +22,6 @@ IGL_INLINE void igl::average_onto_faces(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::average_onto_faces<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<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 #endif

+ 2 - 0
include/igl/barycenter.cpp

@@ -33,6 +33,8 @@ IGL_INLINE void igl::barycenter(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
 template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
 template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);

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

@@ -49,6 +49,8 @@ igl::copyleft::cgal::assign(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
 template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
 // generated by autoexplicit.sh
 template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);

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

@@ -96,6 +96,8 @@ IGL_INLINE void igl::copyleft::cgal::convex_hull(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template void igl::copyleft::cgal::convex_hull<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::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
 template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::copyleft::cgal::convex_hull<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);

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

@@ -48,6 +48,8 @@ IGL_INLINE void igl::copyleft::cgal::mesh_to_cgal_triangle_list(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Simple_cartesian<double> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > 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> > > >&);
+// generated by autoexplicit.sh
 template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 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> > >&);
 // generated by autoexplicit.sh
 template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<float, -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> > >&);

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

@@ -133,7 +133,10 @@ IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Simple_cartesian<double>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > 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&, 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, 3, 1, -1, 3> >&);
 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> > > >&);
+template void igl::copyleft::cgal::point_mesh_squared_distance_precompute<CGAL::Simple_cartesian<double>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > 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 - 0
include/igl/copyleft/cgal/polyhedron_to_mesh.cpp

@@ -61,9 +61,11 @@ IGL_INLINE void igl::copyleft::cgal::polyhedron_to_mesh(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
 #include <CGAL/Simple_cartesian.h>
 #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
 #include <CGAL/Polyhedron_items_with_id_3.h>
+template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0,-1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0,-1, -1> >&);
 #endif

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

@@ -39,6 +39,7 @@ namespace igl
     //   vertices  #V by 3 list of mesh vertex positions
     //   faces  #F by 3 list of mesh triangle indices
     //
+    // See also: igl::marching_cubes
     template <typename DerivedValues, typename DerivedPoints, typename DerivedVertices, typename DerivedFaces>
     IGL_INLINE void marching_cubes(
         const Eigen::MatrixBase<DerivedValues> &values,

+ 0 - 64
include/igl/copyleft/offset_surface.cpp

@@ -1,64 +0,0 @@
-#include "offset_surface.h"
-#include "marching_cubes.h"
-#include "../voxel_grid.h"
-#include "../signed_distance.h"
-#include "../flood_fill.h"
-#include <cassert>
-
-template <
-  typename DerivedV,
-  typename DerivedF,
-  typename isolevelType,
-  typename DerivedSV,
-  typename DerivedSF,
-  typename DerivedGV,
-  typename Derivedside,
-  typename DerivedS>
-void igl::copyleft::offset_surface(
-  const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedF> & F,
-  const isolevelType isolevel,
-  const typename Derivedside::Scalar s,
-  const SignedDistanceType & signed_distance_type,
-  Eigen::PlainObjectBase<DerivedSV> & SV,
-  Eigen::PlainObjectBase<DerivedSF> & SF,
-  Eigen::PlainObjectBase<DerivedGV> &   GV,
-  Eigen::PlainObjectBase<Derivedside> & side,
-  Eigen::PlainObjectBase<DerivedS> & S)
-{
-  typedef typename DerivedV::Scalar Scalar;
-  typedef typename DerivedF::Scalar Index;
-  {
-    Eigen::AlignedBox<Scalar,3> box;
-    typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
-    assert(V.cols() == 3 && "V must contain positions in 3D");
-    RowVector3S min_ext = V.colwise().minCoeff().array() - isolevel;
-    RowVector3S max_ext = V.colwise().maxCoeff().array() + isolevel;
-    box.extend(min_ext.transpose());
-    box.extend(max_ext.transpose());
-    igl::voxel_grid(box,s,1,GV,side);
-  }
-
-  const Scalar h = 
-    (GV.col(0).maxCoeff()-GV.col(0).minCoeff())/((Scalar)(side(0)-1));
-  const Scalar lower_bound = isolevel-sqrt(3.0)*h;
-  const Scalar upper_bound = isolevel+sqrt(3.0)*h;
-  {
-    Eigen::Matrix<Index,Eigen::Dynamic,1> I;
-    Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> C,N;
-    igl::signed_distance(
-      GV,V,F,signed_distance_type,lower_bound,upper_bound,S,I,C,N);
-  }
-  igl::flood_fill(side,S);
-  
-  DerivedS SS = S.array()-isolevel;
-  igl::copyleft::marching_cubes(SS,GV,side(0),side(1),side(2),SV,SF);
-}
-
-#ifdef IGL_STATIC_LIBRARY
-// Explicit template instantiation
-// generated by autoexplicit.sh
-template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, double, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
-template void igl::copyleft::offset_surface<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, float, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
-template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, 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, 3, 1, 1, 3>, 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&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType 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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
-#endif

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

@@ -1,54 +0,0 @@
-#ifndef IGL_COPYLEFT_OFFSET_SURFACE_H
-#define IGL_COPYLEFT_OFFSET_SURFACE_H
-#include "../igl_inline.h"
-#include "../signed_distance.h"
-#include <Eigen/Core>
-
-namespace igl
-{
-  namespace copyleft
-  {
-    // Compute a triangulated offset surface using matching cubes on a grid of
-    // signed distance values from the input triangle mesh.
-    //
-    // Inputs:
-    //   V  #V by 3 list of mesh vertex positions
-    //   F  #F by 3 list of mesh triangle indices into V
-    //   isolevel  iso level to extract (signed distance: negative inside)
-    //   s  number of grid cells along longest side (controls resolution)
-    //   signed_distance_type  type of signing to use (see
-    //     ../signed_distance.h)
-    // Outputs:
-    //   SV  #SV by 3 list of output surface mesh vertex positions
-    //   SF  #SF by 3 list of output mesh triangle indices into SV
-    //   GV  #GV=side(0)*side(1)*side(2) by 3 list of grid cell centers
-    //   side  list of number of grid cells in x, y, and z directions
-    //   S  #GV by 3 list of signed distance values _near_ `isolevel` ("far"
-    //     from `isolevel` these values are incorrect)
-    //
-    template <
-      typename DerivedV,
-      typename DerivedF,
-      typename isolevelType,
-      typename DerivedSV,
-      typename DerivedSF,
-      typename DerivedGV,
-      typename Derivedside,
-      typename DerivedS>
-    void offset_surface(
-      const Eigen::MatrixBase<DerivedV> & V,
-      const Eigen::MatrixBase<DerivedF> & F,
-      const isolevelType isolevel,
-      const typename Derivedside::Scalar s,
-      const SignedDistanceType & signed_distance_type,
-      Eigen::PlainObjectBase<DerivedSV> & SV,
-      Eigen::PlainObjectBase<DerivedSF> & SF,
-      Eigen::PlainObjectBase<DerivedGV> & GV,
-      Eigen::PlainObjectBase<Derivedside> & side,
-      Eigen::PlainObjectBase<DerivedS> & S);
-  }
-}
-#ifndef IGL_STATIC_LIBRARY
-#  include "offset_surface.cpp"
-#endif 
-#endif 

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

@@ -1,41 +0,0 @@
-#ifndef IGL_COPYLEFT_SWEPT_VOLUME_H
-#define IGL_COPYLEFT_SWEPT_VOLUME_H
-#include "../igl_inline.h"
-#include <Eigen/Core>
-#include <Eigen/Geometry>
-namespace igl
-{
-  namespace copyleft
-  {
-    // Compute the surface of the swept volume of a solid object with surface
-    // (V,F) mesh under going rigid motion.
-    // 
-    // Inputs:
-    //   V  #V by 3 list of mesh positions in reference pose
-    //   F  #F by 3 list of mesh indices into V
-    //   transform  function handle so that transform(t) returns the rigid
-    //     transformation at time t∈[0,1]
-    //   steps  number of time steps: steps=3 --> t∈{0,0.5,1}
-    //   grid_res  number of grid cells on the longest side containing the
-    //     motion (isolevel+1 cells will also be added on each side as padding)
-    //   isolevel  distance level to be contoured as swept volume
-    // Outputs:
-    //   SV  #SV by 3 list of mesh positions of the swept surface
-    //   SF  #SF by 3 list of mesh faces into SV
-    IGL_INLINE void swept_volume(
-      const Eigen::MatrixXd & V,
-      const Eigen::MatrixXi & F,
-      const std::function<Eigen::Affine3d(const double t)> & transform,
-      const size_t steps,
-      const size_t grid_res,
-      const size_t isolevel,
-      Eigen::MatrixXd & SV,
-      Eigen::MatrixXi & SF);
-  }
-}
-
-#ifndef IGL_STATIC_LIBRARY
-#  include "swept_volume.cpp"
-#endif
-
-#endif

+ 1 - 1
include/igl/copyleft/tetgen/tetrahedralize.h

@@ -15,7 +15,7 @@
 #ifndef TETLIBRARY
 #define TETLIBRARY 
 #endif
-#include "tetgen.h" // Defined REAL
+#include <tetgen.h> // Defined REAL
 
 namespace igl
 {

+ 86 - 0
include/igl/embree/EmbreeDevice.h

@@ -0,0 +1,86 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2020 Vladimir Fonov <[email protected]>
+//               2013 Alec Jacobson <[email protected]>
+//               2014 Christian Schüller <[email protected]>
+//
+// 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_EMBREE_EMBREE_DEVICE_H
+#define IGL_EMBREE_EMBREE_DEVICE_H
+#include <embree3/rtcore.h>
+#include <iostream>
+
+namespace igl
+{
+  namespace embree
+  {
+     // keep track of embree device
+     struct EmbreeDevice
+     {
+        RTCDevice embree_device;
+        int       embree_device_cntr;
+
+        static EmbreeDevice & instance()
+        {
+            static EmbreeDevice s;
+            return s;
+        } // instance
+
+        EmbreeDevice(const EmbreeDevice &) = delete;
+        EmbreeDevice & operator = (const EmbreeDevice &) = delete;
+
+        static RTCDevice get_device(const char *config=nullptr)
+        {
+            return instance().get(config);
+        }
+
+        static void release_device(void)
+        {
+            instance().release();
+        }
+
+    private:
+
+        EmbreeDevice():embree_device(nullptr),embree_device_cntr(0) {}
+
+        ~EmbreeDevice() 
+        { 
+            if(embree_device)
+                rtcReleaseDevice(embree_device);
+        }
+
+        RTCDevice get(const char *config=nullptr) 
+        {
+            if(!embree_device) 
+            {
+                embree_device = rtcNewDevice (config);
+                if(rtcGetDeviceError (embree_device) != RTC_ERROR_NONE)
+                    std::cerr << "Embree: An error occurred while initializing embree core!" << std::endl;
+            #ifdef IGL_VERBOSE
+                else
+                    std::cerr << "Embree: core initialized." << std::endl;
+            #endif
+            }
+            ++embree_device_cntr;
+            return embree_device;
+        }
+
+        void release()
+        {
+            if(!--embree_device_cntr) {
+                rtcReleaseDevice (embree_device);
+                embree_device = nullptr;                
+            #ifdef IGL_VERBOSE
+                    std::cerr << "Embree: core released." << std::endl;
+            #endif
+            }
+        }
+     };
+  }
+}
+
+#endif // IGL_EMBREE_EMBREE_DEVICE_H

+ 396 - 0
include/igl/embree/EmbreeIntersector.cpp

@@ -0,0 +1,396 @@
+
+#include "EmbreeIntersector.h"
+
+// Implementation
+#include <igl/EPS.h>
+
+IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector()
+  :
+  //scene(NULL),
+  geomID(0),
+  vertices(NULL),
+  triangles(NULL),
+  initialized(false),
+  device(igl::embree::EmbreeDevice::get_device())
+{
+}
+
+IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector(
+  const EmbreeIntersector &)
+  :// To make -Weffc++ happy
+  //scene(NULL),
+  geomID(0),
+  vertices(NULL),
+  triangles(NULL),
+  initialized(false)
+{
+  assert(false && "Embree: Copying EmbreeIntersector is not allowed");
+}
+
+IGL_INLINE igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
+  const EmbreeIntersector &)
+{
+  assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
+  return *this;
+}
+
+
+IGL_INLINE void igl::embree::EmbreeIntersector::init(
+  const PointMatrixType& V,
+  const FaceMatrixType& F,
+  bool isStatic)
+{
+  std::vector<const PointMatrixType*> Vtemp;
+  std::vector<const FaceMatrixType*> Ftemp;
+  std::vector<int> masks;
+  Vtemp.push_back(&V);
+  Ftemp.push_back(&F);
+  masks.push_back(0xFFFFFFFF);
+  init(Vtemp,Ftemp,masks,isStatic);
+}
+
+IGL_INLINE void igl::embree::EmbreeIntersector::init(
+  const std::vector<const PointMatrixType*>& V,
+  const std::vector<const FaceMatrixType*>& F,
+  const std::vector<int>& masks,
+  bool isStatic)
+{
+
+  if(initialized)
+    deinit();
+
+  using namespace std;
+
+  if(V.size() == 0 || F.size() == 0)
+  {
+    std::cerr << "Embree: No geometry specified!";
+    return;
+  }
+
+  RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
+
+  // create a scene
+  scene = rtcNewScene(device);
+  rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
+  rtcSetSceneBuildQuality(scene, buildQuality);
+
+  for(int g=0;g<(int)V.size();g++)
+  {
+    // create triangle mesh geometry in that scene
+    RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE);
+    rtcSetGeometryBuildQuality(geom_0,buildQuality);
+    rtcSetGeometryTimeStepCount(geom_0,1);
+    geomID = rtcAttachGeometry(scene,geom_0);
+    rtcReleaseGeometry(geom_0);
+
+    // fill vertex buffer
+    vertices = (Vertex*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows());
+    for(int i=0;i<(int)V[g]->rows();i++)
+    {
+      vertices[i].x = (float)V[g]->coeff(i,0);
+      vertices[i].y = (float)V[g]->coeff(i,1);
+      vertices[i].z = (float)V[g]->coeff(i,2);
+    }
+
+
+    // fill triangle buffer
+    triangles = (Triangle*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(int),F[g]->rows());
+    for(int i=0;i<(int)F[g]->rows();i++)
+    {
+      triangles[i].v0 = (int)F[g]->coeff(i,0);
+      triangles[i].v1 = (int)F[g]->coeff(i,1);
+      triangles[i].v2 = (int)F[g]->coeff(i,2);
+    }
+
+
+    rtcSetGeometryMask(geom_0,masks[g]);
+    rtcCommitGeometry(geom_0);
+  }
+
+  rtcCommitScene(scene);
+
+  if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
+      std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
+#ifdef IGL_VERBOSE
+  else
+    std::cerr << "Embree: geometry added." << endl;
+#endif
+
+  initialized = true;
+}
+
+igl::embree::EmbreeIntersector
+::~EmbreeIntersector()
+{
+  if(initialized)
+    deinit();
+  igl::embree::EmbreeDevice::release_device();
+}
+
+void igl::embree::EmbreeIntersector::deinit()
+{
+  if(device && scene)
+  {
+    rtcReleaseScene(scene);
+
+    if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
+    {
+        std::cerr << "Embree: An error occurred while resetting!" << std::endl;
+    }
+#ifdef IGL_VERBOSE
+    else
+    {
+      std::cerr << "Embree: geometry removed." << std::endl;
+    }
+#endif
+  }
+}
+
+IGL_INLINE bool igl::embree::EmbreeIntersector::intersectRay(
+  const Eigen::RowVector3f& origin,
+  const Eigen::RowVector3f& direction,
+  Hit& hit,
+  float tnear,
+  float tfar,
+  int mask) const
+{
+  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
+  ray.ray.flags = 0;
+  createRay(ray, origin,direction,tnear,tfar,mask);
+
+  // shot ray
+  {
+    RTCIntersectContext context;
+    rtcInitIntersectContext(&context);
+    rtcIntersect1(scene,&context,&ray);
+    ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
+    ray.hit.Ng_y = -ray.hit.Ng_y;
+    ray.hit.Ng_z = -ray.hit.Ng_z;
+  }
+#ifdef IGL_VERBOSE
+  if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
+      std::cerr << "Embree: An error occurred while resetting!" << std::endl;
+#endif
+
+  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
+  {
+    hit.id = ray.hit.primID;
+    hit.gid = ray.hit.geomID;
+    hit.u = ray.hit.u;
+    hit.v = ray.hit.v;
+    hit.t = ray.ray.tfar;
+    return true;
+  }
+
+  return false;
+}
+
+IGL_INLINE bool igl::embree::EmbreeIntersector::intersectBeam(
+      const Eigen::RowVector3f& origin,
+      const Eigen::RowVector3f& direction,
+      Hit& hit,
+      float tnear,
+      float tfar,
+      int mask,
+      int geoId,
+      bool closestHit,
+	  unsigned int samples) const
+{
+  bool hasHit = false;
+  Hit bestHit;
+
+  if(closestHit)
+    bestHit.t = std::numeric_limits<float>::max();
+  else
+    bestHit.t = 0;
+
+  if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
+  {
+    bestHit = hit;
+    hasHit = true;
+  }
+
+  // sample points around actual ray (conservative hitcheck)
+  const float eps= 1e-5;
+
+  Eigen::RowVector3f up(0,1,0);
+  if (direction.cross(up).norm() < eps) up = Eigen::RowVector3f(1,0,0);
+  Eigen::RowVector3f offset = direction.cross(up).normalized();
+
+  Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
+
+  for(int r=0;r<(int)samples;r++)
+  {
+    if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) &&
+        ((closestHit && (hit.t < bestHit.t)) ||
+           (!closestHit && (hit.t > bestHit.t)))  &&
+        (hit.gid == geoId || geoId == -1))
+    {
+      bestHit = hit;
+      hasHit = true;
+    }
+    offset = rot*offset.transpose();
+  }
+
+  hit = bestHit;
+  return hasHit;
+}
+
+IGL_INLINE bool
+igl::embree::EmbreeIntersector
+::intersectRay(
+  const Eigen::RowVector3f& origin,
+  const Eigen::RowVector3f& direction,
+  std::vector<Hit > &hits,
+  int& num_rays,
+  float tnear,
+  float tfar,
+  int mask) const
+{
+  using namespace std;
+  num_rays = 0;
+  hits.clear();
+  int last_id0 = -1;
+  double self_hits = 0;
+  // This epsilon is directly correleated to the number of missed hits, smaller
+  // means more accurate and slower
+  //const double eps = DOUBLE_EPS;
+  const double eps = FLOAT_EPS;
+  double min_t = tnear;
+  bool large_hits_warned = false;
+  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
+  ray.ray.flags = 0;
+  createRay(ray,origin,direction,tnear,tfar,mask);
+
+  while(true)
+  {
+    ray.ray.tnear = min_t;
+    ray.ray.tfar = tfar;
+    ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
+    ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
+    ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
+    num_rays++;
+    {
+      RTCIntersectContext context;
+      rtcInitIntersectContext(&context);
+      rtcIntersect1(scene,&context,&ray);
+      ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
+      ray.hit.Ng_y = -ray.hit.Ng_y;
+      ray.hit.Ng_z = -ray.hit.Ng_z;
+    }
+    if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
+    {
+      // Hit self again, progressively advance
+      if(ray.hit.primID == last_id0 || ray.ray.tfar <= min_t)
+      {
+        // push min_t a bit more
+        //double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
+        double t_push = pow(2.0,self_hits)*eps;
+        #ifdef IGL_VERBOSE
+        std::cerr<<"  t_push: "<<t_push<<endl;
+        #endif
+        //o = o+t_push*d;
+        min_t += t_push;
+        self_hits++;
+      }
+      else
+      {
+        Hit hit;
+        hit.id = ray.hit.primID;
+        hit.gid = ray.hit.geomID;
+        hit.u = ray.hit.u;
+        hit.v = ray.hit.v;
+        hit.t = ray.ray.tfar;
+        hits.push_back(hit);
+#ifdef IGL_VERBOSE
+        std::cerr<<"  t: "<<hit.t<<endl;
+#endif
+        // Instead of moving origin, just change min_t. That way calculations
+        // all use exactly same origin values
+        min_t = ray.ray.tfar;
+
+        // reset t_scale
+        self_hits = 0;
+      }
+      last_id0 = ray.hit.primID;
+    }
+    else
+      break; // no more hits
+
+    if(hits.size()>1000 && !large_hits_warned)
+    {
+      std::cout<<"Warning: Large number of hits..."<<endl;
+      std::cout<<"[ ";
+      for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
+      {
+        std::cout<<(hit->id+1)<<" ";
+      }
+
+      std::cout.precision(std::numeric_limits< double >::digits10);
+      std::cout<<"[ ";
+
+      for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
+      {
+        std::cout<<(hit->t)<<endl;;
+      }
+
+      std::cout<<"]"<<endl;
+      large_hits_warned = true;
+
+      return hits.empty();
+    }
+  }
+
+  return hits.empty();
+}
+
+IGL_INLINE bool
+igl::embree::EmbreeIntersector
+::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
+{
+  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
+  ray.ray.flags = 0;
+  createRay(ray,a,ab,0,1.0,mask);
+
+  {
+    RTCIntersectContext context;
+    rtcInitIntersectContext(&context);
+    rtcIntersect1(scene,&context,&ray);
+    ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
+    ray.hit.Ng_y = -ray.hit.Ng_y;
+    ray.hit.Ng_z = -ray.hit.Ng_z;
+  }
+
+  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
+  {
+    hit.id = ray.hit.primID;
+    hit.gid = ray.hit.geomID;
+    hit.u = ray.hit.u;
+    hit.v = ray.hit.v;
+    hit.t = ray.ray.tfar;
+    return true;
+  }
+
+  return false;
+}
+
+IGL_INLINE void
+igl::embree::EmbreeIntersector
+::createRay(RTCRayHit& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
+{
+  ray.ray.org_x = origin[0];
+  ray.ray.org_y = origin[1];
+  ray.ray.org_z = origin[2];
+  ray.ray.dir_x = direction[0];
+  ray.ray.dir_y = direction[1];
+  ray.ray.dir_z = direction[2];
+  ray.ray.tnear = tnear;
+  ray.ray.tfar = tfar;
+  ray.ray.id = RTC_INVALID_GEOMETRY_ID;
+  ray.ray.mask = mask;
+  ray.ray.time = 0.0f;
+
+  ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
+  ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
+  ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
+}

+ 18 - 445
include/igl/embree/EmbreeIntersector.h

@@ -19,38 +19,31 @@
 #include "../Hit.h"
 #include <Eigen/Geometry>
 #include <Eigen/Core>
-#include <Eigen/Geometry>
 
 #include <embree3/rtcore.h>
 #include <embree3/rtcore_ray.h>
 #include <iostream>
 #include <vector>
 
+#include "EmbreeDevice.h"
+
 namespace igl
 {
   namespace embree
   {
     class EmbreeIntersector
     {
-    public:
-      // Initialize embree engine. This will be called on instance `init()`
-      // calls. If already inited then this function does nothing: it is harmless
-      // to call more than once.
-      static inline void global_init();
-    private:
-      // Deinitialize the embree engine.
-      static inline void global_deinit();
     public:
       typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
       typedef Eigen::Matrix<int,Eigen::Dynamic,3> FaceMatrixType;
     public:
-      inline EmbreeIntersector();
+      EmbreeIntersector();
     private:
       // Copying and assignment are not allowed.
-      inline EmbreeIntersector(const EmbreeIntersector & that);
-      inline EmbreeIntersector & operator=(const EmbreeIntersector &);
+      EmbreeIntersector(const EmbreeIntersector & that);
+      EmbreeIntersector & operator=(const EmbreeIntersector &);
     public:
-      virtual inline ~EmbreeIntersector();
+      virtual ~EmbreeIntersector();
 
       // Initialize with a given mesh.
       //
@@ -60,7 +53,7 @@ namespace igl
       //   isStatic  scene is optimized for static geometry
       // Side effects:
       //   The first time this is ever called the embree engine is initialized.
-      inline void init(
+      void init(
         const PointMatrixType& V,
         const FaceMatrixType& F,
         bool isStatic = false);
@@ -74,7 +67,7 @@ namespace igl
       //   isStatic  scene is optimized for static geometry
       // Side effects:
       //   The first time this is ever called the embree engine is initialized.
-      inline void init(
+      void init(
         const std::vector<const PointMatrixType*>& V,
         const std::vector<const FaceMatrixType*>& F,
         const std::vector<int>& masks,
@@ -83,7 +76,7 @@ namespace igl
       // Deinitialize embree datasctructures for current mesh.  Also called on
       // destruction: no need to call if you just want to init() once and
       // destroy.
-      inline void deinit();
+      void deinit();
 
       // Given a ray find the first hit
       //
@@ -96,7 +89,7 @@ namespace igl
       // Output:
       //   hit        information about hit
       // Returns true if and only if there was a hit
-      inline bool intersectRay(
+      bool intersectRay(
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
         Hit& hit,
@@ -119,7 +112,7 @@ namespace igl
       // Output:
       //   hit        information about hit
       // Returns true if and only if there was a hit
-      inline bool intersectBeam(
+      bool intersectBeam(
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
         Hit& hit,
@@ -142,7 +135,7 @@ namespace igl
       //   hit        information about hit
       //   num_rays   number of rays shot (at least one)
       // Returns true if and only if there was a hit
-      inline bool intersectRay(
+      bool intersectRay(
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
         std::vector<Hit > &hits,
@@ -159,7 +152,7 @@ namespace igl
       // Output:
       //   hit  information about hit
       // Returns true if and only if there was a hit
-      inline bool intersectSegment(
+      bool intersectSegment(
         const Eigen::RowVector3f& a,
         const Eigen::RowVector3f& ab,
         Hit &hit,
@@ -176,7 +169,9 @@ namespace igl
       Triangle* triangles;
       bool initialized;
 
-      inline void createRay(
+      RTCDevice device;
+
+      void createRay(
         RTCRayHit& ray,
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
@@ -187,430 +182,8 @@ namespace igl
   }
 }
 
-// Implementation
-#include <igl/EPS.h>
-// This unfortunately cannot be a static field of EmbreeIntersector because it
-// would depend on the template and then we might end up with initializing
-// embree twice. If only there was a way to ask embree if it's already
-// initialized...
-namespace igl
-{
-  namespace embree
-  {
-    // Keeps track of whether the **Global** Embree intersector has been
-    // initialized. This should never been done at the global scope.
-    static RTCDevice g_device = nullptr;
-  }
-}
-
-inline void igl::embree::EmbreeIntersector::global_init()
-{
-  if(!g_device)
-  {
-    g_device = rtcNewDevice (NULL);
-    if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
-      std::cerr << "Embree: An error occurred while initializing embree core!" << std::endl;
-#ifdef IGL_VERBOSE
-    else
-      std::cerr << "Embree: core initialized." << std::endl;
-#endif
-  }
-}
-
-inline void igl::embree::EmbreeIntersector::global_deinit()
-{
-  rtcReleaseDevice (g_device);
-  g_device = nullptr;
-}
-
-inline igl::embree::EmbreeIntersector::EmbreeIntersector()
-  :
-  //scene(NULL),
-  geomID(0),
-  vertices(NULL),
-  triangles(NULL),
-  initialized(false)
-{
-}
-
-inline igl::embree::EmbreeIntersector::EmbreeIntersector(
-  const EmbreeIntersector &)
-  :// To make -Weffc++ happy
-  //scene(NULL),
-  geomID(0),
-  vertices(NULL),
-  triangles(NULL),
-  initialized(false)
-{
-  assert(false && "Embree: Copying EmbreeIntersector is not allowed");
-}
-
-inline igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
-  const EmbreeIntersector &)
-{
-  assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
-  return *this;
-}
-
-
-inline void igl::embree::EmbreeIntersector::init(
-  const PointMatrixType& V,
-  const FaceMatrixType& F,
-  bool isStatic)
-{
-  std::vector<const PointMatrixType*> Vtemp;
-  std::vector<const FaceMatrixType*> Ftemp;
-  std::vector<int> masks;
-  Vtemp.push_back(&V);
-  Ftemp.push_back(&F);
-  masks.push_back(0xFFFFFFFF);
-  init(Vtemp,Ftemp,masks,isStatic);
-}
-
-inline void igl::embree::EmbreeIntersector::init(
-  const std::vector<const PointMatrixType*>& V,
-  const std::vector<const FaceMatrixType*>& F,
-  const std::vector<int>& masks,
-  bool isStatic)
-{
-
-  if(initialized)
-    deinit();
-
-  using namespace std;
-  global_init();
-
-  if(V.size() == 0 || F.size() == 0)
-  {
-    std::cerr << "Embree: No geometry specified!";
-    return;
-  }
-
-  RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
-
-  // create a scene
-  scene = rtcNewScene(g_device);
-  rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
-  rtcSetSceneBuildQuality(scene, buildQuality);
-
-  for(int g=0;g<(int)V.size();g++)
-  {
-    // create triangle mesh geometry in that scene
-    RTCGeometry geom_0 = rtcNewGeometry (g_device, RTC_GEOMETRY_TYPE_TRIANGLE);
-    rtcSetGeometryBuildQuality(geom_0,buildQuality);
-    rtcSetGeometryTimeStepCount(geom_0,1);
-    geomID = rtcAttachGeometry(scene,geom_0);
-    rtcReleaseGeometry(geom_0);
-
-    // fill vertex buffer
-    vertices = (Vertex*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows());
-    for(int i=0;i<(int)V[g]->rows();i++)
-    {
-      vertices[i].x = (float)V[g]->coeff(i,0);
-      vertices[i].y = (float)V[g]->coeff(i,1);
-      vertices[i].z = (float)V[g]->coeff(i,2);
-    }
-    
-
-    // fill triangle buffer
-    triangles = (Triangle*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(int),F[g]->rows());
-    for(int i=0;i<(int)F[g]->rows();i++)
-    {
-      triangles[i].v0 = (int)F[g]->coeff(i,0);
-      triangles[i].v1 = (int)F[g]->coeff(i,1);
-      triangles[i].v2 = (int)F[g]->coeff(i,2);
-    }
-    
-
-    rtcSetGeometryMask(geom_0,masks[g]);
-    rtcCommitGeometry(geom_0);
-  }
-
-  rtcCommitScene(scene);
-
-  if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
-      std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
-#ifdef IGL_VERBOSE
-  else
-    std::cerr << "Embree: geometry added." << endl;
+#ifndef IGL_STATIC_LIBRARY
+#  include "EmbreeIntersector.cpp"
 #endif
 
-  initialized = true;
-}
-
-igl::embree::EmbreeIntersector
-::~EmbreeIntersector()
-{
-  if(initialized)
-    deinit();
-}
-
-void igl::embree::EmbreeIntersector::deinit()
-{
-  if(g_device && scene)
-  {
-    rtcReleaseScene(scene);
-
-    if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
-    {
-        std::cerr << "Embree: An error occurred while resetting!" << std::endl;
-    }
-#ifdef IGL_VERBOSE
-    else
-    {
-      std::cerr << "Embree: geometry removed." << std::endl;
-    }
-#endif
-  }
-}
-
-inline bool igl::embree::EmbreeIntersector::intersectRay(
-  const Eigen::RowVector3f& origin,
-  const Eigen::RowVector3f& direction,
-  Hit& hit,
-  float tnear,
-  float tfar,
-  int mask) const
-{
-  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
-  ray.ray.flags = 0;
-  createRay(ray, origin,direction,tnear,tfar,mask);
-
-  // shot ray
-  {
-    RTCIntersectContext context;
-    rtcInitIntersectContext(&context);
-    rtcIntersect1(scene,&context,&ray);
-    ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
-    ray.hit.Ng_y = -ray.hit.Ng_y;
-    ray.hit.Ng_z = -ray.hit.Ng_z;
-  }
-#ifdef IGL_VERBOSE
-  if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
-      std::cerr << "Embree: An error occurred while resetting!" << std::endl;
-#endif
-
-  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
-  {
-    hit.id = ray.hit.primID;
-    hit.gid = ray.hit.geomID;
-    hit.u = ray.hit.u;
-    hit.v = ray.hit.v;
-    hit.t = ray.ray.tfar;
-    return true;
-  }
-
-  return false;
-}
-
-inline bool igl::embree::EmbreeIntersector::intersectBeam(
-      const Eigen::RowVector3f& origin,
-      const Eigen::RowVector3f& direction,
-      Hit& hit,
-      float tnear,
-      float tfar,
-      int mask,
-      int geoId,
-      bool closestHit,
-	  unsigned int samples) const
-{
-  bool hasHit = false;
-  Hit bestHit;
-
-  if(closestHit)
-    bestHit.t = std::numeric_limits<float>::max();
-  else
-    bestHit.t = 0;
-
-  if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
-  {
-    bestHit = hit;
-    hasHit = true;
-  }
-
-  // sample points around actual ray (conservative hitcheck)
-  const float eps= 1e-5;
-
-  Eigen::RowVector3f up(0,1,0);
-  if (direction.cross(up).norm() < eps) up = Eigen::RowVector3f(1,0,0);
-  Eigen::RowVector3f offset = direction.cross(up).normalized();
-
-  Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
-
-  for(int r=0;r<(int)samples;r++)
-  {
-    if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) && 
-        ((closestHit && (hit.t < bestHit.t)) || 
-           (!closestHit && (hit.t > bestHit.t)))  &&
-        (hit.gid == geoId || geoId == -1))
-    {
-      bestHit = hit;
-      hasHit = true;
-    }
-    offset = rot*offset.transpose();
-  }
-
-  hit = bestHit;
-  return hasHit;
-}
-
-inline bool
-igl::embree::EmbreeIntersector
-::intersectRay(
-  const Eigen::RowVector3f& origin,
-  const Eigen::RowVector3f& direction,
-  std::vector<Hit > &hits,
-  int& num_rays,
-  float tnear,
-  float tfar,
-  int mask) const
-{
-  using namespace std;
-  num_rays = 0;
-  hits.clear();
-  int last_id0 = -1;
-  double self_hits = 0;
-  // This epsilon is directly correleated to the number of missed hits, smaller
-  // means more accurate and slower
-  //const double eps = DOUBLE_EPS;
-  const double eps = FLOAT_EPS;
-  double min_t = tnear;
-  bool large_hits_warned = false;
-  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
-  ray.ray.flags = 0;
-  createRay(ray,origin,direction,tnear,tfar,mask);
-
-  while(true)
-  {
-    ray.ray.tnear = min_t;
-    ray.ray.tfar = tfar;
-    ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
-    ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
-    ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
-    num_rays++;
-    {
-      RTCIntersectContext context;
-      rtcInitIntersectContext(&context);
-      rtcIntersect1(scene,&context,&ray);
-      ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
-      ray.hit.Ng_y = -ray.hit.Ng_y;
-      ray.hit.Ng_z = -ray.hit.Ng_z;
-    }
-    if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
-    {
-      // Hit self again, progressively advance
-      if(ray.hit.primID == last_id0 || ray.ray.tfar <= min_t)
-      {
-        // push min_t a bit more
-        //double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
-        double t_push = pow(2.0,self_hits)*eps;
-        #ifdef IGL_VERBOSE
-        std::cerr<<"  t_push: "<<t_push<<endl;
-        #endif
-        //o = o+t_push*d;
-        min_t += t_push;
-        self_hits++;
-      }
-      else
-      {
-        Hit hit;
-        hit.id = ray.hit.primID;
-        hit.gid = ray.hit.geomID;
-        hit.u = ray.hit.u;
-        hit.v = ray.hit.v;
-        hit.t = ray.ray.tfar;
-        hits.push_back(hit);
-#ifdef IGL_VERBOSE
-        std::cerr<<"  t: "<<hit.t<<endl;
-#endif
-        // Instead of moving origin, just change min_t. That way calculations
-        // all use exactly same origin values
-        min_t = ray.ray.tfar;
-
-        // reset t_scale
-        self_hits = 0;
-      }
-      last_id0 = ray.hit.primID;
-    }
-    else
-      break; // no more hits
-
-    if(hits.size()>1000 && !large_hits_warned)
-    {
-      std::cout<<"Warning: Large number of hits..."<<endl;
-      std::cout<<"[ ";
-      for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
-      {
-        std::cout<<(hit->id+1)<<" ";
-      }
-
-      std::cout.precision(std::numeric_limits< double >::digits10);
-      std::cout<<"[ ";
-
-      for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
-      {
-        std::cout<<(hit->t)<<endl;;
-      }
-
-      std::cout<<"]"<<endl;
-      large_hits_warned = true;
-
-      return hits.empty();
-    }
-  }
-
-  return hits.empty();
-}
-
-inline bool
-igl::embree::EmbreeIntersector
-::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
-{
-  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
-  ray.ray.flags = 0;
-  createRay(ray,a,ab,0,1.0,mask);
-
-  {
-    RTCIntersectContext context;
-    rtcInitIntersectContext(&context);
-    rtcIntersect1(scene,&context,&ray);
-    ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
-    ray.hit.Ng_y = -ray.hit.Ng_y;
-    ray.hit.Ng_z = -ray.hit.Ng_z;
-  }
-
-  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
-  {
-    hit.id = ray.hit.primID;
-    hit.gid = ray.hit.geomID;
-    hit.u = ray.hit.u;
-    hit.v = ray.hit.v;
-    hit.t = ray.ray.tfar;
-    return true;
-  }
-
-  return false;
-}
-
-inline void
-igl::embree::EmbreeIntersector
-::createRay(RTCRayHit& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
-{
-  ray.ray.org_x = origin[0];
-  ray.ray.org_y = origin[1];
-  ray.ray.org_z = origin[2];
-  ray.ray.dir_x = direction[0];
-  ray.ray.dir_y = direction[1];
-  ray.ray.dir_z = direction[2];
-  ray.ray.tnear = tnear;
-  ray.ray.tfar = tfar;
-  ray.ray.id = RTC_INVALID_GEOMETRY_ID;
-  ray.ray.mask = mask;
-  ray.ray.time = 0.0f;
-
-  ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
-  ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
-  ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
-}
-
 #endif //EMBREE_INTERSECTOR_H

+ 423 - 0
include/igl/embree/EmbreeRenderer.cpp

@@ -0,0 +1,423 @@
+#include "EmbreeRenderer.h"
+// Implementation
+
+//IGL viewing parts
+#include "../unproject.h"
+#include "../look_at.h"
+#include "../frustum.h"
+#include "../ortho.h"
+
+// color map
+#include "../jet.h"
+
+#include "../PI.h"
+
+
+IGL_INLINE void igl::embree::EmbreeRenderer::init_view()
+{
+  camera_base_zoom = 1.0f;
+  camera_zoom = 1.0f;
+
+  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;
+  
+  rot_matrix = Eigen::Matrix3f::Identity();
+
+  view = Eigen::Matrix4f::Identity();
+  proj = Eigen::Matrix4f::Identity();
+  norm = Eigen::Matrix4f::Identity();
+
+  orthographic = false;
+  
+
+  uC << 1,0,0;
+}
+
+IGL_INLINE igl::embree::EmbreeRenderer::EmbreeRenderer()
+  :
+  scene(NULL),
+  geomID(0),
+  initialized(false),
+  device(igl::embree::EmbreeDevice::get_device())
+{
+  init_view();
+}
+
+IGL_INLINE igl::embree::EmbreeRenderer::EmbreeRenderer(
+  const EmbreeRenderer &)
+  :// To make -Weffc++ happy
+  scene(NULL),
+  geomID(0),
+  initialized(false)
+{
+  assert(false && "Embree: Copying EmbreeRenderer is not allowed");
+}
+
+IGL_INLINE igl::embree::EmbreeRenderer & igl::embree::EmbreeRenderer::operator=(
+  const EmbreeRenderer &)
+{
+  assert(false && "Embree: Assigning an EmbreeRenderer is not allowed");
+  return *this;
+}
+
+
+IGL_INLINE void igl::embree::EmbreeRenderer::init(
+  const PointMatrixType& V,
+  const FaceMatrixType& F,
+  bool isStatic)
+{
+  std::vector<const PointMatrixType*> Vtemp;
+  std::vector<const FaceMatrixType*> Ftemp;
+  std::vector<int> masks;
+  Vtemp.push_back(&V);
+  Ftemp.push_back(&F);
+  masks.push_back(0xFFFFFFFF);
+  init(Vtemp,Ftemp,masks,isStatic);
+}
+
+IGL_INLINE void igl::embree::EmbreeRenderer::init(
+  const std::vector<const PointMatrixType*>& V,
+  const std::vector<const FaceMatrixType*>&  F,
+  const std::vector<int>& masks,
+  bool isStatic)
+{
+  if(initialized)
+    deinit();
+
+  using namespace std;
+
+  if(V.size() == 0 || F.size() == 0)
+  {
+    std::cerr << "Embree: No geometry specified!";
+    return;
+  }
+  RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
+
+  // create a scene
+  scene = rtcNewScene(device);
+  rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
+  rtcSetSceneBuildQuality(scene, buildQuality);
+
+  for(int g=0;g<(int)V.size();g++)
+  {
+    // create triangle mesh geometry in that scene
+    RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE);
+    rtcSetGeometryBuildQuality(geom_0, buildQuality);
+    rtcSetGeometryTimeStepCount(geom_0,1);
+    geomID = rtcAttachGeometry(scene,geom_0);
+    rtcReleaseGeometry(geom_0);
+
+    // fill vertex buffer, have to be 16 byte wide( sizeof(float)*4 )
+    Eigen::Map<Eigen::Matrix<float,-1,4,Eigen::RowMajor>> vertices(
+        (float*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows()),
+        V[g]->rows(),4
+    );
+    vertices.block(0,0,V[g]->rows(),3) = V[g]->cast<float>();
+
+    // fill triangle buffer
+    Eigen::Map<Eigen::Matrix<unsigned int,-1,3,Eigen::RowMajor>> triangles(
+      (unsigned int*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(unsigned int), F[g]->rows()),
+      F[g]->rows(),3
+    );
+    triangles = F[g]->cast<unsigned int>();
+    //TODO: store vertices and triangles in array for whatever reason?
+
+    rtcSetGeometryMask(geom_0, masks[g]);
+    rtcCommitGeometry(geom_0);
+  }
+
+  rtcCommitScene(scene);
+
+  if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
+      std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
+#ifdef IGL_VERBOSE
+  else
+    std::cerr << "Embree: geometry added." << endl;
+#endif
+
+  initialized = true;
+}
+
+IGL_INLINE igl::embree::EmbreeRenderer::~EmbreeRenderer()
+{
+  if(initialized)
+    deinit();
+  
+  igl::embree::EmbreeDevice::release_device();
+}
+
+IGL_INLINE void igl::embree::EmbreeRenderer::deinit()
+{
+  if(scene)
+  {
+    rtcReleaseScene(scene);
+
+    if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
+    {
+        std::cerr << "Embree: An error occurred while resetting!" << std::endl;
+    }
+#ifdef IGL_VERBOSE
+    else
+    {
+      std::cerr << "Embree: geometry removed." << std::endl;
+    }
+#endif
+  }
+}
+
+IGL_INLINE bool igl::embree::EmbreeRenderer::intersect_ray(
+  const Eigen::RowVector3f& origin,
+  const Eigen::RowVector3f& direction,
+  Hit&  hit,
+  float tnear,
+  float tfar,
+  int mask) const
+{
+  RTCRayHit ray;
+  ray.ray.flags = 0;
+  create_ray(ray, origin,direction,tnear,tfar,mask);
+
+  // shot ray
+  {
+    RTCIntersectContext context;
+    rtcInitIntersectContext(&context);
+    rtcIntersect1(scene, &context, &ray);
+    ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
+    ray.hit.Ng_y = -ray.hit.Ng_y;
+    ray.hit.Ng_z = -ray.hit.Ng_z;
+  }
+#ifdef IGL_VERBOSE
+  if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
+      std::cerr << "Embree: An error occurred while resetting!" << std::endl;
+#endif
+
+  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
+  {
+    hit.id = ray.hit.primID;
+    hit.gid = ray.hit.geomID;
+    hit.u = ray.hit.u;
+    hit.v = ray.hit.v;
+    hit.t = ray.ray.tfar;
+    hit.N = Vec3f(ray.hit.Ng_x, ray.hit.Ng_y, ray.hit.Ng_z);
+    return true;
+  }
+
+  return false;
+}
+
+IGL_INLINE void 
+igl::embree::EmbreeRenderer
+::create_ray(RTCRayHit& ray, const Eigen::RowVector3f& origin, 
+ const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
+{
+  ray.ray.org_x = origin[0];
+  ray.ray.org_y = origin[1];
+  ray.ray.org_z = origin[2];
+  ray.ray.dir_x = direction[0];
+  ray.ray.dir_y = direction[1];
+  ray.ray.dir_z = direction[2];
+  ray.ray.tnear = tnear;
+  ray.ray.tfar = tfar;
+  ray.ray.id = RTC_INVALID_GEOMETRY_ID;
+  ray.ray.mask = mask;
+  ray.ray.time = 0.0f;
+
+  ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
+  ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
+  ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
+}
+
+
+IGL_INLINE void
+igl::embree::EmbreeRenderer
+::set_mesh(const Eigen::Matrix<double,Eigen::Dynamic,3> & MV,
+           const Eigen::Matrix<int,  Eigen::Dynamic,3>  & MF,
+           bool is_static)
+{
+  V = MV.cast<float>();
+  F = MF;
+  this->init(V,F,is_static);
+
+  auto min_point = V.colwise().minCoeff();
+  auto max_point = V.colwise().maxCoeff();
+  auto centroid  = (0.5*(min_point + max_point)).eval();
+
+  camera_base_translation.setConstant(0);
+  camera_base_translation.head(centroid.size()) = -centroid.cast<float>();
+  camera_base_zoom = 2.0 / (max_point-min_point).array().abs().maxCoeff();
+}
+
+IGL_INLINE void
+igl::embree::EmbreeRenderer
+::render_buffer(PixelMatrixType& R, PixelMatrixType&G, PixelMatrixType &B,PixelMatrixType &A)
+{
+  assert(R.rows()==G.rows());assert(R.rows()==B.rows());assert(R.rows()==A.rows());
+  assert(R.cols()==G.cols());assert(R.cols()==B.cols());assert(R.cols()==A.cols());
+
+  Eigen::Vector4f viewport(0,0,R.rows(),R.cols());
+
+  float width  = R.rows();
+  float height = R.cols();
+
+  // update view matrix
+  igl::look_at( camera_eye, camera_center, camera_up, view);
+
+  view = view
+    * (rot_matrix * Eigen::Scaling(camera_zoom * camera_base_zoom)
+    * Eigen::Translation3f(camera_translation + camera_base_translation)).matrix();
+  
+  if (orthographic)
+  {
+    float length = (camera_eye - camera_center).norm();
+    float h = tan(camera_view_angle/360.0 * igl::PI) * (length);
+    igl::ortho(-h*width/height, h*width/height, -h, h, camera_dnear, camera_dfar, proj);
+  } else {
+    float fH = tan(camera_view_angle / 360.0 * igl::PI) * camera_dnear;
+    float fW = fH * (double)width/(double)height;
+    igl::frustum(-fW, fW, -fH, fH, camera_dnear, camera_dfar, proj);
+  }
+
+  // go over all pixels in the "view"
+  for(int x=0;x<(int)width;++x) 
+  {
+    for(int y=0;y<(int)height;++y) 
+    {
+      Vec3f s,d,dir;
+      igl::embree::EmbreeRenderer::Hit hit;
+
+      // look into the screen
+      Vec3f win_s(x,y,0);
+      Vec3f win_d(x,y,1);
+      // Source, destination and direction in world
+      igl::unproject(win_s,this->view,this->proj,viewport,s);
+      igl::unproject(win_d,this->view,this->proj,viewport,d);
+      dir = d-s;
+      dir.normalize();
+
+      auto clamp=[](float x)->unsigned char {return (unsigned char)(x<0?0:x>1.0?255:x*255);};
+
+      if(this->intersect_ray(s,dir,hit))
+      {
+        if ( dir.dot(hit.N) > 0.0f)
+        {
+          // TODO: interpolate normals ?
+          hit.N.normalize();
+          // cos between ray and face normal
+          float face_proj=dir.dot(hit.N);
+
+          Eigen::RowVector3f c;
+
+          if(this->uniform_color)
+          {
+            // same color for the whole mesh
+            c=uC;
+          } else if(this->face_based) {
+            // flat color per face
+            c=this->C.row(hit.id);
+          } else { //use barycentric coordinates to interpolate colour
+              c=this->C.row(F(hit.id,1))*hit.u+
+                this->C.row(F(hit.id,2))*hit.v+
+                this->C.row(F(hit.id,0))*(1.0-hit.u-hit.v);
+          }
+
+          R(x,y) = clamp(face_proj*c(0));
+          G(x,y) = clamp(face_proj*c(1));
+          B(x,y) = clamp(face_proj*c(2));
+        }
+        // give the same alpha to all points with something behind
+        A(x,y)=255; 
+      } else {
+        R(x,y)=0;
+        G(x,y)=0;
+        B(x,y)=0;
+        A(x,y)=0;
+      }
+
+    }
+  }
+}
+
+
+IGL_INLINE void
+igl::embree::EmbreeRenderer
+::set_colors(const Eigen::MatrixXd & C)
+{
+  if(C.rows()==V.rows()) // per vertex color
+  {
+    face_based = false;
+    this->C = C.cast<float>();
+    this->uniform_color=false;
+  } else if (C.rows()==F.rows()) {
+    face_based = true;
+    this->C = C.cast<float>();
+    this->uniform_color=false;
+  } else if (C.rows()==1) {
+    face_based = true;
+    this->uC = C.cast<float>();
+    this->uniform_color=true;
+  }else {
+    // don't know what to do
+    this->uniform_color=true;
+    assert(false); //?
+  }
+}
+
+IGL_INLINE void
+igl::embree::EmbreeRenderer
+::set_data(const Eigen::VectorXd & D, igl::ColorMapType cmap)
+{
+  const double caxis_min = D.minCoeff();
+  const double caxis_max = D.maxCoeff();
+  return set_data(D,caxis_min,caxis_max,cmap);
+}
+
+
+IGL_INLINE void igl::embree::EmbreeRenderer::set_data(
+  const Eigen::VectorXd & D,
+  double caxis_min,
+  double caxis_max,
+  igl::ColorMapType cmap)
+{
+    Eigen::MatrixXd C;
+    igl::colormap(cmap,D,caxis_min,caxis_max,C);
+    set_colors(C);
+}
+
+IGL_INLINE void 
+igl::embree::EmbreeRenderer::set_rot(const Eigen::Matrix3d &r)
+{
+  this->rot_matrix = r.cast<float>();
+}
+
+IGL_INLINE void 
+igl::embree::EmbreeRenderer::set_zoom(double zoom)
+{
+  this->camera_zoom=zoom;
+}
+
+IGL_INLINE void 
+igl::embree::EmbreeRenderer::set_translation(const Eigen::Vector3d &tr)
+{
+  this->camera_translation=tr.cast<float>();
+}
+
+IGL_INLINE void 
+igl::embree::EmbreeRenderer::set_face_based(bool _f)
+{
+  this->face_based=_f;
+}
+
+IGL_INLINE void 
+igl::embree::EmbreeRenderer::set_orthographic(bool o)
+{
+  this->orthographic=o;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+#endif //IGL_STATIC_LIBRARY

+ 248 - 0
include/igl/embree/EmbreeRenderer.h

@@ -0,0 +1,248 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+//
+// Copyright (C) 2020 Vladimir Fonov <[email protected]>
+//               2013 Alec Jacobson <[email protected]>
+//               2014 Christian Schüller <[email protected]>
+//
+// 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_EMBREE_EMBREE_RENDERER_H
+#define IGL_EMBREE_EMBREE_RENDERER_H
+
+#include <igl/colormap.h>
+
+#include <Eigen/Geometry>
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include <embree3/rtcore.h>
+#include <embree3/rtcore_ray.h>
+#include <iostream>
+#include <vector>
+
+#include "EmbreeDevice.h"
+
+
+namespace igl
+{
+  namespace embree
+  {
+    // embree-based mesh renderer
+    class EmbreeRenderer
+    {
+    public:
+      typedef Eigen::RowVector3f Vec3f;
+
+      struct Hit
+      {
+        int id;    // primitive id
+        int gid;   // geometry id
+        float u,v; // barycentric coordinates
+        float t;   // distance = direction*t to intersection
+        Vec3f N;    // element normal
+      };
+
+    public:
+      typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
+      typedef Eigen::Matrix<float,Eigen::Dynamic,3> ColorMatrixType;
+      typedef Eigen::Matrix<int,  Eigen::Dynamic,3> FaceMatrixType;
+
+      typedef Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> PixelMatrixType;
+
+    public:
+      EmbreeRenderer();
+    private:
+      // Copying and assignment are not allowed.
+      EmbreeRenderer(const EmbreeRenderer & that);
+      EmbreeRenderer & operator=(const EmbreeRenderer &);
+    public:
+      virtual ~EmbreeRenderer();
+
+      // Specify mesh, this call reinitializes embree structures
+      // Inputs:
+      //   V  #V x dim matrix of vertex coordinates
+      //   F  #F x simplex_size  matrix of indices of simplex corners into V
+      //   is_static - optimize for static thene (HQ rendering)
+      void set_mesh(const Eigen::Matrix<double,Eigen::Dynamic,3> & V,
+                    const Eigen::Matrix<int,  Eigen::Dynamic,3>  & F,
+                    bool is_static=true);
+      // Specify per-vertex or per-face color
+      // Inputs:
+      //   C  #V x 3 matrix of vertex colors
+      //    or #F x 3 matrix of face colors
+      //    or 1 x 3 matrix of uniform color
+      void set_colors(const Eigen::MatrixXd & C);
+
+
+      // Use min(D) and max(D) to set caxis.
+      void set_data(const Eigen::VectorXd & D,
+                    igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS);
+
+      // Specify per-vertex or per-face scalar field
+      //   that will be converted to color using jet color map
+      // Inputs:
+      //   caxis_min  caxis minimum bound
+      //   caxis_max  caxis maximum bound
+      //   D  #V by 1 list of scalar values
+      //   cmap colormap type
+      //   num_steps number of intervals to discretize the colormap
+      void set_data(
+        const Eigen::VectorXd & D,
+        double caxis_min,
+        double caxis_max,
+        igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS);
+
+      // Specify mesh rotation
+      // Inputs:
+      //   r  3 x 3 rotaton matrix
+      void set_rot(const Eigen::Matrix3d &r);
+
+      // Specify mesh magnification
+      // Inputs:
+      //   z  magnification ratio
+      void set_zoom(double z);
+
+      // Specify mesh translation
+      // Inputs:
+      //   tr  translation vector
+      void set_translation(const Eigen::Vector3d &tr);
+
+      // Specify that color is face based
+      // Inputs:
+      //    f - face or vertex colours
+      void set_face_based(bool f);
+
+      // Use orthographic projection
+      // Inputs:
+      //    f - orthographic or perspective projection
+      void set_orthographic(bool f );
+
+      // render full buffer
+      // Outputs:
+      //   all outputs should have the same size (size of the output picture)
+      //     area outside of the visible object will have zero alpha component (transparant)
+      //   R - red channel
+      //   G - green channel
+      //   B - blue channel
+      //   A - alpha channel
+      void render_buffer(PixelMatrixType &R,
+                         PixelMatrixType &G,
+                         PixelMatrixType &B,
+                         PixelMatrixType &A);
+
+      // Given a ray find the first hit
+      //
+      // Inputs:
+      //   origin     3d origin point of ray
+      //   direction  3d (not necessarily normalized) direction vector of ray
+      //   tnear      start of ray segment
+      //   tfar       end of ray segment
+      //   mask      a 32 bit mask to identify active geometries.
+      // Output:
+      //   hit        information about hit
+      // Returns true if and only if there was a hit
+      bool intersect_ray(
+        const Eigen::RowVector3f& origin,
+        const Eigen::RowVector3f& direction,
+        Hit& hit,
+        float tnear = 0,
+        float tfar = std::numeric_limits<float>::infinity(),
+        int mask = 0xFFFFFFFF) const;
+
+    private:
+
+      // Initialize with a given mesh.
+      //
+      // Inputs:
+      //   V  #V by 3 list of vertex positions
+      //   F  #F by 3 list of Oriented triangles
+      //   isStatic  scene is optimized for static geometry
+      // Side effects:
+      //   The first time this is ever called the embree engine is initialized.
+      void init(
+        const PointMatrixType& V,
+        const FaceMatrixType& F,
+        bool isStatic = false);
+
+      // Initialize embree with a given mesh.
+      //
+      // Inputs:
+      //   V  vector of #V by 3 list of vertex positions for each geometry
+      //   F  vector of #F by 3 list of Oriented triangles for each geometry
+      //   masks  a 32 bit mask to identify active geometries.
+      //   isStatic  scene is optimized for static geometry
+      // Side effects:
+      //   The first time this is ever called the embree engine is initialized.
+      void init(
+        const std::vector<const PointMatrixType*>& V,
+        const std::vector<const FaceMatrixType*>& F,
+        const std::vector<int>& masks,
+        bool isStatic = false);
+
+
+      // Deinitialize embree datasctructures for current mesh.  Also called on
+      // destruction: no need to call if you just want to init() once and
+      // destroy.
+      void deinit();
+      // initialize view parameters
+      void init_view();
+
+      // scene data
+      PointMatrixType V; // vertices
+      FaceMatrixType  F; // faces
+      ColorMatrixType C; // colours
+
+      Eigen::RowVector3f uC; // uniform color
+
+      bool face_based;
+      bool uniform_color;
+
+      // Camera parameters
+      float camera_base_zoom;
+      float camera_zoom;
+
+      Eigen::Vector3f camera_base_translation;
+      Eigen::Vector3f camera_translation;
+      Eigen::Vector3f camera_eye;
+      Eigen::Vector3f camera_up;
+      Eigen::Vector3f camera_center;
+      float camera_view_angle;
+      float camera_dnear;
+      float camera_dfar;
+
+      // projection matrixes
+      Eigen::Matrix4f view;
+      Eigen::Matrix4f proj;
+      Eigen::Matrix4f norm;
+
+      Eigen::Matrix3f rot_matrix;
+
+      bool orthographic;
+
+      // embree data
+      RTCScene scene;
+      unsigned geomID;
+      bool initialized;
+
+      RTCDevice device;
+
+      void create_ray(
+        RTCRayHit& ray,
+        const Eigen::RowVector3f& origin,
+        const Eigen::RowVector3f& direction,
+        float tnear,
+        float tfar,
+        int mask) const;
+
+    };
+  }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "EmbreeRenderer.cpp"
+#endif
+#endif //IGL_EMBREE_EMBREE_RENDERER_H

+ 9 - 0
include/igl/extension.cpp

@@ -0,0 +1,9 @@
+#include "extension.h"
+#include "pathinfo.h"
+
+IGL_INLINE std::string igl::extension( const std::string & path)
+{
+  std::string d,b,e,f;
+  pathinfo(path,d,b,e,f);
+  return e;
+}

+ 29 - 0
include/igl/extension.h

@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2020 Alec Jacobson <[email protected]>
+//
+// 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_EXTENSION_H
+#define IGL_EXTENSION_H
+#include "igl_inline.h"
+
+#include <string>
+
+namespace igl
+{
+  //  Inputs:
+  //    path  path with an extension (path/to/foo.obj)
+  //  Returns extension without dot (obj)
+  //
+  //  See also: pathinfo, basename, dirname
+  IGL_INLINE std::string extension( const std::string & path);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "extension.cpp"
+#endif
+
+#endif
+

+ 2 - 0
include/igl/harmonic.cpp

@@ -161,6 +161,8 @@ IGL_INLINE void igl::harmonic(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<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<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
 template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 1, -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<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -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&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 // generated by autoexplicit.sh
 template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 1, -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<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -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&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);

+ 451 - 0
include/igl/marching_cubes.cpp

@@ -0,0 +1,451 @@
+#include "marching_cubes.h"
+
+// Adapted from public domain code at
+// http://paulbourke.net/geometry/polygonise/marchingsource.cpp
+
+#include <unordered_map>
+
+template <typename DerivedS, typename DerivedGV, typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::marching_cubes(
+    const Eigen::MatrixBase<DerivedS> &S,
+    const Eigen::MatrixBase<DerivedGV> &GV,
+    const unsigned nx,
+    const unsigned ny,
+    const unsigned nz,
+    const typename DerivedS::Scalar isovalue,
+    Eigen::PlainObjectBase<DerivedV> &V,
+    Eigen::PlainObjectBase<DerivedF> &F)
+{
+  typedef typename DerivedS::Scalar Scalar;
+  typedef typename DerivedF::Scalar Index;
+  // use same order as a2fVertexOffset
+  const unsigned ioffset[8] = {0,1,1+nx,nx,nx*ny,1+nx*ny,1+nx+nx*ny,nx+nx*ny};
+  const int aiCubeEdgeFlags[256]=
+  {
+    0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 
+    0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 
+    0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 
+    0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 
+    0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 
+    0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 
+    0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 
+    0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 
+    0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 
+    0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 
+    0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 
+    0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460, 
+    0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0, 
+    0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230, 
+    0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190, 
+    0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
+  };
+  //a2eConnection lists the index of the endpoint vertices for each of the 12 edges of the cube
+  const int a2eConnection[12][2] = 
+  {
+    {0,1}, {1,2}, {2,3}, {3,0},
+    {4,5}, {5,6}, {6,7}, {7,4},
+    {0,4}, {1,5}, {2,6}, {3,7}
+  };
+  //  For each of the possible vertex states listed in aiCubeEdgeFlags there is a specific triangulation
+  //  of the edge intersection points.  a2fConnectionTable lists all of them in the form of
+  //  0-5 edge triples with the list terminated by the invalid value -1.
+  //  For example: a2fConnectionTable[3] list the 2 triangles formed when corner[0] 
+  //  and corner[1] are inside of the surface, but the rest of the cube is not.
+  //
+  //  I found this table in an example program someone wrote long ago.  It was probably generated by hand
+  int a2fConnectionTable[256][16] =  
+  {
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+    {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+    {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+    {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+    {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
+    {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+    {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+    {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+    {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+    {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
+    {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
+    {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
+    {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+    {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+    {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+    {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+    {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+    {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
+    {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+    {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+    {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
+    {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
+    {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
+    {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+    {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+    {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+    {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+    {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
+    {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
+    {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
+    {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+    {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
+    {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+    {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
+    {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+    {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
+    {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
+    {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
+    {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+    {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
+    {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+    {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
+    {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+    {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+    {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
+    {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+    {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+    {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
+    {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+    {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
+    {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+    {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+    {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
+    {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
+    {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
+    {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
+    {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+    {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+    {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
+    {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
+    {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+    {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
+    {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
+    {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
+    {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
+    {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+    {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+    {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+    {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
+    {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+    {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
+    {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
+    {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+    {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
+    {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
+    {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
+    {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+    {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+    {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
+    {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
+    {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+    {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+    {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
+    {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+    {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+    {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
+    {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
+    {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
+    {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
+    {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
+    {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+    {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+    {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+    {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
+    {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+    {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
+    {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
+    {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+    {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
+    {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
+    {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+    {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+    {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
+    {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
+    {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
+    {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
+    {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
+    {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+    {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
+    {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+    {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
+    {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+    {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
+    {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+    {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+    {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
+    {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+    {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
+    {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
+    {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
+    {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
+    {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
+    {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
+    {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
+    {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
+    {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
+    {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
+    {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
+    {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+    {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
+    {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
+    {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
+    {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
+    {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
+    {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
+    {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
+    {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+    {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
+    {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
+    {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
+    {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
+    {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
+    {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
+    {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
+    {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
+    {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
+    {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+    {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
+    {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
+    {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
+    {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+    {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+    {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+    {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
+    {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
+    {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
+    {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
+    {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
+    {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
+    {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
+    {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+    {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
+    {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
+    {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
+    {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+    {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
+    {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
+    {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
+    {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
+    {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
+    {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+    {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
+    {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
+    {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
+    {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
+    {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+    {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
+    {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+    {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+    {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+    {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
+    {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+    {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
+    {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
+  };
+
+
+  std::unordered_map<int64_t,int> E2V;
+  V.resize(std::pow(nx*ny*nz,2./3.),3);
+  F.resize(std::pow(nx*ny*nz,2./3.),3);
+  int n = 0;
+  int m = 0;
+
+  const auto xyz2i = [&nx,&ny,&nz]
+    (const int & x, const int & y, const int & z)->unsigned
+  {
+    return x+nx*(y+ny*(z));
+  };
+  const auto ij2key = [](int32_t i,int32_t j)
+  {
+    if(i>j){ std::swap(i,j); }
+    std::int64_t ret = 0;
+    ret |= i;
+    ret |= static_cast<std::int64_t>(j) << 32;
+    return ret;
+  };
+  const auto ij2vertex = [&E2V,&V,&n,&GV,&ij2key]
+    (const unsigned & i, const unsigned & j, const Scalar & t)
+  {
+    const auto key = ij2key(i,j);
+    const auto it = E2V.find(key);
+    int v = -1;
+    if(it == E2V.end())
+    {
+      // new vertex
+      if(n==V.rows()){ V.conservativeResize(V.rows()*2+1,V.cols()); }
+      V.row(n) = GV.row(i) + t*(GV.row(j) - GV.row(i));
+      v = n;
+      E2V[key] = v;
+      n++;
+    }else
+    {
+      v = it->second;
+    }
+    return v;
+  };
+  //fGetOffset finds the approximate point of intersection of the surface
+  // between two points with the values fValue1 and fValue2
+  const auto inv_lerp = [&isovalue](const Scalar & a, const Scalar & b)->Scalar
+  {
+    const Scalar delta = b-a;
+    if(delta == 0) { return 0.5; }
+    return (isovalue - a)/delta;
+  };
+  const auto cube = 
+    [
+      &S,&V,&n,&F,&m,&isovalue,
+      &E2V,&ij2vertex,&xyz2i,&inv_lerp,&ioffset,
+      &aiCubeEdgeFlags,&a2eConnection,a2fConnectionTable
+    ]
+    (const int x, const int y, const int z)
+  {
+    const unsigned i = xyz2i(x,y,z);
+
+    //Make a local copy of the values at the cube's corners
+    static Eigen::Matrix<Scalar,8,1> cS;
+    static Eigen::Matrix<unsigned,8,1> cI;
+    //Find which vertices are inside of the surface and which are outside
+    int c_flags = 0;
+    for(int c = 0; c < 8; c++)
+    {
+      const unsigned ic = i + ioffset[c];
+      cI(c) = ic;
+      cS(c) = S(ic);
+      if(cS(c) > isovalue){ c_flags |= 1<<c; }
+    }
+    //Find which edges are intersected by the surface
+    int e_flags = aiCubeEdgeFlags[c_flags];
+    //If the cube is entirely inside or outside of the surface, then there will be no intersections
+    if(e_flags == 0) { return; }
+    //Find the point of intersection of the surface with each edge
+    //Then find the normal to the surface at those points
+    Eigen::Matrix<Index,12,1> edge_vertices;
+    for(int e = 0; e < 12; e++)
+    {
+#ifndef NDEBUG
+      edge_vertices[e] = -1;
+#endif
+      //if there is an intersection on this edge
+      if(e_flags & (1<<e))
+      {
+        // find crossing point assuming linear interpolation along edges
+        const Scalar t = 
+          inv_lerp(cS(a2eConnection[e][0]),cS(a2eConnection[e][1]));
+        // record global index into local table
+        edge_vertices[e] = 
+          ij2vertex(cI(a2eConnection[e][0]),cI(a2eConnection[e][1]),t);
+        assert(edge_vertices[e] >= 0);
+        assert(edge_vertices[e] < n);
+      }
+    }
+    // Insert the triangles that were found.  There can be up to five per cube
+    for(int f = 0; f < 5; f++)
+    {
+      if(a2fConnectionTable[c_flags][3*f] < 0) break;
+      if(m==F.rows()){ F.conservativeResize(F.rows()*2+1,F.cols()); }
+      assert(edge_vertices[a2fConnectionTable[c_flags][3*f+0]]>=0);
+      assert(edge_vertices[a2fConnectionTable[c_flags][3*f+1]]>=0);
+      assert(edge_vertices[a2fConnectionTable[c_flags][3*f+2]]>=0);
+      F.row(m) <<
+        edge_vertices[a2fConnectionTable[c_flags][3*f+0]],
+        edge_vertices[a2fConnectionTable[c_flags][3*f+1]],
+        edge_vertices[a2fConnectionTable[c_flags][3*f+2]];
+      m++;
+    }
+  };
+
+  // march over all cubes (loop order chosen to match memory)
+  //
+  // Should be possible to parallelize safely if threads a "well separated".
+  // Like red-black Gauss Seidel. Probably each thread need's their own E2V,V,F,
+  // and then merge at the end. Annoying part are the edges lying on the
+  // interface between chunks.
+  for(int z=0;z<nz-1;z++)
+  {
+    for(int y=0;y<ny-1;y++)
+    {
+      for(int x=0;x<nx-1;x++)
+      {
+        cube(x,y,z);
+      }
+    }
+  }
+  V.conservativeResize(n,3);
+  F.conservativeResize(m,3);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::marching_cubes<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -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&, unsigned int, unsigned int, unsigned int, 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> >&);
+#endif

+ 52 - 0
include/igl/marching_cubes.h

@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <[email protected]>
+//
+// 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_MARCHING_CUBES_H
+#define IGL_MARCHING_CUBES_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+namespace igl
+{
+  // marching_cubes( values, points, x_res, y_res, z_res, isovalue, vertices, faces )
+  //
+  // performs marching cubes reconstruction on a grid defined by values, and
+  // points, and generates a mesh defined by vertices and faces
+  //
+  // Input:
+  //   S   nx*ny*nz list of values at each grid corner
+  //       i.e. S(x + y*xres + z*xres*yres) for corner (x,y,z)
+  //   GV  nx*ny*nz by 3 array of corresponding grid corner vertex locations
+  //   nx  resolutions of the grid in x dimension
+  //   ny  resolutions of the grid in y dimension
+  //   nz  resolutions of the grid in z dimension
+  //   isovalue  the isovalue of the surface to reconstruct
+  // Output:
+  //   V  #V by 3 list of mesh vertex positions
+  //   F  #F by 3 list of mesh triangle indices into rows of V
+  //
+  template <
+    typename DerivedS, 
+    typename DerivedGV, 
+    typename DerivedV, 
+    typename DerivedF>
+  IGL_INLINE void marching_cubes(
+    const Eigen::MatrixBase<DerivedS> & S,
+    const Eigen::MatrixBase<DerivedGV> & GV,
+    const unsigned nx,
+    const unsigned ny,
+    const unsigned nz,
+    const typename DerivedS::Scalar isovalue,
+    Eigen::PlainObjectBase<DerivedV> &V,
+    Eigen::PlainObjectBase<DerivedF> &F);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "marching_cubes.cpp"
+#endif
+
+#endif

+ 1 - 1
include/igl/matlab/prepare_lhs.cpp

@@ -122,5 +122,5 @@ template void igl::matlab::prepare_lhs_double<Eigen::Matrix<int, 1, 3, 1, 1, 3>
 template void igl::matlab::prepare_lhs_double<Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, mxArray_tag**);
 template void igl::matlab::prepare_lhs_double<Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, mxArray_tag**);
 template void igl::matlab::prepare_lhs_double<double>(Eigen::SparseMatrix<double, 0, int> const&, mxArray_tag**);
-template void igl::matlab::prepare_lhs_double<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::__1::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::__1::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_double<Eigen::Matrix<double, -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&, mxArray_tag**);
 #endif

+ 2 - 0
include/igl/matlab_format.cpp

@@ -113,6 +113,8 @@ IGL_INLINE const std::string igl::matlab_format(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template Eigen::WithFormat<Eigen::Array<int, -1, 3, 0, -1, 3> > const igl::matlab_format<Eigen::Array<int, -1, 3, 0, -1, 3> >(Eigen::DenseBase<Eigen::Array<int, -1, 3, 0, -1, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
 template Eigen::WithFormat<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const igl::matlab_format<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(Eigen::DenseBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
 template Eigen::WithFormat<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const igl::matlab_format<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
 #if EIGEN_VERSION_AT_LEAST(3,3,0)

+ 2 - 0
include/igl/min_quad_with_fixed.cpp

@@ -584,6 +584,8 @@ IGL_INLINE bool igl::min_quad_with_fixed(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::min_quad_with_fixed<double, 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<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, 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::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 #if EIGEN_VERSION_AT_LEAST(3,3,0)
 #else
 template bool igl::min_quad_with_fixed_solve<double, Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<double>, Eigen::Matrix<double, -1, 1, 0, -1, 1> const>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::min_quad_with_fixed_data<double> const&, Eigen::MatrixBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<double>, Eigen::Matrix<double, -1, 1, 0, -1, 1> const> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);

+ 1 - 1
include/igl/mosek/mosek_guarded.h

@@ -9,7 +9,7 @@
 #define IGL_MOSEK_MOSEK_GUARDED_H
 #include "../igl_inline.h"
 
-#include "mosek.h"
+#include <mosek.h>
 namespace igl
 {
   namespace mosek

+ 4 - 0
include/igl/mosek/mosek_linprog.cpp

@@ -140,7 +140,9 @@ IGL_INLINE bool igl::mosek::mosek_linprog(
   switch(solsta)
   {
     case MSK_SOL_STA_OPTIMAL:   
+#if MSK_VERSION_MAJOR <= 8
     case MSK_SOL_STA_NEAR_OPTIMAL:
+#endif
       x.resize(n);
       /* Request the basic solution. */ 
       MSK_getxx(task,MSK_SOL_BAS,x.data()); 
@@ -148,8 +150,10 @@ IGL_INLINE bool igl::mosek::mosek_linprog(
       break;
     case MSK_SOL_STA_DUAL_INFEAS_CER:
     case MSK_SOL_STA_PRIM_INFEAS_CER:
+#if MSK_VERSION_MAJOR <= 8
     case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
     case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:  
+#endif
       //printf("Primal or dual infeasibility certificate found.\n");
       break;
     case MSK_SOL_STA_UNKNOWN:

+ 18 - 17
include/igl/mosek/mosek_quadprog.cpp

@@ -164,34 +164,27 @@ IGL_INLINE bool igl::mosek::mosek_quadprog(
     // Set constant bounds on variable j
     if(lx[j] == ux[j])
     {
+#if MSK_VERSION_MAJOR <=8
       mosek_guarded(MSK_putbound(task,MSK_ACC_VAR,j,MSK_BK_FX,lx[j],ux[j]));
+#else
+      mosek_guarded(MSK_putvarbound(task,j,MSK_BK_FX,lx[j],ux[j]));
+#endif
     }else
     {
+#if MSK_VERSION_MAJOR <=8
       mosek_guarded(MSK_putbound(task,MSK_ACC_VAR,j,MSK_BK_RA,lx[j],ux[j]));
+#else
+      mosek_guarded(MSK_putvarbound(task,j,MSK_BK_RA,lx[j],ux[j]));
+#endif
     }
 
     if(m>0)
     {
       // Input column j of A
 #if MSK_VERSION_MAJOR >= 7
-      mosek_guarded(
-        MSK_putacol(
-          task,
-          j,
-          Acp[j+1]-Acp[j],
-          &Ari[Acp[j]],
-          &Av[Acp[j]])
-        );
+      mosek_guarded( MSK_putacol( task, j, Acp[j+1]-Acp[j], &Ari[Acp[j]], &Av[Acp[j]]));
 #elif MSK_VERSION_MAJOR == 6
-      mosek_guarded(
-        MSK_putavec(
-          task,
-          MSK_ACC_VAR,
-          j,
-          Acp[j+1]-Acp[j],
-          &Ari[Acp[j]],
-          &Av[Acp[j]])
-        );
+      mosek_guarded( MSK_putavec( task, MSK_ACC_VAR, j, Acp[j+1]-Acp[j], &Ari[Acp[j]], &Av[Acp[j]]));
 #endif
     }
   }
@@ -200,7 +193,11 @@ IGL_INLINE bool igl::mosek::mosek_quadprog(
   for(int i = 0;i<m;i++)
   {
     // put bounds  on constraints
+#if MSK_VERSION_MAJOR <=8
     mosek_guarded(MSK_putbound(task,MSK_ACC_CON,i,MSK_BK_RA,lc[i],uc[i]));
+#else
+    mosek_guarded(MSK_putconbound(task,i,MSK_BK_RA,lc[i],uc[i]));
+#endif
   }
 
   // Input Q for the objective (REMEMBER Q SHOULD ONLY BE LOWER TRIANGLE)
@@ -243,7 +240,9 @@ IGL_INLINE bool igl::mosek::mosek_quadprog(
   switch(solsta)
   {
     case MSK_SOL_STA_OPTIMAL:   
+#if MSK_VERSION_MAJOR <= 8
     case MSK_SOL_STA_NEAR_OPTIMAL:
+#endif
       MSK_getsolutionslice(task,MSK_SOL_ITR,MSK_SOL_ITEM_XX,0,n,&x[0]);
       //printf("Optimal primal solution\n");
       //for(size_t j=0; j<n; ++j)
@@ -254,8 +253,10 @@ IGL_INLINE bool igl::mosek::mosek_quadprog(
       break;
     case MSK_SOL_STA_DUAL_INFEAS_CER:
     case MSK_SOL_STA_PRIM_INFEAS_CER:
+#if MSK_VERSION_MAJOR <= 8
     case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
     case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:  
+#endif
       //printf("Primal or dual infeasibility certificate found.\n");
       break;
     case MSK_SOL_STA_UNKNOWN:

+ 55 - 0
include/igl/offset_surface.cpp

@@ -0,0 +1,55 @@
+#include "offset_surface.h"
+#include "marching_cubes.h"
+#include "voxel_grid.h"
+#include "signed_distance.h"
+#include "flood_fill.h"
+#include <cassert>
+
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename isolevelType,
+  typename DerivedSV,
+  typename DerivedSF,
+  typename DerivedGV,
+  typename Derivedside,
+  typename DerivedS>
+void igl::offset_surface(
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
+  const isolevelType isolevel,
+  const typename Derivedside::Scalar s,
+  const SignedDistanceType & signed_distance_type,
+  Eigen::PlainObjectBase<DerivedSV> & SV,
+  Eigen::PlainObjectBase<DerivedSF> & SF,
+  Eigen::PlainObjectBase<DerivedGV> &   GV,
+  Eigen::PlainObjectBase<Derivedside> & side,
+  Eigen::PlainObjectBase<DerivedS> & S)
+{
+  typedef typename DerivedV::Scalar Scalar;
+  typedef typename DerivedF::Scalar Index;
+  igl::voxel_grid(V,isolevel,s,1,GV,side);
+
+  const Scalar h = 
+    (GV.col(0).maxCoeff()-GV.col(0).minCoeff())/((Scalar)(side(0)-1));
+  const Scalar lower_bound = isolevel-sqrt(3.0)*h;
+  const Scalar upper_bound = isolevel+sqrt(3.0)*h;
+  {
+    Eigen::Matrix<Index,Eigen::Dynamic,1> I;
+    Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> C,N;
+    igl::signed_distance(
+      GV,V,F,signed_distance_type,lower_bound,upper_bound,S,I,C,N);
+  }
+  igl::flood_fill(side,S);
+  
+  DerivedS SS = S.array()-isolevel;
+  igl::marching_cubes(SS,GV,side(0),side(1),side(2),0,SV,SF);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::offset_surface<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, double, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::offset_surface<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, float, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+template void igl::offset_surface<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, 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, 3, 1, 1, 3>, 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&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType 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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif

+ 52 - 0
include/igl/offset_surface.h

@@ -0,0 +1,52 @@
+#ifndef IGL_OFFSET_SURFACE_H
+#define IGL_OFFSET_SURFACE_H
+#include "igl_inline.h"
+#include "signed_distance.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+  // Compute a triangulated offset surface using matching cubes on a grid of
+  // signed distance values from the input triangle mesh.
+  //
+  // Inputs:
+  //   V  #V by 3 list of mesh vertex positions
+  //   F  #F by 3 list of mesh triangle indices into V
+  //   isolevel  iso level to extract (signed distance: negative inside)
+  //   s  number of grid cells along longest side (controls resolution)
+  //   signed_distance_type  type of signing to use (see
+  //     ../signed_distance.h)
+  // Outputs:
+  //   SV  #SV by 3 list of output surface mesh vertex positions
+  //   SF  #SF by 3 list of output mesh triangle indices into SV
+  //   GV  #GV=side(0)*side(1)*side(2) by 3 list of grid cell centers
+  //   side  list of number of grid cells in x, y, and z directions
+  //   S  #GV by 3 list of signed distance values _near_ `isolevel` ("far"
+  //     from `isolevel` these values are incorrect)
+  //
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename isolevelType,
+    typename DerivedSV,
+    typename DerivedSF,
+    typename DerivedGV,
+    typename Derivedside,
+    typename DerivedS>
+  void offset_surface(
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
+    const isolevelType isolevel,
+    const typename Derivedside::Scalar s,
+    const SignedDistanceType & signed_distance_type,
+    Eigen::PlainObjectBase<DerivedSV> & SV,
+    Eigen::PlainObjectBase<DerivedSF> & SF,
+    Eigen::PlainObjectBase<DerivedGV> & GV,
+    Eigen::PlainObjectBase<Derivedside> & side,
+    Eigen::PlainObjectBase<DerivedS> & S);
+  
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "offset_surface.cpp"
+#endif 
+#endif 

+ 208 - 0
include/igl/opengl/glfw/imgui/SelectionPlugin.cpp

@@ -0,0 +1,208 @@
+#include "SelectionPlugin.h"
+
+#include <imgui/imgui.h>
+#include <imgui_impl_glfw.h>
+#include <imgui_impl_opengl3.h>
+#include <imgui_fonts_droid_sans.h>
+#include <GLFW/glfw3.h>
+#include "../../../PI.h"
+
+namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
+
+IGL_INLINE void SelectionPlugin::init(igl::opengl::glfw::Viewer *_viewer)
+{
+  ImGuiMenu::init(_viewer);
+  std::cout<<R"(
+igl::opengl::glfw::imgui::SelectionPlugin usage:
+  [drag]  Draw a 2D selection
+  l       Turn on and toggle between lasso and polygonal lasso tool
+  M,m     Turn on and toggle between rectangular and circular marquee tool
+  V,v     Turn off interactive selection
+)";
+}
+IGL_INLINE bool SelectionPlugin::pre_draw()
+{
+  if(!visible){ return false; }
+  ImGuiMenu::pre_draw();
+  return false;
+}
+IGL_INLINE bool SelectionPlugin::post_draw()
+{
+  if(mode == OFF){ return false; }
+  ImGuiIO& io = ImGui::GetIO();
+
+  float width, height;
+  float highdpi = 1.0;
+  {
+    int fwidth, fheight;
+    glfwGetFramebufferSize(viewer->window, &fwidth, &fheight);
+    int iwidth, iheight;
+    glfwGetWindowSize(viewer->window, &iwidth, &iheight);
+    highdpi = float(iwidth)/float(fwidth);
+    // highdpi
+    width = (float)iwidth;
+    height = (float)iheight;
+  }
+
+  ImGui::SetNextWindowPos( ImVec2(0,0) );
+  ImGui::SetNextWindowSize(ImVec2(width,height), ImGuiCond_Always);
+
+  ImGui::Begin("testing", nullptr,
+               ImGuiWindowFlags_NoBackground
+               | ImGuiWindowFlags_NoTitleBar
+               | ImGuiWindowFlags_NoResize
+               | ImGuiWindowFlags_NoMove
+               | ImGuiWindowFlags_NoScrollbar
+               | ImGuiWindowFlags_NoSavedSettings
+               | ImGuiWindowFlags_NoInputs);
+
+  ImDrawList* list = ImGui::GetWindowDrawList();
+  for(int pass = 0;pass<2;pass++)
+  {
+    for(auto & p : L)
+    {
+      list->PathLineTo({ highdpi*p(0),height-highdpi*p(1) });
+    }
+    const bool closed = !(mode==LASSO || mode==POLYGONAL_LASSO) || !(is_down || is_drawing);
+    if(pass == 0)
+    {
+      list->PathStroke(IM_COL32(255, 255, 255, 255), closed, 2);
+    }else
+    {
+      list->PathStroke(IM_COL32(0, 0, 0, 255), closed, 1);
+    }
+  }
+
+  ImGui::End();
+
+  ImGui::Render();
+  ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
+
+
+  return false;
+}
+
+IGL_INLINE bool SelectionPlugin::mouse_down(int button, int modifier)
+{
+  if(mode == OFF){ return false;}
+  is_down = true;
+  has_moved_since_down = false;
+  if(!is_drawing)
+  {
+    L.clear();
+    is_drawing = true;
+  }
+  M.row(0) = xy(viewer);
+  M.row(1) = M.row(0);
+  L.emplace_back(M.row(0));
+  return true;
+}
+
+IGL_INLINE bool SelectionPlugin::mouse_up(int button, int modifier)
+{
+  is_down = false;
+  // are we done? Check first and last lasso point (need at least 3 (2 real
+  // points + 1 mouse-mouse point))
+  if(is_drawing &&
+    (mode!=POLYGONAL_LASSO ||(L.size()>=3&&(L[0]-L[L.size()-1]).norm()<=10.0)))
+  {
+    if(callback){ callback();}
+    is_drawing = false;
+  }
+  return false;
+}
+
+IGL_INLINE bool SelectionPlugin::mouse_move(int mouse_x, int mouse_y)
+{
+  if(!is_drawing){ return false; }
+  if(!has_moved_since_down)
+  {
+    if(mode == POLYGONAL_LASSO) { L.emplace_back(L[L.size()-1]); }
+    has_moved_since_down = true;
+  }
+  M.row(1) = xy(viewer);
+  switch(mode)
+  {
+    case RECTANGULAR_MARQUEE:
+      rect(M,L);
+      break;
+    case ELLIPTICAL_MARQUEE:
+      circle(M,L);
+      break;
+    case POLYGONAL_LASSO:
+      // Over write last point
+      L[L.size()-1] = xy(viewer);
+      break;
+    case LASSO:
+      L.emplace_back(xy(viewer));
+      break;
+    default: assert(false);
+  }
+  return true;
+}
+
+IGL_INLINE bool SelectionPlugin::key_pressed(unsigned int key, int modifiers)
+{
+  const auto clear = [&]() { M.setZero(); L.clear(); is_drawing = false; is_down = false; };
+  if(OFF_KEY.find(char(key)) != std::string::npos)
+  {
+      mode = OFF;
+      return true;
+  }
+  if(LASSO_KEY.find(char(key)) != std::string::npos)
+  {
+    if(mode == LASSO)
+    {
+      mode = POLYGONAL_LASSO;
+    }else/*if(mode == POLYGONAL_LASSO)*/
+    {
+      mode = LASSO;
+    }
+    clear();
+    return true;
+  }
+  if(MARQUEE_KEY.find(char(key)) != std::string::npos)
+  {
+    if(mode == RECTANGULAR_MARQUEE)
+    {
+      mode = ELLIPTICAL_MARQUEE;
+    }else/*if(mode == ELLIPTICAL_MARQUEE)*/
+    {
+      mode = RECTANGULAR_MARQUEE;
+    }
+    clear();
+    return true;
+  }
+  return false;
+}
+
+IGL_INLINE void SelectionPlugin::circle(const Eigen::Matrix<float,2,2> & M,  std::vector<Eigen::RowVector2f> & L)
+{
+  L.clear();
+  L.reserve(64);
+  const float r = (M.row(1)-M.row(0)).norm();
+  for(float th = 0;th<2.*igl::PI;th+=0.1)
+  {
+    L.emplace_back(M(0,0)+r*cos(th),M(0,1)+r*sin(th));
+  }
+}
+
+IGL_INLINE void SelectionPlugin::rect(const Eigen::Matrix<float,2,2> & M,  std::vector<Eigen::RowVector2f> & L)
+{
+  L.resize(4);
+  L[0] = Eigen::RowVector2f(M(0,0),M(0,1));
+  L[1] = Eigen::RowVector2f(M(1,0),M(0,1));
+  L[2] = Eigen::RowVector2f(M(1,0),M(1,1));
+  L[3] = Eigen::RowVector2f(M(0,0),M(1,1));
+}
+
+IGL_INLINE Eigen::RowVector2f SelectionPlugin::xy(const Viewer * vr)
+{
+  return Eigen::RowVector2f(
+    vr->current_mouse_x,
+    vr->core().viewport(3) - vr->current_mouse_y);
+}
+
+
+
+}}}}

+ 64 - 0
include/igl/opengl/glfw/imgui/SelectionPlugin.h

@@ -0,0 +1,64 @@
+#ifndef IGL_OPENGL_GFLW_IMGUI_IMGUIDRAWLISTPLUGIN_H
+#define IGL_OPENGL_GFLW_IMGUI_IMGUIDRAWLISTPLUGIN_H
+#include <igl/igl_inline.h>
+#include <igl/opengl/glfw/imgui/ImGuiMenu.h>
+#include <imgui/imgui.h>
+#include <imgui/imgui_internal.h>
+#include <imguizmo/ImGuizmo.h>
+#include <Eigen/Dense>
+#include <vector>
+
+namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
+
+class SelectionPlugin: public igl::opengl::glfw::imgui::ImGuiMenu
+{
+public:
+  // callback called when slection is completed (usually on mouse_up)
+  std::function<void(void)> callback;
+  // whether rotating, translating or scaling
+  ImGuizmo::OPERATION operation;
+  // stored transformation
+  Eigen::Matrix4f T;
+  // Initilize with rotate operation on an identity transform (at origin)
+  SelectionPlugin():operation(ImGuizmo::ROTATE),T(Eigen::Matrix4f::Identity()){};
+  IGL_INLINE virtual void init(igl::opengl::glfw::Viewer *_viewer) override;
+  IGL_INLINE virtual bool pre_draw() override;
+  IGL_INLINE virtual bool post_draw() override;
+  IGL_INLINE virtual bool mouse_down(int button, int modifier) override;
+  IGL_INLINE virtual bool mouse_up(int button, int modifier) override;
+  IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
+  IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) override;
+  // helpers
+  IGL_INLINE static void circle(const Eigen::Matrix<float,2,2> & M,  std::vector<Eigen::RowVector2f> & L);
+  IGL_INLINE static void rect(const Eigen::Matrix<float,2,2> & M,  std::vector<Eigen::RowVector2f> & L);
+  IGL_INLINE static Eigen::RowVector2f xy(const Viewer * v);
+  // customizable hotkeys
+  std::string MARQUEE_KEY = "Mm";
+  // leave 'L' for show_lines in viewer
+  std::string LASSO_KEY = "l";
+  std::string OFF_KEY = "Vv";
+  enum Mode
+  {
+    OFF                 = 0,
+    RECTANGULAR_MARQUEE = 1,
+    ELLIPTICAL_MARQUEE  = 2,
+    POLYGONAL_LASSO     = 3,
+    LASSO               = 4,
+    NUM_MODES           = 5
+  } mode = RECTANGULAR_MARQUEE;
+  bool visible = true;
+  bool is_down = false;
+  bool has_moved_since_down = false;
+  bool is_drawing = false;
+  // min and max corners of 2D rectangular marquee
+  Eigen::Matrix<float,2,2> M = Eigen::Matrix<float,2,2>::Zero();
+  // list of points of 2D lasso marquee
+  std::vector<Eigen::RowVector2f> L;
+};
+
+}}}}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "SelectionPlugin.cpp"
+#endif
+#endif

+ 2 - 0
include/igl/per_edge_normals.cpp

@@ -74,6 +74,8 @@ IGL_INLINE void igl::per_edge_normals(
       }
     }
   }
+  // take average via normalization
+  N.rowwise().normalize();
 }
 
 template <

+ 2 - 0
include/igl/point_simplex_squared_distance.cpp

@@ -164,6 +164,8 @@ namespace igl
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template void igl::point_simplex_squared_distance<3, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(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<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+// generated by autoexplicit.sh
 template void igl::point_simplex_squared_distance<3, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(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<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
 // generated by autoexplicit.sh
 template void igl::point_simplex_squared_distance<3, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, float, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, float&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);

+ 1 - 0
include/igl/project.cpp

@@ -51,6 +51,7 @@ IGL_INLINE void igl::project(
 }
 
 #ifdef IGL_STATIC_LIBRARY
+template void igl::project<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 // Explicit template instantiation
 template Eigen::Matrix<double, 3, 1, 0, 3, 1> igl::project<double>(Eigen::Matrix<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 4, 4, 0, 4, 4> const&, Eigen::Matrix<double, 4, 4, 0, 4, 4> const&, Eigen::Matrix<double, 4, 1, 0, 4, 1> const&);
 template Eigen::Matrix<float, 3, 1, 0, 3, 1> igl::project<float>(Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&);

+ 5 - 0
include/igl/project.h

@@ -36,6 +36,11 @@ namespace igl
   // Known issue:
   //   The compiler will not complain if V and P are Vector3d, but the result
   //   will be incorrect.
+  //
+  // Example:
+  //   igl::opengl::glfw::Viewer vr;
+  //   ...
+  //   igl::project(V,vr.core().view,vr.core().proj,vr.core().viewport,P);
   template <typename DerivedV, typename DerivedM, typename DerivedN, typename DerivedO, typename DerivedP>
   IGL_INLINE void project(
     const    Eigen::MatrixBase<DerivedV>&  V,

+ 2 - 1
include/igl/readDMAT.cpp

@@ -215,6 +215,8 @@ IGL_INLINE bool igl::readDMAT(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template bool igl::readDMAT<Eigen::Matrix<double, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
 template bool igl::readDMAT<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template bool igl::readDMAT<double>(std::string, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&);
 template bool igl::readDMAT<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
@@ -227,4 +229,3 @@ template bool igl::readDMAT<Eigen::Matrix<int, -1, -1, 1, -1, -1> >(std::string,
 template bool igl::readDMAT<Eigen::Matrix<float, 1, 3, 1, 1, 3> >( std::string, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
 template bool igl::readDMAT<Eigen::Matrix<double, 1, 1, 0, 1, 1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
 #endif
-

+ 138 - 416
include/igl/readMESH.cpp

@@ -6,235 +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 "readMESH.h"
-
-template <typename Scalar, typename Index>
-IGL_INLINE bool igl::readMESH(
-  const std::string mesh_file_name,
-  std::vector<std::vector<Scalar > > & V,
-  std::vector<std::vector<Index > > & T,
-  std::vector<std::vector<Index > > & F)
-{
-  using namespace std;
-  FILE * mesh_file = fopen(mesh_file_name.c_str(),"r");
-  if(NULL==mesh_file)
-  {
-    fprintf(stderr,"IOError: %s could not be opened...",mesh_file_name.c_str());
-    return false;
-  }
-  return igl::readMESH(mesh_file,V,T,F);
-}
-
-template <typename Scalar, typename Index>
-IGL_INLINE bool igl::readMESH(
-  FILE * mesh_file,
-  std::vector<std::vector<Scalar > > & V,
-  std::vector<std::vector<Index > > & T,
-  std::vector<std::vector<Index > > & F)
-{
-  using namespace std;
-#ifndef LINE_MAX
-#  define LINE_MAX 2048
-#endif
-  char line[LINE_MAX];
-  bool still_comments;
-  V.clear();
-  T.clear();
-  F.clear();
-
-  // eat comments at beginning of file
-  still_comments= true;
-  while(still_comments)
-  {
-    if(fgets(line,LINE_MAX,mesh_file) == NULL)
-    {
-      fprintf(stderr, "Error: couldn't find start of .mesh file");
-      fclose(mesh_file);
-      return false;
-    }
-    still_comments = (line[0] == '#' || line[0] == '\n');
-  }
-  char str[LINE_MAX];
-  sscanf(line," %s",str);
-  // check that first word is MeshVersionFormatted
-  if(0!=strcmp(str,"MeshVersionFormatted"))
-  {
-    fprintf(stderr,
-      "Error: first word should be MeshVersionFormatted not %s\n",str);
-    fclose(mesh_file);
-    return false;
-  }
-
-  int one = -1;
-  if(2 != sscanf(line,"%s %d",str,&one))
-  {
-    // 1 appears on next line?
-    fscanf(mesh_file," %d",&one);
-  }
-  if(one != 1)
-  {
-    fprintf(stderr,"Error: second word should be 1 not %d\n",one);
-    fclose(mesh_file);
-    return false;
-  }
-
-  // eat comments
-  still_comments= true;
-  while(still_comments)
-  {
-    fgets(line,LINE_MAX,mesh_file);
-    still_comments = (line[0] == '#' || line[0] == '\n');
-  }
-
-  sscanf(line," %s",str);
-  // check that third word is Dimension
-  if(0!=strcmp(str,"Dimension"))
-  {
-    fprintf(stderr,"Error: third word should be Dimension not %s\n",str);
-    fclose(mesh_file);
-    return false;
-  }
-  int three = -1;
-  if(2 != sscanf(line,"%s %d",str,&three))
-  {
-    // 1 appears on next line?
-    fscanf(mesh_file," %d",&three);
-  }
-  if(three != 3)
-  {
-    fprintf(stderr,"Error: only Dimension 3 supported not %d\n",three);
-    fclose(mesh_file);
-    return false;
-  }
-
-  // eat comments
-  still_comments= true;
-  while(still_comments)
-  {
-    fgets(line,LINE_MAX,mesh_file);
-    still_comments = (line[0] == '#' || line[0] == '\n');
-  }
-
-  sscanf(line," %s",str);
-  // check that fifth word is Vertices
-  if(0!=strcmp(str,"Vertices"))
-  {
-    fprintf(stderr,"Error: fifth word should be Vertices not %s\n",str);
-    fclose(mesh_file);
-    return false;
-  }
-
-  //fgets(line,LINE_MAX,mesh_file);
-
-  int number_of_vertices;
-  if(1 != fscanf(mesh_file," %d",&number_of_vertices) || number_of_vertices > 1000000000)
-  {
-    fprintf(stderr,"Error: expecting number of vertices less than 10^9...\n");
-    fclose(mesh_file);
-    return false;
-  }
-  // allocate space for vertices
-  V.resize(number_of_vertices,vector<Scalar>(3,0));
-  int extra;
-  for(int i = 0;i<number_of_vertices;i++)
-  {
-    double x,y,z;
-    if(4 != fscanf(mesh_file," %lg %lg %lg %d",&x,&y,&z,&extra))
-    {
-      fprintf(stderr,"Error: expecting vertex position...\n");
-      fclose(mesh_file);
-      return false;
-    }
-    V[i][0] = x;
-    V[i][1] = y;
-    V[i][2] = z;
-  }
-
-  // eat comments
-  still_comments= true;
-  while(still_comments)
-  {
-    fgets(line,LINE_MAX,mesh_file);
-    still_comments = (line[0] == '#' || line[0] == '\n');
-  }
-
-  sscanf(line," %s",str);
-  // check that sixth word is Triangles
-  if(0!=strcmp(str,"Triangles"))
-  {
-    fprintf(stderr,"Error: sixth word should be Triangles not %s\n",str);
-    fclose(mesh_file);
-    return false;
-  }
-  int number_of_triangles;
-  if(1 != fscanf(mesh_file," %d",&number_of_triangles))
-  {
-    fprintf(stderr,"Error: expecting number of triangles...\n");
-    fclose(mesh_file);
-    return false;
-  }
-  // allocate space for triangles
-  F.resize(number_of_triangles,vector<Index>(3));
-  // triangle indices
-  int tri[3];
-  for(int i = 0;i<number_of_triangles;i++)
-  {
-    if(4 != fscanf(mesh_file," %d %d %d %d",&tri[0],&tri[1],&tri[2],&extra))
-    {
-      printf("Error: expecting triangle indices...\n");
-      return false;
-    }
-    for(int j = 0;j<3;j++)
-    {
-      F[i][j] = tri[j]-1;
-    }
-  }
-
-  // eat comments
-  still_comments= true;
-  while(still_comments)
-  {
-    fgets(line,LINE_MAX,mesh_file);
-    still_comments = (line[0] == '#' || line[0] == '\n');
-  }
-
-  sscanf(line," %s",str);
-  // check that sixth word is Triangles
-  if(0!=strcmp(str,"Tetrahedra"))
-  {
-    fprintf(stderr,"Error: seventh word should be Tetrahedra not %s\n",str);
-    fclose(mesh_file);
-    return false;
-  }
-  int number_of_tetrahedra;
-  if(1 != fscanf(mesh_file," %d",&number_of_tetrahedra))
-  {
-    fprintf(stderr,"Error: expecting number of tetrahedra...\n");
-    fclose(mesh_file);
-    return false;
-  }
-  // allocate space for tetrahedra
-  T.resize(number_of_tetrahedra,vector<Index>(4));
-  // tet indices
-  int a,b,c,d;
-  for(int i = 0;i<number_of_tetrahedra;i++)
-  {
-    if(5 != fscanf(mesh_file," %d %d %d %d %d",&a,&b,&c,&d,&extra))
-    {
-      fprintf(stderr,"Error: expecting tetrahedra indices...\n");
-      fclose(mesh_file);
-      return false;
-    }
-    T[i][0] = a-1;
-    T[i][1] = b-1;
-    T[i][2] = c-1;
-    T[i][3] = d-1;
-  }
-  fclose(mesh_file);
-  return true;
-}
-
 #include <Eigen/Core>
-#include "list_to_matrix.h"
 
 
 template <typename DerivedV, typename DerivedF, typename DerivedT>
@@ -269,12 +41,18 @@ IGL_INLINE bool igl::readMESH(
   bool still_comments;
 
   // eat comments at beginning of file
-  still_comments= true;
-  while(still_comments)
+  const auto eat_comments = [&]()->bool
   {
-    fgets(line,LINE_MAX,mesh_file);
-    still_comments = (line[0] == '#' || line[0] == '\n');
-  }
+    bool still_comments= true;
+    bool has_line = false;
+    while(still_comments)
+    {
+      has_line = fgets(line,LINE_MAX,mesh_file) != NULL;
+      still_comments = (line[0] == '#' || line[0] == '\n');
+    }
+    return has_line;
+  };
+  eat_comments();
 
   char str[LINE_MAX];
   sscanf(line," %s",str);
@@ -286,208 +64,153 @@ IGL_INLINE bool igl::readMESH(
     fclose(mesh_file);
     return false;
   }
-  int one = -1;
-  if(2 != sscanf(line,"%s %d",str,&one))
-  {
-    // 1 appears on next line?
-    fscanf(mesh_file," %d",&one);
-  }
-  if(one != 1)
-  {
-    fprintf(stderr,"Error: second word should be 1 not %d\n",one);
-    fclose(mesh_file);
-    return false;
-  }
-
-  // eat comments
-  still_comments= true;
-  while(still_comments)
-  {
-    fgets(line,LINE_MAX,mesh_file);
-    still_comments = (line[0] == '#' || line[0] == '\n');
-  }
-
-  sscanf(line," %s",str);
-  // check that third word is Dimension
-  if(0!=strcmp(str,"Dimension"))
-  {
-    fprintf(stderr,"Error: third word should be Dimension not %s\n",str);
-    fclose(mesh_file);
-    return false;
-  }
-  int three = -1;
-  if(2 != sscanf(line,"%s %d",str,&three))
-  {
-    // 1 appears on next line?
-    fscanf(mesh_file," %d",&three);
-  }
-  if(three != 3)
-  {
-    fprintf(stderr,"Error: only Dimension 3 supported not %d\n",three);
-    fclose(mesh_file);
-    return false;
-  }
-
-  // eat comments
-  still_comments= true;
-  while(still_comments)
+  int version = -1;
+  if(2 != sscanf(line,"%s %d",str,&version)) { fscanf(mesh_file," %d",&version); }
+  if(version != 1 && version != 2)
   {
-    fgets(line,LINE_MAX,mesh_file);
-    still_comments = (line[0] == '#' || line[0] == '\n');
-  }
-
-  sscanf(line," %s",str);
-  // check that fifth word is Vertices
-  if(0!=strcmp(str,"Vertices"))
-  {
-    fprintf(stderr,"Error: fifth word should be Vertices not %s\n",str);
+    fprintf(stderr,"Error: second word should be 1 or 2 not %d\n",version);
     fclose(mesh_file);
     return false;
   }
 
-  //fgets(line,LINE_MAX,mesh_file);
-
-  int number_of_vertices;
-  if(1 != fscanf(mesh_file," %d",&number_of_vertices) || number_of_vertices > 1000000000)
+  while(eat_comments())
   {
-    fprintf(stderr,"Error: expecting number of vertices less than 10^9...\n");
-    fclose(mesh_file);
-    return false;
-  }
-  // allocate space for vertices
-  V.resize(number_of_vertices,3);
-  int extra;
-  for(int i = 0;i<number_of_vertices;i++)
-  {
-    double x,y,z;
-    if(4 != fscanf(mesh_file," %lg %lg %lg %d",&x,&y,&z,&extra))
+    sscanf(line," %s",str);
+    int extra;
+    // check that third word is Dimension
+    if(0==strcmp(str,"Dimension"))
     {
-      fprintf(stderr,"Error: expecting vertex position...\n");
-      fclose(mesh_file);
-      return false;
-    }
-    V(i,0) = x;
-    V(i,1) = y;
-    V(i,2) = z;
-  }
-
-  // eat comments
-  still_comments= true;
-  while(still_comments)
-  {
-    fgets(line,LINE_MAX,mesh_file);
-    still_comments = (line[0] == '#' || line[0] == '\n');
-  }
-
-  sscanf(line," %s",str);
-  // check that sixth word is Triangles
-  if(0!=strcmp(str,"Triangles"))
-  {
-    fprintf(stderr,"Error: sixth word should be Triangles not %s\n",str);
-    fclose(mesh_file);
-    return false;
-  }
-  int number_of_triangles;
-  if(1 != fscanf(mesh_file," %d",&number_of_triangles))
-  {
-    fprintf(stderr,"Error: expecting number of triangles...\n");
-    fclose(mesh_file);
-    return false;
-  }
-  // allocate space for triangles
-  F.resize(number_of_triangles,3);
-  // triangle indices
-  int tri[3];
-  for(int i = 0;i<number_of_triangles;i++)
-  {
-    if(4 != fscanf(mesh_file," %d %d %d %d",&tri[0],&tri[1],&tri[2],&extra))
+      int three = -1;
+      if(2 != sscanf(line,"%s %d",str,&three))
+      {
+        // 1 appears on next line?
+        fscanf(mesh_file," %d",&three);
+      }
+      if(three != 3)
+      {
+        fprintf(stderr,"Error: only Dimension 3 supported not %d\n",three);
+        fclose(mesh_file);
+        return false;
+      }
+    }else if(0==strcmp(str,"Vertices"))
     {
-      printf("Error: expecting triangle indices...\n");
-      return false;
-    }
-    for(int j = 0;j<3;j++)
+      int number_of_vertices;
+      if(1 != fscanf(mesh_file," %d",&number_of_vertices) || number_of_vertices > 1000000000)
+      {
+        fprintf(stderr,"Error: expecting number of vertices less than 10^9...\n");
+        fclose(mesh_file);
+        return false;
+      }
+      // allocate space for vertices
+      V.resize(number_of_vertices,3);
+      for(int i = 0;i<number_of_vertices;i++)
+      {
+        double x,y,z;
+        if(4 != fscanf(mesh_file," %lg %lg %lg %d",&x,&y,&z,&extra))
+        {
+          fprintf(stderr,"Error: expecting vertex position...\n");
+          fclose(mesh_file);
+          return false;
+        }
+        V(i,0) = x;
+        V(i,1) = y;
+        V(i,2) = z;
+      }
+    }else if(0==strcmp(str,"Triangles"))
     {
-      F(i,j) = tri[j]-1;
-    }
-  }
-
-  // eat comments
-  still_comments= true;
-  while(still_comments)
-  {
-    fgets(line,LINE_MAX,mesh_file);
-    still_comments = (line[0] == '#' || line[0] == '\n');
-  }
-
-  sscanf(line," %s",str);
-  // check that sixth word is Triangles
-  if(0!=strcmp(str,"Tetrahedra"))
-  {
-    fprintf(stderr,"Error: seventh word should be Tetrahedra not %s\n",str);
-    fclose(mesh_file);
-    return false;
-  }
-  int number_of_tetrahedra;
-  if(1 != fscanf(mesh_file," %d",&number_of_tetrahedra))
-  {
-    fprintf(stderr,"Error: expecting number of tetrahedra...\n");
-    fclose(mesh_file);
-    return false;
-  }
-  // allocate space for tetrahedra
-  T.resize(number_of_tetrahedra,4);
-  // tet indices
-  int a,b,c,d;
-  for(int i = 0;i<number_of_tetrahedra;i++)
-  {
-    if(5 != fscanf(mesh_file," %d %d %d %d %d",&a,&b,&c,&d,&extra))
+      int number_of_triangles;
+      if(1 != fscanf(mesh_file," %d",&number_of_triangles))
+      {
+        fprintf(stderr,"Error: expecting number of triangles...\n");
+        fclose(mesh_file);
+        return false;
+      }
+      // allocate space for triangles
+      F.resize(number_of_triangles,3);
+      // triangle indices
+      int tri[3];
+      for(int i = 0;i<number_of_triangles;i++)
+      {
+        if(4 != fscanf(mesh_file," %d %d %d %d",&tri[0],&tri[1],&tri[2],&extra))
+        {
+          printf("Error: expecting triangle indices...\n");
+          return false;
+        }
+        for(int j = 0;j<3;j++)
+        {
+          F(i,j) = tri[j]-1;
+        }
+      }
+    }else if(0==strcmp(str,"Tetrahedra"))
+    {
+      int number_of_tetrahedra;
+      if(1 != fscanf(mesh_file," %d",&number_of_tetrahedra))
+      {
+        fprintf(stderr,"Error: expecting number of tetrahedra...\n");
+        fclose(mesh_file);
+        return false;
+      }
+      // allocate space for tetrahedra
+      T.resize(number_of_tetrahedra,4);
+      // tet indices
+      int a,b,c,d;
+      for(int i = 0;i<number_of_tetrahedra;i++)
+      {
+        if(5 != fscanf(mesh_file," %d %d %d %d %d",&a,&b,&c,&d,&extra))
+        {
+          fprintf(stderr,"Error: expecting tetrahedra indices...\n");
+          fclose(mesh_file);
+          return false;
+        }
+        T(i,0) = a-1;
+        T(i,1) = b-1;
+        T(i,2) = c-1;
+        T(i,3) = d-1;
+      }
+    }else if(0==strcmp(str,"Edges"))
     {
-      fprintf(stderr,"Error: expecting tetrahedra indices...\n");
+      int number_of_edges;
+      if(1 != fscanf(mesh_file," %d",&number_of_edges))
+      {
+        fprintf(stderr,"Error: expecting number of edges...\n");
+        fclose(mesh_file);
+        return false;
+      }
+      // allocate space for tetrahedra
+      Eigen::MatrixXi E(number_of_edges,2);
+      // tet indices
+      int a,b;
+      for(int i = 0;i<number_of_edges;i++)
+      {
+        if(3 != fscanf(mesh_file," %d %d %d",&a,&b,&extra))
+        {
+          fprintf(stderr,"Error: expecting tetrahedra indices...\n");
+          fclose(mesh_file);
+          return false;
+        }
+        E(i,0) = a-1;
+        E(i,1) = b-1;
+      }
+    }else if(0==strcmp(str,"End"))
+    {
+      break;
+    }else
+    {
+      fprintf(stderr,"Error: expecting "
+        "Dimension|Triangles|Vertices|Tetrahedra|Edges instead of %s...\n",str);
       fclose(mesh_file);
       return false;
     }
-    T(i,0) = a-1;
-    T(i,1) = b-1;
-    T(i,2) = c-1;
-    T(i,3) = d-1;
   }
+
   fclose(mesh_file);
   return true;
 }
-//{
-//  std::vector<std::vector<double> > vV,vT,vF;
-//  bool success = igl::readMESH(mesh_file_name,vV,vT,vF);
-//  if(!success)
-//  {
-//    // readMESH already printed error message to std err
-//    return false;
-//  }
-//  bool V_rect = igl::list_to_matrix(vV,V);
-//  if(!V_rect)
-//  {
-//    // igl::list_to_matrix(vV,V) already printed error message to std err
-//    return false;
-//  }
-//  bool T_rect = igl::list_to_matrix(vT,T);
-//  if(!T_rect)
-//  {
-//    // igl::list_to_matrix(vT,T) already printed error message to std err
-//    return false;
-//  }
-//  bool F_rect = igl::list_to_matrix(vF,F);
-//  if(!F_rect)
-//  {
-//    // igl::list_to_matrix(vF,F) already printed error message to std err
-//    return false;
-//  }
-//  assert(V.cols() == 3);
-//  assert(T.cols() == 4);
-//  assert(F.cols() == 3);
-//  return true;
-//}
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::readMESH<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template bool igl::readMESH<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::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 bool igl::readMESH<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -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::readMESH<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
@@ -497,5 +220,4 @@ template bool igl::readMESH<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix
 template bool igl::readMESH<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template bool igl::readMESH<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
 template bool igl::readMESH<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
-template bool igl::readMESH<double, int>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, 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> > > >&);
 #endif

+ 2 - 1
include/igl/readPLY.cpp

@@ -623,6 +623,8 @@ IGL_INLINE bool readPLY(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::readPLY<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template bool igl::readPLY<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template bool igl::readPLY<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
 template bool igl::readPLY<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
@@ -637,4 +639,3 @@ template bool igl::readPLY<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matri
 template bool igl::readPLY<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&);
 template bool igl::readPLY<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -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<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&);
 #endif
-

+ 2 - 0
include/igl/readSTL.cpp

@@ -312,6 +312,8 @@ IGL_INLINE bool readSTL(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::readSTL<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template bool igl::readSTL<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, 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 bool igl::readSTL<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template bool igl::readSTL<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);

+ 2 - 0
include/igl/read_triangle_mesh.cpp

@@ -208,6 +208,8 @@ IGL_INLINE bool igl::read_triangle_mesh(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template bool igl::read_triangle_mesh<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
 template bool igl::read_triangle_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(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> >&);
 template bool igl::read_triangle_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(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> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&);
 template bool igl::read_triangle_mesh<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);

+ 2 - 0
include/igl/remove_duplicate_vertices.cpp

@@ -68,6 +68,8 @@ IGL_INLINE void igl::remove_duplicate_vertices(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template void igl::remove_duplicate_vertices<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, 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::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, double, 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> >&);
+// generated by autoexplicit.sh
 template void igl::remove_duplicate_vertices<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -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::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<float, -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> >&);
 // generated by autoexplicit.sh
 template void igl::remove_duplicate_vertices<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, 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, 3, 1, -1, 3> >&);

+ 100 - 0
include/igl/screen_space_selection.cpp

@@ -0,0 +1,100 @@
+#include "screen_space_selection.h"
+
+#include <igl/AABB.h>
+#include <igl/winding_number.h>
+#include <igl/project.h>
+#include <igl/unproject.h>
+#include <igl/Hit.h>
+#include <igl/parallel_for.h>
+
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedM,
+  typename DerivedN,
+  typename DerivedO,
+  typename Ltype,
+  typename DerivedW,
+  typename Deriveda>
+IGL_INLINE void igl::screen_space_selection(
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
+  const igl::AABB<DerivedV, 3> & tree,
+  const Eigen::MatrixBase<DerivedM>& model,
+  const Eigen::MatrixBase<DerivedN>& proj,
+  const Eigen::MatrixBase<DerivedO>& viewport,
+  const std::vector<Eigen::Matrix<Ltype,1,2> > & L,
+  Eigen::PlainObjectBase<DerivedW> & W,
+  Eigen::PlainObjectBase<Deriveda> & and_visible)
+{
+  typedef typename DerivedV::Scalar Scalar;
+  screen_space_selection(V,model,proj,viewport,L,W);
+  const Eigen::RowVector3d origin =
+    (model.inverse().col(3)).head(3).template cast<Scalar>();
+  igl::parallel_for(V.rows(),[&](const int i)
+  {
+    // Skip unselected points
+    if(W(i)<0.5){ return; }
+    igl::Hit hit;
+    tree.intersect_ray(V,F,origin,V.row(i)-origin,hit);
+    and_visible(i) = !(hit.t>1e-5 && hit.t<(1-1e-5));
+  });
+}
+
+template <
+  typename DerivedV,
+  typename DerivedM,
+  typename DerivedN,
+  typename DerivedO,
+  typename Ltype,
+  typename DerivedW>
+IGL_INLINE void igl::screen_space_selection(
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedM>& model,
+  const Eigen::MatrixBase<DerivedN>& proj,
+  const Eigen::MatrixBase<DerivedO>& viewport,
+  const std::vector<Eigen::Matrix<Ltype,1,2> > & L,
+  Eigen::PlainObjectBase<DerivedW> & W)
+{
+  typedef typename DerivedV::Scalar Scalar;
+  Eigen::Matrix<Scalar,Eigen::Dynamic,2> P(L.size(),2);
+  Eigen::Matrix<int,Eigen::Dynamic,2> E(L.size(),2);
+  for(int i = 0;i<E.rows();i++)
+  { 
+    P.row(i) = L[i].template cast<Scalar>();
+    E(i,0) = i; 
+    E(i,1) = (i+1)%E.rows(); 
+  }
+  return screen_space_selection(V,model,proj,viewport,P,E,W);
+}
+
+template <
+  typename DerivedV,
+  typename DerivedM,
+  typename DerivedN,
+  typename DerivedO,
+  typename DerivedP,
+  typename DerivedE,
+  typename DerivedW>
+IGL_INLINE void igl::screen_space_selection(
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedM>& model,
+  const Eigen::MatrixBase<DerivedN>& proj,
+  const Eigen::MatrixBase<DerivedO>& viewport,
+  const Eigen::MatrixBase<DerivedP> & P,
+  const Eigen::MatrixBase<DerivedE> & E,
+  Eigen::PlainObjectBase<DerivedW> & W)
+{
+  // project all mesh vertices to 2D
+  DerivedV V2;
+  igl::project(V,model,proj,viewport,V2);
+  // In 2D this uses O(N*M) naive algorithm.
+  igl::winding_number(P,E,V2,W);
+  W = W.array().abs().eval();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::screen_space_selection<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, float, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Array<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&, igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3> const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, std::vector<Eigen::Matrix<float, 1, 2, 1, 1, 2>, std::allocator<Eigen::Matrix<float, 1, 2, 1, 1, 2> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Array<double, -1, 1, 0, -1, 1> >&);
+template void igl::screen_space_selection<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, float, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, std::vector<Eigen::Matrix<float, 1, 2, 1, 1, 2>, std::allocator<Eigen::Matrix<float, 1, 2, 1, 1, 2> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif

+ 105 - 0
include/igl/screen_space_selection.h

@@ -0,0 +1,105 @@
+#ifndef IGL_SCREEN_SPACE_SELECTION_H
+#define IGL_SCREEN_SPACE_SELECTION_H
+
+#include "igl/igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+// Forward declaration
+namespace igl { template <typename DerivedV, int DIM> class AABB; }
+
+namespace igl
+{
+  // Given a mesh, a camera  determine which points are inside of a given 2D
+  // screen space polygon **culling points based on self-occlusion.**
+  //
+  // Inputs:
+  //   V  #V by 3 list of mesh vertex positions
+  //   F  #F by 3 list of mesh triangle indices into rows of V
+  //   tree  precomputed bounding volume heirarchy
+  //   model  4 by 4 camera model-view matrix
+  //   proj  4 by 4 camera projection matrix (perspective or orthoraphic)
+  //   viewport  4-vector containing camera viewport
+  //   L  #L by 2 list of 2D polygon vertices (in order)
+  // Outputs:
+  //   W  #V by 1 list of winding numbers (|W|>0.5 indicates inside)
+  //   and_visible  #V by 1 list of visibility values (only correct for vertices
+  //     with |W|>0.5)
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedM,
+    typename DerivedN,
+    typename DerivedO,
+    typename Ltype,
+    typename DerivedW,
+    typename Deriveda>
+  IGL_INLINE void screen_space_selection(
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
+    const igl::AABB<DerivedV, 3> & tree,
+    const Eigen::MatrixBase<DerivedM>& model,
+    const Eigen::MatrixBase<DerivedN>& proj,
+    const Eigen::MatrixBase<DerivedO>& viewport,
+    const std::vector<Eigen::Matrix<Ltype,1,2> > & L,
+    Eigen::PlainObjectBase<DerivedW> & W,
+    Eigen::PlainObjectBase<Deriveda> & and_visible);
+  // Given a mesh, a camera  determine which points are inside of a given 2D
+  // screen space polygon
+  //
+  // Inputs:
+  //   V  #V by 3 list of mesh vertex positions
+  //   model  4 by 4 camera model-view matrix
+  //   proj  4 by 4 camera projection matrix (perspective or orthoraphic)
+  //   viewport  4-vector containing camera viewport
+  //   L  #L by 2 list of 2D polygon vertices (in order)
+  // Outputs:
+  //   W  #V by 1 list of winding numbers (|W|>0.5 indicates inside)
+  template <
+    typename DerivedV,
+    typename DerivedM,
+    typename DerivedN,
+    typename DerivedO,
+    typename Ltype,
+    typename DerivedW>
+  IGL_INLINE void screen_space_selection(
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedM>& model,
+    const Eigen::MatrixBase<DerivedN>& proj,
+    const Eigen::MatrixBase<DerivedO>& viewport,
+    const std::vector<Eigen::Matrix<Ltype,1,2> > & L,
+    Eigen::PlainObjectBase<DerivedW> & W);
+  // Given a mesh, a camera  determine which points are inside of a given 2D
+  // screen space polygon
+  //
+  // Inputs:
+  //   V  #V by 3 list of mesh vertex positions
+  //   model  4 by 4 camera model-view matrix
+  //   proj  4 by 4 camera projection matrix (perspective or orthoraphic)
+  //   viewport  4-vector containing camera viewport
+  //   P  #P by 2 list of screen space polygon vertices
+  //   E  #E by 2 list of screen space edges as indices into rows of P
+  // Outputs:
+  //   W  #V by 1 list of winding numbers (|W|>0.5 indicates inside)
+  template <
+    typename DerivedV,
+    typename DerivedM,
+    typename DerivedN,
+    typename DerivedO,
+    typename DerivedP,
+    typename DerivedE,
+    typename DerivedW>
+  IGL_INLINE void screen_space_selection(
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedM>& model,
+    const Eigen::MatrixBase<DerivedN>& proj,
+    const Eigen::MatrixBase<DerivedO>& viewport,
+    const Eigen::MatrixBase<DerivedP> & P,
+    const Eigen::MatrixBase<DerivedE> & E,
+    Eigen::PlainObjectBase<DerivedW> & W);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "screen_space_selection.cpp"
+#endif
+  
+#endif

+ 4 - 0
include/igl/sharp_edges.cpp

@@ -44,6 +44,10 @@ IGL_INLINE void igl::sharp_edges(
   {
     bool u_is_sharp = false;
     // Consider every pair of incident faces
+    //
+    // if there are 3 faces (non-manifold) it appears to follow that the edge
+    // must be sharp if angle<60. Could skip those (they're likely small number
+    // anyway).
     for(int i = 0;i<uE2E[u].size();i++)
     for(int j = i+1;j<uE2E[u].size();j++)
     {

+ 2 - 9
include/igl/signed_angle.cpp

@@ -47,23 +47,16 @@ IGL_INLINE typename DerivedA::Scalar igl::signed_angle(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>, Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
+template Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>, Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&);
 template Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);
-// generated by autoexplicit.sh
 template Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
-// generated by autoexplicit.sh
 template Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
-// generated by autoexplicit.sh
 template Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
-// generated by autoexplicit.sh
 template Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
-// generated by autoexplicit.sh
 template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&);
-// generated by autoexplicit.sh
 template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&);
-// generated by autoexplicit.sh
 template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
-// generated by autoexplicit.sh
 template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);
 template Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Matrix<float, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&);
 template Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<float, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&);

+ 2 - 0
include/igl/slice.cpp

@@ -188,6 +188,8 @@ IGL_INLINE DerivedX igl::slice(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<double, -1, 2, 0, -1, 2>, 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::DenseBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>>(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, int);
 template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::slice<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>>(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &);
 template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::slice<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);

+ 1 - 0
include/igl/slim.cpp

@@ -593,6 +593,7 @@ IGL_INLINE void igl::slim_update_weights_and_closest_rotations_with_jacobians(co
           // change local step
           closest_sing_vec << s1_min, s2_min, s3_min;
           ri = ui * closest_sing_vec.asDiagonal() * vi.transpose();
+          break;
         }
         default: assert(false);
       }

+ 4 - 0
include/igl/solid_angle.cpp

@@ -57,6 +57,10 @@ IGL_INLINE typename DerivedA::Scalar igl::solid_angle(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>, Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>, Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>, Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>, Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, 1, 2, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&);
+// generated by autoexplicit.sh
 template Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
 // generated by autoexplicit.sh
 template Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);

+ 5 - 6
include/igl/copyleft/swept_volume.cpp → include/igl/swept_volume.cpp

@@ -1,11 +1,11 @@
 #include "swept_volume.h"
-#include "../swept_volume_bounding_box.h"
-#include "../swept_volume_signed_distance.h"
-#include "../voxel_grid.h"
+#include "swept_volume_bounding_box.h"
+#include "swept_volume_signed_distance.h"
+#include "voxel_grid.h"
 #include "marching_cubes.h"
 #include <iostream>
 
-IGL_INLINE void igl::copyleft::swept_volume(
+IGL_INLINE void igl::swept_volume(
   const Eigen::MatrixXd & V,
   const Eigen::MatrixXi & F,
   const std::function<Eigen::Affine3d(const double t)> & transform,
@@ -18,7 +18,6 @@ IGL_INLINE void igl::copyleft::swept_volume(
   using namespace std;
   using namespace Eigen;
   using namespace igl;
-  using namespace igl::copyleft;
 
   const auto & Vtransform = 
     [&V,&transform](const size_t vi,const double t)->RowVector3d
@@ -45,5 +44,5 @@ IGL_INLINE void igl::copyleft::swept_volume(
   VectorXd S;
   swept_volume_signed_distance(V,F,transform,steps,GV,res,h,isolevel,S);
   S.array()-=isolevel;
-  marching_cubes(S,GV,res(0),res(1),res(2),SV,SF);
+  marching_cubes(S,GV,res(0),res(1),res(2),0,SV,SF);
 }

+ 39 - 0
include/igl/swept_volume.h

@@ -0,0 +1,39 @@
+#ifndef IGL_SWEPT_VOLUME_H
+#define IGL_SWEPT_VOLUME_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+namespace igl
+{
+  // Compute the surface of the swept volume of a solid object with surface
+  // (V,F) mesh under going rigid motion.
+  // 
+  // Inputs:
+  //   V  #V by 3 list of mesh positions in reference pose
+  //   F  #F by 3 list of mesh indices into V
+  //   transform  function handle so that transform(t) returns the rigid
+  //     transformation at time t∈[0,1]
+  //   steps  number of time steps: steps=3 --> t∈{0,0.5,1}
+  //   grid_res  number of grid cells on the longest side containing the
+  //     motion (isolevel+1 cells will also be added on each side as padding)
+  //   isolevel  distance level to be contoured as swept volume
+  // Outputs:
+  //   SV  #SV by 3 list of mesh positions of the swept surface
+  //   SF  #SF by 3 list of mesh faces into SV
+  IGL_INLINE void swept_volume(
+    const Eigen::MatrixXd & V,
+    const Eigen::MatrixXi & F,
+    const std::function<Eigen::Affine3d(const double t)> & transform,
+    const size_t steps,
+    const size_t grid_res,
+    const size_t isolevel,
+    Eigen::MatrixXd & SV,
+    Eigen::MatrixXi & SF);
+  
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "swept_volume.cpp"
+#endif
+
+#endif

+ 113 - 0
include/igl/tetrahedralized_grid.cpp

@@ -0,0 +1,113 @@
+#include "tetrahedralized_grid.h"
+#include "grid.h"
+
+template <
+  typename DerivedGV,
+  typename DerivedGT>
+IGL_INLINE void igl::tetrahedralized_grid(
+  const int nx,
+  const int ny,
+  const int nz,
+  const TetrahedralizedGripType type,
+  Eigen::PlainObjectBase<DerivedGV> & GV,
+  Eigen::PlainObjectBase<DerivedGT> & GT)
+{
+  Eigen::RowVector3i res(nx,ny,nz);
+  igl::grid(res,GV);
+  return igl::tetrahedralized_grid(GV,res,GT);
+}
+
+template <
+  typename DerivedGV,
+  typename Derivedside,
+  typename DerivedGT>
+IGL_INLINE void igl::tetrahedralized_grid(
+  const Eigen::MatrixBase<DerivedGV> & GV,
+  const Eigen::MatrixBase<Derivedside> & side,
+  const TetrahedralizedGripType type,
+  Eigen::PlainObjectBase<DerivedGT> & GT)
+{
+  const int nx = side(0);
+  const int ny = side(1);
+  const int nz = side(2);
+  typedef typename DerivedGT::Scalar Index;
+  const int m = (nx-1)*(ny-1)*(nz-1);
+  // Rotationally symmetric
+  int nt = -1;
+  switch(type)
+  {
+    default: assert(false); break;
+    case TETRAHEDRALIZED_GRID_TYPE_5: nt = 5; break;
+    case TETRAHEDRALIZED_GRID_TYPE_6_ROTATIONAL: nt = 6; break;
+  }
+  GT.resize(m*nt,4);
+  {
+    int u = 0;
+    for(int i = 0;i<nx-1;i++)
+    {
+      for(int j = 0;j<ny-1;j++)
+      {
+        for(int k = 0;k<nz-1;k++)
+        {
+          int v1 = (i+0)+nx*((j+0)+ny*(k+0));
+          int v2 = (i+0)+nx*((j+1)+ny*(k+0));
+          int v3 = (i+1)+nx*((j+0)+ny*(k+0));
+          int v4 = (i+1)+nx*((j+1)+ny*(k+0));
+          int v5 = (i+0)+nx*((j+0)+ny*(k+1));
+          int v6 = (i+0)+nx*((j+1)+ny*(k+1));
+          int v7 = (i+1)+nx*((j+0)+ny*(k+1));
+          int v8 = (i+1)+nx*((j+1)+ny*(k+1));
+          switch(type)
+          {
+            default: assert(false); break;
+            case TETRAHEDRALIZED_GRID_TYPE_6_ROTATIONAL:
+              // Rotationally symmetric
+              GT.row(u*nt+0) << v1,v3,v8,v7;
+              GT.row(u*nt+1) << v1,v8,v5,v7;
+              GT.row(u*nt+2) << v1,v3,v4,v8;
+              GT.row(u*nt+3) << v1,v4,v2,v8;
+              GT.row(u*nt+4) << v1,v6,v5,v8;
+              GT.row(u*nt+5) << v1,v2,v6,v8;
+              break;
+            case TETRAHEDRALIZED_GRID_TYPE_5:
+            {
+              // Five
+              bool flip = true;
+              if(((bool(i%2))^ (bool(j%2)))^ (bool(k%2)))
+              {
+                std::swap(v1,v3);
+                std::swap(v2,v4);
+                std::swap(v5,v7);
+                std::swap(v6,v8);
+                flip = false;
+              }
+              GT.row(u*nt+0) << v5,v3,v2,v1;
+              GT.row(u*nt+1) << v3,v2,v8,v5;
+              GT.row(u*nt+2) << v3,v4,v8,v2;
+              GT.row(u*nt+3) << v3,v8,v7,v5;
+              GT.row(u*nt+4) << v2,v6,v8,v5;
+              if(flip)
+              {
+                std::swap(GT(u*nt+0,0),GT(u*nt+0,1));
+                std::swap(GT(u*nt+1,0),GT(u*nt+1,1));
+                std::swap(GT(u*nt+2,0),GT(u*nt+2,1));
+                std::swap(GT(u*nt+3,0),GT(u*nt+3,1));
+                std::swap(GT(u*nt+4,0),GT(u*nt+4,1));
+              }
+              break;
+            }
+          }
+          u++;
+        }
+      }
+    }
+    assert(u == m);
+  }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::tetrahedralized_grid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, 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, 3, 1, 1, 3> > const&, igl::TetrahedralizedGripType, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+#endif

+ 67 - 0
include/igl/tetrahedralized_grid.h

@@ -0,0 +1,67 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2020 Alec Jacobson <[email protected]>
+// 
+// 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_TETRAHEDRALIZED_GRID_H
+#define IGL_TETRAHEDRALIZED_GRID_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  enum TetrahedralizedGripType
+  {
+    TETRAHEDRALIZED_GRID_TYPE_5 = 0,
+    TETRAHEDRALIZED_GRID_TYPE_6_ROTATIONAL = 1,
+    NUM_TETRAHEDRALIZED_GRID_TYPE = 2
+  };
+  // Construct vertices of a regular grid, suitable for input to
+  // `igl::marching_tets`
+  //
+  // Inputs:
+  //   nx  number of grid vertices in x direction
+  //   ny  number of grid vertices in y direction
+  //   nz  number of grid vertices in z direction
+  //   type  type of tetrahedralization of cube to use
+  // Outputs:
+  //   GV  nx*ny*nz by 3 list of grid vertex positions
+  //   GT  (nx-1)*(ny-1)*(nz-1)*k by 4 list of tetrahedron indices into rows of
+  //     V, where k is the number of tets per cube (dependent on type)
+  //
+  //   See also: triangulated_grid, quad_grid
+  template <
+    typename DerivedGV,
+    typename DerivedGT>
+  IGL_INLINE void tetrahedralized_grid(
+    const int nx,
+    const int ny,
+    const int nz,
+    const TetrahedralizedGripType type,
+    Eigen::PlainObjectBase<DerivedGV> & GV,
+    Eigen::PlainObjectBase<DerivedGT> & GT);
+  //
+  // Inputs:
+  //   GV  nx*ny*nz by 3 list of grid vertex positions
+  //   side  3-long list {nx,ny,nz} see above
+  //   type  type of tetrahedralization of cube to use
+  // Outputs:
+  //   GT  (nx-1)*(ny-1)*(nz-1)*k by 4 list of tetrahedron indices into rows of
+  //     V, where k is the number of tets per cube (dependent on type)
+  //
+  template <
+    typename DerivedGV,
+    typename Derivedside,
+    typename DerivedGT>
+  IGL_INLINE void tetrahedralized_grid(
+    const Eigen::MatrixBase<DerivedGV> & GV,
+    const Eigen::MatrixBase<Derivedside> & side,
+    const TetrahedralizedGripType type,
+    Eigen::PlainObjectBase<DerivedGT> & GT);
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "tetrahedralized_grid.cpp"
+#endif
+#endif 
+

+ 0 - 2
include/igl/triangle/triangulate.cpp

@@ -174,8 +174,6 @@ IGL_INLINE void igl::triangle::triangulate(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-// generated by autoexplicit.sh
 template void igl::triangle::triangulate<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-// generated by autoexplicit.sh
 template void igl::triangle::triangulate<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::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&, 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> >&);
 #endif

+ 4 - 0
include/igl/unique_rows.cpp

@@ -75,6 +75,10 @@ IGL_INLINE void igl::unique_rows(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template void igl::unique_rows<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, 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::unique_rows<Eigen::Matrix<double, -1, 2, 0, -1, 2>, 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::DenseBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > 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> >&);
+// generated by autoexplicit.sh
 template void igl::unique_rows<Eigen::Matrix<unsigned int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<unsigned int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned 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> >&);
 // generated by autoexplicit.sh
 template void igl::unique_rows<Eigen::Matrix<unsigned int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<unsigned int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);

+ 1 - 0
include/igl/unproject.cpp

@@ -72,4 +72,5 @@ template Eigen::Matrix<double, 3, 1, 0, 3, 1> igl::unproject<double>(Eigen::Matr
 template void igl::unproject<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
 template void igl::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+template void igl::unproject<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
 #endif

+ 6 - 0
include/igl/unproject_onto_mesh.h

@@ -29,6 +29,12 @@ namespace igl
   //    fid  id of the first face hit
   //    bc  barycentric coordinates of hit
   // Returns true if there's a hit
+  //
+  // Example:
+  //   igl::opengl::glfw::Viewer vr;
+  //   ...
+  //   igl::unproject_onto_mesh(
+  //     pos,vr.core().view,vr.core().proj,vr.core().viewport,V,F,fid,bc);
   template < typename DerivedV, typename DerivedF, typename Derivedbc>
   IGL_INLINE bool unproject_onto_mesh(
     const Eigen::Vector2f& pos,

+ 25 - 0
include/igl/voxel_grid.cpp

@@ -63,9 +63,34 @@ IGL_INLINE void igl::voxel_grid(
   GV.rowwise() += offset;
 }
 
+template <
+  typename DerivedV,
+  typename DerivedGV,
+  typename Derivedside>
+IGL_INLINE void igl::voxel_grid(
+  const Eigen::MatrixBase<DerivedV> & V, 
+  const typename DerivedV::Scalar offset,
+  const int s,
+  const int pad_count,
+  Eigen::PlainObjectBase<DerivedGV> & GV,
+  Eigen::PlainObjectBase<Derivedside> & side)
+{
+  typedef typename DerivedV::Scalar Scalar;
+  Eigen::AlignedBox<Scalar,3> box;
+  typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
+  assert(V.cols() == 3 && "V must contain positions in 3D");
+  RowVector3S min_ext = V.colwise().minCoeff().array() - offset;
+  RowVector3S max_ext = V.colwise().maxCoeff().array() + offset;
+  box.extend(min_ext.transpose());
+  box.extend(max_ext.transpose());
+  return igl::voxel_grid(box,s,1,GV,side);
+}
+
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template void igl::voxel_grid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&);
+// generated by autoexplicit.sh
 template void igl::voxel_grid<float, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 3, 1, 0, 3, 1> >(Eigen::AlignedBox<float, 3> const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> >&);
 // generated by autoexplicit.sh
 template void igl::voxel_grid<float, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3> >(Eigen::AlignedBox<float, 3> const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&);

+ 11 - 0
include/igl/voxel_grid.h

@@ -32,6 +32,17 @@ namespace igl
     const int pad_count,
     Eigen::PlainObjectBase<DerivedGV> & GV,
     Eigen::PlainObjectBase<Derivedside> & side);
+  template <
+    typename DerivedV,
+    typename DerivedGV,
+    typename Derivedside>
+  IGL_INLINE void voxel_grid(
+    const Eigen::MatrixBase<DerivedV> & V, 
+    const typename DerivedV::Scalar offset,
+    const int s,
+    const int pad_count,
+    Eigen::PlainObjectBase<DerivedGV> & GV,
+    Eigen::PlainObjectBase<Derivedside> & side);
 }
 #ifndef IGL_STATIC_LIBRARY
 #  include "voxel_grid.cpp"

+ 2 - 0
include/igl/winding_number.cpp

@@ -93,6 +93,8 @@ IGL_INLINE typename DerivedV::Scalar igl::winding_number(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template void igl::winding_number<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
 template Eigen::Matrix<double, -1, 3, 1, -1, 3>::Scalar igl::winding_number<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
 // generated by autoexplicit.sh
 template Eigen::Matrix<double, -1, 3, 1, -1, 3>::Scalar igl::winding_number<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);

+ 7 - 9
include/igl/writeDMAT.cpp

@@ -84,18 +84,16 @@ IGL_INLINE bool igl::writeDMAT(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-// generated by autoexplicit.sh
-template bool igl::writeDMAT<Eigen::Matrix<int, 3, 1, 0, 3, 1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> > const&, bool);
-// generated by autoexplicit.sh
-template bool igl::writeDMAT<Eigen::Matrix<float, -1, -1, 1, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 1, -1, -1> > const&, bool);
-// generated by autoexplicit.sh
-template bool igl::writeDMAT<Eigen::Matrix<float, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, bool);
-// generated by autoexplicit.sh
-template bool igl::writeDMAT<Eigen::Matrix<float, -1, 1, 0, -1, 1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, bool);
 template bool igl::writeDMAT<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, bool);
 template bool igl::writeDMAT<Eigen::Matrix<double, 1, 3, 1, 1, 3> >(std::string, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<float, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<float, -1, -1, 1, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 1, -1, -1> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<float, -1, 1, 0, -1, 1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, bool);
 template bool igl::writeDMAT<Eigen::Matrix<float, 1, 3, 1, 1, 3> >(std::string, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, bool);
 template bool igl::writeDMAT<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool);
 template bool igl::writeDMAT<Eigen::Matrix<int, -1, 2, 0, -1, 2> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, bool);
-template bool igl::writeDMAT<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<int, 1, 3, 1, 1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<int, 3, 1, 0, 3, 1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> > const&, bool);
 #endif

+ 1 - 1
include/igl/writePLY.cpp

@@ -147,7 +147,7 @@ bool writePLY(
         _ed.resize(ED.size());
         Eigen::Map<Eigen::Matrix<EDScalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > >( &_ed[0], ED.rows(), ED.cols() ) = ED;
 
-        file.add_properties_to_element("face", FDheader,
+        file.add_properties_to_element("edge", EDheader,
             tynyply_type<EDScalar>(), ED.rows(), reinterpret_cast<uint8_t*>( &_ed[0] ), tinyply::Type::INVALID, 0);
     }
 

+ 6 - 0
include/igl/xml/writeDAE.cpp

@@ -135,3 +135,9 @@ IGL_INLINE bool igl::xml::writeDAE(
   delete doc;
   return ret;
 }
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::xml::writeDAE<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+#endif

+ 5 - 0
tests/CMakeLists.txt

@@ -52,6 +52,11 @@ if(LIBIGL_WITH_MOSEK)
   target_sources(libigl_tests PRIVATE ${TEST_SRC_FILES} ${TEST_INC_FILES})
 
   target_link_libraries(libigl_tests PUBLIC igl::mosek)
+  # fix mosek
+  IF(APPLE)
+    INCLUDE(../cmake/OSXFixDylibReferences.cmake)
+    OSX_FIX_DYLIB_REFERENCES(libigl_tests "${MOSEK_LIBRARIES}")
+  ENDIF()
 endif()
 
 if(LIBIGL_WITH_CGAL)

+ 32 - 30
tests/include/igl/embree/EmbreeIntersector.cpp

@@ -15,9 +15,32 @@ TEST_CASE("EmbreeIntersector: cube", "[igl/embree]")
   igl::embree::EmbreeIntersector embree;
   embree.init(V.cast<float>(),F.cast<int>());
 
-  const int expected_id[] = {4,8,5,2,7,0};
+  // These are not expected to be exact if the hit is on a vertex of edge.
+  const int expected_id[] =  {4,8,5,2,7,0};
   const float expected_u[] = {0.5,0.5,0.5,0.5,0.5,0.5};
   const float expected_v[] = {0.5,0.0,0.0,0.0,0.5,0.0};
+  Eigen::MatrixXd hit_P(6,3);
+  for (int dim=0; dim<6; ++dim)
+  {
+    hit_P.row(dim) = 
+      V.row(F(expected_id[dim],0))*(1.f - expected_u[dim] - expected_v[dim])+
+      V.row(F(expected_id[dim],1))*expected_u[dim] + 
+      V.row(F(expected_id[dim],2))*expected_v[dim];
+  }
+  const auto test_hit = [&](const bool hitP, const igl::Hit& hit, const int dim)
+  {
+    CHECK(hitP);
+    if(hitP)
+    {
+      const Eigen::RowVectorXd hit_p = 
+        V.row(F(hit.id,0))*(1.f - hit.u - hit.v) +
+        V.row(F(hit.id,1))*hit.u + 
+        V.row(F(hit.id,2))*hit.v;
+      // hits will be along diagonal edge so expected_id may be different
+      test_common::assert_near(hit_P.row(dim),hit_p,epsilon);
+    }
+  };
+
 
   // Shoot ray from inside out
   for (int dim=0; dim<6; ++dim)
@@ -28,11 +51,7 @@ TEST_CASE("EmbreeIntersector: cube", "[igl/embree]")
     dir[dim/2] = dim%2 ? -1 : 1;
     igl::Hit hit;
     bool hitP = embree.intersectRay(pos, dir, hit);
-    CHECK(hitP);
-    REQUIRE(hit.t == Approx(0.5).margin(epsilon));
-    REQUIRE(hit.id == expected_id[dim]);
-    REQUIRE(hit.u == Approx(expected_u[dim]).margin(epsilon));
-    REQUIRE(hit.v == Approx(expected_v[dim]).margin(epsilon));
+    test_hit(hitP,hit,dim);
   }
 
   // Shoot ray from outside in
@@ -46,11 +65,7 @@ TEST_CASE("EmbreeIntersector: cube", "[igl/embree]")
 
     igl::Hit hit;
     bool hitP = embree.intersectRay(pos, dir, hit);
-    CHECK(hitP);
-    REQUIRE(hit.t == Approx(0.5).margin(epsilon));
-    REQUIRE(hit.id == expected_id[dim]);
-    REQUIRE(hit.u == Approx(expected_u[dim]).margin(epsilon));
-    REQUIRE(hit.v == Approx(expected_v[dim]).margin(epsilon));
+    test_hit(hitP,hit,dim);
   }
 
   // Rays that miss
@@ -69,29 +84,16 @@ TEST_CASE("EmbreeIntersector: cube", "[igl/embree]")
 
   // intersect beam
   {
-    Eigen::Vector3f pos(-0.5,-0.5,1);
-    Eigen::Vector3f dir(0,0,-1);
-
-    igl::Hit hit;
-    bool hitP = embree.intersectBeam(pos, dir, hit);
-    CHECK(hitP);
-    REQUIRE(hit.t == Approx(0.5).margin(epsilon));
-    REQUIRE(hit.id == 7);
-    REQUIRE(hit.u == Approx(0).margin(epsilon));
-    REQUIRE(hit.v == Approx(1).margin(epsilon));
-  }
-
-  {
-    Eigen::Vector3f pos(0.5,-1,0.5);
-    Eigen::Vector3f dir(0,1,0);
+    Eigen::Vector3f pos(1.75,0.25,0);
+    Eigen::Vector3f dir(-1,0,0);
 
     igl::Hit hit;
     bool hitP = embree.intersectBeam(pos, dir, hit);
     CHECK(hitP);
-    REQUIRE(hit.t == Approx(0.5).margin(epsilon));
-    REQUIRE(hit.id == 2);
-    REQUIRE(hit.u == Approx(0).margin(epsilon));
-    REQUIRE(hit.v == Approx(0).margin(epsilon));
+    REQUIRE(hit.t == Approx(1.25).margin(epsilon));
+    REQUIRE(hit.id == 4);
+    REQUIRE(hit.u == Approx(0.5).margin(epsilon));
+    REQUIRE(hit.v == Approx(0.25).margin(epsilon));
   }
 }
 

+ 90 - 0
tests/include/igl/readMESH.cpp

@@ -0,0 +1,90 @@
+#include <test_common.h>
+
+#include <catch2/catch.hpp>
+
+#include <igl/readMESH.h>
+#include <fstream>
+
+TEST_CASE("readMESH: single-tet","[igl]")
+{
+  std::ofstream("test.mesh")<< R"(MeshVersionFormatted 1
+Dimension 3
+Vertices
+4
+0 0 0 0
+0 0 1 0
+0 1 0 0
+1 0 0 0
+Triangles
+0
+Tetrahedra
+1
+1 2 3 4 0
+End
+  )";
+
+  Eigen::MatrixXd V;
+  Eigen::MatrixXi T,F;
+  igl::readMESH("test.mesh",V,T,F);
+  REQUIRE(V.rows() == 4);
+  REQUIRE(T.rows() == 1);
+  REQUIRE(T(0,0) == 0);
+  REQUIRE(F.rows() == 0);
+
+}
+
+
+TEST_CASE("readMESH: no-triangles-line","[igl]")
+{
+  std::ofstream("test.mesh")<< R"(MeshVersionFormatted 1
+Dimension 3
+Vertices
+4
+0 0 0 0
+0 0 1 0
+0 1 0 0
+1 0 0 0
+Tetrahedra
+1
+1 2 3 4 0
+  )";
+
+  Eigen::MatrixXd V;
+  Eigen::MatrixXi T,F;
+  igl::readMESH("test.mesh",V,T,F);
+  REQUIRE(V.rows() == 4);
+  REQUIRE(T.rows() == 1);
+  REQUIRE(T(0,0) == 0);
+  REQUIRE(F.rows() == 0);
+
+}
+
+
+TEST_CASE("readMESH: mesh-version-formatted-2","[igl]")
+{
+  std::ofstream("test.mesh")<< R"(MeshVersionFormatted 2
+Dimension 3
+Vertices
+4
+0 0 0 0
+0 0 1 0
+0 1 0 0
+1 0 0 0
+Triangles
+0
+Tetrahedra
+1
+1 2 3 4 0
+End
+  )";
+
+  Eigen::MatrixXd V;
+  Eigen::MatrixXi T,F;
+  igl::readMESH("test.mesh",V,T,F);
+  REQUIRE(V.rows() == 4);
+  REQUIRE(T.rows() == 1);
+  REQUIRE(T(0,0) == 0);
+  REQUIRE(F.rows() == 0);
+
+}
+

+ 17 - 5
tests/include/igl/writePLY.cpp

@@ -27,9 +27,16 @@ TEST_CASE("writePLY: bunny.ply", "[igl]")
     Eigen::MatrixXd VD2(V1.rows(),VD1.cols()+1);
     VD2<<VD1,dummy_data;
 
+    Fheader1.push_back("face_data");
+    Eigen::VectorXd face_data(F1.rows());
+    for(size_t i=0;i<F1.rows();++i)
+        face_data(i)=(double)i;
+    Eigen::MatrixXd FD2(F1.rows(),FD1.cols()+1);
+    // there is no face data in the input file
+    FD2<<face_data;
 
     // test that saving preserves all the data, including new data column
-    REQUIRE (igl::writePLY("test_bunny.ply", V1, F1, E1, N1, UV1, VD2, Vheader1, FD1,Fheader1, ED1, Eheader1, comments1, igl::FileEncoding::Binary));
+    REQUIRE (igl::writePLY("test_bunny.ply", V1, F1, E1, N1, UV1, VD2, Vheader1, FD2,Fheader1, ED1, Eheader1, comments1, igl::FileEncoding::Binary));
 
     Eigen::MatrixXd V,N,UV,VD,FD,ED;
     Eigen::MatrixXi F,E;
@@ -65,10 +72,15 @@ TEST_CASE("writePLY: bunny.ply", "[igl]")
     REQUIRE (Vheader[1] == "intensity" );
     REQUIRE (Vheader[2] == "dummy_data" );
 
-    // no Face data or edge data
-    REQUIRE (FD.rows() == 0);
-    REQUIRE (FD.cols() == 0);
-    REQUIRE (Fheader.size() == 0);
+    // Face should have only one column
+    REQUIRE (Fheader.size() == 1);
+    REQUIRE (Fheader[0] == "face_data" );
+    REQUIRE (FD.rows() == F.rows());
+    REQUIRE (FD.cols() == 1);
+
+    // the dummy column contents check
+    for(size_t i=0;i<F.rows();++i)
+        REQUIRE (FD(i,0) == (double)i);
 
     REQUIRE (ED.rows() == 0);
     REQUIRE (ED.cols() == 0);

+ 5 - 0
tutorial/112_Selection/CMakeLists.txt

@@ -0,0 +1,5 @@
+get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
+project(${PROJECT_NAME})
+
+add_executable(${PROJECT_NAME} main.cpp)
+target_link_libraries(${PROJECT_NAME} igl::core igl::opengl igl::opengl_glfw igl::opengl_glfw_imgui tutorials)

+ 66 - 0
tutorial/112_Selection/main.cpp

@@ -0,0 +1,66 @@
+#include <igl/opengl/glfw/Viewer.h>
+#include <igl/read_triangle_mesh.h>
+#include <igl/list_to_matrix.h>
+#include <igl/matlab_format.h>
+#include <igl/AABB.h>
+#include <igl/screen_space_selection.h>
+
+#include <igl/opengl/glfw/imgui/SelectionPlugin.h>
+
+int main(int argc, char *argv[])
+{
+  // Inline mesh of a cube
+  Eigen::MatrixXd V;
+  Eigen::MatrixXi F;
+  igl::read_triangle_mesh(
+    argc>1?argv[1]: TUTORIAL_SHARED_PATH "/armadillo.obj",V,F);
+
+  // Plot the mesh
+  igl::opengl::glfw::Viewer vr;
+  igl::opengl::glfw::imgui::SelectionPlugin plugin;
+  Eigen::VectorXd W = Eigen::VectorXd::Zero(V.rows());
+  Eigen::Array<double,Eigen::Dynamic,1> and_visible = 
+    Eigen::Array<double,Eigen::Dynamic,1>::Zero(V.rows());
+  const Eigen::MatrixXd CM = (Eigen::MatrixXd(2,3)<<
+      0.3,0.3,0.5,                 
+      255.0/255.0,228.0/255.0,58.0/255.0).finished();
+  bool only_visible = false;
+  const auto update = [&]()
+  {
+    const bool was_face_based = vr.data().face_based;
+    Eigen::VectorXd S = W;
+    if(only_visible) { S.array() *= and_visible; }
+    vr.data().set_data(S,0,1,igl::COLOR_MAP_TYPE_PLASMA,2);
+    vr.data().face_based = was_face_based;
+    vr.data().set_colormap(CM);
+  };
+  igl::AABB<Eigen::MatrixXd, 3> tree;
+  tree.init(V,F);
+  plugin.callback = [&]()
+  {
+    screen_space_selection(V,F,tree,vr.core().view,vr.core().proj,vr.core().viewport,plugin.L,W,and_visible);
+    update();
+  };
+  vr.callback_key_pressed = [&](decltype(vr) &,unsigned int key, int mod)
+  {
+    switch(key)
+    {
+      case ' ': only_visible = !only_visible; update(); return true;
+      case 'D': case 'd': W.setZero(); update(); return true;
+    }
+    return false;
+  };
+  std::cout<<R"(
+Usage:
+  [space]  Toggle whether to take visibility into account
+  D,d      Clear selection
+)";
+  vr.plugins.push_back(&plugin);
+  vr.data().set_mesh(V,F);
+  vr.data().set_face_based(true);
+  vr.core().background_color.head(3) = CM.row(0).head(3).cast<float>();
+  vr.data().line_color.head(3) = (CM.row(0).head(3)*0.5).cast<float>();
+  vr.data().show_lines = F.rows() < 20000;
+  update();
+  vr.launch();
+}

+ 0 - 3
tutorial/403_BoundedBiharmonicWeights/CMakeLists.txt

@@ -3,6 +3,3 @@ project(${PROJECT_NAME})
 
 add_executable(${PROJECT_NAME} main.cpp)
 target_link_libraries(${PROJECT_NAME} igl::core igl::opengl igl::opengl_glfw tutorials)
-if(TARGET igl::mosek)
-  target_link_libraries(${PROJECT_NAME} igl::mosek)
-endif()

+ 0 - 7
tutorial/403_BoundedBiharmonicWeights/main.cpp

@@ -1,10 +1,4 @@
 // Because of Mosek complications, we don't use static library if Mosek is used.
-#ifdef LIBIGL_WITH_MOSEK
-#ifdef IGL_STATIC_LIBRARY
-#undef IGL_STATIC_LIBRARY
-#endif
-#endif
-
 #include <igl/boundary_conditions.h>
 #include <igl/colon.h>
 #include <igl/column_to_quats.h>
@@ -19,7 +13,6 @@
 #include <igl/readTGF.h>
 #include <igl/opengl/glfw/Viewer.h>
 #include <igl/bbw.h>
-//#include <igl/embree/bone_heat.h>
 
 #include <Eigen/Geometry>
 #include <Eigen/StdVector>

+ 5 - 0
tutorial/608_RayTrace/CMakeLists.txt

@@ -0,0 +1,5 @@
+get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
+project(${PROJECT_NAME})
+
+add_executable(${PROJECT_NAME} main.cpp)
+target_link_libraries(${PROJECT_NAME} igl::core igl::embree igl::png tutorials)

+ 70 - 0
tutorial/608_RayTrace/main.cpp

@@ -0,0 +1,70 @@
+#include <igl/gaussian_curvature.h>
+#include <igl/massmatrix.h>
+#include <igl/invert_diag.h>
+#include <igl/read_triangle_mesh.h>
+#include <igl/png/writePNG.h>
+#include <igl/PI.h>
+#include <Eigen/Geometry>
+// embree
+#include <igl/embree/EmbreeRenderer.h>
+
+#include "tutorial_shared_path.h"
+
+#include <iostream>
+
+int main(int argc, char *argv[])
+{
+  int width=640;
+  int height=480;
+
+  Eigen::MatrixXd V;
+  Eigen::MatrixXi F;
+
+  const char *mesh_file=argc > 1 ? argv[1] : TUTORIAL_SHARED_PATH "/fertility.off";
+  const char *png_file=argc > 2 ? argv[2]: "fertility_curvature.png";
+
+  // Load mesh 
+  igl::read_triangle_mesh(mesh_file, V,F);
+  
+  Eigen::VectorXd K;
+  // Compute integral of Gaussian curvature
+  igl::gaussian_curvature(V,F,K);
+  // Compute mass matrix
+  Eigen::SparseMatrix<double> M,Minv;
+  igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_DEFAULT,M);
+  igl::invert_diag(M,Minv);
+  // Divide by area to get integral average
+  K = (Minv*K).eval();
+
+  // embree object
+  igl::embree::EmbreeRenderer er;
+  er.set_mesh(V,F,true);
+
+  //er.set_uniform_color(Eigen::RowVector3d(0.3,0.3,0.3));
+  er.set_data(K,igl::COLOR_MAP_TYPE_JET);
+
+  Eigen::Matrix3d rot_matrix;
+
+  // specify rotation
+  rot_matrix =  Eigen::AngleAxisd( 10*igl::PI/180.0, Eigen::Vector3d::UnitX())
+              * Eigen::AngleAxisd(  5*igl::PI/180.0, Eigen::Vector3d::UnitY())
+              * Eigen::AngleAxisd(  4*igl::PI/180.0, Eigen::Vector3d::UnitZ());
+  er.set_rot(rot_matrix);
+
+  er.set_zoom(1.5);
+  er.set_orthographic(false);
+     
+  Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> R(width, height);
+  Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> G(width, height);
+  Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> B(width, height);
+  Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> A(width, height);
+
+  // render view using embree
+  er.render_buffer(R,G,B,A);
+
+  std::cout<<"Rendered scene saved to "<<png_file<<std::endl;
+
+  // save to PNG file
+  igl::png::writePNG(R,G,B,A,png_file);
+  return 0;
+}

+ 3 - 3
tutorial/705_MarchingCubes/main.cpp

@@ -1,4 +1,4 @@
-#include <igl/copyleft/marching_cubes.h>
+#include <igl/marching_cubes.h>
 #include <igl/signed_distance.h>
 #include <igl/read_triangle_mesh.h>
 #include <igl/opengl/glfw/Viewer.h>
@@ -55,8 +55,8 @@ int main(int argc, char * argv[])
   cout<<"Marching cubes..."<<endl;
   MatrixXd SV,BV;
   MatrixXi SF,BF;
-  igl::copyleft::marching_cubes(S,GV,res(0),res(1),res(2),SV,SF);
-  igl::copyleft::marching_cubes(B,GV,res(0),res(1),res(2),BV,BF);
+  igl::marching_cubes(S,GV,res(0),res(1),res(2),0,SV,SF);
+  igl::marching_cubes(B,GV,res(0),res(1),res(2),0,BV,BF);
 
   cout<<R"(Usage:
 '1'  Show original mesh.

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

@@ -1,8 +1,7 @@
 #include <igl/read_triangle_mesh.h>
 #include <igl/get_seconds.h>
 #include <igl/material_colors.h>
-#include <igl/copyleft/marching_cubes.h>
-#include <igl/copyleft/swept_volume.h>
+#include <igl/swept_volume.h>
 #include <igl/opengl/glfw/Viewer.h>
 #include <igl/PI.h>
 #include <Eigen/Core>
@@ -39,7 +38,7 @@ int main(int argc, char * argv[])
   const int time_steps = 200;
   const double isolevel = 0.1;
   std::cerr<<"Computing swept volume...";
-  igl::copyleft::swept_volume(
+  igl::swept_volume(
     V,F,transform,time_steps,grid_size,isolevel,SV,SF);
   std::cerr<<" finished."<<std::endl;
 

+ 1 - 1
tutorial/714_MarchingTets/CMakeLists.txt

@@ -2,4 +2,4 @@ get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
 project(${PROJECT_NAME})
 
 add_executable(${PROJECT_NAME} main.cpp)
-target_link_libraries(${PROJECT_NAME} igl::core igl::opengl igl::opengl_glfw igl::tetgen tutorials)
+target_link_libraries(${PROJECT_NAME} igl::core igl::opengl igl::opengl_glfw tutorials)

+ 81 - 28
tutorial/714_MarchingTets/main.cpp

@@ -1,48 +1,101 @@
 #include <igl/opengl/glfw/Viewer.h>
-#include <igl/copyleft/tetgen/tetrahedralize.h>
 #include <igl/readOBJ.h>
+#include <igl/read_triangle_mesh.h>
+#include <igl/voxel_grid.h>
+#include <igl/tetrahedralized_grid.h>
 #include <igl/marching_tets.h>
+#include <igl/signed_distance.h>
+#include <igl/writeOBJ.h>
+#include <igl/get_seconds.h>
 #include <Eigen/Core>
 
 #include "tutorial_shared_path.h"
 
+#include <igl/marching_cubes.h>
 
 int main(int argc, char * argv[])
 {
+  const auto & tictoc = []()
+  {
+    static double t_start = igl::get_seconds();
+    double diff = igl::get_seconds()-t_start;
+    t_start += diff;
+    return diff;
+  };
 
   // Load a surface mesh which is a cube
-  Eigen::MatrixXd surfaceV;
-  Eigen::MatrixXi surfaceF;
-  igl::readOBJ(TUTORIAL_SHARED_PATH "/cube.obj", surfaceV, surfaceF);
+  Eigen::MatrixXd V;
+  Eigen::MatrixXi F;
+  igl::read_triangle_mesh(
+    argc>1?argv[1]: TUTORIAL_SHARED_PATH "/armadillo.obj",V,F);
 
-  // Find the centroid of the loaded mesh
-  Eigen::RowVector3d surfaceCenter = surfaceV.colwise().sum() / surfaceV.rows();
+  Eigen::RowVector3i side;
+  Eigen::MatrixXd TV;
+  tictoc();
+  igl::voxel_grid(V,0,100,1,TV,side);
+  printf("igl::voxel_grid               %g secs\n",tictoc());
+  Eigen::MatrixXi TT5,TT6;
+  tictoc();
+  igl::tetrahedralized_grid(TV,side,igl::TETRAHEDRALIZED_GRID_TYPE_5,TT5);
+  printf("igl::tetrahedralized_grid     %g secs\n",tictoc());
+  igl::tetrahedralized_grid(TV,side,igl::TETRAHEDRALIZED_GRID_TYPE_6_ROTATIONAL,TT6);
+  printf("igl::tetrahedralized_grid     %g secs\n",tictoc());
 
-  // Center the mesh about the origin
-  surfaceV.rowwise() -= surfaceCenter;
+  tictoc();
+  Eigen::VectorXd S;
+  {
+    Eigen::VectorXi I;
+    Eigen::MatrixXd C,N;
+    igl::signed_distance(
+      TV,V,F,
+      igl::SIGNED_DISTANCE_TYPE_FAST_WINDING_NUMBER,
+      std::numeric_limits<double>::min(),
+      std::numeric_limits<double>::max(),
+      S,I,C,N);
+  }
+  printf("igl::signed_distance          %g secs\n",tictoc());
+  
+  std::vector<Eigen::MatrixXd> SV(3);
+  std::vector<Eigen::MatrixXi> SF(3);
+  igl::marching_tets(TV,TT5,S,0,SV[0],SF[0]);
+  printf("igl::marching_tets5           %g secs\n",tictoc());
+  igl::marching_tets(TV,TT6,S,0,SV[1],SF[1]);
+  printf("igl::marching_tets6           %g secs\n",tictoc());
+  tictoc();
+  igl::marching_cubes(S,TV,side(0),side(1),side(2),0,SV[2],SF[2]);
+  printf("igl::marching_cubes           %g secs\n",tictoc());
 
-  // Tetrahedralize the surface mesh
-  Eigen::MatrixXd TV; // Tet mesh vertices
-  Eigen::MatrixXi TF; // Tet mesh boundary face indices
-  Eigen::MatrixXi TT; // Tet mesh tetrahedron indices
-  igl::copyleft::tetgen::tetrahedralize(surfaceV, surfaceF, "pq1.414a0.0001", TV, TT, TF);
 
-  // Compute a scalar at each tet vertex which is the distance from the vertex to the origin
-  Eigen::VectorXd S = TV.rowwise().norm();
-
-  // Compute a mesh (stored in SV, SF) representing the iso-level-set for the isovalue 0.5
-  Eigen::MatrixXd SV;
-  Eigen::MatrixXi SF;
-  igl::marching_tets(TV, TT, S, 0.45, SV, SF);
+  //igl::writeOBJ("tmc.obj",SV,SF);
 
   // Draw the mesh stored in (SV, SF)
-  igl::opengl::glfw::Viewer viewer;
-  viewer.data().set_mesh(SV, SF);
-  viewer.callback_key_down =
-    [&](igl::opengl::glfw::Viewer & viewer, unsigned char key, int mod)->bool
+  igl::opengl::glfw::Viewer vr;
+  vr.data().set_mesh(V,F);
+  vr.data().is_visible = false;
+  vr.append_mesh();
+  int sel = 0;
+  const auto update = [&]()
+  {
+    vr.data().clear();
+    vr.data().set_mesh(SV[sel],SF[sel]);
+  };
+  vr.callback_key_pressed = [&](decltype(vr) &,unsigned int key, int mod)
+  {
+    switch(key)
     {
-      viewer.data().set_face_based(true);
-      return true;
-    };
-  viewer.launch();
+      case ',': 
+      case '.': 
+        sel = (sel+SV.size()+(key=='.'?1:-1))%SV.size();
+        update();
+        return true;
+      case ' ': 
+        vr.data_list[0].is_visible = !vr.data_list[0].is_visible;
+        vr.data_list[1].is_visible = !vr.data_list[1].is_visible;
+        vr.selected_data_index = (vr.selected_data_index+1)%2;
+        return true;
+    }
+    return false;
+  };
+  update();
+  vr.launch();
 }

+ 4 - 0
tutorial/CMakeLists.txt

@@ -63,6 +63,7 @@ if(TUTORIALS_CHAPTER1)
   add_subdirectory("108_MultipleViews")
   if(LIBIGL_WITH_OPENGL_GLFW_IMGUI)
     add_subdirectory("109_ImGuizmo")
+    add_subdirectory("112_Selection")
   endif()
   add_subdirectory("110_MshView")
 endif()
@@ -135,6 +136,9 @@ if(TUTORIALS_CHAPTER6)
     add_subdirectory("111_MatCap")
     add_subdirectory("607_ScreenCapture")
   endif()
+  if(LIBIGL_WITH_PNG AND LIBIGL_WITH_EMBREE)
+    add_subdirectory("608_RayTrace")
+  endif()
   if(LIBIGL_WITH_CGAL)
     add_subdirectory("609_Boolean")
     add_subdirectory("610_CSGTree")