Browse Source

Merge pull request #1206 from libigl/dev

Version 2.1.0
Alec Jacobson 6 years ago
parent
commit
f6b4064274
100 changed files with 2852 additions and 1444 deletions
  1. 22 21
      .appveyor.yml
  2. 50 40
      .travis.yml
  3. 8 4
      CMakeLists.txt
  4. 0 1
      cmake/DownloadProject.CMakeLists.cmake.in
  5. 65 50
      cmake/LibiglDownloadExternal.cmake
  6. 22 0
      cmake/LibiglWindows.cmake
  7. 19 17
      cmake/libigl-config.cmake.in
  8. 50 27
      cmake/libigl.cmake
  9. 8 0
      include/igl/AABB.cpp
  10. 0 2
      include/igl/WindingNumberTree.h
  11. 52 0
      include/igl/accumarray.cpp
  12. 50 0
      include/igl/accumarray.h
  13. 20 9
      include/igl/adjacency_list.cpp
  14. 1 1
      include/igl/adjacency_list.h
  15. 2 0
      include/igl/barycenter.cpp
  16. 5 0
      include/igl/bbw.cpp
  17. 118 37
      include/igl/boundary_facets.cpp
  18. 17 12
      include/igl/boundary_facets.h
  19. 5 4
      include/igl/boundary_loop.cpp
  20. 3 3
      include/igl/boundary_loop.h
  21. 68 0
      include/igl/cat.cpp
  22. 10 0
      include/igl/cat.h
  23. 4 6
      include/igl/circulation.cpp
  24. 1 6
      include/igl/circulation.h
  25. 3 3
      include/igl/collapse_edge.cpp
  26. 3 3
      include/igl/collapse_edge.h
  27. 2 0
      include/igl/colon.cpp
  28. 0 4
      include/igl/comb_frame_field.cpp
  29. 1 0
      include/igl/combine.cpp
  30. 1 0
      include/igl/compute_frame_field_bisectors.cpp
  31. 42 12
      include/igl/copyleft/cgal/convex_hull.cpp
  32. 6 1
      include/igl/copyleft/cgal/delaunay_triangulation.cpp
  33. 1 1
      include/igl/copyleft/cgal/delaunay_triangulation.h
  34. 23 22
      include/igl/copyleft/cgal/extract_cells.cpp
  35. 1 1
      include/igl/copyleft/cgal/hausdorff.cpp
  36. 17 8
      include/igl/copyleft/cgal/incircle.cpp
  37. 8 8
      include/igl/copyleft/cgal/incircle.h
  38. 9 6
      include/igl/copyleft/cgal/mesh_to_polyhedron.cpp
  39. 6 3
      include/igl/copyleft/cgal/mesh_to_polyhedron.h
  40. 10 5
      include/igl/copyleft/cgal/order_facets_around_edges.cpp
  41. 18 8
      include/igl/copyleft/cgal/orient2D.cpp
  42. 7 7
      include/igl/copyleft/cgal/orient2D.h
  43. 2 0
      include/igl/copyleft/cgal/outer_element.cpp
  44. 9 6
      include/igl/copyleft/cgal/outer_facet.cpp
  45. 4 0
      include/igl/copyleft/cgal/outer_hull.cpp
  46. 7 4
      include/igl/copyleft/cgal/peel_outer_hull_layers.cpp
  47. 2 0
      include/igl/copyleft/cgal/remesh_intersections.cpp
  48. 1 0
      include/igl/copyleft/cgal/remesh_self_intersections.cpp
  49. 11 1
      include/igl/copyleft/cgal/wire_mesh.cpp
  50. 239 225
      include/igl/copyleft/comiso/miq.cpp
  51. 70 45
      include/igl/copyleft/comiso/miq.h
  52. 131 297
      include/igl/copyleft/comiso/nrosy.cpp
  53. 3 6
      include/igl/copyleft/comiso/nrosy.h
  54. 280 133
      include/igl/copyleft/marching_cubes.cpp
  55. 15 0
      include/igl/copyleft/marching_cubes.h
  56. 1 0
      include/igl/copyleft/opengl2/render_to_tga.cpp
  57. 1 0
      include/igl/copyleft/opengl2/tga.cpp
  58. 2 2
      include/igl/copyleft/progressive_hulls_cost_and_placement.cpp
  59. 40 3
      include/igl/cotmatrix_entries.cpp
  60. 12 0
      include/igl/cotmatrix_entries.h
  61. 67 0
      include/igl/cotmatrix_intrinsic.cpp
  62. 40 0
      include/igl/cotmatrix_intrinsic.h
  63. 132 0
      include/igl/cross_field_mismatch.cpp
  64. 43 0
      include/igl/cross_field_mismatch.h
  65. 0 142
      include/igl/cross_field_missmatch.cpp
  66. 76 0
      include/igl/cumprod.cpp
  67. 44 0
      include/igl/cumprod.h
  68. 4 0
      include/igl/cumsum.cpp
  69. 2 2
      include/igl/cut_mesh_from_singularities.h
  70. 6 0
      include/igl/cut_to_disk.cpp
  71. 11 31
      include/igl/delaunay_triangulation.cpp
  72. 5 8
      include/igl/delaunay_triangulation.h
  73. 9 5
      include/igl/dihedral_angles.cpp
  74. 4 4
      include/igl/dihedral_angles.h
  75. 3 4
      include/igl/doublearea.cpp
  76. 1 1
      include/igl/edge_collapse_is_valid.cpp
  77. 96 0
      include/igl/edge_exists_near.cpp
  78. 47 0
      include/igl/edge_exists_near.h
  79. 9 9
      include/igl/edge_flaps.cpp
  80. 7 5
      include/igl/edge_flaps.h
  81. 3 0
      include/igl/edge_lengths.cpp
  82. 104 72
      include/igl/embree/EmbreeIntersector.h
  83. 15 0
      include/igl/face_occurrences.cpp
  84. 6 1
      include/igl/face_occurrences.h
  85. 8 5
      include/igl/facet_components.cpp
  86. 1 0
      include/igl/find.cpp
  87. 7 8
      include/igl/find_cross_field_singularities.cpp
  88. 3 3
      include/igl/find_cross_field_singularities.h
  89. 1 1
      include/igl/flip_avoiding_line_search.cpp
  90. 16 1
      include/igl/flip_edge.cpp
  91. 64 67
      include/igl/grad.cpp
  92. 8 7
      include/igl/grad.h
  93. 78 0
      include/igl/grad_intrinsic.cpp
  94. 35 0
      include/igl/grad_intrinsic.h
  95. 22 12
      include/igl/grid.cpp
  96. 3 2
      include/igl/grid.h
  97. 160 0
      include/igl/heat_geodesics.cpp
  98. 69 0
      include/igl/heat_geodesics.h
  99. 1 0
      include/igl/internal_angles.cpp
  100. 54 0
      include/igl/intrinsic_delaunay_cotmatrix.cpp

+ 22 - 21
.appveyor.yml

@@ -1,38 +1,39 @@
 version: 1.0.{build}
 os: Visual Studio 2017
-test: off
+platform: x64
 clone_folder: C:\projects\libigl
+shallow_clone: true
 branches:
   only:
     - master
     - dev
 environment:
-  BOOST_ROOT: C:/Libraries/boost_1_65_1
+  matrix:
+  - CONFIG: Debug
+    BOOST_ROOT: C:/Libraries/boost_1_65_1
+    PYTHON: 37
+  - CONFIG: Release
+    BOOST_ROOT: C:/Libraries/boost_1_65_1
+    PYTHON: 37
 install:
-  - git submodule update --init --recursive
   - cinstall: python
+build:
+  parallel: true
 build_script:
   - cd c:\projects\libigl
-  # External libraries (boost)
-  # - cd external
-  # - mkdir build
-  # - cd build
-  # - cmake -G "Visual Studio 15 2017 Win64" -T "host=x64" ..
-  # - msbuild %MSBuildOptions% libigl_external.sln
-  # - cd ../..
-  # Python bindings
-  # - cd python
-  # - mkdir build
-  # - cd build
-  # - cmake -DLIBIGL_WITH_EMBREE=OFF -DLIBIGL_USE_STATIC_LIBRARY=ON ../
-  # - msbuild %MSBuildOptions% pyigl.sln
-  # - cd ../tutorial
-  # - ${PYTHON} 101_FileIO.py
-  # - cd ../../
   # Tutorials and tests
+  - set PATH=C:\Python%PYTHON%-x64;C:\Python%PYTHON%-x64\Scripts;%PATH%
   - mkdir build
   - cd build
-  - cmake -DLIBIGL_BUILD_TESTS=OFF -DLIBIGL_BUILD_TUTORIALS=ON -DLIBIGL_BUILD_PYTHON=OFF -G "Visual Studio 15 2017 Win64" ../
+  - cmake -DCMAKE_BUILD_TYPE=%CONFIG%
+      -DLIBIGL_WITH_CGAL=ON
+      -DLIBIGL_WITH_COMISO=OFF
+      -G "Visual Studio 15 2017 Win64"
+      ../
   - set MSBuildLogger="C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
-  - set MSBuildOptions=/v:m /p:Configuration=Debug /logger:%MSBuildLogger%
+  - set MSBuildOptions=/v:m /m /p:BuildInParallel=true /p:Configuration=%CONFIG% /logger:%MSBuildLogger%
   - msbuild %MSBuildOptions% libigl.sln
+
+test_script:
+  - set CTEST_OUTPUT_ON_FAILURE=1
+  - ctest -C %CONFIG% --verbose --output-on-failure -j 2

+ 50 - 40
.travis.yml

@@ -2,55 +2,58 @@ dist: trusty
 sudo: true
 language: cpp
 cache: ccache
+addons:
+  apt:
+    sources:
+    - ubuntu-toolchain-r-test
+    packages:
+    - g++-7
+    - gcc-7
+    - libblas-dev
+    - libboost-filesystem-dev
+    - libboost-system-dev
+    - libboost-thread-dev
+    - libglu1-mesa-dev
+    - liblapack-dev
+    - libmpfr-dev
+    - libpython3-dev
+    - python3-setuptools
+    - xorg-dev
+  homebrew:
+    packages:
+    - ccache
 matrix:
   include:
   - os: linux
     compiler: gcc # 4.8.4 by default on Trusty
-    addons:
-      apt:
-        sources:
-        - ubuntu-toolchain-r-test
-        packages:
-        - libmpfr-dev
-        - libboost-filesystem-dev
-        - libboost-system-dev
-        - libboost-thread-dev
-        - libblas-dev
-        - liblapack-dev
-        - xorg-dev
-        - libglu1-mesa-dev
-        - python3-setuptools
-        - libpython3-dev
     env:
-    - MATRIX_EVAL="export CONFIG=Debug && CHECK_UNDEFINED=ON && PYTHON=python3"
+    - MATRIX_EVAL="export CONFIG=Release PYTHON=python3"
   - os: linux
     compiler: gcc-7
-    addons:
-      apt:
-        sources:
-        - ubuntu-toolchain-r-test
-        packages:
-        - gcc-7
-        - g++-7
-        - libmpfr-dev
-        - libboost-filesystem-dev
-        - libboost-system-dev
-        - libboost-thread-dev
-        - libblas-dev
-        - liblapack-dev
-        - xorg-dev
-        - libglu1-mesa-dev
-        - python3-setuptools
-        - libpython3-dev
     env:
-    - MATRIX_EVAL="export CC=gcc-7 && CXX=g++-7 && CONFIG=Debug && CHECK_UNDEFINED=ON && PYTHON=python3"
+    - MATRIX_EVAL="export CC=gcc-7 CXX=g++-7 CONFIG=Release PYTHON=python3"
+  - os: linux # same config like above but with -DLIBIGL_USE_STATIC_LIBRARY=OFF to test static and header-only builds
+    compiler: gcc-7
+    env:
+    - MATRIX_EVAL="export CC=gcc-7 CXX=g++-7 CONFIG=Release PYTHON=python3 CMAKE_EXTRA='-DLIBIGL_USE_STATIC_LIBRARY=OFF'"
+  - os: linux
+    compiler: gcc-7
+    env:
+    - MATRIX_EVAL="export CC=gcc-7 CXX=g++-7 CONFIG=Release PYTHON=python3 CMAKE_EXTRA='-DLIBIGL_EIGEN_VERSION=3.3.7'"
+  - os: osx
+    compiler: clang
+    env:
+    - MATRIX_EVAL="export CONFIG=Debug PYTHON=python3 LIBIGL_NUM_THREADS=1"
+  - os: osx # same config like above but with -DLIBIGL_USE_STATIC_LIBRARY=OFF to test static and header-only builds
+    compiler: clang
+    env:
+    - MATRIX_EVAL="export CONFIG=Debug PYTHON=python3 LIBIGL_NUM_THREADS=1 CMAKE_EXTRA='-DLIBIGL_USE_STATIC_LIBRARY=OFF'"
   - os: osx
     compiler: clang
     env:
-    - MATRIX_EVAL="export CONFIG=Debug && CHECK_UNDEFINED=ON && PYTHON=python3"
+    - MATRIX_EVAL="export CONFIG=Debug PYTHON=python3 LIBIGL_NUM_THREADS=1 CMAKE_EXTRA='-DLIBIGL_EIGEN_VERSION=3.3.7'""
 
 install:
-- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache; fi
 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH="/usr/local/opt/ccache/libexec:$PATH"; fi
 - eval "${MATRIX_EVAL}"
 - ccache --max-size=5.0G
@@ -59,10 +62,17 @@ install:
 script:
 # Tutorials and tests
 - mkdir build
-- cd build
-- cmake -DCMAKE_BUILD_TYPE=$CONFIG -DLIBIGL_BUILD_TESTS=ON -DLIBIGL_BUILD_TUTORIALS=ON ../
+- pushd build
+- cmake ${CMAKE_EXTRA}
+    -DCMAKE_BUILD_TYPE=$CONFIG
+    -DLIBIGL_CHECK_UNDEFINED=ON
+    -DLIBIGL_WITH_CGAL=ON
+    ../
 - make -j 2
 - ctest --verbose
-- ccache --show-stats
-- cd ../
+- popd
+- pushd python/tutorial
+- ${PYTHON} 101_FileIO.py
+- popd
 - rm -rf build
+- ccache --show-stats

+ 8 - 4
CMakeLists.txt

@@ -2,7 +2,8 @@ cmake_minimum_required(VERSION 3.1)
 project(libigl)
 
 # Detects whether this is a top-level project
-if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+get_directory_property(LIBIGL_PARENT_DIR PARENT_DIRECTORY)
+if(NOT LIBIGL_PARENT_DIR)
 	set(LIBIGL_TOPLEVEL_PROJECT ON)
 else()
 	set(LIBIGL_TOPLEVEL_PROJECT OFF)
@@ -12,11 +13,12 @@ endif()
 option(LIBIGL_BUILD_TESTS      "Build libigl unit test"        ${LIBIGL_TOPLEVEL_PROJECT})
 option(LIBIGL_BUILD_TUTORIALS  "Build libigl tutorial"         ${LIBIGL_TOPLEVEL_PROJECT})
 option(LIBIGL_BUILD_PYTHON     "Build libigl python bindings"  ${LIBIGL_TOPLEVEL_PROJECT})
+option(LIBIGL_EXPORT_TARGETS   "Export libigl CMake targets"   ${LIBIGL_TOPLEVEL_PROJECT})
 
 # USE_STATIC_LIBRARY speeds up the generation of multiple binaries,
 # at the cost of a longer initial compilation time
 # (by default, static build is off since libigl is a header-only library)
-option(LIBIGL_USE_STATIC_LIBRARY "Use LibIGL as static library" ON)
+option(LIBIGL_USE_STATIC_LIBRARY "Use libigl as static library" ON)
 
 # All dependencies that are downloaded as cmake projects and tested on the auto-builds are ON
 # (by default, all build options are off)
@@ -28,12 +30,13 @@ option(LIBIGL_WITH_OPENGL_GLFW_IMGUI "Use ImGui"                    ON)
 option(LIBIGL_WITH_PNG               "Use PNG"                      ON)
 option(LIBIGL_WITH_TETGEN            "Use Tetgen"                   ON)
 option(LIBIGL_WITH_TRIANGLE          "Use Triangle"                 ON)
+option(LIBIGL_WITH_PREDICATES        "Use exact predicates"         ON)
 option(LIBIGL_WITH_XML               "Use XML"                      ON)
 option(LIBIGL_WITH_PYTHON            "Use Python"                   ${LIBIGL_BUILD_PYTHON})
 ### End
 
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})		
-set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})		
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
 
 ### conditionally compile certain modules depending on libraries found on the system
@@ -47,6 +50,7 @@ if(LIBIGL_BUILD_TUTORIALS)
 endif()
 
 if(LIBIGL_BUILD_TESTS)
+	include(CTest)
 	enable_testing()
 	add_subdirectory(tests)
 endif()

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

@@ -14,5 +14,4 @@ ExternalProject_Add(${DL_ARGS_PROJ}-download
                     BUILD_COMMAND       ""
                     INSTALL_COMMAND     ""
                     TEST_COMMAND        ""
-                    TLS_VERIFY          OFF
 )

+ 65 - 50
cmake/LibiglDownloadExternal.cmake

@@ -2,23 +2,39 @@
 include(DownloadProject)
 
 # With CMake 3.8 and above, we can hide warnings about git being in a
-# detached head by passing an extra GIT_CONFIG option
+# detached head by passing an extra GIT_CONFIG option.
+set(LIBIGL_EXTRA_OPTIONS TLS_VERIFY OFF)
 if(NOT (${CMAKE_VERSION} VERSION_LESS "3.8.0"))
-	set(LIBIGL_EXTRA_OPTIONS "GIT_CONFIG advice.detachedHead=false")
-else()
-	set(LIBIGL_EXTRA_OPTIONS "")
+	list(APPEND LIBIGL_EXTRA_OPTIONS GIT_CONFIG advice.detachedHead=false)
 endif()
 
-# Shortcut function
+# On CMake 3.6.3 and above, there is an option to use shallow clones of git repositories.
+# The shallow clone option only works with real tags, not SHA1, so we use a separate option.
+set(LIBIGL_BRANCH_OPTIONS)
+if(NOT (${CMAKE_VERSION} VERSION_LESS "3.6.3"))
+	# Disabled for now until we can make sure that it has no adverse effects
+	# (Downside is that the eigen mirror is huge again)
+	# list(APPEND LIBIGL_BRANCH_OPTIONS GIT_SHALLOW 1)
+endif()
+
+option(LIBIGL_SKIP_DOWNLOAD "Skip downloading external libraries" OFF)
+
+# Shortcut functions
+function(igl_download_project_aux name source)
+	if(NOT LIBIGL_SKIP_DOWNLOAD)
+		download_project(
+			PROJ         ${name}
+			SOURCE_DIR   "${source}"
+			DOWNLOAD_DIR "${LIBIGL_EXTERNAL}/.cache/${name}"
+			QUIET
+			${LIBIGL_EXTRA_OPTIONS}
+			${ARGN}
+		)
+	endif()
+endfunction()
+
 function(igl_download_project name)
-	download_project(
-		PROJ         ${name}
-		SOURCE_DIR   ${LIBIGL_EXTERNAL}/${name}
-		DOWNLOAD_DIR ${LIBIGL_EXTERNAL}/.cache/${name}
-		QUIET
-		${LIBIGL_EXTRA_OPTIONS}
-		${ARGN}
-	)
+	igl_download_project_aux(${name} "${LIBIGL_EXTERNAL}/${name}" ${ARGN})
 endfunction()
 
 ################################################################################
@@ -35,7 +51,7 @@ endfunction()
 function(igl_download_comiso)
 	igl_download_project(CoMISo
 		GIT_REPOSITORY https://github.com/libigl/CoMISo.git
-		GIT_TAG        fea3ee0ba7d42ee3eca202d484e4fad855e4d6aa
+		GIT_TAG        1f9618cf9b7bd77370d817976470d59091928606
 	)
 endfunction()
 
@@ -48,20 +64,21 @@ function(igl_download_cork)
 endfunction()
 
 ## Eigen
+set(LIBIGL_EIGEN_VERSION 3.2.10 CACHE STRING "Default version of Eigen used by libigl.")
 function(igl_download_eigen)
 	igl_download_project(eigen
-		URL           http://bitbucket.org/eigen/eigen/get/3.2.10.tar.gz
-		URL_MD5       8ad10ac703a78143a4062c9bda9d8fd3
+		GIT_REPOSITORY https://github.com/eigenteam/eigen-git-mirror.git
+		GIT_TAG        ${LIBIGL_EIGEN_VERSION}
+		${LIBIGL_BRANCH_OPTIONS}
 	)
 endfunction()
 
 ## Embree
 function(igl_download_embree)
 	igl_download_project(embree
-		URL            https://github.com/embree/embree/archive/v2.17.4.tar.gz
-		URL_MD5        2038f3216b1d626e87453aee72c470e5
-		# GIT_REPOSITORY https://github.com/embree/embree.git
-		# GIT_TAG        cb61322db3bb7082caed21913ad14869b436fe78
+		GIT_REPOSITORY https://github.com/embree/embree.git
+		GIT_TAG        v3.5.2
+		${LIBIGL_BRANCH_OPTIONS}
 	)
 endfunction()
 
@@ -69,7 +86,7 @@ endfunction()
 function(igl_download_glad)
 	igl_download_project(glad
 		GIT_REPOSITORY https://github.com/libigl/libigl-glad.git
-		GIT_TAG        71e35fe685a0cc160068a2f2f971c40b82d14af0
+		GIT_TAG        09b4969c56779f7ddf8e6176ec1873184aec890f
 	)
 endfunction()
 
@@ -77,7 +94,8 @@ endfunction()
 function(igl_download_glfw)
 	igl_download_project(glfw
 		GIT_REPOSITORY https://github.com/glfw/glfw.git
-		GIT_TAG        58cc4b2c5c2c9a245e09451437dd6f5af4d60c84
+		GIT_TAG        3.3
+		${LIBIGL_BRANCH_OPTIONS}
 	)
 endfunction()
 
@@ -85,11 +103,12 @@ endfunction()
 function(igl_download_imgui)
 	igl_download_project(imgui
 		GIT_REPOSITORY https://github.com/ocornut/imgui.git
-		GIT_TAG        bc6ac8b2aee0614debd940e45bc9cd0d9b355c86
+		GIT_TAG        v1.69
+		${LIBIGL_BRANCH_OPTIONS}
 	)
 	igl_download_project(libigl-imgui
 		GIT_REPOSITORY https://github.com/libigl/libigl-imgui.git
-		GIT_TAG        a37e6e59e72fb07bd787dc7e90f72b9e1928dae7
+		GIT_TAG        07ecd3858acc71e70f0f9b2dea20a139bdddf8ae
 	)
 endfunction()
 
@@ -105,15 +124,15 @@ endfunction()
 function(igl_download_stb)
 	igl_download_project(stb
 		GIT_REPOSITORY https://github.com/libigl/libigl-stb.git
-		GIT_TAG        e671ceb3def5e7029a23de14c55dc16301ad4dab
+		GIT_TAG        cd0fa3fcd90325c83be4d697b00214e029f94ca3
 	)
 endfunction()
 
 ## TetGen
 function(igl_download_tetgen)
 	igl_download_project(tetgen
-		GIT_REPOSITORY https://github.com/libigl/tetgen.git
-		GIT_TAG        d2dcc33cb8551f16e302c8130ce12fa52992cd09
+		GIT_REPOSITORY https://github.com/jdumas/tetgen.git
+		GIT_TAG        c63e7a6434652b8a2065c835bd9d6d298db1a0bc
 	)
 endfunction()
 
@@ -129,15 +148,23 @@ endfunction()
 function(igl_download_triangle)
 	igl_download_project(triangle
 		GIT_REPOSITORY https://github.com/libigl/triangle.git
-		GIT_TAG        d6761dd691e2e1318c83bf7773fea88d9437464a
+		GIT_TAG        d284c4a843efac043c310f5fa640b17cf7d96170
 	)
 endfunction()
 
