Browse Source

Merge branch 'dev' into icp

Alec Jacobson 6 years ago
parent
commit
6121d86961
100 changed files with 9543 additions and 1364 deletions
  1. 0 5
      .appveyor.yml
  2. 9 15
      .travis.yml
  3. 16 7
      CMakeLists.txt
  4. 540 0
      cmake/HunterGate.cmake
  5. 2 2
      cmake/LibiglDownloadExternal.cmake
  6. 8 0
      cmake/libigl-cgal.yml
  7. 50 23
      cmake/libigl.cmake
  8. 7 0
      include/igl/AABB.cpp
  9. 2 2
      include/igl/EPS.h
  10. 7400 0
      include/igl/FastWindingNumberForSoups.h
  11. 10 6
      include/igl/HalfEdgeIterator.cpp
  12. 6 6
      include/igl/HalfEdgeIterator.h
  13. 7 6
      include/igl/MappingEnergyType.h
  14. 1 1
      include/igl/active_set.cpp
  15. 14 14
      include/igl/ambient_occlusion.cpp
  16. 10 10
      include/igl/ambient_occlusion.h
  17. 15 9
      include/igl/arap_linear_block.cpp
  18. 8 8
      include/igl/arap_linear_block.h
  19. 18 12
      include/igl/arap_rhs.cpp
  20. 10 9
      include/igl/arap_rhs.h
  21. 2 2
      include/igl/average_onto_vertices.cpp
  22. 9 9
      include/igl/average_onto_vertices.h
  23. 2 0
      include/igl/barycenter.cpp
  24. 2 2
      include/igl/bfs.cpp
  25. 1 1
      include/igl/bfs.h
  26. 7 7
      include/igl/bfs_orient.cpp
  27. 2 2
      include/igl/bfs_orient.h
  28. 31 27
      include/igl/biharmonic_coordinates.cpp
  29. 4 4
      include/igl/biharmonic_coordinates.h
  30. 8 8
      include/igl/bijective_composite_harmonic_mapping.cpp
  31. 2 2
      include/igl/bone_parents.cpp
  32. 1 1
      include/igl/bone_parents.h
  33. 2 2
      include/igl/boundary_loop.cpp
  34. 1 1
      include/igl/bounding_box.cpp
  35. 1 2
      include/igl/bounding_box_diagonal.h
  36. 2 0
      include/igl/cat.cpp
  37. 6 2
      include/igl/circumradius.cpp
  38. 3 3
      include/igl/circumradius.h
  39. 20 19
      include/igl/colon.cpp
  40. 1 0
      include/igl/colormap.cpp
  41. 14 14
      include/igl/comb_cross_field.cpp
  42. 4 4
      include/igl/comb_cross_field.h
  43. 8 8
      include/igl/comb_frame_field.cpp
  44. 6 6
      include/igl/comb_frame_field.h
  45. 9 9
      include/igl/comb_line_field.cpp
  46. 3 6
      include/igl/comb_line_field.h
  47. 13 13
      include/igl/compute_frame_field_bisectors.cpp
  48. 10 10
      include/igl/compute_frame_field_bisectors.h
  49. 5 5
      include/igl/connect_boundary_to_infinity.cpp
  50. 4 4
      include/igl/connect_boundary_to_infinity.h
  51. 1 1
      include/igl/copyleft/cgal/orient2D.h
  52. 5 0
      include/igl/copyleft/cgal/point_areas.cpp
  53. 2 0
      include/igl/copyleft/cgal/point_areas.h
  54. 31 23
      include/igl/copyleft/comiso/nrosy.cpp
  55. 2 2
      include/igl/copyleft/quadprog.cpp
  56. 22 22
      include/igl/copyleft/tetgen/tetgenio_to_tetmesh.cpp
  57. 13 13
      include/igl/copyleft/tetgen/tetrahedralize.cpp
  58. 10 10
      include/igl/copyleft/tetgen/tetrahedralize.h
  59. 26 24
      include/igl/cross.cpp
  60. 15 15
      include/igl/cross_field_mismatch.cpp
  61. 4 4
      include/igl/cross_field_mismatch.h
  62. 11 11
      include/igl/crouzeix_raviart_cotmatrix.cpp
  63. 4 4
      include/igl/crouzeix_raviart_massmatrix.cpp
  64. 128 309
      include/igl/cut_mesh.cpp
  65. 46 45
      include/igl/cut_mesh.h
  66. 16 16
      include/igl/cut_mesh_from_singularities.cpp
  67. 3 3
      include/igl/cut_mesh_from_singularities.h
  68. 1 1
      include/igl/deprecated.h
  69. 6 6
      include/igl/dihedral_angles.cpp
  70. 4 4
      include/igl/dihedral_angles.h
  71. 51 0
      include/igl/dijkstra.cpp
  72. 26 2
      include/igl/dijkstra.h
  73. 7 7
      include/igl/directed_edge_orientations.cpp
  74. 7 7
      include/igl/directed_edge_orientations.h
  75. 8 6
      include/igl/directed_edge_parents.cpp
  76. 1 1
      include/igl/directed_edge_parents.h
  77. 7 7
      include/igl/dqs.cpp
  78. 7 7
      include/igl/dqs.h
  79. 6 6
      include/igl/ears.cpp
  80. 20 20
      include/igl/edge_topology.cpp
  81. 6 6
      include/igl/edge_topology.h
  82. 0 37
      include/igl/embree/Embree_convenience.h
  83. 3 3
      include/igl/euler_characteristic.cpp
  84. 2 2
      include/igl/euler_characteristic.h
  85. 4 4
      include/igl/exact_geodesic.cpp
  86. 2 2
      include/igl/facet_components.cpp
  87. 1 1
      include/igl/facet_components.h
  88. 421 287
      include/igl/fast_winding_number.cpp
  89. 134 37
      include/igl/fast_winding_number.h
  90. 42 16
      include/igl/file_dialog_open.cpp
  91. 38 11
      include/igl/file_dialog_save.cpp
  92. 14 14
      include/igl/find_cross_field_singularities.cpp
  93. 7 7
      include/igl/find_cross_field_singularities.h
  94. 4 4
      include/igl/gaussian_curvature.cpp
  95. 2 2
      include/igl/gaussian_curvature.h
  96. 13 12
      include/igl/harmonic.cpp
  97. 6 6
      include/igl/harmonic.h
  98. 13 13
      include/igl/hausdorff.cpp
  99. 13 13
      include/igl/hausdorff.h
  100. 12 3
      include/igl/heat_geodesics.cpp

+ 0 - 5
.appveyor.yml

@@ -11,18 +11,13 @@ environment:
   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:
-  - cinstall: python
 build:
   parallel: true
 build_script:
   - cd c:\projects\libigl
   # Tutorials and tests
-  - set PATH=C:\Python%PYTHON%-x64;C:\Python%PYTHON%-x64\Scripts;%PATH%
   - mkdir build
   - cd build
   - cmake -DCMAKE_BUILD_TYPE=%CONFIG%

+ 9 - 15
.travis.yml

@@ -16,8 +16,6 @@ addons:
     - libglu1-mesa-dev
     - liblapack-dev
     - libmpfr-dev
-    - libpython3-dev
-    - python3-setuptools
     - xorg-dev
   homebrew:
     packages:
@@ -27,28 +25,27 @@ matrix:
   - os: linux
     compiler: gcc # 4.8.4 by default on Trusty
     env:
-    - MATRIX_EVAL="export CONFIG=Release PYTHON=python3"
+    - MATRIX_EVAL="export CONFIG=Release"
   - os: linux
     compiler: gcc-7
     env:
-    - MATRIX_EVAL="export CC=gcc-7 CXX=g++-7 CONFIG=Release PYTHON=python3"
+    - MATRIX_EVAL="export CC=gcc-7 CXX=g++-7 CONFIG=Release"
   - 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'"
+    - MATRIX_EVAL="export CC=gcc-7 CXX=g++-7 CONFIG=Release CMAKE_EXTRA='-DLIBIGL_USE_STATIC_LIBRARY=OFF'"
   - os: osx
+    osx_image: xcode10.2
     compiler: clang
     env:
-    - MATRIX_EVAL="export CONFIG=Debug PYTHON=python3 LIBIGL_NUM_THREADS=1"
+    - MATRIX_EVAL="export CONFIG=Debug LIBIGL_NUM_THREADS=1"
   - os: osx # same config like above but with -DLIBIGL_USE_STATIC_LIBRARY=OFF to test static and header-only builds
+    osx_image: xcode10.2
     compiler: clang
     env:
-    - MATRIX_EVAL="export CONFIG=Debug PYTHON=python3 LIBIGL_NUM_THREADS=1 CMAKE_EXTRA='-DLIBIGL_USE_STATIC_LIBRARY=OFF'"
+    - MATRIX_EVAL="export CONFIG=Debug LIBIGL_NUM_THREADS=1 CMAKE_EXTRA='-DLIBIGL_USE_STATIC_LIBRARY=OFF'"
   - os: osx
+    osx_image: xcode10.2
     compiler: clang
     env:
     - MATRIX_EVAL="export CONFIG=Debug PYTHON=python3 LIBIGL_NUM_THREADS=1 CMAKE_EXTRA='-DLIBIGL_EIGEN_VERSION=3.3.7'""
@@ -71,8 +68,5 @@ script:
 - make -j 2
 - ctest --verbose
 - popd
-- pushd python/tutorial
-- ${PYTHON} 101_FileIO.py
-- popd
 - rm -rf build
-- ccache --show-stats
+- ccache --show-stats

+ 16 - 7
CMakeLists.txt

@@ -1,4 +1,14 @@
 cmake_minimum_required(VERSION 3.1)
+
+# Toggles the use of the hunter package manager
+option(HUNTER_ENABLED "Enable Hunter package manager support" OFF)
+
+include("cmake/HunterGate.cmake")
+HunterGate(
+    URL "https://github.com/ruslo/hunter/archive/v0.23.171.tar.gz"
+    SHA1 "5d68bcca78eee347239ca5f4d34f4b6c12683154"
+)
+
 project(libigl)
 
 # Detects whether this is a top-level project
@@ -9,10 +19,9 @@ else()
 	set(LIBIGL_TOPLEVEL_PROJECT OFF)
 endif()
 
-# Build tests, tutorials and python bindings
+# Build tests and tutorials
 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,
@@ -32,9 +41,13 @@ 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})
+option(LIBIGL_WITH_PYTHON            "Use Python"                   OFF)
 ### End
 
+if(${LIBIGL_WITH_PYTHON})
+	MESSAGE(FATAL_ERROR "Python binding are in the process of being redone. Please use the master branch or refer to https://github.com/geometryprocessing/libigl-python-bindings for the developement version or https://anaconda.org/conda-forge/igl for the stable version.")
+endif()
+
 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
@@ -54,7 +67,3 @@ if(LIBIGL_BUILD_TESTS)
 	enable_testing()
 	add_subdirectory(tests)
 endif()
-
-if(LIBIGL_WITH_PYTHON)
-	add_subdirectory(python)
-endif()

+ 540 - 0
cmake/HunterGate.cmake

@@ -0,0 +1,540 @@
+# Copyright (c) 2013-2018, Ruslan Baratov
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+#   list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This is a gate file to Hunter package manager.
+# Include this file using `include` command and add package you need, example:
+#
+#     cmake_minimum_required(VERSION 3.2)
+#
+#     include("cmake/HunterGate.cmake")
+#     HunterGate(
+#         URL "https://github.com/path/to/hunter/archive.tar.gz"
+#         SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d"
+#     )
+#
+#     project(MyProject)
+#
+#     hunter_add_package(Foo)
+#     hunter_add_package(Boo COMPONENTS Bar Baz)
+#
+# Projects:
+#     * https://github.com/hunter-packages/gate/
+#     * https://github.com/ruslo/hunter
+
+option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
+
+if(HUNTER_ENABLED)
+  if(CMAKE_VERSION VERSION_LESS "3.2")
+    message(
+        FATAL_ERROR
+        "At least CMake version 3.2 required for Hunter dependency management."
+        " Update CMake or set HUNTER_ENABLED to OFF."
+    )
+  endif()
+endif()
+
+include(CMakeParseArguments) # cmake_parse_arguments
+
+option(HUNTER_STATUS_PRINT "Print working status" ON)
+option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
+option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
+
+set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki")
+
+function(hunter_gate_status_print)
+  if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
+    foreach(print_message ${ARGV})
+      message(STATUS "[hunter] ${print_message}")
+    endforeach()
+  endif()
+endfunction()
+
+function(hunter_gate_status_debug)
+  if(HUNTER_STATUS_DEBUG)
+    foreach(print_message ${ARGV})
+      string(TIMESTAMP timestamp)
+      message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}")
+    endforeach()
+  endif()
+endfunction()
+
+function(hunter_gate_wiki wiki_page)
+  message("------------------------------ WIKI -------------------------------")
+  message("    ${HUNTER_WIKI}/${wiki_page}")
+  message("-------------------------------------------------------------------")
+  message("")
+  message(FATAL_ERROR "")
+endfunction()
+
+function(hunter_gate_internal_error)
+  message("")
+  foreach(print_message ${ARGV})
+    message("[hunter ** INTERNAL **] ${print_message}")
+  endforeach()
+  message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
+  message("")
+  hunter_gate_wiki("error.internal")
+endfunction()
+
+function(hunter_gate_fatal_error)
+  cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}")
+  string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki)
+  if(have_no_wiki)
+    hunter_gate_internal_error("Expected wiki")
+  endif()
+  message("")
+  foreach(x ${hunter_UNPARSED_ARGUMENTS})
+    message("[hunter ** FATAL ERROR **] ${x}")
+  endforeach()
+  message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
+  message("")
+  hunter_gate_wiki("${hunter_WIKI}")
+endfunction()
+
+function(hunter_gate_user_error)
+  hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data")
+endfunction()
+
+function(hunter_gate_self root version sha1 result)
+  string(COMPARE EQUAL "${root}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("root is empty")
+  endif()
+
+  string(COMPARE EQUAL "${version}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("version is empty")
+  endif()
+
+  string(COMPARE EQUAL "${sha1}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("sha1 is empty")
+  endif()
+
+  string(SUBSTRING "${sha1}" 0 7 archive_id)
+
+  if(EXISTS "${root}/cmake/Hunter")
+    set(hunter_self "${root}")
+  else()
+    set(
+        hunter_self
+        "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked"
+    )
+  endif()
+
+  set("${result}" "${hunter_self}" PARENT_SCOPE)
+endfunction()
+
+# Set HUNTER_GATE_ROOT cmake variable to suitable value.
+function(hunter_gate_detect_root)
+  # Check CMake variable
+  string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty)
+  if(not_empty)
+    set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable")
+    return()
+  endif()
+
+  # Check environment variable
+  string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty)
+  if(not_empty)
+    set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT detected by environment variable")
+    return()
+  endif()
+
+  # Check HOME environment variable
+  string(COMPARE NOTEQUAL "$ENV{HOME}" "" result)
+  if(result)
+    set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable")
+    return()
+  endif()
+
+  # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only)
+  if(WIN32)
+    string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result)
+    if(result)
+      set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE)
+      hunter_gate_status_debug(
+          "HUNTER_ROOT set using SYSTEMDRIVE environment variable"
+      )
+      return()
+    endif()
+
+    string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result)
+    if(result)
+      set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE)
+      hunter_gate_status_debug(
+          "HUNTER_ROOT set using USERPROFILE environment variable"
+      )
+      return()
+    endif()
+  endif()
+
+  hunter_gate_fatal_error(
+      "Can't detect HUNTER_ROOT"
+      WIKI "error.detect.hunter.root"
+  )
+endfunction()
+
+function(hunter_gate_download dir)
+  string(
+      COMPARE
+      NOTEQUAL
+      "$ENV{HUNTER_DISABLE_AUTOINSTALL}"
+      ""
+      disable_autoinstall
+  )
+  if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL)
+    hunter_gate_fatal_error(
+        "Hunter not found in '${dir}'"
+        "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'"
+        "Settings:"
+        "  HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
+        "  HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
+        WIKI "error.run.install"
+    )
+  endif()
+  string(COMPARE EQUAL "${dir}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("Empty 'dir' argument")
+  endif()
+
+  string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("HUNTER_GATE_SHA1 empty")
+  endif()
+
+  string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("HUNTER_GATE_URL empty")
+  endif()
+
+  set(done_location "${dir}/DONE")
+  set(sha1_location "${dir}/SHA1")
+
+  set(build_dir "${dir}/Build")
+  set(cmakelists "${dir}/CMakeLists.txt")
+
+  hunter_gate_status_debug("Locking directory: ${dir}")
+  file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
+  hunter_gate_status_debug("Lock done")
+
+  if(EXISTS "${done_location}")
+    # while waiting for lock other instance can do all the job
+    hunter_gate_status_debug("File '${done_location}' found, skip install")
+    return()
+  endif()
+
+  file(REMOVE_RECURSE "${build_dir}")
+  file(REMOVE_RECURSE "${cmakelists}")
+
+  file(MAKE_DIRECTORY "${build_dir}") # check directory permissions
+
+  # Disabling languages speeds up a little bit, reduces noise in the output
+  # and avoids path too long windows error
+  file(
+      WRITE
+      "${cmakelists}"
+      "cmake_minimum_required(VERSION 3.2)\n"
+      "project(HunterDownload LANGUAGES NONE)\n"
+      "include(ExternalProject)\n"
+      "ExternalProject_Add(\n"
+      "    Hunter\n"
+      "    URL\n"
+      "    \"${HUNTER_GATE_URL}\"\n"
+      "    URL_HASH\n"
+      "    SHA1=${HUNTER_GATE_SHA1}\n"
+      "    DOWNLOAD_DIR\n"
+      "    \"${dir}\"\n"
+      "    TLS_VERIFY\n"
+      "    ${HUNTER_TLS_VERIFY}\n"
+      "    SOURCE_DIR\n"
+      "    \"${dir}/Unpacked\"\n"
+      "    CONFIGURE_COMMAND\n"
+      "    \"\"\n"
+      "    BUILD_COMMAND\n"
+      "    \"\"\n"
+      "    INSTALL_COMMAND\n"
+      "    \"\"\n"
+      ")\n"
+  )
+
+  if(HUNTER_STATUS_DEBUG)
+    set(logging_params "")
+  else()
+    set(logging_params OUTPUT_QUIET)
+  endif()
+
+  hunter_gate_status_debug("Run generate")
+
+  # Need to add toolchain file too.
+  # Otherwise on Visual Studio + MDD this will fail with error:
+  # "Could not find an appropriate version of the Windows 10 SDK installed on this machine"
+  if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
+    get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE)
+    set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}")
+  else()
+    # 'toolchain_arg' can't be empty
+    set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=")
+  endif()
+
+  string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make)
+  if(no_make)
+    set(make_arg "")
+  else()
+    # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM
+    set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}")
+  endif()
+
+  execute_process(
+      COMMAND
+      "${CMAKE_COMMAND}"
+      "-H${dir}"
+      "-B${build_dir}"
+      "-G${CMAKE_GENERATOR}"
+      "${toolchain_arg}"
+      ${make_arg}
+      WORKING_DIRECTORY "${dir}"
+      RESULT_VARIABLE download_result
+      ${logging_params}
+  )
+
+  if(NOT download_result EQUAL 0)
+    hunter_gate_internal_error(
+        "Configure project failed."
+        "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}"
+        "In directory ${dir}"
+    )
+  endif()
+
+  hunter_gate_status_print(
+      "Initializing Hunter workspace (${HUNTER_GATE_SHA1})"
+      "  ${HUNTER_GATE_URL}"
+      "  -> ${dir}"
+  )
+  execute_process(
+      COMMAND "${CMAKE_COMMAND}" --build "${build_dir}"
+      WORKING_DIRECTORY "${dir}"
+      RESULT_VARIABLE download_result
+      ${logging_params}
+  )
+
+  if(NOT download_result EQUAL 0)
+    hunter_gate_internal_error("Build project failed")
+  endif()
+
+  file(REMOVE_RECURSE "${build_dir}")
+  file(REMOVE_RECURSE "${cmakelists}")
+
+  file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}")
+  file(WRITE "${done_location}" "DONE")
+
+  hunter_gate_status_debug("Finished")
+endfunction()
+
+# Must be a macro so master file 'cmake/Hunter' can
+# apply all variables easily just by 'include' command
+# (otherwise PARENT_SCOPE magic needed)
+macro(HunterGate)
+  if(HUNTER_GATE_DONE)
+    # variable HUNTER_GATE_DONE set explicitly for external project
+    # (see `hunter_download`)
+    set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
+  endif()
+
+  # First HunterGate command will init Hunter, others will be ignored
+  get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET)
+
+  if(NOT HUNTER_ENABLED)
+    # Empty function to avoid error "unknown function"
+    function(hunter_add_package)
+    endfunction()
+
+    set(
+        _hunter_gate_disabled_mode_dir
+        "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode"
+    )
+    if(EXISTS "${_hunter_gate_disabled_mode_dir}")
+      hunter_gate_status_debug(
+          "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}"
+      )
+      list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}")
+    endif()
+  elseif(_hunter_gate_done)
+    hunter_gate_status_debug("Secondary HunterGate (use old settings)")
+    hunter_gate_self(
+        "${HUNTER_CACHED_ROOT}"
+        "${HUNTER_VERSION}"
+        "${HUNTER_SHA1}"
+        _hunter_self
+    )
+    include("${_hunter_self}/cmake/Hunter")
+  else()
+    set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}")
+
+    string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name)
+    if(_have_project_name)
+      hunter_gate_fatal_error(
+          "Please set HunterGate *before* 'project' command. "
+          "Detected project: ${PROJECT_NAME}"
+          WIKI "error.huntergate.before.project"
+      )
+    endif()
+
+    cmake_parse_arguments(
+        HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV}
+    )
+
+    string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1)
+    string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url)
+    string(
+        COMPARE
+        NOTEQUAL
+        "${HUNTER_GATE_UNPARSED_ARGUMENTS}"
+        ""
+        _have_unparsed
+    )
+    string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global)
+    string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath)
+
+    if(_have_unparsed)
+      hunter_gate_user_error(
+          "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}"
+      )
+    endif()
+    if(_empty_sha1)
+      hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory")
+    endif()
+    if(_empty_url)
+      hunter_gate_user_error("URL suboption of HunterGate is mandatory")
+    endif()
+    if(_have_global)
+      if(HUNTER_GATE_LOCAL)
+        hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)")
+      endif()
+      if(_have_filepath)
+        hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)")
+      endif()
+    endif()
+    if(HUNTER_GATE_LOCAL)
+      if(_have_global)
+        hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)")
+      endif()
+      if(_have_filepath)
+        hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)")
+      endif()
+    endif()
+    if(_have_filepath)
+      if(_have_global)
+        hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)")
+      endif()
+      if(HUNTER_GATE_LOCAL)
+        hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)")
+      endif()
+    endif()
+
+    hunter_gate_detect_root() # set HUNTER_GATE_ROOT
+
+    # Beautify path, fix probable problems with windows path slashes
+    get_filename_component(
+        HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE
+    )
+    hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}")
+    if(NOT HUNTER_ALLOW_SPACES_IN_PATH)
+      string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces)
+      if(NOT _contain_spaces EQUAL -1)
+        hunter_gate_fatal_error(
+            "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
+            "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
+            "(Use at your own risk!)"
+            WIKI "error.spaces.in.hunter.root"
+        )
+      endif()
+    endif()
+
+    string(
+        REGEX
+        MATCH
+        "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*"
+        HUNTER_GATE_VERSION
+        "${HUNTER_GATE_URL}"
+    )
+    string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty)
+    if(_is_empty)
+      set(HUNTER_GATE_VERSION "unknown")
+    endif()
+
+    hunter_gate_self(
+        "${HUNTER_GATE_ROOT}"
+        "${HUNTER_GATE_VERSION}"
+        "${HUNTER_GATE_SHA1}"
+        _hunter_self
+    )
+
+    set(_master_location "${_hunter_self}/cmake/Hunter")
+    if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter")
+      # Hunter downloaded manually (e.g. by 'git clone')
+      set(_unused "xxxxxxxxxx")
+      set(HUNTER_GATE_SHA1 "${_unused}")
+      set(HUNTER_GATE_VERSION "${_unused}")
+    else()
+      get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
+      set(_done_location "${_archive_id_location}/DONE")
+      set(_sha1_location "${_archive_id_location}/SHA1")
+
+      # Check Hunter already downloaded by HunterGate
+      if(NOT EXISTS "${_done_location}")
+        hunter_gate_download("${_archive_id_location}")
+      endif()
+
+      if(NOT EXISTS "${_done_location}")
+        hunter_gate_internal_error("hunter_gate_download failed")
+      endif()
+
+      if(NOT EXISTS "${_sha1_location}")
+        hunter_gate_internal_error("${_sha1_location} not found")
+      endif()
+      file(READ "${_sha1_location}" _sha1_value)
+      string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal)
+      if(NOT _is_equal)
+        hunter_gate_internal_error(
+            "Short SHA1 collision:"
+            "  ${_sha1_value} (from ${_sha1_location})"
+            "  ${HUNTER_GATE_SHA1} (HunterGate)"
+        )
+      endif()
+      if(NOT EXISTS "${_master_location}")
+        hunter_gate_user_error(
+            "Master file not found:"
+            "  ${_master_location}"
+            "try to update Hunter/HunterGate"
+        )
+      endif()
+    endif()
+    include("${_master_location}")
+    set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
+  endif()
+endmacro()

+ 2 - 2
cmake/LibiglDownloadExternal.cmake

@@ -64,7 +64,7 @@ function(igl_download_cork)
 endfunction()
 
 ## Eigen
-set(LIBIGL_EIGEN_VERSION 3.2.10 CACHE STRING "Default version of Eigen used by libigl.")
+set(LIBIGL_EIGEN_VERSION 3.3.7 CACHE STRING "Default version of Eigen used by libigl.")
 function(igl_download_eigen)
 	igl_download_project(eigen
 		GIT_REPOSITORY https://github.com/eigenteam/eigen-git-mirror.git
@@ -175,7 +175,7 @@ function(igl_download_test_data)
 	igl_download_project_aux(test_data
 		"${LIBIGL_EXTERNAL}/../tests/data"
 		GIT_REPOSITORY https://github.com/libigl/libigl-tests-data
-		GIT_TAG        adc66cabf712a0bd68ac182b4e7f8b5ba009c3dd
+		GIT_TAG        5994ecdab65aebc6c218c4c6f35e7822acf6fe99
 	)
 endfunction()
 

+ 8 - 0
cmake/libigl-cgal.yml

@@ -0,0 +1,8 @@
+# This is a conda environment that can be used to compile libigl with CGAL on Windows
+# Only boost is required to be installed on the system, CGAL is automatically downloaded
+# by CMake and is built with libigl.
+name: libigl-cgal
+channels:
+  - conda-forge
+dependencies:
+  - boost-cpp=1.65.0

+ 50 - 23
cmake/libigl.cmake

@@ -34,10 +34,13 @@ 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)
 
+if(LIBIGL_BUILD_PYTHON)
+  message(FATAL_ERROR "Python bindings have been removed in this version. Please use an older version of libigl, or wait for the new bindings to be released.")
+endif()
+
 ################################################################################
 
 ### Configuration
@@ -90,22 +93,28 @@ if(BUILD_SHARED_LIBS)
   set_target_properties(igl_common PROPERTIES INTERFACE_POSITION_INDEPENDENT_CODE ON)
 endif()
 
-if(UNIX)
+if(UNIX AND NOT HUNTER_ENABLED)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
 endif()
 
+if(HUNTER_ENABLED)
+  hunter_add_package(Eigen)
+  find_package(Eigen3 CONFIG REQUIRED)
+endif()
+
 # Eigen
-if(TARGET Eigen3::Eigen)
-  # If an imported target already exists, use it
-  target_link_libraries(igl_common INTERFACE Eigen3::Eigen)
-else()
+if(NOT TARGET Eigen3::Eigen)
   igl_download_eigen()
-  target_include_directories(igl_common SYSTEM INTERFACE
+  add_library(igl_eigen INTERFACE)
+  target_include_directories(igl_eigen SYSTEM INTERFACE
     $<BUILD_INTERFACE:${LIBIGL_EXTERNAL}/eigen>
     $<INSTALL_INTERFACE:include>
   )
+  set_property(TARGET igl_eigen PROPERTY EXPORT_NAME Eigen3::Eigen)
+  add_library(Eigen3::Eigen ALIAS igl_eigen)
 endif()
+target_link_libraries(igl_common INTERFACE Eigen3::Eigen)
 
 # C++11 Thread library
 find_package(Threads REQUIRED)
@@ -148,7 +157,20 @@ function(compile_igl_module module_dir)
     endif()
     add_library(${module_libname} STATIC ${SOURCES_IGL_${module_name}} ${ARGN})
     if(MSVC)
-      target_compile_options(${module_libname} PRIVATE /w) # disable all warnings (not ideal but...)
+      # Silencing some compile warnings
+      target_compile_options(${module_libname} PRIVATE
+        # Type conversion warnings. These can be fixed with some effort and possibly more verbose code.
+        /wd4267 # conversion from 'size_t' to 'type', possible loss of data
+        /wd4244 # conversion from 'type1' to 'type2', possible loss of data
+        /wd4018 # signed/unsigned mismatch
+        /wd4305 # truncation from 'double' to 'float'
+        # This one is from template instantiations generated by autoexplicit.sh:
+        /wd4667 # no function template defined that matches forced instantiation ()
+        # This one is easy to fix, just need to switch to safe version of C functions
+        /wd4996 # this function or variable may be unsafe
+        # This one is when using bools in adjacency matrices
+        /wd4804 #'+=': unsafe use of type 'bool' in operation
+      )
     else()
       #target_compile_options(${module_libname} PRIVATE -w) # disable all warnings (not ideal but...)
     endif()
@@ -182,7 +204,6 @@ compile_igl_module("core" ${SOURCES_IGL})
 ################################################################################
 ### Download the python part ###
 if(LIBIGL_WITH_PYTHON)
-  igl_download_pybind11()
 endif()
 
 ################################################################################
@@ -198,11 +219,8 @@ if(LIBIGL_WITH_CGAL)
     if(EXISTS ${LIBIGL_EXTERNAL}/boost)
       set(BOOST_ROOT "${LIBIGL_EXTERNAL}/boost")
     endif()
-    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()
+    option(CGAL_Boost_USE_STATIC_LIBS "Use static Boost libs with CGAL" ON)
+
     find_package(CGAL CONFIG COMPONENTS Core PATHS ${CGAL_DIR} NO_DEFAULT_PATH)
   endif()
 
@@ -285,7 +303,7 @@ if(LIBIGL_WITH_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")
+    add_subdirectory("${EMBREE_DIR}" "embree" EXCLUDE_FROM_ALL)
   endif()
 
   compile_igl_module("embree")
@@ -483,21 +501,30 @@ endfunction()
 include(GNUInstallDirs)
 include(CMakePackageConfigHelpers)
 
+if(TARGET igl_eigen)
+  set(IGL_EIGEN igl_eigen)
+else()
+  set(IGL_EIGEN)
+  message(WARNING "Trying to export igl targets while using an imported target for Eigen.")
+endif()
+
 # Install and export core library
 install(
-   TARGETS
-     igl
-     igl_common
-   EXPORT igl-export
-   PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
-   LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-   RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
-   ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  TARGETS
+    igl
+    igl_common
+    ${IGL_EIGEN}
+  EXPORT igl-export
+  PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
 )
 export(
   TARGETS
     igl
     igl_common
+    ${IGL_EIGEN}
   FILE libigl-export.cmake
 )
 

+ 7 - 0
include/igl/AABB.cpp

@@ -1076,6 +1076,13 @@ template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_di
 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;
+
+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 void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::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 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;
+template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> >(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::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, bool) 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;

+ 2 - 2
include/igl/EPS.h

@@ -13,8 +13,8 @@ namespace igl
   // Define a standard value for double epsilon
   const double DOUBLE_EPS    = 1.0e-14;
   const double DOUBLE_EPS_SQ = 1.0e-28;
-  const float FLOAT_EPS    = 1.0e-7;
-  const float FLOAT_EPS_SQ = 1.0e-14;
+  const float FLOAT_EPS    = 1.0e-7f;
+  const float FLOAT_EPS_SQ = 1.0e-14f;
   // Function returning EPS for corresponding type
   template <typename S_type> IGL_INLINE S_type EPS();
   template <typename S_type> IGL_INLINE S_type EPS_SQ();

+ 7400 - 0
include/igl/FastWindingNumberForSoups.h

@@ -0,0 +1,7400 @@
+// This header created by issuing: `echo "// This header created by issuing: \`$BASH_COMMAND\` $(echo "" | cat - LICENSE README.md | sed -e "s#^..*#\/\/ &#") $(echo "" | cat - SYS_Types.h SYS_Math.h VM_SSEFunc.h VM_SIMD.h UT_Array.h UT_ArrayImpl.h UT_SmallArray.h UT_FixedVector.h UT_ParallelUtil.h UT_BVH.h UT_BVHImpl.h UT_SolidAngle.h UT_Array.cpp UT_SolidAngle.cpp | sed -e "s/^#.*include  *\".*$//g")" > ../FastWindingNumberForSoups.h` 
+// MIT License
+
+// Copyright (c) 2018 Side Effects Software Inc.
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+// # Fast Winding Numbers for Soups
+
+// https://github.com/alecjacobson/WindingNumber
+
+// Implementation of the _ACM SIGGRAPH_ 2018 paper, 
+
+// "Fast Winding Numbers for Soups and Clouds" 
+
+// Gavin Barill¹, Neil Dickson², Ryan Schmidt³, David I.W. Levin¹, Alec Jacobson¹
+
+// ¹University of Toronto, ²SideFX, ³Gradient Space
+
+
+// _Note: this implementation is for triangle soups only, not point clouds._
+
+// This version does _not_ depend on Intel TBB. Instead it depends on
+// [libigl](https://github.com/libigl/libigl)'s simpler `igl::parallel_for` (which
+// uses `std::thread`)
+
+// <del>This code, as written, depends on Intel's Threading Building Blocks (TBB) library for parallelism, but it should be fairly easy to change it to use any other means of threading, since it only uses parallel for loops with simple partitioning.</del>
+
+// The main class of interest is UT_SolidAngle and its init and computeSolidAngle functions, which you can use by including UT_SolidAngle.h, and whose implementation is mostly in UT_SolidAngle.cpp, using a 4-way bounding volume hierarchy (BVH) implemented in the UT_BVH.h and UT_BVHImpl.h headers.  The rest of the files are mostly various supporting code.  UT_SubtendedAngle, for computing angles subtended by 2D curves, can also be found in UT_SolidAngle.h and UT_SolidAngle.cpp .
+
+// An example of very similar code and how to use it to create a geometry operator (SOP) in Houdini can be found in the HDK examples (toolkit/samples/SOP/SOP_WindingNumber) for Houdini 16.5.121 and later.  Query points go in the first input and the mesh geometry goes in the second input.
+
+
+// Create a single header using:
+
+//     echo "// This header created by issuing: \`$BASH_COMMAND\` $(echo "" | cat - LICENSE README.md | sed -e "s#^..*#\/\/&#") $(echo "" | cat - SYS_Types.h SYS_Math.h VM_SSEFunc.h VM_SIMD.h UT_Array.h UT_ArrayImpl.h UT_SmallArray.h UT_FixedVector.h UT_ParallelUtil.h UT_BVH.h UT_BVHImpl.h UT_SolidAngle.h UT_Array.cpp UT_SolidAngle.cpp | sed -e "s/^#.*include  *\".*$//g")" 
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      Common type definitions.
+ */
+
+#pragma once
+
+#ifndef __SYS_Types__
+#define __SYS_Types__
+
+/* Include system types */
+#include <limits>
+#include <type_traits>
+#include <sys/types.h>
+#include <stdint.h>
+
+namespace igl { namespace FastWindingNumber {
+
+/*
+ * Integer types
+ */
+typedef signed char	int8;
+typedef	unsigned char	uint8;
+typedef short		int16;
+typedef unsigned short	uint16;
+typedef	int		int32;
+typedef unsigned int	uint32;
+
+#ifndef MBSD
+typedef unsigned int	uint;
+#endif
+
+/*
+ * Avoid using uint64.
+ * The extra bit of precision is NOT worth the cost in pain and suffering
+ * induced by use of unsigned.
+ */
+#if defined(_WIN32)
+    typedef __int64		int64;
+    typedef unsigned __int64	uint64;
+#elif defined(MBSD)
+    // On MBSD, int64/uint64 are also defined in the system headers so we must
+    // declare these in the same way or else we get conflicts.
+    typedef int64_t		int64;
+    typedef uint64_t		uint64;
+#elif defined(AMD64)
+    typedef long		int64;
+    typedef unsigned long	uint64;
+#else
+    typedef long long		int64;
+    typedef unsigned long long	uint64;
+#endif
+
+/// The problem with int64 is that it implies that it is a fixed 64-bit quantity
+/// that is saved to disk. Therefore, we need another integral type for
+/// indexing our arrays.
+typedef int64 exint;
+
+/// Mark function to be inlined. If this is done, taking the address of such
+/// a function is not allowed.
+#if defined(__GNUC__) || defined(__clang__)
+#define SYS_FORCE_INLINE	__attribute__ ((always_inline)) inline
+#elif defined(_MSC_VER)
+#define SYS_FORCE_INLINE	__forceinline
+#else
+#define SYS_FORCE_INLINE	inline
+#endif
+
+/// Floating Point Types
+typedef float   fpreal32;
+typedef double  fpreal64;
+
+/// SYS_FPRealUnionT for type-safe casting with integral types
+template <typename T>
+union SYS_FPRealUnionT;
+
+template <>
+union SYS_FPRealUnionT<fpreal32>
+{
+    typedef int32	int_type;
+    typedef uint32	uint_type;
+    typedef fpreal32	fpreal_type;
+
+    enum {
+	EXPONENT_BITS = 8,
+	MANTISSA_BITS = 23,
+	EXPONENT_BIAS = 127 };
+
+    int_type		ival;
+    uint_type		uval;
+    fpreal_type		fval;
+    
+    struct
+    {
+	uint_type mantissa_val: 23;
+	uint_type exponent_val: 8;
+	uint_type sign_val: 1;
+    };
+};
+
+template <>
+union SYS_FPRealUnionT<fpreal64>
+{
+    typedef int64	int_type;
+    typedef uint64	uint_type;
+    typedef fpreal64	fpreal_type;
+
+    enum {
+	EXPONENT_BITS = 11,
+	MANTISSA_BITS = 52,
+	EXPONENT_BIAS = 1023 };
+
+    int_type		ival;
+    uint_type		uval;
+    fpreal_type		fval;
+    
+    struct
+    {
+	uint_type mantissa_val: 52;
+	uint_type exponent_val: 11;
+	uint_type sign_val: 1;
+    };
+};
+
+typedef union SYS_FPRealUnionT<fpreal32>    SYS_FPRealUnionF;
+typedef union SYS_FPRealUnionT<fpreal64>    SYS_FPRealUnionD;
+
+/// Asserts are disabled
+/// @{
+#define UT_ASSERT_P(ZZ)         ((void)0)
+#define UT_ASSERT(ZZ)           ((void)0)
+#define UT_ASSERT_MSG_P(ZZ, MM) ((void)0)
+#define UT_ASSERT_MSG(ZZ, MM)   ((void)0)
+/// @}
+}}
+
+#endif
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      Miscellaneous math functions. 
+ */
+
+#pragma once
+
+#ifndef __SYS_Math__
+#define __SYS_Math__
+
+
+
+#include <float.h>
+#include <limits>
+#include <math.h>
+
+namespace igl { namespace FastWindingNumber {
+
+// NOTE:
+// These have been carefully written so that in the case of equality
+// we always return the first parameter.  This is so that NANs in
+// in the second parameter are suppressed.
+#define h_min(a, b)	(((a) > (b)) ? (b) : (a))
+#define h_max(a, b)	(((a) < (b)) ? (b) : (a))
+// DO NOT CHANGE THE ABOVE WITHOUT READING THE COMMENT
+#define h_abs(a)	(((a) > 0) ? (a) : -(a))
+
+static constexpr inline  int16 SYSmin(int16 a, int16 b)		{ return h_min(a,b); }
+static constexpr inline  int16 SYSmax(int16 a, int16 b)		{ return h_max(a,b); }
+static constexpr inline  int16 SYSabs(int16 a)			{ return h_abs(a); }
+static constexpr inline  int32 SYSmin(int32 a, int32 b)		{ return h_min(a,b); }
+static constexpr inline  int32 SYSmax(int32 a, int32 b)		{ return h_max(a,b); }
+static constexpr inline  int32 SYSabs(int32 a)			{ return h_abs(a); }
+static constexpr inline  int64 SYSmin(int64 a, int64 b)		{ return h_min(a,b); }
+static constexpr inline  int64 SYSmax(int64 a, int64 b)		{ return h_max(a,b); }
+static constexpr inline  int64 SYSmin(int32 a, int64 b)		{ return h_min(a,b); }
+static constexpr inline  int64 SYSmax(int32 a, int64 b)		{ return h_max(a,b); }
+static constexpr inline  int64 SYSmin(int64 a, int32 b)		{ return h_min(a,b); }
+static constexpr inline  int64 SYSmax(int64 a, int32 b)		{ return h_max(a,b); }
+static constexpr inline  int64 SYSabs(int64 a)			{ return h_abs(a); }
+static constexpr inline uint16 SYSmin(uint16 a, uint16 b)		{ return h_min(a,b); }
+static constexpr inline uint16 SYSmax(uint16 a, uint16 b)		{ return h_max(a,b); }
+static constexpr inline uint32 SYSmin(uint32 a, uint32 b)		{ return h_min(a,b); }
+static constexpr inline uint32 SYSmax(uint32 a, uint32 b)		{ return h_max(a,b); }
+static constexpr inline uint64 SYSmin(uint64 a, uint64 b)		{ return h_min(a,b); }
+static constexpr inline uint64 SYSmax(uint64 a, uint64 b)		{ return h_max(a,b); }
+static constexpr inline fpreal32 SYSmin(fpreal32 a, fpreal32 b)	{ return h_min(a,b); }
+static constexpr inline fpreal32 SYSmax(fpreal32 a, fpreal32 b)	{ return h_max(a,b); }
+static constexpr inline fpreal64 SYSmin(fpreal64 a, fpreal64 b)	{ return h_min(a,b); }
+static constexpr inline fpreal64 SYSmax(fpreal64 a, fpreal64 b)	{ return h_max(a,b); }
+
+// Some systems have size_t as a seperate type from uint.  Some don't.
+#if (defined(LINUX) && defined(IA64)) || defined(MBSD)
+static constexpr inline size_t SYSmin(size_t a, size_t b)		{ return h_min(a,b); }
+static constexpr inline size_t SYSmax(size_t a, size_t b)		{ return h_max(a,b); }
+#endif
+
+#undef h_min
+#undef h_max
+#undef h_abs
+
+#define h_clamp(val, min, max, tol)	\
+	    ((val <= min+tol) ? min : ((val >= max-tol) ? max : val))
+
+    static constexpr inline int
+    SYSclamp(int v, int min, int max)
+	{ return h_clamp(v, min, max, 0); }
+
+    static constexpr inline uint
+    SYSclamp(uint v, uint min, uint max)
+	{ return h_clamp(v, min, max, 0); }
+
+    static constexpr inline int64
+    SYSclamp(int64 v, int64 min, int64 max)
+	{ return h_clamp(v, min, max, int64(0)); }
+
+    static constexpr inline uint64
+    SYSclamp(uint64 v, uint64 min, uint64 max)
+	{ return h_clamp(v, min, max, uint64(0)); }
+
+    static constexpr inline fpreal32
+    SYSclamp(fpreal32 v, fpreal32 min, fpreal32 max, fpreal32 tol=(fpreal32)0)
+	{ return h_clamp(v, min, max, tol); }
+
+    static constexpr inline fpreal64
+    SYSclamp(fpreal64 v, fpreal64 min, fpreal64 max, fpreal64 tol=(fpreal64)0)
+	{ return h_clamp(v, min, max, tol); }
+
+#undef h_clamp
+
+static inline fpreal64 SYSsqrt(fpreal64 arg)
+{ return ::sqrt(arg); }
+static inline fpreal32 SYSsqrt(fpreal32 arg)
+{ return ::sqrtf(arg); }
+static inline fpreal64 SYSatan2(fpreal64 a, fpreal64 b)
+{ return ::atan2(a, b); }
+static inline fpreal32 SYSatan2(fpreal32 a, fpreal32 b)
+{ return ::atan2(a, b); }
+
+static inline fpreal32 SYSabs(fpreal32 a) { return ::fabsf(a); }
+static inline fpreal64 SYSabs(fpreal64 a) { return ::fabs(a); }
+
+}}
+
+#endif
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      SIMD wrapper functions for SSE instructions
+ */
+
+#pragma once
+
+#ifndef __VM_SSEFunc__
+#define __VM_SSEFunc__
+
+
+
+#if defined(_MSC_VER)
+    #pragma warning(push)
+    #pragma warning(disable:4799)
+#endif
+
+#define CPU_HAS_SIMD_INSTR	1
+#define VM_SSE_STYLE		1
+
+#include <emmintrin.h>
+
+#if defined(__SSE4_1__)
+#define VM_SSE41_STYLE		1
+#include <smmintrin.h>
+#endif
+
+#if defined(_MSC_VER)
+    #pragma warning(pop)
+#endif
+
+namespace igl { namespace FastWindingNumber {
+
+typedef __m128	v4sf;
+typedef __m128i	v4si;
+
+// Plain casting (no conversion)
+// MSVC has problems casting between __m128 and __m128i, so we implement a
+// custom casting routine specifically for windows.
+
+#if defined(_MSC_VER)
+
+static SYS_FORCE_INLINE v4sf
+vm_v4sf(const v4si &a)
+{
+    union {
+	v4si ival;
+	v4sf fval;
+    };
+    ival = a;
+    return fval;
+}
+
+static SYS_FORCE_INLINE v4si
+vm_v4si(const v4sf &a)
+{
+    union {
+	v4si ival;
+	v4sf fval;
+    };
+    fval = a;
+    return ival;
+}
+
+#define V4SF(A)		vm_v4sf(A)
+#define V4SI(A)		vm_v4si(A)
+
+#else
+
+#define V4SF(A)		(v4sf)A
+#define V4SI(A)		(v4si)A
+
+#endif
+
+#define VM_SHUFFLE_MASK(a0,a1, b0,b1)	((b1)<<6|(b0)<<4 | (a1)<<2|(a0))
+
+template <int mask>
+static SYS_FORCE_INLINE v4sf
+vm_shuffle(const v4sf &a, const v4sf &b)
+{
+    return _mm_shuffle_ps(a, b, mask);
+}
+
+template <int mask>
+static SYS_FORCE_INLINE v4si
+vm_shuffle(const v4si &a, const v4si &b)
+{
+    return V4SI(_mm_shuffle_ps(V4SF(a), V4SF(b), mask));
+}
+
+template <int A, int B, int C, int D, typename T>
+static SYS_FORCE_INLINE T
+vm_shuffle(const T &a, const T &b)
+{
+    return vm_shuffle<VM_SHUFFLE_MASK(A,B,C,D)>(a, b);
+}
+
+template <int mask, typename T>
+static SYS_FORCE_INLINE T
+vm_shuffle(const T &a)
+{
+    return vm_shuffle<mask>(a, a);
+}
+
+template <int A, int B, int C, int D, typename T>
+static SYS_FORCE_INLINE T
+vm_shuffle(const T &a)
+{
+    return vm_shuffle<A,B,C,D>(a, a);
+}
+
+#if defined(VM_SSE41_STYLE)
+
+static SYS_FORCE_INLINE v4si
+vm_insert(const v4si v, int32 a, int n)
+{
+    switch (n)
+    {
+    case 0: return _mm_insert_epi32(v, a, 0);
+    case 1: return _mm_insert_epi32(v, a, 1);
+    case 2: return _mm_insert_epi32(v, a, 2);
+    case 3: return _mm_insert_epi32(v, a, 3);
+    }
+    return v;
+}
+
+static SYS_FORCE_INLINE v4sf
+vm_insert(const v4sf v, float a, int n)
+{
+    switch (n)
+    {
+    case 0: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,0,0));
+    case 1: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,1,0));
+    case 2: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,2,0));
+    case 3: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,3,0));
+    }
+    return v;
+}
+
+static SYS_FORCE_INLINE int
+vm_extract(const v4si v, int n)
+{
+    switch (n)
+    {
+    case 0: return _mm_extract_epi32(v, 0);
+    case 1: return _mm_extract_epi32(v, 1);
+    case 2: return _mm_extract_epi32(v, 2);
+    case 3: return _mm_extract_epi32(v, 3);
+    }
+    return 0;
+}
+
+static SYS_FORCE_INLINE float
+vm_extract(const v4sf v, int n)
+{
+    SYS_FPRealUnionF	tmp;
+    switch (n)
+    {
+    case 0: tmp.ival = _mm_extract_ps(v, 0); break;
+    case 1: tmp.ival = _mm_extract_ps(v, 1); break;
+    case 2: tmp.ival = _mm_extract_ps(v, 2); break;
+    case 3: tmp.ival = _mm_extract_ps(v, 3); break;
+    }
+    return tmp.fval;
+}
+
+#else
+
+static SYS_FORCE_INLINE v4si
+vm_insert(const v4si v, int32 a, int n)
+{
+    union { v4si vector; int32 comp[4]; };
+    vector = v;
+    comp[n] = a;
+    return vector;
+}
+
+static SYS_FORCE_INLINE v4sf
+vm_insert(const v4sf v, float a, int n)
+{
+    union { v4sf vector; float comp[4]; };
+    vector = v;
+    comp[n] = a;
+    return vector;
+}
+
+static SYS_FORCE_INLINE int
+vm_extract(const v4si v, int n)
+{
+    union { v4si vector; int32 comp[4]; };
+    vector = v;
+    return comp[n];
+}
+
+static SYS_FORCE_INLINE float
+vm_extract(const v4sf v, int n)
+{
+    union { v4sf vector; float comp[4]; };
+    vector = v;
+    return comp[n];
+}
+
+#endif
+
+static SYS_FORCE_INLINE v4sf
+vm_splats(float a)
+{
+    return _mm_set1_ps(a);
+}
+
+static SYS_FORCE_INLINE v4si
+vm_splats(uint32 a)
+{
+    SYS_FPRealUnionF	tmp;
+    tmp.uval = a;
+    return V4SI(vm_splats(tmp.fval));
+}
+
+static SYS_FORCE_INLINE v4si
+vm_splats(int32 a)
+{
+    SYS_FPRealUnionF	tmp;
+    tmp.ival = a;
+    return V4SI(vm_splats(tmp.fval));
+}
+
+static SYS_FORCE_INLINE v4sf
+vm_splats(float a, float b, float c, float d)
+{
+    return vm_shuffle<0,2,0,2>(
+	    vm_shuffle<0>(_mm_set_ss(a), _mm_set_ss(b)),
+	    vm_shuffle<0>(_mm_set_ss(c), _mm_set_ss(d)));
+}
+
+static SYS_FORCE_INLINE v4si
+vm_splats(uint32 a, uint32 b, uint32 c, uint32 d)
+{
+    SYS_FPRealUnionF	af, bf, cf, df;
+    af.uval = a;
+    bf.uval = b;
+    cf.uval = c;
+    df.uval = d;
+    return V4SI(vm_splats(af.fval, bf.fval, cf.fval, df.fval));
+}
+
+static SYS_FORCE_INLINE v4si
+vm_splats(int32 a, int32 b, int32 c, int32 d)
+{
+    SYS_FPRealUnionF	af, bf, cf, df;
+    af.ival = a;
+    bf.ival = b;
+    cf.ival = c;
+    df.ival = d;
+    return V4SI(vm_splats(af.fval, bf.fval, cf.fval, df.fval));
+}
+
+static SYS_FORCE_INLINE v4si
+vm_load(const int32 v[4])
+{
+    return V4SI(_mm_loadu_ps((const float *)v));
+}
+
+static SYS_FORCE_INLINE v4sf
+vm_load(const float v[4])
+{
+    return _mm_loadu_ps(v);
+}
+
+static SYS_FORCE_INLINE void
+vm_store(float dst[4], v4sf value)
+{
+    _mm_storeu_ps(dst, value);
+}
+
+static SYS_FORCE_INLINE v4sf
+vm_negate(v4sf a)
+{
+    return _mm_sub_ps(_mm_setzero_ps(), a);
+}
+
+static SYS_FORCE_INLINE v4sf
+vm_abs(v4sf a)
+{
+    return _mm_max_ps(a, vm_negate(a));
+}
+
+static SYS_FORCE_INLINE v4sf
+vm_fdiv(v4sf a, v4sf b)
+{
+    return _mm_mul_ps(a, _mm_rcp_ps(b));
+}
+
+static SYS_FORCE_INLINE v4sf
+vm_fsqrt(v4sf a)
+{
+    return _mm_rcp_ps(_mm_rsqrt_ps(a));
+}
+
+static SYS_FORCE_INLINE v4sf
+vm_madd(v4sf a, v4sf b, v4sf c)
+{
+    return _mm_add_ps(_mm_mul_ps(a, b), c);
+}
+
+static const v4si	theSSETrue = vm_splats(0xFFFFFFFF);
+
+static SYS_FORCE_INLINE bool
+vm_allbits(const v4si &a)
+{
+    return _mm_movemask_ps(V4SF(_mm_cmpeq_epi32(a, theSSETrue))) == 0xF;
+}
+
+
+#define VM_EXTRACT	vm_extract
+#define VM_INSERT	vm_insert
+#define VM_SPLATS	vm_splats
+#define VM_LOAD		vm_load
+#define VM_STORE	vm_store
+
+#define VM_CMPLT(A,B)	V4SI(_mm_cmplt_ps(A,B))
+#define VM_CMPLE(A,B)	V4SI(_mm_cmple_ps(A,B))
+#define VM_CMPGT(A,B)	V4SI(_mm_cmpgt_ps(A,B))
+#define VM_CMPGE(A,B)	V4SI(_mm_cmpge_ps(A,B))
+#define VM_CMPEQ(A,B)	V4SI(_mm_cmpeq_ps(A,B))
+#define VM_CMPNE(A,B)	V4SI(_mm_cmpneq_ps(A,B))
+
+#define VM_ICMPLT	_mm_cmplt_epi32
+#define VM_ICMPGT	_mm_cmpgt_epi32
+#define VM_ICMPEQ	_mm_cmpeq_epi32
+
+#define VM_IADD		_mm_add_epi32
+#define VM_ISUB		_mm_sub_epi32
+
+#define VM_ADD		_mm_add_ps
+#define VM_SUB		_mm_sub_ps
+#define VM_MUL		_mm_mul_ps
+#define VM_DIV		_mm_div_ps
+#define VM_SQRT		_mm_sqrt_ps
+#define VM_ISQRT	_mm_rsqrt_ps
+#define VM_INVERT	_mm_rcp_ps
+#define VM_ABS		vm_abs
+
+#define VM_FDIV		vm_fdiv
+#define VM_NEG		vm_negate
+#define VM_FSQRT	vm_fsqrt
+#define VM_MADD		vm_madd
+
+#define VM_MIN		_mm_min_ps
+#define VM_MAX		_mm_max_ps
+
+#define VM_AND		_mm_and_si128
+#define VM_ANDNOT	_mm_andnot_si128
+#define VM_OR		_mm_or_si128
+#define VM_XOR		_mm_xor_si128
+
+#define VM_ALLBITS	vm_allbits
+
+#define VM_SHUFFLE	vm_shuffle
+
+// Integer to float conversions
+#define VM_SSE_ROUND_MASK	0x6000
+#define VM_SSE_ROUND_ZERO	0x6000
+#define VM_SSE_ROUND_UP		0x4000
+#define VM_SSE_ROUND_DOWN	0x2000
+#define VM_SSE_ROUND_NEAR	0x0000
+
+#define GETROUND()	(_mm_getcsr()&VM_SSE_ROUND_MASK)
+#define SETROUND(x)	(_mm_setcsr(x|(_mm_getcsr()&~VM_SSE_ROUND_MASK)))
+
+// The P functions must be invoked before FLOOR, the E functions invoked
+// afterwards to reset the state.
+
+#define VM_P_FLOOR()	uint rounding = GETROUND(); \
+			    SETROUND(VM_SSE_ROUND_DOWN);
+#define VM_FLOOR	_mm_cvtps_epi32
+#define VM_INT		_mm_cvttps_epi32
+#define VM_E_FLOOR()	SETROUND(rounding);
+
+// Float to integer conversion
+#define VM_IFLOAT	_mm_cvtepi32_ps
+}}
+
+#endif
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      SIMD wrapper classes for 4 floats or 4 ints
+ */
+
+#pragma once
+
+#ifndef __HDK_VM_SIMD__
+#define __HDK_VM_SIMD__
+
+
+#include <cstdint>
+
+//#define FORCE_NON_SIMD
+
+
+namespace igl { namespace FastWindingNumber {
+
+class v4uf;
+
+class v4uu {
+public:
+    SYS_FORCE_INLINE v4uu() {}
+    SYS_FORCE_INLINE v4uu(const v4si &v) : vector(v) {}
+    SYS_FORCE_INLINE v4uu(const v4uu &v) : vector(v.vector) {}
+    explicit SYS_FORCE_INLINE v4uu(int32 v) { vector = VM_SPLATS(v); }
+    explicit SYS_FORCE_INLINE v4uu(const int32 v[4])
+    { vector = VM_LOAD(v); }
+    SYS_FORCE_INLINE v4uu(int32 a, int32 b, int32 c, int32 d)
+    { vector = VM_SPLATS(a, b, c, d); }
+
+    // Assignment
+    SYS_FORCE_INLINE v4uu operator=(int32 v)
+    { vector = v4uu(v).vector; return *this; }
+    SYS_FORCE_INLINE v4uu operator=(v4si v)
+    { vector = v; return *this; }
+    SYS_FORCE_INLINE v4uu operator=(const v4uu &v)
+    { vector = v.vector; return *this; }
+
+    SYS_FORCE_INLINE void condAssign(const v4uu &val, const v4uu &c)
+    { *this = (c & val) | ((!c) & *this); }
+
+    // Comparison
+    SYS_FORCE_INLINE v4uu operator == (const v4uu &v) const
+    { return v4uu(VM_ICMPEQ(vector, v.vector)); }
+    SYS_FORCE_INLINE v4uu operator != (const v4uu &v) const
+    { return ~(*this == v); }
+    SYS_FORCE_INLINE v4uu operator >  (const v4uu &v) const
+    { return v4uu(VM_ICMPGT(vector, v.vector)); }
+    SYS_FORCE_INLINE v4uu operator <  (const v4uu &v) const
+    { return v4uu(VM_ICMPLT(vector, v.vector)); }
+    SYS_FORCE_INLINE v4uu operator >= (const v4uu &v) const
+    { return ~(*this < v); }
+    SYS_FORCE_INLINE v4uu operator <= (const v4uu &v) const
+    { return ~(*this > v); }
+
+    SYS_FORCE_INLINE v4uu operator == (int32 v) const { return *this == v4uu(v); }
+    SYS_FORCE_INLINE v4uu operator != (int32 v) const { return *this != v4uu(v); }
+    SYS_FORCE_INLINE v4uu operator >  (int32 v) const { return *this > v4uu(v); }
+    SYS_FORCE_INLINE v4uu operator <  (int32 v) const { return *this < v4uu(v); }
+    SYS_FORCE_INLINE v4uu operator >= (int32 v) const { return *this >= v4uu(v); }
+    SYS_FORCE_INLINE v4uu operator <= (int32 v) const { return *this <= v4uu(v); }
+
+    // Basic math
+    SYS_FORCE_INLINE v4uu operator+(const v4uu &r) const
+    { return v4uu(VM_IADD(vector, r.vector)); }
+    SYS_FORCE_INLINE v4uu operator-(const v4uu &r) const
+    { return v4uu(VM_ISUB(vector, r.vector)); }
+    SYS_FORCE_INLINE v4uu operator+=(const v4uu &r) { return (*this = *this + r); }
+    SYS_FORCE_INLINE v4uu operator-=(const v4uu &r) { return (*this = *this - r); }
+    SYS_FORCE_INLINE v4uu operator+(int32 r) const { return *this + v4uu(r); }
+    SYS_FORCE_INLINE v4uu operator-(int32 r) const { return *this - v4uu(r); }
+    SYS_FORCE_INLINE v4uu operator+=(int32 r) { return (*this = *this + r); }
+    SYS_FORCE_INLINE v4uu operator-=(int32 r) { return (*this = *this - r); }
+
+    // logical/bitwise
+
+    SYS_FORCE_INLINE v4uu operator||(const v4uu &r) const
+    { return v4uu(VM_OR(vector, r.vector)); }
+    SYS_FORCE_INLINE v4uu operator&&(const v4uu &r) const
+    { return v4uu(VM_AND(vector, r.vector)); }
+    SYS_FORCE_INLINE v4uu operator^(const v4uu &r) const
+    { return v4uu(VM_XOR(vector, r.vector)); }
+    SYS_FORCE_INLINE v4uu operator!() const
+    { return *this == v4uu(0); }
+
+    SYS_FORCE_INLINE v4uu operator|(const v4uu &r) const { return *this || r; }
+    SYS_FORCE_INLINE v4uu operator&(const v4uu &r) const { return *this && r; }
+    SYS_FORCE_INLINE v4uu operator~() const
+    { return *this ^ v4uu(0xFFFFFFFF); }
+
+    // component
+    SYS_FORCE_INLINE int32 operator[](int idx) const { return VM_EXTRACT(vector, idx); }
+    SYS_FORCE_INLINE void setComp(int idx, int32 v) { vector = VM_INSERT(vector, v, idx); }
+
+    v4uf toFloat() const;
+
+public:
+    v4si vector;
+};
+
+class v4uf {
+public:
+    SYS_FORCE_INLINE v4uf() {}
+    SYS_FORCE_INLINE v4uf(const v4sf &v) : vector(v) {}
+    SYS_FORCE_INLINE v4uf(const v4uf &v) : vector(v.vector) {}
+    explicit SYS_FORCE_INLINE v4uf(float v) { vector = VM_SPLATS(v); }
+    explicit SYS_FORCE_INLINE v4uf(const float v[4])
+    { vector = VM_LOAD(v); }
+    SYS_FORCE_INLINE v4uf(float a, float b, float c, float d)
+    { vector = VM_SPLATS(a, b, c, d); }
+
+    // Assignment
+    SYS_FORCE_INLINE v4uf operator=(float v)
+    { vector = v4uf(v).vector; return *this; }
+    SYS_FORCE_INLINE v4uf operator=(v4sf v)
+    { vector = v; return *this; }
+    SYS_FORCE_INLINE v4uf operator=(const v4uf &v)
+    { vector = v.vector; return *this; }
+
+    SYS_FORCE_INLINE void condAssign(const v4uf &val, const v4uu &c)
+    { *this = (val & c) | (*this & ~c); }
+
+    // Comparison
+    SYS_FORCE_INLINE v4uu operator == (const v4uf &v) const
+    { return v4uu(VM_CMPEQ(vector, v.vector)); }
+    SYS_FORCE_INLINE v4uu operator != (const v4uf &v) const
+    { return v4uu(VM_CMPNE(vector, v.vector)); }
+    SYS_FORCE_INLINE v4uu operator >  (const v4uf &v) const
+    { return v4uu(VM_CMPGT(vector, v.vector)); }
+    SYS_FORCE_INLINE v4uu operator <  (const v4uf &v) const
+    { return v4uu(VM_CMPLT(vector, v.vector)); }
+    SYS_FORCE_INLINE v4uu operator >= (const v4uf &v) const
+    { return v4uu(VM_CMPGE(vector, v.vector)); }
+    SYS_FORCE_INLINE v4uu operator <= (const v4uf &v) const
+    { return v4uu(VM_CMPLE(vector, v.vector)); }
+
+    SYS_FORCE_INLINE v4uu operator == (float v) const { return *this == v4uf(v); }
+    SYS_FORCE_INLINE v4uu operator != (float v) const { return *this != v4uf(v); }
+    SYS_FORCE_INLINE v4uu operator >  (float v) const { return *this > v4uf(v); }
+    SYS_FORCE_INLINE v4uu operator <  (float v) const { return *this < v4uf(v); }
+    SYS_FORCE_INLINE v4uu operator >= (float v) const { return *this >= v4uf(v); }
+    SYS_FORCE_INLINE v4uu operator <= (float v) const { return *this <= v4uf(v); }
+
+
+    // Basic math
+    SYS_FORCE_INLINE v4uf operator+(const v4uf &r) const
+    { return v4uf(VM_ADD(vector, r.vector)); }
+    SYS_FORCE_INLINE v4uf operator-(const v4uf &r) const
+    { return v4uf(VM_SUB(vector, r.vector)); }
+    SYS_FORCE_INLINE v4uf operator-() const
+    { return v4uf(VM_NEG(vector)); }
+    SYS_FORCE_INLINE v4uf operator*(const v4uf &r) const
+    { return v4uf(VM_MUL(vector, r.vector)); }
+    SYS_FORCE_INLINE v4uf operator/(const v4uf &r) const
+    { return v4uf(VM_DIV(vector, r.vector)); }
+
+    SYS_FORCE_INLINE v4uf operator+=(const v4uf &r) { return (*this = *this + r); }
+    SYS_FORCE_INLINE v4uf operator-=(const v4uf &r) { return (*this = *this - r); }
+    SYS_FORCE_INLINE v4uf operator*=(const v4uf &r) { return (*this = *this * r); }
+    SYS_FORCE_INLINE v4uf operator/=(const v4uf &r) { return (*this = *this / r); }
+
+    SYS_FORCE_INLINE v4uf operator+(float r) const { return *this + v4uf(r); }
+    SYS_FORCE_INLINE v4uf operator-(float r) const { return *this - v4uf(r); }
+    SYS_FORCE_INLINE v4uf operator*(float r) const { return *this * v4uf(r); }
+    SYS_FORCE_INLINE v4uf operator/(float r) const { return *this / v4uf(r); }
+    SYS_FORCE_INLINE v4uf operator+=(float r) { return (*this = *this + r); }
+    SYS_FORCE_INLINE v4uf operator-=(float r) { return (*this = *this - r); }
+    SYS_FORCE_INLINE v4uf operator*=(float r) { return (*this = *this * r); }
+    SYS_FORCE_INLINE v4uf operator/=(float r) { return (*this = *this / r); }
+
+    // logical/bitwise
+
+    SYS_FORCE_INLINE v4uf operator||(const v4uu &r) const
+    { return v4uf(V4SF(VM_OR(V4SI(vector), r.vector))); }
+    SYS_FORCE_INLINE v4uf operator&&(const v4uu &r) const
+    { return v4uf(V4SF(VM_AND(V4SI(vector), r.vector))); }
+    SYS_FORCE_INLINE v4uf operator^(const v4uu &r) const
+    { return v4uf(V4SF(VM_XOR(V4SI(vector), r.vector))); }
+    SYS_FORCE_INLINE v4uf operator!() const
+    { return v4uf(V4SF((*this == v4uf(0.0F)).vector)); }
+
+    SYS_FORCE_INLINE v4uf operator||(const v4uf &r) const
+    { return v4uf(V4SF(VM_OR(V4SI(vector), V4SI(r.vector)))); }
+    SYS_FORCE_INLINE v4uf operator&&(const v4uf &r) const
+    { return v4uf(V4SF(VM_AND(V4SI(vector), V4SI(r.vector)))); }
+    SYS_FORCE_INLINE v4uf operator^(const v4uf &r) const
+    { return v4uf(V4SF(VM_XOR(V4SI(vector), V4SI(r.vector)))); }
+
+    SYS_FORCE_INLINE v4uf operator|(const v4uu &r) const { return *this || r; }
+    SYS_FORCE_INLINE v4uf operator&(const v4uu &r) const { return *this && r; }
+    SYS_FORCE_INLINE v4uf operator~() const
+    { return *this ^ v4uu(0xFFFFFFFF); }
+
+    SYS_FORCE_INLINE v4uf operator|(const v4uf &r) const { return *this || r; }
+    SYS_FORCE_INLINE v4uf operator&(const v4uf &r) const { return *this && r; }
+
+    // component
+    SYS_FORCE_INLINE float operator[](int idx) const { return VM_EXTRACT(vector, idx); }
+    SYS_FORCE_INLINE void setComp(int idx, float v) { vector = VM_INSERT(vector, v, idx); }
+
+    // more math
+    SYS_FORCE_INLINE v4uf abs() const { return v4uf(VM_ABS(vector)); }
+    SYS_FORCE_INLINE v4uf clamp(const v4uf &low, const v4uf &high) const
+    { return v4uf(
+        VM_MIN(VM_MAX(vector, low.vector), high.vector)); }
+    SYS_FORCE_INLINE v4uf clamp(float low, float high) const
+    { return v4uf(VM_MIN(VM_MAX(vector,
+        v4uf(low).vector), v4uf(high).vector)); }
+    SYS_FORCE_INLINE v4uf recip() const { return v4uf(VM_INVERT(vector)); }
+
+    /// This is a lie, it is a signed int.
+    SYS_FORCE_INLINE v4uu toUnsignedInt() const { return VM_INT(vector); }
+    SYS_FORCE_INLINE v4uu toSignedInt() const { return VM_INT(vector); }
+
+    v4uu floor() const
+    {
+        VM_P_FLOOR();
+        v4uu result = VM_FLOOR(vector);
+        VM_E_FLOOR();
+        return result;
+    }
+
+    /// Returns the integer part of this float, this becomes the
+    /// 0..1 fractional component.
+    v4uu splitFloat()
+    {
+        v4uu base = toSignedInt();
+        *this -= base.toFloat();
+        return base;
+    }
+
+    template <int A, int B, int C, int D>
+    SYS_FORCE_INLINE v4uf swizzle() const
+    { 
+        return VM_SHUFFLE<A,B,C,D>(vector);
+    }
+
+    SYS_FORCE_INLINE v4uu isFinite() const
+    {
+        // If the exponent is the maximum value, it's either infinite or NaN.
+        const v4si mask = VM_SPLATS(0x7F800000);
+        return ~v4uu(VM_ICMPEQ(VM_AND(V4SI(vector), mask), mask));
+    }
+
+public:
+    v4sf vector;
+};
+
+SYS_FORCE_INLINE v4uf
+v4uu::toFloat() const
+{
+    return v4uf(VM_IFLOAT(vector));
+}
+
+//
+// Custom vector operations
+//
+
+static SYS_FORCE_INLINE v4uf
+sqrt(const v4uf &a)
+{
+    return v4uf(VM_SQRT(a.vector));
+}
+
+static SYS_FORCE_INLINE v4uf
+fabs(const v4uf &a)
+{
+    return a.abs();
+}
+
+// Use this operation to mask disabled values to 0
+// rval = !a ? b : 0;
+
+static SYS_FORCE_INLINE v4uf
+andn(const v4uu &a, const v4uf &b)
+{
+    return v4uf(V4SF(VM_ANDNOT(a.vector, V4SI(b.vector))));
+}
+
+static SYS_FORCE_INLINE v4uu
+andn(const v4uu &a, const v4uu &b)
+{
+    return v4uu(VM_ANDNOT(a.vector, b.vector));
+}
+
+// rval = a ? b : c;
+static SYS_FORCE_INLINE v4uf
+ternary(const v4uu &a, const v4uf &b, const v4uf &c)
+{
+    return (b & a) | andn(a, c);
+}
+
+static SYS_FORCE_INLINE v4uu
+ternary(const v4uu &a, const v4uu &b, const v4uu &c)
+{
+    return (b & a) | andn(a, c);
+}
+
+// rval = !(a && b)
+static SYS_FORCE_INLINE v4uu
+nand(const v4uu &a, const v4uu &b)
+{
+    return !v4uu(VM_AND(a.vector, b.vector));
+}
+
+static SYS_FORCE_INLINE v4uf
+vmin(const v4uf &a, const v4uf &b)
+{
+    return v4uf(VM_MIN(a.vector, b.vector));
+}
+
+static SYS_FORCE_INLINE v4uf
+vmax(const v4uf &a, const v4uf &b)
+{
+    return v4uf(VM_MAX(a.vector, b.vector));
+}
+
+static SYS_FORCE_INLINE v4uf
+clamp(const v4uf &a, const v4uf &b, const v4uf &c)
+{
+    return vmax(vmin(a, c), b);
+}
+
+static SYS_FORCE_INLINE v4uf
+clamp(const v4uf &a, float b, float c)
+{
+    return vmax(vmin(a, v4uf(c)), v4uf(b));
+}
+
+static SYS_FORCE_INLINE bool
+allbits(const v4uu &a)
+{
+    return vm_allbits(a.vector);
+}
+
+static SYS_FORCE_INLINE bool
+anybits(const v4uu &a)
+{
+    return !allbits(~a);
+}
+
+static SYS_FORCE_INLINE v4uf
+madd(const v4uf &v, const v4uf &f, const v4uf &a)
+{
+    return v4uf(VM_MADD(v.vector, f.vector, a.vector));
+}
+
+static SYS_FORCE_INLINE v4uf
+madd(const v4uf &v, float f, float a)
+{
+    return v4uf(VM_MADD(v.vector, v4uf(f).vector, v4uf(a).vector));
+}
+
+static SYS_FORCE_INLINE v4uf
+madd(const v4uf &v, float f, const v4uf &a)
+{
+    return v4uf(VM_MADD(v.vector, v4uf(f).vector, a.vector));
+}
+
+static SYS_FORCE_INLINE v4uf
+msub(const v4uf &v, const v4uf &f, const v4uf &s)
+{
+    return madd(v, f, -s);
+}
+
+static SYS_FORCE_INLINE v4uf
+msub(const v4uf &v, float f, float s)
+{
+    return madd(v, f, -s);
+}
+
+static SYS_FORCE_INLINE v4uf
+lerp(const v4uf &a, const v4uf &b, const v4uf &w)
+{
+    v4uf w1 = v4uf(1.0F) - w;
+    return madd(a, w1, b*w);
+}
+
+static SYS_FORCE_INLINE v4uf
+luminance(const v4uf &r, const v4uf &g, const v4uf &b,
+    float rw, float gw, float bw)
+{
+    return v4uf(madd(r, v4uf(rw), madd(g, v4uf(gw), b * bw)));
+}
+
+static SYS_FORCE_INLINE float
+dot3(const v4uf &a, const v4uf &b)
+{
+    v4uf res = a*b;
+    return res[0] + res[1] + res[2];
+}
+
+static SYS_FORCE_INLINE float
+dot4(const v4uf &a, const v4uf &b)
+{
+    v4uf res = a*b;
+    return res[0] + res[1] + res[2] + res[3];
+}
+
+static SYS_FORCE_INLINE float
+length(const v4uf &a)
+{
+    return SYSsqrt(dot3(a, a));
+}
+
+static SYS_FORCE_INLINE v4uf
+normalize(const v4uf &a)
+{
+    return a / length(a);
+}
+
+static SYS_FORCE_INLINE v4uf
+cross(const v4uf &a, const v4uf &b)
+{
+    return v4uf(a[1]*b[2] - a[2]*b[1],
+        a[2]*b[0] - a[0]*b[2],
+        a[0]*b[1] - a[1]*b[0], 0);
+}
+
+// Currently there is no specific support for signed integers
+typedef v4uu v4ui;
+
+// Assuming that ptr is an array of elements of type STYPE, this operation
+// will return the index of the first element that is aligned to (1<<ASIZE)
+// bytes.
+#define VM_ALIGN(ptr, ASIZE, STYPE)	\
+		((((1<<ASIZE)-(intptr_t)ptr)&((1<<ASIZE)-1))/sizeof(STYPE))
+
+}}
+#endif
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      This is the array class implementation used by almost everything here.
+ */
+
+#pragma once
+
+#ifndef __UT_ARRAY_H_INCLUDED__
+#define __UT_ARRAY_H_INCLUDED__
+
+
+
+#include <algorithm>
+#include <functional>
+#include <type_traits>
+#include <string.h>
+
+namespace igl { namespace FastWindingNumber {
+
+ /// This routine describes how to change the size of an array.
+ /// It must increase the current_size by at least one!
+ ///
+ /// Current expected sequence of small sizes:
+ ///    4,    8,   16,   32,   48,   64,   80,   96,  112,
+ ///  128,  256,  384,  512,  640,  768,  896, 1024,
+ /// (increases by approx factor of 1.125 each time after this)
+template <typename T>
+static inline T
+UTbumpAlloc(T current_size)
+{
+    // NOTE: These must be powers of two.  See below.
+    constexpr T SMALL_ALLOC(16);
+    constexpr T BIG_ALLOC(128);
+
+    // For small values, we increment by fixed amounts.  For
+    // large values, we increment by one eighth of the current size.
+    // This prevents n^2 behaviour with allocation one element at a time.
+    // A factor of 1/8 will waste 1/16 the memory on average, and will
+    // double the size of the array in approximately 6 reallocations.
+    if (current_size < T(8))
+    {
+        return (current_size < T(4)) ? T(4) : T(8);
+    }
+    if (current_size < T(BIG_ALLOC))
+    {
+        // Snap up to next multiple of SMALL_ALLOC (must be power of 2)
+        return (current_size + T(SMALL_ALLOC)) & ~T(SMALL_ALLOC-1);
+    }
+    if (current_size < T(BIG_ALLOC * 8))
+    {
+        // Snap up to next multiple of BIG_ALLOC (must be power of 2)
+        return (current_size + T(BIG_ALLOC)) & ~T(BIG_ALLOC-1);
+    }
+
+    T bump = current_size >> 3; // Divided by 8.
+    current_size += bump;
+    return current_size;
+}
+
+template <typename T>
+class UT_Array
+{
+public:
+    typedef T value_type;
+
+    typedef int (*Comparator)(const T *, const T *);
+
+    /// Copy constructor. It duplicates the data.
+    /// It's marked explicit so that it's not accidentally passed by value.
+    /// You can always pass by reference and then copy it, if needed.
+    /// If you have a line like:
+    /// UT_Array<int> a = otherarray;
+    /// and it really does need to copy instead of referencing,
+    /// you can rewrite it as:
+    /// UT_Array<int> a(otherarray);
+    inline explicit UT_Array(const UT_Array<T> &a);
+    
+    /// Move constructor. Steals the working data from the original.
+    inline UT_Array(UT_Array<T> &&a) noexcept;
+    
+    /// Construct based on given capacity and size
+    UT_Array(exint capacity, exint size)
+    {
+        myData = capacity ? allocateCapacity(capacity) : NULL;
+        if (capacity < size)
+            size = capacity;
+        mySize = size;
+        myCapacity = capacity;
+        trivialConstructRange(myData, mySize);
+    }
+
+    /// Construct based on given capacity with a size of 0
+    explicit UT_Array(exint capacity = 0) : myCapacity(capacity), mySize(0)
+    {
+        myData = capacity ? allocateCapacity(capacity) : NULL;
+    }
+
+    /// Construct with the contents of an initializer list
+    inline explicit UT_Array(std::initializer_list<T> init);
+
+    inline ~UT_Array();
+
+    inline void	    swap(UT_Array<T> &other);
+
+    /// Append an element to the current elements and return its index in the
+    /// array, or insert the element at a specified position; if necessary,
+    /// insert() grows the array to accommodate the element. The insert
+    /// methods use the assignment operator '=' to place the element into the
+    /// right spot; be aware that '=' works differently on objects and pointers.
+    /// The test for duplicates uses the logical equal operator '=='; as with
+    /// '=', the behaviour of the equality operator on pointers versus objects
+    /// is not the same.
+    /// Use the subscript operators instead of insert() if you are appending
+    /// to the array, or if  you don't mind overwriting the element already 
+    /// inserted at the given index.
+    exint           append(void) { return insert(mySize); }
+    exint           append(const T &t) { return appendImpl(t); }
+    exint           append(T &&t) { return appendImpl(std::move(t)); }
+    inline void            append(const T *pt, exint count);
+    inline void	    appendMultiple(const T &t, exint count);
+    inline exint	    insert(exint index);
+    exint	    insert(const T &t, exint i)
+                        { return insertImpl(t, i); }
+    exint	    insert(T &&t, exint i)
+                        { return insertImpl(std::move(t), i); }
+
+    /// Adds a new element to the array (resizing if necessary) and forwards
+    /// the given arguments to T's constructor.
+    /// NOTE: Unlike append(), the arguments cannot reference any existing
+    /// elements in the array. Checking for and handling such cases would
+    /// remove most of the performance gain versus append(T(...)). Debug builds
+    /// will assert that the arguments are valid.
+    template <typename... S>
+    inline exint	    emplace_back(S&&... s);
+
+    /// Takes another T array and concatenate it onto my end
+    inline exint	    concat(const UT_Array<T> &a);
+
+    /// Insert an element "count" times at the given index. Return the index.
+    inline exint	    multipleInsert(exint index, exint count);
+
+    /// An alias for unique element insertion at a certain index. Also used by
+    /// the other insertion methods.
+    exint	    insertAt(const T &t, exint index)
+                        { return insertImpl(t, index); }
+
+    /// Return true if given index is valid.
+    bool	    isValidIndex(exint index) const
+			{ return (index >= 0 && index < mySize); }
+
+    /// Remove one element from the array given its
+    /// position in the list, and fill the gap by shifting the elements down
+    /// by one position.  Return the index of the element removed or -1 if
+    /// the index was out of bounds.
+    exint	    removeIndex(exint index)
+    {
+        return isValidIndex(index) ? removeAt(index) : -1;
+    }
+    void	    removeLast()
+    {
+        if (mySize) removeAt(mySize-1);
+    }
+
+    /// Remove the range [begin_i,end_i) of elements from the array.
+    inline void	    removeRange(exint begin_i, exint end_i);
+
+    /// Remove the range [begin_i, end_i) of elements from this array and place
+    /// them in the dest array, shrinking/growing the dest array as necessary.
+    inline void            extractRange(exint begin_i, exint end_i,
+                                 UT_Array<T>& dest);
+
+    /// Removes all matching elements from the list, shuffling down and changing
+    /// the size appropriately.
+    /// Returns the number of elements left.
+    template <typename IsEqual>
+    inline exint	    removeIf(IsEqual is_equal);
+
+    /// Remove all matching elements. Also sets the capacity of the array.
+    template <typename IsEqual>
+    void	    collapseIf(IsEqual is_equal)
+    {
+        removeIf(is_equal);
+        setCapacity(size());
+    }
+
+    /// Move howMany objects starting at index srcIndex to destIndex;
+    /// This method will remove the elements at [srcIdx, srcIdx+howMany) and
+    /// then insert them at destIdx.  This method can be used in place of
+    /// the old shift() operation.
+    inline void	    move(exint srcIdx, exint destIdx, exint howMany);
+
+    /// Cyclically shifts the entire array by howMany
+    inline void	    cycle(exint howMany);
+
+    /// Quickly set the array to a single value.
+    inline void	    constant(const T &v);
+    /// Zeros the array if a POD type, else trivial constructs if a class type.
+    inline void	    zero();
+
+    /// The fastest search possible, which does pointer arithmetic to find the
+    /// index of the element. WARNING: index() does no out-of-bounds checking.
+    exint	    index(const T &t) const { return &t - myData; }
+    exint	    safeIndex(const T &t) const
+    {
+        return (&t >= myData && &t < (myData + mySize))
+            ? &t - myData : -1;
+    }
+
+    /// Set the capacity of the array, i.e. grow it or shrink it. The
+    /// function copies the data after reallocating space for the array.
+    inline void            setCapacity(exint newcapacity);
+    void            setCapacityIfNeeded(exint mincapacity)
+    {
+        if (capacity() < mincapacity)
+            setCapacity(mincapacity);
+    }
+    /// If the capacity is smaller than mincapacity, expand the array
+    /// to at least mincapacity and to at least a constant factor of the
+    /// array's previous capacity, to avoid having a linear number of
+    /// reallocations in a linear number of calls to bumpCapacity.
+    void            bumpCapacity(exint mincapacity)
+    {
+        if (capacity() >= mincapacity)
+            return;
+        // The following 4 lines are just
+        // SYSmax(mincapacity, UTbumpAlloc(capacity())), avoiding SYSmax
+        exint bumped = UTbumpAlloc(capacity());
+        exint newcapacity = mincapacity;
+        if (bumped > mincapacity)
+            newcapacity = bumped;
+        setCapacity(newcapacity);
+    }
+
+    /// First bumpCapacity to ensure that there's space for newsize,
+    /// expanding either not at all or by at least a constant factor
+    /// of the array's previous capacity,
+    /// then set the size to newsize.
+    void            bumpSize(exint newsize)
+    {
+        bumpCapacity(newsize);
+        setSize(newsize);
+    }
+    /// NOTE: bumpEntries() will be deprecated in favour of bumpSize() in a
+    ///       future version.
+    void            bumpEntries(exint newsize)
+    {
+        bumpSize(newsize);
+    }
+
+    /// Query the capacity, i.e. the allocated length of the array.
+    /// NOTE: capacity() >= size().
+    exint           capacity() const { return myCapacity; }
+    /// Query the size, i.e. the number of occupied elements in the array.
+    /// NOTE: capacity() >= size().
+    exint           size() const     { return mySize; }
+    /// Alias of size().  size() is preferred.
+    exint           entries() const  { return mySize; }
+    /// Returns true iff there are no occupied elements in the array.
+    bool            isEmpty() const  { return mySize==0; }
+
+    /// Set the size, the number of occupied elements in the array.
+    /// NOTE: This will not do bumpCapacity, so if you call this
+    ///       n times to increase the size, it may take
+    ///       n^2 time.
+    void            setSize(exint newsize)
+    {
+        if (newsize < 0)
+            newsize = 0;
+        if (newsize == mySize)
+            return;
+        setCapacityIfNeeded(newsize);
+        if (mySize > newsize)
+            trivialDestructRange(myData + newsize, mySize - newsize);
+        else // newsize > mySize
+            trivialConstructRange(myData + mySize, newsize - mySize);
+        mySize = newsize;
+    }
+    /// Alias of setSize().  setSize() is preferred.
+    void            entries(exint newsize)
+    {
+        setSize(newsize);
+    }
+    /// Set the size, but unlike setSize(newsize), this function
+    /// will not initialize new POD elements to zero. Non-POD data types
+    /// will still have their constructors called.
+    /// This function is faster than setSize(ne) if you intend to fill in
+    /// data for all elements.
+    void            setSizeNoInit(exint newsize)
+    {
+        if (newsize < 0)
+            newsize = 0;
+        if (newsize == mySize)
+            return;
+        setCapacityIfNeeded(newsize);
+        if (mySize > newsize)
+            trivialDestructRange(myData + newsize, mySize - newsize);
+        else if (!isPOD()) // newsize > mySize
+            trivialConstructRange(myData + mySize, newsize - mySize);
+        mySize = newsize;
+    }
+
+    /// Decreases, but never expands, to the given maxsize.
+    void            truncate(exint maxsize)
+    {
+        if (maxsize >= 0 && size() > maxsize)
+            setSize(maxsize);
+    }
+    /// Resets list to an empty list.
+    void            clear() {
+        // Don't call setSize(0) since that would require a valid default
+        // constructor.
+        trivialDestructRange(myData, mySize);
+        mySize = 0;
+    }
+
+    /// Assign array a to this array by copying each of a's elements with
+    /// memcpy for POD types, and with copy construction for class types.
+    inline UT_Array<T> &   operator=(const UT_Array<T> &a);
+
+    /// Replace the contents with those from the initializer_list ilist
+    inline UT_Array<T> &   operator=(std::initializer_list<T> ilist);
+
+    /// Move the contents of array a to this array. 
+    inline UT_Array<T> &   operator=(UT_Array<T> &&a);
+
+    /// Compare two array and return true if they are equal and false otherwise.
+    /// Two elements are checked against each other using operator '==' or
+    /// compare() respectively.
+    /// NOTE: The capacities of the arrays are not checked when
+    ///       determining whether they are equal.
+    inline bool            operator==(const UT_Array<T> &a) const;
+    inline bool            operator!=(const UT_Array<T> &a) const;
+     
+    /// Subscript operator
+    /// NOTE: This does NOT do any bounds checking unless paranoid
+    ///       asserts are enabled.
+    T &		    operator()(exint i)
+    {
+        UT_ASSERT_P(i >= 0 && i < mySize);
+        return myData[i];
+    }
+    /// Const subscript operator
+    /// NOTE: This does NOT do any bounds checking unless paranoid
+    ///       asserts are enabled.
+    const T &	    operator()(exint i) const
+    {
+	UT_ASSERT_P(i >= 0 && i < mySize);
+	return myData[i];
+    }
+
+    /// Subscript operator
+    /// NOTE: This does NOT do any bounds checking unless paranoid
+    ///       asserts are enabled.
+    T &		    operator[](exint i)
+    {
+        UT_ASSERT_P(i >= 0 && i < mySize);
+        return myData[i];
+    }
+    /// Const subscript operator
+    /// NOTE: This does NOT do any bounds checking unless paranoid
+    ///       asserts are enabled.
+    const T &	    operator[](exint i) const
+    {
+	UT_ASSERT_P(i >= 0 && i < mySize);
+	return myData[i];
+    }
+    
+    /// forcedRef(exint) will grow the array if necessary, initializing any
+    /// new elements to zero for POD types and default constructing for
+    /// class types.
+    T &             forcedRef(exint i)
+    {
+        UT_ASSERT_P(i >= 0);
+        if (i >= mySize)
+            bumpSize(i+1);
+        return myData[i];
+    }
+
+    /// forcedGet(exint) does NOT grow the array, and will return default
+    /// objects for out of bound array indices.
+    T               forcedGet(exint i) const
+    {
+        return (i >= 0 && i < mySize) ? myData[i] : T();
+    }
+
+    T &		    last()
+    {
+        UT_ASSERT_P(mySize);
+        return myData[mySize-1];
+    }
+    const T &	    last() const
+    {
+        UT_ASSERT_P(mySize);
+        return myData[mySize-1];
+    }
+
+    T *		    getArray() const		    { return myData; }
+    const T *	    getRawArray() const		    { return myData; }
+
+    T *		    array()			    { return myData; }
+    const T *	    array() const		    { return myData; }
+
+    T *		    data()			    { return myData; }
+    const T *	    data() const		    { return myData; }
+
+    /// This method allows you to swap in a new raw T array, which must be
+    /// the same size as myCapacity. Use caution with this method.
+    T *		    aliasArray(T *newdata)
+    { T *data = myData; myData = newdata; return data; }
+
+    template <typename IT, bool FORWARD>
+    class base_iterator : 
+	public std::iterator<std::random_access_iterator_tag, T, exint> 
+    {
+        public:
+	    typedef IT&		reference;
+	    typedef IT*		pointer;
+	
+	    // Note: When we drop gcc 4.4 support and allow range-based for
+	    // loops, we should also drop atEnd(), which means we can drop
+	    // myEnd here.
+	    base_iterator() : myCurrent(NULL), myEnd(NULL) {}
+	    
+	      // Allow iterator to const_iterator conversion
+	    template<typename EIT>
+	    base_iterator(const base_iterator<EIT, FORWARD> &src)
+		: myCurrent(src.myCurrent), myEnd(src.myEnd) {}
+	    
+	    pointer	operator->() const 
+			{ return FORWARD ? myCurrent : myCurrent - 1; }
+	    
+	    reference	operator*() const
+			{ return FORWARD ? *myCurrent : myCurrent[-1]; }
+
+	    reference	item() const
+			{ return FORWARD ? *myCurrent : myCurrent[-1]; }
+	    
+	    reference	operator[](exint n) const
+			{ return FORWARD ? myCurrent[n] : myCurrent[-n - 1]; } 
+
+	    /// Pre-increment operator
+            base_iterator &operator++()
+			{
+        		    if (FORWARD) ++myCurrent; else --myCurrent;
+			    return *this;
+			}
+	    /// Post-increment operator
+	    base_iterator operator++(int)
+			{
+			    base_iterator tmp = *this;
+        		    if (FORWARD) ++myCurrent; else --myCurrent;
+        		    return tmp;
+			}
+	    /// Pre-decrement operator
+	    base_iterator &operator--()
+			{
+			    if (FORWARD) --myCurrent; else ++myCurrent;
+			    return *this;
+			}
+	    /// Post-decrement operator
+	    base_iterator operator--(int)
+			{
+			    base_iterator tmp = *this;
+			    if (FORWARD) --myCurrent; else ++myCurrent;
+			    return tmp;
+			}
+
+	    base_iterator &operator+=(exint n)   
+			{
+			    if (FORWARD)
+				myCurrent += n;
+			    else
+				myCurrent -= n;
+			    return *this;
+			}
+            base_iterator operator+(exint n) const
+			{
+			    if (FORWARD)
+				return base_iterator(myCurrent + n, myEnd);
+			    else
+				return base_iterator(myCurrent - n, myEnd);
+			}
+	    
+            base_iterator &operator-=(exint n)
+        		{ return (*this) += (-n); }
+            base_iterator operator-(exint n) const
+			{ return (*this) + (-n); }
+            
+	    bool	 atEnd() const		{ return myCurrent == myEnd; }
+	    void	 advance()		{ this->operator++(); }
+	    
+	    // Comparators
+	    template<typename ITR, bool FR>
+	    bool 	 operator==(const base_iterator<ITR, FR> &r) const
+			 { return myCurrent == r.myCurrent; }
+	    
+	    template<typename ITR, bool FR>
+	    bool 	 operator!=(const base_iterator<ITR, FR> &r) const
+			 { return myCurrent != r.myCurrent; }
+	    
+	    template<typename ITR>
+	    bool	 operator<(const base_iterator<ITR, FORWARD> &r) const
+	    {
+		if (FORWARD) 
+		    return myCurrent < r.myCurrent;
+		else
+		    return r.myCurrent < myCurrent;
+	    }
+	    
+	    template<typename ITR>
+	    bool	 operator>(const base_iterator<ITR, FORWARD> &r) const
+	    {
+		if (FORWARD) 
+		    return myCurrent > r.myCurrent;
+		else
+		    return r.myCurrent > myCurrent;
+	    }
+
+	    template<typename ITR>
+	    bool	 operator<=(const base_iterator<ITR, FORWARD> &r) const
+	    {
+		if (FORWARD) 
+		    return myCurrent <= r.myCurrent;
+		else
+		    return r.myCurrent <= myCurrent;
+	    }
+
+	    template<typename ITR>
+	    bool	 operator>=(const base_iterator<ITR, FORWARD> &r) const
+	    {
+		if (FORWARD) 
+		    return myCurrent >= r.myCurrent;
+		else
+		    return r.myCurrent >= myCurrent;
+	    }
+	    
+	    // Difference operator for std::distance
+	    template<typename ITR>
+	    exint	 operator-(const base_iterator<ITR, FORWARD> &r) const
+	    {
+		if (FORWARD) 
+		    return exint(myCurrent - r.myCurrent);
+		else
+		    return exint(r.myCurrent - myCurrent);
+	    }
+	    
+	    
+        protected:
+	    friend class UT_Array<T>;
+	    base_iterator(IT *c, IT *e) : myCurrent(c), myEnd(e) {}
+	private:
+
+	    IT			*myCurrent;
+	    IT			*myEnd;
+    };
+    
+    typedef base_iterator<T, true>		iterator;
+    typedef base_iterator<const T, true>	const_iterator;
+    typedef base_iterator<T, false>		reverse_iterator;
+    typedef base_iterator<const T, false>	const_reverse_iterator;
+    typedef const_iterator	traverser; // For backward compatibility
+
+    /// Begin iterating over the array.  The contents of the array may be 
+    /// modified during the traversal.
+    iterator		begin()
+			{
+			    return iterator(myData, myData + mySize);
+			}
+    /// End iterator.
+    iterator		end()
+			{
+			    return iterator(myData + mySize,
+					    myData + mySize);
+			}
+
+    /// Begin iterating over the array.  The array may not be modified during
+    /// the traversal.
+    const_iterator	begin() const
+			{
+			    return const_iterator(myData, myData + mySize);
+			}
+    /// End const iterator.  Consider using it.atEnd() instead.
+    const_iterator	end() const
+			{
+			    return const_iterator(myData + mySize,
+						  myData + mySize);
+			}
+    
+    /// Begin iterating over the array in reverse. 
+    reverse_iterator	rbegin()
+			{
+			    return reverse_iterator(myData + mySize,
+			                            myData);
+			}
+    /// End reverse iterator.
+    reverse_iterator	rend()
+			{
+			    return reverse_iterator(myData, myData);
+			}
+    /// Begin iterating over the array in reverse. 
+    const_reverse_iterator rbegin() const
+			{
+			    return const_reverse_iterator(myData + mySize,
+							  myData);
+			}
+    /// End reverse iterator.  Consider using it.atEnd() instead.
+    const_reverse_iterator rend() const
+			{
+			    return const_reverse_iterator(myData, myData);
+			}
+    
+    /// Remove item specified by the reverse_iterator.
+    void		removeItem(const reverse_iterator &it)
+			{
+			    removeAt(&it.item() - myData);
+			}
+
+
+    /// Very dangerous methods to share arrays.
+    /// The array is not aware of the sharing, so ensure you clear
+    /// out the array prior a destructor or setCapacity operation.
+    void	    unsafeShareData(UT_Array<T> &src)
+		    {
+			myData = src.myData;
+			myCapacity = src.myCapacity;
+			mySize = src.mySize;
+		    }
+    void	    unsafeShareData(T *src, exint srcsize)
+		    {
+			myData = src;
+			myCapacity = srcsize;
+			mySize = srcsize;
+		    }
+    void	    unsafeShareData(T *src, exint size, exint capacity)
+		    {
+			myData = src;
+			mySize = size;
+			myCapacity = capacity;
+		    }
+    void	    unsafeClearData()
+		    {
+			myData = NULL;
+			myCapacity = 0;
+			mySize = 0;
+		    }
+
+    /// Returns true if the data used by the array was allocated on the heap.
+    inline bool	    isHeapBuffer() const
+		    {
+			return (myData != (T *)(((char*)this) + sizeof(*this)));
+		    }
+    inline bool	    isHeapBuffer(T* data) const
+		    {
+			return (data != (T *)(((char*)this) + sizeof(*this)));
+		    }
+
+protected:
+    // Check whether T may have a constructor, destructor, or copy
+    // constructor.  This test is conservative in that some POD types will
+    // not be recognized as POD by this function. To mark your type as POD,
+    // use the SYS_DECLARE_IS_POD() macro in SYS_TypeDecorate.h.
+    static constexpr SYS_FORCE_INLINE bool isPOD()
+    {
+        return std::is_pod<T>::value;
+    }
+
+    /// Implements both append(const T &) and append(T &&) via perfect
+    /// forwarding. Unlike the variadic emplace_back(), its argument may be a
+    /// reference to another element in the array.
+    template <typename S>
+    inline exint           appendImpl(S &&s);
+
+    /// Similar to appendImpl() but for insertion.
+    template <typename S>
+    inline exint           insertImpl(S &&s, exint index);
+
+    // Construct the given type
+    template <typename... S>
+    static void	    construct(T &dst, S&&... s)
+		    {
+                        new (&dst) T(std::forward<S>(s)...);
+		    }
+
+    // Copy construct the given type
+    static void	    copyConstruct(T &dst, const T &src)
+		    {
+			if (isPOD())
+			    dst = src;
+			else
+			    new (&dst) T(src);
+		    }
+    static void	    copyConstructRange(T *dst, const T *src, exint n)
+		    {
+			if (isPOD())
+                        {
+                            if (n > 0)
+                            {
+                                ::memcpy((void *)dst, (const void *)src,
+                                         n * sizeof(T));
+                            }
+                        }
+			else
+			{
+			    for (exint i = 0; i < n; i++)
+				new (&dst[i]) T(src[i]);
+			}
+		    }
+
+    /// Element Constructor
+    static void	    trivialConstruct(T &dst)
+		    {
+			if (!isPOD())
+			    new (&dst) T();
+			else
+			    memset((void *)&dst, 0, sizeof(T));
+		    }
+    static void	    trivialConstructRange(T *dst, exint n)
+		    {
+			if (!isPOD())
+			{
+			    for (exint i = 0; i < n; i++)
+				new (&dst[i]) T();
+			}
+			else if (n == 1)
+			{
+			    // Special case for n == 1. If the size parameter
+			    // passed to memset is known at compile time, this
+			    // function call will be inlined. This results in
+			    // much faster performance than a real memset
+			    // function call which is required in the case
+			    // below, where n is not known until runtime.
+			    // This makes calls to append() much faster.
+			    memset((void *)dst, 0, sizeof(T));
+			}
+			else
+			    memset((void *)dst, 0, sizeof(T) * n);
+		    }
+
+    /// Element Destructor
+    static void	    trivialDestruct(T &dst)
+		    {
+			if (!isPOD())
+			    dst.~T();
+		    }
+    static void	    trivialDestructRange(T *dst, exint n)
+		    {
+			if (!isPOD())
+			{
+			    for (exint i = 0; i < n; i++)
+				dst[i].~T();
+			}
+		    }
+
+private:
+    /// Pointer to the array of elements of type T
+    T *myData;
+
+    /// The number of elements for which we have allocated memory
+    exint myCapacity;
+
+    /// The actual number of valid elements in the array
+    exint mySize;
+
+    // The guts of the remove() methods.
+    inline exint	    removeAt(exint index);
+
+    inline T *		    allocateCapacity(exint num_items);
+};
+}}
+
+
+
+#endif // __UT_ARRAY_H_INCLUDED__
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      This is meant to be included by UT_Array.h and includes
+ *      the template implementations needed by external code.
+ */
+
+#pragma once
+
+#ifndef __UT_ARRAYIMPL_H_INCLUDED__
+#define __UT_ARRAYIMPL_H_INCLUDED__
+
+
+
+
+#include <algorithm>
+#include <utility>
+#include <stdlib.h>
+#include <string.h>
+
+namespace igl { namespace FastWindingNumber {
+
+// Implemented in UT_Array.C
+extern void ut_ArrayImplFree(void *p);
+
+
+template <typename T>
+inline UT_Array<T>::UT_Array(const UT_Array<T> &a)
+    : myCapacity(a.size()), mySize(a.size())
+{
+    if (myCapacity)
+    {
+	myData = allocateCapacity(myCapacity);
+	copyConstructRange(myData, a.array(), mySize);
+    }
+    else
+    {
+	myData = nullptr;
+    }
+}
+
+template <typename T>
+inline UT_Array<T>::UT_Array(std::initializer_list<T> init)
+    : myCapacity(init.size()), mySize(init.size())
+{
+    if (myCapacity)
+    {
+	myData = allocateCapacity(myCapacity);
+	copyConstructRange(myData, init.begin(), mySize);
+    }
+    else
+    {
+	myData = nullptr;
+    }
+}
+
+template <typename T>
+inline UT_Array<T>::UT_Array(UT_Array<T> &&a) noexcept
+{
+    if (!a.isHeapBuffer())
+    {
+	myData = nullptr;
+	myCapacity = 0;
+	mySize = 0;
+	operator=(std::move(a));
+	return;
+    }
+
+    myCapacity = a.myCapacity;
+    mySize = a.mySize;
+    myData = a.myData;
+    a.myCapacity = a.mySize = 0;
+    a.myData = nullptr;
+}
+
+
+template <typename T>
+inline UT_Array<T>::~UT_Array()
+{
+    // NOTE: We call setCapacity to ensure that we call trivialDestructRange,
+    //       then call free on myData.
+    setCapacity(0);
+}
+
+template <typename T>
+inline T *
+UT_Array<T>::allocateCapacity(exint capacity)
+{
+    T *data = (T *)malloc(capacity * sizeof(T));
+    // Avoid degenerate case if we happen to be aliased the wrong way
+    if (!isHeapBuffer(data))
+    {
+	T *prev = data;
+	data = (T *)malloc(capacity * sizeof(T));
+	ut_ArrayImplFree(prev);
+    }
+    return data;
+}
+
+template <typename T>
+inline void
+UT_Array<T>::swap( UT_Array<T> &other )
+{
+    std::swap( myData, other.myData );
+    std::swap( myCapacity, other.myCapacity );
+    std::swap( mySize, other.mySize );
+}
+
+
+template <typename T>
+inline exint	
+UT_Array<T>::insert(exint index)
+{
+    if (index >= mySize)
+    {
+	bumpCapacity(index + 1);
+
+	trivialConstructRange(myData + mySize, index - mySize + 1);
+
+	mySize = index+1;
+	return index;
+    }
+    bumpCapacity(mySize + 1);
+
+    UT_ASSERT_P(index >= 0);
+    ::memmove((void *)&myData[index+1], (void *)&myData[index],
+              ((mySize-index)*sizeof(T)));
+
+    trivialConstruct(myData[index]);
+
+    mySize++;
+    return index;
+}
+
+template <typename T>
+template <typename S>
+inline exint
+UT_Array<T>::appendImpl(S &&s)
+{
+    if (mySize == myCapacity)
+    {
+	exint idx = safeIndex(s);
+
+        // NOTE: UTbumpAlloc always returns a strictly larger value.
+	setCapacity(UTbumpAlloc(myCapacity));
+        if (idx >= 0)
+            construct(myData[mySize], std::forward<S>(myData[idx]));
+        else
+            construct(myData[mySize], std::forward<S>(s));
+    }
+    else
+    {
+	construct(myData[mySize], std::forward<S>(s));
+    }
+    return mySize++;
+}
+
+template <typename T>
+template <typename... S>
+inline exint
+UT_Array<T>::emplace_back(S&&... s)
+{
+    if (mySize == myCapacity)
+	setCapacity(UTbumpAlloc(myCapacity));
+
+    construct(myData[mySize], std::forward<S>(s)...);
+    return mySize++;
+}
+
+template <typename T>
+inline void
+UT_Array<T>::append(const T *pt, exint count)
+{
+    bumpCapacity(mySize + count);
+    copyConstructRange(myData + mySize, pt, count);
+    mySize += count;
+}
+
+template <typename T>
+inline void
+UT_Array<T>::appendMultiple(const T &t, exint count)
+{
+    UT_ASSERT_P(count >= 0);
+    if (count <= 0)
+	return;
+    if (mySize + count >= myCapacity)
+    {
+	exint tidx = safeIndex(t);
+
+        bumpCapacity(mySize + count);
+
+	for (exint i = 0; i < count; i++)
+	    copyConstruct(myData[mySize+i], tidx >= 0 ? myData[tidx] : t);
+    }
+    else
+    {
+	for (exint i = 0; i < count; i++)
+	    copyConstruct(myData[mySize+i], t);
+    }
+    mySize += count;
+}
+
+template <typename T>
+inline exint
+UT_Array<T>::concat(const UT_Array<T> &a)
+{
+    bumpCapacity(mySize + a.mySize);
+    copyConstructRange(myData + mySize, a.myData, a.mySize);
+    mySize += a.mySize;
+
+    return mySize;
+}
+
+template <typename T>
+inline exint
+UT_Array<T>::multipleInsert(exint beg_index, exint count)
+{
+    exint end_index = beg_index + count;
+
+    if (beg_index >= mySize)
+    {
+	bumpCapacity(end_index);
+
+	trivialConstructRange(myData + mySize, end_index - mySize);
+
+	mySize = end_index;
+	return beg_index;
+    }
+    bumpCapacity(mySize+count);
+
+    ::memmove((void *)&myData[end_index], (void *)&myData[beg_index],
+              ((mySize-beg_index)*sizeof(T)));
+    mySize += count;
+
+    trivialConstructRange(myData + beg_index, count);
+
+    return beg_index;
+}
+
+template <typename T>
+template <typename S>
+inline exint
+UT_Array<T>::insertImpl(S &&s, exint index)
+{
+    if (index == mySize)
+    {
+        // This case avoids an extraneous call to trivialConstructRange()
+        // which the compiler may not optimize out.
+        (void) appendImpl(std::forward<S>(s));
+    }
+    else if (index > mySize)
+    {
+	exint src_i = safeIndex(s);
+
+	bumpCapacity(index + 1);
+
+	trivialConstructRange(myData + mySize, index - mySize);
+
+        if (src_i >= 0)
+	    construct(myData[index], std::forward<S>(myData[src_i]));
+        else
+	    construct(myData[index], std::forward<S>(s));
+
+	mySize = index + 1;
+    }
+    else // (index < mySize)
+    {
+	exint src_i = safeIndex(s);
+
+        bumpCapacity(mySize + 1);
+
+        ::memmove((void *)&myData[index+1], (void *)&myData[index],
+                  ((mySize-index)*sizeof(T)));
+
+        if (src_i >= index)
+            ++src_i;
+
+        if (src_i >= 0)
+	    construct(myData[index], std::forward<S>(myData[src_i]));
+        else
+	    construct(myData[index], std::forward<S>(s));
+
+        ++mySize;
+    }
+
+    return index;
+}
+
+template <typename T>
+inline exint
+UT_Array<T>::removeAt(exint idx)
+{
+    trivialDestruct(myData[idx]);
+    if (idx != --mySize)
+    {
+	::memmove((void *)&myData[idx], (void *)&myData[idx+1],
+	          ((mySize-idx)*sizeof(T)));
+    }
+
+    return idx;
+}
+
+template <typename T>
+inline void
+UT_Array<T>::removeRange(exint begin_i, exint end_i)
+{
+    UT_ASSERT(begin_i <= end_i);
+    UT_ASSERT(end_i <= size());
+    if (end_i < size())
+    {
+	trivialDestructRange(myData + begin_i, end_i - begin_i);
+	::memmove((void *)&myData[begin_i], (void *)&myData[end_i],
+	          (mySize - end_i)*sizeof(T));
+    }
+    setSize(mySize - (end_i - begin_i));
+}
+
+template <typename T>
+inline void
+UT_Array<T>::extractRange(exint begin_i, exint end_i, UT_Array<T>& dest)
+{
+    UT_ASSERT_P(begin_i >= 0);
+    UT_ASSERT_P(begin_i <= end_i);
+    UT_ASSERT_P(end_i <= size());
+    UT_ASSERT(this != &dest);
+
+    exint nelements = end_i - begin_i;
+
+    // grow the raw array if necessary.
+    dest.setCapacityIfNeeded(nelements);
+
+    ::memmove((void*)dest.myData, (void*)&myData[begin_i],
+              nelements * sizeof(T));
+    dest.mySize = nelements;
+
+    // we just asserted this was true, but just in case
+    if (this != &dest)
+    {
+        if (end_i < size())
+        {
+            ::memmove((void*)&myData[begin_i], (void*)&myData[end_i],
+                      (mySize - end_i) * sizeof(T));
+        }
+        setSize(mySize - nelements);
+    }
+}
+
+template <typename T>
+inline void
+UT_Array<T>::move(exint srcIdx, exint destIdx, exint howMany)
+{
+    // Make sure all the parameters are valid.
+    if( srcIdx < 0 )
+	srcIdx = 0;
+    if( destIdx < 0 )
+	destIdx = 0;
+    // If we are told to move a set of elements that would extend beyond the
+    // end of the current array, trim the group.
+    if( srcIdx + howMany > size() )
+	howMany = size() - srcIdx;
+    // If the destIdx would have us move the source beyond the end of the
+    // current array, move the destIdx back.
+    if( destIdx + howMany > size() )
+	destIdx = size() - howMany;
+    if( srcIdx != destIdx && howMany > 0 )
+    {
+	void		**tmp = 0;
+	exint	  	savelen;
+
+	savelen = SYSabs(srcIdx - destIdx);
+	tmp = (void **)::malloc(savelen*sizeof(T));
+	if( srcIdx > destIdx && howMany > 0 )
+	{
+	    // We're moving the group backwards. Save all the stuff that
+	    // we would overwrite, plus everything beyond that to the
+	    // start of the source group. Then move the source group, then
+	    // tack the saved data onto the end of the moved group.
+	    ::memcpy(tmp, (void *)&myData[destIdx],  (savelen*sizeof(T)));
+	    ::memmove((void *)&myData[destIdx], (void *)&myData[srcIdx],
+	              (howMany*sizeof(T)));
+	    ::memcpy((void *)&myData[destIdx+howMany], tmp, (savelen*sizeof(T)));
+	}
+	if( srcIdx < destIdx && howMany > 0 )
+	{
+	    // We're moving the group forwards. Save from the end of the
+	    // group being moved to the end of the where the destination
+	    // group will end up. Then copy the source to the destination.
+	    // Then move back up to the original source location and drop
+	    // in our saved data.
+	    ::memcpy(tmp, (void *)&myData[srcIdx+howMany],  (savelen*sizeof(T)));
+	    ::memmove((void *)&myData[destIdx], (void *)&myData[srcIdx],
+	              (howMany*sizeof(T)));
+	    ::memcpy((void *)&myData[srcIdx], tmp, (savelen*sizeof(T)));
+	}
+	::free(tmp);
+    }
+}
+
+template <typename T>
+template <typename IsEqual>
+inline exint
+UT_Array<T>::removeIf(IsEqual is_equal)
+{
+    // Move dst to the first element to remove.
+    exint dst;
+    for (dst = 0; dst < mySize; dst++)
+    {
+	if (is_equal(myData[dst]))
+	    break;
+    }
+    // Now start looking at all the elements past the first one to remove.
+    for (exint idx = dst+1; idx < mySize; idx++)
+    {
+	if (!is_equal(myData[idx]))
+	{
+	    UT_ASSERT(idx != dst);
+	    myData[dst] = myData[idx];
+	    dst++;
+	}
+	// On match, ignore.
+    }
+    // New size
+    mySize = dst;
+    return mySize;
+}
+
+template <typename T>
+inline void
+UT_Array<T>::cycle(exint howMany)
+{
+    char	*tempPtr;
+    exint	 numShift;	//  The number of items we shift
+    exint   	 remaining;	//  mySize - numShift
+
+    if (howMany == 0 || mySize < 1) return;
+
+    numShift = howMany % (exint)mySize;
+    if (numShift < 0) numShift += mySize;
+    remaining = mySize - numShift;
+    tempPtr = new char[numShift*sizeof(T)];
+
+    ::memmove(tempPtr, (void *)&myData[remaining], (numShift * sizeof(T)));
+    ::memmove((void *)&myData[numShift], (void *)&myData[0], (remaining * sizeof(T)));
+    ::memmove((void *)&myData[0], tempPtr, (numShift * sizeof(T)));
+
+    delete [] tempPtr;
+}
+
+template <typename T>
+inline void
+UT_Array<T>::constant(const T &value)
+{
+    for (exint i = 0; i < mySize; i++)
+    {
+	myData[i] = value;
+    }
+}
+
+template <typename T>
+inline void
+UT_Array<T>::zero()
+{
+    if (isPOD())
+	::memset((void *)myData, 0, mySize*sizeof(T));
+    else
+	trivialConstructRange(myData, mySize);
+}
+
+template <typename T>
+inline void		
+UT_Array<T>::setCapacity(exint capacity)
+{
+    // Do nothing when new capacity is the same as the current
+    if (capacity == myCapacity)
+	return;
+
+    // Special case for non-heap buffers
+    if (!isHeapBuffer())
+    {
+	if (capacity < mySize)
+	{
+	    // Destroy the extra elements without changing myCapacity
+	    trivialDestructRange(myData + capacity, mySize - capacity);
+	    mySize = capacity;
+	}
+	else if (capacity > myCapacity)
+	{
+	    T *prev = myData;
+	    myData = (T *)malloc(sizeof(T) * capacity);
+	    // myData is safe because we're already a stack buffer
+	    UT_ASSERT_P(isHeapBuffer());
+	    if (mySize > 0)
+		memcpy((void *)myData, (void *)prev, sizeof(T) * mySize);
+	    myCapacity = capacity;
+	}
+	else 
+	{
+	    // Keep myCapacity unchanged in this case
+	    UT_ASSERT_P(capacity >= mySize && capacity <= myCapacity);
+	}
+	return;
+    }
+
+    if (capacity == 0)
+    {
+	if (myData)
+	{
+	    trivialDestructRange(myData, mySize);
+	    free(myData);
+	}
+	myData     = 0;
+	myCapacity = 0;
+        mySize = 0;
+	return;
+    }
+
+    if (capacity < mySize)
+    {
+	trivialDestructRange(myData + capacity, mySize - capacity);
+	mySize = capacity;
+    }
+
+    if (myData)
+	myData = (T *)realloc(myData, capacity*sizeof(T));
+    else
+	myData = (T *)malloc(sizeof(T) * capacity);
+
+    // Avoid degenerate case if we happen to be aliased the wrong way
+    if (!isHeapBuffer())
+    {
+	T *prev = myData;
+	myData = (T *)malloc(sizeof(T) * capacity);
+	if (mySize > 0)
+	    memcpy((void *)myData, (void *)prev, sizeof(T) * mySize);
+	ut_ArrayImplFree(prev);
+    }
+
+    myCapacity = capacity;
+    UT_ASSERT(myData);
+}
+
+template <typename T>
+inline UT_Array<T> &
+UT_Array<T>::operator=(const UT_Array<T> &a)
+{
+    if (this == &a)
+	return *this;
+
+    // Grow the raw array if necessary.
+    setCapacityIfNeeded(a.size());
+
+    // Make sure destructors and constructors are called on all elements
+    // being removed/added.
+    trivialDestructRange(myData, mySize);
+    copyConstructRange(myData, a.myData, a.size());
+
+    mySize = a.size();
+
+    return *this;
+}
+
+template <typename T>
+inline UT_Array<T> &
+UT_Array<T>::operator=(std::initializer_list<T> a)
+{
+    const exint new_size = a.size();
+
+    // Grow the raw array if necessary.
+    setCapacityIfNeeded(new_size);
+
+    // Make sure destructors and constructors are called on all elements
+    // being removed/added.
+    trivialDestructRange(myData, mySize);
+
+    copyConstructRange(myData, a.begin(), new_size);
+
+    mySize = new_size;
+
+    return *this;
+}
+
+template <typename T>
+inline UT_Array<T> &
+UT_Array<T>::operator=(UT_Array<T> &&a)
+{
+    if (!a.isHeapBuffer())
+    {
+	// Cannot steal from non-heap buffers
+	clear();
+	const exint n = a.size();
+	setCapacityIfNeeded(n);
+	if (isPOD())
+	{
+	    if (n > 0)
+		memcpy(myData, a.myData, n * sizeof(T));
+	}
+	else
+	{
+	    for (exint i = 0; i < n; ++i)
+		new (&myData[i]) T(std::move(a.myData[i]));
+	}
+	mySize = a.mySize;
+	a.mySize = 0;
+	return *this;
+    }
+    // else, just steal even if we're a small buffer
+
+    // Destroy all the elements we're currently holding.
+    if (myData)
+    {
+	trivialDestructRange(myData, mySize);
+	if (isHeapBuffer())
+	    ::free(myData);
+    }
+    
+    // Move the contents of the other array to us and empty the other container
+    // so that it destructs cleanly.
+    myCapacity = a.myCapacity;
+    mySize = a.mySize;
+    myData = a.myData;
+    a.myCapacity = a.mySize = 0;
+    a.myData = nullptr;
+
+    return *this;
+}
+
+
+template <typename T>
+inline bool
+UT_Array<T>::operator==(const UT_Array<T> &a) const
+{
+    if (this == &a) return true;
+    if (mySize != a.size()) return false;
+    for (exint i = 0; i < mySize; i++)
+	if (!(myData[i] == a(i))) return false;
+    return true;
+}
+
+template <typename T>
+inline bool
+UT_Array<T>::operator!=(const UT_Array<T> &a) const
+{
+    return (!operator==(a));
+}
+
+}}
+
+#endif // __UT_ARRAYIMPL_H_INCLUDED__
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      Special case for arrays that are usually small,
+ *      to avoid a heap allocation when the array really is small.
+ */
+
+#pragma once
+
+#ifndef __UT_SMALLARRAY_H_INCLUDED__
+#define __UT_SMALLARRAY_H_INCLUDED__
+
+
+
+#include <utility>
+#include <stddef.h>
+namespace igl { namespace FastWindingNumber {
+
+/// An array class with the small buffer optimization, making it ideal for
+/// cases when you know it will only contain a few elements at the expense of
+/// increasing the object size by MAX_BYTES (subject to alignment).
+template <typename T, size_t MAX_BYTES = 64>
+class UT_SmallArray : public UT_Array<T>
+{
+    // As many elements that fit into MAX_BYTES with 1 item minimum
+    enum { MAX_ELEMS = MAX_BYTES/sizeof(T) < 1 ? 1 : MAX_BYTES/sizeof(T) };
+
+public:
+
+// gcc falsely warns about our use of offsetof() on non-POD types. We can't
+// easily suppress this because it has to be done in the caller at
+// instantiation time. Instead, punt to a runtime check instead.
+#if defined(__clang__) || defined(_MSC_VER)
+    #define UT_SMALL_ARRAY_SIZE_ASSERT()    \
+        using ThisT = UT_SmallArray<T,MAX_BYTES>; \
+	static_assert(offsetof(ThisT, myBuffer) == sizeof(UT_Array<T>), \
+            "In order for UT_Array's checks for whether it needs to free the buffer to work, " \
+            "the buffer must be exactly following the base class memory.")
+#else
+    #define UT_SMALL_ARRAY_SIZE_ASSERT()    \
+	UT_ASSERT_P(!UT_Array<T>::isHeapBuffer());
+#endif
+
+    /// Default construction
+    UT_SmallArray()
+	: UT_Array<T>(/*capacity*/0)
+    {
+	UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
+	UT_SMALL_ARRAY_SIZE_ASSERT();
+    }
+    
+    /// Copy constructor
+    /// @{
+    explicit UT_SmallArray(const UT_Array<T> &copy)
+	: UT_Array<T>(/*capacity*/0)
+    {
+	UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
+	UT_SMALL_ARRAY_SIZE_ASSERT();
+	UT_Array<T>::operator=(copy);
+    }
+    explicit UT_SmallArray(const UT_SmallArray<T,MAX_BYTES> &copy)
+	: UT_Array<T>(/*capacity*/0)
+    {
+	UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
+	UT_SMALL_ARRAY_SIZE_ASSERT();
+	UT_Array<T>::operator=(copy);
+    }
+    /// @}
+
+    /// Move constructor
+    /// @{
+    UT_SmallArray(UT_Array<T> &&movable) noexcept
+    {
+	UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
+	UT_SMALL_ARRAY_SIZE_ASSERT();
+	UT_Array<T>::operator=(std::move(movable));
+    }
+    UT_SmallArray(UT_SmallArray<T,MAX_BYTES> &&movable) noexcept
+    {
+	UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
+	UT_SMALL_ARRAY_SIZE_ASSERT();
+	UT_Array<T>::operator=(std::move(movable));
+    }
+    /// @}
+
+    /// Initializer list constructor
+    explicit UT_SmallArray(std::initializer_list<T> init)
+    {
+        UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
+        UT_SMALL_ARRAY_SIZE_ASSERT();
+        UT_Array<T>::operator=(init);
+    }
+
+#undef UT_SMALL_ARRAY_SIZE_ASSERT
+
+    /// Assignment operator
+    /// @{
+    UT_SmallArray<T,MAX_BYTES> &
+    operator=(const UT_SmallArray<T,MAX_BYTES> &copy)
+    {
+	UT_Array<T>::operator=(copy);
+	return *this;
+    }
+    UT_SmallArray<T,MAX_BYTES> &
+    operator=(const UT_Array<T> &copy)
+    {
+	UT_Array<T>::operator=(copy);
+	return *this;
+    }
+    /// @}
+
+    /// Move operator
+    /// @{
+    UT_SmallArray<T,MAX_BYTES> &
+    operator=(UT_SmallArray<T,MAX_BYTES> &&movable)
+    {
+	UT_Array<T>::operator=(std::move(movable));
+	return *this;
+    }
+    UT_SmallArray<T,MAX_BYTES> &
+    operator=(UT_Array<T> &&movable)
+    {
+        UT_Array<T>::operator=(std::move(movable));
+        return *this;
+    }
+    /// @}
+
+    UT_SmallArray<T,MAX_BYTES> &
+    operator=(std::initializer_list<T> src)
+    {
+        UT_Array<T>::operator=(src);
+        return *this;
+    }
+private:
+    alignas(T) char myBuffer[MAX_ELEMS*sizeof(T)];
+};
+}}
+
+#endif // __UT_SMALLARRAY_H_INCLUDED__
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      A vector class templated on its size and data type.
+ */
+
+#pragma once
+
+#ifndef __UT_FixedVector__
+#define __UT_FixedVector__
+
+
+
+
+namespace igl { namespace FastWindingNumber {
+
+template<typename T,exint SIZE,bool INSTANTIATED=false>
+class UT_FixedVector
+{
+public:
+    typedef UT_FixedVector<T,SIZE,INSTANTIATED> ThisType;
+    typedef T value_type;
+    typedef T theType;
+    static const exint theSize = SIZE;
+
+    T vec[SIZE];
+
+    SYS_FORCE_INLINE UT_FixedVector() = default;
+
+    /// Initializes every component to the same value
+    SYS_FORCE_INLINE explicit UT_FixedVector(T that) noexcept
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] = that;
+    }
+
+    SYS_FORCE_INLINE UT_FixedVector(const ThisType &that) = default;
+    SYS_FORCE_INLINE UT_FixedVector(ThisType &&that) = default;
+
+    /// Converts vector of S into vector of T,
+    /// or just copies if same type.
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE UT_FixedVector(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) noexcept
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] = that[i];
+    }
+
+    template<typename S>
+    SYS_FORCE_INLINE UT_FixedVector(const S that[SIZE]) noexcept
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] = that[i];
+    }
+
+    SYS_FORCE_INLINE const T &operator[](exint i) const noexcept
+    {
+        UT_ASSERT_P(i >= 0 && i < SIZE);
+        return vec[i];
+    }
+    SYS_FORCE_INLINE T &operator[](exint i) noexcept
+    {
+        UT_ASSERT_P(i >= 0 && i < SIZE);
+        return vec[i];
+    }
+
+    SYS_FORCE_INLINE constexpr const T *data() const noexcept
+    {
+        return vec;
+    }
+    SYS_FORCE_INLINE T *data() noexcept
+    {
+        return vec;
+    }
+
+    SYS_FORCE_INLINE ThisType &operator=(const ThisType &that) = default;
+    SYS_FORCE_INLINE ThisType &operator=(ThisType &&that) = default;
+
+    template <typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE ThisType &operator=(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) noexcept
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] = that[i];
+        return *this;
+    }
+    SYS_FORCE_INLINE const ThisType &operator=(T that) noexcept
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] = that;
+        return *this;
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE void operator+=(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that)
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] += that[i];
+    }
+    SYS_FORCE_INLINE void operator+=(T that)
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] += that;
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE auto operator+(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) const -> UT_FixedVector<decltype(vec[0]+that[0]),SIZE>
+    {
+        using Type = decltype(vec[0]+that[0]);
+        UT_FixedVector<Type,SIZE> result;
+        for (exint i = 0; i < SIZE; ++i)
+            result[i] = vec[i] + that[i];
+        return result;
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE void operator-=(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that)
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] -= that[i];
+    }
+    SYS_FORCE_INLINE void operator-=(T that)
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] -= that;
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE auto operator-(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) const -> UT_FixedVector<decltype(vec[0]-that[0]),SIZE>
+    {
+        using Type = decltype(vec[0]-that[0]);
+        UT_FixedVector<Type,SIZE> result;
+        for (exint i = 0; i < SIZE; ++i)
+            result[i] = vec[i] - that[i];
+        return result;
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE void operator*=(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that)
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] *= that[i];
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE auto operator*(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) const -> UT_FixedVector<decltype(vec[0]*that[0]),SIZE>
+    {
+        using Type = decltype(vec[0]*that[0]);
+        UT_FixedVector<Type,SIZE> result;
+        for (exint i = 0; i < SIZE; ++i)
+            result[i] = vec[i] * that[i];
+        return result;
+    }
+    SYS_FORCE_INLINE void operator*=(T that)
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] *= that;
+    }
+    SYS_FORCE_INLINE UT_FixedVector<T,SIZE> operator*(T that) const
+    {
+        UT_FixedVector<T,SIZE> result;
+        for (exint i = 0; i < SIZE; ++i)
+            result[i] = vec[i] * that;
+        return result;
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE void operator/=(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that)
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] /= that[i];
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE auto operator/(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) const -> UT_FixedVector<decltype(vec[0]/that[0]),SIZE>
+    {
+        using Type = decltype(vec[0]/that[0]);
+        UT_FixedVector<Type,SIZE> result;
+        for (exint i = 0; i < SIZE; ++i)
+            result[i] = vec[i] / that[i];
+        return result;
+    }
+
+    SYS_FORCE_INLINE void operator/=(T that)
+    {
+        if (std::is_integral<T>::value)
+        {
+            for (exint i = 0; i < SIZE; ++i)
+                vec[i] /= that;
+        }
+        else
+        {
+            that = 1/that;
+            for (exint i = 0; i < SIZE; ++i)
+                vec[i] *= that;
+        }
+    }
+    SYS_FORCE_INLINE UT_FixedVector<T,SIZE> operator/(T that) const
+    {
+        UT_FixedVector<T,SIZE> result;
+        if (std::is_integral<T>::value)
+        {
+            for (exint i = 0; i < SIZE; ++i)
+                result[i] = vec[i] / that;
+        }
+        else
+        {
+            that = 1/that;
+            for (exint i = 0; i < SIZE; ++i)
+                result[i] = vec[i] * that;
+        }
+        return result;
+    }
+    SYS_FORCE_INLINE void negate()
+    {
+        for (exint i = 0; i < SIZE; ++i)
+            vec[i] = -vec[i];
+    }
+
+    SYS_FORCE_INLINE UT_FixedVector<T,SIZE> operator-() const
+    {
+        UT_FixedVector<T,SIZE> result;
+        for (exint i = 0; i < SIZE; ++i)
+            result[i] = -vec[i];
+        return result;
+    }
+
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE bool operator==(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) const noexcept
+    {
+        for (exint i = 0; i < SIZE; ++i)
+        {
+            if (vec[i] != T(that[i]))
+                return false;
+        }
+        return true;
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE bool operator!=(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) const noexcept
+    {
+        return !(*this==that);
+    }
+    SYS_FORCE_INLINE bool isZero() const noexcept
+    {
+        for (exint i = 0; i < SIZE; ++i)
+        {
+            if (vec[i] != T(0))
+                return false;
+        }
+        return true;
+    }
+    SYS_FORCE_INLINE T maxComponent() const
+    {
+        T v = vec[0];
+        for (exint i = 1; i < SIZE; ++i)
+            v = (vec[i] > v) ? vec[i] : v;
+        return v;
+    }
+    SYS_FORCE_INLINE T minComponent() const
+    {
+        T v = vec[0];
+        for (exint i = 1; i < SIZE; ++i)
+            v = (vec[i] < v) ? vec[i] : v;
+        return v;
+    }
+    SYS_FORCE_INLINE T avgComponent() const
+    {
+        T v = vec[0];
+        for (exint i = 1; i < SIZE; ++i)
+            v += vec[i];
+        return v / SIZE;
+    }
+
+    SYS_FORCE_INLINE T length2() const noexcept
+    {
+        T a0(vec[0]);
+        T result(a0*a0);
+        for (exint i = 1; i < SIZE; ++i)
+        {
+            T ai(vec[i]);
+            result += ai*ai;
+        }
+        return result;
+    }
+    SYS_FORCE_INLINE T length() const
+    {
+        T len2 = length2();
+        return SYSsqrt(len2);
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE auto dot(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) const -> decltype(vec[0]*that[0])
+    {
+        using TheType = decltype(vec[0]*that.vec[0]);
+        TheType result(vec[0]*that[0]);
+        for (exint i = 1; i < SIZE; ++i)
+            result += vec[i]*that[i];
+        return result;
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE auto distance2(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) const -> decltype(vec[0]-that[0])
+    {
+        using TheType = decltype(vec[0]-that[0]);
+        TheType v(vec[0] - that[0]);
+        TheType result(v*v);
+        for (exint i = 1; i < SIZE; ++i)
+        {
+            v = vec[i] - that[i];
+            result += v*v;
+        }
+        return result;
+    }
+    template<typename S,bool S_INSTANTIATED>
+    SYS_FORCE_INLINE auto distance(const UT_FixedVector<S,SIZE,S_INSTANTIATED> &that) const -> decltype(vec[0]-that[0])
+    {
+        auto dist2 = distance2(that);
+        return SYSsqrt(dist2);
+    }
+
+    SYS_FORCE_INLINE T normalize()
+    {
+        T len2 = length2();
+        if (len2 == T(0))
+            return T(0);
+        if (len2 == T(1))
+            return T(1);
+        T len = SYSsqrt(len2);
+        // Check if the square root is equal 1.  sqrt(1+dx) ~ 1+dx/2,
+        // so it may get rounded to 1 when it wasn't 1 before.
+        if (len != T(1))
+            (*this) /= len;
+        return len;
+    }
+};
+
+/// NOTE: Strictly speaking, this should use decltype(that*a[0]),
+///       but in the interests of avoiding accidental precision escalation,
+///       it uses T.
+template<typename T,exint SIZE,bool INSTANTIATED,typename S>
+SYS_FORCE_INLINE UT_FixedVector<T,SIZE> operator*(const S &that,const UT_FixedVector<T,SIZE,INSTANTIATED> &a)
+{
+    T t(that);
+    UT_FixedVector<T,SIZE> result;
+    for (exint i = 0; i < SIZE; ++i)
+        result[i] = t * a[i];
+    return result;
+}
+
+template<typename T, exint SIZE, bool INSTANTIATED, typename S, bool S_INSTANTIATED>
+SYS_FORCE_INLINE auto
+dot(const UT_FixedVector<T,SIZE,INSTANTIATED> &a, const UT_FixedVector<S,SIZE,S_INSTANTIATED> &b) -> decltype(a[0]*b[0])
+{
+    return a.dot(b);
+}
+
+template<typename T, exint SIZE, bool INSTANTIATED, typename S, bool S_INSTANTIATED>
+SYS_FORCE_INLINE auto
+SYSmin(const UT_FixedVector<T,SIZE,INSTANTIATED> &a, const UT_FixedVector<S,SIZE,S_INSTANTIATED> &b) -> UT_FixedVector<decltype(a[0]+b[1]), SIZE>
+{
+    using Type = decltype(a[0]+b[1]);
+    UT_FixedVector<Type, SIZE> result;
+    for (exint i = 0; i < SIZE; ++i)
+        result[i] = SYSmin(Type(a[i]), Type(b[i]));
+    return result;
+}
+
+template<typename T, exint SIZE, bool INSTANTIATED, typename S, bool S_INSTANTIATED>
+SYS_FORCE_INLINE auto
+SYSmax(const UT_FixedVector<T,SIZE,INSTANTIATED> &a, const UT_FixedVector<S,SIZE,S_INSTANTIATED> &b) -> UT_FixedVector<decltype(a[0]+b[1]), SIZE>
+{
+    using Type = decltype(a[0]+b[1]);
+    UT_FixedVector<Type, SIZE> result;
+    for (exint i = 0; i < SIZE; ++i)
+        result[i] = SYSmax(Type(a[i]), Type(b[i]));
+    return result;
+}
+
+template<typename T>
+struct UT_FixedVectorTraits
+{
+    typedef UT_FixedVector<T,1> FixedVectorType;
+    typedef T DataType;
+    static const exint TupleSize = 1;
+    static const bool isVectorType = false;
+};
+
+template<typename T,exint SIZE,bool INSTANTIATED>
+struct UT_FixedVectorTraits<UT_FixedVector<T,SIZE,INSTANTIATED> >
+{
+    typedef UT_FixedVector<T,SIZE,INSTANTIATED> FixedVectorType;
+    typedef T DataType;
+    static const exint TupleSize = SIZE;
+    static const bool isVectorType = true;
+};
+}}
+
+#endif
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      Simple wrappers on tbb interface
+ */
+
+#ifndef __UT_ParallelUtil__
+#define __UT_ParallelUtil__
+
+
+
+#include <thread> // This is just included for std::thread::hardware_concurrency()
+namespace igl { namespace FastWindingNumber {
+namespace UT_Thread { inline int getNumProcessors() {
+    return std::thread::hardware_concurrency();
+}}
+
+//#include "tbb/blocked_range.h"
+//#include "tbb/parallel_for.h"
+////namespace tbb { class split; }
+//
+///// Declare prior to use.
+//template <typename T> 
+//using UT_BlockedRange = tbb::blocked_range<T>;
+//
+//// Default implementation that calls range.size()
+//template< typename RANGE >
+//struct UT_EstimatorNumItems
+//{
+//    UT_EstimatorNumItems() {}
+//
+//    size_t operator()(const RANGE& range) const
+//    {
+//	return range.size();
+//    }
+//};
+//
+///// This is needed by UT_CoarsenedRange
+//template <typename RANGE>
+//inline size_t UTestimatedNumItems(const RANGE& range)
+//{
+//    return UT_EstimatorNumItems<RANGE>()(range);
+//}
+//
+///// UT_CoarsenedRange: This should be used only inside 
+///// UT_ParallelFor and UT_ParallelReduce
+///// This class wraps an existing range with a new range.
+///// This allows us to use simple_partitioner, rather than
+///// auto_partitioner, which has disastrous performance with
+///// the default grain size in ttb 4.
+//template< typename RANGE >
+//class UT_CoarsenedRange : public RANGE
+//{
+//public:
+//    // Compiler-generated versions are fine:
+//    // ~UT_CoarsenedRange();
+//    // UT_CoarsenedRange(const UT_CoarsenedRange&);
+//
+//    // Split into two sub-ranges:
+//    UT_CoarsenedRange(UT_CoarsenedRange& range, tbb::split spl) :
+//        RANGE(range, spl),
+//        myGrainSize(range.myGrainSize)
+//    {        
+//    }
+//
+//    // Inherited: bool empty() const
+//
+//    bool is_divisible() const
+//    {
+//        return 
+//            RANGE::is_divisible() &&
+//            (UTestimatedNumItems(static_cast<const RANGE&>(*this)) > myGrainSize);
+//    }
+//
+//private:
+//    size_t myGrainSize;
+//
+//    UT_CoarsenedRange(const RANGE& base_range, const size_t grain_size) :
+//        RANGE(base_range),
+//        myGrainSize(grain_size)
+//    {        
+//    }
+//
+//    template <typename Range, typename Body>
+//    friend void UTparallelFor(
+//        const Range &range, const Body &body,
+//        const int subscribe_ratio, const int min_grain_size
+//    );
+//};
+//
+///// Run the @c body function over a range in parallel.
+///// UTparallelFor attempts to spread the range out over at most 
+///// subscribe_ratio * num_processor tasks.
+///// The factor subscribe_ratio can be used to help balance the load.
+///// UTparallelFor() uses tbb for its implementation.
+///// The used grain size is the maximum of min_grain_size and
+///// if UTestimatedNumItems(range) / (subscribe_ratio * num_processor).
+///// If subscribe_ratio == 0, then a grain size of min_grain_size will be used.
+///// A range can be split only when UTestimatedNumItems(range) exceeds the
+///// grain size the range is divisible. 
+//
+/////
+///// Requirements for the Range functor are:
+/////   - the requirements of the tbb Range Concept
+/////   - UT_estimatorNumItems<Range> must return the the estimated number of work items
+/////     for the range. When Range::size() is not the correct estimate, then a 
+/////     (partial) specialization of UT_estimatorNumItemsimatorRange must be provided
+/////     for the type Range.
+/////
+///// Requirements for the Body function are:
+/////  - @code Body(const Body &); @endcode @n
+/////	Copy Constructor
+/////  - @code Body()::~Body(); @endcode @n
+/////	Destructor
+/////  - @code void Body::operator()(const Range &range) const; @endcode
+/////	Function call to perform operation on the range.  Note the operator is
+/////	@b const.
+/////
+///// The requirements for a Range object are:
+/////  - @code Range::Range(const Range&); @endcode @n
+/////	Copy constructor
+/////  - @code Range::~Range(); @endcode @n
+/////	Destructor
+/////  - @code bool Range::is_divisible() const; @endcode @n
+/////	True if the range can be partitioned into two sub-ranges
+/////  - @code bool Range::empty() const; @endcode @n
+/////	True if the range is empty
+/////  - @code Range::Range(Range &r, UT_Split) const; @endcode @n
+/////	Split the range @c r into two sub-ranges (i.e. modify @c r and *this)
+/////
+///// Example: @code
+/////     class Square {
+/////     public:
+/////         Square(double *data) : myData(data) {}
+/////         ~Square();
+/////         void operator()(const UT_BlockedRange<int64> &range) const
+/////         {
+/////             for (int64 i = range.begin(); i != range.end(); ++i)
+/////                 myData[i] *= myData[i];
+/////         }
+/////         double *myData;
+/////     };
+/////     ...
+/////
+/////     void
+/////     parallel_square(double *array, int64 length)
+/////     {
+/////         UTparallelFor(UT_BlockedRange<int64>(0, length), Square(array));
+/////     }
+///// @endcode
+/////	
+///// @see UTparallelReduce(), UT_BlockedRange()
+//
+//template <typename Range, typename Body>
+//void UTparallelFor(
+//    const Range &range, const Body &body,
+//    const int subscribe_ratio = 2,
+//    const int min_grain_size = 1
+//)
+//{
+//    const size_t num_processors( UT_Thread::getNumProcessors() );
+//
+//    UT_ASSERT( num_processors >= 1 );
+//    UT_ASSERT( min_grain_size >= 1 );
+//    UT_ASSERT( subscribe_ratio >= 0 );
+//
+//    const size_t est_range_size( UTestimatedNumItems(range) );
+//
+//    // Don't run on an empty range!
+//    if (est_range_size == 0)
+//        return;
+//
+//    // Avoid tbb overhead if entire range needs to be single threaded
+//    if (num_processors == 1 || est_range_size <= min_grain_size)
+//    {
+//        body(range);
+//        return;
+//    }
+//
+//    size_t grain_size(min_grain_size);
+//    if( subscribe_ratio > 0 )
+//        grain_size = std::max(
+//                         grain_size, 
+//                         est_range_size / (subscribe_ratio * num_processors)
+//                     );
+//
+//    UT_CoarsenedRange< Range > coarsened_range(range, grain_size);
+//
+//    tbb::parallel_for(coarsened_range, body, tbb::simple_partitioner());
+//}
+//
+///// Version of UTparallelFor that is tuned for the case where the range
+///// consists of lightweight items, for example,
+///// float additions or matrix-vector multiplications.
+//template <typename Range, typename Body>
+//void
+//UTparallelForLightItems(const Range &range, const Body &body)
+//{
+//    UTparallelFor(range, body, 2, 1024);
+//}
+//
+///// UTserialFor can be used as a debugging tool to quickly replace a parallel
+///// for with a serial for.
+//template <typename Range, typename Body>
+//void UTserialFor(const Range &range, const Body &body)
+//	{ body(range); }
+//
+}}
+#endif
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      Bounding Volume Hierarchy (BVH) implementation.
+ *      To call functions not implemented here, also include UT_BVHImpl.h
+ */
+
+#pragma once
+
+#ifndef __HDK_UT_BVH_h__
+#define __HDK_UT_BVH_h__
+
+
+
+
+#include <limits>
+#include <memory>
+namespace igl { namespace FastWindingNumber {
+
+template<typename T> class UT_Array;
+class v4uf;
+class v4uu;
+
+namespace HDK_Sample {
+
+namespace UT {
+
+template<typename T,uint NAXES>
+struct Box {
+    T vals[NAXES][2];
+
+    SYS_FORCE_INLINE Box() noexcept = default;
+    SYS_FORCE_INLINE constexpr Box(const Box &other) noexcept = default;
+    SYS_FORCE_INLINE constexpr Box(Box &&other) noexcept = default;
+    SYS_FORCE_INLINE Box& operator=(const Box &other) noexcept = default;
+    SYS_FORCE_INLINE Box& operator=(Box &&other) noexcept = default;
+
+    template<typename S>
+    SYS_FORCE_INLINE Box(const Box<S,NAXES>& other) noexcept {
+        static_assert((std::is_pod<Box<T,NAXES>>::value) || !std::is_pod<T>::value,
+            "UT::Box should be POD, for better performance in UT_Array, etc.");
+
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            vals[axis][0] = T(other.vals[axis][0]);
+            vals[axis][1] = T(other.vals[axis][1]);
+        }
+    }
+    template<typename S,bool INSTANTIATED>
+    SYS_FORCE_INLINE Box(const UT_FixedVector<S,NAXES,INSTANTIATED>& pt) noexcept {
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            vals[axis][0] = pt[axis];
+            vals[axis][1] = pt[axis];
+        }
+    }
+    template<typename S>
+    SYS_FORCE_INLINE Box& operator=(const Box<S,NAXES>& other) noexcept {
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            vals[axis][0] = T(other.vals[axis][0]);
+            vals[axis][1] = T(other.vals[axis][1]);
+        }
+        return *this;
+    }
+
+    SYS_FORCE_INLINE const T* operator[](const size_t axis) const noexcept {
+        UT_ASSERT_P(axis < NAXES);
+        return vals[axis];
+    }
+    SYS_FORCE_INLINE T* operator[](const size_t axis) noexcept {
+        UT_ASSERT_P(axis < NAXES);
+        return vals[axis];
+    }
+
+    SYS_FORCE_INLINE void initBounds() noexcept {
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            vals[axis][0] = std::numeric_limits<T>::max();
+            vals[axis][1] = -std::numeric_limits<T>::max();
+        }
+    }
+    /// Copy the source box.
+    /// NOTE: This is so that in templated code that may have a Box or a
+    ///       UT_FixedVector, it can call initBounds and still work.
+    SYS_FORCE_INLINE void initBounds(const Box<T,NAXES>& src) noexcept {
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            vals[axis][0] = src.vals[axis][0];
+            vals[axis][1] = src.vals[axis][1];
+        }
+    }
+    /// Initialize with the union of the source boxes.
+    /// NOTE: This is so that in templated code that may have Box's or a
+    ///       UT_FixedVector's, it can call initBounds and still work.
+    SYS_FORCE_INLINE void initBoundsUnordered(const Box<T,NAXES>& src0, const Box<T,NAXES>& src1) noexcept {
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            vals[axis][0] = SYSmin(src0.vals[axis][0], src1.vals[axis][0]);
+            vals[axis][1] = SYSmax(src0.vals[axis][1], src1.vals[axis][1]);
+        }
+    }
+    SYS_FORCE_INLINE void combine(const Box<T,NAXES>& src) noexcept {
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            T& minv = vals[axis][0];
+            T& maxv = vals[axis][1];
+            const T curminv = src.vals[axis][0];
+            const T curmaxv = src.vals[axis][1];
+            minv = (minv < curminv) ? minv : curminv;
+            maxv = (maxv > curmaxv) ? maxv : curmaxv;
+        }
+    }
+    SYS_FORCE_INLINE void enlargeBounds(const Box<T,NAXES>& src) noexcept {
+        combine(src);
+    }
+
+    template<typename S,bool INSTANTIATED>
+    SYS_FORCE_INLINE
+    void initBounds(const UT_FixedVector<S,NAXES,INSTANTIATED>& pt) noexcept {
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            vals[axis][0] = pt[axis];
+            vals[axis][1] = pt[axis];
+        }
+    }
+    template<bool INSTANTIATED>
+    SYS_FORCE_INLINE
+    void initBounds(const UT_FixedVector<T,NAXES,INSTANTIATED>& min, const UT_FixedVector<T,NAXES,INSTANTIATED>& max) noexcept {
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            vals[axis][0] = min[axis];
+            vals[axis][1] = max[axis];
+        }
+    }
+    template<bool INSTANTIATED>
+    SYS_FORCE_INLINE
+    void initBoundsUnordered(const UT_FixedVector<T,NAXES,INSTANTIATED>& p0, const UT_FixedVector<T,NAXES,INSTANTIATED>& p1) noexcept {
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            vals[axis][0] = SYSmin(p0[axis], p1[axis]);
+            vals[axis][1] = SYSmax(p0[axis], p1[axis]);
+        }
+    }
+    template<bool INSTANTIATED>
+    SYS_FORCE_INLINE
+    void enlargeBounds(const UT_FixedVector<T,NAXES,INSTANTIATED>& pt) noexcept {
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            vals[axis][0] = SYSmin(vals[axis][0], pt[axis]);
+            vals[axis][1] = SYSmax(vals[axis][1], pt[axis]);
+        }
+    }
+
+    SYS_FORCE_INLINE
+    UT_FixedVector<T,NAXES> getMin() const noexcept {
+        UT_FixedVector<T,NAXES> v;
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            v[axis] = vals[axis][0];
+        }
+        return v;
+    }
+
+    SYS_FORCE_INLINE
+    UT_FixedVector<T,NAXES> getMax() const noexcept {
+        UT_FixedVector<T,NAXES> v;
+        for (uint axis = 0; axis < NAXES; ++axis) {
+            v[axis] = vals[axis][1];
+        }
+        return v;
+    }
+
+    T diameter2() const noexcept {
+        T diff = (vals[0][1]-vals[0][0]);
+        T sum = diff*diff;
+        for (uint axis = 1; axis < NAXES; ++axis) {
+            diff = (vals[axis][1]-vals[axis][0]);
+            sum += diff*diff;
+        }
+        return sum;
+    }
+    T volume() const noexcept {
+        T product = (vals[0][1]-vals[0][0]);
+        for (uint axis = 1; axis < NAXES; ++axis) {
+            product *= (vals[axis][1]-vals[axis][0]);
+        }
+        return product;
+    }
+    T half_surface_area() const noexcept {
+        if (NAXES==1) {
+            // NOTE: Although this should technically be 1,
+            //       that doesn't make any sense as a heuristic,
+            //       so we fall back to the "volume" of this box.
+            return (vals[0][1]-vals[0][0]);
+        }
+        if (NAXES==2) {
+            const T d0 = (vals[0][1]-vals[0][0]);
+            const T d1 = (vals[1][1]-vals[1][0]);
+            return d0 + d1;
+        }
+        if (NAXES==3) {
+            const T d0 = (vals[0][1]-vals[0][0]);
+            const T d1 = (vals[1][1]-vals[1][0]);
+            const T d2 = (vals[2][1]-vals[2][0]);
+            return d0*d1 + d1*d2 + d2*d0;
+        }
+        if (NAXES==4) {
+            const T d0 = (vals[0][1]-vals[0][0]);
+            const T d1 = (vals[1][1]-vals[1][0]);
+            const T d2 = (vals[2][1]-vals[2][0]);
+            const T d3 = (vals[3][1]-vals[3][0]);
+            // This is just d0d1d2 + d1d2d3 + d2d3d0 + d3d0d1 refactored.
+            const T d0d1 = d0*d1;
+            const T d2d3 = d2*d3;
+            return d0d1*(d2+d3) + d2d3*(d0+d1);
+        }
+
+        T sum = 0;
+        for (uint skipped_axis = 0; skipped_axis < NAXES; ++skipped_axis) {
+            T product = 1;
+            for (uint axis = 0; axis < NAXES; ++axis) {
+                if (axis != skipped_axis) {
+                    product *= (vals[axis][1]-vals[axis][0]);
+                }
+            }
+            sum += product;
+        }
+        return sum;
+    }
+    T axis_sum() const noexcept {
+        T sum = (vals[0][1]-vals[0][0]);
+        for (uint axis = 1; axis < NAXES; ++axis) {
+            sum += (vals[axis][1]-vals[axis][0]);
+        }
+        return sum;
+    }
+    template<bool INSTANTIATED0,bool INSTANTIATED1>
+    SYS_FORCE_INLINE void intersect(
+        T &box_tmin,
+        T &box_tmax,
+        const UT_FixedVector<uint,NAXES,INSTANTIATED0> &signs,
+        const UT_FixedVector<T,NAXES,INSTANTIATED1> &origin,
+        const UT_FixedVector<T,NAXES,INSTANTIATED1> &inverse_direction
+    ) const noexcept {
+        for (int axis = 0; axis < NAXES; ++axis)
+        {
+            uint sign = signs[axis];
+            T t1 = (vals[axis][sign]   - origin[axis]) * inverse_direction[axis];
+            T t2 = (vals[axis][sign^1] - origin[axis]) * inverse_direction[axis];
+            box_tmin = SYSmax(t1, box_tmin);
+            box_tmax = SYSmin(t2, box_tmax);
+        }
+    }
+    SYS_FORCE_INLINE void intersect(const Box& other, Box& dest) const noexcept {
+        for (int axis = 0; axis < NAXES; ++axis)
+        {
+            dest.vals[axis][0] = SYSmax(vals[axis][0], other.vals[axis][0]);
+            dest.vals[axis][1] = SYSmin(vals[axis][1], other.vals[axis][1]);
+        }
+    }
+    template<bool INSTANTIATED>
+    SYS_FORCE_INLINE T minDistance2(
+        const UT_FixedVector<T,NAXES,INSTANTIATED> &p
+    ) const noexcept {
+        T diff = SYSmax(SYSmax(vals[0][0]-p[0], p[0]-vals[0][1]), T(0.0f));
+        T d2 = diff*diff;
+        for (int axis = 1; axis < NAXES; ++axis)
+        {
+            diff = SYSmax(SYSmax(vals[axis][0]-p[axis], p[axis]-vals[axis][1]), T(0.0f));
+            d2 += diff*diff;
+        }
+        return d2;
+    }
+    template<bool INSTANTIATED>
+    SYS_FORCE_INLINE T maxDistance2(
+        const UT_FixedVector<T,NAXES,INSTANTIATED> &p
+    ) const noexcept {
+        T diff = SYSmax(p[0]-vals[0][0], vals[0][1]-p[0]);
+        T d2 = diff*diff;
+        for (int axis = 1; axis < NAXES; ++axis)
+        {
+            diff = SYSmax(p[axis]-vals[axis][0], vals[axis][1]-p[axis]);
+            d2 += diff*diff;
+        }
+        return d2;
+    }
+};
+
+/// Used by BVH::init to specify the heuristic to use for choosing between different box splits.
+/// I tried putting this inside the BVH class, but I had difficulty getting it to compile.
+enum class BVH_Heuristic {
+    /// Tries to minimize the sum of axis lengths of the boxes.
+    /// This is useful for applications where the probability of a box being applicable to a
+    /// query is proportional to the "length", e.g. the probability of a random infinite plane
+    /// intersecting the box.
+    BOX_PERIMETER,
+
+    /// Tries to minimize the "surface area" of the boxes.
+    /// In 3D, uses the surface area; in 2D, uses the perimeter; in 1D, uses the axis length.
+    /// This is what most applications, e.g. ray tracing, should use, particularly when the
+    /// probability of a box being applicable to a query is proportional to the surface "area",
+    /// e.g. the probability of a random ray hitting the box.
+    ///
+    /// NOTE: USE THIS ONE IF YOU ARE UNSURE!
+    BOX_AREA,
+
+    /// Tries to minimize the "volume" of the boxes.
+    /// Uses the product of all axis lengths as a heuristic, (volume in 3D, area in 2D, length in 1D).
+    /// This is useful for applications where the probability of a box being applicable to a
+    /// query is proportional to the "volume", e.g. the probability of a random point being inside the box.
+    BOX_VOLUME,
+
+    /// Tries to minimize the "radii" of the boxes (i.e. the distance from the centre to a corner).
+    /// This is useful for applications where the probability of a box being applicable to a
+    /// query is proportional to the distance to the box centre, e.g. the probability of a random
+    /// infinite plane being within the "radius" of the centre.
+    BOX_RADIUS,
+
+    /// Tries to minimize the squared "radii" of the boxes (i.e. the squared distance from the centre to a corner).
+    /// This is useful for applications where the probability of a box being applicable to a
+    /// query is proportional to the squared distance to the box centre, e.g. the probability of a random
+    /// ray passing within the "radius" of the centre.
+    BOX_RADIUS2,
+
+    /// Tries to minimize the cubed "radii" of the boxes (i.e. the cubed distance from the centre to a corner).
+    /// This is useful for applications where the probability of a box being applicable to a
+    /// query is proportional to the cubed distance to the box centre, e.g. the probability of a random
+    /// point being within the "radius" of the centre.
+    BOX_RADIUS3,
+
+    /// Tries to minimize the depth of the tree by primarily splitting at the median of the max axis.
+    /// It may fall back to minimizing the area, but the tree depth should be unaffected.
+    ///
+    /// FIXME: This is not fully implemented yet.
+    MEDIAN_MAX_AXIS
+};
+
+template<uint N>
+class BVH {
+public:
+    using INT_TYPE = uint;
+    struct Node {
+        INT_TYPE child[N];
+
+        static constexpr INT_TYPE theN = N;
+        static constexpr INT_TYPE EMPTY = INT_TYPE(-1);
+        static constexpr INT_TYPE INTERNAL_BIT = (INT_TYPE(1)<<(sizeof(INT_TYPE)*8 - 1));
+        SYS_FORCE_INLINE static INT_TYPE markInternal(INT_TYPE internal_node_num) noexcept {
+            return internal_node_num | INTERNAL_BIT;
+        }
+        SYS_FORCE_INLINE static bool isInternal(INT_TYPE node_int) noexcept {
+            return (node_int & INTERNAL_BIT) != 0;
+        }
+        SYS_FORCE_INLINE static INT_TYPE getInternalNum(INT_TYPE node_int) noexcept {
+            return node_int & ~INTERNAL_BIT;
+        }
+    };
+private:
+    struct FreeDeleter {
+        SYS_FORCE_INLINE void operator()(Node* p) const {
+            if (p) {
+                // The pointer was allocated with malloc by UT_Array,
+                // so it must be freed with free.
+                free(p);
+            }
+        }
+    };
+
+    std::unique_ptr<Node[],FreeDeleter> myRoot;
+    INT_TYPE myNumNodes;
+public:
+    SYS_FORCE_INLINE BVH() noexcept : myRoot(nullptr), myNumNodes(0) {}
+
+    template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE=INT_TYPE>
+    inline void init(const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices=nullptr, bool reorder_indices=false, INT_TYPE max_items_per_leaf=1) noexcept;
+
+    template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE=INT_TYPE>
+    inline void init(Box<T,NAXES> axes_minmax, const BOX_TYPE* boxes, INT_TYPE nboxes, SRC_INT_TYPE* indices=nullptr, bool reorder_indices=false, INT_TYPE max_items_per_leaf=1) noexcept;
+
+    SYS_FORCE_INLINE
+    INT_TYPE getNumNodes() const noexcept
+    {
+        return myNumNodes;
+    }
+    SYS_FORCE_INLINE
+    const Node *getNodes() const noexcept
+    {
+        return myRoot.get();
+    }
+
+    SYS_FORCE_INLINE
+    void clear() noexcept {
+        myRoot.reset();
+        myNumNodes = 0;
+    }
+
+    /// For each node, this effectively does:
+    /// LOCAL_DATA local_data[MAX_ORDER];
+    /// bool descend = functors.pre(nodei, parent_data);
+    /// if (!descend)
+    ///     return;
+    /// for each child {
+    ///     if (isitem(child))
+    ///         functors.item(getitemi(child), nodei, local_data[child]);
+    ///     else if (isnode(child))
+    ///         recurse(getnodei(child), local_data);
+    /// }
+    /// functors.post(nodei, parent_nodei, data_for_parent, num_children, local_data);
+    template<typename LOCAL_DATA,typename FUNCTORS>
+    inline void traverse(
+        FUNCTORS &functors,
+        LOCAL_DATA *data_for_parent=nullptr) const noexcept;
+
+    /// This acts like the traverse function, except if the number of nodes in two subtrees
+    /// of a node contain at least parallel_threshold nodes, they may be executed in parallel.
+    /// If parallel_threshold is 0, even item_functor may be executed on items in parallel.
+    /// NOTE: Make sure that your functors don't depend on the order that they're executed in,
+    ///       e.g. don't add values from sibling nodes together except in post functor,
+    ///       else they might have nondeterministic roundoff or miss some values entirely.
+    template<typename LOCAL_DATA,typename FUNCTORS>
+    inline void traverseParallel(
+        INT_TYPE parallel_threshold,
+        FUNCTORS &functors,
+        LOCAL_DATA *data_for_parent=nullptr) const noexcept;
+
+    /// For each node, this effectively does:
+    /// LOCAL_DATA local_data[MAX_ORDER];
+    /// uint descend = functors.pre(nodei, parent_data);
+    /// if (!descend)
+    ///     return;
+    /// for each child {
+    ///     if (!(descend & (1<<child)))
+    ///         continue;
+    ///     if (isitem(child))
+    ///         functors.item(getitemi(child), nodei, local_data[child]);
+    ///     else if (isnode(child))
+    ///         recurse(getnodei(child), local_data);
+    /// }
+    /// functors.post(nodei, parent_nodei, data_for_parent, num_children, local_data);
+    template<typename LOCAL_DATA,typename FUNCTORS>
+    inline void traverseVector(
+        FUNCTORS &functors,
+        LOCAL_DATA *data_for_parent=nullptr) const noexcept;
+
+    /// Prints a text representation of the tree to stdout.
+    inline void debugDump() const;
+
+    template<typename SRC_INT_TYPE>
+    static inline void createTrivialIndices(SRC_INT_TYPE* indices, const INT_TYPE n) noexcept;
+
+private:
+    template<typename LOCAL_DATA,typename FUNCTORS>
+    inline void traverseHelper(
+        INT_TYPE nodei,
+        INT_TYPE parent_nodei,
+        FUNCTORS &functors,
+        LOCAL_DATA *data_for_parent=nullptr) const noexcept;
+
+    template<typename LOCAL_DATA,typename FUNCTORS>
+    inline void traverseParallelHelper(
+        INT_TYPE nodei,
+        INT_TYPE parent_nodei,
+        INT_TYPE parallel_threshold,
+        INT_TYPE next_node_id,
+        FUNCTORS &functors,
+        LOCAL_DATA *data_for_parent=nullptr) const noexcept;
+
+    template<typename LOCAL_DATA,typename FUNCTORS>
+    inline void traverseVectorHelper(
+        INT_TYPE nodei,
+        INT_TYPE parent_nodei,
+        FUNCTORS &functors,
+        LOCAL_DATA *data_for_parent=nullptr) const noexcept;
+
+    template<typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+    static inline void computeFullBoundingBox(Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices) noexcept;
+
+    template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+    static inline void initNode(UT_Array<Node>& nodes, Node &node, const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes) noexcept;
+
+    template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+    static inline void initNodeReorder(UT_Array<Node>& nodes, Node &node, const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes, const INT_TYPE indices_offset, const INT_TYPE max_items_per_leaf) noexcept;
+
+    template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+    static inline void multiSplit(const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE* sub_indices[N+1], Box<T,NAXES> sub_boxes[N]) noexcept;
+
+    template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+    static inline void split(const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE*& split_indices, Box<T,NAXES>* split_boxes) noexcept;
+
+    template<INT_TYPE PARALLEL_THRESHOLD, typename SRC_INT_TYPE>
+    static inline void adjustParallelChildNodes(INT_TYPE nparallel, UT_Array<Node>& nodes, Node& node, UT_Array<Node>* parallel_nodes, SRC_INT_TYPE* sub_indices) noexcept;
+
+    template<typename T,typename BOX_TYPE,typename SRC_INT_TYPE>
+    static inline void nthElement(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const SRC_INT_TYPE* indices_end, const uint axis, SRC_INT_TYPE*const nth) noexcept;
+
+    template<typename T,typename BOX_TYPE,typename SRC_INT_TYPE>
+    static inline void partitionByCentre(const BOX_TYPE* boxes, SRC_INT_TYPE*const indices, const SRC_INT_TYPE*const indices_end, const uint axis, const T pivotx2, SRC_INT_TYPE*& ppivot_start, SRC_INT_TYPE*& ppivot_end) noexcept;
+
+    /// An overestimate of the number of nodes needed.
+    /// At worst, we could have only 2 children in every leaf, and
+    /// then above that, we have a geometric series with r=1/N and a=(sub_nboxes/2)/N
+    /// The true worst case might be a little worst than this, but
+    /// it's probably fairly unlikely.
+    SYS_FORCE_INLINE static INT_TYPE nodeEstimate(const INT_TYPE nboxes) noexcept {
+        return nboxes/2 + nboxes/(2*(N-1));
+    }
+
+    template<BVH_Heuristic H,typename T, uint NAXES>
+    SYS_FORCE_INLINE static T unweightedHeuristic(const Box<T, NAXES>& box) noexcept {
+        if (H == BVH_Heuristic::BOX_PERIMETER) {
+            return box.axis_sum();
+        }
+        if (H == BVH_Heuristic::BOX_AREA) {
+            return box.half_surface_area();
+        }
+        if (H == BVH_Heuristic::BOX_VOLUME) {
+            return box.volume();
+        }
+        if (H == BVH_Heuristic::BOX_RADIUS) {
+            T diameter2 = box.diameter2();
+            return SYSsqrt(diameter2);
+        }
+        if (H == BVH_Heuristic::BOX_RADIUS2) {
+            return box.diameter2();
+        }
+        if (H == BVH_Heuristic::BOX_RADIUS3) {
+            T diameter2 = box.diameter2();
+            return diameter2*SYSsqrt(diameter2);
+        }
+        UT_ASSERT_MSG(0, "BVH_Heuristic::MEDIAN_MAX_AXIS should be handled separately by caller!");
+        return T(1);
+    }
+
+    /// 16 equal-length spans (15 evenly-spaced splits) should be enough for a decent heuristic
+    static constexpr INT_TYPE NSPANS = 16;
+    static constexpr INT_TYPE NSPLITS = NSPANS-1;
+
+    /// At least 1/16 of all boxes must be on each side, else we could end up with a very deep tree
+    static constexpr INT_TYPE MIN_FRACTION = 16;
+};
+
+} // UT namespace
+
+template<uint N>
+using UT_BVH = UT::BVH<N>;
+
+} // End HDK_Sample namespace
+}}
+#endif
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      Bounding Volume Hierarchy (BVH) implementation.
+ *      The main file is UT_BVH.h; this file is separate so that
+ *      files that don't actually need to call functions on the BVH
+ *      won't have unnecessary headers and functions included.
+ */
+
+#pragma once
+
+#ifndef __HDK_UT_BVHImpl_h__
+#define __HDK_UT_BVHImpl_h__
+
+
+
+
+
+
+
+
+#include <igl/parallel_for.h>
+
+#include <iostream>
+#include <algorithm>
+
+namespace igl { namespace FastWindingNumber {
+namespace HDK_Sample {
+
+namespace UT {
+
+template<typename T,uint NAXES>
+SYS_FORCE_INLINE bool utBoxExclude(const UT::Box<T,NAXES>& box) noexcept {
+    bool has_nan_or_inf = !SYSisFinite(box[0][0]);
+    has_nan_or_inf |= !SYSisFinite(box[0][1]);
+    for (uint axis = 1; axis < NAXES; ++axis)
+    {
+        has_nan_or_inf |= !SYSisFinite(box[axis][0]);
+        has_nan_or_inf |= !SYSisFinite(box[axis][1]);
+    }
+    return has_nan_or_inf;
+}
+template<uint NAXES>
+SYS_FORCE_INLINE bool utBoxExclude(const UT::Box<fpreal32,NAXES>& box) noexcept {
+    const int32 *pboxints = reinterpret_cast<const int32*>(&box);
+    // Fast check for NaN or infinity: check if exponent bits are 0xFF.
+    bool has_nan_or_inf = ((pboxints[0] & 0x7F800000) == 0x7F800000);
+    has_nan_or_inf |= ((pboxints[1] & 0x7F800000) == 0x7F800000);
+    for (uint axis = 1; axis < NAXES; ++axis)
+    {
+        has_nan_or_inf |= ((pboxints[2*axis] & 0x7F800000) == 0x7F800000);
+        has_nan_or_inf |= ((pboxints[2*axis + 1] & 0x7F800000) == 0x7F800000);
+    }
+    return has_nan_or_inf;
+}
+template<typename T,uint NAXES>
+SYS_FORCE_INLINE T utBoxCenter(const UT::Box<T,NAXES>& box, uint axis) noexcept {
+    const T* v = box.vals[axis];
+    return v[0] + v[1];
+}
+template<typename T>
+struct ut_BoxCentre {
+    constexpr static uint scale = 2;
+};
+template<typename T,uint NAXES,bool INSTANTIATED>
+SYS_FORCE_INLINE T utBoxExclude(const UT_FixedVector<T,NAXES,INSTANTIATED>& position) noexcept {
+    bool has_nan_or_inf = !SYSisFinite(position[0]);
+    for (uint axis = 1; axis < NAXES; ++axis)
+        has_nan_or_inf |= !SYSisFinite(position[axis]);
+    return has_nan_or_inf;
+}
+template<uint NAXES,bool INSTANTIATED>
+SYS_FORCE_INLINE bool utBoxExclude(const UT_FixedVector<fpreal32,NAXES,INSTANTIATED>& position) noexcept {
+    const int32 *ppositionints = reinterpret_cast<const int32*>(&position);
+    // Fast check for NaN or infinity: check if exponent bits are 0xFF.
+    bool has_nan_or_inf = ((ppositionints[0] & 0x7F800000) == 0x7F800000);
+    for (uint axis = 1; axis < NAXES; ++axis)
+        has_nan_or_inf |= ((ppositionints[axis] & 0x7F800000) == 0x7F800000);
+    return has_nan_or_inf;
+}
+template<typename T,uint NAXES,bool INSTANTIATED>
+SYS_FORCE_INLINE T utBoxCenter(const UT_FixedVector<T,NAXES,INSTANTIATED>& position, uint axis) noexcept {
+    return position[axis];
+}
+template<typename T,uint NAXES,bool INSTANTIATED>
+struct ut_BoxCentre<UT_FixedVector<T,NAXES,INSTANTIATED>> {
+    constexpr static uint scale = 1;
+};
+
+template<typename BOX_TYPE,typename SRC_INT_TYPE,typename INT_TYPE>
+inline INT_TYPE utExcludeNaNInfBoxIndices(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE& nboxes) noexcept 
+{
+    constexpr INT_TYPE PARALLEL_THRESHOLD = 65536;
+    INT_TYPE ntasks = 1;
+    //if (nboxes >= PARALLEL_THRESHOLD) 
+    //{
+    //    INT_TYPE nprocessors = UT_Thread::getNumProcessors();
+    //    ntasks = (nprocessors > 1) ? SYSmin(4*nprocessors, nboxes/(PARALLEL_THRESHOLD/2)) : 1;
+    //}
+    //if (ntasks == 1) 
+    {
+        // Serial: easy case; just loop through.
+
+        const SRC_INT_TYPE* indices_end = indices + nboxes;
+
+        // Loop through forward once
+        SRC_INT_TYPE* psrc_index = indices;
+        for (; psrc_index != indices_end; ++psrc_index) 
+        {
+            const bool exclude = utBoxExclude(boxes[*psrc_index]);
+            if (exclude)
+                break;
+        }
+        if (psrc_index == indices_end)
+            return 0;
+
+        // First NaN or infinite box
+        SRC_INT_TYPE* nan_start = psrc_index;
+        for (++psrc_index; psrc_index != indices_end; ++psrc_index) 
+	{
+            const bool exclude = utBoxExclude(boxes[*psrc_index]);
+            if (!exclude) 
+	    {
+                *nan_start = *psrc_index;
+                ++nan_start;
+            }
+        }
+        nboxes = nan_start-indices;
+        return indices_end - nan_start;
+    }
+
+}
+
+template<uint N>
+template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+inline void BVH<N>::init(const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices, bool reorder_indices, INT_TYPE max_items_per_leaf) noexcept {
+    Box<T,NAXES> axes_minmax;
+    computeFullBoundingBox(axes_minmax, boxes, nboxes, indices);
+
+    init<H>(axes_minmax, boxes, nboxes, indices, reorder_indices, max_items_per_leaf);
+}
+
+template<uint N>
+template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+inline void BVH<N>::init(Box<T,NAXES> axes_minmax, const BOX_TYPE* boxes, INT_TYPE nboxes, SRC_INT_TYPE* indices, bool reorder_indices, INT_TYPE max_items_per_leaf) noexcept {
+    // Clear the tree in advance to save memory.
+    myRoot.reset();
+
+    if (nboxes == 0) {
+        myNumNodes = 0;
+        return;
+    }
+
+    UT_Array<INT_TYPE> local_indices;
+    if (!indices) {
+        local_indices.setSizeNoInit(nboxes);
+        indices = local_indices.array();
+        createTrivialIndices(indices, nboxes);
+    }
+
+    // Exclude any boxes with NaNs or infinities by shifting down indices
+    // over the bad box indices and updating nboxes.
+    INT_TYPE nexcluded = utExcludeNaNInfBoxIndices(boxes, indices, nboxes);
+    if (nexcluded != 0) {
+        if (nboxes == 0) {
+            myNumNodes = 0;
+            return;
+        }
+        computeFullBoundingBox(axes_minmax, boxes, nboxes, indices);
+    }
+
+    UT_Array<Node> nodes;
+    // Preallocate an overestimate of the number of nodes needed.
+    nodes.setCapacity(nodeEstimate(nboxes));
+    nodes.setSize(1);
+    if (reorder_indices)
+        initNodeReorder<H>(nodes, nodes[0], axes_minmax, boxes, indices, nboxes, 0, max_items_per_leaf);
+    else
+        initNode<H>(nodes, nodes[0], axes_minmax, boxes, indices, nboxes);
+
+    // If capacity is more than 12.5% over the size, rellocate.
+    if (8*nodes.capacity() > 9*nodes.size()) {
+        nodes.setCapacity(nodes.size());
+    }
+    // Steal ownership of the array from the UT_Array
+    myRoot.reset(nodes.array());
+    myNumNodes = nodes.size();
+    nodes.unsafeClearData();
+}
+
+template<uint N>
+template<typename LOCAL_DATA,typename FUNCTORS>
+inline void BVH<N>::traverse(
+    FUNCTORS &functors,
+    LOCAL_DATA* data_for_parent) const noexcept
+{
+    if (!myRoot)
+        return;
+
+    // NOTE: The root is always index 0.
+    traverseHelper(0, INT_TYPE(-1), functors, data_for_parent);
+}
+template<uint N>
+template<typename LOCAL_DATA,typename FUNCTORS>
+inline void BVH<N>::traverseHelper(
+    INT_TYPE nodei,
+    INT_TYPE parent_nodei,
+    FUNCTORS &functors,
+    LOCAL_DATA* data_for_parent) const noexcept
+{
+    const Node &node = myRoot[nodei];
+    bool descend = functors.pre(nodei, data_for_parent);
+    if (!descend)
+        return;
+    LOCAL_DATA local_data[N];
+    INT_TYPE s;
+    for (s = 0; s < N; ++s) {
+        const INT_TYPE node_int = node.child[s];
+        if (Node::isInternal(node_int)) {
+            if (node_int == Node::EMPTY) {
+                // NOTE: Anything after this will be empty too, so we can break.
+                break;
+            }
+            traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]);
+        }
+        else {
+            functors.item(node_int, nodei, local_data[s]);
+        }
+    }
+    // NOTE: s is now the number of non-empty entries in this node.
+    functors.post(nodei, parent_nodei, data_for_parent, s, local_data);
+}
+
+template<uint N>
+template<typename LOCAL_DATA,typename FUNCTORS>
+inline void BVH<N>::traverseParallel(
+    INT_TYPE parallel_threshold,
+    FUNCTORS& functors,
+    LOCAL_DATA* data_for_parent) const noexcept
+{
+    if (!myRoot)
+        return;
+
+    // NOTE: The root is always index 0.
+    traverseParallelHelper(0, INT_TYPE(-1), parallel_threshold, myNumNodes, functors, data_for_parent);
+}
+template<uint N>
+template<typename LOCAL_DATA,typename FUNCTORS>
+inline void BVH<N>::traverseParallelHelper(
+    INT_TYPE nodei,
+    INT_TYPE parent_nodei,
+    INT_TYPE parallel_threshold,
+    INT_TYPE next_node_id,
+    FUNCTORS& functors,
+    LOCAL_DATA* data_for_parent) const noexcept
+{
+    const Node &node = myRoot[nodei];
+    bool descend = functors.pre(nodei, data_for_parent);
+    if (!descend)
+        return;
+
+    // To determine the number of nodes in a child's subtree, we take the next
+    // node ID minus the current child's node ID.
+    INT_TYPE next_nodes[N];
+    INT_TYPE nnodes[N];
+    INT_TYPE nchildren = N;
+    INT_TYPE nparallel = 0;
+    // s is currently unsigned, so we check s < N for bounds check.
+    // The s >= 0 check is in case s ever becomes signed, and should be
+    // automatically removed by the compiler for unsigned s.
+    for (INT_TYPE s = N-1; (std::is_signed<INT_TYPE>::value ? (s >= 0) : (s < N)); --s) {
+        const INT_TYPE node_int = node.child[s];
+        if (node_int == Node::EMPTY) {
+            --nchildren;
+            continue;
+        }
+        next_nodes[s] = next_node_id;
+        if (Node::isInternal(node_int)) {
+            // NOTE: This depends on BVH<N>::initNode appending the child nodes
+            //       in between their content, instead of all at once.
+            INT_TYPE child_node_id = Node::getInternalNum(node_int);
+            nnodes[s] = next_node_id - child_node_id;
+            next_node_id = child_node_id;
+        }
+        else {
+            nnodes[s] = 0;
+        }
+        nparallel += (nnodes[s] >= parallel_threshold);
+    }
+
+    LOCAL_DATA local_data[N];
+    if (nparallel >= 2) {
+        // Do any non-parallel ones first
+        if (nparallel < nchildren) {
+            for (INT_TYPE s = 0; s < N; ++s) {
+                if (nnodes[s] >= parallel_threshold) {
+                    continue;
+                }
+                const INT_TYPE node_int = node.child[s];
+                if (Node::isInternal(node_int)) {
+                    if (node_int == Node::EMPTY) {
+                        // NOTE: Anything after this will be empty too, so we can break.
+                        break;
+                    }
+                    traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]);
+                }
+                else {
+                    functors.item(node_int, nodei, local_data[s]);
+                }
+            }
+        }
+        // Now do the parallel ones
+        igl::parallel_for(
+          nparallel,
+          [this,nodei,&node,&nnodes,&next_nodes,&parallel_threshold,&functors,&local_data](int taski)
+          {
+            INT_TYPE parallel_count = 0;
+            // NOTE: The check for s < N is just so that the compiler can
+            //       (hopefully) figure out that it can fully unroll the loop.
+            INT_TYPE s;
+            for (s = 0; s < N; ++s) {
+                if (nnodes[s] < parallel_threshold) {
+                    continue;
+                }
+                if (parallel_count == taski) {
+                    break;
+                }
+                ++parallel_count;
+            }
+            const INT_TYPE node_int = node.child[s];
+            if (Node::isInternal(node_int)) {
+                UT_ASSERT_MSG_P(node_int != Node::EMPTY, "Empty entries should have been excluded above.");
+                traverseParallelHelper(Node::getInternalNum(node_int), nodei, parallel_threshold, next_nodes[s], functors, &local_data[s]);
+            }
+            else {
+                functors.item(node_int, nodei, local_data[s]);
+            }
+          });
+    }
+    else {
+        // All in serial
+        for (INT_TYPE s = 0; s < N; ++s) {
+            const INT_TYPE node_int = node.child[s];
+            if (Node::isInternal(node_int)) {
+                if (node_int == Node::EMPTY) {
+                    // NOTE: Anything after this will be empty too, so we can break.
+                    break;
+                }
+                traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]);
+            }
+            else {
+                functors.item(node_int, nodei, local_data[s]);
+            }
+        }
+    }
+    functors.post(nodei, parent_nodei, data_for_parent, nchildren, local_data);
+}
+
+template<uint N>
+template<typename LOCAL_DATA,typename FUNCTORS>
+inline void BVH<N>::traverseVector(
+    FUNCTORS &functors,
+    LOCAL_DATA* data_for_parent) const noexcept
+{
+    if (!myRoot)
+        return;
+
+    // NOTE: The root is always index 0.
+    traverseVectorHelper(0, INT_TYPE(-1), functors, data_for_parent);
+}
+template<uint N>
+template<typename LOCAL_DATA,typename FUNCTORS>
+inline void BVH<N>::traverseVectorHelper(
+    INT_TYPE nodei,
+    INT_TYPE parent_nodei,
+    FUNCTORS &functors,
+    LOCAL_DATA* data_for_parent) const noexcept
+{
+    const Node &node = myRoot[nodei];
+    INT_TYPE descend = functors.pre(nodei, data_for_parent);
+    if (!descend)
+        return;
+    LOCAL_DATA local_data[N];
+    INT_TYPE s;
+    for (s = 0; s < N; ++s) {
+        if ((descend>>s) & 1) {
+            const INT_TYPE node_int = node.child[s];
+            if (Node::isInternal(node_int)) {
+                if (node_int == Node::EMPTY) {
+                    // NOTE: Anything after this will be empty too, so we can break.
+                    descend &= (INT_TYPE(1)<<s)-1;
+                    break;
+                }
+                traverseVectorHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]);
+            }
+            else {
+                functors.item(node_int, nodei, local_data[s]);
+            }
+        }
+    }
+    // NOTE: s is now the number of non-empty entries in this node.
+    functors.post(nodei, parent_nodei, data_for_parent, s, local_data, descend);
+}
+
+
+template<uint N>
+template<typename SRC_INT_TYPE>
+inline void BVH<N>::createTrivialIndices(SRC_INT_TYPE* indices, const INT_TYPE n) noexcept {
+    igl::parallel_for(n, [indices,n](INT_TYPE i) { indices[i] = i; }, 65536);
+}
+
+template<uint N>
+template<typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+inline void BVH<N>::computeFullBoundingBox(Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices) noexcept {
+    if (!nboxes) {
+        axes_minmax.initBounds();
+        return;
+    }
+    INT_TYPE ntasks = 1;
+    if (nboxes >= 2*4096) {
+        INT_TYPE nprocessors = UT_Thread::getNumProcessors();
+        ntasks = (nprocessors > 1) ? SYSmin(4*nprocessors, nboxes/4096) : 1;
+    }
+    if (ntasks == 1) {
+        Box<T,NAXES> box;
+        if (indices) {
+            box.initBounds(boxes[indices[0]]);
+            for (INT_TYPE i = 1; i < nboxes; ++i) {
+                box.combine(boxes[indices[i]]);
+            }
+        }
+        else {
+            box.initBounds(boxes[0]);
+            for (INT_TYPE i = 1; i < nboxes; ++i) {
+                box.combine(boxes[i]);
+            }
+        }
+        axes_minmax = box;
+    }
+    else {
+        UT_SmallArray<Box<T,NAXES>> parallel_boxes;
+        Box<T,NAXES> box;
+        igl::parallel_for(
+          nboxes,
+          [&parallel_boxes](int n){parallel_boxes.setSize(n);},
+          [&parallel_boxes,indices,&boxes](int i, int t)
+          {
+            if(indices)
+            {
+              parallel_boxes[t].combine(boxes[indices[i]]);
+            }else
+            {
+              parallel_boxes[t].combine(boxes[i]);
+            }
+          },
+          [&parallel_boxes,&box](int t)
+          {
+            if(t == 0)
+            {
+              box = parallel_boxes[0];
+            }else
+            {
+              box.combine(parallel_boxes[t]);
+            }
+          });
+
+        axes_minmax = box;
+    }
+}
+
+template<uint N>
+template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+inline void BVH<N>::initNode(UT_Array<Node>& nodes, Node &node, const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes) noexcept {
+    if (nboxes <= N) {
+        // Fits in one node
+        for (INT_TYPE i = 0; i < nboxes; ++i) {
+            node.child[i] = indices[i];
+        }
+        for (INT_TYPE i = nboxes; i < N; ++i) {
+            node.child[i] = Node::EMPTY;
+        }
+        return;
+    }
+
+    SRC_INT_TYPE* sub_indices[N+1];
+    Box<T,NAXES> sub_boxes[N];
+
+    if (N == 2) {
+        sub_indices[0] = indices;
+        sub_indices[2] = indices+nboxes;
+        split<H>(axes_minmax, boxes, indices, nboxes, sub_indices[1], &sub_boxes[0]);
+    }
+    else {
+        multiSplit<H>(axes_minmax, boxes, indices, nboxes, sub_indices, sub_boxes);
+    }
+
+    // Count the number of nodes to run in parallel and fill in single items in this node
+    INT_TYPE nparallel = 0;
+    static constexpr INT_TYPE PARALLEL_THRESHOLD = 1024;
+    for (INT_TYPE i = 0; i < N; ++i) {
+        INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
+        if (sub_nboxes == 1) {
+            node.child[i] = sub_indices[i][0];
+        }
+        else if (sub_nboxes >= PARALLEL_THRESHOLD) {
+            ++nparallel;
+        }
+    }
+
+    // NOTE: Child nodes of this node need to be placed just before the nodes in
+    //       their corresponding subtree, in between the subtrees, because
+    //       traverseParallel uses the difference between the child node IDs
+    //       to determine the number of nodes in the subtree.
+
+    // Recurse
+    if (nparallel >= 2) {
+        UT_SmallArray<UT_Array<Node>> parallel_nodes;
+        UT_SmallArray<Node> parallel_parent_nodes;
+        parallel_nodes.setSize(nparallel);
+        parallel_parent_nodes.setSize(nparallel);
+        igl::parallel_for(
+          nparallel,
+          [&parallel_nodes,&parallel_parent_nodes,&sub_indices,boxes,&sub_boxes](int taski)
+          {
+            // First, find which child this is
+            INT_TYPE counted_parallel = 0;
+            INT_TYPE sub_nboxes;
+            INT_TYPE childi;
+            for (childi = 0; childi < N; ++childi) {
+                sub_nboxes = sub_indices[childi+1]-sub_indices[childi];
+                if (sub_nboxes >= PARALLEL_THRESHOLD) {
+                    if (counted_parallel == taski) {
+                        break;
+                    }
+                    ++counted_parallel;
+                }
+            }
+            UT_ASSERT_P(counted_parallel == taski);
+
+            UT_Array<Node>& local_nodes = parallel_nodes[taski];
+            // Preallocate an overestimate of the number of nodes needed.
+            // At worst, we could have only 2 children in every leaf, and
+            // then above that, we have a geometric series with r=1/N and a=(sub_nboxes/2)/N
+            // The true worst case might be a little worst than this, but
+            // it's probably fairly unlikely.
+            local_nodes.setCapacity(nodeEstimate(sub_nboxes));
+            Node& parent_node = parallel_parent_nodes[taski];
+
+            // We'll have to fix the internal node numbers in parent_node and local_nodes later
+            initNode<H>(local_nodes, parent_node, sub_boxes[childi], boxes, sub_indices[childi], sub_nboxes);
+          });
+
+        INT_TYPE counted_parallel = 0;
+        for (INT_TYPE i = 0; i < N; ++i) {
+            INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
+            if (sub_nboxes != 1) {
+                INT_TYPE local_nodes_start = nodes.size();
+                node.child[i] = Node::markInternal(local_nodes_start);
+                if (sub_nboxes >= PARALLEL_THRESHOLD) {
+                    // First, adjust the root child node
+                    Node child_node = parallel_parent_nodes[counted_parallel];
+                    ++local_nodes_start;
+                    for (INT_TYPE childi = 0; childi < N; ++childi) {
+                        INT_TYPE child_child = child_node.child[childi];
+                        if (Node::isInternal(child_child) && child_child != Node::EMPTY) {
+                            child_child += local_nodes_start;
+                            child_node.child[childi] = child_child;
+                        }
+                    }
+
+                    // Make space in the array for the sub-child nodes
+                    const UT_Array<Node>& local_nodes = parallel_nodes[counted_parallel];
+                    ++counted_parallel;
+                    INT_TYPE n = local_nodes.size();
+                    nodes.bumpCapacity(local_nodes_start + n);
+                    nodes.setSizeNoInit(local_nodes_start + n);
+                    nodes[local_nodes_start-1] = child_node;
+                }
+                else {
+                    nodes.bumpCapacity(local_nodes_start + 1);
+                    nodes.setSizeNoInit(local_nodes_start + 1);
+                    initNode<H>(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes);
+                }
+            }
+        }
+
+        // Now, adjust and copy all sub-child nodes that were made in parallel
+        adjustParallelChildNodes<PARALLEL_THRESHOLD>(nparallel, nodes, node, parallel_nodes.array(), sub_indices);
+    }
+    else {
+        for (INT_TYPE i = 0; i < N; ++i) {
+            INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
+            if (sub_nboxes != 1) {
+                INT_TYPE local_nodes_start = nodes.size();
+                node.child[i] = Node::markInternal(local_nodes_start);
+                nodes.bumpCapacity(local_nodes_start + 1);
+                nodes.setSizeNoInit(local_nodes_start + 1);
+                initNode<H>(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes);
+            }
+        }
+    }
+}
+
+template<uint N>
+template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+inline void BVH<N>::initNodeReorder(UT_Array<Node>& nodes, Node &node, const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, const INT_TYPE indices_offset, const INT_TYPE max_items_per_leaf) noexcept {
+    if (nboxes <= N) {
+        // Fits in one node
+        for (INT_TYPE i = 0; i < nboxes; ++i) {
+            node.child[i] = indices_offset+i;
+        }
+        for (INT_TYPE i = nboxes; i < N; ++i) {
+            node.child[i] = Node::EMPTY;
+        }
+        return;
+    }
+
+    SRC_INT_TYPE* sub_indices[N+1];
+    Box<T,NAXES> sub_boxes[N];
+
+    if (N == 2) {
+        sub_indices[0] = indices;
+        sub_indices[2] = indices+nboxes;
+        split<H>(axes_minmax, boxes, indices, nboxes, sub_indices[1], &sub_boxes[0]);
+    }
+    else {
+        multiSplit<H>(axes_minmax, boxes, indices, nboxes, sub_indices, sub_boxes);
+    }
+
+    // Move any children with max_items_per_leaf or fewer indices before any children with more,
+    // for better cache coherence when we're accessing data in a corresponding array.
+    INT_TYPE nleaves = 0;
+    UT_SmallArray<SRC_INT_TYPE> leaf_indices;
+    SRC_INT_TYPE leaf_sizes[N];
+    INT_TYPE sub_nboxes0 = sub_indices[1]-sub_indices[0];
+    if (sub_nboxes0 <= max_items_per_leaf) {
+        leaf_sizes[0] = sub_nboxes0;
+        for (int j = 0; j < sub_nboxes0; ++j)
+            leaf_indices.append(sub_indices[0][j]);
+        ++nleaves;
+    }
+    INT_TYPE sub_nboxes1 = sub_indices[2]-sub_indices[1];
+    if (sub_nboxes1 <= max_items_per_leaf) {
+        leaf_sizes[nleaves] = sub_nboxes1;
+        for (int j = 0; j < sub_nboxes1; ++j)
+            leaf_indices.append(sub_indices[1][j]);
+        ++nleaves;
+    }
+    for (INT_TYPE i = 2; i < N; ++i) {
+        INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
+        if (sub_nboxes <= max_items_per_leaf) {
+            leaf_sizes[nleaves] = sub_nboxes;
+            for (int j = 0; j < sub_nboxes; ++j)
+                leaf_indices.append(sub_indices[i][j]);
+            ++nleaves;
+        }
+    }
+    if (nleaves > 0) {
+        // NOTE: i < N condition is because INT_TYPE is unsigned.
+        //       i >= 0 condition is in case INT_TYPE is changed to signed.
+        INT_TYPE move_distance = 0;
+        INT_TYPE index_move_distance = 0;
+        for (INT_TYPE i = N-1; (std::is_signed<INT_TYPE>::value ? (i >= 0) : (i < N)); --i) {
+            INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
+            if (sub_nboxes <= max_items_per_leaf) {
+                ++move_distance;
+                index_move_distance += sub_nboxes;
+            }
+            else if (move_distance > 0) {
+                SRC_INT_TYPE *start_src_index = sub_indices[i];
+                for (SRC_INT_TYPE *src_index = sub_indices[i+1]-1; src_index >= start_src_index; --src_index) {
+                    src_index[index_move_distance] = src_index[0];
+                }
+                sub_indices[i+move_distance] = sub_indices[i]+index_move_distance;
+            }
+        }
+        index_move_distance = 0;
+        for (INT_TYPE i = 0; i < nleaves; ++i) {
+            INT_TYPE sub_nboxes = leaf_sizes[i];
+            sub_indices[i] = indices+index_move_distance;
+            for (int j = 0; j < sub_nboxes; ++j)
+                indices[index_move_distance+j] = leaf_indices[index_move_distance+j];
+            index_move_distance += sub_nboxes;
+        }
+    }
+
+    // Count the number of nodes to run in parallel and fill in single items in this node
+    INT_TYPE nparallel = 0;
+    static constexpr INT_TYPE PARALLEL_THRESHOLD = 1024;
+    for (INT_TYPE i = 0; i < N; ++i) {
+        INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
+        if (sub_nboxes <= max_items_per_leaf) {
+            node.child[i] = indices_offset+(sub_indices[i]-sub_indices[0]);
+        }
+        else if (sub_nboxes >= PARALLEL_THRESHOLD) {
+            ++nparallel;
+        }
+    }
+
+    // NOTE: Child nodes of this node need to be placed just before the nodes in
+    //       their corresponding subtree, in between the subtrees, because
+    //       traverseParallel uses the difference between the child node IDs
+    //       to determine the number of nodes in the subtree.
+
+    // Recurse
+    if (nparallel >= 2 && false) {
+      assert(false && "Not implemented; should never get here");
+      exit(1);
+      //  // Do the parallel ones first, so that they can be inserted in the right place.
+      //  // Although the choice may seem somewhat arbitrary, we need the results to be
+      //  // identical whether we choose to parallelize or not, and in case we change the
+      //  // threshold later.
+      //  UT_SmallArray<UT_Array<Node>,4*sizeof(UT_Array<Node>)> parallel_nodes;
+      //  parallel_nodes.setSize(nparallel);
+      //  UT_SmallArray<Node,4*sizeof(Node)> parallel_parent_nodes;
+      //  parallel_parent_nodes.setSize(nparallel);
+      //  UTparallelFor(UT_BlockedRange<INT_TYPE>(0,nparallel), [&parallel_nodes,&parallel_parent_nodes,&sub_indices,boxes,&sub_boxes,indices_offset,max_items_per_leaf](const UT_BlockedRange<INT_TYPE>& r) {
+      //      for (INT_TYPE taski = r.begin(), end = r.end(); taski < end; ++taski) {
+      //          // First, find which child this is
+      //          INT_TYPE counted_parallel = 0;
+      //          INT_TYPE sub_nboxes;
+      //          INT_TYPE childi;
+      //          for (childi = 0; childi < N; ++childi) {
+      //              sub_nboxes = sub_indices[childi+1]-sub_indices[childi];
+      //              if (sub_nboxes >= PARALLEL_THRESHOLD) {
+      //                  if (counted_parallel == taski) {
+      //                      break;
+      //                  }
+      //                  ++counted_parallel;
+      //              }
+      //          }
+      //          UT_ASSERT_P(counted_parallel == taski);
+
+      //          UT_Array<Node>& local_nodes = parallel_nodes[taski];
+      //          // Preallocate an overestimate of the number of nodes needed.
+      //          // At worst, we could have only 2 children in every leaf, and
+      //          // then above that, we have a geometric series with r=1/N and a=(sub_nboxes/2)/N
+      //          // The true worst case might be a little worst than this, but
+      //          // it's probably fairly unlikely.
+      //          local_nodes.setCapacity(nodeEstimate(sub_nboxes));
+      //          Node& parent_node = parallel_parent_nodes[taski];
+
+      //          // We'll have to fix the internal node numbers in parent_node and local_nodes later
+      //          initNodeReorder<H>(local_nodes, parent_node, sub_boxes[childi], boxes, sub_indices[childi], sub_nboxes,
+      //              indices_offset+(sub_indices[childi]-sub_indices[0]), max_items_per_leaf);
+      //      }
+      //  }, 0, 1);
+
+      //  INT_TYPE counted_parallel = 0;
+      //  for (INT_TYPE i = 0; i < N; ++i) {
+      //      INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
+      //      if (sub_nboxes > max_items_per_leaf) {
+      //          INT_TYPE local_nodes_start = nodes.size();
+      //          node.child[i] = Node::markInternal(local_nodes_start);
+      //          if (sub_nboxes >= PARALLEL_THRESHOLD) {
+      //              // First, adjust the root child node
+      //              Node child_node = parallel_parent_nodes[counted_parallel];
+      //              ++local_nodes_start;
+      //              for (INT_TYPE childi = 0; childi < N; ++childi) {
+      //                  INT_TYPE child_child = child_node.child[childi];
+      //                  if (Node::isInternal(child_child) && child_child != Node::EMPTY) {
+      //                      child_child += local_nodes_start;
+      //                      child_node.child[childi] = child_child;
+      //                  }
+      //              }
+
+      //              // Make space in the array for the sub-child nodes
+      //              const UT_Array<Node>& local_nodes = parallel_nodes[counted_parallel];
+      //              ++counted_parallel;
+      //              INT_TYPE n = local_nodes.size();
+      //              nodes.bumpCapacity(local_nodes_start + n);
+      //              nodes.setSizeNoInit(local_nodes_start + n);
+      //              nodes[local_nodes_start-1] = child_node;
+      //          }
+      //          else {
+      //              nodes.bumpCapacity(local_nodes_start + 1);
+      //              nodes.setSizeNoInit(local_nodes_start + 1);
+      //              initNodeReorder<H>(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes,
+      //                  indices_offset+(sub_indices[i]-sub_indices[0]), max_items_per_leaf);
+      //          }
+      //      }
+      //  }
+
+      //  // Now, adjust and copy all sub-child nodes that were made in parallel
+      //  adjustParallelChildNodes<PARALLEL_THRESHOLD>(nparallel, nodes, node, parallel_nodes.array(), sub_indices);
+    }
+    else {
+        for (INT_TYPE i = 0; i < N; ++i) {
+            INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
+            if (sub_nboxes > max_items_per_leaf) {
+                INT_TYPE local_nodes_start = nodes.size();
+                node.child[i] = Node::markInternal(local_nodes_start);
+                nodes.bumpCapacity(local_nodes_start + 1);
+                nodes.setSizeNoInit(local_nodes_start + 1);
+                initNodeReorder<H>(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes,
+                    indices_offset+(sub_indices[i]-sub_indices[0]), max_items_per_leaf);
+            }
+        }
+    }
+}
+
+template<uint N>
+template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+inline void BVH<N>::multiSplit(const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE* sub_indices[N+1], Box<T,NAXES> sub_boxes[N]) noexcept {
+    sub_indices[0] = indices;
+    sub_indices[2] = indices+nboxes;
+    split<H>(axes_minmax, boxes, indices, nboxes, sub_indices[1], &sub_boxes[0]);
+
+    if (N == 2) {
+        return;
+    }
+
+    if (H == BVH_Heuristic::MEDIAN_MAX_AXIS) {
+        SRC_INT_TYPE* sub_indices_startend[2*N];
+        Box<T,NAXES> sub_boxes_unsorted[N];
+        sub_boxes_unsorted[0] = sub_boxes[0];
+        sub_boxes_unsorted[1] = sub_boxes[1];
+        sub_indices_startend[0] = sub_indices[0];
+        sub_indices_startend[1] = sub_indices[1];
+        sub_indices_startend[2] = sub_indices[1];
+        sub_indices_startend[3] = sub_indices[2];
+        for (INT_TYPE nsub = 2; nsub < N; ++nsub) {
+            SRC_INT_TYPE* selected_start = sub_indices_startend[0];
+            SRC_INT_TYPE* selected_end = sub_indices_startend[1];
+            Box<T,NAXES> sub_box = sub_boxes_unsorted[0];
+
+            // Shift results back.
+            for (INT_TYPE i = 0; i < nsub-1; ++i) {
+                sub_indices_startend[2*i  ] = sub_indices_startend[2*i+2];
+                sub_indices_startend[2*i+1] = sub_indices_startend[2*i+3];
+            }
+            for (INT_TYPE i = 0; i < nsub-1; ++i) {
+                sub_boxes_unsorted[i] = sub_boxes_unsorted[i-1];
+            }
+
+            // Do the split
+            split<H>(sub_box, boxes, selected_start, selected_end-selected_start, sub_indices_startend[2*nsub-1], &sub_boxes_unsorted[nsub]);
+            sub_indices_startend[2*nsub-2] = selected_start;
+            sub_indices_startend[2*nsub] = sub_indices_startend[2*nsub-1];
+            sub_indices_startend[2*nsub+1] = selected_end;
+
+            // Sort pointers so that they're in the correct order
+            sub_indices[N] = indices+nboxes;
+            for (INT_TYPE i = 0; i < N; ++i) {
+                SRC_INT_TYPE* prev_pointer = (i != 0) ? sub_indices[i-1] : nullptr;
+                SRC_INT_TYPE* min_pointer = nullptr;
+                Box<T,NAXES> box;
+                for (INT_TYPE j = 0; j < N; ++j) {
+                    SRC_INT_TYPE* cur_pointer = sub_indices_startend[2*j];
+                    if ((cur_pointer > prev_pointer) && (!min_pointer || (cur_pointer < min_pointer))) {
+                        min_pointer = cur_pointer;
+                        box = sub_boxes_unsorted[j];
+                    }
+                }
+                UT_ASSERT_P(min_pointer);
+                sub_indices[i] = min_pointer;
+                sub_boxes[i] = box;
+            }
+        }
+    }
+    else {
+        T sub_box_areas[N];
+        sub_box_areas[0] = unweightedHeuristic<H>(sub_boxes[0]);
+        sub_box_areas[1] = unweightedHeuristic<H>(sub_boxes[1]);
+        for (INT_TYPE nsub = 2; nsub < N; ++nsub) {
+            // Choose which one to split
+            INT_TYPE split_choice = INT_TYPE(-1);
+            T max_heuristic;
+            for (INT_TYPE i = 0; i < nsub; ++i) {
+                const INT_TYPE index_count = (sub_indices[i+1]-sub_indices[i]);
+                if (index_count > 1) {
+                    const T heuristic = sub_box_areas[i]*index_count;
+                    if (split_choice == INT_TYPE(-1) || heuristic > max_heuristic) {
+                        split_choice = i;
+                        max_heuristic = heuristic;
+                    }
+                }
+            }
+            UT_ASSERT_MSG_P(split_choice != INT_TYPE(-1), "There should always be at least one that can be split!");
+
+            SRC_INT_TYPE* selected_start = sub_indices[split_choice];
+            SRC_INT_TYPE* selected_end = sub_indices[split_choice+1];
+
+            // Shift results over; we can skip the one we selected.
+            for (INT_TYPE i = nsub; i > split_choice; --i) {
+                sub_indices[i+1] = sub_indices[i];
+            }
+            for (INT_TYPE i = nsub-1; i > split_choice; --i) {
+                sub_boxes[i+1] = sub_boxes[i];
+            }
+            for (INT_TYPE i = nsub-1; i > split_choice; --i) {
+                sub_box_areas[i+1] = sub_box_areas[i];
+            }
+
+            // Do the split
+            split<H>(sub_boxes[split_choice], boxes, selected_start, selected_end-selected_start, sub_indices[split_choice+1], &sub_boxes[split_choice]);
+            sub_box_areas[split_choice] = unweightedHeuristic<H>(sub_boxes[split_choice]);
+            sub_box_areas[split_choice+1] = unweightedHeuristic<H>(sub_boxes[split_choice+1]);
+        }
+    }
+}
+
+template<uint N>
+template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
+inline void BVH<N>::split(const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE*& split_indices, Box<T,NAXES>* split_boxes) noexcept {
+    if (nboxes == 2) {
+        split_boxes[0].initBounds(boxes[indices[0]]);
+        split_boxes[1].initBounds(boxes[indices[1]]);
+        split_indices = indices+1;
+        return;
+    }
+    UT_ASSERT_MSG_P(nboxes > 2, "Cases with less than 3 boxes should have already been handled!");
+
+    if (H == BVH_Heuristic::MEDIAN_MAX_AXIS) {
+        UT_ASSERT_MSG(0, "FIXME: Implement this!!!");
+    }
+
+    constexpr INT_TYPE SMALL_LIMIT = 6;
+    if (nboxes <= SMALL_LIMIT) {
+        // Special case for a small number of boxes: check all (2^(n-1))-1 partitions.
+        // Without loss of generality, we assume that box 0 is in partition 0,
+        // and that not all boxes are in partition 0.
+        Box<T,NAXES> local_boxes[SMALL_LIMIT];
+        for (INT_TYPE box = 0; box < nboxes; ++box) {
+            local_boxes[box].initBounds(boxes[indices[box]]);
+            //printf("Box %u: (%f-%f)x(%f-%f)x(%f-%f)\n", uint(box), local_boxes[box].vals[0][0], local_boxes[box].vals[0][1], local_boxes[box].vals[1][0], local_boxes[box].vals[1][1], local_boxes[box].vals[2][0], local_boxes[box].vals[2][1]);
+        }
+        const INT_TYPE partition_limit = (INT_TYPE(1)<<(nboxes-1));
+        INT_TYPE best_partition = INT_TYPE(-1);
+        T best_heuristic;
+        for (INT_TYPE partition_bits = 1; partition_bits < partition_limit; ++partition_bits) {
+            Box<T,NAXES> sub_boxes[2];
+            sub_boxes[0] = local_boxes[0];
+            sub_boxes[1].initBounds();
+            INT_TYPE sub_counts[2] = {1,0};
+            for (INT_TYPE bit = 0; bit < nboxes-1; ++bit) {
+                INT_TYPE dest = (partition_bits>>bit)&1;
+                sub_boxes[dest].combine(local_boxes[bit+1]);
+                ++sub_counts[dest];
+            }
+            //printf("Partition bits %u: sub_box[0]: (%f-%f)x(%f-%f)x(%f-%f)\n", uint(partition_bits), sub_boxes[0].vals[0][0], sub_boxes[0].vals[0][1], sub_boxes[0].vals[1][0], sub_boxes[0].vals[1][1], sub_boxes[0].vals[2][0], sub_boxes[0].vals[2][1]);
+            //printf("Partition bits %u: sub_box[1]: (%f-%f)x(%f-%f)x(%f-%f)\n", uint(partition_bits), sub_boxes[1].vals[0][0], sub_boxes[1].vals[0][1], sub_boxes[1].vals[1][0], sub_boxes[1].vals[1][1], sub_boxes[1].vals[2][0], sub_boxes[1].vals[2][1]);
+            const T heuristic =
+                unweightedHeuristic<H>(sub_boxes[0])*sub_counts[0] +
+                unweightedHeuristic<H>(sub_boxes[1])*sub_counts[1];
+            //printf("Partition bits %u: heuristic = %f (= %f*%u + %f*%u)\n",uint(partition_bits),heuristic, unweightedHeuristic<H>(sub_boxes[0]), uint(sub_counts[0]), unweightedHeuristic<H>(sub_boxes[1]), uint(sub_counts[1]));
+            if (best_partition == INT_TYPE(-1) || heuristic < best_heuristic) {
+                //printf("    New best\n");
+                best_partition = partition_bits;
+                best_heuristic = heuristic;
+                split_boxes[0] = sub_boxes[0];
+                split_boxes[1] = sub_boxes[1];
+            }
+        }
+
+#if 0 // This isn't actually necessary with the current design, because I changed how the number of subtree nodes is determined.
+        // If best_partition is partition_limit-1, there's only 1 box
+        // in partition 0.  We should instead put this in partition 1,
+        // so that we can help always have the internal node indices first
+        // in each node.  That gets used to (fairly) quickly determine
+        // the number of nodes in a sub-tree.
+        if (best_partition == partition_limit - 1) {
+            // Put the first index last.
+            SRC_INT_TYPE last_index = indices[0];
+            SRC_INT_TYPE* dest_indices = indices;
+            SRC_INT_TYPE* local_split_indices = indices + nboxes-1;
+            for (; dest_indices != local_split_indices; ++dest_indices) {
+                dest_indices[0] = dest_indices[1];
+            }
+            *local_split_indices = last_index;
+            split_indices = local_split_indices;
+
+            // Swap the boxes
+            const Box<T,NAXES> temp_box = sub_boxes[0];
+            sub_boxes[0] = sub_boxes[1];
+            sub_boxes[1] = temp_box;
+            return;
+        }
+#endif
+
+        // Reorder the indices.
+        // NOTE: Index 0 is always in partition 0, so can stay put.
+        SRC_INT_TYPE local_indices[SMALL_LIMIT-1];
+        for (INT_TYPE box = 0; box < nboxes-1; ++box) {
+            local_indices[box] = indices[box+1];
+        }
+        SRC_INT_TYPE* dest_indices = indices+1;
+        SRC_INT_TYPE* src_indices = local_indices;
+        // Copy partition 0
+        for (INT_TYPE bit = 0; bit < nboxes-1; ++bit, ++src_indices) {
+            if (!((best_partition>>bit)&1)) {
+                //printf("Copying %u into partition 0\n",uint(*src_indices));
+                *dest_indices = *src_indices;
+                ++dest_indices;
+            }
+        }
+        split_indices = dest_indices;
+        // Copy partition 1
+        src_indices = local_indices;
+        for (INT_TYPE bit = 0; bit < nboxes-1; ++bit, ++src_indices) {
+            if ((best_partition>>bit)&1) {
+                //printf("Copying %u into partition 1\n",uint(*src_indices));
+                *dest_indices = *src_indices;
+                ++dest_indices;
+            }
+        }
+        return;
+    }
+
+    uint max_axis = 0;
+    T max_axis_length = axes_minmax.vals[0][1] - axes_minmax.vals[0][0];
+    for (uint axis = 1; axis < NAXES; ++axis) {
+        const T axis_length = axes_minmax.vals[axis][1] - axes_minmax.vals[axis][0];
+        if (axis_length > max_axis_length) {
+            max_axis = axis;
+            max_axis_length = axis_length;
+        }
+    }
+
+    if (!(max_axis_length > T(0))) {
+        // All boxes are a single point or NaN.
+        // Pick an arbitrary split point.
+        split_indices = indices + nboxes/2;
+        split_boxes[0] = axes_minmax;
+        split_boxes[1] = axes_minmax;
+        return;
+    }
+
+    const INT_TYPE axis = max_axis;
+
+    constexpr INT_TYPE MID_LIMIT = 2*NSPANS;
+    if (nboxes <= MID_LIMIT) {
+        // Sort along axis, and try all possible splits.
+
+#if 1
+        // First, compute midpoints
+        T midpointsx2[MID_LIMIT];
+        for (INT_TYPE i = 0; i < nboxes; ++i) {
+            midpointsx2[i] = utBoxCenter(boxes[indices[i]], axis);
+        }
+        SRC_INT_TYPE local_indices[MID_LIMIT];
+        for (INT_TYPE i = 0; i < nboxes; ++i) {
+            local_indices[i] = i;
+        }
+
+        const INT_TYPE chunk_starts[5] = {0, nboxes/4, nboxes/2, INT_TYPE((3*uint64(nboxes))/4), nboxes};
+
+        // For sorting, insertion sort 4 chunks and merge them
+        for (INT_TYPE chunk = 0; chunk < 4; ++chunk) {
+            const INT_TYPE start = chunk_starts[chunk];
+            const INT_TYPE end = chunk_starts[chunk+1];
+            for (INT_TYPE i = start+1; i < end; ++i) {
+                SRC_INT_TYPE indexi = local_indices[i];
+                T vi = midpointsx2[indexi];
+                for (INT_TYPE j = start; j < i; ++j) {
+                    SRC_INT_TYPE indexj = local_indices[j];
+                    T vj = midpointsx2[indexj];
+                    if (vi < vj) {
+                        do {
+                            local_indices[j] = indexi;
+                            indexi = indexj;
+                            ++j;
+                            if (j == i) {
+                                local_indices[j] = indexi;
+                                break;
+                            }
+                            indexj = local_indices[j];
+                        } while (true);
+                        break;
+                    }
+                }
+            }
+        }
+        // Merge chunks into another buffer
+        SRC_INT_TYPE local_indices_temp[MID_LIMIT];
+        std::merge(local_indices, local_indices+chunk_starts[1],
+            local_indices+chunk_starts[1], local_indices+chunk_starts[2],
+            local_indices_temp, [&midpointsx2](const SRC_INT_TYPE a, const SRC_INT_TYPE b)->bool {
+            return midpointsx2[a] < midpointsx2[b];
+        });
+        std::merge(local_indices+chunk_starts[2], local_indices+chunk_starts[3],
+            local_indices+chunk_starts[3], local_indices+chunk_starts[4],
+            local_indices_temp+chunk_starts[2], [&midpointsx2](const SRC_INT_TYPE a, const SRC_INT_TYPE b)->bool {
+            return midpointsx2[a] < midpointsx2[b];
+        });
+        std::merge(local_indices_temp, local_indices_temp+chunk_starts[2],
+            local_indices_temp+chunk_starts[2], local_indices_temp+chunk_starts[4],
+            local_indices, [&midpointsx2](const SRC_INT_TYPE a, const SRC_INT_TYPE b)->bool {
+            return midpointsx2[a] < midpointsx2[b];
+        });
+
+        // Translate local_indices into indices
+        for (INT_TYPE i = 0; i < nboxes; ++i) {
+            local_indices[i] = indices[local_indices[i]];
+        }
+        // Copy back
+        for (INT_TYPE i = 0; i < nboxes; ++i) {
+            indices[i] = local_indices[i];
+        }
+#else
+        std::stable_sort(indices, indices+nboxes, [boxes,max_axis](SRC_INT_TYPE a, SRC_INT_TYPE b)->bool {
+            return utBoxCenter(boxes[a], max_axis) < utBoxCenter(boxes[b], max_axis);
+        });
+#endif
+
+        // Accumulate boxes
+        Box<T,NAXES> left_boxes[MID_LIMIT-1];
+        Box<T,NAXES> right_boxes[MID_LIMIT-1];
+        const INT_TYPE nsplits = nboxes-1;
+        Box<T,NAXES> box_accumulator(boxes[local_indices[0]]);
+        left_boxes[0] = box_accumulator;
+        for (INT_TYPE i = 1; i < nsplits; ++i) {
+            box_accumulator.combine(boxes[local_indices[i]]);
+            left_boxes[i] = box_accumulator;
+        }
+        box_accumulator.initBounds(boxes[local_indices[nsplits-1]]);
+        right_boxes[nsplits-1] = box_accumulator;
+        for (INT_TYPE i = nsplits-1; i > 0; --i) {
+            box_accumulator.combine(boxes[local_indices[i]]);
+            right_boxes[i-1] = box_accumulator;
+        }
+
+        INT_TYPE best_split = 0;
+        T best_local_heuristic =
+            unweightedHeuristic<H>(left_boxes[0]) +
+            unweightedHeuristic<H>(right_boxes[0])*(nboxes-1);
+        for (INT_TYPE split = 1; split < nsplits; ++split) {
+            const T heuristic =
+                unweightedHeuristic<H>(left_boxes[split])*(split+1) +
+                unweightedHeuristic<H>(right_boxes[split])*(nboxes-(split+1));
+            if (heuristic < best_local_heuristic) {
+                best_split = split;
+                best_local_heuristic = heuristic;
+            }
+        }
+        split_indices = indices+best_split+1;
+        split_boxes[0] = left_boxes[best_split];
+        split_boxes[1] = right_boxes[best_split];
+        return;
+    }
+
+    const T axis_min = axes_minmax.vals[max_axis][0];
+    const T axis_length = max_axis_length;
+    Box<T,NAXES> span_boxes[NSPANS];
+    for (INT_TYPE i = 0; i < NSPANS; ++i) {
+        span_boxes[i].initBounds();
+    }
+    INT_TYPE span_counts[NSPANS];
+    for (INT_TYPE i = 0; i < NSPANS; ++i) {
+        span_counts[i] = 0;
+    }
+
+    const T axis_min_x2 = ut_BoxCentre<BOX_TYPE>::scale*axis_min;
+    // NOTE: Factor of 0.5 is factored out of the average when using the average value to determine the span that a box lies in.
+    const T axis_index_scale = (T(1.0/ut_BoxCentre<BOX_TYPE>::scale)*NSPANS)/axis_length;
+    constexpr INT_TYPE BOX_SPANS_PARALLEL_THRESHOLD = 2048;
+    INT_TYPE ntasks = 1;
+    if (nboxes >= BOX_SPANS_PARALLEL_THRESHOLD) {
+        INT_TYPE nprocessors = UT_Thread::getNumProcessors();
+        ntasks = (nprocessors > 1) ? SYSmin(4*nprocessors, nboxes/(BOX_SPANS_PARALLEL_THRESHOLD/2)) : 1;
+    }
+    if (ntasks == 1) {
+        for (INT_TYPE indexi = 0; indexi < nboxes; ++indexi) {
+            const auto& box = boxes[indices[indexi]];
+            const T sum = utBoxCenter(box, axis);
+            const uint span_index = SYSclamp(int((sum-axis_min_x2)*axis_index_scale), int(0), int(NSPANS-1));
+            ++span_counts[span_index];
+            Box<T,NAXES>& span_box = span_boxes[span_index];
+            span_box.combine(box);
+        }
+    }
+    else {
+        UT_SmallArray<Box<T,NAXES>> parallel_boxes;
+        UT_SmallArray<INT_TYPE> parallel_counts;
+        igl::parallel_for(
+          nboxes,
+          [&parallel_boxes,&parallel_counts](int n)
+          {
+            parallel_boxes.setSize( NSPANS*n);
+            parallel_counts.setSize(NSPANS*n);
+            for(int t = 0;t<n;t++)
+            {
+              for (INT_TYPE i = 0; i < NSPANS; ++i) 
+              {
+                parallel_boxes[t*NSPANS+i].initBounds();
+                parallel_counts[t*NSPANS+i] = 0;
+              }
+            }
+          },
+          [&parallel_boxes,&parallel_counts,&boxes,indices,axis,axis_min_x2,axis_index_scale](int j, int t)
+          {
+            const auto& box = boxes[indices[j]];
+            const T sum = utBoxCenter(box, axis);
+            const uint span_index = SYSclamp(int((sum-axis_min_x2)*axis_index_scale), int(0), int(NSPANS-1));
+            ++parallel_counts[t*NSPANS+span_index];
+            Box<T,NAXES>& span_box = parallel_boxes[t*NSPANS+span_index];
+            span_box.combine(box);
+          },
+          [&parallel_boxes,&parallel_counts,&span_boxes,&span_counts](int t)
+          {
+            for(int i = 0;i<NSPANS;i++)
+            {
+              span_counts[i] += parallel_counts[t*NSPANS + i];
+              span_boxes[i].combine(parallel_boxes[t*NSPANS + i]);
+            }
+          });
+
+    }
+
+    // Spans 0 to NSPANS-2
+    Box<T,NAXES> left_boxes[NSPLITS];
+    // Spans 1 to NSPANS-1
+    Box<T,NAXES> right_boxes[NSPLITS];
+
+    // Accumulate boxes
+    Box<T,NAXES> box_accumulator = span_boxes[0];
+    left_boxes[0] = box_accumulator;
+    for (INT_TYPE i = 1; i < NSPLITS; ++i) {
+        box_accumulator.combine(span_boxes[i]);
+        left_boxes[i] = box_accumulator;
+    }
+    box_accumulator = span_boxes[NSPANS-1];
+    right_boxes[NSPLITS-1] = box_accumulator;
+    for (INT_TYPE i = NSPLITS-1; i > 0; --i) {
+        box_accumulator.combine(span_boxes[i]);
+        right_boxes[i-1] = box_accumulator;
+    }
+
+    INT_TYPE left_counts[NSPLITS];
+
+    // Accumulate counts
+    INT_TYPE count_accumulator = span_counts[0];
+    left_counts[0] = count_accumulator;
+    for (INT_TYPE spliti = 1; spliti < NSPLITS; ++spliti) {
+        count_accumulator += span_counts[spliti];
+        left_counts[spliti] = count_accumulator;
+    }
+
+    // Check which split is optimal, making sure that at least 1/MIN_FRACTION of all boxes are on each side.
+    const INT_TYPE min_count = nboxes/MIN_FRACTION;
+    UT_ASSERT_MSG_P(min_count > 0, "MID_LIMIT above should have been large enough that nboxes would be > MIN_FRACTION");
+    const INT_TYPE max_count = ((MIN_FRACTION-1)*uint64(nboxes))/MIN_FRACTION;
+    UT_ASSERT_MSG_P(max_count < nboxes, "I'm not sure how this could happen mathematically, but it needs to be checked.");
+    T smallest_heuristic = std::numeric_limits<T>::infinity();
+    INT_TYPE split_index = -1;
+    for (INT_TYPE spliti = 0; spliti < NSPLITS; ++spliti) {
+        const INT_TYPE left_count = left_counts[spliti];
+        if (left_count < min_count || left_count > max_count) {
+            continue;
+        }
+        const INT_TYPE right_count = nboxes-left_count;
+        const T heuristic =
+            left_count*unweightedHeuristic<H>(left_boxes[spliti]) +
+            right_count*unweightedHeuristic<H>(right_boxes[spliti]);
+        if (heuristic < smallest_heuristic) {
+            smallest_heuristic = heuristic;
+            split_index = spliti;
+        }
+    }
+
+    SRC_INT_TYPE*const indices_end = indices+nboxes;
+
+    if (split_index == -1) {
+        // No split was anywhere close to balanced, so we fall back to searching for one.
+
+        // First, find the span containing the "balance" point, namely where left_counts goes from
+        // being less than min_count to more than max_count.
+        // If that's span 0, use max_count as the ordered index to select,
+        // if it's span NSPANS-1, use min_count as the ordered index to select,
+        // else use nboxes/2 as the ordered index to select.
+        //T min_pivotx2 = -std::numeric_limits<T>::infinity();
+        //T max_pivotx2 = std::numeric_limits<T>::infinity();
+        SRC_INT_TYPE* nth_index;
+        if (left_counts[0] > max_count) {
+            // Search for max_count ordered index
+            nth_index = indices+max_count;
+            //max_pivotx2 = max_axis_min_x2 + max_axis_length/(NSPANS/ut_BoxCentre<BOX_TYPE>::scale);
+        }
+        else if (left_counts[NSPLITS-1] < min_count) {
+            // Search for min_count ordered index
+            nth_index = indices+min_count;
+            //min_pivotx2 = max_axis_min_x2 + max_axis_length - max_axis_length/(NSPANS/ut_BoxCentre<BOX_TYPE>::scale);
+        }
+        else {
+            // Search for nboxes/2 ordered index
+            nth_index = indices+nboxes/2;
+            //for (INT_TYPE spliti = 1; spliti < NSPLITS; ++spliti) {
+            //    // The second condition should be redundant, but is just in case.
+            //    if (left_counts[spliti] > max_count || spliti == NSPLITS-1) {
+            //        min_pivotx2 = max_axis_min_x2 + spliti*max_axis_length/(NSPANS/ut_BoxCentre<BOX_TYPE>::scale);
+            //        max_pivotx2 = max_axis_min_x2 + (spliti+1)*max_axis_length/(NSPANS/ut_BoxCentre<BOX_TYPE>::scale);
+            //        break;
+            //    }
+            //}
+        }
+        nthElement<T>(boxes,indices,indices+nboxes,max_axis,nth_index);//,min_pivotx2,max_pivotx2);
+
+        split_indices = nth_index;
+        Box<T,NAXES> left_box(boxes[indices[0]]);
+        for (SRC_INT_TYPE* left_indices = indices+1; left_indices < nth_index; ++left_indices) {
+            left_box.combine(boxes[*left_indices]);
+        }
+        Box<T,NAXES> right_box(boxes[nth_index[0]]);
+        for (SRC_INT_TYPE* right_indices = nth_index+1; right_indices < indices_end; ++right_indices) {
+            right_box.combine(boxes[*right_indices]);
+        }
+        split_boxes[0] = left_box;
+        split_boxes[1] = right_box;
+    }
+    else {
+        const T pivotx2 = axis_min_x2 + (split_index+1)*axis_length/(NSPANS/ut_BoxCentre<BOX_TYPE>::scale);
+        SRC_INT_TYPE* ppivot_start;
+        SRC_INT_TYPE* ppivot_end;
+        partitionByCentre(boxes,indices,indices+nboxes,max_axis,pivotx2,ppivot_start,ppivot_end);
+
+        split_indices = indices + left_counts[split_index];
+
+        // Ignoring roundoff error, we would have
+        // split_indices >= ppivot_start && split_indices <= ppivot_end,
+        // but it may not always be in practice.
+        if (split_indices >= ppivot_start && split_indices <= ppivot_end) {
+            split_boxes[0] = left_boxes[split_index];
+            split_boxes[1] = right_boxes[split_index];
+            return;
+        }
+
+        // Roundoff error changed the split, so we need to recompute the boxes.
+        if (split_indices < ppivot_start) {
+            split_indices = ppivot_start;
+        }
+        else {//(split_indices > ppivot_end)
+            split_indices = ppivot_end;
+        }
+
+        // Emergency checks, just in case
+        if (split_indices == indices) {
+            ++split_indices;
+        }
+        else if (split_indices == indices_end) {
+            --split_indices;
+        }
+
+        Box<T,NAXES> left_box(boxes[indices[0]]);
+        for (SRC_INT_TYPE* left_indices = indices+1; left_indices < split_indices; ++left_indices) {
+            left_box.combine(boxes[*left_indices]);
+        }
+        Box<T,NAXES> right_box(boxes[split_indices[0]]);
+        for (SRC_INT_TYPE* right_indices = split_indices+1; right_indices < indices_end; ++right_indices) {
+            right_box.combine(boxes[*right_indices]);
+        }
+        split_boxes[0] = left_box;
+        split_boxes[1] = right_box;
+    }
+}
+
+template<uint N>
+template<uint PARALLEL_THRESHOLD, typename SRC_INT_TYPE>
+inline void BVH<N>::adjustParallelChildNodes(INT_TYPE nparallel, UT_Array<Node>& nodes, Node& node, UT_Array<Node>* parallel_nodes, SRC_INT_TYPE* sub_indices) noexcept
+{
+  // Alec: No need to parallelize this...
+    //UTparallelFor(UT_BlockedRange<INT_TYPE>(0,nparallel), [&node,&nodes,&parallel_nodes,&sub_indices](const UT_BlockedRange<INT_TYPE>& r) {
+        INT_TYPE counted_parallel = 0;
+        INT_TYPE childi = 0;
+        for(int taski = 0;taski < nparallel; taski++)
+        {
+        //for (INT_TYPE taski = r.begin(), end = r.end(); taski < end; ++taski) {
+            // First, find which child this is
+            INT_TYPE sub_nboxes;
+            for (; childi < N; ++childi) {
+                sub_nboxes = sub_indices[childi+1]-sub_indices[childi];
+                if (sub_nboxes >= PARALLEL_THRESHOLD) {
+                    if (counted_parallel == taski) {
+                        break;
+                    }
+                    ++counted_parallel;
+                }
+            }
+            UT_ASSERT_P(counted_parallel == taski);
+
+            const UT_Array<Node>& local_nodes = parallel_nodes[counted_parallel];
+            INT_TYPE n = local_nodes.size();
+            INT_TYPE local_nodes_start = Node::getInternalNum(node.child[childi])+1;
+            ++counted_parallel;
+            ++childi;
+
+            for (INT_TYPE j = 0; j < n; ++j) {
+                Node local_node = local_nodes[j];
+                for (INT_TYPE childj = 0; childj < N; ++childj) {
+                    INT_TYPE local_child = local_node.child[childj];
+                    if (Node::isInternal(local_child) && local_child != Node::EMPTY) {
+                        local_child += local_nodes_start;
+                        local_node.child[childj] = local_child;
+                    }
+                }
+                nodes[local_nodes_start+j] = local_node;
+            }
+        }
+}
+
+template<uint N>
+template<typename T,typename BOX_TYPE,typename SRC_INT_TYPE>
+void BVH<N>::nthElement(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const SRC_INT_TYPE* indices_end, const uint axis, SRC_INT_TYPE*const nth) noexcept {//, const T min_pivotx2, const T max_pivotx2) noexcept {
+    while (true) {
+        // Choose median of first, middle, and last as the pivot
+        T pivots[3] = {
+            utBoxCenter(boxes[indices[0]], axis),
+            utBoxCenter(boxes[indices[(indices_end-indices)/2]], axis),
+            utBoxCenter(boxes[*(indices_end-1)], axis)
+        };
+        if (pivots[0] < pivots[1]) {
+            const T temp = pivots[0];
+            pivots[0] = pivots[1];
+            pivots[1] = temp;
+        }
+        if (pivots[0] < pivots[2]) {
+            const T temp = pivots[0];
+            pivots[0] = pivots[2];
+            pivots[2] = temp;
+        }
+        if (pivots[1] < pivots[2]) {
+            const T temp = pivots[1];
+            pivots[1] = pivots[2];
+            pivots[2] = temp;
+        }
+        T mid_pivotx2 = pivots[1];
+#if 0
+        // We limit the pivot, because we know that the true value is between min and max
+        if (mid_pivotx2 < min_pivotx2) {
+            mid_pivotx2 = min_pivotx2;
+        }
+        else if (mid_pivotx2 > max_pivotx2) {
+            mid_pivotx2 = max_pivotx2;
+        }
+#endif
+        SRC_INT_TYPE* pivot_start;
+        SRC_INT_TYPE* pivot_end;
+        partitionByCentre(boxes,indices,indices_end,axis,mid_pivotx2,pivot_start,pivot_end);
+        if (nth < pivot_start) {
+            indices_end = pivot_start;
+        }
+        else if (nth < pivot_end) {
+            // nth is in the middle of the pivot range,
+            // which is in the right place, so we're done.
+            return;
+        }
+        else {
+            indices = pivot_end;
+        }
+        if (indices_end <= indices+1) {
+            return;
+        }
+    }
+}
+
+template<uint N>
+template<typename T,typename BOX_TYPE,typename SRC_INT_TYPE>
+void BVH<N>::partitionByCentre(const BOX_TYPE* boxes, SRC_INT_TYPE*const indices, const SRC_INT_TYPE*const indices_end, const uint axis, const T pivotx2, SRC_INT_TYPE*& ppivot_start, SRC_INT_TYPE*& ppivot_end) noexcept {
+    // TODO: Consider parallelizing this!
+
+    // First element >= pivot
+    SRC_INT_TYPE* pivot_start = indices;
+    // First element > pivot
+    SRC_INT_TYPE* pivot_end = indices;
+
+    // Loop through forward once
+    for (SRC_INT_TYPE* psrc_index = indices; psrc_index != indices_end; ++psrc_index) {
+        const T srcsum = utBoxCenter(boxes[*psrc_index], axis);
+        if (srcsum < pivotx2) {
+            if (psrc_index != pivot_start) {
+                if (pivot_start == pivot_end) {
+                    // Common case: nothing equal to the pivot
+                    const SRC_INT_TYPE temp = *psrc_index;
+                    *psrc_index = *pivot_start;
+                    *pivot_start = temp;
+                }
+                else {
+                    // Less common case: at least one thing equal to the pivot
+                    const SRC_INT_TYPE temp = *psrc_index;
+                    *psrc_index = *pivot_end;
+                    *pivot_end = *pivot_start;
+                    *pivot_start = temp;
+                }
+            }
+            ++pivot_start;
+            ++pivot_end;
+        }
+        else if (srcsum == pivotx2) {
+            // Add to the pivot area
+            if (psrc_index != pivot_end) {
+                const SRC_INT_TYPE temp = *psrc_index;
+                *psrc_index = *pivot_end;
+                *pivot_end = temp;
+            }
+            ++pivot_end;
+        }
+    }
+    ppivot_start = pivot_start;
+    ppivot_end = pivot_end;
+}
+
+#if 0
+template<uint N>
+void BVH<N>::debugDump() const {
+    printf("\nNode 0: {\n");
+    UT_WorkBuffer indent;
+    indent.append(80, ' ');
+    UT_Array<INT_TYPE> stack;
+    stack.append(0);
+    stack.append(0);
+    while (!stack.isEmpty()) {
+        int depth = stack.size()/2;
+        if (indent.length() < 4*depth) {
+            indent.append(4, ' ');
+        }
+        INT_TYPE cur_nodei = stack[stack.size()-2];
+        INT_TYPE cur_i = stack[stack.size()-1];
+        if (cur_i == N) {
+            printf(indent.buffer()+indent.length()-(4*(depth-1)));
+            printf("}\n");
+            stack.removeLast();
+            stack.removeLast();
+            continue;
+        }
+        ++stack[stack.size()-1];
+        Node& cur_node = myRoot[cur_nodei];
+        INT_TYPE child_nodei = cur_node.child[cur_i];
+        if (Node::isInternal(child_nodei)) {
+            if (child_nodei == Node::EMPTY) {
+                printf(indent.buffer()+indent.length()-(4*(depth-1)));
+                printf("}\n");
+                stack.removeLast();
+                stack.removeLast();
+                continue;
+            }
+            INT_TYPE internal_node = Node::getInternalNum(child_nodei);
+            printf(indent.buffer()+indent.length()-(4*depth));
+            printf("Node %u: {\n", uint(internal_node));
+            stack.append(internal_node);
+            stack.append(0);
+            continue;
+        }
+        else {
+            printf(indent.buffer()+indent.length()-(4*depth));
+            printf("Tri %u\n", uint(child_nodei));
+        }
+    }
+}
+#endif
+
+} // UT namespace
+} // End HDK_Sample namespace
+}}
+#endif
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      Functions and structures for computing solid angles.
+ */
+
+#pragma once
+
+#ifndef __HDK_UT_SolidAngle_h__
+#define __HDK_UT_SolidAngle_h__
+
+
+
+
+
+#include <memory>
+
+namespace igl { namespace FastWindingNumber {
+namespace HDK_Sample {
+
+template<typename T>
+using UT_Vector2T = UT_FixedVector<T,2>;
+template<typename T>
+using UT_Vector3T = UT_FixedVector<T,3>;
+
+template <typename T>
+SYS_FORCE_INLINE T cross(const UT_Vector2T<T> &v1, const UT_Vector2T<T> &v2)
+{
+    return v1[0]*v2[1] - v1[1]*v2[0];
+}
+
+template <typename T>
+SYS_FORCE_INLINE
+UT_Vector3T<T> cross(const UT_Vector3T<T> &v1, const UT_Vector3T<T> &v2)
+{
+    UT_Vector3T<T> result;
+    // compute the cross product:
+    result[0] = v1[1]*v2[2] - v1[2]*v2[1];
+    result[1] = v1[2]*v2[0] - v1[0]*v2[2];
+    result[2] = v1[0]*v2[1] - v1[1]*v2[0];
+    return result;
+}
+
+/// Returns the signed solid angle subtended by triangle abc
+/// from query point.
+///
+/// WARNING: This uses the right-handed normal convention, whereas most of
+///          Houdini uses the left-handed normal convention, so either
+///          negate the output, or swap b and c if you want it to be
+///          positive inside and negative outside.
+template<typename T>
+inline T UTsignedSolidAngleTri(
+    const UT_Vector3T<T> &a,
+    const UT_Vector3T<T> &b,
+    const UT_Vector3T<T> &c,
+    const UT_Vector3T<T> &query)
+{
+    // Make a, b, and c relative to query
+    UT_Vector3T<T> qa = a-query;
+    UT_Vector3T<T> qb = b-query;
+    UT_Vector3T<T> qc = c-query;
+
+    const T alength = qa.length();
+    const T blength = qb.length();
+    const T clength = qc.length();
+
+    // If any triangle vertices are coincident with query,
+    // query is on the surface, which we treat as no solid angle.
+    if (alength == 0 || blength == 0 || clength == 0)
+        return T(0);
+
+    // Normalize the vectors
+    qa /= alength;
+    qb /= blength;
+    qc /= clength;
+
+    // The formula on Wikipedia has roughly dot(qa,cross(qb,qc)),
+    // but that's unstable when qa, qb, and qc are very close,
+    // (e.g. if the input triangle was very far away).
+    // This should be equivalent, but more stable.
+    const T numerator = dot(qa, cross(qb-qa, qc-qa));
+
+    // If numerator is 0, regardless of denominator, query is on the
+    // surface, which we treat as no solid angle.
+    if (numerator == 0)
+        return T(0);
+
+    const T denominator = T(1) + dot(qa,qb) + dot(qa,qc) + dot(qb,qc);
+
+    return T(2)*SYSatan2(numerator, denominator);
+}
+
+template<typename T>
+inline T UTsignedSolidAngleQuad(
+    const UT_Vector3T<T> &a,
+    const UT_Vector3T<T> &b,
+    const UT_Vector3T<T> &c,
+    const UT_Vector3T<T> &d,
+    const UT_Vector3T<T> &query)
+{
+    // Make a, b, c, and d relative to query
+    UT_Vector3T<T> v[4] = {
+        a-query,
+        b-query,
+        c-query,
+        d-query
+    };
+
+    const T lengths[4] = {
+        v[0].length(),
+        v[1].length(),
+        v[2].length(),
+        v[3].length()
+    };
+
+    // If any quad vertices are coincident with query,
+    // query is on the surface, which we treat as no solid angle.
+    // We could add the contribution from the non-planar part,
+    // but in the context of a mesh, we'd still miss some, like
+    // we do in the triangle case.
+    if (lengths[0] == T(0) || lengths[1] == T(0) || lengths[2] == T(0) || lengths[3] == T(0))
+        return T(0);
+
+    // Normalize the vectors
+    v[0] /= lengths[0];
+    v[1] /= lengths[1];
+    v[2] /= lengths[2];
+    v[3] /= lengths[3];
+
+    // Compute (unnormalized, but consistently-scaled) barycentric coordinates
+    // for the query point inside the tetrahedron of points.
+    // If 0 or 4 of the coordinates are positive, (or slightly negative), the
+    // query is (approximately) inside, so the choice of triangulation matters.
+    // Otherwise, the triangulation doesn't matter.
+
+    const UT_Vector3T<T> diag02 = v[2]-v[0];
+    const UT_Vector3T<T> diag13 = v[3]-v[1];
+    const UT_Vector3T<T> v01 = v[1]-v[0];
+    const UT_Vector3T<T> v23 = v[3]-v[2];
+
+    T bary[4];
+    bary[0] = dot(v[3],cross(v23,diag13));
+    bary[1] = -dot(v[2],cross(v23,diag02));
+    bary[2] = -dot(v[1],cross(v01,diag13));
+    bary[3] = dot(v[0],cross(v01,diag02));
+
+    const T dot01 = dot(v[0],v[1]);
+    const T dot12 = dot(v[1],v[2]);
+    const T dot23 = dot(v[2],v[3]);
+    const T dot30 = dot(v[3],v[0]);
+
+    T omega = T(0);
+
+    // Equation of a bilinear patch in barycentric coordinates of its
+    // tetrahedron is x0*x2 = x1*x3.  Less is one side; greater is other.
+    if (bary[0]*bary[2] < bary[1]*bary[3])
+    {
+        // Split 0-2: triangles 0,1,2 and 0,2,3
+        const T numerator012 = bary[3];
+        const T numerator023 = bary[1];
+        const T dot02 = dot(v[0],v[2]);
+
+        // If numerator is 0, regardless of denominator, query is on the
+        // surface, which we treat as no solid angle.
+        if (numerator012 != T(0))
+        {
+            const T denominator012 = T(1) + dot01 + dot12 + dot02;
+            omega = SYSatan2(numerator012, denominator012);
+        }
+        if (numerator023 != T(0))
+        {
+            const T denominator023 = T(1) + dot02 + dot23 + dot30;
+            omega += SYSatan2(numerator023, denominator023);
+        }
+    }
+    else
+    {
+        // Split 1-3: triangles 0,1,3 and 1,2,3
+        const T numerator013 = -bary[2];
+        const T numerator123 = -bary[0];
+        const T dot13 = dot(v[1],v[3]);
+
+        // If numerator is 0, regardless of denominator, query is on the
+        // surface, which we treat as no solid angle.
+        if (numerator013 != T(0))
+        {
+            const T denominator013 = T(1) + dot01 + dot13 + dot30;
+            omega = SYSatan2(numerator013, denominator013);
+        }
+        if (numerator123 != T(0))
+        {
+            const T denominator123 = T(1) + dot12 + dot23 + dot13;
+            omega += SYSatan2(numerator123, denominator123);
+        }
+    }
+    return T(2)*omega;
+}
+
+/// Class for quickly approximating signed solid angle of a large mesh
+/// from many query points.  This is useful for computing the
+/// generalized winding number at many points.
+///
+/// NOTE: This is currently only instantiated for <float,float>.
+template<typename T,typename S>
+class UT_SolidAngle
+{
+public:
+    /// This is outlined so that we don't need to include UT_BVHImpl.h
+    inline UT_SolidAngle();
+    /// This is outlined so that we don't need to include UT_BVHImpl.h
+    inline ~UT_SolidAngle();
+
+    /// NOTE: This does not take ownership over triangle_points or positions,
+    ///       but does keep pointers to them, so the caller must keep them in
+    ///       scope for the lifetime of this structure.
+    UT_SolidAngle(
+        const int ntriangles,
+        const int *const triangle_points,
+        const int npoints,
+        const UT_Vector3T<S> *const positions,
+        const int order = 2)
+        : UT_SolidAngle()
+    { init(ntriangles, triangle_points, npoints, positions, order); }
+
+    /// Initialize the tree and data.
+    /// NOTE: It is safe to call init on a UT_SolidAngle that has had init
+    ///       called on it before, to re-initialize it.
+    inline void init(
+        const int ntriangles,
+        const int *const triangle_points,
+        const int npoints,
+        const UT_Vector3T<S> *const positions,
+        const int order = 2);
+
+    /// Frees myTree and myData, and clears the rest.
+    inline void clear();
+
+    /// Returns true if this is clear
+    bool isClear() const
+    { return myNTriangles == 0; }
+
+    /// Returns an approximation of the signed solid angle of the mesh from the specified query_point
+    /// accuracy_scale is the value of (maxP/q) beyond which the approximation of the box will be used.
+    inline T computeSolidAngle(const UT_Vector3T<T> &query_point, const T accuracy_scale = T(2.0)) const;
+
+private:
+    struct BoxData;
+
+    static constexpr uint BVH_N = 4;
+    UT_BVH<BVH_N> myTree;
+    int myNBoxes;
+    int myOrder;
+    std::unique_ptr<BoxData[]> myData;
+    int myNTriangles;
+    const int *myTrianglePoints;
+    int myNPoints;
+    const UT_Vector3T<S> *myPositions;
+};
+
+template<typename T>
+inline T UTsignedAngleSegment(
+    const UT_Vector2T<T> &a,
+    const UT_Vector2T<T> &b,
+    const UT_Vector2T<T> &query)
+{
+    // Make a and b relative to query
+    UT_Vector2T<T> qa = a-query;
+    UT_Vector2T<T> qb = b-query;
+
+    // If any segment vertices are coincident with query,
+    // query is on the segment, which we treat as no angle.
+    if (qa.isZero() || qb.isZero())
+        return T(0);
+
+    // numerator = |qa||qb|sin(theta)
+    const T numerator = cross(qa, qb);
+
+    // If numerator is 0, regardless of denominator, query is on the
+    // surface, which we treat as no solid angle.
+    if (numerator == 0)
+        return T(0);
+
+    // denominator = |qa||qb|cos(theta)
+    const T denominator = dot(qa,qb);
+
+    // numerator/denominator = tan(theta)
+    return SYSatan2(numerator, denominator);
+}
+
+/// Class for quickly approximating signed subtended angle of a large curve
+/// from many query points.  This is useful for computing the
+/// generalized winding number at many points.
+///
+/// NOTE: This is currently only instantiated for <float,float>.
+template<typename T,typename S>
+class UT_SubtendedAngle
+{
+public:
+    /// This is outlined so that we don't need to include UT_BVHImpl.h
+    inline UT_SubtendedAngle();
+    /// This is outlined so that we don't need to include UT_BVHImpl.h
+    inline ~UT_SubtendedAngle();
+
+    /// NOTE: This does not take ownership over segment_points or positions,
+    ///       but does keep pointers to them, so the caller must keep them in
+    ///       scope for the lifetime of this structure.
+    UT_SubtendedAngle(
+        const int nsegments,
+        const int *const segment_points,
+        const int npoints,
+        const UT_Vector2T<S> *const positions,
+        const int order = 2)
+        : UT_SubtendedAngle()
+    { init(nsegments, segment_points, npoints, positions, order); }
+
+    /// Initialize the tree and data.
+    /// NOTE: It is safe to call init on a UT_SolidAngle that has had init
+    ///       called on it before, to re-initialize it.
+    inline void init(
+        const int nsegments,
+        const int *const segment_points,
+        const int npoints,
+        const UT_Vector2T<S> *const positions,
+        const int order = 2);
+
+    /// Frees myTree and myData, and clears the rest.
+    inline void clear();
+
+    /// Returns true if this is clear
+    bool isClear() const
+    { return myNSegments == 0; }
+
+    /// Returns an approximation of the signed solid angle of the mesh from the specified query_point
+    /// accuracy_scale is the value of (maxP/q) beyond which the approximation of the box will be used.
+    inline T computeAngle(const UT_Vector2T<T> &query_point, const T accuracy_scale = T(2.0)) const;
+
+private:
+    struct BoxData;
+
+    static constexpr uint BVH_N = 4;
+    UT_BVH<BVH_N> myTree;
+    int myNBoxes;
+    int myOrder;
+    std::unique_ptr<BoxData[]> myData;
+    int myNSegments;
+    const int *mySegmentPoints;
+    int myNPoints;
+    const UT_Vector2T<S> *myPositions;
+};
+
+} // End HDK_Sample namespace
+}}
+#endif
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      A wrapper function for the "free" function, used by UT_(Small)Array
+ */
+
+
+
+#include <stdlib.h>
+
+namespace igl { namespace FastWindingNumber {
+
+// This needs to be here or else the warning suppression doesn't work because
+// the templated calling code won't otherwise be compiled until after we've
+// already popped the warning.state. So we just always disable this at file
+// scope here.
+#if defined(__GNUC__) && !defined(__clang__)
+    _Pragma("GCC diagnostic push")
+    _Pragma("GCC diagnostic ignored \"-Wfree-nonheap-object\"")
+#endif
+inline void ut_ArrayImplFree(void *p)
+{
+    free(p);
+}
+#if defined(__GNUC__) && !defined(__clang__)
+    _Pragma("GCC diagnostic pop")
+#endif
+} }
+/*
+ * Copyright (c) 2018 Side Effects Software Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * COMMENTS:
+ *      Functions and structures for computing solid angles.
+ */
+
+
+
+
+
+
+
+
+#include <igl/parallel_for.h>
+#include <type_traits>
+#include <utility>
+
+#define SOLID_ANGLE_TIME_PRECOMPUTE 0
+
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+#include <UT/UT_StopWatch.h>
+#endif
+
+#define SOLID_ANGLE_DEBUG 0
+#if SOLID_ANGLE_DEBUG
+#include <UT/UT_Debug.h>
+#endif
+
+#define TAYLOR_SERIES_ORDER 2
+
+namespace igl { namespace FastWindingNumber {
+
+namespace HDK_Sample {
+
+template<typename T,typename S>
+struct UT_SolidAngle<T,S>::BoxData
+{
+    void clear()
+    {
+        // Set everything to zero
+        memset(this,0,sizeof(*this));
+    }
+
+    using Type  = typename std::conditional<BVH_N==4 && std::is_same<T,float>::value, v4uf, UT_FixedVector<T,BVH_N>>::type;
+    using SType = typename std::conditional<BVH_N==4 && std::is_same<S,float>::value, v4uf, UT_FixedVector<S,BVH_N>>::type;
+
+    /// An upper bound on the squared distance from myAverageP to the farthest point in the box.
+    SType myMaxPDist2;
+
+    /// Centre of mass of the mesh surface in this box
+    UT_FixedVector<Type,3> myAverageP;
+
+    /// Unnormalized, area-weighted normal of the mesh in this box
+    UT_FixedVector<Type,3> myN;
+
+#if TAYLOR_SERIES_ORDER >= 1
+    /// Values for Omega_1
+    /// @{
+    UT_FixedVector<Type,3> myNijDiag;  // Nxx, Nyy, Nzz
+    Type myNxy_Nyx;               // Nxy+Nyx
+    Type myNyz_Nzy;               // Nyz+Nzy
+    Type myNzx_Nxz;               // Nzx+Nxz
+    /// @}
+#endif
+
+#if TAYLOR_SERIES_ORDER >= 2
+    /// Values for Omega_2
+    /// @{
+    UT_FixedVector<Type,3> myNijkDiag; // Nxxx, Nyyy, Nzzz
+    Type mySumPermuteNxyz;        // (Nxyz+Nxzy+Nyzx+Nyxz+Nzxy+Nzyx) = 2*(Nxyz+Nyzx+Nzxy)
+    Type my2Nxxy_Nyxx; // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx
+    Type my2Nxxz_Nzxx; // Nxxz+Nxzx+Nzxx = 2Nxxz+Nzxx
+    Type my2Nyyz_Nzyy; // Nyyz+Nyzy+Nzyy = 2Nyyz+Nzyy
+    Type my2Nyyx_Nxyy; // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy
+    Type my2Nzzx_Nxzz; // Nzzx+Nzxz+Nxzz = 2Nzzx+Nxzz
+    Type my2Nzzy_Nyzz; // Nzzy+Nzyz+Nyzz = 2Nzzy+Nyzz
+    /// @}
+#endif
+};
+
+template<typename T,typename S>
+inline UT_SolidAngle<T,S>::UT_SolidAngle()
+    : myTree()
+    , myNBoxes(0)
+    , myOrder(2)
+    , myData(nullptr)
+    , myNTriangles(0)
+    , myTrianglePoints(nullptr)
+    , myNPoints(0)
+    , myPositions(nullptr)
+{}
+
+template<typename T,typename S>
+inline UT_SolidAngle<T,S>::~UT_SolidAngle()
+{
+    // Default destruction works, but this needs to be outlined
+    // to avoid having to include UT_BVHImpl.h in the header,
+    // (for the UT_UniquePtr destructor.)
+}
+
+template<typename T,typename S>
+inline void UT_SolidAngle<T,S>::init(
+    const int ntriangles,
+    const int *const triangle_points,
+    const int npoints,
+    const UT_Vector3T<S> *const positions,
+    const int order)
+{
+#if SOLID_ANGLE_DEBUG
+    UTdebugFormat("");
+    UTdebugFormat("");
+    UTdebugFormat("Building BVH for {} ntriangles on {} points:", ntriangles, npoints);
+#endif
+    myOrder = order;
+    myNTriangles = ntriangles;
+    myTrianglePoints = triangle_points;
+    myNPoints = npoints;
+    myPositions = positions;
+
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+    UT_StopWatch timer;
+    timer.start();
+#endif
+    UT_SmallArray<UT::Box<S,3>> triangle_boxes;
+    triangle_boxes.setSizeNoInit(ntriangles);
+    if (ntriangles < 16*1024)
+    {
+        const int *cur_triangle_points = triangle_points;
+        for (int i = 0; i < ntriangles; ++i, cur_triangle_points += 3)
+        {
+            UT::Box<S,3> &box = triangle_boxes[i];
+            box.initBounds(positions[cur_triangle_points[0]]);
+            box.enlargeBounds(positions[cur_triangle_points[1]]);
+            box.enlargeBounds(positions[cur_triangle_points[2]]);
+        }
+    }
+    else
+    {
+      igl::parallel_for(ntriangles,
+        [triangle_points,&triangle_boxes,positions](int i)
+        {
+          const int *cur_triangle_points = triangle_points + i*3;
+          UT::Box<S,3> &box = triangle_boxes[i];
+          box.initBounds(positions[cur_triangle_points[0]]);
+          box.enlargeBounds(positions[cur_triangle_points[1]]);
+          box.enlargeBounds(positions[cur_triangle_points[2]]);
+        });
+    }
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+    double time = timer.stop();
+    UTdebugFormat("{} s to create bounding boxes.", time);
+    timer.start();
+#endif
+    myTree.template init<UT::BVH_Heuristic::BOX_AREA,S,3>(triangle_boxes.array(), ntriangles);
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+    time = timer.stop();
+    UTdebugFormat("{} s to initialize UT_BVH structure.  {} nodes", time, myTree.getNumNodes());
+#endif
+
+    //myTree.debugDump();
+
+    const int nnodes = myTree.getNumNodes();
+
+    myNBoxes = nnodes;
+    BoxData *box_data = new BoxData[nnodes];
+    myData.reset(box_data);
+
+    // Some data are only needed during initialization.
+    struct LocalData
+    {
+        // Bounding box
+        UT::Box<S,3> myBox;
+
+        // P and N are needed from each child for computing Nij.
+        UT_Vector3T<T> myAverageP;
+        UT_Vector3T<T> myAreaP;
+        UT_Vector3T<T> myN;
+
+        // Unsigned area is needed for computing the average position.
+        T myArea;
+
+#if TAYLOR_SERIES_ORDER >= 1
+        // These are needed for computing Nijk.
+        UT_Vector3T<T> myNijDiag;
+        T myNxy; T myNyx;
+        T myNyz; T myNzy;
+        T myNzx; T myNxz;
+#endif
+
+#if TAYLOR_SERIES_ORDER >= 2
+        UT_Vector3T<T> myNijkDiag; // Nxxx, Nyyy, Nzzz
+        T mySumPermuteNxyz; // (Nxyz+Nxzy+Nyzx+Nyxz+Nzxy+Nzyx) = 2*(Nxyz+Nyzx+Nzxy)
+        T my2Nxxy_Nyxx;     // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx
+        T my2Nxxz_Nzxx;     // Nxxz+Nxzx+Nzxx = 2Nxxz+Nzxx
+        T my2Nyyz_Nzyy;     // Nyyz+Nyzy+Nzyy = 2Nyyz+Nzyy
+        T my2Nyyx_Nxyy;     // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy
+        T my2Nzzx_Nxzz;     // Nzzx+Nzxz+Nxzz = 2Nzzx+Nxzz
+        T my2Nzzy_Nyzz;     // Nzzy+Nzyz+Nyzz = 2Nzzy+Nyzz
+#endif
+    };
+
+    struct PrecomputeFunctors
+    {
+        BoxData *const myBoxData;
+        const UT::Box<S,3> *const myTriangleBoxes;
+        const int *const myTrianglePoints;
+        const UT_Vector3T<S> *const myPositions;
+        const int myOrder;
+
+        PrecomputeFunctors(
+            BoxData *box_data,
+            const UT::Box<S,3> *triangle_boxes,
+            const int *triangle_points,
+            const UT_Vector3T<S> *positions,
+            const int order)
+            : myBoxData(box_data)
+            , myTriangleBoxes(triangle_boxes)
+            , myTrianglePoints(triangle_points)
+            , myPositions(positions)
+            , myOrder(order)
+        {}
+        constexpr SYS_FORCE_INLINE bool pre(const int nodei, LocalData *data_for_parent) const
+        {
+            return true;
+        }
+        void item(const int itemi, const int parent_nodei, LocalData &data_for_parent) const
+        {
+            const UT_Vector3T<S> *const positions = myPositions;
+            const int *const cur_triangle_points = myTrianglePoints + 3*itemi;
+            const UT_Vector3T<T> a = positions[cur_triangle_points[0]];
+            const UT_Vector3T<T> b = positions[cur_triangle_points[1]];
+            const UT_Vector3T<T> c = positions[cur_triangle_points[2]];
+            const UT_Vector3T<T> ab = b-a;
+            const UT_Vector3T<T> ac = c-a;
+
+            const UT::Box<S,3> &triangle_box = myTriangleBoxes[itemi];
+            data_for_parent.myBox.initBounds(triangle_box.getMin(), triangle_box.getMax());
+
+            // Area-weighted normal (unnormalized)
+            const UT_Vector3T<T> N = T(0.5)*cross(ab,ac);
+            const T area2 = N.length2();
+            const T area = SYSsqrt(area2);
+            const UT_Vector3T<T> P = (a+b+c)/3;
+            data_for_parent.myAverageP = P;
+            data_for_parent.myAreaP = P*area;
+            data_for_parent.myN = N;
+#if SOLID_ANGLE_DEBUG
+            UTdebugFormat("");
+            UTdebugFormat("Triangle {}: P = {}; N = {}; area = {}", itemi, P, N, area);
+            UTdebugFormat("             box = {}", data_for_parent.myBox);
+#endif
+
+            data_for_parent.myArea = area;
+#if TAYLOR_SERIES_ORDER >= 1
+            const int order = myOrder;
+            if (order < 1)
+                return;
+
+            // NOTE: Due to P being at the centroid, triangles have Nij = 0
+            //       contributions to Nij.
+            data_for_parent.myNijDiag = T(0);
+            data_for_parent.myNxy = 0; data_for_parent.myNyx = 0;
+            data_for_parent.myNyz = 0; data_for_parent.myNzy = 0;
+            data_for_parent.myNzx = 0; data_for_parent.myNxz = 0;
+#endif
+
+#if TAYLOR_SERIES_ORDER >= 2
+            if (order < 2)
+                return;
+
+            // If it's zero-length, the results are zero, so we can skip.
+            if (area == 0)
+            {
+                data_for_parent.myNijkDiag = T(0);
+                data_for_parent.mySumPermuteNxyz = 0;
+                data_for_parent.my2Nxxy_Nyxx = 0;
+                data_for_parent.my2Nxxz_Nzxx = 0;
+                data_for_parent.my2Nyyz_Nzyy = 0;
+                data_for_parent.my2Nyyx_Nxyy = 0;
+                data_for_parent.my2Nzzx_Nxzz = 0;
+                data_for_parent.my2Nzzy_Nyzz = 0;
+                return;
+            }
+
+            // We need to use the NORMALIZED normal to multiply the integrals by.
+            UT_Vector3T<T> n = N/area;
+
+            // Figure out the order of a, b, and c in x, y, and z
+            // for use in computing the integrals for Nijk.
+            UT_Vector3T<T> values[3] = {a, b, c};
+
+            int order_x[3] = {0,1,2};
+            if (a[0] > b[0])
+                std::swap(order_x[0],order_x[1]);
+            if (values[order_x[0]][0] > c[0])
+                std::swap(order_x[0],order_x[2]);
+            if (values[order_x[1]][0] > values[order_x[2]][0])
+                std::swap(order_x[1],order_x[2]);
+            T dx = values[order_x[2]][0] - values[order_x[0]][0];
+
+            int order_y[3] = {0,1,2};
+            if (a[1] > b[1])
+                std::swap(order_y[0],order_y[1]);
+            if (values[order_y[0]][1] > c[1])
+                std::swap(order_y[0],order_y[2]);
+            if (values[order_y[1]][1] > values[order_y[2]][1])
+                std::swap(order_y[1],order_y[2]);
+            T dy = values[order_y[2]][1] - values[order_y[0]][1];
+
+            int order_z[3] = {0,1,2};
+            if (a[2] > b[2])
+                std::swap(order_z[0],order_z[1]);
+            if (values[order_z[0]][2] > c[2])
+                std::swap(order_z[0],order_z[2]);
+            if (values[order_z[1]][2] > values[order_z[2]][2])
+                std::swap(order_z[1],order_z[2]);
+            T dz = values[order_z[2]][2] - values[order_z[0]][2];
+
+            auto &&compute_integrals = [](
+                const UT_Vector3T<T> &a,
+                const UT_Vector3T<T> &b,
+                const UT_Vector3T<T> &c,
+                const UT_Vector3T<T> &P,
+                T *integral_ii,
+                T *integral_ij,
+                T *integral_ik,
+                const int i)
+            {
+#if SOLID_ANGLE_DEBUG
+                UTdebugFormat("             Splitting on {}; a = {}; b = {}; c = {}", char('x'+i), a, b, c);
+#endif
+                // NOTE: a, b, and c must be in order of the i axis.
+                // We're splitting the triangle at the middle i coordinate.
+                const UT_Vector3T<T> oab = b - a;
+                const UT_Vector3T<T> oac = c - a;
+                const UT_Vector3T<T> ocb = b - c;
+                UT_ASSERT_MSG_P(oac[i] > 0, "This should have been checked by the caller.");
+                const T t = oab[i]/oac[i];
+                UT_ASSERT_MSG_P(t >= 0 && t <= 1, "Either sorting must have gone wrong, or there are input NaNs.");
+
+                const int j = (i==2) ? 0 : (i+1);
+                const int k = (j==2) ? 0 : (j+1);
+                const T jdiff = t*oac[j] - oab[j];
+                const T kdiff = t*oac[k] - oab[k];
+                UT_Vector3T<T> cross_a;
+                cross_a[0] = (jdiff*oab[k] - kdiff*oab[j]);
+                cross_a[1] = kdiff*oab[i];
+                cross_a[2] = jdiff*oab[i];
+                UT_Vector3T<T> cross_c;
+                cross_c[0] = (jdiff*ocb[k] - kdiff*ocb[j]);
+                cross_c[1] = kdiff*ocb[i];
+                cross_c[2] = jdiff*ocb[i];
+                const T area_scale_a = cross_a.length();
+                const T area_scale_c = cross_c.length();
+                const T Pai = a[i] - P[i];
+                const T Pci = c[i] - P[i];
+
+                // Integral over the area of the triangle of (pi^2)dA,
+                // by splitting the triangle into two at b, the a side
+                // and the c side.
+                const T int_ii_a = area_scale_a*(T(0.5)*Pai*Pai + T(2.0/3.0)*Pai*oab[i] + T(0.25)*oab[i]*oab[i]);
+                const T int_ii_c = area_scale_c*(T(0.5)*Pci*Pci + T(2.0/3.0)*Pci*ocb[i] + T(0.25)*ocb[i]*ocb[i]);
+                *integral_ii = int_ii_a + int_ii_c;
+#if SOLID_ANGLE_DEBUG
+                UTdebugFormat("             integral_{}{}_a = {}; integral_{}{}_c = {}", char('x'+i), char('x'+i), int_ii_a, char('x'+i), char('x'+i), int_ii_c);
+#endif
+
+                int jk = j;
+                T *integral = integral_ij;
+                T diff = jdiff;
+                while (true) // This only does 2 iterations, one for j and one for k
+                {
+                    if (integral)
+                    {
+                        T obmidj = b[jk] + T(0.5)*diff;
+                        T oabmidj = obmidj - a[jk];
+                        T ocbmidj = obmidj - c[jk];
+                        T Paj = a[jk] - P[jk];
+                        T Pcj = c[jk] - P[jk];
+                        // Integral over the area of the triangle of (pi*pj)dA
+                        const T int_ij_a = area_scale_a*(T(0.5)*Pai*Paj + T(1.0/3.0)*Pai*oabmidj + T(1.0/3.0)*Paj*oab[i] + T(0.25)*oab[i]*oabmidj);
+                        const T int_ij_c = area_scale_c*(T(0.5)*Pci*Pcj + T(1.0/3.0)*Pci*ocbmidj + T(1.0/3.0)*Pcj*ocb[i] + T(0.25)*ocb[i]*ocbmidj);
+                        *integral = int_ij_a + int_ij_c;
+#if SOLID_ANGLE_DEBUG
+                        UTdebugFormat("             integral_{}{}_a = {}; integral_{}{}_c = {}", char('x'+i), char('x'+jk), int_ij_a, char('x'+i), char('x'+jk), int_ij_c);
+#endif
+                    }
+                    if (jk == k)
+                        break;
+                    jk = k;
+                    integral = integral_ik;
+                    diff = kdiff;
+                }
+            };
+
+            T integral_xx = 0;
+            T integral_xy = 0;
+            T integral_yy = 0;
+            T integral_yz = 0;
+            T integral_zz = 0;
+            T integral_zx = 0;
+            // Note that if the span of any axis is zero, the integral must be zero,
+            // since there's a factor of (p_i-P_i), i.e. value minus average,
+            // and every value must be equal to the average, giving zero.
+            if (dx > 0)
+            {
+                compute_integrals(
+                    values[order_x[0]], values[order_x[1]], values[order_x[2]], P,
+                    &integral_xx, ((dx >= dy && dy > 0) ? &integral_xy : nullptr), ((dx >= dz && dz > 0) ? &integral_zx : nullptr), 0);
+            }
+            if (dy > 0)
+            {
+                compute_integrals(
+                    values[order_y[0]], values[order_y[1]], values[order_y[2]], P,
+                    &integral_yy, ((dy >= dz && dz > 0) ? &integral_yz : nullptr), ((dx < dy && dx > 0) ? &integral_xy : nullptr), 1);
+            }
+            if (dz > 0)
+            {
+                compute_integrals(
+                    values[order_z[0]], values[order_z[1]], values[order_z[2]], P,
+                    &integral_zz, ((dx < dz && dx > 0) ? &integral_zx : nullptr), ((dy < dz && dy > 0) ? &integral_yz : nullptr), 2);
+            }
+
+            UT_Vector3T<T> Niii;
+            Niii[0] = integral_xx;
+            Niii[1] = integral_yy;
+            Niii[2] = integral_zz;
+            Niii *= n;
+            data_for_parent.myNijkDiag = Niii;
+            data_for_parent.mySumPermuteNxyz = 2*(n[0]*integral_yz + n[1]*integral_zx + n[2]*integral_xy);
+            T Nxxy = n[0]*integral_xy;
+            T Nxxz = n[0]*integral_zx;
+            T Nyyz = n[1]*integral_yz;
+            T Nyyx = n[1]*integral_xy;
+            T Nzzx = n[2]*integral_zx;
+            T Nzzy = n[2]*integral_yz;
+            data_for_parent.my2Nxxy_Nyxx = 2*Nxxy + n[1]*integral_xx;
+            data_for_parent.my2Nxxz_Nzxx = 2*Nxxz + n[2]*integral_xx;
+            data_for_parent.my2Nyyz_Nzyy = 2*Nyyz + n[2]*integral_yy;
+            data_for_parent.my2Nyyx_Nxyy = 2*Nyyx + n[0]*integral_yy;
+            data_for_parent.my2Nzzx_Nxzz = 2*Nzzx + n[0]*integral_zz;
+            data_for_parent.my2Nzzy_Nyzz = 2*Nzzy + n[1]*integral_zz;
+#if SOLID_ANGLE_DEBUG
+            UTdebugFormat("             integral_xx = {}; yy = {}; zz = {}", integral_xx, integral_yy, integral_zz);
+            UTdebugFormat("             integral_xy = {}; yz = {}; zx = {}", integral_xy, integral_yz, integral_zx);
+#endif
+#endif
+        }
+
+        void post(const int nodei, const int parent_nodei, LocalData *data_for_parent, const int nchildren, const LocalData *child_data_array) const
+        {
+            // NOTE: Although in the general case, data_for_parent may be null for the root call,
+            //       this functor assumes that it's non-null, so the call below must pass a non-null pointer.
+
+            BoxData &current_box_data = myBoxData[nodei];
+
+            UT_Vector3T<T> N = child_data_array[0].myN;
+            ((T*)&current_box_data.myN[0])[0] = N[0];
+            ((T*)&current_box_data.myN[1])[0] = N[1];
+            ((T*)&current_box_data.myN[2])[0] = N[2];
+            UT_Vector3T<T> areaP = child_data_array[0].myAreaP;
+            T area = child_data_array[0].myArea;
+            UT_Vector3T<T> local_P = child_data_array[0].myAverageP;
+            ((T*)&current_box_data.myAverageP[0])[0] = local_P[0];
+            ((T*)&current_box_data.myAverageP[1])[0] = local_P[1];
+            ((T*)&current_box_data.myAverageP[2])[0] = local_P[2];
+            for (int i = 1; i < nchildren; ++i)
+            {
+                const UT_Vector3T<T> local_N = child_data_array[i].myN;
+                N += local_N;
+                ((T*)&current_box_data.myN[0])[i] = local_N[0];
+                ((T*)&current_box_data.myN[1])[i] = local_N[1];
+                ((T*)&current_box_data.myN[2])[i] = local_N[2];
+                areaP += child_data_array[i].myAreaP;
+                area += child_data_array[i].myArea;
+                const UT_Vector3T<T> local_P = child_data_array[i].myAverageP;
+                ((T*)&current_box_data.myAverageP[0])[i] = local_P[0];
+                ((T*)&current_box_data.myAverageP[1])[i] = local_P[1];
+                ((T*)&current_box_data.myAverageP[2])[i] = local_P[2];
+            }
+            for (int i = nchildren; i < BVH_N; ++i)
+            {
+                // Set to zero, just to avoid false positives for uses of uninitialized memory.
+                ((T*)&current_box_data.myN[0])[i] = 0;
+                ((T*)&current_box_data.myN[1])[i] = 0;
+                ((T*)&current_box_data.myN[2])[i] = 0;
+                ((T*)&current_box_data.myAverageP[0])[i] = 0;
+                ((T*)&current_box_data.myAverageP[1])[i] = 0;
+                ((T*)&current_box_data.myAverageP[2])[i] = 0;
+            }
+            data_for_parent->myN = N;
+            data_for_parent->myAreaP = areaP;
+            data_for_parent->myArea = area;
+
+            UT::Box<S,3> box(child_data_array[0].myBox);
+            for (int i = 1; i < nchildren; ++i)
+                box.enlargeBounds(child_data_array[i].myBox);
+
+            // Normalize P
+            UT_Vector3T<T> averageP;
+            if (area > 0)
+                averageP = areaP/area;
+            else
+                averageP = T(0.5)*(box.getMin() + box.getMax());
+            data_for_parent->myAverageP = averageP;
+
+            data_for_parent->myBox = box;
+
+            for (int i = 0; i < nchildren; ++i)
+            {
+                const UT::Box<S,3> &local_box(child_data_array[i].myBox);
+                const UT_Vector3T<T> &local_P = child_data_array[i].myAverageP;
+                const UT_Vector3T<T> maxPDiff = SYSmax(local_P-UT_Vector3T<T>(local_box.getMin()), UT_Vector3T<T>(local_box.getMax())-local_P);
+                ((T*)&current_box_data.myMaxPDist2)[i] = maxPDiff.length2();
+            }
+            for (int i = nchildren; i < BVH_N; ++i)
+            {
+                // This child is non-existent.  If we set myMaxPDist2 to infinity, it will never
+                // use the approximation, and the traverseVector function can check for EMPTY.
+                ((T*)&current_box_data.myMaxPDist2)[i] = std::numeric_limits<T>::infinity();
+            }
+
+#if TAYLOR_SERIES_ORDER >= 1
+            const int order = myOrder;
+            if (order >= 1)
+            {
+                // We now have the current box's P, so we can adjust Nij and Nijk
+                data_for_parent->myNijDiag = child_data_array[0].myNijDiag;
+                data_for_parent->myNxy = 0;
+                data_for_parent->myNyx = 0;
+                data_for_parent->myNyz = 0;
+                data_for_parent->myNzy = 0;
+                data_for_parent->myNzx = 0;
+                data_for_parent->myNxz = 0;
+#if TAYLOR_SERIES_ORDER >= 2
+                data_for_parent->myNijkDiag = child_data_array[0].myNijkDiag;
+                data_for_parent->mySumPermuteNxyz = child_data_array[0].mySumPermuteNxyz;
+                data_for_parent->my2Nxxy_Nyxx = child_data_array[0].my2Nxxy_Nyxx;
+                data_for_parent->my2Nxxz_Nzxx = child_data_array[0].my2Nxxz_Nzxx;
+                data_for_parent->my2Nyyz_Nzyy = child_data_array[0].my2Nyyz_Nzyy;
+                data_for_parent->my2Nyyx_Nxyy = child_data_array[0].my2Nyyx_Nxyy;
+                data_for_parent->my2Nzzx_Nxzz = child_data_array[0].my2Nzzx_Nxzz;
+                data_for_parent->my2Nzzy_Nyzz = child_data_array[0].my2Nzzy_Nyzz;
+#endif
+
+                for (int i = 1; i < nchildren; ++i)
+                {
+                    data_for_parent->myNijDiag += child_data_array[i].myNijDiag;
+#if TAYLOR_SERIES_ORDER >= 2
+                    data_for_parent->myNijkDiag += child_data_array[i].myNijkDiag;
+                    data_for_parent->mySumPermuteNxyz += child_data_array[i].mySumPermuteNxyz;
+                    data_for_parent->my2Nxxy_Nyxx += child_data_array[i].my2Nxxy_Nyxx;
+                    data_for_parent->my2Nxxz_Nzxx += child_data_array[i].my2Nxxz_Nzxx;
+                    data_for_parent->my2Nyyz_Nzyy += child_data_array[i].my2Nyyz_Nzyy;
+                    data_for_parent->my2Nyyx_Nxyy += child_data_array[i].my2Nyyx_Nxyy;
+                    data_for_parent->my2Nzzx_Nxzz += child_data_array[i].my2Nzzx_Nxzz;
+                    data_for_parent->my2Nzzy_Nyzz += child_data_array[i].my2Nzzy_Nyzz;
+#endif
+                }
+                for (int j = 0; j < 3; ++j)
+                    ((T*)&current_box_data.myNijDiag[j])[0] = child_data_array[0].myNijDiag[j];
+                ((T*)&current_box_data.myNxy_Nyx)[0] = child_data_array[0].myNxy + child_data_array[0].myNyx;
+                ((T*)&current_box_data.myNyz_Nzy)[0] = child_data_array[0].myNyz + child_data_array[0].myNzy;
+                ((T*)&current_box_data.myNzx_Nxz)[0] = child_data_array[0].myNzx + child_data_array[0].myNxz;
+                for (int j = 0; j < 3; ++j)
+                    ((T*)&current_box_data.myNijkDiag[j])[0] = child_data_array[0].myNijkDiag[j];
+                ((T*)&current_box_data.mySumPermuteNxyz)[0] = child_data_array[0].mySumPermuteNxyz;
+                ((T*)&current_box_data.my2Nxxy_Nyxx)[0] = child_data_array[0].my2Nxxy_Nyxx;
+                ((T*)&current_box_data.my2Nxxz_Nzxx)[0] = child_data_array[0].my2Nxxz_Nzxx;
+                ((T*)&current_box_data.my2Nyyz_Nzyy)[0] = child_data_array[0].my2Nyyz_Nzyy;
+                ((T*)&current_box_data.my2Nyyx_Nxyy)[0] = child_data_array[0].my2Nyyx_Nxyy;
+                ((T*)&current_box_data.my2Nzzx_Nxzz)[0] = child_data_array[0].my2Nzzx_Nxzz;
+                ((T*)&current_box_data.my2Nzzy_Nyzz)[0] = child_data_array[0].my2Nzzy_Nyzz;
+                for (int i = 1; i < nchildren; ++i)
+                {
+                    for (int j = 0; j < 3; ++j)
+                        ((T*)&current_box_data.myNijDiag[j])[i] = child_data_array[i].myNijDiag[j];
+                    ((T*)&current_box_data.myNxy_Nyx)[i] = child_data_array[i].myNxy + child_data_array[i].myNyx;
+                    ((T*)&current_box_data.myNyz_Nzy)[i] = child_data_array[i].myNyz + child_data_array[i].myNzy;
+                    ((T*)&current_box_data.myNzx_Nxz)[i] = child_data_array[i].myNzx + child_data_array[i].myNxz;
+                    for (int j = 0; j < 3; ++j)
+                        ((T*)&current_box_data.myNijkDiag[j])[i] = child_data_array[i].myNijkDiag[j];
+                    ((T*)&current_box_data.mySumPermuteNxyz)[i] = child_data_array[i].mySumPermuteNxyz;
+                    ((T*)&current_box_data.my2Nxxy_Nyxx)[i] = child_data_array[i].my2Nxxy_Nyxx;
+                    ((T*)&current_box_data.my2Nxxz_Nzxx)[i] = child_data_array[i].my2Nxxz_Nzxx;
+                    ((T*)&current_box_data.my2Nyyz_Nzyy)[i] = child_data_array[i].my2Nyyz_Nzyy;
+                    ((T*)&current_box_data.my2Nyyx_Nxyy)[i] = child_data_array[i].my2Nyyx_Nxyy;
+                    ((T*)&current_box_data.my2Nzzx_Nxzz)[i] = child_data_array[i].my2Nzzx_Nxzz;
+                    ((T*)&current_box_data.my2Nzzy_Nyzz)[i] = child_data_array[i].my2Nzzy_Nyzz;
+                }
+                for (int i = nchildren; i < BVH_N; ++i)
+                {
+                    // Set to zero, just to avoid false positives for uses of uninitialized memory.
+                    for (int j = 0; j < 3; ++j)
+                        ((T*)&current_box_data.myNijDiag[j])[i] = 0;
+                    ((T*)&current_box_data.myNxy_Nyx)[i] = 0;
+                    ((T*)&current_box_data.myNyz_Nzy)[i] = 0;
+                    ((T*)&current_box_data.myNzx_Nxz)[i] = 0;
+                    for (int j = 0; j < 3; ++j)
+                        ((T*)&current_box_data.myNijkDiag[j])[i] = 0;
+                    ((T*)&current_box_data.mySumPermuteNxyz)[i] = 0;
+                    ((T*)&current_box_data.my2Nxxy_Nyxx)[i] = 0;
+                    ((T*)&current_box_data.my2Nxxz_Nzxx)[i] = 0;
+                    ((T*)&current_box_data.my2Nyyz_Nzyy)[i] = 0;
+                    ((T*)&current_box_data.my2Nyyx_Nxyy)[i] = 0;
+                    ((T*)&current_box_data.my2Nzzx_Nxzz)[i] = 0;
+                    ((T*)&current_box_data.my2Nzzy_Nyzz)[i] = 0;
+                }
+
+                for (int i = 0; i < nchildren; ++i)
+                {
+                    const LocalData &child_data = child_data_array[i];
+                    UT_Vector3T<T> displacement = child_data.myAverageP - UT_Vector3T<T>(data_for_parent->myAverageP);
+                    UT_Vector3T<T> N = child_data.myN;
+
+                    // Adjust Nij for the change in centre P
+                    data_for_parent->myNijDiag += N*displacement;
+                    T Nxy = child_data.myNxy + N[0]*displacement[1];
+                    T Nyx = child_data.myNyx + N[1]*displacement[0];
+                    T Nyz = child_data.myNyz + N[1]*displacement[2];
+                    T Nzy = child_data.myNzy + N[2]*displacement[1];
+                    T Nzx = child_data.myNzx + N[2]*displacement[0];
+                    T Nxz = child_data.myNxz + N[0]*displacement[2];
+
+                    data_for_parent->myNxy += Nxy;
+                    data_for_parent->myNyx += Nyx;
+                    data_for_parent->myNyz += Nyz;
+                    data_for_parent->myNzy += Nzy;
+                    data_for_parent->myNzx += Nzx;
+                    data_for_parent->myNxz += Nxz;
+
+#if TAYLOR_SERIES_ORDER >= 2
+                    if (order >= 2)
+                    {
+                        // Adjust Nijk for the change in centre P
+                        data_for_parent->myNijkDiag += T(2)*displacement*child_data.myNijDiag + displacement*displacement*child_data.myN;
+                        data_for_parent->mySumPermuteNxyz += (displacement[0]*(Nyz+Nzy) + displacement[1]*(Nzx+Nxz) + displacement[2]*(Nxy+Nyx));
+                        data_for_parent->my2Nxxy_Nyxx +=
+                            2*(displacement[1]*child_data.myNijDiag[0] + displacement[0]*child_data.myNxy + N[0]*displacement[0]*displacement[1])
+                            + 2*child_data.myNyx*displacement[0] + N[1]*displacement[0]*displacement[0];
+                        data_for_parent->my2Nxxz_Nzxx +=
+                            2*(displacement[2]*child_data.myNijDiag[0] + displacement[0]*child_data.myNxz + N[0]*displacement[0]*displacement[2])
+                            + 2*child_data.myNzx*displacement[0] + N[2]*displacement[0]*displacement[0];
+                        data_for_parent->my2Nyyz_Nzyy +=
+                            2*(displacement[2]*child_data.myNijDiag[1] + displacement[1]*child_data.myNyz + N[1]*displacement[1]*displacement[2])
+                            + 2*child_data.myNzy*displacement[1] + N[2]*displacement[1]*displacement[1];
+                        data_for_parent->my2Nyyx_Nxyy +=
+                            2*(displacement[0]*child_data.myNijDiag[1] + displacement[1]*child_data.myNyx + N[1]*displacement[1]*displacement[0])
+                            + 2*child_data.myNxy*displacement[1] + N[0]*displacement[1]*displacement[1];
+                        data_for_parent->my2Nzzx_Nxzz +=
+                            2*(displacement[0]*child_data.myNijDiag[2] + displacement[2]*child_data.myNzx + N[2]*displacement[2]*displacement[0])
+                            + 2*child_data.myNxz*displacement[2] + N[0]*displacement[2]*displacement[2];
+                        data_for_parent->my2Nzzy_Nyzz +=
+                            2*(displacement[1]*child_data.myNijDiag[2] + displacement[2]*child_data.myNzy + N[2]*displacement[2]*displacement[1])
+                            + 2*child_data.myNyz*displacement[2] + N[1]*displacement[2]*displacement[2];
+                    }
+#endif
+                }
+            }
+#endif
+#if SOLID_ANGLE_DEBUG
+            UTdebugFormat("");
+            UTdebugFormat("Node {}: nchildren = {}; maxP = {}", nodei, nchildren, SYSsqrt(current_box_data.myMaxPDist2));
+            UTdebugFormat("         P = {}; N = {}", current_box_data.myAverageP, current_box_data.myN);
+#if TAYLOR_SERIES_ORDER >= 1
+            UTdebugFormat("         Nii = {}", current_box_data.myNijDiag);
+            UTdebugFormat("         Nxy+Nyx = {}; Nyz+Nzy = {}; Nyz+Nzy = {}", current_box_data.myNxy_Nyx, current_box_data.myNyz_Nzy, current_box_data.myNzx_Nxz);
+#if TAYLOR_SERIES_ORDER >= 2
+            UTdebugFormat("         Niii = {}; 2(Nxyz+Nyzx+Nzxy) = {}", current_box_data.myNijkDiag, current_box_data.mySumPermuteNxyz);
+            UTdebugFormat("         2Nxxy+Nyxx = {}; 2Nxxz+Nzxx = {}", current_box_data.my2Nxxy_Nyxx, current_box_data.my2Nxxz_Nzxx);
+            UTdebugFormat("         2Nyyz+Nzyy = {}; 2Nyyx+Nxyy = {}", current_box_data.my2Nyyz_Nzyy, current_box_data.my2Nyyx_Nxyy);
+            UTdebugFormat("         2Nzzx+Nxzz = {}; 2Nzzy+Nyzz = {}", current_box_data.my2Nzzx_Nxzz, current_box_data.my2Nzzy_Nyzz);
+#endif
+#endif
+#endif
+        }
+    };
+
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+    timer.start();
+#endif
+    const PrecomputeFunctors functors(box_data, triangle_boxes.array(), triangle_points, positions, order);
+    // NOTE: post-functor relies on non-null data_for_parent, so we have to pass one.
+    LocalData local_data;
+    myTree.template traverseParallel<LocalData>(4096, functors, &local_data);
+    //myTree.template traverse<LocalData>(functors);
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+    time = timer.stop();
+    UTdebugFormat("{} s to precompute coefficients.", time);
+#endif
+}
+
+template<typename T,typename S>
+inline void UT_SolidAngle<T, S>::clear()
+{
+    myTree.clear();
+    myNBoxes = 0;
+    myOrder = 2;
+    myData.reset();
+    myNTriangles = 0;
+    myTrianglePoints = nullptr;
+    myNPoints = 0;
+    myPositions = nullptr;
+}
+
+template<typename T,typename S>
+inline T UT_SolidAngle<T, S>::computeSolidAngle(const UT_Vector3T<T> &query_point, const T accuracy_scale) const
+{
+    const T accuracy_scale2 = accuracy_scale*accuracy_scale;
+
+    struct SolidAngleFunctors
+    {
+        const BoxData *const myBoxData;
+        const UT_Vector3T<T> myQueryPoint;
+        const T myAccuracyScale2;
+        const UT_Vector3T<S> *const myPositions;
+        const int *const myTrianglePoints;
+        const int myOrder;
+
+        SolidAngleFunctors(
+            const BoxData *const box_data,
+            const UT_Vector3T<T> &query_point,
+            const T accuracy_scale2,
+            const int order,
+            const UT_Vector3T<S> *const positions,
+            const int *const triangle_points)
+            : myBoxData(box_data)
+            , myQueryPoint(query_point)
+            , myAccuracyScale2(accuracy_scale2)
+            , myOrder(order)
+            , myPositions(positions)
+            , myTrianglePoints(triangle_points)
+        {}
+        uint pre(const int nodei, T *data_for_parent) const
+        {
+            const BoxData &data = myBoxData[nodei];
+            const typename BoxData::Type maxP2 = data.myMaxPDist2;
+            UT_FixedVector<typename BoxData::Type,3> q;
+            q[0] = typename BoxData::Type(myQueryPoint[0]);
+            q[1] = typename BoxData::Type(myQueryPoint[1]);
+            q[2] = typename BoxData::Type(myQueryPoint[2]);
+            q -= data.myAverageP;
+            const typename BoxData::Type qlength2 = q[0]*q[0] + q[1]*q[1] + q[2]*q[2];
+
+            // If the query point is within a factor of accuracy_scale of the box radius,
+            // it's assumed to be not a good enough approximation, so it needs to descend.
+            // TODO: Is there a way to estimate the error?
+            static_assert((std::is_same<typename BoxData::Type,v4uf>::value), "FIXME: Implement support for other tuple types!");
+            v4uu descend_mask = (qlength2 <= maxP2*myAccuracyScale2);
+            uint descend_bitmask = _mm_movemask_ps(V4SF(descend_mask.vector));
+            constexpr uint allchildbits = ((uint(1)<<BVH_N)-1);
+            if (descend_bitmask == allchildbits)
+            {
+                *data_for_parent = 0;
+                return allchildbits;
+            }
+
+            // qlength2 must be non-zero, since it's strictly greater than something.
+            // We still need to be careful for NaNs, though, because the 4th power might cause problems.
+            const typename BoxData::Type qlength_m2 = typename BoxData::Type(1.0)/qlength2;
+            const typename BoxData::Type qlength_m1 = sqrt(qlength_m2);
+
+            // Normalize q to reduce issues with overflow/underflow, since we'd need the 7th power
+            // if we didn't normalize, and (1e-6)^-7 = 1e42, which overflows single-precision.
+            q *= qlength_m1;
+
+            typename BoxData::Type Omega_approx = -qlength_m2*dot(q,data.myN);
+#if TAYLOR_SERIES_ORDER >= 1
+            const int order = myOrder;
+            if (order >= 1)
+            {
+                const UT_FixedVector<typename BoxData::Type,3> q2 = q*q;
+                const typename BoxData::Type qlength_m3 = qlength_m2*qlength_m1;
+                const typename BoxData::Type Omega_1 =
+                    qlength_m3*(data.myNijDiag[0] + data.myNijDiag[1] + data.myNijDiag[2]
+                        -typename BoxData::Type(3.0)*(dot(q2,data.myNijDiag) +
+                            q[0]*q[1]*data.myNxy_Nyx +
+                            q[0]*q[2]*data.myNzx_Nxz +
+                            q[1]*q[2]*data.myNyz_Nzy));
+                Omega_approx += Omega_1;
+#if TAYLOR_SERIES_ORDER >= 2
+                if (order >= 2)
+                {
+                    const UT_FixedVector<typename BoxData::Type,3> q3 = q2*q;
+                    const typename BoxData::Type qlength_m4 = qlength_m2*qlength_m2;
+                    typename BoxData::Type temp0[3] = {
+                        data.my2Nyyx_Nxyy+data.my2Nzzx_Nxzz,
+                        data.my2Nzzy_Nyzz+data.my2Nxxy_Nyxx,
+                        data.my2Nxxz_Nzxx+data.my2Nyyz_Nzyy
+                    };
+                    typename BoxData::Type temp1[3] = {
+                        q[1]*data.my2Nxxy_Nyxx + q[2]*data.my2Nxxz_Nzxx,
+                        q[2]*data.my2Nyyz_Nzyy + q[0]*data.my2Nyyx_Nxyy,
+                        q[0]*data.my2Nzzx_Nxzz + q[1]*data.my2Nzzy_Nyzz
+                    };
+                    const typename BoxData::Type Omega_2 =
+                        qlength_m4*(typename BoxData::Type(1.5)*dot(q, typename BoxData::Type(3)*data.myNijkDiag + UT_FixedVector<typename BoxData::Type,3>(temp0))
+                            -typename BoxData::Type(7.5)*(dot(q3,data.myNijkDiag) + q[0]*q[1]*q[2]*data.mySumPermuteNxyz + dot(q2, UT_FixedVector<typename BoxData::Type,3>(temp1))));
+                    Omega_approx += Omega_2;
+                }
+#endif
+            }
+#endif
+
+            // If q is so small that we got NaNs and we just have a
+            // small bounding box, it needs to descend.
+            const v4uu mask = Omega_approx.isFinite() & ~descend_mask;
+            Omega_approx = Omega_approx & mask;
+            descend_bitmask = (~_mm_movemask_ps(V4SF(mask.vector))) & allchildbits;
+
+            T sum = Omega_approx[0];
+            for (int i = 1; i < BVH_N; ++i)
+                sum += Omega_approx[i];
+            *data_for_parent = sum;
+
+            return descend_bitmask;
+        }
+        void item(const int itemi, const int parent_nodei, T &data_for_parent) const
+        {
+            const UT_Vector3T<S> *const positions = myPositions;
+            const int *const cur_triangle_points = myTrianglePoints + 3*itemi;
+            const UT_Vector3T<T> a = positions[cur_triangle_points[0]];
+            const UT_Vector3T<T> b = positions[cur_triangle_points[1]];
+            const UT_Vector3T<T> c = positions[cur_triangle_points[2]];
+
+            data_for_parent = UTsignedSolidAngleTri(a, b, c, myQueryPoint);
+        }
+        SYS_FORCE_INLINE void post(const int nodei, const int parent_nodei, T *data_for_parent, const int nchildren, const T *child_data_array, const uint descend_bits) const
+        {
+            T sum = (descend_bits&1) ? child_data_array[0] : 0;
+            for (int i = 1; i < nchildren; ++i)
+                sum += ((descend_bits>>i)&1) ? child_data_array[i] : 0;
+
+            *data_for_parent += sum;
+        }
+    };
+    const SolidAngleFunctors functors(myData.get(), query_point, accuracy_scale2, myOrder, myPositions, myTrianglePoints);
+
+    T sum;
+    myTree.traverseVector(functors, &sum);
+    return sum;
+}
+
+template<typename T,typename S>
+struct UT_SubtendedAngle<T,S>::BoxData
+{
+    void clear()
+    {
+        // Set everything to zero
+        memset(this,0,sizeof(*this));
+    }
+
+    using Type  = typename std::conditional<BVH_N==4 && std::is_same<T,float>::value, v4uf, UT_FixedVector<T,BVH_N>>::type;
+    using SType = typename std::conditional<BVH_N==4 && std::is_same<S,float>::value, v4uf, UT_FixedVector<S,BVH_N>>::type;
+
+    /// An upper bound on the squared distance from myAverageP to the farthest point in the box.
+    SType myMaxPDist2;
+
+    /// Centre of mass of the mesh surface in this box
+    UT_FixedVector<Type,2> myAverageP;
+
+    /// Unnormalized, area-weighted normal of the mesh in this box
+    UT_FixedVector<Type,2> myN;
+
+    /// Values for Omega_1
+    /// @{
+    UT_FixedVector<Type,2> myNijDiag;  // Nxx, Nyy
+    Type myNxy_Nyx;               // Nxy+Nyx
+    /// @}
+
+    /// Values for Omega_2
+    /// @{
+    UT_FixedVector<Type,2> myNijkDiag; // Nxxx, Nyyy
+    Type my2Nxxy_Nyxx; // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx
+    Type my2Nyyx_Nxyy; // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy
+    /// @}
+};
+
+template<typename T,typename S>
+inline UT_SubtendedAngle<T,S>::UT_SubtendedAngle()
+    : myTree()
+    , myNBoxes(0)
+    , myOrder(2)
+    , myData(nullptr)
+    , myNSegments(0)
+    , mySegmentPoints(nullptr)
+    , myNPoints(0)
+    , myPositions(nullptr)
+{}
+
+template<typename T,typename S>
+inline UT_SubtendedAngle<T,S>::~UT_SubtendedAngle()
+{
+    // Default destruction works, but this needs to be outlined
+    // to avoid having to include UT_BVHImpl.h in the header,
+    // (for the UT_UniquePtr destructor.)
+}
+
+template<typename T,typename S>
+inline void UT_SubtendedAngle<T,S>::init(
+    const int nsegments,
+    const int *const segment_points,
+    const int npoints,
+    const UT_Vector2T<S> *const positions,
+    const int order)
+{
+#if SOLID_ANGLE_DEBUG
+    UTdebugFormat("");
+    UTdebugFormat("");
+    UTdebugFormat("Building BVH for {} segments on {} points:", nsegments, npoints);
+#endif
+    myOrder = order;
+    myNSegments = nsegments;
+    mySegmentPoints = segment_points;
+    myNPoints = npoints;
+    myPositions = positions;
+
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+    UT_StopWatch timer;
+    timer.start();
+#endif
+    UT_SmallArray<UT::Box<S,2>> segment_boxes;
+    segment_boxes.setSizeNoInit(nsegments);
+    if (nsegments < 16*1024)
+    {
+        const int *cur_segment_points = segment_points;
+        for (int i = 0; i < nsegments; ++i, cur_segment_points += 2)
+        {
+            UT::Box<S,2> &box = segment_boxes[i];
+            box.initBounds(positions[cur_segment_points[0]]);
+            box.enlargeBounds(positions[cur_segment_points[1]]);
+        }
+    }
+    else
+    {
+      igl::parallel_for(nsegments,
+        [segment_points,&segment_boxes,positions](int i)
+        {
+          const int *cur_segment_points = segment_points + i*2;
+          UT::Box<S,2> &box = segment_boxes[i];
+          box.initBounds(positions[cur_segment_points[0]]);
+          box.enlargeBounds(positions[cur_segment_points[1]]);
+        });
+    }
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+    double time = timer.stop();
+    UTdebugFormat("{} s to create bounding boxes.", time);
+    timer.start();
+#endif
+    myTree.template init<UT::BVH_Heuristic::BOX_AREA,S,2>(segment_boxes.array(), nsegments);
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+    time = timer.stop();
+    UTdebugFormat("{} s to initialize UT_BVH structure.  {} nodes", time, myTree.getNumNodes());
+#endif
+
+    //myTree.debugDump();
+
+    const int nnodes = myTree.getNumNodes();
+
+    myNBoxes = nnodes;
+    BoxData *box_data = new BoxData[nnodes];
+    myData.reset(box_data);
+
+    // Some data are only needed during initialization.
+    struct LocalData
+    {
+        // Bounding box
+        UT::Box<S,2> myBox;
+
+        // P and N are needed from each child for computing Nij.
+        UT_Vector2T<T> myAverageP;
+        UT_Vector2T<T> myLengthP;
+        UT_Vector2T<T> myN;
+
+        // Unsigned length is needed for computing the average position.
+        T myLength;
+
+        // These are needed for computing Nijk.
+        UT_Vector2T<T> myNijDiag;
+        T myNxy; T myNyx;
+
+        UT_Vector2T<T> myNijkDiag; // Nxxx, Nyyy
+        T my2Nxxy_Nyxx;     // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx
+        T my2Nyyx_Nxyy;     // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy
+    };
+
+    struct PrecomputeFunctors
+    {
+        BoxData *const myBoxData;
+        const UT::Box<S,2> *const mySegmentBoxes;
+        const int *const mySegmentPoints;
+        const UT_Vector2T<S> *const myPositions;
+        const int myOrder;
+
+        PrecomputeFunctors(
+            BoxData *box_data,
+            const UT::Box<S,2> *segment_boxes,
+            const int *segment_points,
+            const UT_Vector2T<S> *positions,
+            const int order)
+            : myBoxData(box_data)
+            , mySegmentBoxes(segment_boxes)
+            , mySegmentPoints(segment_points)
+            , myPositions(positions)
+            , myOrder(order)
+        {}
+        constexpr SYS_FORCE_INLINE bool pre(const int nodei, LocalData *data_for_parent) const
+        {
+            return true;
+        }
+        void item(const int itemi, const int parent_nodei, LocalData &data_for_parent) const
+        {
+            const UT_Vector2T<S> *const positions = myPositions;
+            const int *const cur_segment_points = mySegmentPoints + 2*itemi;
+            const UT_Vector2T<T> a = positions[cur_segment_points[0]];
+            const UT_Vector2T<T> b = positions[cur_segment_points[1]];
+            const UT_Vector2T<T> ab = b-a;
+
+            const UT::Box<S,2> &segment_box = mySegmentBoxes[itemi];
+            data_for_parent.myBox = segment_box;
+
+            // Length-weighted normal (unnormalized)
+            UT_Vector2T<T> N;
+            N[0] = ab[1];
+            N[1] = -ab[0];
+            const T length2 = ab.length2();
+            const T length = SYSsqrt(length2);
+            const UT_Vector2T<T> P = T(0.5)*(a+b);
+            data_for_parent.myAverageP = P;
+            data_for_parent.myLengthP = P*length;
+            data_for_parent.myN = N;
+#if SOLID_ANGLE_DEBUG
+            UTdebugFormat("");
+            UTdebugFormat("Triangle {}: P = {}; N = {}; length = {}", itemi, P, N, length);
+            UTdebugFormat("             box = {}", data_for_parent.myBox);
+#endif
+
+            data_for_parent.myLength = length;
+            const int order = myOrder;
+            if (order < 1)
+                return;
+
+            // NOTE: Due to P being at the centroid, segments have Nij = 0
+            //       contributions to Nij.
+            data_for_parent.myNijDiag = T(0);
+            data_for_parent.myNxy = 0; data_for_parent.myNyx = 0;
+
+            if (order < 2)
+                return;
+
+            // If it's zero-length, the results are zero, so we can skip.
+            if (length == 0)
+            {
+                data_for_parent.myNijkDiag = T(0);
+                data_for_parent.my2Nxxy_Nyxx = 0;
+                data_for_parent.my2Nyyx_Nxyy = 0;
+                return;
+            }
+
+            T integral_xx = ab[0]*ab[0]/T(12);
+            T integral_xy = ab[0]*ab[1]/T(12);
+            T integral_yy = ab[1]*ab[1]/T(12);
+            data_for_parent.myNijkDiag[0] = integral_xx*N[0];
+            data_for_parent.myNijkDiag[1] = integral_yy*N[1];
+            T Nxxy = N[0]*integral_xy;
+            T Nyxx = N[1]*integral_xx;
+            T Nyyx = N[1]*integral_xy;
+            T Nxyy = N[0]*integral_yy;
+            data_for_parent.my2Nxxy_Nyxx = 2*Nxxy + Nyxx;
+            data_for_parent.my2Nyyx_Nxyy = 2*Nyyx + Nxyy;
+#if SOLID_ANGLE_DEBUG
+            UTdebugFormat("             integral_xx = {}; yy = {}", integral_xx, integral_yy);
+            UTdebugFormat("             integral_xy = {}", integral_xy);
+#endif
+        }
+
+        void post(const int nodei, const int parent_nodei, LocalData *data_for_parent, const int nchildren, const LocalData *child_data_array) const
+        {
+            // NOTE: Although in the general case, data_for_parent may be null for the root call,
+            //       this functor assumes that it's non-null, so the call below must pass a non-null pointer.
+
+            BoxData &current_box_data = myBoxData[nodei];
+
+            UT_Vector2T<T> N = child_data_array[0].myN;
+            ((T*)&current_box_data.myN[0])[0] = N[0];
+            ((T*)&current_box_data.myN[1])[0] = N[1];
+            UT_Vector2T<T> lengthP = child_data_array[0].myLengthP;
+            T length = child_data_array[0].myLength;
+            const UT_Vector2T<T> local_P = child_data_array[0].myAverageP;
+            ((T*)&current_box_data.myAverageP[0])[0] = local_P[0];
+            ((T*)&current_box_data.myAverageP[1])[0] = local_P[1];
+            for (int i = 1; i < nchildren; ++i)
+            {
+                const UT_Vector2T<T> local_N = child_data_array[i].myN;
+                N += local_N;
+                ((T*)&current_box_data.myN[0])[i] = local_N[0];
+                ((T*)&current_box_data.myN[1])[i] = local_N[1];
+                lengthP += child_data_array[i].myLengthP;
+                length += child_data_array[i].myLength;
+                const UT_Vector2T<T> local_P = child_data_array[i].myAverageP;
+                ((T*)&current_box_data.myAverageP[0])[i] = local_P[0];
+                ((T*)&current_box_data.myAverageP[1])[i] = local_P[1];
+            }
+            for (int i = nchildren; i < BVH_N; ++i)
+            {
+                // Set to zero, just to avoid false positives for uses of uninitialized memory.
+                ((T*)&current_box_data.myN[0])[i] = 0;
+                ((T*)&current_box_data.myN[1])[i] = 0;
+                ((T*)&current_box_data.myAverageP[0])[i] = 0;
+                ((T*)&current_box_data.myAverageP[1])[i] = 0;
+            }
+            data_for_parent->myN = N;
+            data_for_parent->myLengthP = lengthP;
+            data_for_parent->myLength = length;
+
+            UT::Box<S,2> box(child_data_array[0].myBox);
+            for (int i = 1; i < nchildren; ++i)
+                box.combine(child_data_array[i].myBox);
+
+            // Normalize P
+            UT_Vector2T<T> averageP;
+            if (length > 0)
+                averageP = lengthP/length;
+            else
+                averageP = T(0.5)*(box.getMin() + box.getMax());
+            data_for_parent->myAverageP = averageP;
+
+            data_for_parent->myBox = box;
+
+            for (int i = 0; i < nchildren; ++i)
+            {
+                const UT::Box<S,2> &local_box(child_data_array[i].myBox);
+                const UT_Vector2T<T> &local_P = child_data_array[i].myAverageP;
+                const UT_Vector2T<T> maxPDiff = SYSmax(local_P-UT_Vector2T<T>(local_box.getMin()), UT_Vector2T<T>(local_box.getMax())-local_P);
+                ((T*)&current_box_data.myMaxPDist2)[i] = maxPDiff.length2();
+            }
+            for (int i = nchildren; i < BVH_N; ++i)
+            {
+                // This child is non-existent.  If we set myMaxPDist2 to infinity, it will never
+                // use the approximation, and the traverseVector function can check for EMPTY.
+                ((T*)&current_box_data.myMaxPDist2)[i] = std::numeric_limits<T>::infinity();
+            }
+
+            const int order = myOrder;
+            if (order >= 1)
+            {
+                // We now have the current box's P, so we can adjust Nij and Nijk
+                data_for_parent->myNijDiag = child_data_array[0].myNijDiag;
+                data_for_parent->myNxy = 0;
+                data_for_parent->myNyx = 0;
+                data_for_parent->myNijkDiag = child_data_array[0].myNijkDiag;
+                data_for_parent->my2Nxxy_Nyxx = child_data_array[0].my2Nxxy_Nyxx;
+                data_for_parent->my2Nyyx_Nxyy = child_data_array[0].my2Nyyx_Nxyy;
+
+                for (int i = 1; i < nchildren; ++i)
+                {
+                    data_for_parent->myNijDiag += child_data_array[i].myNijDiag;
+                    data_for_parent->myNijkDiag += child_data_array[i].myNijkDiag;
+                    data_for_parent->my2Nxxy_Nyxx += child_data_array[i].my2Nxxy_Nyxx;
+                    data_for_parent->my2Nyyx_Nxyy += child_data_array[i].my2Nyyx_Nxyy;
+                }
+                for (int j = 0; j < 2; ++j)
+                    ((T*)&current_box_data.myNijDiag[j])[0] = child_data_array[0].myNijDiag[j];
+                ((T*)&current_box_data.myNxy_Nyx)[0] = child_data_array[0].myNxy + child_data_array[0].myNyx;
+                for (int j = 0; j < 2; ++j)
+                    ((T*)&current_box_data.myNijkDiag[j])[0] = child_data_array[0].myNijkDiag[j];
+                ((T*)&current_box_data.my2Nxxy_Nyxx)[0] = child_data_array[0].my2Nxxy_Nyxx;
+                ((T*)&current_box_data.my2Nyyx_Nxyy)[0] = child_data_array[0].my2Nyyx_Nxyy;
+                for (int i = 1; i < nchildren; ++i)
+                {
+                    for (int j = 0; j < 2; ++j)
+                        ((T*)&current_box_data.myNijDiag[j])[i] = child_data_array[i].myNijDiag[j];
+                    ((T*)&current_box_data.myNxy_Nyx)[i] = child_data_array[i].myNxy + child_data_array[i].myNyx;
+                    for (int j = 0; j < 2; ++j)
+                        ((T*)&current_box_data.myNijkDiag[j])[i] = child_data_array[i].myNijkDiag[j];
+                    ((T*)&current_box_data.my2Nxxy_Nyxx)[i] = child_data_array[i].my2Nxxy_Nyxx;
+                    ((T*)&current_box_data.my2Nyyx_Nxyy)[i] = child_data_array[i].my2Nyyx_Nxyy;
+                }
+                for (int i = nchildren; i < BVH_N; ++i)
+                {
+                    // Set to zero, just to avoid false positives for uses of uninitialized memory.
+                    for (int j = 0; j < 2; ++j)
+                        ((T*)&current_box_data.myNijDiag[j])[i] = 0;
+                    ((T*)&current_box_data.myNxy_Nyx)[i] = 0;
+                    for (int j = 0; j < 2; ++j)
+                        ((T*)&current_box_data.myNijkDiag[j])[i] = 0;
+                    ((T*)&current_box_data.my2Nxxy_Nyxx)[i] = 0;
+                    ((T*)&current_box_data.my2Nyyx_Nxyy)[i] = 0;
+                }
+
+                for (int i = 0; i < nchildren; ++i)
+                {
+                    const LocalData &child_data = child_data_array[i];
+                    UT_Vector2T<T> displacement = child_data.myAverageP - UT_Vector2T<T>(data_for_parent->myAverageP);
+                    UT_Vector2T<T> N = child_data.myN;
+
+                    // Adjust Nij for the change in centre P
+                    data_for_parent->myNijDiag += N*displacement;
+                    T Nxy = child_data.myNxy + N[0]*displacement[1];
+                    T Nyx = child_data.myNyx + N[1]*displacement[0];
+
+                    data_for_parent->myNxy += Nxy;
+                    data_for_parent->myNyx += Nyx;
+
+                    if (order >= 2)
+                    {
+                        // Adjust Nijk for the change in centre P
+                        data_for_parent->myNijkDiag += T(2)*displacement*child_data.myNijDiag + displacement*displacement*child_data.myN;
+                        data_for_parent->my2Nxxy_Nyxx +=
+                            2*(displacement[1]*child_data.myNijDiag[0] + displacement[0]*child_data.myNxy + N[0]*displacement[0]*displacement[1])
+                            + 2*child_data.myNyx*displacement[0] + N[1]*displacement[0]*displacement[0];
+                        data_for_parent->my2Nyyx_Nxyy +=
+                            2*(displacement[0]*child_data.myNijDiag[1] + displacement[1]*child_data.myNyx + N[1]*displacement[1]*displacement[0])
+                            + 2*child_data.myNxy*displacement[1] + N[0]*displacement[1]*displacement[1];
+                    }
+                }
+            }
+#if SOLID_ANGLE_DEBUG
+            UTdebugFormat("");
+            UTdebugFormat("Node {}: nchildren = {}; maxP = {}", nodei, nchildren, SYSsqrt(current_box_data.myMaxPDist2));
+            UTdebugFormat("         P = {}; N = {}", current_box_data.myAverageP, current_box_data.myN);
+            UTdebugFormat("         Nii = {}", current_box_data.myNijDiag);
+            UTdebugFormat("         Nxy+Nyx = {}", current_box_data.myNxy_Nyx);
+            UTdebugFormat("         Niii = {}", current_box_data.myNijkDiag);
+            UTdebugFormat("         2Nxxy+Nyxx = {}; 2Nyyx+Nxyy = {}", current_box_data.my2Nxxy_Nyxx, current_box_data.my2Nyyx_Nxyy);
+#endif
+        }
+    };
+
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+    timer.start();
+#endif
+    const PrecomputeFunctors functors(box_data, segment_boxes.array(), segment_points, positions, order);
+    // NOTE: post-functor relies on non-null data_for_parent, so we have to pass one.
+    LocalData local_data;
+    myTree.template traverseParallel<LocalData>(4096, functors, &local_data);
+    //myTree.template traverse<LocalData>(functors);
+#if SOLID_ANGLE_TIME_PRECOMPUTE
+    time = timer.stop();
+    UTdebugFormat("{} s to precompute coefficients.", time);
+#endif
+}
+
+template<typename T,typename S>
+inline void UT_SubtendedAngle<T, S>::clear()
+{
+    myTree.clear();
+    myNBoxes = 0;
+    myOrder = 2;
+    myData.reset();
+    myNSegments = 0;
+    mySegmentPoints = nullptr;
+    myNPoints = 0;
+    myPositions = nullptr;
+}
+
+template<typename T,typename S>
+inline T UT_SubtendedAngle<T, S>::computeAngle(const UT_Vector2T<T> &query_point, const T accuracy_scale) const
+{
+    const T accuracy_scale2 = accuracy_scale*accuracy_scale;
+
+    struct AngleFunctors
+    {
+        const BoxData *const myBoxData;
+        const UT_Vector2T<T> myQueryPoint;
+        const T myAccuracyScale2;
+        const UT_Vector2T<S> *const myPositions;
+        const int *const mySegmentPoints;
+        const int myOrder;
+
+        AngleFunctors(
+            const BoxData *const box_data,
+            const UT_Vector2T<T> &query_point,
+            const T accuracy_scale2,
+            const int order,
+            const UT_Vector2T<S> *const positions,
+            const int *const segment_points)
+            : myBoxData(box_data)
+            , myQueryPoint(query_point)
+            , myAccuracyScale2(accuracy_scale2)
+            , myOrder(order)
+            , myPositions(positions)
+            , mySegmentPoints(segment_points)
+        {}
+        uint pre(const int nodei, T *data_for_parent) const
+        {
+            const BoxData &data = myBoxData[nodei];
+            const typename BoxData::Type maxP2 = data.myMaxPDist2;
+            UT_FixedVector<typename BoxData::Type,2> q;
+            q[0] = typename BoxData::Type(myQueryPoint[0]);
+            q[1] = typename BoxData::Type(myQueryPoint[1]);
+            q -= data.myAverageP;
+            const typename BoxData::Type qlength2 = q[0]*q[0] + q[1]*q[1];
+
+            // If the query point is within a factor of accuracy_scale of the box radius,
+            // it's assumed to be not a good enough approximation, so it needs to descend.
+            // TODO: Is there a way to estimate the error?
+            static_assert((std::is_same<typename BoxData::Type,v4uf>::value), "FIXME: Implement support for other tuple types!");
+            v4uu descend_mask = (qlength2 <= maxP2*myAccuracyScale2);
+            uint descend_bitmask = _mm_movemask_ps(V4SF(descend_mask.vector));
+            constexpr uint allchildbits = ((uint(1)<<BVH_N)-1);
+            if (descend_bitmask == allchildbits)
+            {
+                *data_for_parent = 0;
+                return allchildbits;
+            }
+
+            // qlength2 must be non-zero, since it's strictly greater than something.
+            // We still need to be careful for NaNs, though, because the 4th power might cause problems.
+            const typename BoxData::Type qlength_m2 = typename BoxData::Type(1.0)/qlength2;
+            const typename BoxData::Type qlength_m1 = sqrt(qlength_m2);
+
+            // Normalize q to reduce issues with overflow/underflow, since we'd need the 6th power
+            // if we didn't normalize, and (1e-7)^-6 = 1e42, which overflows single-precision.
+            q *= qlength_m1;
+
+            typename BoxData::Type Omega_approx = -qlength_m1*dot(q,data.myN);
+            const int order = myOrder;
+            if (order >= 1)
+            {
+                const UT_FixedVector<typename BoxData::Type,2> q2 = q*q;
+                const typename BoxData::Type Omega_1 =
+                    qlength_m2*(data.myNijDiag[0] + data.myNijDiag[1]
+                        -typename BoxData::Type(2.0)*(dot(q2,data.myNijDiag) +
+                            q[0]*q[1]*data.myNxy_Nyx));
+                Omega_approx += Omega_1;
+                if (order >= 2)
+                {
+                    const UT_FixedVector<typename BoxData::Type,2> q3 = q2*q;
+                    const typename BoxData::Type qlength_m3 = qlength_m2*qlength_m1;
+                    typename BoxData::Type temp0[2] = {
+                        data.my2Nyyx_Nxyy,
+                        data.my2Nxxy_Nyxx
+                    };
+                    typename BoxData::Type temp1[2] = {
+                        q[1]*data.my2Nxxy_Nyxx,
+                        q[0]*data.my2Nyyx_Nxyy
+                    };
+                    const typename BoxData::Type Omega_2 =
+                        qlength_m3*(dot(q, typename BoxData::Type(3)*data.myNijkDiag + UT_FixedVector<typename BoxData::Type,2>(temp0))
+                            -typename BoxData::Type(4.0)*(dot(q3,data.myNijkDiag) + dot(q2, UT_FixedVector<typename BoxData::Type,2>(temp1))));
+                    Omega_approx += Omega_2;
+                }
+            }
+
+            // If q is so small that we got NaNs and we just have a
+            // small bounding box, it needs to descend.
+            const v4uu mask = Omega_approx.isFinite() & ~descend_mask;
+            Omega_approx = Omega_approx & mask;
+            descend_bitmask = (~_mm_movemask_ps(V4SF(mask.vector))) & allchildbits;
+
+            T sum = Omega_approx[0];
+            for (int i = 1; i < BVH_N; ++i)
+                sum += Omega_approx[i];
+            *data_for_parent = sum;
+
+            return descend_bitmask;
+        }
+        void item(const int itemi, const int parent_nodei, T &data_for_parent) const
+        {
+            const UT_Vector2T<S> *const positions = myPositions;
+            const int *const cur_segment_points = mySegmentPoints + 2*itemi;
+            const UT_Vector2T<T> a = positions[cur_segment_points[0]];
+            const UT_Vector2T<T> b = positions[cur_segment_points[1]];
+
+            data_for_parent = UTsignedAngleSegment(a, b, myQueryPoint);
+        }
+        SYS_FORCE_INLINE void post(const int nodei, const int parent_nodei, T *data_for_parent, const int nchildren, const T *child_data_array, const uint descend_bits) const
+        {
+            T sum = (descend_bits&1) ? child_data_array[0] : 0;
+            for (int i = 1; i < nchildren; ++i)
+                sum += ((descend_bits>>i)&1) ? child_data_array[i] : 0;
+
+            *data_for_parent += sum;
+        }
+    };
+    const AngleFunctors functors(myData.get(), query_point, accuracy_scale2, myOrder, myPositions, mySegmentPoints);
+
+    T sum;
+    myTree.traverseVector(functors, &sum);
+    return sum;
+}
+
+// Instantiate our templates.
+//template class UT_SolidAngle<fpreal32,fpreal32>;
+// FIXME: The SIMD parts will need to be handled differently in order to support fpreal64.
+//template class UT_SolidAngle<fpreal64,fpreal32>;
+//template class UT_SolidAngle<fpreal64,fpreal64>;
+//template class UT_SubtendedAngle<fpreal32,fpreal32>;
+//template class UT_SubtendedAngle<fpreal64,fpreal32>;
+//template class UT_SubtendedAngle<fpreal64,fpreal64>;
+
+} // End HDK_Sample namespace
+}}

+ 10 - 6
include/igl/HalfEdgeIterator.cpp

@@ -10,9 +10,9 @@
 
 template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
 IGL_INLINE igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::HalfEdgeIterator(
-    const Eigen::PlainObjectBase<DerivedF>& _F,
-    const Eigen::PlainObjectBase<DerivedFF>& _FF,
-    const Eigen::PlainObjectBase<DerivedFFi>& _FFi,
+    const Eigen::MatrixBase<DerivedF>& _F,
+    const Eigen::MatrixBase<DerivedFF>& _FF,
+    const Eigen::MatrixBase<DerivedFFi>& _FFi,
     int _fi,
     int _ei,
     bool _reverse
@@ -138,8 +138,8 @@ IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::operator==
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template      igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>  ,Eigen::Matrix<int, -1, 3, 0, -1, 3>  ,Eigen::Matrix<int, -1, 3, 0, -1, 3>   >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -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> > const&, int, int, bool);
-template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
+template      igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>  ,Eigen::Matrix<int, -1, 3, 0, -1, 3>  ,Eigen::Matrix<int, -1, 3, 0, -1, 3>   >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, int, int, bool);
+template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
 template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
 template int  igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Ei();
 template int  igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>  ,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Ei();
@@ -147,12 +147,16 @@ template int  igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>  ,Eigen:
 template int  igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>  ,Eigen::Matrix<int, -1, 3, 0, -1, 3>  ,Eigen::Matrix<int, -1, 3, 0, -1, 3>   >::Fi();
 template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>  ,Eigen::Matrix<int, -1, 3, 0, -1, 3>  ,Eigen::Matrix<int, -1, 3, 0, -1, 3>   >::NextFE();
 template int  igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Vi();
-template      igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
+template      igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
 template int  igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
 template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipE();
+template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::flipE();
 template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipF();
+template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::flipF();
 template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipV();
 template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::operator==(igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
 template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
+template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::isBorder();
+template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::isBorder();
 #endif

+ 6 - 6
include/igl/HalfEdgeIterator.h

@@ -49,9 +49,9 @@ namespace igl
   public:
     // Init the HalfEdgeIterator by specifying Face,Edge Index and Orientation
     IGL_INLINE HalfEdgeIterator(
-        const Eigen::PlainObjectBase<DerivedF>& _F,
-        const Eigen::PlainObjectBase<DerivedFF>& _FF,
-        const Eigen::PlainObjectBase<DerivedFFi>& _FFi,
+        const Eigen::MatrixBase<DerivedF>& _F,
+        const Eigen::MatrixBase<DerivedFF>& _FF,
+        const Eigen::MatrixBase<DerivedFFi>& _FFi,
         int _fi,
         int _ei,
         bool _reverse = false
@@ -100,9 +100,9 @@ namespace igl
     bool reverse;
 
     // All the same type? This is likely to break.
-    const Eigen::PlainObjectBase<DerivedF> & F;
-    const Eigen::PlainObjectBase<DerivedFF> & FF;
-    const Eigen::PlainObjectBase<DerivedFFi> & FFi;
+    const Eigen::MatrixBase<DerivedF> & F;
+    const Eigen::MatrixBase<DerivedFF> & FF;
+    const Eigen::MatrixBase<DerivedFFi> & FFi;
   };
 
 }

+ 7 - 6
include/igl/MappingEnergyType.h

@@ -15,12 +15,13 @@ namespace igl
   
   enum MappingEnergyType
   {
-    ARAP,
-    LOG_ARAP,
-    SYMMETRIC_DIRICHLET,
-    CONFORMAL,
-    EXP_CONFORMAL,
-    EXP_SYMMETRIC_DIRICHLET
+    ARAP = 0,
+    LOG_ARAP = 1,
+    SYMMETRIC_DIRICHLET = 2,
+    CONFORMAL = 3,
+    EXP_CONFORMAL = 4,
+    EXP_SYMMETRIC_DIRICHLET = 5,
+    NUM_SLIM_ENERGY_TYPES = 6
   };
 }
 #endif

+ 1 - 1
include/igl/active_set.cpp

@@ -223,7 +223,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
     }
     //cout<<matlab_format((known_i.array()+1).eval(),"known_i")<<endl;
     // PREPARE EQUALITY CONSTRAINTS
-    VectorXi as_ieq_list(as_ieq_count,1);
+    Eigen::Matrix<typename DerivedY::Scalar, Eigen::Dynamic, 1> as_ieq_list(as_ieq_count,1);
     // Gather active constraints and resp. rhss
     DerivedBeq Beq_i;
     Beq_i.resize(Beq.rows()+as_ieq_count,1);

+ 14 - 14
include/igl/ambient_occlusion.cpp

@@ -25,8 +25,8 @@ IGL_INLINE void igl::ambient_occlusion(
       const Eigen::Vector3f&,
       const Eigen::Vector3f&)
       > & shoot_ray,
-  const Eigen::PlainObjectBase<DerivedP> & P,
-  const Eigen::PlainObjectBase<DerivedN> & N,
+  const Eigen::MatrixBase<DerivedP> & P,
+  const Eigen::MatrixBase<DerivedN> & N,
   const int num_samples,
   Eigen::PlainObjectBase<DerivedS> & S)
 {
@@ -69,10 +69,10 @@ template <
   typename DerivedS >
 IGL_INLINE void igl::ambient_occlusion(
   const igl::AABB<DerivedV,DIM> & aabb,
-  const Eigen::PlainObjectBase<DerivedV> & V,
-  const Eigen::PlainObjectBase<DerivedF> & F,
-  const Eigen::PlainObjectBase<DerivedP> & P,
-  const Eigen::PlainObjectBase<DerivedN> & N,
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
+  const Eigen::MatrixBase<DerivedP> & P,
+  const Eigen::MatrixBase<DerivedN> & N,
   const int num_samples,
   Eigen::PlainObjectBase<DerivedS> & S)
 {
@@ -100,10 +100,10 @@ template <
   typename DerivedN,
   typename DerivedS >
 IGL_INLINE void igl::ambient_occlusion(
-  const Eigen::PlainObjectBase<DerivedV> & V,
-  const Eigen::PlainObjectBase<DerivedF> & F,
-  const Eigen::PlainObjectBase<DerivedP> & P,
-  const Eigen::PlainObjectBase<DerivedN> & N,
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
+  const Eigen::MatrixBase<DerivedP> & P,
+  const Eigen::MatrixBase<DerivedN> & N,
   const int num_samples,
   Eigen::PlainObjectBase<DerivedS> & S)
 {
@@ -128,10 +128,10 @@ IGL_INLINE void igl::ambient_occlusion(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
-template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 // generated by autoexplicit.sh
-template void igl::ambient_occlusion<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::ambient_occlusion<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 // generated by autoexplicit.sh
-template void igl::ambient_occlusion<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
-template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::ambient_occlusion<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 10 - 10
include/igl/ambient_occlusion.h

@@ -34,8 +34,8 @@ namespace igl
         const Eigen::Vector3f&,
         const Eigen::Vector3f&)
         > & shoot_ray,
-    const Eigen::PlainObjectBase<DerivedP> & P,
-    const Eigen::PlainObjectBase<DerivedN> & N,
+    const Eigen::MatrixBase<DerivedP> & P,
+    const Eigen::MatrixBase<DerivedN> & N,
     const int num_samples,
     Eigen::PlainObjectBase<DerivedS> & S);
   // Inputs:
@@ -49,10 +49,10 @@ namespace igl
     typename DerivedS >
   IGL_INLINE void ambient_occlusion(
     const igl::AABB<DerivedV,DIM> & aabb,
-    const Eigen::PlainObjectBase<DerivedV> & V,
-    const Eigen::PlainObjectBase<DerivedF> & F,
-    const Eigen::PlainObjectBase<DerivedP> & P,
-    const Eigen::PlainObjectBase<DerivedN> & N,
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedP> & P,
+    const Eigen::MatrixBase<DerivedN> & N,
     const int num_samples,
     Eigen::PlainObjectBase<DerivedS> & S);
   // Inputs:
@@ -65,10 +65,10 @@ namespace igl
     typename DerivedN,
     typename DerivedS >
   IGL_INLINE void ambient_occlusion(
-    const Eigen::PlainObjectBase<DerivedV> & V,
-    const Eigen::PlainObjectBase<DerivedF> & F,
-    const Eigen::PlainObjectBase<DerivedP> & P,
-    const Eigen::PlainObjectBase<DerivedN> & N,
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedP> & P,
+    const Eigen::MatrixBase<DerivedN> & N,
     const int num_samples,
     Eigen::PlainObjectBase<DerivedS> & S);
 

+ 15 - 9
include/igl/arap_linear_block.cpp

@@ -10,13 +10,13 @@
 #include "cotmatrix_entries.h"
 #include <Eigen/Dense>
 
-template <typename MatV, typename MatF, typename Scalar>
+template <typename MatV, typename MatF, typename MatK>
 IGL_INLINE void igl::arap_linear_block(
   const MatV & V,
   const MatF & F,
   const int d,
   const igl::ARAPEnergyType energy,
-  Eigen::SparseMatrix<Scalar> & Kd)
+  MatK & Kd)
 {
   switch(energy)
   {
@@ -36,13 +36,15 @@ IGL_INLINE void igl::arap_linear_block(
 }
 
 
-template <typename MatV, typename MatF, typename Scalar>
+template <typename MatV, typename MatF, typename MatK>
 IGL_INLINE void igl::arap_linear_block_spokes(
   const MatV & V,
   const MatF & F,
   const int d,
-  Eigen::SparseMatrix<Scalar> & Kd)
+  MatK & Kd)
 {
+  typedef typename MatK::Scalar Scalar;
+
   using namespace std;
   using namespace Eigen;
   // simplex size (3: triangles, 4: tetrahedra)
@@ -101,13 +103,15 @@ IGL_INLINE void igl::arap_linear_block_spokes(
   Kd.makeCompressed();
 }
 
-template <typename MatV, typename MatF, typename Scalar>
+template <typename MatV, typename MatF, typename MatK>
 IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
   const MatV & V,
   const MatF & F,
   const int d,
-  Eigen::SparseMatrix<Scalar> & Kd)
+  MatK & Kd)
 {
+  typedef typename MatK::Scalar Scalar;
+
   using namespace std;
   using namespace Eigen;
   // simplex size (3: triangles, 4: tetrahedra)
@@ -183,13 +187,14 @@ IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
   Kd.makeCompressed();
 }
 
-template <typename MatV, typename MatF, typename Scalar>
+template <typename MatV, typename MatF, typename MatK>
 IGL_INLINE void igl::arap_linear_block_elements(
   const MatV & V,
   const MatF & F,
   const int d,
-  Eigen::SparseMatrix<Scalar> & Kd)
+  MatK & Kd)
 {
+  typedef typename MatK::Scalar Scalar;
   using namespace std;
   using namespace Eigen;
   // simplex size (3: triangles, 4: tetrahedra)
@@ -249,5 +254,6 @@ IGL_INLINE void igl::arap_linear_block_elements(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template IGL_INLINE void igl::arap_linear_block<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> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::arap_linear_block<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::SparseMatrix<double, 0, int> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::arap_linear_block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::SparseMatrix<double, 0, int> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
 #endif

+ 8 - 8
include/igl/arap_linear_block.h

@@ -43,32 +43,32 @@ namespace igl
   //   Kd  #V by #V/#F block of the linear constructor matrix corresponding to
   //     coordinate d
   //
-  template <typename MatV, typename MatF, typename Scalar>
+  template <typename MatV, typename MatF, typename MatK>
   IGL_INLINE void arap_linear_block(
     const MatV & V,
     const MatF & F,
     const int d,
     const igl::ARAPEnergyType energy,
-    Eigen::SparseMatrix<Scalar> & Kd);
+    MatK & Kd);
   // Helper functions for each energy type
-  template <typename MatV, typename MatF, typename Scalar>
+  template <typename MatV, typename MatF, typename MatK>
   IGL_INLINE void arap_linear_block_spokes(
     const MatV & V,
     const MatF & F,
     const int d,
-    Eigen::SparseMatrix<Scalar> & Kd);
-  template <typename MatV, typename MatF, typename Scalar>
+    MatK & Kd);
+  template <typename MatV, typename MatF, typename MatK>
   IGL_INLINE void arap_linear_block_spokes_and_rims(
     const MatV & V,
     const MatF & F,
     const int d,
-    Eigen::SparseMatrix<Scalar> & Kd);
-  template <typename MatV, typename MatF, typename Scalar>
+    MatK & Kd);
+  template <typename MatV, typename MatF, typename MatK>
   IGL_INLINE void arap_linear_block_elements(
     const MatV & V,
     const MatF & F,
     const int d,
-    Eigen::SparseMatrix<Scalar> & Kd);
+    MatK & Kd);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 18 - 12
include/igl/arap_rhs.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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 "arap_rhs.h"
 #include "arap_linear_block.h"
@@ -12,12 +12,13 @@
 #include "cat.h"
 #include <iostream>
 
+template<typename DerivedV, typename DerivedF, typename DerivedK>
 IGL_INLINE void igl::arap_rhs(
-  const Eigen::MatrixXd & V, 
-  const Eigen::MatrixXi & F,
-  const int dim,
-  const igl::ARAPEnergyType energy,
-  Eigen::SparseMatrix<double>& K)
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
+    const int dim,
+    const igl::ARAPEnergyType energy,
+    Eigen::SparseCompressedBase<DerivedK>& K)
 {
   using namespace std;
   using namespace Eigen;
@@ -48,7 +49,7 @@ IGL_INLINE void igl::arap_rhs(
       return;
   }
 
-  SparseMatrix<double> KX,KY,KZ;
+  DerivedK KX,KY,KZ;
   arap_linear_block(V,F,0,energy,KX);
   arap_linear_block(V,F,1,energy,KY);
   if(Vdim == 2)
@@ -62,7 +63,7 @@ IGL_INLINE void igl::arap_rhs(
       K = cat(2,cat(2,repdiag(KX,dim),repdiag(KY,dim)),repdiag(KZ,dim));
     }else if(dim ==2)
     {
-      SparseMatrix<double> ZZ(KX.rows()*2,KX.cols());
+      DerivedK ZZ(KX.rows()*2,KX.cols());
       K = cat(2,cat(2,
             cat(2,repdiag(KX,dim),ZZ),
             cat(2,repdiag(KY,dim),ZZ)),
@@ -84,6 +85,11 @@ IGL_INLINE void igl::arap_rhs(
      Vdim);
     return;
   }
-  
+
 }
 
+
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::arap_rhs(const Eigen::MatrixBase<Eigen::MatrixXd> & V, const Eigen::MatrixBase<Eigen::MatrixXi> & F,const int dim, const igl::ARAPEnergyType energy,Eigen::SparseCompressedBase<Eigen::SparseMatrix<double>>& K);
+#endif

+ 10 - 9
include/igl/arap_rhs.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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_ARAP_RHS_H
 #define IGL_ARAP_RHS_H
@@ -25,16 +25,17 @@ namespace igl
   //   energy  igl::ARAPEnergyType enum value defining which energy is being
   //     used. See igl::ARAPEnergyType.h for valid options and explanations.
   // Outputs:
-  //   K  #V*dim by #(F|V)*dim*dim matrix such that: 
+  //   K  #V*dim by #(F|V)*dim*dim matrix such that:
   //     b = K * reshape(permute(R,[3 1 2]),size(V|F,1)*size(V,2)*size(V,2),1);
-  //   
+  //
   // See also: arap_linear_block
+  template<typename DerivedV, typename DerivedF, typename DerivedK>
   IGL_INLINE void arap_rhs(
-    const Eigen::MatrixXd & V, 
-    const Eigen::MatrixXi & F,
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
     const int dim,
     const igl::ARAPEnergyType energy,
-    Eigen::SparseMatrix<double>& K);
+    Eigen::SparseCompressedBase<DerivedK>& K);
 }
 #ifndef IGL_STATIC_LIBRARY
 #include "arap_rhs.cpp"

+ 2 - 2
include/igl/average_onto_vertices.cpp

@@ -7,11 +7,11 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "average_onto_vertices.h"
 
-template<typename DerivedV,typename DerivedF,typename DerivedS>
+template<typename DerivedV,typename DerivedF,typename DerivedS,typename DerivedSV >
 IGL_INLINE void igl::average_onto_vertices(const Eigen::MatrixBase<DerivedV> &V,
   const Eigen::MatrixBase<DerivedF> &F,
   const Eigen::MatrixBase<DerivedS> &S,
-  Eigen::MatrixBase<DerivedS> &SV)
+  Eigen::PlainObjectBase<DerivedSV> &SV)
 {
   SV = DerivedS::Zero(V.rows(),S.cols());
   Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,1> COUNT(V.rows());

+ 9 - 9
include/igl/average_onto_vertices.h

@@ -1,31 +1,31 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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_AVERAGE_ONTO_VERTICES_H
 #define IGL_AVERAGE_ONTO_VERTICES_H
 #include "igl_inline.h"
 
 #include <Eigen/Dense>
-namespace igl 
+namespace igl
 {
-  // average_onto_vertices 
+  // average_onto_vertices
   // Move a scalar field defined on faces to vertices by averaging
   //
   // Input:
   // V,F: mesh
   // S: scalar field defined on faces, Fx1
-  // 
+  //
   // Output:
   // SV: scalar field defined on vertices
-  template<typename DerivedV,typename DerivedF,typename DerivedS>
+  template<typename DerivedV,typename DerivedF,typename DerivedS,typename DerivedSV>
   IGL_INLINE void average_onto_vertices(const Eigen::MatrixBase<DerivedV> &V,
     const Eigen::MatrixBase<DerivedF> &F,
     const Eigen::MatrixBase<DerivedS> &S,
-    Eigen::MatrixBase<DerivedS> &SV);
+    Eigen::PlainObjectBase<DerivedSV> &SV);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 2 - 0
include/igl/barycenter.cpp

@@ -56,4 +56,6 @@ template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Mat
 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> >&);
+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<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> >&);
 #endif

+ 2 - 2
include/igl/bfs.cpp

@@ -59,7 +59,7 @@ template <
   typename DType,
   typename PType>
 IGL_INLINE void igl::bfs(
-  const Eigen::SparseMatrix<AType> & A,
+  const Eigen::SparseCompressedBase<AType> & A,
   const size_t s,
   std::vector<DType> & D,
   std::vector<PType> & P)
@@ -83,7 +83,7 @@ IGL_INLINE void igl::bfs(
     D.push_back(f);
     P[f] = p;
     seen[f] = true;
-    for(typename Eigen::SparseMatrix<AType>::InnerIterator it (A,f); it; ++it)
+    for(typename AType::InnerIterator it (A,f); it; ++it)
     {
       if(it.value()) Q.push({it.index(),f});
     }

+ 1 - 1
include/igl/bfs.h

@@ -42,7 +42,7 @@ namespace igl
     typename DType,
     typename PType>
   IGL_INLINE void bfs(
-    const Eigen::SparseMatrix<AType> & A,
+    const Eigen::SparseCompressedBase<AType> & A,
     const size_t s,
     std::vector<DType> & D,
     std::vector<PType> & P);

+ 7 - 7
include/igl/bfs_orient.cpp

@@ -12,13 +12,13 @@
 
 template <typename DerivedF, typename DerivedFF, typename DerivedC>
 IGL_INLINE void igl::bfs_orient(
-  const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::MatrixBase<DerivedF> & F,
   Eigen::PlainObjectBase<DerivedFF> & FF,
   Eigen::PlainObjectBase<DerivedC> & C)
 {
   using namespace Eigen;
   using namespace std;
-  SparseMatrix<int> A;
+  SparseMatrix<typename DerivedF::Scalar> A;
   orientable_patches(F,C,A);
 
   // number of faces
@@ -30,7 +30,7 @@ IGL_INLINE void igl::bfs_orient(
   // Edge sets
   const int ES[3][2] = {{1,2},{2,0},{0,1}};
 
-  if(&FF != &F)
+  if(((void*)&FF) != ((void*)&F))
   {
     FF = F;
   }
@@ -38,7 +38,7 @@ IGL_INLINE void igl::bfs_orient(
 #pragma omp parallel for
   for(int c = 0;c<num_cc;c++)
   {
-    queue<int> Q;
+    queue<typename DerivedF::Scalar> Q;
     // find first member of patch c
     for(int f = 0;f<FF.rows();f++)
     {
@@ -51,7 +51,7 @@ IGL_INLINE void igl::bfs_orient(
     assert(!Q.empty());
     while(!Q.empty())
     {
-      const int f = Q.front();
+      const typename DerivedF::Scalar f = Q.front();
       Q.pop();
       if(seen(f) > 0)
       {
@@ -59,7 +59,7 @@ IGL_INLINE void igl::bfs_orient(
       }
       seen(f)++;
       // loop over neighbors of f
-      for(typename SparseMatrix<int>::InnerIterator it (A,f); it; ++it)
+      for(typename SparseMatrix<typename DerivedF::Scalar>::InnerIterator it (A,f); it; ++it)
       {
         // might be some lingering zeros, and skip self-adjacency
         if(it.value() != 0 && it.row() != f)
@@ -96,5 +96,5 @@ IGL_INLINE void igl::bfs_orient(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::bfs_orient<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::bfs_orient<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #endif

+ 2 - 2
include/igl/bfs_orient.h

@@ -25,10 +25,10 @@ namespace igl
   //
   template <typename DerivedF, typename DerivedFF, typename DerivedC>
   IGL_INLINE void bfs_orient(
-    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedF> & F,
     Eigen::PlainObjectBase<DerivedFF> & FF,
     Eigen::PlainObjectBase<DerivedC> & C);
-};
+}
 #ifndef IGL_STATIC_LIBRARY
 #  include "bfs_orient.cpp"
 #endif

+ 31 - 27
include/igl/biharmonic_coordinates.cpp

@@ -22,8 +22,8 @@ template <
   typename SType,
   typename DerivedW>
 IGL_INLINE bool igl::biharmonic_coordinates(
-  const Eigen::PlainObjectBase<DerivedV> & V,
-  const Eigen::PlainObjectBase<DerivedT> & T,
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedT> & T,
   const std::vector<std::vector<SType> > & S,
   Eigen::PlainObjectBase<DerivedW> & W)
 {
@@ -36,32 +36,36 @@ template <
   typename SType,
   typename DerivedW>
 IGL_INLINE bool igl::biharmonic_coordinates(
-  const Eigen::PlainObjectBase<DerivedV> & V,
-  const Eigen::PlainObjectBase<DerivedT> & T,
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedT> & T,
   const std::vector<std::vector<SType> > & S,
   const int k,
   Eigen::PlainObjectBase<DerivedW> & W)
 {
   using namespace Eigen;
   using namespace std;
+
+  typedef typename DerivedV::Scalar Scalar;
+  typedef typename DerivedT::Scalar Integer;
+
   // This is not the most efficient way to build A, but follows "Linear
   // Subspace Design for Real-Time Shape Deformation" [Wang et al. 2015].
-  SparseMatrix<double> A;
+  SparseMatrix<Scalar> A;
   {
-    DiagonalMatrix<double,Dynamic> Minv;
-    SparseMatrix<double> L,K;
+    DiagonalMatrix<Scalar, Dynamic> Minv;
+    SparseMatrix<Scalar> L, K;
     Array<bool,Dynamic,Dynamic> C;
     {
       Array<bool,Dynamic,1> I;
       on_boundary(T,I,C);
     }
-#ifdef false 
+#ifdef false
     // Version described in paper is "wrong"
     // http://www.cs.toronto.edu/~jacobson/images/error-in-linear-subspace-design-for-real-time-shape-deformation-2017-wang-et-al.pdf
-    SparseMatrix<double> N,Z,M;
+    SparseMatrix<Scalar> N, Z, M;
     normal_derivative(V,T,N);
     {
-      std::vector<Triplet<double> >ZIJV;
+      std::vector<Triplet<Scalar>> ZIJV;
       for(int t =0;t<T.rows();t++)
       {
         for(int f =0;f<T.cols();f++)
@@ -84,37 +88,37 @@ IGL_INLINE bool igl::biharmonic_coordinates(
     K = N+L;
     massmatrix(V,T,MASSMATRIX_TYPE_DEFAULT,M);
     // normalize
-    M /= ((VectorXd)M.diagonal()).array().abs().maxCoeff();
+    M /= ((Matrix<Scalar, Dynamic, 1>)M.diagonal()).array().abs().maxCoeff();
     Minv =
-      ((VectorXd)M.diagonal().array().inverse()).asDiagonal();
+      ((Matrix<Scalar, Dynamic, 1>)M.diagonal().array().inverse()).asDiagonal();
 #else
-    Eigen::SparseMatrix<double> M;
-    Eigen::MatrixXi E;
-    Eigen::VectorXi EMAP;
+    Eigen::SparseMatrix<Scalar> M;
+    Eigen::Matrix<Integer, Dynamic, Dynamic> E;
+    Eigen::Matrix<Integer, Dynamic, 1> EMAP;
     crouzeix_raviart_massmatrix(V,T,M,E,EMAP);
     crouzeix_raviart_cotmatrix(V,T,E,EMAP,L);
     // Ad  #E by #V facet-vertex incidence matrix
-    Eigen::SparseMatrix<double> Ad(E.rows(),V.rows());
+    Eigen::SparseMatrix<Scalar> Ad(E.rows(),V.rows());
     {
-      std::vector<Eigen::Triplet<double> > AIJV(E.size());
+      std::vector<Eigen::Triplet<Scalar>> AIJV(E.size());
       for(int e = 0;e<E.rows();e++)
       {
         for(int c = 0;c<E.cols();c++)
         {
-          AIJV[e+c*E.rows()] = Eigen::Triplet<double>(e,E(e,c),1);
+          AIJV[e + c * E.rows()] = Eigen::Triplet<Scalar>(e, E(e, c), 1);
         }
       }
       Ad.setFromTriplets(AIJV.begin(),AIJV.end());
     }
     // Degrees
-    Eigen::VectorXd De;
+    Eigen::Matrix<Scalar, Dynamic, 1> De;
     sum(Ad,2,De);
-    Eigen::DiagonalMatrix<double,Eigen::Dynamic> De_diag = 
+    Eigen::DiagonalMatrix<Scalar,Eigen::Dynamic> De_diag =
       De.array().inverse().matrix().asDiagonal();
     K = L*(De_diag*Ad);
     // normalize
-    M /= ((VectorXd)M.diagonal()).array().abs().maxCoeff();
-    Minv = ((VectorXd)M.diagonal().array().inverse()).asDiagonal();
+    M /= ((Matrix<Scalar, Dynamic, 1>)M.diagonal()).array().abs().maxCoeff();
+    Minv = ((Matrix<Scalar, Dynamic, 1>)M.diagonal().array().inverse()).asDiagonal();
     // kill boundary edges
     for(int f = 0;f<T.rows();f++)
     {
@@ -159,9 +163,9 @@ IGL_INLINE bool igl::biharmonic_coordinates(
   }
   const size_t dim = T.cols()-1;
   // Might as well be dense... I think...
-  MatrixXd J = MatrixXd::Zero(mp+mr,mp+r*(dim+1));
-  VectorXi b(mp+mr);
-  MatrixXd H(mp+r*(dim+1),dim);
+  Matrix<Scalar, Dynamic, Dynamic> J = Matrix<Scalar, Dynamic, Dynamic>::Zero(mp+mr,mp+r*(dim+1));
+  Matrix<Integer, Dynamic, 1> b(mp+mr);
+  Matrix<Scalar, Dynamic, Dynamic> H(mp+r*(dim+1),dim);
   {
     int v = 0;
     int c = 0;
@@ -194,10 +198,10 @@ IGL_INLINE bool igl::biharmonic_coordinates(
   // minimize    ½ W' A W'
   // subject to  W(b,:) = J
   return min_quad_with_fixed(
-    A,VectorXd::Zero(A.rows()).eval(),b,J,SparseMatrix<double>(),VectorXd(),true,W);
+    A,Matrix<Scalar, Dynamic, 1>::Zero(A.rows()).eval(),b,J,SparseMatrix<Scalar>(),Matrix<Scalar, Dynamic, 1>(),true,W);
 }
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template bool igl::biharmonic_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, 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&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::biharmonic_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, 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&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 4 - 4
include/igl/biharmonic_coordinates.h

@@ -66,8 +66,8 @@ namespace igl
     typename SType,
     typename DerivedW>
   IGL_INLINE bool biharmonic_coordinates(
-    const Eigen::PlainObjectBase<DerivedV> & V,
-    const Eigen::PlainObjectBase<DerivedT> & T,
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedT> & T,
     const std::vector<std::vector<SType> > & S,
     Eigen::PlainObjectBase<DerivedW> & W);
   // k  2-->biharmonic, 3-->triharmonic
@@ -77,8 +77,8 @@ namespace igl
     typename SType,
     typename DerivedW>
   IGL_INLINE bool biharmonic_coordinates(
-    const Eigen::PlainObjectBase<DerivedV> & V,
-    const Eigen::PlainObjectBase<DerivedT> & T,
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedT> & T,
     const std::vector<std::vector<SType> > & S,
     const int k,
     Eigen::PlainObjectBase<DerivedW> & W);

+ 8 - 8
include/igl/bijective_composite_harmonic_mapping.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2017 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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 "bijective_composite_harmonic_mapping.h"
 
@@ -51,11 +51,11 @@ IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
   assert(F.cols() == 3 && "F should contain triangles");
   int tries = 0;
   int nsteps = min_steps;
-  Derivedbc bc0;
+  Eigen::Matrix<typename Derivedbc::Scalar, Eigen::Dynamic, Eigen::Dynamic> bc0;
   slice(V,b,1,bc0);
 
   // It's difficult to check for flips "robustly" in the sense that the input
-  // mesh might not have positive/consistent sign to begin with. 
+  // mesh might not have positive/consistent sign to begin with.
 
   while(nsteps<=max_steps)
   {
@@ -71,7 +71,7 @@ IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
       // of the boundary conditions. Something like "Homotopic Morphing of
       // Planar Curves" [Dym et al. 2015] but also handling multiple connected
       // components.
-      Derivedbc bct = bc0 + t*(bc - bc0);
+      Eigen::Matrix<typename Derivedbc::Scalar, Eigen::Dynamic, Eigen::Dynamic> bct = bc0 + t * (bc - bc0);
       // Compute dsicrete harmonic map using metric of previous step
       for(int iter = 0;iter<num_inner_iters;iter++)
       {
@@ -82,7 +82,7 @@ IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
         //mw.save_index(b,"b");
         //mw.save(bct,"bct");
         //mw.write("numerical.mat");
-        harmonic(DerivedU(U),F,b,bct,1,U);
+        harmonic(Eigen::Matrix<typename DerivedU::Scalar, Eigen::Dynamic, Eigen::Dynamic>(U), F, b, bct, 1, U);
         igl::slice(U,b,1,bct);
         nans = (U.array() != U.array()).count();
         if(test_for_flips)

+ 2 - 2
include/igl/bone_parents.cpp

@@ -9,7 +9,7 @@
 
 template <typename DerivedBE, typename DerivedP>
 IGL_INLINE void igl::bone_parents(
-  const Eigen::PlainObjectBase<DerivedBE>& BE,
+  const Eigen::MatrixBase<DerivedBE>& BE,
   Eigen::PlainObjectBase<DerivedP>& P)
 {
   P.resize(BE.rows(),1);
@@ -28,5 +28,5 @@ IGL_INLINE void igl::bone_parents(
 }
 
 #ifdef IGL_STATIC_LIBRARY
-template void igl::bone_parents<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::bone_parents<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> >&);
 #endif

+ 1 - 1
include/igl/bone_parents.h

@@ -20,7 +20,7 @@ namespace igl
   //
   template <typename DerivedBE, typename DerivedP>
   IGL_INLINE void bone_parents(
-    const Eigen::PlainObjectBase<DerivedBE>& BE,
+    const Eigen::MatrixBase<DerivedBE>& BE,
     Eigen::PlainObjectBase<DerivedP>& P);
 }
 

+ 2 - 2
include/igl/boundary_loop.cpp

@@ -24,7 +24,7 @@ IGL_INLINE void igl::boundary_loop(
     return;
 
   VectorXd Vdummy(F.maxCoeff()+1,1);
-  DerivedF TT,TTi;
+  Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, Eigen::Dynamic> TT,TTi;
   vector<std::vector<int> > VF, VFi;
   triangle_triangle_adjacency(F,TT,TTi);
   vertex_triangle_adjacency(Vdummy,F,VF,VFi);
@@ -142,7 +142,7 @@ IGL_INLINE void igl::boundary_loop(
   vector<int> Lvec;
   boundary_loop(F,Lvec);
 
-  L.resize(Lvec.size());
+  L.resize(Lvec.size(), 1);
   for (size_t i = 0; i < Lvec.size(); ++i)
     L(i) = Lvec[i];
 }

+ 1 - 1
include/igl/bounding_box.cpp

@@ -30,7 +30,7 @@ IGL_INLINE void igl::bounding_box(
   const auto & minV = V.colwise().minCoeff().array()-pad;
   const auto & maxV = V.colwise().maxCoeff().array()+pad;
   // 2^n vertices
-  BV.resize((1<<dim),dim);
+  BV.resize((1ull<<dim),dim);
 
   // Recursive lambda to generate all 2^n combinations
   const std::function<void(const int,const int,int*,int)> combos =

+ 1 - 2
include/igl/bounding_box_diagonal.h

@@ -15,8 +15,7 @@ namespace igl
   // box
   //
   // Inputs:
-  //   V  #V by 3 list of vertex positions
-  //   F  #F by 3 list of triangle indices into V
+  //   V  #V by 3 list of vertex/point positions
   // Returns length of bounding box diagonal
   IGL_INLINE double bounding_box_diagonal( const Eigen::MatrixXd & V);
 }

+ 2 - 0
include/igl/cat.cpp

@@ -333,4 +333,6 @@ template void igl::cat<Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<int, -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> >&);
+template void igl::cat<Eigen::Matrix<int, 1, -1, 1, 1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, -1, 1, 1, -1>, std::allocator<Eigen::Matrix<int, 1, -1, 1, 1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cat<Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<double, 1, 2, 1, 1, 2>, std::allocator<Eigen::Matrix<double, 1, 2, 1, 1, 2> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 6 - 2
include/igl/circumradius.cpp

@@ -13,8 +13,8 @@ template <
   typename DerivedF,
   typename DerivedR>
 IGL_INLINE void igl::circumradius(
-  const Eigen::PlainObjectBase<DerivedV> & V, 
-  const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::MatrixBase<DerivedV> & V, 
+  const Eigen::MatrixBase<DerivedF> & F,
   Eigen::PlainObjectBase<DerivedR> & R)
 {
   Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> l;
@@ -24,3 +24,7 @@ IGL_INLINE void igl::circumradius(
   // use formula: R=abc/(4*area) to compute the circum radius
   R = l.col(0).array() * l.col(1).array() * l.col(2).array() / (2.0*A.array());
 }
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::circumradius<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

+ 3 - 3
include/igl/circumradius.h

@@ -17,15 +17,15 @@ namespace igl
   //   V  #V by dim list of mesh vertex positions
   //   F  #F by 3 list of triangle indices into V
   // Outputs:
-  //   R  #F list of circumradii
+  //   R  #F list of circumradius
   //
   template <
     typename DerivedV, 
     typename DerivedF,
     typename DerivedR>
   IGL_INLINE void circumradius(
-    const Eigen::PlainObjectBase<DerivedV> & V, 
-    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedV> & V, 
+    const Eigen::MatrixBase<DerivedF> & F,
     Eigen::PlainObjectBase<DerivedR> & R);
 }
 #ifndef IGL_STATIC_LIBRARY

+ 20 - 19
include/igl/colon.cpp

@@ -17,7 +17,7 @@ IGL_INLINE void igl::colon(
   const H hi,
   Eigen::Matrix<T,Eigen::Dynamic,1> & I)
 {
-  const int size = ((hi-low)/step)+1;
+  const H size = ((hi-low)/step)+1;
   I = igl::LinSpaced<Eigen::Matrix<T,Eigen::Dynamic,1> >(size,low,low+step*(size-1));
 }
 
@@ -43,26 +43,27 @@ IGL_INLINE Eigen::Matrix<T,Eigen::Dynamic,1> igl::colon(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
-template Eigen::Matrix<int,-1,1,0,-1,1> igl::colon<int,int,int>(int, int);
-template Eigen::Matrix<int,-1,1,0,-1,1> igl::colon<int,int,long>(int,long);
-template Eigen::Matrix<int,-1,1,0,-1,1> igl::colon<int,int,long long int>(int,long long int);
+template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::colon<int, int, int>(int, int);
+template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::colon<int, int, long>(int, long);
+template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::colon<int, int, long long int>(int, long long int);
 template Eigen::Matrix<double, -1, 1, 0, -1, 1> igl::colon<double, double, double>(double, double);
+template void igl::colon<int, long, double>(int, long, Eigen::Matrix<double, -1, 1, 0, -1, 1> &);
 // generated by autoexplicit.sh
-template void igl::colon<int, long, int, int>(int, long, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
-template void igl::colon<int, int, long, int>(int, int, long, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
-template void igl::colon<int, long, int>(int, long, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
-template void igl::colon<int, int, int>(int, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
-template void igl::colon<int,long long int,int>(int,long long int,Eigen::Matrix<int,-1,1,0,-1,1> &);
-template void igl::colon<int, int, int, int>(int, int, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
-template void igl::colon<int, long, long>(int, long, Eigen::Matrix<long, -1, 1, 0, -1, 1>&);
-template void igl::colon<int, double, double, double>(int, double, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
-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>&);
+template void igl::colon<int, long, int, int>(int, long, int, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
+template void igl::colon<int, int, long, int>(int, int, long, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
+template void igl::colon<int, long, int>(int, long, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
+template void igl::colon<int, int, int>(int, int, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
+template void igl::colon<int, long long int, int>(int, long long int, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
+template void igl::colon<int, int, int, int>(int, int, int, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
+template void igl::colon<int, long, long>(int, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> &);
+template void igl::colon<int, double, double, double>(int, double, double, Eigen::Matrix<double, -1, 1, 0, -1, 1> &);
+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, int, double>(int, int, 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, double>(int, __int64, class Eigen::Matrix<double, -1, 1, 0, -1, 1> &);
+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
+#endif

+ 1 - 0
include/igl/colormap.cpp

@@ -1431,4 +1431,5 @@ template void igl::colormap<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matri
 template void igl::colormap<Eigen::Array<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Array<int, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 
 template void igl::colormap<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::colormap<Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<double>, Eigen::Matrix<double, -1, 1, 0, -1, 1> const>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<double>, Eigen::Matrix<double, -1, 1, 0, -1, 1> const> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 14 - 14
include/igl/comb_cross_field.cpp

@@ -23,10 +23,10 @@ namespace igl {
   {
   public:
 
-    const Eigen::PlainObjectBase<DerivedV> &V;
-    const Eigen::PlainObjectBase<DerivedF> &F;
-    const Eigen::PlainObjectBase<DerivedV> &PD1;
-    const Eigen::PlainObjectBase<DerivedV> &PD2;
+    const Eigen::MatrixBase<DerivedV> &V;
+    const Eigen::MatrixBase<DerivedF> &F;
+    const Eigen::MatrixBase<DerivedV> &PD1;
+    const Eigen::MatrixBase<DerivedV> &PD2;
     DerivedV N;
 
   private:
@@ -61,10 +61,10 @@ namespace igl {
 
 
   public:
-    inline Comb(const Eigen::PlainObjectBase<DerivedV> &_V,
-         const Eigen::PlainObjectBase<DerivedF> &_F,
-         const Eigen::PlainObjectBase<DerivedV> &_PD1,
-         const Eigen::PlainObjectBase<DerivedV> &_PD2
+    inline Comb(const Eigen::MatrixBase<DerivedV> &_V,
+         const Eigen::MatrixBase<DerivedF> &_F,
+         const Eigen::MatrixBase<DerivedV> &_PD1,
+         const Eigen::MatrixBase<DerivedV> &_PD2
          ):
     V(_V),
     F(_F),
@@ -137,10 +137,10 @@ namespace igl {
   };
 }
 template <typename DerivedV, typename DerivedF>
-IGL_INLINE void igl::comb_cross_field(const Eigen::PlainObjectBase<DerivedV> &V,
-                                      const Eigen::PlainObjectBase<DerivedF> &F,
-                                      const Eigen::PlainObjectBase<DerivedV> &PD1,
-                                      const Eigen::PlainObjectBase<DerivedV> &PD2,
+IGL_INLINE void igl::comb_cross_field(const Eigen::MatrixBase<DerivedV> &V,
+                                      const Eigen::MatrixBase<DerivedF> &F,
+                                      const Eigen::MatrixBase<DerivedV> &PD1,
+                                      const Eigen::MatrixBase<DerivedV> &PD2,
                                       Eigen::PlainObjectBase<DerivedV> &PD1out,
                                       Eigen::PlainObjectBase<DerivedV> &PD2out)
 {
@@ -150,6 +150,6 @@ IGL_INLINE void igl::comb_cross_field(const Eigen::PlainObjectBase<DerivedV> &V,
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::comb_cross_field<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::comb_cross_field<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::comb_cross_field<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::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<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::comb_cross_field<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, 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<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 4 - 4
include/igl/comb_cross_field.h

@@ -27,10 +27,10 @@ namespace igl
   
   
   template <typename DerivedV, typename DerivedF>
-  IGL_INLINE void comb_cross_field(const Eigen::PlainObjectBase<DerivedV> &V,
-                                   const Eigen::PlainObjectBase<DerivedF> &F,
-                                   const Eigen::PlainObjectBase<DerivedV> &PD1in,
-                                   const Eigen::PlainObjectBase<DerivedV> &PD2in,
+  IGL_INLINE void comb_cross_field(const Eigen::MatrixBase<DerivedV> &V,
+                                   const Eigen::MatrixBase<DerivedF> &F,
+                                   const Eigen::MatrixBase<DerivedV> &PD1in,
+                                   const Eigen::MatrixBase<DerivedV> &PD2in,
                                    Eigen::PlainObjectBase<DerivedV> &PD1out,
                                    Eigen::PlainObjectBase<DerivedV> &PD2out);
 }

+ 8 - 8
include/igl/comb_frame_field.cpp

@@ -16,12 +16,12 @@
 #include "PI.h"
 
 template <typename DerivedV, typename DerivedF, typename DerivedP>
-IGL_INLINE void igl::comb_frame_field(const Eigen::PlainObjectBase<DerivedV> &V,
-                                      const Eigen::PlainObjectBase<DerivedF> &F,
-                                      const Eigen::PlainObjectBase<DerivedP> &PD1,
-                                      const Eigen::PlainObjectBase<DerivedP> &PD2,
-                                      const Eigen::PlainObjectBase<DerivedP> &BIS1_combed,
-                                      const Eigen::PlainObjectBase<DerivedP> &BIS2_combed,
+IGL_INLINE void igl::comb_frame_field(const Eigen::MatrixBase<DerivedV> &V,
+                                      const Eigen::MatrixBase<DerivedF> &F,
+                                      const Eigen::MatrixBase<DerivedP> &PD1,
+                                      const Eigen::MatrixBase<DerivedP> &PD2,
+                                      const Eigen::MatrixBase<DerivedP> &BIS1_combed,
+                                      const Eigen::MatrixBase<DerivedP> &BIS2_combed,
                                       Eigen::PlainObjectBase<DerivedP> &PD1_combed,
                                       Eigen::PlainObjectBase<DerivedP> &PD2_combed)
 {
@@ -73,6 +73,6 @@ IGL_INLINE void igl::comb_frame_field(const Eigen::PlainObjectBase<DerivedV> &V,
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::comb_frame_field<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::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> > 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::comb_frame_field<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<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> >&);
+template void igl::comb_frame_field<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::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<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::comb_frame_field<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 6 - 6
include/igl/comb_frame_field.h

@@ -31,12 +31,12 @@ namespace igl
 
 
   template <typename DerivedV, typename DerivedF, typename DerivedP>
-  IGL_INLINE void comb_frame_field(const Eigen::PlainObjectBase<DerivedV> &V,
-                                        const Eigen::PlainObjectBase<DerivedF> &F,
-                                        const Eigen::PlainObjectBase<DerivedP> &PD1,
-                                        const Eigen::PlainObjectBase<DerivedP> &PD2,
-                                        const Eigen::PlainObjectBase<DerivedP> &BIS1_combed,
-                                        const Eigen::PlainObjectBase<DerivedP> &BIS2_combed,
+  IGL_INLINE void comb_frame_field(const Eigen::MatrixBase<DerivedV> &V,
+                                        const Eigen::MatrixBase<DerivedF> &F,
+                                        const Eigen::MatrixBase<DerivedP> &PD1,
+                                        const Eigen::MatrixBase<DerivedP> &PD2,
+                                        const Eigen::MatrixBase<DerivedP> &BIS1_combed,
+                                        const Eigen::MatrixBase<DerivedP> &BIS2_combed,
                                         Eigen::PlainObjectBase<DerivedP> &PD1_combed,
                                         Eigen::PlainObjectBase<DerivedP> &PD2_combed);
 }

+ 9 - 9
include/igl/comb_line_field.cpp

@@ -22,9 +22,9 @@ class CombLine
 {
 public:
 
-    const Eigen::PlainObjectBase<DerivedV> &V;
-    const Eigen::PlainObjectBase<DerivedF> &F;
-    const Eigen::PlainObjectBase<DerivedV> &PD1;
+    const Eigen::MatrixBase<DerivedV> &V;
+    const Eigen::MatrixBase<DerivedF> &F;
+    const Eigen::MatrixBase<DerivedV> &PD1;
     DerivedV N;
 
 private:
@@ -57,9 +57,9 @@ private:
 
 public:
 
-    inline CombLine(const Eigen::PlainObjectBase<DerivedV> &_V,
-                    const Eigen::PlainObjectBase<DerivedF> &_F,
-                    const Eigen::PlainObjectBase<DerivedV> &_PD1):
+    inline CombLine(const Eigen::MatrixBase<DerivedV> &_V,
+                    const Eigen::MatrixBase<DerivedF> &_F,
+                    const Eigen::MatrixBase<DerivedV> &_PD1):
         V(_V),
         F(_F),
         PD1(_PD1)
@@ -118,9 +118,9 @@ public:
 }
 
 template <typename DerivedV, typename DerivedF>
-IGL_INLINE void igl::comb_line_field(const Eigen::PlainObjectBase<DerivedV> &V,
-                                     const Eigen::PlainObjectBase<DerivedF> &F,
-                                     const Eigen::PlainObjectBase<DerivedV> &PD1,
+IGL_INLINE void igl::comb_line_field(const Eigen::MatrixBase<DerivedV> &V,
+                                     const Eigen::MatrixBase<DerivedF> &F,
+                                     const Eigen::MatrixBase<DerivedV> &PD1,
                                      Eigen::PlainObjectBase<DerivedV> &PD1out)
 {
     igl::CombLine<DerivedV, DerivedF> cmb(V, F, PD1);

+ 3 - 6
include/igl/comb_line_field.h

@@ -19,17 +19,14 @@ namespace igl
   //   V          #V by 3 eigen Matrix of mesh vertex 3D positions
   //   F          #F by 4 eigen Matrix of face (quad) indices
   //   PD1in      #F by 3 eigen Matrix of the first per face cross field vector
-  //   PD2in      #F by 3 eigen Matrix of the second per face cross field vector
   // Output:
   //   PD1out      #F by 3 eigen Matrix of the first combed cross field vector
-  //   PD2out      #F by 3 eigen Matrix of the second combed cross field vector
-  //
 
 
   template <typename DerivedV, typename DerivedF>
-  IGL_INLINE void comb_line_field(const Eigen::PlainObjectBase<DerivedV> &V,
-                                  const Eigen::PlainObjectBase<DerivedF> &F,
-                                  const Eigen::PlainObjectBase<DerivedV> &PD1in,
+  IGL_INLINE void comb_line_field(const Eigen::MatrixBase<DerivedV> &V,
+                                  const Eigen::MatrixBase<DerivedF> &F,
+                                  const Eigen::MatrixBase<DerivedV> &PD1in,
                                   Eigen::PlainObjectBase<DerivedV> &PD1out);
 }
 #ifndef IGL_STATIC_LIBRARY

+ 13 - 13
include/igl/compute_frame_field_bisectors.cpp

@@ -17,12 +17,12 @@
 
 template <typename DerivedV, typename DerivedF>
 IGL_INLINE void igl::compute_frame_field_bisectors(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedF>& F,
-  const Eigen::PlainObjectBase<DerivedV>& B1,
-  const Eigen::PlainObjectBase<DerivedV>& B2,
-  const Eigen::PlainObjectBase<DerivedV>& PD1,
-  const Eigen::PlainObjectBase<DerivedV>& PD2,
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedV>& B1,
+  const Eigen::MatrixBase<DerivedV>& B2,
+  const Eigen::MatrixBase<DerivedV>& PD1,
+  const Eigen::MatrixBase<DerivedV>& PD2,
   Eigen::PlainObjectBase<DerivedV>& BIS1,
   Eigen::PlainObjectBase<DerivedV>& BIS2)
 {
@@ -64,10 +64,10 @@ IGL_INLINE void igl::compute_frame_field_bisectors(
 
 template <typename DerivedV, typename DerivedF>
 IGL_INLINE void igl::compute_frame_field_bisectors(
-                                                   const Eigen::PlainObjectBase<DerivedV>& V,
-                                                   const Eigen::PlainObjectBase<DerivedF>& F,
-                                                   const Eigen::PlainObjectBase<DerivedV>& PD1,
-                                                   const Eigen::PlainObjectBase<DerivedV>& PD2,
+                                                   const Eigen::MatrixBase<DerivedV>& V,
+                                                   const Eigen::MatrixBase<DerivedF>& F,
+                                                   const Eigen::MatrixBase<DerivedV>& PD1,
+                                                   const Eigen::MatrixBase<DerivedV>& PD2,
                                                    Eigen::PlainObjectBase<DerivedV>& BIS1,
                                                    Eigen::PlainObjectBase<DerivedV>& BIS2)
 {
@@ -80,7 +80,7 @@ IGL_INLINE void igl::compute_frame_field_bisectors(
 
 #ifdef IGL_STATIC_LIBRARY
 // 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> >&);
+template void igl::compute_frame_field_bisectors<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::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 10 - 10
include/igl/compute_frame_field_bisectors.h

@@ -26,22 +26,22 @@ namespace igl
   //
   template <typename DerivedV, typename DerivedF>
   IGL_INLINE void compute_frame_field_bisectors(
-                                                const Eigen::PlainObjectBase<DerivedV>& V,
-                                                const Eigen::PlainObjectBase<DerivedF>& F,
-                                                const Eigen::PlainObjectBase<DerivedV>& B1,
-                                                const Eigen::PlainObjectBase<DerivedV>& B2,
-                                                const Eigen::PlainObjectBase<DerivedV>& PD1,
-                                                const Eigen::PlainObjectBase<DerivedV>& PD2,
+                                                const Eigen::MatrixBase<DerivedV>& V,
+                                                const Eigen::MatrixBase<DerivedF>& F,
+                                                const Eigen::MatrixBase<DerivedV>& B1,
+                                                const Eigen::MatrixBase<DerivedV>& B2,
+                                                const Eigen::MatrixBase<DerivedV>& PD1,
+                                                const Eigen::MatrixBase<DerivedV>& PD2,
                                                 Eigen::PlainObjectBase<DerivedV>& BIS1,
                                                 Eigen::PlainObjectBase<DerivedV>& BIS2);
 
   // Wrapper without given basis vectors.
   template <typename DerivedV, typename DerivedF>
   IGL_INLINE void compute_frame_field_bisectors(
-                                                const Eigen::PlainObjectBase<DerivedV>& V,
-                                                const Eigen::PlainObjectBase<DerivedF>& F,
-                                                const Eigen::PlainObjectBase<DerivedV>& PD1,
-                                                const Eigen::PlainObjectBase<DerivedV>& PD2,
+                                                const Eigen::MatrixBase<DerivedV>& V,
+                                                const Eigen::MatrixBase<DerivedF>& F,
+                                                const Eigen::MatrixBase<DerivedV>& PD1,
+                                                const Eigen::MatrixBase<DerivedV>& PD2,
                                                 Eigen::PlainObjectBase<DerivedV>& BIS1,
                                                 Eigen::PlainObjectBase<DerivedV>& BIS2);
 }

+ 5 - 5
include/igl/connect_boundary_to_infinity.cpp

@@ -10,14 +10,14 @@
 
 template <typename DerivedF, typename DerivedFO>
 IGL_INLINE void igl::connect_boundary_to_infinity(
-  const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::MatrixBase<DerivedF> & F,
   Eigen::PlainObjectBase<DerivedFO> & FO)
 {
   return connect_boundary_to_infinity(F,F.maxCoeff(),FO);
 }
 template <typename DerivedF, typename DerivedFO>
 IGL_INLINE void igl::connect_boundary_to_infinity(
-  const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::MatrixBase<DerivedF> & F,
   const typename DerivedF::Scalar inf_index,
   Eigen::PlainObjectBase<DerivedFO> & FO)
 {
@@ -37,8 +37,8 @@ template <
   typename DerivedVO, 
   typename DerivedFO>
 IGL_INLINE void igl::connect_boundary_to_infinity(
-  const Eigen::PlainObjectBase<DerivedV> & V,
-  const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
   Eigen::PlainObjectBase<DerivedVO> & VO,
   Eigen::PlainObjectBase<DerivedFO> & FO)
 {
@@ -51,5 +51,5 @@ IGL_INLINE void igl::connect_boundary_to_infinity(
 }
 
 #ifdef IGL_STATIC_LIBRARY
-template void igl::connect_boundary_to_infinity<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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::connect_boundary_to_infinity<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::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> >&);
 #endif

+ 4 - 4
include/igl/connect_boundary_to_infinity.h

@@ -22,13 +22,13 @@ namespace igl
   //     edge-manifold).
   template <typename DerivedF, typename DerivedFO>
   IGL_INLINE void connect_boundary_to_infinity(
-    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedF> & F,
     Eigen::PlainObjectBase<DerivedFO> & FO);
   // Inputs:
   //   inf_index  index of point at infinity (usually V.rows() or F.maxCoeff())
   template <typename DerivedF, typename DerivedFO>
   IGL_INLINE void connect_boundary_to_infinity(
-    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedF> & F,
     const typename DerivedF::Scalar inf_index,
     Eigen::PlainObjectBase<DerivedFO> & FO);
   // Inputs:
@@ -45,8 +45,8 @@ namespace igl
     typename DerivedVO, 
     typename DerivedFO>
   IGL_INLINE void connect_boundary_to_infinity(
-    const Eigen::PlainObjectBase<DerivedV> & V,
-    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
     Eigen::PlainObjectBase<DerivedVO> & VO,
     Eigen::PlainObjectBase<DerivedFO> & FO);
 }

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

@@ -21,7 +21,7 @@ namespace igl
       //   pa,pb,pc   2D points.
       // Output:
       //   1 if pa,pb,pc are counterclockwise oriented.
-      //   0 if pa,pb,pc are counterclockwise oriented.
+      //   0 if pa,pb,pc are collinear.
       //  -1 if pa,pb,pc are clockwise oriented.
       template <typename Scalar>
       IGL_INLINE short orient2D(

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

@@ -179,3 +179,8 @@ namespace igl {
 
 
 
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::point_areas<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif

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

@@ -38,6 +38,8 @@ namespace igl
     //   N  #P by 3 list of point normals
     // Outputs:
     //   A  #P list of estimated areas
+    //
+    // See also: igl::knn
     template <typename DerivedP, typename DerivedI, typename DerivedN,
       typename DerivedA>
     IGL_INLINE void point_areas(

+ 31 - 23
include/igl/copyleft/comiso/nrosy.cpp

@@ -482,7 +482,7 @@ void igl::copyleft::comiso::NRosyField::computek()
       // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis
       Eigen::MatrixXd P(3,3);
       Eigen::VectorXd o = V.row(F(fid0,fid0_vc));
-      Eigen::VectorXd tmp = -N0.cross(common_edge);
+      Eigen::VectorXd tmp = N0.cross(common_edge);
       P << common_edge, tmp, N0;
       P.transposeInPlace();
 
@@ -494,9 +494,9 @@ void igl::copyleft::comiso::NRosyField::computek()
 
       V0 = (P*V0.transpose()).transpose();
 
-      assert(V0(0,2) < 10e-10);
-      assert(V0(1,2) < 10e-10);
-      assert(V0(2,2) < 10e-10);
+      assert(V0(0,2) < 1e-10);
+      assert(V0(1,2) < 1e-10);
+      assert(V0(2,2) < 1e-10);
 
       Eigen::MatrixXd V1(3,3);
       V1.row(0) = V.row(F(fid1,0)).transpose() -o;
@@ -504,22 +504,22 @@ void igl::copyleft::comiso::NRosyField::computek()
       V1.row(2) = V.row(F(fid1,2)).transpose() -o;
       V1 = (P*V1.transpose()).transpose();
 
-      assert(V1(fid1_vc,2) < 10e-10);
-      assert(V1((fid1_vc+1)%3,2) < 10e-10);
+      assert(V1(fid1_vc,2) < 1e-10);
+      assert(V1((fid1_vc+1)%3,2) < 1e-10);
 
       // compute rotation R such that R * N1 = N0
       // i.e. map both triangles to the same plane
-      double alpha = -std::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));
 
       Eigen::MatrixXd R(3,3);
       R << 1,          0,            0,
-           0, std::cos(alpha), -std::sin(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);
-      assert(V1(1,2) < 10e-10);
-      assert(V1(2,2) < 10e-10);
+      assert(V1(0,2) < 1e-10);
+      assert(V1(1,2) < 1e-10);
+      assert(V1(2,2) < 1e-10);
 
       // measure the angle between the reference frames
       // k_ij is the angle between the triangle on the left and the one on the right
@@ -528,17 +528,25 @@ void igl::copyleft::comiso::NRosyField::computek()
 
       ref0.normalize();
       ref1.normalize();
-
-      double ktemp = std::atan2(ref1(1), ref1(0)) - std::atan2(ref0(1), ref0(0));
-
+      
+      double ktemp = - std::atan2(ref1(1), ref1(0)) + std::atan2(ref0(1), ref0(0));
+      
+      // make sure kappa is in corret range 
+      auto pos_fmod = [](double x, double y){
+        return (0 == y) ? x : x - y * floor(x/y);
+      };
+      ktemp = pos_fmod(ktemp, 2*igl::PI);
+      if (ktemp > igl::PI) 
+        ktemp -= 2*igl::PI;
+      
       // just to be sure, rotate ref0 using angle ktemp...
       Eigen::MatrixXd R2(2,2);
-      R2 << std::cos(ktemp), -std::sin(ktemp), std::sin(ktemp), std::cos(ktemp);
+      R2 << std::cos(-ktemp), -std::sin(-ktemp), std::sin(-ktemp), std::cos(-ktemp);
 
       tmp = R2*ref0.head<2>();
 
-      assert(tmp(0) - ref1(0) < 10^10);
-      assert(tmp(1) - ref1(1) < 10^10);
+      assert(tmp(0) - ref1(0) < 1e-10);
+      assert(tmp(1) - ref1(1) < 1e-10);
 
       k[eid] = ktemp;
     }
@@ -637,7 +645,7 @@ Eigen::Vector3d igl::copyleft::comiso::NRosyField::convertLocalto3D(unsigned fid
 
 Eigen::VectorXd igl::copyleft::comiso::NRosyField::angleDefect()
 {
-  Eigen::VectorXd A = Eigen::VectorXd::Constant(V.rows(),-2*igl::PI);
+  Eigen::VectorXd A = Eigen::VectorXd::Constant(V.rows(), 2*igl::PI);
 
   for (unsigned int i = 0; i < F.rows(); ++i)
   {
@@ -650,7 +658,7 @@ Eigen::VectorXd igl::copyleft::comiso::NRosyField::angleDefect()
         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.));
+      A(F(i, j)) -= std::acos(std::max(std::min(t, 1.), -1.));
     }
   }
 
@@ -668,8 +676,8 @@ void igl::copyleft::comiso::NRosyField::findCones(int N)
   {
     if (!isBorderEdge[i])
     {
-      singularityIndex(EV(i, 0)) -= k(i);
-      singularityIndex(EV(i, 1)) += k(i);
+      singularityIndex(EV(i, 0)) += k(i);
+      singularityIndex(EV(i, 1)) -= k(i);
     }
   }
 
@@ -687,8 +695,8 @@ void igl::copyleft::comiso::NRosyField::findCones(int N)
   {
     if (!isBorderEdge[i])
     {
-      singularityIndex(EV(i, 0)) -= double(p(i)) / double(N);
-      singularityIndex(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);
     }
   }
 

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

@@ -139,7 +139,7 @@ IGL_INLINE bool igl::copyleft::quadprog(
 #ifdef TRACE_SOLVER
     std::cerr << "Add constraint " << iq << '/';
 #endif
-    int i, j, k;
+    int j, k;
     double cc, ss, h, t1, t2, xny;
     
     /* we have to find the Givens rotation which will reduce the element
@@ -284,7 +284,7 @@ IGL_INLINE bool igl::copyleft::quadprog(
     }
   };
 
-  int i, j, k, l; /* indices */
+  int i, k, l; /* indices */
   int ip, me, mi;
   int n=g0.size();  int p=ce0.size();  int m=ci0.size();  
   MatrixXd R(G.rows(),G.cols()), J(G.rows(),G.cols());

+ 22 - 22
include/igl/copyleft/tetgen/tetgenio_to_tetmesh.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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 "tetgenio_to_tetmesh.h"
 
@@ -18,11 +18,11 @@ IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
   std::vector<std::vector<REAL > > & V,
   std::vector<std::vector<int> > & T,
   std::vector<std::vector<int > > & F,
-  std::vector<std::vector<REAL > >&  R, 
+  std::vector<std::vector<REAL > >&  R,
   std::vector<std::vector<int > >& N,
   std::vector<std::vector<int > >& PT,
   std::vector<std::vector<int > >& FT,
-  size_t & nR ) 
+  size_t & nR )
 {
    using namespace std;
    // process points
@@ -63,11 +63,11 @@ IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
        max_index = (max_index < index ? index : max_index);
      }
    }
-  
+
    assert(min_index >= 0);
    assert(max_index >= 0);
    assert(max_index < (int)V.size());
- 
+
    cout<<out.numberoftrifaces<<endl;
 
    // When would this not be 4?
@@ -96,30 +96,30 @@ IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
    // extract region marks
    nR = hashUniqueRegions.size();
 
-   // extract neighbor list 
-   N.resize(out.numberoftetrahedra, vector<int>(4));   
+   // extract neighbor list
+   N.resize(out.numberoftetrahedra, vector<int>(4));
    for (size_t i = 0; i < out.numberoftetrahedra; i++)
    {
      for (size_t j = 0; j < 4; j++)
        N[i][j] = out.neighborlist[i * 4 + j];
-   } 
-  
-   // extract point 2 tetrahedron list 
+   }
+
+   // extract point 2 tetrahedron list
    PT.resize(out.numberofpoints, vector<int>(1));
    for (size_t i = 0; i < out.numberofpoints; i++)
    {
-     PT[i][0] = out.point2tetlist[i]; 
-   }	
- 
+     PT[i][0] = out.point2tetlist[i];
+   }
+
    //extract face to tetrahedron list
-   FT.resize(out.numberoftrifaces, vector<int>(2)); 
+   FT.resize(out.numberoftrifaces, vector<int>(2));
    int triface;
-   
+
    for (size_t i = 0; i < out.numberoftrifaces; i++)
    {
      for (size_t j = 0; j < 2; j++)
      {
-       FT[i][j] = out.face2tetlist[0]; 
+       FT[i][j] = out.face2tetlist[0];
      }
    }
 
@@ -129,7 +129,7 @@ IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
 
 IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
   const tetgenio & out,
-  std::vector<std::vector<REAL > > & V, 
+  std::vector<std::vector<REAL > > & V,
   std::vector<std::vector<int> > & T,
   std::vector<std::vector<int> > & F)
 {
@@ -182,7 +182,7 @@ IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
   // loop over tetrahedra
   for(int i = 0; i < out.numberoftrifaces; i++)
   {
-    if(out.trifacemarkerlist[i]>=0)
+    if (out.trifacemarkerlist && out.trifacemarkerlist[i] >= 0)
     {
       vector<int> face(3);
       for(int j = 0; j<3; j++)
@@ -198,7 +198,7 @@ IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
 
 IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
   const tetgenio & out,
-  std::vector<std::vector<REAL > > & V, 
+  std::vector<std::vector<REAL > > & V,
   std::vector<std::vector<int> > & T)
 {
   std::vector<std::vector<int> > F;

+ 13 - 13
include/igl/copyleft/tetgen/tetrahedralize.cpp

@@ -78,10 +78,10 @@ template <
   typename DerivedTF,
   typename DerivedTR>
 IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedF>& F,
-  const Eigen::PlainObjectBase<DerivedH>& H,
-  const Eigen::PlainObjectBase<DerivedR>& R,
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedH>& H,
+  const Eigen::MatrixBase<DerivedR>& R,
   const std::string switches,
   Eigen::PlainObjectBase<DerivedTV>& TV,
   Eigen::PlainObjectBase<DerivedTT>& TT,
@@ -191,8 +191,8 @@ template <
   typename DerivedTT,
   typename DerivedTF>
 IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
   const std::string switches,
   Eigen::PlainObjectBase<DerivedTV>& TV,
   Eigen::PlainObjectBase<DerivedTT>& TT,
@@ -235,10 +235,10 @@ template <
   typename DerivedTF,
   typename DerivedTM>
 IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedF>& F,
-  const Eigen::PlainObjectBase<DerivedVM>& VM,
-  const Eigen::PlainObjectBase<DerivedFM>& FM,
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedVM>& VM,
+  const Eigen::MatrixBase<DerivedFM>& FM,
   const std::string switches,
   Eigen::PlainObjectBase<DerivedTV>& TV,
   Eigen::PlainObjectBase<DerivedTT>& TT,
@@ -339,7 +339,7 @@ IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1> >(const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &,const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &,const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const std::basic_string<char, std::char_traits<char>, std::allocator<char> >,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &);
-template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1> >(const Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &,const Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &,const Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const std::basic_string<char, std::char_traits<char>, std::allocator<char> >,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &);
+template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

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

@@ -61,8 +61,8 @@ namespace igl
         typename DerivedTT, 
         typename DerivedTF>
       IGL_INLINE int tetrahedralize(
-        const Eigen::PlainObjectBase<DerivedV>& V,
-        const Eigen::PlainObjectBase<DerivedF>& F,
+        const Eigen::MatrixBase<DerivedV>& V,
+        const Eigen::MatrixBase<DerivedF>& F,
         const std::string switches,
         Eigen::PlainObjectBase<DerivedTV>& TV,
         Eigen::PlainObjectBase<DerivedTT>& TT,
@@ -114,10 +114,10 @@ namespace igl
         typename DerivedTF, 
         typename DerivedTM>
       IGL_INLINE int tetrahedralize(
-        const Eigen::PlainObjectBase<DerivedV>& V,
-        const Eigen::PlainObjectBase<DerivedF>& F,
-        const Eigen::PlainObjectBase<DerivedVM>& VM,
-        const Eigen::PlainObjectBase<DerivedFM>& FM,
+        const Eigen::MatrixBase<DerivedV>& V,
+        const Eigen::MatrixBase<DerivedF>& F,
+        const Eigen::MatrixBase<DerivedVM>& VM,
+        const Eigen::MatrixBase<DerivedFM>& FM,
         const std::string switches,
         Eigen::PlainObjectBase<DerivedTV>& TV,
         Eigen::PlainObjectBase<DerivedTT>& TT,
@@ -185,10 +185,10 @@ namespace igl
 	typename DerivedTF,
 	typename DerivedTR>	
       IGL_INLINE int tetrahedralize(
-	const Eigen::PlainObjectBase<DerivedV>& V,
-	const Eigen::PlainObjectBase<DerivedF>& F,
-	const Eigen::PlainObjectBase<DerivedH>& H,
-	const Eigen::PlainObjectBase<DerivedR>& R,
+	const Eigen::MatrixBase<DerivedV>& V,
+	const Eigen::MatrixBase<DerivedF>& F,
+	const Eigen::MatrixBase<DerivedH>& H,
+	const Eigen::MatrixBase<DerivedR>& R,
 	const std::string switches,
 	Eigen::PlainObjectBase<DerivedTV>& TV,
         Eigen::PlainObjectBase<DerivedTT>& TT,

+ 26 - 24
include/igl/cross.cpp

@@ -1,45 +1,47 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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.h"
 
 // http://www.antisphere.com/Wiki/tools:anttweakbar
 IGL_INLINE void igl::cross(
-  const double *a, 
-  const double *b,
-  double *out)
+    const double *a,
+    const double *b,
+    double *out)
 {
-  out[0] = a[1]*b[2]-a[2]*b[1];
-  out[1] = a[2]*b[0]-a[0]*b[2];
-  out[2] = a[0]*b[1]-a[1]*b[0];
+  out[0] = a[1] * b[2] - a[2] * b[1];
+  out[1] = a[2] * b[0] - a[0] * b[2];
+  out[2] = a[0] * b[1] - a[1] * b[0];
 }
 
 template <
-  typename DerivedA,
-  typename DerivedB,
-  typename DerivedC>
+    typename DerivedA,
+    typename DerivedB,
+    typename DerivedC>
 IGL_INLINE void igl::cross(
-  const Eigen::PlainObjectBase<DerivedA> & A,
-  const Eigen::PlainObjectBase<DerivedB> & B,
-  Eigen::PlainObjectBase<DerivedC> & C)
+    const Eigen::PlainObjectBase<DerivedA> &A,
+    const Eigen::PlainObjectBase<DerivedB> &B,
+    Eigen::PlainObjectBase<DerivedC> &C)
 {
   assert(A.cols() == 3 && "#cols should be 3");
   assert(B.cols() == 3 && "#cols should be 3");
   assert(A.rows() == B.rows() && "#rows in A and B should be equal");
-  C.resize(A.rows(),3);
-  for(int d = 0;d<3;d++)
+  C.resize(A.rows(), 3);
+  for (int d = 0; d < 3; d++)
   {
-    C.col(d) = 
-      A.col((d+1)%3).array() * B.col((d+2)%3).array() -
-      A.col((d+2)%3).array() * B.col((d+1)%3).array();
+    C.col(d) =
+        A.col((d + 1) % 3).array() * B.col((d + 2) % 3).array() -
+        A.col((d + 2) % 3).array() * B.col((d + 1) % 3).array();
   }
 }
 
 #ifdef IGL_STATIC_LIBRARY
-template void igl::cross<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::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> >&);
-template void igl::cross<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
-#endif
+template void igl::cross<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::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>> &);
+template void igl::cross<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>>(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3>> const &, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3>> const &, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>> &);
+template void igl::cross<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::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>> &);
+template void igl::cross<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>>(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, 3, 0, -1, 3>> &);
+#endif

+ 15 - 15
include/igl/cross_field_mismatch.cpp

@@ -25,10 +25,10 @@ namespace igl {
   {
   public:
 
-    const Eigen::PlainObjectBase<DerivedV> &V;
-    const Eigen::PlainObjectBase<DerivedF> &F;
-    const Eigen::PlainObjectBase<DerivedV> &PD1;
-    const Eigen::PlainObjectBase<DerivedV> &PD2;
+    const Eigen::MatrixBase<DerivedV> &V;
+    const Eigen::MatrixBase<DerivedF> &F;
+    const Eigen::MatrixBase<DerivedV> &PD1;
+    const Eigen::MatrixBase<DerivedV> &PD2;
     
     DerivedV N;
 
@@ -69,10 +69,10 @@ namespace igl {
 
 
 public:
-  inline MismatchCalculator(const Eigen::PlainObjectBase<DerivedV> &_V,
-                            const Eigen::PlainObjectBase<DerivedF> &_F,
-                            const Eigen::PlainObjectBase<DerivedV> &_PD1,
-                            const Eigen::PlainObjectBase<DerivedV> &_PD2):
+  inline MismatchCalculator(const Eigen::MatrixBase<DerivedV> &_V,
+                            const Eigen::MatrixBase<DerivedF> &_F,
+                            const Eigen::MatrixBase<DerivedV> &_PD1,
+                            const Eigen::MatrixBase<DerivedV> &_PD2):
   V(_V),
   F(_F),
   PD1(_PD1),
@@ -102,10 +102,10 @@ public:
 };
 }
 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,
+IGL_INLINE void igl::cross_field_mismatch(const Eigen::MatrixBase<DerivedV> &V,
+                                          const Eigen::MatrixBase<DerivedF> &F,
+                                          const Eigen::MatrixBase<DerivedV> &PD1,
+                                          const Eigen::MatrixBase<DerivedV> &PD2,
                                           const bool isCombed,
                                           Eigen::PlainObjectBase<DerivedM> &mismatch)
 {
@@ -125,8 +125,8 @@ IGL_INLINE void igl::cross_field_mismatch(const Eigen::PlainObjectBase<DerivedV>
 
 #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> > &);
+template void igl::cross_field_mismatch<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::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const &,  Eigen::MatrixBase<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, Eigen::MatrixBase<Eigen::Matrix<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, const bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > &);
 
 #endif

+ 4 - 4
include/igl/cross_field_mismatch.h

@@ -29,10 +29,10 @@ namespace igl
   //
 
   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,
+  IGL_INLINE void cross_field_mismatch(const Eigen::MatrixBase<DerivedV> &V,
+                                       const Eigen::MatrixBase<DerivedF> &F,
+                                       const Eigen::MatrixBase<DerivedV> &PD1,
+                                       const Eigen::MatrixBase<DerivedV> &PD2,
                                        const bool isCombed,
                                        Eigen::PlainObjectBase<DerivedM> &mismatch);
 }

+ 11 - 11
include/igl/crouzeix_raviart_cotmatrix.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2017 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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 "crouzeix_raviart_cotmatrix.h"
 #include "unique_simplices.h"
@@ -13,14 +13,14 @@
 
 template <typename DerivedV, typename DerivedF, typename LT, typename DerivedE, typename DerivedEMAP>
 void igl::crouzeix_raviart_cotmatrix(
-  const Eigen::MatrixBase<DerivedV> & V, 
-  const Eigen::MatrixBase<DerivedF> & F, 
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
   Eigen::SparseMatrix<LT> & L,
   Eigen::PlainObjectBase<DerivedE> & E,
   Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
 {
   // All occurrences of directed "facets"
-  Eigen::MatrixXi allE;
+  Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, Eigen::Dynamic>  allE;
   oriented_facets(F,allE);
   Eigen::VectorXi _1;
   unique_simplices(allE,E,_1,EMAP);
@@ -29,8 +29,8 @@ void igl::crouzeix_raviart_cotmatrix(
 
 template <typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedEMAP, typename LT>
 void igl::crouzeix_raviart_cotmatrix(
-  const Eigen::MatrixBase<DerivedV> & V, 
-  const Eigen::MatrixBase<DerivedF> & F, 
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
   const Eigen::MatrixBase<DerivedE> & E,
   const Eigen::MatrixBase<DerivedEMAP> & EMAP,
   Eigen::SparseMatrix<LT> & L)
@@ -84,8 +84,8 @@ void igl::crouzeix_raviart_cotmatrix(
     for(int c = 0;c<k;c++)
     {
       LIJV.emplace_back(
-        EMAP(F2E(f,LI(c))),
-        EMAP(F2E(f,LJ(c))),
+        EMAP(F2E(f,LI(c)), 0),
+        EMAP(F2E(f,LJ(c)), 0),
         (c<(k/2)?-1.:1.) * factor *C(f,LV(c)));
     }
   }

+ 4 - 4
include/igl/crouzeix_raviart_massmatrix.cpp

@@ -18,16 +18,16 @@
 
 template <typename MT, typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedEMAP>
 void igl::crouzeix_raviart_massmatrix(
-    const Eigen::MatrixBase<DerivedV> & V, 
+    const Eigen::MatrixBase<DerivedV> & V,
     const Eigen::MatrixBase<DerivedF> & F, 
     Eigen::SparseMatrix<MT> & M,
     Eigen::PlainObjectBase<DerivedE> & E,
     Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
 {
   // All occurrences of directed "facets"
-  Eigen::MatrixXi allE;
+  Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, Eigen::Dynamic> allE;
   oriented_facets(F,allE);
-  Eigen::VectorXi _1;
+  Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, 1> _1;
   unique_simplices(allE,E,_1,EMAP);
   return crouzeix_raviart_massmatrix(V,F,E,EMAP,M);
 }
@@ -69,7 +69,7 @@ void igl::crouzeix_raviart_massmatrix(
   {
     for(int c = 0;c<ss;c++)
     {
-      MIJV[f+m*c] = Triplet<MT>(EMAP(f+m*c),EMAP(f+m*c),TA(f)/(double)(ss));
+      MIJV[f+m*c] = Triplet<MT>(EMAP(f+m*c, 0),EMAP(f+m*c, 0),TA(f)/(double)(ss));
     }
   }
   M.resize(E.rows(),E.rows());

+ 128 - 309
include/igl/cut_mesh.cpp

@@ -1,330 +1,149 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2016 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// Copyright (C) 2019 Hanxiao Shen <[email protected]>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include <igl/cut_mesh.h>
-#include <igl/vertex_triangle_adjacency.h>
 #include <igl/triangle_triangle_adjacency.h>
-#include <igl/is_border_vertex.h>
 #include <igl/HalfEdgeIterator.h>
-#include <set>
-
-// This file violates many of the libigl style guidelines.
-
-namespace igl {
-
-
-  template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-  class MeshCutterMini
-  {
-  public:
-    // Input
-    //mesh
-    const Eigen::PlainObjectBase<DerivedV> &V;
-    const Eigen::PlainObjectBase<DerivedF> &F;
-    // TT is the same type as TTi? This is likely to break at some point
-    const Eigen::PlainObjectBase<DerivedTT> &TT;
-    const Eigen::PlainObjectBase<DerivedTT> &TTi;
-    const std::vector<std::vector<VFType> >& VF;
-    const std::vector<std::vector<VFType> >& VFi;
-    const std::vector<bool> &V_border; // bool
-    //edges to cut
-    const Eigen::PlainObjectBase<DerivedC> &Handle_Seams; // 3 bool
-
-    // total number of scalar variables
-    int num_scalar_variables;
-
-    // per face indexes of vertex in the solver
-    DerivedF HandleS_Index;
-
-    // per vertex variable indexes
-    std::vector<std::vector<int> > HandleV_Integer;
-
-    IGL_INLINE MeshCutterMini(
-      const Eigen::PlainObjectBase<DerivedV> &_V,
-      const Eigen::PlainObjectBase<DerivedF> &_F,
-      const Eigen::PlainObjectBase<DerivedTT> &_TT,
-      const Eigen::PlainObjectBase<DerivedTT> &_TTi,
-      const std::vector<std::vector<VFType> > &_VF,
-      const std::vector<std::vector<VFType> > &_VFi,
-      const std::vector<bool> &_V_border,
-      const Eigen::PlainObjectBase<DerivedC> &_Handle_Seams);
-
-    // vertex to variable mapping
-    // initialize the mapping for a given sampled mesh
-    IGL_INLINE void InitMappingSeam();
-
-  private:
-
-    IGL_INLINE void FirstPos(const int v, int &f, int &edge);
-
-    IGL_INLINE int AddNewIndex(const int v0);
-
-    IGL_INLINE bool IsSeam(const int f0, const int f1);
-
-    // find initial position of the pos to
-    // assing face to vert inxex correctly
-    IGL_INLINE void FindInitialPos(const int vert, int &edge, int &face);
-
-
-    // initialize the mapping given an initial pos
-    // whih must be initialized with FindInitialPos
-    IGL_INLINE void MapIndexes(const int  vert, const int edge_init, const int f_init);
-
-    // initialize the mapping for a given vertex
-    IGL_INLINE void InitMappingSeam(const int vert);
-
-  };
-}
-
-
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-MeshCutterMini(
-  const Eigen::PlainObjectBase<DerivedV> &_V,
-  const Eigen::PlainObjectBase<DerivedF> &_F,
-  const Eigen::PlainObjectBase<DerivedTT> &_TT,
-  const Eigen::PlainObjectBase<DerivedTT> &_TTi,
-  const std::vector<std::vector<VFType> > &_VF,
-  const std::vector<std::vector<VFType> > &_VFi,
-  const std::vector<bool> &_V_border,
-  const Eigen::PlainObjectBase<DerivedC> &_Handle_Seams):
-  V(_V),
-  F(_F),
-  TT(_TT),
-  TTi(_TTi),
-  VF(_VF),
-  VFi(_VFi),
-  V_border(_V_border),
-  Handle_Seams(_Handle_Seams)
-{
-  num_scalar_variables=0;
-  HandleS_Index.setConstant(F.rows(),3,-1);
-  HandleV_Integer.resize(V.rows());
-}
-
-
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-FirstPos(const int v, int &f, int &edge)
-{
-  f    = VF[v][0];  // f=v->cVFp();
-  edge = VFi[v][0]; // edge=v->cVFi();
-}
+#include <igl/is_border_vertex.h>
 
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE int igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-AddNewIndex(const int v0)
-{
-  num_scalar_variables++;
-  HandleV_Integer[v0].push_back(num_scalar_variables);
-  return num_scalar_variables;
+// wrapper for input/output style
+template <typename DerivedV, typename DerivedF, typename DerivedC>
+IGL_INLINE void igl::cut_mesh(
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedC>& C,
+  Eigen::PlainObjectBase<DerivedV>& Vn,
+  Eigen::PlainObjectBase<DerivedF>& Fn
+){
+  Vn = V;
+  Fn = F;
+  typedef typename DerivedF::Scalar Index;
+  Eigen::Matrix<Index,Eigen::Dynamic,1> _I;
+  cut_mesh(Vn,Fn,C,_I);
 }
 
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE bool igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-IsSeam(const int f0, const int f1)
-{
-  for (int i=0;i<3;i++)
-  {
-    int f_clos = TT(f0,i);
-
-    if (f_clos == -1)
-      continue; ///border
-
-    if (f_clos == f1)
-      return(Handle_Seams(f0,i));
-  }
-  assert(0);
-  return false;
+template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedI>
+IGL_INLINE void igl::cut_mesh(
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedC>& C,
+  Eigen::PlainObjectBase<DerivedV>& Vn,
+  Eigen::PlainObjectBase<DerivedF>& Fn,
+  Eigen::PlainObjectBase<DerivedI>& I
+){
+  Vn = V;
+  Fn = F;
+  cut_mesh(Vn,Fn,C,I);
 }
 
-///find initial position of the pos to
-// assing face to vert inxex correctly
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-FindInitialPos(const int vert,
-               int &edge,
-               int &face)
-{
-  int f_init;
-  int edge_init;
-  FirstPos(vert,f_init,edge_init); // todo manually the function
-  igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,edge_init);
-
-  bool vertexB = V_border[vert];
-  bool possible_split=false;
-  bool complete_turn=false;
-  do
-  {
-    int curr_f = VFI.Fi();
-    int curr_edge=VFI.Ei();
-    VFI.NextFE();
-    int next_f=VFI.Fi();
-    ///test if I've just crossed a border
-    bool on_border=(TT(curr_f,curr_edge)==-1);
-    //bool mismatch=false;
-    bool seam=false;
-
-    ///or if I've just crossed a seam
-    ///if I'm on a border I MUST start from the one next t othe border
-    if (!vertexB)
-      //seam=curr_f->IsSeam(next_f);
-      seam=IsSeam(curr_f,next_f);
-    //    if (vertexB)
-    //      assert(!Handle_Singular(vert));
-    //    ;
-    //assert(!vert->IsSingular());
-    possible_split=((on_border)||(seam));
-    complete_turn = next_f == f_init;
-  } while ((!possible_split)&&(!complete_turn));
-  face=VFI.Fi();
-  edge=VFI.Ei();
+template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedI>
+IGL_INLINE void igl::cut_mesh(
+  Eigen::PlainObjectBase<DerivedV>& V,
+  Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedC>& C,
+  Eigen::PlainObjectBase<DerivedI>& I
+){
+  typedef typename DerivedF::Scalar Index;
+  DerivedF FF, FFi;
+  igl::triangle_triangle_adjacency(F,FF,FFi);
+  igl::cut_mesh(V,F,FF,FFi,C,I);
 }
 
-
-
-///initialize the mapping given an initial pos
-///whih must be initialized with FindInitialPos
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-MapIndexes(const int  vert,
-           const int edge_init,
-           const int f_init)
-{
-  ///check that is not on border..
-  ///in such case maybe it's non manyfold
-  ///insert an initial index
-  int curr_index=AddNewIndex(vert);
-  ///and initialize the jumping pos
-  igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,edge_init);
-  bool complete_turn=false;
-  do
-  {
-    int curr_f = VFI.Fi();
-    int curr_edge = VFI.Ei();
-    ///assing the current index
-    HandleS_Index(curr_f,curr_edge) = curr_index;
-    VFI.NextFE();
-    int next_f = VFI.Fi();
-    ///test if I've finiseh with the face exploration
-    complete_turn = (next_f==f_init);
-    ///or if I've just crossed a mismatch
-    if (!complete_turn)
-    {
-      bool seam=false;
-      //seam=curr_f->IsSeam(next_f);
-      seam=IsSeam(curr_f,next_f);
-      if (seam)
-      {
-        ///then add a new index
-        curr_index=AddNewIndex(vert);
+template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedFFi, typename DerivedC, typename DerivedI>
+IGL_INLINE void igl::cut_mesh(
+  Eigen::PlainObjectBase<DerivedV>& V,
+  Eigen::PlainObjectBase<DerivedF>& F,
+  Eigen::MatrixBase<DerivedFF>& FF,
+  Eigen::MatrixBase<DerivedFFi>& FFi,
+  const Eigen::MatrixBase<DerivedC>& C,
+  Eigen::PlainObjectBase<DerivedI>& I
+){
+
+  typedef typename DerivedF::Scalar Index;
+
+  // store current number of occurance of each vertex as the alg proceed
+  Eigen::Matrix<Index,Eigen::Dynamic,1> occurence(V.rows());
+  occurence.setConstant(1);
+  
+  // set eventual number of occurance of each vertex expected
+  Eigen::Matrix<Index,Eigen::Dynamic,1> eventual(V.rows());
+  eventual.setZero();
+  for(Index i=0;i<F.rows();i++){
+    for(Index k=0;k<3;k++){
+      Index u = F(i,k);
+      Index v = F(i,(k+1)%3);
+      if(FF(i,k) == -1){ // add one extra occurance for boundary vertices
+        eventual(u) += 1;
+      }else if(C(i,k) == 1 && u < v){ // only compute every (undirected) edge ones
+        eventual(u) += 1;
+        eventual(v) += 1;
       }
     }
-  } while (!complete_turn);
-}
-
-///initialize the mapping for a given vertex
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-InitMappingSeam(const int vert)
-{
-  ///first rotate until find the first pos after a mismatch
-  ///or a border or return to the first position...
-  int f_init = VF[vert][0];
-  int indexE = VFi[vert][0];
-
-  igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,indexE);
-
-  int edge_init;
-  int face_init;
-  FindInitialPos(vert,edge_init,face_init);
-  MapIndexes(vert,edge_init,face_init);
-}
-
-///vertex to variable mapping
-///initialize the mapping for a given sampled mesh
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-InitMappingSeam()
-{
-  num_scalar_variables=-1;
-  for (unsigned int i=0;i<V.rows();i++)
-    InitMappingSeam(i);
-
-  for (unsigned int j=0;j<V.rows();j++)
-    assert(HandleV_Integer[j].size()>0);
-}
-
-
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::cut_mesh(
-  const Eigen::PlainObjectBase<DerivedV> &V,
-  const Eigen::PlainObjectBase<DerivedF> &F,
-  const std::vector<std::vector<VFType> >& VF,
-  const std::vector<std::vector<VFType> >& VFi,
-  const Eigen::PlainObjectBase<DerivedTT>& TT,
-  const Eigen::PlainObjectBase<DerivedTT>& TTi,
-  const std::vector<bool> &V_border,
-  const Eigen::PlainObjectBase<DerivedC> &cuts,
-  Eigen::PlainObjectBase<DerivedV> &Vcut,
-  Eigen::PlainObjectBase<DerivedF> &Fcut)
-{
-  //finding the cuts is done, now we need to actually generate a cut mesh
-  igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC> mc(V, F, TT, TTi, VF, VFi, V_border, cuts);
-  mc.InitMappingSeam();
-
-  Fcut = mc.HandleS_Index;
-  //we have the faces, we need the vertices;
-  int newNumV = Fcut.maxCoeff()+1;
-  Vcut.setZero(newNumV,3);
-  for (int vi=0; vi<V.rows(); ++vi)
-    for (int i=0; i<mc.HandleV_Integer[vi].size();++i)
-      Vcut.row(mc.HandleV_Integer[vi][i]) = V.row(vi);
-
-  //ugly hack to fix some problematic cases (border vertex that is also on the boundary of the hole
-  for (int fi =0; fi<Fcut.rows(); ++fi)
-    for (int k=0; k<3; ++k)
-      if (Fcut(fi,k)==-1)
-      {
-        //we need to add a vertex
-        Fcut(fi,k) = newNumV;
-        newNumV ++;
-        Vcut.conservativeResize(newNumV, Eigen::NoChange);
-        Vcut.row(newNumV-1) = V.row(F(fi,k));
+  }
+  
+  // original number of vertices
+  Index n_v = V.rows(); 
+  
+  // estimate number of new vertices and resize V
+  Index n_new = 0;
+  for(Index i=0;i<eventual.rows();i++)
+    n_new += ((eventual(i) > 0) ? eventual(i)-1 : 0);
+  V.conservativeResize(n_v+n_new,Eigen::NoChange);
+  I = DerivedI::LinSpaced(V.rows(),0,V.rows());
+  
+  // pointing to the current bottom of V
+  Index pos = n_v;
+  for(Index f=0;f<C.rows();f++){
+    for(Index k=0;k<3;k++){
+      Index v0 = F(f,k);
+      if(F(f,k) >= n_v) continue; // ignore new vertices
+      if(C(f,k) == 1 && occurence(v0) != eventual(v0)){
+        igl::HalfEdgeIterator<DerivedF,DerivedF,DerivedF> he(F,FF,FFi,f,k);
+
+        // rotate clock-wise around v0 until hit another cut
+        std::vector<Index> fan;
+        Index fi = he.Fi();
+        Index ei = he.Ei();
+        do{
+          fan.push_back(fi);
+          he.flipE();
+          he.flipF();
+          fi = he.Fi();
+          ei = he.Ei();
+        }while(C(fi,ei) == 0 && !he.isBorder());
+        
+        // make a copy
+        V.row(pos) << V.row(v0);
+        I(pos) = v0;
+        // add one occurance to v0
+        occurence(v0) += 1;
+        
+        // replace old v0
+        for(Index f0: fan)
+          for(Index j=0;j<3;j++)
+            if(F(f0,j) == v0)
+              F(f0,j) = pos;
+        
+        // mark cuts as boundary
+        FF(f,k) = -1;
+        FF(fi,ei) = -1;
+        
+        pos++;
       }
-
-
+    }
+  }
+  
 }
 
 
-//Wrapper of the above with only vertices and faces as mesh input
-template <typename DerivedV, typename DerivedF, typename DerivedC>
-IGL_INLINE void igl::cut_mesh(
-  const Eigen::PlainObjectBase<DerivedV> &V,
-  const Eigen::PlainObjectBase<DerivedF> &F,
-  const Eigen::PlainObjectBase<DerivedC> &cuts,
-  Eigen::PlainObjectBase<DerivedV> &Vcut,
-  Eigen::PlainObjectBase<DerivedF> &Fcut)
-{
-  std::vector<std::vector<int> > VF, VFi;
-  igl::vertex_triangle_adjacency(V,F,VF,VFi);
-  // Alec: Cast? Why? This is likely to break.
-  Eigen::MatrixXd Vt = V;
-  Eigen::MatrixXi Ft = F;
-  Eigen::MatrixXi TT, TTi;
-  igl::triangle_triangle_adjacency(Ft,TT,TTi);
-  std::vector<bool> V_border = igl::is_border_vertex(V,F);
-  igl::cut_mesh(V, F, VF, VFi, TT, TTi, V_border, cuts, Vcut, Fcut);
-}
-
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::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> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<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::cut_mesh<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::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> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-template void igl::cut_mesh<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<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh<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::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::cut_mesh<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<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::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<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> >&);
 #endif

+ 46 - 45
include/igl/cut_mesh.h

@@ -1,78 +1,79 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 //
-// Copyright (C) 2015 Olga Diamanti <[email protected]>
+// Copyright (C) 2019 Hanxiao Shen <[email protected]>
 //
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef IGL_CUT_MESH
-#define IGL_CUT_MESH
+#ifndef IGL_CUT_MESH_H
+#define IGL_CUT_MESH_H
 #include "igl_inline.h"
 
 #include <Eigen/Core>
-#include <vector>
 
 namespace igl
 {
   // Given a mesh and a list of edges that are to be cut, the function
   // generates a new disk-topology mesh that has the cuts at its boundary.
   //
-  // Todo: this combinatorial operation should not depend on the vertex
-  // positions V.
   //
   // Known issues: Assumes mesh is edge-manifold.
   //
   // Inputs:
   //   V  #V by 3 list of the vertex positions
-  //   F  #F by 3 list of the faces (must be triangles)
-  //   VF  #V list of lists of incident faces (adjacency list), e.g.  as
-  //     returned by igl::vertex_triangle_adjacency
-  //   VFi  #V list of lists of index of incidence within incident faces listed
-  //     in VF, e.g. as returned by igl::vertex_triangle_adjacency
-  //   TT  #F by 3 triangle to triangle adjacent matrix (e.g. computed via
-  //     igl:triangle_triangle_adjacency)
-  //   TTi  #F by 3 adjacent matrix, the element i,j is the id of edge of the
-  //     triangle TT(i,j) that is adjacent with triangle i (e.g. computed via
-  //     igl:triangle_triangle_adjacency)
-  //   V_border  #V by 1 list of booleans, indicating if the corresponging
-  //     vertex is at the mesh boundary, e.g. as returned by
-  //     igl::is_border_vertex
+  //   F  #F by 3 list of the faces
   //   cuts  #F by 3 list of boolean flags, indicating the edges that need to
   //     be cut (has 1 at the face edges that are to be cut, 0 otherwise)
   // Outputs:
-  //   Vcut  #V by 3 list of the vertex positions of the cut mesh. This matrix
+  //   Vn  #V by 3 list of the vertex positions of the cut mesh. This matrix
   //     will be similar to the original vertices except some rows will be
   //     duplicated.
-  //   Fcut  #F by 3 list of the faces of the cut mesh(must be triangles). This
+  //   Fn  #F by 3 list of the faces of the cut mesh(must be triangles). This
   //     matrix will be similar to the original face matrix except some indices
   //     will be redirected to point to the newly duplicated vertices.
-  //
-  template <
-    typename DerivedV, 
-    typename DerivedF, 
-    typename VFType, 
-    typename DerivedTT, 
-    typename DerivedC>
+  //   I   #V by 1 list of the map between Vn to original V index.
+
+  // In place mesh cut
+  template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedI>
   IGL_INLINE void cut_mesh(
-    const Eigen::PlainObjectBase<DerivedV> &V,
-    const Eigen::PlainObjectBase<DerivedF> &F,
-    const std::vector<std::vector<VFType> >& VF,
-    const std::vector<std::vector<VFType> >& VFi,
-    const Eigen::PlainObjectBase<DerivedTT>& TT,
-    const Eigen::PlainObjectBase<DerivedTT>& TTi,
-    const std::vector<bool> &V_border,
-    const Eigen::PlainObjectBase<DerivedC> &cuts,
-    Eigen::PlainObjectBase<DerivedV> &Vcut,
-    Eigen::PlainObjectBase<DerivedF> &Fcut);
-  //Wrapper of the above with only vertices and faces as mesh input
+    Eigen::PlainObjectBase<DerivedV>& V,
+    Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedC>& cuts,
+    Eigen::PlainObjectBase<DerivedI>& I
+  );
+  
+  template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedFFi, typename DerivedC, typename DerivedI>
+  IGL_INLINE void cut_mesh(
+    Eigen::PlainObjectBase<DerivedV>& V,
+    Eigen::PlainObjectBase<DerivedF>& F,
+    Eigen::MatrixBase<DerivedFF>& FF,
+    Eigen::MatrixBase<DerivedFFi>& FFi,
+    const Eigen::MatrixBase<DerivedC>& C,
+    Eigen::PlainObjectBase<DerivedI>& I
+  );
+
   template <typename DerivedV, typename DerivedF, typename DerivedC>
   IGL_INLINE void cut_mesh(
-    const Eigen::PlainObjectBase<DerivedV> &V,
-    const Eigen::PlainObjectBase<DerivedF> &F,
-    const Eigen::PlainObjectBase<DerivedC> &cuts,
-    Eigen::PlainObjectBase<DerivedV> &Vcut,
-    Eigen::PlainObjectBase<DerivedF> &Fcut);
-};
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedC>& cuts,
+    Eigen::PlainObjectBase<DerivedV>& Vn,
+    Eigen::PlainObjectBase<DerivedF>& Fn
+  );
+
+  template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedI>
+  IGL_INLINE void cut_mesh(
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedC>& cuts,
+    Eigen::PlainObjectBase<DerivedV>& Vn,
+    Eigen::PlainObjectBase<DerivedF>& Fn,
+    Eigen::PlainObjectBase<DerivedI>& I
+  );
+
+
+  
+}
 
 
 #ifndef IGL_STATIC_LIBRARY

+ 16 - 16
include/igl/cut_mesh_from_singularities.cpp

@@ -25,9 +25,9 @@ namespace igl {
   class MeshCutter
   {
   protected:
-    const Eigen::PlainObjectBase<DerivedV> &V;
-    const Eigen::PlainObjectBase<DerivedF> &F;
-    const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch;
+    const Eigen::MatrixBase<DerivedV> &V;
+    const Eigen::MatrixBase<DerivedF> &F;
+    const Eigen::MatrixBase<DerivedM> &Handle_MMatch;
 
     Eigen::VectorXi F_visited;
     DerivedF TT;
@@ -140,9 +140,9 @@ namespace igl {
 
   public:
 
-    inline MeshCutter(const Eigen::PlainObjectBase<DerivedV> &V_,
-               const Eigen::PlainObjectBase<DerivedF> &F_,
-               const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch_):
+    inline MeshCutter(const Eigen::MatrixBase<DerivedV> &V_,
+               const Eigen::MatrixBase<DerivedF> &F_,
+               const Eigen::MatrixBase<DerivedM> &Handle_MMatch_):
     V(V_),
     F(F_),
     Handle_MMatch(Handle_MMatch_)
@@ -184,9 +184,9 @@ template <typename DerivedV,
   typename DerivedF,
   typename DerivedM,
   typename DerivedO>
-IGL_INLINE void igl::cut_mesh_from_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
-                                                 const Eigen::PlainObjectBase<DerivedF> &F,
-                                                 const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch,
+IGL_INLINE void igl::cut_mesh_from_singularities(const Eigen::MatrixBase<DerivedV> &V,
+                                                 const Eigen::MatrixBase<DerivedF> &F,
+                                                 const Eigen::MatrixBase<DerivedM> &Handle_MMatch,
                                                  Eigen::PlainObjectBase<DerivedO> &Handle_Seams)
 {
   igl::MeshCutter< DerivedV, DerivedF, DerivedM, DerivedO> mc(V, F, Handle_MMatch);
@@ -195,11 +195,11 @@ IGL_INLINE void igl::cut_mesh_from_singularities(const Eigen::PlainObjectBase<De
 }
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::cut_mesh_from_singularities<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> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<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<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template void igl::cut_mesh_from_singularities<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<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<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-template void igl::cut_mesh_from_singularities<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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template void igl::cut_mesh_from_singularities<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, 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<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-template void igl::cut_mesh_from_singularities<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::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<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::cut_mesh_from_singularities<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::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<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&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh_from_singularities<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<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::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::cut_mesh_from_singularities<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::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<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh_from_singularities<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, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh_from_singularities<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, 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::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::cut_mesh_from_singularities<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::Matrix<int, -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::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
 #endif

+ 3 - 3
include/igl/cut_mesh_from_singularities.h

@@ -30,9 +30,9 @@ namespace igl
     typename DerivedM, 
     typename DerivedO> 
   IGL_INLINE void cut_mesh_from_singularities(
-    const Eigen::PlainObjectBase<DerivedV> &V, 
-    const Eigen::PlainObjectBase<DerivedF> &F, 
-    const Eigen::PlainObjectBase<DerivedM> &MMatch,
+    const Eigen::MatrixBase<DerivedV> &V, 
+    const Eigen::MatrixBase<DerivedF> &F, 
+    const Eigen::MatrixBase<DerivedM> &MMatch,
     Eigen::PlainObjectBase<DerivedO> &seams);
 }
 #ifndef IGL_STATIC_LIBRARY

+ 1 - 1
include/igl/deprecated.h

@@ -10,7 +10,7 @@
 // Macro for marking a function as deprecated.
 // 
 // http://stackoverflow.com/a/295229/148668
-#ifdef __GNUC__
+#if defined(__GNUC__) || defined(__clang__)
 #define IGL_DEPRECATED(func) func __attribute__ ((deprecated))
 #elif defined(_MSC_VER)
 #define IGL_DEPRECATED(func) __declspec(deprecated) func

+ 6 - 6
include/igl/dihedral_angles.cpp

@@ -17,8 +17,8 @@ template <
   typename Derivedtheta,
   typename Derivedcos_theta>
 IGL_INLINE void igl::dihedral_angles(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedT>& T,
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedT>& T,
   Eigen::PlainObjectBase<Derivedtheta>& theta,
   Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta)
 {
@@ -37,8 +37,8 @@ template <
   typename Derivedtheta,
   typename Derivedcos_theta>
 IGL_INLINE void igl::dihedral_angles_intrinsic(
-  const Eigen::PlainObjectBase<DerivedL>& L,
-  const Eigen::PlainObjectBase<DerivedA>& A,
+  const Eigen::MatrixBase<DerivedL>& L,
+  const Eigen::MatrixBase<DerivedA>& A,
   Eigen::PlainObjectBase<Derivedtheta>& theta,
   Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta)
 {
@@ -93,6 +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> >(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> >&);
+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::MatrixBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&, const Eigen::MatrixBase<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::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<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(
-    const Eigen::PlainObjectBase<DerivedV>& V,
-    const Eigen::PlainObjectBase<DerivedT>& T,
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<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(
-    const Eigen::PlainObjectBase<DerivedL>& L,
-    const Eigen::PlainObjectBase<DerivedA>& A,
+    const Eigen::MatrixBase<DerivedL>& L,
+    const Eigen::MatrixBase<DerivedA>& A,
     Eigen::PlainObjectBase<Derivedtheta>& theta,
     Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta);
 

+ 51 - 0
include/igl/dijkstra.cpp

@@ -79,8 +79,59 @@ IGL_INLINE void igl::dijkstra(
     path.push_back(source);
 }
 
+
+template <typename IndexType, typename DerivedV,
+typename DerivedD, typename DerivedP>
+IGL_INLINE int igl::dijkstra(
+  const Eigen::MatrixBase<DerivedV> &V,
+  const std::vector<std::vector<IndexType> >& VV,
+  const IndexType &source,
+  const std::set<IndexType> &targets,
+  Eigen::PlainObjectBase<DerivedD> &min_distance,
+  Eigen::PlainObjectBase<DerivedP> &previous)
+{
+  int numV = VV.size();
+
+  min_distance.setConstant(numV, 1, std::numeric_limits<typename DerivedD::Scalar>::infinity());
+  min_distance[source] = 0;
+  previous.setConstant(numV, 1, -1);
+  std::set<std::pair<typename DerivedD::Scalar, IndexType> > vertex_queue;
+  vertex_queue.insert(std::make_pair(min_distance[source], source));
+
+  while (!vertex_queue.empty())
+  {
+    typename DerivedD::Scalar dist = vertex_queue.begin()->first;
+    IndexType u = vertex_queue.begin()->second;
+    vertex_queue.erase(vertex_queue.begin());
+
+    if (targets.find(u)!= targets.end())
+      return u;
+
+    // Visit each edge exiting u
+    const std::vector<int> &neighbors = VV[u];
+    for (std::vector<int>::const_iterator neighbor_iter = neighbors.begin();
+         neighbor_iter != neighbors.end();
+         neighbor_iter++)
+    {
+      IndexType v = *neighbor_iter;
+      typename DerivedD::Scalar distance_through_u = dist + (V.row(u) - V.row(v)).norm();
+      if (distance_through_u < min_distance[v]) {
+        vertex_queue.erase(std::make_pair(min_distance[v], v));
+
+        min_distance[v] = distance_through_u;
+        previous[v] = u;
+        vertex_queue.insert(std::make_pair(min_distance[v], v));
+
+      }
+
+    }
+  }
+  return -1;
+}
+
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 template int igl::dijkstra<int, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, std::set<int, std::less<int>, std::allocator<int> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::dijkstra<int, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<int, std::allocator<int> >&);
+template int igl::dijkstra<int, 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&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, int const&, std::set<int, std::less<int>, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #endif

+ 26 - 2
include/igl/dijkstra.h

@@ -67,16 +67,40 @@ namespace igl {
   //   previous         #V by 1 list of the previous visited vertices (for each vertex) - result of Dijkstra's algorithm
   //
   // Output:
-  //   path             #P by 1 list of vertex indices in the shortest path from source to vertex
+  //   path             #P by 1 list of vertex indices in the shortest path from vertex to source
   //
   template <typename IndexType, typename DerivedP>
   IGL_INLINE void dijkstra(
     const IndexType &vertex,
     const Eigen::MatrixBase<DerivedP> &previous,
     std::vector<IndexType> &path);
-};
 
 
+  // Dijkstra's algorithm for shortest paths on a mesh, with multiple targets, using edge length
+  //
+  // Inputs:
+  //   V                #V by 3 list of vertex positions
+  //   VV               #V list of lists of incident vertices (adjacency list), e.g.
+  //                    as returned by igl::adjacency_list, will be generated if empty.
+  //   source           index of source vertex
+  //   targets          target vector set
+  //
+  // Output:
+  //   min_distance     #V by 1 list of the minimum distances from source to all vertices
+  //   previous         #V by 1 list of the previous visited vertices (for each vertex) - used for backtracking
+  //
+  template <typename IndexType, typename DerivedV,
+  typename DerivedD, typename DerivedP>
+  IGL_INLINE int dijkstra(
+    const Eigen::MatrixBase<DerivedV> &V,
+    const std::vector<std::vector<IndexType> >& VV,
+    const IndexType &source,
+    const std::set<IndexType> &targets,
+    Eigen::PlainObjectBase<DerivedD> &min_distance,
+    Eigen::PlainObjectBase<DerivedP> &previous);
+
+}
+
 #ifndef IGL_STATIC_LIBRARY
 #include "dijkstra.cpp"
 #endif

+ 7 - 7
include/igl/directed_edge_orientations.cpp

@@ -1,16 +1,16 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2015 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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 "directed_edge_orientations.h"
 
 template <typename DerivedC, typename DerivedE>
 IGL_INLINE void igl::directed_edge_orientations(
-  const Eigen::PlainObjectBase<DerivedC> & C,
-  const Eigen::PlainObjectBase<DerivedE> & E,
+  const Eigen::MatrixBase<DerivedC> & C,
+  const Eigen::MatrixBase<DerivedE> & E,
   std::vector<
       Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & Q)
 {
@@ -25,5 +25,5 @@ IGL_INLINE void igl::directed_edge_orientations(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::directed_edge_orientations<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&, std::vector<Eigen::Quaternion<double, 0>, Eigen::aligned_allocator<Eigen::Quaternion<double, 0> > >&);
+template void igl::directed_edge_orientations<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&, std::vector<Eigen::Quaternion<double, 0>, Eigen::aligned_allocator<Eigen::Quaternion<double, 0> > >&);
 #endif

+ 7 - 7
include/igl/directed_edge_orientations.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2014 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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_DIRECTED_EDGE_ORIENTATIONS_H
 #define IGL_DIRECTED_EDGE_ORIENTATIONS_H
@@ -23,12 +23,12 @@ namespace igl
   //   C  #C by 3 list of edge vertex positions
   //   E  #E by 2 list of directed edges
   // Outputs:
-  //   Q  #E list of quaternions 
+  //   Q  #E list of quaternions
   //
   template <typename DerivedC, typename DerivedE>
   IGL_INLINE void directed_edge_orientations(
-    const Eigen::PlainObjectBase<DerivedC> & C,
-    const Eigen::PlainObjectBase<DerivedE> & E,
+    const Eigen::MatrixBase<DerivedC> & C,
+    const Eigen::MatrixBase<DerivedE> & E,
     std::vector<
       Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & Q);
 }

+ 8 - 6
include/igl/directed_edge_parents.cpp

@@ -14,21 +14,23 @@
 
 template <typename DerivedE, typename DerivedP>
 IGL_INLINE void igl::directed_edge_parents(
-  const Eigen::PlainObjectBase<DerivedE> & E,
+  const Eigen::MatrixBase<DerivedE> & E,
   Eigen::PlainObjectBase<DerivedP> & P)
 {
   using namespace Eigen;
   using namespace std;
-  VectorXi I = VectorXi::Constant(E.maxCoeff()+1,1,-1);
+  typedef Eigen::Matrix<typename DerivedE::Scalar, Eigen::Dynamic, 1> VectorT;
+
+  VectorT I = VectorT::Constant(E.maxCoeff()+1,1,-1);
   //I(E.col(1)) = 0:E.rows()-1
-  slice_into(colon<int>(0,E.rows()-1),E.col(1).eval(),I);
-  VectorXi roots,_;
+  slice_into(colon<typename DerivedE::Scalar>(0, E.rows()-1), E.col(1).eval(), I);
+  VectorT roots,_;
   setdiff(E.col(0).eval(),E.col(1).eval(),roots,_);
-  std::for_each(roots.data(),roots.data()+roots.size(),[&](int r){I(r)=-1;});
+  std::for_each(roots.data(),roots.data()+roots.size(),[&](typename VectorT::Scalar r){I(r)=-1;});
   slice(I,E.col(0).eval(),P);
 }
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::directed_edge_parents<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::directed_edge_parents<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> >&);
 #endif

+ 1 - 1
include/igl/directed_edge_parents.h

@@ -22,7 +22,7 @@ namespace igl
   //
   template <typename DerivedE, typename DerivedP>
   IGL_INLINE void directed_edge_parents(
-    const Eigen::PlainObjectBase<DerivedE> & E,
+    const Eigen::MatrixBase<DerivedE> & E,
     Eigen::PlainObjectBase<DerivedP> & P);
 }
 

+ 7 - 7
include/igl/dqs.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2014 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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 "dqs.h"
 #include <Eigen/Geometry>
@@ -15,8 +15,8 @@ template <
   typename T,
   typename DerivedU>
 IGL_INLINE void igl::dqs(
-  const Eigen::PlainObjectBase<DerivedV> & V,
-  const Eigen::PlainObjectBase<DerivedW> & W,
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedW> & W,
   const std::vector<Q,QAlloc> & vQ,
   const std::vector<T> & vT,
   Eigen::PlainObjectBase<DerivedU> & U)
@@ -70,5 +70,5 @@ IGL_INLINE void igl::dqs(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::dqs<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Quaternion<double, 0>, Eigen::aligned_allocator<Eigen::Quaternion<double, 0> >, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<Eigen::Quaternion<double, 0>, Eigen::aligned_allocator<Eigen::Quaternion<double, 0> > > const&, 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> >&);
+template void igl::dqs<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Quaternion<double, 0>, Eigen::aligned_allocator<Eigen::Quaternion<double, 0> >, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<Eigen::Quaternion<double, 0>, Eigen::aligned_allocator<Eigen::Quaternion<double, 0> > > const&, 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

+ 7 - 7
include/igl/dqs.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2014 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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_DQS_H
 #define IGL_DQS_H
@@ -17,7 +17,7 @@ namespace igl
   // Inputs:
   //   V  #V by 3 list of rest positions
   //   W  #W by #C list of weights
-  //   vQ  #C list of rotation quaternions 
+  //   vQ  #C list of rotation quaternions
   //   vT  #C list of translation vectors
   // Outputs:
   //   U  #V by 3 list of new positions
@@ -29,8 +29,8 @@ namespace igl
     typename T,
     typename DerivedU>
   IGL_INLINE void dqs(
-    const Eigen::PlainObjectBase<DerivedV> & V,
-    const Eigen::PlainObjectBase<DerivedW> & W,
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedW> & W,
     const std::vector<Q,QAlloc> & vQ,
     const std::vector<T> & vT,
     Eigen::PlainObjectBase<DerivedU> & U);

+ 6 - 6
include/igl/ears.cpp

@@ -15,15 +15,15 @@ IGL_INLINE void igl::ears(
   Eigen::PlainObjectBase<Derivedear_opp> & ear_opp)
 {
   assert(F.cols() == 3 && "F should contain triangles");
-  Eigen::Array<bool,Eigen::Dynamic,3> B;
+  Eigen::Array<bool, Eigen::Dynamic, 3> B;
   {
-    Eigen::Array<bool,Eigen::Dynamic,1> I;
+    Eigen::Array<bool, Eigen::Dynamic, 1> I;
     on_boundary(F,I,B);
   }
-  find(B.rowwise().count() == 2,ear);
-  Eigen::Array<bool,Eigen::Dynamic,3> Bear;
-  slice(B,ear,1,Bear);
-  Eigen::Array<bool,Eigen::Dynamic,1> M;
+  find(B.rowwise().count() == 2, ear);
+  Eigen::Array<bool, Eigen::Dynamic, 3> Bear;
+  slice(B, ear, 1, Bear);
+  Eigen::Array<bool, Eigen::Dynamic, 1> M;
   mat_min(Bear,2,M,ear_opp);
 }
 

+ 20 - 20
include/igl/edge_topology.cpp

@@ -9,24 +9,24 @@
 #include "is_edge_manifold.h"
 #include <algorithm>
 
-template<typename DerivedV, typename DerivedF>
+template<typename DerivedV, typename DerivedF, typename DerivedE>
 IGL_INLINE void igl::edge_topology(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedF>& F,
-  Eigen::MatrixXi& EV,
-  Eigen::MatrixXi& FE,
-  Eigen::MatrixXi& EF)
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
+  Eigen::PlainObjectBase<DerivedE>& EV,
+  Eigen::PlainObjectBase<DerivedE>& FE,
+  Eigen::PlainObjectBase<DerivedE>& EF)
 {
   // Only needs to be edge-manifold
   if (V.rows() ==0 || F.rows()==0)
   {
-    EV = Eigen::MatrixXi::Constant(0,2,-1);
-    FE = Eigen::MatrixXi::Constant(0,3,-1);
-    EF = Eigen::MatrixXi::Constant(0,2,-1);
+    EV = Eigen::PlainObjectBase<DerivedE>::Constant(0,2,-1);
+    FE = Eigen::PlainObjectBase<DerivedE>::Constant(0,3,-1);
+    EF = Eigen::PlainObjectBase<DerivedE>::Constant(0,2,-1);
     return;
   }
   assert(igl::is_edge_manifold(F));
-  std::vector<std::vector<int> > ETT;
+  std::vector<std::vector<typename DerivedE::Scalar> > ETT;
   for(int f=0;f<F.rows();++f)
     for (int i=0;i<3;++i)
     {
@@ -34,7 +34,7 @@ IGL_INLINE void igl::edge_topology(
       int v1 = F(f,i);
       int v2 = F(f,(i+1)%3);
       if (v1 > v2) std::swap(v1,v2);
-      std::vector<int> r(4);
+      std::vector<typename DerivedE::Scalar> r(4);
       r[0] = v1; r[1] = v2;
       r[2] = f;  r[3] = i;
       ETT.push_back(r);
@@ -47,9 +47,9 @@ IGL_INLINE void igl::edge_topology(
     if (!((ETT[i][0] == ETT[i+1][0]) && (ETT[i][1] == ETT[i+1][1])))
       ++En;
 
-  EV = Eigen::MatrixXi::Constant((int)(En),2,-1);
-  FE = Eigen::MatrixXi::Constant((int)(F.rows()),3,-1);
-  EF = Eigen::MatrixXi::Constant((int)(En),2,-1);
+  EV = DerivedE::Constant((int)(En),2,-1);
+  FE = DerivedE::Constant((int)(F.rows()),3,-1);
+  EF = DerivedE::Constant((int)(En),2,-1);
   En = 0;
 
   for(unsigned i=0;i<ETT.size();++i)
@@ -59,7 +59,7 @@ IGL_INLINE void igl::edge_topology(
         )
     {
       // Border edge
-      std::vector<int>& r1 = ETT[i];
+      std::vector<typename DerivedE::Scalar>& r1 = ETT[i];
       EV(En,0)     = r1[0];
       EV(En,1)     = r1[1];
       EF(En,0)    = r1[2];
@@ -67,8 +67,8 @@ IGL_INLINE void igl::edge_topology(
     }
     else
     {
-      std::vector<int>& r1 = ETT[i];
-      std::vector<int>& r2 = ETT[i+1];
+      std::vector<typename DerivedE::Scalar>& r1 = ETT[i];
+      std::vector<typename DerivedE::Scalar>& r2 = ETT[i+1];
       EV(En,0)     = r1[0];
       EV(En,1)     = r1[1];
       EF(En,0)    = r1[2];
@@ -84,7 +84,7 @@ IGL_INLINE void igl::edge_topology(
   // the first one is the face on the left of the edge
   for(unsigned i=0; i<EF.rows(); ++i)
   {
-    int fid = EF(i,0);
+    typename DerivedE::Scalar fid = EF(i,0);
     bool flip = true;
     // search for edge EV.row(i)
     for (unsigned j=0; j<3; ++j)
@@ -105,6 +105,6 @@ IGL_INLINE void igl::edge_topology(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::edge_topology<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::Matrix<int, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&);
-template void igl::edge_topology<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::Matrix<int, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&);
+template void igl::edge_topology<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::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<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::edge_topology<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&);
 #endif

+ 6 - 6
include/igl/edge_topology.h

@@ -34,13 +34,13 @@ namespace igl
   //   - FE uses non-standard and ambiguous order: FE(f,c) is merely an edge
   //     incident on corner c of face f. In contrast, edge_flaps's EMAP(f,c)
   //     reveals the edge _opposite_ corner c of face f
-template <typename DerivedV, typename DerivedF>
+template <typename DerivedV, typename DerivedF, typename DerivedE>
   IGL_INLINE void edge_topology(
-    const Eigen::PlainObjectBase<DerivedV>& V,
-    const Eigen::PlainObjectBase<DerivedF>& F, 
-    Eigen::MatrixXi& EV, 
-    Eigen::MatrixXi& FE, 
-    Eigen::MatrixXi& EF);
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F, 
+    Eigen::PlainObjectBase<DerivedE>& EV, 
+    Eigen::PlainObjectBase<DerivedE>& FE, 
+    Eigen::PlainObjectBase<DerivedE>& EF);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 0 - 37
include/igl/embree/Embree_convenience.h

@@ -1,37 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2013 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
-// obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef IGL_EMBREE_EMBREE_CONVENIENCE_H
-#define IGL_EMBREE_EMBREE_CONVENIENCE_H
-
-#undef interface
-#undef near
-#undef far
-// Why are these in quotes? isn't that a bad idea?
-#ifdef __GNUC__
-// This is how it should be done
-#  if __GNUC__ >= 4
-#    if __GNUC_MINOR__ >= 6
-#      pragma GCC diagnostic push
-#      pragma GCC diagnostic ignored "-Weffc++"
-#    endif
-#  endif
-// This is a hack
-#  pragma GCC system_header
-#endif
-#include <embree/include/embree.h>
-#include <embree/include/intersector1.h>
-#include <embree/common/ray.h>
-#ifdef __GNUC__
-#  if __GNUC__ >= 4
-#    if __GNUC_MINOR__ >= 6
-#      pragma GCC diagnostic pop
-#    endif
-#  endif
-#endif
-
-#endif

+ 3 - 3
include/igl/euler_characteristic.cpp

@@ -12,8 +12,8 @@
 
 template <typename Scalar, typename Index>
 IGL_INLINE int igl::euler_characteristic(
-  const Eigen::PlainObjectBase<Scalar> & V,
-  const Eigen::PlainObjectBase<Index> & F)
+  const Eigen::MatrixBase<Scalar> & V,
+  const Eigen::MatrixBase<Index> & F)
 {
 
   int euler_v = V.rows();
@@ -41,6 +41,6 @@ IGL_INLINE int igl::euler_characteristic(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template int igl::euler_characteristic<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&);
+template int igl::euler_characteristic<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&);
 template int igl::euler_characteristic<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
 #endif

+ 2 - 2
include/igl/euler_characteristic.h

@@ -34,8 +34,8 @@ namespace igl
   // Returns An int containing the Euler characteristic
   template <typename Scalar, typename Index>
   IGL_INLINE int euler_characteristic(
-    const Eigen::PlainObjectBase<Scalar> & V,
-    const Eigen::PlainObjectBase<Index> & F);
+    const Eigen::MatrixBase<Scalar> & V,
+    const Eigen::MatrixBase<Index> & F);
 
 }
 

+ 4 - 4
include/igl/exact_geodesic.cpp

@@ -3193,20 +3193,20 @@ IGL_INLINE void igl::exact_geodesic(
   std::vector<igl::geodesic::SurfacePoint> target(VT.rows() + FT.rows());
   for (int i = 0; i < VS.rows(); i++)
   {
-    source[i] = (igl::geodesic::SurfacePoint(&mesh.vertices()[VS(i)]));
+    source[i] = (igl::geodesic::SurfacePoint(&mesh.vertices()[VS(i, 0)]));
   }
   for (int i = 0; i < FS.rows(); i++)
   {
-    source[i] = (igl::geodesic::SurfacePoint(&mesh.faces()[FS(i)]));
+    source[i] = (igl::geodesic::SurfacePoint(&mesh.faces()[FS(i, 0)]));
   }
 
   for (int i = 0; i < VT.rows(); i++)
   {
-    target[i] = (igl::geodesic::SurfacePoint(&mesh.vertices()[VT(i)]));
+    target[i] = (igl::geodesic::SurfacePoint(&mesh.vertices()[VT(i, 0)]));
   }
   for (int i = 0; i < FT.rows(); i++)
   {
-    target[i] = (igl::geodesic::SurfacePoint(&mesh.faces()[FT(i)]));
+    target[i] = (igl::geodesic::SurfacePoint(&mesh.faces()[FT(i, 0)]));
   }
 
   exact_algorithm.propagate(source);

+ 2 - 2
include/igl/facet_components.cpp

@@ -11,7 +11,7 @@
 #include <queue>
 template <typename DerivedF, typename DerivedC>
 IGL_INLINE void igl::facet_components(
-  const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::MatrixBase<DerivedF> & F,
   Eigen::PlainObjectBase<DerivedC> & C)
 {
   using namespace std;
@@ -88,7 +88,7 @@ IGL_INLINE void igl::facet_components(
 // Explicit template instantiation
 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> >&);
+template void igl::facet_components<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> >&);
 #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

+ 1 - 1
include/igl/facet_components.h

@@ -22,7 +22,7 @@ namespace igl
   //   C  #F list of connected component ids
   template <typename DerivedF, typename DerivedC>
   IGL_INLINE void facet_components(
-    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedF> & F,
     Eigen::PlainObjectBase<DerivedC> & C);
 
   // Compute connected components of facets based on edge-edge adjacency.

+ 421 - 287
include/igl/fast_winding_number.cpp

@@ -4,321 +4,455 @@
 #include "parallel_for.h"
 #include "PI.h"
 #include <vector>
+#include <cassert>
 
-namespace igl {
-  template <typename DerivedP, typename DerivedA, typename DerivedN,
-  typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
+template <
+  typename DerivedP, 
+  typename DerivedA, 
+  typename DerivedN,
+  typename Index, 
+  typename DerivedCH, 
+  typename DerivedCM, 
+  typename DerivedR,
   typename DerivedEC>
-  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
-                                      const Eigen::MatrixBase<DerivedN>& N,
-                                      const Eigen::MatrixBase<DerivedA>& A,
-                                      const std::vector<std::vector<Index> > & point_indices,
-                                      const Eigen::MatrixBase<DerivedCH>& CH,
-                                      const int expansion_order,
-                                      Eigen::PlainObjectBase<DerivedCM>& CM,
-                                      Eigen::PlainObjectBase<DerivedR>& R,
-                                      Eigen::PlainObjectBase<DerivedEC>& EC)
-  {
-    typedef typename DerivedP::Scalar real_p;
-    typedef typename DerivedN::Scalar real_n;
-    typedef typename DerivedA::Scalar real_a;
-    typedef typename DerivedCM::Scalar real_cm;
-    typedef typename DerivedR::Scalar real_r;
-    typedef typename DerivedEC::Scalar real_ec;
-  
-    typedef Eigen::Matrix<real_p,1,3> RowVec3p;
-  
-    int m = CH.size();
-    int num_terms;
-  
-    assert(expansion_order < 3 && expansion_order >= 0 && "m must be less than n");
-    if(expansion_order == 0){
-        num_terms = 3;
-    } else if(expansion_order ==1){
-        num_terms = 3 + 9;
-    } else if(expansion_order == 2){
-        num_terms = 3 + 9 + 27;
-    }
-  
-    R.resize(m);
-    CM.resize(m,3);
-    EC.resize(m,num_terms);
-    EC.setZero(m,num_terms);
-    std::function< void(const int) > helper;
-    helper = [&helper,
-              &P,&N,&A,&expansion_order,&point_indices,&CH,&EC,&R,&CM]
-    (const int index)-> void
-    {
-        Eigen::Matrix<real_cm,1,3> masscenter;
-        masscenter << 0,0,0;
-        Eigen::Matrix<real_ec,1,3> zeroth_expansion;
-        zeroth_expansion << 0,0,0;
-        real_p areatotal = 0.0;
-        for(int j = 0; j < point_indices.at(index).size(); j++){
-            int curr_point_index = point_indices.at(index).at(j);
-          
-            areatotal += A(curr_point_index);
-            masscenter += A(curr_point_index)*P.row(curr_point_index);
-            zeroth_expansion += A(curr_point_index)*N.row(curr_point_index);
-        }
-      
-        masscenter = masscenter/areatotal;
-        CM.row(index) = masscenter;
-        EC.block(index,0,1,3) = zeroth_expansion;
-      
-        real_r max_norm = 0;
-        real_r curr_norm;
-      
-        for(int i = 0; i < point_indices.at(index).size(); i++){
-            //Get max distance from center of mass:
-            int curr_point_index = point_indices.at(index).at(i);
-            Eigen::Matrix<real_r,1,3> point =
-                P.row(curr_point_index)-masscenter;
-            curr_norm = point.norm();
-            if(curr_norm > max_norm){
-                max_norm = curr_norm;
-            }
-          
-            //Calculate higher order terms if necessary
-            Eigen::Matrix<real_ec,3,3> TempCoeffs;
-            if(EC.cols() >= (3+9)){
-                TempCoeffs = A(curr_point_index)*point.transpose()*
-                                N.row(curr_point_index);
-                EC.block(index,3,1,9) +=
-                Eigen::Map<Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
-                                                        TempCoeffs.size());
-            }
-          
-            if(EC.cols() == (3+9+27)){
-                for(int k = 0; k < 3; k++){
-                    TempCoeffs = 0.5 * point(k) * (A(curr_point_index)*
-                                  point.transpose()*N.row(curr_point_index));
-                    EC.block(index,12+9*k,1,9) += Eigen::Map<
-                      Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
-                                                   TempCoeffs.size());
-                }
-            }
-        }
-      
-        R(index) = max_norm;
-        if(CH(index,0) != -1)
-        {
-            for(int i = 0; i < 8; i++){
-                int child = CH(index,i);
-                helper(child);
-            }
-        }
-    };
-    helper(0);
+IGL_INLINE void igl::fast_winding_number(
+  const Eigen::MatrixBase<DerivedP>& P,
+  const Eigen::MatrixBase<DerivedN>& N,
+  const Eigen::MatrixBase<DerivedA>& A,
+  const std::vector<std::vector<Index> > & point_indices,
+  const Eigen::MatrixBase<DerivedCH>& CH,
+  const int expansion_order,
+  Eigen::PlainObjectBase<DerivedCM>& CM,
+  Eigen::PlainObjectBase<DerivedR>& R,
+  Eigen::PlainObjectBase<DerivedEC>& EC)
+{
+  typedef typename DerivedP::Scalar real_p;
+  typedef typename DerivedN::Scalar real_n;
+  typedef typename DerivedA::Scalar real_a;
+  typedef typename DerivedCM::Scalar real_cm;
+  typedef typename DerivedR::Scalar real_r;
+  typedef typename DerivedEC::Scalar real_ec;
+
+  typedef Eigen::Matrix<real_p,1,3> RowVec3p;
+
+  int m = CH.size();
+  int num_terms;
+
+  assert(expansion_order < 3 && expansion_order >= 0 && "m must be less than n");
+  if(expansion_order == 0){
+      num_terms = 3;
+  } else if(expansion_order ==1){
+      num_terms = 3 + 9;
+  } else if(expansion_order == 2){
+      num_terms = 3 + 9 + 27;
   }
-  
-  template <typename DerivedP, typename DerivedA, typename DerivedN,
-  typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
-  typename DerivedEC, typename DerivedQ, typename BetaType,
-  typename DerivedWN>
-  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
-                        const Eigen::MatrixBase<DerivedN>& N,
-                        const Eigen::MatrixBase<DerivedA>& A,
-                        const std::vector<std::vector<Index> > & point_indices,
-                        const Eigen::MatrixBase<DerivedCH>& CH,
-                        const Eigen::MatrixBase<DerivedCM>& CM,
-                        const Eigen::MatrixBase<DerivedR>& R,
-                        const Eigen::MatrixBase<DerivedEC>& EC,
-                        const Eigen::MatrixBase<DerivedQ>& Q,
-                        const BetaType beta,
-                        Eigen::PlainObjectBase<DerivedWN>& WN){
-  
-    typedef typename DerivedP::Scalar real_p;
-    typedef typename DerivedN::Scalar real_n;
-    typedef typename DerivedA::Scalar real_a;
-    typedef typename DerivedCM::Scalar real_cm;
-    typedef typename DerivedR::Scalar real_r;
-    typedef typename DerivedEC::Scalar real_ec;
-    typedef typename DerivedQ::Scalar real_q;
-    typedef typename DerivedWN::Scalar real_wn;
-  
-    typedef Eigen::Matrix<real_q,1,3> RowVec;
-    typedef Eigen::Matrix<real_ec,3,3> EC_3by3;
-  
-    auto direct_eval = [](const RowVec & loc,
-                          const Eigen::Matrix<real_ec,1,3> & anorm){
-        real_wn wn = (loc(0)*anorm(0)+loc(1)*anorm(1)+loc(2)*anorm(2))
-                                    /(4.0*igl::PI*std::pow(loc.norm(),3));
-        if(std::isnan(wn)){
-            return 0.5;
-        }else{
-            return wn;
-        }
-    };
-  
-    auto expansion_eval = [&direct_eval](const RowVec & loc,
-                                         const Eigen::RowVectorXd & EC){
-      real_wn wn = direct_eval(loc,EC.head<3>());
-      double r = loc.norm();
-      if(EC.size()>3){
-        Eigen::Matrix<real_ec,3,3> SecondDerivative =
-            Eigen::Matrix<real_ec,3,3>::Identity()/(4.0*igl::PI*std::pow(r,3));
-        SecondDerivative += -3.0*loc.transpose()*loc/(4.0*igl::PI*std::pow(r,5));
-        Eigen::Matrix<real_ec,1,9> derivative_vector =
-          Eigen::Map<Eigen::Matrix<real_ec,1,9> >(SecondDerivative.data(),
-                                                  SecondDerivative.size());
-        wn += derivative_vector.cwiseProduct(EC.segment<9>(3)).sum();
+
+  R.resize(m);
+  CM.resize(m,3);
+  EC.resize(m,num_terms);
+  EC.setZero(m,num_terms);
+  std::function< void(const int) > helper;
+  helper = [&helper,
+            &P,&N,&A,&expansion_order,&point_indices,&CH,&EC,&R,&CM]
+  (const int index)-> void
+  {
+      Eigen::Matrix<real_cm,1,3> masscenter;
+      masscenter << 0,0,0;
+      Eigen::Matrix<real_ec,1,3> zeroth_expansion;
+      zeroth_expansion << 0,0,0;
+      real_p areatotal = 0.0;
+      for(int j = 0; j < point_indices[index].size(); j++){
+          int curr_point_index = point_indices[index][j];
+        
+          areatotal += A(curr_point_index);
+          masscenter += A(curr_point_index)*P.row(curr_point_index);
+          zeroth_expansion += A(curr_point_index)*N.row(curr_point_index);
       }
-      if(EC.size()>3+9){
-          Eigen::Matrix<real_ec,3,3> ThirdDerivative;
-          for(int i = 0; i < 3; i++){
-              ThirdDerivative =
-                  15.0*loc(i)*loc.transpose()*loc/(4.0*igl::PI*std::pow(r,7));
-              Eigen::Matrix<real_ec,3,3> Diagonal;
-              Diagonal << loc(i), 0, 0,
-              0, loc(i), 0,
-              0, 0, loc(i);
-              Eigen::Matrix<real_ec,3,3> RowCol;
-              RowCol.setZero(3,3);
-              RowCol.row(i) = loc;
-              Eigen::Matrix<real_ec,3,3> RowColT = RowCol.transpose();
-              RowCol = RowCol + RowColT;
-              ThirdDerivative +=
-                  -3.0/(4.0*igl::PI*std::pow(r,5))*(RowCol+Diagonal);
-              Eigen::Matrix<real_ec,1,9> derivative_vector =
-                Eigen::Map<Eigen::Matrix<real_ec,1,9> >(ThirdDerivative.data(),
-                                                        ThirdDerivative.size());
-              wn += derivative_vector.cwiseProduct(
-                                              EC.segment<9>(12 + i*9)).sum();
+    
+      masscenter = masscenter/areatotal;
+      CM.row(index) = masscenter;
+      EC.block(index,0,1,3) = zeroth_expansion;
+    
+      real_r max_norm = 0;
+      real_r curr_norm;
+    
+      for(int i = 0; i < point_indices[index].size(); i++){
+          //Get max distance from center of mass:
+          int curr_point_index = point_indices[index][i];
+          Eigen::Matrix<real_r,1,3> point =
+              P.row(curr_point_index)-masscenter;
+          curr_norm = point.norm();
+          if(curr_norm > max_norm){
+              max_norm = curr_norm;
           }
-      }
-      return wn;
-    };
-  
-    int m = Q.rows();
-    WN.resize(m,1);
-  
-    std::function< real_wn(const RowVec, const std::vector<int>) > helper;
-    helper = [&helper,
-              &P,&N,&A,
-              &point_indices,&CH,
-              &CM,&R,&EC,&beta,
-              &direct_eval,&expansion_eval]
-    (const RowVec query, const std::vector<int> near_indices)-> real_wn
-    {
-      std::vector<int> new_near_indices;
-      real_wn wn = 0;
-      for(int i = 0; i < near_indices.size(); i++){
-        int index = near_indices.at(i);
-        //Leaf Case, Brute force
-        if(CH(index,0) == -1){
-          for(int j = 0; j < point_indices.at(index).size(); j++){
-            int curr_row = point_indices.at(index).at(j);
-            wn += direct_eval(P.row(curr_row)-query,
-                              N.row(curr_row)*A(curr_row));
+        
+          //Calculate higher order terms if necessary
+          Eigen::Matrix<real_ec,3,3> TempCoeffs;
+          if(EC.cols() >= (3+9)){
+              TempCoeffs = A(curr_point_index)*point.transpose()*
+                              N.row(curr_point_index);
+              EC.block(index,3,1,9) +=
+              Eigen::Map<Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
+                                                      TempCoeffs.size());
           }
-        }
-        //Non-Leaf Case
-        else {
-          for(int child = 0; child < 8; child++){
-              int child_index = CH(index,child);
-              if(point_indices.at(child_index).size() > 0){
-                if((CM.row(child_index)-query).norm() > beta*R(child_index)){
-                  if(CH(child_index,0) == -1){
-                    for(int j=0;j<point_indices.at(child_index).size();j++){
-                      int curr_row = point_indices.at(child_index).at(j);
-                      wn += direct_eval(P.row(curr_row)-query,
-                                        N.row(curr_row)*A(curr_row));
-                    }
-                  }else{
-                    wn += expansion_eval(CM.row(child_index)-query,
-                                         EC.row(child_index));
-                  }
-                }else {
-                  new_near_indices.emplace_back(child_index);
+        
+          if(EC.cols() == (3+9+27)){
+              for(int k = 0; k < 3; k++){
+                  TempCoeffs = 0.5 * point(k) * (A(curr_point_index)*
+                                point.transpose()*N.row(curr_point_index));
+                  EC.block(index,12+9*k,1,9) += Eigen::Map<
+                    Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
+                                                 TempCoeffs.size());
               }
-            }
           }
-        }
-      }
-      if(new_near_indices.size() > 0){
-          wn += helper(query,new_near_indices);
       }
-      return wn;
-    };
-  
-  
-    if(beta > 0){
-      std::vector<int> near_indices_start = {0};
-      igl::parallel_for(m,[&](int iter){
-        WN(iter) = helper(Q.row(iter),near_indices_start);
-      },1000);
-    } else {
-      igl::parallel_for(m,[&](int iter){
-        double wn = 0;
-        for(int j = 0; j <P.rows(); j++){
-          wn += direct_eval(P.row(j)-Q.row(iter),N.row(j)*A(j));
-        }
-        WN(iter) = wn;
-      },1000);
-    }
-  }
-  
-  template <typename DerivedP, typename DerivedA, typename DerivedN,
-    typename DerivedQ, typename BetaType, typename DerivedWN>
-  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
-                                      const Eigen::MatrixBase<DerivedN>& N,
-                                      const Eigen::MatrixBase<DerivedA>& A,
-                                      const Eigen::MatrixBase<DerivedQ>& Q,
-                                      const int expansion_order,
-                                      const BetaType beta,
-                                      Eigen::PlainObjectBase<DerivedWN>& WN
-                                      ){
-    typedef typename DerivedWN::Scalar real;
     
-    std::vector<std::vector<int> > point_indices;
-    Eigen::Matrix<int,Eigen::Dynamic,8> CH;
-    Eigen::Matrix<real,Eigen::Dynamic,3> CN;
-    Eigen::Matrix<real,Eigen::Dynamic,1> W;
-  
-    octree(P,point_indices,CH,CN,W);
-  
-    Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic> EC;
-    Eigen::Matrix<real,Eigen::Dynamic,3> CM;
-    Eigen::Matrix<real,Eigen::Dynamic,1> R;
-  
-    fast_winding_number(P,N,A,point_indices,CH,expansion_order,CM,R,EC);
-    fast_winding_number(P,N,A,point_indices,CH,CM,R,EC,Q,beta,WN);
-  }
-  
-  template <typename DerivedP, typename DerivedA, typename DerivedN,
-    typename DerivedQ, typename DerivedWN>
-  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
-                                      const Eigen::MatrixBase<DerivedN>& N,
-                                      const Eigen::MatrixBase<DerivedA>& A,
-                                      const Eigen::MatrixBase<DerivedQ>& Q,
-                                      Eigen::PlainObjectBase<DerivedWN>& WN
-                                      ){
-    fast_winding_number(P,N,A,Q,2,2.0,WN);
-  }
+      R(index) = max_norm;
+      if(CH(index,0) != -1)
+      {
+          for(int i = 0; i < 8; i++){
+              int child = CH(index,i);
+              helper(child);
+          }
+      }
+  };
+  helper(0);
 }
 
+template <
+  typename DerivedP, 
+  typename DerivedA, 
+  typename DerivedN,
+  typename Index, 
+  typename DerivedCH, 
+  typename DerivedCM, 
+  typename DerivedR,
+  typename DerivedEC, 
+  typename DerivedQ, 
+  typename BetaType,
+  typename DerivedWN>
+IGL_INLINE void igl::fast_winding_number(
+  const Eigen::MatrixBase<DerivedP>& P,
+  const Eigen::MatrixBase<DerivedN>& N,
+  const Eigen::MatrixBase<DerivedA>& A,
+  const std::vector<std::vector<Index> > & point_indices,
+  const Eigen::MatrixBase<DerivedCH>& CH,
+  const Eigen::MatrixBase<DerivedCM>& CM,
+  const Eigen::MatrixBase<DerivedR>& R,
+  const Eigen::MatrixBase<DerivedEC>& EC,
+  const Eigen::MatrixBase<DerivedQ>& Q,
+  const BetaType beta,
+  Eigen::PlainObjectBase<DerivedWN>& WN)
+{
 
+  typedef typename DerivedP::Scalar real_p;
+  typedef typename DerivedN::Scalar real_n;
+  typedef typename DerivedA::Scalar real_a;
+  typedef typename DerivedCM::Scalar real_cm;
+  typedef typename DerivedR::Scalar real_r;
+  typedef typename DerivedEC::Scalar real_ec;
+  typedef typename DerivedQ::Scalar real_q;
+  typedef typename DerivedWN::Scalar real_wn;
+  const real_wn PI_4 = 4.0*igl::PI;
 
+  typedef Eigen::Matrix<
+    typename DerivedEC::Scalar,
+    1,
+    DerivedEC::ColsAtCompileTime> ECRow;
 
+  typedef Eigen::Matrix<real_q,1,3> RowVec;
+  typedef Eigen::Matrix<real_ec,3,3> EC_3by3;
 
+  auto direct_eval = [&PI_4](
+    const RowVec & loc,
+    const Eigen::Matrix<real_ec,1,3> & anorm)->real_wn
+  {
+    const typename RowVec::Scalar loc_norm = loc.norm();
+    if(loc_norm == 0)
+    {
+      return 0.5;
+    }else
+    {
+      return (loc(0)*anorm(0)+loc(1)*anorm(1)+loc(2)*anorm(2))
+                                  /(PI_4*(loc_norm*loc_norm*loc_norm));
+    }
+  };
 
+  auto expansion_eval = 
+    [&direct_eval,&EC,&PI_4](
+      const RowVec & loc,
+      const int & child_index)->real_wn
+  {
+    real_wn wn;
+    wn = direct_eval(loc,EC.row(child_index).template head<3>());
+    real_wn r = loc.norm();
+    real_wn PI_4_r3;
+    real_wn PI_4_r5;
+    real_wn PI_4_r7;
+    if(EC.row(child_index).size()>3)
+    {
+      PI_4_r3 = PI_4*r*r*r;
+      PI_4_r5 = PI_4_r3*r*r;
+      const real_ec d = 1.0/(PI_4_r3);
+      Eigen::Matrix<real_ec,3,3> SecondDerivative = 
+        loc.transpose()*loc*(-3.0/(PI_4_r5));
+      SecondDerivative(0,0) += d;
+      SecondDerivative(1,1) += d;
+      SecondDerivative(2,2) += d;
+      wn += 
+        Eigen::Map<Eigen::Matrix<real_ec,1,9> >(
+          SecondDerivative.data(),
+          SecondDerivative.size()).dot(
+            EC.row(child_index).template segment<9>(3));
+    }
+    if(EC.row(child_index).size()>3+9)
+    {
+      PI_4_r7 = PI_4_r5*r*r;
+      const Eigen::Matrix<real_ec,3,3> locTloc = loc.transpose()*(loc/(PI_4_r7));
+      for(int i = 0; i < 3; i++)
+      {
+        Eigen::Matrix<real_ec,3,3> RowCol_Diagonal = 
+          Eigen::Matrix<real_ec,3,3>::Zero(3,3);
+        for(int u = 0;u<3;u++)
+        {
+          for(int v = 0;v<3;v++)
+          {
+            if(u==v) RowCol_Diagonal(u,v) += loc(i);
+            if(u==i) RowCol_Diagonal(u,v) += loc(v);
+            if(v==i) RowCol_Diagonal(u,v) += loc(u);
+          }
+        }
+        Eigen::Matrix<real_ec,3,3> ThirdDerivative = 
+          15.0*loc(i)*locTloc + (-3.0/(PI_4_r5))*(RowCol_Diagonal);
 
+        wn += Eigen::Map<Eigen::Matrix<real_ec,1,9> >(
+                ThirdDerivative.data(),
+                ThirdDerivative.size()).dot(
+            EC.row(child_index).template segment<9>(12 + i*9));
+      }
+    }
+    return wn;
+  };
 
+  int m = Q.rows();
+  WN.resize(m,1);
 
+  std::function< real_wn(const RowVec & , const std::vector<int> &) > helper;
+  helper = [&helper,
+            &P,&N,&A,
+            &point_indices,&CH,
+            &CM,&R,&EC,&beta,
+            &direct_eval,&expansion_eval]
+  (const RowVec & query, const std::vector<int> & near_indices)-> real_wn
+  {
+    real_wn wn = 0;
+    std::vector<int> new_near_indices;
+    new_near_indices.reserve(8);
+    for(int i = 0; i < near_indices.size(); i++)
+    {
+      int index = near_indices[i];
+      //Leaf Case, Brute force
+      if(CH(index,0) == -1)
+      {
+        for(int j = 0; j < point_indices[index].size(); j++)
+        {
+          int curr_row = point_indices[index][j];
+          wn += direct_eval(P.row(curr_row)-query,
+                            N.row(curr_row)*A(curr_row));
+        }
+      }
+      //Non-Leaf Case
+      else 
+      {
+        for(int child = 0; child < 8; child++)
+        {
+          int child_index = CH(index,child);
+          if(point_indices[child_index].size() > 0)
+          {
+            const RowVec CMciq = (CM.row(child_index)-query);
+            if(CMciq.norm() > beta*R(child_index))
+            {
+              if(CH(child_index,0) == -1)
+              {
+                for(int j=0;j<point_indices[child_index].size();j++)
+                {
+                  int curr_row = point_indices[child_index][j];
+                  wn += direct_eval(P.row(curr_row)-query,
+                                    N.row(curr_row)*A(curr_row));
+                }
+              }else{
+                wn += expansion_eval(CMciq,child_index);
+              }
+            }else 
+            {
+              new_near_indices.emplace_back(child_index);
+            }
+          }
+        }
+      }
+    }
+    if(new_near_indices.size() > 0)
+    {
+      wn += helper(query,new_near_indices);
+    }
+    return wn;
+  };
 
+  if(beta > 0)
+  {
+    const std::vector<int> near_indices_start = {0};
+    igl::parallel_for(m,[&](int iter){
+      WN(iter) = helper(Q.row(iter).eval(),near_indices_start);
+    },1000);
+  } else 
+  {
+    igl::parallel_for(m,[&](int iter){
+      double wn = 0;
+      for(int j = 0; j <P.rows(); j++)
+      {
+        wn += direct_eval(P.row(j)-Q.row(iter),N.row(j)*A(j));
+      }
+      WN(iter) = wn;
+    },1000);
+  }
+}
 
+template <
+  typename DerivedP, 
+  typename DerivedA, 
+  typename DerivedN,
+  typename DerivedQ, 
+  typename BetaType, 
+  typename DerivedWN>
+IGL_INLINE void igl::fast_winding_number(
+  const Eigen::MatrixBase<DerivedP>& P,
+  const Eigen::MatrixBase<DerivedN>& N,
+  const Eigen::MatrixBase<DerivedA>& A,
+  const Eigen::MatrixBase<DerivedQ>& Q,
+  const int expansion_order,
+  const BetaType beta,
+  Eigen::PlainObjectBase<DerivedWN>& WN)
+{
+  typedef typename DerivedWN::Scalar real;
+  
+  std::vector<std::vector<int> > point_indices;
+  Eigen::Matrix<int,Eigen::Dynamic,8> CH;
+  Eigen::Matrix<real,Eigen::Dynamic,3> CN;
+  Eigen::Matrix<real,Eigen::Dynamic,1> W;
 
+  octree(P,point_indices,CH,CN,W);
 
+  Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic> EC;
+  Eigen::Matrix<real,Eigen::Dynamic,3> CM;
+  Eigen::Matrix<real,Eigen::Dynamic,1> R;
 
+  fast_winding_number(P,N,A,point_indices,CH,expansion_order,CM,R,EC);
+  fast_winding_number(P,N,A,point_indices,CH,CM,R,EC,Q,beta,WN);
+}
 
+template <
+  typename DerivedP, 
+  typename DerivedA, 
+  typename DerivedN,
+  typename DerivedQ, 
+  typename DerivedWN>
+IGL_INLINE void igl::fast_winding_number(
+  const Eigen::MatrixBase<DerivedP>& P,
+  const Eigen::MatrixBase<DerivedN>& N,
+  const Eigen::MatrixBase<DerivedA>& A,
+  const Eigen::MatrixBase<DerivedQ>& Q,
+  Eigen::PlainObjectBase<DerivedWN>& WN)
+{
+  fast_winding_number(P,N,A,Q,2,2.0,WN);
+}
 
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedQ,
+  typename DerivedW>
+IGL_INLINE void igl::fast_winding_number(
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
+  const Eigen::MatrixBase<DerivedQ> & Q,
+  Eigen::PlainObjectBase<DerivedW> & W)
+{
+  igl::FastWindingNumberBVH fwn_bvh;
+  int order = 2;
+  igl::fast_winding_number(V,F,order,fwn_bvh);
+  float accuracy_scale = 2;
+  igl::fast_winding_number(fwn_bvh,accuracy_scale,Q,W);
+}
 
+template <
+  typename DerivedV,
+  typename DerivedF>
+IGL_INLINE void igl::fast_winding_number(
+  const Eigen::MatrixBase<DerivedV> & V,
+  const Eigen::MatrixBase<DerivedF> & F,
+  const int order,
+  FastWindingNumberBVH & fwn_bvh)
+{
+  assert(V.cols() == 3 && "V should be 3D");
+  assert(F.cols() == 3 && "F should contain triangles");
+  // Extra copies. Usuually this won't be the bottleneck.
+  fwn_bvh.U.resize(V.rows());
+  for(int i = 0;i<V.rows();i++)
+  {
+    for(int j = 0;j<3;j++)
+    {
+      fwn_bvh.U[i][j] = V(i,j);
+    }
+  }
+  // Wouldn't need to copy if F is **RowMajor**
+  fwn_bvh.F.resize(F.size());
+  for(int f = 0;f<F.rows();f++)
+  {
+    for(int c = 0;c<F.cols();c++)
+    {
+      fwn_bvh.F[c+f*F.cols()] = F(f,c);
+    }
+  }
+  fwn_bvh.ut_solid_angle.clear();
+  fwn_bvh.ut_solid_angle.init(
+     fwn_bvh.F.size()/3, 
+    &fwn_bvh.F[0], 
+     fwn_bvh.U.size(), 
+    &fwn_bvh.U[0], 
+    order);
+}
 
+template <
+  typename DerivedQ,
+  typename DerivedW>
+IGL_INLINE void igl::fast_winding_number(
+  const FastWindingNumberBVH & fwn_bvh,
+  const float accuracy_scale,
+  const Eigen::MatrixBase<DerivedQ> & Q,
+  Eigen::PlainObjectBase<DerivedW> & W)
+{
+  assert(Q.cols() == 3 && "Q should be 3D");
+  W.resize(Q.rows(),1);
+  igl::parallel_for(Q.rows(),[&](int p)
+    {
+    FastWindingNumber::HDK_Sample::UT_Vector3T<float>Qp;
+          Qp[0] = Q(p,0);
+          Qp[1] = Q(p,1);
+          Qp[2] = Q(p,2);
+      W(p) = fwn_bvh.ut_solid_angle.computeSolidAngle(
+        Qp,
+        accuracy_scale) 
+        / (4.0*igl::PI);
+    },1000);
+}
 
 
-
-
-
-
-
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::fast_winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, int, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::fast_winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::fast_winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::fast_winding_number<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&, int, igl::FastWindingNumberBVH&);
+template void igl::fast_winding_number<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+template void igl::fast_winding_number<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, igl::FastWindingNumberBVH&);
+#endif

+ 134 - 37
include/igl/fast_winding_number.h

@@ -1,6 +1,7 @@
 #ifndef IGL_FAST_WINDING_NUMBER
 #define IGL_FAST_WINDING_NUMBER
 #include "igl_inline.h"
+#include "FastWindingNumberForSoups.h"
 #include <Eigen/Core>
 #include <vector>
 namespace igl
@@ -12,8 +13,8 @@ namespace igl
   // data, and an expansion order, we define a taylor series expansion at each
   // octree cell.
   //
-  // The octree data is designed to come from igl::octree, and the areas
-  // (if not obtained at scan time), may be calculated using
+  // The octree data is designed to come from igl::octree, and the areas (if not
+  // obtained at scan time), may be calculated using
   // igl::copyleft::cgal::point_areas.
   //
   // Inputs:
@@ -32,19 +33,26 @@ namespace igl
   //   EC  #OctreeCells by #TaylorCoefficients list of expansion coefficients.
   //       (Note that #TaylorCoefficients = ∑_{i=1}^{expansion_order} 3^i)
   //
-  template <typename DerivedP, typename DerivedA, typename DerivedN,
-    typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
+  // See also: igl::copyleft::cgal::point_areas, igl::knn
+  template <
+    typename DerivedP, 
+    typename DerivedA, 
+    typename DerivedN,
+    typename Index, 
+    typename DerivedCH, 
+    typename DerivedCM, 
+    typename DerivedR,
     typename DerivedEC>
-  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
-                                      const Eigen::MatrixBase<DerivedN>& N,
-                                      const Eigen::MatrixBase<DerivedA>& A,
-            const std::vector<std::vector<Index> > & point_indices,
-            const Eigen::MatrixBase<DerivedCH>& CH,
-            const int expansion_order,
-            Eigen::PlainObjectBase<DerivedCM>& CM,
-            Eigen::PlainObjectBase<DerivedR>& R,
-            Eigen::PlainObjectBase<DerivedEC>& EC);
-  
+  IGL_INLINE void fast_winding_number(
+    const Eigen::MatrixBase<DerivedP>& P,
+    const Eigen::MatrixBase<DerivedN>& N,
+    const Eigen::MatrixBase<DerivedA>& A,
+    const std::vector<std::vector<Index> > & point_indices,
+    const Eigen::MatrixBase<DerivedCH>& CH,
+    const int expansion_order,
+    Eigen::PlainObjectBase<DerivedCM>& CM,
+    Eigen::PlainObjectBase<DerivedR>& R,
+    Eigen::PlainObjectBase<DerivedEC>& EC);
   // Evaluate the fast winding number for point data, having already done the
   // the precomputation
   //
@@ -70,22 +78,45 @@ namespace igl
   // Outputs:
   //   WN  #Q by 1 list of windinng number values at each query point
   //
-  template <typename DerivedP, typename DerivedA, typename DerivedN,
-    typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
-    typename DerivedEC, typename DerivedQ, typename BetaType,
+  template <
+    typename DerivedP, 
+    typename DerivedA, 
+    typename DerivedN,
+    typename Index, 
+    typename DerivedCH, 
+    typename DerivedCM, 
+    typename DerivedR,
+    typename DerivedEC, 
+    typename DerivedQ, 
+    typename BetaType,
     typename DerivedWN>
-  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
-                                      const Eigen::MatrixBase<DerivedN>& N,
-                                      const Eigen::MatrixBase<DerivedA>& A,
-            const std::vector<std::vector<Index> > & point_indices,
-            const Eigen::MatrixBase<DerivedCH>& CH,
-            const Eigen::MatrixBase<DerivedCM>& CM,
-            const Eigen::MatrixBase<DerivedR>& R,
-            const Eigen::MatrixBase<DerivedEC>& EC,
-            const Eigen::MatrixBase<DerivedQ>& Q,
-            const BetaType beta,
-            Eigen::PlainObjectBase<DerivedWN>& WN);
-  
+  IGL_INLINE void fast_winding_number(
+    const Eigen::MatrixBase<DerivedP>& P,
+    const Eigen::MatrixBase<DerivedN>& N,
+    const Eigen::MatrixBase<DerivedA>& A,
+    const std::vector<std::vector<Index> > & point_indices,
+    const Eigen::MatrixBase<DerivedCH>& CH,
+    const Eigen::MatrixBase<DerivedCM>& CM,
+    const Eigen::MatrixBase<DerivedR>& R,
+    const Eigen::MatrixBase<DerivedEC>& EC,
+    const Eigen::MatrixBase<DerivedQ>& Q,
+    const BetaType beta,
+    Eigen::PlainObjectBase<DerivedWN>& WN);
+  template <
+    typename DerivedP, 
+    typename DerivedA, 
+    typename DerivedN,
+    typename DerivedQ, 
+    typename BetaType, 
+    typename DerivedWN>
+  IGL_INLINE void fast_winding_number(
+    const Eigen::MatrixBase<DerivedP>& P,
+    const Eigen::MatrixBase<DerivedN>& N,
+    const Eigen::MatrixBase<DerivedA>& A,
+    const Eigen::MatrixBase<DerivedQ>& Q,
+    const int expansion_order,
+    const BetaType beta,
+    Eigen::PlainObjectBase<DerivedWN>& WN);
   // Evaluate the fast winding number for point data, with default expansion
   // order and beta (both are set to 2).
   //
@@ -101,14 +132,80 @@ namespace igl
   // Outputs:
   //   WN  #Q by 1 list of windinng number values at each query point
   //
-  template <typename DerivedP, typename DerivedA, typename DerivedN,
-    typename DerivedQ, typename DerivedWN>
-  IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
-                                      const Eigen::MatrixBase<DerivedN>& N,
-                                      const Eigen::MatrixBase<DerivedA>& A,
-                                      const Eigen::MatrixBase<DerivedQ>& Q,
-                                      Eigen::PlainObjectBase<DerivedWN>& WN
-                                      );
+  template <
+    typename DerivedP, 
+    typename DerivedA, 
+    typename DerivedN,
+    typename DerivedQ, 
+    typename DerivedWN>
+  IGL_INLINE void fast_winding_number(
+    const Eigen::MatrixBase<DerivedP>& P,
+    const Eigen::MatrixBase<DerivedN>& N,
+    const Eigen::MatrixBase<DerivedA>& A,
+    const Eigen::MatrixBase<DerivedQ>& Q,
+    Eigen::PlainObjectBase<DerivedWN>& WN);
+  // Class declaration
+  namespace FastWindingNumber { namespace HDK_Sample{ template <typename T1, typename T2> class UT_SolidAngle;} }
+  struct FastWindingNumberBVH {
+    FastWindingNumber::HDK_Sample::UT_SolidAngle<float,float> ut_solid_angle;
+    // Need copies of these so they stay alive between calls.
+    std::vector<FastWindingNumber::HDK_Sample::UT_Vector3T<float> > U;
+    std::vector<int> F;
+  };
+  // Compute approximate winding number of a triangle soup mesh according to
+  // "Fast Winding Numbers for Soups and Clouds" [Barill et al. 2018].
+  //
+  // Inputs:
+  //   V  #V by 3 list of mesh vertex positions
+  //   F  #F by 3 list of triangle mesh indices into rows of V
+  //   Q  #Q by 3 list of query positions
+  // Outputs:
+  //   W  #Q list of winding number values
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedQ,
+    typename DerivedW>
+  IGL_INLINE void fast_winding_number(
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
+    const Eigen::MatrixBase<DerivedQ> & Q,
+    Eigen::PlainObjectBase<DerivedW> & W);
+  // Precomputation for computing approximate winding numbers of a triangle
+  // soup.
+  //
+  // Inputs:
+  //   V  #V by 3 list of mesh vertex positions
+  //   F  #F by 3 list of triangle mesh indices into rows of V
+  //   order  Taylor series expansion order to use (e.g., 2)
+  // Outputs:
+  //   fwn_bvh  Precomputed bounding volume hierarchy
+  //   
+  template <
+    typename DerivedV,
+    typename DerivedF>
+  IGL_INLINE void fast_winding_number(
+    const Eigen::MatrixBase<DerivedV> & V,
+    const Eigen::MatrixBase<DerivedF> & F,
+    const int order,
+    FastWindingNumberBVH & fwn_bvh);
+  // After precomputation, compute winding number at a each of many points in a
+  // list.
+  //
+  // Inputs:
+  //   fwn_bvh  Precomputed bounding volume hierarchy
+  //   accuracy_scale  parameter controlling accuracy (e.g., 2)
+  //   Q  #Q by 3 list of query positions
+  // Outputs:
+  //   W  #Q list of winding number values
+  template <
+    typename DerivedQ,
+    typename DerivedW>
+  IGL_INLINE void fast_winding_number(
+    const FastWindingNumberBVH & fwn_bvh,
+    const float accuracy_scale,
+    const Eigen::MatrixBase<DerivedQ> & Q,
+    Eigen::PlainObjectBase<DerivedW> & W);
 }
 #ifndef IGL_STATIC_LIBRARY
 #  include "fast_winding_number.cpp"

+ 42 - 16
include/igl/file_dialog_open.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2014 Daniele Panozzo <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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 "file_dialog_open.h"
 #include <cstdio>
@@ -13,7 +13,7 @@
   #include <windows.h>
   #undef max
   #undef min
-  
+
   #include <Commdlg.h>
 #endif
 
@@ -21,7 +21,9 @@ IGL_INLINE std::string igl::file_dialog_open()
 {
   const int FILE_DIALOG_MAX_BUFFER = 1024;
   char buffer[FILE_DIALOG_MAX_BUFFER];
-  
+  buffer[0] = '\0';
+  buffer[FILE_DIALOG_MAX_BUFFER - 1] = 'x'; // Initialize last character with a char != '\0'
+
 #ifdef __APPLE__
   // For apple use applescript hack
   FILE * output = popen(
@@ -32,11 +34,22 @@ IGL_INLINE std::string igl::file_dialog_open()
     "   end tell\n"
     "   set existing_file_path to (POSIX path of (existing_file))\n"
     "\" 2>/dev/null | tr -d '\n' ","r");
-  while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
+  if (output)
   {
+    auto ret = fgets(buffer, FILE_DIALOG_MAX_BUFFER, output);
+    if (ret == NULL || ferror(output))
+    {
+      // I/O error
+      buffer[0] = '\0';
+    }
+    if (buffer[FILE_DIALOG_MAX_BUFFER - 1] == '\0')
+    {
+      // File name too long, buffer has been filled, so we return empty string instead
+      buffer[0] = '\0';
+    }
   }
 #elif defined _WIN32
-  
+
   // Use native windows file dialog box
   // (code contributed by Tino Weinkauf)
 
@@ -48,7 +61,7 @@ IGL_INLINE std::string igl::file_dialog_open()
   ofn.lStructSize = sizeof(ofn);
   ofn.hwndOwner = NULL;
   ofn.lpstrFile = new char[100];
-  // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
+  // Set lpstrFile[0] to '\0' so that GetOpenFileName does not
   // use the contents of szFile to initialize itself.
   ofn.lpstrFile[0] = '\0';
   ofn.nMaxFile = sizeof(szFile);
@@ -59,7 +72,7 @@ IGL_INLINE std::string igl::file_dialog_open()
   ofn.lpstrInitialDir = NULL;
   ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
 
-  // Display the Open dialog box. 
+  // Display the Open dialog box.
   int pos = 0;
   if (GetOpenFileName(&ofn)==TRUE)
   {
@@ -68,20 +81,33 @@ IGL_INLINE std::string igl::file_dialog_open()
       buffer[pos] = (char)ofn.lpstrFile[pos];
       pos++;
     }
-  } 
+  }
   buffer[pos] = 0;
 #else
-  
+
   // For linux use zenity
   FILE * output = popen("/usr/bin/zenity --file-selection","r");
-  while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
+  if (output)
   {
+    auto ret = fgets(buffer, FILE_DIALOG_MAX_BUFFER, output);
+    if (ret == NULL || ferror(output))
+    {
+      // I/O error
+      buffer[0] = '\0';
+    }
+    if (buffer[FILE_DIALOG_MAX_BUFFER - 1] == '\0')
+    {
+      // File name too long, buffer has been filled, so we return empty string instead
+      buffer[0] = '\0';
+    }
   }
-  
-  if (strlen(buffer) > 0)
+
+  // Replace last '\n' by '\0'
+  if(strlen(buffer) > 0)
   {
-    buffer[strlen(buffer)-1] = 0;
+    buffer[strlen(buffer)-1] = '\0';
   }
+
 #endif
   return std::string(buffer);
 }

+ 38 - 11
include/igl/file_dialog_save.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2014 Daniele Panozzo <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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 "file_dialog_save.h"
 #include <cstdio>
@@ -18,6 +18,9 @@ IGL_INLINE std::string igl::file_dialog_save()
 {
   const int FILE_DIALOG_MAX_BUFFER = 1024;
   char buffer[FILE_DIALOG_MAX_BUFFER];
+  buffer[0] = '\0';
+  buffer[FILE_DIALOG_MAX_BUFFER - 1] = 'x'; // Initialize last character with a char != '\0'
+
 #ifdef __APPLE__
   // For apple use applescript hack
   // There is currently a bug in Applescript that strips extensions off
@@ -31,8 +34,19 @@ IGL_INLINE std::string igl::file_dialog_save()
     "   end tell\n"
     "   set existing_file_path to (POSIX path of (existing_file))\n"
     "\" 2>/dev/null | tr -d '\n' ","r");
-  while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
+  if (output)
   {
+    auto ret = fgets(buffer, FILE_DIALOG_MAX_BUFFER, output);
+    if (ret == NULL || ferror(output))
+    {
+      // I/O error
+      buffer[0] = '\0';
+    }
+    if (buffer[FILE_DIALOG_MAX_BUFFER - 1] == '\0')
+    {
+      // File name too long, buffer has been filled, so we return empty string instead
+      buffer[0] = '\0';
+    }
   }
 #elif defined _WIN32
 
@@ -47,7 +61,7 @@ IGL_INLINE std::string igl::file_dialog_save()
   ofn.lStructSize = sizeof(ofn);
   ofn.hwndOwner = NULL;//hwnd;
   ofn.lpstrFile = new char[100];
-  // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
+  // Set lpstrFile[0] to '\0' so that GetOpenFileName does not
   // use the contents of szFile to initialize itself.
   ofn.lpstrFile[0] = '\0';
   ofn.nMaxFile = sizeof(szFile);
@@ -58,7 +72,7 @@ IGL_INLINE std::string igl::file_dialog_save()
   ofn.lpstrInitialDir = NULL;
   ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
 
-  // Display the Open dialog box. 
+  // Display the Open dialog box.
   int pos = 0;
   if (GetSaveFileName(&ofn)==TRUE)
   {
@@ -73,14 +87,27 @@ IGL_INLINE std::string igl::file_dialog_save()
 #else
   // For every other machine type use zenity
   FILE * output = popen("/usr/bin/zenity --file-selection --save","r");
-  while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
+  if (output)
   {
+    auto ret = fgets(buffer, FILE_DIALOG_MAX_BUFFER, output);
+    if (ret == NULL || ferror(output))
+    {
+      // I/O error
+      buffer[0] = '\0';
+    }
+    if (buffer[FILE_DIALOG_MAX_BUFFER - 1] == '\0')
+    {
+      // File name too long, buffer has been filled, so we return empty string instead
+      buffer[0] = '\0';
+    }
   }
-  
-  if (strlen(buffer) > 0)
+
+  // Replace last '\n' by '\0'
+  if(strlen(buffer) > 0)
   {
-    buffer[strlen(buffer)-1] = 0;
+    buffer[strlen(buffer)-1] = '\0';
   }
+
 #endif
   return std::string(buffer);
 }

+ 14 - 14
include/igl/find_cross_field_singularities.cpp

@@ -16,9 +16,9 @@
 
 
 template <typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedO>
-IGL_INLINE void igl::find_cross_field_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
-                                                    const Eigen::PlainObjectBase<DerivedF> &F,
-                                                    const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch,
+IGL_INLINE void igl::find_cross_field_singularities(const Eigen::MatrixBase<DerivedV> &V,
+                                                    const Eigen::MatrixBase<DerivedF> &F,
+                                                    const Eigen::MatrixBase<DerivedM> &Handle_MMatch,
                                                     Eigen::PlainObjectBase<DerivedO> &isSingularity,
                                                     Eigen::PlainObjectBase<DerivedO> &singularityIndex)
 {
@@ -59,10 +59,10 @@ IGL_INLINE void igl::find_cross_field_singularities(const Eigen::PlainObjectBase
 }
 
 template <typename DerivedV, typename DerivedF, typename DerivedO>
-IGL_INLINE void igl::find_cross_field_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
-                                                    const Eigen::PlainObjectBase<DerivedF> &F,
-                                                    const Eigen::PlainObjectBase<DerivedV> &PD1,
-                                                    const Eigen::PlainObjectBase<DerivedV> &PD2,
+IGL_INLINE void igl::find_cross_field_singularities(const Eigen::MatrixBase<DerivedV> &V,
+                                                    const Eigen::MatrixBase<DerivedF> &F,
+                                                    const Eigen::MatrixBase<DerivedV> &PD1,
+                                                    const Eigen::MatrixBase<DerivedV> &PD2,
                                                     Eigen::PlainObjectBase<DerivedO> &isSingularity,
                                                     Eigen::PlainObjectBase<DerivedO> &singularityIndex,
                                                     bool isCombed)
@@ -75,11 +75,11 @@ IGL_INLINE void igl::find_cross_field_singularities(const Eigen::PlainObjectBase
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::find_cross_field_singularities<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<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> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
-template void igl::find_cross_field_singularities<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::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<int, -1, 1, 0, -1, 1> >&,
-Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
-template void igl::find_cross_field_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
-template void igl::find_cross_field_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -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> >&, bool);
-template void igl::find_cross_field_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template void igl::find_cross_field_singularities<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::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, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::find_cross_field_singularities<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<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&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::find_cross_field_singularities<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::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, Eigen::MatrixBase<Eigen::Matrix<double, -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>> &, bool);
+template void igl::find_cross_field_singularities<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, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::find_cross_field_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, Eigen::MatrixBase<Eigen::Matrix<double, -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>> &, bool);
+template void igl::find_cross_field_singularities<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, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::find_cross_field_singularities<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::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<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> >&);
 #endif

+ 7 - 7
include/igl/find_cross_field_singularities.h

@@ -25,9 +25,9 @@ namespace igl
   //   singularityIndex #V by 1 integer eigen Vector containing the singularity indices
   //
   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> &mismatch,
+  IGL_INLINE void find_cross_field_singularities(const Eigen::MatrixBase<DerivedV> &V,
+                                                 const Eigen::MatrixBase<DerivedF> &F,
+                                                 const Eigen::MatrixBase<DerivedM> &mismatch,
                                                  Eigen::PlainObjectBase<DerivedO> &isSingularity,
                                                  Eigen::PlainObjectBase<DerivedO> &singularityIndex);
 
@@ -43,10 +43,10 @@ namespace igl
   //   singularityIndex #V by 1 integer eigen Vector containing the singularity indices
   //
   template <typename DerivedV, typename DerivedF, typename DerivedO>
-  IGL_INLINE void find_cross_field_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
-                                                 const Eigen::PlainObjectBase<DerivedF> &F,
-                                                 const Eigen::PlainObjectBase<DerivedV> &PD1,
-                                                 const Eigen::PlainObjectBase<DerivedV> &PD2,
+  IGL_INLINE void find_cross_field_singularities(const Eigen::MatrixBase<DerivedV> &V,
+                                                 const Eigen::MatrixBase<DerivedF> &F,
+                                                 const Eigen::MatrixBase<DerivedV> &PD1,
+                                                 const Eigen::MatrixBase<DerivedV> &PD2,
                                                  Eigen::PlainObjectBase<DerivedO> &isSingularity,
                                                  Eigen::PlainObjectBase<DerivedO> &singularityIndex,
                                                  bool isCombed = false);

+ 4 - 4
include/igl/gaussian_curvature.cpp

@@ -11,8 +11,8 @@
 #include <iostream>
 template <typename DerivedV, typename DerivedF, typename DerivedK>
 IGL_INLINE void igl::gaussian_curvature(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
   Eigen::PlainObjectBase<DerivedK> & K)
 {
   using namespace Eigen;
@@ -51,6 +51,6 @@ IGL_INLINE void igl::gaussian_curvature(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::gaussian_curvature<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
-template void igl::gaussian_curvature<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::gaussian_curvature<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> >&);
+template void igl::gaussian_curvature<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

+ 2 - 2
include/igl/gaussian_curvature.h

@@ -22,8 +22,8 @@ namespace igl
   //
   template <typename DerivedV, typename DerivedF, typename DerivedK>
   IGL_INLINE void gaussian_curvature(
-    const Eigen::PlainObjectBase<DerivedV>& V,
-    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
     Eigen::PlainObjectBase<DerivedK> & K);
 }
 

+ 13 - 12
include/igl/harmonic.cpp

@@ -77,8 +77,8 @@ template <
   typename Derivedbc,
   typename DerivedW>
 IGL_INLINE bool igl::harmonic(
-  const Eigen::SparseMatrix<DerivedL> & L,
-  const Eigen::SparseMatrix<DerivedM> & M,
+  const Eigen::SparseCompressedBase<DerivedL> & L,
+  const Eigen::SparseCompressedBase<DerivedM> & M,
   const Eigen::MatrixBase<Derivedb> & b,
   const Eigen::MatrixBase<Derivedbc> & bc,
   const int k,
@@ -89,15 +89,16 @@ IGL_INLINE bool igl::harmonic(
   assert((k==1 || n == M.cols() ) && "M must be same size as L");
   assert((k==1 || n == M.rows() ) && "M must be square");
   assert((k==1 || igl::isdiag(M))  && "Mass matrix should be diagonal");
+  typedef typename DerivedL::Scalar Scalar;
 
-  Eigen::SparseMatrix<DerivedL> Q;
+  Eigen::SparseMatrix<Scalar> Q;
   igl::harmonic(L,M,k,Q);
 
-  typedef DerivedL Scalar;
+
   min_quad_with_fixed_data<Scalar> data;
   min_quad_with_fixed_precompute(Q,b,Eigen::SparseMatrix<Scalar>(),true,data);
   W.resize(n,bc.cols());
-  typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
+  typedef Eigen::Matrix<typename Derivedbc::Scalar,Eigen::Dynamic,1> VectorXS;
   const VectorXS B = VectorXS::Zero(n,1);
   for(int w = 0;w<bc.cols();w++)
   {
@@ -117,17 +118,17 @@ template <
   typename DerivedM,
   typename DerivedQ>
 IGL_INLINE void igl::harmonic(
-  const Eigen::SparseMatrix<DerivedL> & L,
-  const Eigen::SparseMatrix<DerivedM> & M,
+  const Eigen::SparseCompressedBase<DerivedL> & L,
+  const Eigen::SparseCompressedBase<DerivedM> & M,
   const int k,
-  Eigen::SparseMatrix<DerivedQ> & Q)
+  DerivedQ & Q)
 {
   assert(L.rows() == L.cols()&&"L should be square");
   Q = -L;
   if(k == 1) return;
   assert(L.rows() == M.rows()&&"L should match M's dimensions");
   assert(M.rows() == M.cols()&&"M should be square");
-  Eigen::SparseMatrix<DerivedM> Mi;
+  Eigen::SparseMatrix<typename DerivedM::Scalar> Mi;
   invert_diag(M,Mi);
   // This is **not** robust for k>2. See KKT system in [Jacobson et al. 2010]
   // of the kharmonic function in gptoolbox
@@ -146,9 +147,9 @@ IGL_INLINE void igl::harmonic(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedF> & F,
   const int k,
-  Eigen::SparseMatrix<DerivedQ> & Q)
+  DerivedQ & Q)
 {
-  Eigen::SparseMatrix<DerivedQ> L,M;
+  DerivedQ L,M;
   cotmatrix(V,F,L);
   if(k>1)
   {
@@ -166,7 +167,7 @@ template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Mat
 // generated by autoexplicit.sh
 template bool igl::harmonic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 // generated by autoexplicit.sh
-template void igl::harmonic<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&, int, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::SparseMatrix<double, 0, int> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::SparseMatrix<double, 0, int>&);
 // generated by autoexplicit.sh
 template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 // generated by autoexplicit.sh

+ 6 - 6
include/igl/harmonic.h

@@ -75,8 +75,8 @@ namespace igl
     typename Derivedbc,
     typename DerivedW>
   IGL_INLINE bool harmonic(
-    const Eigen::SparseMatrix<DerivedL> & L,
-    const Eigen::SparseMatrix<DerivedM> & M,
+    const Eigen::SparseCompressedBase<DerivedL> & L,
+    const Eigen::SparseCompressedBase<DerivedM> & M,
     const Eigen::MatrixBase<Derivedb> & b,
     const Eigen::MatrixBase<Derivedbc> & bc,
     const int k,
@@ -95,10 +95,10 @@ namespace igl
     typename DerivedM,
     typename DerivedQ>
   IGL_INLINE void harmonic(
-    const Eigen::SparseMatrix<DerivedL> & L,
-    const Eigen::SparseMatrix<DerivedM> & M,
+    const Eigen::SparseCompressedBase<DerivedL> & L,
+    const Eigen::SparseCompressedBase<DerivedM> & M,
     const int k,
-    Eigen::SparseMatrix<DerivedQ> & Q);
+    DerivedQ & Q);
   // Inputs:
   //   V  #V by dim vertex positions
   //   F  #F by simplex-size list of element indices
@@ -113,7 +113,7 @@ namespace igl
     const Eigen::MatrixBase<DerivedV> & V,
     const Eigen::MatrixBase<DerivedF> & F,
     const int k,
-    Eigen::SparseMatrix<DerivedQ> & Q);
+    DerivedQ & Q);
 };
 
 #ifndef IGL_STATIC_LIBRARY

+ 13 - 13
include/igl/hausdorff.cpp

@@ -1,24 +1,24 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2015 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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 "hausdorff.h"
 #include "point_mesh_squared_distance.h"
 
 template <
-  typename DerivedVA, 
+  typename DerivedVA,
   typename DerivedFA,
   typename DerivedVB,
   typename DerivedFB,
   typename Scalar>
 IGL_INLINE void igl::hausdorff(
-  const Eigen::PlainObjectBase<DerivedVA> & VA, 
-  const Eigen::PlainObjectBase<DerivedFA> & FA,
-  const Eigen::PlainObjectBase<DerivedVB> & VB, 
-  const Eigen::PlainObjectBase<DerivedFB> & FB,
+  const Eigen::MatrixBase<DerivedVA> & VA,
+  const Eigen::MatrixBase<DerivedFA> & FA,
+  const Eigen::MatrixBase<DerivedVB> & VB,
+  const Eigen::MatrixBase<DerivedFB> & FB,
   Scalar & d)
 {
   using namespace Eigen;
@@ -26,7 +26,7 @@ IGL_INLINE void igl::hausdorff(
   assert(FA.cols() == 3 && "FA should contain triangles");
   assert(VB.cols() == 3 && "VB should contain 3d points");
   assert(FB.cols() == 3 && "FB should contain triangles");
-  Matrix<Scalar,Dynamic,1> sqr_DBA,sqr_DAB;
+  Matrix<typename DerivedVA::Scalar, Dynamic, 1> sqr_DBA, sqr_DAB;
   Matrix<typename DerivedVA::Index,Dynamic,1> I;
   Matrix<typename DerivedVA::Scalar,Dynamic,3> C;
   point_mesh_squared_distance(VB,VA,FA,sqr_DBA,I,C);
@@ -73,18 +73,18 @@ IGL_INLINE void igl::hausdorff(
     d(i) = dist_to_B(V(i,0),V(i,1),V(i,2));
     // Lower bound is simply the max over vertex distances
     l = std::max(d(i),l);
-    // u1 is the minimum of corner distances + maximum adjacent edge 
+    // u1 is the minimum of corner distances + maximum adjacent edge
     u1 = std::min(u1,d(i) + std::max(e((i+1)%3),e((i+2)%3)));
     // u2 first takes the maximum over corner distances
     u2 = std::max(u2,d(i));
   }
   // u2 is the distance from the circumcenter/midpoint of obtuse edge plus the
-  // largest corner distance 
+  // largest corner distance
   u2 += (s-r>2.*R ? R : 0.5*e_max);
   u = std::min(u1,u2);
 }
 
 #ifdef IGL_STATIC_LIBRARY
-template void igl::hausdorff<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double&);
+template void igl::hausdorff<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double&);
 template void igl::hausdorff<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::function<double (double const&, double const&, double const&)> const&, double&, double&);
 #endif

+ 13 - 13
include/igl/hausdorff.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2015 Alec Jacobson <[email protected]>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// 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_HAUSDORFF_H
 #define IGL_HAUSDORFF_H
@@ -12,10 +12,10 @@
 #include <Eigen/Dense>
 #include <functional>
 
-namespace igl 
+namespace igl
 {
   // HAUSDORFF compute the Hausdorff distance between mesh (VA,FA) and mesh
-  // (VB,FB). This is the 
+  // (VB,FB). This is the
   //
   // d(A,B) = max ( max min d(a,b) , max min d(b,a) )
   //                a∈A b∈B          b∈B a∈A
@@ -29,7 +29,7 @@ namespace igl
   // the midpoint in the middle of the segment across the concavity and some
   // non-vertex point _on the edge_ of the V.
   // Known issue: due to the issue above, this also means that unreferenced
-  // vertices can give unexpected results. Therefore, we assume the inputs have 
+  // vertices can give unexpected results. Therefore, we assume the inputs have
   // no unreferenced vertices.
   //
   // Inputs:
@@ -43,16 +43,16 @@ namespace igl
   //   //  and pair(2,:) is from B
   //
   template <
-    typename DerivedVA, 
+    typename DerivedVA,
     typename DerivedFA,
     typename DerivedVB,
     typename DerivedFB,
     typename Scalar>
   IGL_INLINE void hausdorff(
-    const Eigen::PlainObjectBase<DerivedVA> & VA, 
-    const Eigen::PlainObjectBase<DerivedFA> & FA,
-    const Eigen::PlainObjectBase<DerivedVB> & VB, 
-    const Eigen::PlainObjectBase<DerivedFB> & FB,
+    const Eigen::MatrixBase<DerivedVA> & VA,
+    const Eigen::MatrixBase<DerivedFA> & FA,
+    const Eigen::MatrixBase<DerivedVB> & VB,
+    const Eigen::MatrixBase<DerivedFB> & FB,
     Scalar & d);
   // Compute lower and upper bounds (l,u) on the Hausdorff distance between a triangle
   // (V) and a pointset (e.g., mesh, triangle soup) given by a distance function
@@ -64,7 +64,7 @@ namespace igl
   //   dist_to_B  function taking the x,y,z coordinate of a query position and
   //     outputting the closest-point distance to some point-set B
   // Outputs:
-  //   l  lower bound on Hausdorff distance 
+  //   l  lower bound on Hausdorff distance
   //   u  upper bound on Hausdorff distance
   //
   template <

+ 12 - 3
include/igl/heat_geodesics.cpp

@@ -126,13 +126,22 @@ IGL_INLINE void igl::heat_geodesics_solve(
   const int m = data.Grad.rows()/data.ng;
   for(int i = 0;i<m;i++)
   {
+    // It is very important to use a stable norm calculation here. If the
+    // triangle is far from a source, then the floating point values in the
+    // gradient can be _very_ small (e.g., 1e-300). The standard/naive norm
+    // calculation will suffer from underflow. Dividing by the max value is more
+    // stable. (Eigen implements this as stableNorm or blueNorm).
     Scalar norm = 0;
+    Scalar ma = 0;
+    for(int d = 0;d<data.ng;d++) {ma = std::max(ma,std::fabs(grad_u(d*m+i)));}
     for(int d = 0;d<data.ng;d++)
     {
-      norm += grad_u(d*m+i)*grad_u(d*m+i);
+      const Scalar gui = grad_u(d*m+i) / ma;
+      norm += gui*gui;
     }
-    norm = sqrt(norm);
-    if(norm == 0)
+    norm = ma*sqrt(norm);
+    // These are probably over kill; ma==0 should be enough
+    if(ma == 0 || norm == 0 || norm!=norm)
     {
       for(int d = 0;d<data.ng;d++) { grad_u(d*m+i) = 0; }
     }else

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