Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc17178bed | ||
|
|
f4585a8ca9 | ||
|
|
c5e6f66748 | ||
|
|
780a5fbea5 | ||
|
|
61588efa78 | ||
|
|
cef9c6594f | ||
|
|
9de4b6640f | ||
|
|
7ebb86734a | ||
|
|
5b7b50c026 | ||
|
|
aafb6870c7 | ||
|
|
4d026eeef1 | ||
|
|
ea57dfa2ad | ||
|
|
85120e557e | ||
|
|
ad54f2dfe2 | ||
|
|
0ac1d696f8 | ||
|
|
fbfb2d56ad | ||
|
|
858c843971 | ||
|
|
723eb8d74d | ||
|
|
c60a948e7d | ||
|
|
ce32c4aa03 | ||
|
|
e7b3e45577 | ||
|
|
7be097d585 | ||
|
|
c47bb0507b | ||
|
|
b35d97472d | ||
|
|
2ea8312e5e | ||
|
|
f9b716fdf8 | ||
|
|
c608c60a6d | ||
|
|
7250ea7d91 | ||
|
|
e6482a8a42 | ||
|
|
dbba9ca921 | ||
|
|
225edb47b6 | ||
|
|
d14ab658df | ||
|
|
c7b5d0b6e3 | ||
|
|
21b62c5777 | ||
|
|
f06fb13014 | ||
|
|
59b517a4a4 | ||
|
|
efee81b7db | ||
|
|
bd30aa03b9 | ||
|
|
49a0ab8640 | ||
|
|
6e1ed534ce | ||
|
|
2ea66c3350 | ||
|
|
a3ba1f24f8 | ||
|
|
2e05e0f178 | ||
|
|
fbd4ce2399 | ||
|
|
6cde8347be | ||
|
|
645718cf77 | ||
|
|
a956dfd37d | ||
|
|
682e4b9685 | ||
|
|
69b0eccb15 | ||
|
|
03e14c609f | ||
|
|
782b7fc95d | ||
|
|
55817544c2 | ||
|
|
0bb27beb88 | ||
|
|
dbec07d9f5 | ||
|
|
80711ea630 | ||
|
|
c744410fe1 | ||
|
|
e706cc5b8b | ||
|
|
7ed7b06696 | ||
|
|
be9b795a16 | ||
|
|
0264736ed3 | ||
|
|
a8a1216363 | ||
|
|
fb3bd3571e | ||
|
|
d2bc41e99b | ||
|
|
0a92f2cdb2 | ||
|
|
870eb14ec2 | ||
|
|
1e905cba3d | ||
|
|
0e4e79f464 | ||
|
|
a2a1479a88 | ||
|
|
51b3f7093a | ||
|
|
249f37af52 | ||
|
|
63b3669a87 | ||
|
|
9814e81b4b | ||
|
|
c21ad49c38 | ||
|
|
d69073c329 | ||
|
|
8b5b424e8c | ||
|
|
1b745f81ed | ||
|
|
fa7eb0befb | ||
|
|
10c90309a8 | ||
|
|
062e3823c3 | ||
|
|
7b4a19da9d | ||
|
|
8c95d1044e | ||
|
|
9a1ab67df9 | ||
|
|
9921615af2 | ||
|
|
8ea0b8c6dc | ||
|
|
d9864be29e | ||
|
|
28008528b4 | ||
|
|
1ad4556268 | ||
|
|
35ba62b1a0 | ||
|
|
ec24dccc29 | ||
|
|
1fda040670 | ||
|
|
9bc3ffd98f | ||
|
|
af8944c7b6 | ||
|
|
3856ea92ce | ||
|
|
91faf24015 | ||
|
|
28ab0d11de | ||
|
|
5358cc5a36 | ||
|
|
775f2354fa | ||
|
|
9c49b73ade | ||
|
|
d2a4b51e1e | ||
|
|
e608aad744 | ||
|
|
10d2f75572 | ||
|
|
a22ed58dc4 | ||
|
|
4cb640737e | ||
|
|
86c7c7db2e | ||
|
|
21acee15fe | ||
|
|
eef47fe34c | ||
|
|
92dd81bb5d | ||
|
|
b42cfeba49 | ||
|
|
317f0522a8 | ||
|
|
b582ecada9 | ||
|
|
bae087d7eb | ||
|
|
f7067c69e9 | ||
|
|
7db28d5700 | ||
|
|
43da16bbd0 | ||
|
|
1de2627280 | ||
|
|
c183f419e7 | ||
|
|
20924d62f1 | ||
|
|
48051bc889 | ||
|
|
cb59839742 | ||
|
|
4a22178717 | ||
|
|
97bd52fb52 | ||
|
|
c61e28fe5a | ||
|
|
07e2b01a3c | ||
|
|
41454f823d | ||
|
|
1a4ccf65b7 | ||
|
|
98a1a31641 | ||
|
|
dde868d297 | ||
|
|
3b80edbd7c | ||
|
|
7be8dc32af | ||
|
|
abd9f0f365 | ||
|
|
b8ee8b99cf | ||
|
|
45cfc79fed | ||
|
|
015ac35cd1 | ||
|
|
d95f3a410f | ||
|
|
3a110bbf4d | ||
|
|
ac56a694f2 | ||
|
|
a3c3ef1572 | ||
|
|
b03769f26e | ||
|
|
1b53e54815 | ||
|
|
d22414e388 | ||
|
|
005ae90b67 | ||
|
|
39c7d33b4c | ||
|
|
61834f4fa1 | ||
|
|
d3248f0a0f | ||
|
|
7ee863c92f | ||
|
|
58a600aebf | ||
|
|
95a7b15efc | ||
|
|
ae5d163f7d | ||
|
|
8268a3f33b | ||
|
|
e4ab356031 | ||
|
|
762a4ec1f4 | ||
|
|
238d52c90f | ||
|
|
1e78a3473a | ||
|
|
3b0ec3ce63 | ||
|
|
d22f873ef2 | ||
|
|
ce201a7433 | ||
|
|
48a7e8cd02 | ||
|
|
feb71ef502 | ||
|
|
dc01d7e277 | ||
|
|
75a0c4fa2c | ||
|
|
60ffe1b0dc | ||
|
|
0b52794637 | ||
|
|
71e65516ae | ||
|
|
3f67752504 | ||
|
|
95a80d3fa9 | ||
|
|
5f72004d0d | ||
|
|
b0a8fa84e1 | ||
|
|
162f9b8f68 | ||
|
|
32e3edf229 | ||
|
|
f3a201f1e1 | ||
|
|
916a5c217d | ||
|
|
3141dfc26d | ||
|
|
14d6bcec3d | ||
|
|
6eb02be7db | ||
|
|
3da9d323fb | ||
|
|
c7324d3fa6 | ||
|
|
ae903ae468 | ||
|
|
3069260f07 | ||
|
|
1df0987271 | ||
|
|
ce9b23e8b9 | ||
|
|
e2548f971c | ||
|
|
6983cfd1f4 | ||
|
|
2f570a0e97 | ||
|
|
edb21bef2c | ||
|
|
48e3c72dfe | ||
|
|
d7dd3c2356 | ||
|
|
61878ade62 | ||
|
|
3404ee671b | ||
|
|
21d95881ed |
@@ -25,13 +25,13 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-18.04, macos-latest]
|
||||
os: [ubuntu-20.04, macos-latest]
|
||||
config: [Release]
|
||||
static: [ON, OFF]
|
||||
include:
|
||||
- os: macos-latest
|
||||
name: macOS
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
name: Linux
|
||||
env:
|
||||
LIBIGL_NUM_THREADS: 1 # See https://github.com/libigl/libigl/pull/996
|
||||
@@ -44,16 +44,17 @@ jobs:
|
||||
- name: Dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install \
|
||||
libblas-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
libglu1-mesa-dev \
|
||||
liblapack-dev \
|
||||
libmpfr-dev \
|
||||
xorg-dev \
|
||||
ccache
|
||||
libblas-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
libglu1-mesa-dev \
|
||||
liblapack-dev \
|
||||
libmpfr-dev \
|
||||
xorg-dev \
|
||||
ccache
|
||||
|
||||
- name: Dependencies (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
@@ -109,11 +110,10 @@ jobs:
|
||||
fetch-depth: 10
|
||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
||||
|
||||
# https://github.com/actions/cache/issues/101
|
||||
- name: Set env
|
||||
run: |
|
||||
echo "::set-env name=appdata::$($env:LOCALAPPDATA)"
|
||||
echo "::set-env name=BOOST_ROOT::$env:BOOST_ROOT_1_69_0"
|
||||
echo "BOOST_ROOT=$env:BOOST_ROOT_1_72_0" >> ${env:GITHUB_ENV}
|
||||
echo "appdata=$env:LOCALAPPDATA" >> ${env:GITHUB_ENV}
|
||||
|
||||
- name: Cache build
|
||||
id: cache-build
|
||||
@@ -126,8 +126,8 @@ jobs:
|
||||
run: |
|
||||
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
|
||||
scoop install sccache --global
|
||||
# Scoop modifies the PATH so we make the modified PATH global.
|
||||
echo "::set-env name=PATH::$env:PATH"
|
||||
# Scoop modifies the PATH so we make it available for the next steps of the job
|
||||
echo "${env:PATH}" >> ${env:GITHUB_PATH}
|
||||
|
||||
# We run configure + build in the same step, since they both need to call VsDevCmd
|
||||
# Also, cmd uses ^ to break commands into multiple lines (in powershell this is `)
|
||||
@@ -141,6 +141,9 @@ jobs:
|
||||
-DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.static }} ^
|
||||
-DLIBIGL_WITH_CGAL=ON ^
|
||||
-DLIBIGL_WITH_COMISO=OFF ^
|
||||
-DCMAKE_JOB_POOLS=pool-linking=1;pool-compilation=2 ^
|
||||
-DCMAKE_JOB_POOL_COMPILE:STRING=pool-compilation ^
|
||||
-DCMAKE_JOB_POOL_LINK:STRING=pool-linking ^
|
||||
-B build ^
|
||||
-S .
|
||||
cmake --build build
|
||||
|
||||
@@ -23,47 +23,47 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
name: [
|
||||
ubuntu-18.04-gcc-7,
|
||||
ubuntu-18.04-gcc-8,
|
||||
ubuntu-18.04-gcc-9,
|
||||
ubuntu-18.04-clang-7,
|
||||
ubuntu-18.04-clang-8,
|
||||
ubuntu-18.04-clang-9,
|
||||
ubuntu-20.04-gcc-8,
|
||||
ubuntu-20.04-gcc-9,
|
||||
ubuntu-20.04-gcc-10,
|
||||
ubuntu-20.04-clang-8,
|
||||
ubuntu-20.04-clang-9,
|
||||
ubuntu-20.04-clang-10,
|
||||
macOS-latest,
|
||||
]
|
||||
config: [Debug, Release]
|
||||
static: [ON, OFF]
|
||||
include:
|
||||
- name: ubuntu-18.04-gcc-7
|
||||
os: ubuntu-18.04
|
||||
compiler: gcc
|
||||
version: "7"
|
||||
|
||||
- name: ubuntu-18.04-gcc-8
|
||||
os: ubuntu-18.04
|
||||
- name: ubuntu-20.04-gcc-8
|
||||
os: ubuntu-20.04
|
||||
compiler: gcc
|
||||
version: "8"
|
||||
|
||||
- name: ubuntu-18.04-gcc-9
|
||||
os: ubuntu-18.04
|
||||
- name: ubuntu-20.04-gcc-9
|
||||
os: ubuntu-20.04
|
||||
compiler: gcc
|
||||
version: "9"
|
||||
|
||||
- name: ubuntu-18.04-clang-7
|
||||
os: ubuntu-18.04
|
||||
compiler: clang
|
||||
version: "7"
|
||||
- name: ubuntu-20.04-gcc-10
|
||||
os: ubuntu-20.04
|
||||
compiler: gcc
|
||||
version: "10"
|
||||
|
||||
- name: ubuntu-18.04-clang-8
|
||||
os: ubuntu-18.04
|
||||
- name: ubuntu-20.04-clang-8
|
||||
os: ubuntu-20.04
|
||||
compiler: clang
|
||||
version: "8"
|
||||
|
||||
- name: ubuntu-18.04-clang-9
|
||||
os: ubuntu-18.04
|
||||
- name: ubuntu-20.04-clang-9
|
||||
os: ubuntu-20.04
|
||||
compiler: clang
|
||||
version: "9"
|
||||
|
||||
- name: ubuntu-20.04-clang-10
|
||||
os: ubuntu-20.04
|
||||
compiler: clang
|
||||
version: "10"
|
||||
|
||||
- name: macOS-latest
|
||||
os: macOS-latest
|
||||
|
||||
@@ -84,20 +84,16 @@ jobs:
|
||||
- name: Dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
# LLVM 9 is not in Bionic's repositories so we add the official LLVM repository.
|
||||
if [ "${{ matrix.compiler }}" = "clang" ] && [ "${{ matrix.version }}" = "9" ]; then
|
||||
sudo add-apt-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main"
|
||||
fi
|
||||
sudo apt-get update
|
||||
|
||||
if [ "${{ matrix.compiler }}" = "gcc" ]; then
|
||||
sudo apt-get install -y g++-${{ matrix.version }}
|
||||
echo "::set-env name=CC::gcc-${{ matrix.version }}"
|
||||
echo "::set-env name=CXX::g++-${{ matrix.version }}"
|
||||
echo "CC=gcc-${{ matrix.version }}" >> $GITHUB_ENV
|
||||
echo "CXX=g++-${{ matrix.version }}" >> $GITHUB_ENV
|
||||
else
|
||||
sudo apt-get install -y clang-${{ matrix.version }}
|
||||
echo "::set-env name=CC::clang-${{ matrix.version }}"
|
||||
echo "::set-env name=CXX::clang++-${{ matrix.version }}"
|
||||
echo "CC=clang-${{ matrix.version }}" >> $GITHUB_ENV
|
||||
echo "CXX=clang++-${{ matrix.version }}" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
sudo apt-get install \
|
||||
@@ -168,7 +164,7 @@ jobs:
|
||||
|
||||
- name: Set env
|
||||
run: |
|
||||
echo "::set-env name=BOOST_ROOT::$env:BOOST_ROOT_1_69_0"
|
||||
echo "BOOST_ROOT=$env:BOOST_ROOT_1_72_0" >> ${env:GITHUB_ENV}
|
||||
|
||||
# We run configure + build in the same step, since they both need to call VsDevCmd
|
||||
# Also, cmd uses ^ to break commands into multiple lines (in powershell this is `)
|
||||
@@ -182,9 +178,12 @@ jobs:
|
||||
-DLIBIGL_BUILD_TUTORIALS=${{ matrix.tutorials }} ^
|
||||
-DLIBIGL_WITH_CGAL=ON ^
|
||||
-DLIBIGL_WITH_COMISO=OFF ^
|
||||
-DCMAKE_JOB_POOLS=pool-linking=1;pool-compilation=2 ^
|
||||
-DCMAKE_JOB_POOL_COMPILE:STRING=pool-compilation ^
|
||||
-DCMAKE_JOB_POOL_LINK:STRING=pool-linking ^
|
||||
-B build ^
|
||||
-S .
|
||||
cmake --build build -j 2
|
||||
cmake --build build -j 1
|
||||
|
||||
- name: Tests
|
||||
run: cd build; ctest --verbose
|
||||
|
||||
@@ -97,3 +97,4 @@ tutorial/cmake-build-debug
|
||||
tutorial/data
|
||||
tutorial/readme.html
|
||||
untitled
|
||||
scripts
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# libigl - A simple C++ geometry processing library
|
||||
[](https://github.com/libigl/libigl/actions)
|
||||
[](https://github.com/libigl/libigl/actions?query=workflow%3ABuild+branch%3Amaster+event%3Apush)
|
||||
[](https://github.com/libigl/libigl/actions?query=workflow%3ANightly+branch%3Amaster+event%3Aschedule)
|
||||
[](https://anaconda.org/conda-forge/igl)
|
||||
|
||||

|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Distributed under the OSI-approved MIT License. See accompanying
|
||||
# file LICENSE or https://github.com/Crascit/DownloadProject for details.
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(${DL_ARGS_PROJ}-download NONE)
|
||||
|
||||
|
||||
@@ -224,7 +224,14 @@ if(NOT MATLAB_ADDITIONAL_VERSIONS)
|
||||
set(MATLAB_ADDITIONAL_VERSIONS)
|
||||
endif()
|
||||
|
||||
# Is this mapping necessary? It's always causing trouble to need to bump these
|
||||
# for each new version.
|
||||
set(MATLAB_VERSIONS_MAPPING
|
||||
"R2020b=9.9"
|
||||
"R2020a=9.8"
|
||||
"R2019b=9.7"
|
||||
"R2019a=9.6"
|
||||
"R2018b=9.5"
|
||||
"R2018a=9.4"
|
||||
"R2017b=9.3"
|
||||
"R2017a=9.2"
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
|
||||
# Hardcoded search paths
|
||||
set(SEARCH_PATHS
|
||||
${CMAKE_SOURCE_DIR}/mosek/9.2/tools/platform/osx64x86/
|
||||
/usr/local/mosek/7/tools/platform/osx64x86/
|
||||
/usr/local/mosek/8/tools/platform/osx64x86/
|
||||
/usr/local/mosek/9.2/tools/platform/osx64x86/
|
||||
/opt/mosek/7/tools/platform/linux64x86/
|
||||
)
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ endfunction()
|
||||
function(igl_download_cgal)
|
||||
igl_download_project(cgal
|
||||
GIT_REPOSITORY https://github.com/CGAL/cgal.git
|
||||
GIT_TAG f7c3c8212b56c0d6dae63787efc99093f4383415
|
||||
GIT_TAG v5.2
|
||||
)
|
||||
endfunction()
|
||||
|
||||
@@ -51,7 +51,7 @@ endfunction()
|
||||
function(igl_download_comiso)
|
||||
igl_download_project(CoMISo
|
||||
GIT_REPOSITORY https://github.com/libigl/CoMISo.git
|
||||
GIT_TAG 1f9618cf9b7bd77370d817976470d59091928606
|
||||
GIT_TAG d60aa4759fba76b0b793b1efb090b7a771dd7c56
|
||||
)
|
||||
endfunction()
|
||||
|
||||
@@ -67,7 +67,7 @@ endfunction()
|
||||
set(LIBIGL_EIGEN_VERSION 3.3.7 CACHE STRING "Default version of Eigen used by libigl.")
|
||||
function(igl_download_eigen)
|
||||
igl_download_project(eigen
|
||||
GIT_REPOSITORY https://github.com/eigenteam/eigen-git-mirror.git
|
||||
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
|
||||
GIT_TAG ${LIBIGL_EIGEN_VERSION}
|
||||
${LIBIGL_BRANCH_OPTIONS}
|
||||
)
|
||||
@@ -77,7 +77,7 @@ endfunction()
|
||||
function(igl_download_embree)
|
||||
igl_download_project(embree
|
||||
GIT_REPOSITORY https://github.com/embree/embree.git
|
||||
GIT_TAG v3.5.2
|
||||
GIT_TAG v3.12.1
|
||||
${LIBIGL_BRANCH_OPTIONS}
|
||||
)
|
||||
endfunction()
|
||||
@@ -94,7 +94,7 @@ endfunction()
|
||||
function(igl_download_glfw)
|
||||
igl_download_project(glfw
|
||||
GIT_REPOSITORY https://github.com/glfw/glfw.git
|
||||
GIT_TAG 3.3
|
||||
GIT_TAG 3327050ca66ad34426a82c217c2d60ced61526b7
|
||||
${LIBIGL_BRANCH_OPTIONS}
|
||||
)
|
||||
endfunction()
|
||||
@@ -103,12 +103,21 @@ endfunction()
|
||||
function(igl_download_imgui)
|
||||
igl_download_project(imgui
|
||||
GIT_REPOSITORY https://github.com/ocornut/imgui.git
|
||||
GIT_TAG v1.69
|
||||
GIT_TAG v1.76
|
||||
${LIBIGL_BRANCH_OPTIONS}
|
||||
)
|
||||
igl_download_project(libigl-imgui
|
||||
GIT_REPOSITORY https://github.com/libigl/libigl-imgui.git
|
||||
GIT_TAG 07ecd3858acc71e70f0f9b2dea20a139bdddf8ae
|
||||
GIT_TAG 99f0643089b19f6daf5b3efd9544a65c9a851966
|
||||
)
|
||||
endfunction()
|
||||
|
||||
## ImGuizmo
|
||||
function(igl_download_imguizmo)
|
||||
igl_download_project(imguizmo
|
||||
GIT_REPOSITORY https://github.com/CedricGuillemet/ImGuizmo.git
|
||||
GIT_TAG a23567269f6617342bcc112394bdad937b54b2d7
|
||||
${LIBIGL_BRANCH_OPTIONS}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
@@ -148,7 +157,7 @@ endfunction()
|
||||
function(igl_download_triangle)
|
||||
igl_download_project(triangle
|
||||
GIT_REPOSITORY https://github.com/libigl/triangle.git
|
||||
GIT_TAG d284c4a843efac043c310f5fa640b17cf7d96170
|
||||
GIT_TAG 5a70326574b34d6a51d9eaf6a9f78813657ee108
|
||||
)
|
||||
endfunction()
|
||||
|
||||
@@ -164,7 +173,7 @@ endfunction()
|
||||
function(igl_download_predicates)
|
||||
igl_download_project(predicates
|
||||
GIT_REPOSITORY https://github.com/libigl/libigl-predicates.git
|
||||
GIT_TAG 5a1d2194ec114bff51d5a33230586cafb83adc86
|
||||
GIT_TAG 488242fa2b1f98a9c5bd1441297fb4a99a6a9ae4
|
||||
)
|
||||
endfunction()
|
||||
|
||||
@@ -175,7 +184,7 @@ function(igl_download_test_data)
|
||||
igl_download_project_aux(test_data
|
||||
"${LIBIGL_EXTERNAL}/../tests/data"
|
||||
GIT_REPOSITORY https://github.com/libigl/libigl-tests-data
|
||||
GIT_TAG b5dddf45e329af685cd107e38770a28cfc18eb15
|
||||
GIT_TAG 19cedf96d70702d8b3a83eb27934780c542356fe
|
||||
)
|
||||
endfunction()
|
||||
|
||||
@@ -184,7 +193,6 @@ function(igl_download_tutorial_data)
|
||||
igl_download_project_aux(tutorial_data
|
||||
"${LIBIGL_EXTERNAL}/../tutorial/data"
|
||||
GIT_REPOSITORY https://github.com/libigl/libigl-tutorial-data
|
||||
GIT_TAG 5c6a1ea809c043d71e5595775709c15325a7158c
|
||||
GIT_TAG c1f9ede366d02e3531ecbaec5e3769312f31cccd
|
||||
)
|
||||
endfunction()
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ igl_folder_targets("Tutorials"
|
||||
405_AsRigidAsPossible_bin
|
||||
406_FastAutomaticSkinningTransformations_bin
|
||||
407_BiharmonicCoordinates_bin
|
||||
408_DirectDeltaMush_bin
|
||||
501_HarmonicParam_bin
|
||||
502_LSCMParam_bin
|
||||
503_ARAPParam_bin
|
||||
@@ -111,6 +112,7 @@ igl_folder_targets("Tutorials"
|
||||
715_MeshImplicitFunction_bin
|
||||
716_HeatGeodesics_bin
|
||||
718_IterativeClosestPoint_bin
|
||||
719_ExplodedView_bin
|
||||
)
|
||||
|
||||
endfunction()
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# OS X requires a Mach-O dynamic library to have a baked "install name", that is used by other modules to link to it. Depending
|
||||
# on how the library is built, the install name is not always an absolute path, nor necessarily the same as the name of the
|
||||
# library file itself. This macro takes as input the name of a target, and a list of libraries that it links to (the output of
|
||||
# FIND_PACKAGE or FIND_LIBRARY calls), and generates a set of custom, post-build commands that, for each linked dylib, changes
|
||||
# the name the target uses to refer to it with a fully-qualified (absolute) version of the library's own install name. This
|
||||
# helps ensure that the target can be used from any location while still being able to locate the linked dynamic libraries.
|
||||
#
|
||||
# Note that this script does NOT handle the case when a linked library itself refers to another library using a non-absolute
|
||||
# name (Boost is a notorious example). To avoid such issues, it is recommended to use a static library instead of a shared one
|
||||
# in a non-standard location. Alternatively, set DYLD_LIBRARY_PATH to include these non-standard locations when running the
|
||||
# program (not recommended).
|
||||
#
|
||||
# Author: Siddhartha Chaudhuri, 2009.
|
||||
#
|
||||
|
||||
# Set the minimum required CMake version
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
|
||||
# See cmake --help-policy CMP0011 for details on this one
|
||||
IF(POLICY CMP0011)
|
||||
CMAKE_POLICY(SET CMP0011 NEW)
|
||||
ENDIF(POLICY CMP0011)
|
||||
|
||||
# See cmake --help-policy CMP0026 for details on this one
|
||||
IF(POLICY CMP0026)
|
||||
CMAKE_POLICY(SET CMP0026 NEW)
|
||||
ENDIF(POLICY CMP0026)
|
||||
|
||||
# See cmake --help-policy CMP0045 for details on this one
|
||||
IF(POLICY CMP0045)
|
||||
CMAKE_POLICY(SET CMP0045 NEW)
|
||||
ENDIF(POLICY CMP0045)
|
||||
|
||||
MACRO(OSX_FIX_DYLIB_REFERENCES target libraries)
|
||||
|
||||
IF(APPLE)
|
||||
SET(OFIN_${target}_RPATHS )
|
||||
|
||||
FOREACH(OFIN_${target}_Library ${libraries})
|
||||
IF(${OFIN_${target}_Library} MATCHES "[.]dylib$"
|
||||
OR ${OFIN_${target}_Library} MATCHES "[.]framework/.+")
|
||||
|
||||
# Resolve symlinks and get absolute location
|
||||
GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolute ${OFIN_${target}_Library} ABSOLUTE)
|
||||
|
||||
# Get the baked install name of the library
|
||||
EXECUTE_PROCESS(COMMAND otool -D ${OFIN_${target}_LibraryAbsolute}
|
||||
OUTPUT_VARIABLE OFIN_${target}_LibraryInstallNameOutput
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
STRING(REGEX REPLACE "[\r\n]" " " OFIN_${target}_LibraryInstallNameOutput ${OFIN_${target}_LibraryInstallNameOutput})
|
||||
SEPARATE_ARGUMENTS(OFIN_${target}_LibraryInstallNameOutput)
|
||||
LIST(GET OFIN_${target}_LibraryInstallNameOutput 1 OFIN_${target}_LibraryInstallName)
|
||||
|
||||
IF(${OFIN_${target}_LibraryInstallName} MATCHES "^[@]rpath/")
|
||||
|
||||
# Ideally, we want to eliminate the longest common suffix of the install name and the absolute path. Whatever's left
|
||||
# will be the desired rpath. But this is difficult to do (especially if there are naming variations, e.g.
|
||||
# "Versions/Current" vs "Versions/5" is a common culprit). So we'll add various candidate rpaths and hope at least one
|
||||
# is correct.
|
||||
|
||||
# Typically, the rpath to a library within a framework looks like this:
|
||||
# @rpath/A.framework/Versions/5/libFoo.dylib
|
||||
#
|
||||
# Hence, we'll extract for the path unit immediately following the @rpath (in this case A.framework) and then look for
|
||||
# it in the library's actual path. Everything before this location will be put in the rpath.
|
||||
SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryInstallName})
|
||||
SET(OFIN_${target}_RpathFirstChild )
|
||||
WHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath")
|
||||
GET_FILENAME_COMPONENT(OFIN_${target}_RpathFirstChild ${OFIN_${target}_PathPrefix} NAME)
|
||||
GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix ${OFIN_${target}_PathPrefix} PATH)
|
||||
|
||||
IF(NOT OFIN_${target}_PathPrefix) # should never happen but just in case
|
||||
BREAK()
|
||||
ENDIF(NOT OFIN_${target}_PathPrefix)
|
||||
|
||||
IF(OFIN_${target}_PathPrefix STREQUAL "/") # should never happen but just in case
|
||||
BREAK()
|
||||
ENDIF(OFIN_${target}_PathPrefix STREQUAL "/")
|
||||
ENDWHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath")
|
||||
|
||||
IF(OFIN_${target}_RpathFirstChild)
|
||||
SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryAbsolute})
|
||||
SET(OFIN_${target}_PathUnit )
|
||||
WHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild})
|
||||
GET_FILENAME_COMPONENT(OFIN_${target}_PathUnit ${OFIN_${target}_PathPrefix} NAME)
|
||||
GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix ${OFIN_${target}_PathPrefix} PATH)
|
||||
|
||||
IF(NOT OFIN_${target}_PathPrefix)
|
||||
BREAK()
|
||||
ENDIF(NOT OFIN_${target}_PathPrefix)
|
||||
|
||||
IF(OFIN_${target}_PathPrefix STREQUAL "/")
|
||||
BREAK()
|
||||
ENDIF(OFIN_${target}_PathPrefix STREQUAL "/")
|
||||
ENDWHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild})
|
||||
|
||||
IF(OFIN_${target}_PathPrefix)
|
||||
SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_PathPrefix}")
|
||||
ENDIF(OFIN_${target}_PathPrefix)
|
||||
ENDIF(OFIN_${target}_RpathFirstChild)
|
||||
|
||||
# Add the directory containing the library
|
||||
GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolutePath ${OFIN_${target}_LibraryAbsolute} PATH)
|
||||
SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_LibraryAbsolutePath}")
|
||||
|
||||
# Add paths specified as library search prefixes
|
||||
FOREACH(prefix ${CMAKE_PREFIX_PATH})
|
||||
SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}")
|
||||
SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}/lib")
|
||||
ENDFOREACH()
|
||||
|
||||
ELSEIF(NOT ${OFIN_${target}_LibraryInstallName} MATCHES "^[@/]") # just a relative path
|
||||
|
||||
# Replace the unqualified filename, if it appears, with the absolute location, either by directly changing the path or
|
||||
# by editing the rpath
|
||||
|
||||
# -- handle the case when the actual filename is baked in
|
||||
GET_FILENAME_COMPONENT(OFIN_${target}_LibraryFilename ${OFIN_${target}_LibraryAbsolute} NAME)
|
||||
ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
|
||||
COMMAND install_name_tool
|
||||
ARGS -change
|
||||
${OFIN_${target}_LibraryFilename}
|
||||
${OFIN_${target}_LibraryAbsolute}
|
||||
$<TARGET_FILE:${target}>)
|
||||
|
||||
# -- handle the case when the install name is baked in
|
||||
ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
|
||||
COMMAND install_name_tool
|
||||
ARGS -change
|
||||
${OFIN_${target}_LibraryInstallName}
|
||||
${OFIN_${target}_LibraryAbsolute}
|
||||
$<TARGET_FILE:${target}>)
|
||||
ENDIF()
|
||||
|
||||
ENDIF()
|
||||
ENDFOREACH(OFIN_${target}_Library)
|
||||
|
||||
# Add the collected rpaths
|
||||
IF(OFIN_${target}_RPATHS)
|
||||
LIST(REMOVE_DUPLICATES OFIN_${target}_RPATHS)
|
||||
|
||||
FOREACH(rpath ${OFIN_${target}_RPATHS})
|
||||
ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
|
||||
COMMAND bash
|
||||
ARGS -c "install_name_tool -add_rpath '${rpath}' '$<TARGET_FILE:${target}>' > /dev/null 2>&1 || true"
|
||||
VERBATIM)
|
||||
ENDFOREACH()
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
ENDMACRO(OSX_FIX_DYLIB_REFERENCES)
|
||||
+9
-2
@@ -301,11 +301,12 @@ if(LIBIGL_WITH_EMBREE)
|
||||
if(NOT TARGET embree)
|
||||
igl_download_embree()
|
||||
|
||||
# Note: On macOS, building embree as a static lib can only be done with a single ISA target.
|
||||
set(EMBREE_MAX_ISA "DEFAULT" CACHE STRING "Selects highest ISA to support.")
|
||||
set(EMBREE_TESTING_INTENSITY 0 CACHE STRING "")
|
||||
set(EMBREE_ISPC_SUPPORT OFF CACHE BOOL " ")
|
||||
set(EMBREE_TASKING_SYSTEM "INTERNAL" CACHE BOOL " ")
|
||||
set(EMBREE_TUTORIALS OFF CACHE BOOL " ")
|
||||
set(EMBREE_MAX_ISA "SSE2" CACHE STRING " ")
|
||||
set(EMBREE_STATIC_LIB ON CACHE BOOL " ")
|
||||
if(MSVC)
|
||||
set(EMBREE_STATIC_RUNTIME ${IGL_STATIC_RUNTIME} CACHE BOOL "Use the static version of the C/C++ runtime library.")
|
||||
@@ -398,7 +399,13 @@ if(LIBIGL_WITH_OPENGL_GLFW_IMGUI)
|
||||
igl_download_imgui()
|
||||
add_subdirectory(${LIBIGL_EXTERNAL}/libigl-imgui imgui)
|
||||
endif()
|
||||
target_link_libraries(igl_opengl_glfw_imgui ${IGL_SCOPE} igl_opengl_glfw imgui)
|
||||
if(NOT TARGET imguizmo)
|
||||
igl_download_imguizmo()
|
||||
add_library(imguizmo ${LIBIGL_EXTERNAL}/imguizmo/ImGuizmo.cpp ${LIBIGL_EXTERNAL}/imguizmo/ImGuizmo.h)
|
||||
target_compile_features(imguizmo PUBLIC cxx_std_11)
|
||||
target_link_libraries(imguizmo PUBLIC imgui)
|
||||
endif()
|
||||
target_link_libraries(igl_opengl_glfw_imgui ${IGL_SCOPE} igl_opengl_glfw imgui imguizmo)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
+35
-55
@@ -1025,64 +1025,44 @@ namespace igl
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template double igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -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::Matrix<double, 1, 3, 1, 1, 3> const&, double, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 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&);
|
||||
// generated by autoexplicit.sh
|
||||
// generated by autoexplicit.sh
|
||||
template float igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, float, float, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::serialize<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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, int) const;
|
||||
// generated by autoexplicit.sh
|
||||
template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::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::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, bool) const;
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::serialize<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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, int) const;
|
||||
// generated by autoexplicit.sh
|
||||
template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::find<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::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, bool) const;
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);
|
||||
// generated by autoexplicit.sh
|
||||
template float igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 2, 1, 1, 2> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) const;
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
|
||||
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
|
||||
template bool igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::intersect_ray<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, igl::Hit&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<int, 2, 1, 0, 2, 1>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&);
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&);
|
||||
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 2, 1, 1, 2> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) const;
|
||||
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
|
||||
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
|
||||
template double igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -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::Matrix<double, 1, 3, 1, 1, 3> const&, double, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
|
||||
template float igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, float, float, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
|
||||
template float igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
|
||||
template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::find<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::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, bool) const;
|
||||
template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, bool) const;
|
||||
template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::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::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, bool) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&);
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::serialize<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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, int) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&);
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::serialize<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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, int) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<int, 2, 1, 0, 2, 1>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
|
||||
template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -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&);
|
||||
template void igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
|
||||
template void igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
|
||||
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
|
||||
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<double, 1, 2, 1, 1, 2> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) const;
|
||||
#ifdef WIN32
|
||||
template void igl::AABB<class Eigen::Matrix<double,-1,-1,0,-1,-1>,2>::squared_distance<class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<double,-1,3,0,-1,3> >(class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > &)const;
|
||||
template void igl::AABB<class Eigen::Matrix<double,-1,-1,0,-1,-1>,3>::squared_distance<class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<double,-1,3,0,-1,3> >(class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > &)const;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
|
||||
//
|
||||
// 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_FILEENCODING_H
|
||||
#define IGL_FILEENCODING_H
|
||||
|
||||
namespace igl
|
||||
{
|
||||
|
||||
enum class FileEncoding {
|
||||
Binary,
|
||||
Ascii
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+7
-3
@@ -17,9 +17,13 @@ namespace igl
|
||||
struct Hit
|
||||
{
|
||||
int id; // primitive id
|
||||
int gid; // geometry id
|
||||
float u,v; // barycentric coordinates
|
||||
float t; // distance = direction*t to intersection
|
||||
int gid; // geometry id (not used)
|
||||
// barycentric coordinates so that
|
||||
// pos = V.row(F(id,0))*(1-u-v)+V.row(F(id,1))*u+V.row(F(id,2))*v;
|
||||
float u,v;
|
||||
// parametric distance so that
|
||||
// pos = origin + t * dir
|
||||
float t;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,497 @@
|
||||
// based on MSH reader from PyMesh
|
||||
|
||||
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
|
||||
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@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 "MshLoader.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace igl {
|
||||
// helper function
|
||||
void inline _msh_eat_white_space(std::ifstream& fin) {
|
||||
char next = fin.peek();
|
||||
while (next == '\n' || next == ' ' || next == '\t' || next == '\r') {
|
||||
fin.get();
|
||||
next = fin.peek();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE igl::MshLoader::MshLoader(const std::string &filename) {
|
||||
std::ifstream fin(filename, std::ios::in | std::ios::binary);
|
||||
|
||||
if (!fin.is_open()) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "failed to open file \"" << filename << "\"";
|
||||
throw std::ios_base::failure(err_msg.str());
|
||||
}
|
||||
// Parse header
|
||||
std::string buf;
|
||||
double version;
|
||||
int type;
|
||||
fin >> buf;
|
||||
if (buf != "$MeshFormat") { throw std::runtime_error("Unexpected .msh format"); }
|
||||
|
||||
fin >> version >> type >> m_data_size;
|
||||
m_binary = (type == 1);
|
||||
if(version>2.2 || version<2.0)
|
||||
{
|
||||
// probably unsupported version
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Error: Unsupported file version:" << version << std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
|
||||
}
|
||||
// Some sanity check.
|
||||
if (m_data_size != 8) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Error: data size must be 8 bytes." << std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
if (sizeof(int) != 4) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Error: code must be compiled with int size 4 bytes." << std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
|
||||
// Read in extra info from binary header.
|
||||
if (m_binary) {
|
||||
int one;
|
||||
igl::_msh_eat_white_space(fin);
|
||||
fin.read(reinterpret_cast<char*>(&one), sizeof(int));
|
||||
if (one != 1) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Binary msh file " << filename
|
||||
<< " is saved with different endianness than this machine."
|
||||
<< std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
fin >> buf;
|
||||
if (buf != "$EndMeshFormat")
|
||||
{
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Unexpected contents in the file header." << std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
|
||||
while (!fin.eof()) {
|
||||
buf.clear();
|
||||
fin >> buf;
|
||||
if (buf == "$Nodes") {
|
||||
parse_nodes(fin);
|
||||
fin >> buf;
|
||||
if (buf != "$EndNodes") { throw std::runtime_error("Unexpected tag"); }
|
||||
} else if (buf == "$Elements") {
|
||||
parse_elements(fin);
|
||||
fin >> buf;
|
||||
if (buf != "$EndElements") { throw std::runtime_error("Unexpected tag"); }
|
||||
} else if (buf == "$NodeData") {
|
||||
parse_node_field(fin);
|
||||
fin >> buf;
|
||||
if (buf != "$EndNodeData") { throw std::runtime_error("Unexpected tag"); }
|
||||
} else if (buf == "$ElementData") {
|
||||
parse_element_field(fin);
|
||||
fin >> buf;
|
||||
if (buf != "$EndElementData") { throw std::runtime_error("Unexpected tag"); }
|
||||
} else if (fin.eof()) {
|
||||
break;
|
||||
} else {
|
||||
parse_unknown_field(fin, buf);
|
||||
}
|
||||
}
|
||||
fin.close();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshLoader::parse_nodes(std::ifstream& fin) {
|
||||
size_t num_nodes;
|
||||
fin >> num_nodes;
|
||||
m_nodes.resize(num_nodes*3);
|
||||
|
||||
if (m_binary) {
|
||||
size_t stride = (4+3*m_data_size);
|
||||
size_t num_bytes = stride * num_nodes;
|
||||
char* data = new char[num_bytes];
|
||||
igl::_msh_eat_white_space(fin);
|
||||
fin.read(data, num_bytes);
|
||||
|
||||
for (size_t i=0; i<num_nodes; i++) {
|
||||
int node_idx;
|
||||
memcpy(&node_idx, data+i*stride, sizeof(int));
|
||||
node_idx-=1;
|
||||
// directly move into vector storage
|
||||
// this works only when m_data_size==sizeof(Float)==sizeof(double)
|
||||
memcpy(&m_nodes[node_idx*3], data+i*stride + 4, m_data_size*3);
|
||||
}
|
||||
delete [] data;
|
||||
} else {
|
||||
int node_idx;
|
||||
for (size_t i=0; i<num_nodes; i++) {
|
||||
fin >> node_idx;
|
||||
node_idx -= 1;
|
||||
// here it's 3D node explicitly
|
||||
fin >> m_nodes[node_idx*3]
|
||||
>> m_nodes[node_idx*3+1]
|
||||
>> m_nodes[node_idx*3+2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshLoader::parse_elements(std::ifstream& fin) {
|
||||
m_elements_tags.resize(2); //hardcoded to have 2 tags
|
||||
size_t num_elements;
|
||||
fin >> num_elements;
|
||||
|
||||
size_t nodes_per_element;
|
||||
|
||||
if (m_binary) {
|
||||
igl::_msh_eat_white_space(fin);
|
||||
int elem_read = 0;
|
||||
while (elem_read < num_elements) {
|
||||
// Parse element header.
|
||||
int elem_type, num_elems, num_tags;
|
||||
fin.read((char*)&elem_type, sizeof(int));
|
||||
fin.read((char*)&num_elems, sizeof(int));
|
||||
fin.read((char*)&num_tags, sizeof(int));
|
||||
nodes_per_element = num_nodes_per_elem_type(elem_type);
|
||||
|
||||
// store node info
|
||||
for (size_t i=0; i<num_elems; i++) {
|
||||
int elem_idx;
|
||||
|
||||
// all elements in the segment share the same elem_type and number of nodes per element
|
||||
m_elements_types.push_back(elem_type);
|
||||
m_elements_lengths.push_back(nodes_per_element);
|
||||
|
||||
fin.read((char*)&elem_idx, sizeof(int));
|
||||
elem_idx -= 1;
|
||||
m_elements_ids.push_back(elem_idx);
|
||||
|
||||
// read first two tags
|
||||
for (size_t j=0; j<num_tags; j++) {
|
||||
int tag;
|
||||
fin.read((char*)&tag, sizeof(int));
|
||||
if(j<2) m_elements_tags[j].push_back(tag);
|
||||
}
|
||||
|
||||
for (size_t j=num_tags; j<2; j++)
|
||||
m_elements_tags[j].push_back(-1); // fill up tags if less then 2
|
||||
|
||||
m_elements_nodes_idx.push_back(m_elements.size());
|
||||
// Element values.
|
||||
for (size_t j=0; j<nodes_per_element; j++) {
|
||||
int idx;
|
||||
fin.read((char*)&idx, sizeof(int));
|
||||
|
||||
m_elements.push_back(idx-1);
|
||||
}
|
||||
}
|
||||
elem_read += num_elems;
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<num_elements; i++) {
|
||||
// Parse per element header
|
||||
int elem_num, elem_type, num_tags;
|
||||
fin >> elem_num >> elem_type >> num_tags;
|
||||
|
||||
// read tags.
|
||||
for (size_t j=0; j<num_tags; j++) {
|
||||
int tag;
|
||||
fin >> tag;
|
||||
if(j<2) m_elements_tags[j].push_back(tag);
|
||||
}
|
||||
for (size_t j=num_tags; j<2; j++)
|
||||
m_elements_tags[j].push_back(-1); // fill up tags if less then 2
|
||||
|
||||
nodes_per_element = num_nodes_per_elem_type(elem_type);
|
||||
m_elements_types.push_back(elem_type);
|
||||
m_elements_lengths.push_back(nodes_per_element);
|
||||
|
||||
elem_num -= 1;
|
||||
m_elements_ids.push_back(elem_num);
|
||||
m_elements_nodes_idx.push_back(m_elements.size());
|
||||
// Parse node idx.
|
||||
for (size_t j=0; j<nodes_per_element; j++) {
|
||||
int idx;
|
||||
fin >> idx;
|
||||
m_elements.push_back(idx-1); // msh index starts from 1.
|
||||
}
|
||||
}
|
||||
}
|
||||
// debug
|
||||
assert(m_elements_types.size() == m_elements_ids.size());
|
||||
assert(m_elements_tags[0].size() == m_elements_ids.size());
|
||||
assert(m_elements_tags[1].size() == m_elements_ids.size());
|
||||
assert(m_elements_lengths.size() == m_elements_ids.size());
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshLoader::parse_node_field( std::ifstream& fin ) {
|
||||
size_t num_string_tags;
|
||||
size_t num_real_tags;
|
||||
size_t num_int_tags;
|
||||
|
||||
fin >> num_string_tags;
|
||||
std::vector<std::string> str_tags(num_string_tags);
|
||||
|
||||
for (size_t i=0; i<num_string_tags; i++) {
|
||||
igl::_msh_eat_white_space(fin);
|
||||
if (fin.peek() == '\"') {
|
||||
// Handle field name between quotes.
|
||||
char buf[128];
|
||||
fin.get(); // remove the quote at the beginning.
|
||||
fin.getline(buf, 128, '\"');
|
||||
str_tags[i] = std::string(buf);
|
||||
} else {
|
||||
fin >> str_tags[i];
|
||||
}
|
||||
}
|
||||
|
||||
fin >> num_real_tags;
|
||||
std::vector<Float> real_tags(num_real_tags);
|
||||
for (size_t i=0; i<num_real_tags; i++)
|
||||
fin >> real_tags[i];
|
||||
|
||||
fin >> num_int_tags;
|
||||
std::vector<int> int_tags(num_int_tags);
|
||||
for (size_t i=0; i<num_int_tags; i++)
|
||||
fin >> int_tags[i];
|
||||
|
||||
if (num_string_tags <= 0 || num_int_tags <= 2) {
|
||||
throw std::runtime_error("Unexpected number of field tags");
|
||||
}
|
||||
std::string fieldname = str_tags[0];
|
||||
int num_components = int_tags[1];
|
||||
int num_entries = int_tags[2];
|
||||
|
||||
std::vector<Float> field( num_entries*num_components );
|
||||
|
||||
if (m_binary) {
|
||||
size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
|
||||
char* data = new char[num_bytes];
|
||||
igl::_msh_eat_white_space(fin);
|
||||
fin.read(data, num_bytes);
|
||||
for (size_t i=0; i<num_entries; i++) {
|
||||
int node_idx;
|
||||
memcpy(&node_idx,&data[i*(4+num_components*m_data_size)],4);
|
||||
|
||||
if(node_idx<1) throw std::runtime_error("Negative or zero index");
|
||||
node_idx -= 1;
|
||||
|
||||
if(node_idx>=num_entries) throw std::runtime_error("Index too big");
|
||||
size_t base_idx = i*(4+num_components*m_data_size) + 4;
|
||||
// TODO: make this work when m_data_size != sizeof(double) ?
|
||||
memcpy(&field[node_idx*num_components], &data[base_idx], num_components*m_data_size);
|
||||
}
|
||||
delete [] data;
|
||||
} else {
|
||||
int node_idx;
|
||||
for (size_t i=0; i<num_entries; i++) {
|
||||
fin >> node_idx;
|
||||
node_idx -= 1;
|
||||
for (size_t j=0; j<num_components; j++) {
|
||||
fin >> field[node_idx*num_components+j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_node_fields_names.push_back(fieldname);
|
||||
m_node_fields.push_back(field);
|
||||
m_node_fields_components.push_back(num_components);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshLoader::parse_element_field(std::ifstream& fin) {
|
||||
size_t num_string_tags;
|
||||
size_t num_real_tags;
|
||||
size_t num_int_tags;
|
||||
|
||||
fin >> num_string_tags;
|
||||
std::vector<std::string> str_tags(num_string_tags);
|
||||
for (size_t i=0; i<num_string_tags; i++) {
|
||||
igl::_msh_eat_white_space(fin);
|
||||
if (fin.peek() == '\"') {
|
||||
// Handle field name between quoates.
|
||||
char buf[128];
|
||||
fin.get(); // remove the quote at the beginning.
|
||||
fin.getline(buf, 128, '\"');
|
||||
str_tags[i] = buf;
|
||||
} else {
|
||||
fin >> str_tags[i];
|
||||
}
|
||||
}
|
||||
|
||||
fin >> num_real_tags;
|
||||
std::vector<Float> real_tags(num_real_tags);
|
||||
for (size_t i=0; i<num_real_tags; i++)
|
||||
fin >> real_tags[i];
|
||||
|
||||
fin >> num_int_tags;
|
||||
std::vector<int> int_tags(num_int_tags);
|
||||
for (size_t i=0; i<num_int_tags; i++)
|
||||
fin >> int_tags[i];
|
||||
|
||||
if (num_string_tags <= 0 || num_int_tags <= 2) {
|
||||
throw std::runtime_error("Invalid file format");
|
||||
}
|
||||
std::string fieldname = str_tags[0];
|
||||
int num_components = int_tags[1];
|
||||
int num_entries = int_tags[2];
|
||||
std::vector<Float> field(num_entries*num_components);
|
||||
|
||||
if (m_binary) {
|
||||
size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
|
||||
char* data = new char[num_bytes];
|
||||
igl::_msh_eat_white_space(fin);
|
||||
fin.read(data, num_bytes);
|
||||
for (int i=0; i<num_entries; i++) {
|
||||
int elem_idx;
|
||||
// works with sizeof(int)==4
|
||||
memcpy(&elem_idx, &data[i*(4+num_components*m_data_size)],4);
|
||||
elem_idx -= 1;
|
||||
|
||||
// directly copy data into vector storage space
|
||||
memcpy(&field[elem_idx*num_components], &data[i*(4+num_components*m_data_size) + 4], m_data_size*num_components);
|
||||
}
|
||||
delete [] data;
|
||||
} else {
|
||||
int elem_idx;
|
||||
for (size_t i=0; i<num_entries; i++) {
|
||||
fin >> elem_idx;
|
||||
elem_idx -= 1;
|
||||
for (size_t j=0; j<num_components; j++) {
|
||||
fin >> field[elem_idx*num_components+j];
|
||||
}
|
||||
}
|
||||
}
|
||||
m_element_fields_names.push_back(fieldname);
|
||||
m_element_fields.push_back(field);
|
||||
m_element_fields_components.push_back(num_components);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshLoader::parse_unknown_field(std::ifstream& fin,
|
||||
const std::string& fieldname) {
|
||||
std::cerr << "Warning: \"" << fieldname << "\" not supported yet. Ignored." << std::endl;
|
||||
std::string endmark = fieldname.substr(0,1) + "End"
|
||||
+ fieldname.substr(1,fieldname.size()-1);
|
||||
|
||||
std::string buf("");
|
||||
while (buf != endmark && !fin.eof()) {
|
||||
fin >> buf;
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE int igl::MshLoader::num_nodes_per_elem_type(int elem_type) {
|
||||
int nodes_per_element = 0;
|
||||
switch (elem_type) {
|
||||
case ELEMENT_LINE: // 2-node line
|
||||
nodes_per_element = 2;
|
||||
break;
|
||||
case ELEMENT_TRI:
|
||||
nodes_per_element = 3; // 3-node triangle
|
||||
break;
|
||||
case ELEMENT_QUAD:
|
||||
nodes_per_element = 4; // 5-node quad
|
||||
break;
|
||||
case ELEMENT_TET:
|
||||
nodes_per_element = 4; // 4-node tetrahedra
|
||||
break;
|
||||
case ELEMENT_HEX: // 8-node hexahedron
|
||||
nodes_per_element = 8;
|
||||
break;
|
||||
case ELEMENT_PRISM: // 6-node prism
|
||||
nodes_per_element = 6;
|
||||
break;
|
||||
case ELEMENT_LINE_2ND_ORDER:
|
||||
nodes_per_element = 3;
|
||||
break;
|
||||
case ELEMENT_TRI_2ND_ORDER:
|
||||
nodes_per_element = 6;
|
||||
break;
|
||||
case ELEMENT_QUAD_2ND_ORDER:
|
||||
nodes_per_element = 9;
|
||||
break;
|
||||
case ELEMENT_TET_2ND_ORDER:
|
||||
nodes_per_element = 10;
|
||||
break;
|
||||
case ELEMENT_HEX_2ND_ORDER:
|
||||
nodes_per_element = 27;
|
||||
break;
|
||||
case ELEMENT_PRISM_2ND_ORDER:
|
||||
nodes_per_element = 18;
|
||||
break;
|
||||
case ELEMENT_PYRAMID_2ND_ORDER:
|
||||
nodes_per_element = 14;
|
||||
break;
|
||||
case ELEMENT_POINT: // 1-node point
|
||||
nodes_per_element = 1;
|
||||
break;
|
||||
default:
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Element type (" << elem_type << ") is not supported yet."
|
||||
<< std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
return nodes_per_element;
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE bool igl::MshLoader::is_element_map_identity() const
|
||||
{
|
||||
for(int i=0;i<m_elements_ids.size();i++) {
|
||||
int id=m_elements_ids[i];
|
||||
if (id!=i) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void igl::MshLoader::index_structures(int tag_column)
|
||||
{
|
||||
//cleanup
|
||||
m_structure_index.clear();
|
||||
m_structures.clear();
|
||||
m_structure_length.clear();
|
||||
|
||||
//index structure tags
|
||||
for(auto i=0; i != m_elements_tags[tag_column].size(); ++i )
|
||||
{
|
||||
m_structure_index.insert(
|
||||
std::pair<msh_struct,int>(
|
||||
msh_struct( m_elements_tags[tag_column][i],
|
||||
m_elements_types[i]), i)
|
||||
);
|
||||
}
|
||||
|
||||
// identify unique structures
|
||||
std::vector<StructIndex::value_type> _unique_structs;
|
||||
std::unique_copy(std::begin(m_structure_index),
|
||||
std::end(m_structure_index),
|
||||
std::back_inserter(_unique_structs),
|
||||
[](const StructIndex::value_type &c1, const StructIndex::value_type &c2)
|
||||
{ return c1.first == c2.first; });
|
||||
|
||||
std::for_each( _unique_structs.begin(), _unique_structs.end(),
|
||||
[this](const StructIndex::value_type &n){ this->m_structures.push_back(n.first); });
|
||||
|
||||
for(auto t = m_structures.begin(); t != m_structures.end(); ++t)
|
||||
{
|
||||
// identify all elements corresponding to this tag
|
||||
auto structure_range = m_structure_index.equal_range( *t );
|
||||
int cnt=0;
|
||||
|
||||
for(auto i=structure_range.first; i!=structure_range.second; i++)
|
||||
cnt++;
|
||||
|
||||
m_structure_length.insert( std::pair<msh_struct,int>( *t, cnt));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
// based on MSH reader from PyMesh
|
||||
|
||||
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
|
||||
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@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_MSH_LOADER_H
|
||||
#define IGL_MSH_LOADER_H
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace igl {
|
||||
|
||||
// Class for loading information from .msh file
|
||||
// depends only on c++stl library
|
||||
class MshLoader {
|
||||
public:
|
||||
|
||||
struct msh_struct {
|
||||
int tag,el_type;
|
||||
msh_struct(int _tag=0,int _type=0):
|
||||
tag(_tag),el_type(_type){}
|
||||
bool operator== (const msh_struct& a) const {
|
||||
return this->tag==a.tag &&
|
||||
this->el_type==a.el_type;
|
||||
}
|
||||
|
||||
bool operator< (const msh_struct& a) const {
|
||||
return (this->tag*100+this->el_type) <
|
||||
(a.tag*100+a.el_type);
|
||||
}
|
||||
};
|
||||
|
||||
typedef double Float;
|
||||
|
||||
typedef std::vector<int> IndexVector;
|
||||
typedef std::vector<int> IntVector;
|
||||
typedef std::vector<Float> FloatVector;
|
||||
typedef std::vector<FloatVector> FloatField;
|
||||
typedef std::vector<IntVector> IntField;
|
||||
typedef std::vector<std::string> FieldNames;
|
||||
typedef std::multimap<msh_struct,int> StructIndex;
|
||||
typedef std::vector<msh_struct> StructVector;
|
||||
|
||||
enum {ELEMENT_LINE=1, ELEMENT_TRI=2, ELEMENT_QUAD=3,
|
||||
ELEMENT_TET=4, ELEMENT_HEX=5, ELEMENT_PRISM=6,
|
||||
ELEMENT_PYRAMID=7,
|
||||
// 2nd order elements
|
||||
ELEMENT_LINE_2ND_ORDER=8, ELEMENT_TRI_2ND_ORDER=9,
|
||||
ELEMENT_QUAD_2ND_ORDER=10,ELEMENT_TET_2ND_ORDER=11,
|
||||
ELEMENT_HEX_2ND_ORDER=12, ELEMENT_PRISM_2ND_ORDER=13,
|
||||
ELEMENT_PYRAMID_2ND_ORDER=14,
|
||||
// other elements
|
||||
ELEMENT_POINT=15 };
|
||||
public:
|
||||
MshLoader(const std::string &filename);
|
||||
|
||||
public:
|
||||
|
||||
// get nodes , x,y,z sequentially
|
||||
const FloatVector& get_nodes() const { return m_nodes; }
|
||||
// get elements , identifying nodes that create an element
|
||||
// variable length per element
|
||||
const IndexVector& get_elements() const { return m_elements; }
|
||||
|
||||
// get element types
|
||||
const IntVector& get_elements_types() const { return m_elements_types; }
|
||||
// get element lengths
|
||||
const IntVector& get_elements_lengths() const { return m_elements_lengths; }
|
||||
// get element tags ( physical (0) and elementary (1) )
|
||||
const IntField& get_elements_tags() const { return m_elements_tags; }
|
||||
// get element IDs
|
||||
const IntVector& get_elements_ids() const { return m_elements_ids; }
|
||||
|
||||
// get reverse index from node to element
|
||||
const IndexVector& get_elements_nodes_idx() const { return m_elements_nodes_idx; }
|
||||
|
||||
// get fields assigned per node, all fields and components sequentially
|
||||
const FloatField& get_node_fields() const { return m_node_fields;}
|
||||
// get node field names,
|
||||
const FieldNames& get_node_fields_names() const { return m_node_fields_names;}
|
||||
// get number of node field components
|
||||
const IntVector& get_node_fields_components() const {return m_node_fields_components;}
|
||||
|
||||
int get_node_field_components(size_t c) const
|
||||
{
|
||||
return m_node_fields_components[c];
|
||||
}
|
||||
|
||||
// get fields assigned per element, all fields and components sequentially
|
||||
const FloatField& get_element_fields() const { return m_element_fields;}
|
||||
// get element field names
|
||||
const FieldNames& get_element_fields_names() const { return m_element_fields_names;}
|
||||
// get number of element field components
|
||||
const IntVector& get_element_fields_components() const {return m_element_fields_components;}
|
||||
|
||||
int get_element_field_components(size_t c) const {
|
||||
return m_element_fields_components[c];
|
||||
}
|
||||
// check if field is present at node level
|
||||
bool is_node_field(const std::string& fieldname) const {
|
||||
return (std::find(std::begin(m_node_fields_names),
|
||||
std::end(m_node_fields_names),
|
||||
fieldname) != std::end(m_node_fields_names) );
|
||||
}
|
||||
// check if field is present at element level
|
||||
bool is_element_field(const std::string& fieldname) const {
|
||||
return (std::find(std::begin(m_element_fields_names),
|
||||
std::end(m_element_fields_names),
|
||||
fieldname) != std::end(m_node_fields_names) );
|
||||
}
|
||||
|
||||
// check if all elements have ids assigned sequentially
|
||||
bool is_element_map_identity() const ;
|
||||
|
||||
// create tag index
|
||||
// tag_column: ( physical (0) or elementary (1) ) specifying which tag to use
|
||||
void index_structures(int tag_column);
|
||||
|
||||
// get tag index, call index_structure_tags first
|
||||
const StructIndex& get_structure_index() const
|
||||
{
|
||||
return m_structure_index;
|
||||
}
|
||||
|
||||
// get size of a structure identified by tag and element type
|
||||
const StructIndex& get_structure_length() const
|
||||
{
|
||||
return m_structure_length;
|
||||
}
|
||||
|
||||
//! get list of structures
|
||||
const StructVector& get_structures() const
|
||||
{
|
||||
return m_structures;
|
||||
}
|
||||
|
||||
public:
|
||||
// helper function, calculate number of nodes associated with an element
|
||||
static int num_nodes_per_elem_type(int elem_type);
|
||||
|
||||
private:
|
||||
void parse_nodes(std::ifstream& fin);
|
||||
void parse_elements(std::ifstream& fin);
|
||||
void parse_node_field(std::ifstream& fin);
|
||||
void parse_element_field(std::ifstream& fin);
|
||||
void parse_unknown_field(std::ifstream& fin,
|
||||
const std::string& fieldname);
|
||||
|
||||
private:
|
||||
bool m_binary;
|
||||
size_t m_data_size;
|
||||
|
||||
FloatVector m_nodes; // len x 3 vector
|
||||
|
||||
IndexVector m_elements; // linear array for nodes corresponding to each element
|
||||
IndexVector m_elements_nodes_idx; // element indexes
|
||||
|
||||
IntVector m_elements_ids; // element id's
|
||||
IntVector m_elements_types; // Element types
|
||||
IntVector m_elements_lengths; // Element lengths
|
||||
IntField m_elements_tags; // Element tags, currently 2xtags per element
|
||||
|
||||
FloatField m_node_fields; // Float field defined at each node
|
||||
IntVector m_node_fields_components; // Number of components for node field
|
||||
FieldNames m_node_fields_names; // Node field name
|
||||
|
||||
FloatField m_element_fields; // Float field defined at each element
|
||||
IntVector m_element_fields_components; // Number of components for element field
|
||||
FieldNames m_element_fields_names; // Element field name
|
||||
|
||||
StructIndex m_structure_index; // index tag ids
|
||||
StructVector m_structures; // unique structures
|
||||
StructIndex m_structure_length; // length of structures with consistent element type
|
||||
};
|
||||
|
||||
} //igl
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "MshLoader.cpp"
|
||||
#endif
|
||||
|
||||
#endif //IGL_MSH_LOADER_H
|
||||
@@ -0,0 +1,347 @@
|
||||
// based on MSH writer from PyMesh
|
||||
|
||||
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
|
||||
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@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 "MshSaver.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <exception>
|
||||
|
||||
|
||||
IGL_INLINE igl::MshSaver::MshSaver(const std::string& filename, bool binary) :
|
||||
m_binary(binary), m_num_nodes(0), m_num_elements(0) {
|
||||
if (!m_binary) {
|
||||
fout.open(filename.c_str(), std::fstream::out);
|
||||
} else {
|
||||
fout.open(filename.c_str(), std::fstream::binary);
|
||||
}
|
||||
if (!fout) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Error opening " << filename << " to write msh file." << std::endl;
|
||||
throw std::ios_base::failure(err_msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE igl::MshSaver::~MshSaver() {
|
||||
fout.close();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_mesh(
|
||||
const FloatVector& nodes,
|
||||
const IndexVector& elements,
|
||||
const IntVector& element_lengths,
|
||||
const IntVector& element_types,
|
||||
const IntVector& element_tags
|
||||
) {
|
||||
|
||||
save_header();
|
||||
|
||||
save_nodes(nodes);
|
||||
|
||||
save_elements(elements, element_lengths, element_types, element_tags );
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_header() {
|
||||
if (!m_binary) {
|
||||
fout << "$MeshFormat" << std::endl;
|
||||
fout << "2.2 0 " << sizeof(double) << std::endl;
|
||||
fout << "$EndMeshFormat" << std::endl;
|
||||
fout.precision(17);
|
||||
} else {
|
||||
fout << "$MeshFormat" << std::endl;
|
||||
fout << "2.2 1 " << sizeof(double) << std::endl;
|
||||
int one = 1;
|
||||
fout.write((char*)&one, sizeof(int));
|
||||
fout << "\n$EndMeshFormat" << std::endl;
|
||||
}
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_nodes(const FloatVector& nodes) {
|
||||
// Save nodes.
|
||||
// 3D hadrcoded
|
||||
m_num_nodes = nodes.size() / 3;
|
||||
fout << "$Nodes" << std::endl;
|
||||
fout << m_num_nodes << std::endl;
|
||||
if (!m_binary) {
|
||||
for (size_t i=0; i<nodes.size(); i+=3) {
|
||||
//const VectorF& v = nodes.segment(i,m_dim);
|
||||
int node_idx = i/3 + 1;
|
||||
fout << node_idx << " " << nodes[i] << " " << nodes[i+1] << " " << nodes[i+2] << std::endl;
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<nodes.size(); i+=3) {
|
||||
//const VectorF& v = nodes.segment(i,m_dim);
|
||||
int node_idx = i/3 + 1;
|
||||
fout.write((const char*)&node_idx, sizeof(int));
|
||||
fout.write((const char*)&nodes[i], sizeof(Float)*3);
|
||||
}
|
||||
}
|
||||
fout << "$EndNodes" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_elements(const IndexVector& elements,
|
||||
const IntVector& element_lengths,
|
||||
const IntVector& element_types,
|
||||
const IntVector& element_tags)
|
||||
{
|
||||
|
||||
m_num_elements = element_tags.size();
|
||||
assert(element_lengths.size() == element_types.size() );
|
||||
assert(element_lengths.size() == element_tags.size() );
|
||||
// TODO: sum up all lengths
|
||||
// Save elements.
|
||||
// node inxes are 1-based
|
||||
fout << "$Elements" << std::endl;
|
||||
fout << m_num_elements << std::endl;
|
||||
|
||||
if (m_num_elements > 0) {
|
||||
//int elem_type = el_type;
|
||||
int num_elems = m_num_elements;
|
||||
//int tags = 0;
|
||||
if (!m_binary) {
|
||||
size_t el_ptr=0;
|
||||
for (size_t i=0;i<m_num_elements;++i) {
|
||||
|
||||
int elem_num = (int) i + 1;
|
||||
///VectorI elem = elements.segment(i, nodes_per_element) + VectorI::Ones(nodes_per_element);
|
||||
// hardcoded: duplicate tags (I don't know why)
|
||||
fout << elem_num << " " << element_types[i] << " " << 2 << " "<< element_tags[i] << " "<< element_tags[i] << " ";
|
||||
for (size_t j=0; j<element_lengths[i]; j++) {
|
||||
fout << elements[el_ptr + j] + 1 << " ";
|
||||
}
|
||||
fout << std::endl;
|
||||
el_ptr+=element_lengths[i];
|
||||
}
|
||||
} else {
|
||||
size_t el_ptr=0,i=0;
|
||||
while(i<m_num_elements) {
|
||||
|
||||
// write elements in consistent chunks
|
||||
// TODO: refactor this code to be able to specify different elements
|
||||
// more effeciently
|
||||
|
||||
int elem_type=-1;
|
||||
int elem_len=-1;
|
||||
size_t j=i;
|
||||
for(;j<m_num_elements;++j)
|
||||
{
|
||||
if( elem_type==-1 )
|
||||
{
|
||||
elem_type=element_types[j];
|
||||
elem_len=element_lengths[j];
|
||||
} else if( elem_type!=element_types[j] ||
|
||||
elem_len!=element_lengths[j]) {
|
||||
break; // found the edge of the segment
|
||||
}
|
||||
}
|
||||
|
||||
//hardcoded: 2 tags
|
||||
int num_elems=j-i, num_tags=2;
|
||||
|
||||
fout.write((const char*)& elem_type, sizeof(int));
|
||||
fout.write((const char*)& num_elems, sizeof(int));
|
||||
fout.write((const char*)& num_tags, sizeof(int));
|
||||
|
||||
for(int k=0;k<num_elems; ++k,++i){
|
||||
int elem_num = (int )i + 1;
|
||||
fout.write((const char*)&elem_num, sizeof(int));
|
||||
|
||||
// HACK: hardcoded 2 tags
|
||||
fout.write((const char*)& element_tags[i], sizeof(int));
|
||||
fout.write((const char*)& element_tags[i], sizeof(int));
|
||||
|
||||
for (size_t e=0; e<elem_len; e++) {
|
||||
int _elem = static_cast<int>( elements[el_ptr + e] )+1;
|
||||
fout.write((const char*)&_elem, sizeof(int));
|
||||
}
|
||||
el_ptr+=elem_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fout << "$EndElements" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_scalar_field(const std::string& fieldname, const FloatVector& field) {
|
||||
assert(field.size() == m_num_nodes);
|
||||
fout << "$NodeData" << std::endl;
|
||||
fout << "1" << std::endl; // num string tags.
|
||||
fout << "\"" << fieldname << "\"" << std::endl;
|
||||
fout << "1" << std::endl; // num real tags.
|
||||
fout << "0.0" << std::endl; // time value.
|
||||
fout << "3" << std::endl; // num int tags.
|
||||
fout << "0" << std::endl; // the time step
|
||||
fout << "1" << std::endl; // 1-component scalar field.
|
||||
fout << m_num_nodes << std::endl; // number of nodes
|
||||
|
||||
if (m_binary) {
|
||||
for (size_t i=0; i<m_num_nodes; i++) {
|
||||
int node_idx = i+1;
|
||||
fout.write((char*)&node_idx, sizeof(int));
|
||||
fout.write((char*)&field[i], sizeof(Float));
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<m_num_nodes; i++) {
|
||||
int node_idx = i+1;
|
||||
fout << node_idx << " " << field[i] << std::endl;
|
||||
}
|
||||
}
|
||||
fout << "$EndNodeData" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_vector_field(const std::string& fieldname, const FloatVector& field) {
|
||||
assert(field.size() == 3 * m_num_nodes);
|
||||
|
||||
fout << "$NodeData" << std::endl;
|
||||
fout << "1" << std::endl; // num string tags.
|
||||
fout << "\"" << fieldname << "\"" << std::endl;
|
||||
fout << "1" << std::endl; // num real tags.
|
||||
fout << "0.0" << std::endl; // time value.
|
||||
fout << "3" << std::endl; // num int tags.
|
||||
fout << "0" << std::endl; // the time step
|
||||
fout << "3" << std::endl; // 3-component vector field.
|
||||
fout << m_num_nodes << std::endl; // number of nodes
|
||||
|
||||
const Float zero = 0.0;
|
||||
if (m_binary) {
|
||||
for (size_t i=0; i<m_num_nodes; i++) {
|
||||
int node_idx = i+1;
|
||||
fout.write((const char*)&node_idx, sizeof(int));
|
||||
fout.write((const char*)&field[i*3], sizeof(Float)*3);
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<m_num_nodes; i++) {
|
||||
int node_idx = i+1;
|
||||
fout << node_idx
|
||||
<< " " << field[i*3]
|
||||
<< " " << field[i*3+1]
|
||||
<< " " << field[i*3+2]
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
fout << "$EndNodeData" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_elem_scalar_field(const std::string& fieldname, const FloatVector& field) {
|
||||
assert(field.size() == m_num_elements);
|
||||
fout << "$ElementData" << std::endl;
|
||||
fout << 1 << std::endl; // num string tags.
|
||||
fout << "\"" << fieldname << "\"" << std::endl;
|
||||
fout << "1" << std::endl; // num real tags.
|
||||
fout << "0.0" << std::endl; // time value.
|
||||
fout << "3" << std::endl; // num int tags.
|
||||
fout << "0" << std::endl; // the time step
|
||||
fout << "1" << std::endl; // 1-component scalar field.
|
||||
fout << m_num_elements << std::endl; // number of elements
|
||||
|
||||
if (m_binary) {
|
||||
for (size_t i=0; i<m_num_elements; i++) {
|
||||
int elem_idx = i+1;
|
||||
fout.write((const char*)&elem_idx, sizeof(int));
|
||||
fout.write((const char*)&field[i], sizeof(Float));
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<m_num_elements; i++) {
|
||||
int elem_idx = i+1;
|
||||
fout << elem_idx << " " << field[i] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
fout << "$EndElementData" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_elem_vector_field(const std::string& fieldname, const FloatVector& field) {
|
||||
assert(field.size() == m_num_elements * 3);
|
||||
fout << "$ElementData" << std::endl;
|
||||
fout << 1 << std::endl; // num string tags.
|
||||
fout << "\"" << fieldname << "\"" << std::endl;
|
||||
fout << "1" << std::endl; // num real tags.
|
||||
fout << "0.0" << std::endl; // time value.
|
||||
fout << "3" << std::endl; // num int tags.
|
||||
fout << "0" << std::endl; // the time step
|
||||
fout << "3" << std::endl; // 3-component vector field.
|
||||
fout << m_num_elements << std::endl; // number of elements
|
||||
|
||||
const Float zero = 0.0;
|
||||
if (m_binary) {
|
||||
for (size_t i=0; i<m_num_elements; ++i) {
|
||||
int elem_idx = i+1;
|
||||
fout.write((const char*)&elem_idx, sizeof(int));
|
||||
fout.write((const char*)&field[i*3], sizeof(Float) * 3);
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<m_num_elements; ++i) {
|
||||
int elem_idx = i+1;
|
||||
fout << elem_idx
|
||||
<< " " << field[i*3]
|
||||
<< " " << field[i*3+1]
|
||||
<< " " << field[i*3+2]
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
fout << "$EndElementData" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_elem_tensor_field(const std::string& fieldname, const FloatVector& field) {
|
||||
assert(field.size() == m_num_elements * 3 * (3 + 1) / 2);
|
||||
fout << "$ElementData" << std::endl;
|
||||
fout << 1 << std::endl; // num string tags.
|
||||
fout << "\"" << fieldname << "\"" << std::endl;
|
||||
fout << "1" << std::endl; // num real tags.
|
||||
fout << "0.0" << std::endl; // time value.
|
||||
fout << "3" << std::endl; // num int tags.
|
||||
fout << "0" << std::endl; // the time step
|
||||
fout << "9" << std::endl; // 9-component tensor field.
|
||||
fout << m_num_elements << std::endl; // number of elements
|
||||
|
||||
const Float zero = 0.0;
|
||||
|
||||
if (m_binary) {
|
||||
for (size_t i=0; i<m_num_elements; i++) {
|
||||
int elem_idx = i+1;
|
||||
fout.write((char*)&elem_idx, sizeof(int));
|
||||
//const VectorF& val = field.segment(i*6, 6);
|
||||
const Float* val = &field[i*6];
|
||||
Float tensor[9] = {
|
||||
val[0], val[5], val[4],
|
||||
val[5], val[1], val[3],
|
||||
val[4], val[3], val[2] };
|
||||
fout.write((char*)tensor, sizeof(Float) * 9);
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<m_num_elements; i++) {
|
||||
int elem_idx = i+1;
|
||||
const Float* val = &field[i*6];
|
||||
fout << elem_idx
|
||||
<< " " << val[0]
|
||||
<< " " << val[5]
|
||||
<< " " << val[4]
|
||||
<< " " << val[5]
|
||||
<< " " << val[1]
|
||||
<< " " << val[3]
|
||||
<< " " << val[4]
|
||||
<< " " << val[3]
|
||||
<< " " << val[2]
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
fout << "$EndElementData" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// based on MSH writer from PyMesh
|
||||
|
||||
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
|
||||
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@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_MSH_SAVER_H
|
||||
#define IGL_MSH_SAVER_H
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace igl {
|
||||
|
||||
// Class for dumping information to .msh file
|
||||
// depends only on c++stl library
|
||||
// current implementation works only with 3D information
|
||||
class MshSaver {
|
||||
public:
|
||||
typedef double Float;
|
||||
|
||||
typedef std::vector<int> IndexVector;
|
||||
typedef std::vector<int> IntVector;
|
||||
typedef std::vector<Float> FloatVector;
|
||||
typedef std::vector<FloatVector> FloatField;
|
||||
typedef std::vector<IntVector> IntField;
|
||||
typedef std::vector<std::string> FieldNames;
|
||||
|
||||
MshSaver(const std::string& filename, bool binary=true);
|
||||
~MshSaver();
|
||||
|
||||
public:
|
||||
// Only these element types are supported right now
|
||||
enum {ELEMENT_LINE=1, ELEMENT_TRI=2, ELEMENT_QUAD=3,
|
||||
ELEMENT_TET=4, ELEMENT_HEX=5, ELEMENT_PRISM=6 };
|
||||
|
||||
public:
|
||||
// save mesh geometry
|
||||
void save_mesh(
|
||||
const FloatVector& nodes,
|
||||
const IndexVector& elements,
|
||||
const IntVector& element_lengths,
|
||||
const IntVector& element_type,
|
||||
const IntVector& element_tags );
|
||||
|
||||
// save additional fields associated with the mesh
|
||||
|
||||
// add node scalar field
|
||||
void save_scalar_field(const std::string& fieldname, const FloatVector& field);
|
||||
// add node vectot field
|
||||
void save_vector_field(const std::string& fieldname, const FloatVector& field);
|
||||
// add element scalar field
|
||||
void save_elem_scalar_field(const std::string& fieldname, const FloatVector& field);
|
||||
// add element vector field
|
||||
void save_elem_vector_field(const std::string& fieldname, const FloatVector& field);
|
||||
// add element tensor field
|
||||
void save_elem_tensor_field(const std::string& fieldname, const FloatVector& field);
|
||||
|
||||
protected:
|
||||
void save_header();
|
||||
void save_nodes(const FloatVector& nodes);
|
||||
void save_elements(const IndexVector& elements,
|
||||
const IntVector& element_lengths,
|
||||
const IntVector& element_type,
|
||||
const IntVector& element_tags);
|
||||
|
||||
private:
|
||||
bool m_binary;
|
||||
size_t m_num_nodes;
|
||||
size_t m_num_elements;
|
||||
|
||||
std::ofstream fout;
|
||||
};
|
||||
} //igl
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "MshSaver.cpp"
|
||||
#endif
|
||||
|
||||
#endif //MSH_SAVER_H
|
||||
+2
-2
@@ -11,9 +11,9 @@ namespace igl
|
||||
{
|
||||
// Use standard mathematical constants' M_PI if available
|
||||
#ifdef M_PI
|
||||
const double PI = M_PI;
|
||||
constexpr double PI = M_PI;
|
||||
#else
|
||||
const double PI = 3.1415926535897932384626433832795;
|
||||
constexpr double PI = 3.1415926535897932384626433832795;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -374,4 +374,16 @@ inline typename DerivedV::Scalar
|
||||
return igl::winding_number(BV,PBF,p);
|
||||
}
|
||||
|
||||
// This is a bullshit template because AABB annoyingly needs templates for bad
|
||||
// combinations of 3D V with DIM=2 AABB
|
||||
//
|
||||
// _Define_ as a no-op rather than monkeying around with the proper code above
|
||||
namespace igl
|
||||
{
|
||||
template <> inline igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::WindingNumberAABB(const Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2>> & V, const Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2>> & F){};
|
||||
template <> inline void igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::grow(){};
|
||||
template <> inline void igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::init(){};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -65,8 +65,58 @@ IGL_INLINE void igl::adjacency_matrix(
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedI, typename DerivedC, typename T>
|
||||
IGL_INLINE void igl::adjacency_matrix(
|
||||
const Eigen::MatrixBase<DerivedI> & I,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::SparseMatrix<T>& A)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
typedef Triplet<T> IJV;
|
||||
vector<IJV > ijv;
|
||||
ijv.reserve(C(C.size()-1)*2);
|
||||
typedef typename DerivedI::Scalar Index;
|
||||
const Index n = I.maxCoeff()+1;
|
||||
{
|
||||
// loop over polygons
|
||||
for(Index p = 0;p<C.size()-1;p++)
|
||||
{
|
||||
// number of edges
|
||||
const Index np = C(p+1)-C(p);
|
||||
// loop over edges
|
||||
for(Index c = 0;c<np;c++)
|
||||
{
|
||||
const Index i = I(C(p)+c);
|
||||
const Index j = I(C(p)+((c+1)%np));
|
||||
ijv.emplace_back(i,j,1);
|
||||
ijv.emplace_back(j,i,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
A.resize(n,n);
|
||||
A.reserve(6*n);
|
||||
A.setFromTriplets(ijv.begin(),ijv.end());
|
||||
|
||||
// Force all non-zeros to be one
|
||||
|
||||
// Iterate over outside
|
||||
for(int k=0; k<A.outerSize(); ++k)
|
||||
{
|
||||
// Iterate over inside
|
||||
for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
assert(it.value() != 0);
|
||||
A.coeffRef(it.row(),it.col()) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
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>&);
|
||||
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace igl
|
||||
// Inputs:
|
||||
// F #F by dim list of mesh simplices
|
||||
// Outputs:
|
||||
// A max(F) by max(F) adjacency matrix, each row i corresponding to V(i,:)
|
||||
// A max(F)+1 by max(F)+1 adjacency matrix, each row i corresponding to V(i,:)
|
||||
//
|
||||
// Example:
|
||||
// // Mesh in (V,F)
|
||||
@@ -42,6 +42,21 @@ namespace igl
|
||||
IGL_INLINE void adjacency_matrix(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::SparseMatrix<T>& A);
|
||||
// Constructs an vertex adjacency for a polygon mesh.
|
||||
//
|
||||
// Inputs:
|
||||
// I #I vectorized list of polygon corner indices into rows of some matrix V
|
||||
// C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) =
|
||||
// size of the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the
|
||||
// indices of the ith polygon
|
||||
// Outputs:
|
||||
// A max(I)+1 by max(I)+1 adjacency matrix, each row i corresponding to V(i,:)
|
||||
//
|
||||
template <typename DerivedI, typename DerivedC, typename T>
|
||||
IGL_INLINE void adjacency_matrix(
|
||||
const Eigen::MatrixBase<DerivedI> & I,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::SparseMatrix<T>& A);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "all_edges.h"
|
||||
#include "oriented_facets.h"
|
||||
|
||||
template <typename DerivedF, typename DerivedE>
|
||||
IGL_INLINE void igl::all_edges(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedE> & E)
|
||||
{
|
||||
return oriented_facets(F,E);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::all_edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::all_edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
|
||||
template void igl::all_edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
|
||||
template void igl::all_edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::all_edges<Eigen::Matrix<double, -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::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_ALL_EDGES_H
|
||||
#define IGL_ALL_EDGES_H
|
||||
#include "igl_inline.h"
|
||||
#include "deprecated.h"
|
||||
#include <Eigen/Dense>
|
||||
namespace igl
|
||||
{
|
||||
// Deprecated: call oriented_facets instead.
|
||||
//
|
||||
// ALL_EDGES Determines all "directed edges" of a given set of simplices. For
|
||||
// a manifold mesh, this computes all of the half-edges
|
||||
//
|
||||
// Inputs:
|
||||
// F #F by simplex_size list of "faces"
|
||||
// Outputs:
|
||||
// E #E by simplex_size-1 list of edges
|
||||
//
|
||||
// Note: this is not the same as igl::edges because this includes every
|
||||
// directed edge including repeats (meaning interior edges on a surface will
|
||||
// show up once for each direction and non-manifold edges may appear more than
|
||||
// once for each direction).
|
||||
template <typename DerivedF, typename DerivedE>
|
||||
IGL_DEPRECATED IGL_INLINE void all_edges(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedE> & E);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "all_edges.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -128,6 +128,8 @@ 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> >&);
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include "get_seconds_hires.h"
|
||||
//#include "MKLEigenInterface.h"
|
||||
#include "min_quad_dense.h"
|
||||
#include "kkt_inverse.h"
|
||||
#include "get_seconds.h"
|
||||
#include "columnize.h"
|
||||
|
||||
@@ -543,7 +543,7 @@ IGL_INLINE bool igl::arap_dof_recomputation(
|
||||
#endif
|
||||
|
||||
// Compute dense solve matrix (alternative of matrix factorization)
|
||||
//printf("min_quad_dense_precompute()\n");
|
||||
//printf("kkt_inverse()\n");
|
||||
MatrixXd Qfull(*Q);
|
||||
MatrixXd A_eqfull(A_eq);
|
||||
MatrixXd M_Solve;
|
||||
@@ -552,7 +552,7 @@ IGL_INLINE bool igl::arap_dof_recomputation(
|
||||
bool use_lu = data.effective_dim != 2;
|
||||
//use_lu = false;
|
||||
//printf("use_lu: %s\n",(use_lu?"TRUE":"FALSE"));
|
||||
min_quad_dense_precompute(Qfull, A_eqfull, use_lu,M_Solve);
|
||||
kkt_inverse(Qfull, A_eqfull, use_lu,M_Solve);
|
||||
double timer0_end = get_seconds_hires();
|
||||
verbose("Bob timing: %.20f\n", (timer0_end - timer0_start)*1000.0);
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// 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 "average_from_edges_onto_vertices.h"
|
||||
|
||||
template<typename DerivedF,typename DerivedE,typename DerivedoE,
|
||||
typename DeriveduE,typename DeriveduV>
|
||||
IGL_INLINE void
|
||||
igl::average_from_edges_onto_vertices(
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
const Eigen::MatrixBase<DeriveduE> &uE,
|
||||
Eigen::PlainObjectBase<DeriveduV> &uV)
|
||||
{
|
||||
using Scalar = typename DeriveduE::Scalar;
|
||||
using VecX = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
|
||||
using Int = typename DerivedF::Scalar;
|
||||
|
||||
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
|
||||
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
|
||||
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
|
||||
"This method is for triangle meshes.");
|
||||
|
||||
const Int n = F.maxCoeff()+1;
|
||||
|
||||
VecX edgesPerVertex(n);
|
||||
edgesPerVertex.setZero();
|
||||
uV.resize(n,1);
|
||||
uV.setZero();
|
||||
|
||||
for(Eigen::Index i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
if(oE(i,j)<0) {
|
||||
continue;
|
||||
}
|
||||
const Int e = E(i,j);
|
||||
const Int vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
|
||||
|
||||
//Count vertex valence
|
||||
++edgesPerVertex(vi);
|
||||
++edgesPerVertex(vj);
|
||||
|
||||
//Average uE value onto vertices
|
||||
uV(vi) += uE(e);
|
||||
uV(vj) += uE(e);
|
||||
}
|
||||
}
|
||||
|
||||
//Divide by valence
|
||||
for(Int i=0; i<n; ++i) {
|
||||
const Scalar valence = edgesPerVertex(i);
|
||||
if(valence>0) {
|
||||
uV(i) /= valence;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::average_from_edges_onto_vertices<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::PartialReduxExpr<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::internal::member_norm<double>, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::PartialReduxExpr<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::internal::member_norm<double>, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_AVERAGE_FROM_EDGES_ONTO_VERTICES_H
|
||||
#define IGL_AVERAGE_FROM_EDGES_ONTO_VERTICES_H
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
namespace igl
|
||||
{
|
||||
// Move a scalar field defined on edges to vertices by averaging
|
||||
//
|
||||
// Input:
|
||||
// F: triangle mesh connectivity
|
||||
// E, oE: mapping from halfedges to edges and orientation as generated by
|
||||
// orient_halfedges
|
||||
// uE: scalar field defined on edges, one per edge
|
||||
//
|
||||
// Output:
|
||||
// uV: scalar field defined on vertices
|
||||
template<typename DerivedF,typename DerivedE,typename DerivedoE,
|
||||
typename DeriveduE,typename DeriveduV>
|
||||
IGL_INLINE void average_from_edges_onto_vertices(
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
const Eigen::MatrixBase<DeriveduE> &uE,
|
||||
Eigen::PlainObjectBase<DeriveduV> &uV);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "average_from_edges_onto_vertices.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -22,4 +22,6 @@ IGL_INLINE void igl::average_onto_faces(
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::average_onto_faces<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
|
||||
@@ -34,18 +34,13 @@ IGL_INLINE void igl::barycenter(
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -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, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 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, 4, 0, -1, 4> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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 "barycentric_interpolation.h"
|
||||
#include "parallel_for.h"
|
||||
|
||||
template <
|
||||
typename DerivedD,
|
||||
typename DerivedF,
|
||||
typename DerivedB,
|
||||
typename DerivedI,
|
||||
typename DerivedX>
|
||||
IGL_INLINE void igl::barycentric_interpolation(
|
||||
const Eigen::MatrixBase<DerivedD> & D,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedB> & B,
|
||||
const Eigen::MatrixBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedX> & X)
|
||||
{
|
||||
assert(B.rows() == I.size());
|
||||
assert(F.cols() == B.cols());
|
||||
X.setZero(B.rows(),D.cols());
|
||||
// should use parallel_for
|
||||
//for(int i = 0;i<X.rows();i++)
|
||||
parallel_for(X.rows(),[&X,&B,&D,&F,&I](const int i)
|
||||
{
|
||||
for(int j = 0;j<F.cols();j++)
|
||||
{
|
||||
X.row(i) += B(i,j) * D.row(F(I(i),j));
|
||||
}
|
||||
},1000);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycentric_interpolation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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_BARYCENTRIC_INTERPOLATION_H
|
||||
#define IGL_BARYCENTRIC_INTERPOLATION_H
|
||||
#include "igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
// Interpolate data on a triangle mesh using barycentric coordinates
|
||||
//
|
||||
// Inputs:
|
||||
// D #D by dim list of per-vertex data
|
||||
// F #F by 3 list of triangle indices
|
||||
// B #X by 3 list of barycentric corodinates
|
||||
// I #X list of triangle indices
|
||||
// Outputs:
|
||||
// X #X by dim list of interpolated data
|
||||
template <
|
||||
typename DerivedD,
|
||||
typename DerivedF,
|
||||
typename DerivedB,
|
||||
typename DerivedI,
|
||||
typename DerivedX>
|
||||
IGL_INLINE void barycentric_interpolation(
|
||||
const Eigen::MatrixBase<DerivedD> & D,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedB> & B,
|
||||
const Eigen::MatrixBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedX> & X);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "barycentric_interpolation.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "barycentric_to_global.h"
|
||||
|
||||
// For error printing
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
template <typename Scalar, typename Index>
|
||||
IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> barycentric_to_global(
|
||||
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
|
||||
const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
|
||||
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc)
|
||||
{
|
||||
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> R;
|
||||
R.resize(bc.rows(),3);
|
||||
|
||||
for (unsigned i=0; i<R.rows(); ++i)
|
||||
{
|
||||
unsigned id = round(bc(i,0));
|
||||
double u = bc(i,1);
|
||||
double v = bc(i,2);
|
||||
|
||||
if (id != -1)
|
||||
R.row(i) = V.row(F(id,0)) +
|
||||
((V.row(F(id,1)) - V.row(F(id,0))) * u +
|
||||
(V.row(F(id,2)) - V.row(F(id,0))) * v );
|
||||
else
|
||||
R.row(i) << 0,0,0;
|
||||
}
|
||||
return R;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::barycentric_to_global<double, int>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&);
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_BARYCENTRIC2GLOBAL_H
|
||||
#define IGL_BARYCENTRIC2GLOBAL_H
|
||||
#include <igl/igl_inline.h>
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Converts barycentric coordinates in the embree form to 3D coordinates
|
||||
// Embree stores barycentric coordinates as triples: fid, bc1, bc2
|
||||
// fid is the id of a face, bc1 is the displacement of the point wrt the
|
||||
// first vertex v0 and the edge v1-v0. Similarly, bc2 is the displacement
|
||||
// wrt v2-v0.
|
||||
//
|
||||
// Input:
|
||||
// V: #Vx3 Vertices of the mesh
|
||||
// F: #Fxe Faces of the mesh
|
||||
// bc: #Xx3 Barycentric coordinates, one row per point
|
||||
//
|
||||
// Output:
|
||||
// #X: #Xx3 3D coordinates of all points in bc
|
||||
template <typename Scalar, typename Index>
|
||||
IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
|
||||
barycentric_to_global(
|
||||
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
|
||||
const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
|
||||
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "barycentric_to_global.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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 "blkdiag.h"
|
||||
|
||||
template <typename Scalar>
|
||||
IGL_INLINE void igl::blkdiag(
|
||||
const std::vector<Eigen::SparseMatrix<Scalar>> & L,
|
||||
Eigen::SparseMatrix<Scalar> & Y)
|
||||
{
|
||||
int nr = 0;
|
||||
int nc = 0;
|
||||
int nnz = 0;
|
||||
for(const auto & A : L)
|
||||
{
|
||||
nr += A.rows();
|
||||
nc += A.cols();
|
||||
}
|
||||
Y.resize(nr,nc);
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for(const auto & A : L)
|
||||
{
|
||||
for(int k = 0;k<A.outerSize();++k)
|
||||
{
|
||||
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it(A,k);it;++it)
|
||||
{
|
||||
Y.insert(i+it.row(),j+k) = it.value();
|
||||
}
|
||||
}
|
||||
i += A.rows();
|
||||
j += A.cols();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedY>
|
||||
IGL_INLINE void igl::blkdiag(
|
||||
const std::vector<DerivedY> & L,
|
||||
Eigen::PlainObjectBase<DerivedY> & Y)
|
||||
{
|
||||
int nr = 0;
|
||||
int nc = 0;
|
||||
for(const auto & A : L)
|
||||
{
|
||||
nr += A.rows();
|
||||
nc += A.cols();
|
||||
}
|
||||
Y.setZero(nr,nc);
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for(const auto & A : L)
|
||||
{
|
||||
Y.block(i,j,A.rows(),A.cols()) = A;
|
||||
i += A.rows();
|
||||
j += A.cols();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// explicit template instantiations
|
||||
template void igl::blkdiag<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::blkdiag<double>(std::vector<Eigen::SparseMatrix<double, 0, int>, std::allocator<Eigen::SparseMatrix<double, 0, int> > > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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_BLKDIAG_H
|
||||
#define IGL_BLKDIAG_H
|
||||
#include "igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Given a list of matrices place them along the diagonal as blocks of the
|
||||
// output matrix. Like matlab's blkdiag.
|
||||
//
|
||||
// Inputs:
|
||||
// L list of matrices {A,B, ...}
|
||||
// Outputs:
|
||||
// Y A.rows()+B.rows()+... by A.cols()+B.cols()+... block diagonal
|
||||
//
|
||||
// See also: cat, repdiag
|
||||
template <typename Scalar>
|
||||
IGL_INLINE void blkdiag(
|
||||
const std::vector<Eigen::SparseMatrix<Scalar>> & L,
|
||||
Eigen::SparseMatrix<Scalar> & Y);
|
||||
template <typename DerivedY>
|
||||
IGL_INLINE void blkdiag(
|
||||
const std::vector<DerivedY> & L,
|
||||
Eigen::PlainObjectBase<DerivedY> & Y);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "blkdiag.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,372 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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 "blue_noise.h"
|
||||
#include "doublearea.h"
|
||||
#include "random_points_on_mesh.h"
|
||||
#include "slice.h"
|
||||
#include "sortrows.h"
|
||||
#include "PI.h"
|
||||
#include "get_seconds.h"
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
namespace igl
|
||||
{
|
||||
// Should probably find and replace with less generic name
|
||||
//
|
||||
// Map 3D subscripts (x,y,z) to unique index (return value)
|
||||
//
|
||||
// Inputs:
|
||||
// w side length of w×w×w integer cube lattice
|
||||
// x subscript along x direction
|
||||
// y subscript along y direction
|
||||
// z subscript along z direction
|
||||
// Returns index value
|
||||
//
|
||||
inline BlueNoiseKeyType blue_noise_key(
|
||||
const BlueNoiseKeyType w, // pass by copy --> int64_t so that multiplication is OK
|
||||
const BlueNoiseKeyType x, // pass by copy --> int64_t so that multiplication is OK
|
||||
const BlueNoiseKeyType y, // pass by copy --> int64_t so that multiplication is OK
|
||||
const BlueNoiseKeyType z) // pass by copy --> int64_t so that multiplication is OK
|
||||
{
|
||||
return x+w*(y+w*z);
|
||||
}
|
||||
// Determine if a query candidate at position X.row(i) is too close to already
|
||||
// selected sites (stored in S).
|
||||
//
|
||||
// Inputs:
|
||||
// X #X by 3 list of raw candidate positions
|
||||
// Xs #Xs by 3 list of corresponding integer cell subscripts
|
||||
// i index of candidate in question
|
||||
// S map from cell index to index into X of selected candidate (or -1 if
|
||||
// cell is currently empty)
|
||||
// rr Poisson disk radius squared
|
||||
// w side length of w×w×w integer cube lattice (into which Xs subscripts)
|
||||
template <
|
||||
typename DerivedX,
|
||||
typename DerivedXs>
|
||||
inline bool blue_noise_far_enough(
|
||||
const Eigen::MatrixBase<DerivedX> & X,
|
||||
const Eigen::MatrixBase<DerivedXs> & Xs,
|
||||
const std::unordered_map<BlueNoiseKeyType,int> & S,
|
||||
const double & rr,
|
||||
const int & w,
|
||||
const int i)
|
||||
{
|
||||
const int xi = Xs(i,0);
|
||||
const int yi = Xs(i,1);
|
||||
const int zi = Xs(i,2);
|
||||
BlueNoiseKeyType k = blue_noise_key(w,xi,yi,zi);
|
||||
int g = 2; // ceil(r/s)
|
||||
for(int x = std::max(xi-g,0);x<=std::min(xi+g,w-1);x++)
|
||||
for(int y = std::max(yi-g,0);y<=std::min(yi+g,w-1);y++)
|
||||
for(int z = std::max(zi-g,0);z<=std::min(zi+g,w-1);z++)
|
||||
{
|
||||
if(x!=xi || y!=yi || z!=zi)
|
||||
{
|
||||
const BlueNoiseKeyType nk = blue_noise_key(w,x,y,z);
|
||||
// have already selected from this cell
|
||||
const auto Siter = S.find(nk);
|
||||
if(Siter !=S.end() && Siter->second >= 0)
|
||||
{
|
||||
const int ni = Siter->second;
|
||||
// too close
|
||||
if( (X.row(i)-X.row(ni)).squaredNorm() < rr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Try to activate a candidate in a given cell
|
||||
//
|
||||
// Inputs:
|
||||
// X #X by 3 list of raw candidate positions
|
||||
// Xs #Xs by 3 list of corresponding integer cell subscripts
|
||||
// rr Poisson disk radius squared
|
||||
// w side length of w×w×w integer cube lattice (into which Xs subscripts)
|
||||
// nk index of cell in which we'd like to activate a candidate
|
||||
// M map from cell index to list of candidates
|
||||
// S map from cell index to index into X of selected candidate (or -1 if
|
||||
// cell is currently empty)
|
||||
// active list of indices into X of active candidates
|
||||
// Outputs:
|
||||
// M visited candidates deemed too close to already selected points are
|
||||
// removed
|
||||
// S updated to reflect activated point (if successful)
|
||||
// active updated to reflect activated point (if successful)
|
||||
// Returns true iff activation was successful
|
||||
template <
|
||||
typename DerivedX,
|
||||
typename DerivedXs>
|
||||
inline bool activate(
|
||||
const Eigen::MatrixBase<DerivedX> & X,
|
||||
const Eigen::MatrixBase<DerivedXs> & Xs,
|
||||
const double & rr,
|
||||
const int & i,
|
||||
const int & w,
|
||||
const BlueNoiseKeyType & nk,
|
||||
std::unordered_map<BlueNoiseKeyType,std::vector<int> > & M,
|
||||
std::unordered_map<BlueNoiseKeyType,int> & S,
|
||||
std::vector<int> & active)
|
||||
{
|
||||
assert(M.count(nk));
|
||||
auto & Mvec = M.find(nk)->second;
|
||||
auto miter = Mvec.begin();
|
||||
while(miter != Mvec.end())
|
||||
{
|
||||
const int mi = *miter;
|
||||
// mi is our candidate sample. Is it far enough from all existing
|
||||
// samples?
|
||||
if(i>=0 && (X.row(i)-X.row(mi)).squaredNorm() > 4.*rr)
|
||||
{
|
||||
// too far skip (reject)
|
||||
miter++;
|
||||
} else if(blue_noise_far_enough(X,Xs,S,rr,w,mi))
|
||||
{
|
||||
active.push_back(mi);
|
||||
S.find(nk)->second = mi;
|
||||
//printf(" found %d\n",mi);
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
// remove forever (instead of incrementing we swap and eat from the
|
||||
// back)
|
||||
//std::swap(*miter,Mvec.back());
|
||||
*miter = Mvec.back();
|
||||
bool was_last = (std::next(miter) == Mvec.end());
|
||||
Mvec.pop_back();
|
||||
if (was_last) {
|
||||
// popping from the vector can invalidate the iterator, if it was
|
||||
// pointing to the last element that was popped. Alternatively,
|
||||
// one could use indices directly...
|
||||
miter = Mvec.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedX,
|
||||
typename DerivedXs>
|
||||
inline bool step(
|
||||
const Eigen::MatrixBase<DerivedX> & X,
|
||||
const Eigen::MatrixBase<DerivedXs> & Xs,
|
||||
const double & rr,
|
||||
const int & w,
|
||||
std::unordered_map<BlueNoiseKeyType,std::vector<int> > & M,
|
||||
std::unordered_map<BlueNoiseKeyType,int> & S,
|
||||
std::vector<int> & active,
|
||||
std::vector<int> & collected
|
||||
)
|
||||
{
|
||||
//considered.clear();
|
||||
if(active.size() == 0) return false;
|
||||
// random entry
|
||||
const int e = rand() % active.size();
|
||||
const int i = active[e];
|
||||
//printf("%d\n",i);
|
||||
const int xi = Xs(i,0);
|
||||
const int yi = Xs(i,1);
|
||||
const int zi = Xs(i,2);
|
||||
//printf("%d %d %d - %g %g %g\n",xi,yi,zi,X(i,0),X(i,1),X(i,2));
|
||||
// cell indices of neighbors
|
||||
int g = 4;
|
||||
std::vector<BlueNoiseKeyType> N;N.reserve((1+g*1)^3-1);
|
||||
for(int x = std::max(xi-g,0);x<=std::min(xi+g,w-1);x++)
|
||||
for(int y = std::max(yi-g,0);y<=std::min(yi+g,w-1);y++)
|
||||
for(int z = std::max(zi-g,0);z<=std::min(zi+g,w-1);z++)
|
||||
{
|
||||
if(x!=xi || y!=yi || z!=zi)
|
||||
{
|
||||
//printf(" %d %d %d\n",x,y,z);
|
||||
const BlueNoiseKeyType nk = blue_noise_key(w,x,y,z);
|
||||
// haven't yet selected from this cell?
|
||||
const auto Siter = S.find(nk);
|
||||
if(Siter !=S.end() && Siter->second < 0)
|
||||
{
|
||||
assert(M.find(nk) != M.end());
|
||||
N.emplace_back(nk);
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf(" --------\n");
|
||||
// randomize order: this might be a little paranoid...
|
||||
std::random_shuffle(std::begin(N), std::end(N));
|
||||
bool found = false;
|
||||
for(const BlueNoiseKeyType & nk : N)
|
||||
{
|
||||
assert(M.find(nk) != M.end());
|
||||
if(activate(X,Xs,rr,i,w,nk,M,S,active))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
{
|
||||
// remove i from active list
|
||||
// https://stackoverflow.com/a/60765833/148668
|
||||
collected.push_back(i);
|
||||
//printf(" before: "); for(const int j : active) { printf("%d ",j); } printf("\n");
|
||||
std::swap(active[e], active.back());
|
||||
//printf(" after : "); for(const int j : active) { printf("%d ",j); } printf("\n");
|
||||
active.pop_back();
|
||||
//printf(" removed %d\n",i);
|
||||
}
|
||||
//printf(" active: "); for(const int j : active) { printf("%d ",j); } printf("\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedB,
|
||||
typename DerivedFI,
|
||||
typename DerivedP>
|
||||
IGL_INLINE void igl::blue_noise(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const typename DerivedV::Scalar r,
|
||||
Eigen::PlainObjectBase<DerivedB> & B,
|
||||
Eigen::PlainObjectBase<DerivedFI> & FI,
|
||||
Eigen::PlainObjectBase<DerivedP> & P)
|
||||
{
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
|
||||
// float+RowMajor is faster...
|
||||
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,3,Eigen::RowMajor> MatrixX3S;
|
||||
assert(V.cols() == 3 && "Only 3D embeddings allowed");
|
||||
// minimum radius
|
||||
const Scalar min_r = r;
|
||||
// cell size based on 3D distance
|
||||
// It works reasonably well (but is probably biased to use s=2*r/√3 here and
|
||||
// g=1 in the outer loop below.
|
||||
//
|
||||
// One thing to try would be to store a list in S (rather than a single point)
|
||||
// or equivalently a mask over M and just use M as a generic spatial hash
|
||||
// (with arbitrary size) and then tune its size (being careful to make g a
|
||||
// function of r and s; and removing the `if S=-1 checks`)
|
||||
const Scalar s = r/sqrt(3.0);
|
||||
|
||||
const double area =
|
||||
[&](){Eigen::VectorXd A;igl::doublearea(V,F,A);return A.array().sum()/2;}();
|
||||
// Circle packing in the plane has igl::PI*sqrt(3)/6 efficiency
|
||||
const double expected_number_of_points =
|
||||
area * (igl::PI * sqrt(3.0) / 6.0) / (igl::PI * min_r * min_r / 4.0);
|
||||
|
||||
// Make a uniform random sampling with 30*expected_number_of_points.
|
||||
const int nx = 30.0*expected_number_of_points;
|
||||
MatrixX3S X,XB;
|
||||
Eigen::VectorXi XFI;
|
||||
igl::random_points_on_mesh(nx,V,F,XB,XFI,X);
|
||||
|
||||
// Rescale so that s = 1
|
||||
Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> Xs =
|
||||
((X.rowwise()-X.colwise().minCoeff())/s).template cast<int>();
|
||||
const int w = Xs.maxCoeff()+1;
|
||||
{
|
||||
Eigen::VectorXi I;
|
||||
igl::sortrows(decltype(Xs)(Xs),true,Xs,I);
|
||||
igl::slice(decltype(X)(X),I,1,X);
|
||||
// These two could be spun off in their own thread.
|
||||
igl::slice(decltype(XB)(XB),I,1,XB);
|
||||
igl::slice(decltype(XFI)(XFI),I,1,XFI);
|
||||
}
|
||||
// Initialization
|
||||
std::unordered_map<BlueNoiseKeyType,std::vector<int> > M;
|
||||
std::unordered_map<BlueNoiseKeyType, int > S;
|
||||
// attempted to seed
|
||||
std::unordered_map<BlueNoiseKeyType, int > A;
|
||||
// Q: Too many?
|
||||
// A: Seems to help though.
|
||||
M.reserve(Xs.rows());
|
||||
S.reserve(Xs.rows());
|
||||
for(int i = 0;i<Xs.rows();i++)
|
||||
{
|
||||
BlueNoiseKeyType k = blue_noise_key(w,Xs(i,0),Xs(i,1),Xs(i,2));
|
||||
const auto Miter = M.find(k);
|
||||
if(Miter == M.end())
|
||||
{
|
||||
M.insert({k,{i}});
|
||||
}else
|
||||
{
|
||||
Miter->second.push_back(i);
|
||||
}
|
||||
S.emplace(k,-1);
|
||||
A.emplace(k,false);
|
||||
}
|
||||
|
||||
std::vector<int> active;
|
||||
// precompute r²
|
||||
// Q: is this necessary?
|
||||
const double rr = r*r;
|
||||
std::vector<int> collected;
|
||||
collected.reserve(2.0*expected_number_of_points);
|
||||
|
||||
auto Mouter = M.begin();
|
||||
// Just take the first point as the initial seed
|
||||
const auto initialize = [&]()->bool
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
if(Mouter == M.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const BlueNoiseKeyType k = Mouter->first;
|
||||
// Haven't placed in this cell yet
|
||||
if(S[k]<0)
|
||||
{
|
||||
if(activate(X,Xs,rr,-1,w,k,M,S,active)) return true;
|
||||
}
|
||||
Mouter++;
|
||||
}
|
||||
assert(false && "should not be reachable.");
|
||||
};
|
||||
|
||||
// important if mesh contains many connected components
|
||||
while(initialize())
|
||||
{
|
||||
while(active.size()>0)
|
||||
{
|
||||
step(X,Xs,rr,w,M,S,active,collected);
|
||||
}
|
||||
}
|
||||
{
|
||||
const int n = collected.size();
|
||||
P.resize(n,3);
|
||||
B.resize(n,3);
|
||||
FI.resize(n);
|
||||
for(int i = 0;i<n;i++)
|
||||
{
|
||||
const int c = collected[i];
|
||||
P.row(i) = X.row(c).template cast<typename DerivedP::Scalar>();
|
||||
B.row(i) = XB.row(c).template cast<typename DerivedB::Scalar>();
|
||||
FI(i) = XFI(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template void igl::blue_noise<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<float, -1, 3, 1, -1, 3>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::blue_noise<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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_BLUE_NOISE_H
|
||||
#define IGL_BLUE_NOISE_H
|
||||
#include "igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
// "Fast Poisson Disk Sampling in Arbitrary Dimensions" [Bridson 2007]
|
||||
//
|
||||
// For very dense samplings this is faster than (up to 2x) cyCodeBase's
|
||||
// implementation of "Sample Elimination for Generating Poisson Disk Sample
|
||||
// Sets" [Yuksel 2015]. YMMV
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by dim list of mesh vertex positions
|
||||
// F #F by 3 list of mesh triangle indices into rows of V
|
||||
// r Poisson disk radius (evaluated according to Euclidean distance on V)
|
||||
// Outputs:
|
||||
// B #P by 3 list of barycentric coordinates, ith row are coordinates of
|
||||
// ith sampled point in face FI(i)
|
||||
// FI #P list of indices into F
|
||||
// P #P by dim list of sample positions.
|
||||
// See also: random_points_on_mesh
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedB,
|
||||
typename DerivedFI,
|
||||
typename DerivedP>
|
||||
IGL_INLINE void blue_noise(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const typename DerivedV::Scalar r,
|
||||
Eigen::PlainObjectBase<DerivedB> & B,
|
||||
Eigen::PlainObjectBase<DerivedFI> & FI,
|
||||
Eigen::PlainObjectBase<DerivedP> & P);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "blue_noise.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -67,3 +67,77 @@ IGL_INLINE void igl::circulation(
|
||||
std::vector<int> N = circulation(e,ccw,EMAP,EF,EI);
|
||||
igl::list_to_matrix(N,vN);
|
||||
}
|
||||
|
||||
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,
|
||||
/*std::vector<int> & Ne,*/
|
||||
std::vector<int> & Nv,
|
||||
std::vector<int> & Nf)
|
||||
{
|
||||
//
|
||||
// for e --> (bf) and ccw=true
|
||||
//
|
||||
// c---d
|
||||
// / \ / \
|
||||
// a---b-e-f
|
||||
// \ / \ /
|
||||
// g---h
|
||||
//
|
||||
// // (might start with {bhf} depending on edge)
|
||||
// Ne = […] -> [fd db dc cb ca ab ag gb gh hb hf fb]
|
||||
// {upto cylic order}
|
||||
// Nf = […] -> [{bfd}, {bdc}, {bca}, {bag}, {bgh}, {bhf}]
|
||||
// Nv = [d c a g h f]
|
||||
//
|
||||
// prepare output
|
||||
//Ne.clear();Ne.reserve(2*10);
|
||||
Nv.clear();Nv.reserve(10);
|
||||
Nf.clear();Nf.reserve(10);
|
||||
const int m = EMAP.size()/3;
|
||||
assert(m*3 == EMAP.size());
|
||||
const auto & step = [&](
|
||||
const int e,
|
||||
const int ff,
|
||||
int & ne,
|
||||
//int & re,
|
||||
int & rv,
|
||||
int & nf)
|
||||
{
|
||||
assert((EF(e,1) == ff || EF(e,0) == ff) && "e should touch ff");
|
||||
//const int fside = EF(e,1)==ff?1:0;
|
||||
const int nside = EF(e,0)==ff?1:0;
|
||||
const int nv = EI(e,nside);
|
||||
// get next face
|
||||
nf = EF(e,nside);
|
||||
// get next edge
|
||||
const int dir = ccw?-1:1;
|
||||
rv = F(nf,nv);
|
||||
ne = EMAP(nf+m*((nv+dir+3)%3));
|
||||
//re = EMAP(nf+m*((nv+2*dir+3)%3));
|
||||
};
|
||||
// Always start with first face (ccw in step will be sure to turn right
|
||||
// direction)
|
||||
const int f0 = EF(e,0);
|
||||
int fi = f0;
|
||||
int ei = e;
|
||||
while(true)
|
||||
{
|
||||
int re,rv;
|
||||
step(ei,fi,ei/*,re*/,rv,fi);
|
||||
Nf.push_back(fi);
|
||||
//Ne.push_back(re);
|
||||
//Ne.push_back(ei);
|
||||
Nv.push_back(rv);
|
||||
// back to start?
|
||||
if(fi == f0)
|
||||
{
|
||||
assert(ei == e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,20 @@ namespace igl
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI,
|
||||
Eigen::VectorXi & vN);
|
||||
// Outputs:
|
||||
//// Ne 2*#Nf list of indices into E of "next" rim-spoke-rim-spoke-...
|
||||
// Nv #Nv list of "next" vertex indices
|
||||
// Nf #Nf list of face indices
|
||||
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,
|
||||
/*std::vector<int> & Ne,*/
|
||||
std::vector<int> & Nv,
|
||||
std::vector<int> & Nf);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
|
||||
+159
-180
@@ -8,6 +8,7 @@
|
||||
#include "collapse_edge.h"
|
||||
#include "circulation.h"
|
||||
#include "edge_collapse_is_valid.h"
|
||||
#include "decimate_trivial_callbacks.h"
|
||||
#include <vector>
|
||||
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
@@ -19,6 +20,32 @@ IGL_INLINE bool igl::collapse_edge(
|
||||
Eigen::VectorXi & EMAP,
|
||||
Eigen::MatrixXi & EF,
|
||||
Eigen::MatrixXi & EI,
|
||||
int & e1,
|
||||
int & e2,
|
||||
int & f1,
|
||||
int & f2)
|
||||
{
|
||||
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);
|
||||
return collapse_edge(
|
||||
e,p,Nsv,Nsf,Ndv,Ndf,V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
const int e,
|
||||
const Eigen::RowVectorXd & 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 & a_e1,
|
||||
int & a_e2,
|
||||
int & a_f1,
|
||||
@@ -34,17 +61,19 @@ IGL_INLINE bool igl::collapse_edge(
|
||||
const int s = eflip?E(e,1):E(e,0);
|
||||
const int d = eflip?E(e,0):E(e,1);
|
||||
|
||||
if(!edge_collapse_is_valid(e,F,E,EMAP,EF,EI))
|
||||
if(!edge_collapse_is_valid(Nsv,Ndv))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// OVERLOAD: caller may have just computed this
|
||||
//
|
||||
// Important to grab neighbors of d before monkeying with edges
|
||||
const std::vector<int> nV2Fd = circulation(e,!eflip,EMAP,EF,EI);
|
||||
const std::vector<int> & nV2Fd = (!eflip ? Nsf : Ndf);
|
||||
|
||||
// The following implementation strongly relies on s<d
|
||||
assert(s<d && "s should be less than d");
|
||||
// move source and destination to midpoint
|
||||
// move source and destination to placement
|
||||
V.row(s) = p;
|
||||
V.row(d) = p;
|
||||
|
||||
@@ -112,31 +141,40 @@ IGL_INLINE bool igl::collapse_edge(
|
||||
// make sense.
|
||||
//
|
||||
// Could actually skip first and last, since those are always the two
|
||||
// collpased faces.
|
||||
for(auto f : nV2Fd)
|
||||
// collpased faces. Nah, this is handled by (F(f,v) == d)
|
||||
//
|
||||
// Don't attempt to use Nde,Nse here because EMAP has changed
|
||||
{
|
||||
for(int v = 0;v<3;v++)
|
||||
int p1 = -1;
|
||||
for(auto f : nV2Fd)
|
||||
{
|
||||
if(F(f,v) == d)
|
||||
for(int v = 0;v<3;v++)
|
||||
{
|
||||
const int flip1 = (EF(EMAP(f+m*((v+1)%3)),0)==f)?1:0;
|
||||
const int flip2 = (EF(EMAP(f+m*((v+2)%3)),0)==f)?0:1;
|
||||
assert(
|
||||
E(EMAP(f+m*((v+1)%3)),flip1) == d ||
|
||||
E(EMAP(f+m*((v+1)%3)),flip1) == s);
|
||||
E(EMAP(f+m*((v+1)%3)),flip1) = s;
|
||||
assert(
|
||||
E(EMAP(f+m*((v+2)%3)),flip2) == d ||
|
||||
E(EMAP(f+m*((v+2)%3)),flip2) == s);
|
||||
E(EMAP(f+m*((v+2)%3)),flip2) = s;
|
||||
F(f,v) = s;
|
||||
break;
|
||||
if(F(f,v) == d)
|
||||
{
|
||||
const int e1 = EMAP(f+m*((v+1)%3));
|
||||
const int flip1 = (EF(e1,0)==f)?1:0;
|
||||
assert( E(e1,flip1) == d || E(e1,flip1) == s);
|
||||
E(e1,flip1) = s;
|
||||
const int e2 = EMAP(f+m*((v+2)%3));
|
||||
// Skip if we just handled this edge (claim: this will be all except
|
||||
// for the first non-trivial face)
|
||||
if(e2 != p1)
|
||||
{
|
||||
const int flip2 = (EF(e2,0)==f)?0:1;
|
||||
assert( E(e2,flip2) == d || E(e2,flip2) == s);
|
||||
E(e2,flip2) = s;
|
||||
}
|
||||
|
||||
F(f,v) = s;
|
||||
p1 = e1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally, "remove" this edge and its information
|
||||
kill_edge(e);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -155,168 +193,61 @@ IGL_INLINE bool igl::collapse_edge(
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
const std::function<void(
|
||||
const int,
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
double &,
|
||||
Eigen::RowVectorXd &)> & cost_and_placement,
|
||||
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,
|
||||
std::set<std::pair<double,int> > & Q,
|
||||
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C)
|
||||
{
|
||||
int e,e1,e2,f1,f2;
|
||||
const auto always_try = [](
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
) -> bool { return true;};
|
||||
const auto never_care = [](
|
||||
const Eigen::MatrixXd & , /*V*/
|
||||
const Eigen::MatrixXi & , /*F*/
|
||||
const Eigen::MatrixXi & , /*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & , /*EF*/
|
||||
const Eigen::MatrixXi & , /*EI*/
|
||||
const std::set<std::pair<double,int> > & , /*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
|
||||
const Eigen::MatrixXd & , /*C*/
|
||||
const int , /*e*/
|
||||
const int , /*e1*/
|
||||
const int , /*e2*/
|
||||
const int , /*f1*/
|
||||
const int , /*f2*/
|
||||
const bool /*collapsed*/
|
||||
)-> void { };
|
||||
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,Qit,C,e,e1,e2,f1,f2);
|
||||
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2);
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
const std::function<void(
|
||||
const int,
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
double &,
|
||||
Eigen::RowVectorXd &)> & cost_and_placement,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
)> & pre_collapse,
|
||||
const std::function<void(
|
||||
const Eigen::MatrixXd & , /*V*/
|
||||
const Eigen::MatrixXi & , /*F*/
|
||||
const Eigen::MatrixXi & , /*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & , /*EF*/
|
||||
const Eigen::MatrixXi & , /*EI*/
|
||||
const std::set<std::pair<double,int> > & , /*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
|
||||
const Eigen::MatrixXd & , /*C*/
|
||||
const int , /*e*/
|
||||
const int , /*e1*/
|
||||
const int , /*e2*/
|
||||
const int , /*f1*/
|
||||
const int , /*f2*/
|
||||
const bool /*collapsed*/
|
||||
)> & post_collapse,
|
||||
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,
|
||||
std::set<std::pair<double,int> > & Q,
|
||||
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
||||
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,Qit,C,e,e1,e2,f1,f2);
|
||||
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2);
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE bool igl::collapse_edge(
|
||||
const std::function<void(
|
||||
const int,
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
double &,
|
||||
Eigen::RowVectorXd &)> & cost_and_placement,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
)> & pre_collapse,
|
||||
const std::function<void(
|
||||
const Eigen::MatrixXd & , /*V*/
|
||||
const Eigen::MatrixXi & , /*F*/
|
||||
const Eigen::MatrixXi & , /*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & , /*EF*/
|
||||
const Eigen::MatrixXi & , /*EI*/
|
||||
const std::set<std::pair<double,int> > & , /*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
|
||||
const Eigen::MatrixXd & , /*C*/
|
||||
const int , /*e*/
|
||||
const int , /*e1*/
|
||||
const int , /*e2*/
|
||||
const int , /*f1*/
|
||||
const int , /*f2*/
|
||||
const bool /*collapsed*/
|
||||
)> & post_collapse,
|
||||
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,
|
||||
std::set<std::pair<double,int> > & Q,
|
||||
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C,
|
||||
int & e,
|
||||
int & e1,
|
||||
@@ -325,43 +256,82 @@ IGL_INLINE bool igl::collapse_edge(
|
||||
int & f2)
|
||||
{
|
||||
using namespace Eigen;
|
||||
if(Q.empty())
|
||||
using namespace igl;
|
||||
std::tuple<double,int,int> p;
|
||||
while(true)
|
||||
{
|
||||
// no edges to collapse
|
||||
return false;
|
||||
// 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.
|
||||
}
|
||||
std::pair<double,int> p = *(Q.begin());
|
||||
if(p.first == std::numeric_limits<double>::infinity())
|
||||
{
|
||||
// min cost edge is infinite cost
|
||||
return false;
|
||||
}
|
||||
Q.erase(Q.begin());
|
||||
e = p.second;
|
||||
Qit[e] = Q.end();
|
||||
std::vector<int> N = circulation(e, true,EMAP,EF,EI);
|
||||
std::vector<int> Nd = circulation(e,false,EMAP,EF,EI);
|
||||
N.insert(N.begin(),Nd.begin(),Nd.end());
|
||||
|
||||
// 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,Qit,C,e))
|
||||
if(pre_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e))
|
||||
{
|
||||
collapsed = collapse_edge(e,C.row(e),V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
|
||||
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,Qit,C,e,e1,e2,f1,f2,collapsed);
|
||||
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
|
||||
Q.erase(Qit[e1]);
|
||||
Qit[e1] = Q.end();
|
||||
Q.erase(Qit[e2]);
|
||||
Qit[e2] = Q.end();
|
||||
// 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
|
||||
for(auto n : N)
|
||||
//
|
||||
// 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 ||
|
||||
@@ -371,24 +341,33 @@ IGL_INLINE bool igl::collapse_edge(
|
||||
{
|
||||
// get edge id
|
||||
const int ei = EMAP(v*F.rows()+n);
|
||||
// erase old entry
|
||||
Q.erase(Qit[ei]);
|
||||
// compute cost and potential placement
|
||||
double cost;
|
||||
RowVectorXd place;
|
||||
cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place);
|
||||
// Replace in queue
|
||||
Qit[ei] = Q.insert(std::pair<double,int>(cost,ei)).first;
|
||||
C.row(ei) = place;
|
||||
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)
|
||||
p.first = std::numeric_limits<double>::infinity();
|
||||
Qit[e] = Q.insert(p).first;
|
||||
// Increment timestamp
|
||||
EQ(e)++;
|
||||
// Replace in queue
|
||||
Q.emplace(std::numeric_limits<double>::infinity(),e,EQ(e));
|
||||
}
|
||||
return collapsed;
|
||||
}
|
||||
|
||||
+42
-97
@@ -8,6 +8,8 @@
|
||||
#ifndef IGL_COLLAPSE_EDGE_H
|
||||
#define IGL_COLLAPSE_EDGE_H
|
||||
#include "igl_inline.h"
|
||||
#include "min_heap.h"
|
||||
#include "decimate_callback_types.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
@@ -55,6 +57,24 @@ namespace igl
|
||||
int & e2,
|
||||
int & f1,
|
||||
int & f2);
|
||||
// Inputs:
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const int e,
|
||||
const Eigen::RowVectorXd & 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);
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const int e,
|
||||
const Eigen::RowVectorXd & p,
|
||||
@@ -73,28 +93,19 @@ namespace igl
|
||||
// **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.
|
||||
// Q queue containing pairs of costs and edge indices
|
||||
// Qit list of iterators so that Qit[e] --> iterator of edge e in Q
|
||||
// Q queue containing pairs of costs and edge indices and insertion "time"
|
||||
// EQ #E list of "time" of last time pushed into Q
|
||||
// C #E by dim list of stored placements
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const std::function<void(
|
||||
const int,
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
double &,
|
||||
Eigen::RowVectorXd &)> & cost_and_placement,
|
||||
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,
|
||||
std::set<std::pair<double,int> > & Q,
|
||||
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C);
|
||||
// Inputs:
|
||||
// pre_collapse callback called with index of edge whose collapse is about
|
||||
@@ -105,103 +116,37 @@ namespace igl
|
||||
// post_collapse callback called with index of edge whose collapse was
|
||||
// just attempted and a flag revealing whether this was successful.
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const std::function<void(
|
||||
const int,
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
double &,
|
||||
Eigen::RowVectorXd &)> & cost_and_placement,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
)> & pre_collapse,
|
||||
const std::function<void(
|
||||
const Eigen::MatrixXd & , /*V*/
|
||||
const Eigen::MatrixXi & , /*F*/
|
||||
const Eigen::MatrixXi & , /*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & , /*EF*/
|
||||
const Eigen::MatrixXi & , /*EI*/
|
||||
const std::set<std::pair<double,int> > & , /*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
|
||||
const Eigen::MatrixXd & , /*C*/
|
||||
const int , /*e*/
|
||||
const int , /*e1*/
|
||||
const int , /*e2*/
|
||||
const int , /*f1*/
|
||||
const int , /*f2*/
|
||||
const bool /*collapsed*/
|
||||
)> & post_collapse,
|
||||
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,
|
||||
std::set<std::pair<double,int> > & Q,
|
||||
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C);
|
||||
|
||||
// Outputs:
|
||||
// e index into E of attempted collapsed edge. Set to -1 if Q is empty or
|
||||
// contains only infinite cost edges.
|
||||
// e1 index into E of edge collpased on left.
|
||||
// e2 index into E of edge collpased on right.
|
||||
// f1 index into F of face collpased on left.
|
||||
// f2 index into F of face collpased on right.
|
||||
IGL_INLINE bool collapse_edge(
|
||||
const std::function<void(
|
||||
const int,
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
double &,
|
||||
Eigen::RowVectorXd &)> & cost_and_placement,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
)> & pre_collapse,
|
||||
const std::function<void(
|
||||
const Eigen::MatrixXd & , /*V*/
|
||||
const Eigen::MatrixXi & , /*F*/
|
||||
const Eigen::MatrixXi & , /*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & , /*EF*/
|
||||
const Eigen::MatrixXi & , /*EI*/
|
||||
const std::set<std::pair<double,int> > & , /*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
|
||||
const Eigen::MatrixXd & , /*C*/
|
||||
const int , /*e*/
|
||||
const int , /*e1*/
|
||||
const int , /*e2*/
|
||||
const int , /*f1*/
|
||||
const int , /*f2*/
|
||||
const bool /*collapsed*/
|
||||
)> & post_collapse,
|
||||
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,
|
||||
std::set<std::pair<double,int> > & Q,
|
||||
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
||||
igl::min_heap< std::tuple<double,int,int> > & Q,
|
||||
Eigen::VectorXi & EQ,
|
||||
Eigen::MatrixXd & C,
|
||||
int & e,
|
||||
int & e1,
|
||||
|
||||
@@ -49,6 +49,8 @@ igl::copyleft::cgal::assign(
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
|
||||
@@ -96,6 +96,8 @@ IGL_INLINE void igl::copyleft::cgal::convex_hull(
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
|
||||
@@ -48,6 +48,8 @@ IGL_INLINE void igl::copyleft::cgal::mesh_to_cgal_triangle_list(
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Simple_cartesian<double> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
|
||||
@@ -382,6 +382,8 @@ IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::minkowski_sum<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, 3, 1, double, 3, 1, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::minkowski_sum<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Lazy_exact_nt<CGAL::Gmpq>, 3, 1, CGAL::Lazy_exact_nt<CGAL::Gmpq>, 3, 1, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 3, 1, 1, 3> const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::minkowski_sum<
|
||||
|
||||
@@ -133,7 +133,10 @@ IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance(
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Simple_cartesian<double>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Simple_cartesian<double>, CGAL::AABB_triangle_primitive<CGAL::Simple_cartesian<double>, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> > const&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::point_mesh_squared_distance_precompute<CGAL::Simple_cartesian<double>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Simple_cartesian<double>, CGAL::AABB_triangle_primitive<CGAL::Simple_cartesian<double>, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> >&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >&);
|
||||
template void igl::copyleft::cgal::point_mesh_squared_distance_precompute<CGAL::Simple_cartesian<double>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Simple_cartesian<double>, CGAL::AABB_triangle_primitive<CGAL::Simple_cartesian<double>, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> >&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >&);
|
||||
#endif
|
||||
|
||||
@@ -61,9 +61,11 @@ IGL_INLINE void igl::copyleft::cgal::polyhedron_to_mesh(
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0,-1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0,-1, -1> >&);
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace igl
|
||||
// vertices #V by 3 list of mesh vertex positions
|
||||
// faces #F by 3 list of mesh triangle indices
|
||||
//
|
||||
// See also: igl::marching_cubes
|
||||
template <typename DerivedValues, typename DerivedPoints, typename DerivedVertices, typename DerivedFaces>
|
||||
IGL_INLINE void marching_cubes(
|
||||
const Eigen::MatrixBase<DerivedValues> &values,
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
#include "offset_surface.h"
|
||||
#include "marching_cubes.h"
|
||||
#include "../voxel_grid.h"
|
||||
#include "../signed_distance.h"
|
||||
#include "../flood_fill.h"
|
||||
#include <cassert>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename isolevelType,
|
||||
typename DerivedSV,
|
||||
typename DerivedSF,
|
||||
typename DerivedGV,
|
||||
typename Derivedside,
|
||||
typename DerivedS>
|
||||
void igl::copyleft::offset_surface(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const isolevelType isolevel,
|
||||
const typename Derivedside::Scalar s,
|
||||
const SignedDistanceType & signed_distance_type,
|
||||
Eigen::PlainObjectBase<DerivedSV> & SV,
|
||||
Eigen::PlainObjectBase<DerivedSF> & SF,
|
||||
Eigen::PlainObjectBase<DerivedGV> & GV,
|
||||
Eigen::PlainObjectBase<Derivedside> & side,
|
||||
Eigen::PlainObjectBase<DerivedS> & S)
|
||||
{
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
{
|
||||
Eigen::AlignedBox<Scalar,3> box;
|
||||
typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
|
||||
assert(V.cols() == 3 && "V must contain positions in 3D");
|
||||
RowVector3S min_ext = V.colwise().minCoeff().array() - isolevel;
|
||||
RowVector3S max_ext = V.colwise().maxCoeff().array() + isolevel;
|
||||
box.extend(min_ext.transpose());
|
||||
box.extend(max_ext.transpose());
|
||||
igl::voxel_grid(box,s,1,GV,side);
|
||||
}
|
||||
|
||||
const Scalar h =
|
||||
(GV.col(0).maxCoeff()-GV.col(0).minCoeff())/((Scalar)(side(0)-1));
|
||||
const Scalar lower_bound = isolevel-sqrt(3.0)*h;
|
||||
const Scalar upper_bound = isolevel+sqrt(3.0)*h;
|
||||
{
|
||||
Eigen::Matrix<Index,Eigen::Dynamic,1> I;
|
||||
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> C,N;
|
||||
igl::signed_distance(
|
||||
GV,V,F,signed_distance_type,lower_bound,upper_bound,S,I,C,N);
|
||||
}
|
||||
igl::flood_fill(side,S);
|
||||
|
||||
DerivedS SS = S.array()-isolevel;
|
||||
igl::copyleft::marching_cubes(SS,GV,side(0),side(1),side(2),SV,SF);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, double, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::offset_surface<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, float, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -1,54 +0,0 @@
|
||||
#ifndef IGL_COPYLEFT_OFFSET_SURFACE_H
|
||||
#define IGL_COPYLEFT_OFFSET_SURFACE_H
|
||||
#include "../igl_inline.h"
|
||||
#include "../signed_distance.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
// Compute a triangulated offset surface using matching cubes on a grid of
|
||||
// signed distance values from the input triangle mesh.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertex positions
|
||||
// F #F by 3 list of mesh triangle indices into V
|
||||
// isolevel iso level to extract (signed distance: negative inside)
|
||||
// s number of grid cells along longest side (controls resolution)
|
||||
// signed_distance_type type of signing to use (see
|
||||
// ../signed_distance.h)
|
||||
// Outputs:
|
||||
// SV #SV by 3 list of output surface mesh vertex positions
|
||||
// SF #SF by 3 list of output mesh triangle indices into SV
|
||||
// GV #GV=side(0)*side(1)*side(2) by 3 list of grid cell centers
|
||||
// side list of number of grid cells in x, y, and z directions
|
||||
// S #GV by 3 list of signed distance values _near_ `isolevel` ("far"
|
||||
// from `isolevel` these values are incorrect)
|
||||
//
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename isolevelType,
|
||||
typename DerivedSV,
|
||||
typename DerivedSF,
|
||||
typename DerivedGV,
|
||||
typename Derivedside,
|
||||
typename DerivedS>
|
||||
void offset_surface(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const isolevelType isolevel,
|
||||
const typename Derivedside::Scalar s,
|
||||
const SignedDistanceType & signed_distance_type,
|
||||
Eigen::PlainObjectBase<DerivedSV> & SV,
|
||||
Eigen::PlainObjectBase<DerivedSF> & SF,
|
||||
Eigen::PlainObjectBase<DerivedGV> & GV,
|
||||
Eigen::PlainObjectBase<Derivedside> & side,
|
||||
Eigen::PlainObjectBase<DerivedS> & S);
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "offset_surface.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef IGL_COPYLEFT_SWEPT_VOLUME_H
|
||||
#define IGL_COPYLEFT_SWEPT_VOLUME_H
|
||||
#include "../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
// Compute the surface of the swept volume of a solid object with surface
|
||||
// (V,F) mesh under going rigid motion.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh positions in reference pose
|
||||
// F #F by 3 list of mesh indices into V
|
||||
// transform function handle so that transform(t) returns the rigid
|
||||
// transformation at time t∈[0,1]
|
||||
// steps number of time steps: steps=3 --> t∈{0,0.5,1}
|
||||
// grid_res number of grid cells on the longest side containing the
|
||||
// motion (isolevel+1 cells will also be added on each side as padding)
|
||||
// isolevel distance level to be contoured as swept volume
|
||||
// Outputs:
|
||||
// SV #SV by 3 list of mesh positions of the swept surface
|
||||
// SF #SF by 3 list of mesh faces into SV
|
||||
IGL_INLINE void swept_volume(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
const std::function<Eigen::Affine3d(const double t)> & transform,
|
||||
const size_t steps,
|
||||
const size_t grid_res,
|
||||
const size_t isolevel,
|
||||
Eigen::MatrixXd & SV,
|
||||
Eigen::MatrixXi & SF);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "swept_volume.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -13,120 +13,6 @@
|
||||
// STL includes
|
||||
#include <iostream>
|
||||
|
||||
IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
|
||||
const tetgenio & out,
|
||||
std::vector<std::vector<REAL > > & V,
|
||||
std::vector<std::vector<int> > & T,
|
||||
std::vector<std::vector<int > > & F,
|
||||
std::vector<std::vector<REAL > >& R,
|
||||
std::vector<std::vector<int > >& N,
|
||||
std::vector<std::vector<int > >& PT,
|
||||
std::vector<std::vector<int > >& FT,
|
||||
size_t & nR )
|
||||
{
|
||||
using namespace std;
|
||||
// process points
|
||||
if(out.pointlist == NULL)
|
||||
{
|
||||
cerr<<"^tetgenio_to_tetmesh Error: point list is NULL\n"<<endl;
|
||||
return false;
|
||||
}
|
||||
V.resize(out.numberofpoints,vector<REAL>(3));
|
||||
// loop over points
|
||||
for(int i = 0;i < out.numberofpoints; i++)
|
||||
{
|
||||
V[i][0] = out.pointlist[i*3+0];
|
||||
V[i][1] = out.pointlist[i*3+1];
|
||||
V[i][2] = out.pointlist[i*3+2];
|
||||
}
|
||||
|
||||
// process tets
|
||||
if(out.tetrahedronlist == NULL)
|
||||
{
|
||||
cerr<<"^tetgenio_to_tetmesh Error: tet list is NULL\n"<<endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// When would this not be 4?
|
||||
assert(out.numberofcorners == 4);
|
||||
T.resize(out.numberoftetrahedra,vector<int>(out.numberofcorners));
|
||||
int min_index = 1e7;
|
||||
int max_index = -1e7;
|
||||
// loop over tetrahedra
|
||||
for(int i = 0; i < out.numberoftetrahedra; i++)
|
||||
{
|
||||
for(int j = 0; j<out.numberofcorners; j++)
|
||||
{
|
||||
int index = out.tetrahedronlist[i * out.numberofcorners + j];
|
||||
T[i][j] = index;
|
||||
min_index = (min_index > index ? index : min_index);
|
||||
max_index = (max_index < index ? index : max_index);
|
||||
}
|
||||
}
|
||||
|
||||
assert(min_index >= 0);
|
||||
assert(max_index >= 0);
|
||||
assert(max_index < (int)V.size());
|
||||
|
||||
cout<<out.numberoftrifaces<<endl;
|
||||
|
||||
// When would this not be 4?
|
||||
F.clear();
|
||||
// loop over tetrahedra
|
||||
for(int i = 0; i < out.numberoftrifaces; i++)
|
||||
{
|
||||
if(out.trifacemarkerlist[i]>=0)
|
||||
{
|
||||
vector<int> face(3);
|
||||
for(int j = 0; j<3; j++)
|
||||
{
|
||||
face[j] = out.trifacelist[i * 3 + j];
|
||||
}
|
||||
F.push_back(face);
|
||||
}
|
||||
}
|
||||
|
||||
R.resize(out.numberoftetrahedra, vector<REAL>(1));
|
||||
unordered_map<REAL, REAL> hashUniqueRegions;
|
||||
for(size_t i = 0; i < out.numberoftetrahedra; i++)
|
||||
{
|
||||
R[i][0] = out.tetrahedronattributelist[i];
|
||||
hashUniqueRegions[R[i][0]] = i;
|
||||
}
|
||||
// extract region marks
|
||||
nR = hashUniqueRegions.size();
|
||||
|
||||
// extract neighbor list
|
||||
N.resize(out.numberoftetrahedra, vector<int>(4));
|
||||
for (size_t i = 0; i < out.numberoftetrahedra; i++)
|
||||
{
|
||||
for (size_t j = 0; j < 4; j++)
|
||||
N[i][j] = out.neighborlist[i * 4 + j];
|
||||
}
|
||||
|
||||
// extract point 2 tetrahedron list
|
||||
PT.resize(out.numberofpoints, vector<int>(1));
|
||||
for (size_t i = 0; i < out.numberofpoints; i++)
|
||||
{
|
||||
PT[i][0] = out.point2tetlist[i];
|
||||
}
|
||||
|
||||
//extract face to tetrahedron list
|
||||
FT.resize(out.numberoftrifaces, vector<int>(2));
|
||||
int triface;
|
||||
|
||||
for (size_t i = 0; i < out.numberoftrifaces; i++)
|
||||
{
|
||||
for (size_t j = 0; j < 2; j++)
|
||||
{
|
||||
FT[i][j] = out.face2tetlist[0];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
|
||||
const tetgenio & out,
|
||||
std::vector<std::vector<REAL > > & V,
|
||||
@@ -196,12 +82,13 @@ IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename DerivedV, typename DerivedT>
|
||||
IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
|
||||
const tetgenio & out,
|
||||
std::vector<std::vector<REAL > > & V,
|
||||
std::vector<std::vector<int> > & T)
|
||||
Eigen::PlainObjectBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedT>& T)
|
||||
{
|
||||
std::vector<std::vector<int> > F;
|
||||
Eigen::Matrix<typename DerivedT::Scalar,Eigen::Dynamic,3> F;
|
||||
return tetgenio_to_tetmesh(out,V,T,F);
|
||||
}
|
||||
|
||||
@@ -242,16 +129,151 @@ IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename DerivedV, typename DerivedT>
|
||||
IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
|
||||
const tetgenio & out,
|
||||
Eigen::PlainObjectBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedT>& T)
|
||||
std::vector<std::vector<REAL > > & V,
|
||||
std::vector<std::vector<int> > & T)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedT::Scalar,Eigen::Dynamic,3> F;
|
||||
std::vector<std::vector<int> > F;
|
||||
return tetgenio_to_tetmesh(out,V,T,F);
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
|
||||
const tetgenio & out,
|
||||
std::vector<std::vector<REAL > > & V,
|
||||
std::vector<std::vector<int> > & T,
|
||||
std::vector<std::vector<int > > & F,
|
||||
std::vector<std::vector<REAL > >& R,
|
||||
std::vector<std::vector<int > >& N,
|
||||
std::vector<std::vector<int > >& PT,
|
||||
std::vector<std::vector<int > >& FT,
|
||||
size_t & nR )
|
||||
{
|
||||
using namespace std;
|
||||
// process points
|
||||
if(out.pointlist == NULL)
|
||||
{
|
||||
cerr<<"^tetgenio_to_tetmesh Error: point list is NULL\n"<<endl;
|
||||
return false;
|
||||
}
|
||||
V.resize(out.numberofpoints,vector<REAL>(3));
|
||||
// loop over points
|
||||
for(int i = 0;i < out.numberofpoints; i++)
|
||||
{
|
||||
V[i][0] = out.pointlist[i*3+0];
|
||||
V[i][1] = out.pointlist[i*3+1];
|
||||
V[i][2] = out.pointlist[i*3+2];
|
||||
}
|
||||
|
||||
// process tets
|
||||
if(out.tetrahedronlist == NULL)
|
||||
{
|
||||
cerr<<"^tetgenio_to_tetmesh Error: tet list is NULL\n"<<endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// When would this not be 4?
|
||||
assert(out.numberofcorners == 4);
|
||||
T.resize(out.numberoftetrahedra,vector<int>(out.numberofcorners));
|
||||
int min_index = 1e7;
|
||||
int max_index = -1e7;
|
||||
// loop over tetrahedra
|
||||
for(int i = 0; i < out.numberoftetrahedra; i++)
|
||||
{
|
||||
for(int j = 0; j<out.numberofcorners; j++)
|
||||
{
|
||||
int index = out.tetrahedronlist[i * out.numberofcorners + j];
|
||||
T[i][j] = index;
|
||||
min_index = (min_index > index ? index : min_index);
|
||||
max_index = (max_index < index ? index : max_index);
|
||||
}
|
||||
}
|
||||
|
||||
assert(min_index >= 0);
|
||||
assert(max_index >= 0);
|
||||
assert(max_index < (int)V.size());
|
||||
|
||||
// When would this not be 4?
|
||||
F.clear();
|
||||
// loop over tetrahedra
|
||||
for(int i = 0; i < out.numberoftrifaces; i++)
|
||||
{
|
||||
if(out.trifacemarkerlist[i]>=0)
|
||||
{
|
||||
vector<int> face(3);
|
||||
for(int j = 0; j<3; j++)
|
||||
{
|
||||
face[j] = out.trifacelist[i * 3 + j];
|
||||
}
|
||||
F.push_back(face);
|
||||
}
|
||||
}
|
||||
|
||||
if(out.tetrahedronattributelist)
|
||||
{
|
||||
R.resize(out.numberoftetrahedra, vector<REAL>(1));
|
||||
unordered_map<REAL, REAL> hashUniqueRegions;
|
||||
for(size_t i = 0; i < out.numberoftetrahedra; i++)
|
||||
{
|
||||
R[i][0] = out.tetrahedronattributelist[i];
|
||||
hashUniqueRegions[R[i][0]] = i;
|
||||
}
|
||||
// extract region marks
|
||||
nR = hashUniqueRegions.size();
|
||||
}else
|
||||
{
|
||||
R.clear();
|
||||
nR = 0;
|
||||
}
|
||||
|
||||
// extract neighbor list
|
||||
if(out.neighborlist)
|
||||
{
|
||||
N.resize(out.numberoftetrahedra, vector<int>(4));
|
||||
for (size_t i = 0; i < out.numberoftetrahedra; i++)
|
||||
{
|
||||
for (size_t j = 0; j < 4; j++)
|
||||
N[i][j] = out.neighborlist[i * 4 + j];
|
||||
}
|
||||
}else
|
||||
{
|
||||
N.clear();
|
||||
}
|
||||
|
||||
// extract point 2 tetrahedron list
|
||||
if(out.point2tetlist)
|
||||
{
|
||||
PT.resize(out.numberofpoints, vector<int>(1));
|
||||
for (size_t i = 0; i < out.numberofpoints; i++)
|
||||
{
|
||||
PT[i][0] = out.point2tetlist[i];
|
||||
}
|
||||
}else
|
||||
{
|
||||
PT.clear();
|
||||
}
|
||||
|
||||
//extract face to tetrahedron list
|
||||
if(out.face2tetlist)
|
||||
{
|
||||
FT.resize(out.numberoftrifaces, vector<int>(2));
|
||||
int triface;
|
||||
for (size_t i = 0; i < out.numberoftrifaces; i++)
|
||||
{
|
||||
for (size_t j = 0; j < 2; j++)
|
||||
{
|
||||
FT[i][j] = out.face2tetlist[0];
|
||||
}
|
||||
}
|
||||
}else
|
||||
{
|
||||
FT.clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::copyleft::tetgen::tetgenio_to_tetmesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(tetgenio const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace igl
|
||||
std::vector<std::vector<REAL > > & V,
|
||||
std::vector<std::vector<int> > & T,
|
||||
std::vector<std::vector<int> > & F);
|
||||
|
||||
IGL_INLINE bool tetgenio_to_tetmesh(
|
||||
const tetgenio & out,
|
||||
std::vector<std::vector<REAL > > & V,
|
||||
@@ -50,6 +51,7 @@ namespace igl
|
||||
Eigen::PlainObjectBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedT>& T,
|
||||
Eigen::PlainObjectBase<DerivedF>& F);
|
||||
|
||||
template <typename DerivedV, typename DerivedT>
|
||||
IGL_INLINE bool tetgenio_to_tetmesh(
|
||||
const tetgenio & out,
|
||||
|
||||
@@ -18,6 +18,200 @@
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
|
||||
const std::vector<std::vector<REAL > > & V,
|
||||
const std::vector<std::vector<int> > & F,
|
||||
const std::string switches,
|
||||
std::vector<std::vector<REAL > > & TV,
|
||||
std::vector<std::vector<int > > & TT,
|
||||
std::vector<std::vector<int> > & TF)
|
||||
{
|
||||
using namespace std;
|
||||
tetgenio in,out;
|
||||
bool success;
|
||||
success = mesh_to_tetgenio(V,F,in);
|
||||
if(!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
try
|
||||
{
|
||||
char * cswitches = new char[switches.size() + 1];
|
||||
std::strcpy(cswitches,switches.c_str());
|
||||
::tetrahedralize(cswitches,&in, &out);
|
||||
delete[] cswitches;
|
||||
}catch(int e)
|
||||
{
|
||||
cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"<<endl;
|
||||
return 1;
|
||||
}
|
||||
if(out.numberoftetrahedra == 0)
|
||||
{
|
||||
cerr<<"^"<<__FUNCTION__<<": Tetgen failed to create tets"<<endl;
|
||||
return 2;
|
||||
}
|
||||
success = tetgenio_to_tetmesh(out,TV,TT,TF);
|
||||
if(!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
boundary_facets(TT,TF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedTV,
|
||||
typename DerivedTT,
|
||||
typename DerivedTF>
|
||||
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const std::string switches,
|
||||
Eigen::PlainObjectBase<DerivedTV>& TV,
|
||||
Eigen::PlainObjectBase<DerivedTT>& TT,
|
||||
Eigen::PlainObjectBase<DerivedTF>& TF)
|
||||
{
|
||||
using namespace std;
|
||||
vector<vector<REAL> > vV,vTV;
|
||||
vector<vector<int> > vF,vTT,vTF;
|
||||
matrix_to_list(V,vV);
|
||||
matrix_to_list(F,vF);
|
||||
int e = tetrahedralize(vV,vF,switches,vTV,vTT,vTF);
|
||||
if(e == 0)
|
||||
{
|
||||
bool TV_rect = list_to_matrix(vTV,TV);
|
||||
if(!TV_rect)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
bool TT_rect = list_to_matrix(vTT,TT);
|
||||
if(!TT_rect)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
bool TF_rect = list_to_matrix(vTF,TF);
|
||||
if(!TF_rect)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVM,
|
||||
typename DerivedFM,
|
||||
typename DerivedTV,
|
||||
typename DerivedTT,
|
||||
typename DerivedTF,
|
||||
typename DerivedTM>
|
||||
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedVM>& VM,
|
||||
const Eigen::MatrixBase<DerivedFM>& FM,
|
||||
const std::string switches,
|
||||
Eigen::PlainObjectBase<DerivedTV>& TV,
|
||||
Eigen::PlainObjectBase<DerivedTT>& TT,
|
||||
Eigen::PlainObjectBase<DerivedTF>& TF,
|
||||
Eigen::PlainObjectBase<DerivedTM>& TM)
|
||||
{
|
||||
using namespace std;
|
||||
vector<vector<REAL> > vV,vTV;
|
||||
vector<vector<int> > vF,vTT,vTF;
|
||||
vector<int> vTM;
|
||||
|
||||
matrix_to_list(V,vV);
|
||||
matrix_to_list(F,vF);
|
||||
vector<int> vVM = matrix_to_list(VM);
|
||||
vector<int> vFM = matrix_to_list(FM);
|
||||
int e = tetrahedralize(vV,vF,vVM,vFM,switches,vTV,vTT,vTF,vTM);
|
||||
if(e == 0)
|
||||
{
|
||||
bool TV_rect = list_to_matrix(vTV,TV);
|
||||
if(!TV_rect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool TT_rect = list_to_matrix(vTT,TT);
|
||||
if(!TT_rect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool TF_rect = list_to_matrix(vTF,TF);
|
||||
if(!TF_rect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool TM_rect = list_to_matrix(vTM,TM);
|
||||
if(!TM_rect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
|
||||
const std::vector<std::vector<REAL > > & V,
|
||||
const std::vector<std::vector<int> > & F,
|
||||
const std::vector<int> & VM,
|
||||
const std::vector<int> & FM,
|
||||
const std::string switches,
|
||||
std::vector<std::vector<REAL > > & TV,
|
||||
std::vector<std::vector<int > > & TT,
|
||||
std::vector<std::vector<int> > & TF,
|
||||
std::vector<int> & TM)
|
||||
{
|
||||
using namespace std;
|
||||
tetgenio in,out;
|
||||
bool success;
|
||||
success = mesh_to_tetgenio(V,F,in);
|
||||
if(!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
in.pointmarkerlist = new int[VM.size()];
|
||||
for (int i = 0; i < VM.size(); ++i) {
|
||||
in.pointmarkerlist[i] = VM[i];
|
||||
}
|
||||
// These have already been created in mesh_to_tetgenio.
|
||||
// Reset them here.
|
||||
for (int i = 0; i < FM.size(); ++i) {
|
||||
in.facetmarkerlist[i] = FM[i];
|
||||
}
|
||||
try
|
||||
{
|
||||
char * cswitches = new char[switches.size() + 1];
|
||||
std::strcpy(cswitches,switches.c_str());
|
||||
::tetrahedralize(cswitches,&in, &out);
|
||||
delete[] cswitches;
|
||||
}catch(int e)
|
||||
{
|
||||
cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"<<endl;
|
||||
return 1;
|
||||
}
|
||||
if(out.numberoftetrahedra == 0)
|
||||
{
|
||||
cerr<<"^"<<__FUNCTION__<<": Tetgen failed to create tets"<<endl;
|
||||
return 2;
|
||||
}
|
||||
success = tetgenio_to_tetmesh(out,TV,TT,TF);
|
||||
if(!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TM.resize(out.numberofpoints);
|
||||
for (int i = 0; i < out.numberofpoints; ++i) {
|
||||
TM[i] = out.pointmarkerlist[i];
|
||||
}
|
||||
boundary_facets(TT,TF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
|
||||
const std::vector<std::vector<REAL > > & V,
|
||||
@@ -143,203 +337,10 @@ IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
|
||||
return e;
|
||||
}
|
||||
|
||||
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
|
||||
const std::vector<std::vector<REAL > > & V,
|
||||
const std::vector<std::vector<int> > & F,
|
||||
const std::string switches,
|
||||
std::vector<std::vector<REAL > > & TV,
|
||||
std::vector<std::vector<int > > & TT,
|
||||
std::vector<std::vector<int> > & TF)
|
||||
{
|
||||
using namespace std;
|
||||
tetgenio in,out;
|
||||
bool success;
|
||||
success = mesh_to_tetgenio(V,F,in);
|
||||
if(!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
try
|
||||
{
|
||||
char * cswitches = new char[switches.size() + 1];
|
||||
std::strcpy(cswitches,switches.c_str());
|
||||
::tetrahedralize(cswitches,&in, &out);
|
||||
delete[] cswitches;
|
||||
}catch(int e)
|
||||
{
|
||||
cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"<<endl;
|
||||
return 1;
|
||||
}
|
||||
if(out.numberoftetrahedra == 0)
|
||||
{
|
||||
cerr<<"^"<<__FUNCTION__<<": Tetgen failed to create tets"<<endl;
|
||||
return 2;
|
||||
}
|
||||
success = tetgenio_to_tetmesh(out,TV,TT,TF);
|
||||
if(!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
boundary_facets(TT,TF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedTV,
|
||||
typename DerivedTT,
|
||||
typename DerivedTF>
|
||||
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const std::string switches,
|
||||
Eigen::PlainObjectBase<DerivedTV>& TV,
|
||||
Eigen::PlainObjectBase<DerivedTT>& TT,
|
||||
Eigen::PlainObjectBase<DerivedTF>& TF)
|
||||
{
|
||||
using namespace std;
|
||||
vector<vector<REAL> > vV,vTV;
|
||||
vector<vector<int> > vF,vTT,vTF;
|
||||
matrix_to_list(V,vV);
|
||||
matrix_to_list(F,vF);
|
||||
int e = tetrahedralize(vV,vF,switches,vTV,vTT,vTF);
|
||||
if(e == 0)
|
||||
{
|
||||
bool TV_rect = list_to_matrix(vTV,TV);
|
||||
if(!TV_rect)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
bool TT_rect = list_to_matrix(vTT,TT);
|
||||
if(!TT_rect)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
bool TF_rect = list_to_matrix(vTF,TF);
|
||||
if(!TF_rect)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVM,
|
||||
typename DerivedFM,
|
||||
typename DerivedTV,
|
||||
typename DerivedTT,
|
||||
typename DerivedTF,
|
||||
typename DerivedTM>
|
||||
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedVM>& VM,
|
||||
const Eigen::MatrixBase<DerivedFM>& FM,
|
||||
const std::string switches,
|
||||
Eigen::PlainObjectBase<DerivedTV>& TV,
|
||||
Eigen::PlainObjectBase<DerivedTT>& TT,
|
||||
Eigen::PlainObjectBase<DerivedTF>& TF,
|
||||
Eigen::PlainObjectBase<DerivedTM>& TM)
|
||||
{
|
||||
using namespace std;
|
||||
vector<vector<REAL> > vV,vTV;
|
||||
vector<vector<int> > vF,vTT,vTF;
|
||||
vector<int> vTM;
|
||||
|
||||
matrix_to_list(V,vV);
|
||||
matrix_to_list(F,vF);
|
||||
vector<int> vVM = matrix_to_list(VM);
|
||||
vector<int> vFM = matrix_to_list(FM);
|
||||
int e = tetrahedralize(vV,vF,vVM,vFM,switches,vTV,vTT,vTF,vTM);
|
||||
if(e == 0)
|
||||
{
|
||||
bool TV_rect = list_to_matrix(vTV,TV);
|
||||
if(!TV_rect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool TT_rect = list_to_matrix(vTT,TT);
|
||||
if(!TT_rect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool TF_rect = list_to_matrix(vTF,TF);
|
||||
if(!TF_rect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool TM_rect = list_to_matrix(vTM,TM);
|
||||
if(!TM_rect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
|
||||
const std::vector<std::vector<REAL > > & V,
|
||||
const std::vector<std::vector<int> > & F,
|
||||
const std::vector<int> & VM,
|
||||
const std::vector<int> & FM,
|
||||
const std::string switches,
|
||||
std::vector<std::vector<REAL > > & TV,
|
||||
std::vector<std::vector<int > > & TT,
|
||||
std::vector<std::vector<int> > & TF,
|
||||
std::vector<int> & TM)
|
||||
{
|
||||
using namespace std;
|
||||
tetgenio in,out;
|
||||
bool success;
|
||||
success = mesh_to_tetgenio(V,F,in);
|
||||
if(!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
in.pointmarkerlist = new int[VM.size()];
|
||||
for (int i = 0; i < VM.size(); ++i) {
|
||||
in.pointmarkerlist[i] = VM[i];
|
||||
}
|
||||
// These have already been created in mesh_to_tetgenio.
|
||||
// Reset them here.
|
||||
for (int i = 0; i < FM.size(); ++i) {
|
||||
in.facetmarkerlist[i] = FM[i];
|
||||
}
|
||||
try
|
||||
{
|
||||
char * cswitches = new char[switches.size() + 1];
|
||||
std::strcpy(cswitches,switches.c_str());
|
||||
::tetrahedralize(cswitches,&in, &out);
|
||||
delete[] cswitches;
|
||||
}catch(int e)
|
||||
{
|
||||
cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"<<endl;
|
||||
return 1;
|
||||
}
|
||||
if(out.numberoftetrahedra == 0)
|
||||
{
|
||||
cerr<<"^"<<__FUNCTION__<<": Tetgen failed to create tets"<<endl;
|
||||
return 2;
|
||||
}
|
||||
success = tetgenio_to_tetmesh(out,TV,TT,TF);
|
||||
if(!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TM.resize(out.numberofpoints);
|
||||
for (int i = 0; i < out.numberofpoints; ++i) {
|
||||
TM[i] = out.pointmarkerlist[i];
|
||||
}
|
||||
boundary_facets(TT,TF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1> >(const Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &,const Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &,const Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const std::basic_string<char, std::char_traits<char>, std::allocator<char> >,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &);
|
||||
template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::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&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, unsigned long&);
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#ifndef TETLIBRARY
|
||||
#define TETLIBRARY
|
||||
#endif
|
||||
#include "tetgen.h" // Defined REAL
|
||||
#include <tetgen.h> // Defined REAL
|
||||
|
||||
namespace igl
|
||||
{
|
||||
@@ -68,12 +68,12 @@ namespace igl
|
||||
Eigen::PlainObjectBase<DerivedTT>& TT,
|
||||
Eigen::PlainObjectBase<DerivedTF>& TF);
|
||||
|
||||
// Mesh the interior of a surface mesh (V,F) using tetgen
|
||||
// Mesh the interior of a surface mesh (V,F) using tetgen
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 vertex position list
|
||||
// F #F list of polygon face indices into V (0-indexed)
|
||||
// M #V list of markers for vertices
|
||||
// M #V list of markers for vertices
|
||||
// switches string of tetgen options (See tetgen documentation) e.g.
|
||||
// "pq1.414a0.01" tries to mesh the interior of a given surface with
|
||||
// quality and area constraints
|
||||
@@ -82,7 +82,7 @@ namespace igl
|
||||
// TV #V by 3 vertex position list
|
||||
// TT #T by 4 list of tet face indices
|
||||
// TF #F by 3 list of triangle face indices
|
||||
// TM #V list of markers for vertices
|
||||
// TM #V list of markers for vertices
|
||||
// Returns status:
|
||||
// 0 success
|
||||
// 1 tetgen threw exception
|
||||
@@ -92,14 +92,13 @@ namespace igl
|
||||
IGL_INLINE int tetrahedralize(
|
||||
const std::vector<std::vector<REAL > > & V,
|
||||
const std::vector<std::vector<int> > & F,
|
||||
const std::vector<int> & VM,
|
||||
const std::vector<int> & FM,
|
||||
const std::vector<int> & VM,
|
||||
const std::vector<int> & FM,
|
||||
const std::string switches,
|
||||
std::vector<std::vector<REAL > > & TV,
|
||||
std::vector<std::vector<int > > & TT,
|
||||
std::vector<std::vector<int> > & TF,
|
||||
std::vector<int> & TM);
|
||||
|
||||
std::vector<int> & TM);
|
||||
// Wrapper with Eigen types
|
||||
// Templates:
|
||||
// DerivedV real-value: i.e. from MatrixXd
|
||||
@@ -107,8 +106,8 @@ namespace igl
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVM,
|
||||
typename DerivedFM,
|
||||
typename DerivedVM,
|
||||
typename DerivedFM,
|
||||
typename DerivedTV,
|
||||
typename DerivedTT,
|
||||
typename DerivedTF,
|
||||
@@ -123,16 +122,13 @@ namespace igl
|
||||
Eigen::PlainObjectBase<DerivedTT>& TT,
|
||||
Eigen::PlainObjectBase<DerivedTF>& TF,
|
||||
Eigen::PlainObjectBase<DerivedTM>& TM);
|
||||
|
||||
|
||||
// Mesh the interior of a surface mesh (V,F) using tetgen
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 vertex position list
|
||||
// F #F list of polygon face indices into V (0-indexed)
|
||||
// H #H by 3 list of seed points inside holes
|
||||
// R #R by 5 list of region attributes
|
||||
|
||||
// R #R by 5 list of region attributes
|
||||
// switches string of tetgen options (See tetgen documentation) e.g.
|
||||
// "pq1.414a0.01" tries to mesh the interior of a given surface with
|
||||
// quality and area constraints
|
||||
@@ -141,64 +137,58 @@ namespace igl
|
||||
// TV #V by 3 vertex position list
|
||||
// TT #T by 4 list of tet face indices
|
||||
// TF #F by 3 list of triangle face indices
|
||||
// TR #T list of region ID for each tetrahedron
|
||||
// TR #T list of region ID for each tetrahedron
|
||||
// TN #T by 4 list of indices neighbors for each tetrahedron
|
||||
// PT #V list of incident tetrahedron for a vertex
|
||||
// FT #F by 2 list of tetrahedrons sharing a triface
|
||||
// FT #F by 2 list of tetrahedrons sharing a triface
|
||||
// numRegions Number of regions in output mesh
|
||||
|
||||
// Returns status:
|
||||
// 0 success
|
||||
// 1 tetgen threw exception
|
||||
// 2 tetgen did not crash but could not create any tets (probably there are
|
||||
// holes, duplicate faces etc.)
|
||||
// -1 other error
|
||||
IGL_INLINE int tetrahedralize(
|
||||
const std::vector<std::vector<REAL> > &V,
|
||||
const std::vector<std::vector<int> > &F,
|
||||
const std::vector<std::vector<REAL> > &H,
|
||||
const std::vector<std::vector<REAL> > &R,
|
||||
|
||||
const std::string switches,
|
||||
|
||||
std::vector<std::vector<REAL > > & TV,
|
||||
std::vector<std::vector<int > > & TT,
|
||||
std::vector<std::vector<int > > & TF,
|
||||
std::vector<std::vector<REAL > > &TR,
|
||||
std::vector<std::vector<int > > &TN,
|
||||
std::vector<std::vector<int > > &PT,
|
||||
std::vector<std::vector<int > > &FT,
|
||||
size_t & numRegions);
|
||||
|
||||
|
||||
IGL_INLINE int tetrahedralize(
|
||||
const std::vector<std::vector<REAL> > &V,
|
||||
const std::vector<std::vector<int> > &F,
|
||||
const std::vector<std::vector<REAL> > &H,
|
||||
const std::vector<std::vector<REAL> > &R,
|
||||
const std::string switches,
|
||||
std::vector<std::vector<REAL > > & TV,
|
||||
std::vector<std::vector<int > > & TT,
|
||||
std::vector<std::vector<int > > & TF,
|
||||
std::vector<std::vector<REAL > > &TR,
|
||||
std::vector<std::vector<int > > &TN,
|
||||
std::vector<std::vector<int > > &PT,
|
||||
std::vector<std::vector<int > > &FT,
|
||||
size_t & numRegions);
|
||||
// Wrapper with Eigen types
|
||||
// Templates:
|
||||
// DerivedV real-value: i.e. from MatrixXd
|
||||
// DerivedF integer-value: i.e. from MatrixXi
|
||||
// DerivedF integer-value: i.e. from MatrixXi
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedH,
|
||||
typename DerivedR,
|
||||
typename DerivedTV,
|
||||
typename DerivedTT,
|
||||
typename DerivedTF,
|
||||
typename DerivedTR>
|
||||
typename DerivedF,
|
||||
typename DerivedH,
|
||||
typename DerivedR,
|
||||
typename DerivedTV,
|
||||
typename DerivedTT,
|
||||
typename DerivedTF,
|
||||
typename DerivedTR>
|
||||
IGL_INLINE int tetrahedralize(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedH>& H,
|
||||
const Eigen::MatrixBase<DerivedR>& R,
|
||||
const std::string switches,
|
||||
Eigen::PlainObjectBase<DerivedTV>& TV,
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedH>& H,
|
||||
const Eigen::MatrixBase<DerivedR>& R,
|
||||
const std::string switches,
|
||||
Eigen::PlainObjectBase<DerivedTV>& TV,
|
||||
Eigen::PlainObjectBase<DerivedTT>& TT,
|
||||
Eigen::PlainObjectBase<DerivedTF>& TF,
|
||||
Eigen::PlainObjectBase<DerivedTR>& TR,
|
||||
Eigen::PlainObjectBase<DerivedTT>& TN,
|
||||
Eigen::PlainObjectBase<DerivedTT>& PT,
|
||||
Eigen::PlainObjectBase<DerivedTT>& FT,
|
||||
size_t & numRegions);
|
||||
|
||||
Eigen::PlainObjectBase<DerivedTF>& TF,
|
||||
Eigen::PlainObjectBase<DerivedTR>& TR,
|
||||
Eigen::PlainObjectBase<DerivedTT>& TN,
|
||||
Eigen::PlainObjectBase<DerivedTT>& PT,
|
||||
Eigen::PlainObjectBase<DerivedTT>& FT,
|
||||
size_t & numRegions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,9 +78,152 @@ IGL_INLINE void igl::cotmatrix(
|
||||
L.setFromTriplets(IJV.begin(),IJV.end());
|
||||
}
|
||||
|
||||
#include "massmatrix.h"
|
||||
#include "pinv.h"
|
||||
#include "cotmatrix_entries.h"
|
||||
#include "diag.h"
|
||||
#include "massmatrix.h"
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedI,
|
||||
typename DerivedC,
|
||||
typename Scalar>
|
||||
IGL_INLINE void igl::cotmatrix(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedI> & I,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::SparseMatrix<Scalar>& L,
|
||||
Eigen::SparseMatrix<Scalar>& M,
|
||||
Eigen::SparseMatrix<Scalar>& P)
|
||||
{
|
||||
typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
|
||||
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixXS;
|
||||
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
|
||||
typedef Eigen::Index Index;
|
||||
// number of vertices
|
||||
const Index n = V.rows();
|
||||
// number of polyfaces
|
||||
const Index m = C.size()-1;
|
||||
assert(V.cols() == 2 || V.cols() == 3);
|
||||
std::vector<Eigen::Triplet<Scalar> > Lfijv;
|
||||
std::vector<Eigen::Triplet<Scalar> > Mfijv;
|
||||
std::vector<Eigen::Triplet<Scalar> > Pijv;
|
||||
// loop over vertices; set identity for original vertices
|
||||
for(Index i = 0;i<V.rows();i++) { Pijv.emplace_back(i,i,1); }
|
||||
// loop over faces
|
||||
for(Index p = 0;p<C.size()-1;p++)
|
||||
{
|
||||
// number of faces/vertices in this simple polygon
|
||||
const Index np = C(p+1)-C(p);
|
||||
// Working "local" list of vertices; last vertex is new one
|
||||
// this needs to have 3 columns so Eigen doesn't complain about cross
|
||||
// products below.
|
||||
Eigen::Matrix<Scalar,Eigen::Dynamic,3> X = decltype(X)::Zero(np+1,3);
|
||||
for(Index i = 0;i<np;i++){ X.row(i).head(V.cols()) = V.row(I(C(p)+i)); };
|
||||
// determine weights definig position of inserted vertex
|
||||
{
|
||||
MatrixXS A = decltype(A)::Zero(np+1,np);
|
||||
// My equation (38) would be A w = b.
|
||||
VectorXS b = decltype(b)::Zero(np+1);
|
||||
for(Index k = 0;k<np;k++)
|
||||
{
|
||||
const RowVector3S Xkp1mk = X.row((k+1)%np)-X.row(k);
|
||||
const RowVector3S Xkp1mkck = Xkp1mk.cross(X.row(k));
|
||||
for(Index i = 0;i<np;i++)
|
||||
{
|
||||
b(i) -= 2.*(X.row(i).cross(Xkp1mk)).dot(Xkp1mkck);
|
||||
for(Index j = 0;j<np;j++)
|
||||
{
|
||||
A(i,j) += 2.*(X.row(j).cross(Xkp1mk)).dot(X.row(i).cross(Xkp1mk));
|
||||
}
|
||||
}
|
||||
}
|
||||
A.row(np).setConstant(1);
|
||||
b(np) = 1;
|
||||
const VectorXS w =
|
||||
Eigen::CompleteOrthogonalDecomposition<Eigen::MatrixXd>(A).solve(b);
|
||||
X.row(np) = w.transpose()*X.topRows(np);
|
||||
// scatter w into new row of P
|
||||
for(Index i = 0;i<np;i++) { Pijv.emplace_back(n+p,I(C(p)+i),w(i)); }
|
||||
}
|
||||
// "local" fan of faces. These could be statically cached, but this will
|
||||
// not be the bottleneck.
|
||||
Eigen::MatrixXi F(np,3);
|
||||
for(Index i = 0;i<np;i++)
|
||||
{
|
||||
F(i,0) = i;
|
||||
F(i,1) = (i+1)%np;
|
||||
F(i,2) = np;
|
||||
}
|
||||
// Cotangent contributions
|
||||
MatrixXS K;
|
||||
igl::cotmatrix_entries(X,F,K);
|
||||
// Massmatrix entried
|
||||
VectorXS Mp;
|
||||
{
|
||||
Eigen::SparseMatrix<Scalar> M;
|
||||
igl::massmatrix(X,F,igl::MASSMATRIX_TYPE_DEFAULT,M);
|
||||
Mp = M.diagonal();
|
||||
}
|
||||
// Scatter into fine Laplacian and mass matrices
|
||||
const auto J = [&n,&np,&p,&I,&C](Index i)->Index{return i==np?n+p:I(C(p)+i);};
|
||||
// Should just build Mf as a vector...
|
||||
for(Index i = 0;i<np+1;i++) { Mfijv.emplace_back(J(i),J(i),Mp(i)); }
|
||||
// loop over faces
|
||||
for(Index f = 0;f<np;f++)
|
||||
{
|
||||
for(Index c = 0;c<3;c++)
|
||||
{
|
||||
const Index i = F(f,(c+1)%3);
|
||||
const Index j = F(f,(c+2)%3);
|
||||
// symmetric off-diagonal
|
||||
Lfijv.emplace_back(J(i),J(j),K(f,c));
|
||||
Lfijv.emplace_back(J(j),J(i),K(f,c));
|
||||
// diagonal
|
||||
Lfijv.emplace_back(J(i),J(i),-K(f,c));
|
||||
Lfijv.emplace_back(J(j),J(j),-K(f,c));
|
||||
}
|
||||
}
|
||||
}
|
||||
P.resize(n+m,n);
|
||||
P.setFromTriplets(Pijv.begin(),Pijv.end());
|
||||
Eigen::SparseMatrix<Scalar> Lf(n+m,n+m);
|
||||
Lf.setFromTriplets(Lfijv.begin(),Lfijv.end());
|
||||
Eigen::SparseMatrix<Scalar> Mf(n+m,n+m);
|
||||
Mf.setFromTriplets(Mfijv.begin(),Mfijv.end());
|
||||
L = P.transpose() * Lf * P;
|
||||
// "unlumped" M
|
||||
const Eigen::SparseMatrix<Scalar> PTMP = P.transpose() * Mf * P;
|
||||
// Lump M
|
||||
const VectorXS Mdiag = PTMP * VectorXS::Ones(n,1);
|
||||
igl::diag(Mdiag,M);
|
||||
|
||||
MatrixXS Vf = P*V;
|
||||
Eigen::MatrixXi Ff(I.size(),3);
|
||||
{
|
||||
Index f = 0;
|
||||
for(Index p = 0;p<C.size()-1;p++)
|
||||
{
|
||||
const Index np = C(p+1)-C(p);
|
||||
for(Index c = 0;c<np;c++)
|
||||
{
|
||||
Ff(f,0) = I(C(p)+c);
|
||||
Ff(f,1) = I(C(p)+(c+1)%np);
|
||||
Ff(f,2) = V.rows()+p;
|
||||
f++;
|
||||
}
|
||||
}
|
||||
assert(f == Ff.rows());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, double>(Eigen::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::SparseMatrix<double, 0, int>&, Eigen::SparseMatrix<double, 0, int>&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::cotmatrix<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::cotmatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::cotmatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
|
||||
@@ -48,6 +48,31 @@ namespace igl
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::SparseMatrix<Scalar>& L);
|
||||
// Cotangent Laplacian (and mass matrix) for polygon meshes according to
|
||||
// "Polygon Laplacian Made Simple" [Bunge et al. 2020]
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertex positions
|
||||
// I #I vectorized list of polygon corner indices into rows of some matrix V
|
||||
// C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) = size of
|
||||
// the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the indices of
|
||||
// the ith polygon
|
||||
// Outputs:
|
||||
// L #V by #V polygon Laplacian made simple matrix
|
||||
// M #V by #V mass matrix
|
||||
// P #V+#polygons by #V prolongation operator
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedI,
|
||||
typename DerivedC,
|
||||
typename Scalar>
|
||||
IGL_INLINE void cotmatrix(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedI> & I,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::SparseMatrix<Scalar>& L,
|
||||
Eigen::SparseMatrix<Scalar>& M,
|
||||
Eigen::SparseMatrix<Scalar>& P);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
|
||||
@@ -136,6 +136,8 @@ IGL_INLINE void igl::cotmatrix_entries(
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::cotmatrix_entries<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::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> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// 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 "cr_vector_curvature_correction.h"
|
||||
|
||||
#include "orient_halfedges.h"
|
||||
#include "gaussian_curvature.h"
|
||||
|
||||
#include "squared_edge_lengths.h"
|
||||
#include "doublearea.h"
|
||||
#include "boundary_loop.h"
|
||||
#include "internal_angles.h"
|
||||
|
||||
#include "PI.h"
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_curvature_correction(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sq;
|
||||
squared_edge_lengths(V, F, l_sq);
|
||||
cr_vector_curvature_correction_intrinsic(F, l_sq, E, oE, K);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_curvature_correction(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K)
|
||||
{
|
||||
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
|
||||
oE.cols()!=F.cols()) {
|
||||
orient_halfedges(F, E, oE);
|
||||
}
|
||||
|
||||
const Eigen::PlainObjectBase<DerivedE>& cE = E;
|
||||
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
|
||||
cr_vector_curvature_correction(V, F, cE, coE, K);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar,Eigen::Dynamic,Eigen::Dynamic>
|
||||
theta;
|
||||
internal_angles_using_squared_edge_lengths(l_sq, theta);
|
||||
|
||||
cr_vector_curvature_correction_intrinsic(F, l_sq, theta, E, oE, K);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
|
||||
typename DerivedE, typename DerivedOE,
|
||||
typename ScalarK>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<Derivedtheta>& theta,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K)
|
||||
{
|
||||
// Compute the angle defect kappa, set it to 0 at the boundary
|
||||
const typename DerivedF::Scalar n = F.maxCoeff() + 1;
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar,Eigen::Dynamic,1> kappa(n);
|
||||
kappa.setZero();
|
||||
for(Eigen::Index i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
kappa(F(i,j)) -= theta(i,j);
|
||||
}
|
||||
}
|
||||
kappa.array() += 2 * PI;
|
||||
std::vector<std::vector<typename DerivedF::Scalar> > b;
|
||||
boundary_loop(F, b);
|
||||
for(const auto& loop : b) {
|
||||
for(auto v : loop) {
|
||||
kappa(v) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cr_vector_curvature_correction_intrinsic(F, l_sq, theta, kappa, E, oE, K);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
|
||||
typename Derivedkappa, typename DerivedE, typename DerivedOE,
|
||||
typename ScalarK>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<Derivedtheta>& theta,
|
||||
const Eigen::MatrixBase<Derivedkappa>& kappa,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K)
|
||||
{
|
||||
assert(F.cols()==3 && "Faces have three vertices");
|
||||
assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() &&
|
||||
theta.rows()==F.rows() && theta.cols()==F.cols() &&
|
||||
oE.cols()==F.cols() && "Wrong dimension in edge vectors");
|
||||
assert(kappa.rows()==F.maxCoeff()+1 &&
|
||||
"Wrong dimension in theta or kappa");
|
||||
|
||||
const Eigen::Index m = F.rows();
|
||||
const typename DerivedE::Scalar nE = E.maxCoeff() + 1;
|
||||
|
||||
//Divide kappa by the actual angle sum to weigh consistently.
|
||||
Derivedtheta angleSum = Derivedtheta::Zero(kappa.rows(), 1);
|
||||
for(Eigen::Index i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
angleSum(F(i,j)) += theta(i,j);
|
||||
}
|
||||
}
|
||||
const Eigen::Matrix<typename Derivedkappa::Scalar, Eigen::Dynamic, 1>
|
||||
scaledKappa = kappa.array() / angleSum.array();
|
||||
|
||||
std::vector<Eigen::Triplet<ScalarK> > tripletList;
|
||||
tripletList.reserve(10*3*m);
|
||||
for(Eigen::Index f=0; f<m; ++f) {
|
||||
for(int e=0; e<3; ++e) {
|
||||
const ScalarK eij=l_sq(f,e), ejk=l_sq(f,(e+1)%3),
|
||||
eki=l_sq(f,(e+2)%3); //These are squared quantities.
|
||||
const ScalarK lens = sqrt(eij*eki);
|
||||
const ScalarK o = oE(f,e)*oE(f,(e+2)%3);
|
||||
const typename DerivedF::Scalar i=F(f,(e+1)%3), j=F(f,(e+2)%3), k=F(f,e);
|
||||
const ScalarK ki=scaledKappa(i)*theta(f,(e+1)%3),
|
||||
kj=scaledKappa(j)*theta(f,(e+2)%3), kk=scaledKappa(k)*theta(f,e);
|
||||
|
||||
const ScalarK costhetaidiv = (eij-ejk+eki)/(2.*lens);
|
||||
const ScalarK sinthetaidiv = sqrt( (1.-pow(eij-ejk+eki,2)/
|
||||
(4.*eij*eki)) );
|
||||
|
||||
const ScalarK Corrijij = (ki+kj+kk);
|
||||
tripletList.emplace_back(E(f,e), E(f,e), Corrijij);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,e)+nE, Corrijij);
|
||||
|
||||
const ScalarK Corrijki = -o*(ki-kj-kk)*costhetaidiv;
|
||||
tripletList.emplace_back(E(f,e), E(f,(e+2)%3), Corrijki);
|
||||
tripletList.emplace_back(E(f,(e+2)%3), E(f,e), Corrijki);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3)+nE, Corrijki);
|
||||
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e)+nE, Corrijki);
|
||||
|
||||
const ScalarK Corrijkiperp = o*(ki-kj-kk)*sinthetaidiv;
|
||||
tripletList.emplace_back(E(f,e), E(f,(e+2)%3)+nE, Corrijkiperp);
|
||||
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e), Corrijkiperp);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3), -Corrijkiperp);
|
||||
tripletList.emplace_back(E(f,(e+2)%3), E(f,e)+nE, -Corrijkiperp);
|
||||
}
|
||||
}
|
||||
|
||||
K.resize(2*nE, 2*nE);
|
||||
K.setFromTriplets(tripletList.begin(), tripletList.end());
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::cr_vector_curvature_correction_intrinsic<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>, double>(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::SparseMatrix<double, 0, int>&);
|
||||
template void igl::cr_vector_curvature_correction<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>, 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<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -0,0 +1,115 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// 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_CR_VECTOR_CURVATURE_CORRECTION_H
|
||||
#define IGL_CR_VECTOR_CURVATURE_CORRECTION_H
|
||||
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Computes the vector Crouzeix-Raviart curvature correction
|
||||
// term of Oded Stein, Alec Jacobson, Max Wardetzky, Eitan
|
||||
// Grinspun, 2020. "A Smoothness Energy without Boundary Distortion for
|
||||
// Curved Surfaces", but using the basis functions by Oded Stein,
|
||||
// Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020.
|
||||
// "A Simple Discretization of the Vector Dirichlet Energy"
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
// E: a mapping from each halfedge to each edge, as computed with
|
||||
// orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge, as computed with orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
//
|
||||
// Outputs:
|
||||
// K: computed curvature correction matrix
|
||||
// E, oE: these are computed if they are not present, as described above
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
cr_vector_curvature_correction(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K);
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
cr_vector_curvature_correction(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K);
|
||||
|
||||
|
||||
// Version that uses intrinsic quantities as input
|
||||
//
|
||||
// Inputs:
|
||||
// F: input mesh connectivity
|
||||
// l_sq: squared edge lengths of each halfedge
|
||||
// theta: the tip angles at each halfedge
|
||||
// kappa: the Gaussian curvature at each vertex
|
||||
// E: a mapping from each halfedge to each edge.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge.
|
||||
//
|
||||
// Outputs:
|
||||
// K: computed curvature correction matrix
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
|
||||
typename DerivedE, typename DerivedOE,
|
||||
typename ScalarK>
|
||||
IGL_INLINE void
|
||||
cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<Derivedtheta>& theta,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
|
||||
typename Derivedkappa, typename DerivedE, typename DerivedOE,
|
||||
typename ScalarK>
|
||||
IGL_INLINE void
|
||||
cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<Derivedtheta>& theta,
|
||||
const Eigen::MatrixBase<Derivedkappa>& kappa,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K);
|
||||
}
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "cr_vector_curvature_correction.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// 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 "cr_vector_laplacian.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "orient_halfedges.h"
|
||||
|
||||
#include "doublearea.h"
|
||||
#include "squared_edge_lengths.h"
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_laplacian(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sq;
|
||||
squared_edge_lengths(V, F, l_sq);
|
||||
cr_vector_laplacian_intrinsic(F, l_sq, E, oE, L);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_laplacian(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L)
|
||||
{
|
||||
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
|
||||
oE.cols()!=F.cols()) {
|
||||
orient_halfedges(F, E, oE);
|
||||
}
|
||||
|
||||
const Eigen::PlainObjectBase<DerivedE>& cE = E;
|
||||
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
|
||||
cr_vector_laplacian(V, F, cE, coE, L);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_laplacian_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
dA;
|
||||
DerivedL_sq l_sqrt = l_sq.array().sqrt().matrix();
|
||||
doublearea(l_sqrt, dA);
|
||||
cr_vector_laplacian_intrinsic(F, l_sq, dA, E, oE, L);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_laplacian_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L)
|
||||
{
|
||||
assert(F.cols()==3 && "Faces have three vertices");
|
||||
assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() &&
|
||||
oE.cols()==F.cols() && "Wrong dimension in edge vectors");
|
||||
assert(l_sq.rows()==F.rows() && l_sq.cols()==3 && "l_sq dimensions wrong");
|
||||
assert(dA.size()==F.rows() && "dA dimensions wrong");
|
||||
|
||||
const Eigen::Index m = F.rows();
|
||||
const typename DerivedE::Scalar nE = E.maxCoeff() + 1;
|
||||
|
||||
std::vector<Eigen::Triplet<ScalarL> > tripletList;
|
||||
tripletList.reserve(10*3*m);
|
||||
for(Eigen::Index f=0; f<m; ++f) {
|
||||
for(int e=0; e<3; ++e) {
|
||||
const ScalarL eij=l_sq(f,e), ejk=l_sq(f,(e+1)%3),
|
||||
eki=l_sq(f,(e+2)%3); //These are squared quantities.
|
||||
const ScalarL lens = sqrt(eij*eki);
|
||||
const ScalarL o = oE(f,e)*oE(f,(e+2)%3);
|
||||
|
||||
tripletList.emplace_back(E(f,e), E(f,e), 2./dA(f) * eij);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,e)+nE, 2./dA(f) * eij);
|
||||
|
||||
const ScalarL Dijki = o * pow(eij-ejk+eki,2)/(2.*lens*dA(f));
|
||||
tripletList.emplace_back(E(f,e), E(f,(e+2)%3), Dijki);
|
||||
tripletList.emplace_back(E(f,(e+2)%3), E(f,e), Dijki);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3)+nE, Dijki);
|
||||
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e)+nE, Dijki);
|
||||
|
||||
const ScalarL Dijkiperp = -o * (eij-ejk+eki)/lens;
|
||||
tripletList.emplace_back(E(f,e), E(f,(e+2)%3)+nE, Dijkiperp);
|
||||
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e), Dijkiperp);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3), -Dijkiperp);
|
||||
tripletList.emplace_back(E(f,(e+2)%3), E(f,e)+nE, -Dijkiperp);
|
||||
}
|
||||
}
|
||||
L.resize(2*nE, 2*nE);
|
||||
L.setFromTriplets(tripletList.begin(), tripletList.end());
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::cr_vector_laplacian<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>, 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<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::cr_vector_laplacian_intrinsic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// 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_CR_VECTOR_LAPLACIAN_H
|
||||
#define IGL_CR_VECTOR_LAPLACIAN_H
|
||||
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Computes the CR vector Laplacian matrix.
|
||||
// See Oded Stein, Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020.
|
||||
// "A Simple Discretization of the Vector Dirichlet Energy"
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
// E: a mapping from each halfedge to each edge, as computed with
|
||||
// orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge, as computed with orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
//
|
||||
// Outputs:
|
||||
// L: computed Laplacian matrix
|
||||
// E, oE: these are computed if they are not present, as described above
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
cr_vector_laplacian(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L);
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
cr_vector_laplacian(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L);
|
||||
|
||||
|
||||
// Version that uses intrinsic quantities as input
|
||||
//
|
||||
// Inputs:
|
||||
// F: input mesh connectivity
|
||||
// l_sq: squared edge lengths of each halfedge
|
||||
// dA: double area of each face
|
||||
// E: a mapping from each halfedge to each edge.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge.
|
||||
//
|
||||
// Outputs:
|
||||
// L: computed Laplacian matrix
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
cr_vector_laplacian_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
cr_vector_laplacian_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "cr_vector_laplacian.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,112 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// 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 "cr_vector_mass.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "orient_halfedges.h"
|
||||
|
||||
#include "doublearea.h"
|
||||
#include "squared_edge_lengths.h"
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_mass(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sq;
|
||||
squared_edge_lengths(V, F, l_sq);
|
||||
cr_vector_mass_intrinsic(F, l_sq, E, oE, M);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_mass(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M)
|
||||
{
|
||||
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
|
||||
oE.cols()!=F.cols()) {
|
||||
orient_halfedges(F, E, oE);
|
||||
}
|
||||
|
||||
const Eigen::PlainObjectBase<DerivedE>& cE = E;
|
||||
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
|
||||
cr_vector_mass(V, F, cE, coE, M);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_mass_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
dA;
|
||||
DerivedL_sq l_sqrt = l_sq.array().sqrt().matrix();
|
||||
doublearea(l_sqrt, dA);
|
||||
cr_vector_mass_intrinsic(F, l_sq, dA, E, oE, M);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_mass_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M)
|
||||
{
|
||||
assert(F.cols()==3 && "Faces have three vertices");
|
||||
assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() &&
|
||||
oE.cols()==F.cols() && "Wrong dimension in edge vectors");
|
||||
|
||||
const Eigen::Index m = F.rows();
|
||||
const typename DerivedE::Scalar nE = E.maxCoeff() + 1;
|
||||
|
||||
std::vector<Eigen::Triplet<ScalarM> > tripletList;
|
||||
tripletList.reserve(2*3*m);
|
||||
for(Eigen::Index f=0; f<m; ++f) {
|
||||
for(int e=0; e<3; ++e) {
|
||||
const typename DerivedF::Scalar v1=F(f,(e+1)%3), v2=F(f,(e+2)%3);
|
||||
//Scaled
|
||||
const ScalarM entry = dA(f) / 6;
|
||||
tripletList.emplace_back(E(f,e), E(f,e), entry);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,e)+nE, entry);
|
||||
}
|
||||
}
|
||||
M.resize(2*nE, 2*nE);
|
||||
M.setFromTriplets(tripletList.begin(), tripletList.end());
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::cr_vector_mass<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>, 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<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::cr_vector_mass_intrinsic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// 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_CR_VECTOR_MASS
|
||||
#define IGL_CR_VECTOR_MASS
|
||||
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Computes the CR vector mass matrix, using an arrangement of all parallel
|
||||
// degrees of freedom first, and all perpendicular degrees of freedom next.
|
||||
// See Oded Stein, Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020.
|
||||
// "A Simple Discretization of the Vector Dirichlet Energy"
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
// E: a mapping from each halfedge to each edge, as computed with
|
||||
// orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge, as computed with orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
//
|
||||
// Outputs:
|
||||
// M: computed mass matrix
|
||||
// E, oE: these are computed if they are not present, as described above
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
cr_vector_mass(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M);
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
cr_vector_mass(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M);
|
||||
|
||||
|
||||
// Version that uses intrinsic quantities as input
|
||||
//
|
||||
// Inputs:
|
||||
// F: input mesh connectivity
|
||||
// l_sq: squared edge lengths of each halfedge
|
||||
// dA: double area of each face
|
||||
// E: a mapping from each halfedge to each edge.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge.
|
||||
//
|
||||
// Outputs:
|
||||
// M: computed mass matrix
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
cr_vector_mass_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
cr_vector_mass_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "cr_vector_mass.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -97,4 +97,5 @@ void igl::crouzeix_raviart_cotmatrix(
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::crouzeix_raviart_cotmatrix<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>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::crouzeix_raviart_cotmatrix<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>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
|
||||
@@ -82,4 +82,5 @@ void igl::crouzeix_raviart_massmatrix(
|
||||
template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::crouzeix_raviart_massmatrix<float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<float, 0, int>&);
|
||||
template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// 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 "curved_hessian_energy.h"
|
||||
|
||||
#include "orient_halfedges.h"
|
||||
#include "doublearea.h"
|
||||
#include "squared_edge_lengths.h"
|
||||
#include "cr_vector_laplacian.h"
|
||||
#include "cr_vector_mass.h"
|
||||
#include "cr_vector_curvature_correction.h"
|
||||
#include "scalar_to_cr_vector_gradient.h"
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
igl::curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q)
|
||||
{
|
||||
Eigen::MatrixXi E, oE;
|
||||
curved_hessian_energy(V, F, E, oE, Q);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
igl::curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sq;
|
||||
squared_edge_lengths(V, F, l_sq);
|
||||
curved_hessian_energy_intrinsic(F, l_sq, E, oE, Q);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
igl::curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q)
|
||||
{
|
||||
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
|
||||
oE.cols()!=F.cols()) {
|
||||
orient_halfedges(F, E, oE);
|
||||
}
|
||||
|
||||
const Eigen::PlainObjectBase<DerivedE>& cE = E;
|
||||
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
|
||||
curved_hessian_energy(V, F, cE, coE, Q);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
igl::curved_hessian_energy_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
dA;
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sqrt = l_sq.array().sqrt().matrix();
|
||||
doublearea(l_sqrt, dA);
|
||||
curved_hessian_energy_intrinsic(F, l_sq, dA, E, oE, Q);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
igl::curved_hessian_energy_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q)
|
||||
{
|
||||
//Matrices that need to be combined
|
||||
Eigen::SparseMatrix<ScalarQ> M, D, L, K;
|
||||
cr_vector_mass_intrinsic(F, l_sq, dA, E, oE, M);
|
||||
scalar_to_cr_vector_gradient_intrinsic(F, l_sq, dA, E, oE, D);
|
||||
cr_vector_laplacian_intrinsic(F, l_sq, dA, E, oE, L);
|
||||
cr_vector_curvature_correction_intrinsic(F, l_sq, E, oE, K);
|
||||
|
||||
//Invert M
|
||||
std::vector<Eigen::Triplet<ScalarQ> > tripletListMi;
|
||||
for(Eigen::Index k=0; k<M.outerSize(); ++k) {
|
||||
for(typename Eigen::SparseMatrix<ScalarQ>::InnerIterator it(M,k);
|
||||
it; ++it) {
|
||||
if(it.value() > 0) {
|
||||
tripletListMi.emplace_back(it.row(), it.col(), 1./it.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
Eigen::SparseMatrix<ScalarQ> Mi(M.rows(), M.cols());
|
||||
Mi.setFromTriplets(tripletListMi.begin(), tripletListMi.end());
|
||||
|
||||
//Hessian energy matrix
|
||||
Q = D.transpose()*Mi*(L + K)*Mi*D;
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::curved_hessian_energy<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -0,0 +1,114 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// 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_CURVED_HESSIAN_ENERGY_H
|
||||
#define IGL_CURVED_HESSIAN_ENERGY_H
|
||||
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Computes the curved Hessian energy using the Crouzeix-Raviart
|
||||
// discretization.
|
||||
// See Oded Stein, Alec Jacobson, Max Wardetzky, Eitan Grinspun, 2020.
|
||||
// "A Smoothness Energy without Boundary Distortion for Curved Surfaces"
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
//
|
||||
// Outputs:
|
||||
// Q: computed Hessian energy matrix
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q);
|
||||
|
||||
// Version that exposes the edge orientation used.
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
// E: a mapping from each halfedge to each edge, as computed with
|
||||
// orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge, as computed with orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
//
|
||||
// Outputs:
|
||||
// Q: computed Hessian energy matrix
|
||||
// E, oE: these are computed if they are not present, as described above
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q);
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q);
|
||||
|
||||
|
||||
// Version that uses intrinsic quantities as input
|
||||
//
|
||||
// Inputs:
|
||||
// F: input mesh connectivity
|
||||
// l_sq: squared edge lengths of each halfedge
|
||||
// dA: double area of each face
|
||||
// E: a mapping from each halfedge to each edge.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge.
|
||||
//
|
||||
// Outputs:
|
||||
// Q: computed Hessian energy matrix
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
curved_hessian_energy_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
curved_hessian_energy_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "curved_hessian_energy.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+80
-197
@@ -8,11 +8,13 @@
|
||||
#include "decimate.h"
|
||||
#include "collapse_edge.h"
|
||||
#include "edge_flaps.h"
|
||||
#include "decimate_trivial_callbacks.h"
|
||||
#include "is_edge_manifold.h"
|
||||
#include "remove_unreferenced.h"
|
||||
#include "slice_mask.h"
|
||||
#include "slice.h"
|
||||
#include "connect_boundary_to_infinity.h"
|
||||
#include "parallel_for.h"
|
||||
#include "max_faces_stopping_condition.h"
|
||||
#include "shortest_edge_and_midpoint.h"
|
||||
|
||||
@@ -34,18 +36,34 @@ IGL_INLINE bool igl::decimate(
|
||||
DerivedV VO;
|
||||
DerivedF FO;
|
||||
igl::connect_boundary_to_infinity(V,F,VO,FO);
|
||||
Eigen::VectorXi EMAP;
|
||||
Eigen::MatrixXi E,EF,EI;
|
||||
edge_flaps(FO,E,EMAP,EF,EI);
|
||||
// decimate will not work correctly on non-edge-manifold meshes. By extension
|
||||
// this includes meshes with non-manifold vertices on the boundary since these
|
||||
// will create a non-manifold edge when connected to infinity.
|
||||
if(!is_edge_manifold(FO))
|
||||
{
|
||||
return false;
|
||||
Eigen::Array<bool,Eigen::Dynamic,Eigen::Dynamic> BF;
|
||||
Eigen::Array<bool,Eigen::Dynamic,1> BE;
|
||||
if(!is_edge_manifold(FO,E.rows(),EMAP,BF,BE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
decimate_pre_collapse_callback always_try;
|
||||
decimate_post_collapse_callback never_care;
|
||||
decimate_trivial_callbacks(always_try,never_care);
|
||||
bool ret = decimate(
|
||||
VO,
|
||||
FO,
|
||||
shortest_edge_and_midpoint,
|
||||
max_faces_stopping_condition(m,orig_m,max_m),
|
||||
always_try,
|
||||
never_care,
|
||||
E,
|
||||
EMAP,
|
||||
EF,
|
||||
EI,
|
||||
U,
|
||||
G,
|
||||
J,
|
||||
@@ -74,66 +92,17 @@ IGL_INLINE bool igl::decimate(
|
||||
IGL_INLINE bool igl::decimate(
|
||||
const Eigen::MatrixXd & OV,
|
||||
const Eigen::MatrixXi & OF,
|
||||
const std::function<void(
|
||||
const int,
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
double &,
|
||||
Eigen::RowVectorXd &)> & cost_and_placement,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const std::set<std::pair<double,int> > &,
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,
|
||||
const Eigen::MatrixXd &,
|
||||
const int,
|
||||
const int,
|
||||
const int,
|
||||
const int,
|
||||
const int)> & stopping_condition,
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_stopping_condition_callback & stopping_condition,
|
||||
Eigen::MatrixXd & U,
|
||||
Eigen::MatrixXi & G,
|
||||
Eigen::VectorXi & J,
|
||||
Eigen::VectorXi & I
|
||||
)
|
||||
{
|
||||
const auto always_try = [](
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
) -> bool { return true;};
|
||||
const auto never_care = [](
|
||||
const Eigen::MatrixXd & , /*V*/
|
||||
const Eigen::MatrixXi & , /*F*/
|
||||
const Eigen::MatrixXi & , /*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & , /*EF*/
|
||||
const Eigen::MatrixXi & , /*EI*/
|
||||
const std::set<std::pair<double,int> > & , /*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
|
||||
const Eigen::MatrixXd & , /*C*/
|
||||
const int , /*e*/
|
||||
const int , /*e1*/
|
||||
const int , /*e2*/
|
||||
const int , /*f1*/
|
||||
const int , /*f2*/
|
||||
const bool /*collapsed*/
|
||||
)-> void { };
|
||||
decimate_pre_collapse_callback always_try;
|
||||
decimate_post_collapse_callback never_care;
|
||||
decimate_trivial_callbacks(always_try,never_care);
|
||||
return igl::decimate(
|
||||
OV,OF,cost_and_placement,stopping_condition,always_try,never_care,U,G,J,I);
|
||||
}
|
||||
@@ -141,70 +110,18 @@ IGL_INLINE bool igl::decimate(
|
||||
IGL_INLINE bool igl::decimate(
|
||||
const Eigen::MatrixXd & OV,
|
||||
const Eigen::MatrixXi & OF,
|
||||
const std::function<void(
|
||||
const int,
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
double &,
|
||||
Eigen::RowVectorXd &)> & cost_and_placement,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const std::set<std::pair<double,int> > &,
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,
|
||||
const Eigen::MatrixXd &,
|
||||
const int,
|
||||
const int,
|
||||
const int,
|
||||
const int,
|
||||
const int)> & stopping_condition,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
)> & pre_collapse,
|
||||
const std::function<void(
|
||||
const Eigen::MatrixXd & , /*V*/
|
||||
const Eigen::MatrixXi & , /*F*/
|
||||
const Eigen::MatrixXi & , /*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & , /*EF*/
|
||||
const Eigen::MatrixXi & , /*EI*/
|
||||
const std::set<std::pair<double,int> > & , /*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
|
||||
const Eigen::MatrixXd & , /*C*/
|
||||
const int , /*e*/
|
||||
const int , /*e1*/
|
||||
const int , /*e2*/
|
||||
const int , /*f1*/
|
||||
const int , /*f2*/
|
||||
const bool /*collapsed*/
|
||||
)> & post_collapse,
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_stopping_condition_callback & stopping_condition,
|
||||
const decimate_pre_collapse_callback & pre_collapse,
|
||||
const decimate_post_collapse_callback & post_collapse,
|
||||
Eigen::MatrixXd & U,
|
||||
Eigen::MatrixXi & G,
|
||||
Eigen::VectorXi & J,
|
||||
Eigen::VectorXi & I
|
||||
)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
VectorXi EMAP;
|
||||
MatrixXi E,EF,EI;
|
||||
Eigen::VectorXi EMAP;
|
||||
Eigen::MatrixXi E,EF,EI;
|
||||
edge_flaps(OF,E,EMAP,EF,EI);
|
||||
return igl::decimate(
|
||||
OV,OF,
|
||||
@@ -213,64 +130,13 @@ IGL_INLINE bool igl::decimate(
|
||||
U,G,J,I);
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE bool igl::decimate(
|
||||
const Eigen::MatrixXd & OV,
|
||||
const Eigen::MatrixXi & OF,
|
||||
const std::function<void(
|
||||
const int,
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
double &,
|
||||
Eigen::RowVectorXd &)> & cost_and_placement,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::VectorXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const Eigen::MatrixXi &,
|
||||
const std::set<std::pair<double,int> > &,
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,
|
||||
const Eigen::MatrixXd &,
|
||||
const int,
|
||||
const int,
|
||||
const int,
|
||||
const int,
|
||||
const int)> & stopping_condition,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
)> & pre_collapse,
|
||||
const std::function<void(
|
||||
const Eigen::MatrixXd & , /*V*/
|
||||
const Eigen::MatrixXi & , /*F*/
|
||||
const Eigen::MatrixXi & , /*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & , /*EF*/
|
||||
const Eigen::MatrixXi & , /*EI*/
|
||||
const std::set<std::pair<double,int> > & , /*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
|
||||
const Eigen::MatrixXd & , /*C*/
|
||||
const int , /*e*/
|
||||
const int , /*e1*/
|
||||
const int , /*e2*/
|
||||
const int , /*f1*/
|
||||
const int , /*f2*/
|
||||
const bool /*collapsed*/
|
||||
)> & post_collapse,
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_stopping_condition_callback & stopping_condition,
|
||||
const decimate_pre_collapse_callback & pre_collapse,
|
||||
const decimate_post_collapse_callback & post_collapse,
|
||||
const Eigen::MatrixXi & OE,
|
||||
const Eigen::VectorXi & OEMAP,
|
||||
const Eigen::MatrixXi & OEF,
|
||||
@@ -281,57 +147,74 @@ IGL_INLINE bool igl::decimate(
|
||||
Eigen::VectorXi & I
|
||||
)
|
||||
{
|
||||
|
||||
// Decimate 1
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
// Working copies
|
||||
Eigen::MatrixXd V = OV;
|
||||
Eigen::MatrixXi F = OF;
|
||||
Eigen::MatrixXi E = OE;
|
||||
Eigen::VectorXi EMAP = OEMAP;
|
||||
Eigen::MatrixXi EF = OEF;
|
||||
Eigen::MatrixXi EI = OEI;
|
||||
typedef std::set<std::pair<double,int> > PriorityQueue;
|
||||
PriorityQueue Q;
|
||||
std::vector<PriorityQueue::iterator > Qit;
|
||||
Qit.resize(E.rows());
|
||||
VectorXi EMAP;
|
||||
MatrixXi E,EF,EI;
|
||||
edge_flaps(F,E,EMAP,EF,EI);
|
||||
{
|
||||
Eigen::Array<bool,Eigen::Dynamic,Eigen::Dynamic> BF;
|
||||
Eigen::Array<bool,Eigen::Dynamic,1> BE;
|
||||
if(!is_edge_manifold(F,E.rows(),EMAP,BF,BE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
igl::min_heap<std::tuple<double,int,int> > Q;
|
||||
// Could reserve with https://stackoverflow.com/a/29236236/148668
|
||||
Eigen::VectorXi EQ = Eigen::VectorXi::Zero(E.rows());
|
||||
// If an edge were collapsed, we'd collapse it to these points:
|
||||
MatrixXd C(E.rows(),V.cols());
|
||||
for(int e = 0;e<E.rows();e++)
|
||||
// Pushing into a vector then using constructor was slower. Maybe using
|
||||
// std::move + make_heap would squeeze out something?
|
||||
|
||||
// Separating the cost/placement evaluation from the Q filling is a
|
||||
// performance hit for serial but faster if we can parallelize the
|
||||
// cost/placement.
|
||||
{
|
||||
double cost = e;
|
||||
RowVectorXd p(1,3);
|
||||
cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
|
||||
C.row(e) = p;
|
||||
Qit[e] = Q.insert(std::pair<double,int>(cost,e)).first;
|
||||
Eigen::VectorXd costs(E.rows());
|
||||
igl::parallel_for(E.rows(),[&](const int e)
|
||||
{
|
||||
double cost = e;
|
||||
RowVectorXd p(1,3);
|
||||
cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
|
||||
C.row(e) = p;
|
||||
costs(e) = cost;
|
||||
},10000);
|
||||
for(int e = 0;e<E.rows();e++)
|
||||
{
|
||||
Q.emplace(costs(e),e,0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int prev_e = -1;
|
||||
bool clean_finish = false;
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(Q.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(Q.begin()->first == std::numeric_limits<double>::infinity())
|
||||
{
|
||||
// min cost edge is infinite cost
|
||||
break;
|
||||
}
|
||||
int e,e1,e2,f1,f2;
|
||||
if(collapse_edge(
|
||||
cost_and_placement, pre_collapse, post_collapse,
|
||||
V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
|
||||
cost_and_placement, pre_collapse, post_collapse,
|
||||
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2))
|
||||
{
|
||||
if(stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
|
||||
if(stopping_condition(V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2))
|
||||
{
|
||||
clean_finish = true;
|
||||
break;
|
||||
}
|
||||
}else
|
||||
{
|
||||
if(e == -1)
|
||||
{
|
||||
// a candidate edge was not even found in Q.
|
||||
break;
|
||||
}
|
||||
if(prev_e == e)
|
||||
{
|
||||
assert(false && "Edge collapse no progress... bad stopping condition?");
|
||||
@@ -361,6 +244,6 @@ IGL_INLINE bool igl::decimate(
|
||||
F2.conservativeResize(m,F2.cols());
|
||||
J.conservativeResize(m);
|
||||
VectorXi _1;
|
||||
remove_unreferenced(V,F2,U,G,_1,I);
|
||||
igl::remove_unreferenced(V,F2,U,G,_1,I);
|
||||
return clean_finish;
|
||||
}
|
||||
|
||||
+11
-144
@@ -8,9 +8,8 @@
|
||||
#ifndef IGL_DECIMATE_H
|
||||
#define IGL_DECIMATE_H
|
||||
#include "igl_inline.h"
|
||||
#include "decimate_callback_types.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
namespace igl
|
||||
{
|
||||
// Assumes (V,F) is a manifold mesh (possibly with boundary) Collapses edges
|
||||
@@ -68,38 +67,12 @@ namespace igl
|
||||
IGL_INLINE bool decimate(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
const std::function<void(
|
||||
const int /*e*/,
|
||||
const Eigen::MatrixXd &/*V*/,
|
||||
const Eigen::MatrixXi &/*F*/,
|
||||
const Eigen::MatrixXi &/*E*/,
|
||||
const Eigen::VectorXi &/*EMAP*/,
|
||||
const Eigen::MatrixXi &/*EF*/,
|
||||
const Eigen::MatrixXi &/*EI*/,
|
||||
double & /*cost*/,
|
||||
Eigen::RowVectorXd & /*p*/
|
||||
)> & cost_and_placement,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int ,/*e*/
|
||||
const int ,/*e1*/
|
||||
const int ,/*e2*/
|
||||
const int ,/*f1*/
|
||||
const int /*f2*/
|
||||
)> & stopping_condition,
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_stopping_condition_callback & stopping_condition,
|
||||
Eigen::MatrixXd & U,
|
||||
Eigen::MatrixXi & G,
|
||||
Eigen::VectorXi & J,
|
||||
Eigen::VectorXi & I);
|
||||
|
||||
// Inputs:
|
||||
// pre_collapse callback called with index of edge whose collapse is about
|
||||
// to be attempted (see collapse_edge)
|
||||
@@ -109,67 +82,14 @@ namespace igl
|
||||
IGL_INLINE bool decimate(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
const std::function<void(
|
||||
const int /*e*/,
|
||||
const Eigen::MatrixXd &/*V*/,
|
||||
const Eigen::MatrixXi &/*F*/,
|
||||
const Eigen::MatrixXi &/*E*/,
|
||||
const Eigen::VectorXi &/*EMAP*/,
|
||||
const Eigen::MatrixXi &/*EF*/,
|
||||
const Eigen::MatrixXi &/*EI*/,
|
||||
double & /*cost*/,
|
||||
Eigen::RowVectorXd & /*p*/
|
||||
)> & cost_and_placement,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int ,/*e*/
|
||||
const int ,/*e1*/
|
||||
const int ,/*e2*/
|
||||
const int ,/*f1*/
|
||||
const int /*f2*/
|
||||
)> & stopping_condition,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
)> & pre_collapse,
|
||||
const std::function<void(
|
||||
const Eigen::MatrixXd & , /*V*/
|
||||
const Eigen::MatrixXi & , /*F*/
|
||||
const Eigen::MatrixXi & , /*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & , /*EF*/
|
||||
const Eigen::MatrixXi & , /*EI*/
|
||||
const std::set<std::pair<double,int> > & , /*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
|
||||
const Eigen::MatrixXd & , /*C*/
|
||||
const int , /*e*/
|
||||
const int , /*e1*/
|
||||
const int , /*e2*/
|
||||
const int , /*f1*/
|
||||
const int , /*f2*/
|
||||
const bool /*collapsed*/
|
||||
)> & post_collapse,
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_stopping_condition_callback & stopping_condition,
|
||||
const decimate_pre_collapse_callback & pre_collapse,
|
||||
const decimate_post_collapse_callback & post_collapse,
|
||||
Eigen::MatrixXd & U,
|
||||
Eigen::MatrixXi & G,
|
||||
Eigen::VectorXi & J,
|
||||
Eigen::VectorXi & I);
|
||||
|
||||
// Inputs:
|
||||
// EMAP #F*3 list of indices into E, mapping each directed edge to unique
|
||||
// unique edge in E
|
||||
@@ -177,66 +97,13 @@ namespace igl
|
||||
// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
|
||||
// e=(j->i)
|
||||
// EI #E by 2 list of edge flap corners (see above).
|
||||
|
||||
IGL_INLINE bool decimate(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
const std::function<void(
|
||||
const int /*e*/,
|
||||
const Eigen::MatrixXd &/*V*/,
|
||||
const Eigen::MatrixXi &/*F*/,
|
||||
const Eigen::MatrixXi &/*E*/,
|
||||
const Eigen::VectorXi &/*EMAP*/,
|
||||
const Eigen::MatrixXi &/*EF*/,
|
||||
const Eigen::MatrixXi &/*EI*/,
|
||||
double & /*cost*/,
|
||||
Eigen::RowVectorXd & /*p*/
|
||||
)> & cost_and_placement,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int ,/*e*/
|
||||
const int ,/*e1*/
|
||||
const int ,/*e2*/
|
||||
const int ,/*f1*/
|
||||
const int /*f2*/
|
||||
)> & stopping_condition,
|
||||
const std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const std::set<std::pair<double,int> > & ,/*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
)> & pre_collapse,
|
||||
const std::function<void(
|
||||
const Eigen::MatrixXd & , /*V*/
|
||||
const Eigen::MatrixXi & , /*F*/
|
||||
const Eigen::MatrixXi & , /*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & , /*EF*/
|
||||
const Eigen::MatrixXi & , /*EI*/
|
||||
const std::set<std::pair<double,int> > & , /*Q*/
|
||||
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
|
||||
const Eigen::MatrixXd & , /*C*/
|
||||
const int , /*e*/
|
||||
const int , /*e1*/
|
||||
const int , /*e2*/
|
||||
const int , /*f1*/
|
||||
const int , /*f2*/
|
||||
const bool /*collapsed*/
|
||||
)> & post_collapse,
|
||||
const decimate_cost_and_placement_callback & cost_and_placement,
|
||||
const decimate_stopping_condition_callback & stopping_condition,
|
||||
const decimate_pre_collapse_callback & pre_collapse,
|
||||
const decimate_post_collapse_callback & post_collapse,
|
||||
const Eigen::MatrixXi & E,
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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_DECIMATE_CALLBACK_TYPES_H
|
||||
#define IGL_DECIMATE_CALLBACK_TYPES_H
|
||||
#include <Eigen/Core>
|
||||
#include "min_heap.h"
|
||||
namespace igl
|
||||
{
|
||||
// Function handles used to customize the `igl::decimate` command.
|
||||
using decimate_cost_and_placement_callback =
|
||||
std::function<void(
|
||||
const int ,/*e*/
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
double & ,/*cost*/
|
||||
Eigen::RowVectorXd & /*p*/
|
||||
)>;
|
||||
using decimate_stopping_condition_callback =
|
||||
std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const igl::min_heap< std::tuple<double,int,int> > & ,/*Q*/
|
||||
const Eigen::VectorXi & ,/*EQ*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int ,/*e*/
|
||||
const int ,/*e1*/
|
||||
const int ,/*e2*/
|
||||
const int ,/*f1*/
|
||||
const int /*f2*/
|
||||
)>;
|
||||
using decimate_pre_collapse_callback =
|
||||
std::function<bool(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const igl::min_heap< std::tuple<double,int,int> > & ,/*Q*/
|
||||
const Eigen::VectorXi & ,/*EQ*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
)>;
|
||||
using decimate_post_collapse_callback =
|
||||
std::function<void(
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const igl::min_heap< std::tuple<double,int,int> > & ,/*Q*/
|
||||
const Eigen::VectorXi & ,/*EQ*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int ,/*e*/
|
||||
const int ,/*e1*/
|
||||
const int ,/*e2*/
|
||||
const int ,/*f1*/
|
||||
const int ,/*f2*/
|
||||
const bool /*collapsed*/
|
||||
)>;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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 "decimate_trivial_callbacks.h"
|
||||
|
||||
IGL_INLINE void igl::decimate_trivial_callbacks(
|
||||
decimate_pre_collapse_callback & always_try,
|
||||
decimate_post_collapse_callback & never_care)
|
||||
{
|
||||
always_try = [](
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const igl::min_heap< std::tuple<double,int,int> > & ,/*Q*/
|
||||
const Eigen::VectorXi & ,/*EQ*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int /*e*/
|
||||
) -> bool { return true;};
|
||||
never_care = [](
|
||||
const Eigen::MatrixXd & ,/*V*/
|
||||
const Eigen::MatrixXi & ,/*F*/
|
||||
const Eigen::MatrixXi & ,/*E*/
|
||||
const Eigen::VectorXi & ,/*EMAP*/
|
||||
const Eigen::MatrixXi & ,/*EF*/
|
||||
const Eigen::MatrixXi & ,/*EI*/
|
||||
const igl::min_heap< std::tuple<double,int,int> > & ,/*Q*/
|
||||
const Eigen::VectorXi & ,/*EQ*/
|
||||
const Eigen::MatrixXd & ,/*C*/
|
||||
const int ,/*e*/
|
||||
const int ,/*e1*/
|
||||
const int ,/*e2*/
|
||||
const int ,/*f1*/
|
||||
const int ,/*f2*/
|
||||
const bool /*collapsed*/
|
||||
)-> void { };
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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_DECIMATE_TRIVIAL_CALLBACKS_H
|
||||
#define IGL_DECIMATE_TRIVIAL_CALLBACKS_H
|
||||
#include "igl_inline.h"
|
||||
#include "decimate_callback_types.h"
|
||||
namespace igl
|
||||
{
|
||||
// Function to build trivial pre and post collapse actions.
|
||||
//
|
||||
// Outputs:
|
||||
// always_try function that always returns true (always attempt the next
|
||||
// edge collapse)
|
||||
// never_care fuction that is always a no-op (never have a post collapse
|
||||
// response)
|
||||
IGL_INLINE void decimate_trivial_callbacks(
|
||||
decimate_pre_collapse_callback & always_try,
|
||||
decimate_post_collapse_callback & never_care);
|
||||
};
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "decimate_trivial_callbacks.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
@@ -17,7 +17,7 @@ IGL_INLINE int igl::dijkstra(
|
||||
Eigen::PlainObjectBase<DerivedP> &previous)
|
||||
{
|
||||
int numV = VV.size();
|
||||
min_distance.setConstant(numV, 1, std::numeric_limits<typename DerivedD::Scalar>::infinity());
|
||||
min_distance.setConstant(numV, 1, std::numeric_limits<typename DerivedD::Scalar>::max());
|
||||
min_distance[source] = 0;
|
||||
previous.setConstant(numV, 1, -1);
|
||||
std::set<std::pair<typename DerivedD::Scalar, IndexType> > vertex_queue;
|
||||
@@ -132,6 +132,7 @@ IGL_INLINE int igl::dijkstra(
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template int igl::dijkstra<int, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, std::set<int, std::less<int>, std::allocator<int> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template int igl::dijkstra<int, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, std::set<int, std::less<int>, std::allocator<int> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::dijkstra<int, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<int, std::allocator<int> >&);
|
||||
template int igl::dijkstra<int, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, int const&, std::set<int, std::less<int>, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
// This file is part of libigl, a simple C++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Xiangyu Kong <xiangyu.kong@mail.utoronto.ca>
|
||||
//
|
||||
// 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 "direct_delta_mush.h"
|
||||
#include "cotmatrix.h"
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedOmega,
|
||||
typename DerivedU>
|
||||
IGL_INLINE void igl::direct_delta_mush(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const std::vector<Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d> > & T,
|
||||
const Eigen::MatrixBase<DerivedOmega> & Omega,
|
||||
Eigen::PlainObjectBase<DerivedU> & U)
|
||||
{
|
||||
using namespace Eigen;
|
||||
|
||||
// Shape checks
|
||||
assert(V.cols() == 3 && "V should contain 3D positions.");
|
||||
assert(Omega.rows() == V.rows() && "Omega contain the same number of rows as V.");
|
||||
assert(Omega.cols() == T.size() * 10 && "Omega should have #T*10 columns.");
|
||||
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
|
||||
int n = V.rows();
|
||||
int m = T.size();
|
||||
|
||||
// V_homogeneous: #V by 4, homogeneous version of V
|
||||
// Note:
|
||||
// In the paper, the rest pose vertices are represented in U \in R^{4 x #V}
|
||||
// Thus the formulae involving U would differ from the paper by a transpose.
|
||||
Matrix<Scalar, Dynamic, 4> V_homogeneous(n, 4);
|
||||
V_homogeneous << V, Matrix<Scalar, Dynamic, 1>::Ones(n, 1);
|
||||
U.resize(n, 3);
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
// Construct Q matrix using Omega and Transformations
|
||||
Matrix<Scalar, 4, 4> Q_mat(4, 4);
|
||||
Q_mat = Matrix<Scalar, 4, 4>::Zero(4, 4);
|
||||
for (int j = 0; j < m; ++j)
|
||||
{
|
||||
Matrix<typename DerivedOmega::Scalar, 4, 4> Omega_curr(4, 4);
|
||||
Matrix<typename DerivedOmega::Scalar, 10, 1> curr = Omega.block(i, j * 10, 1, 10).transpose();
|
||||
Omega_curr << curr(0), curr(1), curr(2), curr(3),
|
||||
curr(1), curr(4), curr(5), curr(6),
|
||||
curr(2), curr(5), curr(7), curr(8),
|
||||
curr(3), curr(6), curr(8), curr(9);
|
||||
|
||||
Affine3d M_curr = T[j];
|
||||
Q_mat += M_curr.matrix() * Omega_curr;
|
||||
}
|
||||
// Normalize so that the last element is 1
|
||||
Q_mat /= Q_mat(Q_mat.rows() - 1, Q_mat.cols() - 1);
|
||||
|
||||
Matrix<Scalar, 3, 3> Q_i = Q_mat.block(0, 0, 3, 3);
|
||||
Matrix<Scalar, 3, 1> q_i = Q_mat.block(0, 3, 3, 1);
|
||||
Matrix<Scalar, 3, 1> p_i = Q_mat.block(3, 0, 1, 3).transpose();
|
||||
|
||||
// Get rotation and translation matrices using SVD
|
||||
Matrix<Scalar, 3, 3> SVD_i = Q_i - q_i * p_i.transpose();
|
||||
JacobiSVD<Matrix<Scalar, 3, 3>> svd;
|
||||
svd.compute(SVD_i, ComputeFullU | ComputeFullV);
|
||||
Matrix<Scalar, 3, 3> R_i = svd.matrixU() * svd.matrixV().transpose();
|
||||
Matrix<Scalar, 3, 1> t_i = q_i - R_i * p_i;
|
||||
|
||||
// Gamma final transformation matrix
|
||||
Matrix<Scalar, 3, 4> Gamma_i(3, 4);
|
||||
Gamma_i.block(0, 0, 3, 3) = R_i;
|
||||
Gamma_i.block(0, 3, 3, 1) = t_i;
|
||||
|
||||
// Final deformed position
|
||||
Matrix<Scalar, 4, 1> v_i = V_homogeneous.row(i);
|
||||
U.row(i) = Gamma_i * v_i;
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedW,
|
||||
typename DerivedOmega>
|
||||
IGL_INLINE void igl::direct_delta_mush_precomputation(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedW> & W,
|
||||
const int p,
|
||||
const typename DerivedV::Scalar lambda,
|
||||
const typename DerivedV::Scalar kappa,
|
||||
const typename DerivedV::Scalar alpha,
|
||||
Eigen::PlainObjectBase<DerivedOmega> & Omega)
|
||||
{
|
||||
using namespace Eigen;
|
||||
|
||||
// Shape checks
|
||||
assert(V.cols() == 3 && "V should contain 3D positions.");
|
||||
assert(F.cols() == 3 && "F should contain triangles.");
|
||||
assert(W.rows() == V.rows() && "W.rows() should be equal to V.rows().");
|
||||
|
||||
// Parameter checks
|
||||
assert(p > 0 && "Laplacian iteration p should be positive.");
|
||||
assert(lambda > 0 && "lambda should be positive.");
|
||||
assert(kappa > 0 && kappa < lambda && "kappa should be positive and less than lambda.");
|
||||
assert(alpha >= 0 && alpha < 1 && "alpha should be non-negative and less than 1.");
|
||||
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
|
||||
// lambda helper
|
||||
// Given a square matrix, extract the upper triangle (including diagonal) to an array.
|
||||
// E.g. 1 2 3 4
|
||||
// 5 6 7 8 -> [1, 2, 3, 4, 6, 7, 8, 11, 12, 16]
|
||||
// 9 10 11 12 0 1 2 3 4 5 6 7 8 9
|
||||
// 13 14 15 16
|
||||
auto extract_upper_triangle = [](
|
||||
const Matrix<Scalar, Dynamic, Dynamic> & full) -> Matrix<Scalar, Dynamic, 1>
|
||||
{
|
||||
int dims = full.rows();
|
||||
Matrix<Scalar, Dynamic, 1> upper_triangle((dims * (dims + 1)) / 2);
|
||||
int vector_idx = 0;
|
||||
for (int i = 0; i < dims; ++i)
|
||||
{
|
||||
for (int j = i; j < dims; ++j)
|
||||
{
|
||||
upper_triangle(vector_idx) = full(i, j);
|
||||
vector_idx++;
|
||||
}
|
||||
}
|
||||
return upper_triangle;
|
||||
};
|
||||
|
||||
const int n = V.rows();
|
||||
const int m = W.cols();
|
||||
|
||||
// V_homogeneous: #V by 4, homogeneous version of V
|
||||
// Note:
|
||||
// in the paper, the rest pose vertices are represented in U \in R^{4 \times #V}
|
||||
// Thus the formulae involving U would differ from the paper by a transpose.
|
||||
Matrix<Scalar, Dynamic, 4> V_homogeneous(n, 4);
|
||||
V_homogeneous << V, Matrix<Scalar, Dynamic, 1>::Ones(n);
|
||||
|
||||
// Identity matrix of #V by #V
|
||||
SparseMatrix<Scalar> I(n, n);
|
||||
I.setIdentity();
|
||||
|
||||
// Laplacian matrix of #V by #V
|
||||
// L_bar = L \times D_L^{-1}
|
||||
SparseMatrix<Scalar> L;
|
||||
igl::cotmatrix(V, F, L);
|
||||
L = -L;
|
||||
// Inverse of diagonal matrix = reciprocal elements in diagonal
|
||||
Matrix<Scalar, Dynamic, 1> D_L = L.diagonal();
|
||||
// D_L = D_L.array().pow(-1); // Not using this since not sure if diagonal contains 0
|
||||
for (int i = 0; i < D_L.size(); ++i)
|
||||
{
|
||||
if (D_L(i) != 0)
|
||||
{
|
||||
D_L(i) = 1 / D_L(i);
|
||||
}
|
||||
}
|
||||
SparseMatrix<Scalar> D_L_inv = D_L.asDiagonal().toDenseMatrix().sparseView();
|
||||
SparseMatrix<Scalar> L_bar = L * D_L_inv;
|
||||
|
||||
// Implicitly and iteratively solve for W'
|
||||
// w'_{ij} = \sum_{k=1}^{n}{C_{ki} w_{kj}} where C = (I + kappa L_bar)^{-p}:
|
||||
// W' = C^T \times W => c^T W_k = W_{k-1} where c = (I + kappa L_bar)
|
||||
// C positive semi-definite => ldlt solver
|
||||
SimplicialLDLT<SparseMatrix<Scalar>> ldlt_W_prime;
|
||||
SparseMatrix<Scalar> c(I + kappa * L_bar);
|
||||
// working copy
|
||||
DerivedW W_prime(W);
|
||||
ldlt_W_prime.compute(c.transpose());
|
||||
for (int iter = 0; iter < p; ++iter)
|
||||
{
|
||||
W_prime = ldlt_W_prime.solve(W_prime);
|
||||
}
|
||||
|
||||
// U_precomputed: #V by 10
|
||||
// Cache u_i^T \dot u_i \in R^{4 x 4} to reduce computation time.
|
||||
Matrix<Scalar, Dynamic, 10> U_precomputed(n, 10);
|
||||
for (int k = 0; k < n; ++k)
|
||||
{
|
||||
Matrix<Scalar, 4, 4> u_full = V_homogeneous.row(k).transpose() * V_homogeneous.row(k);
|
||||
U_precomputed.row(k) = extract_upper_triangle(u_full);
|
||||
}
|
||||
|
||||
// U_prime: #V by #T*10 of u_{jx}
|
||||
// Each column of U_prime (u_{jx}) is the element-wise product of
|
||||
// W_j and U_precomputed_x where j \in {1...m}, x \in {1...10}
|
||||
Matrix<Scalar, Dynamic, Dynamic> U_prime(n, m * 10);
|
||||
for (int j = 0; j < m; ++j)
|
||||
{
|
||||
Matrix<Scalar, Dynamic, 1> w_j = W.col(j);
|
||||
for (int x = 0; x < 10; ++x)
|
||||
{
|
||||
Matrix<Scalar, Dynamic, 1> u_x = U_precomputed.col(x);
|
||||
U_prime.col(10 * j + x) = w_j.array() * u_x.array();
|
||||
}
|
||||
}
|
||||
|
||||
// Implicitly and iteratively solve for Psi: #V by #T*10 of \Psi_{ij}s.
|
||||
// Note: Using dense matrices to solve for Psi will cause the program to hang.
|
||||
// The following won't work
|
||||
// Matrix<Scalar, Dynamic, Dynamic> Psi(U_prime);
|
||||
// Matrix<Scalar, Dynamic, Dynamic> b((I + lambda * L_bar).transpose());
|
||||
// for (int iter = 0; iter < p; ++iter)
|
||||
// {
|
||||
// Psi = b.ldlt().solve(Psi); // hangs here
|
||||
// }
|
||||
// Convert to sparse matrices and compute
|
||||
Matrix<Scalar, Dynamic, Dynamic> Psi = U_prime.sparseView();
|
||||
SparseMatrix<Scalar> b = (I + lambda * L_bar).transpose();
|
||||
SimplicialLDLT<SparseMatrix<Scalar>> ldlt_Psi;
|
||||
ldlt_Psi.compute(b);
|
||||
for (int iter = 0; iter < p; ++iter)
|
||||
{
|
||||
Psi = ldlt_Psi.solve(Psi);
|
||||
}
|
||||
|
||||
// P: #V by 10 precomputed upper triangle of
|
||||
// p_i p_i^T , p_i
|
||||
// p_i^T , 1
|
||||
// where p_i = (\sum_{j=1}^{n} Psi_{ij})'s top right 3 by 1 column
|
||||
Matrix<Scalar, Dynamic, 10> P(n, 10);
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
Matrix<Scalar, 3, 1> p_i = Matrix<Scalar, 3, 1>::Zero(3);
|
||||
Scalar last = 0;
|
||||
for (int j = 0; j < m; ++j)
|
||||
{
|
||||
Matrix<Scalar, 3, 1> p_i_curr(3);
|
||||
p_i_curr << Psi(i, j * 10 + 3), Psi(i, j * 10 + 6), Psi(i, j * 10 + 8);
|
||||
p_i += p_i_curr;
|
||||
last += Psi(i, j * 10 + 9);
|
||||
}
|
||||
p_i /= last; // normalize
|
||||
Matrix<Scalar, 4, 4> p_matrix(4, 4);
|
||||
p_matrix.block(0, 0, 3, 3) = p_i * p_i.transpose();
|
||||
p_matrix.block(0, 3, 3, 1) = p_i;
|
||||
p_matrix.block(3, 0, 1, 3) = p_i.transpose();
|
||||
p_matrix(3, 3) = 1;
|
||||
P.row(i) = extract_upper_triangle(p_matrix);
|
||||
}
|
||||
|
||||
// Omega
|
||||
Omega.resize(n, m * 10);
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
Matrix<Scalar, 10, 1> p_vector = P.row(i);
|
||||
for (int j = 0; j < m; ++j)
|
||||
{
|
||||
Matrix<Scalar, 10, 1> Omega_curr(10);
|
||||
Matrix<Scalar, 10, 1> Psi_curr = Psi.block(i, j * 10, 1, 10).transpose();
|
||||
Omega_curr = (1. - alpha) * Psi_curr + alpha * W_prime(i, j) * p_vector;
|
||||
Omega.block(i, j * 10, 1, 10) = Omega_curr.transpose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
|
||||
// Explicit template instantiation
|
||||
template void igl::direct_delta_mush<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&, std::vector<Eigen::Transform<double, 3, 2, 0>, Eigen::aligned_allocator<Eigen::Transform<double, 3, 2, 0> > > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&); template void igl::direct_delta_mush_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Xiangyu Kong <xiangyu.kong@mail.utoronto.ca>
|
||||
//
|
||||
// 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_DIRECT_DELTA_MUSH_H
|
||||
#define IGL_DIRECT_DELTA_MUSH_H
|
||||
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
#include <Eigen/Geometry>
|
||||
#include <vector>
|
||||
|
||||
namespace igl {
|
||||
// Computes Direct Delta Mesh Skinning (Variant 0) from "Direct Delta Mush
|
||||
// Skinning and Variants"
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of rest pose vertex positions
|
||||
// T #T list of bone pose transformations
|
||||
// Omega #V by #T*10 list of precomputated matrix values
|
||||
// Outputs:
|
||||
// U #V by 3 list of output vertex positions
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedOmega,
|
||||
typename DerivedU>
|
||||
IGL_INLINE void direct_delta_mush(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const std::vector<
|
||||
Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d>
|
||||
> & T, /* should eventually be templated more generally than double */
|
||||
const Eigen::MatrixBase<DerivedOmega> & Omega,
|
||||
Eigen::PlainObjectBase<DerivedU> & U);
|
||||
|
||||
// Precomputation
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of rest pose vertex positions
|
||||
// F #F by 3 list of triangle indices into rows of V
|
||||
// W #V by #Edges list of weights
|
||||
// p number of smoothing iterations
|
||||
// lambda rotation smoothing step size
|
||||
// kappa translation smoothness step size
|
||||
// alpha translation smoothness blending weight
|
||||
// Outputs:
|
||||
// Omega #V by #T*10 list of precomputated matrix values
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedW,
|
||||
typename DerivedOmega>
|
||||
IGL_INLINE void direct_delta_mush_precomputation(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedW> & W,
|
||||
const int p,
|
||||
const typename DerivedV::Scalar lambda,
|
||||
const typename DerivedV::Scalar kappa,
|
||||
const typename DerivedV::Scalar alpha,
|
||||
Eigen::PlainObjectBase<DerivedOmega> & Omega);
|
||||
} // namespace igl
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "direct_delta_mush.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -84,3 +84,41 @@ IGL_INLINE bool igl::edge_collapse_is_valid(
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::edge_collapse_is_valid(
|
||||
std::vector<int> & Nsv,
|
||||
std::vector<int> & Ndv)
|
||||
{
|
||||
// Do we really need to check if edge is IGL_COLLAPSE_EDGE_NULL ?
|
||||
|
||||
if(Nsv.size()<2 || Ndv.size()<2)
|
||||
{
|
||||
// Bogus data
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
// determine if the first two vertices are the same before reordering.
|
||||
// If they are and there are 3 each, then (I claim) this is an edge on a
|
||||
// single tet.
|
||||
const bool first_two_same = (Nsv[0] == Ndv[0]) && (Nsv[1] == Ndv[1]);
|
||||
if(Nsv.size() == 3 && Ndv.size() == 3 && first_two_same)
|
||||
{
|
||||
// single tet
|
||||
return false;
|
||||
}
|
||||
// https://stackoverflow.com/a/19483741/148668
|
||||
std::sort(Nsv.begin(), Nsv.end());
|
||||
std::sort(Ndv.begin(), Ndv.end());
|
||||
std::vector<int> Nint;
|
||||
std::set_intersection(
|
||||
Nsv.begin(), Nsv.end(), Ndv.begin(), Ndv.end(), std::back_inserter(Nint));
|
||||
// check if edge collapse is valid: intersection of vertex neighbors of s and
|
||||
// d should be exactly 2+(s,d) = 4
|
||||
// http://stackoverflow.com/a/27049418/148668
|
||||
if(Nint.size() != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define IGL_EDGE_COLLAPSE_IS_VALID_H
|
||||
#include "igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
namespace igl
|
||||
{
|
||||
// Assumes (V,F) is a closed manifold mesh (except for previouslly collapsed
|
||||
@@ -37,6 +38,20 @@ namespace igl
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI);
|
||||
// Inputs:
|
||||
// Nsv #Nsv list of "next" vertices circulating around starting vertex of
|
||||
// edge
|
||||
// Ndv #Ndv list of "next" vertices circulating around destination vertex of
|
||||
// edge
|
||||
// Outputs:
|
||||
// Nsv (side-effect: sorted by value)
|
||||
// Ndv (side-effect: sorted by value)
|
||||
// Returns true iff edge collapse is valid
|
||||
//
|
||||
// See also: circulation
|
||||
IGL_INLINE bool edge_collapse_is_valid(
|
||||
/*const*/ std::vector<int> & Nsv,
|
||||
/*const*/ std::vector<int> & Ndv);
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "edge_collapse_is_valid.cpp"
|
||||
|
||||
@@ -51,8 +51,7 @@ IGL_INLINE void igl::edge_flaps(
|
||||
Eigen::MatrixXi & EI)
|
||||
{
|
||||
Eigen::MatrixXi allE;
|
||||
std::vector<std::vector<int> > uE2E;
|
||||
igl::unique_edge_map(F,allE,uE,EMAP,uE2E);
|
||||
igl::unique_edge_map(F,allE,uE,EMAP);
|
||||
// Const-ify to call overload
|
||||
const auto & cuE = uE;
|
||||
const auto & cEMAP = EMAP;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// Copyright (C) 2020 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
|
||||
|
||||
@@ -22,6 +22,8 @@ IGL_INLINE void igl::edge_lengths(
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(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, 6, 0, -1, 6> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::edge_lengths<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(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, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::edge_lengths<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "edge_midpoints.h"
|
||||
|
||||
template<typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename Derivedmps>
|
||||
IGL_INLINE void
|
||||
igl::edge_midpoints(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<Derivedmps> &mps)
|
||||
{
|
||||
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
|
||||
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
|
||||
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
|
||||
"This method is for triangle meshes.");
|
||||
assert(F.maxCoeff()<V.rows() && "V does not seem to belong to F.");
|
||||
|
||||
using ScalarE = typename DerivedE::Scalar;
|
||||
using ScalarF = typename DerivedF::Scalar;
|
||||
|
||||
const ScalarE m = E.maxCoeff()+1;
|
||||
|
||||
mps.resize(m, V.cols());
|
||||
for(Eigen::Index i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
if(oE(i,j)<0) {
|
||||
continue;
|
||||
}
|
||||
const ScalarE e = E(i,j);
|
||||
const ScalarF vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
|
||||
|
||||
mps.row(e) = 0.5*(V.row(vi) + V.row(vj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::edge_midpoints<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_EDGE_MIDPOINTS_H
|
||||
#define IGL_EDGE_MIDPOINTS_H
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
namespace igl
|
||||
{
|
||||
// Computes the midpoints of edges in a triangle mesh.
|
||||
//
|
||||
// Input:
|
||||
// V, F: triangle mesh
|
||||
// E, oE: mapping from halfedges to edges and orientation as generated by
|
||||
// orient_halfedges
|
||||
//
|
||||
// Output:
|
||||
// mps: edge midpoints, one per edge in E
|
||||
template<typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename Derivedmps>
|
||||
IGL_INLINE void edge_midpoints(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<Derivedmps> &mps);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "edge_midpoints.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "edge_vectors.h"
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
#include "per_face_normals.h"
|
||||
|
||||
#include "PI.h"
|
||||
|
||||
|
||||
template<typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename Derivedvec>
|
||||
IGL_INLINE void
|
||||
igl::edge_vectors(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<Derivedvec> &vec)
|
||||
{
|
||||
Eigen::Matrix<typename Derivedvec::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
dummy;
|
||||
edge_vectors<false>(V, F, E, oE, vec, dummy);
|
||||
}
|
||||
|
||||
|
||||
template<bool computePerpendicular,
|
||||
typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename DerivedvecParallel,
|
||||
typename DerivedvecPerpendicular>
|
||||
IGL_INLINE void
|
||||
igl::edge_vectors(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<DerivedvecParallel> &vecParallel,
|
||||
Eigen::PlainObjectBase<DerivedvecPerpendicular> &vecPerpendicular)
|
||||
{
|
||||
using Scalar = typename DerivedvecParallel::Scalar;
|
||||
using MatX = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
|
||||
|
||||
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
|
||||
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
|
||||
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
|
||||
"This method is for triangle meshes.");
|
||||
assert(F.maxCoeff()<V.rows() && "V does not seem to belong to F.");
|
||||
|
||||
const typename DerivedE::Scalar m = E.maxCoeff()+1;
|
||||
|
||||
//Compute edge-based normal
|
||||
MatX N, edgeN(m, 3);
|
||||
edgeN.setZero();
|
||||
per_face_normals(V, F, N);
|
||||
for(Eigen::Index i=0; i<E.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
edgeN.row(E(i,j)) += N.row(i);
|
||||
}
|
||||
}
|
||||
edgeN.rowwise().normalize();
|
||||
|
||||
//Compute edge vectors
|
||||
vecParallel.resize(m, 3);
|
||||
if(computePerpendicular) { //This should ideally be an if constexpr
|
||||
vecPerpendicular.resize(m, 3);
|
||||
}
|
||||
for(Eigen::Index i=0; i<E.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
if(oE(i,j)<0) {
|
||||
continue;
|
||||
}
|
||||
const typename DerivedE::Scalar e=E(i,j);
|
||||
const typename DerivedF::Scalar vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
|
||||
vecParallel.row(e) = (V.row(vj)-V.row(vi)).normalized();
|
||||
if(computePerpendicular) { //This should ideally be an if constexpr
|
||||
vecPerpendicular.row(e) =
|
||||
Eigen::AngleAxis<Scalar>(0.5*PI, edgeN.row(e)) *
|
||||
vecParallel.row(e).transpose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::edge_vectors<true, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<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<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_EDGE_VECTORS_H
|
||||
#define IGL_EDGE_VECTORS_H
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
namespace igl
|
||||
{
|
||||
// Computes the normalized edge vectors for edges in a triangle mesh
|
||||
//
|
||||
// Input:
|
||||
// V, F: triangle mesh
|
||||
// E, oE: mapping from halfedges to edges and orientation as generated by
|
||||
// orient_halfedges
|
||||
//
|
||||
// Output:
|
||||
// vec: normalized edge vectors for each unique edge in E, according to order
|
||||
// of E.
|
||||
template<typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename Derivedvec>
|
||||
IGL_INLINE void edge_vectors(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<Derivedvec> &vec);
|
||||
|
||||
|
||||
// Computes the normalized edge vectors for edges in a triangle mesh
|
||||
//
|
||||
// Input:
|
||||
// V, F: triangle mesh
|
||||
// E, oE: mapping from halfedges to edges and orientation as generated by
|
||||
// orient_halfedges
|
||||
// template parameter computePerpendicular: whether to compute
|
||||
// vecPerpendicular or not.
|
||||
//
|
||||
// Output:
|
||||
// vecParallel: normalized edge vectors for each unique edge in E, according
|
||||
// to order of E.
|
||||
// vecPerpendicular: tangent unit perpendicular vector to each edge, according
|
||||
// to orientation in oE, corresponds to each vector in
|
||||
// vecParallel rotated by pi/2 around an edge-based normal.
|
||||
//
|
||||
template<bool computePerpendicular=true,
|
||||
typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename DerivedvecParallel,
|
||||
typename DerivedvecPerpendicular>
|
||||
IGL_INLINE void edge_vectors(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<DerivedvecParallel> &vecParallel,
|
||||
Eigen::PlainObjectBase<DerivedvecPerpendicular> &vecPerpendicular);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "edge_vectors.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+24
-1
@@ -18,6 +18,26 @@ IGL_INLINE void igl::edges(
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
Eigen::SparseMatrix<Index> A;
|
||||
igl::adjacency_matrix(F,A);
|
||||
igl::edges(A,E);
|
||||
}
|
||||
|
||||
template <typename DerivedI, typename DerivedC, typename DerivedE>
|
||||
IGL_INLINE void igl::edges(
|
||||
const Eigen::MatrixBase<DerivedI> & I,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedE> & E)
|
||||
{
|
||||
typedef typename DerivedE::Scalar Index;
|
||||
Eigen::SparseMatrix<Index> A;
|
||||
igl::adjacency_matrix(I,C,A);
|
||||
igl::edges(A,E);
|
||||
}
|
||||
|
||||
template <typename T, typename DerivedE>
|
||||
IGL_INLINE void igl::edges(
|
||||
const Eigen::SparseMatrix<T> & A,
|
||||
Eigen::PlainObjectBase<DerivedE> & E)
|
||||
{
|
||||
// Number of non zeros should be twice number of edges
|
||||
assert(A.nonZeros()%2 == 0);
|
||||
// Resize to fit edges
|
||||
@@ -27,7 +47,7 @@ IGL_INLINE void igl::edges(
|
||||
for(int k=0; k<A.outerSize(); ++k)
|
||||
{
|
||||
// Iterate over inside
|
||||
for(typename Eigen::SparseMatrix<Index>::InnerIterator it (A,k); it; ++it)
|
||||
for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
// only add edge in one direction
|
||||
if(it.row()<it.col())
|
||||
@@ -38,10 +58,13 @@ IGL_INLINE void igl::edges(
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(i == E.rows() && "A should be symmetric");
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::edges<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
|
||||
template void igl::edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
@@ -27,6 +28,28 @@ namespace igl
|
||||
IGL_INLINE void edges(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedE> & E);
|
||||
// Constructs a list of unique edges represented in a given polygon mesh.
|
||||
//
|
||||
// Inputs:
|
||||
// I #I vectorized list of polygon corner indices into rows of some matrix V
|
||||
// C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) =
|
||||
// size of the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the
|
||||
// indices of the ith polygon
|
||||
// Outputs:
|
||||
// E #E by 2 list of edges in no particular order
|
||||
template <typename DerivedI, typename DerivedC, typename DerivedE>
|
||||
IGL_INLINE void edges(
|
||||
const Eigen::MatrixBase<DerivedI> & I,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedE> & E);
|
||||
// Inputs:
|
||||
// A #V by #V symmetric adjacency matrix
|
||||
// Outputs:
|
||||
// E #E by 2 list of edges in no particular order
|
||||
template <typename T, typename DerivedE>
|
||||
IGL_INLINE void edges(
|
||||
const Eigen::SparseMatrix<T> & A,
|
||||
Eigen::PlainObjectBase<DerivedE> & E);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
|
||||
// 2013 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// 2014 Christian Schüller <schuellchr@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_EMBREE_EMBREE_DEVICE_H
|
||||
#define IGL_EMBREE_EMBREE_DEVICE_H
|
||||
#include <embree3/rtcore.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace embree
|
||||
{
|
||||
// keep track of embree device
|
||||
struct EmbreeDevice
|
||||
{
|
||||
RTCDevice embree_device;
|
||||
int embree_device_cntr;
|
||||
|
||||
static EmbreeDevice & instance()
|
||||
{
|
||||
static EmbreeDevice s;
|
||||
return s;
|
||||
} // instance
|
||||
|
||||
EmbreeDevice(const EmbreeDevice &) = delete;
|
||||
EmbreeDevice & operator = (const EmbreeDevice &) = delete;
|
||||
|
||||
static RTCDevice get_device(const char *config=nullptr)
|
||||
{
|
||||
return instance().get(config);
|
||||
}
|
||||
|
||||
static void release_device(void)
|
||||
{
|
||||
instance().release();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
EmbreeDevice():embree_device(nullptr),embree_device_cntr(0) {}
|
||||
|
||||
~EmbreeDevice()
|
||||
{
|
||||
if(embree_device)
|
||||
rtcReleaseDevice(embree_device);
|
||||
}
|
||||
|
||||
RTCDevice get(const char *config=nullptr)
|
||||
{
|
||||
if(!embree_device)
|
||||
{
|
||||
embree_device = rtcNewDevice (config);
|
||||
if(rtcGetDeviceError (embree_device) != RTC_ERROR_NONE)
|
||||
std::cerr << "Embree: An error occurred while initializing embree core!" << std::endl;
|
||||
#ifdef IGL_VERBOSE
|
||||
else
|
||||
std::cerr << "Embree: core initialized." << std::endl;
|
||||
#endif
|
||||
}
|
||||
++embree_device_cntr;
|
||||
return embree_device;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if(!--embree_device_cntr) {
|
||||
rtcReleaseDevice (embree_device);
|
||||
embree_device = nullptr;
|
||||
#ifdef IGL_VERBOSE
|
||||
std::cerr << "Embree: core released." << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IGL_EMBREE_EMBREE_DEVICE_H
|
||||
@@ -0,0 +1,396 @@
|
||||
|
||||
#include "EmbreeIntersector.h"
|
||||
|
||||
// Implementation
|
||||
#include <igl/EPS.h>
|
||||
|
||||
IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector()
|
||||
:
|
||||
//scene(NULL),
|
||||
geomID(0),
|
||||
vertices(NULL),
|
||||
triangles(NULL),
|
||||
initialized(false),
|
||||
device(igl::embree::EmbreeDevice::get_device())
|
||||
{
|
||||
}
|
||||
|
||||
IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector(
|
||||
const EmbreeIntersector &)
|
||||
:// To make -Weffc++ happy
|
||||
//scene(NULL),
|
||||
geomID(0),
|
||||
vertices(NULL),
|
||||
triangles(NULL),
|
||||
initialized(false)
|
||||
{
|
||||
assert(false && "Embree: Copying EmbreeIntersector is not allowed");
|
||||
}
|
||||
|
||||
IGL_INLINE igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
|
||||
const EmbreeIntersector &)
|
||||
{
|
||||
assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void igl::embree::EmbreeIntersector::init(
|
||||
const PointMatrixType& V,
|
||||
const FaceMatrixType& F,
|
||||
bool isStatic)
|
||||
{
|
||||
std::vector<const PointMatrixType*> Vtemp;
|
||||
std::vector<const FaceMatrixType*> Ftemp;
|
||||
std::vector<int> masks;
|
||||
Vtemp.push_back(&V);
|
||||
Ftemp.push_back(&F);
|
||||
masks.push_back(0xFFFFFFFF);
|
||||
init(Vtemp,Ftemp,masks,isStatic);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::embree::EmbreeIntersector::init(
|
||||
const std::vector<const PointMatrixType*>& V,
|
||||
const std::vector<const FaceMatrixType*>& F,
|
||||
const std::vector<int>& masks,
|
||||
bool isStatic)
|
||||
{
|
||||
|
||||
if(initialized)
|
||||
deinit();
|
||||
|
||||
using namespace std;
|
||||
|
||||
if(V.size() == 0 || F.size() == 0)
|
||||
{
|
||||
std::cerr << "Embree: No geometry specified!";
|
||||
return;
|
||||
}
|
||||
|
||||
RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
|
||||
|
||||
// create a scene
|
||||
scene = rtcNewScene(device);
|
||||
rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
|
||||
rtcSetSceneBuildQuality(scene, buildQuality);
|
||||
|
||||
for(int g=0;g<(int)V.size();g++)
|
||||
{
|
||||
// create triangle mesh geometry in that scene
|
||||
RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE);
|
||||
rtcSetGeometryBuildQuality(geom_0,buildQuality);
|
||||
rtcSetGeometryTimeStepCount(geom_0,1);
|
||||
geomID = rtcAttachGeometry(scene,geom_0);
|
||||
rtcReleaseGeometry(geom_0);
|
||||
|
||||
// fill vertex buffer
|
||||
vertices = (Vertex*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows());
|
||||
for(int i=0;i<(int)V[g]->rows();i++)
|
||||
{
|
||||
vertices[i].x = (float)V[g]->coeff(i,0);
|
||||
vertices[i].y = (float)V[g]->coeff(i,1);
|
||||
vertices[i].z = (float)V[g]->coeff(i,2);
|
||||
}
|
||||
|
||||
|
||||
// fill triangle buffer
|
||||
triangles = (Triangle*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(int),F[g]->rows());
|
||||
for(int i=0;i<(int)F[g]->rows();i++)
|
||||
{
|
||||
triangles[i].v0 = (int)F[g]->coeff(i,0);
|
||||
triangles[i].v1 = (int)F[g]->coeff(i,1);
|
||||
triangles[i].v2 = (int)F[g]->coeff(i,2);
|
||||
}
|
||||
|
||||
|
||||
rtcSetGeometryMask(geom_0,masks[g]);
|
||||
rtcCommitGeometry(geom_0);
|
||||
}
|
||||
|
||||
rtcCommitScene(scene);
|
||||
|
||||
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
|
||||
std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
|
||||
#ifdef IGL_VERBOSE
|
||||
else
|
||||
std::cerr << "Embree: geometry added." << endl;
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
igl::embree::EmbreeIntersector
|
||||
::~EmbreeIntersector()
|
||||
{
|
||||
if(initialized)
|
||||
deinit();
|
||||
igl::embree::EmbreeDevice::release_device();
|
||||
}
|
||||
|
||||
void igl::embree::EmbreeIntersector::deinit()
|
||||
{
|
||||
if(device && scene)
|
||||
{
|
||||
rtcReleaseScene(scene);
|
||||
|
||||
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
|
||||
{
|
||||
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
|
||||
}
|
||||
#ifdef IGL_VERBOSE
|
||||
else
|
||||
{
|
||||
std::cerr << "Embree: geometry removed." << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::embree::EmbreeIntersector::intersectRay(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
Hit& hit,
|
||||
float tnear,
|
||||
float tfar,
|
||||
int mask) const
|
||||
{
|
||||
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
|
||||
ray.ray.flags = 0;
|
||||
createRay(ray, origin,direction,tnear,tfar,mask);
|
||||
|
||||
// shot ray
|
||||
{
|
||||
RTCIntersectContext context;
|
||||
rtcInitIntersectContext(&context);
|
||||
rtcIntersect1(scene,&context,&ray);
|
||||
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
|
||||
ray.hit.Ng_y = -ray.hit.Ng_y;
|
||||
ray.hit.Ng_z = -ray.hit.Ng_z;
|
||||
}
|
||||
#ifdef IGL_VERBOSE
|
||||
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
|
||||
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
|
||||
#endif
|
||||
|
||||
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
|
||||
{
|
||||
hit.id = ray.hit.primID;
|
||||
hit.gid = ray.hit.geomID;
|
||||
hit.u = ray.hit.u;
|
||||
hit.v = ray.hit.v;
|
||||
hit.t = ray.ray.tfar;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::embree::EmbreeIntersector::intersectBeam(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
Hit& hit,
|
||||
float tnear,
|
||||
float tfar,
|
||||
int mask,
|
||||
int geoId,
|
||||
bool closestHit,
|
||||
unsigned int samples) const
|
||||
{
|
||||
bool hasHit = false;
|
||||
Hit bestHit;
|
||||
|
||||
if(closestHit)
|
||||
bestHit.t = std::numeric_limits<float>::max();
|
||||
else
|
||||
bestHit.t = 0;
|
||||
|
||||
if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
|
||||
{
|
||||
bestHit = hit;
|
||||
hasHit = true;
|
||||
}
|
||||
|
||||
// sample points around actual ray (conservative hitcheck)
|
||||
const float eps= 1e-5;
|
||||
|
||||
Eigen::RowVector3f up(0,1,0);
|
||||
if (direction.cross(up).norm() < eps) up = Eigen::RowVector3f(1,0,0);
|
||||
Eigen::RowVector3f offset = direction.cross(up).normalized();
|
||||
|
||||
Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
|
||||
|
||||
for(int r=0;r<(int)samples;r++)
|
||||
{
|
||||
if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) &&
|
||||
((closestHit && (hit.t < bestHit.t)) ||
|
||||
(!closestHit && (hit.t > bestHit.t))) &&
|
||||
(hit.gid == geoId || geoId == -1))
|
||||
{
|
||||
bestHit = hit;
|
||||
hasHit = true;
|
||||
}
|
||||
offset = rot*offset.transpose();
|
||||
}
|
||||
|
||||
hit = bestHit;
|
||||
return hasHit;
|
||||
}
|
||||
|
||||
IGL_INLINE bool
|
||||
igl::embree::EmbreeIntersector
|
||||
::intersectRay(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
std::vector<Hit > &hits,
|
||||
int& num_rays,
|
||||
float tnear,
|
||||
float tfar,
|
||||
int mask) const
|
||||
{
|
||||
using namespace std;
|
||||
num_rays = 0;
|
||||
hits.clear();
|
||||
int last_id0 = -1;
|
||||
double self_hits = 0;
|
||||
// This epsilon is directly correleated to the number of missed hits, smaller
|
||||
// means more accurate and slower
|
||||
//const double eps = DOUBLE_EPS;
|
||||
const double eps = FLOAT_EPS;
|
||||
double min_t = tnear;
|
||||
bool large_hits_warned = false;
|
||||
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
|
||||
ray.ray.flags = 0;
|
||||
createRay(ray,origin,direction,tnear,tfar,mask);
|
||||
|
||||
while(true)
|
||||
{
|
||||
ray.ray.tnear = min_t;
|
||||
ray.ray.tfar = tfar;
|
||||
ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
|
||||
num_rays++;
|
||||
{
|
||||
RTCIntersectContext context;
|
||||
rtcInitIntersectContext(&context);
|
||||
rtcIntersect1(scene,&context,&ray);
|
||||
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
|
||||
ray.hit.Ng_y = -ray.hit.Ng_y;
|
||||
ray.hit.Ng_z = -ray.hit.Ng_z;
|
||||
}
|
||||
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
|
||||
{
|
||||
// Hit self again, progressively advance
|
||||
if(ray.hit.primID == last_id0 || ray.ray.tfar <= min_t)
|
||||
{
|
||||
// push min_t a bit more
|
||||
//double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
|
||||
double t_push = pow(2.0,self_hits)*eps;
|
||||
#ifdef IGL_VERBOSE
|
||||
std::cerr<<" t_push: "<<t_push<<endl;
|
||||
#endif
|
||||
//o = o+t_push*d;
|
||||
min_t += t_push;
|
||||
self_hits++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Hit hit;
|
||||
hit.id = ray.hit.primID;
|
||||
hit.gid = ray.hit.geomID;
|
||||
hit.u = ray.hit.u;
|
||||
hit.v = ray.hit.v;
|
||||
hit.t = ray.ray.tfar;
|
||||
hits.push_back(hit);
|
||||
#ifdef IGL_VERBOSE
|
||||
std::cerr<<" t: "<<hit.t<<endl;
|
||||
#endif
|
||||
// Instead of moving origin, just change min_t. That way calculations
|
||||
// all use exactly same origin values
|
||||
min_t = ray.ray.tfar;
|
||||
|
||||
// reset t_scale
|
||||
self_hits = 0;
|
||||
}
|
||||
last_id0 = ray.hit.primID;
|
||||
}
|
||||
else
|
||||
break; // no more hits
|
||||
|
||||
if(hits.size()>1000 && !large_hits_warned)
|
||||
{
|
||||
std::cout<<"Warning: Large number of hits..."<<endl;
|
||||
std::cout<<"[ ";
|
||||
for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
|
||||
{
|
||||
std::cout<<(hit->id+1)<<" ";
|
||||
}
|
||||
|
||||
std::cout.precision(std::numeric_limits< double >::digits10);
|
||||
std::cout<<"[ ";
|
||||
|
||||
for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
|
||||
{
|
||||
std::cout<<(hit->t)<<endl;;
|
||||
}
|
||||
|
||||
std::cout<<"]"<<endl;
|
||||
large_hits_warned = true;
|
||||
|
||||
return hits.empty();
|
||||
}
|
||||
}
|
||||
|
||||
return hits.empty();
|
||||
}
|
||||
|
||||
IGL_INLINE bool
|
||||
igl::embree::EmbreeIntersector
|
||||
::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
|
||||
{
|
||||
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
|
||||
ray.ray.flags = 0;
|
||||
createRay(ray,a,ab,0,1.0,mask);
|
||||
|
||||
{
|
||||
RTCIntersectContext context;
|
||||
rtcInitIntersectContext(&context);
|
||||
rtcIntersect1(scene,&context,&ray);
|
||||
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
|
||||
ray.hit.Ng_y = -ray.hit.Ng_y;
|
||||
ray.hit.Ng_z = -ray.hit.Ng_z;
|
||||
}
|
||||
|
||||
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
|
||||
{
|
||||
hit.id = ray.hit.primID;
|
||||
hit.gid = ray.hit.geomID;
|
||||
hit.u = ray.hit.u;
|
||||
hit.v = ray.hit.v;
|
||||
hit.t = ray.ray.tfar;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeIntersector
|
||||
::createRay(RTCRayHit& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
|
||||
{
|
||||
ray.ray.org_x = origin[0];
|
||||
ray.ray.org_y = origin[1];
|
||||
ray.ray.org_z = origin[2];
|
||||
ray.ray.dir_x = direction[0];
|
||||
ray.ray.dir_y = direction[1];
|
||||
ray.ray.dir_z = direction[2];
|
||||
ray.ray.tnear = tnear;
|
||||
ray.ray.tfar = tfar;
|
||||
ray.ray.id = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.ray.mask = mask;
|
||||
ray.ray.time = 0.0f;
|
||||
|
||||
ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
|
||||
}
|
||||
@@ -19,38 +19,31 @@
|
||||
#include "../Hit.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#include <embree3/rtcore.h>
|
||||
#include <embree3/rtcore_ray.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "EmbreeDevice.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace embree
|
||||
{
|
||||
class EmbreeIntersector
|
||||
{
|
||||
public:
|
||||
// Initialize embree engine. This will be called on instance `init()`
|
||||
// calls. If already inited then this function does nothing: it is harmless
|
||||
// to call more than once.
|
||||
static inline void global_init();
|
||||
private:
|
||||
// Deinitialize the embree engine.
|
||||
static inline void global_deinit();
|
||||
public:
|
||||
typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
|
||||
typedef Eigen::Matrix<int,Eigen::Dynamic,3> FaceMatrixType;
|
||||
public:
|
||||
inline EmbreeIntersector();
|
||||
EmbreeIntersector();
|
||||
private:
|
||||
// Copying and assignment are not allowed.
|
||||
inline EmbreeIntersector(const EmbreeIntersector & that);
|
||||
inline EmbreeIntersector & operator=(const EmbreeIntersector &);
|
||||
EmbreeIntersector(const EmbreeIntersector & that);
|
||||
EmbreeIntersector & operator=(const EmbreeIntersector &);
|
||||
public:
|
||||
virtual inline ~EmbreeIntersector();
|
||||
virtual ~EmbreeIntersector();
|
||||
|
||||
// Initialize with a given mesh.
|
||||
//
|
||||
@@ -60,7 +53,7 @@ namespace igl
|
||||
// isStatic scene is optimized for static geometry
|
||||
// Side effects:
|
||||
// The first time this is ever called the embree engine is initialized.
|
||||
inline void init(
|
||||
void init(
|
||||
const PointMatrixType& V,
|
||||
const FaceMatrixType& F,
|
||||
bool isStatic = false);
|
||||
@@ -74,7 +67,7 @@ namespace igl
|
||||
// isStatic scene is optimized for static geometry
|
||||
// Side effects:
|
||||
// The first time this is ever called the embree engine is initialized.
|
||||
inline void init(
|
||||
void init(
|
||||
const std::vector<const PointMatrixType*>& V,
|
||||
const std::vector<const FaceMatrixType*>& F,
|
||||
const std::vector<int>& masks,
|
||||
@@ -83,7 +76,7 @@ namespace igl
|
||||
// Deinitialize embree datasctructures for current mesh. Also called on
|
||||
// destruction: no need to call if you just want to init() once and
|
||||
// destroy.
|
||||
inline void deinit();
|
||||
void deinit();
|
||||
|
||||
// Given a ray find the first hit
|
||||
//
|
||||
@@ -96,7 +89,7 @@ namespace igl
|
||||
// Output:
|
||||
// hit information about hit
|
||||
// Returns true if and only if there was a hit
|
||||
inline bool intersectRay(
|
||||
bool intersectRay(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
Hit& hit,
|
||||
@@ -119,7 +112,7 @@ namespace igl
|
||||
// Output:
|
||||
// hit information about hit
|
||||
// Returns true if and only if there was a hit
|
||||
inline bool intersectBeam(
|
||||
bool intersectBeam(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
Hit& hit,
|
||||
@@ -142,7 +135,7 @@ namespace igl
|
||||
// hit information about hit
|
||||
// num_rays number of rays shot (at least one)
|
||||
// Returns true if and only if there was a hit
|
||||
inline bool intersectRay(
|
||||
bool intersectRay(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
std::vector<Hit > &hits,
|
||||
@@ -159,7 +152,7 @@ namespace igl
|
||||
// Output:
|
||||
// hit information about hit
|
||||
// Returns true if and only if there was a hit
|
||||
inline bool intersectSegment(
|
||||
bool intersectSegment(
|
||||
const Eigen::RowVector3f& a,
|
||||
const Eigen::RowVector3f& ab,
|
||||
Hit &hit,
|
||||
@@ -176,7 +169,9 @@ namespace igl
|
||||
Triangle* triangles;
|
||||
bool initialized;
|
||||
|
||||
inline void createRay(
|
||||
RTCDevice device;
|
||||
|
||||
void createRay(
|
||||
RTCRayHit& ray,
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
@@ -187,430 +182,8 @@ namespace igl
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation
|
||||
#include <igl/EPS.h>
|
||||
// This unfortunately cannot be a static field of EmbreeIntersector because it
|
||||
// would depend on the template and then we might end up with initializing
|
||||
// embree twice. If only there was a way to ask embree if it's already
|
||||
// initialized...
|
||||
namespace igl
|
||||
{
|
||||
namespace embree
|
||||
{
|
||||
// Keeps track of whether the **Global** Embree intersector has been
|
||||
// initialized. This should never been done at the global scope.
|
||||
static RTCDevice g_device = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline void igl::embree::EmbreeIntersector::global_init()
|
||||
{
|
||||
if(!g_device)
|
||||
{
|
||||
g_device = rtcNewDevice (NULL);
|
||||
if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
|
||||
std::cerr << "Embree: An error occurred while initializing embree core!" << std::endl;
|
||||
#ifdef IGL_VERBOSE
|
||||
else
|
||||
std::cerr << "Embree: core initialized." << std::endl;
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "EmbreeIntersector.cpp"
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline void igl::embree::EmbreeIntersector::global_deinit()
|
||||
{
|
||||
rtcReleaseDevice (g_device);
|
||||
g_device = nullptr;
|
||||
}
|
||||
|
||||
inline igl::embree::EmbreeIntersector::EmbreeIntersector()
|
||||
:
|
||||
//scene(NULL),
|
||||
geomID(0),
|
||||
vertices(NULL),
|
||||
triangles(NULL),
|
||||
initialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
inline igl::embree::EmbreeIntersector::EmbreeIntersector(
|
||||
const EmbreeIntersector &)
|
||||
:// To make -Weffc++ happy
|
||||
//scene(NULL),
|
||||
geomID(0),
|
||||
vertices(NULL),
|
||||
triangles(NULL),
|
||||
initialized(false)
|
||||
{
|
||||
assert(false && "Embree: Copying EmbreeIntersector is not allowed");
|
||||
}
|
||||
|
||||
inline igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
|
||||
const EmbreeIntersector &)
|
||||
{
|
||||
assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline void igl::embree::EmbreeIntersector::init(
|
||||
const PointMatrixType& V,
|
||||
const FaceMatrixType& F,
|
||||
bool isStatic)
|
||||
{
|
||||
std::vector<const PointMatrixType*> Vtemp;
|
||||
std::vector<const FaceMatrixType*> Ftemp;
|
||||
std::vector<int> masks;
|
||||
Vtemp.push_back(&V);
|
||||
Ftemp.push_back(&F);
|
||||
masks.push_back(0xFFFFFFFF);
|
||||
init(Vtemp,Ftemp,masks,isStatic);
|
||||
}
|
||||
|
||||
inline void igl::embree::EmbreeIntersector::init(
|
||||
const std::vector<const PointMatrixType*>& V,
|
||||
const std::vector<const FaceMatrixType*>& F,
|
||||
const std::vector<int>& masks,
|
||||
bool isStatic)
|
||||
{
|
||||
|
||||
if(initialized)
|
||||
deinit();
|
||||
|
||||
using namespace std;
|
||||
global_init();
|
||||
|
||||
if(V.size() == 0 || F.size() == 0)
|
||||
{
|
||||
std::cerr << "Embree: No geometry specified!";
|
||||
return;
|
||||
}
|
||||
|
||||
RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
|
||||
|
||||
// create a scene
|
||||
scene = rtcNewScene(g_device);
|
||||
rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
|
||||
rtcSetSceneBuildQuality(scene, buildQuality);
|
||||
|
||||
for(int g=0;g<(int)V.size();g++)
|
||||
{
|
||||
// create triangle mesh geometry in that scene
|
||||
RTCGeometry geom_0 = rtcNewGeometry (g_device, RTC_GEOMETRY_TYPE_TRIANGLE);
|
||||
rtcSetGeometryBuildQuality(geom_0,buildQuality);
|
||||
rtcSetGeometryTimeStepCount(geom_0,1);
|
||||
geomID = rtcAttachGeometry(scene,geom_0);
|
||||
rtcReleaseGeometry(geom_0);
|
||||
|
||||
// fill vertex buffer
|
||||
vertices = (Vertex*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows());
|
||||
for(int i=0;i<(int)V[g]->rows();i++)
|
||||
{
|
||||
vertices[i].x = (float)V[g]->coeff(i,0);
|
||||
vertices[i].y = (float)V[g]->coeff(i,1);
|
||||
vertices[i].z = (float)V[g]->coeff(i,2);
|
||||
}
|
||||
|
||||
|
||||
// fill triangle buffer
|
||||
triangles = (Triangle*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(int),F[g]->rows());
|
||||
for(int i=0;i<(int)F[g]->rows();i++)
|
||||
{
|
||||
triangles[i].v0 = (int)F[g]->coeff(i,0);
|
||||
triangles[i].v1 = (int)F[g]->coeff(i,1);
|
||||
triangles[i].v2 = (int)F[g]->coeff(i,2);
|
||||
}
|
||||
|
||||
|
||||
rtcSetGeometryMask(geom_0,masks[g]);
|
||||
rtcCommitGeometry(geom_0);
|
||||
}
|
||||
|
||||
rtcCommitScene(scene);
|
||||
|
||||
if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
|
||||
std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
|
||||
#ifdef IGL_VERBOSE
|
||||
else
|
||||
std::cerr << "Embree: geometry added." << endl;
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
igl::embree::EmbreeIntersector
|
||||
::~EmbreeIntersector()
|
||||
{
|
||||
if(initialized)
|
||||
deinit();
|
||||
}
|
||||
|
||||
void igl::embree::EmbreeIntersector::deinit()
|
||||
{
|
||||
if(g_device && scene)
|
||||
{
|
||||
rtcReleaseScene(scene);
|
||||
|
||||
if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
|
||||
{
|
||||
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
|
||||
}
|
||||
#ifdef IGL_VERBOSE
|
||||
else
|
||||
{
|
||||
std::cerr << "Embree: geometry removed." << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline bool igl::embree::EmbreeIntersector::intersectRay(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
Hit& hit,
|
||||
float tnear,
|
||||
float tfar,
|
||||
int mask) const
|
||||
{
|
||||
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
|
||||
ray.ray.flags = 0;
|
||||
createRay(ray, origin,direction,tnear,tfar,mask);
|
||||
|
||||
// shot ray
|
||||
{
|
||||
RTCIntersectContext context;
|
||||
rtcInitIntersectContext(&context);
|
||||
rtcIntersect1(scene,&context,&ray);
|
||||
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
|
||||
ray.hit.Ng_y = -ray.hit.Ng_y;
|
||||
ray.hit.Ng_z = -ray.hit.Ng_z;
|
||||
}
|
||||
#ifdef IGL_VERBOSE
|
||||
if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
|
||||
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
|
||||
#endif
|
||||
|
||||
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
|
||||
{
|
||||
hit.id = ray.hit.primID;
|
||||
hit.gid = ray.hit.geomID;
|
||||
hit.u = ray.hit.u;
|
||||
hit.v = ray.hit.v;
|
||||
hit.t = ray.ray.tfar;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool igl::embree::EmbreeIntersector::intersectBeam(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
Hit& hit,
|
||||
float tnear,
|
||||
float tfar,
|
||||
int mask,
|
||||
int geoId,
|
||||
bool closestHit,
|
||||
unsigned int samples) const
|
||||
{
|
||||
bool hasHit = false;
|
||||
Hit bestHit;
|
||||
|
||||
if(closestHit)
|
||||
bestHit.t = std::numeric_limits<float>::max();
|
||||
else
|
||||
bestHit.t = 0;
|
||||
|
||||
if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
|
||||
{
|
||||
bestHit = hit;
|
||||
hasHit = true;
|
||||
}
|
||||
|
||||
// sample points around actual ray (conservative hitcheck)
|
||||
const float eps= 1e-5;
|
||||
|
||||
Eigen::RowVector3f up(0,1,0);
|
||||
if (direction.cross(up).norm() < eps) up = Eigen::RowVector3f(1,0,0);
|
||||
Eigen::RowVector3f offset = direction.cross(up).normalized();
|
||||
|
||||
Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
|
||||
|
||||
for(int r=0;r<(int)samples;r++)
|
||||
{
|
||||
if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) &&
|
||||
((closestHit && (hit.t < bestHit.t)) ||
|
||||
(!closestHit && (hit.t > bestHit.t))) &&
|
||||
(hit.gid == geoId || geoId == -1))
|
||||
{
|
||||
bestHit = hit;
|
||||
hasHit = true;
|
||||
}
|
||||
offset = rot*offset.transpose();
|
||||
}
|
||||
|
||||
hit = bestHit;
|
||||
return hasHit;
|
||||
}
|
||||
|
||||
inline bool
|
||||
igl::embree::EmbreeIntersector
|
||||
::intersectRay(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
std::vector<Hit > &hits,
|
||||
int& num_rays,
|
||||
float tnear,
|
||||
float tfar,
|
||||
int mask) const
|
||||
{
|
||||
using namespace std;
|
||||
num_rays = 0;
|
||||
hits.clear();
|
||||
int last_id0 = -1;
|
||||
double self_hits = 0;
|
||||
// This epsilon is directly correleated to the number of missed hits, smaller
|
||||
// means more accurate and slower
|
||||
//const double eps = DOUBLE_EPS;
|
||||
const double eps = FLOAT_EPS;
|
||||
double min_t = tnear;
|
||||
bool large_hits_warned = false;
|
||||
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
|
||||
ray.ray.flags = 0;
|
||||
createRay(ray,origin,direction,tnear,tfar,mask);
|
||||
|
||||
while(true)
|
||||
{
|
||||
ray.ray.tnear = min_t;
|
||||
ray.ray.tfar = tfar;
|
||||
ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
|
||||
num_rays++;
|
||||
{
|
||||
RTCIntersectContext context;
|
||||
rtcInitIntersectContext(&context);
|
||||
rtcIntersect1(scene,&context,&ray);
|
||||
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
|
||||
ray.hit.Ng_y = -ray.hit.Ng_y;
|
||||
ray.hit.Ng_z = -ray.hit.Ng_z;
|
||||
}
|
||||
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
|
||||
{
|
||||
// Hit self again, progressively advance
|
||||
if(ray.hit.primID == last_id0 || ray.ray.tfar <= min_t)
|
||||
{
|
||||
// push min_t a bit more
|
||||
//double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
|
||||
double t_push = pow(2.0,self_hits)*eps;
|
||||
#ifdef IGL_VERBOSE
|
||||
std::cerr<<" t_push: "<<t_push<<endl;
|
||||
#endif
|
||||
//o = o+t_push*d;
|
||||
min_t += t_push;
|
||||
self_hits++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Hit hit;
|
||||
hit.id = ray.hit.primID;
|
||||
hit.gid = ray.hit.geomID;
|
||||
hit.u = ray.hit.u;
|
||||
hit.v = ray.hit.v;
|
||||
hit.t = ray.ray.tfar;
|
||||
hits.push_back(hit);
|
||||
#ifdef IGL_VERBOSE
|
||||
std::cerr<<" t: "<<hit.t<<endl;
|
||||
#endif
|
||||
// Instead of moving origin, just change min_t. That way calculations
|
||||
// all use exactly same origin values
|
||||
min_t = ray.ray.tfar;
|
||||
|
||||
// reset t_scale
|
||||
self_hits = 0;
|
||||
}
|
||||
last_id0 = ray.hit.primID;
|
||||
}
|
||||
else
|
||||
break; // no more hits
|
||||
|
||||
if(hits.size()>1000 && !large_hits_warned)
|
||||
{
|
||||
std::cout<<"Warning: Large number of hits..."<<endl;
|
||||
std::cout<<"[ ";
|
||||
for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
|
||||
{
|
||||
std::cout<<(hit->id+1)<<" ";
|
||||
}
|
||||
|
||||
std::cout.precision(std::numeric_limits< double >::digits10);
|
||||
std::cout<<"[ ";
|
||||
|
||||
for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
|
||||
{
|
||||
std::cout<<(hit->t)<<endl;;
|
||||
}
|
||||
|
||||
std::cout<<"]"<<endl;
|
||||
large_hits_warned = true;
|
||||
|
||||
return hits.empty();
|
||||
}
|
||||
}
|
||||
|
||||
return hits.empty();
|
||||
}
|
||||
|
||||
inline bool
|
||||
igl::embree::EmbreeIntersector
|
||||
::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
|
||||
{
|
||||
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
|
||||
ray.ray.flags = 0;
|
||||
createRay(ray,a,ab,0,1.0,mask);
|
||||
|
||||
{
|
||||
RTCIntersectContext context;
|
||||
rtcInitIntersectContext(&context);
|
||||
rtcIntersect1(scene,&context,&ray);
|
||||
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
|
||||
ray.hit.Ng_y = -ray.hit.Ng_y;
|
||||
ray.hit.Ng_z = -ray.hit.Ng_z;
|
||||
}
|
||||
|
||||
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
|
||||
{
|
||||
hit.id = ray.hit.primID;
|
||||
hit.gid = ray.hit.geomID;
|
||||
hit.u = ray.hit.u;
|
||||
hit.v = ray.hit.v;
|
||||
hit.t = ray.ray.tfar;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void
|
||||
igl::embree::EmbreeIntersector
|
||||
::createRay(RTCRayHit& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
|
||||
{
|
||||
ray.ray.org_x = origin[0];
|
||||
ray.ray.org_y = origin[1];
|
||||
ray.ray.org_z = origin[2];
|
||||
ray.ray.dir_x = direction[0];
|
||||
ray.ray.dir_y = direction[1];
|
||||
ray.ray.dir_z = direction[2];
|
||||
ray.ray.tnear = tnear;
|
||||
ray.ray.tfar = tfar;
|
||||
ray.ray.id = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.ray.mask = mask;
|
||||
ray.ray.time = 0.0f;
|
||||
|
||||
ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
|
||||
}
|
||||
|
||||
#endif //EMBREE_INTERSECTOR_H
|
||||
|
||||
@@ -0,0 +1,423 @@
|
||||
#include "EmbreeRenderer.h"
|
||||
// Implementation
|
||||
|
||||
//IGL viewing parts
|
||||
#include "../unproject.h"
|
||||
#include "../look_at.h"
|
||||
#include "../frustum.h"
|
||||
#include "../ortho.h"
|
||||
|
||||
// color map
|
||||
#include "../jet.h"
|
||||
|
||||
#include "../PI.h"
|
||||
|
||||
|
||||
IGL_INLINE void igl::embree::EmbreeRenderer::init_view()
|
||||
{
|
||||
camera_base_zoom = 1.0f;
|
||||
camera_zoom = 1.0f;
|
||||
|
||||
camera_view_angle = 45.0;
|
||||
camera_dnear = 1.0;
|
||||
camera_dfar = 100.0;
|
||||
camera_base_translation << 0, 0, 0;
|
||||
camera_translation << 0, 0, 0;
|
||||
camera_eye << 0, 0, 5;
|
||||
camera_center << 0, 0, 0;
|
||||
camera_up << 0, 1, 0;
|
||||
|
||||
rot_matrix = Eigen::Matrix3f::Identity();
|
||||
|
||||
view = Eigen::Matrix4f::Identity();
|
||||
proj = Eigen::Matrix4f::Identity();
|
||||
norm = Eigen::Matrix4f::Identity();
|
||||
|
||||
orthographic = false;
|
||||
|
||||
|
||||
uC << 1,0,0;
|
||||
}
|
||||
|
||||
IGL_INLINE igl::embree::EmbreeRenderer::EmbreeRenderer()
|
||||
:
|
||||
scene(NULL),
|
||||
geomID(0),
|
||||
initialized(false),
|
||||
device(igl::embree::EmbreeDevice::get_device())
|
||||
{
|
||||
init_view();
|
||||
}
|
||||
|
||||
IGL_INLINE igl::embree::EmbreeRenderer::EmbreeRenderer(
|
||||
const EmbreeRenderer &)
|
||||
:// To make -Weffc++ happy
|
||||
scene(NULL),
|
||||
geomID(0),
|
||||
initialized(false)
|
||||
{
|
||||
assert(false && "Embree: Copying EmbreeRenderer is not allowed");
|
||||
}
|
||||
|
||||
IGL_INLINE igl::embree::EmbreeRenderer & igl::embree::EmbreeRenderer::operator=(
|
||||
const EmbreeRenderer &)
|
||||
{
|
||||
assert(false && "Embree: Assigning an EmbreeRenderer is not allowed");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void igl::embree::EmbreeRenderer::init(
|
||||
const PointMatrixType& V,
|
||||
const FaceMatrixType& F,
|
||||
bool isStatic)
|
||||
{
|
||||
std::vector<const PointMatrixType*> Vtemp;
|
||||
std::vector<const FaceMatrixType*> Ftemp;
|
||||
std::vector<int> masks;
|
||||
Vtemp.push_back(&V);
|
||||
Ftemp.push_back(&F);
|
||||
masks.push_back(0xFFFFFFFF);
|
||||
init(Vtemp,Ftemp,masks,isStatic);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::embree::EmbreeRenderer::init(
|
||||
const std::vector<const PointMatrixType*>& V,
|
||||
const std::vector<const FaceMatrixType*>& F,
|
||||
const std::vector<int>& masks,
|
||||
bool isStatic)
|
||||
{
|
||||
if(initialized)
|
||||
deinit();
|
||||
|
||||
using namespace std;
|
||||
|
||||
if(V.size() == 0 || F.size() == 0)
|
||||
{
|
||||
std::cerr << "Embree: No geometry specified!";
|
||||
return;
|
||||
}
|
||||
RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
|
||||
|
||||
// create a scene
|
||||
scene = rtcNewScene(device);
|
||||
rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
|
||||
rtcSetSceneBuildQuality(scene, buildQuality);
|
||||
|
||||
for(int g=0;g<(int)V.size();g++)
|
||||
{
|
||||
// create triangle mesh geometry in that scene
|
||||
RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE);
|
||||
rtcSetGeometryBuildQuality(geom_0, buildQuality);
|
||||
rtcSetGeometryTimeStepCount(geom_0,1);
|
||||
geomID = rtcAttachGeometry(scene,geom_0);
|
||||
rtcReleaseGeometry(geom_0);
|
||||
|
||||
// fill vertex buffer, have to be 16 byte wide( sizeof(float)*4 )
|
||||
Eigen::Map<Eigen::Matrix<float,-1,4,Eigen::RowMajor>> vertices(
|
||||
(float*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows()),
|
||||
V[g]->rows(),4
|
||||
);
|
||||
vertices.block(0,0,V[g]->rows(),3) = V[g]->cast<float>();
|
||||
|
||||
// fill triangle buffer
|
||||
Eigen::Map<Eigen::Matrix<unsigned int,-1,3,Eigen::RowMajor>> triangles(
|
||||
(unsigned int*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(unsigned int), F[g]->rows()),
|
||||
F[g]->rows(),3
|
||||
);
|
||||
triangles = F[g]->cast<unsigned int>();
|
||||
//TODO: store vertices and triangles in array for whatever reason?
|
||||
|
||||
rtcSetGeometryMask(geom_0, masks[g]);
|
||||
rtcCommitGeometry(geom_0);
|
||||
}
|
||||
|
||||
rtcCommitScene(scene);
|
||||
|
||||
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
|
||||
std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
|
||||
#ifdef IGL_VERBOSE
|
||||
else
|
||||
std::cerr << "Embree: geometry added." << endl;
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
IGL_INLINE igl::embree::EmbreeRenderer::~EmbreeRenderer()
|
||||
{
|
||||
if(initialized)
|
||||
deinit();
|
||||
|
||||
igl::embree::EmbreeDevice::release_device();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::embree::EmbreeRenderer::deinit()
|
||||
{
|
||||
if(scene)
|
||||
{
|
||||
rtcReleaseScene(scene);
|
||||
|
||||
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
|
||||
{
|
||||
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
|
||||
}
|
||||
#ifdef IGL_VERBOSE
|
||||
else
|
||||
{
|
||||
std::cerr << "Embree: geometry removed." << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::embree::EmbreeRenderer::intersect_ray(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
Hit& hit,
|
||||
float tnear,
|
||||
float tfar,
|
||||
int mask) const
|
||||
{
|
||||
RTCRayHit ray;
|
||||
ray.ray.flags = 0;
|
||||
create_ray(ray, origin,direction,tnear,tfar,mask);
|
||||
|
||||
// shot ray
|
||||
{
|
||||
RTCIntersectContext context;
|
||||
rtcInitIntersectContext(&context);
|
||||
rtcIntersect1(scene, &context, &ray);
|
||||
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
|
||||
ray.hit.Ng_y = -ray.hit.Ng_y;
|
||||
ray.hit.Ng_z = -ray.hit.Ng_z;
|
||||
}
|
||||
#ifdef IGL_VERBOSE
|
||||
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
|
||||
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
|
||||
#endif
|
||||
|
||||
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
|
||||
{
|
||||
hit.id = ray.hit.primID;
|
||||
hit.gid = ray.hit.geomID;
|
||||
hit.u = ray.hit.u;
|
||||
hit.v = ray.hit.v;
|
||||
hit.t = ray.ray.tfar;
|
||||
hit.N = Vec3f(ray.hit.Ng_x, ray.hit.Ng_y, ray.hit.Ng_z);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeRenderer
|
||||
::create_ray(RTCRayHit& ray, const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
|
||||
{
|
||||
ray.ray.org_x = origin[0];
|
||||
ray.ray.org_y = origin[1];
|
||||
ray.ray.org_z = origin[2];
|
||||
ray.ray.dir_x = direction[0];
|
||||
ray.ray.dir_y = direction[1];
|
||||
ray.ray.dir_z = direction[2];
|
||||
ray.ray.tnear = tnear;
|
||||
ray.ray.tfar = tfar;
|
||||
ray.ray.id = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.ray.mask = mask;
|
||||
ray.ray.time = 0.0f;
|
||||
|
||||
ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeRenderer
|
||||
::set_mesh(const Eigen::Matrix<double,Eigen::Dynamic,3> & MV,
|
||||
const Eigen::Matrix<int, Eigen::Dynamic,3> & MF,
|
||||
bool is_static)
|
||||
{
|
||||
V = MV.cast<float>();
|
||||
F = MF;
|
||||
this->init(V,F,is_static);
|
||||
|
||||
auto min_point = V.colwise().minCoeff();
|
||||
auto max_point = V.colwise().maxCoeff();
|
||||
auto centroid = (0.5*(min_point + max_point)).eval();
|
||||
|
||||
camera_base_translation.setConstant(0);
|
||||
camera_base_translation.head(centroid.size()) = -centroid.cast<float>();
|
||||
camera_base_zoom = 2.0 / (max_point-min_point).array().abs().maxCoeff();
|
||||
}
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeRenderer
|
||||
::render_buffer(PixelMatrixType& R, PixelMatrixType&G, PixelMatrixType &B,PixelMatrixType &A)
|
||||
{
|
||||
assert(R.rows()==G.rows());assert(R.rows()==B.rows());assert(R.rows()==A.rows());
|
||||
assert(R.cols()==G.cols());assert(R.cols()==B.cols());assert(R.cols()==A.cols());
|
||||
|
||||
Eigen::Vector4f viewport(0,0,R.rows(),R.cols());
|
||||
|
||||
float width = R.rows();
|
||||
float height = R.cols();
|
||||
|
||||
// update view matrix
|
||||
igl::look_at( camera_eye, camera_center, camera_up, view);
|
||||
|
||||
view = view
|
||||
* (rot_matrix * Eigen::Scaling(camera_zoom * camera_base_zoom)
|
||||
* Eigen::Translation3f(camera_translation + camera_base_translation)).matrix();
|
||||
|
||||
if (orthographic)
|
||||
{
|
||||
float length = (camera_eye - camera_center).norm();
|
||||
float h = tan(camera_view_angle/360.0 * igl::PI) * (length);
|
||||
igl::ortho(-h*width/height, h*width/height, -h, h, camera_dnear, camera_dfar, proj);
|
||||
} else {
|
||||
float fH = tan(camera_view_angle / 360.0 * igl::PI) * camera_dnear;
|
||||
float fW = fH * (double)width/(double)height;
|
||||
igl::frustum(-fW, fW, -fH, fH, camera_dnear, camera_dfar, proj);
|
||||
}
|
||||
|
||||
// go over all pixels in the "view"
|
||||
for(int x=0;x<(int)width;++x)
|
||||
{
|
||||
for(int y=0;y<(int)height;++y)
|
||||
{
|
||||
Vec3f s,d,dir;
|
||||
igl::embree::EmbreeRenderer::Hit hit;
|
||||
|
||||
// look into the screen
|
||||
Vec3f win_s(x,y,0);
|
||||
Vec3f win_d(x,y,1);
|
||||
// Source, destination and direction in world
|
||||
igl::unproject(win_s,this->view,this->proj,viewport,s);
|
||||
igl::unproject(win_d,this->view,this->proj,viewport,d);
|
||||
dir = d-s;
|
||||
dir.normalize();
|
||||
|
||||
auto clamp=[](float x)->unsigned char {return (unsigned char)(x<0?0:x>1.0?255:x*255);};
|
||||
|
||||
if(this->intersect_ray(s,dir,hit))
|
||||
{
|
||||
if ( dir.dot(hit.N) > 0.0f)
|
||||
{
|
||||
// TODO: interpolate normals ?
|
||||
hit.N.normalize();
|
||||
// cos between ray and face normal
|
||||
float face_proj=dir.dot(hit.N);
|
||||
|
||||
Eigen::RowVector3f c;
|
||||
|
||||
if(this->uniform_color)
|
||||
{
|
||||
// same color for the whole mesh
|
||||
c=uC;
|
||||
} else if(this->face_based) {
|
||||
// flat color per face
|
||||
c=this->C.row(hit.id);
|
||||
} else { //use barycentric coordinates to interpolate colour
|
||||
c=this->C.row(F(hit.id,1))*hit.u+
|
||||
this->C.row(F(hit.id,2))*hit.v+
|
||||
this->C.row(F(hit.id,0))*(1.0-hit.u-hit.v);
|
||||
}
|
||||
|
||||
R(x,y) = clamp(face_proj*c(0));
|
||||
G(x,y) = clamp(face_proj*c(1));
|
||||
B(x,y) = clamp(face_proj*c(2));
|
||||
}
|
||||
// give the same alpha to all points with something behind
|
||||
A(x,y)=255;
|
||||
} else {
|
||||
R(x,y)=0;
|
||||
G(x,y)=0;
|
||||
B(x,y)=0;
|
||||
A(x,y)=0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeRenderer
|
||||
::set_colors(const Eigen::MatrixXd & C)
|
||||
{
|
||||
if(C.rows()==V.rows()) // per vertex color
|
||||
{
|
||||
face_based = false;
|
||||
this->C = C.cast<float>();
|
||||
this->uniform_color=false;
|
||||
} else if (C.rows()==F.rows()) {
|
||||
face_based = true;
|
||||
this->C = C.cast<float>();
|
||||
this->uniform_color=false;
|
||||
} else if (C.rows()==1) {
|
||||
face_based = true;
|
||||
this->uC = C.cast<float>();
|
||||
this->uniform_color=true;
|
||||
}else {
|
||||
// don't know what to do
|
||||
this->uniform_color=true;
|
||||
assert(false); //?
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeRenderer
|
||||
::set_data(const Eigen::VectorXd & D, igl::ColorMapType cmap)
|
||||
{
|
||||
const double caxis_min = D.minCoeff();
|
||||
const double caxis_max = D.maxCoeff();
|
||||
return set_data(D,caxis_min,caxis_max,cmap);
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void igl::embree::EmbreeRenderer::set_data(
|
||||
const Eigen::VectorXd & D,
|
||||
double caxis_min,
|
||||
double caxis_max,
|
||||
igl::ColorMapType cmap)
|
||||
{
|
||||
Eigen::MatrixXd C;
|
||||
igl::colormap(cmap,D,caxis_min,caxis_max,C);
|
||||
set_colors(C);
|
||||
}
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeRenderer::set_rot(const Eigen::Matrix3d &r)
|
||||
{
|
||||
this->rot_matrix = r.cast<float>();
|
||||
}
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeRenderer::set_zoom(double zoom)
|
||||
{
|
||||
this->camera_zoom=zoom;
|
||||
}
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeRenderer::set_translation(const Eigen::Vector3d &tr)
|
||||
{
|
||||
this->camera_translation=tr.cast<float>();
|
||||
}
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeRenderer::set_face_based(bool _f)
|
||||
{
|
||||
this->face_based=_f;
|
||||
}
|
||||
|
||||
IGL_INLINE void
|
||||
igl::embree::EmbreeRenderer::set_orthographic(bool o)
|
||||
{
|
||||
this->orthographic=o;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
#endif //IGL_STATIC_LIBRARY
|
||||
@@ -0,0 +1,248 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
//
|
||||
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
|
||||
// 2013 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// 2014 Christian Schüller <schuellchr@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_EMBREE_EMBREE_RENDERER_H
|
||||
#define IGL_EMBREE_EMBREE_RENDERER_H
|
||||
|
||||
#include <igl/colormap.h>
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#include <embree3/rtcore.h>
|
||||
#include <embree3/rtcore_ray.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "EmbreeDevice.h"
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace embree
|
||||
{
|
||||
// embree-based mesh renderer
|
||||
class EmbreeRenderer
|
||||
{
|
||||
public:
|
||||
typedef Eigen::RowVector3f Vec3f;
|
||||
|
||||
struct Hit
|
||||
{
|
||||
int id; // primitive id
|
||||
int gid; // geometry id
|
||||
float u,v; // barycentric coordinates
|
||||
float t; // distance = direction*t to intersection
|
||||
Vec3f N; // element normal
|
||||
};
|
||||
|
||||
public:
|
||||
typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
|
||||
typedef Eigen::Matrix<float,Eigen::Dynamic,3> ColorMatrixType;
|
||||
typedef Eigen::Matrix<int, Eigen::Dynamic,3> FaceMatrixType;
|
||||
|
||||
typedef Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> PixelMatrixType;
|
||||
|
||||
public:
|
||||
EmbreeRenderer();
|
||||
private:
|
||||
// Copying and assignment are not allowed.
|
||||
EmbreeRenderer(const EmbreeRenderer & that);
|
||||
EmbreeRenderer & operator=(const EmbreeRenderer &);
|
||||
public:
|
||||
virtual ~EmbreeRenderer();
|
||||
|
||||
// Specify mesh, this call reinitializes embree structures
|
||||
// Inputs:
|
||||
// V #V x dim matrix of vertex coordinates
|
||||
// F #F x simplex_size matrix of indices of simplex corners into V
|
||||
// is_static - optimize for static thene (HQ rendering)
|
||||
void set_mesh(const Eigen::Matrix<double,Eigen::Dynamic,3> & V,
|
||||
const Eigen::Matrix<int, Eigen::Dynamic,3> & F,
|
||||
bool is_static=true);
|
||||
// Specify per-vertex or per-face color
|
||||
// Inputs:
|
||||
// C #V x 3 matrix of vertex colors
|
||||
// or #F x 3 matrix of face colors
|
||||
// or 1 x 3 matrix of uniform color
|
||||
void set_colors(const Eigen::MatrixXd & C);
|
||||
|
||||
|
||||
// Use min(D) and max(D) to set caxis.
|
||||
void set_data(const Eigen::VectorXd & D,
|
||||
igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS);
|
||||
|
||||
// Specify per-vertex or per-face scalar field
|
||||
// that will be converted to color using jet color map
|
||||
// Inputs:
|
||||
// caxis_min caxis minimum bound
|
||||
// caxis_max caxis maximum bound
|
||||
// D #V by 1 list of scalar values
|
||||
// cmap colormap type
|
||||
// num_steps number of intervals to discretize the colormap
|
||||
void set_data(
|
||||
const Eigen::VectorXd & D,
|
||||
double caxis_min,
|
||||
double caxis_max,
|
||||
igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS);
|
||||
|
||||
// Specify mesh rotation
|
||||
// Inputs:
|
||||
// r 3 x 3 rotaton matrix
|
||||
void set_rot(const Eigen::Matrix3d &r);
|
||||
|
||||
// Specify mesh magnification
|
||||
// Inputs:
|
||||
// z magnification ratio
|
||||
void set_zoom(double z);
|
||||
|
||||
// Specify mesh translation
|
||||
// Inputs:
|
||||
// tr translation vector
|
||||
void set_translation(const Eigen::Vector3d &tr);
|
||||
|
||||
// Specify that color is face based
|
||||
// Inputs:
|
||||
// f - face or vertex colours
|
||||
void set_face_based(bool f);
|
||||
|
||||
// Use orthographic projection
|
||||
// Inputs:
|
||||
// f - orthographic or perspective projection
|
||||
void set_orthographic(bool f );
|
||||
|
||||
// render full buffer
|
||||
// Outputs:
|
||||
// all outputs should have the same size (size of the output picture)
|
||||
// area outside of the visible object will have zero alpha component (transparant)
|
||||
// R - red channel
|
||||
// G - green channel
|
||||
// B - blue channel
|
||||
// A - alpha channel
|
||||
void render_buffer(PixelMatrixType &R,
|
||||
PixelMatrixType &G,
|
||||
PixelMatrixType &B,
|
||||
PixelMatrixType &A);
|
||||
|
||||
// Given a ray find the first hit
|
||||
//
|
||||
// Inputs:
|
||||
// origin 3d origin point of ray
|
||||
// direction 3d (not necessarily normalized) direction vector of ray
|
||||
// tnear start of ray segment
|
||||
// tfar end of ray segment
|
||||
// mask a 32 bit mask to identify active geometries.
|
||||
// Output:
|
||||
// hit information about hit
|
||||
// Returns true if and only if there was a hit
|
||||
bool intersect_ray(
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
Hit& hit,
|
||||
float tnear = 0,
|
||||
float tfar = std::numeric_limits<float>::infinity(),
|
||||
int mask = 0xFFFFFFFF) const;
|
||||
|
||||
private:
|
||||
|
||||
// Initialize with a given mesh.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of Oriented triangles
|
||||
// isStatic scene is optimized for static geometry
|
||||
// Side effects:
|
||||
// The first time this is ever called the embree engine is initialized.
|
||||
void init(
|
||||
const PointMatrixType& V,
|
||||
const FaceMatrixType& F,
|
||||
bool isStatic = false);
|
||||
|
||||
// Initialize embree with a given mesh.
|
||||
//
|
||||
// Inputs:
|
||||
// V vector of #V by 3 list of vertex positions for each geometry
|
||||
// F vector of #F by 3 list of Oriented triangles for each geometry
|
||||
// masks a 32 bit mask to identify active geometries.
|
||||
// isStatic scene is optimized for static geometry
|
||||
// Side effects:
|
||||
// The first time this is ever called the embree engine is initialized.
|
||||
void init(
|
||||
const std::vector<const PointMatrixType*>& V,
|
||||
const std::vector<const FaceMatrixType*>& F,
|
||||
const std::vector<int>& masks,
|
||||
bool isStatic = false);
|
||||
|
||||
|
||||
// Deinitialize embree datasctructures for current mesh. Also called on
|
||||
// destruction: no need to call if you just want to init() once and
|
||||
// destroy.
|
||||
void deinit();
|
||||
// initialize view parameters
|
||||
void init_view();
|
||||
|
||||
// scene data
|
||||
PointMatrixType V; // vertices
|
||||
FaceMatrixType F; // faces
|
||||
ColorMatrixType C; // colours
|
||||
|
||||
Eigen::RowVector3f uC; // uniform color
|
||||
|
||||
bool face_based;
|
||||
bool uniform_color;
|
||||
|
||||
// Camera parameters
|
||||
float camera_base_zoom;
|
||||
float camera_zoom;
|
||||
|
||||
Eigen::Vector3f camera_base_translation;
|
||||
Eigen::Vector3f camera_translation;
|
||||
Eigen::Vector3f camera_eye;
|
||||
Eigen::Vector3f camera_up;
|
||||
Eigen::Vector3f camera_center;
|
||||
float camera_view_angle;
|
||||
float camera_dnear;
|
||||
float camera_dfar;
|
||||
|
||||
// projection matrixes
|
||||
Eigen::Matrix4f view;
|
||||
Eigen::Matrix4f proj;
|
||||
Eigen::Matrix4f norm;
|
||||
|
||||
Eigen::Matrix3f rot_matrix;
|
||||
|
||||
bool orthographic;
|
||||
|
||||
// embree data
|
||||
RTCScene scene;
|
||||
unsigned geomID;
|
||||
bool initialized;
|
||||
|
||||
RTCDevice device;
|
||||
|
||||
void create_ray(
|
||||
RTCRayHit& ray,
|
||||
const Eigen::RowVector3f& origin,
|
||||
const Eigen::RowVector3f& direction,
|
||||
float tnear,
|
||||
float tfar,
|
||||
int mask) const;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "EmbreeRenderer.cpp"
|
||||
#endif
|
||||
#endif //IGL_EMBREE_EMBREE_RENDERER_H
|
||||
@@ -1027,7 +1027,6 @@ inline void Mesh::build_adjacencies()
|
||||
|
||||
inline bool Mesh::verify() //verifies connectivity of the mesh and prints some debug info
|
||||
{
|
||||
std::cout << std::endl;
|
||||
// make sure that all vertices are mentioned at least once.
|
||||
// though the loose vertex is not a bug, it most likely indicates that something is wrong with the mesh
|
||||
std::vector<bool> map(m_vertices.size(), false);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "extension.h"
|
||||
#include "pathinfo.h"
|
||||
|
||||
IGL_INLINE std::string igl::extension( const std::string & path)
|
||||
{
|
||||
std::string d,b,e,f;
|
||||
pathinfo(path,d,b,e,f);
|
||||
return e;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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_EXTENSION_H
|
||||
#define IGL_EXTENSION_H
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Inputs:
|
||||
// path path with an extension (path/to/foo.obj)
|
||||
// Returns extension without dot (obj)
|
||||
//
|
||||
// See also: pathinfo, basename, dirname
|
||||
IGL_INLINE std::string extension( const std::string & path);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "extension.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "extract_non_manifold_edge_curves.h"
|
||||
#include <algorithm>
|
||||
@@ -17,8 +17,8 @@ typename DerivedF,
|
||||
typename DerivedEMAP,
|
||||
typename uE2EType >
|
||||
IGL_INLINE void igl::extract_non_manifold_edge_curves(
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& /*EMAP*/,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedEMAP>& /*EMAP*/,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<size_t> >& curves) {
|
||||
const size_t num_faces = F.rows();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_NON_MANIFOLD_EDGE_CURVES
|
||||
#define IGL_NON_MANIFOLD_EDGE_CURVES
|
||||
@@ -34,8 +34,8 @@ namespace igl {
|
||||
typename DerivedEMAP,
|
||||
typename uE2EType>
|
||||
IGL_INLINE void extract_non_manifold_edge_curves(
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedEMAP>& EMAP,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<size_t> >& curves);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <queue>
|
||||
|
||||
template <typename DerivedF, typename DerivedC>
|
||||
IGL_INLINE void igl::facet_components(
|
||||
IGL_INLINE int igl::facet_components(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedC> & C)
|
||||
{
|
||||
@@ -23,7 +23,7 @@ IGL_INLINE void igl::facet_components(
|
||||
igl::facet_adjacency_matrix(F,A);
|
||||
Eigen::Matrix<Index,Eigen::Dynamic,1> counts;
|
||||
C = DerivedC::Zero(1,1);
|
||||
connected_components(A,C,counts);
|
||||
return connected_components(A,C,counts);
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -91,7 +91,7 @@ IGL_INLINE void igl::facet_components(
|
||||
// Explicit template instantiation
|
||||
template void igl::facet_components<long, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::facet_components<int, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::facet_components<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template int igl::facet_components<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#ifdef WIN32
|
||||
template void igl::facet_components<__int64,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class std::vector<class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > >,class std::allocator<class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > > > > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace igl
|
||||
// Outputs:
|
||||
// C #F list of connected component ids
|
||||
template <typename DerivedF, typename DerivedC>
|
||||
IGL_INLINE void facet_components(
|
||||
IGL_INLINE int facet_components(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedC> & C);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user