-## Google test
-function(igl_download_googletest)
-	igl_download_project(googletest
-		GIT_REPOSITORY https://github.com/google/googletest
-		GIT_TAG        release-1.8.1
+## Catch2
+function(igl_download_catch2)
+	igl_download_project(catch2
+		GIT_REPOSITORY https://github.com/catchorg/Catch2.git
+		GIT_TAG        03d122a35c3f5c398c43095a87bc82ed44642516
+	)
+endfunction()
+
+## Predicates
+function(igl_download_predicates)
+	igl_download_project(predicates
+		GIT_REPOSITORY https://github.com/libigl/libigl-predicates.git
+		GIT_TAG        4c57c1d3f31646b010d1d58bfbe201e75c2b2ad8
 	)
 endfunction()
 
@@ -145,31 +172,19 @@ endfunction()
 
 ## Test data
 function(igl_download_test_data)
-	set(IGL_TEST_DATA ${LIBIGL_EXTERNAL}/../tests/data)
-
-	download_project(
-		PROJ         test_data
-		SOURCE_DIR   ${IGL_TEST_DATA}
-		DOWNLOAD_DIR ${LIBIGL_EXTERNAL}/.cache/test_data
-		QUIET
+	igl_download_project_aux(test_data
+		"${LIBIGL_EXTERNAL}/../tests/data"
 		GIT_REPOSITORY https://github.com/libigl/libigl-tests-data
-		GIT_TAG        c81bb3b3db4cfd78bac6d359d845c45bc1059c9a
-		${LIBIGL_EXTRA_OPTIONS}
+		GIT_TAG        adc66cabf712a0bd68ac182b4e7f8b5ba009c3dd
 	)
 endfunction()
 
 ## Tutorial data
 function(igl_download_tutorial_data)
-	set(IGL_TUTORIAL_DATA ${LIBIGL_EXTERNAL}/../tutorial/data)
-
-	download_project(
-		PROJ         tutorial_data
-		SOURCE_DIR   ${IGL_TUTORIAL_DATA}
-		DOWNLOAD_DIR ${LIBIGL_EXTERNAL}/.cache/tutorial_data
-		QUIET
+	igl_download_project_aux(tutorial_data
+		"${LIBIGL_EXTERNAL}/../tutorial/data"
 		GIT_REPOSITORY https://github.com/libigl/libigl-tutorial-data
 		GIT_TAG        5c6a1ea809c043d71e5595775709c15325a7158c
-		${LIBIGL_EXTRA_OPTIONS}
 	)
 endfunction()
 

+ 22 - 0
cmake/LibiglWindows.cmake

@@ -0,0 +1,22 @@
+if(MSVC)
+	if("${MSVC_RUNTIME}" STREQUAL "")
+		set(MSVC_RUNTIME "static")
+	endif()
+	if(${MSVC_RUNTIME} STREQUAL "static")
+		message(STATUS "MSVC -> forcing use of statically-linked runtime.")
+		foreach(config ${CMAKE_CONFIGURATION_TYPES})
+			string(TOUPPER ${config} config)
+			string(REPLACE /MD /MT CMAKE_C_FLAGS_${config} "${CMAKE_C_FLAGS_${config}}")
+			string(REPLACE /MD /MT CMAKE_CXX_FLAGS_${config} "${CMAKE_CXX_FLAGS_${config}}")
+		endforeach()
+		string(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
+	else()
+		message(STATUS "MSVC -> forcing use of dynamically-linked runtime.")
+		foreach(config ${CMAKE_CONFIGURATION_TYPES})
+			string(TOUPPER ${config} config)
+			string(REPLACE /MT /MD CMAKE_C_FLAGS_${config} "${CMAKE_C_FLAGS_${config}}")
+			string(REPLACE /MT /MD CMAKE_CXX_FLAGS_${config} "${CMAKE_CXX_FLAGS_${config}}")
+		endforeach()
+		string(REPLACE "/MTd" "/MDd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
+	endif()
+endif()

+ 19 - 17
cmake/libigl-config.cmake.in

@@ -2,27 +2,29 @@
 
 include(${CMAKE_CURRENT_LIST_DIR}/libigl-export.cmake)
 
-if (TARGET igl::core)
-  if (NOT TARGET Eigen3::Eigen)
-    find_package(Eigen3 QUIET)
-    if (NOT Eigen3_FOUND)
-      # try with PkgCOnfig
-      find_package(PkgConfig REQUIRED)
-      pkg_check_modules(Eigen3 QUIET IMPORTED_TARGET eigen3)
-    endif()
+# Check if Eigen3 target is avaiable, if not try to locate it
+# with find_package.
+message(STATUS "[libigl] Looking for Eigen3")
+if (NOT TARGET Eigen3::Eigen)
+  # Try if Eigen3 can be found with find_package
+  find_package(Eigen3 CONFIG REQUIRED)
+endif()
+
 
-    if (NOT Eigen3_FOUND)
-      message(FATAL_ERROR "Could not find required dependency Eigen3")
-      set(libigl_core_FOUND FALSE)
-    else()
-      target_link_libraries(igl::core INTERFACE PkgConfig::Eigen3)
-      set(libigl_core_FOUND TRUE)
-    endif()
-  else()
-    target_link_libraries(igl::core INTERFACE Eigen3::Eigen)
+if (TARGET igl::core)
+  if (TARGET Eigen3::Eigen)
+    # Inject dependency
+    set_target_properties(igl::core PROPERTIES INTERFACE_LINK_LIBRARIES Eigen3::Eigen)
     set(libigl_core_FOUND TRUE)
   endif()
+endif()
 
+if (TARGET igl::common)
+  if (TARGET Eigen3::Eigen)
+    # Inject dependency
+    set_target_properties(igl::common PROPERTIES INTERFACE_LINK_LIBRARIES Eigen3::Eigen)
+    set(libigl_common_FOUND TRUE)
+  endif()
 endif()
 
 check_required_components(libigl)

+ 50 - 27
cmake/libigl.cmake

@@ -32,9 +32,11 @@ option(LIBIGL_WITH_OPENGL_GLFW_IMGUI "Use ImGui"                    OFF)
 option(LIBIGL_WITH_PNG               "Use PNG"                      OFF)
 option(LIBIGL_WITH_TETGEN            "Use Tetgen"                   OFF)
 option(LIBIGL_WITH_TRIANGLE          "Use Triangle"                 OFF)
+option(LIBIGL_WITH_PREDICATES        "Use exact predicates"         OFF)
 option(LIBIGL_WITH_XML               "Use XML"                      OFF)
 option(LIBIGL_WITH_PYTHON            "Use Python"                   OFF)
 option(LIBIGL_WITHOUT_COPYLEFT       "Disable Copyleft libraries"   OFF)
+option(LIBIGL_EXPORT_TARGETS         "Export libigl CMake targets"  OFF)
 
 ################################################################################
 
@@ -77,11 +79,12 @@ target_compile_features(igl_common INTERFACE ${CXX11_FEATURES})
 if(MSVC)
   # Enable parallel compilation for Visual Studio
   target_compile_options(igl_common INTERFACE /MP /bigobj)
-  if(LIBIGL_WITH_CGAL)
-    target_compile_options(igl_common INTERFACE "/MD$<$<CONFIG:Debug>:d>")
-  endif()
+  target_compile_definitions(igl_common INTERFACE -DNOMINMAX)
 endif()
 
+### Set compiler flags for building the tests on Windows with Visual Studio
+include(LibiglWindows)
+
 if(BUILD_SHARED_LIBS)
   # Generate position independent code
   set_target_properties(igl_common PROPERTIES INTERFACE_POSITION_INDEPENDENT_CODE ON)
@@ -195,7 +198,11 @@ if(LIBIGL_WITH_CGAL)
     if(EXISTS ${LIBIGL_EXTERNAL}/boost)
       set(BOOST_ROOT "${LIBIGL_EXTERNAL}/boost")
     endif()
-    option(CGAL_Boost_USE_STATIC_LIBS "Use static Boost libs with CGAL" ON)
+    if(LIBIGL_WITH_PYTHON)
+      option(CGAL_Boost_USE_STATIC_LIBS "Use static Boost libs with CGAL" OFF)
+    else()
+      option(CGAL_Boost_USE_STATIC_LIBS "Use static Boost libs with CGAL" ON)
+    endif()
     find_package(CGAL CONFIG COMPONENTS Core PATHS ${CGAL_DIR} NO_DEFAULT_PATH)
   endif()
 
@@ -264,45 +271,33 @@ endif()
 if(LIBIGL_WITH_EMBREE)
   set(EMBREE_DIR "${LIBIGL_EXTERNAL}/embree")
 
+  set(EMBREE_TESTING_INTENSITY 0 CACHE STRING "" FORCE)
   set(EMBREE_ISPC_SUPPORT OFF CACHE BOOL " " FORCE)
   set(EMBREE_TASKING_SYSTEM "INTERNAL" CACHE BOOL " " FORCE)
   set(EMBREE_TUTORIALS OFF CACHE BOOL " " FORCE)
-  set(EMBREE_MAX_ISA NONE CACHE STRINGS " " FORCE)
-  set(BUILD_TESTING OFF CACHE BOOL " " FORCE)
-
-  # set(ENABLE_INSTALLER OFF CACHE BOOL " " FORCE)
+  set(EMBREE_MAX_ISA "SSE2" CACHE STRING " " FORCE)
+  set(EMBREE_STATIC_LIB ON CACHE BOOL " " FORCE)
   if(MSVC)
-    # set(EMBREE_STATIC_RUNTIME OFF CACHE BOOL " " FORCE)
-    set(EMBREE_STATIC_LIB OFF CACHE BOOL " " FORCE)
-  else()
-    set(EMBREE_STATIC_LIB ON CACHE BOOL " " FORCE)
+    set(EMBREE_STATIC_RUNTIME ON CACHE BOOL " " FORCE)
   endif()
 
   if(NOT TARGET embree)
+    # TODO: Should probably save/restore the CMAKE_CXX_FLAGS_*, since embree seems to be
+    # overriding them on Windows. But well... it works for now.
     igl_download_embree()
     add_subdirectory("${EMBREE_DIR}" "embree")
   endif()
 
-  if(MSVC)
-    add_custom_target(Copy-Embree-DLL ALL # Adds a post-build event
-        COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E
-        $<TARGET_FILE:embree> # <--this is in-file
-        "${CMAKE_BINARY_DIR}" # <--this is out-file path
-        DEPENDS embree) # Execute after embree target has been built
-  endif()
-
   compile_igl_module("embree")
   target_link_libraries(igl_embree ${IGL_SCOPE} embree)
   target_include_directories(igl_embree ${IGL_SCOPE} ${EMBREE_DIR}/include)
-  if(NOT MSVC)
-    target_compile_definitions(igl_embree ${IGL_SCOPE} -DENABLE_STATIC_LIB)
-  endif()
+  target_compile_definitions(igl_embree ${IGL_SCOPE} -DEMBREE_STATIC_LIB)
 endif()
 
 ################################################################################
 ### Compile the matlab part ###
 if(LIBIGL_WITH_MATLAB)
-  find_package(Matlab REQUIRED COMPONENTS MEX_COMPILER MX_LIBRARY ENG_LIBRARY)
+  find_package(Matlab REQUIRED COMPONENTS MEX_COMPILER MX_LIBRARY ENG_LIBRARY MAT_LIBRARY)
   compile_igl_module("matlab")
   target_link_libraries(igl_matlab ${IGL_SCOPE} ${Matlab_LIBRARIES})
   target_include_directories(igl_matlab ${IGL_SCOPE} ${Matlab_INCLUDE_DIRS})
@@ -322,10 +317,19 @@ endif()
 ### Compile the opengl part ###
 if(LIBIGL_WITH_OPENGL)
   # OpenGL module
-  find_package(OpenGL REQUIRED)
   compile_igl_module("opengl")
-  target_link_libraries(igl_opengl ${IGL_SCOPE} ${OPENGL_gl_LIBRARY})
-  target_include_directories(igl_opengl SYSTEM ${IGL_SCOPE} ${OPENGL_INCLUDE_DIR})
+
+  # OpenGL library
+  if (NOT CMAKE_VERSION VERSION_LESS "3.11")
+    cmake_policy(SET CMP0072 NEW)
+  endif()
+  find_package(OpenGL REQUIRED)
+  if(TARGET OpenGL::GL)
+    target_link_libraries(igl_opengl ${IGL_SCOPE} OpenGL::GL)
+  else()
+    target_link_libraries(igl_opengl ${IGL_SCOPE} ${OPENGL_gl_LIBRARY})
+    target_include_directories(igl_opengl SYSTEM ${IGL_SCOPE} ${OPENGL_INCLUDE_DIR})
+  endif()
 
   # glad module
   if(NOT TARGET glad)
@@ -408,6 +412,20 @@ if(LIBIGL_WITH_TRIANGLE)
   target_include_directories(igl_triangle ${IGL_SCOPE} ${TRIANGLE_DIR})
 endif()
 
+################################################################################
+### Compile the predicates part ###
+if(LIBIGL_WITH_PREDICATES)
+  set(PREDICATES_DIR "${LIBIGL_EXTERNAL}/predicates")
+  if(NOT TARGET predicates)
+    igl_download_predicates()
+    add_subdirectory("${PREDICATES_DIR}" "predicates")
+  endif()
+  compile_igl_module("predicates")
+  target_link_libraries(igl_predicates ${IGL_SCOPE} predicates)
+  target_include_directories(igl_predicates ${IGL_SCOPE} ${PREDICATES_DIR})
+  target_compile_definitions(igl_predicates ${IGL_SCOPE} -DLIBIGL_WITH_PREDICATES)
+endif()
+
 ################################################################################
 ### Compile the xml part ###
 if(LIBIGL_WITH_XML)
@@ -429,6 +447,10 @@ endif()
 ################################################################################
 ### Install and export all modules
 
+if(NOT LIBIGL_EXPORT_TARGETS)
+  return()
+endif()
+
 function(install_dir_files dir_name)
   if (dir_name STREQUAL "core")
     set(subpath "")
@@ -445,6 +467,7 @@ function(install_dir_files dir_name)
   if(NOT LIBIGL_USE_STATIC_LIBRARY)
     file(GLOB public_sources
       ${CMAKE_CURRENT_SOURCE_DIR}/include/igl${subpath}/*.cpp
+      ${CMAKE_CURRENT_SOURCE_DIR}/include/igl${subpath}/*.c
     )
   endif()
   list(APPEND files_to_install ${public_sources})

+ 8 - 0
include/igl/AABB.cpp

@@ -1072,4 +1072,12 @@ template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen
 template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
 template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
 template bool igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::intersect_ray<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, igl::Hit&) const;
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<int, 2, 1, 0, 2, 1>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(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, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&) const;
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::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> >&) const;
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::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> >&) const;
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::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> >&) const;
+#ifdef WIN32
+template void igl::AABB<class Eigen::Matrix<double,-1,-1,0,-1,-1>,2>::squared_distance<class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<double,-1,3,0,-1,3> >(class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > &)const;
+template void igl::AABB<class Eigen::Matrix<double,-1,-1,0,-1,-1>,3>::squared_distance<class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<double,-1,3,0,-1,3> >(class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > &)const;
+#endif
 #endif

+ 0 - 2
include/igl/WindingNumberTree.h

@@ -164,7 +164,6 @@ inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree():
   V(dummyV),
   SV(),
   F(),
-  //boundary(igl::boundary_facets<Eigen::MatrixXi,Eigen::MatrixXi>(F))
   cap(),
   radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
   center(0,0,0)
@@ -180,7 +179,6 @@ inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
   V(dummyV),
   SV(),
   F(),
-  //boundary(igl::boundary_facets<Eigen::MatrixXi,Eigen::MatrixXi>(F))
   cap(),
   radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
   center(0,0,0)

+ 52 - 0
include/igl/accumarray.cpp

@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "accumarray.h"
+#include <cassert>
+
+template <
+  typename DerivedS,
+  typename DerivedV,
+  typename DerivedA
+  >
+void igl::accumarray(
+  const Eigen::MatrixBase<DerivedS> & S,
+  const Eigen::MatrixBase<DerivedV> & V,
+  Eigen::PlainObjectBase<DerivedA> & A)
+{
+  assert(V.size() == S.size() && "S and V should be same size");
+  if(S.size() == 0) { A.resize(0,1); return; }
+  A.setZero(S.maxCoeff()+1,1);
+  for(int s = 0;s<S.size();s++)
+  {
+    A(S(s)) += V(s);
+  }
+}
+
+template <
+  typename DerivedS,
+  typename DerivedA
+  >
+void igl::accumarray(
+  const Eigen::MatrixBase<DerivedS> & S,
+  const typename DerivedA::Scalar V,
+  Eigen::PlainObjectBase<DerivedA> & A)
+{
+  if(S.size() == 0) { A.resize(0,1); return; }
+  A.setZero(S.maxCoeff()+1,1);
+  for(int s = 0;s<S.size();s++)
+  {
+    A(S(s)) += V;
+  }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::accumarray<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::accumarray<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

+ 50 - 0
include/igl/accumarray.h

@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef ACCUMARRY_H
+#define ACCUMARRY_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  // ACCUMARRY Like Matlab's accumarray. Accumulate values in V using subscripts
+  // in S.
+  //
+  // Inputs:
+  //   S  #S list of subscripts
+  //   V  #V list of values
+  // Outputs:
+  //   A  max(subs)+1 list of accumulated values
+  template <
+    typename DerivedS,
+    typename DerivedV,
+    typename DerivedA
+    >
+  void accumarray(
+    const Eigen::MatrixBase<DerivedS> & S,
+    const Eigen::MatrixBase<DerivedV> & V,
+    Eigen::PlainObjectBase<DerivedA> & A);
+  // Inputs:
+  //   S  #S list of subscripts
+  //   V  single value used for all
+  // Outputs:
+  //   A  max(subs)+1 list of accumulated values
+  template <
+    typename DerivedS,
+    typename DerivedA
+    >
+  void accumarray(
+    const Eigen::MatrixBase<DerivedS> & S,
+    const typename DerivedA::Scalar V,
+    Eigen::PlainObjectBase<DerivedA> & A);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "accumarray.cpp"
+#endif
+
+#endif

+ 20 - 9
include/igl/adjacency_list.cpp

@@ -12,7 +12,7 @@
 
 template <typename Index, typename IndexVector>
 IGL_INLINE void igl::adjacency_list(
-    const Eigen::PlainObjectBase<Index>  & F,
+    const Eigen::MatrixBase<Index>  & F,
     std::vector<std::vector<IndexVector> >& A,
     bool sorted)
 {
@@ -132,8 +132,18 @@ IGL_INLINE void igl::adjacency_list(
   const std::vector<std::vector<Index> > & F,
   std::vector<std::vector<Index> >& A)
 {
-  A.clear(); 
-  A.resize(F.maxCoeff()+1);
+  A.clear();
+  
+  // Find maxCoeff
+  Index maxCoeff = 0;
+  for(const auto &vec : F)
+  {
+    for(int coeff : vec)
+    {
+      maxCoeff = std::max(coeff, maxCoeff);
+    }
+  }
+  A.resize(maxCoeff + 1);
   
   // Loop over faces
   for(int i = 0;i<F.size();i++)
@@ -142,8 +152,8 @@ IGL_INLINE void igl::adjacency_list(
     for(int j = 0;j<F[i].size();j++)
     {
       // Get indices of edge: s --> d
-      int s = F(i,j);
-      int d = F(i,(j+1)%F[i].size());
+      int s = F[i][j];
+      int d = F[i][(j+1)%F[i].size()];
       A.at(s).push_back(d);
       A.at(d).push_back(s);
     }
@@ -161,9 +171,10 @@ IGL_INLINE void igl::adjacency_list(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
-template void igl::adjacency_list<Eigen::Matrix<int, -1, 2, 0, -1, 2>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
+template void igl::adjacency_list<Eigen::Matrix<int, -1, 2, 0, -1, 2>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
 // generated by autoexplicit.sh
-template void igl::adjacency_list<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
-template void igl::adjacency_list<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
-template void igl::adjacency_list<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned int>(class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &, class std::vector<class std::vector<unsigned int, class std::allocator<unsigned int> >, class std::allocator<class std::vector<unsigned int, class std::allocator<unsigned int> > > > &, bool);
+template void igl::adjacency_list<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
+template void igl::adjacency_list<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
+template void igl::adjacency_list<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned int>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &, class std::vector<class std::vector<unsigned int, class std::allocator<unsigned int> >, class std::allocator<class std::vector<unsigned int, class std::allocator<unsigned int> > > > &, bool);
+template void igl::adjacency_list<int>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
 #endif

+ 1 - 1
include/igl/adjacency_list.h

@@ -31,7 +31,7 @@ namespace igl
   // See also: edges, cotmatrix, diag
   template <typename Index, typename IndexVector>
   IGL_INLINE void adjacency_list(
-    const Eigen::PlainObjectBase<Index> & F, 
+    const Eigen::MatrixBase<Index>  & F,
     std::vector<std::vector<IndexVector> >& A,
     bool sorted = false);
 

+ 2 - 0
include/igl/barycenter.cpp

@@ -54,4 +54,6 @@ template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::M
 template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
 template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&);
+template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&);
 #endif

+ 5 - 0
include/igl/bbw.cpp

@@ -118,7 +118,12 @@ IGL_INLINE bool igl::bbw(
     }
     W.col(i) = Wi;
   };
+#ifdef WIN32
+  for (int i = 0; i < m; ++i)
+    optimize_weight(i);
+#else
   parallel_for(m,optimize_weight,2);
+#endif
   if(error)
   {
     return false;

+ 118 - 37
include/igl/boundary_facets.cpp

@@ -7,19 +7,127 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "boundary_facets.h"
 #include "face_occurrences.h"
-
-// IGL includes
+#include "list_to_matrix.h"
+#include "matrix_to_list.h"
 #include "sort.h"
+#include "unique_rows.h"
+#include "accumarray.h"
+#include "slice_mask.h"
+
+#include <Eigen/Core>
 
-// STL includes
 #include <map>
 #include <iostream>
 
+template <
+  typename DerivedT, 
+  typename DerivedF,
+  typename DerivedJ,
+  typename DerivedK>
+IGL_INLINE void igl::boundary_facets(
+  const Eigen::MatrixBase<DerivedT>& T,
+  Eigen::PlainObjectBase<DerivedF>& F,
+  Eigen::PlainObjectBase<DerivedJ>& J,
+  Eigen::PlainObjectBase<DerivedK>& K)
+{
+  const int simplex_size = T.cols();
+  // Handle boring base case
+  if(T.rows() == 0)
+  {
+    F.resize(0,simplex_size-1);
+    J.resize(0,1);
+    K.resize(0,1);
+    return;
+  }
+  // Get a list of all facets
+  DerivedF allF(T.rows()*simplex_size,simplex_size-1);
+  // Gather faces (e.g., loop over tets)
+  for(int i = 0; i< (int)T.rows();i++)
+  {
+    switch(simplex_size)
+    {
+      case 4:
+        // get face in correct order
+        allF(i*simplex_size+0,0) = T(i,1);
+        allF(i*simplex_size+0,1) = T(i,3);
+        allF(i*simplex_size+0,2) = T(i,2);
+        // get face in correct order
+        allF(i*simplex_size+1,0) = T(i,0);
+        allF(i*simplex_size+1,1) = T(i,2);
+        allF(i*simplex_size+1,2) = T(i,3);
+        // get face in correct order
+        allF(i*simplex_size+2,0) = T(i,0);
+        allF(i*simplex_size+2,1) = T(i,3);
+        allF(i*simplex_size+2,2) = T(i,1);
+        // get face in correct order
+        allF(i*simplex_size+3,0) = T(i,0);
+        allF(i*simplex_size+3,1) = T(i,1);
+        allF(i*simplex_size+3,2) = T(i,2);
+        break;
+      case 3:
+        allF(i*simplex_size+0,0) = T(i,1);
+        allF(i*simplex_size+0,1) = T(i,2);
+        allF(i*simplex_size+1,0) = T(i,2);
+        allF(i*simplex_size+1,1) = T(i,0);
+        allF(i*simplex_size+2,0) = T(i,0);
+        allF(i*simplex_size+2,1) = T(i,1);
+        break;
+    }
+  }
+  DerivedF sortedF;
+  igl::sort(allF,2,true,sortedF);
+  Eigen::VectorXi m,n;
+  {
+    DerivedF _1;
+    igl::unique_rows(sortedF,_1,m,n);
+  }
+  Eigen::VectorXi C;
+  igl::accumarray(n,1,C);
+  const int ones = (C.array()==1).count();
+  // Resize output to fit number of non-twos
+  F.resize(ones, allF.cols());
+  J.resize(F.rows(),1);
+  K.resize(F.rows(),1);
+  int k = 0;
+  for(int c = 0;c< (int)C.size();c++)
+  {
+    if(C(c) == 1)
+    {
+      const int i = m(c);
+      assert(k<(int)F.rows());
+      F.row(k) = allF.row(i);
+      J(k) = i/simplex_size;
+      K(k) = i%simplex_size;
+      k++;
+    }
+  }
+  assert(k==(int)F.rows());
+}
+
+template <typename DerivedT, typename DerivedF>
+IGL_INLINE void igl::boundary_facets(
+  const Eigen::MatrixBase<DerivedT>& T,
+  Eigen::PlainObjectBase<DerivedF>& F)
+{
+  Eigen::VectorXi J,K;
+  return boundary_facets(T,F,J,K);
+}
+
+template <typename DerivedT, typename Ret>
+Ret igl::boundary_facets(
+  const Eigen::MatrixBase<DerivedT>& T)
+{
+  Ret F;
+  igl::boundary_facets(T,F);
+  return F;
+}
+
 template <typename IntegerT, typename IntegerF>
 IGL_INLINE void igl::boundary_facets(
   const std::vector<std::vector<IntegerT> > & T,
   std::vector<std::vector<IntegerF> > & F)
 {
+  // Kept for legacy reasons. Could probably just delete.
   using namespace std;
 
   if(T.size() == 0)
@@ -98,44 +206,17 @@ IGL_INLINE void igl::boundary_facets(
 
 }
 
-#include "list_to_matrix.h"
-#include "matrix_to_list.h"
-
-template <typename DerivedT, typename DerivedF>
-IGL_INLINE void igl::boundary_facets(
-  const Eigen::PlainObjectBase<DerivedT>& T,
-  Eigen::PlainObjectBase<DerivedF>& F)
-{
-  assert(T.cols() == 0 || T.cols() == 4 || T.cols() == 3);
-  using namespace std;
-  using namespace Eigen;
-  // Cop out: use vector of vectors version
-  vector<vector<typename DerivedT::Scalar> > vT;
-  matrix_to_list(T,vT);
-  vector<vector<typename DerivedF::Scalar> > vF;
-  boundary_facets(vT,vF);
-  list_to_matrix(vF,F);
-}
-
-template <typename DerivedT, typename Ret>
-Ret igl::boundary_facets(
-  const Eigen::PlainObjectBase<DerivedT>& T)
-{
-  Ret F;
-  igl::boundary_facets(T,F);
-  return F;
-}
-
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
-template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
+template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
 // generated by autoexplicit.sh
-template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
 template void igl::boundary_facets<int, int>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
-//template Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > igl::boundary_facets(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
-template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
-template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+//template Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > igl::boundary_facets(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
 #endif

+ 17 - 12
include/igl/boundary_facets.h

@@ -18,31 +18,36 @@ namespace igl
   // BOUNDARY_FACETS Determine boundary faces (edges) of tetrahedra (triangles)
   // stored in T (analogous to qptoolbox's `outline` and `boundary_faces`).
   //
-  // Templates:
-  //   IntegerT  integer-value: e.g. int
-  //   IntegerF  integer-value: e.g. int
   // Input:
   //  T  tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra
   // Output:
   //  F  list of boundary faces, n by 3 (2), where n is the number of boundary faces
+  //  J  list of indices into T, n by 1
+  //  K  list of indices revealing across from which vertex is this facet
   //
   //
-  template <typename IntegerT, typename IntegerF>
+  template <
+    typename DerivedT, 
+    typename DerivedF,
+    typename DerivedJ,
+    typename DerivedK>
   IGL_INLINE void boundary_facets(
-    const std::vector<std::vector<IntegerT> > & T,
-    std::vector<std::vector<IntegerF> > & F);
-
-  // Templates:
-  //   DerivedT  integer-value: i.e. from MatrixXi
-  //   DerivedF  integer-value: i.e. from MatrixXi
+    const Eigen::MatrixBase<DerivedT>& T,
+    Eigen::PlainObjectBase<DerivedF>& F,
+    Eigen::PlainObjectBase<DerivedJ>& J,
+    Eigen::PlainObjectBase<DerivedK>& K);
   template <typename DerivedT, typename DerivedF>
   IGL_INLINE void boundary_facets(
-    const Eigen::PlainObjectBase<DerivedT>& T,
+    const Eigen::MatrixBase<DerivedT>& T,
     Eigen::PlainObjectBase<DerivedF>& F);
   // Same as above but returns F
   template <typename DerivedT, typename Ret>
   Ret boundary_facets(
-    const Eigen::PlainObjectBase<DerivedT>& T);
+    const Eigen::MatrixBase<DerivedT>& T);
+  template <typename IntegerT, typename IntegerF>
+  IGL_INLINE void boundary_facets(
+    const std::vector<std::vector<IntegerT> > & T,
+    std::vector<std::vector<IntegerF> > & F);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 5 - 4
include/igl/boundary_loop.cpp

@@ -14,7 +14,7 @@
 
 template <typename DerivedF, typename Index>
 IGL_INLINE void igl::boundary_loop(
-    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedF> & F,
     std::vector<std::vector<Index> >& L)
 {
   using namespace std;
@@ -91,7 +91,7 @@ IGL_INLINE void igl::boundary_loop(
 
 template <typename DerivedF, typename Index>
 IGL_INLINE void igl::boundary_loop(
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedF>& F,
   std::vector<Index>& L)
 {
   using namespace Eigen;
@@ -130,7 +130,7 @@ IGL_INLINE void igl::boundary_loop(
 
 template <typename DerivedF, typename DerivedL>
 IGL_INLINE void igl::boundary_loop(
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedF>& F,
   Eigen::PlainObjectBase<DerivedL>& L)
 {
   using namespace Eigen;
@@ -149,5 +149,6 @@ IGL_INLINE void igl::boundary_loop(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::boundary_loop<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::boundary_loop<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::boundary_loop<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
 #endif

+ 3 - 3
include/igl/boundary_loop.h

@@ -25,7 +25,7 @@ namespace igl
   //
   template <typename DerivedF, typename Index>
   IGL_INLINE void boundary_loop(
-    const Eigen::PlainObjectBase<DerivedF>& F, 
+    const Eigen::MatrixBase<DerivedF>& F, 
     std::vector<std::vector<Index> >& L);
 
 
@@ -41,7 +41,7 @@ namespace igl
   //
   template <typename DerivedF, typename Index>
   IGL_INLINE void boundary_loop(
-    const Eigen::PlainObjectBase<DerivedF>& F, 
+    const Eigen::MatrixBase<DerivedF>& F, 
     std::vector<Index>& L);
 
   // Compute ordered boundary loops for a manifold mesh and return the 
@@ -56,7 +56,7 @@ namespace igl
   //
   template <typename DerivedF, typename DerivedL>
   IGL_INLINE void boundary_loop(
-    const Eigen::PlainObjectBase<DerivedF>& F, 
+    const Eigen::MatrixBase<DerivedF>& F, 
     Eigen::PlainObjectBase<DerivedL>& L);
 }
 

+ 68 - 0
include/igl/cat.cpp

@@ -251,6 +251,65 @@ IGL_INLINE void igl::cat(const std::vector<std::vector< Mat > > & A, Mat & C)
   }
 }
 
+template <typename T, typename DerivedC>
+IGL_INLINE void igl::cat(const int dim, const std::vector<T> & A, Eigen::PlainObjectBase<DerivedC> & C)
+{
+  assert(dim == 1 || dim == 2);
+  using namespace Eigen;
+
+  const int num_mat = A.size();
+  if(num_mat == 0)
+  {
+    C.resize(0,0);
+    return;
+  }
+
+  if(dim == 1)
+  {
+    const int A_cols = A[0].cols();
+
+    int tot_rows = 0;
+    for(const auto & m : A)
+    {
+      tot_rows += m.rows();
+    }
+
+    C.resize(tot_rows, A_cols);
+
+    int cur_row = 0;
+    for(int i = 0; i < num_mat; i++)
+    {
+      assert(A_cols == A[i].cols());
+      C.block(cur_row,0,A[i].rows(),A_cols) = A[i];
+      cur_row += A[i].rows();
+    }
+  }
+  else if(dim == 2)
+  {
+    const int A_rows = A[0].rows();
+
+    int tot_cols = 0;
+    for(const auto & m : A)
+    {
+      tot_cols += m.cols();
+    }
+
+    C.resize(A_rows,tot_cols);
+
+    int cur_col = 0;
+    for(int i = 0; i < num_mat; i++)
+    {
+      assert(A_rows == A[i].rows());
+      C.block(0,cur_col,A_rows,A[i].cols()) = A[i];
+      cur_col += A[i].cols();
+    }
+  }
+  else
+  {
+    fprintf(stderr,"cat.h: Error: Unsupported dimension %d\n",dim);
+  }
+}
+
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
@@ -265,4 +324,13 @@ template Eigen::Matrix<double, -1, 1, 0, -1, 1> igl::cat<Eigen::Matrix<double, -
 template void igl::cat<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
 template void igl::cat<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&);
 template void igl::cat<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+template void igl::cat<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cat<Eigen::Matrix<int, 1, 4, 1, 1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, 4, 1, 1, 4>, std::allocator<Eigen::Matrix<int, 1, 4, 1, 1, 4> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cat<Eigen::Matrix<int, 1, 15, 1, 1, 15>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, 15, 1, 1, 15>, std::allocator<Eigen::Matrix<int, 1, 15, 1, 1, 15> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cat<Eigen::Matrix<int, 1, 2, 1, 1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, 2, 1, 1, 2>, std::allocator<Eigen::Matrix<int, 1, 2, 1, 1, 2> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cat<Eigen::Matrix<int, 1, 27, 1, 1, 27>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, 27, 1, 1, 27>, std::allocator<Eigen::Matrix<int, 1, 27, 1, 1, 27> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cat<Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, 3, 1, 1, 3>, std::allocator<Eigen::Matrix<int, 1, 3, 1, 1, 3> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cat<Eigen::Matrix<int, 3, 1, 0, 3, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 3, 1, 0, 3, 1>, std::allocator<Eigen::Matrix<int, 3, 1, 0, 3, 1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cat<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<double, 1, 3, 1, 1, 3>, std::allocator<Eigen::Matrix<double, 1, 3, 1, 1, 3> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::cat<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<double, 3, 1, 0, 3, 1>, std::allocator<Eigen::Matrix<double, 3, 1, 0, 3, 1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 10 - 0
include/igl/cat.h

@@ -62,6 +62,16 @@ namespace igl
   //   C
   template <class Mat>
   IGL_INLINE void cat(const std::vector<std::vector< Mat > > & A, Mat & C);
+
+  // Concatenate a std::vector of matrices along the specified dimension
+  //
+  // Inputs:
+  //   dim  dimension along which to concatenate, 1 or 2
+  //   A  std::vector of eigen matrices. Must have identical # cols if dim == 1 or rows if dim == 2
+  // Outputs:
+  //   C  output matrix
+  template <typename T, typename DerivedC>
+  IGL_INLINE void cat(const int dim, const std::vector<T> & A, Eigen::PlainObjectBase<DerivedC> & C);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 4 - 6
include/igl/circulation.cpp

@@ -7,12 +7,11 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "circulation.h"
 #include "list_to_matrix.h"
+#include <cassert>
 
 IGL_INLINE std::vector<int> igl::circulation(
   const int e,
   const bool ccw,
-  const Eigen::MatrixXi & F,
-  const Eigen::MatrixXi & E,
   const Eigen::VectorXi & EMAP,
   const Eigen::MatrixXi & EF,
   const Eigen::MatrixXi & EI)
@@ -20,7 +19,8 @@ IGL_INLINE std::vector<int> igl::circulation(
   // prepare output
   std::vector<int> N;
   N.reserve(6);
-  const int m = F.rows();
+  const int m = EMAP.size()/3;
+  assert(m*3 == EMAP.size());
   const auto & step = [&](
     const int e, 
     const int ff,
@@ -59,13 +59,11 @@ IGL_INLINE std::vector<int> igl::circulation(
 IGL_INLINE void igl::circulation(
   const int e,
   const bool ccw,
-  const Eigen::MatrixXi & F,
-  const Eigen::MatrixXi & E,
   const Eigen::VectorXi & EMAP,
   const Eigen::MatrixXi & EF,
   const Eigen::MatrixXi & EI,
   Eigen::VectorXi & vN)
 {
-  std::vector<int> N = circulation(e,ccw,F,E,EMAP,EF,EI);
+  std::vector<int> N = circulation(e,ccw,EMAP,EF,EI);
   igl::list_to_matrix(N,vN);
 }

+ 1 - 6
include/igl/circulation.h

@@ -20,8 +20,6 @@ namespace igl
   //   e  index into E of edge to circulate
   //   ccw  whether to _continue_ in ccw direction of edge (circulate around
   //     E(e,1))
-  //   F  #F by 3 list of face indices
-  //   E  #E by 2 list of edge indices
   //   EMAP #F*3 list of indices into E, mapping each directed edge to unique
   //     unique edge in E
   //   EF  #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
@@ -30,11 +28,10 @@ namespace igl
   //   EI  #E by 2 list of edge flap corners (see above).
   // Returns list of faces touched by circulation (in cyclically order).
   //   
+  // See also: edge_flaps
   IGL_INLINE std::vector<int> circulation(
     const int e,
     const bool ccw,
-    const Eigen::MatrixXi & F,
-    const Eigen::MatrixXi & E,
     const Eigen::VectorXi & EMAP,
     const Eigen::MatrixXi & EF,
     const Eigen::MatrixXi & EI);
@@ -42,8 +39,6 @@ namespace igl
   IGL_INLINE void circulation(
     const int e,
     const bool ccw,
-    const Eigen::MatrixXi & F,
-    const Eigen::MatrixXi & E,
     const Eigen::VectorXi & EMAP,
     const Eigen::MatrixXi & EF,
     const Eigen::MatrixXi & EI,

+ 3 - 3
include/igl/collapse_edge.cpp

@@ -40,7 +40,7 @@ IGL_INLINE bool igl::collapse_edge(
   }
 
   // Important to grab neighbors of d before monkeying with edges
-  const std::vector<int> nV2Fd = circulation(e,!eflip,F,E,EMAP,EF,EI);
+  const std::vector<int> nV2Fd = circulation(e,!eflip,EMAP,EF,EI);
 
   // The following implementation strongly relies on s<d
   assert(s<d && "s should be less than d");
@@ -339,8 +339,8 @@ IGL_INLINE bool igl::collapse_edge(
   Q.erase(Q.begin());
   e = p.second;
   Qit[e] = Q.end();
-  std::vector<int> N  = circulation(e, true,F,E,EMAP,EF,EI);
-  std::vector<int> Nd = circulation(e,false,F,E,EMAP,EF,EI);
+  std::vector<int> N  = circulation(e, true,EMAP,EF,EI);
+  std::vector<int> Nd = circulation(e,false,EMAP,EF,EI);
   N.insert(N.begin(),Nd.begin(),Nd.end());
   bool collapsed = true;
   if(pre_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e))

+ 3 - 3
include/igl/collapse_edge.h

@@ -37,9 +37,9 @@ namespace igl
   //     e=(j->i)
   //   EI  #E by 2 list of edge flap corners (see above).
   //   e1  index into E of edge collpased on left
-  //   e2  index into E of edge collpased on left
-  //   f1  index into E of edge collpased on left
-  //   f2  index into E of edge collpased on left
+  //   e2  index into E of edge collpased on right
+  //   f1  index into F of face collpased on left
+  //   f2  index into F of face collpased on right
   // Returns true if edge was collapsed
   #define IGL_COLLAPSE_EDGE_NULL 0
   IGL_INLINE bool collapse_edge(

+ 2 - 0
include/igl/colon.cpp

@@ -59,8 +59,10 @@ template void igl::colon<int, double, double, double>(int, double, double, Eigen
 template void igl::colon<double, double, double>(double, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
 template void igl::colon<double, double, double, double>(double, double, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
 template void igl::colon<int, int, long>(int, int, Eigen::Matrix<long, -1, 1, 0, -1, 1>&);
+template void igl::colon<int, long, double>(int, long, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
 #ifdef WIN32
 template void igl::colon<int, long long,long>(int, long long, class Eigen::Matrix<long,-1,1,0,-1,1> &);
 template void igl::colon<int, __int64, __int64>(int, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> &);
+template void igl::colon<int,__int64,double>(int,__int64,class Eigen::Matrix<double,-1,1,0,-1,1> &);
 #endif
 #endif

+ 0 - 4
include/igl/comb_frame_field.cpp

@@ -69,10 +69,6 @@ IGL_INLINE void igl::comb_frame_field(const Eigen::PlainObjectBase<DerivedV> &V,
     PD2_combed.row(i) = DIRs.row(M);
 
   }
-
-
-  //    PD1_combed = BIS1_combed;
-  //    PD2_combed = BIS2_combed;
 }
 
 #ifdef IGL_STATIC_LIBRARY

+ 1 - 0
include/igl/combine.cpp

@@ -90,6 +90,7 @@ IGL_INLINE void igl::combine(
 // Explicit template instantiation
 template void igl::combine<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<unsigned long, -1, 1, 0, -1, 1>, Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&);
 template void igl::combine<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::vector<Eigen::Matrix<double, -1, 3, 1, -1, 3>, std::allocator<Eigen::Matrix<double, -1, 3, 1, -1, 3> > > const&, std::vector<Eigen::Matrix<int, -1, 3, 1, -1, 3>, std::allocator<Eigen::Matrix<int, -1, 3, 1, -1, 3> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+template void igl::combine<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> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #ifdef WIN32
 template void igl::combine<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<unsigned __int64,-1,1,0,-1,1>,Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> >(class std::vector<Eigen::Matrix<double,-1,-1,0,-1,-1>,class std::allocator<Eigen::Matrix<double,-1,-1,0,-1,-1> > > const &,class std::vector<Eigen::Matrix<int,-1,-1,0,-1,-1>,class std::allocator<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<unsigned __int64,-1,1,0,-1,1> > &,Eigen::PlainObjectBase<Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> > &);
 template void igl::combine<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<unsigned __int64,-1,1,0,-1,1>,Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> >(class std::vector<Eigen::Matrix<double,-1,-1,0,-1,-1>,class std::allocator<Eigen::Matrix<double,-1,-1,0,-1,-1> > > const &,class std::vector<Eigen::Matrix<int,-1,-1,0,-1,-1>,class std::allocator<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<unsigned __int64,-1,1,0,-1,1> > &,Eigen::PlainObjectBase<Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> > &);

+ 1 - 0
include/igl/compute_frame_field_bisectors.cpp

@@ -82,4 +82,5 @@ IGL_INLINE void igl::compute_frame_field_bisectors(
 // Explicit template instantiation
 template void igl::compute_frame_field_bisectors<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
 template void igl::compute_frame_field_bisectors<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&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::compute_frame_field_bisectors<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&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 42 - 12
include/igl/copyleft/cgal/convex_hull.cpp

@@ -24,20 +24,48 @@ IGL_INLINE void igl::copyleft::cgal::convex_hull(
   Eigen::PlainObjectBase<DerivedG> & G)
 {
   typedef CGAL::Exact_predicates_inexact_constructions_kernel      K;
-  typedef K::Point_3                                              Point_3;
-  //typedef CGAL::Delaunay_triangulation_3<K>                       Delaunay;
-  //typedef Delaunay::Vertex_handle                                 Vertex_handle;
-  //typedef CGAL::Surface_mesh<Point_3>                             Surface_mesh;
-  typedef CGAL::Polyhedron_3<K>                             Polyhedron_3;
-  std::vector<Point_3> points(V.rows());
-  for(int i = 0;i<V.rows();i++)
+  switch(V.cols())
   {
-    points[i] = Point_3(V(i,0),V(i,1),V(i,2));
+    case 3:
+    {
+      typedef K::Point_3                                              Point_3;
+      //typedef CGAL::Delaunay_triangulation_3<K>                       Delaunay;
+      //typedef Delaunay::Vertex_handle                                 Vertex_handle;
+      //typedef CGAL::Surface_mesh<Point_3>                             Surface_mesh;
+      typedef CGAL::Polyhedron_3<K>                             Polyhedron_3;
+      std::vector<Point_3> points(V.rows());
+      for(int i = 0;i<V.rows();i++)
+      {
+        points[i] = Point_3(V(i,0),V(i,1),V(i,2));
+      }
+      Polyhedron_3 poly;
+      CGAL::convex_hull_3(points.begin(),points.end(),poly);
+      assert(poly.is_pure_triangle() && "Assuming CGAL outputs a triangle mesh");
+      polyhedron_to_mesh(poly,W,G);
+      break;
+    }
+    case 2:
+    {
+      typedef K::Point_2 Point_2;
+      std::vector<Point_2> points(V.rows());
+      std::vector<Point_2> result;
+      for(int i = 0;i<V.rows();i++)
+      {
+        points[i] = Point_2(V(i,0),V(i,1));
+      }
+      CGAL::convex_hull_2(points.begin(),points.end(),std::back_inserter(result));
+      W.resize(result.size(),2);
+      G.resize(result.size(),2);
+      for(int i = 0;i<result.size();i++)
+      {
+        W(i,0) = result[i].x();
+        W(i,1) = result[i].y();
+        G(i,0) = i;
+        G(i,1) = (i+1)%result.size();
+      }
+      break;
+    }
   }
-  Polyhedron_3 poly;
-  CGAL::convex_hull_3(points.begin(),points.end(),poly);
-  assert(poly.is_pure_triangle() && "Assuming CGAL outputs a triangle mesh");
-  polyhedron_to_mesh(poly,W,G);
 }
 
 template <
@@ -69,4 +97,6 @@ IGL_INLINE void igl::copyleft::cgal::convex_hull(
 // Explicit template instantiation
 // 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> >&);
 #endif

+ 6 - 1
include/igl/copyleft/cgal/delaunay_triangulation.cpp

@@ -16,7 +16,7 @@ template<
   typename DerivedV,
   typename DerivedF>
 IGL_INLINE void igl::copyleft::cgal::delaunay_triangulation(
-    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedV>& V,
     Eigen::PlainObjectBase<DerivedF>& F)
 {
   typedef typename DerivedV::Scalar Scalar;
@@ -60,3 +60,8 @@ IGL_INLINE void igl::copyleft::cgal::delaunay_triangulation(
 //  };
 }
 
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::delaunay_triangulation<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> >&);
+#endif

+ 1 - 1
include/igl/copyleft/cgal/delaunay_triangulation.h

@@ -32,7 +32,7 @@ namespace igl
         typename DerivedF
         >
       IGL_INLINE void delaunay_triangulation(
-          const Eigen::PlainObjectBase<DerivedV>& V,
+          const Eigen::MatrixBase<DerivedV>& V,
           Eigen::PlainObjectBase<DerivedF>& F);
     }
   }

+ 23 - 22
include/igl/copyleft/cgal/extract_cells.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 //
 #include "extract_cells.h"
@@ -56,7 +56,7 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
     igl::copyleft::cgal::extract_cells(V,F,P,E,uE,uE2E,EMAP,per_patch_cells);
   // Distribute per-patch cell information to each face
   cells.resize(num_faces, 2);
-  for (size_t i=0; i<num_faces; i++) 
+  for (size_t i=0; i<num_faces; i++)
   {
     cells.row(i) = per_patch_cells.row(P[i]);
   }
@@ -81,7 +81,7 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
   const Eigen::PlainObjectBase<DeriveduE>& uE,
   const std::vector<std::vector<uE2EType> >& uE2E,
   const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
-  Eigen::PlainObjectBase<DerivedC>& cells) 
+  Eigen::PlainObjectBase<DerivedC>& cells)
 {
   // Trivial base case
   if(P.size() == 0)
@@ -143,7 +143,7 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
   // components[c] --> list of face indices into F of faces in component c
   std::vector<std::vector<size_t> > components(num_components);
   // Loop over all faces
-  for (size_t i=0; i<num_faces; i++) 
+  for (size_t i=0; i<num_faces; i++)
   {
     components[C[i]].push_back(i);
   }
@@ -155,11 +155,11 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
   std::vector<
     CGAL::AABB_tree<
       CGAL::AABB_traits<
-        Kernel, 
+        Kernel,
         CGAL::AABB_triangle_primitive<
           Kernel, std::vector<
             Kernel::Triangle_3 >::iterator > > > > trees(num_components);
-  std::vector< std::vector<Kernel::Triangle_3 > > 
+  std::vector< std::vector<Kernel::Triangle_3 > >
     triangle_lists(num_components);
   std::vector<std::vector<bool> > in_Is(num_components);
 
@@ -185,7 +185,7 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
   // Inputs:
   //   fid  index into F
   // Returns row-vector of barycenter coordinates
-  const auto get_triangle_center = [&V,&F](const size_t fid) 
+  const auto get_triangle_center = [&V,&F](const size_t fid)
   {
     return ((V.row(F(fid,0))+V.row(F(fid,1))+V.row(F(fid,2)))/3.0).eval();
   };
@@ -193,7 +193,7 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
   std::vector<std::vector<size_t> > ambient_cells(num_raw_cells);
   std::vector<std::vector<size_t> > ambient_comps(num_components);
   // Only bother if there's more than one component
-  if(num_components > 1) 
+  if(num_components > 1)
   {
     // construct bounding boxes for each component
     DerivedV bbox_min(num_components, 3);
@@ -207,7 +207,7 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
       // component of this face
       const auto comp_id = C[i];
       const auto& f = F.row(i);
-      for (size_t j=0; j<3; j++) 
+      for (size_t j=0; j<3; j++)
       {
         for(size_t d=0;d<3;d++)
         {
@@ -227,7 +227,7 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
         bbox_max(cj,1) < bbox_min(ci,1) ||
         bbox_max(cj,2) < bbox_min(ci,2));
     };
-    
+
     // Loop over components. This section is O(m²)
     for (size_t i=0; i<num_components; i++)
     {
@@ -235,7 +235,7 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
       std::vector<size_t> candidate_comps;
       candidate_comps.reserve(num_components);
       // Loop over components
-      for (size_t j=0; j<num_components; j++) 
+      for (size_t j=0; j<num_components; j++)
       {
         if (i == j) continue;
         if (bbox_intersects(i,j)) candidate_comps.push_back(j);
@@ -248,7 +248,7 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
       submesh_aabb_tree(V,F,Is[i],trees[i],triangle_lists[i],in_Is[i]);
 
       // Get query points on each candidate component: barycenter of
-      // outer-facet 
+      // outer-facet
       DerivedV queries(num_candidate_comps, 3);
       for (size_t j=0; j<num_candidate_comps; j++)
       {
@@ -266,17 +266,17 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
       Eigen::VectorXi closest_facets, closest_facet_orientations;
       closest_facet(
         V,
-        F, 
-        I, 
+        F,
+        I,
         queries,
-        uE2E, 
-        EMAP, 
+        uE2E,
+        EMAP,
         VF,
         VFi,
         tree,
         triangles,
         in_I,
-        closest_facets, 
+        closest_facets,
         closest_facet_orientations);
       // Loop over all candidates
       for (size_t j=0; j<num_candidate_comps; j++)
@@ -402,13 +402,13 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells_single_component(
   };
   // Determine if a face (containing undirected edge {s,d} is consistently
   // oriented with directed edge {s,d} (or otherwise it is with {d,s})
-  // 
+  //
   // Inputs:
   //   fid  face index into F
   //   s  source index of edge
   //   d  destination index of edge
   // Returns true if face F(fid,:) is consistent with {s,d}
-  const auto is_consistent = 
+  const auto is_consistent =
     [&F](const size_t fid, const size_t s, const size_t d) -> bool
   {
     if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false;
@@ -543,5 +543,6 @@ template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::La
 template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
 template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
 template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
+template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1> >(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > &);
 #endif
 #endif

+ 1 - 1
include/igl/copyleft/cgal/hausdorff.cpp

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

+ 17 - 8
include/igl/copyleft/cgal/incircle.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 #include "incircle.h"
@@ -12,10 +12,10 @@
 
 template<typename Scalar>
 IGL_INLINE short igl::copyleft::cgal::incircle(
-    const Scalar pa[2],
-    const Scalar pb[2],
-    const Scalar pc[2],
-    const Scalar pd[2])
+    const Scalar *pa,
+    const Scalar *pb,
+    const Scalar *pc,
+    const Scalar *pd)
 {
   typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
   typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
@@ -37,3 +37,12 @@ IGL_INLINE short igl::copyleft::cgal::incircle(
       throw "Invalid incircle result";
   }
 }
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template short igl::copyleft::cgal::incircle<double>(double const*, double const*, double const*, double const*);
+#ifdef WIN32
+template short igl::copyleft::cgal::incircle<double>(double const * const,double const * const,double const * const,double const * const);
+#endif
+#endif

+ 8 - 8
include/igl/copyleft/cgal/incircle.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 #ifndef IGL_COPYLEFT_CGAL_INCIRCLE_H
@@ -25,10 +25,10 @@ namespace igl
       //  -1 if pd is outside of the oriented circle formed by pa,pb,pc.
       template <typename Scalar>
       IGL_INLINE short incircle(
-          const Scalar pa[2],
-          const Scalar pb[2],
-          const Scalar pc[2],
-          const Scalar pd[2]);
+          const Scalar *pa,
+          const Scalar *pb,
+          const Scalar *pc,
+          const Scalar *pd);
     }
   }
 }

+ 9 - 6
include/igl/copyleft/cgal/mesh_to_polyhedron.cpp

@@ -9,12 +9,14 @@
 #include <CGAL/Polyhedron_3.h>
 #include <CGAL/Polyhedron_incremental_builder_3.h>
 
-
-template <typename Polyhedron>
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename Polyhedron>
 IGL_INLINE bool igl::copyleft::cgal::mesh_to_polyhedron(
-  const Eigen::MatrixXd & V,
-  const Eigen::MatrixXi & F,
-  Polyhedron & poly)
+  const Eigen::MatrixBase<DerivedV>& V, 
+  const Eigen::MatrixBase<DerivedF>& F,
+  Polyhedron& poly) 
 {
   typedef typename Polyhedron::HalfedgeDS HalfedgeDS;
   // Postcondition: hds is a valid polyhedral surface.
@@ -50,5 +52,6 @@ IGL_INLINE bool igl::copyleft::cgal::mesh_to_polyhedron(
 // Explicit template instantiation
 #include <CGAL/Simple_cartesian.h>
 #include <CGAL/Polyhedron_items_with_id_3.h>
-template bool igl::copyleft::cgal::mesh_to_polyhedron<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> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>, CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >&);
+#include <CGAL/Polyhedron_3.h>
+template bool igl::copyleft::cgal::mesh_to_polyhedron<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> > >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>, CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >&);
 #endif

+ 6 - 3
include/igl/copyleft/cgal/mesh_to_polyhedron.h

@@ -27,10 +27,13 @@ namespace igl
       //   poly  cgal polyhedron
       // Returns true only if (V,F) can be converted to a valid polyhedron (i.e. if
       // (V,F) is vertex and edge manifold).
-      template <typename Polyhedron>
+      template <
+        typename DerivedV,
+        typename DerivedF,
+        typename Polyhedron>
       IGL_INLINE bool mesh_to_polyhedron(
-        const Eigen::MatrixXd & V,
-        const Eigen::MatrixXi & F,
+        const Eigen::MatrixBase<DerivedV> & V,
+        const Eigen::MatrixBase<DerivedF> & F,
         Polyhedron & poly);
     }
   }

+ 10 - 5
include/igl/copyleft/cgal/order_facets_around_edges.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "order_facets_around_edges.h"
 #include "order_facets_around_edge.h"
@@ -160,7 +160,7 @@ template<
     typename uE2EType,
     typename uE2oEType,
     typename uE2CType >
-IGL_INLINE 
+IGL_INLINE
 typename std::enable_if<std::is_same<typename DerivedV::Scalar,
 typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
 igl::copyleft::cgal::order_facets_around_edges(
@@ -329,4 +329,9 @@ template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<CGAL:
 template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
 template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
 template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
+#ifdef WIN32
+template void igl::copyleft::cgal::order_facets_around_edges<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,2,0,-1,2>,__int64,__int64,bool>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,2,0,-1,2> > const &,class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > > const &,class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > > &,class std::vector<class std::vector<bool,class std::allocator<bool> >,class std::allocator<class std::vector<bool,class std::allocator<bool> > > > &);
+template void igl::copyleft::cgal::order_facets_around_edges<class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,2,0,-1,2>,__int64,__int64,bool>(class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,2,0,-1,2> > const &,class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > > const &,class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > > &,class std::vector<class std::vector<bool,class std::allocator<bool> >,class std::allocator<class std::vector<bool,class std::allocator<bool> > > > &);
+template void igl::copyleft::cgal::order_facets_around_edges<class Eigen::Matrix<double,-1,3,0,-1,3>,class Eigen::Matrix<int,-1,3,0,-1,3>,class Eigen::Matrix<int,-1,2,0,-1,2>,__int64,__int64,bool>(class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,3,0,-1,3> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,2,0,-1,2> > const &,class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > > const &,class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > > &,class std::vector<class std::vector<bool,class std::allocator<bool> >,class std::allocator<class std::vector<bool,class std::allocator<bool> > > > &);
+#endif
 #endif

+ 18 - 8
include/igl/copyleft/cgal/orient2D.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 #include "orient2D.h"
@@ -12,9 +12,9 @@
 
 template<typename Scalar>
 IGL_INLINE short igl::copyleft::cgal::orient2D(
-    const Scalar pa[2],
-    const Scalar pb[2],
-    const Scalar pc[2])
+    const Scalar *pa,
+    const Scalar *pb,
+    const Scalar *pc)
 {
   typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
   typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
@@ -24,7 +24,8 @@ IGL_INLINE short igl::copyleft::cgal::orient2D(
   switch(CGAL::orientation(
         typename Kernel::Point_2(pa[0], pa[1]),
         typename Kernel::Point_2(pb[0], pb[1]),
-        typename Kernel::Point_2(pc[0], pc[1]))) {
+        typename Kernel::Point_2(pc[0], pc[1])))
+  {
     case CGAL::LEFT_TURN:
       return 1;
     case CGAL::RIGHT_TURN:
@@ -35,3 +36,12 @@ IGL_INLINE short igl::copyleft::cgal::orient2D(
       throw "Invalid orientation";
   }
 }
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template short igl::copyleft::cgal::orient2D<double>(double const*, double const*, double const*);
+#ifdef WIN32
+template short igl::copyleft::cgal::orient2D<double>(double const * const, double const * const, double const * const);
+#endif
+#endif

+ 7 - 7
include/igl/copyleft/cgal/orient2D.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 #ifndef IGL_COPYLEFT_CGAL_ORIENT_2D_H
@@ -25,9 +25,9 @@ namespace igl
       //  -1 if pa,pb,pc are clockwise oriented.
       template <typename Scalar>
       IGL_INLINE short orient2D(
-          const Scalar pa[2],
-          const Scalar pb[2],
-          const Scalar pc[2]);
+          const Scalar *pa,
+          const Scalar *pb,
+          const Scalar *pc);
     }
   }
 }

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

@@ -224,9 +224,11 @@ template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::La
 template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
 template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
 template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,__int64,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > const &,__int64 &,__int64 &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
 template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
 template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
 template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 1, -1, -1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 1, -1, -1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
 template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double,-1,3,0,-1,3>,class Eigen::Matrix<int,-1,3,0,-1,3>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,__int64,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,3,0,-1,3> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > const &,__int64 &,__int64 &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
 #endif
 #endif

+ 9 - 6
include/igl/copyleft/cgal/outer_facet.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 #include "outer_facet.h"
@@ -39,7 +39,7 @@ IGL_INLINE void igl::copyleft::cgal::outer_facet(
     //    implemnetation of outer_edge()). The first adjacent facet is facing
     //    outside (i.e. flipped=false) if it has positive X normal component.
     //    If it has zero normal component, it is facing outside if it contains
-    //    directed edge (s, d).  
+    //    directed edge (s, d).
 
     //typedef typename DerivedV::Scalar Scalar;
     typedef typename DerivedV::Index Index;
@@ -118,7 +118,7 @@ IGL_INLINE void igl::copyleft::cgal::outer_facet(
     Scalar max_nx = 0;
     size_t outer_fid = INVALID;
     const size_t num_incident_faces = incident_faces.size();
-    for (size_t i=0; i<num_incident_faces; i++) 
+    for (size_t i=0; i<num_incident_faces; i++)
     {
         const auto& fid = incident_faces(i);
         const Scalar nx = N(fid, 0);
@@ -176,5 +176,8 @@ template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0,
 template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
 template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
 template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
+template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,int>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > const &,int &,bool &);
+template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,1,0,-1,1>,unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > const &,unsigned __int64 &,bool &);
+template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<double,-1,3,0,-1,3>,class Eigen::Matrix<int,-1,3,0,-1,3>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,int>(class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,3,0,-1,3> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > const &,int &,bool &);
 #endif
 #endif

+ 4 - 0
include/igl/copyleft/cgal/outer_hull.cpp

@@ -532,4 +532,8 @@ template void igl::copyleft::cgal::outer_hull_legacy< Eigen::Matrix<double, -1,
 template void igl::copyleft::cgal::outer_hull_legacy< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::copyleft::cgal::outer_hull_legacy<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::copyleft::cgal::outer_hull_legacy<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::copyleft::cgal::outer_hull_legacy<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<int,-1,1,0,-1,1> >(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > &);
+template void igl::copyleft::cgal::outer_hull_legacy<class Eigen::Matrix<double,-1,3,0,-1,3>,class Eigen::Matrix<int,-1,3,0,-1,3>,class Eigen::Matrix<int,-1,3,0,-1,3>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<int,-1,1,0,-1,1> >(class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,3,0,-1,3> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,3,0,-1,3> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > &);
+#endif
 #endif

+ 7 - 4
include/igl/copyleft/cgal/peel_outer_hull_layers.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "peel_outer_hull_layers.h"
 #include "outer_hull.h"
@@ -121,4 +121,7 @@ IGL_INLINE size_t igl::copyleft::cgal::peel_outer_hull_layers(
 #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
 template unsigned long igl::copyleft::cgal::peel_outer_hull_layers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template size_t igl::copyleft::cgal::peel_outer_hull_layers<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template unsigned __int64 igl::copyleft::cgal::peel_outer_hull_layers<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,1,0,-1,1>,class Eigen::Matrix<int,-1,1,0,-1,1> >(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > &);
+#endif
 #endif

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

@@ -524,6 +524,8 @@ template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy
 template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, 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<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, 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<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1,   0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck,   Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>,   Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>,   Eigen::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&, std::vector<CGAL::Triangle_3<CGAL::Epeck>,   std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&,   std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index,   std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index,   CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1,   0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1,   -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int,   -1, -1, 0, -1, -1>::Index const,   std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index,   CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1,   0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool,   Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3,   0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&,   Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&,   Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck, 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, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick, 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, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, 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> >&);
 #ifdef WIN32
 template void igl::copyleft::cgal::remesh_intersections<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class CGAL::Epeck, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::map<__int64, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>, struct std::less<__int64>, class std::allocator<struct std::pair<__int64 const, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>>>> const &, bool, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
 template void igl::copyleft::cgal::remesh_intersections<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class CGAL::Epick, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epick>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epick>>> const &, class std::map<__int64, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>, struct std::less<__int64>, class std::allocator<struct std::pair<__int64 const, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>>>> const &, bool, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);

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

@@ -101,6 +101,7 @@ template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<CGAL:
 template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 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<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, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam 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<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam 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<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, -1, 1, -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<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, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam 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<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam 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<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #ifdef WIN32
 template void igl::copyleft::cgal::remesh_self_intersections<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, struct igl::copyleft::cgal::RemeshSelfIntersectionsParam const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
 template void igl::copyleft::cgal::remesh_self_intersections<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, struct igl::copyleft::cgal::RemeshSelfIntersectionsParam const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);

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

@@ -62,6 +62,15 @@ IGL_INLINE void igl::copyleft::cgal::wire_mesh(
     v = v-c*(PV.rows());
     p = v;
   };
+
+  // Count each vertex's indicident edges.
+  std::vector<int> nedges(WV.rows(), 0);
+  for(int e = 0;e<WE.rows();e++)
+  {
+    ++nedges[WE(e, 0)];
+    ++nedges[WE(e, 1)];
+  }
+
   // loop over all edges
   for(int e = 0;e<WE.rows();e++)
   {
@@ -88,7 +97,8 @@ IGL_INLINE void igl::copyleft::cgal::wire_mesh(
         // Start with factor of thickness;
         // Max out amount at 1/3 of edge length so that there's always some
         // amount of edge
-        Scalar dist = std::min(1.*th,len/3.0);
+        // Zero out if vertex is incident on only one edge
+        Scalar dist = std::min(1.*th,len/3.0) * (nedges[WE(e,c)] > 1);
         // Move to endpoint, offset by amount
         V.row(index(e,c,p)) = 
           qp+WV.row(WE(e,c)) + dist*dir*uv;

File diff suppressed because it is too large
+ 239 - 225
include/igl/copyleft/comiso/miq.cpp


+ 70 - 45
include/igl/copyleft/comiso/miq.h

@@ -17,35 +17,37 @@ namespace igl
   {
   namespace comiso
   {
-  // Global seamless parametrization aligned with a given per-face jacobian (PD1,PD2).
+    // Global seamless parametrization aligned with a given per-face Jacobian (PD1, PD2).
     // The algorithm is based on
     // "Mixed-Integer Quadrangulation" by D. Bommes, H. Zimmer, L. Kobbelt
     // ACM SIGGRAPH 2009, Article No. 77 (http://dl.acm.org/citation.cfm?id=1531383)
     // We thank Nico Pietroni for providing a reference implementation of MIQ
     // on which our code is based.
 
-    // Inputs:
-    //   V              #V by 3 list of mesh vertex 3D positions
-    //   F              #F by 3 list of faces indices in V
-    //   PD1            #V by 3 first line of the Jacobian per triangle
-    //   PD2            #V by 3 second line of the Jacobian per triangle
-    //                  (optional, if empty it will be a vector in the tangent plane orthogonal to PD1)
-    //   scale          global scaling for the gradient (controls the quads resolution)
-    //   stiffness      weight for the stiffness iterations
-    //   direct_round   greedily round all integer variables at once (greatly improves optimization speed but lowers quality)
-    //   iter           stiffness iterations (0 = no stiffness)
-    //   local_iter     number of local iterations for the integer rounding
-    //   do_round       enables the integer rounding (disabling it could be useful for debugging)
-    //   round_vertices id of additional vertices that should be snapped to integer coordinates
-    //   hard_features  #H by 2 list of pairs of vertices that belongs to edges that should be snapped to integer coordinates
+    //  Limitations:
+    //  -  Due to the way of handling of hardFeatures the algorithm  may fail in difficult cases.
+    //  -  Meshes with boundaries are not hendled properly i.e., jagged edges along the boundary are possible
+
+    // Input:
+    // V                 #V by 3 list of mesh vertex 3D positions
+    // F                 #F by 3 list of faces indices in V
+    // PD1               #V by 3 first line of the Jacobian per triangle
+    // PD2               #V by 3 second line of the Jacobian per triangle
+    //                   (optional, if empty it will be a vector in the tangent plane orthogonal to PD1)
+    // gradientSize      global scaling for the gradient (controls the quads resolution)
+    // stiffness         weight for the stiffness iterations (Reserved but not used!)
+    // directRound       greedily round all integer variables at once (greatly improves optimization speed but lowers quality)
+    // iter              stiffness iterations (0 = no stiffness)
+    // localIter         number of local iterations for the integer rounding
+    // doRound           enables the integer rounding (disabling it could be useful for debugging)
+    // singularityRound  set true/false to decide if the singularities' coordinates should be rounded to the nearest integers
+    // roundVertices     id of additional vertices that should be snapped to integer coordinates
+    // hardFeatures      #H by 2 list of pairs of vertices that belongs to edges that should be snapped to integer coordinates
     //
     // Output:
-    //   UV             #UV by 2 list of vertices in 2D
-    //   FUV            #FUV by 3 list of face indices in UV
+    // UV                 #UV by 2 list of vertices in 2D
+    // FUV                #FUV by 3 list of face indices in UV
     //
-    // TODO: rename the parameters name in the cpp consistently
-    //       improve the handling of hard_features, right now it might fail in difficult cases
-
     template <typename DerivedV, typename DerivedF, typename DerivedU>
     IGL_INLINE void miq(
       const Eigen::PlainObjectBase<DerivedV> &V,
@@ -54,41 +56,64 @@ namespace igl
       const Eigen::PlainObjectBase<DerivedV> &PD2,
       Eigen::PlainObjectBase<DerivedU> &UV,
       Eigen::PlainObjectBase<DerivedF> &FUV,
-      double scale = 30.0,
+      double gradientSize = 30.0,
       double stiffness = 5.0,
-      bool direct_round = false,
-      int iter = 5,
-      int local_iter = 5,
-      bool DoRound = true,bool SingularityRound=true,
-      std::vector<int> round_vertices = std::vector<int>(),
-      std::vector<std::vector<int> > hard_features = std::vector<std::vector<int> >());
+      bool directRound = false,
+      unsigned int iter = 5,
+      unsigned int localIter = 5,
+      bool doRound = true,
+      bool singularityRound = true,
+      const std::vector<int> &roundVertices = std::vector<int>(),
+      const std::vector<std::vector<int>> &hardFeatures = std::vector<std::vector<int> >());
 
     // Helper function that allows to directly provided pre-combed bisectors for an already cut mesh
-    // Additional input:
-    // PD1_combed, PD2_combed  :   #F by 3 combed jacobian
-    // BIS1_combed, BIS2_combed:   #F by 3 pre combed bi-sectors
-    // MMatch:                     #F by 3 list of per-corner integer PI/2 rotations
-    // Singular:                   #V list of flag that denotes if a vertex is singular or not
-    // SingularDegree:             #V list of flag that denotes the degree of the singularity
-    // Seams:                      #F by 3 list of per-corner flag that denotes seams
 
+    // Input:
+    // V                  #V by 3 list of mesh vertex 3D positions
+    // F                  #F by 3 list of faces indices in V
+
+    // Additional Input:
+    // PD1_combed         #F by 3 first combed Jacobian
+    // PD2_combed         #F by 3 second combed Jacobian
+    // mismatch             #F by 3 list of per-corner integer PI/2 rotations
+    // singular           #V list of flag that denotes if a vertex is singular or not
+    // seams              #F by 3 list of per-corner flag that denotes seams
+
+    // Input:
+    // gradientSize       global scaling for the gradient (controls the quads resolution)
+    // stiffness          weight for the stiffness iterations (Reserved but not used!)
+    // directRound        greedily round all integer variables at once (greatly improves optimization speed but lowers quality)
+    // iter               stiffness iterations (0 = no stiffness)
+    // localIter          number of local iterations for the integer rounding
+    // doRound            enables the integer rounding (disabling it could be useful for debugging)
+    // singularityRound   set true/false to decide if the singularities' coordinates should be rounded to the nearest integers
+    // roundVertices      id of additional vertices that should be snapped to integer coordinates
+    // hardFeatures       #H by 2 list of pairs of vertices that belongs to edges that should be snapped to integer coordinates
+
+    // Output:
+    // UV                 #UV by 2 list of vertices in 2D
+    // FUV                #FUV by 3 list of face indices in UV
+    //
     template <typename DerivedV, typename DerivedF, typename DerivedU>
-    IGL_INLINE void miq(const Eigen::PlainObjectBase<DerivedV> &V,
+    IGL_INLINE void miq(
+      const Eigen::PlainObjectBase<DerivedV> &V,
       const Eigen::PlainObjectBase<DerivedF> &F,
       const Eigen::PlainObjectBase<DerivedV> &PD1_combed,
       const Eigen::PlainObjectBase<DerivedV> &PD2_combed,
-      const Eigen::Matrix<int, Eigen::Dynamic, 3> &MMatch,
-      const Eigen::Matrix<int, Eigen::Dynamic, 1> &Singular,
-      const Eigen::Matrix<int, Eigen::Dynamic, 3> &Seams,
+      const Eigen::Matrix<int, Eigen::Dynamic, 3> &mismatch,
+      const Eigen::Matrix<int, Eigen::Dynamic, 1> &singular,
+      const Eigen::Matrix<int, Eigen::Dynamic, 3> &seams,
       Eigen::PlainObjectBase<DerivedU> &UV,
       Eigen::PlainObjectBase<DerivedF> &FUV,
-      double GradientSize = 30.0,
-      double Stiffness = 5.0,
-      bool DirectRound = false,
-      int iter = 5,
-      int localIter = 5, bool DoRound = true,bool SingularityRound=true,
-      std::vector<int> roundVertices = std::vector<int>(),
-      std::vector<std::vector<int> > hardFeatures = std::vector<std::vector<int> >());
+      double gradientSize = 30.0,
+      double stiffness = 5.0,
+      bool directRound = false,
+      unsigned int iter = 5,
+      unsigned int localIter = 5,
+      bool doRound = true,
+      bool singularityRound = true,
+      const std::vector<int> &roundVertices = std::vector<int>(),
+      const std::vector<std::vector<int>> &hardFeatures = std::vector<std::vector<int> >());
   };
 };
 };

+ 131 - 297
include/igl/copyleft/comiso/nrosy.cpp

@@ -13,12 +13,13 @@
 #include <igl/edge_topology.h>
 #include <igl/per_face_normals.h>
 
-#include <iostream>
-#include <fstream>
+#include <stdexcept>
+#include "../../PI.h"
 
 #include <Eigen/Geometry>
 #include <Eigen/Sparse>
 #include <queue>
+#include <vector>
 
 #include <gmm/gmm.h>
 #include <CoMISo/Solver/ConstrainedSolver.hh>
@@ -40,19 +41,19 @@ public:
 
   // Generate the N-rosy field
   // N degree of the rosy field
-  // roundseparately: round the integer variables one at a time, slower but higher quality
-  IGL_INLINE void solve(const int N = 4);
+  // round separately: round the integer variables one at a time, slower but higher quality
+  IGL_INLINE void solve(int N = 4);
 
   // Set a hard constraint on fid
   // fid: face id
   // v: direction to fix (in 3d)
-  IGL_INLINE void setConstraintHard(const int fid, const Eigen::Vector3d& v);
+  IGL_INLINE void setConstraintHard(int fid, const Eigen::Vector3d& v);
 
   // Set a soft constraint on fid
   // fid: face id
   // w: weight of the soft constraint, clipped between 0 and 1
   // v: direction to fix (in 3d)
-  IGL_INLINE void setConstraintSoft(const int fid, const double w, const Eigen::Vector3d& v);
+  IGL_INLINE void setConstraintSoft(int fid, double w, const Eigen::Vector3d& v);
 
   // Set the ratio between smoothness and soft constraints (0 -> smoothness only, 1 -> soft constr only)
   IGL_INLINE void setSoftAlpha(double alpha);
@@ -63,9 +64,6 @@ public:
   // Return the current field
   IGL_INLINE Eigen::MatrixXd getFieldPerFace();
 
-  // Return the current field (in Ahish's ffield format)
-  IGL_INLINE Eigen::MatrixXd getFFieldPerFace();
-
   // Compute singularity indexes
   IGL_INLINE void findCones(int N);
 
@@ -73,7 +71,6 @@ public:
   IGL_INLINE Eigen::VectorXd getSingularityIndexPerVertex();
 
 private:
-
   // Compute angle differences between reference frames
   IGL_INLINE void computek();
 
@@ -81,20 +78,11 @@ private:
   IGL_INLINE void reduceSpace();
 
   // Prepare the system matrix
-  IGL_INLINE void prepareSystemMatrix(const int N);
-
-  // Solve without roundings
-  IGL_INLINE void solveNoRoundings();
+  IGL_INLINE void prepareSystemMatrix(int N);
 
   // Solve with roundings using CoMIso
   IGL_INLINE void solveRoundings();
 
-  // Round all p to 0 and fix
-  IGL_INLINE void roundAndFixToZero();
-
-  // Round all p and fix
-  IGL_INLINE void roundAndFix();
-
   // Convert a vector in 3d to an angle wrt the local reference system
   IGL_INLINE double convert3DtoLocal(unsigned fid, const Eigen::Vector3d& v);
 
@@ -114,7 +102,7 @@ private:
   // Soft constraints
   Eigen::VectorXd soft;
   Eigen::VectorXd wSoft;
-  double          softAlpha;
+  double softAlpha;
 
   // Face Topology
   Eigen::MatrixXi TT, TTi;
@@ -158,16 +146,12 @@ private:
 
 igl::copyleft::comiso::NRosyField::NRosyField(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F)
 {
-  using namespace std;
-  using namespace Eigen;
-
   V = _V;
   F = _F;
 
   assert(V.rows() > 0);
   assert(F.rows() > 0);
 
-
   // Generate topological relations
   igl::triangle_triangle_adjacency(F,TT,TTi);
   igl::edge_topology(V,F, EV, FE, EF);
@@ -184,30 +168,29 @@ igl::copyleft::comiso::NRosyField::NRosyField(const Eigen::MatrixXd& _V, const E
   for(unsigned fid=0; fid<F.rows(); ++fid)
   {
     // First edge
-    Vector3d e1 = V.row(F(fid,1)) - V.row(F(fid,0));
+    Eigen::Vector3d e1 = V.row(F(fid,1)) - V.row(F(fid,0));
     e1.normalize();
-    Vector3d e2 = N.row(fid);
+    Eigen::Vector3d e2 = N.row(fid);
     e2 = e2.cross(e1);
     e2.normalize();
 
-    MatrixXd TP(2,3);
+    Eigen::MatrixXd TP(2,3);
     TP << e1.transpose(), e2.transpose();
     TPs.push_back(TP);
   }
 
   // Alloc internal variables
-  angles = VectorXd::Zero(F.rows());
-  p = VectorXi::Zero(EV.rows());
+  angles = Eigen::VectorXd::Zero(F.rows());
+  p = Eigen::VectorXi::Zero(EV.rows());
   pFixed.resize(EV.rows());
-  k = VectorXd::Zero(EV.rows());
-  singularityIndex = VectorXd::Zero(V.rows());
+  k = Eigen::VectorXd::Zero(EV.rows());
+  singularityIndex = Eigen::VectorXd::Zero(V.rows());
 
   // Reset the constraints
   resetConstraints();
 
   // Compute k, differences between reference frames
   computek();
-
   softAlpha = 0.5;
 }
 
@@ -220,9 +203,6 @@ void igl::copyleft::comiso::NRosyField::setSoftAlpha(double alpha)
 
 void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
 {
-  using namespace std;
-  using namespace Eigen;
-
   double Nd = N;
 
   // Minimize the MIQ energy
@@ -239,9 +219,9 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
   // pij [   4pi/N   -4pi/N    2*(2pi/N)^2   4pi/N  ]
 
   // Count and tag the variables
-  tag_t = VectorXi::Constant(F.rows(),-1);
-  vector<int> id_t;
-  int count = 0;
+  tag_t = Eigen::VectorXi::Constant(F.rows(),-1);
+  std::vector<int> id_t;
+  size_t count = 0;
   for(unsigned i=0; i<F.rows(); ++i)
     if (!isHard[i])
     {
@@ -249,10 +229,10 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
       id_t.push_back(i);
     }
 
-  unsigned count_t = id_t.size();
+  size_t count_t = id_t.size();
 
-  tag_p = VectorXi::Constant(EF.rows(),-1);
-  vector<int> id_p;
+  tag_p = Eigen::VectorXi::Constant(EF.rows(),-1);
+  std::vector<int> id_p;
   for(unsigned i=0; i<EF.rows(); ++i)
   {
     if (!pFixed[i])
@@ -273,20 +253,20 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
     }
   }
 
-  unsigned count_p = count - count_t;
+  size_t count_p = count - count_t;
   // System sizes: A (count_t + count_p) x (count_t + count_p)
   //               b (count_t + count_p)
 
-  b = VectorXd::Zero(count_t + count_p);
+  b.resize(count_t + count_p);
+  b.setZero();
 
   std::vector<Eigen::Triplet<double> > T;
   T.reserve(3 * 4 * count_p);
 
-  for(unsigned r=0; r<id_p.size(); ++r)
+  for(auto eid : id_p)
   {
-    int eid = id_p[r];
-    int i = EF(eid,0);
-    int j = EF(eid,1);
+    int i = EF(eid, 0);
+    int j = EF(eid, 1);
     bool isFixed_i = isHard[i];
     bool isFixed_j = isHard[j];
     bool isFixed_p = pFixed[eid];
@@ -295,9 +275,15 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
     if (!isFixed_i)
     {
       row = tag_t[i];
-      if (isFixed_i) b(row) += -2               * hard[i]; else T.push_back(Eigen::Triplet<double>(row,tag_t[i]  , 2             ));
-      if (isFixed_j) b(row) +=  2               * hard[j]; else T.push_back(Eigen::Triplet<double>(row,tag_t[j]  ,-2             ));
-      if (isFixed_p) b(row) += -((4 * igl::PI)/Nd) * p[eid] ; else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],((4 * igl::PI)/Nd)));
+      T.emplace_back(row, tag_t[i], 2);
+      if (isFixed_j)
+        b(row) +=  2 * hard[j];
+      else
+        T.emplace_back(row, tag_t[j], -2);
+      if (isFixed_p)
+        b(row) += -((4. * igl::PI) / Nd) * p[eid];
+      else
+        T.emplace_back(row, tag_p[eid], ((4. * igl::PI) / Nd));
       b(row) += -2 * k[eid];
       assert(hard[i] == hard[i]);
       assert(hard[j] == hard[j]);
@@ -309,9 +295,15 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
     if (!isFixed_j)
     {
       row = tag_t[j];
-      if (isFixed_i) b(row) += 2               * hard[i]; else T.push_back(Eigen::Triplet<double>(row,tag_t[i]  , -2             ));
-      if (isFixed_j) b(row) += -2              * hard[j]; else T.push_back(Eigen::Triplet<double>(row,tag_t[j] ,  2              ));
-      if (isFixed_p) b(row) += ((4 * igl::PI)/Nd) * p[eid] ; else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],-((4 * igl::PI)/Nd)));
+      T.emplace_back(row, tag_t[j], 2);
+      if (isFixed_i)
+        b(row) += 2 * hard[i];
+      else
+        T.emplace_back(row, tag_t[i], -2);
+      if (isFixed_p)
+        b(row) += ((4. * igl::PI) / Nd) * p[eid];
+      else
+        T.emplace_back(row, tag_p[eid], -((4. * igl::PI) / Nd));
       b(row) += 2 * k[eid];
       assert(k[eid] == k[eid]);
       assert(b(row) == b(row));
@@ -320,17 +312,22 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
     if (!isFixed_p)
     {
       row = tag_p[eid];
-      if (isFixed_i) b(row) += -(4 * igl::PI)/Nd              * hard[i]; else T.push_back(Eigen::Triplet<double>(row,tag_t[i] ,   (4 * igl::PI)/Nd             ));
-      if (isFixed_j) b(row) +=  (4 * igl::PI)/Nd              * hard[j]; else T.push_back(Eigen::Triplet<double>(row,tag_t[j] ,  -(4 * igl::PI)/Nd             ));
-      if (isFixed_p) b(row) += -(2 * pow(((2*igl::PI)/Nd),2)) * p[eid] ;  else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],  (2 * pow(((2*igl::PI)/Nd),2))));
+      T.emplace_back(row, tag_p[eid], (2. * pow(((2. * igl::PI) / Nd), 2)));
+      if (isFixed_i)
+        b(row) += -(4. * igl::PI) / Nd * hard[i];
+      else
+        T.emplace_back(row, tag_t[i], (4. * igl::PI) / Nd);
+      if (isFixed_j)
+        b(row) += (4. * igl::PI) / Nd * hard[j];
+      else
+        T.emplace_back(row,tag_t[j], -(4. * igl::PI) / Nd);
       b(row) += - (4 * igl::PI)/Nd * k[eid];
       assert(k[eid] == k[eid]);
       assert(b(row) == b(row));
     }
-
   }
 
-  A = SparseMatrix<double>(count_t + count_p, count_t + count_p);
+  A.resize(count_t + count_p, count_t + count_p);
   A.setFromTriplets(T.begin(), T.end());
 
   // Soft constraints
@@ -342,10 +339,7 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
 
   if (addSoft)
   {
-    cerr << " Adding soft here: " << endl;
-    cerr << " softAplha: " << softAlpha << endl;
-    VectorXd bSoft = VectorXd::Zero(count_t + count_p);
-
+    Eigen::VectorXd bSoft = Eigen::VectorXd::Zero(count_t + count_p);
     std::vector<Eigen::Triplet<double> > TSoft;
     TSoft.reserve(2 * count_p);
 
@@ -354,98 +348,36 @@ void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
       int varid = tag_t[i];
       if (varid != -1) // if it is a variable in the system
       {
-        TSoft.push_back(Eigen::Triplet<double>(varid,varid,wSoft[i]));
+        TSoft.emplace_back(varid, varid, wSoft[i]);
         bSoft[varid] += wSoft[i] * soft[i];
       }
     }
-    SparseMatrix<double> ASoft(count_t + count_p, count_t + count_p);
+    Eigen::SparseMatrix<double> ASoft(count_t + count_p, count_t + count_p);
     ASoft.setFromTriplets(TSoft.begin(), TSoft.end());
 
-//    ofstream s("/Users/daniele/As.txt");
-//    for(unsigned i=0; i<TSoft.size(); ++i)
-//      s << TSoft[i].row() << " " << TSoft[i].col() << " " << TSoft[i].value() << endl;
-//    s.close();
-
-//    ofstream s2("/Users/daniele/bs.txt");
-//    for(unsigned i=0; i<bSoft.rows(); ++i)
-//      s2 << bSoft(i) << endl;
-//    s2.close();
-
-    // Stupid Eigen bug
-    SparseMatrix<double> Atmp (count_t + count_p, count_t + count_p);
-    SparseMatrix<double> Atmp2(count_t + count_p, count_t + count_p);
-    SparseMatrix<double> Atmp3(count_t + count_p, count_t + count_p);
-
-    // Merge the two part of the energy
-    Atmp = (1.0 - softAlpha)*A;
-    Atmp2 = softAlpha * ASoft;
-    Atmp3 = Atmp+Atmp2;
-
-    A = Atmp3;
-    b = b*(1.0 - softAlpha) + bSoft * softAlpha;
+    A = (1.0 - softAlpha) * A + softAlpha * ASoft;
+    b = b * (1.0 - softAlpha) + bSoft * softAlpha;
   }
-
-//  ofstream s("/Users/daniele/A.txt");
-//  for (int k=0; k<A.outerSize(); ++k)
-//    for (SparseMatrix<double>::InnerIterator it(A,k); it; ++it)
-//    {
-//      s << it.row() << " " << it.col() << " " << it.value() << endl;
-//    }
-//  s.close();
-//
-//  ofstream s2("/Users/daniele/b.txt");
-//  for(unsigned i=0; i<b.rows(); ++i)
-//    s2 << b(i) << endl;
-//  s2.close();
-}
-
-void igl::copyleft::comiso::NRosyField::solveNoRoundings()
-{
-  using namespace std;
-  using namespace Eigen;
-
-  // Solve the linear system
-  SimplicialLDLT<SparseMatrix<double> > solver;
-  solver.compute(A);
-  VectorXd x = solver.solve(b);
-
-  // Copy the result back
-  for(unsigned i=0; i<F.rows(); ++i)
-    if (tag_t[i] != -1)
-      angles[i] = x(tag_t[i]);
-    else
-      angles[i] = hard[i];
-
-  for(unsigned i=0; i<EF.rows(); ++i)
-    if(tag_p[i]  != -1)
-      p[i] = roundl(x[tag_p[i]]);
 }
 
 void igl::copyleft::comiso::NRosyField::solveRoundings()
 {
-  using namespace std;
-  using namespace Eigen;
-
   unsigned n = A.rows();
 
-  gmm::col_matrix< gmm::wsvector< double > > gmm_A;
-  std::vector<double> gmm_b;
+  gmm::col_matrix< gmm::wsvector< double > > gmm_A(n, n);
+  std::vector<double> gmm_b(n);
   std::vector<int> ids_to_round;
-  std::vector<double> x;
-
-  gmm_A.resize(n,n);
-  gmm_b.resize(n);
-  x.resize(n);
+  std::vector<double> x(n);
 
   // Copy A
   for (int k=0; k<A.outerSize(); ++k)
-    for (SparseMatrix<double>::InnerIterator it(A,k); it; ++it)
+    for (Eigen::SparseMatrix<double>::InnerIterator it(A, k); it; ++it)
     {
       gmm_A(it.row(),it.col()) += it.value();
     }
 
   // Copy b
-  for(unsigned i=0; i<n;++i)
+  for(unsigned int i = 0; i < n;++i)
     gmm_b[i] = b[i];
 
   // Set variables to round
@@ -458,7 +390,6 @@ void igl::copyleft::comiso::NRosyField::solveRoundings()
   gmm::row_matrix< gmm::wsvector< double > > gmm_C(0, n);
 
   COMISO::ConstrainedSolver cs;
-  //print_miso_settings(cs.misolver());
   cs.solve(gmm_C, gmm_A, x, gmm_b, ids_to_round, 0.0, false, true);
 
   // Copy the result back
@@ -470,26 +401,10 @@ void igl::copyleft::comiso::NRosyField::solveRoundings()
 
   for(unsigned i=0; i<EF.rows(); ++i)
     if(tag_p[i]  != -1)
-      p[i] = roundl(x[tag_p[i]]);
-
+      p[i] = (int)std::round(x[tag_p[i]]);
 }
 
 
-void igl::copyleft::comiso::NRosyField::roundAndFix()
-{
-  for(unsigned i=0; i<p.rows(); ++i)
-    pFixed[i] = true;
-}
-
-void igl::copyleft::comiso::NRosyField::roundAndFixToZero()
-{
-  for(unsigned i=0; i<p.rows(); ++i)
-  {
-    pFixed[i] = true;
-    p[i] = 0;
-  }
-}
-
 void igl::copyleft::comiso::NRosyField::solve(const int N)
 {
   // Reduce the search space by fixing matchings
@@ -501,19 +416,6 @@ void igl::copyleft::comiso::NRosyField::solve(const int N)
   // Solve with integer roundings
   solveRoundings();
 
-  // This is a very greedy solving strategy
-  // // Solve with no roundings
-  // solveNoRoundings();
-  //
-  // // Round all p and fix them
-  // roundAndFix();
-  //
-  // // Build the system
-  // prepareSystemMatrix(N);
-  //
-  // // Solve with no roundings (they are all fixed)
-  // solveNoRoundings();
-
   // Find the cones
   findCones(N);
 }
@@ -532,65 +434,34 @@ void igl::copyleft::comiso::NRosyField::setConstraintSoft(const int fid, const d
 
 void igl::copyleft::comiso::NRosyField::resetConstraints()
 {
-  using namespace std;
-  using namespace Eigen;
-
   isHard.resize(F.rows());
-  for(unsigned i=0; i<F.rows(); ++i)
+  for(unsigned i = 0; i < F.rows(); ++i)
     isHard[i] = false;
-  hard   = VectorXd::Zero(F.rows());
-
-  wSoft  = VectorXd::Zero(F.rows());
-  soft   = VectorXd::Zero(F.rows());
+  hard   = Eigen::VectorXd::Zero(F.rows());
+  wSoft = Eigen::VectorXd::Zero(F.rows());
+  soft = Eigen::VectorXd::Zero(F.rows());
 }
 
 Eigen::MatrixXd igl::copyleft::comiso::NRosyField::getFieldPerFace()
 {
-  using namespace std;
-  using namespace Eigen;
-
-  MatrixXd result(F.rows(),3);
-  for(unsigned i=0; i<F.rows(); ++i)
+  Eigen::MatrixXd result(F.rows(),3);
+  for(unsigned int i = 0; i < F.rows(); ++i)
     result.row(i) = convertLocalto3D(i, angles(i));
   return result;
 }
 
-Eigen::MatrixXd igl::copyleft::comiso::NRosyField::getFFieldPerFace()
-{
-  using namespace std;
-  using namespace Eigen;
-
-  MatrixXd result(F.rows(),6);
-  for(unsigned i=0; i<F.rows(); ++i)
-  {
-      Vector3d v1 = convertLocalto3D(i, angles(i));
-      Vector3d n = N.row(i);
-      Vector3d v2 = n.cross(v1);
-      v1.normalize();
-      v2.normalize();
-
-      result.block(i,0,1,3) = v1.transpose();
-      result.block(i,3,1,3) = v2.transpose();
-  }
-  return result;
-}
-
-
 void igl::copyleft::comiso::NRosyField::computek()
 {
-  using namespace std;
-  using namespace Eigen;
-
   // For every non-border edge
-  for (unsigned eid=0; eid<EF.rows(); ++eid)
+  for (unsigned eid = 0; eid < EF.rows(); ++eid)
   {
     if (!isBorderEdge[eid])
     {
       int fid0 = EF(eid,0);
       int fid1 = EF(eid,1);
 
-      Vector3d N0 = N.row(fid0);
-      Vector3d N1 = N.row(fid1);
+      Eigen::Vector3d N0 = N.row(fid0);
+      Eigen::Vector3d N1 = N.row(fid1);
 
       // find common edge on triangle 0 and 1
       int fid0_vc = -1;
@@ -605,18 +476,18 @@ void igl::copyleft::comiso::NRosyField::computek()
       assert(fid0_vc != -1);
       assert(fid1_vc != -1);
 
-      Vector3d common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc));
+      Eigen::Vector3d common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc));
       common_edge.normalize();
 
       // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis
-      MatrixXd P(3,3);
-      VectorXd o = V.row(F(fid0,fid0_vc));
-      VectorXd tmp = -N0.cross(common_edge);
+      Eigen::MatrixXd P(3,3);
+      Eigen::VectorXd o = V.row(F(fid0,fid0_vc));
+      Eigen::VectorXd tmp = -N0.cross(common_edge);
       P << common_edge, tmp, N0;
       P.transposeInPlace();
 
 
-      MatrixXd V0(3,3);
+      Eigen::MatrixXd V0(3,3);
       V0.row(0) = V.row(F(fid0,0)).transpose() -o;
       V0.row(1) = V.row(F(fid0,1)).transpose() -o;
       V0.row(2) = V.row(F(fid0,2)).transpose() -o;
@@ -627,7 +498,7 @@ void igl::copyleft::comiso::NRosyField::computek()
       assert(V0(1,2) < 10e-10);
       assert(V0(2,2) < 10e-10);
 
-      MatrixXd V1(3,3);
+      Eigen::MatrixXd V1(3,3);
       V1.row(0) = V.row(F(fid1,0)).transpose() -o;
       V1.row(1) = V.row(F(fid1,1)).transpose() -o;
       V1.row(2) = V.row(F(fid1,2)).transpose() -o;
@@ -638,12 +509,12 @@ void igl::copyleft::comiso::NRosyField::computek()
 
       // compute rotation R such that R * N1 = N0
       // i.e. map both triangles to the same plane
-      double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1));
+      double alpha = -std::atan2(V1((fid1_vc + 2) % 3, 2), V1((fid1_vc + 2) % 3, 1));
 
-      MatrixXd R(3,3);
+      Eigen::MatrixXd R(3,3);
       R << 1,          0,            0,
-           0, cos(alpha), -sin(alpha) ,
-           0, sin(alpha),  cos(alpha);
+           0, std::cos(alpha), -std::sin(alpha) ,
+           0, std::sin(alpha),  std::cos(alpha);
       V1 = (R*V1.transpose()).transpose();
 
       assert(V1(0,2) < 10e-10);
@@ -652,17 +523,17 @@ void igl::copyleft::comiso::NRosyField::computek()
 
       // measure the angle between the reference frames
       // k_ij is the angle between the triangle on the left and the one on the right
-      VectorXd ref0 = V0.row(1) - V0.row(0);
-      VectorXd ref1 = V1.row(1) - V1.row(0);
+      Eigen::VectorXd ref0 = V0.row(1) - V0.row(0);
+      Eigen::VectorXd ref1 = V1.row(1) - V1.row(0);
 
       ref0.normalize();
       ref1.normalize();
 
-      double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0));
+      double ktemp = std::atan2(ref1(1), ref1(0)) - std::atan2(ref0(1), ref0(0));
 
       // just to be sure, rotate ref0 using angle ktemp...
-      MatrixXd R2(2,2);
-      R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp);
+      Eigen::MatrixXd R2(2,2);
+      R2 << std::cos(ktemp), -std::sin(ktemp), std::sin(ktemp), std::cos(ktemp);
 
       tmp = R2*ref0.head<2>();
 
@@ -677,30 +548,15 @@ void igl::copyleft::comiso::NRosyField::computek()
 
 void igl::copyleft::comiso::NRosyField::reduceSpace()
 {
-  using namespace std;
-  using namespace Eigen;
-
   // All variables are free in the beginning
-  for(unsigned i=0; i<EV.rows(); ++i)
+  for(unsigned int i = 0; i < EV.rows(); ++i)
     pFixed[i] = false;
 
-  vector<VectorXd> debug;
-
-  // debug
-//  MatrixXd B(F.rows(),3);
-//  for(unsigned i=0; i<F.rows(); ++i)
-//    B.row(i) = 1./3. * (V.row(F(i,0)) + V.row(F(i,1)) + V.row(F(i,2)));
+  std::vector<bool> visited(EV.rows(), false);
+  std::vector<bool> starting(EV.rows(), false);
 
-  vector<bool> visited(EV.rows());
-  for(unsigned i=0; i<EV.rows(); ++i)
-    visited[i] = false;
-
-  vector<bool> starting(EV.rows());
-  for(unsigned i=0; i<EV.rows(); ++i)
-    starting[i] = false;
-
-  queue<int> q;
-  for(unsigned i=0; i<F.rows(); ++i)
+  std::queue<int> q;
+  for(unsigned int i = 0; i < F.rows(); ++i)
     if (isHard[i] || wSoft[i] != 0)
     {
       q.push(i);
@@ -730,7 +586,6 @@ void igl::copyleft::comiso::NRosyField::reduceSpace()
           p[eid] = 0;
           visited[fid] = true;
           q.push(fid);
-
         }
       }
       else
@@ -740,15 +595,14 @@ void igl::copyleft::comiso::NRosyField::reduceSpace()
         p[eid] = 0;
       }
     }
-
   }
 
   // Force matchings between fixed faces
-  for(unsigned i=0; i<F.rows();++i)
+  for(unsigned int i = 0; i < F.rows();++i)
   {
     if (isHard[i])
     {
-      for(unsigned int j=0; j<3; ++j)
+      for(unsigned int j = 0; j < 3; ++j)
       {
         int fid = TT(i,j);
         if ((fid!=-1) && (isHard[fid]))
@@ -759,37 +613,25 @@ void igl::copyleft::comiso::NRosyField::reduceSpace()
           int fid1 = EF(eid,1);
 
           pFixed[eid] = true;
-          p[eid] = roundl(2.0/igl::PI*(hard(fid1) - hard(fid0) - k(eid)));
+          p[eid] = (int)std::round(2.0 / igl::PI * (hard(fid1) - hard(fid0) - k(eid)));
         }
       }
     }
   }
-
-//  std::ofstream s("/Users/daniele/debug.txt");
-//  for(unsigned i=0; i<debug.size(); i += 2)
-//    s << debug[i].transpose() << " " << debug[i+1].transpose() << endl;
-//  s.close();
-
 }
 
 double igl::copyleft::comiso::NRosyField::convert3DtoLocal(unsigned fid, const Eigen::Vector3d& v)
 {
-  using namespace std;
-  using namespace Eigen;
-
   // Project onto the tangent plane
-  Vector2d vp = TPs[fid] * v;
+  Eigen::Vector2d vp = TPs[fid] * v;
 
   // Convert to angle
-  return atan2(vp(1),vp(0));
+  return std::atan2(vp(1), vp(0));
 }
 
 Eigen::Vector3d igl::copyleft::comiso::NRosyField::convertLocalto3D(unsigned fid, double a)
 {
-  using namespace std;
-  using namespace Eigen;
-
-  Vector2d vp(cos(a),sin(a));
+  Eigen::Vector2d vp(std::cos(a), std::sin(a));
   return vp.transpose() * TPs[fid];
 }
 
@@ -797,15 +639,18 @@ Eigen::VectorXd igl::copyleft::comiso::NRosyField::angleDefect()
 {
   Eigen::VectorXd A = Eigen::VectorXd::Constant(V.rows(),-2*igl::PI);
 
-  for (unsigned i=0; i < F.rows(); ++i)
+  for (unsigned int i = 0; i < F.rows(); ++i)
   {
     for (int j = 0; j < 3; ++j)
     {
       Eigen::VectorXd a = V.row(F(i,(j+1)%3)) - V.row(F(i,j));
       Eigen::VectorXd b = V.row(F(i,(j+2)%3)) - V.row(F(i,j));
-      double t = a.transpose()*b;
-      t /= (a.norm() * b.norm());
-      A(F(i,j)) += acos(t);
+      double t = a.transpose() * b;
+      if(a.norm() > 0. && b.norm() > 0.)
+        t /= (a.norm() * b.norm());
+      else
+        throw std::runtime_error("igl::copyleft::comiso::NRosyField::angleDefect: Division by zero!");
+      A(F(i, j)) += std::acos(std::max(std::min(t, 1.), -1.));
     }
   }
 
@@ -816,57 +661,46 @@ void igl::copyleft::comiso::NRosyField::findCones(int N)
 {
   // Compute I0, see http://www.graphics.rwth-aachen.de/media/papers/bommes_zimmer_2009_siggraph_011.pdf for details
 
-  Eigen::VectorXd I0 = Eigen::VectorXd::Zero(V.rows());
+  singularityIndex = Eigen::VectorXd::Zero(V.rows());
 
   // first the k
-  for (unsigned i=0; i < EV.rows(); ++i)
+  for (unsigned i = 0; i < EV.rows(); ++i)
   {
     if (!isBorderEdge[i])
     {
-      I0(EV(i,0)) -= k(i);
-      I0(EV(i,1)) += k(i);
+      singularityIndex(EV(i, 0)) -= k(i);
+      singularityIndex(EV(i, 1)) += k(i);
     }
   }
 
   // then the A
   Eigen::VectorXd A = angleDefect();
-
-  I0 = I0 + A;
-
+  singularityIndex += A;
   // normalize
-  I0 = I0 / (2*igl::PI);
+  singularityIndex /= (2 * igl::PI);
 
   // round to integer (remove numerical noise)
-  for (unsigned i=0; i < I0.size(); ++i)
-    I0(i) = round(I0(i));
+  for (unsigned i = 0; i < singularityIndex.size(); ++i)
+    singularityIndex(i) = round(singularityIndex(i));
 
-  // compute I
-  Eigen::VectorXd I = I0;
-
-  for (unsigned i=0; i < EV.rows(); ++i)
+  for (unsigned i = 0; i < EV.rows(); ++i)
   {
     if (!isBorderEdge[i])
     {
-      I(EV(i,0)) -= double(p(i))/double(N);
-      I(EV(i,1)) += double(p(i))/double(N);
+      singularityIndex(EV(i, 0)) -= double(p(i)) / double(N);
+      singularityIndex(EV(i, 1)) += double(p(i)) / double(N);
     }
   }
 
   // Clear the vertices on the edges
-  for (unsigned i=0; i < EV.rows(); ++i)
+  for (unsigned i = 0; i < EV.rows(); ++i)
   {
     if (isBorderEdge[i])
     {
-      I0(EV(i,0)) = 0;
-      I0(EV(i,1)) = 0;
-      I(EV(i,0)) = 0;
-      I(EV(i,1)) = 0;
-      A(EV(i,0)) = 0;
-      A(EV(i,1)) = 0;
+      singularityIndex(EV(i,0)) = 0;
+      singularityIndex(EV(i,1)) = 0;
     }
   }
-
-  singularityIndex = I;
 }
 
 Eigen::VectorXd igl::copyleft::comiso::NRosyField::getSingularityIndexPerVertex()
@@ -889,15 +723,15 @@ IGL_INLINE void igl::copyleft::comiso::nrosy(
   )
 {
   // Init solver
-  igl::copyleft::comiso::NRosyField solver(V,F);
+  igl::copyleft::comiso::NRosyField solver(V, F);
 
   // Add hard constraints
-  for (unsigned i=0; i<b.size();++i)
-    solver.setConstraintHard(b(i),bc.row(i));
+  for (unsigned i = 0; i < b.size(); ++i)
+    solver.setConstraintHard(b(i), bc.row(i));
 
   // Add soft constraints
-  for (unsigned i=0; i<b_soft.size();++i)
-    solver.setConstraintSoft(b_soft(i),w_soft(i),bc_soft.row(i));
+  for (unsigned i = 0; i < b_soft.size(); ++i)
+    solver.setConstraintSoft(b_soft(i), w_soft(i), bc_soft.row(i));
 
   // Set the soft constraints global weight
   solver.setSoftAlpha(soft);
@@ -924,11 +758,11 @@ IGL_INLINE void igl::copyleft::comiso::nrosy(
                            )
 {
   // Init solver
-  igl::copyleft::comiso::NRosyField solver(V,F);
+  igl::copyleft::comiso::NRosyField solver(V, F);
 
   // Add hard constraints
-  for (unsigned i=0; i<b.size();++i)
-    solver.setConstraintHard(b(i),bc.row(i));
+  for (unsigned i= 0; i < b.size(); ++i)
+    solver.setConstraintHard(b(i), bc.row(i));
 
   // Interpolate
   solver.solve(N);

+ 3 - 6
include/igl/copyleft/comiso/nrosy.h

@@ -8,12 +8,9 @@
 #ifndef IGL_COMISO_NROSY_H
 #define IGL_COMISO_NROSY_H
 
-#include <iostream>
 #include <Eigen/Core>
 #include <Eigen/Sparse>
-#include <vector>
 #include "../../igl_inline.h"
-#include "../../PI.h"
 
 namespace igl
 {
@@ -46,8 +43,8 @@ namespace igl
       const Eigen::VectorXi& b_soft,
       const Eigen::VectorXd& w_soft,
       const Eigen::MatrixXd& bc_soft,
-      const int N,
-      const double soft,
+      int N,
+      double soft,
       Eigen::MatrixXd& R,
       Eigen::VectorXd& S
       );
@@ -57,7 +54,7 @@ namespace igl
      const Eigen::MatrixXi& F,
      const Eigen::VectorXi& b,
      const Eigen::MatrixXd& bc,
-     const int N,
+     int N,
      Eigen::MatrixXd& R,
      Eigen::VectorXd& S
       );

+ 280 - 133
include/igl/copyleft/marching_cubes.cpp

@@ -84,7 +84,6 @@ public:
     vertices.resize(10000,3);
     int num_vertices = 0;
 
-
     unsigned n_cubes  = (x_res-1) * (y_res-1) * (z_res-1);
     assert(unsigned(points.rows()) == x_res * y_res * z_res);
 
@@ -100,15 +99,9 @@ public:
 
     for (unsigned cube_it =0 ; cube_it < n_cubes; ++cube_it)
     {
-
       unsigned         corner[8];
-      typename DerivedFaces::Scalar samples[12];
-      unsigned char    cubetype(0);
-      unsigned int     i;
-
-
       // get point indices of corner vertices
-      for (i=0; i<8; ++i)
+      for (int i=0; i<8; ++i)
       {
         // get cube coordinates
         unsigned int _idx = cube_it;
@@ -116,73 +109,15 @@ public:
         unsigned int x = _idx % X;  _idx /= X;
         unsigned int y = _idx % Y;  _idx /= Y;
         unsigned int z = _idx;
-
         // transform to point coordinates
         _idx = x + y*x_res + z*x_res*y_res;
-
         // add offset
         corner[i] = _idx + offsets_[i];
       }
-
-
-      // determine cube type
-      for (i=0; i<8; ++i)
-        if (values(corner[i]) > isovalue)
-          cubetype |= (1<<i);
-
-
-      // trivial reject ?
-      if (cubetype == 0 || cubetype == 255)
-        continue;
-
-
-      // compute samples on cube's edges
-      if (edgeTable[cubetype]&1)
-        samples[0]  = add_vertex(values, points, corner[0], corner[1], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&2)
-        samples[1]  = add_vertex(values, points, corner[1], corner[2], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&4)
-        samples[2]  = add_vertex(values, points, corner[3], corner[2], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&8)
-        samples[3]  = add_vertex(values, points, corner[0], corner[3], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&16)
-        samples[4]  = add_vertex(values, points, corner[4], corner[5], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&32)
-        samples[5]  = add_vertex(values, points, corner[5], corner[6], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&64)
-        samples[6]  = add_vertex(values, points, corner[7], corner[6], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&128)
-        samples[7]  = add_vertex(values, points, corner[4], corner[7], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&256)
-        samples[8]  = add_vertex(values, points, corner[0], corner[4], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&512)
-        samples[9]  = add_vertex(values, points, corner[1], corner[5], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&1024)
-        samples[10] = add_vertex(values, points, corner[2], corner[6], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&2048)
-        samples[11] = add_vertex(values, points, corner[3], corner[7], vertices, num_vertices, edge2vertex);
-
-
-
-      // connect samples by triangles
-      for (i=0; triTable[cubetype][0][i] != -1; i+=3 )
-      {
-        num_faces++;
-        if (num_faces > faces.rows())
-          faces.conservativeResize(faces.rows()+10000, Eigen::NoChange);
-
-        faces.row(num_faces-1) <<
-        samples[triTable[cubetype][0][i  ]],
-        samples[triTable[cubetype][0][i+1]],
-        samples[triTable[cubetype][0][i+2]];
-
-      }
-
+      add_cube(values,points,isovalue,corner,vertices,num_vertices,faces,num_faces,edge2vertex);
     }
-
     vertices.conservativeResize(num_vertices, Eigen::NoChange);
     faces.conservativeResize(num_faces, Eigen::NoChange);
-
   }
 
   // Sparse index grid version
@@ -214,83 +149,225 @@ public:
     for (unsigned cube_it =0 ; cube_it < n_cubes; ++cube_it)
     {
       typedef Eigen::Matrix<typename DerivedIndices::Scalar, 1, 8> CubeIndexVector;
-      typedef typename DerivedFaces::Scalar SampleScalar;
 
-      CubeIndexVector  cube = cubes.row(cube_it);
-      SampleScalar     samples[12];
-      unsigned char    cubetype(0);
+      CubeIndexVector  corner = cubes.row(cube_it);
+      add_cube(values,points,isovalue,corner.data(),vertices,num_vertices,faces,num_faces,edge2vertex);
+    }
+    vertices.conservativeResize(num_vertices, Eigen::NoChange);
+    faces.conservativeResize(num_faces, Eigen::NoChange);
+  }
+
+  // Dense index grid function version
+  template <typename DerivedValue, typename DerivedPoint>
+  MarchingCubes(
+    const std::function< DerivedValue(const DerivedPoint & ) > & value_fun,
+    const Eigen::MatrixBase<DerivedPoints> &points,
+    const unsigned x_res,
+    const unsigned y_res,
+    const unsigned z_res,
+    const double isovalue,
+    Eigen::PlainObjectBase<DerivedVertices> &vertices,
+    Eigen::PlainObjectBase<DerivedFaces> &faces)
+  {
+    assert(points.cols() == 3);
+
+    if(x_res <2 || y_res<2 ||z_res<2)
+      return;
+    faces.resize(10000,3);
+    int num_faces = 0;
 
-      // determine cube type
+    vertices.resize(10000,3);
+    int num_vertices = 0;
+
+    unsigned n_cubes  = (x_res-1) * (y_res-1) * (z_res-1);
+    assert(unsigned(points.rows()) == x_res * y_res * z_res);
+
+    unsigned int         offsets_[8];
+    offsets_[0] = 0;
+    offsets_[1] = 1;
+    offsets_[2] = 1 + x_res;
+    offsets_[3] =     x_res;
+    offsets_[4] =             x_res*y_res;
+    offsets_[5] = 1         + x_res*y_res;
+    offsets_[6] = 1 + x_res + x_res*y_res;
+    offsets_[7] =     x_res + x_res*y_res;
+
+    for (unsigned cube_it =0 ; cube_it < n_cubes; ++cube_it)
+    {
+      unsigned         corner[8];
+      // get point indices of corner vertices
       for (int i=0; i<8; ++i)
       {
-        if (values[cube[i]] > isovalue)
-        {
-          cubetype |= (1<<i);
-        }
+        // get cube coordinates
+        unsigned int _idx = cube_it;
+        unsigned int X(x_res-1), Y(y_res-1);
+        unsigned int x = _idx % X;  _idx /= X;
+        unsigned int y = _idx % Y;  _idx /= Y;
+        unsigned int z = _idx;
+        // transform to point coordinates
+        _idx = x + y*x_res + z*x_res*y_res;
+        // add offset
+        corner[i] = _idx + offsets_[i];
       }
+      add_cube(value_fun,points,isovalue,corner,vertices,num_vertices,faces,num_faces,edge2vertex);
+    }
+    vertices.conservativeResize(num_vertices, Eigen::NoChange);
+    faces.conservativeResize(num_faces, Eigen::NoChange);
+  }
 
+  template <typename CubeIndexType>
+  static void add_cube(
+      const Eigen::MatrixBase<DerivedValues> &values,
+      const Eigen::MatrixBase<DerivedPoints> &points,
+      const double isovalue,
+      const CubeIndexType corner[],
+      Eigen::PlainObjectBase<DerivedVertices> &vertices,
+      int &num_vertices,
+      Eigen::PlainObjectBase<DerivedFaces> &faces,
+      int & num_faces,
+      MyMap &edge2vertex)
+  {
+    typedef typename DerivedFaces::Scalar SampleScalar;
+    SampleScalar     samples[12];
+    unsigned char    cubetype(0);
 
-      // trivial reject ?
-      if (cubetype == 0 || cubetype == 255)
+    // determine cube type
+    for (int i=0; i<8; ++i)
+    {
+      if (values(corner[i]) > isovalue)
       {
-        continue;
+        cubetype |= (1<<i);
       }
+    }
+
+    // trivial reject ?
+    if (cubetype == 0 || cubetype == 255)
+    {
+      return;
+    }
 
-      // compute samples on cube's edges
-      if (edgeTable[cubetype]&1)
-        samples[0]  = add_vertex(values, points, cube[0], cube[1], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&2)
-        samples[1]  = add_vertex(values, points, cube[1], cube[2], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&4)
-        samples[2]  = add_vertex(values, points, cube[3], cube[2], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&8)
-        samples[3]  = add_vertex(values, points, cube[0], cube[3], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&16)
-        samples[4]  = add_vertex(values, points, cube[4], cube[5], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&32)
-        samples[5]  = add_vertex(values, points, cube[5], cube[6], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&64)
-        samples[6]  = add_vertex(values, points, cube[7], cube[6], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&128)
-        samples[7]  = add_vertex(values, points, cube[4], cube[7], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&256)
-        samples[8]  = add_vertex(values, points, cube[0], cube[4], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&512)
-        samples[9]  = add_vertex(values, points, cube[1], cube[5], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&1024)
-        samples[10] = add_vertex(values, points, cube[2], cube[6], vertices, num_vertices, edge2vertex);
-      if (edgeTable[cubetype]&2048)
-        samples[11] = add_vertex(values, points, cube[3], cube[7], vertices, num_vertices, edge2vertex);
-
-      // connect samples by triangles
-      for (int i=0; triTable[cubetype][0][i] != -1; i+=3 )
+    // compute samples on cube's edges
+    if (edgeTable[cubetype]&1)
+      samples[0]  = add_vertex(values, points, isovalue, corner[0], corner[1], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&2)
+      samples[1]  = add_vertex(values, points, isovalue, corner[1], corner[2], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&4)
+      samples[2]  = add_vertex(values, points, isovalue, corner[3], corner[2], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&8)
+      samples[3]  = add_vertex(values, points, isovalue, corner[0], corner[3], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&16)
+      samples[4]  = add_vertex(values, points, isovalue, corner[4], corner[5], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&32)
+      samples[5]  = add_vertex(values, points, isovalue, corner[5], corner[6], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&64)
+      samples[6]  = add_vertex(values, points, isovalue, corner[7], corner[6], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&128)
+      samples[7]  = add_vertex(values, points, isovalue, corner[4], corner[7], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&256)
+      samples[8]  = add_vertex(values, points, isovalue, corner[0], corner[4], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&512)
+      samples[9]  = add_vertex(values, points, isovalue, corner[1], corner[5], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&1024)
+      samples[10] = add_vertex(values, points, isovalue, corner[2], corner[6], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&2048)
+      samples[11] = add_vertex(values, points, isovalue, corner[3], corner[7], vertices, num_vertices, edge2vertex);
+
+    // connect samples by triangles
+    for (int i=0; triTable[cubetype][0][i] != -1; i+=3 )
+    {
+      num_faces++;
+      if (num_faces > faces.rows())
       {
-        num_faces++;
-        if (num_faces > faces.rows())
-        {
-          faces.conservativeResize(faces.rows()+10000, Eigen::NoChange);
-        }
-        faces.row(num_faces-1) <<
+        faces.conservativeResize(faces.rows()+10000, Eigen::NoChange);
+      }
+      faces.row(num_faces-1) <<
         samples[triTable[cubetype][0][i  ]],
         samples[triTable[cubetype][0][i+1]],
         samples[triTable[cubetype][0][i+2]];
+    }
+  };
 
-      }
+  template <typename DerivedValue, typename DerivedPoint, typename CubeIndexType>
+  static void add_cube(
+      const std::function< DerivedValue(const DerivedPoint & ) > & value_fun,
+      const Eigen::MatrixBase<DerivedPoints> &points,
+      const double isovalue,
+      const CubeIndexType corner[],
+      Eigen::PlainObjectBase<DerivedVertices> &vertices,
+      int &num_vertices,
+      Eigen::PlainObjectBase<DerivedFaces> &faces,
+      int & num_faces,
+      MyMap &edge2vertex)
+  {
+    typedef typename DerivedFaces::Scalar SampleScalar;
+    SampleScalar     samples[12];
+    unsigned char    cubetype(0);
 
+    // determine cube type
+    for (int i=0; i<8; ++i)
+    {
+      if (value_fun(points.row(corner[i])) > isovalue)
+      {
+        cubetype |= (1<<i);
+      }
     }
 
-    vertices.conservativeResize(num_vertices, Eigen::NoChange);
-    faces.conservativeResize(num_faces, Eigen::NoChange);
+    // trivial reject ?
+    if (cubetype == 0 || cubetype == 255)
+    {
+      return;
+    }
 
-  }
+    // compute samples on cube's edges
+    if (edgeTable[cubetype]&1)
+      samples[0]  = add_vertex(value_fun, points, isovalue, corner[0], corner[1], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&2)
+      samples[1]  = add_vertex(value_fun, points, isovalue, corner[1], corner[2], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&4)
+      samples[2]  = add_vertex(value_fun, points, isovalue, corner[3], corner[2], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&8)
+      samples[3]  = add_vertex(value_fun, points, isovalue, corner[0], corner[3], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&16)
+      samples[4]  = add_vertex(value_fun, points, isovalue, corner[4], corner[5], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&32)
+      samples[5]  = add_vertex(value_fun, points, isovalue, corner[5], corner[6], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&64)
+      samples[6]  = add_vertex(value_fun, points, isovalue, corner[7], corner[6], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&128)
+      samples[7]  = add_vertex(value_fun, points, isovalue, corner[4], corner[7], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&256)
+      samples[8]  = add_vertex(value_fun, points, isovalue, corner[0], corner[4], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&512)
+      samples[9]  = add_vertex(value_fun, points, isovalue, corner[1], corner[5], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&1024)
+      samples[10] = add_vertex(value_fun, points, isovalue, corner[2], corner[6], vertices, num_vertices, edge2vertex);
+    if (edgeTable[cubetype]&2048)
+      samples[11] = add_vertex(value_fun, points, isovalue, corner[3], corner[7], vertices, num_vertices, edge2vertex);
+
+    // connect samples by triangles
+    for (int i=0; triTable[cubetype][0][i] != -1; i+=3 )
+    {
+      num_faces++;
+      if (num_faces > faces.rows())
+      {
+        faces.conservativeResize(faces.rows()+10000, Eigen::NoChange);
+      }
+      faces.row(num_faces-1) <<
+        samples[triTable[cubetype][0][i  ]],
+        samples[triTable[cubetype][0][i+1]],
+        samples[triTable[cubetype][0][i+2]];
+    }
+  };
 
-  static typename DerivedFaces::Scalar add_vertex(const Eigen::MatrixBase<DerivedValues> &values,
-                                                  const Eigen::MatrixBase<DerivedPoints> &points,
-                                                  unsigned int i0,
-                                                  unsigned int i1,
-                                                  Eigen::PlainObjectBase<DerivedVertices> &vertices,
-                                                  int &num_vertices,
-                                                  MyMap &edge2vertex)
+  static typename DerivedFaces::Scalar add_vertex(
+    const Eigen::MatrixBase<DerivedValues> &values,
+    const Eigen::MatrixBase<DerivedPoints> &points,
+    const double isovalue, 
+    unsigned int i0,
+    unsigned int i1,
+    Eigen::PlainObjectBase<DerivedVertices> &vertices,
+    int &num_vertices,
+    MyMap &edge2vertex)
   {
     // find vertex if it has been computed already
     MyMapIterator it = edge2vertex.find(EdgeKey(i0, i1));
@@ -302,21 +379,71 @@ public:
     // generate new vertex
     const Eigen::Matrix<typename DerivedPoints::Scalar, 1, 3> & p0 = points.row(i0);
     const Eigen::Matrix<typename DerivedPoints::Scalar, 1, 3> & p1 = points.row(i1);
-
-    typename DerivedValues::Scalar s0 = fabs(values[i0]);
-    typename DerivedValues::Scalar s1 = fabs(values[i1]);
+    typename DerivedValues::Scalar s0 = fabs(values(i0)-isovalue);
+    typename DerivedValues::Scalar s1 = fabs(values(i1)-isovalue);
     typename DerivedValues::Scalar t  = s0 / (s0+s1);
+    num_vertices++;
+    if (num_vertices > vertices.rows())
+    {
+      vertices.conservativeResize(vertices.rows()+10000, Eigen::NoChange);
+    }
+    //
+    // Linear interpolation based on linearly interpolating values
+    vertices.row(num_vertices-1)  = ((1.0f-t)*p0 + t*p1).template cast<typename DerivedVertices::Scalar>();
+    edge2vertex[EdgeKey(i0, i1)] = num_vertices-1;
+    return num_vertices-1;
+  }
 
+  template <typename DerivedValue, typename DerivedPoint>
+  static typename DerivedFaces::Scalar add_vertex(
+    const std::function< DerivedValue(const DerivedPoint & ) > & value_fun,
+    const Eigen::MatrixBase<DerivedPoints> &points,
+    const double isovalue, 
+    unsigned int i0,
+    unsigned int i1,
+    Eigen::PlainObjectBase<DerivedVertices> &vertices,
+    int &num_vertices,
+    MyMap &edge2vertex)
+  {
+    // find vertex if it has been computed already
+    MyMapIterator it = edge2vertex.find(EdgeKey(i0, i1));
+    if (it != edge2vertex.end())
+    {
+      return it->second;
+    }
     num_vertices++;
     if (num_vertices > vertices.rows())
     {
       vertices.conservativeResize(vertices.rows()+10000, Eigen::NoChange);
     }
 
+    // generate new vertex
+    typedef Eigen::Matrix<typename DerivedPoints::Scalar, 1, 3> RowVector3S;
+    const RowVector3S & p0 = points.row(i0);
+    const RowVector3S & p1 = points.row(i1);
     // Linear interpolation based on linearly interpolating values
+    //typename DerivedValues::Scalar s0 = fabs(value_fun(points.row(i0))-isovalue);
+    //typename DerivedValues::Scalar s1 = fabs(value_fun(points.row(i1))-isovalue);
+    //typename DerivedValues::Scalar t  = s0 / (s0+s1);
+    const DerivedValue v1 = value_fun(p1);
+    double t0 = (v1>isovalue)?0:1;
+    double t1 = (v1>isovalue)?1:0;
+    double t;
+    for(int j = 0;j<10;j++)
+    {
+      t = 0.5*(t0+t1);
+      const double val = value_fun( ((1.0f-t)*p0 + t*p1) );
+      if( val > isovalue )
+      {
+        t1 = t;
+      }else
+      {
+        t0 = t;
+      }
+    }
     vertices.row(num_vertices-1)  = ((1.0f-t)*p0 + t*p1).template cast<typename DerivedVertices::Scalar>();
-    edge2vertex[EdgeKey(i0, i1)] = num_vertices-1;
 
+    edge2vertex[EdgeKey(i0, i1)] = num_vertices-1;
     return num_vertices-1;
   }
 
@@ -341,6 +468,29 @@ IGL_INLINE void igl::copyleft::marching_cubes(
           mc(values, points, x_res, y_res, z_res, isovalue, vertices, faces);
 }
 
+template <
+  typename DerivedValue, 
+  typename DerivedPoint,
+  typename DerivedPoints, 
+  typename DerivedVertices, 
+  typename DerivedFaces>
+IGL_INLINE void igl::copyleft::marching_cubes(
+    const std::function< DerivedValue(const DerivedPoint & ) > & value_fun,
+    const Eigen::MatrixBase<DerivedPoints> &points,
+    const unsigned x_res,
+    const unsigned y_res,
+    const unsigned z_res,
+    const double isovalue, 
+    Eigen::PlainObjectBase<DerivedVertices> &vertices,
+    Eigen::PlainObjectBase<DerivedFaces> &faces)
+{
+  MarchingCubes<
+    Eigen::Matrix<DerivedValue,Eigen::Dynamic,1>, /* unnecessary */
+    DerivedPoints, DerivedVertices, 
+    Eigen::Matrix<int,Eigen::Dynamic,1>, /* unnecessary */
+    DerivedFaces> mc(value_fun, points, x_res, y_res, z_res, isovalue, vertices, faces);
+}
+
 template <typename DerivedValues, typename DerivedPoints, typename DerivedVertices, typename DerivedFaces>
 IGL_INLINE void igl::copyleft::marching_cubes(
   const Eigen::MatrixBase<DerivedValues> &values,
@@ -381,14 +531,9 @@ IGL_INLINE void igl::copyleft::marching_cubes(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-
-// generated by autoexplicit.sh
 template void igl::copyleft::marching_cubes<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-// generated by autoexplicit.sh
 template void igl::copyleft::marching_cubes<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
-// generated by autoexplicit.sh
 template void igl::copyleft::marching_cubes<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
-// generated by autoexplicit.sh
 template void igl::copyleft::marching_cubes<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(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::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
 template void igl::copyleft::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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::copyleft::marching_cubes<Eigen::Matrix<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::Matrix<int, -1, -1, 0, -1, -1> >(const Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, const Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, const Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
@@ -399,4 +544,6 @@ template void igl::copyleft::marching_cubes<Eigen::Matrix<double, -1, 1, 0, -1,
 template void igl::copyleft::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::Matrix<int, -1, 3, 0, -1, 3> >(const Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&,const Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&,const Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
 template void igl::copyleft::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, 8, 0, -1, 8>,Eigen::Matrix<int, -1, 3, 0, -1, 3> >(const Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&,const Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&,const Eigen::MatrixBase<Eigen::Matrix<int, -1, 8, 0, -1, 8> >&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
 template void igl::copyleft::marching_cubes<Eigen::Matrix<double, -1, 1, 0, -1, 1>,Eigen::Matrix<double, -1, 3, 0, -1, 3>,Eigen::Matrix<double, -1, 3, 0, -1, 3>,Eigen::Matrix<int, -1, 8, 0, -1, 8>,Eigen::Matrix<int, -1, 3, 0, -1, 3> >(const Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&,const Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&,const Eigen::MatrixBase<Eigen::Matrix<int, -1, 8, 0, -1, 8> >&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::marching_cubes<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<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> >&);
+template void igl::copyleft::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, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

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

@@ -49,6 +49,21 @@ namespace igl
         const double isovalue,
         Eigen::PlainObjectBase<DerivedVertices> &vertices,
         Eigen::PlainObjectBase<DerivedFaces> &faces);
+    template <
+      typename DerivedValue, 
+      typename DerivedPoint,
+      typename DerivedPoints, 
+      typename DerivedVertices, 
+      typename DerivedFaces>
+    IGL_INLINE void marching_cubes(
+        const std::function< DerivedValue(const DerivedPoint & ) > & value_fun,
+        const Eigen::MatrixBase<DerivedPoints> &points,
+        const unsigned x_res,
+        const unsigned y_res,
+        const unsigned z_res,
+        const double isovalue, 
+        Eigen::PlainObjectBase<DerivedVertices> &vertices,
+        Eigen::PlainObjectBase<DerivedFaces> &faces);
 
     // Overload of the above function where the isovalue defaults to 0.0
     template <typename DerivedValues, typename DerivedPoints, typename DerivedVertices, typename DerivedFaces>

+ 1 - 0
include/igl/copyleft/opengl2/render_to_tga.cpp

@@ -72,6 +72,7 @@ IGL_INLINE bool igl::opengl::render_to_tga(
     if(NULL==imgFile)
     {
       printf("IOError: %s could not be opened...\n",tga_file.c_str());
+      free(genericImage);
       return false;
     }
   }

+ 1 - 0
include/igl/copyleft/opengl2/tga.cpp

@@ -373,6 +373,7 @@ igl::opengl::gliReadTGA(FILE *fp, char *name, int /*hflip*/, int vflip)
       sprintf(error, "TGA: error reading colormap (ftell == %ld)\n",
         ftell (fp));
       if (_verbose) printf("%s\n", error);
+      free(cmap);
       return NULL;
     }
 

+ 2 - 2
include/igl/copyleft/progressive_hulls_cost_and_placement.cpp

@@ -32,8 +32,8 @@ IGL_INLINE void igl::copyleft::progressive_hulls_cost_and_placement(
 
   assert(V.cols() == 3 && "V.cols() should be 3");
   // Gather list of unique face neighbors
-  vector<int> Nall =  circulation(e, true,F,E,EMAP,EF,EI);
-  vector<int> Nother= circulation(e,false,F,E,EMAP,EF,EI);
+  vector<int> Nall =  circulation(e, true,EMAP,EF,EI);
+  vector<int> Nother= circulation(e,false,EMAP,EF,EI);
   Nall.insert(Nall.end(),Nother.begin(),Nother.end());
   vector<int> N;
   igl::unique(Nall,N);

+ 40 - 3
include/igl/cotmatrix_entries.cpp

@@ -1,6 +1,7 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // 
 // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
 // 
 // This Source Code Form is subject to the terms of the Mozilla Public License 
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can 
@@ -50,6 +51,7 @@ IGL_INLINE void igl::cotmatrix_entries(
       C.resize(m,3);
       for(int i = 0;i<m;i++)
       {
+        // Alec: I'm doubtful that using l2 here is actually improving numerics.
         C(i,0) = (l2(i,1) + l2(i,2) - l2(i,0))/dblA(i)/4.0;
         C(i,1) = (l2(i,2) + l2(i,0) - l2(i,1))/dblA(i)/4.0;
         C(i,2) = (l2(i,0) + l2(i,1) - l2(i,2))/dblA(i)/4.0;
@@ -97,14 +99,49 @@ IGL_INLINE void igl::cotmatrix_entries(
   }
 }
 
+template <typename Derivedl, typename DerivedC>
+IGL_INLINE void igl::cotmatrix_entries(
+  const Eigen::MatrixBase<Derivedl>& l,
+  Eigen::PlainObjectBase<DerivedC>& C)
+{
+  using namespace Eigen;
+  const int m = l.rows();
+  assert(l.cols() == 3 && "Only triangles accepted");
+  //Compute squared Edge lengths 
+  Matrix<typename DerivedC::Scalar,Dynamic,3> l2;
+  l2 = l.array().square();
+  // Alec: It's a little annoying that there's duplicate code here. The
+  // "extrinic" version above is first computing squared edge lengths, taking
+  // the square root and calling this. We can't have a cotmatrix_entries(l,l2,C)
+  // overload because it will confuse Eigen with the cotmatrix_entries(V,F,C)
+  // overload. In the end, I'd like to be convinced that using l2 directly above
+  // is actually better numerically (or significantly faster) than just calling
+  // edge_lengths and this cotmatrix_entries(l,C);
+  //
+  // double area
+  Matrix<typename DerivedC::Scalar,Dynamic,1> dblA;
+  doublearea(l,0.,dblA);
+  // cotangents and diagonal entries for element matrices
+  // correctly divided by 4 (alec 2010)
+  C.resize(m,3);
+  for(int i = 0;i<m;i++)
+  {
+    // Alec: I'm doubtful that using l2 here is actually improving numerics.
+    C(i,0) = (l2(i,1) + l2(i,2) - l2(i,0))/dblA(i)/4.0;
+    C(i,1) = (l2(i,2) + l2(i,0) - l2(i,1))/dblA(i)/4.0;
+    C(i,2) = (l2(i,0) + l2(i,1) - l2(i,2))/dblA(i)/4.0;
+  }
+}
+
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
-template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 // generated by autoexplicit.sh
+template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::cotmatrix_entries<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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::cotmatrix_entries<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
-// generated by autoexplicit.sh
 template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
-// generated by autoexplicit.sh
 template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 12 - 0
include/igl/cotmatrix_entries.h

@@ -1,6 +1,7 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // 
 // Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
 // 
 // This Source Code Form is subject to the terms of the Mozilla Public License 
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can 
@@ -28,6 +29,17 @@ namespace igl
     const Eigen::MatrixBase<DerivedV>& V,
     const Eigen::MatrixBase<DerivedF>& F,
     Eigen::PlainObjectBase<DerivedC>& C);
+  // Intrinsic version.
+  //
+  // Inputs:
+  //   l  #F by 3 list of triangle edge lengths (see edge_lengths)
+  // Outputs:
+  //   C  #F by 3 list of 1/2*cotangents corresponding angles
+  //     for triangles, columns correspond to edges [1,2],[2,0],[0,1]
+  template <typename Derivedl, typename DerivedC>
+  IGL_INLINE void cotmatrix_entries(
+    const Eigen::MatrixBase<Derivedl>& l,
+    Eigen::PlainObjectBase<DerivedC>& C);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 67 - 0
include/igl/cotmatrix_intrinsic.cpp

@@ -0,0 +1,67 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "cotmatrix_intrinsic.h"
+#include "cotmatrix_entries.h"
+#include <iostream>
+
+template <typename Derivedl, typename DerivedF, typename Scalar>
+IGL_INLINE void igl::cotmatrix_intrinsic(
+  const Eigen::MatrixBase<Derivedl> & l, 
+  const Eigen::MatrixBase<DerivedF> & F, 
+  Eigen::SparseMatrix<Scalar>& L)
+{
+  using namespace Eigen;
+  using namespace std;
+  // Cribbed from cotmatrix
+
+  const int nverts = F.maxCoeff()+1;
+  L.resize(nverts,nverts);
+  Matrix<int,Dynamic,2> edges;
+  int simplex_size = F.cols();
+  // 3 for triangles, 4 for tets
+  assert(simplex_size == 3);
+  // This is important! it could decrease the comptuation time by a factor of 2
+  // Laplacian for a closed 2d manifold mesh will have on average 7 entries per
+  // row
+  L.reserve(10*nverts);
+  edges.resize(3,2);
+  edges << 
+    1,2,
+    2,0,
+    0,1;
+  // Gather cotangents
+  Matrix<Scalar,Dynamic,Dynamic> C;
+  cotmatrix_entries(l,C);
+  
+  vector<Triplet<Scalar> > IJV;
+  IJV.reserve(F.rows()*edges.rows()*4);
+  // Loop over triangles
+  for(int i = 0; i < F.rows(); i++)
+  {
+    // loop over edges of element
+    for(int e = 0;e<edges.rows();e++)
+    {
+      int source = F(i,edges(e,0));
+      int dest = F(i,edges(e,1));
+      IJV.push_back(Triplet<Scalar>(source,dest,C(i,e)));
+      IJV.push_back(Triplet<Scalar>(dest,source,C(i,e)));
+      IJV.push_back(Triplet<Scalar>(source,source,-C(i,e)));
+      IJV.push_back(Triplet<Scalar>(dest,dest,-C(i,e)));
+    }
+  }
+  L.setFromTriplets(IJV.begin(),IJV.end());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::cotmatrix_intrinsic<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::cotmatrix_intrinsic<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::cotmatrix_intrinsic<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::cotmatrix_intrinsic<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::cotmatrix_intrinsic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+#endif

+ 40 - 0
include/igl/cotmatrix_intrinsic.h

@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COTMATRIX_INTRINSIC_H
+#define IGL_COTMATRIX_INTRINSIC_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl 
+{
+  // Constructs the cotangent stiffness matrix (discrete laplacian) for a given
+  // mesh with faces F and edge lengths l.
+  //
+  // Inputs:
+  //   l  #F by 3 list of (half-)edge lengths
+  //   F  #F by 3 list of face indices into some (not necessarily
+  //     determined/embedable) list of vertex positions V. It is assumed #V ==
+  //     F.maxCoeff()+1
+  // Outputs:
+  //   L  #V by #V sparse Laplacian matrix
+  //
+  // See also: cotmatrix, intrinsic_delaunay_cotmatrix
+  template <typename Derivedl, typename DerivedF, typename Scalar>
+  IGL_INLINE void cotmatrix_intrinsic(
+    const Eigen::MatrixBase<Derivedl> & l, 
+    const Eigen::MatrixBase<DerivedF> & F, 
+    Eigen::SparseMatrix<Scalar>& L);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "cotmatrix_intrinsic.cpp"
+#endif
+
+#endif

+ 132 - 0
include/igl/cross_field_mismatch.cpp

@@ -0,0 +1,132 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "cross_field_mismatch.h"
+
+#include <cmath>
+#include <vector>
+#include <deque>
+#include <igl/comb_cross_field.h>
+#include <igl/per_face_normals.h>
+#include <igl/is_border_vertex.h>
+#include <igl/vertex_triangle_adjacency.h>
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/rotation_matrix_from_directions.h>
+#include <igl/PI.h>
+
+namespace igl {
+  template <typename DerivedV, typename DerivedF, typename DerivedM>
+  class MismatchCalculator
+  {
+  public:
+
+    const Eigen::PlainObjectBase<DerivedV> &V;
+    const Eigen::PlainObjectBase<DerivedF> &F;
+    const Eigen::PlainObjectBase<DerivedV> &PD1;
+    const Eigen::PlainObjectBase<DerivedV> &PD2;
+    
+    DerivedV N;
+
+  private:
+    // internal
+    std::vector<bool> V_border; // bool
+    std::vector<std::vector<int> > VF;
+    std::vector<std::vector<int> > VFi;
+    
+    DerivedF TT;
+    DerivedF TTi;
+
+
+  private:
+    ///compute the mismatch between 2 faces
+    inline int mismatchByCross(const int f0,
+                               const int f1)
+    {
+      Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0 = PD1.row(f0);
+      Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1 = PD1.row(f1);
+      Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n0 = N.row(f0);
+      Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n1 = N.row(f1);
+
+      Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1Rot = igl::rotation_matrix_from_directions(n1,n0)*dir1;
+      dir1Rot.normalize();
+
+      double angle_diff = atan2(dir1Rot.dot(PD2.row(f0)),dir1Rot.dot(PD1.row(f0)));
+
+      double step=igl::PI/2.0;
+      int i=(int)std::floor((angle_diff/step)+0.5);
+      int k=0;
+      if (i>=0)
+        k=i%4;
+      else
+        k=(-(3*i))%4;
+      return k;
+    }
+
+
+public:
+  inline MismatchCalculator(const Eigen::PlainObjectBase<DerivedV> &_V,
+                            const Eigen::PlainObjectBase<DerivedF> &_F,
+                            const Eigen::PlainObjectBase<DerivedV> &_PD1,
+                            const Eigen::PlainObjectBase<DerivedV> &_PD2):
+  V(_V),
+  F(_F),
+  PD1(_PD1),
+  PD2(_PD2)
+  {
+    igl::per_face_normals(V,F,N);
+    V_border = igl::is_border_vertex(V,F);
+    igl::vertex_triangle_adjacency(V,F,VF,VFi);
+    igl::triangle_triangle_adjacency(F,TT,TTi);
+  }
+
+  inline void calculateMismatch(Eigen::PlainObjectBase<DerivedM> &Handle_MMatch)
+  {
+    Handle_MMatch.setConstant(F.rows(),3,-1);
+    for (size_t i=0;i<F.rows();i++)
+    {
+      for (int j=0;j<3;j++)
+      {
+        if (((int)i)==TT(i,j) || TT(i,j) == -1)
+          Handle_MMatch(i,j)=0;
+        else
+          Handle_MMatch(i,j) = mismatchByCross(i, TT(i, j));
+      }
+    }
+  }
+
+};
+}
+template <typename DerivedV, typename DerivedF, typename DerivedM>
+IGL_INLINE void igl::cross_field_mismatch(const Eigen::PlainObjectBase<DerivedV> &V,
+                                          const Eigen::PlainObjectBase<DerivedF> &F,
+                                          const Eigen::PlainObjectBase<DerivedV> &PD1,
+                                          const Eigen::PlainObjectBase<DerivedV> &PD2,
+                                          const bool isCombed,
+                                          Eigen::PlainObjectBase<DerivedM> &mismatch)
+{
+  DerivedV PD1_combed;
+  DerivedV PD2_combed;
+
+  if (!isCombed)
+    igl::comb_cross_field(V,F,PD1,PD2,PD1_combed,PD2_combed);
+  else
+  {
+    PD1_combed = PD1;
+    PD2_combed = PD2;
+  }
+  igl::MismatchCalculator<DerivedV, DerivedF, DerivedM> sf(V, F, PD1_combed, PD2_combed);
+  sf.calculateMismatch(mismatch);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::cross_field_mismatch<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const &,  Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const &,  Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const &, const bool,  Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > &);
+template void igl::cross_field_mismatch<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 &, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, const bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &);
+template void igl::cross_field_mismatch<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, const bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > &);
+
+#endif

+ 43 - 0
include/igl/cross_field_mismatch.h

@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_CROSS_FIELD_MISMATCH_H
+#define IGL_CROSS_FIELD_MISMATCH_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  // Calculates the mismatch (integer), at each face edge, of a cross field defined on the mesh faces.
+  // The integer mismatch is a multiple of pi/2 that transforms the cross on one side of the edge to
+  // the cross on the other side. It represents the deviation from a Lie connection across the edge.
+
+  // Inputs:
+  //   V         #V by 3 eigen Matrix of mesh vertex 3D positions
+  //   F         #F by 3 eigen Matrix of face (quad) indices
+  //   PD1       #F by 3 eigen Matrix of the first per face cross field vector
+  //   PD2       #F by 3 eigen Matrix of the second per face cross field vector
+  //   isCombed  boolean, specifying whether the field is combed (i.e. matching has been precomputed.
+  //             If not, the field is combed first.
+  // Output:
+  //   mismatch  #F by 3 eigen Matrix containing the integer mismatch of the cross field
+  //             across all face edges
+  //
+
+  template <typename DerivedV, typename DerivedF, typename DerivedM>
+  IGL_INLINE void cross_field_mismatch(const Eigen::PlainObjectBase<DerivedV> &V,
+                                       const Eigen::PlainObjectBase<DerivedF> &F,
+                                       const Eigen::PlainObjectBase<DerivedV> &PD1,
+                                       const Eigen::PlainObjectBase<DerivedV> &PD2,
+                                       const bool isCombed,
+                                       Eigen::PlainObjectBase<DerivedM> &mismatch);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "cross_field_mismatch.cpp"
+#endif
+
+#endif

+ 0 - 142
include/igl/cross_field_missmatch.cpp

@@ -1,142 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-//
-// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla Public License
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can
-// obtain one at http://mozilla.org/MPL/2.0/.
-
-#include "cross_field_missmatch.h"
-
-#include <cmath>
-#include <vector>
-#include <deque>
-#include <igl/comb_cross_field.h>
-#include <igl/per_face_normals.h>
-#include <igl/is_border_vertex.h>
-#include <igl/vertex_triangle_adjacency.h>
-#include <igl/triangle_triangle_adjacency.h>
-#include <igl/rotation_matrix_from_directions.h>
-#include <igl/PI.h>
-
-namespace igl {
-  template <typename DerivedV, typename DerivedF, typename DerivedM>
-  class MissMatchCalculator
-  {
-  public:
-
-    const Eigen::PlainObjectBase<DerivedV> &V;
-    const Eigen::PlainObjectBase<DerivedF> &F;
-    const Eigen::PlainObjectBase<DerivedV> &PD1;
-    const Eigen::PlainObjectBase<DerivedV> &PD2;
-    
-    DerivedV N;
-
-  private:
-    // internal
-    std::vector<bool> V_border; // bool
-    std::vector<std::vector<int> > VF;
-    std::vector<std::vector<int> > VFi;
-    
-    DerivedF TT;
-    DerivedF TTi;
-
-
-  private:
-    ///compute the mismatch between 2 faces
-    inline int MissMatchByCross(const int f0,
-                         const int f1)
-    {
-      Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0 = PD1.row(f0);
-      Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1 = PD1.row(f1);
-      Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n0 = N.row(f0);
-      Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n1 = N.row(f1);
-
-      Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1Rot = igl::rotation_matrix_from_directions(n1,n0)*dir1;
-      dir1Rot.normalize();
-
-      // TODO: this should be equivalent to the other code below, to check!
-      // Compute the angle between the two vectors
-      //    double a0 = atan2(dir0.dot(B2.row(f0)),dir0.dot(B1.row(f0)));
-      //    double a1 = atan2(dir1Rot.dot(B2.row(f0)),dir1Rot.dot(B1.row(f0)));
-      //
-      //    double angle_diff = a1-a0;   //VectToAngle(f0,dir1Rot);
-
-      double angle_diff = atan2(dir1Rot.dot(PD2.row(f0)),dir1Rot.dot(PD1.row(f0)));
-
-      //    std::cerr << "Dani: " << dir0(0) << " " << dir0(1) << " " << dir0(2) << " " << dir1Rot(0) << " " << dir1Rot(1) << " " << dir1Rot(2) << " " << angle_diff << std::endl;
-
-      double step=igl::PI/2.0;
-      int i=(int)std::floor((angle_diff/step)+0.5);
-      int k=0;
-      if (i>=0)
-        k=i%4;
-      else
-        k=(-(3*i))%4;
-      return k;
-    }
-
-
-public:
-  inline MissMatchCalculator(const Eigen::PlainObjectBase<DerivedV> &_V,
-                      const Eigen::PlainObjectBase<DerivedF> &_F,
-                      const Eigen::PlainObjectBase<DerivedV> &_PD1,
-                      const Eigen::PlainObjectBase<DerivedV> &_PD2
-                      ):
-  V(_V),
-  F(_F),
-  PD1(_PD1),
-  PD2(_PD2)
-  {
-    igl::per_face_normals(V,F,N);
-    V_border = igl::is_border_vertex(V,F);
-    igl::vertex_triangle_adjacency(V,F,VF,VFi);
-    igl::triangle_triangle_adjacency(F,TT,TTi);
-  }
-
-  inline void calculateMissmatch(Eigen::PlainObjectBase<DerivedM> &Handle_MMatch)
-  {
-    Handle_MMatch.setConstant(F.rows(),3,-1);
-    for (size_t i=0;i<F.rows();i++)
-    {
-      for (int j=0;j<3;j++)
-      {
-        if (((int)i)==TT(i,j) || TT(i,j) == -1)
-          Handle_MMatch(i,j)=0;
-        else
-          Handle_MMatch(i,j) = MissMatchByCross(i,TT(i,j));
-      }
-    }
-  }
-
-};
-}
-template <typename DerivedV, typename DerivedF, typename DerivedM>
-IGL_INLINE void igl::cross_field_missmatch(const Eigen::PlainObjectBase<DerivedV> &V,
-                                           const Eigen::PlainObjectBase<DerivedF> &F,
-                                           const Eigen::PlainObjectBase<DerivedV> &PD1,
-                                           const Eigen::PlainObjectBase<DerivedV> &PD2,
-                                           const bool isCombed,
-                                           Eigen::PlainObjectBase<DerivedM> &missmatch)
-{
-  DerivedV PD1_combed;
-  DerivedV PD2_combed;
-
-  if (!isCombed)
-    igl::comb_cross_field(V,F,PD1,PD2,PD1_combed,PD2_combed);
-  else
-  {
-    PD1_combed = PD1;
-    PD2_combed = PD2;
-  }
-  igl::MissMatchCalculator<DerivedV, DerivedF, DerivedM> sf(V, F, PD1_combed, PD2_combed);
-  sf.calculateMissmatch(missmatch);
-}
-
-#ifdef IGL_STATIC_LIBRARY
-// Explicit template instantiation
-template void igl::cross_field_missmatch<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-template void igl::cross_field_missmatch<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&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template void igl::cross_field_missmatch<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-
-#endif

+ 76 - 0
include/igl/cumprod.cpp

@@ -0,0 +1,76 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "cumprod.h"
+#include <numeric>
+#include <iostream>
+
+template <typename DerivedX, typename DerivedY>
+IGL_INLINE void igl::cumprod(
+  const Eigen::MatrixBase<DerivedX > & X,
+  const int dim,
+  Eigen::PlainObjectBase<DerivedY > & Y)
+{
+  using namespace Eigen;
+  using namespace std;
+  Y.resizeLike(X);
+  // get number of columns (or rows)
+  int num_outer = (dim == 1 ? X.cols() : X.rows() );
+  // get number of rows (or columns)
+  int num_inner = (dim == 1 ? X.rows() : X.cols() );
+  // This has been optimized so that dim = 1 or 2 is roughly the same cost.
+  // (Optimizations assume ColMajor order)
+  if(dim == 1)
+  {
+#pragma omp parallel for
+    for(int o = 0;o<num_outer;o++)
+    {
+      typename DerivedX::Scalar prod = 1;
+      for(int i = 0;i<num_inner;i++)
+      {
+        prod *= X(i,o);
+        Y(i,o) = prod;
+      }
+    }
+  }else
+  {
+    for(int i = 0;i<num_inner;i++)
+    {
+      // Notice that it is *not* OK to put this above the inner loop
+      // Though here it doesn't seem to pay off...
+//#pragma omp parallel for
+      for(int o = 0;o<num_outer;o++)
+      {
+        if(i == 0)
+        {
+          Y(o,i) = X(o,i);
+        }else
+        {
+          Y(o,i) = Y(o,i-1) * X(o,i);
+        }
+      }
+    }
+  }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::cumprod<Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 4, 1, 0, 4, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 4, 1, 0, 4, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 0, 4, 1> >&);
+// generated by autoexplicit.sh
+template void igl::cumprod<Eigen::Matrix<double, 1, 4, 1, 1, 4>, Eigen::Matrix<double, 1, 4, 1, 1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 4, 1, 1, 4> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 4, 1, 1, 4> >&);
+template void igl::cumprod<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&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::cumprod<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&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::cumprod<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+template void igl::cumprod<Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1>, Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1> >(Eigen::MatrixBase<Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1> >&);
+template void igl::cumprod<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1>, Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&);
+template void igl::cumprod<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::cumprod<class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>> const &, int, class Eigen::PlainObjectBase<class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>> &);
+template void igl::cumprod<class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>, class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>> const &, int, class Eigen::PlainObjectBase<class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>> &);
+#endif
+#endif

+ 44 - 0
include/igl/cumprod.h

@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CUMPROD_H
+#define IGL_CUMPROD_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+  // Computes a cumulative product of the columns of X, like matlab's `cumprod`.
+  //
+  // Templates:
+  //   DerivedX  Type of matrix X
+  //   DerivedY  Type of matrix Y
+  // Inputs:
+  //   X  m by n Matrix to be cumulatively multiplied.
+  //   dim  dimension to take cumulative product (1 or 2)
+  // Output:
+  //   Y  m by n Matrix containing cumulative product.
+  //
+  template <typename DerivedX, typename DerivedY>
+  IGL_INLINE void cumprod(
+    const Eigen::MatrixBase<DerivedX > & X,
+    const int dim,
+    Eigen::PlainObjectBase<DerivedY > & Y);
+  //template <typename DerivedX, typename DerivedY>
+  //IGL_INLINE void cumprod(
+  //  const Eigen::MatrixBase<DerivedX > & X,
+  //  Eigen::PlainObjectBase<DerivedY > & Y);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "cumprod.cpp"
+#endif
+
+#endif
+
+

+ 4 - 0
include/igl/cumsum.cpp

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

+ 2 - 2
include/igl/cut_mesh_from_singularities.h

@@ -13,13 +13,13 @@
 namespace igl
 {
   // Given a mesh (V,F) and the integer mismatch of a cross field per edge
-  // (MMatch), finds the cut_graph connecting the singularities (seams) and the
+  // (mismatch), finds the cut_graph connecting the singularities (seams) and the
   // degree of the singularities singularity_index
   //
   // Input:
   //   V  #V by 3 list of mesh vertex positions
   //   F  #F by 3 list of faces
-  //   MMatch  #F by 3 list of per corner integer mismatch
+  //   mismatch  #F by 3 list of per corner integer mismatch
   // Outputs:
   //   seams  #F by 3 list of per corner booleans that denotes if an edge is a
   //     seam or not

+ 6 - 0
include/igl/cut_to_disk.cpp

@@ -261,6 +261,12 @@ namespace igl {
                 // we've hit a dead end. reverse and try the other direction
                 std::reverse(cycleverts.begin(), cycleverts.end());
                 std::reverse(cycleedges.begin(), cycleedges.end());
+                cycleidx.clear();
+                for (Index i = 0; i < cycleverts.size(); i++)
+                {
+                    cycleidx[cycleverts[i]] = i;
+                }
+                
                 curvert = cycleverts.back();
                 cure = cycleedges.back();
                 while (curvert != -1 && !foundcycle)

+ 11 - 31
include/igl/delaunay_triangulation.cpp

@@ -10,6 +10,7 @@
 #include "flip_edge.h"
 #include "lexicographic_triangulation.h"
 #include "unique_edge_map.h"
+#include "is_delaunay.h"
 
 #include <vector>
 #include <sstream>
@@ -20,7 +21,7 @@ template<
   typename InCircle,
   typename DerivedF>
 IGL_INLINE void igl::delaunay_triangulation(
-    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedV>& V,
     Orient2D orient2D,
     InCircle incircle,
     Eigen::PlainObjectBase<DerivedF>& F)
@@ -36,43 +37,18 @@ IGL_INLINE void igl::delaunay_triangulation(
   }
   assert(F.cols() == 3);
 
-  Eigen::MatrixXi E;
-  Eigen::MatrixXi uE;
+  typedef Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,2> MatrixX2I;
+  MatrixX2I E,uE;
   Eigen::VectorXi EMAP;
   std::vector<std::vector<Index> > uE2E;
   igl::unique_edge_map(F, E, uE, EMAP, uE2E);
 
-  auto is_delaunay = [&V,&F,&uE2E,num_faces,&incircle](size_t uei) {
-    auto& half_edges = uE2E[uei];
-    if (half_edges.size() != 2) {
-      throw "Cannot flip non-manifold or boundary edge";
-    }
-
-    const size_t f1 = half_edges[0] % num_faces;
-    const size_t f2 = half_edges[1] % num_faces;
-    const size_t c1 = half_edges[0] / num_faces;
-    const size_t c2 = half_edges[1] / num_faces;
-    assert(c1 < 3);
-    assert(c2 < 3);
-    assert(f1 != f2);
-    const size_t v1 = F(f1, (c1+1)%3);
-    const size_t v2 = F(f1, (c1+2)%3);
-    const size_t v4 = F(f1, c1);
-    const size_t v3 = F(f2, c2);
-    const Scalar p1[] = {V(v1, 0), V(v1, 1)};
-    const Scalar p2[] = {V(v2, 0), V(v2, 1)};
-    const Scalar p3[] = {V(v3, 0), V(v3, 1)};
-    const Scalar p4[] = {V(v4, 0), V(v4, 1)};
-    auto orientation = incircle(p1, p2, p4, p3);
-    return orientation <= 0;
-  };
-
   bool all_delaunay = false;
   while(!all_delaunay) {
     all_delaunay = true;
     for (size_t i=0; i<uE2E.size(); i++) {
       if (uE2E[i].size() == 2) {
-        if (!is_delaunay(i)) {
+        if (!is_delaunay(V,F,uE2E,incircle,i)) {
           all_delaunay = false;
           flip_edge(F, E, uE, EMAP, uE2E, i);
         }
@@ -82,5 +58,9 @@ IGL_INLINE void igl::delaunay_triangulation(
 }
 
 #ifdef IGL_STATIC_LIBRARY
-template void igl::delaunay_triangulation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, short (*)(double const*, double const*, double const*), short (*)(double const*, double const*, double const*, double const*), Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, short (*)(double const*, double const*, double const*), short (*)(double const*, double const*, double const*, double const*), Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-#endif
+// Explicit template instantiation
+template void igl::delaunay_triangulation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, short (*)(double const*, double const*, double const*), short (*)(double const*, double const*, double const*, double const*), Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, short (*)(double const*, double const*, double const*), short (*)(double const*, double const*, double const*, double const*), Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#ifdef WIN32
+template void igl::delaunay_triangulation<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, short(*)(double const *, double const *, double const *), short(*)(double const *, double const *, double const *, double const *), class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::MatrixBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, short(*const)(double const *, double const *, double const *), short(*const)(double const *, double const *, double const *, double const *), class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
+#endif
+#endif

+ 5 - 8
include/igl/delaunay_triangulation.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 #ifndef IGL_DELAUNAY_TRIANGULATION_H
@@ -37,15 +37,12 @@ namespace igl
     typename DerivedF
     >
   IGL_INLINE void delaunay_triangulation(
-      const Eigen::PlainObjectBase<DerivedV>& V,
+      const Eigen::MatrixBase<DerivedV>& V,
       Orient2D orient2D,
       InCircle incircle,
       Eigen::PlainObjectBase<DerivedF>& F);
 }
 
-
-
-
 #ifndef IGL_STATIC_LIBRARY
 #  include "delaunay_triangulation.cpp"
 #endif

+ 9 - 5
include/igl/dihedral_angles.cpp

@@ -6,6 +6,9 @@
 // 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 "dihedral_angles.h"
+#include "edge_lengths.h"
+#include "face_areas.h"
+
 #include <cassert>
 
 template <
@@ -14,8 +17,8 @@ template <
   typename Derivedtheta,
   typename Derivedcos_theta>
 IGL_INLINE void igl::dihedral_angles(
-  Eigen::PlainObjectBase<DerivedV>& V,
-  Eigen::PlainObjectBase<DerivedT>& T,
+  const Eigen::PlainObjectBase<DerivedV>& V,
+  const Eigen::PlainObjectBase<DerivedT>& T,
   Eigen::PlainObjectBase<Derivedtheta>& theta,
   Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta)
 {
@@ -34,8 +37,8 @@ template <
   typename Derivedtheta,
   typename Derivedcos_theta>
 IGL_INLINE void igl::dihedral_angles_intrinsic(
-  Eigen::PlainObjectBase<DerivedL>& L,
-  Eigen::PlainObjectBase<DerivedA>& A,
+  const Eigen::PlainObjectBase<DerivedL>& L,
+  const Eigen::PlainObjectBase<DerivedA>& A,
   Eigen::PlainObjectBase<Derivedtheta>& theta,
   Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta)
 {
@@ -90,5 +93,6 @@ IGL_INLINE void igl::dihedral_angles_intrinsic(
 }
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::dihedral_angles_intrinsic<Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+template void igl::dihedral_angles_intrinsic< Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&, const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+template void igl::dihedral_angles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 4 - 4
include/igl/dihedral_angles.h

@@ -30,8 +30,8 @@ namespace igl
     typename Derivedtheta,
     typename Derivedcos_theta>
   IGL_INLINE void dihedral_angles(
-    Eigen::PlainObjectBase<DerivedV>& V,
-    Eigen::PlainObjectBase<DerivedT>& T,
+    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::PlainObjectBase<DerivedT>& T,
     Eigen::PlainObjectBase<Derivedtheta>& theta,
     Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta);
   template <
@@ -40,8 +40,8 @@ namespace igl
     typename Derivedtheta,
     typename Derivedcos_theta>
   IGL_INLINE void dihedral_angles_intrinsic(
-    Eigen::PlainObjectBase<DerivedL>& L,
-    Eigen::PlainObjectBase<DerivedA>& A,
+    const Eigen::PlainObjectBase<DerivedL>& L,
+    const Eigen::PlainObjectBase<DerivedA>& A,
     Eigen::PlainObjectBase<Derivedtheta>& theta,
     Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta);
 

+ 3 - 4
include/igl/doublearea.cpp

@@ -231,13 +231,12 @@ IGL_INLINE void igl::doublearea_quad(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-// generated by autoexplicit.sh
+template void igl::doublearea<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::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -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, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 1, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 template void igl::doublearea<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(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, 1, 0, -1, 1> >&);
-// generated by autoexplicit.sh
 template void igl::doublearea<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(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<double, -1, 1, 0, -1, 1> >&);
-// generated by autoexplicit.sh
 template void igl::doublearea<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
-// generated by autoexplicit.sh
 template void igl::doublearea<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::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
 template void igl::doublearea<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -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&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 template void igl::doublearea<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);

+ 1 - 1
include/igl/edge_collapse_is_valid.cpp

@@ -49,7 +49,7 @@ IGL_INLINE bool igl::edge_collapse_is_valid(
       const Eigen::MatrixXi & EI) 
     {
       vector<int> N,uN;
-      vector<int> V2Fe = circulation(e, ccw,F,E,EMAP,EF,EI);
+      vector<int> V2Fe = circulation(e, ccw,EMAP,EF,EI);
       for(auto f : V2Fe)
       {
         N.push_back(F(f,0));

+ 96 - 0
include/igl/edge_exists_near.cpp

@@ -0,0 +1,96 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "edge_exists_near.h"
+
+template <
+  typename DeriveduE,
+  typename DerivedEMAP,
+  typename uE2EType,
+  typename Index>
+IGL_INLINE bool igl::edge_exists_near(
+  const Eigen::MatrixBase<DeriveduE> & uE,
+  const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+  const std::vector<std::vector< uE2EType> > & uE2E,
+  const Index & a,
+  const Index & b,
+  const Index & uei)
+{
+  std::vector<Index> face_queue;
+  face_queue.reserve(32);
+  std::vector<Index> pushed;
+  // 32 is faster than 8
+  pushed.reserve(32);
+  assert(a!=b);
+  // starting with the (2) faces incident on e, consider all faces
+  // incident on edges containing either a or b.
+  //
+  // face_queue  Queue containing faces incident on exactly one of a/b
+  // Using a vector seems mildly faster
+  assert(EMAP.size()%3 == 0);
+  const Index num_faces = EMAP.size()/3;
+  const Index f1 = uE2E[uei][0]%num_faces;
+  const Index f2 = uE2E[uei][1]%num_faces;
+  // map is faster than unordered_map here, and vector + brute force
+  // is_member check is even faster
+  face_queue.push_back(f1);
+  pushed.push_back(f1);
+  face_queue.push_back(f2);
+  pushed.push_back(f2);
+  while(!face_queue.empty())
+  {
+    const Index f = face_queue.back();
+    face_queue.pop_back();
+    // consider each edge of this face
+    for(int c = 0;c<3;c++)
+    {
+      // Unique edge id
+      const Index uec = EMAP(c*num_faces+f);
+      const Index s = uE(uec,0);
+      const Index d = uE(uec,1);
+      const bool ona = s == a || d == a;
+      const bool onb = s == b || d == b;
+      // Is this the edge we're looking for?
+      if(ona && onb)
+      {
+        return true;
+      }
+      // not incident on either?
+      if(!ona && !onb)
+      {
+        continue;
+      }
+      // loop over all incident half-edges
+      for(const auto & he : uE2E[uec])
+      {
+        // face of this he
+        const Index fhe = he%num_faces;
+        bool already_pushed = false;
+        for(const auto & fp : pushed)
+        {
+          if(fp == fhe)
+          {
+            already_pushed = true;
+            break;
+          }
+        }
+        if(!already_pushed)
+        {
+          pushed.push_back(fhe);
+          face_queue.push_back(fhe);
+        }
+      }
+    }
+  }
+  return false;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::edge_exists_near<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, int const&, int const&, int const&);
+#endif 

+ 47 - 0
include/igl/edge_exists_near.h

@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EDGE_EXISTS_NEAR_H
+#define IGL_EDGE_EXISTS_NEAR_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+  // Does edge (a,b) exist in the edges of all faces incident on
+  // existing unique edge uei.
+  //
+  // Inputs:
+  //   uE  #uE by 2 list of unique undirected edges
+  //   EMAP #F*3 list of indices into uE, mapping each directed edge to unique
+  //     undirected edge
+  //   uE2E  #uE list of lists of indices into E of coexisting edges
+  //   E  #F*3 by 2 list of half-edges
+  //   a  1st end-point of query edge
+  //   b  2nd end-point of query edge
+  //   uei  index into uE/uE2E of unique edge
+  // Returns true if edge exists near uei.
+  //
+  // See also: unique_edge_map
+  template <
+    typename DeriveduE,
+    typename DerivedEMAP,
+    typename uE2EType,
+    typename Index>
+  IGL_INLINE bool edge_exists_near(
+    const Eigen::MatrixBase<DeriveduE> & uE,
+    const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+    const std::vector<std::vector< uE2EType> > & uE2E,
+    const Index & a,
+    const Index & b,
+    const Index & uei);
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "edge_exists_near.cpp"
+#endif
+#endif
+

+ 9 - 9
include/igl/edge_flaps.cpp

@@ -12,14 +12,14 @@
 
 IGL_INLINE void igl::edge_flaps(
   const Eigen::MatrixXi & F,
-  const Eigen::MatrixXi & E,
+  const Eigen::MatrixXi & uE,
   const Eigen::VectorXi & EMAP,
   Eigen::MatrixXi & EF,
   Eigen::MatrixXi & EI)
 {
   // Initialize to boundary value
-  EF.setConstant(E.rows(),2,-1);
-  EI.setConstant(E.rows(),2,-1);
+  EF.setConstant(uE.rows(),2,-1);
+  EI.setConstant(uE.rows(),2,-1);
   // loop over all faces
   for(int f = 0;f<F.rows();f++)
   {
@@ -29,13 +29,13 @@ IGL_INLINE void igl::edge_flaps(
       // get edge id
       const int e = EMAP(v*F.rows()+f);
       // See if this is left or right flap w.r.t. edge orientation
-      if( F(f,(v+1)%3) == E(e,0) && F(f,(v+2)%3) == E(e,1))
+      if( F(f,(v+1)%3) == uE(e,0) && F(f,(v+2)%3) == uE(e,1))
       {
         EF(e,0) = f;
         EI(e,0) = v;
       }else
       {
-        assert(F(f,(v+1)%3) == E(e,1) && F(f,(v+2)%3) == E(e,0));
+        assert(F(f,(v+1)%3) == uE(e,1) && F(f,(v+2)%3) == uE(e,0));
         EF(e,1) = f;
         EI(e,1) = v;
       }
@@ -45,16 +45,16 @@ IGL_INLINE void igl::edge_flaps(
 
 IGL_INLINE void igl::edge_flaps(
   const Eigen::MatrixXi & F,
-  Eigen::MatrixXi & E,
+  Eigen::MatrixXi & uE,
   Eigen::VectorXi & EMAP,
   Eigen::MatrixXi & EF,
   Eigen::MatrixXi & EI)
 {
   Eigen::MatrixXi allE;
   std::vector<std::vector<int> > uE2E;
-  igl::unique_edge_map(F,allE,E,EMAP,uE2E);
+  igl::unique_edge_map(F,allE,uE,EMAP,uE2E);
   // Const-ify to call overload
-  const auto & cE = E;
+  const auto & cuE = uE;
   const auto & cEMAP = EMAP;
-  return edge_flaps(F,cE,cEMAP,EF,EI);
+  return edge_flaps(F,cuE,cEMAP,EF,EI);
 }

+ 7 - 5
include/igl/edge_flaps.h

@@ -16,15 +16,17 @@ namespace igl
   //
   // Inputs:
   //   F  #F by 3 list of face indices
-  //   E  #E by 2 list of edge indices into V.
-  //   EMAP #F*3 list of indices into E, mapping each directed edge to unique
-  //     unique edge in E
+  //   uE  #uE by 2 list of edge indices into V.
+  //   EMAP #F*3 list of indices into uE, mapping each directed edge to unique
+  //     unique edge in uE
   // Outputs:
   //   EF  #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
   //     F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
   //     e=(j->i)
   //   EI  #E by 2 list of edge flap corners (see above).
   //
+  // See also: unique_edge_map
+  //
   // TODO: This seems to be a duplicate of edge_topology.h
   // igl::edge_topology(V,F,etEV,etFE,etEF);
   // igl::edge_flaps(F,efE,efEMAP,efEF,efEI);
@@ -34,14 +36,14 @@ namespace igl
   // all(efEMAP(sub2ind(size(F),repmat(1:size(F,1),3,1)',repmat([1 2 3],size(F,1),1))) == etFE(:,[2 3 1]))
   IGL_INLINE void edge_flaps(
     const Eigen::MatrixXi & F,
-    const Eigen::MatrixXi & E,
+    const Eigen::MatrixXi & uE,
     const Eigen::VectorXi & EMAP,
     Eigen::MatrixXi & EF,
     Eigen::MatrixXi & EI);
   // Only faces as input
   IGL_INLINE void edge_flaps(
     const Eigen::MatrixXi & F,
-    Eigen::MatrixXi & E,
+    Eigen::MatrixXi & uE,
     Eigen::VectorXi & EMAP,
     Eigen::MatrixXi & EF,
     Eigen::MatrixXi & EI);

+ 3 - 0
include/igl/edge_lengths.cpp

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

+ 104 - 72
include/igl/embree/EmbreeIntersector.h

@@ -21,8 +21,8 @@
 #include <Eigen/Core>
 #include <Eigen/Geometry>
 
-#include <embree2/rtcore.h>
-#include <embree2/rtcore_ray.h>
+#include <embree3/rtcore.h>
+#include <embree3/rtcore_ray.h>
 #include <iostream>
 #include <vector>
 
@@ -177,7 +177,7 @@ namespace igl
       bool initialized;
 
       inline void createRay(
-        RTCRay& ray,
+        RTCRayHit& ray,
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
         float tnear,
@@ -199,29 +199,28 @@ namespace igl
   {
     // Keeps track of whether the **Global** Embree intersector has been
     // initialized. This should never been done at the global scope.
-    static bool EmbreeIntersector_inited = false;
+    static RTCDevice g_device = nullptr;
   }
 }
 
 inline void igl::embree::EmbreeIntersector::global_init()
 {
-  if(!EmbreeIntersector_inited)
+  if(!g_device)
   {
-    rtcInit();
-    if(rtcGetError() != RTC_NO_ERROR)
+    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
-    EmbreeIntersector_inited = true;
   }
 }
 
 inline void igl::embree::EmbreeIntersector::global_deinit()
 {
-  EmbreeIntersector_inited = false;
-  rtcExit();
+  rtcReleaseDevice (g_device);
+  g_device = nullptr;
 }
 
 inline igl::embree::EmbreeIntersector::EmbreeIntersector()
@@ -287,43 +286,49 @@ inline void igl::embree::EmbreeIntersector::init(
     return;
   }
 
+  RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
+
   // create a scene
-  RTCSceneFlags flags = RTC_SCENE_ROBUST | RTC_SCENE_HIGH_QUALITY;
-  if(isStatic)
-    flags = flags | RTC_SCENE_STATIC;
-  scene = rtcNewScene(flags,RTC_INTERSECT1);
+  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
-    geomID = rtcNewTriangleMesh(scene,RTC_GEOMETRY_STATIC,F[g]->rows(),V[g]->rows(),1);
+    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*)rtcMapBuffer(scene,geomID,RTC_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);
     }
-    rtcUnmapBuffer(scene,geomID,RTC_VERTEX_BUFFER);
+    
 
     // fill triangle buffer
-    triangles = (Triangle*) rtcMapBuffer(scene,geomID,RTC_INDEX_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);
     }
-    rtcUnmapBuffer(scene,geomID,RTC_INDEX_BUFFER);
+    
 
-    rtcSetMask(scene,geomID,masks[g]);
+    rtcSetGeometryMask(geom_0,masks[g]);
+    rtcCommitGeometry(geom_0);
   }
 
-  rtcCommit(scene);
+  rtcCommitScene(scene);
 
-  if(rtcGetError() != RTC_NO_ERROR)
+  if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
       std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
 #ifdef IGL_VERBOSE
   else
@@ -342,11 +347,11 @@ igl::embree::EmbreeIntersector
 
 void igl::embree::EmbreeIntersector::deinit()
 {
-  if(EmbreeIntersector_inited && scene)
+  if(g_device && scene)
   {
-    rtcDeleteScene(scene);
+    rtcReleaseScene(scene);
 
-    if(rtcGetError() != RTC_NO_ERROR)
+    if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
     {
         std::cerr << "Embree: An error occurred while resetting!" << std::endl;
     }
@@ -367,23 +372,31 @@ inline bool igl::embree::EmbreeIntersector::intersectRay(
   float tfar,
   int mask) const
 {
-  RTCRay ray;
+  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
+  ray.ray.flags = 0;
   createRay(ray, origin,direction,tnear,tfar,mask);
 
   // shot ray
-  rtcIntersect(scene,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(rtcGetError() != RTC_NO_ERROR)
+  if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
       std::cerr << "Embree: An error occurred while resetting!" << std::endl;
 #endif
 
-  if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)
+  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
   {
-    hit.id = ray.primID;
-    hit.gid = ray.geomID;
-    hit.u = ray.u;
-    hit.v = ray.v;
-    hit.t = ray.tfar;
+    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;
   }
 
@@ -419,6 +432,7 @@ inline bool igl::embree::EmbreeIntersector::intersectBeam(
   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();
@@ -462,22 +476,30 @@ igl::embree::EmbreeIntersector
   const double eps = FLOAT_EPS;
   double min_t = tnear;
   bool large_hits_warned = false;
-  RTCRay ray;
+  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
+  ray.ray.flags = 0;
   createRay(ray,origin,direction,tnear,tfar,mask);
 
   while(true)
   {
-    ray.tnear = min_t;
-    ray.tfar = tfar;
-    ray.geomID = RTC_INVALID_GEOMETRY_ID;
-    ray.primID = RTC_INVALID_GEOMETRY_ID;
-    ray.instID = RTC_INVALID_GEOMETRY_ID;
+    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++;
-    rtcIntersect(scene,ray);
-    if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)
+    {
+      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.primID == last_id0 || ray.tfar <= min_t)
+      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);
@@ -492,23 +514,23 @@ igl::embree::EmbreeIntersector
       else
       {
         Hit hit;
-        hit.id = ray.primID;
-        hit.gid = ray.geomID;
-        hit.u = ray.u;
-        hit.v = ray.v;
-        hit.t = ray.tfar;
+        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.tfar;
+        min_t = ray.ray.tfar;
 
         // reset t_scale
         self_hits = 0;
       }
-      last_id0 = ray.primID;
+      last_id0 = ray.hit.primID;
     }
     else
       break; // no more hits
@@ -544,18 +566,26 @@ inline bool
 igl::embree::EmbreeIntersector
 ::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
 {
-  RTCRay ray;
+  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
+  ray.ray.flags = 0;
   createRay(ray,a,ab,0,1.0,mask);
 
-  rtcIntersect(scene,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;
+  }
 
-  if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)
+  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
   {
-    hit.id = ray.primID;
-    hit.gid = ray.geomID;
-    hit.u = ray.u;
-    hit.v = ray.v;
-    hit.t = ray.tfar;
+    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;
   }
 
@@ -564,21 +594,23 @@ igl::embree::EmbreeIntersector
 
 inline void
 igl::embree::EmbreeIntersector
-::createRay(RTCRay& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
+::createRay(RTCRayHit& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
 {
-  ray.org[0] = origin[0];
-  ray.org[1] = origin[1];
-  ray.org[2] = origin[2];
-  ray.dir[0] = direction[0];
-  ray.dir[1] = direction[1];
-  ray.dir[2] = direction[2];
-  ray.tnear = tnear;
-  ray.tfar = tfar;
-  ray.geomID = RTC_INVALID_GEOMETRY_ID;
-  ray.primID = RTC_INVALID_GEOMETRY_ID;
-  ray.instID = RTC_INVALID_GEOMETRY_ID;
-  ray.mask = mask;
-  ray.time = 0.0f;
+  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

+ 15 - 0
include/igl/face_occurrences.cpp

@@ -6,6 +6,8 @@
 // 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 "face_occurrences.h"
+#include "list_to_matrix.h"
+#include "matrix_to_list.h"
 
 #include <map>
 #include "sort.h"
@@ -50,6 +52,19 @@ IGL_INLINE void igl::face_occurrences(
   }
 }
 
+template <typename DerivedF, typename DerivedC>
+IGL_INLINE void igl::face_occurrences(
+  const Eigen::MatrixBase<DerivedF> & F,
+  Eigen::PlainObjectBase<DerivedC> & C)
+{
+  // Should really just rewrite using Eigen+libigl ...
+  std::vector<std::vector<typename DerivedF::Scalar> > vF;
+  matrix_to_list(F,vF);
+  std::vector<std::vector<typename DerivedC::Scalar> > vC;
+  igl::face_occurrences(vF,vC);
+  list_to_matrix(vC,C);
+}
+
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh

+ 6 - 1
include/igl/face_occurrences.h

@@ -8,11 +8,12 @@
 #ifndef IGL_FACE_OCCURRENCES
 #define IGL_FACE_OCCURRENCES
 #include "igl_inline.h"
+#include <Eigen/Core>
 
 #include <vector>
 namespace igl
 {
-  // Count the occruances of each face (row) in a list of face indices
+  // Count the occurances of each face (row) in a list of face indices
   // (irrespecitive of order)
   // Inputs:
   //   F  #F by simplex-size
@@ -23,6 +24,10 @@ namespace igl
   IGL_INLINE void face_occurrences(
     const std::vector<std::vector<IntegerF> > & F,
     std::vector<IntegerC> & C);
+  template <typename DerivedF, typename DerivedC>
+  IGL_INLINE void face_occurrences(
+    const Eigen::MatrixBase<DerivedF> & F,
+    Eigen::PlainObjectBase<DerivedC> & C);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 8 - 5
include/igl/facet_components.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "facet_components.h"
 #include <igl/triangle_triangle_adjacency.h>
@@ -24,7 +24,7 @@ IGL_INLINE void igl::facet_components(
 }
 
 template <
-  typename TTIndex, 
+  typename TTIndex,
   typename DerivedC,
   typename Derivedcounts>
 IGL_INLINE void igl::facet_components(
@@ -89,4 +89,7 @@ IGL_INLINE void igl::facet_components(
 template void igl::facet_components<long, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
 template void igl::facet_components<int, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::facet_components<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::facet_components<__int64,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class std::vector<class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > >,class std::allocator<class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > > > > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+#endif
 #endif

+ 1 - 0
include/igl/find.cpp

@@ -129,6 +129,7 @@ template void igl::find<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::M
 template void igl::find<double, 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::SparseMatrix<double, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::find<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::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::find<double, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::find<Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #if EIGEN_VERSION_AT_LEAST(3,3,0)
 #else
 template void igl::find<Eigen::CwiseBinaryOp<Eigen::internal::scalar_cmp_op<long, (Eigen::internal::ComparisonName)0>, Eigen::PartialReduxExpr<Eigen::Array<bool, -1, 3, 0, -1, 3>, Eigen::internal::member_count<long>, 1> const, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<long>, Eigen::Array<long, -1, 1, 0, -1, 1> > const>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::CwiseBinaryOp<Eigen::internal::scalar_cmp_op<long, (Eigen::internal::ComparisonName)0>, Eigen::PartialReduxExpr<Eigen::Array<bool, -1, 3, 0, -1, 3>, Eigen::internal::member_count<long>, 1> const, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<long>, Eigen::Array<long, -1, 1, 0, -1, 1> > const> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);

+ 7 - 8
include/igl/find_cross_field_singularities.cpp

@@ -9,11 +9,10 @@
 #include "find_cross_field_singularities.h"
 
 #include <vector>
-#include <igl/cross_field_missmatch.h>
+#include <igl/cross_field_mismatch.h>
 #include <igl/is_border_vertex.h>
 #include <igl/vertex_triangle_adjacency.h>
 #include <igl/is_border_vertex.h>
-#include <igl/cross_field_missmatch.h>
 
 
 template <typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedO>
@@ -38,7 +37,7 @@ IGL_INLINE void igl::find_cross_field_singularities(const Eigen::PlainObjectBase
     if (V_border[vid])
       continue;
 
-    int missmatch=0;
+    int mismatch=0;
     for (unsigned int i=0;i<VF[vid].size();i++)
     {
       // look for the vertex
@@ -48,12 +47,12 @@ IGL_INLINE void igl::find_cross_field_singularities(const Eigen::PlainObjectBase
           j=z;
       assert(j!=-1);
 
-      missmatch+=Handle_MMatch(VF[vid][i],j);
+      mismatch+=Handle_MMatch(VF[vid][i],j);
     }
-    missmatch=missmatch%4;
+    mismatch=mismatch%4;
 
-    isSingularity(vid)=(missmatch!=0);
-    singularityIndex(vid)=missmatch;
+    isSingularity(vid)=(mismatch!=0);
+    singularityIndex(vid)=mismatch;
   }
 
 
@@ -70,7 +69,7 @@ IGL_INLINE void igl::find_cross_field_singularities(const Eigen::PlainObjectBase
 {
   Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, 3> Handle_MMatch;
 
-  igl::cross_field_missmatch(V, F, PD1, PD2, isCombed, Handle_MMatch);
+  igl::cross_field_mismatch(V, F, PD1, PD2, isCombed, Handle_MMatch);
   igl::find_cross_field_singularities(V, F, Handle_MMatch, isSingularity, singularityIndex);
 }
 

+ 3 - 3
include/igl/find_cross_field_singularities.h

@@ -18,7 +18,7 @@ namespace igl
   // Inputs:
   //   V                #V by 3 eigen Matrix of mesh vertex 3D positions
   //   F                #F by 3 eigen Matrix of face (quad) indices
-  //   Handle_MMatch    #F by 3 eigen Matrix containing the integer missmatch of the cross field
+  //   mismatch         #F by 3 eigen Matrix containing the integer mismatch of the cross field
   //                    across all face edges
   // Output:
   //   isSingularity    #V by 1 boolean eigen Vector indicating the presence of a singularity on a vertex
@@ -27,11 +27,11 @@ namespace igl
   template <typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedO>
   IGL_INLINE void find_cross_field_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
                                                  const Eigen::PlainObjectBase<DerivedF> &F,
-                                                 const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch,
+                                                 const Eigen::PlainObjectBase<DerivedM> &mismatch,
                                                  Eigen::PlainObjectBase<DerivedO> &isSingularity,
                                                  Eigen::PlainObjectBase<DerivedO> &singularityIndex);
 
-  // Wrapper that calculates the missmatch if it is not provided.
+  // Wrapper that calculates the mismatch if it is not provided.
   // Note that the field in PD1 and PD2 MUST BE combed (see igl::comb_cross_field).
   // Inputs:
   //   V                #V by 3 eigen Matrix of mesh vertex 3D positions

+ 1 - 1
include/igl/flip_avoiding_line_search.cpp

@@ -47,7 +47,7 @@ namespace igl
         {
           A =-pow(fabs(r)+sqrt(r2-q3),1./3);
           if( r<0 ) A=-A;
-          B = A==0? 0 : B=q/A;
+          B = A==0? 0 : q/A;
 
           a/=3;
           x[0] =(A+B)-a;

+ 16 - 1
include/igl/flip_edge.cpp

@@ -25,6 +25,14 @@ IGL_INLINE void igl::flip_edge(
   typedef typename DerivedF::Scalar Index;
   const size_t num_faces = F.rows();
   assert(F.cols() == 3);
+  // Edge to flip [v1,v2] --> [v3,v4]
+  // Before:
+  // F(f1,:) = [v1,v2,v4] // in some cyclic order
+  // F(f2,:) = [v1,v3,v2] // in some cyclic order
+  // After: 
+  // F(f1,:) = [v1,v3,v4] // in *this* order 
+  // F(f2,:) = [v2,v4,v3] // in *this* order
+  //
   //          v1                 v1
   //          /|\                / \
   //         / | \              /f1 \
@@ -149,5 +157,12 @@ IGL_INLINE void igl::flip_edge(
 
 
 #ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::flip_edge<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, unsigned long);
 template void igl::flip_edge<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, unsigned long);
-#endif
+#ifdef WIN32
+template void igl::flip_edge<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, unsigned __int64);
+template void igl::flip_edge<class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,2,0,-1,2>,class Eigen::Matrix<int,-1,2,0,-1,2>,class Eigen::Matrix<int,-1,1,0,-1,1>,int>(class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,2,0,-1,2> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,2,0,-1,2> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > &,class std::vector<class std::vector<int,class std::allocator<int> >,class std::allocator<class std::vector<int,class std::allocator<int> > > > &,unsigned __int64);
+#endif
+#endif

+ 64 - 67
include/igl/grad.cpp

@@ -14,11 +14,17 @@
 #include "volume.h"
 #include "doublearea.h"
 
+namespace igl {
+
+namespace {
+
 template <typename DerivedV, typename DerivedF>
-IGL_INLINE void grad_tet(const Eigen::PlainObjectBase<DerivedV>&V,
-                     const Eigen::PlainObjectBase<DerivedF>&T,
-                            Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
-                            bool uniform) {
+IGL_INLINE void grad_tet(
+  const Eigen::MatrixBase<DerivedV>&V,
+  const Eigen::MatrixBase<DerivedF>&T,
+  Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
+  bool uniform)
+{
   using namespace Eigen;
   assert(T.cols() == 4);
   const int n = V.rows(); int m = T.rows();
@@ -37,7 +43,7 @@ IGL_INLINE void grad_tet(const Eigen::PlainObjectBase<DerivedV>&V,
     F.row(3*m + i) << T(i,1), T(i,3), T(i,2);
   }
   // compute volume of each tet
-  Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> vol; 
+  Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> vol;
   igl::volume(V,T,vol);
 
   Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> A(F.rows());
@@ -116,15 +122,22 @@ IGL_INLINE void grad_tet(const Eigen::PlainObjectBase<DerivedV>&V,
 }
 
 template <typename DerivedV, typename DerivedF>
-IGL_INLINE void grad_tri(const Eigen::PlainObjectBase<DerivedV>&V,
-                     const Eigen::PlainObjectBase<DerivedF>&F,
-                    Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
-                    bool uniform)
+IGL_INLINE void grad_tri(
+  const Eigen::MatrixBase<DerivedV>&V,
+  const Eigen::MatrixBase<DerivedF>&F,
+  Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
+  bool uniform)
 {
+  // Number of faces
+  const int m = F.rows();
+  // Number of vertices
+  const int nv = V.rows();
+  // Number of dimensions
+  const int dims = V.cols();
   Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3>
-    eperp21(F.rows(),3), eperp13(F.rows(),3);
+    eperp21(m,3), eperp13(m,3);
 
-  for (int i=0;i<F.rows();++i)
+  for (int i=0;i<m;++i)
   {
     // renaming indices of vertices of triangles for convenience
     int i1 = F(i,0);
@@ -132,10 +145,14 @@ IGL_INLINE void grad_tri(const Eigen::PlainObjectBase<DerivedV>&V,
     int i3 = F(i,2);
 
     // #F x 3 matrices of triangle edge vectors, named after opposite vertices
-    Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v32 = V.row(i3) - V.row(i2);
-    Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v13 = V.row(i1) - V.row(i3);
-    Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v21 = V.row(i2) - V.row(i1);
-    Eigen::Matrix<typename DerivedV::Scalar, 1, 3> n = v32.cross(v13);
+    typedef Eigen::Matrix<typename DerivedV::Scalar, 1, 3> RowVector3S;
+    RowVector3S v32 = RowVector3S::Zero(1,3);
+    RowVector3S v13 = RowVector3S::Zero(1,3);
+    RowVector3S v21 = RowVector3S::Zero(1,3);
+    v32.head(V.cols()) = V.row(i3) - V.row(i2);
+    v13.head(V.cols()) = V.row(i1) - V.row(i3);
+    v21.head(V.cols()) = V.row(i2) - V.row(i1);
+    RowVector3S n = v32.cross(v13);
     // area of parallelogram is twice area of triangle
     // area of parallelogram is || v1 x v2 ||
     // This does correct l2 norm of rows, so that it contains #F list of twice
@@ -174,70 +191,50 @@ IGL_INLINE void grad_tri(const Eigen::PlainObjectBase<DerivedV>&V,
     eperp13.row(i) *= norm13 / dblA;
   }
 
-  std::vector<int> rs;
-  rs.reserve(F.rows()*4*3);
-  std::vector<int> cs;
-  cs.reserve(F.rows()*4*3);
-  std::vector<double> vs;
-  vs.reserve(F.rows()*4*3);
-
-  // row indices
-  for(int r=0;r<3;r++)
+  // create sparse gradient operator matrix
+  G.resize(dims*m,nv);
+  std::vector<Eigen::Triplet<typename DerivedV::Scalar> > Gijv;
+  Gijv.reserve(4*dims*m);
+  for(int f = 0;f<F.rows();f++)
   {
-    for(int j=0;j<4;j++)
+    for(int d = 0;d<dims;d++)
     {
-      for(int i=r*F.rows();i<(r+1)*F.rows();i++) rs.push_back(i);
+      Gijv.emplace_back(f+d*m,F(f,1), eperp13(f,d));
+      Gijv.emplace_back(f+d*m,F(f,0),-eperp13(f,d));
+      Gijv.emplace_back(f+d*m,F(f,2), eperp21(f,d));
+      Gijv.emplace_back(f+d*m,F(f,0),-eperp21(f,d));
     }
   }
+  G.setFromTriplets(Gijv.begin(), Gijv.end());
+}
 
-  // column indices
-  for(int r=0;r<3;r++)
-  {
-    for(int i=0;i<F.rows();i++) cs.push_back(F(i,1));
-    for(int i=0;i<F.rows();i++) cs.push_back(F(i,0));
-    for(int i=0;i<F.rows();i++) cs.push_back(F(i,2));
-    for(int i=0;i<F.rows();i++) cs.push_back(F(i,0));
-  }
-
-  // values
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,0));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,0));
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,0));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,0));
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,1));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,1));
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,1));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,1));
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,2));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,2));
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,2));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,2));
+} // anonymous namespace
 
-  // create sparse gradient operator matrix
-  G.resize(3*F.rows(),V.rows());
-  std::vector<Eigen::Triplet<typename DerivedV::Scalar> > triplets;
-  for (int i=0;i<(int)vs.size();++i)
-  {
-    triplets.push_back(Eigen::Triplet<typename DerivedV::Scalar>(rs[i],cs[i],vs[i]));
-  }
-  G.setFromTriplets(triplets.begin(), triplets.end());
-}
+} // namespace igl
 
 template <typename DerivedV, typename DerivedF>
-IGL_INLINE void igl::grad(const Eigen::PlainObjectBase<DerivedV>&V,
-                     const Eigen::PlainObjectBase<DerivedF>&F,
-                    Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
-                    bool uniform)
+IGL_INLINE void igl::grad(
+  const Eigen::MatrixBase<DerivedV>&V,
+  const Eigen::MatrixBase<DerivedF>&F,
+  Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
+  bool uniform)
 {
   assert(F.cols() == 3 || F.cols() == 4);
-  if (F.cols() == 3)
-    return grad_tri(V,F,G,uniform);
-  if (F.cols() == 4)
-    return grad_tet(V,F,G,uniform);
+  switch(F.cols())
+  {
+    case 3:
+      return grad_tri(V,F,G,uniform);
+    case 4:
+      return grad_tet(V,F,G,uniform);
+    default:
+      assert(false);
+  }
 }
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::grad<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&, Eigen::SparseMatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, 0, int>&, bool);
-template void igl::grad<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, 0, int>&, bool);
+// generated by autoexplicit.sh
+template void igl::grad<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::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<Eigen::Matrix<double, -1, 2, 0, -1, 2>::Scalar, 0, int>&, bool);
+template void igl::grad<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::SparseMatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, 0, int>&, bool);
+template void igl::grad<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, 0, int>&, bool);
 #endif

