Compare commits
69
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d73dc1e4e0 | ||
|
|
aacd402f73 | ||
|
|
e6a7331381 | ||
|
|
8e5aa93e62 | ||
|
|
cd73f3a4f3 | ||
|
|
ae8f959ea2 | ||
|
|
b0aa5f2a1c | ||
|
|
09e1598e6d | ||
|
|
678e1fff76 | ||
|
|
47b557df58 | ||
|
|
182e36df24 | ||
|
|
bf9bdb9c70 | ||
|
|
73a2e0de9b | ||
|
|
8866f214a0 | ||
|
|
cf9ed7f492 | ||
|
|
40e7900ccb | ||
|
|
b443ac0261 | ||
|
|
b286e13ac6 | ||
|
|
e91ffcb549 | ||
|
|
d9524ade53 | ||
|
|
89267b4a80 | ||
|
|
7c3c05d637 | ||
|
|
7888711039 | ||
|
|
08be0704c2 | ||
|
|
0e360d5250 | ||
|
|
5e561c28c8 | ||
|
|
25d63024bb | ||
|
|
f85a3c76db | ||
|
|
0c9c8cd643 | ||
|
|
a72b9386c8 | ||
|
|
ba69acc509 | ||
|
|
a221faf1e4 | ||
|
|
69e2b7ee67 | ||
|
|
667101084a | ||
|
|
7472691fe6 | ||
|
|
20c3ee0740 | ||
|
|
5067c8b7eb | ||
|
|
c2f96e8e18 | ||
|
|
f962e4a6b6 | ||
|
|
5d93f800ba | ||
|
|
8aca5bd0c4 | ||
|
|
fac5d4a01d | ||
|
|
0e02103df7 | ||
|
|
dd9654a476 | ||
|
|
01f2dc0a60 | ||
|
|
8afe66e8fd | ||
|
|
6e32964a82 | ||
|
|
dafd52343b | ||
|
|
36930e5d19 | ||
|
|
b4d8556a6b | ||
|
|
81180a6e6a | ||
|
|
a8819dcf9b | ||
|
|
1886d18147 | ||
|
|
7e6bf3b81c | ||
|
|
c7a84522c3 | ||
|
|
fe65ecb907 | ||
|
|
33a931d019 | ||
|
|
94c6afde11 | ||
|
|
8185a213d0 | ||
|
|
7d1614af1e | ||
|
|
293e79ff86 | ||
|
|
37f3b1d821 | ||
|
|
a8b3833942 | ||
|
|
7f7f0fe007 | ||
|
|
0b9030b1ed | ||
|
|
112c1b8e48 | ||
|
|
7c9387c92b | ||
|
|
1c8c6d38ba | ||
|
|
7991ee81d8 |
@@ -25,11 +25,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-latest]
|
||||
os: [ubuntu-24.04, macos-latest]
|
||||
config: [Release]
|
||||
build-params: [ {static: ON, tutorials: ON, tests: ON }, {static: OFF, tutorials: OFF, tests: ON }, {static: OFF, tutorials: ON, tests: OFF }]
|
||||
env:
|
||||
IGL_NUM_THREADS: 1 # See https://github.com/libigl/libigl/pull/996
|
||||
IGL_NUM_THREADS: 4 # don't go wild, but let the parallel_for tests do something
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v1
|
||||
@@ -52,9 +52,15 @@ jobs:
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache
|
||||
|
||||
- name: Setup Xcode version
|
||||
if: runner.os == 'macOS'
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: '16.3.0'
|
||||
|
||||
- name: Cache Build
|
||||
id: cache-build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.build-params.static }}-cache
|
||||
@@ -68,7 +74,9 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
# https://github.com/eclipse-ecal/ecal/issues/2041
|
||||
cmake .. \
|
||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.config }} \
|
||||
-DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.build-params.static }} \
|
||||
@@ -81,7 +89,7 @@ jobs:
|
||||
run: cd build; make -j2; ccache --show-stats
|
||||
|
||||
- name: Tests
|
||||
run: cd build; ctest --verbose
|
||||
run: cd build; ctest --show-only; ctest --verbose
|
||||
|
||||
####################
|
||||
# Windows
|
||||
@@ -106,6 +114,7 @@ jobs:
|
||||
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 7},
|
||||
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 8},
|
||||
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 9},
|
||||
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 10},
|
||||
]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -122,7 +131,7 @@ jobs:
|
||||
|
||||
- name: Cache build
|
||||
id: cache-build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.appdata }}\Mozilla\sccache
|
||||
key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.build-params.static }}-cache
|
||||
@@ -139,7 +148,9 @@ jobs:
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x64
|
||||
# https://github.com/eclipse-ecal/ecal/issues/2041
|
||||
cmake -G Ninja ^
|
||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 ^
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache ^
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.config }} ^
|
||||
-DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.build-params.static }} ^
|
||||
@@ -156,10 +167,11 @@ jobs:
|
||||
-DLIBIGL_TUTORIALS_CHAPTER7=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '7') && 'ON' || 'OFF' }} ^
|
||||
-DLIBIGL_TUTORIALS_CHAPTER8=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '8') && 'ON' || 'OFF' }} ^
|
||||
-DLIBIGL_TUTORIALS_CHAPTER9=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '9') && 'ON' || 'OFF' }} ^
|
||||
-DLIBIGL_TUTORIALS_CHAPTER10=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '10') && 'ON' || 'OFF' }} ^
|
||||
-B build ^
|
||||
-S .
|
||||
cmake --build build -j2
|
||||
|
||||
- name: Tests
|
||||
run: cd build; ctest --verbose -j2
|
||||
run: cd build; ctest --show-only; ctest --verbose -j2
|
||||
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ if(HUNTER_ENABLED)
|
||||
endif()
|
||||
|
||||
################################################################################
|
||||
project(libigl VERSION 2.4.0)
|
||||
project(libigl VERSION 2.5.0)
|
||||
|
||||
# CMake module path
|
||||
list(PREPEND CMAKE_MODULE_PATH
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
# Try to find the GNU Multiple Precision Arithmetic Library (GMP)
|
||||
# See http://gmplib.org/
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.18.0")
|
||||
set(REQUIRED_FLAG "")
|
||||
else()
|
||||
set(REQUIRED_FLAG REQUIRED)
|
||||
endif()
|
||||
|
||||
# On Windows, we must use the pre-compiled versions downloaded with libigl
|
||||
if(WIN32)
|
||||
set(NO_DEFAULT_FLAG NO_DEFAULT_PATH)
|
||||
else()
|
||||
set(NO_DEFAULT_FLAG "")
|
||||
endif()
|
||||
|
||||
find_path(GMP_INCLUDES
|
||||
NAMES
|
||||
gmp.h
|
||||
PATHS
|
||||
ENV GMP_DIR
|
||||
${INCLUDE_INSTALL_DIR}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
${REQUIRED_FLAG}
|
||||
${NO_DEFAULT_FLAG}
|
||||
)
|
||||
|
||||
find_library(GMP_LIBRARIES
|
||||
NAMES
|
||||
gmp
|
||||
libgmp-10
|
||||
PATHS
|
||||
ENV GMP_DIR
|
||||
${LIB_INSTALL_DIR}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
${REQUIRED_FLAG}
|
||||
${NO_DEFAULT_FLAG}
|
||||
)
|
||||
|
||||
set(GMP_EXTRA_VARS "")
|
||||
if(WIN32)
|
||||
# Find dll file and set IMPORTED_LOCATION to the .dll file
|
||||
find_file(GMP_RUNTIME_LIB
|
||||
NAMES
|
||||
gmp.dll
|
||||
libgmp-10.dll
|
||||
PATHS
|
||||
ENV GMP_DIR
|
||||
${LIB_INSTALL_DIR}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
${REQUIRED_FLAG}
|
||||
${NO_DEFAULT_FLAG}
|
||||
)
|
||||
list(APPEND GMP_EXTRA_VARS GMP_RUNTIME_LIB)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GMP
|
||||
REQUIRED_VARS
|
||||
GMP_INCLUDES
|
||||
GMP_LIBRARIES
|
||||
${GMP_EXTRA_VARS}
|
||||
REASON_FAILURE_MESSAGE
|
||||
"GMP is not installed on your system. Either install GMP using your preferred package manager, or disable libigl modules that depend on GMP, such as CGAL. See LibiglOptions.cmake.sample for configuration options. Do not forget to delete your <build>/CMakeCache.txt for the changes to take effect."
|
||||
)
|
||||
mark_as_advanced(GMP_INCLUDES GMP_LIBRARIES)
|
||||
|
||||
if(GMP_INCLUDES AND GMP_LIBRARIES AND NOT TARGET gmp::gmp)
|
||||
if(GMP_RUNTIME_LIB)
|
||||
add_library(gmp::gmp SHARED IMPORTED)
|
||||
else()
|
||||
add_library(gmp::gmp UNKNOWN IMPORTED)
|
||||
endif()
|
||||
|
||||
# Set public header location and link language
|
||||
set_target_properties(gmp::gmp PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${GMP_INCLUDES}"
|
||||
)
|
||||
|
||||
# Set lib location. On Windows we specify both the .lib and the .dll paths
|
||||
if(GMP_RUNTIME_LIB)
|
||||
set_target_properties(gmp::gmp PROPERTIES
|
||||
IMPORTED_IMPLIB "${GMP_LIBRARIES}"
|
||||
IMPORTED_LOCATION "${GMP_RUNTIME_LIB}"
|
||||
)
|
||||
else()
|
||||
set_target_properties(gmp::gmp PROPERTIES
|
||||
IMPORTED_LOCATION "${GMP_LIBRARIES}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,95 +0,0 @@
|
||||
# Try to find the MPFR library
|
||||
# See http://www.mpfr.org/
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.18.0")
|
||||
set(REQUIRED_FLAG "")
|
||||
else()
|
||||
set(REQUIRED_FLAG REQUIRED)
|
||||
endif()
|
||||
|
||||
# On Windows, we must use the pre-compiled versions downloaded with libigl
|
||||
if(WIN32)
|
||||
set(NO_DEFAULT_FLAG NO_DEFAULT_PATH)
|
||||
else()
|
||||
set(NO_DEFAULT_FLAG "")
|
||||
endif()
|
||||
|
||||
find_path(MPFR_INCLUDES
|
||||
NAMES
|
||||
mpfr.h
|
||||
PATHS
|
||||
ENV MPFR_DIR
|
||||
${INCLUDE_INSTALL_DIR}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
${REQUIRED_FLAG}
|
||||
${NO_DEFAULT_FLAG}
|
||||
)
|
||||
|
||||
find_library(MPFR_LIBRARIES
|
||||
NAMES
|
||||
mpfr
|
||||
libmpfr-4
|
||||
PATHS
|
||||
ENV MPFR_DIR
|
||||
${LIB_INSTALL_DIR}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
${REQUIRED_FLAG}
|
||||
${NO_DEFAULT_FLAG}
|
||||
)
|
||||
|
||||
set(MPFR_EXTRA_VARS "")
|
||||
if(WIN32)
|
||||
# Find dll file and set IMPORTED_LOCATION to the .dll file
|
||||
find_file(MPFR_RUNTIME_LIB
|
||||
NAMES
|
||||
mpfr.dll
|
||||
libmpfr-4.dll
|
||||
PATHS
|
||||
ENV MPFR_DIR
|
||||
${LIB_INSTALL_DIR}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
${REQUIRED_FLAG}
|
||||
${NO_DEFAULT_FLAG}
|
||||
)
|
||||
list(APPEND MPFR_EXTRA_VARS MPFR_RUNTIME_LIB)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(MPFR
|
||||
REQUIRED_VARS
|
||||
MPFR_INCLUDES
|
||||
MPFR_LIBRARIES
|
||||
${MPFR_EXTRA_VARS}
|
||||
REASON_FAILURE_MESSAGE
|
||||
"MPFR is not installed on your system. Either install MPFR using your preferred package manager, or disable libigl modules that depend on MPFR, such as CGAL. See LibiglOptions.cmake.sample for configuration options. Do not forget to delete your <build>/CMakeCache.txt for the changes to take effect."
|
||||
)
|
||||
mark_as_advanced(MPFR_INCLUDES MPFR_LIBRARIES)
|
||||
|
||||
if(MPFR_INCLUDES AND MPFR_LIBRARIES AND NOT TARGET mpfr::mpfr)
|
||||
if(MPFR_RUNTIME_LIB)
|
||||
add_library(mpfr::mpfr SHARED IMPORTED)
|
||||
else()
|
||||
add_library(mpfr::mpfr UNKNOWN IMPORTED)
|
||||
endif()
|
||||
|
||||
# Set public header location and link language
|
||||
set_target_properties(mpfr::mpfr PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${MPFR_INCLUDES}"
|
||||
)
|
||||
|
||||
# Set lib location. On Windows we specify both the .lib and the .dll paths
|
||||
if(MPFR_RUNTIME_LIB)
|
||||
set_target_properties(mpfr::mpfr PROPERTIES
|
||||
IMPORTED_IMPLIB "${MPFR_LIBRARIES}"
|
||||
IMPORTED_LOCATION "${MPFR_RUNTIME_LIB}"
|
||||
)
|
||||
else()
|
||||
set_target_properties(mpfr::mpfr PROPERTIES
|
||||
IMPORTED_LOCATION "${MPFR_LIBRARIES}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
@@ -33,8 +33,8 @@ function(igl_add_library module_name)
|
||||
target_compile_definitions(${module_name} ${IGL_SCOPE} -DIGL_STATIC_LIBRARY)
|
||||
endif()
|
||||
|
||||
# C++11 features
|
||||
target_compile_features(${module_name} ${IGL_SCOPE} cxx_std_11)
|
||||
# C++17 features
|
||||
target_compile_features(${module_name} ${IGL_SCOPE} cxx_std_17)
|
||||
|
||||
if(LIBIGL_WARNINGS_AS_ERRORS)
|
||||
target_compile_options(${module_name} PRIVATE -Wall -Wextra -Wpedantic -Wno-sign-compare -Werror -Wno-gnu -Wno-unknown-pragmas)
|
||||
|
||||
@@ -17,4 +17,13 @@ function(igl_add_tutorial name)
|
||||
)
|
||||
|
||||
set_target_properties(${name} PROPERTIES FOLDER Libigl_Tutorials)
|
||||
|
||||
# Do this codesign only on macOS
|
||||
# add_custom_command(TARGET your_target POST_BUILD COMMAND codesign -s - $<TARGET_FILE:your_target>
|
||||
if(APPLE)
|
||||
add_custom_command(TARGET ${name} POST_BUILD
|
||||
COMMAND codesign -f -s - $<TARGET_FILE:${name}>
|
||||
COMMENT "Codesigning ${name}"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -50,6 +50,10 @@ function(igl_copy_dll target)
|
||||
if(NOT WIN32)
|
||||
return()
|
||||
endif()
|
||||
if(NOT TARGET ${target})
|
||||
message(STATUS "igl_copy_dll() was called with a non-target: ${target}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Sanity checks
|
||||
get_target_property(TYPE ${target} TYPE)
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# 1. Define module
|
||||
igl_add_library(igl_copyleft_comiso)
|
||||
|
||||
# 2. Include headers
|
||||
include(GNUInstallDirs)
|
||||
target_include_directories(igl_copyleft_comiso ${IGL_SCOPE}
|
||||
$<BUILD_INTERFACE:${libigl_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
# 3. Target sources
|
||||
file(GLOB INC_FILES "${libigl_SOURCE_DIR}/include/igl/copyleft/comiso/*.h")
|
||||
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/include/igl/copyleft/comiso/*.cpp")
|
||||
igl_target_sources(igl_copyleft_comiso ${INC_FILES} ${SRC_FILES})
|
||||
|
||||
# 4. Dependencies
|
||||
include(comiso)
|
||||
igl_include(copyleft core)
|
||||
target_link_libraries(igl_copyleft_comiso ${IGL_SCOPE}
|
||||
igl::core
|
||||
igl_copyleft::core
|
||||
CoMISo::CoMISo
|
||||
)
|
||||
|
||||
# 5. Unit tests
|
||||
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/tests/include/igl/copyleft/comiso/*.cpp")
|
||||
igl_add_test(igl_copyleft_comiso ${SRC_FILES})
|
||||
@@ -25,7 +25,6 @@ igl_include_optional(xml)
|
||||
# Libigl copyleft modules
|
||||
igl_include_optional(copyleft core)
|
||||
igl_include_optional(copyleft cgal)
|
||||
igl_include_optional(copyleft comiso)
|
||||
igl_include_optional(copyleft tetgen)
|
||||
|
||||
# Libigl restricted modules
|
||||
|
||||
Vendored
+22
-26
@@ -4,32 +4,27 @@ endif()
|
||||
|
||||
message(STATUS "Third-party: creating targets 'Boost::boost'...")
|
||||
|
||||
cmake_minimum_required(VERSION 3.24) # Ensure modern FetchContent features
|
||||
project(BoostFetchExample)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
# Define the Boost library to fetch
|
||||
FetchContent_Declare(
|
||||
boost-cmake
|
||||
GIT_REPOSITORY https://github.com/Orphis/boost-cmake.git
|
||||
GIT_TAG 7f97a08b64bd5d2e53e932ddf80c40544cf45edf
|
||||
Boost
|
||||
URL https://archives.boost.io/release/1.86.0/source/boost_1_86_0.tar.gz
|
||||
URL_HASH MD5=ac857d73bb754b718a039830b07b9624
|
||||
)
|
||||
# Fetch Boost
|
||||
FetchContent_MakeAvailable(Boost)
|
||||
|
||||
set(PREVIOUS_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
set(OLD_CMAKE_POSITION_INDEPENDENT_CODE ${CMAKE_POSITION_INDEPENDENT_CODE})
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# This guy will download boost using FetchContent
|
||||
FetchContent_GetProperties(boost-cmake)
|
||||
if(NOT boost-cmake_POPULATED)
|
||||
FetchContent_Populate(boost-cmake)
|
||||
# File lcid.cpp from Boost_locale.cpp doesn't compile on MSVC, so we exclude them from the default
|
||||
# targets being built by the project (only targets explicitly used by other targets will be built).
|
||||
add_subdirectory(${boost-cmake_SOURCE_DIR} ${boost-cmake_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
# Ensure Boost paths are set before CGAL
|
||||
set(Boost_INCLUDE_DIR ${boost_SOURCE_DIR})
|
||||
set(Boost_LIBRARY_DIR ${boost_BINARY_DIR})
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ${OLD_CMAKE_POSITION_INDEPENDENT_CODE})
|
||||
set(CMAKE_CXX_FLAGS "${PREVIOUS_CMAKE_CXX_FLAGS}")
|
||||
|
||||
# Set VS target folders
|
||||
set(boost_modules
|
||||
# Add Boost libraries needed for your project
|
||||
set(BOOST_LIBRARIES
|
||||
container
|
||||
regex
|
||||
atomic
|
||||
@@ -48,6 +43,7 @@ set(boost_modules
|
||||
log_setup
|
||||
unit_test_framework
|
||||
math
|
||||
multiprecision
|
||||
program_options
|
||||
timer
|
||||
random
|
||||
@@ -55,10 +51,10 @@ set(boost_modules
|
||||
system
|
||||
thread
|
||||
type_erasure
|
||||
)
|
||||
foreach(module IN ITEMS ${boost_modules})
|
||||
if(TARGET Boost_${module})
|
||||
set_target_properties(Boost_${module} PROPERTIES FOLDER ThirdParty/Boost)
|
||||
endif()
|
||||
endforeach()
|
||||
)
|
||||
|
||||
foreach(lib IN LISTS BOOST_LIBRARIES)
|
||||
add_library(boost_${lib} INTERFACE)
|
||||
target_include_directories(boost_${lib} INTERFACE ${Boost_SOURCE_DIR})
|
||||
target_link_libraries(boost_${lib} INTERFACE Boost::${lib})
|
||||
endforeach()
|
||||
|
||||
Vendored
+6
-14
@@ -7,8 +7,8 @@ message(STATUS "Third-party: creating target 'CGAL::CGAL'")
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
cgal
|
||||
URL https://github.com/CGAL/cgal/releases/download/v5.6/CGAL-5.6-library.tar.xz
|
||||
URL_MD5 793da2d1597f3a5c0e3524f73a0b4039
|
||||
URL https://github.com/CGAL/cgal/releases/download/v6.0.1/CGAL-6.0.1-library.tar.xz
|
||||
URL_MD5 ea827f6778063e00554ae41f4c845492
|
||||
)
|
||||
FetchContent_GetProperties(cgal)
|
||||
if(cgal_POPULATED)
|
||||
@@ -29,29 +29,21 @@ function(cgal_import_target)
|
||||
set(${NAME}_ROOT ${CMAKE_CURRENT_BINARY_DIR}/${NAME} CACHE PATH "")
|
||||
endmacro()
|
||||
|
||||
include(gmp)
|
||||
include(mpfr)
|
||||
include(boost)
|
||||
|
||||
ignore_package(GMP 5.0.1)
|
||||
set(GMP_INCLUDE_DIR ${gmp_INCLUDE_DIR})
|
||||
set(GMP_LIBRARIES gmp::gmp)
|
||||
set(GMPXX_INCLUDE_DIR ${GMP_INCLUDE_DIR})
|
||||
set(GMPXX_LIBRARIES ${GMP_LIBRARIES})
|
||||
|
||||
ignore_package(MPFR 3.0.0)
|
||||
set(MPFR_INCLUDE_DIR "")
|
||||
set(MPFR_LIBRARIES mpfr::mpfr)
|
||||
|
||||
ignore_package(Boost 1.71.0)
|
||||
set(Boost_INCLUDE_DIRS "")
|
||||
set(Boost_LIBRARIES Boost::thread Boost::system)
|
||||
set(Boost_LIBRARIES Boost::thread Boost::system Boost::multiprecision)
|
||||
|
||||
# Prefer Config mode before Module mode to prevent CGAL from loading its own FindXXX.cmake
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
|
||||
|
||||
# https://stackoverflow.com/a/71714947/148668
|
||||
set(CGAL_DATA_DIR "unspecified")
|
||||
|
||||
set(CGAL_CMAKE_EXACT_NT_BACKEND "BOOST_BACKEND" CACHE STRING "CGAL exact NT backend")
|
||||
set(CGAL_DISABLE_GMP ON CACHE BOOL "Disable GMP")
|
||||
find_package(CGAL CONFIG COMPONENTS Core PATHS ${cgal_SOURCE_DIR} NO_DEFAULT_PATH)
|
||||
endfunction()
|
||||
|
||||
|
||||
Vendored
-31
@@ -1,31 +0,0 @@
|
||||
if(TARGET CoMISo::CoMISo)
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "Third-party: creating target 'CoMISo::CoMISo'")
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
comiso
|
||||
GIT_REPOSITORY https://github.com/libigl/CoMISo.git
|
||||
GIT_TAG 536440e714f412e7ef6c0b96b90ba37b1531bb39
|
||||
)
|
||||
|
||||
include(eigen)
|
||||
|
||||
FetchContent_MakeAvailable(comiso)
|
||||
|
||||
add_library(CoMISo::CoMISo ALIAS CoMISo)
|
||||
|
||||
# Copy .hh headers into a subfolder `CoMISo/`
|
||||
file(GLOB_RECURSE INC_FILES "${comiso_SOURCE_DIR}/*.hh" "${comiso_SOURCE_DIR}/*.cc")
|
||||
set(output_folder "${CMAKE_CURRENT_BINARY_DIR}/CoMISo/include/CoMISo")
|
||||
message(VERBOSE "Copying CoMISo headers to '${output_folder}'")
|
||||
foreach(filepath IN ITEMS ${INC_FILES})
|
||||
file(RELATIVE_PATH filename "${comiso_SOURCE_DIR}" ${filepath})
|
||||
configure_file(${filepath} "${output_folder}/${filename}" COPYONLY)
|
||||
endforeach()
|
||||
|
||||
target_include_directories(CoMISo PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/CoMISo/include)
|
||||
|
||||
set_target_properties(CoMISo PROPERTIES FOLDER ThirdParty)
|
||||
Vendored
+1
-1
@@ -8,7 +8,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
embree
|
||||
GIT_REPOSITORY https://github.com/embree/embree.git
|
||||
GIT_TAG v3.13.3
|
||||
GIT_TAG v4.4.0
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -8,7 +8,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
glad
|
||||
GIT_REPOSITORY https://github.com/libigl/libigl-glad.git
|
||||
GIT_TAG ead2d21fd1d9f566d8f9a9ce99ddf85829258c7a
|
||||
GIT_TAG 651a425101365aa6e8504988ef9bb363d066c5ee
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(glad)
|
||||
|
||||
Vendored
-96
@@ -1,96 +0,0 @@
|
||||
if(TARGET gmp::gmp)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Download precompiled .dll on Windows
|
||||
if(WIN32)
|
||||
include(gmp_mpfr)
|
||||
# Find_package will look for our downloaded lib on Windows, and system-wide on Linux/macOS
|
||||
find_package(GMP REQUIRED)
|
||||
else()
|
||||
message(STATUS "Third-party: creating target 'gmp::gmp'")
|
||||
|
||||
# SERIOUSLY !?! CMAKE and configure use transposed definitions of "build" and
|
||||
# "host"?
|
||||
#
|
||||
# https://cmake.org/cmake/help/latest/variable/CMAKE_SYSTEM_NAME.html#variable:CMAKE_SYSTEM_NAME
|
||||
# https://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html
|
||||
#
|
||||
# Seems these aren't to be trusted much
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/issues/20989
|
||||
if(APPLE)
|
||||
# https://gmplib.org/list-archives/gmp-discuss/2020-November/006607.html
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
|
||||
set(gmp_BUILD "x86_64-apple-darwin")
|
||||
set(gmp_HOST "arm64-apple-darwin")
|
||||
set(gmp_CFLAGS "--target=arm64-apple-darwin")
|
||||
set(gmp_LDFLAGS "-arch arm64")
|
||||
message(STATUS "GMP Recipe notices building on ${gmp_BUILD} for ${gmp_HOST}")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" AND CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64")
|
||||
set(gmp_HOST "x86_64-apple-darwin")
|
||||
set(gmp_BUILD "arm64-apple-darwin")
|
||||
set(gmp_CFLAGS "--target=x86_64-apple-darwin13.0.0")
|
||||
set(gmp_LDFLAGS "")
|
||||
message(STATUS "GMP Recipe notices building on ${gmp_HOST} for ${gmp_BUILD}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(FetchContent)
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(Ncpu)
|
||||
include(ExternalProject)
|
||||
set(prefix ${FETCHCONTENT_BASE_DIR}/gmp)
|
||||
set(gmp_INSTALL ${prefix}/install)
|
||||
set(gmp_LIB_DIR ${gmp_INSTALL}/lib)
|
||||
set(gmp_LIBRARY
|
||||
${gmp_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmp${CMAKE_STATIC_LIBRARY_SUFFIX}
|
||||
${gmp_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmpxx${CMAKE_STATIC_LIBRARY_SUFFIX}
|
||||
)
|
||||
set(gmp_INCLUDE_DIR ${gmp_INSTALL}/include)
|
||||
|
||||
# Try to use CONFIGURE_HANDLED_BY_BUILD ON to avoid constantly reconfiguring
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.20)
|
||||
# CMake < 3.20, do not use any extra option
|
||||
set(gmp_ExternalProject_Add_extra_options)
|
||||
else()
|
||||
# CMake >= 3.20
|
||||
set(gmp_ExternalProject_Add_extra_options "CONFIGURE_HANDLED_BY_BUILD;ON")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(gmp
|
||||
PREFIX ${prefix}
|
||||
URL https://github.com/alisw/GMP/archive/refs/tags/v6.2.1.tar.gz
|
||||
URL_MD5 f060ad4e762ae550d16f1bb477aadba5
|
||||
UPDATE_DISCONNECTED true # need this to avoid constant rebuild
|
||||
PATCH_COMMAND
|
||||
curl "https://gist.githubusercontent.com/alecjacobson/d34d9307c17d1b853571699b9786e9d1/raw/8d14fc21cb7654f51c2e8df4deb0f82f9d0e8355/gmp-patch" "|" git apply -v
|
||||
${gmp_ExternalProject_Add_extra_options}
|
||||
CONFIGURE_COMMAND
|
||||
${CMAKE_COMMAND} -E env
|
||||
CFLAGS=${gmp_CFLAGS}
|
||||
LDFLAGS=${gmp_LDFLAGS}
|
||||
${prefix}/src/gmp/configure
|
||||
--disable-debug --disable-dependency-tracking --enable-cxx --with-pic
|
||||
--prefix=${gmp_INSTALL}
|
||||
--build=${gmp_BUILD}
|
||||
--host=${gmp_HOST}
|
||||
--disable-shared
|
||||
BUILD_COMMAND make -j${Ncpu}
|
||||
INSTALL_COMMAND make -j${Ncpu} install
|
||||
INSTALL_DIR ${gmp_INSTALL}
|
||||
TEST_COMMAND ""
|
||||
BUILD_BYPRODUCTS ${gmp_LIBRARY}
|
||||
)
|
||||
ExternalProject_Get_Property(gmp SOURCE_DIR)
|
||||
set(gmp_LIBRARIES ${gmp_LIBRARY})
|
||||
add_library(gmp::gmp INTERFACE IMPORTED GLOBAL)
|
||||
file(MAKE_DIRECTORY ${gmp_INCLUDE_DIR}) # avoid race condition
|
||||
target_include_directories(gmp::gmp INTERFACE ${gmp_INCLUDE_DIR})
|
||||
target_link_libraries(gmp::gmp INTERFACE "${gmp_LIBRARIES}") # need the quotes to expand list
|
||||
add_dependencies(gmp::gmp gmp)
|
||||
|
||||
endif()
|
||||
|
||||
if(NOT TARGET gmp::gmp)
|
||||
message(FATAL_ERROR "Creation of target 'gmp::gmp' failed")
|
||||
endif()
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
if(WIN32)
|
||||
message(STATUS "Third-party: downloading gmp + mpfr")
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
# CGAL 5+ ships with a single .zip combining GMP + MPFR's precompiled dlls.
|
||||
# For now we still download them separately.
|
||||
|
||||
FetchContent_Declare(
|
||||
gmp
|
||||
URL https://cgal.geometryfactory.com/CGAL/precompiled_libs/auxiliary/x64/GMP/5.0.1/gmp-all-CGAL-3.9.zip
|
||||
URL_MD5 508c1292319c832609329116a8234c9f
|
||||
)
|
||||
FetchContent_MakeAvailable(gmp)
|
||||
|
||||
FetchContent_Declare(
|
||||
mpfr
|
||||
URL https://cgal.geometryfactory.com/CGAL/precompiled_libs/auxiliary/x64/MPFR/3.0.0/mpfr-all-CGAL-3.9.zip
|
||||
URL_MD5 48840454eef0ff18730050c05028734b
|
||||
)
|
||||
FetchContent_MakeAvailable(mpfr)
|
||||
|
||||
# FetchContent_Declare(
|
||||
# gmp_mpfr
|
||||
# URL https://github.com/CGAL/cgal/releases/download/v5.2.1/CGAL-5.2.1-win64-auxiliary-libraries-gmp-mpfr.zip
|
||||
# URL_MD5 247f4dca741c6b9a9be76286414070fa
|
||||
# )
|
||||
|
||||
# For CGAL
|
||||
set(ENV{GMP_DIR} "${gmp_SOURCE_DIR}")
|
||||
set(ENV{MPFR_DIR} "${mpfr_SOURCE_DIR}")
|
||||
else()
|
||||
# On Linux/macOS, gmp+mpfr will be fetched and compiled
|
||||
endif()
|
||||
+3
-3
@@ -6,13 +6,13 @@ message(STATUS "Third-party: creating target 'igl::tests_data'")
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
libigl_tests_tata
|
||||
libigl_tests_data
|
||||
GIT_REPOSITORY https://github.com/libigl/libigl-tests-data
|
||||
GIT_TAG 19cedf96d70702d8b3a83eb27934780c542356fe
|
||||
)
|
||||
FetchContent_MakeAvailable(libigl_tests_tata)
|
||||
FetchContent_MakeAvailable(libigl_tests_data)
|
||||
|
||||
add_library(igl_tests_data INTERFACE)
|
||||
add_library(igl::tests_data ALIAS igl_tests_data)
|
||||
|
||||
target_compile_definitions(igl_tests_data INTERFACE LIBIGL_DATA_DIR=\"${libigl_tests_tata_SOURCE_DIR}\")
|
||||
target_compile_definitions(igl_tests_data INTERFACE LIBIGL_DATA_DIR=\"${libigl_tests_data_SOURCE_DIR}\")
|
||||
|
||||
+3
-3
@@ -6,13 +6,13 @@ message(STATUS "Third-party: creating target 'igl::tutorial_data'")
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
libigl_tutorial_tata
|
||||
libigl_tutorial_data
|
||||
GIT_REPOSITORY https://github.com/libigl/libigl-tutorial-data
|
||||
GIT_TAG c1f9ede366d02e3531ecbaec5e3769312f31cccd
|
||||
)
|
||||
FetchContent_MakeAvailable(libigl_tutorial_tata)
|
||||
FetchContent_MakeAvailable(libigl_tutorial_data)
|
||||
|
||||
add_library(igl_tutorial_data INTERFACE)
|
||||
add_library(igl::tutorial_data ALIAS igl_tutorial_data)
|
||||
|
||||
target_compile_definitions(igl_tutorial_data INTERFACE "-DTUTORIAL_SHARED_PATH=\"${libigl_tutorial_tata_SOURCE_DIR}\"")
|
||||
target_compile_definitions(igl_tutorial_data INTERFACE "-DTUTORIAL_SHARED_PATH=\"${libigl_tutorial_data_SOURCE_DIR}\"")
|
||||
|
||||
Vendored
-91
@@ -1,91 +0,0 @@
|
||||
# Expects
|
||||
# gmp_INCLUDE_DIR
|
||||
# gmp_LIB_DIR
|
||||
# gmp_LIBRARIES
|
||||
if(TARGET mpfr::mpfr)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Download precompiled .dll on Windows
|
||||
if(WIN32)
|
||||
include(gmp_mpfr)
|
||||
# Find_package will look for our downloaded lib on Windows, and system-wide on Linux/macOS
|
||||
find_package(MPFR REQUIRED)
|
||||
else()
|
||||
message(STATUS "Third-party: creating target 'mpfr::mpfr'")
|
||||
|
||||
# Praying this will work the same as gmp
|
||||
if(APPLE)
|
||||
# https://gmplib.org/list-archives/gmp-discuss/2020-November/006607.html
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
|
||||
set(mpfr_BUILD "x86_64-apple-darwin")
|
||||
set(mpfr_HOST "arm64-apple-darwin")
|
||||
set(mpfr_CFLAGS "--target=arm64-apple-darwin")
|
||||
set(mpfr_LDFLAGS "-arch arm64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" AND CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64")
|
||||
set(mpfr_HOST "x86_64-apple-darwin")
|
||||
set(mpfr_BUILD "arm64-apple-darwin")
|
||||
set(mpfr_CFLAGS "--target=x86_64-apple-darwin13.0.0")
|
||||
set(mpfr_LDFLAGS "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(FetchContent)
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(Ncpu)
|
||||
include(ExternalProject)
|
||||
set(prefix ${FETCHCONTENT_BASE_DIR}/mpfr)
|
||||
set(mpfr_INSTALL ${prefix}/install)
|
||||
set(mpfr_LIBRARY ${mpfr_INSTALL}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}mpfr${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
set(mpfr_INCLUDE_DIR ${mpfr_INSTALL}/include)
|
||||
|
||||
# Try to use CONFIGURE_HANDLED_BY_BUILD ON to avoid constantly reconfiguring
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.20)
|
||||
# CMake < 3.20, do not use any extra option
|
||||
set(mpfr_ExternalProject_Add_extra_options)
|
||||
else()
|
||||
# CMake >= 3.20
|
||||
set(mpfr_ExternalProject_Add_extra_options "CONFIGURE_HANDLED_BY_BUILD;ON")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(mpfr
|
||||
PREFIX ${prefix}
|
||||
DEPENDS gmp
|
||||
URL https://ftp.gnu.org/gnu/mpfr/mpfr-4.2.0.tar.xz
|
||||
URL_MD5 a25091f337f25830c16d2054d74b5af7
|
||||
UPDATE_DISCONNECTED true # need this to avoid constant rebuild
|
||||
${mpfr_ExternalProject_Add_extra_options} # avoid constant reconfigure
|
||||
CONFIGURE_COMMAND
|
||||
${CMAKE_COMMAND} -E env
|
||||
CFLAGS=${gmp_CFLAGS}
|
||||
LDFLAGS=${gmp_LDFLAGS}
|
||||
${prefix}/src/mpfr/configure
|
||||
--disable-debug --disable-dependency-tracking --disable-silent-rules --enable-cxx --with-pic
|
||||
--with-gmp-include=${gmp_INCLUDE_DIR} --with-gmp-lib=${gmp_LIB_DIR}
|
||||
--disable-shared
|
||||
--prefix=${mpfr_INSTALL}
|
||||
--build=${gmp_BUILD}
|
||||
--host=${gmp_HOST}
|
||||
--disable-shared
|
||||
BUILD_COMMAND make -j${Ncpu}
|
||||
INSTALL_COMMAND make -j${Ncpu} install
|
||||
INSTALL_DIR ${mpfr_INSTALL}
|
||||
TEST_COMMAND ""
|
||||
BUILD_BYPRODUCTS ${mpfr_LIBRARY}
|
||||
)
|
||||
#PATCH_COMMAND curl "https://raw.githubusercontent.com/Homebrew/formula-patches/03cf8088210822aa2c1ab544ed58ea04c897d9c4/libtool/configure-big_sur.diff" "|" sed -e "s/configure.orig/configure/g" "|" git apply -v
|
||||
ExternalProject_Get_Property(mpfr SOURCE_DIR)
|
||||
set(mpfr_LIBRARIES ${mpfr_LIBRARY})
|
||||
add_library(mpfr::mpfr INTERFACE IMPORTED GLOBAL)
|
||||
file(MAKE_DIRECTORY ${mpfr_INCLUDE_DIR}) # avoid race condition
|
||||
target_include_directories(mpfr::mpfr INTERFACE ${mpfr_INCLUDE_DIR})
|
||||
target_link_libraries(mpfr::mpfr INTERFACE "${mpfr_LIBRARIES}") # need the quotes to expand list
|
||||
# This is necessary to ensure that mpfr appears before gmp in link order.
|
||||
# Otherwise undefined reference errors occur at link time on Linux with gcc
|
||||
target_link_libraries(mpfr::mpfr INTERFACE "${gmp_LIBRARIES}")
|
||||
add_dependencies(mpfr::mpfr mpfr)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET mpfr::mpfr)
|
||||
message(FATAL_ERROR "Creation of target 'mpfr::mpfr' failed")
|
||||
endif()
|
||||
+1
-1
@@ -8,7 +8,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
predicates
|
||||
GIT_REPOSITORY https://github.com/libigl/libigl-predicates.git
|
||||
GIT_TAG 488242fa2b1f98a9c5bd1441297fb4a99a6a9ae4
|
||||
GIT_TAG decb7bc1260e689cbe008109e3cc5d3a5a433aea
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(predicates)
|
||||
|
||||
Vendored
+1
-1
@@ -8,7 +8,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
tetgen
|
||||
GIT_REPOSITORY https://github.com/libigl/tetgen.git
|
||||
GIT_TAG 4f3bfba3997f20aa1f96cfaff604313a8c2c85b6
|
||||
GIT_TAG e05aca7df74e3f531bc35733ed87d36d437266c5
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(tetgen)
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
triangle
|
||||
GIT_REPOSITORY https://github.com/libigl/triangle.git
|
||||
GIT_TAG 3ee6cac2230f0fe1413879574f741c7b6da11221
|
||||
GIT_TAG 62f02db9ab4ff4b62d5ff82a77c8ea458c84c23a
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(triangle)
|
||||
|
||||
+845
-208
File diff suppressed because it is too large
Load Diff
+483
-121
@@ -1,15 +1,16 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_AABB_H
|
||||
#define IGL_AABB_H
|
||||
|
||||
#include "Hit.h"
|
||||
#include "igl_inline.h"
|
||||
#include <cassert>
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
#include <vector>
|
||||
@@ -26,9 +27,12 @@ namespace igl
|
||||
/// @tparam DerivedV Matrix type of vertex positions (e.g., `Eigen::MatrixXd`)
|
||||
/// @tparam DIM Dimension of mesh vertex positions (2 or 3)
|
||||
template <typename DerivedV, int DIM>
|
||||
class AABB
|
||||
class AABB
|
||||
{
|
||||
public:
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Member variables
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Scalar type of vertex positions (e.g., `double`)
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
/// Fixed-size (`DIM`) RowVector type using `Scalar`
|
||||
@@ -39,29 +43,35 @@ public:
|
||||
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,DIM> MatrixXDIMS;
|
||||
/// Pointer to "left" child node (`nullptr` if leaf)
|
||||
// Shared pointers are slower...
|
||||
AABB * m_left;
|
||||
AABB * m_left;
|
||||
/// Pointer to "right" child node (`nullptr` if leaf)
|
||||
AABB * m_right;
|
||||
/// Pointer to "parent" node (`nullptr` if root)
|
||||
AABB * m_parent;
|
||||
/// Axis-Aligned Bounding Box containing this node
|
||||
Eigen::AlignedBox<Scalar,DIM> m_box;
|
||||
/// Index of single primitive in this node if full leaf, otherwise -1 for non-leaf
|
||||
int m_primitive;
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Non-templated member functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//Scalar m_low_sqr_d;
|
||||
//int m_depth;
|
||||
/// @private
|
||||
AABB():
|
||||
m_left(NULL), m_right(NULL),
|
||||
m_left(nullptr), m_right(nullptr),m_parent(nullptr),
|
||||
m_box(), m_primitive(-1)
|
||||
//m_low_sqr_d(std::numeric_limits<double>::infinity()),
|
||||
//m_depth(0)
|
||||
{
|
||||
static_assert(DerivedV::ColsAtCompileTime == DIM || DerivedV::ColsAtCompileTime == Eigen::Dynamic,"DerivedV::ColsAtCompileTime == DIM || DerivedV::ColsAtCompileTime == Eigen::Dynamic");
|
||||
}
|
||||
{
|
||||
static_assert(DerivedV::ColsAtCompileTime == DIM || DerivedV::ColsAtCompileTime == Eigen::Dynamic,"DerivedV::ColsAtCompileTime == DIM || DerivedV::ColsAtCompileTime == Eigen::Dynamic");
|
||||
}
|
||||
/// @private
|
||||
// http://stackoverflow.com/a/3279550/148668
|
||||
AABB(const AABB& other):
|
||||
m_left(other.m_left ? new AABB(*other.m_left) : NULL),
|
||||
m_right(other.m_right ? new AABB(*other.m_right) : NULL),
|
||||
m_left (other.m_left ? new AABB(*other.m_left) : nullptr),
|
||||
m_right(other.m_right ? new AABB(*other.m_right) : nullptr),
|
||||
m_parent(other.m_parent),
|
||||
m_box(other.m_box),
|
||||
m_primitive(other.m_primitive)
|
||||
//m_low_sqr_d(other.m_low_sqr_d),
|
||||
@@ -69,6 +79,8 @@ public:
|
||||
// m_left ? m_left->m_depth + 1 : 0,
|
||||
// m_right ? m_right->m_depth + 1 : 0))
|
||||
{
|
||||
if(m_left) { m_left->m_parent = this; }
|
||||
if(m_right) { m_right->m_parent = this; }
|
||||
}
|
||||
/// @private
|
||||
// copy-swap idiom
|
||||
@@ -78,6 +90,7 @@ public:
|
||||
using std::swap;
|
||||
swap(first.m_left,second.m_left);
|
||||
swap(first.m_right,second.m_right);
|
||||
swap(first.m_parent,second.m_parent);
|
||||
swap(first.m_box,second.m_box);
|
||||
swap(first.m_primitive,second.m_primitive);
|
||||
//swap(first.m_low_sqr_d,second.m_low_sqr_d);
|
||||
@@ -93,44 +106,381 @@ public:
|
||||
/// @private
|
||||
AABB(AABB&& other):
|
||||
// initialize via default constructor
|
||||
AABB()
|
||||
AABB()
|
||||
{
|
||||
swap(*this,other);
|
||||
}
|
||||
/// @private
|
||||
// Seems like there should have been an elegant solution to this using
|
||||
// the copy-swap idiom above:
|
||||
IGL_INLINE void deinit()
|
||||
IGL_INLINE void clear()
|
||||
{
|
||||
m_primitive = -1;
|
||||
m_box = Eigen::AlignedBox<Scalar,DIM>();
|
||||
delete m_left;
|
||||
m_left = NULL;
|
||||
m_left = nullptr;
|
||||
delete m_right;
|
||||
m_right = NULL;
|
||||
m_right = nullptr;
|
||||
// Tell my parent I'm dead
|
||||
if(m_parent)
|
||||
{
|
||||
if(m_parent->m_left == this)
|
||||
{
|
||||
m_parent->m_left = nullptr;
|
||||
}else if(m_parent->m_right == this)
|
||||
{
|
||||
m_parent->m_right = nullptr;
|
||||
}else
|
||||
{
|
||||
assert(false && "I'm not my parent's child");
|
||||
}
|
||||
auto * grandparent = m_parent->m_parent;
|
||||
if(grandparent)
|
||||
{
|
||||
// Before
|
||||
// grandparent
|
||||
// ╱ ╲
|
||||
// parent pibling
|
||||
// ╱ ╲
|
||||
// sibling this
|
||||
//
|
||||
// After
|
||||
// grandparent
|
||||
// ╱ ╲
|
||||
// sibling® pibling
|
||||
}else
|
||||
{
|
||||
// Before
|
||||
// parent=root
|
||||
// ╱ ╲
|
||||
// sibling this
|
||||
//
|
||||
// After
|
||||
// grandparent
|
||||
// ╱ ╲
|
||||
// sibling® pibling
|
||||
}
|
||||
}
|
||||
// Now my parent is dead to me.
|
||||
m_parent = nullptr;
|
||||
}
|
||||
/// @private
|
||||
~AABB()
|
||||
{
|
||||
deinit();
|
||||
clear();
|
||||
}
|
||||
/// Return whether at leaf node
|
||||
IGL_INLINE bool is_leaf() const;
|
||||
/// Return whether at root node
|
||||
IGL_INLINE bool is_root() const;
|
||||
/// Return the root node of this node's tree by following its parent
|
||||
IGL_INLINE AABB<DerivedV,DIM>* root() const;
|
||||
IGL_INLINE AABB<DerivedV,DIM>* detach();
|
||||
IGL_INLINE void refit_lineage();
|
||||
/// Get a vector of leaves indexed by their m_primitive id (these better
|
||||
/// be non-negative and tightly packed.
|
||||
/// @param[in] m number of leaves/elements (Ele.rows())
|
||||
/// @returns leaves m list of pointers to leaves
|
||||
IGL_INLINE std::vector<AABB<DerivedV,DIM>*> gather_leaves(const int m);
|
||||
/// \overload where m is the max m_primitive id in the tree.
|
||||
IGL_INLINE std::vector<AABB<DerivedV,DIM>*> gather_leaves();
|
||||
/// Pad leaves by `pad` in each dimension
|
||||
/// @param[in] pad padding amount
|
||||
/// @param[in] polish_rotate_passes number of passes to polish rotations
|
||||
/// @returns pointer to (potentially new) root
|
||||
IGL_INLINE AABB<DerivedV,DIM>* pad(
|
||||
const std::vector<AABB<DerivedV,DIM>*> & leaves,
|
||||
const Scalar pad,
|
||||
const int polish_rotate_passes=0);
|
||||
/// @returns `this` if no update was needed, otherwise returns pointer to
|
||||
/// (potentially new) root
|
||||
///
|
||||
/// Example:
|
||||
/// ```cpp
|
||||
/// auto * up = leaf->update(new_box);
|
||||
/// if(up != leaf)
|
||||
/// {
|
||||
/// tree = up->root();
|
||||
/// }else
|
||||
/// {
|
||||
/// printf("no update occurred\n");
|
||||
/// }
|
||||
///
|
||||
/// // or simply
|
||||
/// tree = leaf->update(new_box)->root();
|
||||
/// ```
|
||||
IGL_INLINE AABB<DerivedV,DIM>* update(
|
||||
const Eigen::AlignedBox<Scalar,DIM> & new_box,
|
||||
const Scalar pad=0);
|
||||
/// Insert a (probably a leaf) AABB `other` into this AABB tree. If
|
||||
/// `other`'s box is contained in this AABB's box then insert it as a child recursively.
|
||||
///
|
||||
/// If `other`'s box is not contained in this AABB's box then insert it as a
|
||||
/// sibling.
|
||||
///
|
||||
/// It's a very good idea to call either `rotate` (faster, less good) or `rotate_lineage` (slower, better)
|
||||
/// after insertion. Rotating continues to improve the tree's quality so
|
||||
/// after doing a bunch of insertions you might even consider calling
|
||||
/// `rotate` on all nodes.
|
||||
///
|
||||
/// `insert` attempts to minimize total internal surface area. Where as
|
||||
/// `init` is top-down and splits boxes based on the median along the
|
||||
/// longest dimension. When initializing a tree, `init` seems to result in
|
||||
/// great trees (small height and small total internal surface area).
|
||||
///
|
||||
/// @param[in] other pointer to another AABB node
|
||||
/// @returns pointer to the parent of `other` or `other` itself. This
|
||||
/// could be == to a `new`ly created internal node or to `other` if
|
||||
/// `this==other`. Calling ->root() on this returned node will give you
|
||||
/// the root of the tree.
|
||||
///
|
||||
/// ##### Example
|
||||
///
|
||||
/// ```cpp
|
||||
/// // Create a tree (use pointer to track changes to root)
|
||||
/// auto * tree = new igl::AABB<DerivedV,3>::AABB();
|
||||
/// // Fill the tree (e.g., using ->init())
|
||||
/// …
|
||||
/// // Create a new leafe node
|
||||
/// auto * leaf = new igl::AABB<DerivedV,3>::AABB();
|
||||
/// // Fill the leaf node with a primitive and box
|
||||
/// …
|
||||
/// // Insert into the tree and find the possibly new root
|
||||
/// tree = tree->insert(leaf)->root();
|
||||
/// ```
|
||||
IGL_INLINE AABB<DerivedV,DIM>* insert(AABB * other);
|
||||
/// Insert `other` as a sibling to `this` by creating a new internal node
|
||||
/// to be their shared parent.
|
||||
///
|
||||
/// Before
|
||||
/// parent
|
||||
/// ╱ ╲
|
||||
/// this(C) sibling
|
||||
/// ╱ ╲
|
||||
/// left right
|
||||
///
|
||||
/// After
|
||||
/// parent
|
||||
/// ╱ ╲
|
||||
/// newbie sibling
|
||||
/// ╱ ╲
|
||||
/// this other
|
||||
/// ╱ ╲
|
||||
/// left right
|
||||
///
|
||||
///
|
||||
/// @param[in] other pointer to another AABB node
|
||||
/// @returns pointer to the new shared parent.
|
||||
IGL_INLINE AABB<DerivedV,DIM>* insert_as_sibling(AABB * other);
|
||||
/// Try to swap this node with its close relatives if it will decrease
|
||||
/// total internal surface area.
|
||||
///
|
||||
///
|
||||
/// grandparent
|
||||
/// ╱ ╲
|
||||
/// parent pibling°
|
||||
/// ╱ ╲ ╱ ╲
|
||||
/// sibling this cuz1° cuz2°
|
||||
/// ╱ ╲
|
||||
/// nib1° nib2°
|
||||
///
|
||||
/// °Swap Candidates
|
||||
///
|
||||
/// @param[in] dry_run if true then don't actually swap
|
||||
/// @return[in] the change in total internal surface area, 0 if no
|
||||
/// improvement and rotate won't be carried out.
|
||||
IGL_INLINE Scalar rotate(const bool dry_run = false);
|
||||
/// Try to swap this node with its cousins if it will decrease
|
||||
/// total internal surface area.
|
||||
///
|
||||
/// @param[in] dry_run if true then don't actually swap
|
||||
/// @return[in] the change in total internal surface area, 0 if no
|
||||
/// improvement and rotate won't be carried out.
|
||||
///
|
||||
/// Before
|
||||
/// grandparent
|
||||
/// ╱ ╲
|
||||
/// parent pibling
|
||||
/// ╱ ╲ ╱ ╲
|
||||
/// sibling this cuz1 cuz2
|
||||
///
|
||||
///
|
||||
/// Candidates
|
||||
/// grandparent
|
||||
/// ╱ ╲
|
||||
/// parent pibling
|
||||
/// ╱ ╲ ╱ ╲
|
||||
/// sibling cuz1 this cuz2
|
||||
///
|
||||
/// Or
|
||||
/// grandparent
|
||||
/// ╱ ╲
|
||||
/// parent pibling
|
||||
/// ╱ ╲ ╱ ╲
|
||||
/// sibling cuz2 cuz1 this
|
||||
IGL_INLINE Scalar rotate_across(const bool dry_run = false);
|
||||
/// Try to swap this node with its pibling if it will decrease
|
||||
/// total internal surface area.
|
||||
///
|
||||
/// @param[in] dry_run if true then don't actually swap
|
||||
/// @return[in] the change in total internal surface area, 0 if no
|
||||
/// improvement and rotate won't be carried out.
|
||||
///
|
||||
/// Before
|
||||
/// grandparent
|
||||
/// ╱ ╲
|
||||
/// other parent
|
||||
/// ╱ ╲
|
||||
/// this sibling
|
||||
///
|
||||
///
|
||||
/// Candidate
|
||||
/// grandparent
|
||||
/// ╱ ╲
|
||||
/// this parent
|
||||
/// ╱ ╲
|
||||
/// other sibling
|
||||
IGL_INLINE Scalar rotate_up(const bool dry_run = false);
|
||||
/// Try to swap this node with one of its niblings if it will decrease
|
||||
/// total internal surface area.
|
||||
///
|
||||
/// @param[in] dry_run if true then don't actually swap
|
||||
/// @return[in] the change in total internal surface area, 0 if no
|
||||
/// improvement and rotate won't be carried out.
|
||||
///
|
||||
/// Before
|
||||
/// parent
|
||||
/// ╱ ╲
|
||||
/// this sibling
|
||||
/// ╱ ╲
|
||||
/// left right
|
||||
///
|
||||
///
|
||||
/// Candidates
|
||||
/// parent
|
||||
/// ╱ ╲
|
||||
/// left sibling
|
||||
/// ╱ ╲
|
||||
/// this right
|
||||
///
|
||||
/// Or
|
||||
///
|
||||
/// parent
|
||||
/// ╱ ╲
|
||||
/// right sibling
|
||||
/// ╱ ╲
|
||||
/// left this
|
||||
IGL_INLINE Scalar rotate_down(const bool dry_run = false);
|
||||
/// "Rotate" (swap) `reining` with `challenger`.
|
||||
///
|
||||
/// Before
|
||||
/// grandparent
|
||||
/// ╱ ╲
|
||||
/// reining parent
|
||||
/// ╱ ╲
|
||||
/// challenger sibling
|
||||
///
|
||||
///
|
||||
/// Candidate
|
||||
/// grandparent
|
||||
/// ╱ ╲
|
||||
/// challenger parent
|
||||
/// ╱ ╲
|
||||
/// reining sibling
|
||||
/// @param[in] reining pointer to AABB node to be rotated
|
||||
/// @param[in] grandparent pointer to challenger's grandparent
|
||||
/// @param[in] parent pointer to challenger's parent
|
||||
/// @param[in] challenger pointer to AABB node to be rotated
|
||||
/// @param[in] sibling pointer to challenger's sibling
|
||||
/// @returns true only if rotation was possible and successfully carried
|
||||
/// out.
|
||||
static IGL_INLINE Scalar rotate_up(
|
||||
const bool dry_run,
|
||||
AABB<DerivedV,DIM>* reining,
|
||||
AABB<DerivedV,DIM>* grandparent,
|
||||
AABB<DerivedV,DIM>* parent,
|
||||
AABB<DerivedV,DIM>* challenger,
|
||||
AABB<DerivedV,DIM>* sibling);
|
||||
// Should this be a static function with an argument?
|
||||
IGL_INLINE void rotate_lineage();
|
||||
/// Number of nodes contained in subtree (is it?)
|
||||
///
|
||||
/// \note At best, this function has a dubious name. This is really an
|
||||
/// internal helper function for the serialization.
|
||||
///
|
||||
/// \see size()
|
||||
///
|
||||
/// @return Number of elements m then total tree size should be 2*h where h is
|
||||
/// the deepest depth 2^ceil(log(#Ele*2-1))
|
||||
IGL_INLINE int subtree_size() const;
|
||||
/// @param[in] box query box
|
||||
/// @param[in,out] leaves list of leaves to append to
|
||||
IGL_INLINE bool append_intersecting_leaves(
|
||||
const Eigen::AlignedBox<Scalar,DIM> & box,
|
||||
std::vector<const AABB<DerivedV,DIM>*> & leaves) const;
|
||||
/// Compute sum of surface area of all internal (non-root, non-leaf) boxes
|
||||
IGL_INLINE typename DerivedV::Scalar internal_surface_area() const;
|
||||
/// Validate the subtree under this node by running a bunch of assertions.
|
||||
/// Does nothing when not in debug mode
|
||||
IGL_INLINE void validate() const;
|
||||
/// print the memory addresses of the tree in a somewhat legible way
|
||||
IGL_INLINE void print(const int depth = 0) const;
|
||||
/// @returns Actual size of tree. Total number of nodes in tree. A singleton root
|
||||
/// has size 1.
|
||||
///
|
||||
/// \see subtree_size
|
||||
IGL_INLINE int size() const;
|
||||
/// @returns Height of the tree. A singleton root has height 1.
|
||||
IGL_INLINE int height() const;
|
||||
private:
|
||||
/// If new distance (sqr_d_candidate) is less than current distance
|
||||
/// (sqr_d), then update this distance and its associated values
|
||||
/// _in-place_:
|
||||
///
|
||||
/// @param[in] p dim-long query point (only used in DEBUG mode)
|
||||
/// @param[in] sqr_d candidate minimum distance for this query, see
|
||||
/// output
|
||||
/// @param[in] i candidate index into Ele of closest point, see output
|
||||
/// @param[in] c dim-long candidate closest point, see output
|
||||
/// @param[in] sqr_d current minimum distance for this query, see output
|
||||
/// @param[in] i current index into Ele of closest point, see output
|
||||
/// @param[in] c dim-long current closest point, see output
|
||||
/// @param[out] sqr_d minimum of initial value and squared distance to
|
||||
/// this primitive
|
||||
/// @param[out] i possibly updated index into Ele of closest point
|
||||
/// @param[out] c dim-long possibly updated closest point
|
||||
IGL_INLINE void set_min(
|
||||
const RowVectorDIMS & p,
|
||||
const Scalar sqr_d_candidate,
|
||||
const int & i_candidate,
|
||||
const RowVectorDIMS & c_candidate,
|
||||
Scalar & sqr_d,
|
||||
int & i,
|
||||
Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
|
||||
public:
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Templated member functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Build an Axis-Aligned Bounding Box tree for a given mesh and given
|
||||
/// serialization of a previous AABB tree.
|
||||
///
|
||||
/// @param[in] V #V by dim list of mesh vertex positions.
|
||||
/// @param[in] Ele #Ele by dim+1 list of mesh indices into #V.
|
||||
/// @param[in] bb_mins max_tree by dim list of bounding box min corner positions
|
||||
/// @param[in] bb_maxs max_tree by dim list of bounding box max corner positions
|
||||
/// @param[in] elements max_tree list of element or (not leaf id) indices into Ele
|
||||
/// @param[in] V #V by dim list of mesh vertex positions.
|
||||
/// @param[in] Ele #Ele by dim+1 list of mesh indices into #V.
|
||||
/// @param[in] bb_mins max_tree by dim list of bounding box min corner
|
||||
/// positions
|
||||
/// @param[in] bb_maxs max_tree by dim list of bounding box max corner
|
||||
/// positions
|
||||
/// @param[in] elements max_tree list of element or (not leaf id) indices
|
||||
/// into Ele
|
||||
/// @param[in] i recursive call index {0}
|
||||
template <
|
||||
typename DerivedEle,
|
||||
typename Derivedbb_mins,
|
||||
typename DerivedEle,
|
||||
typename Derivedbb_mins,
|
||||
typename Derivedbb_maxs,
|
||||
typename Derivedelements>
|
||||
IGL_INLINE void init(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<Derivedbb_mins> & bb_mins,
|
||||
const Eigen::MatrixBase<Derivedbb_maxs> & bb_maxs,
|
||||
const Eigen::MatrixBase<Derivedelements> & elements,
|
||||
@@ -138,62 +488,65 @@ public:
|
||||
/// Build an Axis-Aligned Bounding Box tree for a given mesh and given
|
||||
/// serialization of a previous AABB tree.
|
||||
///
|
||||
/// @param[in] V #V by dim list of mesh vertex positions.
|
||||
/// @param[in] Ele #Ele by dim+1 list of mesh indices into #V.
|
||||
/// @param[in] V #V by dim list of mesh vertex positions.
|
||||
/// @param[in] Ele #Ele by dim+1 list of mesh indices into #V.
|
||||
template <typename DerivedEle>
|
||||
IGL_INLINE void init(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele);
|
||||
/// Build an Axis-Aligned Bounding Box tree for a given mesh.
|
||||
///
|
||||
/// @param[in] V #V by dim list of mesh vertex positions.
|
||||
/// @param[in] Ele #Ele by dim+1 list of mesh indices into #V.
|
||||
/// @param[in] SI #Ele by dim list revealing for each coordinate where Ele's
|
||||
/// barycenters would be sorted: SI(e,d) = i --> the dth coordinate of
|
||||
/// the barycenter of the eth element would be placed at position i in a
|
||||
/// sorted list.
|
||||
/// @param[in] I #I list of indices into Ele of elements to include (for recursive
|
||||
/// calls)
|
||||
///
|
||||
/// @param[in] V #V by dim list of mesh vertex positions.
|
||||
/// @param[in] Ele #Ele by dim+1 list of mesh indices into #V.
|
||||
/// @param[in] SI #Ele by dim list revealing for each coordinate where
|
||||
/// Ele's barycenters would be sorted: SI(e,d) = i --> the dth
|
||||
/// coordinate of the barycenter of the eth element would be placed at
|
||||
/// position i in a sorted list.
|
||||
/// @param[in] I #I list of indices into Ele of elements to include (for
|
||||
/// recursive calls)
|
||||
///
|
||||
template <typename DerivedEle, typename DerivedSI, typename DerivedI>
|
||||
IGL_INLINE void init(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedSI> & SI,
|
||||
const Eigen::MatrixBase<DerivedI>& I);
|
||||
/// Return whether at leaf node
|
||||
IGL_INLINE bool is_leaf() const;
|
||||
/// @returns `this` if no update was needed, otherwise returns pointer to
|
||||
/// (potentially new) root
|
||||
template <typename DerivedEle>
|
||||
IGL_INLINE AABB<DerivedV,DIM>* update_primitive(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Scalar pad=0);
|
||||
|
||||
/// Find the indices of elements containing given point: this makes sense
|
||||
/// when Ele is a co-dimension 0 simplex (tets in 3D, triangles in 2D).
|
||||
///
|
||||
/// @param[in] V #V by dim list of mesh vertex positions. **Should be same as used to
|
||||
/// construct mesh.**
|
||||
/// @param[in] Ele #Ele by dim+1 list of mesh indices into #V. **Should be same as used to
|
||||
/// construct mesh.**
|
||||
/// @param[in] V #V by dim list of mesh vertex positions. **Should be
|
||||
/// same as used to construct mesh.**
|
||||
/// @param[in] Ele #Ele by dim+1 list of mesh indices into #V. **Should
|
||||
/// be same as used to construct mesh.**
|
||||
/// @param[in] q dim row-vector query position
|
||||
/// @param[in] first whether to only return first element containing q
|
||||
/// @return list of indices of elements containing q
|
||||
template <typename DerivedEle, typename Derivedq>
|
||||
IGL_INLINE std::vector<int> find(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<Derivedq> & q,
|
||||
const bool first=false) const;
|
||||
|
||||
/// Number of nodes contained in subtree
|
||||
///
|
||||
/// @return Number of elements m then total tree size should be 2*h where h is
|
||||
/// the deepest depth 2^ceil(log(#Ele*2-1))
|
||||
IGL_INLINE int subtree_size() const;
|
||||
|
||||
/// Serialize this class into 3 arrays (so we can pass it pack to matlab)
|
||||
///
|
||||
/// @param[out] bb_mins max_tree by dim list of bounding box min corner positions
|
||||
/// @param[out] bb_maxs max_tree by dim list of bounding box max corner positions
|
||||
/// @param[out] elements max_tree list of element or (not leaf id) indices into Ele
|
||||
/// @param[out] bb_mins max_tree by dim list of bounding box min corner
|
||||
/// positions
|
||||
/// @param[out] bb_maxs max_tree by dim list of bounding box max corner
|
||||
/// positions
|
||||
/// @param[out] elements max_tree list of element or (not leaf id)
|
||||
/// indices into Ele
|
||||
/// @param[in] i recursive call index into these arrays {0}
|
||||
template <
|
||||
typename Derivedbb_mins,
|
||||
typename Derivedbb_mins,
|
||||
typename Derivedbb_maxs,
|
||||
typename Derivedelements>
|
||||
IGL_INLINE void serialize(
|
||||
@@ -205,7 +558,7 @@ public:
|
||||
///
|
||||
/// @param[in] V #V by dim list of vertex positions
|
||||
/// @param[in] Ele #Ele by dim list of simplex indices
|
||||
/// @param[in] p dim-long query point
|
||||
/// @param[in] p dim-long query point
|
||||
/// @param[out] i facet index corresponding to smallest distances
|
||||
/// @param[out] c closest point
|
||||
/// @return squared distance
|
||||
@@ -215,7 +568,7 @@ public:
|
||||
template <typename DerivedEle>
|
||||
IGL_INLINE Scalar squared_distance(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const RowVectorDIMS & p,
|
||||
int & i,
|
||||
Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
|
||||
@@ -224,12 +577,12 @@ public:
|
||||
///
|
||||
/// @param[in] V #V by dim list of vertex positions
|
||||
/// @param[in] Ele #Ele by dim list of simplex indices
|
||||
/// @param[in] p dim-long query point
|
||||
/// @param[in] low_sqr_d lower bound on squared distance, specified maximum squared
|
||||
/// distance
|
||||
/// @param[in] up_sqr_d current upper bounded on squared distance, current minimum
|
||||
/// squared distance (only consider distances less than this), see
|
||||
/// output.
|
||||
/// @param[in] p dim-long query point
|
||||
/// @param[in] low_sqr_d lower bound on squared distance, specified
|
||||
/// maximum squared distance
|
||||
/// @param[in] up_sqr_d current upper bounded on squared distance,
|
||||
/// current minimum squared distance (only consider distances less than
|
||||
/// this), see output.
|
||||
/// @param[out] i facet index corresponding to smallest distances
|
||||
/// @param[out] c closest point
|
||||
/// @return squared distance
|
||||
@@ -239,7 +592,7 @@ public:
|
||||
template <typename DerivedEle>
|
||||
IGL_INLINE Scalar squared_distance(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const RowVectorDIMS & p,
|
||||
const Scalar low_sqr_d,
|
||||
const Scalar up_sqr_d,
|
||||
@@ -249,10 +602,10 @@ public:
|
||||
///
|
||||
/// @param[in] V #V by dim list of vertex positions
|
||||
/// @param[in] Ele #Ele by dim list of simplex indices
|
||||
/// @param[in] p dim-long query point
|
||||
/// @param[in] up_sqr_d current upper bounded on squared distance, current minimum
|
||||
/// squared distance (only consider distances less than this), see
|
||||
/// output.
|
||||
/// @param[in] p dim-long query point
|
||||
/// @param[in] up_sqr_d current upper bounded on squared distance,
|
||||
/// current minimum squared distance (only consider distances less than
|
||||
/// this), see output.
|
||||
/// @param[out] i facet index corresponding to smallest distances
|
||||
/// @param[out] c closest point
|
||||
/// @return squared distance
|
||||
@@ -260,7 +613,7 @@ public:
|
||||
template <typename DerivedEle>
|
||||
IGL_INLINE Scalar squared_distance(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const RowVectorDIMS & p,
|
||||
const Scalar up_sqr_d,
|
||||
int & i,
|
||||
@@ -276,10 +629,10 @@ public:
|
||||
template <typename DerivedEle>
|
||||
IGL_INLINE bool intersect_ray(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const RowVectorDIMS & origin,
|
||||
const RowVectorDIMS & dir,
|
||||
std::vector<igl::Hit> & hits) const;
|
||||
std::vector<igl::Hit<typename DerivedV::Scalar>> & hits) const;
|
||||
/// Intersect a ray with the mesh return first hit
|
||||
///
|
||||
/// @param[in] V #V by dim list of vertex positions
|
||||
@@ -291,10 +644,11 @@ public:
|
||||
template <typename DerivedEle>
|
||||
IGL_INLINE bool intersect_ray(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const RowVectorDIMS & origin,
|
||||
const RowVectorDIMS & dir,
|
||||
igl::Hit & hit) const;
|
||||
igl::Hit<typename DerivedV::Scalar> & hit) const;
|
||||
|
||||
/// Intersect a ray with the mesh return first hit farther than `min_t`
|
||||
///
|
||||
/// @param[in] V #V by dim list of vertex positions
|
||||
@@ -307,13 +661,48 @@ public:
|
||||
template <typename DerivedEle>
|
||||
IGL_INLINE bool intersect_ray(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const RowVectorDIMS & origin,
|
||||
const RowVectorDIMS & dir,
|
||||
const Scalar min_t,
|
||||
igl::Hit & hit) const;
|
||||
|
||||
public:
|
||||
igl::Hit<typename DerivedV::Scalar> & hit) const;
|
||||
/// Intersect a rays with the mesh return first hit for each
|
||||
///
|
||||
/// @param[in] V #V by dim list of vertex positions
|
||||
/// @param[in] Ele #Ele by dim list of simplex indices
|
||||
/// @param[in] origin #ray by dim+1 list of ray origins
|
||||
/// @param[in] dir #ray by dim list of ray directions
|
||||
/// @param[in] min_t minimum t value to consider
|
||||
/// @param[out] I #ray list of indices into Ele of closest primitives
|
||||
/// (-1 indicates no hit)
|
||||
/// @param[out] T #ray list of t values (nan indicates no hit)
|
||||
/// @param[out] UV #ray by dim list of barycentric coordinates
|
||||
template <
|
||||
typename DerivedEle,
|
||||
typename DerivedOrigin,
|
||||
typename DerivedDir,
|
||||
typename DerivedI,
|
||||
typename DerivedT,
|
||||
typename DerivedUV>
|
||||
IGL_INLINE void intersect_ray(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedOrigin> & origin,
|
||||
const Eigen::MatrixBase<DerivedDir> & dir,
|
||||
const Scalar min_t,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedT> & T,
|
||||
Eigen::PlainObjectBase<DerivedUV> & UV);
|
||||
template <
|
||||
typename DerivedEle,
|
||||
typename DerivedOrigin,
|
||||
typename DerivedDir>
|
||||
IGL_INLINE void intersect_ray(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedOrigin> & origin,
|
||||
const Eigen::MatrixBase<DerivedDir> & dir,
|
||||
std::vector<std::vector<igl::Hit<typename DerivedV::Scalar>>> & hits);
|
||||
/// Compute the squared distance from all query points in P to the
|
||||
/// _closest_ points on the primitives stored in the AABB hierarchy for
|
||||
/// the mesh (V,Ele).
|
||||
@@ -326,18 +715,17 @@ public:
|
||||
/// @param[out] C #P by dim list of closest points
|
||||
template <
|
||||
typename DerivedEle,
|
||||
typename DerivedP,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE void squared_distance(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedP> & P,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedC> & C) const;
|
||||
|
||||
/// Compute the squared distance from all query points in P already stored
|
||||
/// in its own AABB hierarchy to the _closest_ points on the primitives
|
||||
/// stored in the AABB hierarchy for the mesh (V,Ele).
|
||||
@@ -351,36 +739,36 @@ public:
|
||||
/// @param[out] sqrD #P list of squared distances
|
||||
/// @param[out] I #P list of indices into Ele of closest primitives
|
||||
/// @param[out] C #P by dim list of closest points
|
||||
template <
|
||||
template <
|
||||
typename DerivedEle,
|
||||
typename Derivedother_V,
|
||||
typename Derivedother_Ele,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE void squared_distance(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const AABB<Derivedother_V,DIM> & other,
|
||||
const Eigen::MatrixBase<Derivedother_V> & other_V,
|
||||
const Eigen::MatrixBase<Derivedother_Ele> & other_Ele,
|
||||
const Eigen::MatrixBase<Derivedother_Ele> & other_Ele,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedC> & C) const;
|
||||
private:
|
||||
template <
|
||||
template <
|
||||
typename DerivedEle,
|
||||
typename Derivedother_V,
|
||||
typename Derivedother_Ele,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE Scalar squared_distance_helper(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const AABB<Derivedother_V,DIM> * other,
|
||||
const Eigen::MatrixBase<Derivedother_V> & other_V,
|
||||
const Eigen::MatrixBase<Derivedother_Ele>& other_Ele,
|
||||
const Eigen::MatrixBase<Derivedother_Ele>& other_Ele,
|
||||
const Scalar up_sqr_d,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
@@ -403,7 +791,7 @@ private:
|
||||
template <typename DerivedEle>
|
||||
IGL_INLINE void leaf_squared_distance(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const RowVectorDIMS & p,
|
||||
const Scalar low_sqr_d,
|
||||
Scalar & sqr_d,
|
||||
@@ -413,37 +801,11 @@ private:
|
||||
template <typename DerivedEle>
|
||||
IGL_INLINE void leaf_squared_distance(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const RowVectorDIMS & p,
|
||||
Scalar & sqr_d,
|
||||
int & i,
|
||||
Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
|
||||
// If new distance (sqr_d_candidate) is less than current distance
|
||||
// (sqr_d), then update this distance and its associated values
|
||||
// _in-place_:
|
||||
//
|
||||
// Inputs:
|
||||
// p dim-long query point (only used in DEBUG mode)
|
||||
// sqr_d candidate minimum distance for this query, see output
|
||||
// i candidate index into Ele of closest point, see output
|
||||
// c dim-long candidate closest point, see output
|
||||
// sqr_d current minimum distance for this query, see output
|
||||
// i current index into Ele of closest point, see output
|
||||
// c dim-long current closest point, see output
|
||||
// Outputs:
|
||||
// sqr_d minimum of initial value and squared distance to this
|
||||
// primitive
|
||||
// i possibly updated index into Ele of closest point
|
||||
// c dim-long possibly updated closest point
|
||||
IGL_INLINE void set_min(
|
||||
const RowVectorDIMS & p,
|
||||
const Scalar sqr_d_candidate,
|
||||
const int i_candidate,
|
||||
const RowVectorDIMS & c_candidate,
|
||||
Scalar & sqr_d,
|
||||
int & i,
|
||||
Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
|
||||
|
||||
/// Intersect a ray with the mesh return all hits
|
||||
///
|
||||
/// @param[in] V #V by dim list of vertex positions
|
||||
@@ -460,7 +822,7 @@ private:
|
||||
const RowVectorDIMS & dir,
|
||||
const RowVectorDIMS & inv_dir,
|
||||
const RowVectorDIMS & inv_dir_pad,
|
||||
std::vector<igl::Hit> & hits) const;
|
||||
std::vector<igl::Hit<typename DerivedV::Scalar>> & hits) const;
|
||||
/// Intersect a ray with the mesh return first hit farther than `min_t`
|
||||
///
|
||||
/// @param[in] V #V by dim list of vertex positions
|
||||
@@ -479,7 +841,7 @@ private:
|
||||
const RowVectorDIMS & inv_dir,
|
||||
const RowVectorDIMS & inv_dir_pad,
|
||||
const Scalar min_t,
|
||||
igl::Hit & hit) const;
|
||||
igl::Hit<typename DerivedV::Scalar> & hit) const;
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2025 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_COLLAPSE_EDGE_NULL_H
|
||||
#define IGL_COLLAPSE_EDGE_NULL_H
|
||||
namespace igl
|
||||
{
|
||||
#ifndef IGL_COLLAPSE_EDGE_NULL
|
||||
/// Special value for indicating a null vertex index as the result of a
|
||||
/// collapsed edge.
|
||||
#define IGL_COLLAPSE_EDGE_NULL 0
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -84,6 +84,7 @@
|
||||
#include <type_traits>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace igl {
|
||||
/// @private
|
||||
|
||||
@@ -63,10 +63,10 @@ IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::isBorder()
|
||||
/*!
|
||||
* Returns the next edge skipping the border
|
||||
* _________
|
||||
* /\ c | b /\
|
||||
* / \ | / \
|
||||
* / d \ | / a \
|
||||
* /______\|/______\
|
||||
* ╱╲ c | b ╱╲
|
||||
* ╱ ╲ | ╱ ╲
|
||||
* ╱ d ╲ | ╱ a ╲
|
||||
* ╱______╲|╱______╲
|
||||
* v
|
||||
* In this example, if a and d are of-border and the pos is iterating counterclockwise, this method iterate through the faces incident on vertex v,
|
||||
* producing the sequence a, b, c, d, a, b, c, ...
|
||||
|
||||
@@ -69,10 +69,10 @@ namespace igl
|
||||
|
||||
/// Change to next edge skipping the border
|
||||
/// _________
|
||||
/// /\ c | b /\
|
||||
/// / \ | / \
|
||||
/// / d \ | / a \
|
||||
/// /______\|/______\
|
||||
/// ╱╲ c | b ╱╲
|
||||
/// ╱ ╲ | ╱ ╲
|
||||
/// ╱ d ╲ | ╱ a ╲
|
||||
/// ╱______╲|╱______╲
|
||||
/// v
|
||||
/// In this example, if a and d are of-border and the pos is iterating
|
||||
/// counterclockwise, this method iterate through the faces incident on vertex
|
||||
|
||||
+3
-3
@@ -13,7 +13,7 @@ namespace igl
|
||||
{
|
||||
/// Reimplementation of the embree::Hit struct from embree1.0
|
||||
///
|
||||
// TODO: template on floating point type
|
||||
template <typename Scalar>
|
||||
struct Hit
|
||||
{
|
||||
/// primitive id
|
||||
@@ -22,10 +22,10 @@ namespace igl
|
||||
int gid;
|
||||
/// barycentric coordinates so that
|
||||
/// pos = V.row(F(id,0))*(1-u-v)+V.row(F(id,1))*u+V.row(F(id,2))*v;
|
||||
float u,v;
|
||||
Scalar u,v;
|
||||
/// parametric distance so that
|
||||
/// pos = origin + t * dir
|
||||
float t;
|
||||
Scalar t;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2024 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_PLAINMATRIX_H
|
||||
#define IGL_PLAINMATRIX_H
|
||||
#include <Eigen/Core>
|
||||
|
||||
#include <type_traits>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
// Define void_t for compatibility if it's not in the standard library (C++11 and later)
|
||||
#if __cplusplus < 201703L
|
||||
namespace std {
|
||||
template <typename... Ts>
|
||||
using void_t = void;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef IGL_DEFAULT_MAJORING
|
||||
#define IGL_DEFAULT_MAJORING Eigen::ColMajor
|
||||
#endif
|
||||
|
||||
namespace igl
|
||||
{
|
||||
template <typename Derived, int Rows, int Cols, int Options>
|
||||
struct PlainMatrixHelper {
|
||||
using Type = Eigen::Matrix<typename Derived::Scalar,Rows,Cols,((Rows == 1 && Cols != 1) ? Eigen::RowMajor : ((Cols == 1 && Rows != 1) ? Eigen::ColMajor : Options))>;
|
||||
};
|
||||
template <typename Derived, typename = void>
|
||||
struct get_options {
|
||||
static constexpr int value = IGL_DEFAULT_MAJORING;
|
||||
};
|
||||
|
||||
template <typename Derived>
|
||||
struct get_options<Derived, std::void_t<decltype(Derived::Options)>> {
|
||||
static constexpr int value = Derived::Options;
|
||||
};
|
||||
/// Some libigl implementations would (still do?) use a pattern like:
|
||||
///
|
||||
/// template <typename DerivedA>
|
||||
/// void foo(const Eigen::MatrixBase<DerivedA>& A)
|
||||
/// {
|
||||
/// DerivedA B;
|
||||
/// igl::unique_rows(A,true,B);
|
||||
/// }
|
||||
///
|
||||
/// If `DerivedA` is `Eigen::Matrix`, then this may compile, but `DerivedA` might be
|
||||
/// from a Eigen::Map or Eigen::Ref and fail to compile due to missing
|
||||
/// construtor.
|
||||
///
|
||||
/// Even worse, the code above will work if `DerivedA` has dynamic rows, but will
|
||||
/// throw a runtime error if `DerivedA` has fixed number of rows.
|
||||
///
|
||||
/// Instead it's better to declare `B` as a `Eigen::Matrix`
|
||||
///
|
||||
/// Eigen::Matrix<typename DerivedA::Scalar,Eigen::Dynamic,DerivedA::ColsAtCompileTime,DerivedA::Options> B;
|
||||
///
|
||||
/// Using `Eigen::Dynamic` for dimensions that may not be known at compile
|
||||
/// time (or may be different from A).
|
||||
///
|
||||
/// `igl::PlainMatrix` is just a helper to make this easier. So in this case
|
||||
/// we could write:
|
||||
///
|
||||
/// igl::PlainMatrix<DerivedA,Eigen::Dynamic> B;
|
||||
///
|
||||
/// IIUC, if the code in question looks like:
|
||||
///
|
||||
/// template <typename DerivedC>
|
||||
/// void foo(Eigen::PlainObjectBase<DerivedC>& C)
|
||||
/// {
|
||||
/// DerivedC B;
|
||||
/// …
|
||||
/// C.resize(not_known_at_compile_time,also_not_known_at_compile_time);
|
||||
/// }
|
||||
///
|
||||
/// Then it's probably fine. If C can be resized to different sizes, then
|
||||
/// `DerivedC` should be `Eigen::Matrix`-like .
|
||||
// Helper to check if `Options` exists in Derived
|
||||
|
||||
// Modify PlainMatrix to use get_options
|
||||
template <typename Derived,
|
||||
int Rows = Derived::RowsAtCompileTime,
|
||||
int Cols = Derived::ColsAtCompileTime,
|
||||
int Options = get_options<Derived>::value>
|
||||
using PlainMatrix = typename PlainMatrixHelper<Derived, Rows, Cols, Options>::Type;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2024 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_PLAINVECTOR_H
|
||||
#define IGL_PLAINVECTOR_H
|
||||
#include <Eigen/Core>
|
||||
#include "PlainMatrix.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// PlainVectorHelper to determine correct matrix type based on Derived and Size
|
||||
template <typename Derived, int Size, int Options>
|
||||
struct PlainVectorHelper {
|
||||
// Conditional Type: Column vector if is_column_vector is true, otherwise row vector
|
||||
using Type = Eigen::Matrix<
|
||||
typename Derived::Scalar,
|
||||
(Derived::ColsAtCompileTime == 1 && Derived::RowsAtCompileTime != 1) ? Size : 1,
|
||||
(Derived::ColsAtCompileTime == 1 && Derived::RowsAtCompileTime != 1) ? 1 : Size,
|
||||
Options>;
|
||||
};
|
||||
|
||||
/// \see PlainMatrix
|
||||
template <
|
||||
typename Derived,
|
||||
int Size = (Derived::ColsAtCompileTime == 1 && Derived::RowsAtCompileTime != 1) ? Derived::RowsAtCompileTime : Derived::ColsAtCompileTime,
|
||||
int Options = get_options<Derived>::value>
|
||||
using PlainVector = typename PlainVectorHelper<Derived, Size, Options>::Type;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2025 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "SphereMeshWedge.h"
|
||||
#include "round_cone_signed_distance.h"
|
||||
#include "sign.h"
|
||||
#include <Eigen/QR>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
template <typename Scalar>
|
||||
IGL_INLINE igl::SphereMeshWedge<Scalar>::SphereMeshWedge(
|
||||
const RowVector3S & V0,
|
||||
const RowVector3S & V1,
|
||||
const RowVector3S & V2,
|
||||
const Scalar r0,
|
||||
const Scalar r1,
|
||||
const Scalar r2)
|
||||
{
|
||||
// Internal copy
|
||||
V.row(0) = V0;
|
||||
V.row(1) = V1;
|
||||
V.row(2) = V2;
|
||||
r(0) = r0;
|
||||
r(1) = r1;
|
||||
r(2) = r2;
|
||||
|
||||
flavor = FULL;
|
||||
// By default use full
|
||||
|
||||
EV.row(0) = V.row(2) - V.row(1);
|
||||
EV.row(1) = V.row(0) - V.row(2);
|
||||
EV.row(2) = V.row(1) - V.row(0);
|
||||
l = EV.rowwise().norm();
|
||||
l2 = l.array().square();
|
||||
rr << r(1) - r(2), r(2) - r(0), r(0) - r(1);
|
||||
a2 = l2.array() - rr.array().square();
|
||||
il2 = 1.0/l2.array();
|
||||
|
||||
/////////////////////////////////////////////
|
||||
/// BIG_VERTEX ?
|
||||
/////////////////////////////////////////////
|
||||
{
|
||||
r.maxCoeff(&max_i);
|
||||
int j = (max_i+1)%3;
|
||||
int k = (max_i+2)%3;
|
||||
if((l(k) + r(j) < r(max_i)) && (l(j) + r(k) < r(max_i)))
|
||||
{
|
||||
flavor = BIG_VERTEX;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
/// BIG_EDGE ?
|
||||
/////////////////////////////////////////////
|
||||
if(flavor == FULL)
|
||||
{
|
||||
// Case where one edge's roundCone containes the others
|
||||
for(int e = 0;e<3;e++)
|
||||
{
|
||||
const int i = (e+1)%3;
|
||||
const int j = (e+2)%3;
|
||||
const int k = (e+3)%3;
|
||||
const Scalar s =
|
||||
igl::round_cone_signed_distance(V.row(k),V.row(i),V.row(j),r(i),r(j));
|
||||
if(-s > r(k))
|
||||
{
|
||||
flavor = BIG_EDGE;
|
||||
max_i = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(flavor == FULL && !compute_planes())
|
||||
{
|
||||
flavor = NO_TRIANGLE;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
IGL_INLINE Scalar igl::SphereMeshWedge<Scalar>::operator()(const RowVector3S & p) const
|
||||
{
|
||||
if(flavor == BIG_VERTEX)
|
||||
{
|
||||
// Case 0: Vertex i
|
||||
return (p - V.row(max_i)).norm() - r(max_i);
|
||||
}
|
||||
|
||||
if(flavor == BIG_EDGE)
|
||||
{
|
||||
const int i = max_i;
|
||||
const int j = (i+1)%3;
|
||||
// Case 1: Edge e
|
||||
return this->round_cone_signed_distance(p,i,j);
|
||||
}
|
||||
|
||||
Scalar s = std::numeric_limits<Scalar>::infinity();
|
||||
if(flavor == FULL)
|
||||
{
|
||||
// This is possibly the bottleneck and could be turned into precomputed
|
||||
// plane equations.
|
||||
|
||||
// signed distance to triangle plane (this is immediately recomputed later in
|
||||
// sdSkewedExtrudedTriangle...)
|
||||
const auto plane_sdf = [](
|
||||
const RowVector3S & p,
|
||||
const Eigen::RowVector4d & plane)
|
||||
{
|
||||
return plane.head<3>().dot(p) + plane(3);
|
||||
};
|
||||
Scalar d0 = plane_sdf(p, planes.row(0));
|
||||
Scalar planes_s = -std::abs(d0);
|
||||
// Reflect if necessary so that q is always on negative side of plane
|
||||
RowVector3S q = p - (d0 - planes_s) * planes.row(0).template head<3>();
|
||||
// Other planes (for negative side slab, by symmetry)
|
||||
for(int i = 1;i<planes.rows();i++)
|
||||
{
|
||||
planes_s = std::max(planes_s,plane_sdf(q, planes.row(i)));
|
||||
}
|
||||
// This produces correct interior distance
|
||||
if(planes_s <= 0)
|
||||
{
|
||||
s = std::min(s,planes_s);
|
||||
}else
|
||||
{
|
||||
|
||||
const auto & nor = planes.row(1).template head<3>();
|
||||
const RowVector3S q0 = q - T.row(0);
|
||||
const RowVector3S q1 = q - T.row(1);
|
||||
const RowVector3S q2 = q - T.row(2);
|
||||
|
||||
if(!(sign(C.row(0).dot(q0)) +
|
||||
sign(C.row(1).dot(q1)) +
|
||||
sign(C.row(2).dot(q2))<2.0))
|
||||
{
|
||||
s = std::min(s,planes_s);
|
||||
}
|
||||
}
|
||||
|
||||
//s = std::min(s,sdSkewedExtrudedTriangle(q,V,T));
|
||||
//s = std::min(s,sdSkewedExtrudedTriangle(p,B,V));
|
||||
}
|
||||
assert(flavor == FULL || flavor == NO_TRIANGLE);
|
||||
|
||||
for(int e = 0;e<3;e++)
|
||||
{
|
||||
const int i = (e+1)%3;
|
||||
const int j = (e+2)%3;
|
||||
s = std::min(s,this->round_cone_signed_distance(p,i,j));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
IGL_INLINE bool igl::SphereMeshWedge<Scalar>::compute_planes()
|
||||
{
|
||||
// Non-degenerate case
|
||||
const RowVector3S & a = V.row(0);
|
||||
const RowVector3S & b = V.row(1);
|
||||
const RowVector3S & c = V.row(2);
|
||||
const Scalar & ra = r(0);
|
||||
const Scalar & rb = r(1);
|
||||
const Scalar & rc = r(2);
|
||||
Eigen::Matrix<Scalar,2,3,Eigen::RowMajor> A;
|
||||
A<<
|
||||
b-a,
|
||||
c-a;
|
||||
const Eigen::Vector2d d(rb-ra,rc-ra);
|
||||
const RowVector3S N = (A.row(0).cross(A.row(1))).normalized();
|
||||
//const Eigen::CompleteOrthogonalDecomposition<decltype(A)> cod(A);
|
||||
const RowVector3S n0 = A.completeOrthogonalDecomposition().solve(d);
|
||||
const Scalar qA = N.squaredNorm();
|
||||
// qB is zeros by construction. We could delete all terms involving qB
|
||||
// It's not even clear if keeping them would lead to more accurate results.
|
||||
const Scalar qB = 2 * N.dot(n0);
|
||||
const Scalar qC = n0.squaredNorm() - 1;
|
||||
const Scalar qD = qB*qB - 4*qA*qC;
|
||||
|
||||
if(qD<0) { return false; }
|
||||
|
||||
Scalar t_sol_1 = (-qB + std::sqrt(qD)) / (2*qA);
|
||||
RowVector3S n1 = -(t_sol_1 * N + n0);
|
||||
T = V + r * n1;
|
||||
|
||||
const auto plane_equation = [](
|
||||
const RowVector3S & a,
|
||||
const RowVector3S & b,
|
||||
const RowVector3S & c)->Eigen::RowVector4d
|
||||
{
|
||||
RowVector3S n = (b-a).cross(c-a).normalized();
|
||||
n.normalize();
|
||||
Scalar d = -n.dot(a);
|
||||
return Eigen::RowVector4d(n(0),n(1),n(2),d);
|
||||
};
|
||||
|
||||
planes.row(0) = plane_equation(V.row(0),V.row(1),V.row(2));
|
||||
planes.row(1) = plane_equation(T.row(2),T.row(1),T.row(0));
|
||||
planes.row(2) = plane_equation(V.row(1),V.row(0),T.row(0));
|
||||
planes.row(3) = plane_equation(V.row(2),V.row(1),T.row(1));
|
||||
planes.row(4) = plane_equation(V.row(0),V.row(2),T.row(2));
|
||||
|
||||
// Determine if the closest point is on the face.
|
||||
const RowVector3S v10 = T.row(1) - T.row(0);
|
||||
const RowVector3S v21 = T.row(2) - T.row(1);
|
||||
const RowVector3S v02 = T.row(0) - T.row(2);
|
||||
const auto & nor = planes.row(1).template head<3>();
|
||||
const RowVector3S c10 = v10.cross(nor);
|
||||
const RowVector3S c21 = v21.cross(nor);
|
||||
const RowVector3S c02 = v02.cross(nor);
|
||||
C<<c10,c21,c02;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
IGL_INLINE Scalar igl::SphereMeshWedge<Scalar>::round_cone_signed_distance(const RowVector3S & p, const int i, const int j) const
|
||||
{
|
||||
const int e = (j+1)%3;
|
||||
return igl::round_cone_signed_distance(
|
||||
p, V.row(i), r(i), r(j), EV.row(e), l2(e), rr(e), a2(e), il2(e));
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
/// Explicit template instantiation
|
||||
template class igl::SphereMeshWedge<double>;
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2025 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_SPHERE_MESH_WEDGE_H
|
||||
#define IGL_SPHERE_MESH_WEDGE_H
|
||||
|
||||
#include "igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
/// A class to compute the signed distance to a "Sphere-Mesh Wedge" as seen in
|
||||
/// variable radius offset surfaces or Sphere-Meshes. Each wedge is defined
|
||||
/// by three vertices and three radii, one at each vertex. The wedge is
|
||||
/// the union of all spheres at points on the triangle with radius linearly
|
||||
/// interpolated. See, e.g., "Sphere-Meshes for Real-Time Hand Modeling and
|
||||
/// Tracking" or "A Multilinear Model for Bidirectional Craniofacial
|
||||
/// Reconstruction" or "Sphere-Meshes: Shape Approximation using Spherical
|
||||
/// Quadric Error Metrics" or "Variable-Radius Offset Surface Approximation on
|
||||
/// the GPU".
|
||||
///
|
||||
template <typename Scalar>
|
||||
class SphereMeshWedge
|
||||
{
|
||||
public:
|
||||
using RowVector3S = Eigen::Matrix<Scalar, 1, 3>;
|
||||
// Fields
|
||||
enum
|
||||
{
|
||||
BIG_VERTEX = 0,
|
||||
BIG_EDGE = 1,
|
||||
NO_TRIANGLE = 2,
|
||||
FULL = 3
|
||||
} flavor;
|
||||
Eigen::Matrix<Scalar,3,3,Eigen::RowMajor> V;
|
||||
Eigen::Matrix<Scalar,3,1> r;
|
||||
Eigen::Matrix<Scalar,3,3,Eigen::RowMajor> EV;
|
||||
Eigen::Matrix<Scalar,3,1> l,l2,rr,a2,il2;
|
||||
int max_i;
|
||||
Eigen::Matrix<Scalar,5,4,Eigen::RowMajor> planes;
|
||||
Eigen::Matrix<Scalar,3,3,Eigen::RowMajor> T;
|
||||
Eigen::Matrix<Scalar,3,3,Eigen::RowMajor> C;
|
||||
|
||||
SphereMeshWedge(){}
|
||||
/// Constructor that takes three vertices and three radii
|
||||
///
|
||||
/// @param V0 first vertex position
|
||||
/// @param V1 second vertex position
|
||||
/// @param V2 third vertex position
|
||||
/// @param r0 radius at first vertex
|
||||
/// @param r1 radius at second vertex
|
||||
/// @param r2 radius at third vertex
|
||||
IGL_INLINE SphereMeshWedge(
|
||||
const RowVector3S & V0,
|
||||
const RowVector3S & V1,
|
||||
const RowVector3S & V2,
|
||||
const Scalar r0,
|
||||
const Scalar r1,
|
||||
const Scalar r2);
|
||||
/// @param[in] p 3-vector query point
|
||||
/// @return signed distance to the wedge at point p
|
||||
IGL_INLINE Scalar operator()(const RowVector3S & p) const;
|
||||
private:
|
||||
/// Precompute planes used for determining bounded signed to the skewed
|
||||
/// triangular slab portion.
|
||||
///
|
||||
/// @return true if planes are well defined (false implies this slab has
|
||||
/// no contribution).
|
||||
IGL_INLINE bool compute_planes();
|
||||
/// Compute the signed distance to the wedge at a point p for the edge
|
||||
/// (i,j)
|
||||
///
|
||||
/// @param[in] p 3-vector query point
|
||||
/// @param[in] i index of first vertex (0,1,2)
|
||||
/// @param[in] j index of second vertex (0,1,2)
|
||||
IGL_INLINE Scalar round_cone_signed_distance(const RowVector3S & p, const int i, const int j) const;
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "SphereMeshWedge.cpp"
|
||||
#endif
|
||||
#endif
|
||||
+5
-4
@@ -22,6 +22,7 @@
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
@@ -69,9 +70,9 @@ namespace igl
|
||||
/// @param[in] endTime end time
|
||||
/// @param[in] startTime start time
|
||||
/// @return time
|
||||
double subtractTimes( uint64_t endTime, uint64_t startTime )
|
||||
double subtractTimes( std::uint64_t endTime, std::uint64_t startTime )
|
||||
{
|
||||
uint64_t difference = endTime - startTime;
|
||||
std::uint64_t difference = endTime - startTime;
|
||||
static double conversion = 0.0;
|
||||
|
||||
if( conversion == 0.0 )
|
||||
@@ -175,8 +176,8 @@ namespace igl
|
||||
LARGE_INTEGER startCount;
|
||||
LARGE_INTEGER endCount;
|
||||
#elif __APPLE__
|
||||
uint64_t startCount;
|
||||
uint64_t endCount;
|
||||
std::uint64_t startCount;
|
||||
std::uint64_t endCount;
|
||||
#else
|
||||
timeval startCount;
|
||||
timeval endCount;
|
||||
|
||||
@@ -13,21 +13,24 @@
|
||||
#ifndef IGL_WINDINGNUMBERAABB_H
|
||||
#define IGL_WINDINGNUMBERAABB_H
|
||||
#include "WindingNumberTree.h"
|
||||
#include "PlainMatrix.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
/// Class for building an AABB tree to implement the divide and conquer
|
||||
/// algorithm described in [Jacobson et al. 2013].
|
||||
template <
|
||||
typename Point,
|
||||
typename DerivedV,
|
||||
typename DerivedF >
|
||||
class WindingNumberAABB : public WindingNumberTree<Point,DerivedV,DerivedF>
|
||||
typename Scalar,
|
||||
typename Index>
|
||||
class WindingNumberAABB : public WindingNumberTree<Scalar,Index>
|
||||
{
|
||||
protected:
|
||||
// WindingNumberTree defines Point
|
||||
using Point = typename WindingNumberTree<Scalar,Index>::Point;
|
||||
using MatrixXF = typename WindingNumberTree<Scalar,Index>::MatrixXF;
|
||||
Point min_corner;
|
||||
Point max_corner;
|
||||
typename DerivedV::Scalar total_positive_area;
|
||||
Scalar total_positive_area;
|
||||
public:
|
||||
enum SplitMethod
|
||||
{
|
||||
@@ -37,23 +40,25 @@ namespace igl
|
||||
} split_method;
|
||||
public:
|
||||
inline WindingNumberAABB():
|
||||
total_positive_area(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
|
||||
total_positive_area(std::numeric_limits<Scalar>::infinity()),
|
||||
split_method(MEDIAN_ON_LONGEST_AXIS)
|
||||
{}
|
||||
/// Constructor
|
||||
///
|
||||
/// @param[in] V #V by 3 list of vertex positions
|
||||
/// @param[in] F #F by 3 list of triangle indices into V
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
inline WindingNumberAABB(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F);
|
||||
inline WindingNumberAABB(
|
||||
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
|
||||
const Eigen::MatrixBase<DerivedF> & F);
|
||||
const WindingNumberTree<Scalar,Index> & parent,
|
||||
const typename WindingNumberTree<Scalar,Index>::MatrixXF & F);
|
||||
/// Initialize the hierarchy to a given mesh
|
||||
///
|
||||
/// @param[in] V #V by 3 list of vertex positions
|
||||
/// @param[in] F #F by 3 list of triangle indices into V
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
inline void set_mesh(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F);
|
||||
@@ -62,8 +67,8 @@ namespace igl
|
||||
inline virtual void grow();
|
||||
// Compute min and max corners
|
||||
inline void compute_min_max_corners();
|
||||
inline typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
|
||||
inline typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
|
||||
inline Scalar max_abs_winding_number(const Point & p) const;
|
||||
inline Scalar max_simple_abs_winding_number(const Point & p) const;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -86,70 +91,73 @@ namespace igl
|
||||
# define WindingNumberAABB_MIN_F 100
|
||||
#endif
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::set_mesh(
|
||||
template <typename Scalar, typename Index>
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberAABB<Scalar,Index>::set_mesh(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F)
|
||||
{
|
||||
igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(V,F);
|
||||
// static assert that DerivedF::ColsAtCompileTime == 3 or Eigen::Dynamic
|
||||
static_assert(
|
||||
DerivedF::ColsAtCompileTime == 3 || DerivedF::ColsAtCompileTime == Eigen::Dynamic,
|
||||
"F should have 3 or Dynamic columns");
|
||||
igl::WindingNumberTree<Scalar,Index>::set_mesh(V,F);
|
||||
init();
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::init()
|
||||
template <typename Scalar, typename Index>
|
||||
inline void igl::WindingNumberAABB<Scalar,Index>::init()
|
||||
{
|
||||
using namespace Eigen;
|
||||
assert(max_corner.size() == 3);
|
||||
assert(min_corner.size() == 3);
|
||||
compute_min_max_corners();
|
||||
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,1> dblA;
|
||||
doublearea(this->getV(),this->getF(),dblA);
|
||||
Eigen::Matrix<Scalar,Eigen::Dynamic,1> dblA;
|
||||
doublearea((*this->Vptr),(this->F),dblA);
|
||||
total_positive_area = dblA.sum()/2.0;
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline igl::WindingNumberAABB<Point,DerivedV,DerivedF>::WindingNumberAABB(
|
||||
template <typename Scalar, typename Index>
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
inline igl::WindingNumberAABB<Scalar,Index>::WindingNumberAABB(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F):
|
||||
WindingNumberTree<Point,DerivedV,DerivedF>(V,F),
|
||||
WindingNumberTree<Scalar,Index>(V,F),
|
||||
min_corner(),
|
||||
max_corner(),
|
||||
total_positive_area(
|
||||
std::numeric_limits<typename DerivedV::Scalar>::infinity()),
|
||||
std::numeric_limits<Scalar>::infinity()),
|
||||
split_method(MEDIAN_ON_LONGEST_AXIS)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline igl::WindingNumberAABB<Point,DerivedV,DerivedF>::WindingNumberAABB(
|
||||
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
|
||||
const Eigen::MatrixBase<DerivedF> & F):
|
||||
WindingNumberTree<Point,DerivedV,DerivedF>(parent,F),
|
||||
template <typename Scalar, typename Index>
|
||||
inline igl::WindingNumberAABB<Scalar,Index>::WindingNumberAABB(
|
||||
const WindingNumberTree<Scalar,Index> & parent,
|
||||
const typename WindingNumberTree<Scalar,Index>::MatrixXF & F):
|
||||
WindingNumberTree<Scalar,Index>(parent,F),
|
||||
min_corner(),
|
||||
max_corner(),
|
||||
total_positive_area(
|
||||
std::numeric_limits<typename DerivedV::Scalar>::infinity()),
|
||||
std::numeric_limits<Scalar>::infinity()),
|
||||
split_method(MEDIAN_ON_LONGEST_AXIS)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
|
||||
template <typename Scalar, typename Index>
|
||||
inline void igl::WindingNumberAABB<Scalar,Index>::grow()
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// Clear anything that already exists
|
||||
this->delete_children();
|
||||
|
||||
//cout<<"cap.rows(): "<<this->getcap().rows()<<endl;
|
||||
//cout<<"F.rows(): "<<this->getF().rows()<<endl;
|
||||
//cout<<"cap.rows(): "<<(this->cap).rows()<<endl;
|
||||
//cout<<"F.rows(): "<<(this->F).rows()<<endl;
|
||||
|
||||
// Base cases
|
||||
if(
|
||||
this->getF().rows() <= (WindingNumberAABB_MIN_F>0?WindingNumberAABB_MIN_F:0) ||
|
||||
(this->getcap().rows() - 2) >= this->getF().rows())
|
||||
(this->F).rows() <= (WindingNumberAABB_MIN_F>0?WindingNumberAABB_MIN_F:0) ||
|
||||
((this->cap).rows() - 2) >= (this->F).rows())
|
||||
{
|
||||
// Don't grow
|
||||
return;
|
||||
@@ -157,8 +165,8 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
|
||||
|
||||
// Compute longest direction
|
||||
int max_d = -1;
|
||||
typename DerivedV::Scalar max_len =
|
||||
-numeric_limits<typename DerivedV::Scalar>::infinity();
|
||||
Scalar max_len =
|
||||
-std::numeric_limits<Scalar>::infinity();
|
||||
for(int d = 0;d<min_corner.size();d++)
|
||||
{
|
||||
if( (max_corner[d] - min_corner[d]) > max_len )
|
||||
@@ -168,13 +176,13 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
|
||||
}
|
||||
}
|
||||
// Compute facet barycenters
|
||||
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic> BC;
|
||||
barycenter(this->getV(),this->getF(),BC);
|
||||
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> BC;
|
||||
barycenter((*this->Vptr),(this->F),BC);
|
||||
|
||||
|
||||
// Blerg, why is selecting rows so difficult
|
||||
|
||||
typename DerivedV::Scalar split_value;
|
||||
Scalar split_value;
|
||||
// Split in longest direction
|
||||
switch(split_method)
|
||||
{
|
||||
@@ -191,8 +199,8 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
|
||||
//cout<<"c: "<<0.5*(max_corner[max_d] + min_corner[max_d])<<" "<<
|
||||
// "m: "<<split_value<<endl;;
|
||||
|
||||
vector<int> id( this->getF().rows());
|
||||
for(int i = 0;i<this->getF().rows();i++)
|
||||
std::vector<int> id( (this->F).rows());
|
||||
for(int i = 0;i<(this->F).rows();i++)
|
||||
{
|
||||
if(BC(i,max_d) <= split_value)
|
||||
{
|
||||
@@ -210,19 +218,19 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
|
||||
// badly balanced base case (could try to recut)
|
||||
return;
|
||||
}
|
||||
assert(lefts+rights == this->getF().rows());
|
||||
DerivedF leftF(lefts, this->getF().cols());
|
||||
DerivedF rightF(rights,this->getF().cols());
|
||||
assert(lefts+rights == (this->F).rows());
|
||||
MatrixXF leftF(lefts, (this->F).cols());
|
||||
MatrixXF rightF(rights,(this->F).cols());
|
||||
int left_i = 0;
|
||||
int right_i = 0;
|
||||
for(int i = 0;i<this->getF().rows();i++)
|
||||
for(int i = 0;i<(this->F).rows();i++)
|
||||
{
|
||||
if(id[i] == 0)
|
||||
{
|
||||
leftF.row(left_i++) = this->getF().row(i);
|
||||
leftF.row(left_i++) = (this->F).row(i);
|
||||
}else if(id[i] == 1)
|
||||
{
|
||||
rightF.row(right_i++) = this->getF().row(i);
|
||||
rightF.row(right_i++) = (this->F).row(i);
|
||||
}else
|
||||
{
|
||||
assert(false);
|
||||
@@ -231,18 +239,18 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
|
||||
assert(right_i == rightF.rows());
|
||||
assert(left_i == leftF.rows());
|
||||
// Finally actually grow children and Recursively grow
|
||||
WindingNumberAABB<Point,DerivedV,DerivedF> * leftWindingNumberAABB =
|
||||
new WindingNumberAABB<Point,DerivedV,DerivedF>(*this,leftF);
|
||||
WindingNumberAABB<Scalar,Index> * leftWindingNumberAABB =
|
||||
new WindingNumberAABB<Scalar,Index>(*this,leftF);
|
||||
leftWindingNumberAABB->grow();
|
||||
this->children.push_back(leftWindingNumberAABB);
|
||||
WindingNumberAABB<Point,DerivedV,DerivedF> * rightWindingNumberAABB =
|
||||
new WindingNumberAABB<Point,DerivedV,DerivedF>(*this,rightF);
|
||||
WindingNumberAABB<Scalar,Index> * rightWindingNumberAABB =
|
||||
new WindingNumberAABB<Scalar,Index>(*this,rightF);
|
||||
rightWindingNumberAABB->grow();
|
||||
this->children.push_back(rightWindingNumberAABB);
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline bool igl::WindingNumberAABB<Point,DerivedV,DerivedF>::inside(const Point & p) const
|
||||
template <typename Scalar, typename Index>
|
||||
inline bool igl::WindingNumberAABB<Scalar,Index>::inside(const Point & p) const
|
||||
{
|
||||
assert(p.size() == max_corner.size());
|
||||
assert(p.size() == min_corner.size());
|
||||
@@ -259,39 +267,38 @@ inline bool igl::WindingNumberAABB<Point,DerivedV,DerivedF>::inside(const Point
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::compute_min_max_corners()
|
||||
template <typename Scalar, typename Index>
|
||||
inline void igl::WindingNumberAABB<Scalar,Index>::compute_min_max_corners()
|
||||
{
|
||||
using namespace std;
|
||||
// initialize corners
|
||||
for(int d = 0;d<min_corner.size();d++)
|
||||
{
|
||||
min_corner[d] = numeric_limits<typename Point::Scalar>::infinity();
|
||||
max_corner[d] = -numeric_limits<typename Point::Scalar>::infinity();
|
||||
min_corner[d] = std::numeric_limits<typename Point::Scalar>::infinity();
|
||||
max_corner[d] = -std::numeric_limits<typename Point::Scalar>::infinity();
|
||||
}
|
||||
|
||||
this->center = Point(0,0,0);
|
||||
// Loop over facets
|
||||
for(int i = 0;i<this->getF().rows();i++)
|
||||
for(int i = 0;i<(this->F).rows();i++)
|
||||
{
|
||||
for(int j = 0;j<this->getF().cols();j++)
|
||||
for(int j = 0;j<(this->F).cols();j++)
|
||||
{
|
||||
for(int d = 0;d<min_corner.size();d++)
|
||||
{
|
||||
min_corner[d] =
|
||||
this->getV()(this->getF()(i,j),d) < min_corner[d] ?
|
||||
this->getV()(this->getF()(i,j),d) : min_corner[d];
|
||||
(*this->Vptr)((this->F)(i,j),d) < min_corner[d] ?
|
||||
(*this->Vptr)((this->F)(i,j),d) : min_corner[d];
|
||||
max_corner[d] =
|
||||
this->getV()(this->getF()(i,j),d) > max_corner[d] ?
|
||||
this->getV()(this->getF()(i,j),d) : max_corner[d];
|
||||
(*this->Vptr)((this->F)(i,j),d) > max_corner[d] ?
|
||||
(*this->Vptr)((this->F)(i,j),d) : max_corner[d];
|
||||
}
|
||||
// This is biased toward vertices incident on more than one face, but
|
||||
// perhaps that's good
|
||||
this->center += this->getV().row(this->getF()(i,j));
|
||||
this->center += (*this->Vptr).row((this->F)(i,j));
|
||||
}
|
||||
}
|
||||
// Average
|
||||
this->center.array() /= this->getF().size();
|
||||
this->center.array() /= (this->F).size();
|
||||
|
||||
//cout<<"min_corner: "<<this->min_corner.transpose()<<endl;
|
||||
//cout<<"Center: "<<this->center.transpose()<<endl;
|
||||
@@ -302,32 +309,29 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::compute_min_max_cor
|
||||
this->radius = (max_corner-min_corner).norm()/2.0;
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline typename DerivedV::Scalar
|
||||
igl::WindingNumberAABB<Point,DerivedV,DerivedF>::max_abs_winding_number(const Point & p) const
|
||||
template <typename Scalar, typename Index>
|
||||
inline Scalar
|
||||
igl::WindingNumberAABB<Scalar,Index>::max_abs_winding_number(const Point & p) const
|
||||
{
|
||||
using namespace std;
|
||||
// Only valid if not inside
|
||||
if(inside(p))
|
||||
{
|
||||
return numeric_limits<typename DerivedV::Scalar>::infinity();
|
||||
return std::numeric_limits<Scalar>::infinity();
|
||||
}
|
||||
// Q: we know the total positive area so what's the most this could project
|
||||
// to? Remember it could be layered in the same direction.
|
||||
return numeric_limits<typename DerivedV::Scalar>::infinity();
|
||||
return std::numeric_limits<Scalar>::infinity();
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline typename DerivedV::Scalar
|
||||
igl::WindingNumberAABB<Point,DerivedV,DerivedF>::max_simple_abs_winding_number(
|
||||
template <typename Scalar, typename Index>
|
||||
inline Scalar
|
||||
igl::WindingNumberAABB<Scalar,Index>::max_simple_abs_winding_number(
|
||||
const Point & p) const
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// Only valid if not inside
|
||||
if(inside(p))
|
||||
{
|
||||
return numeric_limits<typename DerivedV::Scalar>::infinity();
|
||||
return std::numeric_limits<Scalar>::infinity();
|
||||
}
|
||||
// Max simple is the same as sum of positive winding number contributions of
|
||||
// bounding box
|
||||
@@ -335,10 +339,10 @@ inline typename DerivedV::Scalar
|
||||
// begin precomputation
|
||||
//MatrixXd BV((int)pow(2,3),3);
|
||||
typedef
|
||||
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
|
||||
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
|
||||
MatrixXS;
|
||||
typedef
|
||||
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
|
||||
Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic>
|
||||
MatrixXF;
|
||||
MatrixXS BV((int)(1<<3),3);
|
||||
BV <<
|
||||
@@ -383,16 +387,4 @@ inline typename DerivedV::Scalar
|
||||
return igl::winding_number(BV,PBF,p);
|
||||
}
|
||||
|
||||
// This is a bullshit template because AABB annoyingly needs templates for bad
|
||||
// combinations of 3D V with DIM=2 AABB
|
||||
//
|
||||
// _Define_ as a no-op rather than monkeying around with the proper code above
|
||||
namespace igl
|
||||
{
|
||||
template <> inline igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::WindingNumberAABB(const Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2>> & , const Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2>> & ){};
|
||||
template <> inline void igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::grow(){};
|
||||
template <> inline void igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::init(){};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+104
-137
@@ -11,73 +11,67 @@
|
||||
#include <map>
|
||||
#include <Eigen/Dense>
|
||||
#include "WindingNumberMethod.h"
|
||||
#include <memory>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
/// Space partitioning tree for computing winding number hierarchically.
|
||||
///
|
||||
/// @tparam Point type for points in space, e.g. Eigen::Vector3d
|
||||
template <
|
||||
typename Point,
|
||||
typename DerivedV,
|
||||
typename DerivedF >
|
||||
typename Scalar,
|
||||
typename Index>
|
||||
class WindingNumberTree
|
||||
{
|
||||
public:
|
||||
using Point = Eigen::Matrix<Scalar,1,3>;
|
||||
// Method to use (see enum above)
|
||||
//static double min_max_w;
|
||||
static std::map<
|
||||
std::pair<const WindingNumberTree*,const WindingNumberTree*>,
|
||||
typename DerivedV::Scalar>
|
||||
Scalar>
|
||||
cached;
|
||||
// This is only need to fill in references, it should never actually be touched
|
||||
// and shouldn't cause race conditions. (This is a hack, but I think it's "safe")
|
||||
static DerivedV dummyV;
|
||||
protected:
|
||||
WindingNumberMethod method;
|
||||
const WindingNumberTree * parent;
|
||||
std::list<WindingNumberTree * > children;
|
||||
typedef
|
||||
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
|
||||
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
|
||||
MatrixXS;
|
||||
typedef
|
||||
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
|
||||
Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic>
|
||||
MatrixXF;
|
||||
//// List of boundary edges (recall edges are vertices in 2d)
|
||||
//const Eigen::MatrixXi boundary;
|
||||
// Base mesh vertices
|
||||
DerivedV & V;
|
||||
// Base mesh vertices with duplicates removed
|
||||
// Base mesh vertices with duplicates removed (root will fill this in and
|
||||
// then everyone's Vptr will point to it.
|
||||
MatrixXS SV;
|
||||
// Shared pointer to base mesh vertices
|
||||
std::shared_ptr<MatrixXS> Vptr;
|
||||
// Facets in this bounding volume
|
||||
MatrixXF F;
|
||||
// Tessellated boundary curve
|
||||
MatrixXF cap;
|
||||
// Upper Bound on radius of enclosing ball
|
||||
typename DerivedV::Scalar radius;
|
||||
Scalar radius;
|
||||
// (Approximate) center (of mass)
|
||||
Point center;
|
||||
public:
|
||||
inline WindingNumberTree();
|
||||
// For root
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
inline WindingNumberTree(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F);
|
||||
// For chilluns
|
||||
inline WindingNumberTree(
|
||||
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
|
||||
const Eigen::MatrixBase<DerivedF> & F);
|
||||
const WindingNumberTree<Scalar,Index> & parent,
|
||||
const typename igl::WindingNumberTree<Scalar,Index>::MatrixXF & F);
|
||||
inline virtual ~WindingNumberTree();
|
||||
inline void delete_children();
|
||||
inline virtual void set_mesh(
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
inline void set_mesh(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F);
|
||||
// Set method
|
||||
inline void set_method( const WindingNumberMethod & m);
|
||||
public:
|
||||
inline const DerivedV & getV() const;
|
||||
inline const MatrixXF & getF() const;
|
||||
inline const MatrixXF & getcap() const;
|
||||
// Grow the Tree recursively
|
||||
inline virtual void grow();
|
||||
// Determine whether a given point is inside the bounding
|
||||
@@ -92,12 +86,12 @@ namespace igl
|
||||
// Inputs:
|
||||
// p query point
|
||||
// Returns winding number
|
||||
inline typename DerivedV::Scalar winding_number(const Point & p) const;
|
||||
inline Scalar winding_number(const Point & p) const;
|
||||
// Same as above, but always computes winding number using exact method
|
||||
// (sum over every facet)
|
||||
inline typename DerivedV::Scalar winding_number_all(const Point & p) const;
|
||||
inline Scalar winding_number_all(const Point & p) const;
|
||||
// Same as above, but always computes using sum over tessllated boundary
|
||||
inline typename DerivedV::Scalar winding_number_boundary(const Point & p) const;
|
||||
inline Scalar winding_number_boundary(const Point & p) const;
|
||||
//// Same as winding_number above, but if max_simple_abs_winding_number is
|
||||
//// less than some threshold min_max_w just return 0 (colloquially the "fast
|
||||
//// multipole method)
|
||||
@@ -120,10 +114,10 @@ namespace igl
|
||||
// Inputs:
|
||||
// p query point
|
||||
// Returns max winding number of
|
||||
inline virtual typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
|
||||
inline virtual Scalar max_abs_winding_number(const Point & p) const;
|
||||
// Same as above, but stronger assumptions on (V,F). Assumes (V,F) is a
|
||||
// simple polyhedron
|
||||
inline virtual typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
|
||||
inline virtual Scalar max_simple_abs_winding_number(const Point & p) const;
|
||||
// Compute or read cached winding number for point p with respect to mesh
|
||||
// in bounding box, recursing according to approximation criteria
|
||||
//
|
||||
@@ -131,7 +125,7 @@ namespace igl
|
||||
// p query point
|
||||
// that WindingNumberTree containing mesh w.r.t. which we're computing w.n.
|
||||
// Returns cached winding number
|
||||
inline virtual typename DerivedV::Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const;
|
||||
inline virtual Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -148,83 +142,89 @@ namespace igl
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
//template <typename Point, typename DerivedV, typename DerivedF>
|
||||
//WindingNumberMethod WindingNumberTree<Point,DerivedV,DerivedF>::method = EXACT_WINDING_NUMBER_METHOD;
|
||||
//template <typename Point, typename DerivedV, typename DerivedF>
|
||||
//double WindingNumberTree<Point,DerivedV,DerivedF>::min_max_w = 0;
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
std::map< std::pair<const igl::WindingNumberTree<Point,DerivedV,DerivedF>*,const igl::WindingNumberTree<Point,DerivedV,DerivedF>*>, typename DerivedV::Scalar>
|
||||
igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached;
|
||||
//template <typename Scalar, typename Index>
|
||||
//WindingNumberMethod WindingNumberTree<Scalar,Index>::method = EXACT_WINDING_NUMBER_METHOD;
|
||||
//template <typename Scalar, typename Index>
|
||||
//double WindingNumberTree<Scalar,Index>::min_max_w = 0;
|
||||
template <typename Scalar, typename Index>
|
||||
std::map< std::pair<const igl::WindingNumberTree<Scalar,Index>*,const igl::WindingNumberTree<Scalar,Index>*>, Scalar>
|
||||
igl::WindingNumberTree<Scalar,Index>::cached;
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree():
|
||||
template <typename Scalar, typename Index>
|
||||
inline igl::WindingNumberTree<Scalar,Index>::WindingNumberTree():
|
||||
method(EXACT_WINDING_NUMBER_METHOD),
|
||||
parent(NULL),
|
||||
V(dummyV),
|
||||
SV(),
|
||||
F(),
|
||||
cap(),
|
||||
radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
|
||||
radius(std::numeric_limits<Scalar>::infinity()),
|
||||
center(0,0,0)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
|
||||
template <typename Scalar, typename Index>
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
inline igl::WindingNumberTree<Scalar,Index>::WindingNumberTree(
|
||||
const Eigen::MatrixBase<DerivedV> & _V,
|
||||
const Eigen::MatrixBase<DerivedF> & _F):
|
||||
method(EXACT_WINDING_NUMBER_METHOD),
|
||||
parent(NULL),
|
||||
V(dummyV),
|
||||
SV(),
|
||||
F(),
|
||||
cap(),
|
||||
radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
|
||||
radius(std::numeric_limits<Scalar>::infinity()),
|
||||
center(0,0,0)
|
||||
{
|
||||
set_mesh(_V,_F);
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(
|
||||
template <typename Scalar, typename Index>
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberTree<Scalar,Index>::set_mesh(
|
||||
const Eigen::MatrixBase<DerivedV> & _V,
|
||||
const Eigen::MatrixBase<DerivedF> & _F)
|
||||
{
|
||||
using namespace std;
|
||||
// Remove any exactly duplicate vertices
|
||||
// Q: Can this ever increase the complexity of the boundary?
|
||||
// Q: Would we gain even more by remove almost exactly duplicate vertices?
|
||||
Eigen::Matrix<typename MatrixXF::Scalar,Eigen::Dynamic,1> SVI,SVJ;
|
||||
igl::remove_duplicate_vertices(_V,_F,0.0,SV,SVI,SVJ,F);
|
||||
triangle_fan(igl::exterior_edges(F),cap);
|
||||
V = SV;
|
||||
{
|
||||
Eigen::Matrix<typename MatrixXF::Scalar,Eigen::Dynamic,2> EE;
|
||||
igl::exterior_edges(F,EE);
|
||||
triangle_fan(EE,cap);
|
||||
}
|
||||
// point Vptr to SV
|
||||
Vptr = std::make_shared<MatrixXS>(SV);
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
|
||||
const igl::WindingNumberTree<Point,DerivedV,DerivedF> & parent,
|
||||
const Eigen::MatrixBase<DerivedF> & _F):
|
||||
template <typename Scalar, typename Index>
|
||||
inline igl::WindingNumberTree<Scalar,Index>::WindingNumberTree(
|
||||
const igl::WindingNumberTree<Scalar,Index> & parent,
|
||||
const typename igl::WindingNumberTree<Scalar,Index>::MatrixXF & _F):
|
||||
method(parent.method),
|
||||
parent(&parent),
|
||||
V(parent.V),
|
||||
Vptr(parent.Vptr),
|
||||
SV(),
|
||||
F(_F),
|
||||
cap(triangle_fan(igl::exterior_edges(_F)))
|
||||
cap()
|
||||
{
|
||||
Eigen::Matrix<typename MatrixXF::Scalar,Eigen::Dynamic,2> EE;
|
||||
igl::exterior_edges(F,EE);
|
||||
triangle_fan(EE,cap);
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::~WindingNumberTree<Point,DerivedV,DerivedF>()
|
||||
template <typename Scalar, typename Index>
|
||||
inline igl::WindingNumberTree<Scalar,Index>::~WindingNumberTree()
|
||||
{
|
||||
delete_children();
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::delete_children()
|
||||
template <typename Scalar, typename Index>
|
||||
inline void igl::WindingNumberTree<Scalar,Index>::delete_children()
|
||||
{
|
||||
using namespace std;
|
||||
// Delete children
|
||||
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
|
||||
typename std::list<WindingNumberTree<Scalar,Index>* >::iterator cit = children.begin();
|
||||
while(cit != children.end())
|
||||
{
|
||||
// clear the memory of this item
|
||||
@@ -234,8 +234,8 @@ inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::delete_children()
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_method(const WindingNumberMethod & m)
|
||||
template <typename Scalar, typename Index>
|
||||
inline void igl::WindingNumberTree<Scalar,Index>::set_method(const WindingNumberMethod & m)
|
||||
{
|
||||
this->method = m;
|
||||
for(auto child : children)
|
||||
@@ -244,44 +244,23 @@ inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_method(const Wi
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline const DerivedV & igl::WindingNumberTree<Point,DerivedV,DerivedF>::getV() const
|
||||
{
|
||||
return V;
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline const typename igl::WindingNumberTree<Point,DerivedV,DerivedF>::MatrixXF&
|
||||
igl::WindingNumberTree<Point,DerivedV,DerivedF>::getF() const
|
||||
{
|
||||
return F;
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline const typename igl::WindingNumberTree<Point,DerivedV,DerivedF>::MatrixXF&
|
||||
igl::WindingNumberTree<Point,DerivedV,DerivedF>::getcap() const
|
||||
{
|
||||
return cap;
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::grow()
|
||||
template <typename Scalar, typename Index>
|
||||
inline void igl::WindingNumberTree<Scalar,Index>::grow()
|
||||
{
|
||||
// Don't grow
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline bool igl::WindingNumberTree<Point,DerivedV,DerivedF>::inside(const Point & /*p*/) const
|
||||
template <typename Scalar, typename Index>
|
||||
inline bool igl::WindingNumberTree<Scalar,Index>::inside(const Point & /*p*/) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline typename DerivedV::Scalar
|
||||
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p) const
|
||||
template <typename Scalar, typename Index>
|
||||
inline Scalar
|
||||
igl::WindingNumberTree<Scalar,Index>::winding_number(const Point & p) const
|
||||
{
|
||||
using namespace std;
|
||||
//cout<<"+"<<boundary.rows();
|
||||
// If inside then we need to be careful
|
||||
if(inside(p))
|
||||
@@ -290,9 +269,9 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p)
|
||||
if(children.size()>0)
|
||||
{
|
||||
// Recurse on each child and accumulate
|
||||
typename DerivedV::Scalar sum = 0;
|
||||
Scalar sum = 0;
|
||||
for(
|
||||
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
|
||||
typename std::list<WindingNumberTree<Scalar,Index>* >::const_iterator cit = children.begin();
|
||||
cit != children.end();
|
||||
cit++)
|
||||
{
|
||||
@@ -330,7 +309,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p)
|
||||
return winding_number_boundary(p);
|
||||
case APPROX_SIMPLE_WINDING_NUMBER_METHOD:
|
||||
{
|
||||
typename DerivedV::Scalar dist = (p-center).norm();
|
||||
Scalar dist = (p-center).norm();
|
||||
// Radius is already an overestimate of inside
|
||||
if(dist>1.0*radius)
|
||||
{
|
||||
@@ -355,24 +334,22 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline typename DerivedV::Scalar
|
||||
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_all(const Point & p) const
|
||||
template <typename Scalar, typename Index>
|
||||
inline Scalar
|
||||
igl::WindingNumberTree<Scalar,Index>::winding_number_all(const Point & p) const
|
||||
{
|
||||
return igl::winding_number(V,F,p);
|
||||
return igl::winding_number(*Vptr,F,p);
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline typename DerivedV::Scalar
|
||||
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_boundary(const Point & p) const
|
||||
template <typename Scalar, typename Index>
|
||||
inline Scalar
|
||||
igl::WindingNumberTree<Scalar,Index>::winding_number_boundary(const Point & p) const
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
return igl::winding_number(V,cap,p);
|
||||
return igl::winding_number(*Vptr,cap,p);
|
||||
}
|
||||
|
||||
//template <typename Point, typename DerivedV, typename DerivedF>
|
||||
//inline double igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_approx_simple(
|
||||
//template <typename Scalar, typename Index>
|
||||
//inline double igl::WindingNumberTree<Scalar,Index>::winding_number_approx_simple(
|
||||
// const Point & p,
|
||||
// const double min_max_w)
|
||||
//{
|
||||
@@ -387,46 +364,43 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_boundary(const P
|
||||
// }
|
||||
//}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::print(const char * tab)
|
||||
template <typename Scalar, typename Index>
|
||||
inline void igl::WindingNumberTree<Scalar,Index>::print(const char * tab)
|
||||
{
|
||||
using namespace std;
|
||||
// Print all facets
|
||||
cout<<tab<<"["<<endl<<F<<endl<<"]";
|
||||
std::cout<<tab<<"["<<std::endl<<F<<std::endl<<"]";
|
||||
// Print children
|
||||
for(
|
||||
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
|
||||
typename std::list<WindingNumberTree<Scalar,Index>* >::iterator cit = children.begin();
|
||||
cit != children.end();
|
||||
cit++)
|
||||
{
|
||||
cout<<","<<endl;
|
||||
(*cit)->print((string(tab)+"").c_str());
|
||||
std::cout<<","<<std::endl;
|
||||
(*cit)->print((std::string(tab)+"").c_str());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline typename DerivedV::Scalar
|
||||
igl::WindingNumberTree<Point,DerivedV,DerivedF>::max_abs_winding_number(const Point & /*p*/) const
|
||||
template <typename Scalar, typename Index>
|
||||
inline Scalar
|
||||
igl::WindingNumberTree<Scalar,Index>::max_abs_winding_number(const Point & /*p*/) const
|
||||
{
|
||||
return std::numeric_limits<typename DerivedV::Scalar>::infinity();
|
||||
return std::numeric_limits<Scalar>::infinity();
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline typename DerivedV::Scalar
|
||||
igl::WindingNumberTree<Point,DerivedV,DerivedF>::max_simple_abs_winding_number(
|
||||
template <typename Scalar, typename Index>
|
||||
inline Scalar
|
||||
igl::WindingNumberTree<Scalar,Index>::max_simple_abs_winding_number(
|
||||
const Point & /*p*/) const
|
||||
{
|
||||
using namespace std;
|
||||
return numeric_limits<typename DerivedV::Scalar>::infinity();
|
||||
return std::numeric_limits<Scalar>::infinity();
|
||||
}
|
||||
|
||||
template <typename Point, typename DerivedV, typename DerivedF>
|
||||
inline typename DerivedV::Scalar
|
||||
igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
|
||||
const igl::WindingNumberTree<Point,DerivedV,DerivedF> & that,
|
||||
template <typename Scalar, typename Index>
|
||||
inline Scalar
|
||||
igl::WindingNumberTree<Scalar,Index>::cached_winding_number(
|
||||
const igl::WindingNumberTree<Scalar,Index> & that,
|
||||
const Point & p) const
|
||||
{
|
||||
using namespace std;
|
||||
// Simple metric for `is_far`
|
||||
//
|
||||
// this that
|
||||
@@ -447,7 +421,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
|
||||
bool is_far = this->radius<that.radius;
|
||||
if(is_far)
|
||||
{
|
||||
typename DerivedV::Scalar a = atan2(
|
||||
Scalar a = atan2(
|
||||
that.radius - this->radius,
|
||||
(that.center - this->center).norm());
|
||||
assert(a>0);
|
||||
@@ -457,7 +431,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
|
||||
if(is_far)
|
||||
{
|
||||
// Not implemented yet
|
||||
pair<const WindingNumberTree*,const WindingNumberTree*> this_that(this,&that);
|
||||
std::pair<const WindingNumberTree*,const WindingNumberTree*> this_that(this,&that);
|
||||
// Need to compute it for first time?
|
||||
if(cached.count(this_that)==0)
|
||||
{
|
||||
@@ -472,7 +446,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
|
||||
}else
|
||||
{
|
||||
for(
|
||||
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
|
||||
typename std::list<WindingNumberTree<Scalar,Index>* >::const_iterator cit = children.begin();
|
||||
cit != children.end();
|
||||
cit++)
|
||||
{
|
||||
@@ -490,11 +464,4 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Explicit instantiation of static variable
|
||||
template <
|
||||
typename Point,
|
||||
typename DerivedV,
|
||||
typename DerivedF >
|
||||
DerivedV igl::WindingNumberTree<Point,DerivedV,DerivedF>::dummyV;
|
||||
|
||||
#endif
|
||||
|
||||
+34
-28
@@ -11,6 +11,8 @@
|
||||
#include "slice_into.h"
|
||||
#include "cat.h"
|
||||
//#include "matlab_format.h"
|
||||
#include "placeholders.h"
|
||||
#include "PlainMatrix.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
@@ -31,15 +33,15 @@ template <
|
||||
>
|
||||
IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
const Eigen::SparseMatrix<AT>& A,
|
||||
const Eigen::PlainObjectBase<DerivedB> & B,
|
||||
const Eigen::PlainObjectBase<Derivedknown> & known,
|
||||
const Eigen::PlainObjectBase<DerivedY> & Y,
|
||||
const Eigen::MatrixBase<DerivedB> & B,
|
||||
const Eigen::MatrixBase<Derivedknown> & known,
|
||||
const Eigen::MatrixBase<DerivedY> & Y,
|
||||
const Eigen::SparseMatrix<AeqT>& Aeq,
|
||||
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
|
||||
const Eigen::MatrixBase<DerivedBeq> & Beq,
|
||||
const Eigen::SparseMatrix<AieqT>& Aieq,
|
||||
const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
|
||||
const Eigen::PlainObjectBase<Derivedlx> & p_lx,
|
||||
const Eigen::PlainObjectBase<Derivedux> & p_ux,
|
||||
const Eigen::MatrixBase<DerivedBieq> & Bieq,
|
||||
const Eigen::MatrixBase<Derivedlx> & p_lx,
|
||||
const Eigen::MatrixBase<Derivedux> & p_ux,
|
||||
const igl::active_set_params & params,
|
||||
Eigen::PlainObjectBase<DerivedZ> & Z
|
||||
)
|
||||
@@ -49,8 +51,6 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
#if defined(ACTIVE_SET_CPP_DEBUG) && !defined(_MSC_VER)
|
||||
# warning "ACTIVE_SET_CPP_DEBUG"
|
||||
#endif
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
SolverStatus ret = SOLVER_STATUS_ERROR;
|
||||
const int n = A.rows();
|
||||
assert(n == A.cols() && "A must be square");
|
||||
@@ -73,7 +73,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
if(p_lx.size() == 0)
|
||||
{
|
||||
lx = Derivedlx::Constant(
|
||||
n,1,-numeric_limits<typename Derivedlx::Scalar>::max());
|
||||
n,1,-std::numeric_limits<typename Derivedlx::Scalar>::max());
|
||||
}else
|
||||
{
|
||||
lx = p_lx;
|
||||
@@ -81,7 +81,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
if(p_ux.size() == 0)
|
||||
{
|
||||
ux = Derivedux::Constant(
|
||||
n,1,numeric_limits<typename Derivedux::Scalar>::max());
|
||||
n,1,std::numeric_limits<typename Derivedux::Scalar>::max());
|
||||
}else
|
||||
{
|
||||
ux = p_ux;
|
||||
@@ -105,12 +105,12 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
typedef int BOOL;
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
Matrix<BOOL,Dynamic,1> as_lx = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
|
||||
Matrix<BOOL,Dynamic,1> as_ux = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
|
||||
Matrix<BOOL,Dynamic,1> as_ieq = Matrix<BOOL,Dynamic,1>::Constant(Aieq.rows(),1,FALSE);
|
||||
Eigen::Matrix<BOOL,Eigen::Dynamic,1> as_lx = Eigen::Matrix<BOOL,Eigen::Dynamic,1>::Constant(n,1,FALSE);
|
||||
Eigen::Matrix<BOOL,Eigen::Dynamic,1> as_ux = Eigen::Matrix<BOOL,Eigen::Dynamic,1>::Constant(n,1,FALSE);
|
||||
Eigen::Matrix<BOOL,Eigen::Dynamic,1> as_ieq = Eigen::Matrix<BOOL,Eigen::Dynamic,1>::Constant(Aieq.rows(),1,FALSE);
|
||||
|
||||
// Keep track of previous Z for comparison
|
||||
DerivedZ old_Z;
|
||||
PlainMatrix<DerivedZ> old_Z;
|
||||
|
||||
int iter = 0;
|
||||
while(true)
|
||||
@@ -148,7 +148,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
}
|
||||
if(Aieq.rows() > 0)
|
||||
{
|
||||
DerivedZ AieqZ;
|
||||
PlainMatrix<DerivedZ,Eigen::Dynamic> AieqZ;
|
||||
AieqZ = Aieq*Z;
|
||||
for(int a = 0;a<Aieq.rows();a++)
|
||||
{
|
||||
@@ -202,7 +202,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
// PREPARE FIXED VALUES
|
||||
Eigen::Matrix<typename Derivedknown::Scalar,Eigen::Dynamic,1> known_i;
|
||||
known_i.resize(nk + as_lx_count + as_ux_count,1);
|
||||
DerivedY Y_i;
|
||||
PlainMatrix<DerivedY,Eigen::Dynamic,1> Y_i;
|
||||
Y_i.resize(nk + as_lx_count + as_ux_count,1);
|
||||
{
|
||||
known_i.block(0,0,known.rows(),known.cols()) = known;
|
||||
@@ -235,7 +235,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
// PREPARE EQUALITY CONSTRAINTS
|
||||
Eigen::Matrix<typename DerivedY::Scalar, Eigen::Dynamic, 1> as_ieq_list(as_ieq_count,1);
|
||||
// Gather active constraints and resp. rhss
|
||||
DerivedBeq Beq_i;
|
||||
PlainMatrix<DerivedBeq,Eigen::Dynamic,1> Beq_i;
|
||||
Beq_i.resize(Beq.rows()+as_ieq_count,1);
|
||||
Beq_i.head(Beq.rows()) = Beq;
|
||||
{
|
||||
@@ -253,7 +253,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
assert(k == as_ieq_count);
|
||||
}
|
||||
// extract active constraint rows
|
||||
SparseMatrix<AeqT> Aeq_i,Aieq_i;
|
||||
Eigen::SparseMatrix<AeqT> Aeq_i,Aieq_i;
|
||||
slice(Aieq,as_ieq_list,1,Aieq_i);
|
||||
// Append to equality constraints
|
||||
cat(1,Aeq,Aieq_i,Aeq_i);
|
||||
@@ -263,7 +263,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
// NO DUPES!
|
||||
Matrix<BOOL,Dynamic,1> fixed = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
|
||||
Eigen::Matrix<BOOL ,Eigen::Dynamic,1> fixed = Eigen::Matrix<BOOL ,Eigen::Dynamic,1>::Constant(n,1,FALSE);
|
||||
for(int k = 0;k<known_i.size();k++)
|
||||
{
|
||||
assert(!fixed[known_i(k)]);
|
||||
@@ -272,7 +272,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
}
|
||||
#endif
|
||||
|
||||
DerivedZ sol;
|
||||
PlainMatrix<DerivedZ,Eigen::Dynamic,Eigen::Dynamic> sol;
|
||||
if(known_i.size() == A.rows())
|
||||
{
|
||||
// Everything's fixed?
|
||||
@@ -280,7 +280,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
cout<<" everything's fixed."<<endl;
|
||||
#endif
|
||||
Z.resize(A.rows(),Y_i.cols());
|
||||
Z(known_i,Eigen::all) = Y_i;
|
||||
Z(known_i,igl::placeholders::all) = Y_i;
|
||||
sol.resize(0,Y_i.cols());
|
||||
assert(Aeq_i.rows() == 0 && "All fixed but linearly constrained");
|
||||
}else
|
||||
@@ -290,11 +290,15 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
#endif
|
||||
if(!min_quad_with_fixed_precompute(A,known_i,Aeq_i,params.Auu_pd,data))
|
||||
{
|
||||
#ifdef ACTIVE_SET_CPP_DEBUG
|
||||
cerr<<"Error: min_quad_with_fixed precomputation failed."<<endl;
|
||||
#endif
|
||||
if(iter > 0 && Aeq_i.rows() > Aeq.rows())
|
||||
{
|
||||
#ifdef ACTIVE_SET_CPP_DEBUG
|
||||
cerr<<" *Are you sure rows of [Aeq;Aieq] are linearly independent?*"<<
|
||||
endl;
|
||||
#endif
|
||||
}
|
||||
ret = SOLVER_STATUS_ERROR;
|
||||
break;
|
||||
@@ -304,7 +308,9 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
#endif
|
||||
if(!min_quad_with_fixed_solve(data,B,Y_i,Beq_i,Z,sol))
|
||||
{
|
||||
#ifdef ACTIVE_SET_CPP_DEBUG
|
||||
cerr<<"Error: min_quad_with_fixed solve failed."<<endl;
|
||||
#endif
|
||||
ret = SOLVER_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
@@ -318,18 +324,18 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
}
|
||||
|
||||
// Compute Lagrange multiplier values for known_i
|
||||
SparseMatrix<AT> Ak;
|
||||
Eigen::SparseMatrix<AT> Ak;
|
||||
// Slow
|
||||
slice(A,known_i,1,Ak);
|
||||
//slice(B,known_i,Bk);
|
||||
DerivedB Bk = B(known_i,Eigen::all);
|
||||
MatrixXd Lambda_known_i = -(0.5*Ak*Z + 0.5*Bk);
|
||||
PlainMatrix<DerivedB,Eigen::Dynamic> Bk = B(known_i,igl::placeholders::all);
|
||||
Eigen::MatrixXd Lambda_known_i = -(0.5*Ak*Z + 0.5*Bk);
|
||||
// reverse the lambda values for lx
|
||||
Lambda_known_i.block(nk,0,as_lx_count,1) =
|
||||
(-1*Lambda_known_i.block(nk,0,as_lx_count,1)).eval();
|
||||
|
||||
// Extract Lagrange multipliers for Aieq_i (always at back of sol)
|
||||
VectorXd Lambda_Aieq_i(Aieq_i.rows(),1);
|
||||
Eigen::VectorXd Lambda_Aieq_i(Aieq_i.rows(),1);
|
||||
for(int l = 0;l<Aieq_i.rows();l++)
|
||||
{
|
||||
Lambda_Aieq_i(Aieq_i.rows()-1-l) = sol(sol.rows()-1-l);
|
||||
@@ -375,6 +381,6 @@ IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::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::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> 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&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::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::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> 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&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> 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&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> 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&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
|
||||
@@ -70,15 +70,15 @@ namespace igl
|
||||
>
|
||||
IGL_INLINE igl::SolverStatus active_set(
|
||||
const Eigen::SparseMatrix<AT>& A,
|
||||
const Eigen::PlainObjectBase<DerivedB> & B,
|
||||
const Eigen::PlainObjectBase<Derivedknown> & known,
|
||||
const Eigen::PlainObjectBase<DerivedY> & Y,
|
||||
const Eigen::MatrixBase<DerivedB> & B,
|
||||
const Eigen::MatrixBase<Derivedknown> & known,
|
||||
const Eigen::MatrixBase<DerivedY> & Y,
|
||||
const Eigen::SparseMatrix<AeqT>& Aeq,
|
||||
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
|
||||
const Eigen::MatrixBase<DerivedBeq> & Beq,
|
||||
const Eigen::SparseMatrix<AieqT>& Aieq,
|
||||
const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
|
||||
const Eigen::PlainObjectBase<Derivedlx> & lx,
|
||||
const Eigen::PlainObjectBase<Derivedux> & ux,
|
||||
const Eigen::MatrixBase<DerivedBieq> & Bieq,
|
||||
const Eigen::MatrixBase<Derivedlx> & lx,
|
||||
const Eigen::MatrixBase<Derivedux> & ux,
|
||||
const igl::active_set_params & params,
|
||||
Eigen::PlainObjectBase<DerivedZ> & Z
|
||||
);
|
||||
|
||||
@@ -16,12 +16,10 @@ IGL_INLINE void igl::adjacency_matrix(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::SparseMatrix<T>& A)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
|
||||
typedef Triplet<T> IJV;
|
||||
vector<IJV > ijv;
|
||||
typedef Eigen::Triplet<T> IJV;
|
||||
std::vector<IJV > ijv;
|
||||
ijv.reserve(F.size()*2);
|
||||
// Loop over **simplex** (i.e., **not quad**)
|
||||
for(int i = 0;i<F.rows();i++)
|
||||
@@ -71,11 +69,8 @@ IGL_INLINE void igl::adjacency_matrix(
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::SparseMatrix<T>& A)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
typedef Triplet<T> IJV;
|
||||
vector<IJV > ijv;
|
||||
typedef Eigen::Triplet<T> IJV;
|
||||
std::vector<IJV > ijv;
|
||||
ijv.reserve(C(C.size()-1)*2);
|
||||
typedef typename DerivedI::Scalar Index;
|
||||
const Index n = I.maxCoeff()+1;
|
||||
@@ -116,6 +111,8 @@ IGL_INLINE void igl::adjacency_matrix(
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 3, 1, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3>> const&, Eigen::SparseMatrix<int, 0, int>&);
|
||||
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<int, 0, int>& );
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, bool>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<bool, 0, int>&);
|
||||
|
||||
@@ -30,10 +30,10 @@ namespace igl
|
||||
/// SparseVector<double> Asum;
|
||||
/// sum(A,1,Asum);
|
||||
/// // Convert row sums into diagonal of sparse matrix
|
||||
/// SparseMatrix<double> Adiag;
|
||||
/// Eigen::SparseMatrix<double> Adiag;
|
||||
/// diag(Asum,Adiag);
|
||||
/// // Build uniform laplacian
|
||||
/// SparseMatrix<double> U;
|
||||
/// Eigen::SparseMatrix<double> U;
|
||||
/// U = A-Adiag;
|
||||
/// \endcode
|
||||
///
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace igl
|
||||
///
|
||||
/// D = all_pairs_distances(V,U)
|
||||
///
|
||||
/// @tparam matrix class like MatrixXd
|
||||
/// @tparam matrix class like Eigen::MatrixXd
|
||||
/// @param[in] V #V by dim list of points
|
||||
/// @param[in] U #U by dim list of points
|
||||
/// @param[in] squared whether to return squared distances
|
||||
|
||||
@@ -22,29 +22,31 @@ template <
|
||||
IGL_INLINE void igl::ambient_occlusion(
|
||||
const std::function<
|
||||
bool(
|
||||
const Eigen::Vector3f&,
|
||||
const Eigen::Vector3f&)
|
||||
const Eigen::Matrix<typename DerivedP::Scalar,3,1> &,
|
||||
const Eigen::Matrix<typename DerivedP::Scalar,3,1> &)
|
||||
> & shoot_ray,
|
||||
const Eigen::MatrixBase<DerivedP> & P,
|
||||
const Eigen::MatrixBase<DerivedN> & N,
|
||||
const int num_samples,
|
||||
Eigen::PlainObjectBase<DerivedS> & S)
|
||||
{
|
||||
using namespace Eigen;
|
||||
const int n = P.rows();
|
||||
// Resize output
|
||||
S.resize(n,1);
|
||||
// Embree seems to be parallel when constructing but not when tracing rays
|
||||
const MatrixXf D = random_dir_stratified(num_samples).cast<float>();
|
||||
typedef typename DerivedP::Scalar Scalar;
|
||||
typedef Eigen::Matrix<Scalar,3,1> Vector3N;
|
||||
|
||||
const Eigen::Matrix<Scalar,Eigen::Dynamic,3> D = random_dir_stratified(num_samples).cast<Scalar>();
|
||||
|
||||
const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p)
|
||||
{
|
||||
const Vector3f origin = P.row(p).template cast<float>();
|
||||
const Vector3f normal = N.row(p).template cast<float>();
|
||||
const Vector3N origin = P.row(p);
|
||||
const Vector3N normal = N.row(p);
|
||||
int num_hits = 0;
|
||||
for(int s = 0;s<num_samples;s++)
|
||||
{
|
||||
Vector3f d = D.row(s);
|
||||
Vector3N d = D.row(s);
|
||||
if(d.dot(normal) < 0)
|
||||
{
|
||||
// reverse ray
|
||||
@@ -76,17 +78,19 @@ IGL_INLINE void igl::ambient_occlusion(
|
||||
const int num_samples,
|
||||
Eigen::PlainObjectBase<DerivedS> & S)
|
||||
{
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
using Vector3S = Eigen::Matrix<Scalar,3,1>;
|
||||
const auto & shoot_ray = [&aabb,&V,&F](
|
||||
const Eigen::Vector3f& _s,
|
||||
const Eigen::Vector3f& dir)->bool
|
||||
const Eigen::Matrix<Scalar,3,1> & _s,
|
||||
const Eigen::Matrix<Scalar,3,1> & dir)->bool
|
||||
{
|
||||
Eigen::Vector3f s = _s+1e-4*dir;
|
||||
igl::Hit hit;
|
||||
Vector3S s = _s+1e-4*dir;
|
||||
igl::Hit<Scalar> hit;
|
||||
return aabb.intersect_ray(
|
||||
V,
|
||||
F,
|
||||
s .cast<typename DerivedV::Scalar>().eval(),
|
||||
dir.cast<typename DerivedV::Scalar>().eval(),
|
||||
s,
|
||||
dir,
|
||||
hit);
|
||||
};
|
||||
return ambient_occlusion(shoot_ray,P,N,num_samples,S);
|
||||
@@ -107,15 +111,17 @@ IGL_INLINE void igl::ambient_occlusion(
|
||||
const int num_samples,
|
||||
Eigen::PlainObjectBase<DerivedS> & S)
|
||||
{
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
using Vector3S = Eigen::Matrix<Scalar,3,1>;
|
||||
if(F.rows() < 100)
|
||||
{
|
||||
// Super naive
|
||||
const auto & shoot_ray = [&V,&F](
|
||||
const Eigen::Vector3f& _s,
|
||||
const Eigen::Vector3f& dir)->bool
|
||||
const Eigen::Matrix<Scalar,3,1> & _s,
|
||||
const Eigen::Matrix<Scalar,3,1> & dir)->bool
|
||||
{
|
||||
Eigen::Vector3f s = _s+1e-4*dir;
|
||||
igl::Hit hit;
|
||||
Vector3S s = _s+1e-4*dir;
|
||||
igl::Hit<Scalar> hit;
|
||||
return ray_mesh_intersect(s,dir,V,F,hit);
|
||||
};
|
||||
return ambient_occlusion(shoot_ray,P,N,num_samples,S);
|
||||
@@ -127,13 +133,12 @@ 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<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<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&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
// 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::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::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::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> >&);
|
||||
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<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 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> >&);
|
||||
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<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 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> >&);
|
||||
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<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 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<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 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> >&);
|
||||
template void igl::ambient_occlusion<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1>>(std::function<bool (Eigen::Matrix<Eigen::Matrix<float, 1, 3, 1, 1, 3>::Scalar, 3, 1, 0, 3, 1> const&, Eigen::Matrix<Eigen::Matrix<float, 1, 3, 1, 1, 3>::Scalar, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3>> const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3>> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1>>&);
|
||||
template void igl::ambient_occlusion<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1>>(std::function<bool (Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, 3, 1, 0, 3, 1> const&, Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3>> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3>> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1>>&);
|
||||
template void igl::ambient_occlusion<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1>>(std::function<bool (Eigen::Matrix<Eigen::Matrix<float, -1, -1, 0, -1, -1>::Scalar, 3, 1, 0, 3, 1> const&, Eigen::Matrix<Eigen::Matrix<float, -1, -1, 0, -1, -1>::Scalar, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1>> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1>>&);
|
||||
#endif
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace igl
|
||||
IGL_INLINE void ambient_occlusion(
|
||||
const std::function<
|
||||
bool(
|
||||
const Eigen::Vector3f&,
|
||||
const Eigen::Vector3f&)
|
||||
const Eigen::Matrix<typename DerivedP::Scalar,3,1>&,
|
||||
const Eigen::Matrix<typename DerivedP::Scalar,3,1>&)
|
||||
> & shoot_ray,
|
||||
const Eigen::MatrixBase<DerivedP> & P,
|
||||
const Eigen::MatrixBase<DerivedN> & N,
|
||||
|
||||
+21
-25
@@ -35,8 +35,6 @@ IGL_INLINE bool igl::arap_precomputation(
|
||||
const Eigen::MatrixBase<Derivedb> & b,
|
||||
ARAPData & data)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
typedef typename DerivedF::Scalar Integer;
|
||||
// number of vertices
|
||||
@@ -53,14 +51,14 @@ IGL_INLINE bool igl::arap_precomputation(
|
||||
data.dim = dim;
|
||||
//assert(dim == 3 && "Only 3d supported");
|
||||
// Defaults
|
||||
data.f_ext = MatrixXd::Zero(n,data.dim);
|
||||
data.f_ext = Eigen::MatrixXd::Zero(n,data.dim);
|
||||
|
||||
assert(data.dim <= V.cols() && "solve dim should be <= embedding");
|
||||
bool flat = (V.cols() - data.dim)==1;
|
||||
|
||||
MatrixXX<Scalar> plane_V;
|
||||
MatrixXX<Integer> plane_F;
|
||||
typedef SparseMatrix<Scalar> SparseMatrixS;
|
||||
typedef Eigen::SparseMatrix<Scalar> SparseMatrixS;
|
||||
SparseMatrixS ref_map,ref_map_dim;
|
||||
if(flat)
|
||||
{
|
||||
@@ -106,7 +104,7 @@ IGL_INLINE bool igl::arap_precomputation(
|
||||
|
||||
// Get group sum scatter matrix, when applied sums all entries of the same
|
||||
// group according to G
|
||||
SparseMatrix<double> G_sum;
|
||||
Eigen::SparseMatrix<double> G_sum;
|
||||
if(data.G.size() == 0)
|
||||
{
|
||||
if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
|
||||
@@ -122,7 +120,7 @@ IGL_INLINE bool igl::arap_precomputation(
|
||||
if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
|
||||
{
|
||||
Eigen::Matrix<int,Eigen::Dynamic,1> GG;
|
||||
MatrixXi GF(F.rows(),F.cols());
|
||||
Eigen::MatrixXi GF(F.rows(),F.cols());
|
||||
for(int j = 0;j<F.cols();j++)
|
||||
{
|
||||
GF.col(j) = data.G(F.col(j));
|
||||
@@ -133,7 +131,7 @@ IGL_INLINE bool igl::arap_precomputation(
|
||||
//printf("group_sum_matrix()\n");
|
||||
group_sum_matrix(data.G,G_sum);
|
||||
}
|
||||
SparseMatrix<double> G_sum_dim;
|
||||
Eigen::SparseMatrix<double> G_sum_dim;
|
||||
repdiag(G_sum,data.dim,G_sum_dim);
|
||||
assert(G_sum_dim.cols() == data.CSM.rows());
|
||||
data.CSM = (G_sum_dim * data.CSM).eval();
|
||||
@@ -146,24 +144,24 @@ IGL_INLINE bool igl::arap_precomputation(
|
||||
}
|
||||
assert(data.K.rows() == data.n*data.dim);
|
||||
|
||||
SparseMatrix<double> Q = (-L).eval();
|
||||
Eigen::SparseMatrix<double> Q = (-L).eval();
|
||||
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
const double h = data.h;
|
||||
assert(h != 0);
|
||||
SparseMatrix<double> M;
|
||||
Eigen::SparseMatrix<double> M;
|
||||
massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,data.M);
|
||||
const double dw = (1./data.ym)*(h*h);
|
||||
SparseMatrix<double> DQ = dw * 1./(h*h)*data.M;
|
||||
Eigen::SparseMatrix<double> DQ = dw * 1./(h*h)*data.M;
|
||||
Q += DQ;
|
||||
// Dummy external forces
|
||||
data.f_ext = MatrixXd::Zero(n,data.dim);
|
||||
data.vel = MatrixXd::Zero(n,data.dim);
|
||||
data.f_ext = Eigen::MatrixXd::Zero(n,data.dim);
|
||||
data.vel = Eigen::MatrixXd::Zero(n,data.dim);
|
||||
}
|
||||
|
||||
return min_quad_with_fixed_precompute(
|
||||
Q,b,SparseMatrix<double>(),true,data.solver_data);
|
||||
Q,b,Eigen::SparseMatrix<double>(),true,data.solver_data);
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -174,8 +172,6 @@ IGL_INLINE bool igl::arap_solve(
|
||||
ARAPData & data,
|
||||
Eigen::MatrixBase<DerivedU> & U)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
assert(data.b.size() == bc.rows());
|
||||
assert(U.size() != 0 && "U cannot be empty");
|
||||
assert(U.cols() == data.dim && "U.cols() match data.dim");
|
||||
@@ -185,9 +181,9 @@ IGL_INLINE bool igl::arap_solve(
|
||||
const int n = data.n;
|
||||
int iter = 0;
|
||||
// changes each arap iteration
|
||||
MatrixXd U_prev = U;
|
||||
Eigen::MatrixXd U_prev = U;
|
||||
// doesn't change for fixed with_dynamics timestep
|
||||
MatrixXd U0;
|
||||
Eigen::MatrixXd U0;
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
U0 = U_prev;
|
||||
@@ -204,13 +200,13 @@ IGL_INLINE bool igl::arap_solve(
|
||||
const auto & Udim = U.replicate(data.dim,1);
|
||||
assert(U.cols() == data.dim);
|
||||
// As if U.col(2) was 0
|
||||
MatrixXd S = data.CSM * Udim;
|
||||
Eigen::MatrixXd S = data.CSM * Udim;
|
||||
// THIS NORMALIZATION IS IMPORTANT TO GET SINGLE PRECISION SVD CODE TO WORK
|
||||
// CORRECTLY.
|
||||
S /= S.array().abs().maxCoeff();
|
||||
|
||||
const int Rdim = data.dim;
|
||||
MatrixXd R(Rdim,data.CSM.rows());
|
||||
Eigen::MatrixXd R(Rdim,data.CSM.rows());
|
||||
if(R.rows() == 2)
|
||||
{
|
||||
fit_rotations_planar(S,R);
|
||||
@@ -225,14 +221,14 @@ IGL_INLINE bool igl::arap_solve(
|
||||
}
|
||||
//for(int k = 0;k<(data.CSM.rows()/dim);k++)
|
||||
//{
|
||||
// R.block(0,dim*k,dim,dim) = MatrixXd::Identity(dim,dim);
|
||||
// R.block(0,dim*k,dim,dim) = Eigen::MatrixXd::Identity(dim,dim);
|
||||
//}
|
||||
|
||||
|
||||
// Number of rotations: #vertices or #elements
|
||||
int num_rots = data.K.cols()/Rdim/Rdim;
|
||||
// distribute group rotations to vertices in each group
|
||||
MatrixXd eff_R;
|
||||
Eigen::MatrixXd eff_R;
|
||||
if(data.G.size() == 0)
|
||||
{
|
||||
// copy...
|
||||
@@ -247,7 +243,7 @@ IGL_INLINE bool igl::arap_solve(
|
||||
}
|
||||
}
|
||||
|
||||
MatrixXd Dl;
|
||||
Eigen::MatrixXd Dl;
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
assert(data.M.rows() == n &&
|
||||
@@ -263,13 +259,13 @@ IGL_INLINE bool igl::arap_solve(
|
||||
Dl = dw * (1./(h*h)*data.M*(-U0 - h*data.vel) - data.f_ext);
|
||||
}
|
||||
|
||||
VectorXd Rcol;
|
||||
Eigen::VectorXd Rcol;
|
||||
columnize(eff_R,num_rots,2,Rcol);
|
||||
VectorXd Bcol = -data.K * Rcol;
|
||||
Eigen::VectorXd Bcol = -data.K * Rcol;
|
||||
assert(Bcol.size() == data.n*data.dim);
|
||||
for(int c = 0;c<data.dim;c++)
|
||||
{
|
||||
VectorXd Uc,Bc,bcc,Beq;
|
||||
Eigen::VectorXd Uc,Bc,bcc,Beq;
|
||||
Bc = Bcol.block(c*n,0,n,1);
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
|
||||
+29
-32
@@ -66,8 +66,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
|
||||
ArapDOFData<LbsMatrixType, SSCALAR> & data)
|
||||
{
|
||||
using namespace Eigen;
|
||||
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
|
||||
typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
|
||||
// number of mesh (domain) vertices
|
||||
int n = V.rows();
|
||||
// cache problem size
|
||||
@@ -95,11 +94,11 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
//printf("n=%d; dim=%d; m=%d;\n",n,data.dim,data.m);
|
||||
|
||||
// Build cotangent laplacian
|
||||
SparseMatrix<double> Lcot;
|
||||
Eigen::SparseMatrix<double> Lcot;
|
||||
//printf("cotmatrix()\n");
|
||||
cotmatrix(V,F,Lcot);
|
||||
// Discrete laplacian (should be minus matlab version)
|
||||
SparseMatrix<double> Lapl = -2.0*Lcot;
|
||||
Eigen::SparseMatrix<double> Lapl = -2.0*Lcot;
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"LaplIJV=["<<endl;print_ijv(Lapl,1);cout<<endl<<"];"<<
|
||||
endl<<"Lapl=sparse(LaplIJV(:,1),LaplIJV(:,2),LaplIJV(:,3),"<<
|
||||
@@ -108,7 +107,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
|
||||
// Get group sum scatter matrix, when applied sums all entries of the same
|
||||
// group according to G
|
||||
SparseMatrix<double> G_sum;
|
||||
Eigen::SparseMatrix<double> G_sum;
|
||||
if(G.size() == 0)
|
||||
{
|
||||
speye(n,G_sum);
|
||||
@@ -118,7 +117,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
Eigen::Matrix<int,Eigen::Dynamic,1> GG;
|
||||
if(data.energy == ARAP_ENERGY_TYPE_ELEMENTS)
|
||||
{
|
||||
MatrixXi GF(F.rows(),F.cols());
|
||||
Eigen::MatrixXi GF(F.rows(),F.cols());
|
||||
for(int j = 0;j<F.cols();j++)
|
||||
{
|
||||
GF.col(j) = G(F.col(j));
|
||||
@@ -140,7 +139,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
|
||||
// Get covariance scatter matrix, when applied collects the covariance matrices
|
||||
// used to fit rotations to during optimization
|
||||
SparseMatrix<double> CSM;
|
||||
Eigen::SparseMatrix<double> CSM;
|
||||
//printf("covariance_scatter_matrix()\n");
|
||||
covariance_scatter_matrix(V,F,data.energy,CSM);
|
||||
#ifdef EXTREME_VERBOSE
|
||||
@@ -167,7 +166,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
// S((k-1)*dim + 1:dim,:)
|
||||
|
||||
// Apply group sum to each dimension's block of covariance scatter matrix
|
||||
SparseMatrix<double> G_sum_dim;
|
||||
Eigen::SparseMatrix<double> G_sum_dim;
|
||||
repdiag(G_sum,data.dim,G_sum_dim);
|
||||
CSM = (G_sum_dim * CSM).eval();
|
||||
#ifdef EXTREME_VERBOSE
|
||||
@@ -205,7 +204,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
//printf("CSM_M(): slice\n");
|
||||
#if __cplusplus >= 201703L
|
||||
// Check if LbsMatrixType is a sparse matrix
|
||||
if constexpr (std::is_base_of<SparseMatrixBase<LbsMatrixType>, LbsMatrixType>::value)
|
||||
if constexpr (std::is_base_of<Eigen::SparseMatrixBase<LbsMatrixType>, LbsMatrixType>::value)
|
||||
{
|
||||
slice(M,(span_n.array()+i*n).matrix().eval(),span_mlbs_cols,M_i);
|
||||
}
|
||||
@@ -214,7 +213,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
M_i = M((span_n.array()+i*n).eval(),span_mlbs_cols);
|
||||
}
|
||||
#else
|
||||
constexpr bool LbsMatrixTypeIsSparse = std::is_base_of<SparseMatrixBase<LbsMatrixType>, LbsMatrixType>::value;
|
||||
constexpr bool LbsMatrixTypeIsSparse = std::is_base_of<Eigen::SparseMatrixBase<LbsMatrixType>, LbsMatrixType>::value;
|
||||
arap_dof_slice_helper<LbsMatrixType,LbsMatrixTypeIsSparse>::slice(M,(span_n.array()+i*n).matrix().eval(),span_mlbs_cols,M_i);
|
||||
#endif
|
||||
LbsMatrixType M_i_dim;
|
||||
@@ -222,7 +221,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
assert(data.CSM_M[i].cols() == M.cols());
|
||||
for(int j = 0;j<data.dim;j++)
|
||||
{
|
||||
SparseMatrix<double> CSMj;
|
||||
Eigen::SparseMatrix<double> CSMj;
|
||||
//printf("CSM_M(): slice\n");
|
||||
slice(
|
||||
CSM,
|
||||
@@ -236,7 +235,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
{
|
||||
// Convert to full
|
||||
//printf("CSM_M(): full\n");
|
||||
MatrixXd CSMjM_ifull(CSMjM_i);
|
||||
Eigen::MatrixXd CSMjM_ifull(CSMjM_i);
|
||||
// printf("CSM_M[%d]: %d %d\n",i,data.CSM_M[i].rows(),data.CSM_M[i].cols());
|
||||
// printf("CSM_M[%d].block(%d*%d=%d,0,%d,%d): %d %d\n",i,j,k,CSMjM_i.rows(),CSMjM_i.cols(),
|
||||
// data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).rows(),
|
||||
@@ -256,7 +255,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
|
||||
// precompute arap_rhs matrix
|
||||
//printf("arap_rhs()\n");
|
||||
SparseMatrix<double> K;
|
||||
Eigen::SparseMatrix<double> K;
|
||||
arap_rhs(V,F,V.cols(),data.energy,K);
|
||||
//#ifdef EXTREME_VERBOSE
|
||||
// cout<<"KIJV=["<<endl;print_ijv(K,1);cout<<endl<<"];"<<
|
||||
@@ -264,8 +263,8 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
// K.rows()<<","<<K.cols()<<");"<<endl;
|
||||
//#endif
|
||||
// Precompute left muliplication by M and right multiplication by G_sum
|
||||
SparseMatrix<double> G_sumT = G_sum.transpose();
|
||||
SparseMatrix<double> G_sumT_dim_dim;
|
||||
Eigen::SparseMatrix<double> G_sumT = G_sum.transpose();
|
||||
Eigen::SparseMatrix<double> G_sumT_dim_dim;
|
||||
repdiag(G_sumT,data.dim*data.dim,G_sumT_dim_dim);
|
||||
LbsMatrixType MT = M.transpose();
|
||||
// If this is a bottle neck then consider reordering matrix multiplication
|
||||
@@ -278,7 +277,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
|
||||
// Precompute system matrix
|
||||
//printf("A()\n");
|
||||
SparseMatrix<double> A;
|
||||
Eigen::SparseMatrix<double> A;
|
||||
repdiag(Lapl,data.dim,A);
|
||||
data.Q = MT * (A * M);
|
||||
//#ifdef EXTREME_VERBOSE
|
||||
@@ -291,19 +290,19 @@ IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
//if(data.with_dynamics)
|
||||
//{
|
||||
// Build cotangent laplacian
|
||||
SparseMatrix<double> Mass;
|
||||
Eigen::SparseMatrix<double> Mass;
|
||||
//printf("massmatrix()\n");
|
||||
massmatrix(V,F,(F.cols()>3?MASSMATRIX_TYPE_BARYCENTRIC:MASSMATRIX_TYPE_VORONOI),Mass);
|
||||
//cout<<"MIJV=["<<endl;print_ijv(Mass,1);cout<<endl<<"];"<<
|
||||
// endl<<"M=sparse(MIJV(:,1),MIJV(:,2),MIJV(:,3),"<<
|
||||
// Mass.rows()<<","<<Mass.cols()<<");"<<endl;
|
||||
//speye(data.n,Mass);
|
||||
SparseMatrix<double> Mass_rep;
|
||||
Eigen::SparseMatrix<double> Mass_rep;
|
||||
repdiag(Mass,data.dim,Mass_rep);
|
||||
|
||||
// Multiply either side by weights matrix (should be dense)
|
||||
data.Mass_tilde = MT * Mass_rep * M;
|
||||
MatrixXd ones(data.dim*data.n,data.dim);
|
||||
Eigen::MatrixXd ones(data.dim*data.n,data.dim);
|
||||
for(int i = 0;i<data.n;i++)
|
||||
{
|
||||
for(int d = 0;d<data.dim;d++)
|
||||
@@ -531,8 +530,7 @@ IGL_INLINE bool igl::arap_dof_recomputation(
|
||||
const Eigen::SparseMatrix<double> & A_eq,
|
||||
ArapDOFData<LbsMatrixType, SSCALAR> & data)
|
||||
{
|
||||
using namespace Eigen;
|
||||
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
|
||||
typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
|
||||
|
||||
LbsMatrixType * Q;
|
||||
LbsMatrixType Qdyn;
|
||||
@@ -577,9 +575,9 @@ IGL_INLINE bool igl::arap_dof_recomputation(
|
||||
|
||||
// Compute dense solve matrix (alternative of matrix factorization)
|
||||
//printf("kkt_inverse()\n");
|
||||
MatrixXd Qfull(*Q);
|
||||
MatrixXd A_eqfull(A_eq);
|
||||
MatrixXd M_Solve;
|
||||
Eigen::MatrixXd Qfull(*Q);
|
||||
Eigen::MatrixXd A_eqfull(A_eq);
|
||||
Eigen::MatrixXd M_Solve;
|
||||
|
||||
double timer0_start = get_seconds();
|
||||
bool use_lu = data.effective_dim != 2;
|
||||
@@ -646,8 +644,7 @@ IGL_INLINE bool igl::arap_dof_update(
|
||||
Eigen::MatrixXd & L
|
||||
)
|
||||
{
|
||||
using namespace Eigen;
|
||||
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
|
||||
typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
|
||||
#ifdef ARAP_GLOBAL_TIMING
|
||||
double timer_start = get_seconds();
|
||||
#endif
|
||||
@@ -700,9 +697,9 @@ IGL_INLINE bool igl::arap_dof_update(
|
||||
MatrixXS S(k*data.dim,data.dim);
|
||||
MatrixXS R(data.dim,data.dim*k);
|
||||
Eigen::Matrix<SSCALAR,Eigen::Dynamic,1> Rcol(data.dim * data.dim * k);
|
||||
Matrix<SSCALAR,Dynamic,1> B_eq_SSCALAR = B_eq.cast<SSCALAR>();
|
||||
Matrix<SSCALAR,Dynamic,1> L0SSCALAR = L0.cast<SSCALAR>();
|
||||
Matrix<SSCALAR,Dynamic,1> B_eq_fix_SSCALAR = L0SSCALAR(data.fixed_dim);
|
||||
Eigen::Matrix<SSCALAR ,Eigen::Dynamic,1> B_eq_SSCALAR = B_eq.cast<SSCALAR>();
|
||||
Eigen::Matrix<SSCALAR ,Eigen::Dynamic,1> L0SSCALAR = L0.cast<SSCALAR>();
|
||||
Eigen::Matrix<SSCALAR ,Eigen::Dynamic,1> B_eq_fix_SSCALAR = L0SSCALAR(data.fixed_dim);
|
||||
//MatrixXS rhsFull(Rcol.rows() + B_eq.rows() + B_eq_fix_SSCALAR.rows(), 1);
|
||||
|
||||
MatrixXS Lsep(data.m*(data.dim + 1), 3);
|
||||
@@ -831,13 +828,13 @@ IGL_INLINE bool igl::arap_dof_update(
|
||||
( (-1.0/(data.h*data.h)) * data.L0.array() +
|
||||
(1.0/(data.h)) * data.Lvel0.array()
|
||||
).matrix();
|
||||
MatrixXd temp_d = temp.template cast<double>();
|
||||
Eigen::MatrixXd temp_d = temp.template cast<double>();
|
||||
|
||||
MatrixXd temp_g = data.fgrav*(data.grav_mag*data.grav_dir);
|
||||
Eigen::MatrixXd temp_g = data.fgrav*(data.grav_mag*data.grav_dir);
|
||||
|
||||
assert(data.fext.rows() == temp_g.rows());
|
||||
assert(data.fext.cols() == temp_g.cols());
|
||||
MatrixXd temp2 = data.Mass_tilde * temp_d + temp_g + data.fext.template cast<double>();
|
||||
Eigen::MatrixXd temp2 = data.Mass_tilde * temp_d + temp_g + data.fext.template cast<double>();
|
||||
MatrixXS temp2_f = temp2.template cast<SSCALAR>();
|
||||
L_part1_dyn = data.Pi_1 * temp2_f;
|
||||
L_part1.array() = L_part1.array() + L_part1_dyn.array();
|
||||
|
||||
@@ -45,16 +45,14 @@ IGL_INLINE void igl::arap_linear_block_spokes(
|
||||
{
|
||||
typedef typename MatK::Scalar Scalar;
|
||||
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// simplex size (3: triangles, 4: tetrahedra)
|
||||
int simplex_size = F.cols();
|
||||
// Number of elements
|
||||
int m = F.rows();
|
||||
// Temporary output
|
||||
Matrix<int,Dynamic,2> edges;
|
||||
Eigen::Matrix<int ,Eigen::Dynamic,2> edges;
|
||||
Kd.resize(V.rows(), V.rows());
|
||||
vector<Triplet<Scalar> > Kd_IJV;
|
||||
std::vector<Eigen::Triplet<Scalar> > Kd_IJV;
|
||||
if(simplex_size == 3)
|
||||
{
|
||||
// triangles
|
||||
@@ -80,7 +78,7 @@ IGL_INLINE void igl::arap_linear_block_spokes(
|
||||
3,2;
|
||||
}
|
||||
// gather cotangent weights
|
||||
Matrix<Scalar,Dynamic,Dynamic> C;
|
||||
Eigen::Matrix<Scalar ,Eigen::Dynamic ,Eigen::Dynamic> C;
|
||||
cotmatrix_entries(V,F,C);
|
||||
// should have weights for each edge
|
||||
assert(C.cols() == edges.rows());
|
||||
@@ -93,10 +91,10 @@ IGL_INLINE void igl::arap_linear_block_spokes(
|
||||
int source = F(i,edges(e,0));
|
||||
int dest = F(i,edges(e,1));
|
||||
double v = 0.5*C(i,e)*(V(source,d)-V(dest,d));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(source,dest,v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(dest,source,-v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(source,dest,v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(dest,source,-v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(source,source,v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(dest,dest,-v));
|
||||
}
|
||||
}
|
||||
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
|
||||
@@ -112,16 +110,14 @@ IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
|
||||
{
|
||||
typedef typename MatK::Scalar Scalar;
|
||||
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// simplex size (3: triangles, 4: tetrahedra)
|
||||
int simplex_size = F.cols();
|
||||
// Number of elements
|
||||
int m = F.rows();
|
||||
// Temporary output
|
||||
Kd.resize(V.rows(), V.rows());
|
||||
vector<Triplet<Scalar> > Kd_IJV;
|
||||
Matrix<int,Dynamic,2> edges;
|
||||
std::vector<Eigen::Triplet<Scalar> > Kd_IJV;
|
||||
Eigen::Matrix<int ,Eigen::Dynamic,2> edges;
|
||||
if(simplex_size == 3)
|
||||
{
|
||||
// triangles
|
||||
@@ -149,7 +145,7 @@ IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
|
||||
assert(false);
|
||||
}
|
||||
// gather cotangent weights
|
||||
Matrix<Scalar,Dynamic,Dynamic> C;
|
||||
Eigen::Matrix<Scalar ,Eigen::Dynamic ,Eigen::Dynamic> C;
|
||||
cotmatrix_entries(V,F,C);
|
||||
// should have weights for each edge
|
||||
assert(C.cols() == edges.rows());
|
||||
@@ -169,18 +165,18 @@ IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
|
||||
int Rd = F(i,edges(f,1));
|
||||
if(Rs == source && Rd == dest)
|
||||
{
|
||||
Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,-v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(Rs,Rd,v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(Rd,Rs,-v));
|
||||
}else if(Rd == source)
|
||||
{
|
||||
Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(Rd,Rs,v));
|
||||
}else if(Rs == dest)
|
||||
{
|
||||
Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,-v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(Rs,Rd,-v));
|
||||
}
|
||||
}
|
||||
Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(source,source,v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(dest,dest,-v));
|
||||
}
|
||||
}
|
||||
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
|
||||
@@ -195,16 +191,14 @@ IGL_INLINE void igl::arap_linear_block_elements(
|
||||
MatK & Kd)
|
||||
{
|
||||
typedef typename MatK::Scalar Scalar;
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// simplex size (3: triangles, 4: tetrahedra)
|
||||
int simplex_size = F.cols();
|
||||
// Number of elements
|
||||
int m = F.rows();
|
||||
// Temporary output
|
||||
Kd.resize(V.rows(), F.rows());
|
||||
vector<Triplet<Scalar> > Kd_IJV;
|
||||
Matrix<int,Dynamic,2> edges;
|
||||
std::vector<Eigen::Triplet<Scalar> > Kd_IJV;
|
||||
Eigen::Matrix<int ,Eigen::Dynamic,2> edges;
|
||||
if(simplex_size == 3)
|
||||
{
|
||||
// triangles
|
||||
@@ -230,7 +224,7 @@ IGL_INLINE void igl::arap_linear_block_elements(
|
||||
3,2;
|
||||
}
|
||||
// gather cotangent weights
|
||||
Matrix<Scalar,Dynamic,Dynamic> C;
|
||||
Eigen::Matrix<Scalar ,Eigen::Dynamic ,Eigen::Dynamic> C;
|
||||
cotmatrix_entries(V,F,C);
|
||||
// should have weights for each edge
|
||||
assert(C.cols() == edges.rows());
|
||||
@@ -243,8 +237,8 @@ IGL_INLINE void igl::arap_linear_block_elements(
|
||||
int source = F(i,edges(e,0));
|
||||
int dest = F(i,edges(e,1));
|
||||
double v = C(i,e)*(V(source,d)-V(dest,d));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(source,i,v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(dest,i,-v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(source,i,v));
|
||||
Kd_IJV.push_back(Eigen::Triplet<Scalar>(dest,i,-v));
|
||||
}
|
||||
}
|
||||
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
|
||||
|
||||
@@ -20,8 +20,6 @@ IGL_INLINE void igl::arap_rhs(
|
||||
const igl::ARAPEnergyType energy,
|
||||
Eigen::SparseCompressedBase<DerivedK>& K)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// Number of dimensions
|
||||
int Vdim = V.cols();
|
||||
//// Number of mesh vertices
|
||||
@@ -49,7 +47,7 @@ IGL_INLINE void igl::arap_rhs(
|
||||
return;
|
||||
}
|
||||
|
||||
DerivedK KX,KY,KZ;
|
||||
Eigen::SparseMatrix<typename DerivedK::Scalar> KX,KY,KZ;
|
||||
arap_linear_block(V,F,0,energy,KX);
|
||||
arap_linear_block(V,F,1,energy,KY);
|
||||
if(Vdim == 2)
|
||||
@@ -63,7 +61,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)
|
||||
{
|
||||
DerivedK ZZ(KX.rows()*2,KX.cols());
|
||||
Eigen::SparseMatrix<typename DerivedK::Scalar> ZZ(KX.rows()*2,KX.cols());
|
||||
K = cat(2,cat(2,
|
||||
cat(2,repdiag(KX,dim),ZZ),
|
||||
cat(2,repdiag(KY,dim),ZZ)),
|
||||
@@ -92,4 +90,4 @@ IGL_INLINE void igl::arap_rhs(
|
||||
|
||||
#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
|
||||
#endif
|
||||
|
||||
@@ -15,9 +15,9 @@ namespace igl
|
||||
/// Move a scalar field defined on edges to vertices by averaging
|
||||
///
|
||||
/// @param[in] F #F by 3 triangle mesh connectivity
|
||||
/// @param[in] E #E by 3 mapping from each halfedge to each edge
|
||||
/// @param[in] oE #E by 3 orientation as generated by orient_halfedges
|
||||
/// @param[in] uE #E by 1 list of scalars
|
||||
/// @param[in] E #F by 3 mapping from each halfedge to each edge
|
||||
/// @param[in] oE #F by 3 orientation as generated by orient_halfedges
|
||||
/// @param[in] uE #uE by 1 list of scalars
|
||||
/// @param[out] uV #V by 1 list of scalar defined on vertices
|
||||
///
|
||||
/// \see orient_halfedges
|
||||
|
||||
@@ -17,9 +17,9 @@ namespace igl
|
||||
{
|
||||
/// Compute the average edge length for the given triangle mesh
|
||||
///
|
||||
/// @tparam DerivedV derived from vertex positions matrix type: i.e. MatrixXd
|
||||
/// @tparam DerivedF derived from face indices matrix type: i.e. MatrixXi
|
||||
/// @tparam DerivedL derived from edge lengths matrix type: i.e. MatrixXd
|
||||
/// @tparam DerivedV derived from vertex positions matrix type: i.e. Eigen::MatrixXd
|
||||
/// @tparam DerivedF derived from face indices matrix type: i.e. Eigen::MatrixXi
|
||||
/// @tparam DerivedL derived from edge lengths matrix type: i.e. Eigen::MatrixXd
|
||||
/// @param[in] V #V by dim list of mesh vertex positions
|
||||
/// @param[in] F #F by simplex-size list of mesh faces (must be simplex)
|
||||
/// @return average edge length
|
||||
|
||||
@@ -60,4 +60,5 @@ template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::M
|
||||
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> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -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&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1>>&);
|
||||
#endif
|
||||
|
||||
@@ -23,7 +23,6 @@ IGL_INLINE void igl::barycentric_coordinates(
|
||||
const Eigen::MatrixBase<DerivedD> & D,
|
||||
Eigen::PlainObjectBase<DerivedL> & L)
|
||||
{
|
||||
using namespace Eigen;
|
||||
assert(P.cols() == 3 && "query must be in 3d");
|
||||
assert(A.cols() == 3 && "corners must be in 3d");
|
||||
assert(B.cols() == 3 && "corners must be in 3d");
|
||||
@@ -33,7 +32,7 @@ IGL_INLINE void igl::barycentric_coordinates(
|
||||
assert(A.rows() == B.rows() && "Corners must be same size");
|
||||
assert(A.rows() == C.rows() && "Corners must be same size");
|
||||
assert(A.rows() == D.rows() && "Corners must be same size");
|
||||
typedef Matrix<typename DerivedL::Scalar,DerivedL::RowsAtCompileTime,1>
|
||||
typedef Eigen::Matrix<typename DerivedL::Scalar,DerivedL::RowsAtCompileTime,1>
|
||||
VectorXS;
|
||||
// Total volume
|
||||
VectorXS vol,LA,LB,LC,LD;
|
||||
@@ -60,7 +59,6 @@ IGL_INLINE void igl::barycentric_coordinates(
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedL> & L)
|
||||
{
|
||||
using namespace Eigen;
|
||||
#ifndef NDEBUG
|
||||
const int DIM = P.cols();
|
||||
assert(A.cols() == DIM && "corners must be in same dimension as query");
|
||||
|
||||
+26
-25
@@ -26,9 +26,8 @@ igl::BBWData::BBWData():
|
||||
|
||||
void igl::BBWData::print()
|
||||
{
|
||||
using namespace std;
|
||||
cout<<"partition_unity: "<<partition_unity<<endl;
|
||||
cout<<"W0=["<<endl<<W0<<endl<<"];"<<endl;
|
||||
std::cout<<"partition_unity: "<<partition_unity<<std::endl;
|
||||
std::cout<<"W0=["<<std::endl<<W0<<std::endl<<"];"<<std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,16 +38,14 @@ template <
|
||||
typename Derivedbc,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool igl::bbw(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedEle> & Ele,
|
||||
const Eigen::PlainObjectBase<Derivedb> & b,
|
||||
const Eigen::PlainObjectBase<Derivedbc> & bc,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<Derivedb> & b,
|
||||
const Eigen::MatrixBase<Derivedbc> & bc,
|
||||
igl::BBWData & data,
|
||||
Eigen::PlainObjectBase<DerivedW> & W
|
||||
)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
assert(!data.partition_unity && "partition_unity not implemented yet");
|
||||
// number of domain vertices
|
||||
int n = V.rows();
|
||||
@@ -59,23 +56,23 @@ IGL_INLINE bool igl::bbw(
|
||||
harmonic(V,Ele,2,Q);
|
||||
W.derived().resize(n,m);
|
||||
// No linear terms
|
||||
VectorXd c = VectorXd::Zero(n);
|
||||
Eigen::VectorXd c = Eigen::VectorXd::Zero(n);
|
||||
// No linear constraints
|
||||
SparseMatrix<typename DerivedW::Scalar> A(0,n),Aeq(0,n),Aieq(0,n);
|
||||
VectorXd Beq(0,1),Bieq(0,1);
|
||||
Eigen::SparseMatrix<typename DerivedW::Scalar> A(0,n),Aeq(0,n),Aieq(0,n);
|
||||
Eigen::VectorXd Beq(0,1),Bieq(0,1);
|
||||
// Upper and lower box constraints (Constant bounds)
|
||||
VectorXd ux = VectorXd::Ones(n);
|
||||
VectorXd lx = VectorXd::Zero(n);
|
||||
Eigen::VectorXd ux = Eigen::VectorXd::Ones(n);
|
||||
Eigen::VectorXd lx = Eigen::VectorXd::Zero(n);
|
||||
active_set_params eff_params = data.active_set_params;
|
||||
if(data.verbosity >= 1)
|
||||
{
|
||||
cout<<"BBW: max_iter: "<<data.active_set_params.max_iter<<endl;
|
||||
cout<<"BBW: eff_max_iter: "<<eff_params.max_iter<<endl;
|
||||
std::cout<<"BBW: max_iter: "<<data.active_set_params.max_iter<<std::endl;
|
||||
std::cout<<"BBW: eff_max_iter: "<<eff_params.max_iter<<std::endl;
|
||||
}
|
||||
if(data.verbosity >= 1)
|
||||
{
|
||||
cout<<"BBW: Computing initial weights for "<<m<<" handle"<<
|
||||
(m!=1?"s":"")<<"."<<endl;
|
||||
std::cout<<"BBW: Computing initial weights for "<<m<<" handle"<<
|
||||
(m!=1?"s":"")<<"."<<std::endl;
|
||||
}
|
||||
min_quad_with_fixed_data<typename DerivedW::Scalar > mqwf;
|
||||
min_quad_with_fixed_precompute(Q,b,Aeq,true,mqwf);
|
||||
@@ -95,11 +92,11 @@ IGL_INLINE bool igl::bbw(
|
||||
if(data.verbosity >= 1)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(critical);
|
||||
cout<<"BBW: Computing weight for handle "<<i+1<<" out of "<<m<<
|
||||
"."<<endl;
|
||||
std::cout<<"BBW: Computing weight for handle "<<i+1<<" out of "<<m<<
|
||||
"."<<std::endl;
|
||||
}
|
||||
VectorXd bci = bc.col(i);
|
||||
VectorXd Wi;
|
||||
Eigen::VectorXd bci = bc.col(i);
|
||||
Eigen::VectorXd Wi;
|
||||
// use initial guess
|
||||
Wi = W.col(i);
|
||||
SolverStatus ret = active_set(
|
||||
@@ -109,11 +106,15 @@ IGL_INLINE bool igl::bbw(
|
||||
case SOLVER_STATUS_CONVERGED:
|
||||
break;
|
||||
case SOLVER_STATUS_MAX_ITER:
|
||||
#ifdef IGL_BBW_DEBUG
|
||||
cerr<<"active_set: max iter without convergence."<<endl;
|
||||
#endif
|
||||
break;
|
||||
case SOLVER_STATUS_ERROR:
|
||||
default:
|
||||
#ifdef IGL_BBW_DEBUG
|
||||
cerr<<"active_set error."<<endl;
|
||||
#endif
|
||||
error = true;
|
||||
}
|
||||
W.col(i) = Wi;
|
||||
@@ -129,8 +130,8 @@ IGL_INLINE bool igl::bbw(
|
||||
const double min_rowsum = W.rowwise().sum().array().abs().minCoeff();
|
||||
if(min_rowsum < 0.1)
|
||||
{
|
||||
cerr<<"bbw.cpp: Warning, minimum row sum is very low. Consider more "
|
||||
"active set iterations or enforcing partition of unity."<<endl;
|
||||
std::cerr<<"bbw.cpp: Warning, minimum row sum is very low. Consider more "
|
||||
"active set iterations or enforcing partition of unity."<<std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -139,6 +140,6 @@ IGL_INLINE bool igl::bbw(
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::bbw<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::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> > const&, igl::BBWData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::bbw<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&, igl::BBWData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&);
|
||||
#endif
|
||||
|
||||
|
||||
+9
-9
@@ -40,11 +40,11 @@ namespace igl
|
||||
/// Compute Bounded Biharmonic Weights on a given domain (V,Ele) with a given
|
||||
/// set of boundary conditions
|
||||
///
|
||||
/// @tparam DerivedV derived type of eigen matrix for V (e.g. MatrixXd)
|
||||
/// @tparam DerivedF derived type of eigen matrix for F (e.g. MatrixXi)
|
||||
/// @tparam Derivedb derived type of eigen matrix for b (e.g. VectorXi)
|
||||
/// @tparam Derivedbc derived type of eigen matrix for bc (e.g. MatrixXd)
|
||||
/// @tparam DerivedW derived type of eigen matrix for W (e.g. MatrixXd)
|
||||
/// @tparam DerivedV derived type of eigen matrix for V (e.g. Eigen::MatrixXd)
|
||||
/// @tparam DerivedF derived type of eigen matrix for F (e.g. Eigen::MatrixXi)
|
||||
/// @tparam Derivedb derived type of eigen matrix for b (e.g. Eigen::VectorXi)
|
||||
/// @tparam Derivedbc derived type of eigen matrix for bc (e.g. Eigen::MatrixXd)
|
||||
/// @tparam DerivedW derived type of eigen matrix for W (e.g. Eigen::MatrixXd)
|
||||
/// @param[in] V #V by dim vertex positions
|
||||
/// @param[in] Ele #Elements by simplex-size list of element indices
|
||||
/// @param[in] b #b boundary indices into V
|
||||
@@ -60,10 +60,10 @@ namespace igl
|
||||
typename Derivedbc,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool bbw(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedEle> & Ele,
|
||||
const Eigen::PlainObjectBase<Derivedb> & b,
|
||||
const Eigen::PlainObjectBase<Derivedbc> & bc,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<Derivedb> & b,
|
||||
const Eigen::MatrixBase<Derivedbc> & bc,
|
||||
BBWData & data,
|
||||
Eigen::PlainObjectBase<DerivedW> & W);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "bezier.h"
|
||||
#include "PlainMatrix.h"
|
||||
#include <cassert>
|
||||
|
||||
// Adapted from main.c accompanying
|
||||
@@ -19,7 +20,7 @@ IGL_INLINE void igl::bezier(
|
||||
Eigen::PlainObjectBase<DerivedP> & P)
|
||||
{
|
||||
// working local copy
|
||||
DerivedV Vtemp = V;
|
||||
PlainMatrix<DerivedV> Vtemp = V;
|
||||
int degree = Vtemp.rows()-1;
|
||||
/* Triangle computation */
|
||||
for (int i = 1; i <= degree; i++)
|
||||
|
||||
@@ -17,16 +17,14 @@ IGL_INLINE void igl::bfs_orient(
|
||||
Eigen::PlainObjectBase<DerivedFF> & FF,
|
||||
Eigen::PlainObjectBase<DerivedC> & C)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
SparseMatrix<typename DerivedF::Scalar> A;
|
||||
Eigen::SparseMatrix<typename DerivedF::Scalar> A;
|
||||
orientable_patches(F,C,A);
|
||||
|
||||
// number of faces
|
||||
const int m = F.rows();
|
||||
// number of patches
|
||||
const int num_cc = C.maxCoeff()+1;
|
||||
VectorXi seen = VectorXi::Zero(m);
|
||||
Eigen::VectorXi seen = Eigen::VectorXi::Zero(m);
|
||||
|
||||
// Edge sets
|
||||
const int ES[3][2] = {{1,2},{2,0},{0,1}};
|
||||
@@ -38,7 +36,7 @@ IGL_INLINE void igl::bfs_orient(
|
||||
// loop over patches
|
||||
parallel_for(num_cc,[&](const int c)
|
||||
{
|
||||
queue<typename DerivedF::Scalar> Q;
|
||||
std::queue<typename DerivedF::Scalar> Q;
|
||||
// find first member of patch c
|
||||
for(int f = 0;f<FF.rows();f++)
|
||||
{
|
||||
@@ -59,7 +57,7 @@ IGL_INLINE void igl::bfs_orient(
|
||||
}
|
||||
seen(f)++;
|
||||
// loop over neighbors of f
|
||||
for(typename SparseMatrix<typename DerivedF::Scalar>::InnerIterator it (A,f); it; ++it)
|
||||
for(typename Eigen::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)
|
||||
@@ -70,12 +68,12 @@ IGL_INLINE void igl::bfs_orient(
|
||||
for(int efi = 0;efi<3;efi++)
|
||||
{
|
||||
// efi'th edge of face f
|
||||
Vector2i ef(FF(f,ES[efi][0]),FF(f,ES[efi][1]));
|
||||
Eigen::Vector2i ef(FF(f,ES[efi][0]),FF(f,ES[efi][1]));
|
||||
// loop over edges of n
|
||||
for(int eni = 0;eni<3;eni++)
|
||||
{
|
||||
// eni'th edge of face n
|
||||
Vector2i en(FF(n,ES[eni][0]),FF(n,ES[eni][1]));
|
||||
Eigen::Vector2i en(FF(n,ES[eni][0]),FF(n,ES[eni][1]));
|
||||
// Match (half-edges go same direction)
|
||||
if(ef(0) == en(0) && ef(1) == en(1))
|
||||
{
|
||||
|
||||
@@ -42,30 +42,27 @@ IGL_INLINE bool igl::biharmonic_coordinates(
|
||||
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<Scalar> A;
|
||||
Eigen::SparseMatrix<Scalar> A;
|
||||
{
|
||||
DiagonalMatrix<Scalar, Dynamic> Minv;
|
||||
SparseMatrix<Scalar> L, K;
|
||||
Array<bool,Dynamic,Dynamic> C;
|
||||
Eigen::DiagonalMatrix<Scalar, Eigen::Dynamic> Minv;
|
||||
Eigen::SparseMatrix<Scalar> L, K;
|
||||
Eigen::Array<bool ,Eigen::Dynamic ,Eigen::Dynamic> C;
|
||||
{
|
||||
Array<bool,Dynamic,1> I;
|
||||
Eigen::Array<bool ,Eigen::Dynamic,1> I;
|
||||
on_boundary(T,I,C);
|
||||
}
|
||||
#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<Scalar> N, Z, M;
|
||||
Eigen::SparseMatrix<Scalar> N, Z, M;
|
||||
normal_derivative(V,T,N);
|
||||
{
|
||||
std::vector<Triplet<Scalar>> ZIJV;
|
||||
std::vector<Eigen::Triplet<Scalar>> ZIJV;
|
||||
for(int t =0;t<T.rows();t++)
|
||||
{
|
||||
for(int f =0;f<T.cols();f++)
|
||||
@@ -88,13 +85,13 @@ IGL_INLINE bool igl::biharmonic_coordinates(
|
||||
K = N+L;
|
||||
massmatrix(V,T,MASSMATRIX_TYPE_DEFAULT,M);
|
||||
// normalize
|
||||
M /= ((Matrix<Scalar, Dynamic, 1>)M.diagonal()).array().abs().maxCoeff();
|
||||
M /= ((Matrix<Scalar, Eigen::Dynamic, 1>)M.diagonal()).array().abs().maxCoeff();
|
||||
Minv =
|
||||
((Matrix<Scalar, Dynamic, 1>)M.diagonal().array().inverse()).asDiagonal();
|
||||
((Matrix<Scalar, Eigen::Dynamic, 1>)M.diagonal().array().inverse()).asDiagonal();
|
||||
#else
|
||||
Eigen::SparseMatrix<Scalar> M;
|
||||
Eigen::Matrix<Integer, Dynamic, Dynamic> E;
|
||||
Eigen::Matrix<Integer, Dynamic, 1> EMAP;
|
||||
Eigen::Matrix<Integer, Eigen::Dynamic, Eigen::Dynamic> E;
|
||||
Eigen::Matrix<Integer, Eigen::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
|
||||
@@ -111,14 +108,14 @@ IGL_INLINE bool igl::biharmonic_coordinates(
|
||||
Ad.setFromTriplets(AIJV.begin(),AIJV.end());
|
||||
}
|
||||
// Degrees
|
||||
Eigen::Matrix<Scalar, Dynamic, 1> De;
|
||||
Eigen::Matrix<Scalar, Eigen::Dynamic, 1> De;
|
||||
sum(Ad,2,De);
|
||||
Eigen::DiagonalMatrix<Scalar,Eigen::Dynamic> De_diag =
|
||||
De.array().inverse().matrix().asDiagonal();
|
||||
K = L*(De_diag*Ad);
|
||||
// normalize
|
||||
M /= ((Matrix<Scalar, Dynamic, 1>)M.diagonal()).array().abs().maxCoeff();
|
||||
Minv = ((Matrix<Scalar, Dynamic, 1>)M.diagonal().array().inverse()).asDiagonal();
|
||||
M /= ((Eigen::Matrix<Scalar, Eigen::Dynamic, 1>)M.diagonal()).array().abs().maxCoeff();
|
||||
Minv = ((Eigen::Matrix<Scalar, Eigen::Dynamic, 1>)M.diagonal().array().inverse()).asDiagonal();
|
||||
// kill boundary edges
|
||||
for(int f = 0;f<T.rows();f++)
|
||||
{
|
||||
@@ -149,7 +146,7 @@ IGL_INLINE bool igl::biharmonic_coordinates(
|
||||
}
|
||||
// Vertices in point handles
|
||||
const size_t mp =
|
||||
count_if(S.begin(),S.end(),[](const vector<int> & h){return h.size()==1;});
|
||||
count_if(S.begin(),S.end(),[](const std::vector<SType> & h){return h.size()==1;});
|
||||
// number of region handles
|
||||
const size_t r = S.size()-mp;
|
||||
// Vertices in region handles
|
||||
@@ -163,9 +160,9 @@ IGL_INLINE bool igl::biharmonic_coordinates(
|
||||
}
|
||||
const size_t dim = T.cols()-1;
|
||||
// Might as well be dense... I think...
|
||||
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);
|
||||
Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> J = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>::Zero(mp+mr,mp+r*(dim+1));
|
||||
Eigen::Matrix<Integer, Eigen::Dynamic, 1> b(mp+mr);
|
||||
Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> H(mp+r*(dim+1),dim);
|
||||
{
|
||||
int v = 0;
|
||||
int c = 0;
|
||||
@@ -198,7 +195,7 @@ IGL_INLINE bool igl::biharmonic_coordinates(
|
||||
// minimize ½ W' A W'
|
||||
// subject to W(b,:) = J
|
||||
return min_quad_with_fixed(
|
||||
A,Matrix<Scalar, Dynamic, 1>::Zero(A.rows()).eval(),b,J,SparseMatrix<Scalar>(),Matrix<Scalar, Dynamic, 1>(),true,W);
|
||||
A,Eigen::Matrix<Scalar, Eigen::Dynamic, 1>::Zero(A.rows()).eval(),b,J,Eigen::SparseMatrix<Scalar>(),Eigen::Matrix<Scalar, Eigen::Dynamic, 1>(),true,W);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
|
||||
@@ -39,10 +39,10 @@ namespace igl
|
||||
/// #### Example:
|
||||
///
|
||||
/// \code{cpp}
|
||||
/// MatrixXd W;
|
||||
/// Eigen::MatrixXd W;
|
||||
/// igl::biharmonic_coordinates(V,F,S,W);
|
||||
/// const size_t dim = T.cols()-1;
|
||||
/// MatrixXd H(W.cols(),dim);
|
||||
/// Eigen::MatrixXd H(W.cols(),dim);
|
||||
/// {
|
||||
/// int c = 0;
|
||||
/// for(int h = 0;h<S.size();h++)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "doublearea.h"
|
||||
#include "harmonic.h"
|
||||
#include "placeholders.h"
|
||||
//#include "matlab/MatlabWorkspace.h"
|
||||
#include <iostream>
|
||||
|
||||
@@ -50,7 +51,7 @@ IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
|
||||
assert(F.cols() == 3 && "F should contain triangles");
|
||||
int nsteps = min_steps;
|
||||
Eigen::Matrix<typename Derivedbc::Scalar, Eigen::Dynamic, Eigen::Dynamic> bc0 =
|
||||
V(b.col(0),Eigen::all);
|
||||
V(b.col(0),igl::placeholders::all);
|
||||
|
||||
// It's difficult to check for flips "robustly" in the sense that the input
|
||||
// mesh might not have positive/consistent sign to begin with.
|
||||
@@ -81,7 +82,7 @@ IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
|
||||
//mw.save(bct,"bct");
|
||||
//mw.write("numerical.mat");
|
||||
harmonic(Eigen::Matrix<typename DerivedU::Scalar, Eigen::Dynamic, Eigen::Dynamic>(U), F, b, bct, 1, U);
|
||||
bct = U(b.col(0),Eigen::all);
|
||||
bct = U(b.col(0),igl::placeholders::all);
|
||||
nans = (U.array() != U.array()).count();
|
||||
if(test_for_flips)
|
||||
{
|
||||
|
||||
@@ -9,18 +9,20 @@
|
||||
#include "doublearea.h"
|
||||
#include "random_points_on_mesh.h"
|
||||
#include "sortrows.h"
|
||||
#include "placeholders.h"
|
||||
#include "PI.h"
|
||||
#include "get_seconds.h"
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <cstdint>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// It is very important that we use 64bit keys to avoid out of bounds (easy to
|
||||
// get to happen with dense samplings (e.g., r = 0.0005*bbd)
|
||||
typedef int64_t BlueNoiseKeyType;
|
||||
typedef std::int64_t BlueNoiseKeyType;
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
@@ -289,10 +291,10 @@ IGL_INLINE void igl::blue_noise(
|
||||
{
|
||||
Eigen::VectorXi I;
|
||||
igl::sortrows(decltype(Xs)(Xs),true,Xs,I);
|
||||
X = X(I,Eigen::all).eval();
|
||||
X = X(I,igl::placeholders::all).eval();
|
||||
// These two could be spun off in their own thread.
|
||||
XB = XB(I,Eigen::all).eval();
|
||||
XFI = XFI(I,Eigen::all).eval();
|
||||
XB = XB(I,igl::placeholders::all).eval();
|
||||
XFI = XFI(I,igl::placeholders::all).eval();
|
||||
}
|
||||
// Initialization
|
||||
std::unordered_map<BlueNoiseKeyType,std::vector<int> > M;
|
||||
|
||||
@@ -15,34 +15,41 @@
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedEle,
|
||||
typename DerivedC,
|
||||
typename DerivedP,
|
||||
typename DerivedBE,
|
||||
typename DerivedCE,
|
||||
typename DerivedCF,
|
||||
typename Derivedb,
|
||||
typename Derivedbc>
|
||||
IGL_INLINE bool igl::boundary_conditions(
|
||||
const Eigen::MatrixXd & V ,
|
||||
const Eigen::MatrixXi & /*Ele*/,
|
||||
const Eigen::MatrixXd & C ,
|
||||
const Eigen::VectorXi & P ,
|
||||
const Eigen::MatrixXi & BE ,
|
||||
const Eigen::MatrixXi & CE ,
|
||||
const Eigen::MatrixXi & CF ,
|
||||
Eigen::VectorXi & b ,
|
||||
Eigen::MatrixXd & bc )
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
const Eigen::MatrixBase<DerivedP> & P,
|
||||
const Eigen::MatrixBase<DerivedBE> & BE,
|
||||
const Eigen::MatrixBase<DerivedCE> & CE,
|
||||
const Eigen::MatrixBase<DerivedCF> & CF,
|
||||
Eigen::PlainObjectBase<Derivedb> & b,
|
||||
Eigen::PlainObjectBase<Derivedbc> & bc)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
||||
if(P.size()+BE.rows() == 0)
|
||||
{
|
||||
verbose("^%s: Error: no handles found\n",__FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<int> bci;
|
||||
vector<int> bcj;
|
||||
vector<double> bcv;
|
||||
std::vector<int> bci;
|
||||
std::vector<int> bcj;
|
||||
std::vector<double> bcv;
|
||||
|
||||
// loop over points
|
||||
for(int p = 0;p<P.size();p++)
|
||||
{
|
||||
VectorXd pos = C.row(P(p));
|
||||
Eigen::VectorXd pos = C.row(P(p));
|
||||
// loop over domain vertices
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
@@ -51,7 +58,7 @@ IGL_INLINE bool igl::boundary_conditions(
|
||||
// EIGEN GOTCHA:
|
||||
// double sqrd = (V.row(i)-pos).array().pow(2).sum();
|
||||
// Must first store in temporary
|
||||
VectorXd vi = V.row(i);
|
||||
Eigen::VectorXd vi = V.row(i);
|
||||
double sqrd = (vi-pos).squaredNorm();
|
||||
if(sqrd <= FLOAT_EPS)
|
||||
{
|
||||
@@ -76,8 +83,8 @@ IGL_INLINE bool igl::boundary_conditions(
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
// Find samples from tip up to tail
|
||||
VectorXd tip = C.row(BE(e,0));
|
||||
VectorXd tail = C.row(BE(e,1));
|
||||
Eigen::VectorXd tip = C.row(BE(e,0));
|
||||
Eigen::VectorXd tail = C.row(BE(e,1));
|
||||
// Compute parameter along bone and squared distance
|
||||
double t,sqrd;
|
||||
project_to_line(
|
||||
@@ -101,8 +108,8 @@ IGL_INLINE bool igl::boundary_conditions(
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
// Find samples from tip up to tail
|
||||
VectorXd tip = C.row(P(CE(e,0)));
|
||||
VectorXd tail = C.row(P(CE(e,1)));
|
||||
Eigen::VectorXd tip = C.row(P(CE(e,0)));
|
||||
Eigen::VectorXd tail = C.row(P(CE(e,1)));
|
||||
// Compute parameter along bone and squared distance
|
||||
double t,sqrd;
|
||||
project_to_line(
|
||||
@@ -122,14 +129,14 @@ IGL_INLINE bool igl::boundary_conditions(
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> vertices_marked(V.rows(), 0);
|
||||
std::vector<bool> vertices_marked(V.rows(), false);
|
||||
// loop over cage faces
|
||||
for(int f = 0;f<CF.rows();f++)
|
||||
{
|
||||
Vector3d v_0 = C.row(P(CF(f, 0)));
|
||||
Vector3d v_1 = C.row(P(CF(f, 1)));
|
||||
Vector3d v_2 = C.row(P(CF(f, 2)));
|
||||
Vector3d n = (v_1 - v_0).cross(v_2 - v_1);
|
||||
Eigen::Vector3d v_0 = C.row(P(CF(f, 0)));
|
||||
Eigen::Vector3d v_1 = C.row(P(CF(f, 1)));
|
||||
Eigen::Vector3d v_2 = C.row(P(CF(f, 2)));
|
||||
Eigen::Vector3d n = (v_1 - v_0).cross(v_2 - v_1);
|
||||
n.normalize();
|
||||
// loop over domain vertices
|
||||
for (int i = 0;i<V.rows();i++)
|
||||
@@ -139,13 +146,13 @@ IGL_INLINE bool igl::boundary_conditions(
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Vector3d point = V.row(i);
|
||||
Vector3d v = point - v_0;
|
||||
Eigen::Vector3d point = V.row(i);
|
||||
Eigen::Vector3d v = point - v_0;
|
||||
double dist = abs(v.dot(n));
|
||||
if (dist <= 1.e-1f)
|
||||
{
|
||||
//barycentric coordinates
|
||||
Vector3d vec_0 = v_1 - v_0, vec_1 = v_2 - v_0, vec_2 = point - v_0;
|
||||
Eigen::Vector3d vec_0 = v_1 - v_0, vec_1 = v_2 - v_0, vec_2 = point - v_0;
|
||||
double d00 = vec_0.dot(vec_0);
|
||||
double d01 = vec_0.dot(vec_1);
|
||||
double d11 = vec_1.dot(vec_1);
|
||||
@@ -158,7 +165,7 @@ IGL_INLINE bool igl::boundary_conditions(
|
||||
|
||||
if (u>=0. && u<=1.0 && v>=0. && v<=1.0 && w >=0. && w<=1.0)
|
||||
{
|
||||
vertices_marked[i] = 1;
|
||||
vertices_marked[i] = true;
|
||||
bci.push_back(i);
|
||||
bcj.push_back(CF(f, 0));
|
||||
bcv.push_back(u);
|
||||
@@ -174,17 +181,17 @@ IGL_INLINE bool igl::boundary_conditions(
|
||||
}
|
||||
|
||||
// find unique boundary indices
|
||||
vector<int> vb = bci;
|
||||
sort(vb.begin(),vb.end());
|
||||
std::vector<int> vb = bci;
|
||||
std::sort(vb.begin(),vb.end());
|
||||
vb.erase(unique(vb.begin(), vb.end()), vb.end());
|
||||
|
||||
b.resize(vb.size());
|
||||
bc = MatrixXd::Zero(vb.size(),P.size()+BE.rows());
|
||||
bc = Eigen::MatrixXd::Zero(vb.size(),P.size()+BE.rows());
|
||||
// Map from boundary index to index in boundary
|
||||
map<int,int> bim;
|
||||
std::map<int,int> bim;
|
||||
int i = 0;
|
||||
// Also fill in b
|
||||
for(vector<int>::iterator bit = vb.begin();bit != vb.end();bit++)
|
||||
for(std::vector<int>::iterator bit = vb.begin();bit != vb.end();bit++)
|
||||
{
|
||||
b(i) = *bit;
|
||||
bim[*bit] = i;
|
||||
@@ -242,3 +249,8 @@ IGL_INLINE bool igl::boundary_conditions(
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::boundary_conditions<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::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::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&, 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&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&);
|
||||
#endif
|
||||
|
||||
@@ -36,16 +36,26 @@ namespace igl
|
||||
/// some column of bc doesn't have a 0 (assuming bc has >1 columns)
|
||||
/// some column of bc doesn't have a 1 (assuming bc has >1 columns)
|
||||
///
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedEle,
|
||||
typename DerivedC,
|
||||
typename DerivedP,
|
||||
typename DerivedBE,
|
||||
typename DerivedCE,
|
||||
typename DerivedCF,
|
||||
typename Derivedb,
|
||||
typename Derivedbc>
|
||||
IGL_INLINE bool boundary_conditions(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & Ele,
|
||||
const Eigen::MatrixXd & C,
|
||||
const Eigen::VectorXi & P,
|
||||
const Eigen::MatrixXi & BE,
|
||||
const Eigen::MatrixXi & CE,
|
||||
const Eigen::MatrixXi & CF,
|
||||
Eigen::VectorXi & b,
|
||||
Eigen::MatrixXd & bc);
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedEle> & Ele,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
const Eigen::MatrixBase<DerivedP> & P,
|
||||
const Eigen::MatrixBase<DerivedBE> & BE,
|
||||
const Eigen::MatrixBase<DerivedCE> & CE,
|
||||
const Eigen::MatrixBase<DerivedCF> & CF,
|
||||
Eigen::PlainObjectBase<Derivedb> & b,
|
||||
Eigen::PlainObjectBase<Derivedbc> & bc);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
|
||||
@@ -47,21 +47,21 @@ IGL_INLINE void igl::boundary_facets(
|
||||
for(int i = 0; i< (int)T.rows();i++)
|
||||
{
|
||||
// get face in correct order
|
||||
allF(i*simplex_size+0,0) = T(i,1);
|
||||
allF(i*simplex_size+0,2) = T(i,1);
|
||||
allF(i*simplex_size+0,1) = T(i,3);
|
||||
allF(i*simplex_size+0,2) = T(i,2);
|
||||
allF(i*simplex_size+0,0) = T(i,2);
|
||||
// get face in correct order
|
||||
allF(i*simplex_size+1,0) = T(i,0);
|
||||
allF(i*simplex_size+1,2) = T(i,0);
|
||||
allF(i*simplex_size+1,1) = T(i,2);
|
||||
allF(i*simplex_size+1,2) = T(i,3);
|
||||
allF(i*simplex_size+1,0) = T(i,3);
|
||||
// get face in correct order
|
||||
allF(i*simplex_size+2,0) = T(i,0);
|
||||
allF(i*simplex_size+2,2) = T(i,0);
|
||||
allF(i*simplex_size+2,1) = T(i,3);
|
||||
allF(i*simplex_size+2,2) = T(i,1);
|
||||
allF(i*simplex_size+2,0) = T(i,1);
|
||||
// get face in correct order
|
||||
allF(i*simplex_size+3,0) = T(i,0);
|
||||
allF(i*simplex_size+3,2) = T(i,0);
|
||||
allF(i*simplex_size+3,1) = T(i,1);
|
||||
allF(i*simplex_size+3,2) = T(i,2);
|
||||
allF(i*simplex_size+3,0) = T(i,2);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
@@ -124,101 +124,12 @@ Ret igl::boundary_facets(
|
||||
return F;
|
||||
}
|
||||
|
||||
template <typename IntegerT, typename IntegerF>
|
||||
IGL_INLINE void igl::boundary_facets(
|
||||
const std::vector<std::vector<IntegerT> > & T,
|
||||
std::vector<std::vector<IntegerF> > & F)
|
||||
{
|
||||
// Kept for legacy reasons. Could probably just delete.
|
||||
using namespace std;
|
||||
|
||||
if(T.size() == 0)
|
||||
{
|
||||
F.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
int simplex_size = T[0].size();
|
||||
// Get a list of all faces
|
||||
vector<vector<IntegerF> > allF(
|
||||
T.size()*simplex_size,
|
||||
vector<IntegerF>(simplex_size-1));
|
||||
|
||||
// Gather faces, loop over tets
|
||||
for(int i = 0; i< (int)T.size();i++)
|
||||
{
|
||||
assert((int)T[i].size() == simplex_size);
|
||||
switch(simplex_size)
|
||||
{
|
||||
case 4:
|
||||
// get face in correct order
|
||||
allF[i*simplex_size+0][0] = T[i][1];
|
||||
allF[i*simplex_size+0][1] = T[i][3];
|
||||
allF[i*simplex_size+0][2] = T[i][2];
|
||||
// get face in correct order
|
||||
allF[i*simplex_size+1][0] = T[i][0];
|
||||
allF[i*simplex_size+1][1] = T[i][2];
|
||||
allF[i*simplex_size+1][2] = T[i][3];
|
||||
// get face in correct order
|
||||
allF[i*simplex_size+2][0] = T[i][0];
|
||||
allF[i*simplex_size+2][1] = T[i][3];
|
||||
allF[i*simplex_size+2][2] = T[i][1];
|
||||
// get face in correct order
|
||||
allF[i*simplex_size+3][0] = T[i][0];
|
||||
allF[i*simplex_size+3][1] = T[i][1];
|
||||
allF[i*simplex_size+3][2] = T[i][2];
|
||||
break;
|
||||
case 3:
|
||||
allF[i*simplex_size+0][0] = T[i][1];
|
||||
allF[i*simplex_size+0][1] = T[i][2];
|
||||
allF[i*simplex_size+1][0] = T[i][2];
|
||||
allF[i*simplex_size+1][1] = T[i][0];
|
||||
allF[i*simplex_size+2][0] = T[i][0];
|
||||
allF[i*simplex_size+2][1] = T[i][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Counts
|
||||
vector<int> C;
|
||||
face_occurrences(allF,C);
|
||||
|
||||
// Q: Why not just count the number of ones?
|
||||
// A: because we are including non-manifold edges as boundary edges
|
||||
int twos = (int) count(C.begin(),C.end(),2);
|
||||
//int ones = (int) count(C.begin(),C.end(),1);
|
||||
// Resize output to fit number of ones
|
||||
F.resize(allF.size() - twos);
|
||||
//F.resize(ones);
|
||||
int k = 0;
|
||||
for(int i = 0;i< (int)allF.size();i++)
|
||||
{
|
||||
if(C[i] != 2)
|
||||
{
|
||||
assert(k<(int)F.size());
|
||||
F[k] = allF[i];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
assert(k==(int)F.size());
|
||||
//if(k != F.size())
|
||||
//{
|
||||
// printf("%d =? %d\n",k,F.size());
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::boundary_facets<int, int>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
|
||||
//template Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > igl::boundary_facets(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
|
||||
template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
|
||||
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,9 @@ namespace igl
|
||||
/// (analogous to qptoolbox's `outline` and `boundary_faces`).
|
||||
///
|
||||
/// @param[in] T tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra
|
||||
/// @param[out] F list of boundary faces, n by 3 (2), where n is the number of boundary faces
|
||||
/// @param[out] F list of boundary faces, n by 3 (2), where n is the number
|
||||
/// of boundary faces. Faces are oriented so that igl::centroid(V,F,…)
|
||||
/// computes the same sign volume as igl::volume(V,T)
|
||||
/// @param[out] J list of indices into T, n by 1
|
||||
/// @param[out] K list of indices revealing across from which vertex is this facet
|
||||
///
|
||||
@@ -48,15 +50,6 @@ namespace igl
|
||||
template <typename DerivedT, typename Ret>
|
||||
Ret boundary_facets(
|
||||
const Eigen::MatrixBase<DerivedT>& T);
|
||||
/// Determine boundary faces (edges) of tetrahedra (triangles) stored in T;
|
||||
/// inputs and outputs lists.
|
||||
///
|
||||
/// @param[in] T tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra
|
||||
/// @param[out] F list of boundary faces, n by 3 (2), where n is the number of boundary faces
|
||||
template <typename IntegerT, typename IntegerF>
|
||||
IGL_INLINE void boundary_facets(
|
||||
const std::vector<std::vector<IntegerT> > & T,
|
||||
std::vector<std::vector<IntegerF> > & F);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
|
||||
@@ -16,20 +16,17 @@ IGL_INLINE void igl::boundary_loop(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
std::vector<std::vector<Index> >& L)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
if(F.rows() == 0)
|
||||
return;
|
||||
|
||||
VectorXd Vdummy(F.maxCoeff()+1,1);
|
||||
Eigen::VectorXd Vdummy(F.maxCoeff()+1,1);
|
||||
Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, Eigen::Dynamic> TT,TTi;
|
||||
vector<std::vector<int> > VF, VFi;
|
||||
std::vector<std::vector<int> > VF, VFi;
|
||||
triangle_triangle_adjacency(F,TT,TTi);
|
||||
vertex_triangle_adjacency(Vdummy,F,VF,VFi);
|
||||
|
||||
vector<bool> unvisited = is_border_vertex(F);
|
||||
set<int> unseen;
|
||||
std::vector<bool> unvisited = is_border_vertex(F);
|
||||
std::set<int> unseen;
|
||||
for (size_t i = 0; i < unvisited.size(); ++i)
|
||||
{
|
||||
if (unvisited[i])
|
||||
@@ -38,7 +35,7 @@ IGL_INLINE void igl::boundary_loop(
|
||||
|
||||
while (!unseen.empty())
|
||||
{
|
||||
vector<Index> l;
|
||||
std::vector<Index> l;
|
||||
|
||||
// Get first vertex of loop
|
||||
int start = *unseen.begin();
|
||||
@@ -93,13 +90,10 @@ IGL_INLINE void igl::boundary_loop(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
std::vector<Index>& L)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
||||
if(F.rows() == 0)
|
||||
return;
|
||||
|
||||
vector<vector<int> > Lall;
|
||||
std::vector<std::vector<int> > Lall;
|
||||
boundary_loop(F,Lall);
|
||||
|
||||
int idxMax = -1;
|
||||
@@ -132,13 +126,10 @@ IGL_INLINE void igl::boundary_loop(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedL>& L)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
||||
if(F.rows() == 0)
|
||||
return;
|
||||
|
||||
vector<int> Lvec;
|
||||
std::vector<int> Lvec;
|
||||
boundary_loop(F,Lvec);
|
||||
|
||||
L.resize(Lvec.size(), 1);
|
||||
|
||||
@@ -24,7 +24,6 @@ IGL_INLINE void igl::bounding_box(
|
||||
Eigen::PlainObjectBase<DerivedBV>& BV,
|
||||
Eigen::PlainObjectBase<DerivedBF>& BF)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
const int dim = V.cols();
|
||||
const auto & minV = V.colwise().minCoeff().array()-pad;
|
||||
|
||||
@@ -13,9 +13,8 @@
|
||||
IGL_INLINE double igl::bounding_box_diagonal(
|
||||
const Eigen::MatrixXd & V)
|
||||
{
|
||||
using namespace Eigen;
|
||||
VectorXd maxV,minV;
|
||||
VectorXi maxVI,minVI;
|
||||
Eigen::VectorXd maxV,minV;
|
||||
Eigen::VectorXi maxVI,minVI;
|
||||
igl::max(V,1,maxV,maxVI);
|
||||
igl::min(V,1,minV,minVI);
|
||||
return sqrt((maxV-minV).array().square().sum());
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "box_faces.h"
|
||||
#include "AABB.h"
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
template <typename DerivedV, typename DerivedQ>
|
||||
IGL_INLINE void igl::box_faces(
|
||||
const Eigen::AlignedBox<typename DerivedV::Scalar,3> & box,
|
||||
const typename DerivedV::Scalar shrink,
|
||||
Eigen::PlainObjectBase<DerivedV> & P,
|
||||
Eigen::PlainObjectBase<DerivedQ> & Q)
|
||||
{
|
||||
auto min_corner = box.min();
|
||||
auto max_corner = box.max();
|
||||
// shrink by 3%
|
||||
min_corner = min_corner + shrink*(max_corner-min_corner);
|
||||
max_corner = max_corner - shrink*(max_corner-min_corner);
|
||||
P.resize(8,3);
|
||||
Q.resize(6,4);
|
||||
int p = 0;
|
||||
int q = 0;
|
||||
Q.row(q++) << p+0,p+1,p+2,p+3;
|
||||
Q.row(q++) << p+0,p+1,p+5,p+4;
|
||||
Q.row(q++) << p+1,p+2,p+6,p+5;
|
||||
Q.row(q++) << p+2,p+3,p+7,p+6;
|
||||
Q.row(q++) << p+3,p+0,p+4,p+7;
|
||||
Q.row(q++) << p+4,p+5,p+6,p+7;
|
||||
P.row(p++) = min_corner;
|
||||
P.row(p++) = Eigen::RowVector3d(max_corner[0],min_corner[1],min_corner[2]);
|
||||
P.row(p++) = Eigen::RowVector3d(max_corner[0],max_corner[1],min_corner[2]);
|
||||
P.row(p++) = Eigen::RowVector3d(min_corner[0],max_corner[1],min_corner[2]);
|
||||
P.row(p++) = Eigen::RowVector3d(min_corner[0],min_corner[1],max_corner[2]);
|
||||
P.row(p++) = Eigen::RowVector3d(max_corner[0],min_corner[1],max_corner[2]);
|
||||
P.row(p++) = max_corner;
|
||||
P.row(p++) = Eigen::RowVector3d(min_corner[0],max_corner[1],max_corner[2]);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedP,
|
||||
typename DerivedQ,
|
||||
typename DerivedD >
|
||||
IGL_INLINE void igl::box_faces(
|
||||
const igl::AABB<DerivedV,3> & tree,
|
||||
Eigen::PlainObjectBase<DerivedP> & P,
|
||||
Eigen::PlainObjectBase<DerivedQ> & Q,
|
||||
Eigen::PlainObjectBase<DerivedD> & D)
|
||||
{
|
||||
const int num_nodes = tree.size();
|
||||
P.resize(8*num_nodes,3);
|
||||
Q.resize(6*num_nodes,4);
|
||||
D.resize(6*num_nodes);
|
||||
int d = 0;
|
||||
int p = 0;
|
||||
int q = 0;
|
||||
std::vector<std::pair<const igl::AABB<DerivedV,3> *,int> > stack;
|
||||
stack.push_back({&tree,0});
|
||||
while(!stack.empty())
|
||||
{
|
||||
const auto pair = stack.back();
|
||||
const auto * node = pair.first;
|
||||
const int depth = pair.second;
|
||||
D(d++) = depth;
|
||||
D(d++) = depth;
|
||||
D(d++) = depth;
|
||||
D(d++) = depth;
|
||||
D(d++) = depth;
|
||||
D(d++) = depth;
|
||||
stack.pop_back();
|
||||
const auto & box = node->m_box;
|
||||
|
||||
DerivedP Pi;
|
||||
DerivedQ Qi;
|
||||
box_faces(box,0.03,Pi,Qi);
|
||||
P.block(p,0,8,3) = Pi;
|
||||
Q.block(q,0,6,4) = Qi.array()+p;
|
||||
p += 8;
|
||||
q += 6;
|
||||
if(node->m_left)
|
||||
{
|
||||
stack.push_back({node->m_left,depth+1});
|
||||
}
|
||||
if(node->m_right)
|
||||
{
|
||||
stack.push_back({node->m_right,depth+1});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::box_faces<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2025 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_BOX_FACES_H
|
||||
#define IGL_BOX_FACES_H
|
||||
#include "igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
/// Compute the quad faces of an axis-aligned bounding box) shrunk by a given
|
||||
/// factor.
|
||||
///
|
||||
/// @param[in] box Axis-aligned bounding box
|
||||
/// @param[in] shrink Factor by which to shrink the box
|
||||
/// @param[out] P #P by 3 list of vertex positions
|
||||
/// @param[out] Q #Q by 4 list of triangle indices into rows of P
|
||||
template <typename DerivedV, typename DerivedQ>
|
||||
IGL_INLINE void box_faces(
|
||||
const Eigen::AlignedBox<typename DerivedV::Scalar,3> & box,
|
||||
const typename DerivedV::Scalar shrink,
|
||||
Eigen::PlainObjectBase<DerivedV> & P,
|
||||
Eigen::PlainObjectBase<DerivedQ> & Q);
|
||||
// Forward declaration
|
||||
template <typename DerivedV, int DIM> class AABB;
|
||||
/// Compute the quad faces of a tree of axis-aligned bounding boxes.
|
||||
///
|
||||
/// @param[in] tree Tree of axis-aligned bounding boxes
|
||||
/// @param[out] P #P by 3 list of vertex positions
|
||||
/// @param[out] Q #Q by 4 list of triangle indices into rows of P
|
||||
/// @param[out] D #Q list of tree depths (0==root)
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedP,
|
||||
typename DerivedQ,
|
||||
typename DerivedD >
|
||||
IGL_INLINE void box_faces(
|
||||
const igl::AABB<DerivedV,3> & tree,
|
||||
Eigen::PlainObjectBase<DerivedP> & P,
|
||||
Eigen::PlainObjectBase<DerivedQ> & Q,
|
||||
Eigen::PlainObjectBase<DerivedD> & D);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "box_faces.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2025 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "box_simplices.h"
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedB
|
||||
>
|
||||
IGL_INLINE void igl::box_simplices(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedB> & B1,
|
||||
Eigen::PlainObjectBase<DerivedB> & B2)
|
||||
{
|
||||
B1.setConstant(F.rows(),V.cols(),std::numeric_limits<double>::infinity());
|
||||
B2.setConstant(F.rows(),V.cols(),-std::numeric_limits<double>::infinity());
|
||||
for(int f = 0; f < F.rows(); f++)
|
||||
{
|
||||
for(int c = 0; c < F.cols(); c++)
|
||||
{
|
||||
for(int d = 0; d < V.cols(); d++)
|
||||
{
|
||||
B1(f,d) = std::min(B1(f,d),V(F(f,c),d));
|
||||
B2(f,d) = std::max(B2(f,d),V(F(f,c),d));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::box_simplices<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 2, 1, -1, 2>, Eigen::Matrix<double, -1, 3, 1, -1, 3>>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 1, -1, 2>> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>>&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::box_simplices<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3>> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>>&);
|
||||
template void igl::box_simplices<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3>> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3>> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3>>&);
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2025 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_BOX_SIMPLICES_H
|
||||
#define IGL_BOX_SIMPLICES_H
|
||||
#include "igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
///
|
||||
///
|
||||
/// @param[in] V #V by dim list of vertex positions
|
||||
/// @param[in] F #F by ss list of simplex indices into V
|
||||
/// @param[out] B1 #B by dim list of minimum corners of the Eytzinger AABBs
|
||||
/// @param[out] B2 #B by dim list of maximum corners of the Eytzinger AABBs
|
||||
///
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedB
|
||||
>
|
||||
IGL_INLINE void box_simplices(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedB> & B1,
|
||||
Eigen::PlainObjectBase<DerivedB> & B2);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "box_simplices.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "box_surface_area.h"
|
||||
|
||||
|
||||
template <typename DerivedCorner>
|
||||
IGL_INLINE typename DerivedCorner::Scalar igl::box_surface_area(
|
||||
const Eigen::MatrixBase<DerivedCorner> & min_corner,
|
||||
const Eigen::MatrixBase<DerivedCorner> & max_corner)
|
||||
{
|
||||
using Scalar = typename DerivedCorner::Scalar;
|
||||
const auto dimensions = (max_corner - min_corner).eval();
|
||||
const auto num_dimensions = dimensions.size();
|
||||
|
||||
Scalar surface_area = 0;
|
||||
for (int i = 0; i < num_dimensions; ++i) {
|
||||
for (int j = i + 1; j < num_dimensions; ++j) {
|
||||
surface_area += 2 * dimensions[i] * dimensions[j];
|
||||
}
|
||||
}
|
||||
|
||||
return surface_area;
|
||||
}
|
||||
|
||||
template <typename Scalar, int AmbientDim>
|
||||
IGL_INLINE Scalar igl::box_surface_area(
|
||||
const Eigen::AlignedBox<Scalar,AmbientDim> & box)
|
||||
{
|
||||
return igl::box_surface_area(box.min(),box.max());
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template double igl::box_surface_area<double, 2>(Eigen::AlignedBox<double, 2> const&);
|
||||
template double igl::box_surface_area<double, 3>(Eigen::AlignedBox<double, 3> const&);
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef IGL_BOX_SURFACE_AREA_H
|
||||
#define IGL_BOX_SURFACE_AREA_H
|
||||
#include "igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
/// Compute the surface area of a box given its min and max corners
|
||||
///
|
||||
/// @param[in] min_corner #d vector of min corner position
|
||||
/// @param[in] max_corner #d vector of max corner position
|
||||
/// @return surface area of box
|
||||
template <typename DerivedCorner>
|
||||
IGL_INLINE typename DerivedCorner::Scalar box_surface_area(
|
||||
const Eigen::MatrixBase<DerivedCorner> & min_corner,
|
||||
const Eigen::MatrixBase<DerivedCorner> & max_corner);
|
||||
/// \overload
|
||||
/// @param[in] box axis-aligned bounding box
|
||||
template <typename Scalar, int AmbientDim>
|
||||
IGL_INLINE Scalar box_surface_area(
|
||||
const Eigen::AlignedBox<Scalar,AmbientDim> & box);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "box_surface_area.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+9
-13
@@ -26,7 +26,6 @@ IGL_INLINE void igl::cat(
|
||||
{
|
||||
|
||||
assert(dim == 1 || dim == 2);
|
||||
using namespace Eigen;
|
||||
// Special case if B or A is empty
|
||||
if(A.size() == 0)
|
||||
{
|
||||
@@ -40,7 +39,7 @@ IGL_INLINE void igl::cat(
|
||||
}
|
||||
|
||||
// This is faster than using DynamicSparseMatrix or setFromTriplets
|
||||
C = SparseMatrix<Scalar>(
|
||||
C = Eigen::SparseMatrix<Scalar>(
|
||||
dim == 1 ? A.rows()+B.rows() : A.rows(),
|
||||
dim == 1 ? A.cols() : A.cols()+B.cols());
|
||||
Eigen::VectorXi per_col = Eigen::VectorXi::Zero(C.cols());
|
||||
@@ -49,11 +48,11 @@ IGL_INLINE void igl::cat(
|
||||
assert(A.outerSize() == B.outerSize());
|
||||
for(int k = 0;k<A.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
per_col(k)++;
|
||||
}
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
{
|
||||
per_col(k)++;
|
||||
}
|
||||
@@ -62,14 +61,14 @@ IGL_INLINE void igl::cat(
|
||||
{
|
||||
for(int k = 0;k<A.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
per_col(k)++;
|
||||
}
|
||||
}
|
||||
for(int k = 0;k<B.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
{
|
||||
per_col(A.cols() + k)++;
|
||||
}
|
||||
@@ -80,11 +79,11 @@ IGL_INLINE void igl::cat(
|
||||
{
|
||||
for(int k = 0;k<A.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
C.insert(it.row(),k) = it.value();
|
||||
}
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
{
|
||||
C.insert(A.rows()+it.row(),k) = it.value();
|
||||
}
|
||||
@@ -93,14 +92,14 @@ IGL_INLINE void igl::cat(
|
||||
{
|
||||
for(int k = 0;k<A.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
C.insert(it.row(),k) = it.value();
|
||||
}
|
||||
}
|
||||
for(int k = 0;k<B.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
{
|
||||
C.insert(it.row(),A.cols()+k) = it.value();
|
||||
}
|
||||
@@ -157,7 +156,6 @@ IGL_INLINE Mat igl::cat(const int dim, const Mat & A, const Mat & B)
|
||||
template <class Mat>
|
||||
IGL_INLINE void igl::cat(const std::vector<std::vector< Mat > > & A, Mat & C)
|
||||
{
|
||||
using namespace std;
|
||||
// Start with empty matrix
|
||||
C.resize(0,0);
|
||||
for(const auto & row_vec : A)
|
||||
@@ -178,8 +176,6 @@ template <typename T, typename DerivedC>
|
||||
IGL_INLINE void igl::cat(const int dim, const std::vector<T> & A, Eigen::PlainObjectBase<DerivedC> & C)
|
||||
{
|
||||
assert(dim == 1 || dim == 2);
|
||||
using namespace Eigen;
|
||||
|
||||
const int num_mat = A.size();
|
||||
if(num_mat == 0)
|
||||
{
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ namespace igl
|
||||
/// This is an attempt to act like matlab's cat function.
|
||||
///
|
||||
/// @tparam Scalar scalar data type for sparse matrices like double or int
|
||||
/// @tparam Mat matrix type for all matrices (e.g. MatrixXd, SparseMatrix)
|
||||
/// @tparam MatC matrix type for output matrix (e.g. MatrixXd) needs to support
|
||||
/// @tparam Mat matrix type for all matrices (e.g. Eigen::MatrixXd, SparseMatrix)
|
||||
/// @tparam MatC matrix type for output matrix (e.g. Eigen::MatrixXd) needs to support
|
||||
/// resize
|
||||
/// @param[in] dim dimension along which to concatenate, 1 or 2
|
||||
/// @param[in] A first input matrix
|
||||
|
||||
@@ -10,15 +10,14 @@
|
||||
|
||||
template < typename DerivedX, typename DerivedY>
|
||||
IGL_INLINE void igl::ceil(
|
||||
const Eigen::PlainObjectBase<DerivedX>& X,
|
||||
const Eigen::MatrixBase<DerivedX>& X,
|
||||
Eigen::PlainObjectBase<DerivedY>& Y)
|
||||
{
|
||||
using namespace std;
|
||||
typedef typename DerivedX::Scalar Scalar;
|
||||
Y = X.unaryExpr([](const Scalar &x)->Scalar{return std::ceil(x);}).template cast<typename DerivedY::Scalar >();
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::ceil<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> >&);
|
||||
template void igl::ceil<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ namespace igl
|
||||
/// @param[out] Y m by n matrix of ceiled integers
|
||||
template < typename DerivedX, typename DerivedY>
|
||||
IGL_INLINE void ceil(
|
||||
const Eigen::PlainObjectBase<DerivedX>& X,
|
||||
const Eigen::MatrixBase<DerivedX>& X,
|
||||
Eigen::PlainObjectBase<DerivedY>& Y);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,19 @@ IGL_INLINE void igl::centroid(
|
||||
Eigen::PlainObjectBase<Derivedc>& cen,
|
||||
Derivedvol & vol)
|
||||
{
|
||||
using namespace Eigen;
|
||||
assert(F.cols() == 3 && "F should contain triangles.");
|
||||
assert(V.cols() == 3 && "V should contain 3d points.");
|
||||
const int m = F.rows();
|
||||
cen.setZero();
|
||||
// static assert that cen is either a 3d rowvector a 3d vector or a variable
|
||||
// size vector
|
||||
static_assert(Derivedc::IsVectorAtCompileTime,"cen should be a vector");
|
||||
static_assert(
|
||||
Derivedc::RowsAtCompileTime == 3 ||
|
||||
Derivedc::RowsAtCompileTime == -1 ||
|
||||
Derivedc::ColsAtCompileTime == 3 ||
|
||||
Derivedc::ColsAtCompileTime == -1,
|
||||
"cen should be sizeable to 3 vector");
|
||||
cen.setZero(3);
|
||||
vol = 0;
|
||||
// loop over faces
|
||||
for(int f = 0;f<m;f++)
|
||||
@@ -61,6 +69,8 @@ IGL_INLINE void igl::centroid(
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::centroid<Eigen::Matrix<double, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, double&);
|
||||
template void igl::centroid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double>(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, 1, 1, 3> >&, double&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::centroid<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, float>(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&, float&);
|
||||
@@ -70,4 +80,5 @@ template void igl::centroid<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix
|
||||
template void igl::centroid<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
|
||||
template void igl::centroid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 3, 1, 0, 3, 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, 3, 1, 0, 3, 1> >&);
|
||||
template void igl::centroid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
|
||||
template void igl::centroid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 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, 1, 1, -1>>&);
|
||||
#endif
|
||||
|
||||
+35
-25
@@ -1,20 +1,21 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "circulation.h"
|
||||
#include "list_to_matrix.h"
|
||||
#include <cassert>
|
||||
|
||||
template <typename DerivedEMAP, typename DerivedEF, typename DerivedEI>
|
||||
IGL_INLINE std::vector<int> igl::circulation(
|
||||
const int e,
|
||||
const bool ccw,
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI)
|
||||
const Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
const Eigen::MatrixBase<DerivedEF> & EF,
|
||||
const Eigen::MatrixBase<DerivedEI> & EI)
|
||||
{
|
||||
// prepare output
|
||||
std::vector<int> N;
|
||||
@@ -22,9 +23,9 @@ IGL_INLINE std::vector<int> igl::circulation(
|
||||
const int m = EMAP.size()/3;
|
||||
assert(m*3 == EMAP.size());
|
||||
const auto & step = [&](
|
||||
const int e,
|
||||
const int e,
|
||||
const int ff,
|
||||
int & ne,
|
||||
int & ne,
|
||||
int & nf)
|
||||
{
|
||||
assert((EF(e,1) == ff || EF(e,0) == ff) && "e should touch ff");
|
||||
@@ -33,7 +34,7 @@ IGL_INLINE std::vector<int> igl::circulation(
|
||||
const int nv = EI(e,nside);
|
||||
// get next face
|
||||
nf = EF(e,nside);
|
||||
// get next edge
|
||||
// get next edge
|
||||
const int dir = ccw?-1:1;
|
||||
ne = EMAP(nf+m*((nv+dir+3)%3));
|
||||
};
|
||||
@@ -56,36 +57,38 @@ IGL_INLINE std::vector<int> igl::circulation(
|
||||
return N;
|
||||
}
|
||||
|
||||
template <typename DerivedEMAP, typename DerivedEF, typename DerivedEI, typename DerivedvN>
|
||||
IGL_INLINE void igl::circulation(
|
||||
const int e,
|
||||
const bool ccw,
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI,
|
||||
Eigen::VectorXi & vN)
|
||||
const Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
const Eigen::MatrixBase<DerivedEF> & EF,
|
||||
const Eigen::MatrixBase<DerivedEI> & EI,
|
||||
Eigen::PlainObjectBase<DerivedvN> & vN)
|
||||
{
|
||||
std::vector<int> N = circulation(e,ccw,EMAP,EF,EI);
|
||||
igl::list_to_matrix(N,vN);
|
||||
}
|
||||
|
||||
template <typename DerivedF, typename DerivedEMAP, typename DerivedEF, typename DerivedEI, typename Nv_type>
|
||||
IGL_INLINE void igl::circulation(
|
||||
const int e,
|
||||
const bool ccw,
|
||||
const Eigen::MatrixXi & F,
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
const Eigen::MatrixBase<DerivedEF> & EF,
|
||||
const Eigen::MatrixBase<DerivedEI> & EI,
|
||||
/*std::vector<int> & Ne,*/
|
||||
std::vector<int> & Nv,
|
||||
std::vector<int> & Nf)
|
||||
std::vector<Nv_type> & Nv,
|
||||
std::vector<Nv_type> & Nf)
|
||||
{
|
||||
//
|
||||
// for e --> (bf) and ccw=true
|
||||
//
|
||||
// c---d
|
||||
// / \ / \
|
||||
// ╱ ╲ ╱ ╲
|
||||
// a---b-e-f
|
||||
// \ / \ /
|
||||
// ╲ ╱ ╲ ╱
|
||||
// g---h
|
||||
//
|
||||
// // (might start with {bhf} depending on edge)
|
||||
@@ -101,9 +104,9 @@ IGL_INLINE void igl::circulation(
|
||||
const int m = EMAP.size()/3;
|
||||
assert(m*3 == EMAP.size());
|
||||
const auto & step = [&](
|
||||
const int e,
|
||||
const int e,
|
||||
const int ff,
|
||||
int & ne,
|
||||
int & ne,
|
||||
//int & re,
|
||||
int & rv,
|
||||
int & nf)
|
||||
@@ -114,7 +117,7 @@ IGL_INLINE void igl::circulation(
|
||||
const int nv = EI(e,nside);
|
||||
// get next face
|
||||
nf = EF(e,nside);
|
||||
// get next edge
|
||||
// get next edge
|
||||
const int dir = ccw?-1:1;
|
||||
rv = F(nf,nv);
|
||||
ne = EMAP(nf+m*((nv+dir+3)%3));
|
||||
@@ -141,3 +144,10 @@ IGL_INLINE void igl::circulation(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template specialization
|
||||
template std::vector<int, std::allocator<int>> igl::circulation<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>>(int, bool, 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&);
|
||||
template void igl::circulation<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>>(int, bool, 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&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>>&);
|
||||
template void igl::circulation<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(int, bool, 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&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>> const&, std::vector<int, std::allocator<int>>&, std::vector<int, std::allocator<int>>&);
|
||||
#endif
|
||||
|
||||
+16
-13
@@ -28,12 +28,13 @@ namespace igl
|
||||
/// @return list of faces touched by circulation (in cyclically order).
|
||||
///
|
||||
/// \see edge_flaps
|
||||
template <typename DerivedEMAP, typename DerivedEF, typename DerivedEI>
|
||||
IGL_INLINE std::vector<int> circulation(
|
||||
const int e,
|
||||
const bool ccw,
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI);
|
||||
const Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
const Eigen::MatrixBase<DerivedEF> & EF,
|
||||
const Eigen::MatrixBase<DerivedEI> & EI);
|
||||
/// Return list of faces around the end point of an edge. Assumes
|
||||
/// data-structures are built from an edge-manifold **closed** mesh.
|
||||
///
|
||||
@@ -49,13 +50,14 @@ namespace igl
|
||||
/// @param[out] #vN list of of faces touched by circulation (in cyclically order).
|
||||
///
|
||||
/// \see edge_flaps
|
||||
template <typename DerivedEMAP, typename DerivedEF, typename DerivedEI, typename DerivedvN>
|
||||
IGL_INLINE void circulation(
|
||||
const int e,
|
||||
const bool ccw,
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI,
|
||||
Eigen::VectorXi & vN);
|
||||
const Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
const Eigen::MatrixBase<DerivedEF> & EF,
|
||||
const Eigen::MatrixBase<DerivedEI> & EI,
|
||||
Eigen::PlainObjectBase<DerivedvN> & vN);
|
||||
/// Return list of faces around the end point of an edge. Assumes
|
||||
/// data-structures are built from an edge-manifold **closed** mesh.
|
||||
///
|
||||
@@ -72,16 +74,17 @@ namespace igl
|
||||
/// @param[out] Nf #Nf list of face indices
|
||||
///
|
||||
/// \see edge_flaps
|
||||
template <typename DerivedF, typename DerivedEMAP, typename DerivedEF, typename DerivedEI, typename Nv_type>
|
||||
IGL_INLINE void circulation(
|
||||
const int e,
|
||||
const bool ccw,
|
||||
const Eigen::MatrixXi & F,
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
const Eigen::MatrixBase<DerivedEF> & EF,
|
||||
const Eigen::MatrixBase<DerivedEI> & EI,
|
||||
/*std::vector<int> & Ne,*/
|
||||
std::vector<int> & Nv,
|
||||
std::vector<int> & Nf);
|
||||
std::vector<Nv_type> & Nv,
|
||||
std::vector<Nv_type> & Nf);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "circumradius.h"
|
||||
#include "edge_lengths.h"
|
||||
#include "doublearea.h"
|
||||
#include "placeholders.h"
|
||||
#include <Eigen/QR>
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
@@ -17,6 +19,9 @@ IGL_INLINE void igl::circumradius(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedR> & R)
|
||||
{
|
||||
// cols at compiletime should be Dynamic or 3
|
||||
static_assert(DerivedF::ColsAtCompileTime == Eigen::Dynamic || DerivedF::ColsAtCompileTime == 3,"F should contain triangles");
|
||||
assert(F.cols() == 3 && "F should contain triangles");
|
||||
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> l;
|
||||
igl::edge_lengths(V,F,l);
|
||||
DerivedR A;
|
||||
@@ -25,6 +30,59 @@ IGL_INLINE void igl::circumradius(
|
||||
R = l.col(0).array() * l.col(1).array() * l.col(2).array() / (2.0*A.array());
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedT,
|
||||
typename DerivedR,
|
||||
typename DerivedC,
|
||||
typename DerivedB>
|
||||
IGL_INLINE void igl::circumradius(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedT> & T,
|
||||
Eigen::PlainObjectBase<DerivedR> & R,
|
||||
Eigen::PlainObjectBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedB> & B)
|
||||
{
|
||||
using Scalar = typename DerivedV::Scalar;
|
||||
const int TCOLS = DerivedT::ColsAtCompileTime;
|
||||
const int VCOLS = DerivedV::ColsAtCompileTime;
|
||||
const int ACOLS = TCOLS==Eigen::Dynamic?Eigen::Dynamic:TCOLS+1;
|
||||
const int ss = T.cols();
|
||||
R.resize(T.rows(),1);
|
||||
C.resize(T.rows(),V.cols());
|
||||
B.resize(T.rows(),T.cols());
|
||||
for(int i = 0;i<T.rows();i++)
|
||||
{
|
||||
Eigen::Matrix<Scalar,ACOLS,ACOLS> A(T.cols()+1,T.cols()+1);
|
||||
// Not sure if this .eval() is a good idea
|
||||
const auto Vi = V(T.row(i),igl::placeholders::all).eval();
|
||||
A.topLeftCorner(T.cols(),T.cols()) = 2*(Vi*Vi.transpose());
|
||||
A.block(0,T.cols(),T.cols(),1).setConstant(1);
|
||||
A.block(T.cols(),0,1,T.cols()).setConstant(1);
|
||||
A(T.cols(),T.cols()) = 0;
|
||||
Eigen::Matrix<Scalar,ACOLS,1> b(T.cols()+1,1);
|
||||
b.head(T.cols()) = (Vi.array().square().rowwise().sum()).eval();
|
||||
b(T.cols()) = 1;
|
||||
// [B;λ] = A\b
|
||||
const auto x = (A.colPivHouseholderQr().solve(b)).eval();
|
||||
B.row(i) = x.head(T.cols());
|
||||
C.row(i) = B.row(i) * Vi;
|
||||
const Scalar lambda = x(T.cols());
|
||||
R(i) = std::sqrt(lambda + C.row(i).squaredNorm());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
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::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> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
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> >&);
|
||||
template void igl::circumradius<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
|
||||
template void igl::circumradius<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -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<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
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::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(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, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
|
||||
template void igl::circumradius<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -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<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::circumradius<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > 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, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
|
||||
template void igl::circumradius<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
|
||||
template void igl::circumradius<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
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
|
||||
|
||||
@@ -25,6 +25,26 @@ namespace igl
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedR> & R);
|
||||
/// Generic version
|
||||
///
|
||||
/// @param[in] V #V by dim list of mesh vertex positions
|
||||
/// @param[in] T #T by simplex-size list of simplex indices into V
|
||||
/// @param[out] R #T list of circumradius
|
||||
/// @param[out] C #T by dim list of circumcenter
|
||||
/// @param[out] B #T by simplex-size list of barycentric coordinates of circumcenter
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedT,
|
||||
typename DerivedR,
|
||||
typename DerivedC,
|
||||
typename DerivedB>
|
||||
IGL_INLINE void circumradius(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedT> & T,
|
||||
Eigen::PlainObjectBase<DerivedR> & R,
|
||||
Eigen::PlainObjectBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedB> & B);
|
||||
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "circumradius.cpp"
|
||||
|
||||
+36
-209
@@ -8,18 +8,25 @@
|
||||
#include "collapse_edge.h"
|
||||
#include "circulation.h"
|
||||
#include "edge_collapse_is_valid.h"
|
||||
#include "decimate_trivial_callbacks.h"
|
||||
#include <vector>
|
||||
|
||||
template <
|
||||
typename Derivedp,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedEF,
|
||||
typename DerivedEI>
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
const int e,
|
||||
const Eigen::RowVectorXd & p,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
const Eigen::MatrixBase<Derivedp> & p,
|
||||
Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::MatrixBase<DerivedE> & E,
|
||||
Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
Eigen::MatrixBase<DerivedEF> & EF,
|
||||
Eigen::MatrixBase<DerivedEI> & EI,
|
||||
int & e1,
|
||||
int & e2,
|
||||
int & f1,
|
||||
@@ -33,19 +40,28 @@ IGL_INLINE bool igl::collapse_edge(
|
||||
e,p,Nsv,Nsf,Ndv,Ndf,V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename Derivedp,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedEF,
|
||||
typename DerivedEI>
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
const int e,
|
||||
const Eigen::RowVectorXd & p,
|
||||
const Eigen::MatrixBase<Derivedp> & p,
|
||||
/*const*/ std::vector<int> & Nsv,
|
||||
const std::vector<int> & Nsf,
|
||||
/*const*/ std::vector<int> & Ndv,
|
||||
const std::vector<int> & Ndf,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::MatrixBase<DerivedE> & E,
|
||||
Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
Eigen::MatrixBase<DerivedEF> & EF,
|
||||
Eigen::MatrixBase<DerivedEI> & EI,
|
||||
int & a_e1,
|
||||
int & a_e2,
|
||||
int & a_f1,
|
||||
@@ -54,8 +70,6 @@ IGL_INLINE bool igl::collapse_edge(
|
||||
// Assign this to 0 rather than, say, -1 so that deleted elements will get
|
||||
// draw as degenerate elements at vertex 0 (which should always exist and
|
||||
// never get collapsed to anything else since it is the smallest index)
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
const int eflip = E(e,0)>E(e,1);
|
||||
// source and destination
|
||||
const int s = eflip?E(e,1):E(e,0);
|
||||
@@ -178,196 +192,9 @@ IGL_INLINE bool igl::collapse_edge(
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
const int e,
|
||||
const Eigen::RowVectorXd & p,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI)
|
||||
{
|
||||
int e1,e2,f1,f2;
|
||||
return collapse_edge(e,p,V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C)
|
||||
{
|
||||
int e,e1,e2,f1,f2;
|
||||
decimate_pre_collapse_callback always_try;
|
||||
decimate_post_collapse_callback never_care;
|
||||
decimate_trivial_callbacks(always_try,never_care);
|
||||
return
|
||||
collapse_edge(
|
||||
cost_and_placement,always_try,never_care,
|
||||
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2);
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_pre_collapse_callback & pre_collapse,
|
||||
const decimate_post_collapse_callback & post_collapse,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C)
|
||||
{
|
||||
int e,e1,e2,f1,f2;
|
||||
return
|
||||
collapse_edge(
|
||||
cost_and_placement,pre_collapse,post_collapse,
|
||||
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2);
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_pre_collapse_callback & pre_collapse,
|
||||
const decimate_post_collapse_callback & post_collapse,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C,
|
||||
int & e,
|
||||
int & e1,
|
||||
int & e2,
|
||||
int & f1,
|
||||
int & f2)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace igl;
|
||||
std::tuple<double,int,int> p;
|
||||
while(true)
|
||||
{
|
||||
// Check if Q is empty
|
||||
if(Q.empty())
|
||||
{
|
||||
// no edges to collapse
|
||||
e = -1;
|
||||
return false;
|
||||
}
|
||||
// pop from Q
|
||||
p = Q.top();
|
||||
if(std::get<0>(p) == std::numeric_limits<double>::infinity())
|
||||
{
|
||||
e = -1;
|
||||
// min cost edge is infinite cost
|
||||
return false;
|
||||
}
|
||||
Q.pop();
|
||||
e = std::get<1>(p);
|
||||
// Check if matches timestamp
|
||||
if(std::get<2>(p) == EQ(e))
|
||||
{
|
||||
break;
|
||||
}
|
||||
// must be stale or dead.
|
||||
assert(std::get<2>(p) < EQ(e) || EQ(e) == -1);
|
||||
// try again.
|
||||
}
|
||||
|
||||
// Why is this computed up here?
|
||||
// If we just need original face neighbors of edge, could we gather that more
|
||||
// directly than gathering face neighbors of each vertex?
|
||||
std::vector<int> /*Nse,*/Nsf,Nsv;
|
||||
circulation(e, true,F,EMAP,EF,EI,/*Nse,*/Nsv,Nsf);
|
||||
std::vector<int> /*Nde,*/Ndf,Ndv;
|
||||
circulation(e, false,F,EMAP,EF,EI,/*Nde,*/Ndv,Ndf);
|
||||
|
||||
|
||||
bool collapsed = true;
|
||||
if(pre_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e))
|
||||
{
|
||||
collapsed = collapse_edge(
|
||||
e,C.row(e),
|
||||
Nsv,Nsf,Ndv,Ndf,
|
||||
V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
|
||||
}else
|
||||
{
|
||||
// Aborted by pre collapse callback
|
||||
collapsed = false;
|
||||
}
|
||||
post_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2,collapsed);
|
||||
if(collapsed)
|
||||
{
|
||||
// Erase the two, other collapsed edges by marking their timestamps as -1
|
||||
EQ(e1) = -1;
|
||||
EQ(e2) = -1;
|
||||
// TODO: visits edges multiple times, ~150% more updates than should
|
||||
//
|
||||
// update local neighbors
|
||||
// loop over original face neighbors
|
||||
//
|
||||
// Can't use previous computed Nse and Nde because those refer to EMAP
|
||||
// before it was changed...
|
||||
std::vector<int> Nf;
|
||||
Nf.reserve( Nsf.size() + Ndf.size() ); // preallocate memory
|
||||
Nf.insert( Nf.end(), Nsf.begin(), Nsf.end() );
|
||||
Nf.insert( Nf.end(), Ndf.begin(), Ndf.end() );
|
||||
// https://stackoverflow.com/a/1041939/148668
|
||||
std::sort( Nf.begin(), Nf.end() );
|
||||
Nf.erase( std::unique( Nf.begin(), Nf.end() ), Nf.end() );
|
||||
// Collect all edges that must be updated
|
||||
std::vector<int> Ne;
|
||||
Ne.reserve(3*Nf.size());
|
||||
for(auto & n : Nf)
|
||||
{
|
||||
if(F(n,0) != IGL_COLLAPSE_EDGE_NULL ||
|
||||
F(n,1) != IGL_COLLAPSE_EDGE_NULL ||
|
||||
F(n,2) != IGL_COLLAPSE_EDGE_NULL)
|
||||
{
|
||||
for(int v = 0;v<3;v++)
|
||||
{
|
||||
// get edge id
|
||||
const int ei = EMAP(v*F.rows()+n);
|
||||
Ne.push_back(ei);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Only process edge once
|
||||
std::sort( Ne.begin(), Ne.end() );
|
||||
Ne.erase( std::unique( Ne.begin(), Ne.end() ), Ne.end() );
|
||||
for(auto & ei : Ne)
|
||||
{
|
||||
// compute cost and potential placement
|
||||
double cost;
|
||||
RowVectorXd place;
|
||||
cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place);
|
||||
// Increment timestamp
|
||||
EQ(ei)++;
|
||||
// Replace in queue
|
||||
Q.emplace(cost,ei,EQ(ei));
|
||||
C.row(ei) = place;
|
||||
}
|
||||
}else
|
||||
{
|
||||
// reinsert with infinite weight (the provided cost function must **not**
|
||||
// have given this un-collapsable edge inf cost already)
|
||||
// Increment timestamp
|
||||
EQ(e)++;
|
||||
// Replace in queue
|
||||
Q.emplace(std::numeric_limits<double>::infinity(),e,EQ(e));
|
||||
}
|
||||
return collapsed;
|
||||
}
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::collapse_edge<Eigen::Matrix<double, 1, -1, 1, 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::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>>(int, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, int&, int&, int&, int&);
|
||||
template bool igl::collapse_edge<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1, -1, false>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>>(int, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1, -1, false>> const&, std::vector<int, std::allocator<int>>&, std::vector<int, std::allocator<int>> const&, std::vector<int, std::allocator<int>>&, std::vector<int, std::allocator<int>> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, int&, int&, int&, int&);
|
||||
#endif
|
||||
|
||||
+96
-116
@@ -8,18 +8,11 @@
|
||||
#ifndef IGL_COLLAPSE_EDGE_H
|
||||
#define IGL_COLLAPSE_EDGE_H
|
||||
#include "igl_inline.h"
|
||||
#include "min_heap.h"
|
||||
#include "decimate_callback_types.h"
|
||||
#include "COLLAPSE_EDGE_NULL.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
namespace igl
|
||||
{
|
||||
#ifndef IGL_COLLAPSE_EDGE_NULL
|
||||
/// Special value for indicating a null vertex index as the result of a
|
||||
/// collapsed edge.
|
||||
#define IGL_COLLAPSE_EDGE_NULL 0
|
||||
#endif
|
||||
/// Attempt to collapse a given edge of a mesh. Assumes (V,F) is a closed
|
||||
/// manifold mesh (except for previously collapsed faces which should be set
|
||||
/// to: [IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL
|
||||
@@ -48,15 +41,83 @@ namespace igl
|
||||
/// @param[out] f1 index into F of face collpased on left
|
||||
/// @param[out] f2 index into F of face collpased on right
|
||||
/// @return true if edge was collapsed
|
||||
///
|
||||
///
|
||||
/// Define [s,d] = sort(E(e,:)) so that s<d, then d is "detached" from
|
||||
/// connectivity meaning all faces/edges incident on d will now be incident on
|
||||
/// s. (This reduces fragmentation by preferring to collapse toward the start
|
||||
/// of V)¹. If E(e,1)==s then we say the edge is "flipped" (`eflip` true in
|
||||
/// the implementation).
|
||||
///
|
||||
/// f1 is set to EF(e,0) and f2 is set to EF(e,1). Let v1 be EI(e,0) the
|
||||
/// corner of F(f1,:) opposite e. _If_ (s<d) then e1 will be the edge after e
|
||||
/// within f1:
|
||||
///
|
||||
/// s<d
|
||||
/// ✅s----e-----d☠️
|
||||
/// \ ← /
|
||||
/// \ ↘f₁↗ /
|
||||
/// e₁ /
|
||||
/// \ /
|
||||
/// \/
|
||||
///
|
||||
/// _If_ (s>d) then e1 will be the edge after e within f1:
|
||||
///
|
||||
/// s>d
|
||||
/// ✅s----e-----d☠️
|
||||
/// \ ← /
|
||||
/// \ ↘f₁↗ /
|
||||
/// \ e₁
|
||||
/// \ /
|
||||
/// \/
|
||||
///
|
||||
///
|
||||
/// ¹Or at least it would if we templated these functions to allow using
|
||||
/// RowMajor V.
|
||||
///
|
||||
/// It really seems that this callback should provide a meaningful edge on the
|
||||
/// _new_ mesh. Meanwhile – Oof – You can use this gross mechanism to find the faces incident on the
|
||||
/// collapsed vertex:
|
||||
///
|
||||
/// ```cpp
|
||||
/// const auto survivors =
|
||||
/// [&F,&e,&EMAP](const int f1, const int e1, int & d1)
|
||||
/// {
|
||||
/// for(int c=0;c<3;c++)
|
||||
/// {
|
||||
/// d1 = EMAP(f1+c*F.rows());
|
||||
/// if((d1 != e) && (d1 != e1)) { break; }
|
||||
/// }
|
||||
/// };
|
||||
/// int d1,d2;
|
||||
/// survivors(f1,e1,d1);
|
||||
/// survivors(f2,e2,d2);
|
||||
/// // Will circulating by continuing in the CCW direction of E(d1,:)
|
||||
/// // encircle the common edge? That is, is E(d1,1) the common vertex?
|
||||
/// const bool ccw = E(d1,1) == E(d2,0) || E(d1,1) == E(d2,1);
|
||||
/// std::vector<int> Nf;
|
||||
/// {
|
||||
/// std::vector<int> Nv;
|
||||
/// igl::circulation(d1,ccw,F,EMAP,EF,EI,Nv,Nf);
|
||||
/// }
|
||||
/// ```
|
||||
template <
|
||||
typename Derivedp,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedEF,
|
||||
typename DerivedEI>
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const int e,
|
||||
const Eigen::RowVectorXd & p,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
const Eigen::MatrixBase<Derivedp> & p,
|
||||
Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::MatrixBase<DerivedE> & E,
|
||||
Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
Eigen::MatrixBase<DerivedEF> & EF,
|
||||
Eigen::MatrixBase<DerivedEI> & EI,
|
||||
int & e1,
|
||||
int & e2,
|
||||
int & f1,
|
||||
@@ -67,113 +128,32 @@ namespace igl
|
||||
/// @param[in] Nsf #Nsf face circulation around s
|
||||
/// @param[in] Ndv #Ndv vertex circulation around d
|
||||
/// @param[in] Ndf #Ndf face circulation around d
|
||||
template
|
||||
<
|
||||
typename Derivedp,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedEF,
|
||||
typename DerivedEI>
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const int e,
|
||||
const Eigen::RowVectorXd & p,
|
||||
const Eigen::MatrixBase<Derivedp> & p,
|
||||
/*const*/ std::vector<int> & Nsv,
|
||||
const std::vector<int> & Nsf,
|
||||
/*const*/ std::vector<int> & Ndv,
|
||||
const std::vector<int> & Ndf,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
int & e1,
|
||||
int & e2,
|
||||
int & f1,
|
||||
int & f2);
|
||||
/// \overload
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const int e,
|
||||
const Eigen::RowVectorXd & p,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI);
|
||||
/// Collapse least-cost edge from a priority queue and update queue
|
||||
///
|
||||
/// See decimate.h for more details.
|
||||
///
|
||||
/// @param[in] cost_and_placement function computing cost of collapsing an edge and 3d
|
||||
/// position where it should be placed:
|
||||
/// cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement);
|
||||
/// **If the edges is collapsed** then this function will be called on all
|
||||
/// edges of all faces previously incident on the endpoints of the
|
||||
/// collapsed edge.
|
||||
/// @param[in] pre_collapse callback called with index of edge whose collapse is about
|
||||
/// to be attempted. This function should return whether to **proceed**
|
||||
/// with the collapse: returning true means "yes, try to collapse",
|
||||
/// returning false means "No, consider this edge 'uncollapsable', behave
|
||||
/// as if collapse_edge(e) returned false.
|
||||
/// @param[in] post_collapse callback called with index of edge whose collapse was
|
||||
/// just attempted and a flag revealing whether this was successful.
|
||||
/// @param[in,out] V #V by dim list of vertex positions, lesser index of E(e,:) will be set
|
||||
/// to midpoint of edge.
|
||||
/// @param[in,out] F #F by 3 list of face indices into V.
|
||||
/// @param[in,out] E #E by 2 list of edge indices into V.
|
||||
/// @param[in,out] EMAP #F*3 list of indices into E, mapping each directed edge to unique
|
||||
/// unique edge in E
|
||||
/// @param[in,out] EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
|
||||
/// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1)
|
||||
/// e=(j->i)
|
||||
/// @param[in,out] EI #E by 2 list of edge flap corners (see above).
|
||||
/// @param[in] Q queue containing pairs of costs and edge indices and insertion "time"
|
||||
/// @param[in] EQ #E list of "time" of last time pushed into Q
|
||||
/// @param[in] C #E by dim list of stored placements
|
||||
/// @param[out] e index into E of attempted collapsed edge. Set to -1 if Q is empty or
|
||||
/// contains only infinite cost edges.
|
||||
/// @param[out] e1 index into E of edge collpased on left.
|
||||
/// @param[out] e2 index into E of edge collpased on right.
|
||||
/// @param[out] f1 index into F of face collpased on left.
|
||||
/// @param[out] f2 index into F of face collpased on right.
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_pre_collapse_callback & pre_collapse,
|
||||
const decimate_post_collapse_callback & post_collapse,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C,
|
||||
int & e,
|
||||
int & e1,
|
||||
int & e2,
|
||||
int & f1,
|
||||
int & f2);
|
||||
/// \overload
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C);
|
||||
/// \overload
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_pre_collapse_callback & pre_collapse,
|
||||
const decimate_post_collapse_callback & post_collapse,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C);
|
||||
Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::MatrixBase<DerivedE> & E,
|
||||
Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
Eigen::MatrixBase<DerivedEF> & EF,
|
||||
Eigen::MatrixBase<DerivedEI> & EI,
|
||||
int & a_e1,
|
||||
int & a_e2,
|
||||
int & a_f1,
|
||||
int & a_f2);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
#include "collapse_edge_would_create_intersections.h"
|
||||
#include "AABB.h"
|
||||
#include "circulation.h"
|
||||
#include "writePLY.h"
|
||||
#include "triangle_triangle_intersect.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
template <
|
||||
typename Derivedp,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedEF,
|
||||
typename DerivedEI>
|
||||
IGL_INLINE bool igl::collapse_edge_would_create_intersections(
|
||||
const int e,
|
||||
const Eigen::MatrixBase<Derivedp> & p,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedE> & E,
|
||||
const Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
const Eigen::MatrixBase<DerivedEF> & EF,
|
||||
const Eigen::MatrixBase<DerivedEI> & EI,
|
||||
const igl::AABB<DerivedV,3> & tree,
|
||||
const int inf_face_id)
|
||||
{
|
||||
// Merge two lists of integers
|
||||
const auto merge = [&](
|
||||
const std::vector<int> & A, const std::vector<int> & B)->
|
||||
std::vector<int>
|
||||
{
|
||||
std::vector<int> C;
|
||||
C.reserve( A.size() + B.size() ); // preallocate memory
|
||||
C.insert( C.end(), A.begin(), A.end() );
|
||||
C.insert( C.end(), B.begin(), B.end() );
|
||||
// https://stackoverflow.com/a/1041939/148668
|
||||
std::sort( C.begin(), C.end() );
|
||||
C.erase( std::unique( C.begin(), C.end() ), C.end() );
|
||||
return C;
|
||||
};
|
||||
|
||||
std::vector<int> old_one_ring;
|
||||
{
|
||||
std::vector<int> Nsv,Nsf,Ndv,Ndf;
|
||||
igl::circulation(e, true,F,EMAP,EF,EI,Nsv,Nsf);
|
||||
igl::circulation(e,false,F,EMAP,EF,EI,Ndv,Ndf);
|
||||
old_one_ring = merge(Nsf,Ndf);
|
||||
}
|
||||
int f1 = EF(e,0);
|
||||
int f2 = EF(e,1);
|
||||
std::vector<int> new_one_ring = old_one_ring;
|
||||
// erase if ==f1 or ==f2
|
||||
new_one_ring.erase(
|
||||
std::remove(new_one_ring.begin(), new_one_ring.end(), f1),
|
||||
new_one_ring.end());
|
||||
new_one_ring.erase(
|
||||
std::remove(new_one_ring.begin(), new_one_ring.end(), f2),
|
||||
new_one_ring.end());
|
||||
|
||||
|
||||
// big box containing new_one_ring
|
||||
Eigen::AlignedBox<double,3> big_box;
|
||||
// Extend box by placement point
|
||||
big_box.extend(p.transpose());
|
||||
// Extend box by all other corners (skipping old edge vertices)
|
||||
for(const auto f : new_one_ring)
|
||||
{
|
||||
Eigen::RowVector3d corners[3];
|
||||
for(int c = 0;c<3;c++)
|
||||
{
|
||||
if(F(f,c) == E(e,0) || F(f,c) == E(e,1))
|
||||
{
|
||||
corners[c] = p;
|
||||
}else
|
||||
{
|
||||
corners[c] = V.row(F(f,c));
|
||||
big_box.extend(V.row(F(f,c)).transpose());
|
||||
}
|
||||
}
|
||||
// Degenerate triangles are considered intersections
|
||||
if((corners[0]-corners[1]).cross(corners[0]-corners[2]).squaredNorm() < 1e-16)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<const igl::AABB<Eigen::MatrixXd,3>*> candidates;
|
||||
tree.append_intersecting_leaves(big_box,candidates);
|
||||
|
||||
|
||||
// Exclude any candidates that are in old_one_ring.
|
||||
// consider using unordered_set above so that this is O(n+m) rather than O(nm)
|
||||
candidates.erase(
|
||||
std::remove_if(candidates.begin(), candidates.end(),
|
||||
[&](const igl::AABB<Eigen::MatrixXd,3>* candidate) {
|
||||
return std::find(old_one_ring.begin(), old_one_ring.end(), candidate->m_primitive) != old_one_ring.end();
|
||||
}),
|
||||
candidates.end());
|
||||
// print candidates
|
||||
//const bool stinker = e==2581;
|
||||
constexpr bool stinker = false;
|
||||
if(stinker)
|
||||
{
|
||||
igl::writePLY("before.ply",V,F);
|
||||
std::cout<<"Ee = ["<<E(e,0)<<" "<<E(e,1)<<"]+1;"<<std::endl;
|
||||
std::cout<<"p = ["<<p<<"];"<<std::endl;
|
||||
// print new_one_ring as matlab vector of indices
|
||||
std::cout<<"new_one_ring = [";
|
||||
for(const auto f : new_one_ring)
|
||||
{
|
||||
std::cout<<f<<" ";
|
||||
}
|
||||
std::cout<<"]+1;"<<std::endl;
|
||||
// print candidates as matlab vector of indices
|
||||
std::cout<<"candidates = [";
|
||||
for(const auto * candidate : candidates)
|
||||
{
|
||||
std::cout<<candidate->m_primitive<<" ";
|
||||
}
|
||||
std::cout<<"]+1;"<<std::endl;
|
||||
}
|
||||
|
||||
// For each pair of candidate and new_one_ring, check if they intersect
|
||||
bool found_intersection = false;
|
||||
for(const int & f : new_one_ring)
|
||||
{
|
||||
if(inf_face_id >= 0 && f >= inf_face_id) { continue; }
|
||||
|
||||
Eigen::AlignedBox<double,3> small_box;
|
||||
small_box.extend(p.transpose());
|
||||
for(int c = 0;c<3;c++)
|
||||
{
|
||||
if(F(f,c) != E(e,0) && F(f,c) != E(e,1))
|
||||
{
|
||||
small_box.extend(V.row(F(f,c)).transpose());
|
||||
}
|
||||
}
|
||||
for(const auto * candidate : candidates)
|
||||
{
|
||||
const int g = candidate->m_primitive;
|
||||
//constexpr bool inner_stinker = false;
|
||||
const bool inner_stinker = stinker && (f==1492 && g==1554);
|
||||
if(inner_stinker){ printf(" f: %d g: %d\n",f,g); }
|
||||
if(!small_box.intersects(candidate->m_box))
|
||||
{
|
||||
if(inner_stinker){ printf(" ✅ boxes don't overlap\n"); }
|
||||
continue;
|
||||
}
|
||||
// Corner replaced by p
|
||||
int c;
|
||||
for(c = 0;c<3;c++)
|
||||
{
|
||||
if(F(f,c) == E(e,0) || F(f,c) == E(e,1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(c<3);
|
||||
found_intersection = triangle_triangle_intersect(V,F,E,EMAP,EF,f,c,p,g);
|
||||
if(found_intersection) { break; }
|
||||
}
|
||||
if(found_intersection) { break; }
|
||||
}
|
||||
return found_intersection;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::collapse_edge_would_create_intersections<Eigen::Matrix<double, 1, -1, 1, 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::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>>(int, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 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&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>> const&, igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3> const&, int);
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef IGL_COLLAPSE_EDGE_WOULD_CREATE_INTERSECTIONS_H
|
||||
#define IGL_COLLAPSE_EDGE_WOULD_CREATE_INTERSECTIONS_H
|
||||
#include "igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
/// Determine if collapse the edge `e` would create new intersections.
|
||||
///
|
||||
/// @param[in] e index into E of edge to try to collapse. E(e,:) = [s d] or [d s] so
|
||||
/// that s<d, then d is collapsed to s.
|
||||
/// @param[in] p dim list of vertex position where to place merged vertex
|
||||
/// [mesh inputs]
|
||||
/// @param[in,out] V #V by dim list of vertex positions, lesser index of E(e,:) will be set
|
||||
/// to midpoint of edge.
|
||||
/// @param[in,out] F #F by 3 list of face indices into V.
|
||||
/// @param[in,out] E #E by 2 list of edge indices into V.
|
||||
/// @param[in,out] EMAP #F*3 list of indices into E, mapping each directed edge to unique
|
||||
/// unique edge in E
|
||||
/// @param[in,out] EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
|
||||
/// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
|
||||
/// e=(j->i)
|
||||
/// @param[in,out] EI #E by 2 list of edge flap corners (see above).
|
||||
/// [mesh inputs]
|
||||
/// @param[in] tree AABB tree whose leaves correspond to the current
|
||||
/// (non-null) faces in (V,F)
|
||||
///
|
||||
/// \see collapse_edge
|
||||
template <typename DerivedV, int DIM> class AABB;
|
||||
|
||||
template <
|
||||
typename Derivedp,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedEF,
|
||||
typename DerivedEI>
|
||||
IGL_INLINE bool collapse_edge_would_create_intersections(
|
||||
const int e,
|
||||
const Eigen::MatrixBase<Derivedp> & p,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedE> & E,
|
||||
const Eigen::MatrixBase<DerivedEMAP> & EMAP,
|
||||
const Eigen::MatrixBase<DerivedEF> & EF,
|
||||
const Eigen::MatrixBase<DerivedEI> & EI,
|
||||
const igl::AABB<DerivedV,3> & tree,
|
||||
const int inf_face_id = -1);
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "collapse_edge_would_create_intersections.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,147 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2025 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "collapse_least_cost_edge.h"
|
||||
#include "collapse_edge.h"
|
||||
#include "circulation.h"
|
||||
|
||||
IGL_INLINE bool igl::collapse_least_cost_edge(
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_pre_collapse_callback & pre_collapse,
|
||||
const decimate_post_collapse_callback & post_collapse,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C,
|
||||
int & e,
|
||||
int & e1,
|
||||
int & e2,
|
||||
int & f1,
|
||||
int & f2)
|
||||
{
|
||||
using namespace igl;
|
||||
std::tuple<double,int,int> p;
|
||||
while(true)
|
||||
{
|
||||
// Check if Q is empty
|
||||
if(Q.empty())
|
||||
{
|
||||
// no edges to collapse
|
||||
e = -1;
|
||||
return false;
|
||||
}
|
||||
// pop from Q
|
||||
p = Q.top();
|
||||
if(std::get<0>(p) == std::numeric_limits<double>::infinity())
|
||||
{
|
||||
e = -1;
|
||||
// min cost edge is infinite cost
|
||||
return false;
|
||||
}
|
||||
Q.pop();
|
||||
e = std::get<1>(p);
|
||||
// Check if matches timestamp
|
||||
if(std::get<2>(p) == EQ(e))
|
||||
{
|
||||
break;
|
||||
}
|
||||
// must be stale or dead.
|
||||
assert(std::get<2>(p) < EQ(e) || EQ(e) == -1);
|
||||
// try again.
|
||||
}
|
||||
|
||||
// Why is this computed up here?
|
||||
// If we just need original face neighbors of edge, could we gather that more
|
||||
// directly than gathering face neighbors of each vertex?
|
||||
std::vector<int> /*Nse,*/Nsf,Nsv;
|
||||
circulation(e, true,F,EMAP,EF,EI,/*Nse,*/Nsv,Nsf);
|
||||
std::vector<int> /*Nde,*/Ndf,Ndv;
|
||||
circulation(e, false,F,EMAP,EF,EI,/*Nde,*/Ndv,Ndf);
|
||||
|
||||
|
||||
bool collapsed = true;
|
||||
if(pre_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e))
|
||||
{
|
||||
collapsed = collapse_edge(
|
||||
e,C.row(e),
|
||||
Nsv,Nsf,Ndv,Ndf,
|
||||
V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
|
||||
}else
|
||||
{
|
||||
// Aborted by pre collapse callback
|
||||
collapsed = false;
|
||||
}
|
||||
post_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2,collapsed);
|
||||
if(collapsed)
|
||||
{
|
||||
// Erase the center edge, marking its timestamp as -1
|
||||
EQ(e) = -1;
|
||||
// Erase the two, other collapsed edges by marking their timestamps as -1
|
||||
EQ(e1) = -1;
|
||||
EQ(e2) = -1;
|
||||
// TODO: visits edges multiple times, ~150% more updates than should
|
||||
//
|
||||
// update local neighbors
|
||||
// loop over original face neighbors
|
||||
//
|
||||
// Can't use previous computed Nse and Nde because those refer to EMAP
|
||||
// before it was changed...
|
||||
std::vector<int> Nf;
|
||||
Nf.reserve( Nsf.size() + Ndf.size() ); // preallocate memory
|
||||
Nf.insert( Nf.end(), Nsf.begin(), Nsf.end() );
|
||||
Nf.insert( Nf.end(), Ndf.begin(), Ndf.end() );
|
||||
// https://stackoverflow.com/a/1041939/148668
|
||||
std::sort( Nf.begin(), Nf.end() );
|
||||
Nf.erase( std::unique( Nf.begin(), Nf.end() ), Nf.end() );
|
||||
// Collect all edges that must be updated
|
||||
std::vector<int> Ne;
|
||||
Ne.reserve(3*Nf.size());
|
||||
for(auto & n : Nf)
|
||||
{
|
||||
if(F(n,0) != IGL_COLLAPSE_EDGE_NULL ||
|
||||
F(n,1) != IGL_COLLAPSE_EDGE_NULL ||
|
||||
F(n,2) != IGL_COLLAPSE_EDGE_NULL)
|
||||
{
|
||||
for(int v = 0;v<3;v++)
|
||||
{
|
||||
// get edge id
|
||||
const int ei = EMAP(v*F.rows()+n);
|
||||
Ne.push_back(ei);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Only process edge once
|
||||
std::sort( Ne.begin(), Ne.end() );
|
||||
Ne.erase( std::unique( Ne.begin(), Ne.end() ), Ne.end() );
|
||||
for(auto & ei : Ne)
|
||||
{
|
||||
// compute cost and potential placement
|
||||
double cost;
|
||||
Eigen::RowVectorXd place;
|
||||
cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place);
|
||||
// Increment timestamp
|
||||
EQ(ei)++;
|
||||
// Replace in queue
|
||||
Q.emplace(cost,ei,EQ(ei));
|
||||
C.row(ei) = place;
|
||||
}
|
||||
}else
|
||||
{
|
||||
// reinsert with infinite weight (the provided cost function must **not**
|
||||
// have given this un-collapsable edge inf cost already)
|
||||
// Increment timestamp
|
||||
EQ(e)++;
|
||||
// Replace in queue
|
||||
Q.emplace(std::numeric_limits<double>::infinity(),e,EQ(e));
|
||||
}
|
||||
return collapsed;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COLLAPSE_LEAST_COST_EDGE_H
|
||||
#define IGL_COLLAPSE_LEAST_COST_EDGE_H
|
||||
#include "igl_inline.h"
|
||||
#include "min_heap.h"
|
||||
#include "decimate_callback_types.h"
|
||||
#include "COLLAPSE_EDGE_NULL.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
namespace igl
|
||||
{
|
||||
/// Collapse least-cost edge from a priority queue and update queue
|
||||
///
|
||||
/// See decimate.h for more details.
|
||||
///
|
||||
/// @param[in] cost_and_placement function computing cost of collapsing an edge and 3d
|
||||
/// position where it should be placed:
|
||||
/// cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement);
|
||||
/// **If the edges is collapsed** then this function will be called on all
|
||||
/// edges of all faces previously incident on the endpoints of the
|
||||
/// collapsed edge.
|
||||
/// @param[in] pre_collapse callback called with index of edge whose collapse is about
|
||||
/// to be attempted. This function should return whether to **proceed**
|
||||
/// with the collapse: returning true means "yes, try to collapse",
|
||||
/// returning false means "No, consider this edge 'uncollapsable', behave
|
||||
/// as if collapse_edge(e) returned false.
|
||||
/// @param[in] post_collapse callback called with index of edge whose collapse was
|
||||
/// just attempted and a flag revealing whether this was successful.
|
||||
/// @param[in,out] V #V by dim list of vertex positions, lesser index of E(e,:) will be set
|
||||
/// to midpoint of edge.
|
||||
/// @param[in,out] F #F by 3 list of face indices into V.
|
||||
/// @param[in,out] E #E by 2 list of edge indices into V.
|
||||
/// @param[in,out] EMAP #F*3 list of indices into E, mapping each directed edge to unique
|
||||
/// unique edge in E
|
||||
/// @param[in,out] EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
|
||||
/// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1)
|
||||
/// e=(j->i)
|
||||
/// @param[in,out] EI #E by 2 list of edge flap corners (see above).
|
||||
/// @param[in] Q queue containing pairs of costs and edge indices and insertion "time"
|
||||
/// @param[in] EQ #E list of "time" of last time pushed into Q
|
||||
/// @param[in] C #E by dim list of stored placements
|
||||
/// @param[out] e index into E of attempted collapsed edge. Set to -1 if Q is empty or
|
||||
/// contains only infinite cost edges.
|
||||
/// @param[out] e1 index into E of edge collpased on left.
|
||||
/// @param[out] e2 index into E of edge collpased on right.
|
||||
/// @param[out] f1 index into F of face collpased on left.
|
||||
/// @param[out] f2 index into F of face collpased on right.
|
||||
///
|
||||
/// \bug This function is not templated nicely and refactoring it and its
|
||||
/// dependencies to do so is non-trivial, see
|
||||
/// https://github.com/libigl/libigl/issues/2452
|
||||
IGL_INLINE bool collapse_least_cost_edge(
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_pre_collapse_callback & pre_collapse,
|
||||
const decimate_post_collapse_callback & post_collapse,
|
||||
Eigen::MatrixXd & V,
|
||||
Eigen::MatrixXi & F,
|
||||
Eigen::MatrixXi & E,
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C,
|
||||
int & e,
|
||||
int & e1,
|
||||
int & e2,
|
||||
int & f1,
|
||||
int & f2);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "collapse_least_cost_edge.cpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -17,20 +17,21 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedFF>
|
||||
void igl::collapse_small_triangles(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const double eps,
|
||||
Eigen::MatrixXi & FF)
|
||||
Eigen::PlainObjectBase<DerivedFF> & FF)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
||||
// Compute bounding box diagonal length
|
||||
double bbd = bounding_box_diagonal(V);
|
||||
MatrixXd l;
|
||||
Eigen::MatrixXd l;
|
||||
edge_lengths(V,F,l);
|
||||
VectorXd dblA;
|
||||
Eigen::VectorXd dblA;
|
||||
doublearea(l,0.,dblA);
|
||||
|
||||
// Minimum area tolerance
|
||||
@@ -81,7 +82,7 @@ void igl::collapse_small_triangles(
|
||||
}
|
||||
|
||||
// Reindex faces
|
||||
MatrixXi rF = F;
|
||||
Eigen::MatrixXi rF = F;
|
||||
// Loop over triangles
|
||||
for(int f = 0;f<rF.rows();f++)
|
||||
{
|
||||
@@ -138,6 +139,11 @@ void igl::collapse_small_triangles(
|
||||
//// force base case
|
||||
//return;
|
||||
|
||||
MatrixXi recFF = FF;
|
||||
Eigen::MatrixXi recFF = FF;
|
||||
return collapse_small_triangles(V,recFF,eps,FF);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::collapse_small_triangles<Eigen::MatrixXd, Eigen::MatrixXi, Eigen::MatrixXi> ( const Eigen::MatrixBase<Eigen::MatrixXd> &, const Eigen::MatrixBase<Eigen::MatrixXi> &, const double , Eigen::PlainObjectBase<Eigen::MatrixXi> & );
|
||||
#endif
|
||||
|
||||
@@ -24,11 +24,15 @@ namespace igl
|
||||
/// @param[out] FF #FF by 3 list of triangle indices into V
|
||||
///
|
||||
///
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedFF>
|
||||
void collapse_small_triangles(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const double eps,
|
||||
Eigen::MatrixXi & FF);
|
||||
Eigen::PlainObjectBase<DerivedFF> & FF);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
|
||||
@@ -11,7 +11,6 @@ IGL_INLINE bool igl::column_to_quats(
|
||||
std::vector<
|
||||
Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ)
|
||||
{
|
||||
using namespace Eigen;
|
||||
if(Q.size() % 4 != 0)
|
||||
{
|
||||
return false;
|
||||
@@ -21,7 +20,7 @@ IGL_INLINE bool igl::column_to_quats(
|
||||
for(int q=0;q<nQ;q++)
|
||||
{
|
||||
// Constructor uses wxyz
|
||||
vQ[q] = Quaterniond( Q(q*4+3), Q(q*4+0), Q(q*4+1), Q(q*4+2));
|
||||
vQ[q] = Eigen::Quaterniond( Q(q*4+3), Q(q*4+0), Q(q*4+1), Q(q*4+2));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
template <typename DerivedA, typename DerivedB>
|
||||
IGL_INLINE void igl::columnize(
|
||||
const Eigen::PlainObjectBase<DerivedA> & A,
|
||||
const Eigen::MatrixBase<DerivedA> & A,
|
||||
const int k,
|
||||
const int dim,
|
||||
Eigen::PlainObjectBase<DerivedB> & B)
|
||||
@@ -56,8 +56,8 @@ IGL_INLINE void igl::columnize(
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::columnize<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&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::columnize<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&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::columnize<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::columnize<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::columnize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::columnize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::columnize<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::columnize<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace igl
|
||||
/// \see transpose_blocks
|
||||
template <typename DerivedA, typename DerivedB>
|
||||
IGL_INLINE void columnize(
|
||||
const Eigen::PlainObjectBase<DerivedA> & A,
|
||||
const Eigen::MatrixBase<DerivedA> & A,
|
||||
const int k,
|
||||
const int dim,
|
||||
Eigen::PlainObjectBase<DerivedB> & B);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "per_face_normals.h"
|
||||
#include "is_border_vertex.h"
|
||||
#include "rotation_matrix_from_directions.h"
|
||||
#include "PlainMatrix.h"
|
||||
|
||||
#include "triangle_triangle_adjacency.h"
|
||||
|
||||
@@ -27,12 +28,12 @@ namespace igl {
|
||||
const Eigen::MatrixBase<DerivedF> &F;
|
||||
const Eigen::MatrixBase<DerivedV> &PD1;
|
||||
const Eigen::MatrixBase<DerivedV> &PD2;
|
||||
DerivedV N;
|
||||
PlainMatrix<DerivedV> N;
|
||||
|
||||
private:
|
||||
// internal
|
||||
DerivedF TT;
|
||||
DerivedF TTi;
|
||||
PlainMatrix<DerivedF> TT;
|
||||
PlainMatrix<DerivedF> TTi;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -14,18 +14,20 @@
|
||||
#include "comb_frame_field.h"
|
||||
#include "local_basis.h"
|
||||
#include "PI.h"
|
||||
#include "PlainMatrix.h"
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedP>
|
||||
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)
|
||||
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)
|
||||
{
|
||||
DerivedV B1, B2, B3;
|
||||
PlainMatrix<DerivedV,Eigen::Dynamic> B1, B2, B3;
|
||||
igl::local_basis(V,F,B1,B2,B3);
|
||||
|
||||
PD1_combed.resize(BIS1_combed.rows(),3);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "rotation_matrix_from_directions.h"
|
||||
|
||||
#include "triangle_triangle_adjacency.h"
|
||||
#include "PlainMatrix.h"
|
||||
|
||||
namespace igl {
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
@@ -25,12 +26,12 @@ public:
|
||||
const Eigen::MatrixBase<DerivedV> &V;
|
||||
const Eigen::MatrixBase<DerivedF> &F;
|
||||
const Eigen::MatrixBase<DerivedV> &PD1;
|
||||
DerivedV N;
|
||||
PlainMatrix<DerivedV> N;
|
||||
|
||||
private:
|
||||
// internal
|
||||
DerivedF TT;
|
||||
DerivedF TTi;
|
||||
PlainMatrix<DerivedF> TT;
|
||||
PlainMatrix<DerivedF> TTi;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "compute_frame_field_bisectors.h"
|
||||
#include "igl/local_basis.h"
|
||||
#include "PI.h"
|
||||
#include "PlainMatrix.h"
|
||||
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void igl::compute_frame_field_bisectors(
|
||||
@@ -71,7 +72,7 @@ IGL_INLINE void igl::compute_frame_field_bisectors(
|
||||
Eigen::PlainObjectBase<DerivedV>& BIS1,
|
||||
Eigen::PlainObjectBase<DerivedV>& BIS2)
|
||||
{
|
||||
DerivedV B1, B2, B3;
|
||||
PlainMatrix<DerivedV,Eigen::Dynamic> B1, B2, B3;
|
||||
igl::local_basis(V,F,B1,B2,B3);
|
||||
|
||||
compute_frame_field_bisectors( V, F, B1, B2, PD1, PD2, BIS1, BIS2);
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace igl
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
|
||||
const Eigen::MatrixBase<DerivedW>& /*win_nums*/) const {
|
||||
throw (std::runtime_error("not implemented!"));
|
||||
}
|
||||
};
|
||||
@@ -43,7 +43,7 @@ namespace igl
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
const Eigen::MatrixBase<DerivedW>& win_nums) const
|
||||
{
|
||||
for(int i = 0;i<win_nums.size();i++)
|
||||
{
|
||||
@@ -59,7 +59,7 @@ namespace igl
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
const Eigen::MatrixBase<DerivedW>& win_nums) const
|
||||
{
|
||||
for(int i = 0;i<win_nums.size();i++)
|
||||
{
|
||||
@@ -75,7 +75,7 @@ namespace igl
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
const Eigen::MatrixBase<DerivedW>& win_nums) const
|
||||
{
|
||||
assert(win_nums.size()>1);
|
||||
// Union of objects 1 through n-1
|
||||
@@ -96,7 +96,7 @@ namespace igl
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
const Eigen::MatrixBase<DerivedW>& win_nums) const
|
||||
{
|
||||
// If inside an odd number of objects
|
||||
int count = 0;
|
||||
@@ -114,7 +114,7 @@ namespace igl
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
|
||||
const Eigen::MatrixBase<DerivedW>& /*win_nums*/) const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -139,7 +139,7 @@ namespace igl
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
short operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
|
||||
const Eigen::MatrixBase<DerivedW>& /*win_nums*/) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace igl
|
||||
/// converted to exact)
|
||||
/// @param[in] F #F by 3 list of mesh face indices into V
|
||||
template <typename DerivedV>
|
||||
CSGTree(const Eigen::PlainObjectBase<DerivedV> & V, const POBF & F)//:
|
||||
CSGTree(const Eigen::MatrixBase<DerivedV> & V, const POBF & F)//:
|
||||
// Possible Eigen bug:
|
||||
// https://forum.kde.org/viewtopic.php?f=74&t=128414
|
||||
//m_V(V.template cast<ExactScalar>()),m_F(F)
|
||||
|
||||
@@ -252,7 +252,6 @@ namespace igl
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
// References:
|
||||
// http://minregret.googlecode.com/svn/trunk/skyline/src/extern/CGAL-3.3.1/examples/Polyhedron/polyhedron_self_intersection.cpp
|
||||
@@ -332,9 +331,6 @@ inline igl::copyleft::cgal::SelfIntersectMesh<
|
||||
offending(),
|
||||
params(params)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
#ifdef IGL_SELFINTERSECTMESH_TIMING
|
||||
const auto & tictoc = []() -> double
|
||||
{
|
||||
@@ -344,7 +340,7 @@ inline igl::copyleft::cgal::SelfIntersectMesh<
|
||||
return diff;
|
||||
};
|
||||
const auto log_time = [&](const std::string& label) -> void{
|
||||
printf("%50s: %0.5lf\n",
|
||||
std::printf("%50s: %0.5lf\n",
|
||||
C_STR("SelfIntersectMesh." << label),tictoc());
|
||||
};
|
||||
tictoc();
|
||||
@@ -454,7 +450,6 @@ inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
DerivedJ,
|
||||
DerivedIM>::mark_offensive(const Index f)
|
||||
{
|
||||
using namespace std;
|
||||
lIF.push_back(f);
|
||||
if(offending.count(f) == 0)
|
||||
{
|
||||
@@ -595,7 +590,6 @@ inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
const Index va)
|
||||
{
|
||||
// This was not a good idea. It will not handle coplanar triangles well.
|
||||
using namespace std;
|
||||
Segment_3 sa(
|
||||
A.vertex((va+1)%3),
|
||||
A.vertex((va+2)%3));
|
||||
@@ -630,8 +624,8 @@ inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
cerr<<"Segment ∩ triangle neither point nor segment?"<<endl;
|
||||
assert(false);
|
||||
// Should never happen.
|
||||
assert(false && "Segment ∩ triangle neither point nor segment?");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,8 +657,6 @@ inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
const Index fb,
|
||||
const std::vector<std::pair<Index,Index> > shared)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
auto opposite_vertex = [](const Index a0, const Index a1) {
|
||||
// get opposite index of A
|
||||
int a2=-1;
|
||||
|
||||
@@ -152,43 +152,6 @@ IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
} while (d < float(interval.second));
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
CGAL::Simple_cartesian<mpq_class>::FT & d)
|
||||
{
|
||||
d = cgal;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
double & d)
|
||||
{
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const double next = std::nextafter(d, interval.second);
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < interval.second);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
float& d)
|
||||
{
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const float next = std::nextafter(d, float(interval.second));
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < float(interval.second));
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user