+ 8 - 7
include/igl/grad.h

@@ -5,8 +5,8 @@
 // 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_GRAD_MAT_H
-#define IGL_GRAD_MAT_H
+#ifndef IGL_GRAD_H
+#define IGL_GRAD_H
 #include "igl_inline.h"
 
 #include <Eigen/Core>
@@ -33,11 +33,12 @@ namespace igl {
   // i, and A is the area of triangle (i,j,k). ^R90 represent a rotation of
   // 90 degrees
   //
-template <typename DerivedV, typename DerivedF>
-IGL_INLINE void grad(const Eigen::PlainObjectBase<DerivedV>&V,
-                     const Eigen::PlainObjectBase<DerivedF>&F,
-                    Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
-                    bool uniform = false);
+  template <typename DerivedV, typename DerivedF>
+  IGL_INLINE void grad(
+    const Eigen::MatrixBase<DerivedV>&V,
+    const Eigen::MatrixBase<DerivedF>&F,
+    Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
+    bool uniform = false);
 }
 #ifndef IGL_STATIC_LIBRARY
 #  include "grad.cpp"

+ 78 - 0
include/igl/grad_intrinsic.cpp

@@ -0,0 +1,78 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "grad_intrinsic.h"
+#include "grad.h"
+
+template <typename Derivedl, typename DerivedF, typename Gtype>
+IGL_INLINE void igl::grad_intrinsic(
+  const Eigen::MatrixBase<Derivedl>&l,
+  const Eigen::MatrixBase<DerivedF>&F,
+  Eigen::SparseMatrix<Gtype> &G)
+{
+  assert(F.cols() ==3 && "Only triangles supported");
+  // number of vertices
+  const int n = F.maxCoeff()+1;
+  // number of faces
+  const int m = F.rows();
+  // JD: There is a pretty subtle bug when using a fixed column size for this matrix.
+  // When calling igl::grad(V, ...), the two code paths `grad_tet` and `grad_tri`
+  // will be compiled. It turns out that `igl::grad_tet` calls `igl::volume`, which
+  // reads the coordinates of the `V` matrix into `RowVector3d`. If the matrix `V`
+  // has a known compile-time size of 2, this produces a compilation error when
+  // libigl is compiled in header-only mode. In static mode this doesn't happen
+  // because the matrix `V` is probably implicitly copied into a `Eigen::MatrixXd`.
+  // This is a situation that could be solved using `if constexpr` in C++17.
+  // In C++11, the alternative is to use SFINAE and `std::enable_if` (ugh).
+  typedef Eigen::Matrix<Gtype,Eigen::Dynamic,Eigen::Dynamic> MatrixX2S;
+  MatrixX2S V2 = MatrixX2S::Zero(3*m,2);
+  //     1=[x,y]
+  //     /\
+  // l3 /   \ l2
+  //   /      \
+  //  /         \
+  // 2-----------3
+  //       l1
+  //
+  // x = (l2²-l1²-l3²)/(-2*l1)
+  // y = sqrt(l3² - x²)
+  //
+  //
+  // Place 3rd vertex at [l(:,1) 0]
+  V2.block(2*m,0,m,1) = l.col(0);
+  // Place second vertex at [0 0]
+  // Place third vertex at [x y]
+  V2.block(0,0,m,1) =
+    (l.col(1).cwiseAbs2()-l.col(0).cwiseAbs2()-l.col(2).cwiseAbs2()).array()/
+    (-2.*l.col(0)).array();
+  V2.block(0,1,m,1) =
+    (l.col(2).cwiseAbs2() - V2.block(0,0,m,1).cwiseAbs2()).array().sqrt();
+  DerivedF F2(F.rows(),F.cols());
+  std::vector<Eigen::Triplet<Gtype> > Pijv;
+  Pijv.reserve(F.size());
+  for(int f = 0;f<m;f++)
+  {
+    for(int c = 0;c<F.cols();c++)
+    {
+      F2(f,c) = f+c*m;
+      Pijv.emplace_back(F2(f,c),F(f,c),1);
+    }
+  }
+  Eigen::SparseMatrix<Gtype> P(m*3,n);
+  P.setFromTriplets(Pijv.begin(),Pijv.end());
+  Eigen::SparseMatrix<Gtype> G2;
+  grad(V2,F2,G2);
+  G = G2*P;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::grad_intrinsic<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+// generated by autoexplicit.sh
+template void igl::grad_intrinsic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+#endif

+ 35 - 0
include/igl/grad_intrinsic.h

@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_GRAD_INTRINSIC_H
+#define IGL_GRAD_INTRINSIC_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+namespace igl {
+  // GRAD_INTRINSIC Construct an intrinsic gradient operator.
+  //
+  // Inputs:
+  //  l  #F by 3 list of edge lengths
+  //  F  #F by 3 list of triangle indices into some vertex list V
+  // Outputs:
+  //  G  #F*2 by #V gradient matrix: G=[Gx;Gy] where x runs along the 23 edge and
+  //    y runs in the counter-clockwise 90° rotation.
+  template <typename Derivedl, typename DerivedF, typename Gtype>
+  IGL_INLINE void grad_intrinsic(
+    const Eigen::MatrixBase<Derivedl>&l,
+    const Eigen::MatrixBase<DerivedF>&F,
+    Eigen::SparseMatrix<Gtype> &G);
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "grad_intrinsic.cpp"
+#endif
+
+#endif
+

+ 22 - 12
include/igl/grid.cpp

@@ -6,6 +6,7 @@
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can 
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "grid.h"
+#include <cassert>
 
 template <
   typename Derivedres,
@@ -16,23 +17,30 @@ IGL_INLINE void igl::grid(
 {
   using namespace Eigen;
   typedef typename DerivedGV::Scalar Scalar;
-  GV.resize(res(0)*res(1)*res(2),3);
-  for(int zi = 0;zi<res(2);zi++)
+  GV.resize(res.array().prod(),res.size());
+  const auto lerp = 
+    [&res](const Scalar di, const int d)->Scalar{return di/(Scalar)(res(d)-1);};
+  int gi = 0;
+  Derivedres sub;
+  sub.resizeLike(res);
+  sub.setConstant(0);
+  for(int gi = 0;gi<GV.rows();gi++)
   {
-    const auto lerp = 
-      [&](const Scalar di, const int d)->Scalar{return di/(Scalar)(res(d)-1);};
-    const Scalar z = lerp(zi,2);
-    for(int yi = 0;yi<res(1);yi++)
+    // omg, I'm implementing addition...
+    for(int c = 0;c<res.size()-1;c++)
     {
-      const Scalar y = lerp(yi,1);
-      for(int xi = 0;xi<res(0);xi++)
+      if(sub(c)>=res(c))
       {
-        const Scalar x = lerp(xi,0);
-        const int gi = xi+res(0)*(yi + res(1)*zi);
-        GV.row(gi) = 
-          Eigen::Matrix<Scalar,1,3>(x,y,z);
+        sub(c) = 0;
+        // roll over
+        sub(c+1)++;
       }
     }
+    for(int c = 0;c<res.size();c++)
+    {
+      GV(gi,c) = lerp(sub(c),c);
+    }
+    sub(0)++;
   }
 }
 
@@ -40,6 +48,8 @@ IGL_INLINE void igl::grid(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template void igl::grid<Eigen::Matrix<int, 2, 1, 0, 2, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, 2, 1, 0, 2, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
 template void igl::grid<Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
 // generated by autoexplicit.sh
 template void igl::grid<Eigen::Matrix<int, 3, 1, 0, 3, 1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);

+ 3 - 2
include/igl/grid.h

@@ -1,6 +1,7 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // 
 // Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
 // 
 // This Source Code Form is subject to the terms of the Mozilla Public License 
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can 
@@ -15,9 +16,9 @@ namespace igl
   // `igl::marching_cubes`
   //
   // Inputs:
-  //   res  3-long list of number of vertices along the x y and z dimensions
+  //   res  #res list of number of vertices along each dimension
   // Outputs:
-  //   GV  res(0)*res(1)*res(2) by 3 list of mesh vertex positions.
+  //   GV  res.array().prod() by #res list of mesh vertex positions.
   //   
   template <
     typename Derivedres,

+ 160 - 0
include/igl/heat_geodesics.cpp

@@ -0,0 +1,160 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "heat_geodesics.h"
+#include "grad.h"
+#include "doublearea.h"
+#include "cotmatrix.h"
+#include "intrinsic_delaunay_cotmatrix.h"
+#include "massmatrix.h"
+#include "massmatrix_intrinsic.h"
+#include "grad_intrinsic.h"
+#include "boundary_facets.h"
+#include "unique.h"
+#include "slice.h"
+#include "avg_edge_length.h"
+
+
+template < typename DerivedV, typename DerivedF, typename Scalar >
+IGL_INLINE bool igl::heat_geodesics_precompute(
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
+  HeatGeodesicsData<Scalar> & data)
+{
+  // default t value
+  const Scalar h = avg_edge_length(V,F);
+  const Scalar t = h*h;
+  return heat_geodesics_precompute(V,F,t,data);
+}
+
+template < typename DerivedV, typename DerivedF, typename Scalar >
+IGL_INLINE bool igl::heat_geodesics_precompute(
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
+  const Scalar t,
+  HeatGeodesicsData<Scalar> & data)
+{
+  typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
+  typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixXS;
+  Eigen::SparseMatrix<Scalar> L,M;
+  Eigen::Matrix<Scalar,Eigen::Dynamic,3> l_intrinsic;
+  DerivedF F_intrinsic;
+  VectorXS dblA;
+  if(data.use_intrinsic_delaunay)
+  {
+    igl::intrinsic_delaunay_cotmatrix(V,F,L,l_intrinsic,F_intrinsic);
+    igl::massmatrix_intrinsic(l_intrinsic,F_intrinsic,MASSMATRIX_TYPE_DEFAULT,M);
+    igl::doublearea(l_intrinsic,0,dblA);
+    igl::grad_intrinsic(l_intrinsic,F_intrinsic,data.Grad);
+  }else
+  {
+    igl::cotmatrix(V,F,L);
+    igl::massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M);
+    igl::doublearea(V,F,dblA);
+    igl::grad(V,F,data.Grad);
+  }
+  // div
+  assert(F.cols() == 3 && "Only triangles are supported");
+  // number of gradient components
+  data.ng = data.Grad.rows() / F.rows();
+  assert(data.ng == 3 || data.ng == 2);
+  data.Div = -0.25*data.Grad.transpose()*dblA.colwise().replicate(data.ng).asDiagonal();
+
+  Eigen::SparseMatrix<Scalar> Q = M - t*L;
+  Eigen::MatrixXi O;
+  igl::boundary_facets(F,O);
+  igl::unique(O,data.b);
+  {
+    Eigen::SparseMatrix<Scalar> _;
+    if(!igl::min_quad_with_fixed_precompute(
+      Q,Eigen::VectorXi(),_,true,data.Neumann))
+    {
+      return false;
+    }
+    // Only need if there's a boundary
+    if(data.b.size()>0)
+    {
+      if(!igl::min_quad_with_fixed_precompute(Q,data.b,_,true,data.Dirichlet))
+      {
+        return false;
+      }
+    }
+    const Eigen::SparseMatrix<double> Aeq = M.diagonal().transpose().sparseView();
+    L *= -0.5;
+    if(!igl::min_quad_with_fixed_precompute(
+      L,Eigen::VectorXi(),Aeq,true,data.Poisson))
+    {
+      return false;
+    }
+  }
+  return true;
+}
+
+template < typename Scalar, typename Derivedgamma, typename DerivedD>
+IGL_INLINE void igl::heat_geodesics_solve(
+  const HeatGeodesicsData<Scalar> & data,
+  const Eigen::MatrixBase<Derivedgamma> & gamma,
+  Eigen::PlainObjectBase<DerivedD> & D)
+{
+  // number of mesh vertices
+  const int n = data.Grad.cols();
+  // Set up delta at gamma
+  DerivedD u0 = DerivedD::Zero(n,1);
+  for(int g = 0;g<gamma.size();g++)
+  {
+    u0(gamma(g)) = 1;
+  }
+  // Neumann solution
+  DerivedD u;
+  igl::min_quad_with_fixed_solve(
+    data.Neumann,u0,DerivedD(),DerivedD(),u);
+  if(data.b.size()>0)
+  {
+    // Average Dirichelt and Neumann solutions
+    DerivedD uD;
+    igl::min_quad_with_fixed_solve(
+      data.Dirichlet,u0,DerivedD::Zero(data.b.size()).eval(),DerivedD(),uD);
+    u += uD;
+    u *= 0.5;
+  }
+  DerivedD grad_u = data.Grad*u;
+  const int m = data.Grad.rows()/data.ng;
+  for(int i = 0;i<m;i++)
+  {
+    Scalar norm = 0;
+    for(int d = 0;d<data.ng;d++)
+    {
+      norm += grad_u(d*m+i)*grad_u(d*m+i);
+    }
+    norm = sqrt(norm);
+    if(norm == 0)
+    {
+      for(int d = 0;d<data.ng;d++) { grad_u(d*m+i) = 0; }
+    }else
+    {
+      for(int d = 0;d<data.ng;d++) { grad_u(d*m+i) /= norm; }
+    }
+  }
+  const DerivedD div_X = -data.Div*grad_u;
+  const DerivedD Beq = (DerivedD(1,1)<<0).finished();
+  igl::min_quad_with_fixed_solve(data.Poisson,(-2.0*div_X).eval(),DerivedD(),Beq,D);
+  DerivedD Dgamma;
+  igl::slice(D,gamma,Dgamma);
+  D.array() -= Dgamma.mean();
+  if(D.mean() < 0)
+  {
+    D = -D;
+  }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::heat_geodesics_solve<double, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::HeatGeodesicsData<double> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template bool igl::heat_geodesics_precompute<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, igl::HeatGeodesicsData<double>&);
+template bool igl::heat_geodesics_precompute<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::HeatGeodesicsData<double>&);
+#endif

+ 69 - 0
include/igl/heat_geodesics.h

@@ -0,0 +1,69 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_HEAT_GEODESICS_H
+#define IGL_HEAT_GEODESICS_H
+#include "igl_inline.h"
+#include "min_quad_with_fixed.h"
+#include <Eigen/Sparse>
+#include <Eigen/Sparse>
+namespace igl
+{
+  template <typename Scalar>
+  struct HeatGeodesicsData
+  {
+    // Gradient and Divergence operators
+    Eigen::SparseMatrix<Scalar> Grad,Div;
+    // Number of gradient components
+    int ng;
+    // List of boundary vertex indices
+    Eigen::VectorXi b;
+    // Solvers for Dirichet, Neumann problems
+    min_quad_with_fixed_data<Scalar> Dirichlet,Neumann,Poisson;
+    bool use_intrinsic_delaunay = false;
+  };
+  // Precompute factorized solvers for computing a fast approximation of
+  // geodesic distances on a mesh (V,F). [Crane et al. 2013]
+  //
+  // Inputs:
+  //   V  #V by dim list of mesh vertex positions
+  //   F  #F by 3 list of mesh face indices into V
+  // Outputs:
+  //   data  precomputation data (see heat_geodesics_solve)
+  template < typename DerivedV, typename DerivedF, typename Scalar >
+  IGL_INLINE bool heat_geodesics_precompute(
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
+    HeatGeodesicsData<Scalar> & data);
+  // Inputs:
+  //   t  "heat" parameter (smaller --> more accurate, less stable)
+  template < typename DerivedV, typename DerivedF, typename Scalar >
+  IGL_INLINE bool heat_geodesics_precompute(
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
+    const Scalar t,
+    HeatGeodesicsData<Scalar> & data);
+  // Compute fast approximate geodesic distances using precomputed data from a
+  // set of selected source vertices (gamma)
+  //
+  // Inputs: 
+  //   data  precomputation data (see heat_geodesics_precompute)
+  //   gamma  #gamma list of indices into V of source vertices
+  // Outputs:
+  //   D  #V list of distances to gamma 
+  template < typename Scalar, typename Derivedgamma, typename DerivedD>
+  IGL_INLINE void heat_geodesics_solve(
+    const HeatGeodesicsData<Scalar> & data,
+    const Eigen::MatrixBase<Derivedgamma> & gamma,
+    Eigen::PlainObjectBase<DerivedD> & D);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "heat_geodesics.cpp"
+#endif
+
+#endif

+ 1 - 0
include/igl/internal_angles.cpp

@@ -127,4 +127,5 @@ template void igl::internal_angles<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen
 template void igl::internal_angles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > 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::internal_angles<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
 template void igl::internal_angles<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::internal_angles_using_squared_edge_lengths<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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 54 - 0
include/igl/intrinsic_delaunay_cotmatrix.cpp

@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "intrinsic_delaunay_cotmatrix.h"
+#include "edge_lengths.h"
+#include "intrinsic_delaunay_triangulation.h"
+#include "cotmatrix_intrinsic.h"
+#include <cassert>
+
+template <typename DerivedV, typename DerivedF, typename Scalar>
+IGL_INLINE void igl::intrinsic_delaunay_cotmatrix(
+  const Eigen::MatrixBase<DerivedV> & V, 
+  const Eigen::MatrixBase<DerivedF> & F, 
+  Eigen::SparseMatrix<Scalar>& L)
+{
+  Eigen::Matrix<Scalar, Eigen::Dynamic, 3> l_intrinsic;
+  DerivedF F_intrinsic;
+  return igl::intrinsic_delaunay_cotmatrix(V,F,L,l_intrinsic,F_intrinsic);
+}
+
+template <
+  typename DerivedV, 
+  typename DerivedF, 
+  typename Scalar,
+  typename Derivedl_intrinsic,
+  typename DerivedF_intrinsic>
+IGL_INLINE void igl::intrinsic_delaunay_cotmatrix(
+  const Eigen::MatrixBase<DerivedV> & V, 
+  const Eigen::MatrixBase<DerivedF> & F, 
+  Eigen::SparseMatrix<Scalar>& L,
+  Eigen::PlainObjectBase<Derivedl_intrinsic> & l_intrinsic,
+  Eigen::PlainObjectBase<DerivedF_intrinsic> & F_intrinsic)
+{
+  assert(F.cols() == 3 && "Only triangles are supported");
+  Eigen::Matrix<Scalar, Eigen::Dynamic, 3> l;
+  igl::edge_lengths(V,F,l);
+  igl::intrinsic_delaunay_triangulation(l,F,l_intrinsic,F_intrinsic);
+  igl::cotmatrix_intrinsic(l_intrinsic,F_intrinsic,L);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::intrinsic_delaunay_cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, 3, 0, -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, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::intrinsic_delaunay_cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+// generated by autoexplicit.sh
+template void igl::intrinsic_delaunay_cotmatrix<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+#endif

Some files were not shown because too many files changed in this diff