From 89116688f6a31b3ea59786ea850cc2bac8cb5be8 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 6 Sep 2023 09:11:33 +0200 Subject: [PATCH 01/70] Update tbb git tag --- cmake/FloatTetwildDownloadExternal.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/FloatTetwildDownloadExternal.cmake b/cmake/FloatTetwildDownloadExternal.cmake index 965e2592..2801e616 100644 --- a/cmake/FloatTetwildDownloadExternal.cmake +++ b/cmake/FloatTetwildDownloadExternal.cmake @@ -60,7 +60,7 @@ endfunction() function(float_tetwild_download_tbb) float_tetwild_download_project(tbb GIT_REPOSITORY https://github.com/wjakob/tbb.git - GIT_TAG ddbe45cd3ad89df9a84cd77013d5898fc48b8e89 + GIT_TAG 9e219e2 ) endfunction() @@ -121,4 +121,4 @@ function(float_tetwild_download_exact_envelope) GIT_REPOSITORY https://github.com/wangbolun300/fast-envelope GIT_TAG 520ee04b6c69a802db31d1fd3a3e6e382d10ef98 ) -endfunction() \ No newline at end of file +endfunction() From b6b306226eef0d4f40716a40859b22ab5f97b7be Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sat, 21 Dec 2024 21:12:10 +0100 Subject: [PATCH 02/70] Revert "handle sizing field better; rm fast winding number" This reverts commit f2b09d3cca4faf7a4486c37e3565e4211c9ca802. --- src/MeshImprovement.cpp | 88 ++++++++++--------------------------- src/Parameters.h | 3 -- src/external/CMakeLists.txt | 13 +++--- src/main.cpp | 44 +++++++++++++++++-- 4 files changed, 70 insertions(+), 78 deletions(-) diff --git a/src/MeshImprovement.cpp b/src/MeshImprovement.cpp index 764844ff..8d5f0fa4 100644 --- a/src/MeshImprovement.cpp +++ b/src/MeshImprovement.cpp @@ -15,7 +15,7 @@ #include #include #include -//#include +#include #include //#include @@ -1296,52 +1296,11 @@ void floatTetWild::apply_sizingfield(Mesh& mesh, AABBWrapper& tree) { auto &tet_vertices = mesh.tet_vertices; auto &tets = mesh.tets; - GEO::Mesh bg_mesh; - bg_mesh.vertices.clear(); - bg_mesh.vertices.create_vertices((int)mesh.params.V_sizing_field.rows() / 3); - for (int i = 0; i < mesh.params.V_sizing_field.rows() / 3; i++) { - GEO::vec3& p = bg_mesh.vertices.point(i); - for (int j = 0; j < 3; j++) - p[j] = mesh.params.V_sizing_field(i * 3 + j); - } - bg_mesh.cells.clear(); - bg_mesh.cells.create_tets((int)mesh.params.T_sizing_field.rows() / 4); - for (int i = 0; i < mesh.params.T_sizing_field.rows() / 4; i++) { - for (int j = 0; j < 4; j++) - bg_mesh.cells.set_vertex(i, j, mesh.params.T_sizing_field(i * 4 + j)); - } - GEO::MeshCellsAABB bg_aabb(bg_mesh, false); - - auto get_sizing_field_value = [&](const Vector3& p) { - GEO::vec3 geo_p(p[0], p[1], p[2]); - int bg_t_id = bg_aabb.containing_tet(geo_p); - if (bg_t_id == GEO::MeshCellsAABB::NO_TET) - return -1.; - - // compute barycenter - std::array vs; - for (int j = 0; j < 4; j++) { - vs[j] = Vector3(mesh.params.V_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + j) * 3), - mesh.params.V_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + j) * 3 + 1), - mesh.params.V_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + j) * 3 + 2)); - } - double value = 0; - for (int j = 0; j < 4; j++) { - Vector3 n = ((vs[(j + 1) % 4] - vs[j]).cross(vs[(j + 2) % 4] - vs[j])).normalized(); - double d = (vs[(j + 3) % 4] - vs[j]).dot(n); - if (d == 0) - continue; - double weight = abs((p - vs[j]).dot(n) / d); - value += weight * mesh.params.values_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + (j + 3) % 4)); - } - return value; // / mesh.params.ideal_edge_length; - }; - for (auto &p: tet_vertices) { if (p.is_removed) continue; p.sizing_scalar = 1; //reset - double value = get_sizing_field_value(p.pos); + double value = mesh.params.get_sizing_field_value(p.pos); if (value > 0) { p.sizing_scalar = value / mesh.params.ideal_edge_length; } @@ -1512,10 +1471,10 @@ void floatTetWild::boolean_operation(Mesh& mesh, const json& csg_tree_with_ids, for (int i = 0; i <= max_id; ++i) { get_tracked_surface(mesh, vs, fs, i); -// if (!mesh.params.use_general_wn) -// floatTetWild::fast_winding_number( -// Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); -// else + if (!mesh.params.use_general_wn) + floatTetWild::fast_winding_number( + Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); + else igl::winding_number( Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); } @@ -1546,10 +1505,10 @@ void floatTetWild::boolean_operation(Mesh& mesh, const json& csg_tree_with_ids, for (int k = 0; k < fs.rows(); ++k) fs.row(k) = Fs[i][k]; -// if (!mesh.params.use_general_wn) -// floatTetWild::fast_winding_number( -// Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); -// else + if (!mesh.params.use_general_wn) + floatTetWild::fast_winding_number( + Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); + else igl::winding_number( Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); } @@ -1613,11 +1572,10 @@ void floatTetWild::boolean_operation(Mesh& mesh, int op){ } Eigen::VectorXd w1, w2; -// if(!mesh.params.use_general_wn) { -// floatTetWild::fast_winding_number(Eigen::MatrixXd(v1.cast()), Eigen::MatrixXi(f1), C, w1); -// floatTetWild::fast_winding_number(Eigen::MatrixXd(v2.cast()), Eigen::MatrixXi(f2), C, w2); -// }else - { + if(!mesh.params.use_general_wn) { + floatTetWild::fast_winding_number(Eigen::MatrixXd(v1.cast()), Eigen::MatrixXi(f1), C, w1); + floatTetWild::fast_winding_number(Eigen::MatrixXd(v2.cast()), Eigen::MatrixXi(f2), C, w2); + }else { igl::winding_number(Eigen::MatrixXd(v1.cast()), Eigen::MatrixXi(f1), C, w1); igl::winding_number(Eigen::MatrixXd(v2.cast()), Eigen::MatrixXi(f2), C, w2); } @@ -1671,9 +1629,9 @@ void floatTetWild::filter_outside(Mesh& mesh, bool invert_faces) { F.col(1) = F.col(2).eval(); F.col(2) = tmp; } -// if(!mesh.params.use_general_wn) -// floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); -// else + if(!mesh.params.use_general_wn) + floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); + else igl::winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); index = 0; @@ -1748,9 +1706,9 @@ void floatTetWild::filter_outside(Mesh& mesh, const std::vector &input_ // F.col(1) = F.col(2).eval(); // F.col(2) = tmp; // } -// if(!mesh.params.use_general_wn) -// floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); -// else + if(!mesh.params.use_general_wn) + floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); + else igl::winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); index = 0; @@ -1862,9 +1820,9 @@ void floatTetWild::mark_outside(Mesh& mesh, bool invert_faces){ F.col(2) = tmp; } Eigen::VectorXd W; -// if(!mesh.params.use_general_wn) -// floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); -// else + if(!mesh.params.use_general_wn) + floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); + else igl::winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); index = 0; diff --git a/src/Parameters.h b/src/Parameters.h index 3805de7e..0209e09b 100644 --- a/src/Parameters.h +++ b/src/Parameters.h @@ -42,9 +42,6 @@ namespace floatTetWild { bool coarsen = false; bool apply_sizing_field = false; - Eigen::VectorXd V_sizing_field; - Eigen::VectorXi T_sizing_field; - Eigen::VectorXd values_sizing_field; std::function get_sizing_field_value;//get sizing field value for an point #ifdef NEW_ENVELOPE diff --git a/src/external/CMakeLists.txt b/src/external/CMakeLists.txt index 3dc2b289..c610ba34 100644 --- a/src/external/CMakeLists.txt +++ b/src/external/CMakeLists.txt @@ -23,11 +23,12 @@ if(FLOAT_TETWILD_WITH_EXACT_ENVELOPE ) bfs_orient.h bfs_orient.cpp -# WindingNumber.h -# FastWindingNumber.hpp -# FastWindingNumber.cpp + FastWindingNumber.hpp + FastWindingNumber.cpp Rational.h + + WindingNumber.h ) else() set(SOURCES @@ -54,9 +55,9 @@ else() bfs_orient.h bfs_orient.cpp -# WindingNumber.h -# FastWindingNumber.hpp -# FastWindingNumber.cpp + WindingNumber.h + FastWindingNumber.hpp + FastWindingNumber.cpp Rational.h ) diff --git a/src/main.cpp b/src/main.cpp index f277e892..7649e475 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -321,11 +321,47 @@ int main(int argc, char** argv) values = mshLoader.get_node_field("values"); } if (V_in.rows() != 0 && T_in.rows() != 0 && values.rows() != 0) { - params.apply_sizing_field = true; + params.apply_sizing_field = true; + params.get_sizing_field_value = [&V_in, &T_in, &values](const Vector3& p) { + GEO::Mesh bg_mesh; + bg_mesh.vertices.clear(); + bg_mesh.vertices.create_vertices((int)V_in.rows() / 3); + for (int i = 0; i < V_in.rows() / 3; i++) { + GEO::vec3& p = bg_mesh.vertices.point(i); + for (int j = 0; j < 3; j++) + p[j] = V_in(i * 3 + j); + } + bg_mesh.cells.clear(); + bg_mesh.cells.create_tets((int)T_in.rows() / 4); + for (int i = 0; i < T_in.rows() / 4; i++) { + for (int j = 0; j < 4; j++) + bg_mesh.cells.set_vertex(i, j, T_in(i * 4 + j)); + } - params.V_sizing_field = V_in; - params.T_sizing_field = T_in; - params.values_sizing_field = values; + GEO::MeshCellsAABB bg_aabb(bg_mesh, false); + GEO::vec3 geo_p(p[0], p[1], p[2]); + int bg_t_id = bg_aabb.containing_tet(geo_p); + if (bg_t_id == GEO::MeshCellsAABB::NO_TET) + return -1.; + + // compute barycenter + std::array vs; + for (int j = 0; j < 4; j++) { + vs[j] = Vector3(V_in(T_in(bg_t_id * 4 + j) * 3), + V_in(T_in(bg_t_id * 4 + j) * 3 + 1), + V_in(T_in(bg_t_id * 4 + j) * 3 + 2)); + } + double value = 0; + for (int j = 0; j < 4; j++) { + Vector3 n = ((vs[(j + 1) % 4] - vs[j]).cross(vs[(j + 2) % 4] - vs[j])).normalized(); + double d = (vs[(j + 3) % 4] - vs[j]).dot(n); + if (d == 0) + continue; + double weight = abs((p - vs[j]).dot(n) / d); + value += weight * values(T_in(bg_t_id * 4 + (j + 3) % 4)); + } + return value; // / mesh.params.ideal_edge_length; + }; } /// set input tage From 25860aa8df490180f7c4b3493e046c27b021ff6b Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sat, 21 Dec 2024 21:13:50 +0100 Subject: [PATCH 03/70] revert tbb hash --- cmake/FloatTetwildDownloadExternal.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/FloatTetwildDownloadExternal.cmake b/cmake/FloatTetwildDownloadExternal.cmake index 965e2592..2801e616 100644 --- a/cmake/FloatTetwildDownloadExternal.cmake +++ b/cmake/FloatTetwildDownloadExternal.cmake @@ -60,7 +60,7 @@ endfunction() function(float_tetwild_download_tbb) float_tetwild_download_project(tbb GIT_REPOSITORY https://github.com/wjakob/tbb.git - GIT_TAG ddbe45cd3ad89df9a84cd77013d5898fc48b8e89 + GIT_TAG 9e219e2 ) endfunction() @@ -121,4 +121,4 @@ function(float_tetwild_download_exact_envelope) GIT_REPOSITORY https://github.com/wangbolun300/fast-envelope GIT_TAG 520ee04b6c69a802db31d1fd3a3e6e382d10ef98 ) -endfunction() \ No newline at end of file +endfunction() From 8aaebbfe0853066489de7090d8f84189da6d1016 Mon Sep 17 00:00:00 2001 From: Tristan Schulz Date: Thu, 14 Mar 2024 04:51:04 +0100 Subject: [PATCH 04/70] Migrated from tbb to oneapi/tbb --- CMakeLists.txt | 183 +- cmake/DownloadProject.CMakeLists.cmake.in | 24 +- cmake/FloatTetwildDependencies.cmake | 160 +- cmake/FloatTetwildDownloadExternal.cmake | 144 +- src/EdgeCollapsing.cpp | 582 ++-- src/LocalOperations.cpp | 1548 +++++---- src/Simplification.cpp | 640 ++-- src/TriangleInsertion.cpp | 3679 ++++++++++++--------- src/VertexSmoothing.cpp | 295 +- src/main.cpp | 93 +- 10 files changed, 4009 insertions(+), 3339 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a384d01f..fe69b6d7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,24 +1,29 @@ -################################################################################ -cmake_minimum_required(VERSION 3.8) +# ############################################################################## +cmake_minimum_required(VERSION 3.20) project(FloatTetwild) -################################################################################ +# ############################################################################## # Detects whether this is a top-level project get_directory_property(HAS_PARENT PARENT_DIRECTORY) if(HAS_PARENT) - set(FLOAT_TETWILD_TOPLEVEL_PROJECT OFF) + set(FLOAT_TETWILD_TOPLEVEL_PROJECT OFF) else() - set(FLOAT_TETWILD_TOPLEVEL_PROJECT ON) + set(FLOAT_TETWILD_TOPLEVEL_PROJECT ON) endif() if(INPUT_THIRD_PARTY_DIR) - set(FLOAT_TETWILD_EXTERNAL ${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_THIRD_PARTY_DIR}/) + set(FLOAT_TETWILD_EXTERNAL + ${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_THIRD_PARTY_DIR}/) else() - set(FLOAT_TETWILD_EXTERNAL ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/) + set(FLOAT_TETWILD_EXTERNAL ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/) endif() list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +add_compile_options(-Wfatal-errors) + # Color output include(UseColors) @@ -37,54 +42,53 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) # Generate position independent code by default set(CMAKE_POSITION_INDEPENDENT_CODE ON) -################################################################################ +# ############################################################################## # FloatTetwild options -option(FLOAT_TETWILD_ENABLE_TBB "Enable TBB" ON) -option(FLOAT_TETWILD_USE_FLOAT "Use floats instead of double" OFF) -option(FLOAT_TETWILD_WITH_SANITIZERS "Use sanitizers" OFF) -option(FLOAT_TETWILD_WITH_EXACT_ENVELOPE "Use exact envelope" OFF) +option(FLOAT_TETWILD_ENABLE_TBB "Enable TBB" ON) +option(FLOAT_TETWILD_USE_FLOAT "Use floats instead of double" OFF) +option(FLOAT_TETWILD_WITH_SANITIZERS "Use sanitizers" OFF) +option(FLOAT_TETWILD_WITH_EXACT_ENVELOPE "Use exact envelope" OFF) # Sanitizer options -option(SANITIZE_ADDRESS "Sanitize Address" OFF) -option(SANITIZE_MEMORY "Sanitize Memory" OFF) -option(SANITIZE_THREAD "Sanitize Thread" OFF) -option(SANITIZE_UNDEFINED "Sanitize Undefined" OFF) +option(SANITIZE_ADDRESS "Sanitize Address" OFF) +option(SANITIZE_MEMORY "Sanitize Memory" OFF) +option(SANITIZE_THREAD "Sanitize Thread" OFF) +option(SANITIZE_UNDEFINED "Sanitize Undefined" OFF) # Options for libigl modules -option(LIBIGL_USE_STATIC_LIBRARY "Use libigl as static library" OFF) -option(LIBIGL_WITH_COMISO "Use CoMiso" OFF) -option(LIBIGL_WITH_EMBREE "Use Embree" OFF) -option(LIBIGL_WITH_OPENGL "Use OpenGL" OFF) -option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" OFF) -option(LIBIGL_WITH_OPENGL_GLFW_IMGUI "Use ImGui" OFF) -option(LIBIGL_WITH_PNG "Use PNG" OFF) -option(LIBIGL_WITH_TETGEN "Use Tetgen" OFF) -option(LIBIGL_WITH_TRIANGLE "Use Triangle" OFF) -option(LIBIGL_WITH_PREDICATES "Use exact predicates" ON) -option(LIBIGL_WITH_XML "Use XML" OFF) +option(LIBIGL_USE_STATIC_LIBRARY "Use libigl as static library" OFF) +option(LIBIGL_WITH_COMISO "Use CoMiso" OFF) +option(LIBIGL_WITH_EMBREE "Use Embree" OFF) +option(LIBIGL_WITH_OPENGL "Use OpenGL" OFF) +option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" OFF) +option(LIBIGL_WITH_OPENGL_GLFW_IMGUI "Use ImGui" OFF) +option(LIBIGL_WITH_PNG "Use PNG" OFF) +option(LIBIGL_WITH_TETGEN "Use Tetgen" OFF) +option(LIBIGL_WITH_TRIANGLE "Use Triangle" OFF) +option(LIBIGL_WITH_PREDICATES "Use exact predicates" ON) +option(LIBIGL_WITH_XML "Use XML" OFF) # Sanitizers if(FLOAT_TETWILD_WITH_SANITIZERS) - list(APPEND CMAKE_MODULE_PATH ${FLOAT_TETWILD_EXTERNAL}/sanitizers-cmake/cmake) + list(APPEND CMAKE_MODULE_PATH + ${FLOAT_TETWILD_EXTERNAL}/sanitizers-cmake/cmake) endif() # Setup dependencies include(FloatTetwildDependencies) -################################################################################ +# ############################################################################## # FloatTetwild library -################################################################################ +# ############################################################################## find_package(GMPfTetWild) -IF(NOT ${GMP_FOUND}) - MESSAGE(FATAL_ERROR "Cannot find GMP") -ENDIF() +if(NOT ${GMP_FOUND}) + message(FATAL_ERROR "Cannot find GMP") +endif() -# find_package(MPFR) -# IF(NOT ${MPFR_FOUND}) -# MESSAGE(FATAL_ERROR "Cannot find MPFR") -# ENDIF() +# find_package(MPFR) IF(NOT ${MPFR_FOUND}) MESSAGE(FATAL_ERROR "Cannot find +# MPFR") ENDIF() # add_library() can only be called without any source since CMake 3.11 ... add_library(${PROJECT_NAME} src/Logger.cpp src/external/WindingNumber.h) @@ -93,7 +97,8 @@ add_library(${PROJECT_NAME} src/Logger.cpp src/external/WindingNumber.h) target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR}/include) # set(MESH_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests/") -# target_compile_definitions(${PROJECT_NAME} PUBLIC -DFLOAT_TETWILD_MESH_PATH=\"${MESH_PATH}\") +# target_compile_definitions(${PROJECT_NAME} PUBLIC +# -DFLOAT_TETWILD_MESH_PATH=\"${MESH_PATH}\") # Extra warnings target_link_libraries(${PROJECT_NAME} PRIVATE warnings::all) @@ -101,88 +106,84 @@ target_link_libraries(${PROJECT_NAME} PRIVATE warnings::all) # Use C++11 target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) # if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") -# target_compile_options(${PROJECT_NAME} PUBLIC "/Zc:__cplusplus") -# endif() -# target_compile_definitions(${PROJECT_NAME} PUBLIC -DEIGEN_STACK_ALLOCATION_LIMIT=8388608) +# target_compile_options(${PROJECT_NAME} PUBLIC "/Zc:__cplusplus") endif() +# target_compile_definitions(${PROJECT_NAME} PUBLIC +# -DEIGEN_STACK_ALLOCATION_LIMIT=8388608) if(FLOAT_TETWILD_WITH_SANITIZERS) - add_sanitizers(${PROJECT_NAME}) + add_sanitizers(${PROJECT_NAME}) endif() -################################################################################ +# ############################################################################## # Required libraries -################################################################################ +# ############################################################################## if(FLOAT_TETWILD_USE_FLOAT) - target_compile_definitions(${PROJECT_NAME} PUBLIC -DFLOAT_TETWILD_USE_FLOAT) + target_compile_definitions(${PROJECT_NAME} PUBLIC -DFLOAT_TETWILD_USE_FLOAT) endif() target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${GMP_INCLUDE_DIRS}) -target_link_libraries(${PROJECT_NAME} - PUBLIC - igl::core - igl::predicates - geogram::geogram - spdlog::spdlog - Threads::Threads -# fast_winding_number - json - ${GMP_LIBRARIES} - # ${MPFR_LIBRARIES} +target_link_libraries( + ${PROJECT_NAME} + PUBLIC igl::core + igl::predicates + geogram::geogram + spdlog::spdlog + Threads::Threads + # fast_winding_number + json + ${GMP_LIBRARIES} + # ${MPFR_LIBRARIES} ) if(FLOAT_TETWILD_ENABLE_TBB) - target_link_libraries(${PROJECT_NAME} PUBLIC tbb::tbb) - target_compile_definitions(${PROJECT_NAME} PUBLIC FLOAT_TETWILD_USE_TBB) + target_link_libraries(${PROJECT_NAME} PUBLIC TBB::tbb) + target_compile_definitions(${PROJECT_NAME} PUBLIC FLOAT_TETWILD_USE_TBB) endif() if(FLOAT_TETWILD_WITH_EXACT_ENVELOPE) - target_link_libraries(${PROJECT_NAME} PUBLIC FastEnvelope) - target_compile_definitions(${PROJECT_NAME} PUBLIC NEW_ENVELOPE) + target_link_libraries(${PROJECT_NAME} PUBLIC FastEnvelope) + target_compile_definitions(${PROJECT_NAME} PUBLIC NEW_ENVELOPE) endif() - -################################################################################ +# ############################################################################## # FloatTetwild binary -################################################################################ +# ############################################################################## # Main executable if(FLOAT_TETWILD_TOPLEVEL_PROJECT) - add_executable(${PROJECT_NAME}_bin src/main.cpp) - target_compile_features(${PROJECT_NAME}_bin PUBLIC ${CXX14_FEATURES}) - - target_link_libraries(${PROJECT_NAME}_bin - PUBLIC - ${PROJECT_NAME} - CLI11::CLI11 - warnings::all - ) - - if(TARGET igl::tetgen) - target_link_libraries(${PROJECT_NAME} PUBLIC igl::tetgen) - target_compile_definitions(${PROJECT_NAME} PUBLIC -DLIBIGL_WITH_TETGEN) - endif() - - if(FLOAT_TETWILD_WITH_SANITIZERS) - add_sanitizers(${PROJECT_NAME}_bin) - endif() - - if(NOT (${CMAKE_VERSION} VERSION_LESS "3.6.0")) - set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}_bin) - endif() + add_executable(${PROJECT_NAME}_bin src/main.cpp) + target_compile_features(${PROJECT_NAME}_bin PUBLIC ${CXX14_FEATURES}) + + target_link_libraries(${PROJECT_NAME}_bin PUBLIC ${PROJECT_NAME} CLI11::CLI11 + warnings::all) + + if(TARGET igl::tetgen) + target_link_libraries(${PROJECT_NAME} PUBLIC igl::tetgen) + target_compile_definitions(${PROJECT_NAME} PUBLIC -DLIBIGL_WITH_TETGEN) + endif() + + if(FLOAT_TETWILD_WITH_SANITIZERS) + add_sanitizers(${PROJECT_NAME}_bin) + endif() + + if(NOT (${CMAKE_VERSION} VERSION_LESS "3.6.0")) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}_bin) + endif() endif() -################################################################################ +# ############################################################################## # Subdirectories -################################################################################ +# ############################################################################## # Other sources add_subdirectory(src) # Compile extras only if this is a top-level project if(FLOAT_TETWILD_TOPLEVEL_PROJECT) - # Unit tests - include(CTest) - enable_testing() - add_subdirectory(tests) + # Unit tests + include(CTest) + enable_testing() + add_subdirectory(tests) endif() diff --git a/cmake/DownloadProject.CMakeLists.cmake.in b/cmake/DownloadProject.CMakeLists.cmake.in index 89be4fdd..e0122f38 100644 --- a/cmake/DownloadProject.CMakeLists.cmake.in +++ b/cmake/DownloadProject.CMakeLists.cmake.in @@ -1,17 +1,17 @@ -# Distributed under the OSI-approved MIT License. See accompanying -# file LICENSE or https://github.com/Crascit/DownloadProject for details. +# 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.20) project(${DL_ARGS_PROJ}-download NONE) include(ExternalProject) -ExternalProject_Add(${DL_ARGS_PROJ}-download - ${DL_ARGS_UNPARSED_ARGUMENTS} - SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" - BINARY_DIR "${DL_ARGS_BINARY_DIR}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" -) +ExternalProject_Add( + ${DL_ARGS_PROJ}-download + ${DL_ARGS_UNPARSED_ARGUMENTS} + SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" + BINARY_DIR "${DL_ARGS_BINARY_DIR}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "") diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index 486abd85..861e074e 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -1,122 +1,128 @@ -################################################################################ +# ############################################################################## # Prepare dependencies -################################################################################ +# ############################################################################## # Download external dependencies include(FloatTetwildDownloadExternal) -################################################################################ +# ############################################################################## # Required libraries -################################################################################ +# ############################################################################## # Sanitizers if(FLOAT_TETWILD_WITH_SANITIZERS) - float_tetwild_download_sanitizers() - find_package(Sanitizers) + float_tetwild_download_sanitizers() + find_package(Sanitizers) endif() # CL11 if(FLOAT_TETWILD_TOPLEVEL_PROJECT AND NOT TARGET CLI11::CLI11) - float_tetwild_download_cli11() - add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/cli11) + float_tetwild_download_cli11() + add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/cli11) endif() # fmt if(NOT TARGET fmt::fmt) - float_tetwild_download_fmt() - add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/fmt) + float_tetwild_download_fmt() + add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/fmt) endif() # spdlog if(NOT TARGET spdlog::spdlog) - float_tetwild_download_spdlog() - - # Create interface target - add_library(spdlog INTERFACE) - add_library(spdlog::spdlog ALIAS spdlog) - target_include_directories(spdlog INTERFACE ${FLOAT_TETWILD_EXTERNAL}/spdlog/include) - target_link_libraries(spdlog INTERFACE fmt::fmt) - target_compile_definitions(spdlog INTERFACE SPDLOG_FMT_EXTERNAL) + float_tetwild_download_spdlog() + + # Create interface target + add_library(spdlog INTERFACE) + add_library(spdlog::spdlog ALIAS spdlog) + target_include_directories(spdlog + INTERFACE ${FLOAT_TETWILD_EXTERNAL}/spdlog/include) + target_link_libraries(spdlog INTERFACE fmt::fmt) + target_compile_definitions(spdlog INTERFACE SPDLOG_FMT_EXTERNAL) endif() # Libigl if(NOT TARGET igl::core) - float_tetwild_download_libigl() + float_tetwild_download_libigl() - # Import libigl targets - list(APPEND CMAKE_MODULE_PATH "${FLOAT_TETWILD_EXTERNAL}/libigl/cmake") - include(libigl) + # Import libigl targets + list(APPEND CMAKE_MODULE_PATH "${FLOAT_TETWILD_EXTERNAL}/libigl/cmake") + include(libigl) endif() # Geogram if(NOT TARGET geogram::geogram) - float_tetwild_download_geogram() - include(geogram) + float_tetwild_download_geogram() + include(geogram) endif() - # TBB -if(FLOAT_TETWILD_ENABLE_TBB AND NOT TARGET tbb::tbb) - float_tetwild_download_tbb() - - set(TBB_BUILD_STATIC ON CACHE BOOL " " FORCE) - set(TBB_BUILD_SHARED OFF CACHE BOOL " " FORCE) - set(TBB_BUILD_TBBMALLOC OFF CACHE BOOL " " FORCE) - set(TBB_BUILD_TBBMALLOC_PROXY OFF CACHE BOOL " " FORCE) - set(TBB_BUILD_TESTS OFF CACHE BOOL " " FORCE) - set(TBB_NO_DATE ON CACHE BOOL " " FORCE) - - add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/tbb tbb) - set_target_properties(tbb_static PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${FLOAT_TETWILD_EXTERNAL}/tbb/include" - ) - if(NOT MSVC) - set_target_properties(tbb_static PROPERTIES - COMPILE_FLAGS "-Wno-implicit-fallthrough -Wno-missing-field-initializers -Wno-unused-parameter -Wno-keyword-macro" - ) - set_target_properties(tbb_static PROPERTIES POSITION_INDEPENDENT_CODE ON) - endif() - add_library(tbb::tbb ALIAS tbb_static) +if(FLOAT_TETWILD_ENABLE_TBB AND NOT TARGET TBB::tbb) + float_tetwild_download_tbb() + + set(TBB_BUILD_STATIC + ON + CACHE BOOL " " FORCE) + set(TBB_BUILD_SHARED + OFF + CACHE BOOL " " FORCE) + set(TBB_BUILD_TBBMALLOC + OFF + CACHE BOOL " " FORCE) + set(TBB_BUILD_TBBMALLOC_PROXY + OFF + CACHE BOOL " " FORCE) + set(TBB_BUILD_TESTS + OFF + CACHE BOOL " " FORCE) + set(TBB_NO_DATE + ON + CACHE BOOL " " FORCE) + + add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/tbb tbb) + # set_target_properties( tbb_static PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + # "${FLOAT_TETWILD_EXTERNAL}/tbb/include") + if(NOT MSVC) + # set_target_properties( tbb_static PROPERTIES COMPILE_FLAGS + # "-Wno-implicit-fallthrough -Wno-missing-field-initializers + # -Wno-unused-parameter -Wno-keyword-macro" ) + # set_target_properties(tbb_static PROPERTIES POSITION_INDEPENDENT_CODE ON) + endif() endif() # C++11 threads find_package(Threads REQUIRED) - # Json if(NOT TARGET json) - float_tetwild_download_json() - add_library(json INTERFACE) - target_include_directories(json SYSTEM INTERFACE ${FLOAT_TETWILD_EXTERNAL}/json/include) + float_tetwild_download_json() + add_library(json INTERFACE) + target_include_directories(json SYSTEM + INTERFACE ${FLOAT_TETWILD_EXTERNAL}/json/include) endif() - - -# winding number -#float_tetwild_download_windingnumber() -#set(windingnumber_SOURCES -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/SYS_Math.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/SYS_Types.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_Array.cpp -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_Array.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_ArrayImpl.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_BVH.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_BVHImpl.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_FixedVector.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_ParallelUtil.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_SmallArray.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_SolidAngle.cpp -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_SolidAngle.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/VM_SIMD.h -# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/VM_SSEFunc.h -#) +# winding number float_tetwild_download_windingnumber() +# set(windingnumber_SOURCES ${FLOAT_TETWILD_EXTERNAL}/windingnumber/SYS_Math.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/SYS_Types.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_Array.cpp +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_Array.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_ArrayImpl.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_BVH.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_BVHImpl.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_FixedVector.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_ParallelUtil.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_SmallArray.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_SolidAngle.cpp +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/UT_SolidAngle.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/VM_SIMD.h +# ${FLOAT_TETWILD_EXTERNAL}/windingnumber/VM_SSEFunc.h ) # -#add_library(fast_winding_number ${windingnumber_SOURCES}) -##target_link_libraries(fast_winding_number PRIVATE tbb::tbb) -#target_compile_features(fast_winding_number PRIVATE ${CXX17_FEATURES}) -#target_include_directories(fast_winding_number PUBLIC "${FLOAT_TETWILD_EXTERNAL}/") +# add_library(fast_winding_number ${windingnumber_SOURCES}) +# target_link_libraries(fast_winding_number PRIVATE tbb::tbb) +# target_compile_features(fast_winding_number PRIVATE ${CXX17_FEATURES}) +# target_include_directories(fast_winding_number PUBLIC +# "${FLOAT_TETWILD_EXTERNAL}/") if(FLOAT_TETWILD_WITH_EXACT_ENVELOPE) - float_tetwild_download_exact_envelope() - add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/exact_envelope) -endif() \ No newline at end of file + float_tetwild_download_exact_envelope() + add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/exact_envelope) +endif() diff --git a/cmake/FloatTetwildDownloadExternal.cmake b/cmake/FloatTetwildDownloadExternal.cmake index 2801e616..f9a5167f 100644 --- a/cmake/FloatTetwildDownloadExternal.cmake +++ b/cmake/FloatTetwildDownloadExternal.cmake @@ -1,9 +1,9 @@ -################################################################################ +# ############################################################################## include(DownloadProject) -# With CMake 3.8 and above, we can hide warnings about git being in a -# detached head by passing an extra GIT_CONFIG option +# With CMake 3.8 and above, we can hide warnings about git being in a detached +# head by passing an extra GIT_CONFIG option if(NOT (${CMAKE_VERSION} VERSION_LESS "3.8.0")) set(FLOAT_TETWILD_EXTRA_OPTIONS "GIT_CONFIG advice.detachedHead=false") else() @@ -13,112 +13,104 @@ endif() # Shortcut function function(float_tetwild_download_project name) download_project( - PROJ ${name} - SOURCE_DIR ${FLOAT_TETWILD_EXTERNAL}/${name} - DOWNLOAD_DIR ${FLOAT_TETWILD_EXTERNAL}/.cache/${name} - QUIET - ${FLOAT_TETWILD_EXTRA_OPTIONS} - ${ARGN} - ) + PROJ + ${name} + SOURCE_DIR + ${FLOAT_TETWILD_EXTERNAL}/${name} + DOWNLOAD_DIR + ${FLOAT_TETWILD_EXTERNAL}/.cache/${name} + QUIET + ${FLOAT_TETWILD_EXTRA_OPTIONS} + ${ARGN}) endfunction() -################################################################################ +# ############################################################################## -## libigl +# libigl function(float_tetwild_download_libigl) - float_tetwild_download_project(libigl - GIT_REPOSITORY https://github.com/libigl/libigl.git - GIT_TAG 45cfc79fede992ea3923ded9de3c21d1c4faced1 - ) + float_tetwild_download_project( + libigl GIT_REPOSITORY https://github.com/libigl/libigl.git GIT_TAG + 45cfc79fede992ea3923ded9de3c21d1c4faced1) endfunction() -## Json +# Json function(float_tetwild_download_json) - float_tetwild_download_project(json - GIT_REPOSITORY https://github.com/jdumas/json - GIT_TAG 0901d33bf6e7dfe6f70fd9d142c8f5c6695c6c5b - ) + float_tetwild_download_project( + json GIT_REPOSITORY https://github.com/jdumas/json GIT_TAG + 0901d33bf6e7dfe6f70fd9d142c8f5c6695c6c5b) endfunction() -## Catch2 +# Catch2 function(float_tetwild_download_catch2) - float_tetwild_download_project(Catch2 - URL https://github.com/catchorg/Catch2/archive/refs/tags/v3.1.1.tar.gz - URL_MD5 1f3e0d8c3297252f77d643ff06d058cb - ) + float_tetwild_download_project( + Catch2 URL + https://github.com/catchorg/Catch2/archive/refs/tags/v3.5.3.tar.gz URL_MD5 + 1f51d817ce81d54b12e87d06e159305f) endfunction() -## CLI11 +# CLI11 function(float_tetwild_download_cli11) - float_tetwild_download_project(cli11 - URL https://github.com/CLIUtils/CLI11/archive/v1.8.0.tar.gz - URL_MD5 5e5470abcb76422360409297bfc446ac - ) + float_tetwild_download_project( + cli11 URL https://github.com/CLIUtils/CLI11/archive/v1.8.0.tar.gz URL_MD5 + 5e5470abcb76422360409297bfc446ac) endfunction() -## tbb +# tbb function(float_tetwild_download_tbb) - float_tetwild_download_project(tbb - GIT_REPOSITORY https://github.com/wjakob/tbb.git - GIT_TAG 9e219e2 - ) + float_tetwild_download_project( + tbb GIT_REPOSITORY https://github.com/oneapi-src/oneTBB GIT_TAG + 9afd759b72c0c233cd5ea3c3c06b0894c9da9c54) endfunction() -## Sanitizers +# Sanitizers function(float_tetwild_download_sanitizers) - float_tetwild_download_project(sanitizers-cmake - GIT_REPOSITORY https://github.com/arsenm/sanitizers-cmake.git - GIT_TAG 6947cff3a9c9305eb9c16135dd81da3feb4bf87f - ) + float_tetwild_download_project( + sanitizers-cmake GIT_REPOSITORY + https://github.com/arsenm/sanitizers-cmake.git GIT_TAG + 6947cff3a9c9305eb9c16135dd81da3feb4bf87f) endfunction() -## fmt +# fmt function(float_tetwild_download_fmt) - float_tetwild_download_project(fmt - URL https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz - URL_MD5 1015bf3ff2a140dfe03de50ee2469401 - ) + float_tetwild_download_project( + fmt URL https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz URL_MD5 + 1015bf3ff2a140dfe03de50ee2469401) endfunction() -## spdlog +# spdlog function(float_tetwild_download_spdlog) - float_tetwild_download_project(spdlog - URL https://github.com/gabime/spdlog/archive/v1.3.1.tar.gz - URL_MD5 3c17dd6983de2a66eca8b5a0b213d29f - ) + float_tetwild_download_project( + spdlog URL https://github.com/gabime/spdlog/archive/v1.3.1.tar.gz URL_MD5 + 3c17dd6983de2a66eca8b5a0b213d29f) endfunction() -## Geogram LGPL +# Geogram LGPL function(float_tetwild_download_geogram) - float_tetwild_download_project(geogram -# GIT_REPOSITORY https://github.com/polyfem/geogram.git -# GIT_TAG e6b9612f1146370e40deaa341b4dd7ef90502102 - GIT_REPOSITORY https://github.com/Yixin-Hu/geogram - GIT_TAG b613750341a6cdd31ae8df80ecfc26ac7ca1a6ad - ) + float_tetwild_download_project( + geogram + # GIT_REPOSITORY https://github.com/polyfem/geogram.git GIT_TAG + # e6b9612f1146370e40deaa341b4dd7ef90502102 + GIT_REPOSITORY + https://github.com/Yixin-Hu/geogram + GIT_TAG + b613750341a6cdd31ae8df80ecfc26ac7ca1a6ad) endfunction() -## aabbcc +# aabbcc function(float_tetwild_download_aabbcc) - float_tetwild_download_project(aabbcc - GIT_REPOSITORY https://github.com/lohedges/aabbcc.git - GIT_TAG 0c85e61362d384d70c71946826bfed0fb24a74ba - ) + float_tetwild_download_project( + aabbcc GIT_REPOSITORY https://github.com/lohedges/aabbcc.git GIT_TAG + 0c85e61362d384d70c71946826bfed0fb24a74ba) endfunction() -### winding number -#function(float_tetwild_download_windingnumber) -# float_tetwild_download_project(windingnumber -# GIT_REPOSITORY https://github.com/alecjacobson/WindingNumber.git -# GIT_TAG bde8780ec848fa71c1294a0af50347e968b19493 -# ) -#endfunction() +# winding number function(float_tetwild_download_windingnumber) +# float_tetwild_download_project(windingnumber GIT_REPOSITORY +# https://github.com/alecjacobson/WindingNumber.git GIT_TAG +# bde8780ec848fa71c1294a0af50347e968b19493 ) endfunction() - -## exact envelope +# exact envelope function(float_tetwild_download_exact_envelope) - float_tetwild_download_project(exact_envelope - GIT_REPOSITORY https://github.com/wangbolun300/fast-envelope - GIT_TAG 520ee04b6c69a802db31d1fd3a3e6e382d10ef98 - ) + float_tetwild_download_project( + exact_envelope GIT_REPOSITORY https://github.com/wangbolun300/fast-envelope + GIT_TAG 520ee04b6c69a802db31d1fd3a3e6e382d10ef98) endfunction() diff --git a/src/EdgeCollapsing.cpp b/src/EdgeCollapsing.cpp index 755f202f..8d8f91ee 100644 --- a/src/EdgeCollapsing.cpp +++ b/src/EdgeCollapsing.cpp @@ -9,13 +9,10 @@ #include #include -#include //todo: tmp - +#include //todo: tmp #ifdef FLOAT_TETWILD_USE_TBB -#include -#include -#include +#include #endif @@ -30,22 +27,25 @@ #define EC_POSTPROCESS true - namespace floatTetWild { namespace { -void edge_collapsing_aux(Mesh& mesh, const AABBWrapper& tree, std::vector> &edges) { - auto &tets = mesh.tets; - auto &tet_vertices = mesh.tet_vertices; - - int counter = 0; - int suc_counter = 0; +void edge_collapsing_aux(Mesh& mesh, + const AABBWrapper& tree, + std::vector>& edges) +{ + auto& tets = mesh.tets; + auto& tet_vertices = mesh.tet_vertices; + + int counter = 0; + int suc_counter = 0; int suc_counter_env = 0; ////init std::priority_queue, cmp_s> ec_queue; - for (auto &e:edges) { + for (auto& e : edges) { Scalar l_2 = get_edge_length_2(mesh, e[0], e[1]); - if (is_collapsable_length(mesh, e[0], e[1], l_2) && is_collapsable_boundary(mesh, e[0], e[1], tree)) { + if (is_collapsable_length(mesh, e[0], e[1], l_2) && + is_collapsable_boundary(mesh, e[0], e[1], tree)) { ec_queue.push(ElementInQueue(e, l_2)); ec_queue.push(ElementInQueue({{e[1], e[0]}}, l_2)); } @@ -53,19 +53,19 @@ void edge_collapsing_aux(Mesh& mesh, const AABBWrapper& tree, std::vector> inf_es; - std::vector inf_e_tss; - std::vector tet_tss; + std::vector inf_e_tss; + std::vector tet_tss; tet_tss.assign(tets.size(), 0); do { - counter = 0; - suc_counter = 0; + counter = 0; + suc_counter = 0; suc_counter_env = 0; while (!ec_queue.empty()) { - std::array v_ids = ec_queue.top().v_ids; - Scalar old_weight = ec_queue.top().weight; + std::array v_ids = ec_queue.top().v_ids; + Scalar old_weight = ec_queue.top().weight; ec_queue.pop(); while (!ec_queue.empty()) { @@ -75,13 +75,13 @@ void edge_collapsing_aux(Mesh& mesh, const AABBWrapper& tree, std::vector n12_t_ids; -//// set_intersection(tet_vertices[v1_id].conn_tets, tet_vertices[v2_id].conn_tets, n12_t_ids); -// -// Scalar old_max_quality = 0; -// std::vector new_qs; -// new_qs.reserve(tet_vertices[v1_id].conn_tets.size()); -// for (int t_id:tet_vertices[v1_id].conn_tets) { -// if (tets[t_id].quality > old_max_quality) -// old_max_quality = tets[t_id].quality; -// } -// if(old_max_quality>5e9){ -// cout<<"resilt = "< n12_t_ids; + //// set_intersection(tet_vertices[v1_id].conn_tets, + /// tet_vertices[v2_id].conn_tets, n12_t_ids); + // + // Scalar old_max_quality = 0; + // std::vector new_qs; + // new_qs.reserve(tet_vertices[v1_id].conn_tets.size()); + // for (int t_id:tet_vertices[v1_id].conn_tets) { + // if (tets[t_id].quality > old_max_quality) + // old_max_quality = tets[t_id].quality; + // } + // if(old_max_quality>5e9){ + // cout<<"resilt = "<> tmp_inf_es; - const unsigned int inf_es_size = inf_es.size(); + const unsigned int inf_es_size = inf_es.size(); tmp_inf_es.reserve(inf_es_size / 4.0 + 1); for (unsigned int i = 0; i < inf_es_size; i++) { - if(is_edge_freezed(mesh, inf_es[i][0], inf_es[i][1])) + if (is_edge_freezed(mesh, inf_es[i][0], inf_es[i][1])) continue; if (!is_valid_edge(mesh, inf_es[i][0], inf_es[i][1])) continue; @@ -177,7 +180,7 @@ void edge_collapsing_aux(Mesh& mesh, const AABBWrapper& tree, std::vector inf_e_tss[i]) { is_recal = true; break; @@ -189,7 +192,8 @@ void edge_collapsing_aux(Mesh& mesh, const AABBWrapper& tree, std::vector 0); } -} -} +} // namespace +} // namespace floatTetWild -void floatTetWild::edge_collapsing(Mesh& mesh, const AABBWrapper& tree) { - auto &tet_vertices = mesh.tet_vertices; - auto &tets = mesh.tets; +void floatTetWild::edge_collapsing(Mesh& mesh, const AABBWrapper& tree) +{ + auto& tet_vertices = mesh.tet_vertices; + auto& tets = mesh.tets; std::vector> edges; -// #ifdef FLOAT_TETWILD_USE_TBB_bug //TODO: remove bug and fix -// std::vector> partition; -// int num_partition = tbb::task_scheduler_init::default_num_threads(); -// partition.clear(); -// cout << "num_partition = " << num_partition << endl; -// mesh.partition(num_partition, partition); - -// for (int p_id = 0; p_id < partition.size(); p_id++) { -// for (int t_id: partition[p_id]) -// tets[t_id].scalar = p_id; -// } -// for (auto &v:tet_vertices) { -// std::unordered_set p_ids; -// v.is_freezed = false; -// for (int t_id: v.conn_tets) { -// p_ids.insert(tets[t_id].scalar); -// if (p_ids.size() > 1) { -// v.is_freezed = true; -// break; -// } -// } -// } - -// const bool skip_freezed = true; -// tbb::parallel_for(size_t(0), size_t(partition.size()), [&](size_t i) { -// std::vector> edges; -// get_all_edges(mesh, partition[i], edges, skip_freezed); -// edge_collapsing_aux(mesh, tree, edges); -// }); - -// // for (auto &t: mesh.tets) { -// // for (int j = 0; j < 3; j++) { -// // if (mesh.tet_vertices[t[0]].is_freezed || mesh.tet_vertices[t[j + 1]].is_freezed) { -// // std::array e = {{t[0], t[j + 1]}}; -// // if (e[0] > e[1]) -// // std::swap(e[0], e[1]); -// // edges.push_back(e); -// // } -// // if (mesh.tet_vertices[t[j + 1]].is_freezed || mesh.tet_vertices[mod3(j + 1) + 1].is_freezed) { -// // std::array e = {{t[j + 1], t[mod3(j + 1) + 1]}}; -// // if (e[0] > e[1]) -// // std::swap(e[0], e[1]); -// // edges.push_back(e); -// // } -// // } -// // } -// // vector_unique(edges); -// get_all_edges(mesh, edges); -// edge_collapsing_aux(mesh, tree, edges); - -// for (auto &v:tet_vertices) -// v.is_freezed = false; -// for (auto &t:tets) -// t.scalar = 0; -// #else + // #ifdef FLOAT_TETWILD_USE_TBB_bug //TODO: remove bug and fix + // std::vector> partition; + // int num_partition = tbb::task_scheduler_init::default_num_threads(); + // partition.clear(); + // cout << "num_partition = " << num_partition << endl; + // mesh.partition(num_partition, partition); + + // for (int p_id = 0; p_id < partition.size(); p_id++) { + // for (int t_id: partition[p_id]) + // tets[t_id].scalar = p_id; + // } + // for (auto &v:tet_vertices) { + // std::unordered_set p_ids; + // v.is_freezed = false; + // for (int t_id: v.conn_tets) { + // p_ids.insert(tets[t_id].scalar); + // if (p_ids.size() > 1) { + // v.is_freezed = true; + // break; + // } + // } + // } + + // const bool skip_freezed = true; + // tbb::parallel_for(size_t(0), size_t(partition.size()), [&](size_t i) { + // std::vector> edges; + // get_all_edges(mesh, partition[i], edges, skip_freezed); + // edge_collapsing_aux(mesh, tree, edges); + // }); + + // // for (auto &t: mesh.tets) { + // // for (int j = 0; j < 3; j++) { + // // if (mesh.tet_vertices[t[0]].is_freezed || mesh.tet_vertices[t[j + + // 1]].is_freezed) { + // // std::array e = {{t[0], t[j + 1]}}; + // // if (e[0] > e[1]) + // // std::swap(e[0], e[1]); + // // edges.push_back(e); + // // } + // // if (mesh.tet_vertices[t[j + 1]].is_freezed || mesh.tet_vertices[mod3(j + 1) + + // 1].is_freezed) { + // // std::array e = {{t[j + 1], t[mod3(j + 1) + 1]}}; + // // if (e[0] > e[1]) + // // std::swap(e[0], e[1]); + // // edges.push_back(e); + // // } + // // } + // // } + // // vector_unique(edges); + // get_all_edges(mesh, edges); + // edge_collapsing_aux(mesh, tree, edges); + + // for (auto &v:tet_vertices) + // v.is_freezed = false; + // for (auto &t:tets) + // t.scalar = 0; + // #else get_all_edges(mesh, edges); edge_collapsing_aux(mesh, tree, edges); -// #endif + // #endif } -int floatTetWild::collapse_an_edge(Mesh& mesh, int v1_id, int v2_id, const AABBWrapper& tree, - std::vector>& new_edges, int ts, std::vector& tet_tss, - bool is_check_quality, bool is_update_tss) { - auto &tet_vertices = mesh.tet_vertices; - auto &tets = mesh.tets; +int floatTetWild::collapse_an_edge(Mesh& mesh, + int v1_id, + int v2_id, + const AABBWrapper& tree, + std::vector>& new_edges, + int ts, + std::vector& tet_tss, + bool is_check_quality, + bool is_update_tss) +{ + auto& tet_vertices = mesh.tet_vertices; + auto& tets = mesh.tets; ////check vertices - //check isolate surface points + // check isolate surface points if (tet_vertices[v1_id].is_on_surface && is_isolate_surface_point(mesh, v1_id)) { - tet_vertices[v1_id].is_on_surface = false; + tet_vertices[v1_id].is_on_surface = false; tet_vertices[v1_id].is_on_boundary = false; } - //check boundary/surface - if (tet_vertices[v1_id].is_on_boundary && is_point_out_boundary_envelope(mesh, tet_vertices[v2_id].pos, tree))//todo: you should check/unmark is_on_boundary around here + // check boundary/surface + if (tet_vertices[v1_id].is_on_boundary && + is_point_out_boundary_envelope( + mesh, + tet_vertices[v2_id].pos, + tree)) // todo: you should check/unmark is_on_boundary around here return EC_FAIL_ENVELOPE0; - if (tet_vertices[v1_id].is_on_surface && is_point_out_envelope(mesh, tet_vertices[v2_id].pos, tree)) + if (tet_vertices[v1_id].is_on_surface && + is_point_out_envelope(mesh, tet_vertices[v2_id].pos, tree)) return EC_FAIL_ENVELOPE1; - ////check tets std::vector n12_t_ids; set_intersection(tet_vertices[v1_id].conn_tets, tet_vertices[v2_id].conn_tets, n12_t_ids); - if(n12_t_ids.empty()) + if (n12_t_ids.empty()) return EC_FAIL_INVERSION; -// std::unordered_set n1_t_ids = tet_vertices[v1_id].conn_tets;//v1.conn_tets - n12_t_ids -// for (int t_id:n12_t_ids) -// n1_t_ids.erase(t_id); - std::vector n1_t_ids;//v1.conn_tets - n12_t_ids + // std::unordered_set n1_t_ids = tet_vertices[v1_id].conn_tets;//v1.conn_tets - + // n12_t_ids for (int t_id:n12_t_ids) + // n1_t_ids.erase(t_id); + std::vector n1_t_ids; // v1.conn_tets - n12_t_ids std::sort(tet_vertices[v1_id].conn_tets.begin(), tet_vertices[v1_id].conn_tets.end()); std::sort(n12_t_ids.begin(), n12_t_ids.end()); - std::set_difference(tet_vertices[v1_id].conn_tets.begin(), tet_vertices[v1_id].conn_tets.end(), - n12_t_ids.begin(), n12_t_ids.end(), std::back_inserter(n1_t_ids)); + std::set_difference(tet_vertices[v1_id].conn_tets.begin(), + tet_vertices[v1_id].conn_tets.end(), + n12_t_ids.begin(), + n12_t_ids.end(), + std::back_inserter(n1_t_ids)); - //inversion + // inversion std::vector js_n1_t_ids; - for (int t_id:n1_t_ids) { + for (int t_id : n1_t_ids) { int j = tets[t_id].find(v1_id); js_n1_t_ids.push_back(j); assert(j < 4); @@ -310,13 +331,14 @@ int floatTetWild::collapse_an_edge(Mesh& mesh, int v1_id, int v2_id, const AABBW return EC_FAIL_INVERSION; } - //quality + // quality Scalar old_max_quality = 0; - if(mesh.is_coarsening){ + if (mesh.is_coarsening) { old_max_quality = mesh.params.stop_energy; - } else { + } + else { if (is_check_quality) { - for (int t_id:tet_vertices[v1_id].conn_tets) { + for (int t_id : tet_vertices[v1_id].conn_tets) { if (tets[t_id].quality > old_max_quality) old_max_quality = tets[t_id].quality; } @@ -325,16 +347,18 @@ int floatTetWild::collapse_an_edge(Mesh& mesh, int v1_id, int v2_id, const AABBW std::vector new_qs; new_qs.reserve(tet_vertices[v1_id].conn_tets.size()); int ii = 0; - for (int t_id:n1_t_ids) { - int j = js_n1_t_ids[ii++]; - Scalar new_q = get_quality(tet_vertices[v2_id], tet_vertices[tets[t_id][mod4(j + 1)]], - tet_vertices[tets[t_id][mod4(j + 2)]], tet_vertices[tets[t_id][mod4(j + 3)]]); + for (int t_id : n1_t_ids) { + int j = js_n1_t_ids[ii++]; + Scalar new_q = get_quality(tet_vertices[v2_id], + tet_vertices[tets[t_id][mod4(j + 1)]], + tet_vertices[tets[t_id][mod4(j + 2)]], + tet_vertices[tets[t_id][mod4(j + 3)]]); if (is_check_quality && new_q > old_max_quality) return EC_FAIL_QUALITY; new_qs.push_back(new_q); } - //envelope + // envelope Scalar l = get_edge_length_2(mesh, v1_id, v2_id); if (l > 0) { if (tet_vertices[v1_id].is_on_boundary) { @@ -347,99 +371,104 @@ int floatTetWild::collapse_an_edge(Mesh& mesh, int v1_id, int v2_id, const AABBW } } - ////real update - //vertex + // vertex tet_vertices[v1_id].is_removed = true; - tet_vertices[v2_id].is_on_bbox = tet_vertices[v1_id].is_on_bbox || tet_vertices[v2_id].is_on_bbox; - tet_vertices[v2_id].is_on_surface = tet_vertices[v1_id].is_on_surface || tet_vertices[v2_id].is_on_surface; - tet_vertices[v2_id].is_on_boundary = tet_vertices[v1_id].is_on_boundary || tet_vertices[v2_id].is_on_boundary; - if(tet_vertices[v1_id].on_boundary_e_id >= 0) + tet_vertices[v2_id].is_on_bbox = + tet_vertices[v1_id].is_on_bbox || tet_vertices[v2_id].is_on_bbox; + tet_vertices[v2_id].is_on_surface = + tet_vertices[v1_id].is_on_surface || tet_vertices[v2_id].is_on_surface; + tet_vertices[v2_id].is_on_boundary = + tet_vertices[v1_id].is_on_boundary || tet_vertices[v2_id].is_on_boundary; + if (tet_vertices[v1_id].on_boundary_e_id >= 0) tet_vertices[v2_id].on_boundary_e_id = tet_vertices[v1_id].on_boundary_e_id; - //tets - //update quality - int i=0; - for (int t_id:n1_t_ids) { + // tets + // update quality + int i = 0; + for (int t_id : n1_t_ids) { tets[t_id].quality = new_qs[i++]; } - //n_v_id for repush -// std::vector n12_v_ids; -// std::vector n1_v_ids; -// n12_v_ids.reserve(n12_t_ids.size() * 4); -// for (int t_id:n12_t_ids) { -// for (int j = 0; j < 4; j++) -// n12_v_ids.push_back(tets[t_id][j]); -// } -// n1_v_ids.reserve(n1_t_ids.size() * 4); -// for (int t_id:n1_t_ids) { -// for (int j = 0; j < 4; j++) -// n1_v_ids.push_back(tets[t_id][j]); -// } -// vector_unique(n12_v_ids); -// vector_unique(n1_v_ids); -// std::vector n_v_ids; -// std::set_difference(n1_v_ids.begin(), n1_v_ids.end(), n12_v_ids.begin(), n12_v_ids.end(), -// std::inserter(n_v_ids, n_v_ids.begin())); + // n_v_id for repush + // std::vector n12_v_ids; + // std::vector n1_v_ids; + // n12_v_ids.reserve(n12_t_ids.size() * 4); + // for (int t_id:n12_t_ids) { + // for (int j = 0; j < 4; j++) + // n12_v_ids.push_back(tets[t_id][j]); + // } + // n1_v_ids.reserve(n1_t_ids.size() * 4); + // for (int t_id:n1_t_ids) { + // for (int j = 0; j < 4; j++) + // n1_v_ids.push_back(tets[t_id][j]); + // } + // vector_unique(n12_v_ids); + // vector_unique(n1_v_ids); + // std::vector n_v_ids; + // std::set_difference(n1_v_ids.begin(), n1_v_ids.end(), n12_v_ids.begin(), n12_v_ids.end(), + // std::inserter(n_v_ids, n_v_ids.begin())); std::vector n1_v_ids; n1_v_ids.reserve(n1_t_ids.size() * 4); - for (int t_id:n1_t_ids) { + for (int t_id : n1_t_ids) { for (int j = 0; j < 4; j++) n1_v_ids.push_back(tets[t_id][j]); } vector_unique(n1_v_ids); - //update tags -// cout<<"n12_t_ids = "; -// vector_print(n12_t_ids, " "); + // update tags + // cout<<"n12_t_ids = "; + // vector_print(n12_t_ids, " "); - for (int t_id:n12_t_ids) { -// cout<<"t_id = "< 1) { int opp_t_id = pair[0] == t_id ? pair[1] : pair[0]; for (int j = 0; j < 4; j++) { - if (tets[opp_t_id][j] != tets[t_id][mod4(j12[mod2(i + 1)] + 1)] - && tets[opp_t_id][j] != tets[t_id][mod4(j12[mod2(i + 1)] + 2)] - && tets[opp_t_id][j] != tets[t_id][mod4(j12[mod2(i + 1)] + 3)]) { + if (tets[opp_t_id][j] != tets[t_id][mod4(j12[mod2(i + 1)] + 1)] && + tets[opp_t_id][j] != tets[t_id][mod4(j12[mod2(i + 1)] + 2)] && + tets[opp_t_id][j] != tets[t_id][mod4(j12[mod2(i + 1)] + 3)]) { tets[opp_t_id].is_surface_fs[j] = sf_connecting_v12[i]; - tets[opp_t_id].surface_tags[j] = tag_connecting_v12[i]; - tets[opp_t_id].is_bbox_fs[j] = bbox_connecting_v12[i]; + tets[opp_t_id].surface_tags[j] = tag_connecting_v12[i]; + tets[opp_t_id].is_bbox_fs[j] = bbox_connecting_v12[i]; break; } } @@ -487,22 +516,22 @@ int floatTetWild::collapse_an_edge(Mesh& mesh, int v1_id, int v2_id, const AABBW } } - //update connectivity + // update connectivity ts++; ii = 0; - for (int t_id:n1_t_ids) { - int j = js_n1_t_ids[ii++]; + for (int t_id : n1_t_ids) { + int j = js_n1_t_ids[ii++]; tets[t_id][j] = v2_id; -// tet_vertices[v2_id].conn_tets.insert(t_id); + // tet_vertices[v2_id].conn_tets.insert(t_id); tet_vertices[v2_id].conn_tets.push_back(t_id); - if(is_update_tss) - tet_tss[t_id] = ts;//update timestamp + if (is_update_tss) + tet_tss[t_id] = ts; // update timestamp } - for (int t_id: n12_t_ids) { + for (int t_id : n12_t_ids) { tets[t_id].is_removed = true; for (int j = 0; j < 4; j++) { if (tets[t_id][j] != v1_id) -// tet_vertices[tets[t_id][j]].conn_tets.erase(t_id); + // tet_vertices[tets[t_id][j]].conn_tets.erase(t_id); vector_erase(tet_vertices[tets[t_id][j]].conn_tets, t_id); } } @@ -510,52 +539,54 @@ int floatTetWild::collapse_an_edge(Mesh& mesh, int v1_id, int v2_id, const AABBW tet_vertices[v1_id].conn_tets.clear(); ////re-push - for (int v_id:n1_v_ids) { - if(v_id!=v1_id) + for (int v_id : n1_v_ids) { + if (v_id != v1_id) new_edges.push_back({{v2_id, v_id}}); } -// for (int v_id:n_v_ids) { -// new_edges.push_back({{v2_id, v_id}}); -// } + // for (int v_id:n_v_ids) { + // new_edges.push_back({{v2_id, v_id}}); + // } - if(tet_vertices[v1_id].is_on_surface) + if (tet_vertices[v1_id].is_on_surface) return EC_SUCCESS_ENVELOPE; return EC_SUCCESS; } -bool floatTetWild::is_edge_freezed(Mesh& mesh, int v1_id, int v2_id){ - if(mesh.tet_vertices[v1_id].is_freezed || mesh.tet_vertices[v2_id].is_freezed) +bool floatTetWild::is_edge_freezed(Mesh& mesh, int v1_id, int v2_id) +{ + if (mesh.tet_vertices[v1_id].is_freezed || mesh.tet_vertices[v2_id].is_freezed) return true; return false; } -bool floatTetWild::is_collapsable_bbox(Mesh& mesh, int v1_id, int v2_id) { +bool floatTetWild::is_collapsable_bbox(Mesh& mesh, int v1_id, int v2_id) +{ if (!mesh.tet_vertices[v1_id].is_on_bbox) return true; else if (!mesh.tet_vertices[v2_id].is_on_bbox) return false; -// std::unordered_set bbox_fs2; -// for (int t_id:mesh.tet_vertices[v2_id].conn_tets) { -// for (int j = 0; j < 4; j++) { -// if (mesh.tets[t_id][j] != v2_id && mesh.tets[t_id].is_bbox_fs[j] != NOT_BBOX) -// bbox_fs2.insert(mesh.tets[t_id].is_bbox_fs[j]); -// } -// } -// int old_size = bbox_fs2.size(); -// for (int t_id:mesh.tet_vertices[v1_id].conn_tets) { -// for (int j = 0; j < 4; j++) { -// if (mesh.tets[t_id][j] != v1_id && mesh.tets[t_id].is_bbox_fs[j] != NOT_BBOX) { -// bbox_fs2.insert(mesh.tets[t_id].is_bbox_fs[j]); -// if (bbox_fs2.size() > old_size) -// return false; -// } -// } -// } + // std::unordered_set bbox_fs2; + // for (int t_id:mesh.tet_vertices[v2_id].conn_tets) { + // for (int j = 0; j < 4; j++) { + // if (mesh.tets[t_id][j] != v2_id && mesh.tets[t_id].is_bbox_fs[j] != NOT_BBOX) + // bbox_fs2.insert(mesh.tets[t_id].is_bbox_fs[j]); + // } + // } + // int old_size = bbox_fs2.size(); + // for (int t_id:mesh.tet_vertices[v1_id].conn_tets) { + // for (int j = 0; j < 4; j++) { + // if (mesh.tets[t_id][j] != v1_id && mesh.tets[t_id].is_bbox_fs[j] != NOT_BBOX) { + // bbox_fs2.insert(mesh.tets[t_id].is_bbox_fs[j]); + // if (bbox_fs2.size() > old_size) + // return false; + // } + // } + // } std::vector bbox_fs2; - for (int t_id:mesh.tet_vertices[v2_id].conn_tets) { + for (int t_id : mesh.tet_vertices[v2_id].conn_tets) { for (int j = 0; j < 4; j++) { if (mesh.tets[t_id][j] != v2_id && mesh.tets[t_id].is_bbox_fs[j] != NOT_BBOX) bbox_fs2.push_back(mesh.tets[t_id].is_bbox_fs[j]); @@ -563,10 +594,11 @@ bool floatTetWild::is_collapsable_bbox(Mesh& mesh, int v1_id, int v2_id) { } vector_unique(bbox_fs2); - for (int t_id:mesh.tet_vertices[v1_id].conn_tets) { + for (int t_id : mesh.tet_vertices[v1_id].conn_tets) { for (int j = 0; j < 4; j++) { if (mesh.tets[t_id][j] != v1_id && mesh.tets[t_id].is_bbox_fs[j] != NOT_BBOX) { - if(std::find(bbox_fs2.begin(), bbox_fs2.end(), mesh.tets[t_id].is_bbox_fs[j]) == bbox_fs2.end()) + if (std::find(bbox_fs2.begin(), bbox_fs2.end(), mesh.tets[t_id].is_bbox_fs[j]) == + bbox_fs2.end()) return false; } } @@ -575,21 +607,27 @@ bool floatTetWild::is_collapsable_bbox(Mesh& mesh, int v1_id, int v2_id) { return true; } -bool floatTetWild::is_collapsable_length(Mesh& mesh, int v1_id, int v2_id, Scalar l_2) { - Scalar sizing_scalar = (mesh.tet_vertices[v1_id].sizing_scalar + mesh.tet_vertices[v2_id].sizing_scalar) / 2; +bool floatTetWild::is_collapsable_length(Mesh& mesh, int v1_id, int v2_id, Scalar l_2) +{ + Scalar sizing_scalar = + (mesh.tet_vertices[v1_id].sizing_scalar + mesh.tet_vertices[v2_id].sizing_scalar) / 2; if (l_2 <= mesh.params.collapse_threshold_2 * sizing_scalar * sizing_scalar) return true; return false; } -bool floatTetWild::is_collapsable_boundary(Mesh& mesh, int v1_id, int v2_id, const AABBWrapper& tree) { +bool floatTetWild::is_collapsable_boundary(Mesh& mesh, + int v1_id, + int v2_id, + const AABBWrapper& tree) +{ if (mesh.tet_vertices[v1_id].is_on_boundary && !is_boundary_edge(mesh, v1_id, v2_id, tree)) return false; return true; - -// if (mesh.tet_vertices[v1_id].on_boundary_e_id >= 0 && mesh.tet_vertices[v2_id].on_boundary_e_id -// && mesh.tet_vertices[v1_id].on_boundary_e_id != mesh.tet_vertices[v2_id].on_boundary_e_id) -// return false; -// return true; -} \ No newline at end of file + // if (mesh.tet_vertices[v1_id].on_boundary_e_id >= 0 && + // mesh.tet_vertices[v2_id].on_boundary_e_id + // && mesh.tet_vertices[v1_id].on_boundary_e_id != + // mesh.tet_vertices[v2_id].on_boundary_e_id) return false; + // return true; +} diff --git a/src/LocalOperations.cpp b/src/LocalOperations.cpp index 0d06422f..d823ee1c 100644 --- a/src/LocalOperations.cpp +++ b/src/LocalOperations.cpp @@ -12,22 +12,21 @@ #include #ifdef FLOAT_TETWILD_USE_TBB -#include -#include -#include -#include -#include +#include +#include +#include #endif namespace floatTetWild { - bool use_old_energy = false; - std::string envelope_log_csv = ""; - int envelope_log_csv_cnt = 0; -} +bool use_old_energy = false; +std::string envelope_log_csv = ""; +int envelope_log_csv_cnt = 0; +} // namespace floatTetWild using floatTetWild::Scalar; -// void floatTetWild::init_b_tree(const std::vector& input_vertices, const std::vector& input_faces, +// void floatTetWild::init_b_tree(const std::vector& input_vertices, const +// std::vector& input_faces, // GEO::Mesh& b_mesh) { // // std::vector> edges; // // for(int i=0;i tmp; // std::set_intersection(conn_tris[e[0]].begin(), conn_tris[e[0]].end(), -// conn_tris[e[1]].begin(), conn_tris[e[1]].end(), std::back_inserter(tmp)); +// conn_tris[e[1]].begin(), conn_tris[e[1]].end(), +// std::back_inserter(tmp)); // if (tmp.size() == 1) { // b_edges.push_back(e); // } @@ -93,41 +93,47 @@ using floatTetWild::Scalar; // } // } -int floatTetWild::get_opp_t_id(const Mesh& mesh, int t_id, int j) { +int floatTetWild::get_opp_t_id(const Mesh& mesh, int t_id, int j) +{ std::vector pair; set_intersection(mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].conn_tets, mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].conn_tets, - mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].conn_tets, pair); + mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].conn_tets, + pair); if (pair.size() == 2) return pair[0] == t_id ? pair[1] : pair[0]; return OPP_T_ID_BOUNDARY; } -void floatTetWild::set_opp_t_id(Mesh& mesh, int t_id, int j){ +void floatTetWild::set_opp_t_id(Mesh& mesh, int t_id, int j) +{ auto& t = mesh.tets[t_id]; -// static double time = 0; - const int jp1 = mod4(j+1); - const int jp2 = mod4(j+2); - const int jp3 = mod4(j+3); + // static double time = 0; + const int jp1 = mod4(j + 1); + const int jp2 = mod4(j + 2); + const int jp3 = mod4(j + 3); assert((j + 1) % 4 == jp1); assert((j + 2) % 4 == jp2); assert((j + 3) % 4 == jp3); -// igl::Timer timer; -// timer.start(); -// std::unordered_set tmp; -// set_intersection(mesh.tet_vertices[t[(j + 1) % 4]].conn_tets, -// mesh.tet_vertices[t[(j + 2) % 4]].conn_tets, tmp); + // igl::Timer timer; + // timer.start(); + // std::unordered_set tmp; + // set_intersection(mesh.tet_vertices[t[(j + 1) % 4]].conn_tets, + // mesh.tet_vertices[t[(j + 2) % 4]].conn_tets, tmp); static std::vector pair; pair.clear(); -// set_intersection(mesh.tet_vertices[t[(j + 3) % 4]].conn_tets, tmp, pair); - set_intersection(mesh.tet_vertices[t[jp1]].conn_tets, mesh.tet_vertices[t[jp2]].conn_tets, mesh.tet_vertices[t[jp3]].conn_tets, pair); -// timer.stop(); -// time+=timer.getElapsedTimeInSec(); -// std::cout<<"set_opp_t_id "<>& edges){ - edges.reserve(mesh.tets.size()*6); +void floatTetWild::get_all_edges(const Mesh& mesh, std::vector>& edges) +{ + edges.reserve(mesh.tets.size() * 6); #ifdef FLOAT_TETWILD_USE_TBB tbb::concurrent_vector> edges_tbb; - tbb::parallel_for( size_t(0), mesh.tets.size(), [&](size_t i) + tbb::parallel_for(size_t(0), + mesh.tets.size(), + [&](size_t i) #else for (unsigned int i = 0; i < mesh.tets.size(); i++) #endif - { - if (mesh.tets[i].is_removed){ + { + if (mesh.tets[i].is_removed) { #ifdef FLOAT_TETWILD_USE_TBB - return; + return; #else continue; #endif - } - for (int j = 0; j < 3; j++) { - std::array e = {{mesh.tets[i][0], mesh.tets[i][j + 1]}}; - if (e[0] > e[1]) - std::swap(e[0], e[1]); + } + for (int j = 0; j < 3; j++) { + std::array e = {{mesh.tets[i][0], mesh.tets[i][j + 1]}}; + if (e[0] > e[1]) + std::swap(e[0], e[1]); #ifdef FLOAT_TETWILD_USE_TBB - edges_tbb.push_back(e); + edges_tbb.push_back(e); #else edges.push_back(e); #endif - e = {{mesh.tets[i][j + 1], mesh.tets[i][mod3(j + 1) + 1]}}; - if (e[0] > e[1]) - std::swap(e[0], e[1]); + e = {{mesh.tets[i][j + 1], mesh.tets[i][mod3(j + 1) + 1]}}; + if (e[0] > e[1]) + std::swap(e[0], e[1]); #ifdef FLOAT_TETWILD_USE_TBB - edges_tbb.push_back(e); + edges_tbb.push_back(e); #else edges.push_back(e); #endif - } - } + } + } #ifdef FLOAT_TETWILD_USE_TBB ); edges.reserve(edges_tbb.size()); @@ -186,24 +195,31 @@ void floatTetWild::get_all_edges(const Mesh& mesh, std::vector& t_ids, std::vector>& edges, bool skip_freezed) { +void floatTetWild::get_all_edges(const Mesh& mesh, + const std::vector& t_ids, + std::vector>& edges, + bool skip_freezed) +{ for (unsigned int i = 0; i < t_ids.size(); i++) { - auto &t = mesh.tets[t_ids[i]]; + auto& t = mesh.tets[t_ids[i]]; for (int j = 0; j < 3; j++) { if (skip_freezed) { - if (!mesh.tet_vertices[t[0]].is_freezed && !mesh.tet_vertices[t[j + 1]].is_freezed) { + if (!mesh.tet_vertices[t[0]].is_freezed && + !mesh.tet_vertices[t[j + 1]].is_freezed) { std::array e = {{t[0], t[j + 1]}}; if (e[0] > e[1]) std::swap(e[0], e[1]); edges.push_back(e); } - if (!mesh.tet_vertices[t[j + 1]].is_freezed && !mesh.tet_vertices[mod3(j + 1) + 1].is_freezed) { + if (!mesh.tet_vertices[t[j + 1]].is_freezed && + !mesh.tet_vertices[mod3(j + 1) + 1].is_freezed) { std::array e = {{t[j + 1], t[mod3(j + 1) + 1]}}; if (e[0] > e[1]) std::swap(e[0], e[1]); edges.push_back(e); } - } else { + } + else { std::array e = {{t[0], t[j + 1]}}; if (e[0] > e[1]) std::swap(e[0], e[1]); @@ -218,116 +234,137 @@ void floatTetWild::get_all_edges(const Mesh& mesh, const std::vector& t_ids vector_unique(edges); } -Scalar floatTetWild::get_edge_length(const Mesh& mesh, int v1_id, int v2_id) { +Scalar floatTetWild::get_edge_length(const Mesh& mesh, int v1_id, int v2_id) +{ return (mesh.tet_vertices[v1_id].pos - mesh.tet_vertices[v2_id].pos).norm(); } -Scalar floatTetWild::get_edge_length_2(const Mesh& mesh, int v1_id, int v2_id) { +Scalar floatTetWild::get_edge_length_2(const Mesh& mesh, int v1_id, int v2_id) +{ return (mesh.tet_vertices[v1_id].pos - mesh.tet_vertices[v2_id].pos).squaredNorm(); } -bool floatTetWild::is_bbox_edge(const Mesh& mesh, int v1_id, int v2_id, const std::vector& n12_t_ids) { +bool floatTetWild::is_bbox_edge(const Mesh& mesh, + int v1_id, + int v2_id, + const std::vector& n12_t_ids) +{ if (!mesh.tet_vertices[v1_id].is_on_bbox || !mesh.tet_vertices[v2_id].is_on_bbox) return false; - for (int t_id:n12_t_ids) { + for (int t_id : n12_t_ids) { for (int j = 0; j < 4; j++) { - if (mesh.tets[t_id][j] != v1_id && mesh.tets[t_id][j] != v2_id - && mesh.tets[t_id].is_bbox_fs[j] != NOT_BBOX) + if (mesh.tets[t_id][j] != v1_id && mesh.tets[t_id][j] != v2_id && + mesh.tets[t_id].is_bbox_fs[j] != NOT_BBOX) return true; } } return false; } -bool floatTetWild::is_surface_edge(const Mesh& mesh, int v1_id, int v2_id, const std::vector& n12_t_ids){ +bool floatTetWild::is_surface_edge(const Mesh& mesh, + int v1_id, + int v2_id, + const std::vector& n12_t_ids) +{ if (!mesh.tet_vertices[v1_id].is_on_surface || !mesh.tet_vertices[v2_id].is_on_surface) return false; - for (int t_id:n12_t_ids) { + for (int t_id : n12_t_ids) { for (int j = 0; j < 4; j++) { - if (mesh.tets[t_id][j] != v1_id && mesh.tets[t_id][j] != v2_id - && mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE) + if (mesh.tets[t_id][j] != v1_id && mesh.tets[t_id][j] != v2_id && + mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE) return true; } } return false; } -bool floatTetWild::is_boundary_edge(const Mesh& mesh, int v1_id, int v2_id, const AABBWrapper& tree) { +bool floatTetWild::is_boundary_edge(const Mesh& mesh, int v1_id, int v2_id, const AABBWrapper& tree) +{ if (!mesh.tet_vertices[v1_id].is_on_boundary || !mesh.tet_vertices[v2_id].is_on_boundary) return false; #ifdef NEW_ENVELOPE - if(!mesh.is_input_all_inserted) { - return !tree.is_out_tmp_b_envelope_exact({{mesh.tet_vertices[v1_id].pos, mesh.tet_vertices[v2_id].pos, - mesh.tet_vertices[v2_id].pos}}); - } else { - return !tree.is_out_b_envelope_exact({{mesh.tet_vertices[v1_id].pos, mesh.tet_vertices[v2_id].pos, - mesh.tet_vertices[v2_id].pos}}); + if (!mesh.is_input_all_inserted) { + return !tree.is_out_tmp_b_envelope_exact({{mesh.tet_vertices[v1_id].pos, + mesh.tet_vertices[v2_id].pos, + mesh.tet_vertices[v2_id].pos}}); + } + else { + return !tree.is_out_b_envelope_exact({{mesh.tet_vertices[v1_id].pos, + mesh.tet_vertices[v2_id].pos, + mesh.tet_vertices[v2_id].pos}}); } #else std::vector ps; - ps.push_back(GEO::vec3(mesh.tet_vertices[v1_id].pos[0], mesh.tet_vertices[v1_id].pos[1], - mesh.tet_vertices[v1_id].pos[2])); - int p0_id = 0; - Scalar l = get_edge_length(mesh, v1_id, v2_id); - int N = l / mesh.params.dd + 1; - ps.push_back(GEO::vec3(mesh.tet_vertices[v2_id][0], mesh.tet_vertices[v2_id][1], - mesh.tet_vertices[v2_id][2])); + ps.push_back(GEO::vec3(mesh.tet_vertices[v1_id].pos[0], + mesh.tet_vertices[v1_id].pos[1], + mesh.tet_vertices[v1_id].pos[2])); + int p0_id = 0; + Scalar l = get_edge_length(mesh, v1_id, v2_id); + int N = l / mesh.params.dd + 1; + ps.push_back(GEO::vec3( + mesh.tet_vertices[v2_id][0], mesh.tet_vertices[v2_id][1], mesh.tet_vertices[v2_id][2])); int p1_id = ps.size() - 1; for (Scalar j = 1; j < N - 1; j++) { ps.push_back(ps[p0_id] * (j / N) + ps[p1_id] * (1 - j / N)); } - if(!mesh.is_input_all_inserted) { + if (!mesh.is_input_all_inserted) { return !tree.is_out_tmp_b_envelope(ps, mesh.params.eps_2); - } else { + } + else { return !tree.is_out_b_envelope(ps, mesh.params.eps_2); } #endif -// if(!mesh.is_input_all_inserted) -// return true; -// -// int cnt = 0; -// for (int t_id: mesh.tet_vertices[v1_id].conn_tets) { -// std::array opp_js; -// int ii = 0; -// for (int j = 0; j < 4; j++) { -// if (mesh.tets[t_id][j] == v1_id || mesh.tets[t_id][j] == v2_id) -// continue; -// opp_js[ii++] = j; -// } -// if (ii == 2) { -// if (mesh.tets[t_id].is_surface_fs[opp_js[0]] != NOT_SURFACE) -// cnt++; -// if (mesh.tets[t_id].is_surface_fs[opp_js[1]] != NOT_SURFACE) -// cnt++; -// if (cnt > 2) -// return false; -// } -// } -// if (cnt == 2) -// return true; -// return false; + // if(!mesh.is_input_all_inserted) + // return true; + // + // int cnt = 0; + // for (int t_id: mesh.tet_vertices[v1_id].conn_tets) { + // std::array opp_js; + // int ii = 0; + // for (int j = 0; j < 4; j++) { + // if (mesh.tets[t_id][j] == v1_id || mesh.tets[t_id][j] == v2_id) + // continue; + // opp_js[ii++] = j; + // } + // if (ii == 2) { + // if (mesh.tets[t_id].is_surface_fs[opp_js[0]] != NOT_SURFACE) + // cnt++; + // if (mesh.tets[t_id].is_surface_fs[opp_js[1]] != NOT_SURFACE) + // cnt++; + // if (cnt > 2) + // return false; + // } + // } + // if (cnt == 2) + // return true; + // return false; } -bool floatTetWild::is_valid_edge(const Mesh& mesh, int v1_id, int v2_id) { +bool floatTetWild::is_valid_edge(const Mesh& mesh, int v1_id, int v2_id) +{ if (mesh.tet_vertices[v1_id].is_removed || mesh.tet_vertices[v2_id].is_removed) return false; -// std::vector tmp; -// set_intersection(mesh.tet_vertices[v1_id].conn_tets, mesh.tet_vertices[v2_id].conn_tets, tmp); -// if (tmp.empty()) { -// cout<<"happen"< tmp; + // set_intersection(mesh.tet_vertices[v1_id].conn_tets, mesh.tet_vertices[v2_id].conn_tets, + // tmp); if (tmp.empty()) { + // cout<<"happen"<& n12_t_ids) { +bool floatTetWild::is_valid_edge(const Mesh& mesh, + int v1_id, + int v2_id, + const std::vector& n12_t_ids) +{ if (mesh.tet_vertices[v1_id].is_removed || mesh.tet_vertices[v2_id].is_removed) return false; if (n12_t_ids.empty()) @@ -336,8 +373,9 @@ bool floatTetWild::is_valid_edge(const Mesh& mesh, int v1_id, int v2_id, const s return true; } -bool floatTetWild::is_isolate_surface_point(const Mesh& mesh, int v_id) { - for (int t_id:mesh.tet_vertices[v_id].conn_tets) { +bool floatTetWild::is_isolate_surface_point(const Mesh& mesh, int v_id) +{ + for (int t_id : mesh.tet_vertices[v_id].conn_tets) { for (int j = 0; j < 4; j++) { if (mesh.tets[t_id][j] != v_id && mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE) return false; @@ -347,35 +385,42 @@ bool floatTetWild::is_isolate_surface_point(const Mesh& mesh, int v_id) { return true; } -bool floatTetWild::is_point_out_envelope(const Mesh& mesh, const Vector3& p, const AABBWrapper& tree){ +bool floatTetWild::is_point_out_envelope(const Mesh& mesh, + const Vector3& p, + const AABBWrapper& tree) +{ #ifdef NEW_ENVELOPE return tree.is_out_sf_envelope_exact(p); #else GEO::index_t prev_facet; return tree.is_out_sf_envelope(p, mesh.params.eps_2, prev_facet); #endif -// GEO::vec3 geo_p(p[0], p[1], p[2]); -// if (sf_tree.squared_distance(geo_p) > mesh.params.eps_2) -// return true; -// -// return false; + // GEO::vec3 geo_p(p[0], p[1], p[2]); + // if (sf_tree.squared_distance(geo_p) > mesh.params.eps_2) + // return true; + // + // return false; } -bool floatTetWild::is_point_out_boundary_envelope(const Mesh& mesh, const Vector3& p, const AABBWrapper& tree){ - if(mesh.is_input_all_inserted) +bool floatTetWild::is_point_out_boundary_envelope(const Mesh& mesh, + const Vector3& p, + const AABBWrapper& tree) +{ + if (mesh.is_input_all_inserted) return false; GEO::index_t prev_facet; return tree.is_out_tmp_b_envelope(p, mesh.params.eps_2, prev_facet); -// GEO::vec3 geo_p(p[0], p[1], p[2]); -// if (b_tree.squared_distance(geo_p) > mesh.params.eps_2) -// return true; -// -// return false; + // GEO::vec3 geo_p(p[0], p[1], p[2]); + // if (b_tree.squared_distance(geo_p) > mesh.params.eps_2) + // return true; + // + // return false; } -Scalar floatTetWild::get_quality(const Mesh& mesh, const MeshTet& t) { +Scalar floatTetWild::get_quality(const Mesh& mesh, const MeshTet& t) +{ std::array T; for (int i = 0; i < 4; i++) { for (int j = 0; j < 3; j++) @@ -383,54 +428,74 @@ Scalar floatTetWild::get_quality(const Mesh& mesh, const MeshTet& t) { } return AMIPS_energy(T); -// Scalar q = AMIPS_energy(T); -// if (q > 1e8) -// return MAX_ENERGY; -// else -// return q; + // Scalar q = AMIPS_energy(T); + // if (q > 1e8) + // return MAX_ENERGY; + // else + // return q; } -Scalar floatTetWild::get_quality(const Mesh& mesh, int t_id) { +Scalar floatTetWild::get_quality(const Mesh& mesh, int t_id) +{ std::array T; for (int i = 0; i < 4; i++) { for (int j = 0; j < 3; j++) T[i * 3 + j] = mesh.tet_vertices[mesh.tets[t_id][i]].pos[j]; } return AMIPS_energy(T); -// Scalar q = AMIPS_energy(T); -// if (q > 1e8) -// return MAX_ENERGY; -// else -// return q; + // Scalar q = AMIPS_energy(T); + // if (q > 1e8) + // return MAX_ENERGY; + // else + // return q; } -Scalar floatTetWild::get_quality(const MeshVertex& v0, const MeshVertex& v1, const MeshVertex& v2, const MeshVertex& v3) { - std::array T = {{v0.pos[0], v0.pos[1], v0.pos[2], v1.pos[0], v1.pos[1], v1.pos[2], - v2.pos[0], v2.pos[1], v2.pos[2], v3.pos[0], v3.pos[1], v3.pos[2]}}; +Scalar floatTetWild::get_quality(const MeshVertex& v0, + const MeshVertex& v1, + const MeshVertex& v2, + const MeshVertex& v3) +{ + std::array T = {{v0.pos[0], + v0.pos[1], + v0.pos[2], + v1.pos[0], + v1.pos[1], + v1.pos[2], + v2.pos[0], + v2.pos[1], + v2.pos[2], + v3.pos[0], + v3.pos[1], + v3.pos[2]}}; return AMIPS_energy(T); -// Scalar q = AMIPS_energy(T); -// if (q > 1e8) -// return MAX_ENERGY; -// else -// return q; + // Scalar q = AMIPS_energy(T); + // if (q > 1e8) + // return MAX_ENERGY; + // else + // return q; } -Scalar floatTetWild::get_quality(const Vector3& v0, const Vector3& v1, const Vector3& v2, const Vector3& v3){ - std::array T = {{v0[0], v0[1], v0[2], v1[0], v1[1], v1[2], - v2[0], v2[1], v2[2], v3[0], v3[1], v3[2]}}; +Scalar floatTetWild::get_quality(const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& v3) +{ + std::array T = { + {v0[0], v0[1], v0[2], v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2]}}; return AMIPS_energy(T); -// Scalar q = AMIPS_energy(T); -// if (q > 1e8) -// return MAX_ENERGY; -// else -// return q; + // Scalar q = AMIPS_energy(T); + // if (q > 1e8) + // return MAX_ENERGY; + // else + // return q; } -void floatTetWild::get_max_avg_energy(const Mesh& mesh, Scalar& max_energy, Scalar& avg_energy) { +void floatTetWild::get_max_avg_energy(const Mesh& mesh, Scalar& max_energy, Scalar& avg_energy) +{ max_energy = 0; avg_energy = 0; - int cnt = 0; - for (auto &t: mesh.tets) { + int cnt = 0; + for (auto& t : mesh.tets) { if (t.is_removed) continue; if (t.quality > max_energy) @@ -441,9 +506,10 @@ void floatTetWild::get_max_avg_energy(const Mesh& mesh, Scalar& max_energy, Scal avg_energy /= cnt; } -Scalar floatTetWild::get_mid_energy(const Mesh& mesh){ - std::vector tmp; - for (auto& t:mesh.tets) { +Scalar floatTetWild::get_mid_energy(const Mesh& mesh) +{ + std::vector tmp; + for (auto& t : mesh.tets) { if (t.is_removed) continue; tmp.push_back(t.quality); @@ -452,73 +518,100 @@ Scalar floatTetWild::get_mid_energy(const Mesh& mesh){ return tmp[tmp.size() / 2]; } -bool floatTetWild::is_inverted(const Mesh& mesh, int t_id) { - if (Predicates::orient_3d(mesh.tet_vertices[mesh.tets[t_id][0]].pos, mesh.tet_vertices[mesh.tets[t_id][1]].pos, - mesh.tet_vertices[mesh.tets[t_id][2]].pos, mesh.tet_vertices[mesh.tets[t_id][3]].pos) == +bool floatTetWild::is_inverted(const Mesh& mesh, int t_id) +{ + if (Predicates::orient_3d(mesh.tet_vertices[mesh.tets[t_id][0]].pos, + mesh.tet_vertices[mesh.tets[t_id][1]].pos, + mesh.tet_vertices[mesh.tets[t_id][2]].pos, + mesh.tet_vertices[mesh.tets[t_id][3]].pos) == Predicates::ORI_POSITIVE) return false; return true; } -bool floatTetWild::is_inverted(const Mesh& mesh, int t_id, int j, const Vector3& new_p) { +bool floatTetWild::is_inverted(const Mesh& mesh, int t_id, int j, const Vector3& new_p) +{ int ori; if (j == 0) { - ori = Predicates::orient_3d(new_p, mesh.tet_vertices[mesh.tets[t_id][1]].pos, + ori = Predicates::orient_3d(new_p, + mesh.tet_vertices[mesh.tets[t_id][1]].pos, mesh.tet_vertices[mesh.tets[t_id][2]].pos, mesh.tet_vertices[mesh.tets[t_id][3]].pos); - } else if (j == 1) { - ori = Predicates::orient_3d(mesh.tet_vertices[mesh.tets[t_id][0]].pos, new_p, + } + else if (j == 1) { + ori = Predicates::orient_3d(mesh.tet_vertices[mesh.tets[t_id][0]].pos, + new_p, mesh.tet_vertices[mesh.tets[t_id][2]].pos, mesh.tet_vertices[mesh.tets[t_id][3]].pos); - } else if (j == 2) { + } + else if (j == 2) { ori = Predicates::orient_3d(mesh.tet_vertices[mesh.tets[t_id][0]].pos, - mesh.tet_vertices[mesh.tets[t_id][1]].pos, new_p, + mesh.tet_vertices[mesh.tets[t_id][1]].pos, + new_p, mesh.tet_vertices[mesh.tets[t_id][3]].pos); - } else { + } + else { ori = Predicates::orient_3d(mesh.tet_vertices[mesh.tets[t_id][0]].pos, mesh.tet_vertices[mesh.tets[t_id][1]].pos, - mesh.tet_vertices[mesh.tets[t_id][2]].pos, new_p); + mesh.tet_vertices[mesh.tets[t_id][2]].pos, + new_p); } if (ori == Predicates::ORI_POSITIVE) return false; return true; } -bool floatTetWild::is_inverted(const MeshVertex& v0, const MeshVertex& v1, const MeshVertex& v2, const MeshVertex& v3){ +bool floatTetWild::is_inverted(const MeshVertex& v0, + const MeshVertex& v1, + const MeshVertex& v2, + const MeshVertex& v3) +{ if (Predicates::orient_3d(v0.pos, v1.pos, v2.pos, v3.pos) == Predicates::ORI_POSITIVE) return false; return true; } -bool floatTetWild::is_inverted(const Vector3& v0, const Vector3& v1, const Vector3& v2, const Vector3& v3){ +bool floatTetWild::is_inverted(const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& v3) +{ if (Predicates::orient_3d(v0, v1, v2, v3) == Predicates::ORI_POSITIVE) return false; return true; } -bool floatTetWild::is_degenerate(const Vector3& v0, const Vector3& v1, const Vector3& v2, const Vector3& v3){ +bool floatTetWild::is_degenerate(const Vector3& v0, + const Vector3& v1, + const Vector3& v2, + const Vector3& v3) +{ if (Predicates::orient_3d(v0, v1, v2, v3) == Predicates::ORI_ZERO) return true; return false; } -bool floatTetWild::is_out_boundary_envelope(const Mesh& mesh, int v_id, const Vector3& new_pos, const AABBWrapper& tree){ - if(mesh.is_input_all_inserted) +bool floatTetWild::is_out_boundary_envelope(const Mesh& mesh, + int v_id, + const Vector3& new_pos, + const AABBWrapper& tree) +{ + if (mesh.is_input_all_inserted) return false; - if(!mesh.tet_vertices[v_id].is_on_cut) + if (!mesh.tet_vertices[v_id].is_on_cut) return false; GEO::index_t prev_facet; - if(tree.is_out_tmp_b_envelope(new_pos, mesh.params.eps_2/100, prev_facet)) + if (tree.is_out_tmp_b_envelope(new_pos, mesh.params.eps_2 / 100, prev_facet)) return true; std::vector tmp_b_v_ids; - for (int t_id:mesh.tet_vertices[v_id].conn_tets) { + for (int t_id : mesh.tet_vertices[v_id].conn_tets) { for (int j = 0; j < 4; j++) { if (mesh.tets[t_id][j] != v_id && mesh.tets[t_id].is_surface_fs[j] <= 0) { - for(int k=0;k<3;k++){ - int b_v_id = mesh.tets[t_id][(j+1+k)%4]; - if(b_v_id != v_id && mesh.tet_vertices[b_v_id].is_on_boundary) + for (int k = 0; k < 3; k++) { + int b_v_id = mesh.tets[t_id][(j + 1 + k) % 4]; + if (b_v_id != v_id && mesh.tet_vertices[b_v_id].is_on_boundary) tmp_b_v_ids.push_back(b_v_id); } } @@ -528,104 +621,112 @@ bool floatTetWild::is_out_boundary_envelope(const Mesh& mesh, int v_id, const Ve std::vector b_v_ids; b_v_ids.reserve(tmp_b_v_ids.size()); - for(int b_v_id:tmp_b_v_ids){ - if(is_boundary_edge(mesh, v_id, b_v_id, tree)) + for (int b_v_id : tmp_b_v_ids) { + if (is_boundary_edge(mesh, v_id, b_v_id, tree)) b_v_ids.push_back(b_v_id); } - if(b_v_ids.empty()) + if (b_v_ids.empty()) return false; std::vector ps; ps.push_back(GEO::vec3(new_pos[0], new_pos[1], new_pos[2])); int p0_id = 0; - for(int b_v_id:b_v_ids) { + for (int b_v_id : b_v_ids) { Scalar l = get_edge_length(mesh, v_id, b_v_id); - int N = l / mesh.params.dd + 1; - ps.push_back(GEO::vec3(mesh.tet_vertices[b_v_id][0], mesh.tet_vertices[b_v_id][1], + int N = l / mesh.params.dd + 1; + ps.push_back(GEO::vec3(mesh.tet_vertices[b_v_id][0], + mesh.tet_vertices[b_v_id][1], mesh.tet_vertices[b_v_id][2])); int p1_id = ps.size() - 1; for (Scalar j = 1; j < N - 1; j++) { -// ps.push_back(ps[0] * (j / N) + ps[1] * (1 - j / N)); + // ps.push_back(ps[0] * (j / N) + ps[1] * (1 - j / N)); ps.push_back(ps[p0_id] * (j / N) + ps[p1_id] * (1 - j / N)); } } - return tree.is_out_tmp_b_envelope(ps, mesh.params.eps_2/100, prev_facet); - -// GEO::vec3 init_point(new_pos[0], new_pos[1], new_pos[2]); -// GEO::vec3 nearest_point; -// double sq_distg; -// GEO::index_t prev_facet = b_tree.nearest_facet(init_point, nearest_point, sq_distg); -// Scalar sq_dist = sq_distg; -// if(sq_dist > mesh.params.eps_2) -// return true; -// -// std::vector tmp_b_v_ids; -// for (int t_id:mesh.tet_vertices[v_id].conn_tets) { -// for (int j = 0; j < 4; j++) { -// if (mesh.tets[t_id][j] != v_id && mesh.tets[t_id].is_surface_fs[j] < 0) { -// for(int k=0;k<3;k++){ -// int b_v_id = mesh.tets[t_id][(j+1+k)%4]; -// if(b_v_id != v_id && mesh.tet_vertices[b_v_id].is_on_boundary) -// tmp_b_v_ids.push_back(b_v_id); -// } -// } -// } -// } -// vector_unique(tmp_b_v_ids); -// -// std::vector b_v_ids; -// b_v_ids.reserve(tmp_b_v_ids.size()); -// for(int b_v_id:tmp_b_v_ids){ -// if(is_boundary_edge(mesh, v_id, b_v_id))//todo: can be improved, see meshimprovemnet init() -// b_v_ids.push_back(b_v_id); -// } -// if(b_v_ids.empty()) -// return false; -// -// std::vector ps; -// for(int b_v_id:b_v_ids) { -// Scalar l = get_edge_length(mesh, v_id, b_v_id); -// int N = l / mesh.params.dd + 1; -//// ps.push_back(GEO::vec3(mesh.tet_vertices[v_id][0], mesh.tet_vertices[v_id][1], mesh.tet_vertices[v_id][2])); -// ps.push_back(GEO::vec3(new_pos[0], new_pos[1], new_pos[2])); -// ps.push_back( -// GEO::vec3(mesh.tet_vertices[b_v_id][0], mesh.tet_vertices[b_v_id][1], mesh.tet_vertices[b_v_id][2])); -// for (Scalar j = 0; j < N - 1; j++) { -// ps.push_back(ps[0] * (j / N) + ps[1] * (1 - j / N)); -// } -// } -// -// int cnt = 0; -// const unsigned int ps_size = ps.size(); -// for (unsigned int i = ps_size / 2; ; i = (i + 1) % ps_size) {//check from the middle -// GEO::vec3 ¤t_point = ps[i]; -// sq_distg = current_point.distance2(nearest_point); -// b_tree.nearest_facet_with_hint(current_point, prev_facet, nearest_point, sq_distg); -// sq_dist = sq_distg; -// if (sq_dist > mesh.params.eps_2) -// return true; -// cnt++; -// if (cnt >= ps_size) -// break; -// } -// -// return false; + return tree.is_out_tmp_b_envelope(ps, mesh.params.eps_2 / 100, prev_facet); + + // GEO::vec3 init_point(new_pos[0], new_pos[1], new_pos[2]); + // GEO::vec3 nearest_point; + // double sq_distg; + // GEO::index_t prev_facet = b_tree.nearest_facet(init_point, nearest_point, sq_distg); + // Scalar sq_dist = sq_distg; + // if(sq_dist > mesh.params.eps_2) + // return true; + // + // std::vector tmp_b_v_ids; + // for (int t_id:mesh.tet_vertices[v_id].conn_tets) { + // for (int j = 0; j < 4; j++) { + // if (mesh.tets[t_id][j] != v_id && mesh.tets[t_id].is_surface_fs[j] < 0) { + // for(int k=0;k<3;k++){ + // int b_v_id = mesh.tets[t_id][(j+1+k)%4]; + // if(b_v_id != v_id && mesh.tet_vertices[b_v_id].is_on_boundary) + // tmp_b_v_ids.push_back(b_v_id); + // } + // } + // } + // } + // vector_unique(tmp_b_v_ids); + // + // std::vector b_v_ids; + // b_v_ids.reserve(tmp_b_v_ids.size()); + // for(int b_v_id:tmp_b_v_ids){ + // if(is_boundary_edge(mesh, v_id, b_v_id))//todo: can be improved, see meshimprovemnet + // init() + // b_v_ids.push_back(b_v_id); + // } + // if(b_v_ids.empty()) + // return false; + // + // std::vector ps; + // for(int b_v_id:b_v_ids) { + // Scalar l = get_edge_length(mesh, v_id, b_v_id); + // int N = l / mesh.params.dd + 1; + //// ps.push_back(GEO::vec3(mesh.tet_vertices[v_id][0], mesh.tet_vertices[v_id][1], + ///mesh.tet_vertices[v_id][2])); + // ps.push_back(GEO::vec3(new_pos[0], new_pos[1], new_pos[2])); + // ps.push_back( + // GEO::vec3(mesh.tet_vertices[b_v_id][0], mesh.tet_vertices[b_v_id][1], + // mesh.tet_vertices[b_v_id][2])); + // for (Scalar j = 0; j < N - 1; j++) { + // ps.push_back(ps[0] * (j / N) + ps[1] * (1 - j / N)); + // } + // } + // + // int cnt = 0; + // const unsigned int ps_size = ps.size(); + // for (unsigned int i = ps_size / 2; ; i = (i + 1) % ps_size) {//check from the middle + // GEO::vec3 ¤t_point = ps[i]; + // sq_distg = current_point.distance2(nearest_point); + // b_tree.nearest_facet_with_hint(current_point, prev_facet, nearest_point, sq_distg); + // sq_dist = sq_distg; + // if (sq_dist > mesh.params.eps_2) + // return true; + // cnt++; + // if (cnt >= ps_size) + // break; + // } + // + // return false; } #include -bool floatTetWild::is_out_envelope(Mesh& mesh, int v_id, const Vector3& new_pos, const AABBWrapper& tree) { +bool floatTetWild::is_out_envelope(Mesh& mesh, + int v_id, + const Vector3& new_pos, + const AABBWrapper& tree) +{ #ifdef NEW_ENVELOPE - if(tree.is_out_sf_envelope_exact(new_pos)) + if (tree.is_out_sf_envelope_exact(new_pos)) return true; #else GEO::index_t prev_facet; - if(tree.is_out_sf_envelope(new_pos, mesh.params.eps_2, prev_facet)) + if (tree.is_out_sf_envelope(new_pos, mesh.params.eps_2, prev_facet)) return true; #endif std::vector ps; - for (int t_id:mesh.tet_vertices[v_id].conn_tets) { + for (int t_id : mesh.tet_vertices[v_id].conn_tets) { for (int j = 0; j < 4; j++) { if (mesh.tets[t_id][j] != v_id && mesh.tets[t_id].is_surface_fs[j] <= 0) { std::array vs; @@ -636,19 +737,20 @@ bool floatTetWild::is_out_envelope(Mesh& mesh, int v_id, const Vector3& new_pos, vs[k] = mesh.tet_vertices[mesh.tets[t_id][mod4(j + 1 + k)]].pos; } #ifdef NEW_ENVELOPE - bool is_out =tree.is_out_sf_envelope_exact(vs); - if(!mesh.params.envelope_log.empty()){ - if(envelope_log_csv_cnt < 1e5) { + bool is_out = tree.is_out_sf_envelope_exact(vs); + if (!mesh.params.envelope_log.empty()) { + if (envelope_log_csv_cnt < 1e5) { std::ostringstream ss; ss << std::setprecision(17); - for (const auto &v: vs) { + for (const auto& v : vs) { ss << v[0] << ',' << v[1] << ',' << v[2] << ','; } ss << is_out << "\n"; std::string tmp = ss.str(); envelope_log_csv += tmp; envelope_log_csv_cnt += 1; - } else { + } + else { std::ofstream fout(mesh.params.envelope_log); fout << envelope_log_csv; fout.close(); @@ -658,111 +760,118 @@ bool floatTetWild::is_out_envelope(Mesh& mesh, int v_id, const Vector3& new_pos, if (is_out) return true; #else - #ifdef STORE_SAMPLE_POINTS - ps.clear(); - sample_triangle(vs, ps, mesh.params.dd); - bool is_out = tree.is_out_sf_envelope(ps, mesh.params.eps_2, prev_facet); - #else - bool is_out = sample_triangle_and_check_is_out(vs, mesh.params.dd, mesh.params.eps_2, tree, prev_facet); - #endif - if(!mesh.params.envelope_log.empty()){ - if(envelope_log_csv_cnt < 1e5) { - std::ostringstream ss; - ss << std::setprecision(17); - for (const auto &v: vs) { - ss << v[0] << ',' << v[1] << ',' << v[2] << ','; - } - ss << is_out << "\n"; - std::string tmp = ss.str(); - envelope_log_csv += tmp; - envelope_log_csv_cnt += 1; - } else { - std::ofstream fout(mesh.params.envelope_log); - fout << envelope_log_csv; - fout.close(); - mesh.params.envelope_log = ""; +#ifdef STORE_SAMPLE_POINTS + ps.clear(); + sample_triangle(vs, ps, mesh.params.dd); + bool is_out = tree.is_out_sf_envelope(ps, mesh.params.eps_2, prev_facet); +#else + bool is_out = sample_triangle_and_check_is_out( + vs, mesh.params.dd, mesh.params.eps_2, tree, prev_facet); +#endif + if (!mesh.params.envelope_log.empty()) { + if (envelope_log_csv_cnt < 1e5) { + std::ostringstream ss; + ss << std::setprecision(17); + for (const auto& v : vs) { + ss << v[0] << ',' << v[1] << ',' << v[2] << ','; } + ss << is_out << "\n"; + std::string tmp = ss.str(); + envelope_log_csv += tmp; + envelope_log_csv_cnt += 1; } - if (is_out) - return true; + else { + std::ofstream fout(mesh.params.envelope_log); + fout << envelope_log_csv; + fout.close(); + mesh.params.envelope_log = ""; + } + } + if (is_out) + return true; #endif -// int cnt = 0; -// const unsigned int ps_size = ps.size(); -// for (unsigned int i = ps_size / 2; ; i = (i + 1) % ps_size) {//check from the middle -// GEO::vec3 ¤t_point = ps[i]; -// sq_distg = current_point.distance2(nearest_point); -// sf_tree.nearest_facet_with_hint(current_point, prev_facet, nearest_point, sq_distg); -// sq_dist = sq_distg; -// if (sq_dist > mesh.params.eps_2) -// return true; -// cnt++; -// if (cnt >= ps_size) -// break; -// } + // int cnt = 0; + // const unsigned int ps_size = ps.size(); + // for (unsigned int i = ps_size / 2; ; i = (i + 1) % ps_size) + // {//check from the middle + // GEO::vec3 ¤t_point = ps[i]; + // sq_distg = current_point.distance2(nearest_point); + // sf_tree.nearest_facet_with_hint(current_point, prev_facet, + // nearest_point, sq_distg); sq_dist = sq_distg; if (sq_dist > + // mesh.params.eps_2) + // return true; + // cnt++; + // if (cnt >= ps_size) + // break; + // } } } } return false; -// GEO::vec3 init_point(new_pos[0], new_pos[1], new_pos[2]); -// GEO::vec3 nearest_point; -// double sq_distg; -// GEO::index_t prev_facet = sf_tree.nearest_facet(init_point, nearest_point, sq_distg); -// Scalar sq_dist = sq_distg; -// if(sq_dist > mesh.params.eps_2) -// return true; -// -// std::vector ps; -// for (int t_id:mesh.tet_vertices[v_id].conn_tets) { -// for (int j = 0; j < 4; j++) { -// if (mesh.tets[t_id][j] != v_id && mesh.tets[t_id].is_surface_fs[j] < 0) { -// std::array vs; -// for(int k=0;k<3;k++){ -// if(mesh.tets[t_id][mod4(j + 1 + k)] == v_id) -// vs[k] = new_pos; -// else -// vs[k] = mesh.tet_vertices[mesh.tets[t_id][(j + 1 + k) % 4]].pos; -// } -// -// ps.clear(); -//// sample_triangle({{mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos, -//// mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos, -//// mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos}}, ps, mesh.params.dd); -// sample_triangle(vs, ps, mesh.params.dd); -// -// int cnt = 0; -// const unsigned int ps_size = ps.size(); -// for (unsigned int i = ps_size / 2; ; i = (i + 1) % ps_size) {//check from the middle -// GEO::vec3 ¤t_point = ps[i]; -// sq_distg = current_point.distance2(nearest_point); -// sf_tree.nearest_facet_with_hint(current_point, prev_facet, nearest_point, sq_distg); -// sq_dist = sq_distg; -// if (sq_dist > mesh.params.eps_2) -// return true; -// cnt++; -// if (cnt >= ps_size) -// break; -// } -// } -// } -// } -// -// return false; + // GEO::vec3 init_point(new_pos[0], new_pos[1], new_pos[2]); + // GEO::vec3 nearest_point; + // double sq_distg; + // GEO::index_t prev_facet = sf_tree.nearest_facet(init_point, nearest_point, sq_distg); + // Scalar sq_dist = sq_distg; + // if(sq_dist > mesh.params.eps_2) + // return true; + // + // std::vector ps; + // for (int t_id:mesh.tet_vertices[v_id].conn_tets) { + // for (int j = 0; j < 4; j++) { + // if (mesh.tets[t_id][j] != v_id && mesh.tets[t_id].is_surface_fs[j] < 0) { + // std::array vs; + // for(int k=0;k<3;k++){ + // if(mesh.tets[t_id][mod4(j + 1 + k)] == v_id) + // vs[k] = new_pos; + // else + // vs[k] = mesh.tet_vertices[mesh.tets[t_id][(j + 1 + k) % 4]].pos; + // } + // + // ps.clear(); + //// sample_triangle({{mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos, + //// mesh.tet_vertices[mesh.tets[t_id][(j + 2) % + ///4]].pos, / mesh.tet_vertices[mesh.tets[t_id][(j + 3) + ///% 4]].pos}}, ps, mesh.params.dd); + // sample_triangle(vs, ps, mesh.params.dd); + // + // int cnt = 0; + // const unsigned int ps_size = ps.size(); + // for (unsigned int i = ps_size / 2; ; i = (i + 1) % ps_size) {//check from the + // middle + // GEO::vec3 ¤t_point = ps[i]; + // sq_distg = current_point.distance2(nearest_point); + // sf_tree.nearest_facet_with_hint(current_point, prev_facet, nearest_point, + // sq_distg); sq_dist = sq_distg; if (sq_dist > mesh.params.eps_2) + // return true; + // cnt++; + // if (cnt >= ps_size) + // break; + // } + // } + // } + // } + // + // return false; } -void floatTetWild::sample_triangle(const std::array& vs, std::vector& ps, Scalar sampling_dist) { +void floatTetWild::sample_triangle(const std::array& vs, + std::vector& ps, + Scalar sampling_dist) +{ Scalar sqrt3_2 = std::sqrt(3) / 2; std::array ls; for (int i = 0; i < 3; i++) { ls[i] = (vs[i] - vs[mod3(i + 1)]).squaredNorm(); } - auto min_max = std::minmax_element(ls.begin(), ls.end()); - int min_i = min_max.first - ls.begin(); - int max_i = min_max.second - ls.begin(); - Scalar N = sqrt(ls[max_i]) / sampling_dist; + auto min_max = std::minmax_element(ls.begin(), ls.end()); + int min_i = min_max.first - ls.begin(); + int max_i = min_max.second - ls.begin(); + Scalar N = sqrt(ls[max_i]) / sampling_dist; if (N <= 1) { for (int i = 0; i < 3; i++) ps.push_back(GEO::vec3(vs[i][0], vs[i][1], vs[i][2])); @@ -782,7 +891,7 @@ void floatTetWild::sample_triangle(const std::array& vs, std::vector ps.push_back(v1); Scalar h = GEO::distance(GEO::dot((v2 - v0), (v1 - v0)) * (v1 - v0) / ls[max_i] + v0, v2); - int M = h / (sqrt3_2 * sampling_dist); + int M = h / (sqrt3_2 * sampling_dist); if (M < 1) { ps.push_back(v2); return; @@ -790,14 +899,16 @@ void floatTetWild::sample_triangle(const std::array& vs, std::vector GEO::vec3 n_v0v2 = GEO::normalize(v2 - v0); GEO::vec3 n_v1v2 = GEO::normalize(v2 - v1); - Scalar tan_v0, tan_v1, sin_v0, sin_v1; - sin_v0 = GEO::length(GEO::cross((v2 - v0), (v1 - v0))) / (GEO::distance(v0, v2) * GEO::distance(v0, v1)); + Scalar tan_v0, tan_v1, sin_v0, sin_v1; + sin_v0 = GEO::length(GEO::cross((v2 - v0), (v1 - v0))) / + (GEO::distance(v0, v2) * GEO::distance(v0, v1)); tan_v0 = GEO::length(GEO::cross((v2 - v0), (v1 - v0))) / GEO::dot((v2 - v0), (v1 - v0)); tan_v1 = GEO::length(GEO::cross((v2 - v1), (v0 - v1))) / GEO::dot((v2 - v1), (v0 - v1)); - sin_v1 = GEO::length(GEO::cross((v2 - v1), (v0 - v1))) / (GEO::distance(v1, v2) * GEO::distance(v0, v1)); + sin_v1 = GEO::length(GEO::cross((v2 - v1), (v0 - v1))) / + (GEO::distance(v1, v2) * GEO::distance(v0, v1)); for (int m = 1; m <= M; m++) { - int n = sqrt3_2 / tan_v0 * m + 0.5; + int n = sqrt3_2 / tan_v0 * m + 0.5; int n1 = sqrt3_2 / tan_v0 * m; if (m % 2 == 0 && n == n1) { n += 1; @@ -807,18 +918,18 @@ void floatTetWild::sample_triangle(const std::array& vs, std::vector if (GEO::distance(v0_m, v1_m) <= sampling_dist) break; - Scalar delta_d = ((n + (m % 2) / 2.0) - m * sqrt3_2 / tan_v0) * sampling_dist; - GEO::vec3 v = v0_m + delta_d * n_v0v1; - int N1 = GEO::distance(v, v1_m) / sampling_dist; -// ps.push_back(v0_m); + Scalar delta_d = ((n + (m % 2) / 2.0) - m * sqrt3_2 / tan_v0) * sampling_dist; + GEO::vec3 v = v0_m + delta_d * n_v0v1; + int N1 = GEO::distance(v, v1_m) / sampling_dist; + // ps.push_back(v0_m); for (int i = 0; i <= N1; i++) { ps.push_back(v + i * n_v0v1 * sampling_dist); } -// ps.push_back(v1_m); + // ps.push_back(v1_m); } ps.push_back(v2); - //sample edges + // sample edges N = sqrt(ls[mod3(max_i + 1)]) / sampling_dist; if (N > 1) { if (N == int(N)) @@ -840,10 +951,14 @@ void floatTetWild::sample_triangle(const std::array& vs, std::vector } } -bool floatTetWild::sample_triangle_and_check_is_out(const std::array& vs, Scalar sampling_dist, - Scalar eps_2, const AABBWrapper& tree, GEO::index_t& prev_facet){ +bool floatTetWild::sample_triangle_and_check_is_out(const std::array& vs, + Scalar sampling_dist, + Scalar eps_2, + const AABBWrapper& tree, + GEO::index_t& prev_facet) +{ GEO::vec3 nearest_point; - double sq_dist = std::numeric_limits::max(); + double sq_dist = std::numeric_limits::max(); Scalar sqrt3_2 = std::sqrt(3) / 2; @@ -851,17 +966,17 @@ bool floatTetWild::sample_triangle_and_check_is_out(const std::array for (int i = 0; i < 3; i++) { ls[i] = (vs[i] - vs[mod3(i + 1)]).squaredNorm(); } - auto min_max = std::minmax_element(ls.begin(), ls.end()); - int min_i = min_max.first - ls.begin(); - int max_i = min_max.second - ls.begin(); - Scalar N = sqrt(ls[max_i]) / sampling_dist; + auto min_max = std::minmax_element(ls.begin(), ls.end()); + int min_i = min_max.first - ls.begin(); + int max_i = min_max.second - ls.begin(); + Scalar N = sqrt(ls[max_i]) / sampling_dist; if (N <= 1) { for (int i = 0; i < 3; i++) { -// ps.push_back(GEO::vec3(vs[i][0], vs[i][1], vs[i][2])); + // ps.push_back(GEO::vec3(vs[i][0], vs[i][1], vs[i][2])); if (tree.is_out_sf_envelope(vs[i], eps_2, prev_facet, sq_dist, nearest_point)) return true; } -// return; + // return; return false; } if (N == int(N)) @@ -873,32 +988,35 @@ bool floatTetWild::sample_triangle_and_check_is_out(const std::array GEO::vec3 n_v0v1 = GEO::normalize(v1 - v0); for (int n = 0; n <= N; n++) { -// ps.push_back(v0 + n_v0v1 * sampling_dist * n); - if (tree.is_out_sf_envelope(v0 + n_v0v1 * sampling_dist * n, eps_2, prev_facet, sq_dist, nearest_point)) + // ps.push_back(v0 + n_v0v1 * sampling_dist * n); + if (tree.is_out_sf_envelope( + v0 + n_v0v1 * sampling_dist * n, eps_2, prev_facet, sq_dist, nearest_point)) return true; } -// ps.push_back(v1); + // ps.push_back(v1); if (tree.is_out_sf_envelope(v1, eps_2, prev_facet, sq_dist, nearest_point)) return true; Scalar h = GEO::distance(GEO::dot((v2 - v0), (v1 - v0)) * (v1 - v0) / ls[max_i] + v0, v2); - int M = h / (sqrt3_2 * sampling_dist); + int M = h / (sqrt3_2 * sampling_dist); if (M < 1) { -// ps.push_back(v2); -// return; + // ps.push_back(v2); + // return; return tree.is_out_sf_envelope(v2, eps_2, prev_facet, sq_dist, nearest_point); } GEO::vec3 n_v0v2 = GEO::normalize(v2 - v0); GEO::vec3 n_v1v2 = GEO::normalize(v2 - v1); - Scalar tan_v0, tan_v1, sin_v0, sin_v1; - sin_v0 = GEO::length(GEO::cross((v2 - v0), (v1 - v0))) / (GEO::distance(v0, v2) * GEO::distance(v0, v1)); + Scalar tan_v0, tan_v1, sin_v0, sin_v1; + sin_v0 = GEO::length(GEO::cross((v2 - v0), (v1 - v0))) / + (GEO::distance(v0, v2) * GEO::distance(v0, v1)); tan_v0 = GEO::length(GEO::cross((v2 - v0), (v1 - v0))) / GEO::dot((v2 - v0), (v1 - v0)); tan_v1 = GEO::length(GEO::cross((v2 - v1), (v0 - v1))) / GEO::dot((v2 - v1), (v0 - v1)); - sin_v1 = GEO::length(GEO::cross((v2 - v1), (v0 - v1))) / (GEO::distance(v1, v2) * GEO::distance(v0, v1)); + sin_v1 = GEO::length(GEO::cross((v2 - v1), (v0 - v1))) / + (GEO::distance(v1, v2) * GEO::distance(v0, v1)); for (int m = 1; m <= M; m++) { - int n = sqrt3_2 / tan_v0 * m + 0.5; + int n = sqrt3_2 / tan_v0 * m + 0.5; int n1 = sqrt3_2 / tan_v0 * m; if (m % 2 == 0 && n == n1) { n += 1; @@ -908,28 +1026,30 @@ bool floatTetWild::sample_triangle_and_check_is_out(const std::array if (GEO::distance(v0_m, v1_m) <= sampling_dist) break; - Scalar delta_d = ((n + (m % 2) / 2.0) - m * sqrt3_2 / tan_v0) * sampling_dist; - GEO::vec3 v = v0_m + delta_d * n_v0v1; - int N1 = GEO::distance(v, v1_m) / sampling_dist; + Scalar delta_d = ((n + (m % 2) / 2.0) - m * sqrt3_2 / tan_v0) * sampling_dist; + GEO::vec3 v = v0_m + delta_d * n_v0v1; + int N1 = GEO::distance(v, v1_m) / sampling_dist; for (int i = 0; i <= N1; i++) { -// ps.push_back(v + i * n_v0v1 * sampling_dist); - if (tree.is_out_sf_envelope(v + i * n_v0v1 * sampling_dist, eps_2, prev_facet, sq_dist, nearest_point)) + // ps.push_back(v + i * n_v0v1 * sampling_dist); + if (tree.is_out_sf_envelope( + v + i * n_v0v1 * sampling_dist, eps_2, prev_facet, sq_dist, nearest_point)) return true; } } -// ps.push_back(v2); + // ps.push_back(v2); if (tree.is_out_sf_envelope(v2, eps_2, prev_facet, sq_dist, nearest_point)) return true; - //sample edges + // sample edges N = sqrt(ls[mod3(max_i + 1)]) / sampling_dist; if (N > 1) { if (N == int(N)) N -= 1; GEO::vec3 n_v1v2 = GEO::normalize(v2 - v1); for (int n = 1; n <= N; n++) { -// ps.push_back(v1 + n_v1v2 * sampling_dist * n); - if (tree.is_out_sf_envelope(v1 + n_v1v2 * sampling_dist * n, eps_2, prev_facet, sq_dist, nearest_point)) + // ps.push_back(v1 + n_v1v2 * sampling_dist * n); + if (tree.is_out_sf_envelope( + v1 + n_v1v2 * sampling_dist * n, eps_2, prev_facet, sq_dist, nearest_point)) return true; } } @@ -940,8 +1060,9 @@ bool floatTetWild::sample_triangle_and_check_is_out(const std::array N -= 1; GEO::vec3 n_v2v0 = GEO::normalize(v0 - v2); for (int n = 1; n <= N; n++) { -// ps.push_back(v2 + n_v2v0 * sampling_dist * n); - if (tree.is_out_sf_envelope(v2 + n_v2v0 * sampling_dist * n, eps_2, prev_facet, sq_dist, nearest_point)) + // ps.push_back(v2 + n_v2v0 * sampling_dist * n); + if (tree.is_out_sf_envelope( + v2 + n_v2v0 * sampling_dist * n, eps_2, prev_facet, sq_dist, nearest_point)) return true; } } @@ -949,7 +1070,8 @@ bool floatTetWild::sample_triangle_and_check_is_out(const std::array return false; } -void floatTetWild::get_new_tet_slots(Mesh& mesh, int n, std::vector& new_conn_tets) { +void floatTetWild::get_new_tet_slots(Mesh& mesh, int n, std::vector& new_conn_tets) +{ int cnt = 0; for (int i = mesh.t_empty_start; i < mesh.tets.size(); i++) { if (mesh.tets[i].is_removed) { @@ -969,7 +1091,10 @@ void floatTetWild::get_new_tet_slots(Mesh& mesh, int n, std::vector& new_co } } -void floatTetWild::set_intersection(const std::unordered_set& s1, const std::unordered_set& s2, std::vector& v) { +void floatTetWild::set_intersection(const std::unordered_set& s1, + const std::unordered_set& s2, + std::vector& v) +{ if (s2.size() < s1.size()) { set_intersection(s2, s1, v); return; @@ -981,11 +1106,13 @@ void floatTetWild::set_intersection(const std::unordered_set& s1, const std v.push_back(x); } } -// std::sort(v.begin(), v.end()); + // std::sort(v.begin(), v.end()); } -void floatTetWild::set_intersection(const std::unordered_set& s1, const std::unordered_set& s2, - std::unordered_set& v) { +void floatTetWild::set_intersection(const std::unordered_set& s1, + const std::unordered_set& s2, + std::unordered_set& v) +{ if (s2.size() < s1.size()) { set_intersection(s2, s1, v); return; @@ -999,8 +1126,11 @@ void floatTetWild::set_intersection(const std::unordered_set& s1, const std } } -void floatTetWild::set_intersection(const std::unordered_set& s1, const std::unordered_set& s2, const std::unordered_set& s3, - std::vector& v) { +void floatTetWild::set_intersection(const std::unordered_set& s1, + const std::unordered_set& s2, + const std::unordered_set& s3, + std::vector& v) +{ if (s2.size() < s1.size() && s2.size() < s1.size()) { set_intersection(s2, s1, s3, v); return; @@ -1019,13 +1149,16 @@ void floatTetWild::set_intersection(const std::unordered_set& s1, const std for (int x : s1) { if (s2.count(x) && s3.count(x)) { v.push_back(x); - if(v.size() == 2) + if (v.size() == 2) break; } } } -void floatTetWild::set_intersection(const std::vector& s11, const std::vector& s22, std::vector& v) { +void floatTetWild::set_intersection(const std::vector& s11, + const std::vector& s22, + std::vector& v) +{ std::vector s1 = s11; std::vector s2 = s22; std::sort(s1.begin(), s1.end()); @@ -1033,7 +1166,11 @@ void floatTetWild::set_intersection(const std::vector& s11, const std::vect std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), std::back_inserter(v)); } -void floatTetWild::set_intersection(const std::vector& s11, const std::vector& s22, const std::vector& s33, std::vector& v) { +void floatTetWild::set_intersection(const std::vector& s11, + const std::vector& s22, + const std::vector& s33, + std::vector& v) +{ std::vector s1 = s11; std::vector s2 = s22; std::vector s3 = s33; @@ -1045,13 +1182,18 @@ void floatTetWild::set_intersection(const std::vector& s11, const std::vect v.resize(it - v.begin()); } -void floatTetWild::set_intersection_sorted(const std::vector& s1, const std::vector& s2, const std::vector& s3, std::vector& v) { +void floatTetWild::set_intersection_sorted(const std::vector& s1, + const std::vector& s2, + const std::vector& s3, + std::vector& v) +{ std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), std::back_inserter(v)); auto it = std::set_intersection(v.begin(), v.end(), s3.begin(), s3.end(), v.begin()); v.resize(it - v.begin()); } -void floatTetWild::pausee(std::string msg) { +void floatTetWild::pausee(std::string msg) +{ return; // if (!msg.empty()) // cout << msg << endl; @@ -1062,30 +1204,14 @@ void floatTetWild::pausee(std::string msg) { // exit(0); } -bool floatTetWild::is_energy_unstable(const std::array& T, Scalar res) { - static const std::vector> combs = {{{0, 1, 3, 2}}, - {{0, 2, 1, 3}}, - {{0, 2, 3, 1}}, - {{0, 3, 1, 2}}, - {{0, 3, 2, 1}}, - {{1, 0, 2, 3}}, - {{1, 0, 3, 2}}, - {{1, 2, 0, 3}}, - {{1, 2, 3, 0}}, - {{1, 3, 0, 2}}, - {{1, 3, 2, 0}}, - {{2, 0, 1, 3}}, - {{2, 0, 3, 1}}, - {{2, 1, 0, 3}}, - {{2, 1, 3, 0}}, - {{2, 3, 0, 1}}, - {{2, 3, 1, 0}}, - {{3, 0, 1, 2}}, - {{3, 0, 2, 1}}, - {{3, 1, 0, 2}}, - {{3, 1, 2, 0}}, - {{3, 2, 0, 1}}, - {{3, 2, 1, 0}}}; +bool floatTetWild::is_energy_unstable(const std::array& T, Scalar res) +{ + static const std::vector> combs = { + {{0, 1, 3, 2}}, {{0, 2, 1, 3}}, {{0, 2, 3, 1}}, {{0, 3, 1, 2}}, {{0, 3, 2, 1}}, + {{1, 0, 2, 3}}, {{1, 0, 3, 2}}, {{1, 2, 0, 3}}, {{1, 2, 3, 0}}, {{1, 3, 0, 2}}, + {{1, 3, 2, 0}}, {{2, 0, 1, 3}}, {{2, 0, 3, 1}}, {{2, 1, 0, 3}}, {{2, 1, 3, 0}}, + {{2, 3, 0, 1}}, {{2, 3, 1, 0}}, {{3, 0, 1, 2}}, {{3, 0, 2, 1}}, {{3, 1, 0, 2}}, + {{3, 1, 2, 0}}, {{3, 2, 0, 1}}, {{3, 2, 1, 0}}}; Scalar res0; if (std::isinf(res)) return true; @@ -1101,46 +1227,49 @@ bool floatTetWild::is_energy_unstable(const std::array& T, Scalar re continue; if (res0 == 0) res0 = res1; -// if (res1 - res0 > 10) - if (abs(res1 - res0)/res0 > 0.01) + // if (res1 - res0 > 10) + if (abs(res1 - res0) / res0 > 0.01) return true; } return false; } int cnt_stable = 0; -int cnt_large = 0; +int cnt_large = 0; #include -Scalar floatTetWild::AMIPS_energy(const std::array& T) { +Scalar floatTetWild::AMIPS_energy(const std::array& T) +{ Scalar res = AMIPS_energy_aux(T); - if(use_old_energy) { + if (use_old_energy) { return res; } if (res > 1e8) { -// //fortest -// if (res > 1e10) { -// cout << std::setprecision(16) << res << endl; -// for (int i = 0; i < T.size(); i++) { -// if (i % 3 == 0) -// cout << endl; -// cout << T[i] << ", "; -// } -// cout << endl; -// char c; -// cin >> c; -// } -// //fortest - -// //fortest -// cnt_large++; -// if(!is_energy_unstable(T, res)){ -// cout<<(cnt_stable++)<<"/"< 1e10) { + // cout << std::setprecision(16) << res << endl; + // for (int i = 0; i < T.size(); i++) { + // if (i % 3 == 0) + // cout << endl; + // cout << T[i] << ", "; + // } + // cout << endl; + // char c; + // cin >> c; + // } + // //fortest + + // //fortest + // cnt_large++; + // if(!is_energy_unstable(T, res)){ + // cout<<(cnt_stable++)<<"/"<::infinity(); } @@ -1149,307 +1278,386 @@ Scalar floatTetWild::AMIPS_energy(const std::array& T) { for (int j = 0; j < 12; j++) r_T[j] = T[j]; const triwild::Rational twothird = triwild::Rational(2) / triwild::Rational(3); - triwild::Rational tmp = ((-r_T[1 + 2] + r_T[1 + 5]) * r_T[1 + 1] + r_T[1 + 2] * r_T[1 + 7] + - (r_T[1 + -1] - r_T[1 + 5]) * r_T[1 + 4] - r_T[1 + -1] * r_T[1 + 7]) * r_T[1 + 9] + - ((r_T[1 + 2] - r_T[1 + 5]) * r_T[1 + 0] - r_T[1 + 2] * r_T[1 + 6] + - (-r_T[1 + -1] + r_T[1 + 5]) * r_T[1 + 3] + r_T[1 + -1] * r_T[1 + 6]) * r_T[1 + 10] + - (-r_T[1 + 2] * r_T[1 + 7] + (-r_T[1 + 8] + r_T[1 + 5]) * r_T[1 + 4] + - r_T[1 + 8] * r_T[1 + 7]) * r_T[1 + 0] + - (r_T[1 + 2] * r_T[1 + 6] + (r_T[1 + 8] - r_T[1 + 5]) * r_T[1 + 3] - r_T[1 + 8] * r_T[1 + 6]) * - r_T[1 + 1] + (r_T[1 + 3] * r_T[1 + 7] - r_T[1 + 4] * r_T[1 + 6]) * (r_T[1 + -1] - r_T[1 + 8]); - if(tmp == 0) + triwild::Rational tmp = + ((-r_T[1 + 2] + r_T[1 + 5]) * r_T[1 + 1] + r_T[1 + 2] * r_T[1 + 7] + + (r_T[1 + -1] - r_T[1 + 5]) * r_T[1 + 4] - r_T[1 + -1] * r_T[1 + 7]) * + r_T[1 + 9] + + ((r_T[1 + 2] - r_T[1 + 5]) * r_T[1 + 0] - r_T[1 + 2] * r_T[1 + 6] + + (-r_T[1 + -1] + r_T[1 + 5]) * r_T[1 + 3] + r_T[1 + -1] * r_T[1 + 6]) * + r_T[1 + 10] + + (-r_T[1 + 2] * r_T[1 + 7] + (-r_T[1 + 8] + r_T[1 + 5]) * r_T[1 + 4] + + r_T[1 + 8] * r_T[1 + 7]) * + r_T[1 + 0] + + (r_T[1 + 2] * r_T[1 + 6] + (r_T[1 + 8] - r_T[1 + 5]) * r_T[1 + 3] - + r_T[1 + 8] * r_T[1 + 6]) * + r_T[1 + 1] + + (r_T[1 + 3] * r_T[1 + 7] - r_T[1 + 4] * r_T[1 + 6]) * (r_T[1 + -1] - r_T[1 + 8]); + if (tmp == 0) return std::numeric_limits::infinity(); - auto res_r = triwild::Rational(27) / 16 * - pow(tmp, -2) * pow(r_T[1 + 9] * r_T[1 + 9] + - (-twothird * r_T[1 + 0] - twothird * r_T[1 + 3] - twothird * r_T[1 + 6]) * - r_T[1 + 9] + r_T[1 + 10] * r_T[1 + 10] + - (-twothird * r_T[1 + 1] - twothird * r_T[1 + 4] - twothird * r_T[1 + 7]) * - r_T[1 + 10] + r_T[1 + 0] * r_T[1 + 0] + - (-twothird * r_T[1 + 3] - twothird * r_T[1 + 6]) * r_T[1 + 0] + - r_T[1 + 1] * r_T[1 + 1] + - (-twothird * r_T[1 + 4] - twothird * r_T[1 + 7]) * r_T[1 + 1] + - r_T[1 + 2] * r_T[1 + 2] + - (-twothird * r_T[1 + -1] - twothird * r_T[1 + 8] - twothird * r_T[1 + 5]) * - r_T[1 + 2] + r_T[1 + 3] * r_T[1 + 3] - twothird * r_T[1 + 3] * r_T[1 + 6] + - r_T[1 + 4] * r_T[1 + 4] - twothird * r_T[1 + 4] * r_T[1 + 7] + - r_T[1 + 5] * r_T[1 + 5] + - (-twothird * r_T[1 + -1] - twothird * r_T[1 + 8]) * r_T[1 + 5] - - twothird * r_T[1 + -1] * r_T[1 + 8] + r_T[1 + -1] * r_T[1 + -1] + - r_T[1 + 8] * r_T[1 + 8] + r_T[1 + 6] * r_T[1 + 6] + r_T[1 + 7] * r_T[1 + 7], 3); + auto res_r = + triwild::Rational(27) / 16 * pow(tmp, -2) * + pow(r_T[1 + 9] * r_T[1 + 9] + + (-twothird * r_T[1 + 0] - twothird * r_T[1 + 3] - twothird * r_T[1 + 6]) * + r_T[1 + 9] + + r_T[1 + 10] * r_T[1 + 10] + + (-twothird * r_T[1 + 1] - twothird * r_T[1 + 4] - twothird * r_T[1 + 7]) * + r_T[1 + 10] + + r_T[1 + 0] * r_T[1 + 0] + + (-twothird * r_T[1 + 3] - twothird * r_T[1 + 6]) * r_T[1 + 0] + + r_T[1 + 1] * r_T[1 + 1] + + (-twothird * r_T[1 + 4] - twothird * r_T[1 + 7]) * r_T[1 + 1] + + r_T[1 + 2] * r_T[1 + 2] + + (-twothird * r_T[1 + -1] - twothird * r_T[1 + 8] - twothird * r_T[1 + 5]) * + r_T[1 + 2] + + r_T[1 + 3] * r_T[1 + 3] - twothird * r_T[1 + 3] * r_T[1 + 6] + + r_T[1 + 4] * r_T[1 + 4] - twothird * r_T[1 + 4] * r_T[1 + 7] + + r_T[1 + 5] * r_T[1 + 5] + + (-twothird * r_T[1 + -1] - twothird * r_T[1 + 8]) * r_T[1 + 5] - + twothird * r_T[1 + -1] * r_T[1 + 8] + r_T[1 + -1] * r_T[1 + -1] + + r_T[1 + 8] * r_T[1 + 8] + r_T[1 + 6] * r_T[1 + 6] + r_T[1 + 7] * r_T[1 + 7], + 3); return std::cbrt(res_r.to_double()); - } else { + } + else { return res; } } -Scalar floatTetWild::AMIPS_energy_aux(const std::array& T) { +Scalar floatTetWild::AMIPS_energy_aux(const std::array& T) +{ Scalar helper_0[12]; - helper_0[0] = T[0]; - helper_0[1] = T[1]; - helper_0[2] = T[2]; - helper_0[3] = T[3]; - helper_0[4] = T[4]; - helper_0[5] = T[5]; - helper_0[6] = T[6]; - helper_0[7] = T[7]; - helper_0[8] = T[8]; - helper_0[9] = T[9]; - helper_0[10] = T[10]; - helper_0[11] = T[11]; + helper_0[0] = T[0]; + helper_0[1] = T[1]; + helper_0[2] = T[2]; + helper_0[3] = T[3]; + helper_0[4] = T[4]; + helper_0[5] = T[5]; + helper_0[6] = T[6]; + helper_0[7] = T[7]; + helper_0[8] = T[8]; + helper_0[9] = T[9]; + helper_0[10] = T[10]; + helper_0[11] = T[11]; Scalar helper_1 = helper_0[2]; Scalar helper_2 = helper_0[11]; Scalar helper_3 = helper_0[0]; Scalar helper_4 = helper_0[3]; Scalar helper_5 = helper_0[9]; - Scalar helper_6 = 0.577350269189626 * helper_3 - 1.15470053837925 * helper_4 + 0.577350269189626 * helper_5; - Scalar helper_7 = helper_0[1]; - Scalar helper_8 = helper_0[4]; - Scalar helper_9 = helper_0[7]; + Scalar helper_6 = + 0.577350269189626 * helper_3 - 1.15470053837925 * helper_4 + 0.577350269189626 * helper_5; + Scalar helper_7 = helper_0[1]; + Scalar helper_8 = helper_0[4]; + Scalar helper_9 = helper_0[7]; Scalar helper_10 = helper_0[10]; - Scalar helper_11 = 0.408248290463863 * helper_10 + 0.408248290463863 * helper_7 + 0.408248290463863 * helper_8 - - 1.22474487139159 * helper_9; - Scalar helper_12 = 0.577350269189626 * helper_10 + 0.577350269189626 * helper_7 - 1.15470053837925 * helper_8; + Scalar helper_11 = 0.408248290463863 * helper_10 + 0.408248290463863 * helper_7 + + 0.408248290463863 * helper_8 - 1.22474487139159 * helper_9; + Scalar helper_12 = + 0.577350269189626 * helper_10 + 0.577350269189626 * helper_7 - 1.15470053837925 * helper_8; Scalar helper_13 = helper_0[6]; - Scalar helper_14 = -1.22474487139159 * helper_13 + 0.408248290463863 * helper_3 + 0.408248290463863 * helper_4 + - 0.408248290463863 * helper_5; + Scalar helper_14 = -1.22474487139159 * helper_13 + 0.408248290463863 * helper_3 + + 0.408248290463863 * helper_4 + 0.408248290463863 * helper_5; Scalar helper_15 = helper_0[5]; Scalar helper_16 = helper_0[8]; - Scalar helper_17 = 0.408248290463863 * helper_1 + 0.408248290463863 * helper_15 - 1.22474487139159 * helper_16 + - 0.408248290463863 * helper_2; - Scalar helper_18 = 0.577350269189626 * helper_1 - 1.15470053837925 * helper_15 + 0.577350269189626 * helper_2; + Scalar helper_17 = 0.408248290463863 * helper_1 + 0.408248290463863 * helper_15 - + 1.22474487139159 * helper_16 + 0.408248290463863 * helper_2; + Scalar helper_18 = + 0.577350269189626 * helper_1 - 1.15470053837925 * helper_15 + 0.577350269189626 * helper_2; Scalar helper_19 = 0.5 * helper_13 + 0.5 * helper_4; Scalar helper_20 = 0.5 * helper_8 + 0.5 * helper_9; Scalar helper_21 = 0.5 * helper_15 + 0.5 * helper_16; Scalar helper_22 = (helper_1 - helper_2) * (helper_11 * helper_6 - helper_12 * helper_14) - (-helper_10 + helper_7) * (-helper_14 * helper_18 + helper_17 * helper_6) + (helper_3 - helper_5) * (-helper_11 * helper_18 + helper_12 * helper_17); - Scalar res = -(helper_1 * (-1.5 * helper_1 + 0.5 * helper_2 + helper_21) + - helper_10 * (-1.5 * helper_10 + helper_20 + 0.5 * helper_7) + - helper_13 * (-1.5 * helper_13 + 0.5 * helper_3 + 0.5 * helper_4 + 0.5 * helper_5) + - helper_15 * (0.5 * helper_1 - 1.5 * helper_15 + 0.5 * helper_16 + 0.5 * helper_2) + - helper_16 * (0.5 * helper_1 + 0.5 * helper_15 - 1.5 * helper_16 + 0.5 * helper_2) + - helper_2 * (0.5 * helper_1 - 1.5 * helper_2 + helper_21) + - helper_3 * (helper_19 - 1.5 * helper_3 + 0.5 * helper_5) + - helper_4 * (0.5 * helper_13 + 0.5 * helper_3 - 1.5 * helper_4 + 0.5 * helper_5) + - helper_5 * (helper_19 + 0.5 * helper_3 - 1.5 * helper_5) + - helper_7 * (0.5 * helper_10 + helper_20 - 1.5 * helper_7) + - helper_8 * (0.5 * helper_10 + 0.5 * helper_7 - 1.5 * helper_8 + 0.5 * helper_9) + - helper_9 * (0.5 * helper_10 + 0.5 * helper_7 + 0.5 * helper_8 - 1.5 * helper_9)) - / std::cbrt(helper_22*helper_22); -// * pow(pow((helper_1 - helper_2) * (helper_11 * helper_6 - helper_12 * helper_14) - -// (-helper_10 + helper_7) * (-helper_14 * helper_18 + helper_17 * helper_6) + -// (helper_3 - helper_5) * (-helper_11 * helper_18 + helper_12 * helper_17), 2), -// -0.333333333333333); + Scalar res = + -(helper_1 * (-1.5 * helper_1 + 0.5 * helper_2 + helper_21) + + helper_10 * (-1.5 * helper_10 + helper_20 + 0.5 * helper_7) + + helper_13 * (-1.5 * helper_13 + 0.5 * helper_3 + 0.5 * helper_4 + 0.5 * helper_5) + + helper_15 * (0.5 * helper_1 - 1.5 * helper_15 + 0.5 * helper_16 + 0.5 * helper_2) + + helper_16 * (0.5 * helper_1 + 0.5 * helper_15 - 1.5 * helper_16 + 0.5 * helper_2) + + helper_2 * (0.5 * helper_1 - 1.5 * helper_2 + helper_21) + + helper_3 * (helper_19 - 1.5 * helper_3 + 0.5 * helper_5) + + helper_4 * (0.5 * helper_13 + 0.5 * helper_3 - 1.5 * helper_4 + 0.5 * helper_5) + + helper_5 * (helper_19 + 0.5 * helper_3 - 1.5 * helper_5) + + helper_7 * (0.5 * helper_10 + helper_20 - 1.5 * helper_7) + + helper_8 * (0.5 * helper_10 + 0.5 * helper_7 - 1.5 * helper_8 + 0.5 * helper_9) + + helper_9 * (0.5 * helper_10 + 0.5 * helper_7 + 0.5 * helper_8 - 1.5 * helper_9)) / + std::cbrt(helper_22 * helper_22); + // * pow(pow((helper_1 - helper_2) * (helper_11 * helper_6 - helper_12 * + // helper_14) - + // (-helper_10 + helper_7) * (-helper_14 * helper_18 + helper_17 * + // helper_6) + (helper_3 - helper_5) * (-helper_11 * helper_18 + + // helper_12 * helper_17), 2), + // -0.333333333333333); return res; } -void floatTetWild::AMIPS_jacobian(const std::array& T, Vector3& result_0){ +void floatTetWild::AMIPS_jacobian(const std::array& T, Vector3& result_0) +{ Scalar helper_0[12]; - helper_0[0] = T[0]; - helper_0[1] = T[1]; - helper_0[2] = T[2]; - helper_0[3] = T[3]; - helper_0[4] = T[4]; - helper_0[5] = T[5]; - helper_0[6] = T[6]; - helper_0[7] = T[7]; - helper_0[8] = T[8]; - helper_0[9] = T[9]; - helper_0[10] = T[10]; - helper_0[11] = T[11]; + helper_0[0] = T[0]; + helper_0[1] = T[1]; + helper_0[2] = T[2]; + helper_0[3] = T[3]; + helper_0[4] = T[4]; + helper_0[5] = T[5]; + helper_0[6] = T[6]; + helper_0[7] = T[7]; + helper_0[8] = T[8]; + helper_0[9] = T[9]; + helper_0[10] = T[10]; + helper_0[11] = T[11]; Scalar helper_1 = helper_0[1]; Scalar helper_2 = helper_0[10]; Scalar helper_3 = helper_1 - helper_2; Scalar helper_4 = helper_0[0]; Scalar helper_5 = helper_0[3]; Scalar helper_6 = helper_0[9]; - Scalar helper_7 = 0.577350269189626*helper_4 - 1.15470053837925*helper_5 + 0.577350269189626*helper_6; - Scalar helper_8 = helper_0[2]; - Scalar helper_9 = 0.408248290463863*helper_8; + Scalar helper_7 = + 0.577350269189626 * helper_4 - 1.15470053837925 * helper_5 + 0.577350269189626 * helper_6; + Scalar helper_8 = helper_0[2]; + Scalar helper_9 = 0.408248290463863 * helper_8; Scalar helper_10 = helper_0[5]; - Scalar helper_11 = 0.408248290463863*helper_10; + Scalar helper_11 = 0.408248290463863 * helper_10; Scalar helper_12 = helper_0[8]; - Scalar helper_13 = 1.22474487139159*helper_12; + Scalar helper_13 = 1.22474487139159 * helper_12; Scalar helper_14 = helper_0[11]; - Scalar helper_15 = 0.408248290463863*helper_14; + Scalar helper_15 = 0.408248290463863 * helper_14; Scalar helper_16 = helper_11 - helper_13 + helper_15 + helper_9; - Scalar helper_17 = 0.577350269189626*helper_8; - Scalar helper_18 = 1.15470053837925*helper_10; - Scalar helper_19 = 0.577350269189626*helper_14; + Scalar helper_17 = 0.577350269189626 * helper_8; + Scalar helper_18 = 1.15470053837925 * helper_10; + Scalar helper_19 = 0.577350269189626 * helper_14; Scalar helper_20 = helper_17 - helper_18 + helper_19; Scalar helper_21 = helper_0[6]; - Scalar helper_22 = -1.22474487139159*helper_21 + 0.408248290463863*helper_4 + 0.408248290463863*helper_5 + 0.408248290463863*helper_6; - Scalar helper_23 = helper_16*helper_7 - helper_20*helper_22; + Scalar helper_22 = -1.22474487139159 * helper_21 + 0.408248290463863 * helper_4 + + 0.408248290463863 * helper_5 + 0.408248290463863 * helper_6; + Scalar helper_23 = helper_16 * helper_7 - helper_20 * helper_22; Scalar helper_24 = -helper_14 + helper_8; - Scalar helper_25 = 0.408248290463863*helper_1; + Scalar helper_25 = 0.408248290463863 * helper_1; Scalar helper_26 = helper_0[4]; - Scalar helper_27 = 0.408248290463863*helper_26; + Scalar helper_27 = 0.408248290463863 * helper_26; Scalar helper_28 = helper_0[7]; - Scalar helper_29 = 1.22474487139159*helper_28; - Scalar helper_30 = 0.408248290463863*helper_2; + Scalar helper_29 = 1.22474487139159 * helper_28; + Scalar helper_30 = 0.408248290463863 * helper_2; Scalar helper_31 = helper_25 + helper_27 - helper_29 + helper_30; - Scalar helper_32 = helper_31*helper_7; - Scalar helper_33 = 0.577350269189626*helper_1; - Scalar helper_34 = 1.15470053837925*helper_26; - Scalar helper_35 = 0.577350269189626*helper_2; + Scalar helper_32 = helper_31 * helper_7; + Scalar helper_33 = 0.577350269189626 * helper_1; + Scalar helper_34 = 1.15470053837925 * helper_26; + Scalar helper_35 = 0.577350269189626 * helper_2; Scalar helper_36 = helper_33 - helper_34 + helper_35; - Scalar helper_37 = helper_22*helper_36; + Scalar helper_37 = helper_22 * helper_36; Scalar helper_38 = helper_4 - helper_6; - Scalar helper_39 = helper_23*helper_3 - helper_24*(helper_32 - helper_37) - helper_38*(helper_16*helper_36 - helper_20*helper_31); + Scalar helper_39 = helper_23 * helper_3 - helper_24 * (helper_32 - helper_37) - + helper_38 * (helper_16 * helper_36 - helper_20 * helper_31); Scalar helper_40 = pow(pow(helper_39, 2), -0.333333333333333); - Scalar helper_41 = 0.707106781186548*helper_10 - 0.707106781186548*helper_12; - Scalar helper_42 = 0.707106781186548*helper_26 - 0.707106781186548*helper_28; - Scalar helper_43 = 0.5*helper_21 + 0.5*helper_5; - Scalar helper_44 = 0.5*helper_26 + 0.5*helper_28; - Scalar helper_45 = 0.5*helper_10 + 0.5*helper_12; - Scalar helper_46 = 0.666666666666667*(helper_1*(-1.5*helper_1 + 0.5*helper_2 + helper_44) + helper_10*(-1.5*helper_10 + 0.5*helper_12 + 0.5*helper_14 + 0.5*helper_8) + helper_12*(0.5*helper_10 - 1.5*helper_12 + 0.5*helper_14 + 0.5*helper_8) + helper_14*(-1.5*helper_14 + helper_45 + 0.5*helper_8) + helper_2*(0.5*helper_1 - 1.5*helper_2 + helper_44) + helper_21*(-1.5*helper_21 + 0.5*helper_4 + 0.5*helper_5 + 0.5*helper_6) + helper_26*(0.5*helper_1 + 0.5*helper_2 - 1.5*helper_26 + 0.5*helper_28) + helper_28*(0.5*helper_1 + 0.5*helper_2 + 0.5*helper_26 - 1.5*helper_28) + helper_4*(-1.5*helper_4 + helper_43 + 0.5*helper_6) + helper_5*(0.5*helper_21 + 0.5*helper_4 - 1.5*helper_5 + 0.5*helper_6) + helper_6*(0.5*helper_4 + helper_43 - 1.5*helper_6) + helper_8*(0.5*helper_14 + helper_45 - 1.5*helper_8))/helper_39; - Scalar helper_47 = -0.707106781186548*helper_21 + 0.707106781186548*helper_5; - result_0[0] = -helper_40*(1.0*helper_21 - 3.0*helper_4 + helper_46*(helper_41*(-helper_1 + helper_2) - helper_42*(helper_14 - helper_8) - (-helper_17 + helper_18 - helper_19)*(-helper_25 - helper_27 + helper_29 - helper_30) + (-helper_33 + helper_34 - helper_35)*(-helper_11 + helper_13 - helper_15 - helper_9)) + 1.0*helper_5 + 1.0*helper_6); - result_0[1] = helper_40*(3.0*helper_1 - 1.0*helper_2 - 1.0*helper_26 - 1.0*helper_28 + helper_46*(helper_23 + helper_24*helper_47 - helper_38*helper_41)); - result_0[2] = helper_40*(-1.0*helper_10 - 1.0*helper_12 - 1.0*helper_14 + helper_46*(-helper_3*helper_47 - helper_32 + helper_37 + helper_38*helper_42) + 3.0*helper_8); + Scalar helper_41 = 0.707106781186548 * helper_10 - 0.707106781186548 * helper_12; + Scalar helper_42 = 0.707106781186548 * helper_26 - 0.707106781186548 * helper_28; + Scalar helper_43 = 0.5 * helper_21 + 0.5 * helper_5; + Scalar helper_44 = 0.5 * helper_26 + 0.5 * helper_28; + Scalar helper_45 = 0.5 * helper_10 + 0.5 * helper_12; + Scalar helper_46 = + 0.666666666666667 * + (helper_1 * (-1.5 * helper_1 + 0.5 * helper_2 + helper_44) + + helper_10 * (-1.5 * helper_10 + 0.5 * helper_12 + 0.5 * helper_14 + 0.5 * helper_8) + + helper_12 * (0.5 * helper_10 - 1.5 * helper_12 + 0.5 * helper_14 + 0.5 * helper_8) + + helper_14 * (-1.5 * helper_14 + helper_45 + 0.5 * helper_8) + + helper_2 * (0.5 * helper_1 - 1.5 * helper_2 + helper_44) + + helper_21 * (-1.5 * helper_21 + 0.5 * helper_4 + 0.5 * helper_5 + 0.5 * helper_6) + + helper_26 * (0.5 * helper_1 + 0.5 * helper_2 - 1.5 * helper_26 + 0.5 * helper_28) + + helper_28 * (0.5 * helper_1 + 0.5 * helper_2 + 0.5 * helper_26 - 1.5 * helper_28) + + helper_4 * (-1.5 * helper_4 + helper_43 + 0.5 * helper_6) + + helper_5 * (0.5 * helper_21 + 0.5 * helper_4 - 1.5 * helper_5 + 0.5 * helper_6) + + helper_6 * (0.5 * helper_4 + helper_43 - 1.5 * helper_6) + + helper_8 * (0.5 * helper_14 + helper_45 - 1.5 * helper_8)) / + helper_39; + Scalar helper_47 = -0.707106781186548 * helper_21 + 0.707106781186548 * helper_5; + result_0[0] = + -helper_40 * + (1.0 * helper_21 - 3.0 * helper_4 + + helper_46 * + (helper_41 * (-helper_1 + helper_2) - helper_42 * (helper_14 - helper_8) - + (-helper_17 + helper_18 - helper_19) * (-helper_25 - helper_27 + helper_29 - helper_30) + + (-helper_33 + helper_34 - helper_35) * (-helper_11 + helper_13 - helper_15 - helper_9)) + + 1.0 * helper_5 + 1.0 * helper_6); + result_0[1] = + helper_40 * (3.0 * helper_1 - 1.0 * helper_2 - 1.0 * helper_26 - 1.0 * helper_28 + + helper_46 * (helper_23 + helper_24 * helper_47 - helper_38 * helper_41)); + result_0[2] = + helper_40 * + (-1.0 * helper_10 - 1.0 * helper_12 - 1.0 * helper_14 + + helper_46 * (-helper_3 * helper_47 - helper_32 + helper_37 + helper_38 * helper_42) + + 3.0 * helper_8); } -void floatTetWild::AMIPS_hessian(const std::array& T, Matrix3& result_0){ +void floatTetWild::AMIPS_hessian(const std::array& T, Matrix3& result_0) +{ Scalar helper_0[12]; - helper_0[0] = T[0]; - helper_0[1] = T[1]; - helper_0[2] = T[2]; - helper_0[3] = T[3]; - helper_0[4] = T[4]; - helper_0[5] = T[5]; - helper_0[6] = T[6]; - helper_0[7] = T[7]; - helper_0[8] = T[8]; - helper_0[9] = T[9]; - helper_0[10] = T[10]; - helper_0[11] = T[11]; - Scalar helper_1 = helper_0[2]; - Scalar helper_2 = helper_0[11]; - Scalar helper_3 = helper_1 - helper_2; - Scalar helper_4 = helper_0[0]; - Scalar helper_5 = 0.577350269189626*helper_4; - Scalar helper_6 = helper_0[3]; - Scalar helper_7 = 1.15470053837925*helper_6; - Scalar helper_8 = helper_0[9]; - Scalar helper_9 = 0.577350269189626*helper_8; + helper_0[0] = T[0]; + helper_0[1] = T[1]; + helper_0[2] = T[2]; + helper_0[3] = T[3]; + helper_0[4] = T[4]; + helper_0[5] = T[5]; + helper_0[6] = T[6]; + helper_0[7] = T[7]; + helper_0[8] = T[8]; + helper_0[9] = T[9]; + helper_0[10] = T[10]; + helper_0[11] = T[11]; + Scalar helper_1 = helper_0[2]; + Scalar helper_2 = helper_0[11]; + Scalar helper_3 = helper_1 - helper_2; + Scalar helper_4 = helper_0[0]; + Scalar helper_5 = 0.577350269189626 * helper_4; + Scalar helper_6 = helper_0[3]; + Scalar helper_7 = 1.15470053837925 * helper_6; + Scalar helper_8 = helper_0[9]; + Scalar helper_9 = 0.577350269189626 * helper_8; Scalar helper_10 = helper_5 - helper_7 + helper_9; Scalar helper_11 = helper_0[1]; - Scalar helper_12 = 0.408248290463863*helper_11; + Scalar helper_12 = 0.408248290463863 * helper_11; Scalar helper_13 = helper_0[4]; - Scalar helper_14 = 0.408248290463863*helper_13; + Scalar helper_14 = 0.408248290463863 * helper_13; Scalar helper_15 = helper_0[7]; - Scalar helper_16 = 1.22474487139159*helper_15; + Scalar helper_16 = 1.22474487139159 * helper_15; Scalar helper_17 = helper_0[10]; - Scalar helper_18 = 0.408248290463863*helper_17; + Scalar helper_18 = 0.408248290463863 * helper_17; Scalar helper_19 = helper_12 + helper_14 - helper_16 + helper_18; - Scalar helper_20 = helper_10*helper_19; - Scalar helper_21 = 0.577350269189626*helper_11; - Scalar helper_22 = 1.15470053837925*helper_13; - Scalar helper_23 = 0.577350269189626*helper_17; + Scalar helper_20 = helper_10 * helper_19; + Scalar helper_21 = 0.577350269189626 * helper_11; + Scalar helper_22 = 1.15470053837925 * helper_13; + Scalar helper_23 = 0.577350269189626 * helper_17; Scalar helper_24 = helper_21 - helper_22 + helper_23; - Scalar helper_25 = 0.408248290463863*helper_4; - Scalar helper_26 = 0.408248290463863*helper_6; + Scalar helper_25 = 0.408248290463863 * helper_4; + Scalar helper_26 = 0.408248290463863 * helper_6; Scalar helper_27 = helper_0[6]; - Scalar helper_28 = 1.22474487139159*helper_27; - Scalar helper_29 = 0.408248290463863*helper_8; + Scalar helper_28 = 1.22474487139159 * helper_27; + Scalar helper_29 = 0.408248290463863 * helper_8; Scalar helper_30 = helper_25 + helper_26 - helper_28 + helper_29; - Scalar helper_31 = helper_24*helper_30; - Scalar helper_32 = helper_3*(helper_20 - helper_31); + Scalar helper_31 = helper_24 * helper_30; + Scalar helper_32 = helper_3 * (helper_20 - helper_31); Scalar helper_33 = helper_4 - helper_8; - Scalar helper_34 = 0.408248290463863*helper_1; + Scalar helper_34 = 0.408248290463863 * helper_1; Scalar helper_35 = helper_0[5]; - Scalar helper_36 = 0.408248290463863*helper_35; + Scalar helper_36 = 0.408248290463863 * helper_35; Scalar helper_37 = helper_0[8]; - Scalar helper_38 = 1.22474487139159*helper_37; - Scalar helper_39 = 0.408248290463863*helper_2; + Scalar helper_38 = 1.22474487139159 * helper_37; + Scalar helper_39 = 0.408248290463863 * helper_2; Scalar helper_40 = helper_34 + helper_36 - helper_38 + helper_39; - Scalar helper_41 = helper_24*helper_40; - Scalar helper_42 = 0.577350269189626*helper_1; - Scalar helper_43 = 1.15470053837925*helper_35; - Scalar helper_44 = 0.577350269189626*helper_2; + Scalar helper_41 = helper_24 * helper_40; + Scalar helper_42 = 0.577350269189626 * helper_1; + Scalar helper_43 = 1.15470053837925 * helper_35; + Scalar helper_44 = 0.577350269189626 * helper_2; Scalar helper_45 = helper_42 - helper_43 + helper_44; - Scalar helper_46 = helper_19*helper_45; + Scalar helper_46 = helper_19 * helper_45; Scalar helper_47 = helper_41 - helper_46; - Scalar helper_48 = helper_33*helper_47; + Scalar helper_48 = helper_33 * helper_47; Scalar helper_49 = helper_11 - helper_17; - Scalar helper_50 = helper_10*helper_40; - Scalar helper_51 = helper_30*helper_45; + Scalar helper_50 = helper_10 * helper_40; + Scalar helper_51 = helper_30 * helper_45; Scalar helper_52 = helper_50 - helper_51; - Scalar helper_53 = helper_49*helper_52; + Scalar helper_53 = helper_49 * helper_52; Scalar helper_54 = helper_32 + helper_48 - helper_53; Scalar helper_55 = pow(helper_54, 2); Scalar helper_56 = pow(helper_55, -0.333333333333333); - Scalar helper_57 = 1.0*helper_27 - 3.0*helper_4 + 1.0*helper_6 + 1.0*helper_8; - Scalar helper_58 = 0.707106781186548*helper_13; - Scalar helper_59 = 0.707106781186548*helper_15; + Scalar helper_57 = 1.0 * helper_27 - 3.0 * helper_4 + 1.0 * helper_6 + 1.0 * helper_8; + Scalar helper_58 = 0.707106781186548 * helper_13; + Scalar helper_59 = 0.707106781186548 * helper_15; Scalar helper_60 = helper_58 - helper_59; - Scalar helper_61 = helper_3*helper_60; - Scalar helper_62 = 0.707106781186548*helper_35 - 0.707106781186548*helper_37; - Scalar helper_63 = helper_49*helper_62; + Scalar helper_61 = helper_3 * helper_60; + Scalar helper_62 = 0.707106781186548 * helper_35 - 0.707106781186548 * helper_37; + Scalar helper_63 = helper_49 * helper_62; Scalar helper_64 = helper_47 + helper_61 - helper_63; - Scalar helper_65 = 1.33333333333333/helper_54; - Scalar helper_66 = 1.0/helper_55; - Scalar helper_67 = 0.5*helper_27 + 0.5*helper_6; - Scalar helper_68 = -1.5*helper_4 + helper_67 + 0.5*helper_8; - Scalar helper_69 = 0.5*helper_4 + helper_67 - 1.5*helper_8; - Scalar helper_70 = -1.5*helper_27 + 0.5*helper_4 + 0.5*helper_6 + 0.5*helper_8; - Scalar helper_71 = 0.5*helper_27 + 0.5*helper_4 - 1.5*helper_6 + 0.5*helper_8; - Scalar helper_72 = 0.5*helper_13 + 0.5*helper_15; - Scalar helper_73 = -1.5*helper_11 + 0.5*helper_17 + helper_72; - Scalar helper_74 = 0.5*helper_11 - 1.5*helper_17 + helper_72; - Scalar helper_75 = 0.5*helper_11 + 0.5*helper_13 - 1.5*helper_15 + 0.5*helper_17; - Scalar helper_76 = 0.5*helper_11 - 1.5*helper_13 + 0.5*helper_15 + 0.5*helper_17; - Scalar helper_77 = 0.5*helper_35 + 0.5*helper_37; - Scalar helper_78 = -1.5*helper_1 + 0.5*helper_2 + helper_77; - Scalar helper_79 = 0.5*helper_1 - 1.5*helper_2 + helper_77; - Scalar helper_80 = 0.5*helper_1 + 0.5*helper_2 + 0.5*helper_35 - 1.5*helper_37; - Scalar helper_81 = 0.5*helper_1 + 0.5*helper_2 - 1.5*helper_35 + 0.5*helper_37; - Scalar helper_82 = helper_1*helper_78 + helper_11*helper_73 + helper_13*helper_76 + helper_15*helper_75 + helper_17*helper_74 + helper_2*helper_79 + helper_27*helper_70 + helper_35*helper_81 + helper_37*helper_80 + helper_4*helper_68 + helper_6*helper_71 + helper_69*helper_8; - Scalar helper_83 = 0.444444444444444*helper_66*helper_82; - Scalar helper_84 = helper_66*helper_82; + Scalar helper_65 = 1.33333333333333 / helper_54; + Scalar helper_66 = 1.0 / helper_55; + Scalar helper_67 = 0.5 * helper_27 + 0.5 * helper_6; + Scalar helper_68 = -1.5 * helper_4 + helper_67 + 0.5 * helper_8; + Scalar helper_69 = 0.5 * helper_4 + helper_67 - 1.5 * helper_8; + Scalar helper_70 = -1.5 * helper_27 + 0.5 * helper_4 + 0.5 * helper_6 + 0.5 * helper_8; + Scalar helper_71 = 0.5 * helper_27 + 0.5 * helper_4 - 1.5 * helper_6 + 0.5 * helper_8; + Scalar helper_72 = 0.5 * helper_13 + 0.5 * helper_15; + Scalar helper_73 = -1.5 * helper_11 + 0.5 * helper_17 + helper_72; + Scalar helper_74 = 0.5 * helper_11 - 1.5 * helper_17 + helper_72; + Scalar helper_75 = 0.5 * helper_11 + 0.5 * helper_13 - 1.5 * helper_15 + 0.5 * helper_17; + Scalar helper_76 = 0.5 * helper_11 - 1.5 * helper_13 + 0.5 * helper_15 + 0.5 * helper_17; + Scalar helper_77 = 0.5 * helper_35 + 0.5 * helper_37; + Scalar helper_78 = -1.5 * helper_1 + 0.5 * helper_2 + helper_77; + Scalar helper_79 = 0.5 * helper_1 - 1.5 * helper_2 + helper_77; + Scalar helper_80 = 0.5 * helper_1 + 0.5 * helper_2 + 0.5 * helper_35 - 1.5 * helper_37; + Scalar helper_81 = 0.5 * helper_1 + 0.5 * helper_2 - 1.5 * helper_35 + 0.5 * helper_37; + Scalar helper_82 = helper_1 * helper_78 + helper_11 * helper_73 + helper_13 * helper_76 + + helper_15 * helper_75 + helper_17 * helper_74 + helper_2 * helper_79 + + helper_27 * helper_70 + helper_35 * helper_81 + helper_37 * helper_80 + + helper_4 * helper_68 + helper_6 * helper_71 + helper_69 * helper_8; + Scalar helper_83 = 0.444444444444444 * helper_66 * helper_82; + Scalar helper_84 = helper_66 * helper_82; Scalar helper_85 = -helper_32 - helper_48 + helper_53; - Scalar helper_86 = 1.0/helper_85; - Scalar helper_87 = helper_86*pow(pow(helper_85, 2), -0.333333333333333); - Scalar helper_88 = 0.707106781186548*helper_6; - Scalar helper_89 = 0.707106781186548*helper_27; + Scalar helper_86 = 1.0 / helper_85; + Scalar helper_87 = helper_86 * pow(pow(helper_85, 2), -0.333333333333333); + Scalar helper_88 = 0.707106781186548 * helper_6; + Scalar helper_89 = 0.707106781186548 * helper_27; Scalar helper_90 = helper_88 - helper_89; - Scalar helper_91 = 0.666666666666667*helper_10*helper_40 + 0.666666666666667*helper_3*helper_90 - 0.666666666666667*helper_30*helper_45 - 0.666666666666667*helper_33*helper_62; - Scalar helper_92 = -3.0*helper_11 + 1.0*helper_13 + 1.0*helper_15 + 1.0*helper_17; + Scalar helper_91 = + 0.666666666666667 * helper_10 * helper_40 + 0.666666666666667 * helper_3 * helper_90 - + 0.666666666666667 * helper_30 * helper_45 - 0.666666666666667 * helper_33 * helper_62; + Scalar helper_92 = -3.0 * helper_11 + 1.0 * helper_13 + 1.0 * helper_15 + 1.0 * helper_17; Scalar helper_93 = -helper_11 + helper_17; Scalar helper_94 = -helper_1 + helper_2; Scalar helper_95 = -helper_21 + helper_22 - helper_23; Scalar helper_96 = -helper_34 - helper_36 + helper_38 - helper_39; Scalar helper_97 = -helper_42 + helper_43 - helper_44; Scalar helper_98 = -helper_12 - helper_14 + helper_16 - helper_18; - Scalar helper_99 = -0.666666666666667*helper_60*helper_94 + 0.666666666666667*helper_62*helper_93 + 0.666666666666667*helper_95*helper_96 - 0.666666666666667*helper_97*helper_98; - Scalar helper_100 = helper_3*helper_90; - Scalar helper_101 = helper_33*helper_62; + Scalar helper_99 = + -0.666666666666667 * helper_60 * helper_94 + 0.666666666666667 * helper_62 * helper_93 + + 0.666666666666667 * helper_95 * helper_96 - 0.666666666666667 * helper_97 * helper_98; + Scalar helper_100 = helper_3 * helper_90; + Scalar helper_101 = helper_33 * helper_62; Scalar helper_102 = helper_100 - helper_101 + helper_52; - Scalar helper_103 = -helper_60*helper_94 + helper_62*helper_93 + helper_95*helper_96 - helper_97*helper_98; - Scalar helper_104 = 0.444444444444444*helper_102*helper_103*helper_82*helper_86 + helper_57*helper_91 - helper_92*helper_99; - Scalar helper_105 = 1.85037170770859e-17*helper_1*helper_78 + 1.85037170770859e-17*helper_11*helper_73 + 1.85037170770859e-17*helper_13*helper_76 + 1.85037170770859e-17*helper_15*helper_75 + 1.85037170770859e-17*helper_17*helper_74 + 1.85037170770859e-17*helper_2*helper_79 + 1.85037170770859e-17*helper_27*helper_70 + 1.85037170770859e-17*helper_35*helper_81 + 1.85037170770859e-17*helper_37*helper_80 + 1.85037170770859e-17*helper_4*helper_68 + 1.85037170770859e-17*helper_6*helper_71 + 1.85037170770859e-17*helper_69*helper_8; - Scalar helper_106 = helper_64*helper_82*helper_86; - Scalar helper_107 = -0.666666666666667*helper_10*helper_19 + 0.666666666666667*helper_24*helper_30 + 0.666666666666667*helper_33*helper_60 - 0.666666666666667*helper_49*helper_90; - Scalar helper_108 = -3.0*helper_1 + 1.0*helper_2 + 1.0*helper_35 + 1.0*helper_37; - Scalar helper_109 = -helper_20 + helper_31 + helper_33*helper_60 - helper_49*helper_90; - Scalar helper_110 = 0.444444444444444*helper_109*helper_82*helper_86; - Scalar helper_111 = helper_103*helper_110 + helper_107*helper_57 - helper_108*helper_99; + Scalar helper_103 = -helper_60 * helper_94 + helper_62 * helper_93 + helper_95 * helper_96 - + helper_97 * helper_98; + Scalar helper_104 = 0.444444444444444 * helper_102 * helper_103 * helper_82 * helper_86 + + helper_57 * helper_91 - helper_92 * helper_99; + Scalar helper_105 = + 1.85037170770859e-17 * helper_1 * helper_78 + 1.85037170770859e-17 * helper_11 * helper_73 + + 1.85037170770859e-17 * helper_13 * helper_76 + 1.85037170770859e-17 * helper_15 * helper_75 + + 1.85037170770859e-17 * helper_17 * helper_74 + 1.85037170770859e-17 * helper_2 * helper_79 + + 1.85037170770859e-17 * helper_27 * helper_70 + 1.85037170770859e-17 * helper_35 * helper_81 + + 1.85037170770859e-17 * helper_37 * helper_80 + 1.85037170770859e-17 * helper_4 * helper_68 + + 1.85037170770859e-17 * helper_6 * helper_71 + 1.85037170770859e-17 * helper_69 * helper_8; + Scalar helper_106 = helper_64 * helper_82 * helper_86; + Scalar helper_107 = + -0.666666666666667 * helper_10 * helper_19 + 0.666666666666667 * helper_24 * helper_30 + + 0.666666666666667 * helper_33 * helper_60 - 0.666666666666667 * helper_49 * helper_90; + Scalar helper_108 = -3.0 * helper_1 + 1.0 * helper_2 + 1.0 * helper_35 + 1.0 * helper_37; + Scalar helper_109 = -helper_20 + helper_31 + helper_33 * helper_60 - helper_49 * helper_90; + Scalar helper_110 = 0.444444444444444 * helper_109 * helper_82 * helper_86; + Scalar helper_111 = helper_103 * helper_110 + helper_107 * helper_57 - helper_108 * helper_99; Scalar helper_112 = -helper_4 + helper_8; Scalar helper_113 = -helper_88 + helper_89; Scalar helper_114 = -helper_5 + helper_7 - helper_9; Scalar helper_115 = -helper_25 - helper_26 + helper_28 - helper_29; - Scalar helper_116 = helper_82*helper_86*(helper_112*helper_62 + helper_113*helper_94 + helper_114*helper_96 - helper_115*helper_97); + Scalar helper_116 = helper_82 * helper_86 * + (helper_112 * helper_62 + helper_113 * helper_94 + helper_114 * helper_96 - + helper_115 * helper_97); Scalar helper_117 = -helper_100 + helper_101 - helper_50 + helper_51; - Scalar helper_118 = -helper_102*helper_110 + helper_107*helper_92 + helper_108*helper_91; - Scalar helper_119 = helper_82*helper_86*(helper_112*(-helper_58 + helper_59) - helper_113*helper_93 - helper_114*helper_98 + helper_115*helper_95); - result_0(0, 0) = helper_56*(helper_57*helper_64*helper_65 - pow(helper_64, 2)*helper_83 + 0.666666666666667*helper_64*helper_84*(-helper_41 + helper_46 - helper_61 + helper_63) + 3.0); - result_0(0, 1) = helper_87*(helper_104 - helper_105*helper_35 + helper_106*helper_91); - result_0(0, 2) = helper_87*(helper_106*helper_107 + helper_111); - result_0(1, 0) = helper_87*(helper_104 + helper_116*helper_99); - result_0(1, 1) = helper_56*(-pow(helper_117, 2)*helper_83 + helper_117*helper_65*helper_92 + helper_117*helper_84*helper_91 + 3.0); - result_0(1, 2) = helper_87*(-helper_105*helper_6 - helper_107*helper_116 + helper_118); - result_0(2, 0) = helper_87*(-helper_105*helper_13 + helper_111 + helper_119*helper_99); - result_0(2, 1) = helper_87*(helper_118 - helper_119*helper_91); - result_0(2, 2) = helper_56*(-helper_108*helper_109*helper_65 - 1.11111111111111*pow(helper_109, 2)*helper_84 + 3.0); + Scalar helper_118 = -helper_102 * helper_110 + helper_107 * helper_92 + helper_108 * helper_91; + Scalar helper_119 = helper_82 * helper_86 * + (helper_112 * (-helper_58 + helper_59) - helper_113 * helper_93 - + helper_114 * helper_98 + helper_115 * helper_95); + result_0(0, 0) = + helper_56 * (helper_57 * helper_64 * helper_65 - pow(helper_64, 2) * helper_83 + + 0.666666666666667 * helper_64 * helper_84 * + (-helper_41 + helper_46 - helper_61 + helper_63) + + 3.0); + result_0(0, 1) = helper_87 * (helper_104 - helper_105 * helper_35 + helper_106 * helper_91); + result_0(0, 2) = helper_87 * (helper_106 * helper_107 + helper_111); + result_0(1, 0) = helper_87 * (helper_104 + helper_116 * helper_99); + result_0(1, 1) = + helper_56 * (-pow(helper_117, 2) * helper_83 + helper_117 * helper_65 * helper_92 + + helper_117 * helper_84 * helper_91 + 3.0); + result_0(1, 2) = helper_87 * (-helper_105 * helper_6 - helper_107 * helper_116 + helper_118); + result_0(2, 0) = helper_87 * (-helper_105 * helper_13 + helper_111 + helper_119 * helper_99); + result_0(2, 1) = helper_87 * (helper_118 - helper_119 * helper_91); + result_0(2, 2) = helper_56 * (-helper_108 * helper_109 * helper_65 - + 1.11111111111111 * pow(helper_109, 2) * helper_84 + 3.0); } diff --git a/src/Simplification.cpp b/src/Simplification.cpp index a85753c3..78f85820 100644 --- a/src/Simplification.cpp +++ b/src/Simplification.cpp @@ -6,33 +6,35 @@ // obtain one at http://mozilla.org/MPL/2.0/. // +#include #include #include -#include -#include -#include #include +#include #include +#include #ifdef FLOAT_TETWILD_USE_TBB -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #endif -void floatTetWild::simplify(std::vector& input_vertices, std::vector& input_faces, std::vector& input_tags, - const AABBWrapper& tree, const Parameters& params, bool skip_simplify) { - +void floatTetWild::simplify(std::vector& input_vertices, + std::vector& input_faces, + std::vector& input_tags, + const AABBWrapper& tree, + const Parameters& params, + bool skip_simplify) +{ remove_duplicates(input_vertices, input_faces, input_tags, params); if (skip_simplify) return; - std::vector v_is_removed(input_vertices.size(), false); - std::vector f_is_removed(input_faces.size(), false); + std::vector v_is_removed(input_vertices.size(), false); + std::vector f_is_removed(input_faces.size(), false); std::vector> conn_fs(input_vertices.size()); for (int i = 0; i < input_faces.size(); i++) { for (int j = 0; j < 3; j++) @@ -42,16 +44,16 @@ void floatTetWild::simplify(std::vector& input_vertices, std::vector map_v_ids(input_vertices.size(), -1); - int cnt = 0; + int cnt = 0; for (int i = 0; i < input_vertices.size(); i++) { if (v_is_removed[i] || conn_fs[i].empty()) continue; @@ -68,7 +70,7 @@ void floatTetWild::simplify(std::vector& input_vertices, std::vector& input_vertices, std::vector new_input_faces(cnt); - std::vector new_input_tags(cnt); + std::vector new_input_tags(cnt); cnt = 0; for (int i = 0; i < input_faces.size(); i++) { if (f_is_removed[i]) continue; new_input_faces[cnt] = input_faces[i]; - new_input_tags[cnt] = input_tags[i]; + new_input_tags[cnt] = input_tags[i]; cnt++; } input_faces = new_input_faces; - input_tags = new_input_tags; + input_tags = new_input_tags; -// flattening(input_vertices, input_faces, tree, params); + // flattening(input_vertices, input_faces, tree, params); remove_duplicates(input_vertices, input_faces, input_tags, params); @@ -99,8 +101,8 @@ void floatTetWild::simplify(std::vector& input_vertices, std::vector& input_vertices, std::vector(a[0], a[1], a[2]) < std::tuple(b[0], b[1], b[2]); -// }); -// for(int i=0;i(a[0], a[1], a[2]) < std::tuple(b[0], b[1], b[2]); + // }); + // for(int i=0;i& input_vertices, std::vector& input_faces, std::vector& input_tags, const Parameters& params) { -// std::vector indices(input_vertices.size()); -// for(size_t i=0;i& input_vertices, + std::vector& input_faces, + std::vector& input_tags, + const Parameters& params) +{ + // std::vector indices(input_vertices.size()); + // for(size_t i=0;i& input_vertices, std:: // Eigen::VectorXi IV, _; - igl::remove_duplicate_vertices(V_tmp, F_tmp, SCALAR_ZERO * params.bbox_diag_length, V_in, IV, _, F_in); + igl::remove_duplicate_vertices( + V_tmp, F_tmp, SCALAR_ZERO * params.bbox_diag_length, V_in, IV, _, F_in); // for (int i = 0; i < F_in.rows(); i++) { int j_min = 0; @@ -168,7 +181,7 @@ bool floatTetWild::remove_duplicates(std::vector& input_vertices, std:: F_tmp.resize(0, 0); Eigen::VectorXi IF; igl::unique_rows(F_in, F_tmp, IF, _); - F_in = F_tmp; + F_in = F_tmp; std::vector old_input_tags = input_tags; input_tags.resize(IF.rows()); for (int i = 0; i < IF.rows(); i++) { @@ -192,11 +205,12 @@ bool floatTetWild::remove_duplicates(std::vector& input_vertices, std:: for (int i = 0; i < F_in.rows(); i++) { if (F_in(i, 0) == F_in(i, 1) || F_in(i, 0) == F_in(i, 2) || F_in(i, 2) == F_in(i, 1)) continue; - if (i > 0 && (F_in(i, 0) == F_in(i - 1, 0) && F_in(i, 1) == F_in(i - 1, 2) && F_in(i, 2) == F_in(i - 1, 1))) + if (i > 0 && (F_in(i, 0) == F_in(i - 1, 0) && F_in(i, 1) == F_in(i - 1, 2) && + F_in(i, 2) == F_in(i - 1, 1))) continue; - //check area - Vector3 u = V_in.row(F_in(i, 1)) - V_in.row(F_in(i, 0)); - Vector3 v = V_in.row(F_in(i, 2)) - V_in.row(F_in(i, 0)); + // check area + Vector3 u = V_in.row(F_in(i, 1)) - V_in.row(F_in(i, 0)); + Vector3 v = V_in.row(F_in(i, 2)) - V_in.row(F_in(i, 0)); Vector3 area = u.cross(v); if (area.norm() / 2 <= SCALAR_ZERO * params.bbox_diag_length) continue; @@ -207,24 +221,27 @@ bool floatTetWild::remove_duplicates(std::vector& input_vertices, std:: return true; } -void floatTetWild::collapsing(std::vector& input_vertices, std::vector& input_faces, - const AABBWrapper& tree, const Parameters& params, - std::vector& v_is_removed, std::vector& f_is_removed, std::vector>& conn_fs){ - +void floatTetWild::collapsing(std::vector& input_vertices, + std::vector& input_faces, + const AABBWrapper& tree, + const Parameters& params, + std::vector& v_is_removed, + std::vector& f_is_removed, + std::vector>& conn_fs) +{ #ifdef FLOAT_TETWILD_USE_TBB - std::vector> edges; + std::vector> edges; tbb::concurrent_vector> edges_tbb; - const auto build_edges = [&](){ + const auto build_edges = [&]() { edges.clear(); - edges.reserve(input_faces.size()*3); + edges.reserve(input_faces.size() * 3); edges_tbb.clear(); - edges_tbb.reserve(input_faces.size()*3); + edges_tbb.reserve(input_faces.size() * 3); - tbb::parallel_for( size_t(0), input_faces.size(), [&](size_t f_id) - { - if(f_is_removed[f_id]) + tbb::parallel_for(size_t(0), input_faces.size(), [&](size_t f_id) { + if (f_is_removed[f_id]) return; for (int j = 0; j < 3; j++) { @@ -235,7 +252,6 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< } }); - edges.reserve(edges_tbb.size()); edges.insert(edges.end(), edges_tbb.begin(), edges_tbb.end()); assert(edges_tbb.size() == edges.size()); @@ -246,10 +262,9 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< #else std::vector> edges; edges.clear(); - edges.reserve(input_faces.size()*3); - for(size_t f_id = 0; f_id < input_faces.size(); ++f_id) - { - if(f_is_removed[f_id]) + edges.reserve(input_faces.size() * 3); + for (size_t f_id = 0; f_id < input_faces.size(); ++f_id) { + if (f_is_removed[f_id]) continue; const auto& f = input_faces[f_id]; @@ -263,7 +278,7 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< vector_unique(edges); std::priority_queue, cmp_s> sm_queue; - for (auto& e: edges) { + for (auto& e : edges) { Scalar weight = (input_vertices[e[0]] - input_vertices[e[1]]).squaredNorm(); sm_queue.push(ElementInQueue(e, weight)); sm_queue.push(ElementInQueue(std::array({{e[1], e[0]}}), weight)); @@ -273,7 +288,7 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< auto is_onering_clean = [&](int v_id) { std::vector v_ids; v_ids.reserve(conn_fs[v_id].size() * 2); - for (const auto &f_id:conn_fs[v_id]) { + for (const auto& f_id : conn_fs[v_id]) { for (int j = 0; j < 3; j++) { if (input_faces[f_id][j] != v_id) v_ids.push_back(input_faces[f_id][j]); @@ -291,28 +306,28 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< return true; }; - static const int SUC = 1; + static const int SUC = 1; static const int FAIL_CLEAN = 0; - static const int FAIL_FLIP = -1; - static const int FAIL_ENV = -2; + static const int FAIL_FLIP = -1; + static const int FAIL_ENV = -2; auto remove_an_edge = [&](int v1_id, int v2_id, const std::vector& n12_f_ids) { if (!is_onering_clean(v1_id) || !is_onering_clean(v2_id)) return FAIL_CLEAN; -// std::unordered_set new_f_ids; + // std::unordered_set new_f_ids; std::vector new_f_ids; - for (int f_id:conn_fs[v1_id]) { + for (int f_id : conn_fs[v1_id]) { if (f_id != n12_f_ids[0] && f_id != n12_f_ids[1]) new_f_ids.push_back(f_id); } - for (int f_id:conn_fs[v2_id]) { + for (int f_id : conn_fs[v2_id]) { if (f_id != n12_f_ids[0] && f_id != n12_f_ids[1]) new_f_ids.push_back(f_id); } vector_unique(new_f_ids); - //compute new point + // compute new point Vector3 p = (input_vertices[v1_id] + input_vertices[v2_id]) / 2; tree.project_to_sf(p); // GEO::vec3 geo_p(p[0], p[1], p[2]); @@ -323,16 +338,20 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< // p[1] = nearest_p[1]; // p[2] = nearest_p[2]; - //computing normal for checking flipping - for (int f_id:new_f_ids) { - Vector3 old_nv = (input_vertices[input_faces[f_id][1]] - input_vertices[input_faces[f_id][2]]).cross(input_vertices[input_faces[f_id][0]] - input_vertices[input_faces[f_id][2]]); + // computing normal for checking flipping + for (int f_id : new_f_ids) { + Vector3 old_nv = + (input_vertices[input_faces[f_id][1]] - input_vertices[input_faces[f_id][2]]) + .cross(input_vertices[input_faces[f_id][0]] - input_vertices[input_faces[f_id][2]]); for (int j = 0; j < 3; j++) { if (input_faces[f_id][j] == v1_id || input_faces[f_id][j] == v2_id) { - Vector3 new_nv = (input_vertices[input_faces[f_id][mod3(j + 1)]] - input_vertices[input_faces[f_id][mod3(j + 2)]]).cross(p - input_vertices[input_faces[f_id][mod3(j + 2)]]); + Vector3 new_nv = (input_vertices[input_faces[f_id][mod3(j + 1)]] - + input_vertices[input_faces[f_id][mod3(j + 2)]]) + .cross(p - input_vertices[input_faces[f_id][mod3(j + 2)]]); if (old_nv.dot(new_nv) <= 0) return FAIL_FLIP; - //check new tris' area + // check new tris' area if (new_nv.norm() / 2 <= SCALAR_ZERO_2) return FAIL_FLIP; break; @@ -340,15 +359,14 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< } } - //check if go outside of envelop - for (int f_id:new_f_ids) { + // check if go outside of envelop + for (int f_id : new_f_ids) { for (int j = 0; j < 3; j++) { if (input_faces[f_id][j] == v1_id || input_faces[f_id][j] == v2_id) { - const std::array tri = {{ - p, - input_vertices[input_faces[f_id][mod3(j + 1)]], - input_vertices[input_faces[f_id][mod3(j + 2)]] - }}; + const std::array tri = { + {p, + input_vertices[input_faces[f_id][mod3(j + 1)]], + input_vertices[input_faces[f_id][mod3(j + 2)]]}}; if (is_out_envelope(tri, tree, params)) return FAIL_ENV; break; @@ -356,10 +374,10 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< } } - //real update -// std::unordered_set n_v_ids;//get this info before real update for later usage - std::vector n_v_ids;//get this info before real update for later usage - for (int f_id:new_f_ids) { + // real update + // std::unordered_set n_v_ids;//get this info before real update for later usage + std::vector n_v_ids; // get this info before real update for later usage + for (int f_id : new_f_ids) { for (int j = 0; j < 3; j++) { if (input_faces[f_id][j] != v1_id && input_faces[f_id][j] != v2_id) n_v_ids.push_back(input_faces[f_id][j]); @@ -367,19 +385,19 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< } vector_unique(n_v_ids); - v_is_removed[v1_id] = true; + v_is_removed[v1_id] = true; input_vertices[v2_id] = p; - for (int f_id:n12_f_ids) { + for (int f_id : n12_f_ids) { f_is_removed[f_id] = true; #ifndef FLOAT_TETWILD_USE_TBB - for (int j = 0; j < 3; j++) {//rm conn_fs + for (int j = 0; j < 3; j++) { // rm conn_fs if (input_faces[f_id][j] != v1_id) { conn_fs[input_faces[f_id][j]].erase(f_id); } } #endif } - for (int f_id:conn_fs[v1_id]) {//add conn_fs + for (int f_id : conn_fs[v1_id]) { // add conn_fs if (f_is_removed[f_id]) continue; conn_fs[v2_id].insert(f_id); @@ -390,8 +408,8 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< } #ifndef FLOAT_TETWILD_USE_TBB - //push new edges into the queue - for (int v_id:n_v_ids) { + // push new edges into the queue + for (int v_id : n_v_ids) { double weight = (input_vertices[v2_id] - input_vertices[v_id]).squaredNorm(); sm_queue.push(ElementInQueue(std::array({{v2_id, v_id}}), weight)); sm_queue.push(ElementInQueue(std::array({{v_id, v2_id}}), weight)); @@ -401,78 +419,79 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< }; #ifdef FLOAT_TETWILD_USE_TBB - tbb::atomic cnt(0); - int cnt_suc = 0; + std::atomic cnt(0); + int cnt_suc = 0; // tbb::atomic fail_clean(0); // tbb::atomic fail_flip(0); // tbb::atomic fail_env(0); - const int stopping = input_vertices.size()/10000.; + const int stopping = input_vertices.size() / 10000.; std::vector safe_set; do { build_edges(); - Mesh::one_ring_edge_set(edges, v_is_removed, f_is_removed, conn_fs, input_vertices, safe_set); + Mesh::one_ring_edge_set( + edges, v_is_removed, f_is_removed, conn_fs, input_vertices, safe_set); cnt = 0; tbb::parallel_for(size_t(0), safe_set.size(), [&](size_t i) { -// for (int i = 0; i < safe_set.size(); i++) { - std::array &v_ids = edges[safe_set[i]]; + // for (int i = 0; i < safe_set.size(); i++) { + std::array& v_ids = edges[safe_set[i]]; -// if (v_is_removed[v_ids[0]] || v_is_removed[v_ids[1]]) -// return; + // if (v_is_removed[v_ids[0]] || v_is_removed[v_ids[1]]) + // return; std::vector n12_f_ids; set_intersection(conn_fs[v_ids[0]], conn_fs[v_ids[1]], n12_f_ids); if (n12_f_ids.size() != 2) return; -// continue; + // continue; int res = remove_an_edge(v_ids[0], v_ids[1], n12_f_ids); if (res == SUC) cnt++; }); -// } + // } - //cleanup conn_fs + // cleanup conn_fs tbb::parallel_for(size_t(0), conn_fs.size(), [&](size_t i) { -// for (int i = 0; i < conn_fs.size(); i++) { + // for (int i = 0; i < conn_fs.size(); i++) { if (v_is_removed[i]) -// continue; + // continue; return; std::vector r_f_ids; - for (int f_id: conn_fs[i]) { + for (int f_id : conn_fs[i]) { if (f_is_removed[f_id]) r_f_ids.push_back(f_id); } - for (int f_id:r_f_ids) + for (int f_id : r_f_ids) conn_fs[i].erase(f_id); -// } + // } }); cnt_suc += cnt; - } while(cnt > stopping); + } while (cnt > stopping); #else - int cnt_suc = 0; + int cnt_suc = 0; int fail_clean = 0; - int fail_flip = 0; - int fail_env = 0; + int fail_flip = 0; + int fail_env = 0; while (!sm_queue.empty()) { - std::array v_ids = sm_queue.top().v_ids; - Scalar old_weight = sm_queue.top().weight; + std::array v_ids = sm_queue.top().v_ids; + Scalar old_weight = sm_queue.top().weight; sm_queue.pop(); if (v_is_removed[v_ids[0]] || v_is_removed[v_ids[1]]) continue; - if(old_weight!=(input_vertices[v_ids[0]] - input_vertices[v_ids[1]]).squaredNorm()) + if (old_weight != (input_vertices[v_ids[0]] - input_vertices[v_ids[1]]).squaredNorm()) continue; std::vector n12_f_ids; set_intersection(conn_fs[v_ids[0]], conn_fs[v_ids[1]], n12_f_ids); - if(n12_f_ids.size()!=2) + if (n12_f_ids.size() != 2) continue; int res = remove_an_edge(v_ids[0], v_ids[1], n12_f_ids); @@ -490,19 +509,24 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< // cout<& input_vertices, std::vector& input_faces, - const AABBWrapper& tree, const Parameters& params, - std::vector& v_is_removed, std::vector& f_is_removed, std::vector>& conn_fs) { +void floatTetWild::swapping(std::vector& input_vertices, + std::vector& input_faces, + const AABBWrapper& tree, + const Parameters& params, + std::vector& v_is_removed, + std::vector& f_is_removed, + std::vector>& conn_fs) +{ std::vector> edges; edges.reserve(input_faces.size() * 6); for (int i = 0; i < input_faces.size(); i++) { if (f_is_removed[i]) continue; - auto &f = input_faces[i]; + auto& f = input_faces[i]; for (int j = 0; j < 3; j++) { std::array e = {{f[j], f[mod3(j + 1)]}}; if (e[0] > e[1]) @@ -513,7 +537,7 @@ void floatTetWild::swapping(std::vector& input_vertices, std::vector, cmp_l> sm_queue; - for (auto &e: edges) { + for (auto& e : edges) { Scalar weight = (input_vertices[e[0]] - input_vertices[e[1]]).squaredNorm(); sm_queue.push(ElementInQueue(e, weight)); sm_queue.push(ElementInQueue(std::array({{e[1], e[0]}}), weight)); @@ -532,37 +556,39 @@ void floatTetWild::swapping(std::vector& input_vertices, std::vector n_v_ids = {{-1, -1}}; for (int j = 0; j < 3; j++) { - if (n_v_ids[0] < 0 - && input_faces[n12_f_ids[0]][j] != v1_id && input_faces[n12_f_ids[0]][j] != v2_id) + if (n_v_ids[0] < 0 && input_faces[n12_f_ids[0]][j] != v1_id && + input_faces[n12_f_ids[0]][j] != v2_id) n_v_ids[0] = input_faces[n12_f_ids[0]][j]; - if (n_v_ids[1] < 0 - && input_faces[n12_f_ids[1]][j] != v1_id && input_faces[n12_f_ids[1]][j] != v2_id) + if (n_v_ids[1] < 0 && input_faces[n12_f_ids[1]][j] != v1_id && + input_faces[n12_f_ids[1]][j] != v2_id) n_v_ids[1] = input_faces[n12_f_ids[1]][j]; } - //check coplanar - Scalar cos_a0 = get_angle_cos(input_vertices[n_v_ids[0]], input_vertices[v1_id], input_vertices[v2_id]); - Scalar cos_a1 = get_angle_cos(input_vertices[n_v_ids[1]], input_vertices[v1_id], input_vertices[v2_id]); + // check coplanar + Scalar cos_a0 = + get_angle_cos(input_vertices[n_v_ids[0]], input_vertices[v1_id], input_vertices[v2_id]); + Scalar cos_a1 = + get_angle_cos(input_vertices[n_v_ids[1]], input_vertices[v1_id], input_vertices[v2_id]); std::array old_nvs; for (int f = 0; f < 2; f++) { - auto &a = input_vertices[input_faces[n12_f_ids[f]][0]]; - auto &b = input_vertices[input_faces[n12_f_ids[f]][1]]; - auto &c = input_vertices[input_faces[n12_f_ids[f]][2]]; + auto& a = input_vertices[input_faces[n12_f_ids[f]][0]]; + auto& b = input_vertices[input_faces[n12_f_ids[f]][1]]; + auto& c = input_vertices[input_faces[n12_f_ids[f]][2]]; old_nvs[f] = ((b - c).cross(a - c)).normalized(); } - if (cos_a0 > -0.999) {//maybe it's for avoiding numerical issue - if (old_nvs[0].dot(old_nvs[1]) < 1 - 1e-6)//not coplanar + if (cos_a0 > -0.999) { // maybe it's for avoiding numerical issue + if (old_nvs[0].dot(old_nvs[1]) < 1 - 1e-6) // not coplanar continue; } - //check inversion - auto &old_nv = cos_a1 < cos_a0 ? old_nvs[0] : old_nvs[1]; - bool is_filp = false; - for (int f_id:n12_f_ids) { - auto &a = input_vertices[input_faces[f_id][0]]; - auto &b = input_vertices[input_faces[f_id][1]]; - auto &c = input_vertices[input_faces[f_id][2]]; + // check inversion + auto& old_nv = cos_a1 < cos_a0 ? old_nvs[0] : old_nvs[1]; + bool is_filp = false; + for (int f_id : n12_f_ids) { + auto& a = input_vertices[input_faces[f_id][0]]; + auto& b = input_vertices[input_faces[f_id][1]]; + auto& c = input_vertices[input_faces[f_id][2]]; if (old_nv.dot(((b - c).cross(a - c)).normalized()) < 0) { is_filp = true; break; @@ -571,29 +597,34 @@ void floatTetWild::swapping(std::vector& input_vertices, std::vector& input_vertices, std::vector& input_vertices, std::vector n12_f_ids; @@ -640,28 +671,33 @@ void floatTetWild::swapping(std::vector& input_vertices, std::vector old_nvs; for (int f = 0; f < 2; f++) { - auto& a = input_vertices[input_faces[n12_f_ids[f]][0]]; - auto& b = input_vertices[input_faces[n12_f_ids[f]][1]]; - auto& c = input_vertices[input_faces[n12_f_ids[f]][2]]; + auto& a = input_vertices[input_faces[n12_f_ids[f]][0]]; + auto& b = input_vertices[input_faces[n12_f_ids[f]][1]]; + auto& c = input_vertices[input_faces[n12_f_ids[f]][2]]; old_nvs[f] = ((b - c).cross(a - c)).normalized(); } if (cos_a > -0.999) { -// continue; - if (old_nvs[0].dot(old_nvs[1]) < 1-1e-6)//not coplanar + // continue; + if (old_nvs[0].dot(old_nvs[1]) < 1 - 1e-6) // not coplanar continue; } - Scalar cos_a_new = get_angle_cos(input_vertices[v1_id], input_vertices[v_id], input_vertices[v3_id]); - Scalar cos_a1_new = get_angle_cos(input_vertices[v2_id], input_vertices[v_id], input_vertices[v3_id]); + Scalar cos_a_new = + get_angle_cos(input_vertices[v1_id], input_vertices[v_id], input_vertices[v3_id]); + Scalar cos_a1_new = + get_angle_cos(input_vertices[v2_id], input_vertices[v_id], input_vertices[v3_id]); if (std::min(cos_a_new, cos_a1_new) <= std::min(cos_a, cos_a1)) continue; @@ -674,9 +710,9 @@ void floatTetWild::swapping(std::vector& input_vertices, std::vector& input_vertices, std::vector& input_vertices, std::vector& input_vertices, std::vector& input_faces, - const AABBWrapper& sf_tree, const Parameters& params) { +void floatTetWild::flattening(std::vector& input_vertices, + std::vector& input_faces, + const AABBWrapper& sf_tree, + const Parameters& params) +{ std::vector ns(input_faces.size()); for (int i = 0; i < input_faces.size(); i++) { - ns[i] = ((input_vertices[input_faces[i][2]] - input_vertices[input_faces[i][0]]).cross( - input_vertices[input_faces[i][1]] - input_vertices[input_faces[i][0]])).normalized(); + ns[i] = ((input_vertices[input_faces[i][2]] - input_vertices[input_faces[i][0]]) + .cross(input_vertices[input_faces[i][1]] - input_vertices[input_faces[i][0]])) + .normalized(); } - std::vector> conn_fs(input_vertices.size()); + std::vector> conn_fs(input_vertices.size()); std::vector> edges; edges.reserve(input_faces.size() * 6); for (int i = 0; i < input_faces.size(); i++) { - auto &f = input_faces[i]; + auto& f = input_faces[i]; for (int j = 0; j < 3; j++) { conn_fs[f[j]].push_back(i); std::array e = {{f[j], f[mod3(j + 1)]}}; @@ -743,24 +786,24 @@ void floatTetWild::flattening(std::vector& input_vertices, std::vector< } vector_unique(edges); - auto needs_flattening = [](const Vector3 &n1, const Vector3 &n2) { - if(n1.dot(n2)>0.98) { + auto needs_flattening = [](const Vector3& n1, const Vector3& n2) { + if (n1.dot(n2) > 0.98) { cout << std::setprecision(17) << n1.dot(n2) << endl; cout << n1.norm() << " " << n2.norm() << endl; } return true; double d = std::abs(n1.dot(n2) - 1); - cout< 1e-15 && d < 1e-5) return true; return false; }; - std::vector f_tss(input_faces.size(), 0); - int ts = 0; + std::vector f_tss(input_faces.size(), 0); + int ts = 0; std::queue> edge_queue; - for (auto &e: edges) { + for (auto& e : edges) { std::vector n_f_ids; set_intersection(conn_fs[e[0]], conn_fs[e[1]], n_f_ids); if (n_f_ids.size() != 2) @@ -771,9 +814,9 @@ void floatTetWild::flattening(std::vector& input_vertices, std::vector< } while (!edge_queue.empty()) { - std::array e = {{edge_queue.front()[0], edge_queue.front()[1]}}; + std::array e = {{edge_queue.front()[0], edge_queue.front()[1]}}; std::array n_f_ids = {{edge_queue.front()[2], edge_queue.front()[3]}}; - int e_ts = edge_queue.front().back(); + int e_ts = edge_queue.front().back(); edge_queue.pop(); std::vector all_f_ids; @@ -782,25 +825,25 @@ void floatTetWild::flattening(std::vector& input_vertices, std::vector< vector_unique(all_f_ids); bool is_valid = true; - for(int f_id: all_f_ids){ - if(f_tss[f_id]>e_ts) { + for (int f_id : all_f_ids) { + if (f_tss[f_id] > e_ts) { is_valid = false; break; } } - if(!is_valid) + if (!is_valid) continue; - auto &n1 = ns[n_f_ids[0]]; - auto &n2 = ns[n_f_ids[1]]; -// if(n_f_ids[0] == 61 && n_f_ids[0] == 62 || n_f_ids[0] == 62 && n_f_ids[0] == 61){ -// cout< n_v_ids; - for (int f_id: n_f_ids) { + for (int f_id : n_f_ids) { for (int j = 0; j < 3; j++) { if (input_faces[f_id][j] != e[0] && input_faces[f_id][j] != e[1]) { n_v_ids.push_back(input_faces[f_id][j]); @@ -810,7 +853,7 @@ void floatTetWild::flattening(std::vector& input_vertices, std::vector< } assert(n_v_ids.size() == 2 && n_v_ids[0] != n_v_ids[1]); Vector3 n = (n1 + n2) / 2; -// Vector3 p = (input_vertices[e[0]] + input_vertices[e[1]]) / 2; + // Vector3 p = (input_vertices[e[0]] + input_vertices[e[1]]) / 2; Vector3 p = (input_vertices[n_v_ids[0]] + input_vertices[n_v_ids[1]]) / 2; std::array old_ps; @@ -818,13 +861,13 @@ void floatTetWild::flattening(std::vector& input_vertices, std::vector< old_ps[j] = input_vertices[e[j]]; input_vertices[e[j]] -= n.dot(input_vertices[e[j]] - p) * n; } -// cout<<"ok1"< tri = {{input_vertices[input_faces[f_id][0]], - input_vertices[input_faces[f_id][1]], - input_vertices[input_faces[f_id][2]]}}; + input_vertices[input_faces[f_id][1]], + input_vertices[input_faces[f_id][2]]}}; if (is_out_envelope(tri, sf_tree, params)) { is_valid = false; break; @@ -834,66 +877,75 @@ void floatTetWild::flattening(std::vector& input_vertices, std::vector< for (int j = 0; j < 2; j++) input_vertices[e[j]] = old_ps[j]; } -// cout<<"ok2"<> new_edges; -// for (int f_id: all_f_ids) { -// for (int j = 0; j < 3; j++) { -// if (input_faces[f_id][j] < input_faces[f_id][(j + 1) % 3]) -// new_edges.push_back({{input_faces[f_id][j], input_faces[f_id][(j + 1) % 3]}}); -// else -// new_edges.push_back({{input_faces[f_id][(j + 1) % 3], input_faces[f_id][j]}}); -// } -// } -// vector_unique(new_edges); -// for(auto& new_e: new_edges){ -// if(new_e == e) -// continue; -// std::vector new_n_f_ids; -// set_intersection(conn_fs[new_e[0]], conn_fs[new_e[1]], new_n_f_ids); -// if (new_n_f_ids.size() != 2) -// continue; -// if (!needs_flattening(ns[new_n_f_ids[0]], ns[new_n_f_ids[1]])) -// continue; -// edge_queue.push({{new_e[0], new_e[1], new_n_f_ids[0], new_n_f_ids[1], ts}}); -// } + // std::vector> new_edges; + // for (int f_id: all_f_ids) { + // for (int j = 0; j < 3; j++) { + // if (input_faces[f_id][j] < input_faces[f_id][(j + 1) % 3]) + // new_edges.push_back({{input_faces[f_id][j], input_faces[f_id][(j + 1) + // % 3]}}); + // else + // new_edges.push_back({{input_faces[f_id][(j + 1) % 3], + // input_faces[f_id][j]}}); + // } + // } + // vector_unique(new_edges); + // for(auto& new_e: new_edges){ + // if(new_e == e) + // continue; + // std::vector new_n_f_ids; + // set_intersection(conn_fs[new_e[0]], conn_fs[new_e[1]], new_n_f_ids); + // if (new_n_f_ids.size() != 2) + // continue; + // if (!needs_flattening(ns[new_n_f_ids[0]], ns[new_n_f_ids[1]])) + // continue; + // edge_queue.push({{new_e[0], new_e[1], new_n_f_ids[0], new_n_f_ids[1], ts}}); + // } } cout << "flattening " << ts << " faces" << endl; } -floatTetWild::Scalar floatTetWild::get_angle_cos(const Vector3& p, const Vector3& p1, const Vector3& p2) { - Vector3 v1 = p1 - p; - Vector3 v2 = p2 - p; - Scalar res = v1.dot(v2) / (v1.norm() * v2.norm()); - if(res > 1) +floatTetWild::Scalar floatTetWild::get_angle_cos(const Vector3& p, + const Vector3& p1, + const Vector3& p2) +{ + Vector3 v1 = p1 - p; + Vector3 v2 = p2 - p; + Scalar res = v1.dot(v2) / (v1.norm() * v2.norm()); + if (res > 1) return 1; if (res < -1) return -1; return res; } -bool floatTetWild::is_out_envelope(const std::array& vs, const AABBWrapper& tree, const Parameters& params) { +bool floatTetWild::is_out_envelope(const std::array& vs, + const AABBWrapper& tree, + const Parameters& params) +{ #ifdef NEW_ENVELOPE return tree.is_out_sf_envelope_exact_simplify(vs); #else - #ifdef STORE_SAMPLE_POINTS - std::vector ps; - sample_triangle(vs, ps, params.dd_simplification); - return tree.is_out_sf_envelope(ps, params.eps_2_simplification); - #else - GEO::index_t prev_facet = GEO::NO_FACET; - return sample_triangle_and_check_is_out(vs, params.dd_simplification, params.eps_2_simplification, tree, prev_facet); - #endif +#ifdef STORE_SAMPLE_POINTS + std::vector ps; + sample_triangle(vs, ps, params.dd_simplification); + return tree.is_out_sf_envelope(ps, params.eps_2_simplification); +#else + GEO::index_t prev_facet = GEO::NO_FACET; + return sample_triangle_and_check_is_out( + vs, params.dd_simplification, params.eps_2_simplification, tree, prev_facet); +#endif #endif // GEO::vec3 init_point(vs[0][0], vs[0][1], vs[0][2]); @@ -923,47 +975,55 @@ bool floatTetWild::is_out_envelope(const std::array& vs, const AABBW // return false; } -void floatTetWild::check_surface(std::vector& input_vertices, std::vector& input_faces, const std::vector& f_is_removed, - const AABBWrapper& tree, const Parameters& params) { - cout<<"checking surface"<& input_vertices, + std::vector& input_faces, + const std::vector& f_is_removed, + const AABBWrapper& tree, + const Parameters& params) +{ + cout << "checking surface" << endl; bool is_valid = true; for (int i = 0; i < input_faces.size(); i++) { - if(f_is_removed[i]) + if (f_is_removed[i]) continue; std::vector ps; - sample_triangle( - {{input_vertices[input_faces[i][0]], input_vertices[input_faces[i][1]], input_vertices[input_faces[i][2]]}}, - ps, params.dd_simplification); + sample_triangle({{input_vertices[input_faces[i][0]], + input_vertices[input_faces[i][1]], + input_vertices[input_faces[i][2]]}}, + ps, + params.dd_simplification); Scalar dist = tree.dist_sf_envelope(ps, params.eps_2); if (dist > 0) { cout << "is_out_sf_envelope!!" << endl; is_valid = false; -// cout<& input_vertices, const std::vector& input_faces, - const std::vector& input_tags){ +void floatTetWild::output_component(const std::vector& input_vertices, + const std::vector& input_faces, + const std::vector& input_tags) +{ return; Eigen::MatrixXd V(input_vertices.size(), 3); - for(int i=0;i #include -#include +#include +#include #include +#include #include -#include -#include -#include //fortest +#include //fortest -#include -#include #include +#include +#include + +#include +#include #ifdef FLOAT_TETWILD_USE_TBB -#include -#include -#include -//#include -#include -#include +// #include #endif #include #include #include - #define III -1 -//fortest +// fortest #include -double time_find_cutting_tets = 0; -double time_find_cutting_tets1 = 0; -double time_find_cutting_tets2 = 0; -double time_find_cutting_tets3 = 0; -double time_find_cutting_tets4 = 0; -double time_cut_mesh = 0; -double time_cut_mesh1 = 0; -double time_cut_mesh2 = 0; +double time_find_cutting_tets = 0; +double time_find_cutting_tets1 = 0; +double time_find_cutting_tets2 = 0; +double time_find_cutting_tets3 = 0; +double time_find_cutting_tets4 = 0; +double time_cut_mesh = 0; +double time_cut_mesh1 = 0; +double time_cut_mesh2 = 0; double time_get_intersecting_edges_and_points = 0; -double time_subdivide_tets = 0; -double time_push_new_tets = 0; -double time_push_new_tets1 = 0; -double time_push_new_tets2 = 0; -double time_push_new_tets3 = 0; -double time_simplify_subdivision_result = 0; -int cnt_snapped = 0; - -double old_time_find_cutting_tets = 0; -double old_time_cut_mesh = 0; +double time_subdivide_tets = 0; +double time_push_new_tets = 0; +double time_push_new_tets1 = 0; +double time_push_new_tets2 = 0; +double time_push_new_tets3 = 0; +double time_simplify_subdivision_result = 0; +int cnt_snapped = 0; + +double old_time_find_cutting_tets = 0; +double old_time_cut_mesh = 0; double old_time_get_intersecting_edges_and_points = 0; -double old_time_subdivide_tets = 0; -double old_time_push_new_tets = 0; -double old_time_simplify_subdivision_result = 0; +double old_time_subdivide_tets = 0; +double old_time_push_new_tets = 0; +double old_time_simplify_subdivision_result = 0; -std::vector> covered_tet_fs;//fortest -//fortest +std::vector> covered_tet_fs; // fortest +// fortest -///two places to update quality: snapping tet vertices to plane, push new tets +/// two places to update quality: snapping tet vertices to plane, push new tets -floatTetWild::Vector3 floatTetWild::get_normal(const Vector3& a, const Vector3& b, const Vector3& c) { +floatTetWild::Vector3 floatTetWild::get_normal(const Vector3& a, const Vector3& b, const Vector3& c) +{ return ((b - c).cross(a - c)).normalized(); } -void floatTetWild::match_surface_fs(const Mesh &mesh, - const std::vector &input_vertices, const std::vector &input_faces, - std::vector &is_face_inserted, - std::vector, 4>> &track_surface_fs){ - auto comp = [](const std::array &a, const std::array &b) { - return std::tuple(a[0], a[1], a[2]) < std::tuple(b[0], b[1], b[2]); +void floatTetWild::match_surface_fs(const Mesh& mesh, + const std::vector& input_vertices, + const std::vector& input_faces, + std::vector& is_face_inserted, + std::vector, 4>>& track_surface_fs) +{ + auto comp = [](const std::array& a, const std::array& b) { + return std::tuple(a[0], a[1], a[2]) < + std::tuple(b[0], b[1], b[2]); }; std::vector> input_fs(input_faces.size()); @@ -92,15 +93,14 @@ void floatTetWild::match_surface_fs(const Mesh &mesh, std::sort(input_fs.begin(), input_fs.end(), comp); for (int i = 0; i < mesh.tets.size(); i++) { - auto &t = mesh.tets[i]; + auto& t = mesh.tets[i]; for (int j = 0; j < 4; j++) { std::array f = {{t[mod4(j + 1)], t[mod4(j + 2)], t[mod4(j + 3)]}}; std::sort(f.begin(), f.end()); - auto bounds = std::equal_range(input_fs.begin(), input_fs.end(), - std::array({{f[0], f[1], f[2], -1}}), - comp); + auto bounds = std::equal_range( + input_fs.begin(), input_fs.end(), std::array({{f[0], f[1], f[2], -1}}), comp); for (auto it = bounds.first; it != bounds.second; ++it) { - int f_id = (*it)[3]; + int f_id = (*it)[3]; is_face_inserted[f_id] = true; track_surface_fs[i][j].push_back(f_id); } @@ -108,32 +108,36 @@ void floatTetWild::match_surface_fs(const Mesh &mesh, } } -void floatTetWild::sort_input_faces(const std::vector &input_vertices, const std::vector &input_faces, - const Mesh &mesh, std::vector &sorted_f_ids) {///use 38416, 232368 as example //todo: think why +void floatTetWild::sort_input_faces(const std::vector& input_vertices, + const std::vector& input_faces, + const Mesh& mesh, + std::vector& sorted_f_ids) +{ /// use 38416, 232368 as example //todo: think why std::vector weights(input_faces.size()); sorted_f_ids.resize(input_faces.size()); for (int i = 0; i < input_faces.size(); i++) { sorted_f_ids[i] = i; -// //fortest -// Vector3 u = input_vertices[input_faces[i][1]] - input_vertices[input_faces[i][0]]; -// Vector3 v = input_vertices[input_faces[i][2]] - input_vertices[input_faces[i][0]]; -// if(u.cross(v).norm()/2 < SCALAR_ZERO_2) { -// cout << "degenerate input triangle!!" << endl; -// pausee(); -// } -// //fortest - -// for (int j = 0; j < 3; j++) { -// Scalar dis = -// (input_vertices[input_faces[i][j]] - input_vertices[input_faces[i][(j + 1) % 3]]).squaredNorm(); -// if (j == 0) -// weights[i] = dis; -// else if (dis > weights[i]) -// weights[i] = dis; -// } - Vector3 u = input_vertices[input_faces[i][1]] - input_vertices[input_faces[i][0]]; - Vector3 v = input_vertices[input_faces[i][2]] - input_vertices[input_faces[i][0]]; + // //fortest + // Vector3 u = input_vertices[input_faces[i][1]] - input_vertices[input_faces[i][0]]; + // Vector3 v = input_vertices[input_faces[i][2]] - input_vertices[input_faces[i][0]]; + // if(u.cross(v).norm()/2 < SCALAR_ZERO_2) { + // cout << "degenerate input triangle!!" << endl; + // pausee(); + // } + // //fortest + + // for (int j = 0; j < 3; j++) { + // Scalar dis = + // (input_vertices[input_faces[i][j]] - input_vertices[input_faces[i][(j + // + 1) % 3]]).squaredNorm(); + // if (j == 0) + // weights[i] = dis; + // else if (dis > weights[i]) + // weights[i] = dis; + // } + Vector3 u = input_vertices[input_faces[i][1]] - input_vertices[input_faces[i][0]]; + Vector3 v = input_vertices[input_faces[i][2]] - input_vertices[input_faces[i][0]]; weights[i] = u.cross(v).squaredNorm(); } @@ -141,35 +145,41 @@ void floatTetWild::sort_input_faces(const std::vector &input_vertices, return; std::random_shuffle(sorted_f_ids.begin(), sorted_f_ids.end()); -// std::sort(sorted_f_ids.begin(), sorted_f_ids.end(), [&weights](int a, int b) { -// return weights[a] < weights[b]; -// }); + // std::sort(sorted_f_ids.begin(), sorted_f_ids.end(), [&weights](int a, int b) { + // return weights[a] < weights[b]; + // }); } -void floatTetWild::insert_triangles(const std::vector &input_vertices, - const std::vector &input_faces, const std::vector &input_tags, - Mesh &mesh, std::vector &is_face_inserted, AABBWrapper &tree, bool is_again) { - insert_triangles_aux(input_vertices, input_faces, input_tags, mesh, is_face_inserted, tree, is_again); +void floatTetWild::insert_triangles(const std::vector& input_vertices, + const std::vector& input_faces, + const std::vector& input_tags, + Mesh& mesh, + std::vector& is_face_inserted, + AABBWrapper& tree, + bool is_again) +{ + insert_triangles_aux( + input_vertices, input_faces, input_tags, mesh, is_face_inserted, tree, is_again); return; if (mesh.is_input_all_inserted) return; - for (auto &v: mesh.tet_vertices) { + for (auto& v : mesh.tet_vertices) { if (v.is_removed) continue; v.is_on_surface = false; - v.is_on_bbox = false; + v.is_on_bbox = false; } // - for (auto &t: mesh.tets) { + for (auto& t : mesh.tets) { if (t.is_removed) continue; for (int j = 0; j < 4; j++) { if (t.is_surface_fs[j] <= 0) { for (int k = 0; k < 3; k++) { mesh.tet_vertices[t[(j + 1 + k) % 4]].is_on_surface = true; - mesh.tet_vertices[t[(j + 1 + k) % 4]].is_freezed = true; + mesh.tet_vertices[t[(j + 1 + k) % 4]].is_freezed = true; } } if (t.is_bbox_fs[j] != NOT_BBOX) { @@ -180,42 +190,54 @@ void floatTetWild::insert_triangles(const std::vector &input_vertices, } } // - operation(input_vertices, input_faces, input_tags, is_face_inserted, mesh, tree, + operation(input_vertices, + input_faces, + input_tags, + is_face_inserted, + mesh, + tree, std::array({{0, 1, 0, 1, 0}})); // - for (auto &v: mesh.tet_vertices) { + for (auto& v : mesh.tet_vertices) { v.is_freezed = false; } - insert_triangles_aux(input_vertices, input_faces, input_tags, mesh, is_face_inserted, tree, is_again); + insert_triangles_aux( + input_vertices, input_faces, input_tags, mesh, is_face_inserted, tree, is_again); } -void floatTetWild::optimize_non_surface(const std::vector &input_vertices, const std::vector &input_faces, - const std::vector &input_tags, std::vector &is_face_inserted, - const std::vector, 4 >>& track_surface_fs, - Mesh &mesh, AABBWrapper &tree, bool is_again) { +void floatTetWild::optimize_non_surface( + const std::vector& input_vertices, + const std::vector& input_faces, + const std::vector& input_tags, + std::vector& is_face_inserted, + const std::vector, 4>>& track_surface_fs, + Mesh& mesh, + AABBWrapper& tree, + bool is_again) +{ if (!is_again) { for (int i = 0; i < mesh.tet_vertices.size(); i++) if (i < input_vertices.size()) mesh.tet_vertices[i].is_freezed = true; } // - for (auto &v: mesh.tet_vertices) { + for (auto& v : mesh.tet_vertices) { if (v.is_removed) continue; v.is_on_surface = false; - v.is_on_bbox = false; + v.is_on_bbox = false; } // for (int i = 0; i < mesh.tets.size(); i++) { - auto &t = mesh.tets[i]; + auto& t = mesh.tets[i]; if (t.is_removed) continue; for (int j = 0; j < 4; j++) { if (t.is_surface_fs[j] <= 0) { for (int k = 0; k < 3; k++) { mesh.tet_vertices[t[(j + 1 + k) % 4]].is_on_surface = true; - mesh.tet_vertices[t[(j + 1 + k) % 4]].is_freezed = true; + mesh.tet_vertices[t[(j + 1 + k) % 4]].is_freezed = true; } } if (t.is_bbox_fs[j] != NOT_BBOX) { @@ -227,201 +249,257 @@ void floatTetWild::optimize_non_surface(const std::vector &input_vertic mesh.tet_vertices[t[(j + 1 + k) % 4]].is_freezed = true; } } -// if (t.quality == 0) -// t.quality = get_quality(mesh, t); + // if (t.quality == 0) + // t.quality = get_quality(mesh, t); } // - operation(input_vertices, input_faces, input_tags, is_face_inserted, mesh, tree, + operation(input_vertices, + input_faces, + input_tags, + is_face_inserted, + mesh, + tree, std::array({{0, 1, 1, 1, 0}})); // - for (auto &v: mesh.tet_vertices) + for (auto& v : mesh.tet_vertices) v.is_freezed = false; } -void floatTetWild::insert_triangles_aux(const std::vector &input_vertices, - const std::vector &input_faces, const std::vector &input_tags, - Mesh &mesh, std::vector &is_face_inserted, - AABBWrapper &tree, bool is_again) { - std::vector old_is_face_inserted = is_face_inserted;///is_face_inserted has been intialized in main +void floatTetWild::insert_triangles_aux(const std::vector& input_vertices, + const std::vector& input_faces, + const std::vector& input_tags, + Mesh& mesh, + std::vector& is_face_inserted, + AABBWrapper& tree, + bool is_again) +{ + std::vector old_is_face_inserted = + is_face_inserted; /// is_face_inserted has been intialized in main logger().info("triangle insertion start, #f = {}, #v = {}, #t = {}", - input_faces.size(), mesh.tet_vertices.size(), mesh.tets.size()); + input_faces.size(), + mesh.tet_vertices.size(), + mesh.tets.size()); ///// - std::vector, 4 >> track_surface_fs(mesh.tets.size()); + std::vector, 4>> track_surface_fs(mesh.tets.size()); if (!is_again) { match_surface_fs(mesh, input_vertices, input_faces, is_face_inserted, track_surface_fs); } int cnt_matched = std::count(is_face_inserted.begin(), is_face_inserted.end(), true); - logger().info("matched #f = {}, uninserted #f = {}", cnt_matched, is_face_inserted.size() - cnt_matched); + logger().info( + "matched #f = {}, uninserted #f = {}", cnt_matched, is_face_inserted.size() - cnt_matched); std::vector sorted_f_ids; sort_input_faces(input_vertices, input_faces, mesh, sorted_f_ids); ///// - std::vector new_vertices; + std::vector new_vertices; std::vector> new_tets; - int cnt_fail = 0; - int cnt_total = 0; + int cnt_fail = 0; + int cnt_total = 0; ///// -// if(!is_again) { -// std::vector> conn_fs(input_vertices.size()); -// for (int i = 0; i < input_faces.size(); i++) { -// for (int j = 0; j < 3; j++) -// conn_fs[input_faces[i][j]].push_back(i); -// } -// std::vector is_visited(input_faces.size(), false); -// std::vector ns(input_faces.size()); -// for (int i = 0; i < input_faces.size(); i++) { -// ns[i] = (input_vertices[input_faces[i][1]] - input_vertices[input_faces[i][0]]).cross( -// input_vertices[input_faces[i][2]] - input_vertices[input_faces[i][0]]).normalized(); -// } -// for (int i = 0; i < sorted_f_ids.size(); i++) { -// int f_id = sorted_f_ids[i]; -// if (is_face_inserted[f_id]) -// continue; -// -// std::vector f_ids; -// if (insert_multi_triangles(f_id, input_vertices, input_faces, input_tags, -// conn_fs, ns, is_visited, f_ids, -// mesh, track_surface_fs, tree, is_again)) { -// for (int inserted_f_id: f_ids) -// is_face_inserted[inserted_f_id] = true; -// } else -// cnt_total += f_ids.size(); -// cnt_total += f_ids.size(); -// } -// logger().info("insert_multi_triangles * n done, #v = {}, #t = {}", mesh.tet_vertices.size(), mesh.tets.size()); -// logger().info("uninserted #f = {}/{}", std::count(is_face_inserted.begin(), is_face_inserted.end(), false), -// is_face_inserted.size() - cnt_matched); -// } + // if(!is_again) { + // std::vector> conn_fs(input_vertices.size()); + // for (int i = 0; i < input_faces.size(); i++) { + // for (int j = 0; j < 3; j++) + // conn_fs[input_faces[i][j]].push_back(i); + // } + // std::vector is_visited(input_faces.size(), false); + // std::vector ns(input_faces.size()); + // for (int i = 0; i < input_faces.size(); i++) { + // ns[i] = (input_vertices[input_faces[i][1]] - + // input_vertices[input_faces[i][0]]).cross( + // input_vertices[input_faces[i][2]] - + // input_vertices[input_faces[i][0]]).normalized(); + // } + // for (int i = 0; i < sorted_f_ids.size(); i++) { + // int f_id = sorted_f_ids[i]; + // if (is_face_inserted[f_id]) + // continue; + // + // std::vector f_ids; + // if (insert_multi_triangles(f_id, input_vertices, input_faces, input_tags, + // conn_fs, ns, is_visited, f_ids, + // mesh, track_surface_fs, tree, is_again)) { + // for (int inserted_f_id: f_ids) + // is_face_inserted[inserted_f_id] = true; + // } else + // cnt_total += f_ids.size(); + // cnt_total += f_ids.size(); + // } + // logger().info("insert_multi_triangles * n done, #v = {}, #t = {}", + // mesh.tet_vertices.size(), mesh.tets.size()); logger().info("uninserted #f = {}/{}", + // std::count(is_face_inserted.begin(), is_face_inserted.end(), false), + // is_face_inserted.size() - cnt_matched); + // } ////// for (int i = 0; i < sorted_f_ids.size(); i++) { - //fortest + // fortest if (!is_again && i > 0 && i % 1000 == 0) { logger().debug("inserting f{}... {} failed", i, cnt_fail); logger().debug("snapped {}/{}", cnt_snapped, cnt_total); logger().debug("\t- time_find_cutting_tets = {}s (total {}s)", - time_find_cutting_tets - old_time_find_cutting_tets, time_find_cutting_tets); -// logger().info("\t\t- time_find_cutting_tets1 = {}s", time_find_cutting_tets1); -// logger().info("\t\t- time_find_cutting_tets2 = {}s", time_find_cutting_tets2); -// logger().info("\t\t- time_find_cutting_tets3 = {}s", time_find_cutting_tets3); -// logger().info("\t\t- time_find_cutting_tets4 = {}s", time_find_cutting_tets4); + time_find_cutting_tets - old_time_find_cutting_tets, + time_find_cutting_tets); + // logger().info("\t\t- time_find_cutting_tets1 = {}s", + // time_find_cutting_tets1); logger().info("\t\t- time_find_cutting_tets2 = + // {}s", time_find_cutting_tets2); logger().info("\t\t- + // time_find_cutting_tets3 = {}s", time_find_cutting_tets3); + // logger().info("\t\t- time_find_cutting_tets4 = {}s", + // time_find_cutting_tets4); logger().debug("\t- time_cut_mesh = {}s (total {}s)", - time_cut_mesh - old_time_cut_mesh, time_cut_mesh); -// logger().info("\t\t- time_cut_mesh1 = {}s", time_cut_mesh1); -// logger().info("\t\t- time_cut_mesh2 = {}s", time_cut_mesh2); -// print_times1(); - logger().debug("\t- time_get_intersecting_edges_and_points = {}s (total {}s)", - time_get_intersecting_edges_and_points - old_time_get_intersecting_edges_and_points, - time_get_intersecting_edges_and_points); + time_cut_mesh - old_time_cut_mesh, + time_cut_mesh); + // logger().info("\t\t- time_cut_mesh1 = {}s", time_cut_mesh1); + // logger().info("\t\t- time_cut_mesh2 = {}s", time_cut_mesh2); + // print_times1(); + logger().debug( + "\t- time_get_intersecting_edges_and_points = {}s (total {}s)", + time_get_intersecting_edges_and_points - old_time_get_intersecting_edges_and_points, + time_get_intersecting_edges_and_points); print_times1(); logger().debug("\t- time_subdivide_tets = {}s (total {}s)", - time_subdivide_tets - old_time_subdivide_tets, time_subdivide_tets); + time_subdivide_tets - old_time_subdivide_tets, + time_subdivide_tets); logger().debug("\t- time_push_new_tets = {}s (total {}s)", - time_push_new_tets - old_time_push_new_tets, time_push_new_tets); -// logger().info("\t\t- time_push_new_tets1 = {}s", time_push_new_tets1); -// logger().info("\t\t- time_push_new_tets2 = {}s", time_push_new_tets2); -// logger().info("\t\t- time_push_new_tets3 = {}s", time_push_new_tets3); + time_push_new_tets - old_time_push_new_tets, + time_push_new_tets); + // logger().info("\t\t- time_push_new_tets1 = {}s", time_push_new_tets1); + // logger().info("\t\t- time_push_new_tets2 = {}s", time_push_new_tets2); + // logger().info("\t\t- time_push_new_tets3 = {}s", time_push_new_tets3); logger().debug("\t- time_simplify_subdivision_result = {}s (total {}s)", - time_simplify_subdivision_result - old_time_simplify_subdivision_result, - time_simplify_subdivision_result); + time_simplify_subdivision_result - old_time_simplify_subdivision_result, + time_simplify_subdivision_result); - old_time_find_cutting_tets = time_find_cutting_tets; - old_time_cut_mesh = time_cut_mesh; + old_time_find_cutting_tets = time_find_cutting_tets; + old_time_cut_mesh = time_cut_mesh; old_time_get_intersecting_edges_and_points = time_get_intersecting_edges_and_points; - old_time_subdivide_tets = time_subdivide_tets; - old_time_push_new_tets = time_push_new_tets; - old_time_simplify_subdivision_result = time_simplify_subdivision_result; + old_time_subdivide_tets = time_subdivide_tets; + old_time_push_new_tets = time_push_new_tets; + old_time_simplify_subdivision_result = time_simplify_subdivision_result; logger().debug("#v = {}/{}", mesh.get_v_num(), mesh.tet_vertices.size()); logger().debug("#t = {}/{}", mesh.get_t_num(), mesh.tets.size()); } - //fortest - -// //fortest -// if(i>0 && i%10000 == 0) { -// logger().info("before opt"); -// logger().info("#v = {}/{}", mesh.get_v_num(), mesh.tet_vertices.size()); -// logger().info("#t = {}/{}", mesh.get_t_num(), mesh.tets.size()); -// optimize_non_surface(input_vertices, input_faces, input_tags, is_face_inserted, track_surface_fs, -// mesh, tree, is_again); -// logger().info("after opt"); -// logger().info("#v = {}/{}", mesh.get_v_num(), mesh.tet_vertices.size()); -// logger().info("#t = {}/{}", mesh.get_t_num(), mesh.tets.size()); -// } -// //fortest + // fortest + + // //fortest + // if(i>0 && i%10000 == 0) { + // logger().info("before opt"); + // logger().info("#v = {}/{}", mesh.get_v_num(), mesh.tet_vertices.size()); + // logger().info("#t = {}/{}", mesh.get_t_num(), mesh.tets.size()); + // optimize_non_surface(input_vertices, input_faces, input_tags, + // is_face_inserted, track_surface_fs, + // mesh, tree, is_again); + // logger().info("after opt"); + // logger().info("#v = {}/{}", mesh.get_v_num(), mesh.tet_vertices.size()); + // logger().info("#t = {}/{}", mesh.get_t_num(), mesh.tets.size()); + // } + // //fortest int f_id = sorted_f_ids[i]; if (is_face_inserted[f_id]) continue; cnt_total++; - if (insert_one_triangle(f_id, input_vertices, input_faces, input_tags, mesh, track_surface_fs, - tree, is_again)) + if (insert_one_triangle(f_id, + input_vertices, + input_faces, + input_tags, + mesh, + track_surface_fs, + tree, + is_again)) is_face_inserted[f_id] = true; else cnt_fail++; -// pausee();//fortest + // pausee();//fortest if (f_id == III) - break;//fortest + break; // fortest } - logger().info("insert_one_triangle * n done, #v = {}, #t = {}", mesh.tet_vertices.size(), mesh.tets.size()); - logger().info("uninserted #f = {}/{}", std::count(is_face_inserted.begin(), is_face_inserted.end(), false), + logger().info( + "insert_one_triangle * n done, #v = {}, #t = {}", mesh.tet_vertices.size(), mesh.tets.size()); + logger().info("uninserted #f = {}/{}", + std::count(is_face_inserted.begin(), is_face_inserted.end(), false), is_face_inserted.size() - cnt_matched); - logger().info("total timing: {}s", time_find_cutting_tets + time_cut_mesh + time_get_intersecting_edges_and_points + - time_subdivide_tets + time_push_new_tets); + logger().info("total timing: {}s", + time_find_cutting_tets + time_cut_mesh + time_get_intersecting_edges_and_points + + time_subdivide_tets + time_push_new_tets); pair_track_surface_fs(mesh, track_surface_fs); logger().info("pair_track_surface_fs done"); - ///// - std::vector> b_edges1; + std::vector> b_edges1; std::vector, std::vector>> b_edge_infos; - std::vector is_on_cut_edges; - find_boundary_edges(input_vertices, input_faces, is_face_inserted, old_is_face_inserted, - b_edge_infos, is_on_cut_edges, b_edges1); + std::vector is_on_cut_edges; + find_boundary_edges(input_vertices, + input_faces, + is_face_inserted, + old_is_face_inserted, + b_edge_infos, + is_on_cut_edges, + b_edges1); logger().info("find_boundary_edges done"); std::vector> known_surface_fs; std::vector> known_not_surface_fs; - insert_boundary_edges(input_vertices, input_faces, b_edge_infos, is_on_cut_edges, track_surface_fs, mesh, tree, - is_face_inserted, is_again, known_surface_fs, known_not_surface_fs); - logger().info("uninserted #f = {}/{}", std::count(is_face_inserted.begin(), is_face_inserted.end(), false), + insert_boundary_edges(input_vertices, + input_faces, + b_edge_infos, + is_on_cut_edges, + track_surface_fs, + mesh, + tree, + is_face_inserted, + is_again, + known_surface_fs, + known_not_surface_fs); + logger().info("uninserted #f = {}/{}", + std::count(is_face_inserted.begin(), is_face_inserted.end(), false), is_face_inserted.size() - cnt_matched); - //fortest + // fortest check_track_surface_fs(mesh, track_surface_fs, input_vertices, input_faces, sorted_f_ids); - //fortest + // fortest ///// std::vector> b_edges2; - mark_surface_fs(input_vertices, input_faces, input_tags, track_surface_fs, is_face_inserted, - known_surface_fs, known_not_surface_fs, b_edges2, mesh, tree); - //fortest: output and check -// output_surface(mesh, mesh.params.output_path+"_"+mesh.params.postfix+"_surface.stl"); + mark_surface_fs(input_vertices, + input_faces, + input_tags, + track_surface_fs, + is_face_inserted, + known_surface_fs, + known_not_surface_fs, + b_edges2, + mesh, + tree); + // fortest: output and check + // output_surface(mesh, mesh.params.output_path+"_"+mesh.params.postfix+"_surface.stl"); logger().info("mark_surface_fs done"); ///// - //build b_tree using b_edges + // build b_tree using b_edges tree.init_tmp_b_mesh_and_tree(input_vertices, input_faces, b_edges1, mesh, b_edges2); -// for (int v_id = 0; v_id < mesh.tet_vertices.size(); v_id++) { -// if (mesh.tet_vertices[v_id].is_removed) -// continue; -// if (!mesh.tet_vertices[v_id].is_on_boundary) -// continue; -// -// GEO::index_t prev_facet; -// if (tree.is_out_tmp_b_envelope(mesh.tet_vertices[v_id].pos, mesh.params.eps_2, prev_facet)) -// mesh.tet_vertices[v_id].is_on_boundary = false; -// } + // for (int v_id = 0; v_id < mesh.tet_vertices.size(); v_id++) { + // if (mesh.tet_vertices[v_id].is_removed) + // continue; + // if (!mesh.tet_vertices[v_id].is_on_boundary) + // continue; + // + // GEO::index_t prev_facet; + // if (tree.is_out_tmp_b_envelope(mesh.tet_vertices[v_id].pos, mesh.params.eps_2, + // prev_facet)) + // mesh.tet_vertices[v_id].is_on_boundary = false; + // } #ifdef FLOAT_TETWILD_USE_TBB - tbb::parallel_for(size_t(0), mesh.tets.size(), [&](size_t i){ - auto &t = mesh.tets[i]; + oneapi::tbb::parallel_for(size_t(0), mesh.tets.size(), [&](size_t i) { + auto& t = mesh.tets[i]; #else - for (auto &t:mesh.tets) { + for (auto& t : mesh.tets) { #endif if (!t.is_removed) { t.quality = get_quality(mesh, t); @@ -436,56 +514,64 @@ void floatTetWild::insert_triangles_aux(const std::vector &input_vertic mesh.is_input_all_inserted = true; logger().info("#b_edge1 = {}, #b_edges2 = {}", b_edges1.size(), b_edges2.size()); -// ///fortest -// Eigen::MatrixXd V(input_vertices.size(), 3); -// Eigen::MatrixXi F(std::count(is_face_inserted.begin(), is_face_inserted.end(), false), 3); -// for (int i = 0; i < input_vertices.size(); i++) -// V.row(i) = input_vertices[i]; -// int cnt = 0; -// for (int i = 0; i < input_faces.size(); i++) { -// if (is_face_inserted[i]) -// continue; -// F.row(cnt) << input_faces[i][0], input_faces[i][1], input_faces[i][2]; -// cnt++; -// } -// igl::writeSTL(mesh.params.output_path+"_"+mesh.params.postfix+"_uninserted.stl", V, F); -// // -// std::ofstream fout(mesh.params.output_path+"_"+mesh.params.postfix+"_b_es.obj"); -// for(int i=0;i &input_vertices, - const std::vector &input_faces, const std::vector &input_tags, - const std::vector>& conn_fs, - const std::vector &ns, std::vector & is_visited, std::vector& f_ids, - Mesh &mesh, std::vector, 4>> &track_surface_fs, - AABBWrapper &tree, bool is_again){ +bool floatTetWild::insert_multi_triangles( + int insert_f_id, + const std::vector& input_vertices, + const std::vector& input_faces, + const std::vector& input_tags, + const std::vector>& conn_fs, + const std::vector& ns, + std::vector& is_visited, + std::vector& f_ids, + Mesh& mesh, + std::vector, 4>>& track_surface_fs, + AABBWrapper& tree, + bool is_again) +{ std::array vs = {{input_vertices[input_faces[insert_f_id][0]], - input_vertices[input_faces[insert_f_id][1]], - input_vertices[input_faces[insert_f_id][2]]}}; - const auto& n = ns[insert_f_id]; - int t = get_t(vs[0], vs[1], vs[2]); + input_vertices[input_faces[insert_f_id][1]], + input_vertices[input_faces[insert_f_id][2]]}}; + const auto& n = ns[insert_f_id]; + int t = get_t(vs[0], vs[1], vs[2]); f_ids.push_back(insert_f_id); std::queue f_queue; f_queue.push(insert_f_id); - while(!f_queue.empty()){ + while (!f_queue.empty()) { int f_id = f_queue.front(); f_queue.pop(); - for(int j=0;j<3;j++){ - for(int n_f_id: conn_fs[input_faces[f_id][j]]) { + for (int j = 0; j < 3; j++) { + for (int n_f_id : conn_fs[input_faces[f_id][j]]) { if (is_visited[n_f_id] || abs(ns[n_f_id].dot(n) - 1) > 1e-6) continue; is_visited[n_f_id] = true; @@ -495,17 +581,17 @@ bool floatTetWild::insert_multi_triangles(int insert_f_id, const std::vector points; + // if (cut_mesh.snap_to_plane()) { + // cnt_snapped++; + // cut_mesh.project_to_plane(input_vertices.size()); + //// cut_mesh.expand_new(cut_t_ids); + //// cut_mesh.project_to_plane(input_vertices.size()); + // } + + std::vector points; std::map, int> map_edge_to_intersecting_point; - std::vector subdivide_t_ids; - if (!cut_mesh.get_intersecting_edges_and_points(points, map_edge_to_intersecting_point, subdivide_t_ids)) { -// cout<<"fail 1"< subdivide_t_ids; + if (!cut_mesh.get_intersecting_edges_and_points( + points, map_edge_to_intersecting_point, subdivide_t_ids)) { + // cout<<"fail 1"< tmp; - std::set_difference(subdivide_t_ids.begin(), subdivide_t_ids.end(), cut_t_ids.begin(), cut_t_ids.end(), + std::set_difference(subdivide_t_ids.begin(), + subdivide_t_ids.end(), + cut_t_ids.begin(), + cut_t_ids.end(), std::back_inserter(tmp)); std::vector is_mark_surface(cut_t_ids.size(), true); cut_t_ids.insert(cut_t_ids.end(), tmp.begin(), tmp.end()); is_mark_surface.resize(is_mark_surface.size() + tmp.size(), false); - std::vector new_tets; + std::vector new_tets; std::vector, 4>> new_track_surface_fs; - std::vector modified_t_ids; - if (!subdivide_tets(insert_f_id, mesh, cut_mesh, points, map_edge_to_intersecting_point, track_surface_fs, - cut_t_ids, is_mark_surface, - new_tets, new_track_surface_fs, modified_t_ids)) { -// cout<<"fail 2"< modified_t_ids; + if (!subdivide_tets(insert_f_id, + mesh, + cut_mesh, + points, + map_edge_to_intersecting_point, + track_surface_fs, + cut_t_ids, + is_mark_surface, + new_tets, + new_track_surface_fs, + modified_t_ids)) { + // cout<<"fail 2"< &input_vertices, - const std::vector &input_faces, const std::vector &input_tags, - Mesh &mesh, std::vector, 4>>& track_surface_fs, - AABBWrapper &tree, bool is_again) { -// igl::Timer timer; +bool floatTetWild::insert_one_triangle( + int insert_f_id, + const std::vector& input_vertices, + const std::vector& input_faces, + const std::vector& input_tags, + Mesh& mesh, + std::vector, 4>>& track_surface_fs, + AABBWrapper& tree, + bool is_again) +{ + // igl::Timer timer; std::array vs = {{input_vertices[input_faces[insert_f_id][0]], - input_vertices[input_faces[insert_f_id][1]], - input_vertices[input_faces[insert_f_id][2]]}}; - Vector3 n = (vs[1] - vs[0]).cross(vs[2] - vs[0]); + input_vertices[input_faces[insert_f_id][1]], + input_vertices[input_faces[insert_f_id][2]]}}; + Vector3 n = (vs[1] - vs[0]).cross(vs[2] - vs[0]); n.normalize(); int t = get_t(vs[0], vs[1], vs[2]); ///// -// timer.start(); + // timer.start(); std::vector cut_t_ids; find_cutting_tets(insert_f_id, input_vertices, input_faces, vs, mesh, cut_t_ids, is_again); -// time_find_cutting_tets += timer.getElapsedTime(); + // time_find_cutting_tets += timer.getElapsedTime(); - //fortest + // fortest myassert(!cut_t_ids.empty(), "cut_t_ids.empty()!!!"); if (cut_t_ids.empty()) { cout << get_area(vs[0], vs[1], vs[2]) << endl; - cout << "f" << insert_f_id << ": " << input_faces[insert_f_id][0] << " " << input_faces[insert_f_id][1] - << " " << input_faces[insert_f_id][2] << endl; + cout << "f" << insert_f_id << ": " << input_faces[insert_f_id][0] << " " + << input_faces[insert_f_id][1] << " " << input_faces[insert_f_id][2] << endl; pausee(); return false; } - //fortest + // fortest ///// -// timer.start(); -// igl::Timer timer1; -// timer1.start(); + // timer.start(); + // igl::Timer timer1; + // timer1.start(); CutMesh cut_mesh(mesh, n, vs); cut_mesh.construct(cut_t_ids); -// time_cut_mesh1 += timer1.getElapsedTime(); -// timer1.start(); -// bool is_expanded = false;//fortest + // time_cut_mesh1 += timer1.getElapsedTime(); + // timer1.start(); + // bool is_expanded = false;//fortest if (cut_mesh.snap_to_plane()) { cnt_snapped++; cut_mesh.project_to_plane(input_vertices.size()); cut_mesh.expand_new(cut_t_ids); cut_mesh.project_to_plane(input_vertices.size()); - //fortest -// int cnt_proj = cut_mesh.project_to_plane(input_vertices.size()); -// int cnt_all = std::count(cut_mesh.is_snapped.begin(), cut_mesh.is_snapped.end(), true); -// if (cnt_proj != cnt_all) -// cout << cnt_proj << "/" << cnt_all << endl; - //fortest + // fortest + // int cnt_proj = cut_mesh.project_to_plane(input_vertices.size()); + // int cnt_all = std::count(cut_mesh.is_snapped.begin(), cut_mesh.is_snapped.end(), + // true); if (cnt_proj != cnt_all) + // cout << cnt_proj << "/" << cnt_all << endl; + // fortest } -// time_cut_mesh2 += timer1.getElapsedTime(); -// time_cut_mesh += timer.getElapsedTime(); + // time_cut_mesh2 += timer1.getElapsedTime(); + // time_cut_mesh += timer.getElapsedTime(); ///// -// timer.start(); - std::vector points; + // timer.start(); + std::vector points; std::map, int> map_edge_to_intersecting_point; - std::vector subdivide_t_ids; - if (!cut_mesh.get_intersecting_edges_and_points(points, map_edge_to_intersecting_point, subdivide_t_ids)) { -// time_get_intersecting_edges_and_points += timer.getElapsedTime(); - if(is_again){ - if(is_uninserted_face_covered(insert_f_id, input_vertices, input_faces, cut_t_ids, mesh)) + std::vector subdivide_t_ids; + if (!cut_mesh.get_intersecting_edges_and_points( + points, map_edge_to_intersecting_point, subdivide_t_ids)) { + // time_get_intersecting_edges_and_points += timer.getElapsedTime(); + if (is_again) { + if (is_uninserted_face_covered( + insert_f_id, input_vertices, input_faces, cut_t_ids, mesh)) return true; } - cout<<"FAIL get_intersecting_edges_and_points"< tmp; - std::set_difference(subdivide_t_ids.begin(), subdivide_t_ids.end(), cut_t_ids.begin(), cut_t_ids.end(), + std::set_difference(subdivide_t_ids.begin(), + subdivide_t_ids.end(), + cut_t_ids.begin(), + cut_t_ids.end(), std::back_inserter(tmp)); std::vector is_mark_surface(cut_t_ids.size(), true); cut_t_ids.insert(cut_t_ids.end(), tmp.begin(), tmp.end()); is_mark_surface.resize(is_mark_surface.size() + tmp.size(), false); -// cout << "cut_mesh.get_intersecting_edges_and_points OK" << endl; -// time_get_intersecting_edges_and_points += timer.getElapsedTime(); + // cout << "cut_mesh.get_intersecting_edges_and_points OK" << endl; + // time_get_intersecting_edges_and_points += timer.getElapsedTime(); ///// -// timer.start(); - std::vector new_tets; + // timer.start(); + std::vector new_tets; std::vector, 4>> new_track_surface_fs; - std::vector modified_t_ids; - if (!subdivide_tets(insert_f_id, mesh, cut_mesh, points, map_edge_to_intersecting_point, track_surface_fs, - cut_t_ids, is_mark_surface, - new_tets, new_track_surface_fs, modified_t_ids)) { -// time_subdivide_tets += timer.getElapsedTime(); - if(is_again){ - if(is_uninserted_face_covered(insert_f_id, input_vertices, input_faces, cut_t_ids, mesh)) + std::vector modified_t_ids; + if (!subdivide_tets(insert_f_id, + mesh, + cut_mesh, + points, + map_edge_to_intersecting_point, + track_surface_fs, + cut_t_ids, + is_mark_surface, + new_tets, + new_track_surface_fs, + modified_t_ids)) { + // time_subdivide_tets += timer.getElapsedTime(); + if (is_again) { + if (is_uninserted_face_covered( + insert_f_id, input_vertices, input_faces, cut_t_ids, mesh)) return true; } - cout<<"FAIL subdivide_tets"<, 4>> &track_surface_fs, - std::vector &points, std::vector &new_tets, - std::vector, 4>> &new_track_surface_fs, - std::vector &modified_t_ids, bool is_again) { -// igl::Timer timer; -// timer.start(); - ///vs +void floatTetWild::push_new_tets(Mesh& mesh, + std::vector, 4>>& track_surface_fs, + std::vector& points, + std::vector& new_tets, + std::vector, 4>>& new_track_surface_fs, + std::vector& modified_t_ids, + bool is_again) +{ + // igl::Timer timer; + // timer.start(); + /// vs const int old_v_size = mesh.tet_vertices.size(); mesh.tet_vertices.resize(mesh.tet_vertices.size() + points.size()); for (int i = 0; i < points.size(); i++) { mesh.tet_vertices[old_v_size + i].pos = points[i]; - //todo: tags??? + // todo: tags??? } -// time_push_new_tets1 += timer.getElapsedTime(); + // time_push_new_tets1 += timer.getElapsedTime(); - ///tets -// timer.start(); -// mesh.tets.reserve(mesh.tets.size() + new_tets.size() - modified_t_ids.size()); -// time_push_new_tets2 += timer.getElapsedTime(); + /// tets + // timer.start(); + // mesh.tets.reserve(mesh.tets.size() + new_tets.size() - modified_t_ids.size()); + // time_push_new_tets2 += timer.getElapsedTime(); -// timer.start(); + // timer.start(); for (int i = 0; i < new_tets.size(); i++) { -// if (is_again) -// new_tets[i].quality = get_quality(mesh, new_tets[i]); + // if (is_again) + // new_tets[i].quality = get_quality(mesh, new_tets[i]); if (i < modified_t_ids.size()) { for (int j = 0; j < 4; j++) { - vector_erase(mesh.tet_vertices[mesh.tets[modified_t_ids[i]][j]].conn_tets, modified_t_ids[i]); + vector_erase(mesh.tet_vertices[mesh.tets[modified_t_ids[i]][j]].conn_tets, + modified_t_ids[i]); } - mesh.tets[modified_t_ids[i]] = new_tets[i]; + mesh.tets[modified_t_ids[i]] = new_tets[i]; track_surface_fs[modified_t_ids[i]] = new_track_surface_fs[i]; for (int j = 0; j < 4; j++) { - mesh.tet_vertices[mesh.tets[modified_t_ids[i]][j]].conn_tets.push_back(modified_t_ids[i]); - } - } else { -// mesh.tets.push_back(new_tets[i]); -// track_surface_fs.push_back(new_track_surface_fs[i]); -// for (int j = 0; j < 4; j++) { -// mesh.tet_vertices[mesh.tets.back()[j]].conn_tets.push_back(mesh.tets.size() - 1); -// } + mesh.tet_vertices[mesh.tets[modified_t_ids[i]][j]].conn_tets.push_back( + modified_t_ids[i]); + } + } + else { + // mesh.tets.push_back(new_tets[i]); + // track_surface_fs.push_back(new_track_surface_fs[i]); + // for (int j = 0; j < 4; j++) { + // mesh.tet_vertices[mesh.tets.back()[j]].conn_tets.push_back(mesh.tets.size() + // - 1); + // } for (int j = 0; j < 4; j++) { - mesh.tet_vertices[new_tets[i][j]].conn_tets.push_back(mesh.tets.size() + i - modified_t_ids.size()); + mesh.tet_vertices[new_tets[i][j]].conn_tets.push_back(mesh.tets.size() + i - + modified_t_ids.size()); } } - //todo: tags??? + // todo: tags??? } -// time_push_new_tets2 += timer.getElapsedTime(); + // time_push_new_tets2 += timer.getElapsedTime(); -// timer.start(); + // timer.start(); mesh.tets.insert(mesh.tets.end(), new_tets.begin() + modified_t_ids.size(), new_tets.end()); - track_surface_fs.insert(track_surface_fs.end(), new_track_surface_fs.begin() + modified_t_ids.size(), + track_surface_fs.insert(track_surface_fs.end(), + new_track_surface_fs.begin() + modified_t_ids.size(), new_track_surface_fs.end()); modified_t_ids.clear(); -// time_push_new_tets3 += timer.getElapsedTime(); + // time_push_new_tets3 += timer.getElapsedTime(); } #include -void floatTetWild::simplify_subdivision_result(int insert_f_id, int input_v_size, Mesh &mesh, AABBWrapper &tree, - std::vector, 4>> &track_surface_fs) { - if(covered_tet_fs.empty()) +void floatTetWild::simplify_subdivision_result( + int insert_f_id, + int input_v_size, + Mesh& mesh, + AABBWrapper& tree, + std::vector, 4>>& track_surface_fs) +{ + if (covered_tet_fs.empty()) return; for (int i = 0; i < covered_tet_fs.size(); i++) @@ -750,24 +885,26 @@ void floatTetWild::simplify_subdivision_result(int insert_f_id, int input_v_size edges.push_back({{f[(j + 1) % 3], f[j], i}}); } } - std::sort(edges.begin(), edges.end(), [](const std::array &a, const std::array &b) { - return std::make_tuple(a[0], a[1]) < std::make_tuple(b[0], b[1]); - }); + std::sort( + edges.begin(), edges.end(), [](const std::array& a, const std::array& b) { + return std::make_tuple(a[0], a[1]) < std::make_tuple(b[0], b[1]); + }); // std::unordered_set freezed_v_ids; - bool is_duplicated = false; + bool is_duplicated = false; for (int i = 0; i < edges.size() - 1; i++) { - if(edges[i][0], cmp_s> ec_queue; - for (const auto &e:edges) { + for (const auto& e : edges) { Scalar l_2 = get_edge_length_2(mesh, e[0], e[1]); if (freezed_v_ids.find(e[0]) == freezed_v_ids.end()) ec_queue.push(ElementInQueue({{e[0], e[1]}}, l_2)); @@ -788,22 +925,22 @@ void floatTetWild::simplify_subdivision_result(int insert_f_id, int input_v_size ec_queue.push(ElementInQueue({{e[1], e[0]}}, l_2)); } // - if(ec_queue.empty()) + if (ec_queue.empty()) return; // std::unordered_set all_v_ids; - for (const auto &e:edges) { + for (const auto& e : edges) { all_v_ids.insert(e[0]); all_v_ids.insert(e[1]); } // - int _ts = 0; + int _ts = 0; std::vector _tet_tss; - bool is_update_tss = false; - int cnt_suc = 0; + bool is_update_tss = false; + int cnt_suc = 0; while (!ec_queue.empty()) { - std::array v_ids = ec_queue.top().v_ids; - Scalar old_weight = ec_queue.top().weight; + std::array v_ids = ec_queue.top().v_ids; + Scalar old_weight = ec_queue.top().weight; ec_queue.pop(); while (!ec_queue.empty()) { @@ -821,14 +958,17 @@ void floatTetWild::simplify_subdivision_result(int insert_f_id, int input_v_size if (weight != old_weight) continue; - //check track_surface_fs - int v1_id = v_ids[0]; - int v2_id = v_ids[1]; + // check track_surface_fs + int v1_id = v_ids[0]; + int v2_id = v_ids[1]; bool is_valid = true; - for (int t_id: mesh.tet_vertices[v1_id].conn_tets) { + for (int t_id : mesh.tet_vertices[v1_id].conn_tets) { for (int j = 0; j < 4; j++) { - if ((!track_surface_fs[t_id][j].empty() && !vector_contains(track_surface_fs[t_id][j], insert_f_id)) - || (mesh.tets[t_id][j] != v1_id && (mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE || mesh.tets[t_id].is_bbox_fs[j] != NOT_BBOX))) { + if ((!track_surface_fs[t_id][j].empty() && + !vector_contains(track_surface_fs[t_id][j], insert_f_id)) || + (mesh.tets[t_id][j] != v1_id && + (mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE || + mesh.tets[t_id].is_bbox_fs[j] != NOT_BBOX))) { is_valid = false; break; } @@ -840,17 +980,25 @@ void floatTetWild::simplify_subdivision_result(int insert_f_id, int input_v_size continue; std::vector> new_edges; - static const bool is_check_quality = true; - auto v1_conn_tets = mesh.tet_vertices[v1_id].conn_tets; - for (int t_id: mesh.tet_vertices[v1_id].conn_tets) { -// if(mesh.tets[t_id].quality == 0) - mesh.tets[t_id].quality = get_quality(mesh, t_id); - } - int result = collapse_an_edge(mesh, v_ids[0], v_ids[1], tree, new_edges, _ts, _tet_tss, - is_check_quality, is_update_tss); + static const bool is_check_quality = true; + auto v1_conn_tets = mesh.tet_vertices[v1_id].conn_tets; + for (int t_id : mesh.tet_vertices[v1_id].conn_tets) { + // if(mesh.tets[t_id].quality == 0) + mesh.tets[t_id].quality = get_quality(mesh, t_id); + } + int result = collapse_an_edge(mesh, + v_ids[0], + v_ids[1], + tree, + new_edges, + _ts, + _tet_tss, + is_check_quality, + is_update_tss); if (result > 0) { - for(const auto& e: new_edges){ - if(all_v_ids.find(e[0]) == all_v_ids.end() || all_v_ids.find(e[1]) == all_v_ids.end()) + for (const auto& e : new_edges) { + if (all_v_ids.find(e[0]) == all_v_ids.end() || + all_v_ids.find(e[1]) == all_v_ids.end()) continue; Scalar l_2 = get_edge_length_2(mesh, e[0], e[1]); if (freezed_v_ids.find(e[0]) == freezed_v_ids.end()) @@ -861,93 +1009,109 @@ void floatTetWild::simplify_subdivision_result(int insert_f_id, int input_v_size cnt_suc++; } -// //// -// std::vector n12_t_ids; -// set_intersection(mesh.tet_vertices[v1_id].conn_tets, mesh.tet_vertices[v2_id].conn_tets, n12_t_ids); -// std::vector n1_t_ids;//v1.conn_tets - n12_t_ids -// std::sort(mesh.tet_vertices[v1_id].conn_tets.begin(), mesh.tet_vertices[v1_id].conn_tets.end()); -// std::sort(n12_t_ids.begin(), n12_t_ids.end()); -// std::set_difference(mesh.tet_vertices[v1_id].conn_tets.begin(), mesh.tet_vertices[v1_id].conn_tets.end(), -// n12_t_ids.begin(), n12_t_ids.end(), std::back_inserter(n1_t_ids)); -// -// //inversion -// std::vector js_n1_t_ids; -// for (int t_id:n1_t_ids) { -// int j = mesh.tets[t_id].find(v1_id); -// js_n1_t_ids.push_back(j); -// if (is_inverted(mesh, t_id, j, mesh.tet_vertices[v2_id].pos)) { -// is_valid = false; -// break; -// } -// } -// if (!is_valid) -// continue; -// -// //check quality -// //todo -// -// //real update -// mesh.tet_vertices[v2_id].pos = mesh.tet_vertices[v1_id].pos; -// int ii = 0; -// for (int t_id:n1_t_ids) { -// int j = js_n1_t_ids[ii++]; -// mesh.tets[t_id][j] = v2_id; -// mesh.tet_vertices[v2_id].conn_tets.push_back(t_id); -// } -// for (int t_id: n12_t_ids) { -// mesh.tets[t_id].is_removed = true; -// for (int j = 0; j < 4; j++) { -// if (mesh.tets[t_id][j] != v1_id) -// vector_erase(mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets, t_id); -// } -// } -// mesh.tet_vertices[v1_id].is_removed = true; -// mesh.tet_vertices[v1_id].conn_tets.clear(); -// -// cnt_suc++; + // //// + // std::vector n12_t_ids; + // set_intersection(mesh.tet_vertices[v1_id].conn_tets, + // mesh.tet_vertices[v2_id].conn_tets, n12_t_ids); std::vector + // n1_t_ids;//v1.conn_tets - n12_t_ids + // std::sort(mesh.tet_vertices[v1_id].conn_tets.begin(), + // mesh.tet_vertices[v1_id].conn_tets.end()); std::sort(n12_t_ids.begin(), + // n12_t_ids.end()); std::set_difference(mesh.tet_vertices[v1_id].conn_tets.begin(), + // mesh.tet_vertices[v1_id].conn_tets.end(), + // n12_t_ids.begin(), n12_t_ids.end(), + // std::back_inserter(n1_t_ids)); + // + // //inversion + // std::vector js_n1_t_ids; + // for (int t_id:n1_t_ids) { + // int j = mesh.tets[t_id].find(v1_id); + // js_n1_t_ids.push_back(j); + // if (is_inverted(mesh, t_id, j, mesh.tet_vertices[v2_id].pos)) { + // is_valid = false; + // break; + // } + // } + // if (!is_valid) + // continue; + // + // //check quality + // //todo + // + // //real update + // mesh.tet_vertices[v2_id].pos = mesh.tet_vertices[v1_id].pos; + // int ii = 0; + // for (int t_id:n1_t_ids) { + // int j = js_n1_t_ids[ii++]; + // mesh.tets[t_id][j] = v2_id; + // mesh.tet_vertices[v2_id].conn_tets.push_back(t_id); + // } + // for (int t_id: n12_t_ids) { + // mesh.tets[t_id].is_removed = true; + // for (int j = 0; j < 4; j++) { + // if (mesh.tets[t_id][j] != v1_id) + // vector_erase(mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets, t_id); + // } + // } + // mesh.tet_vertices[v1_id].is_removed = true; + // mesh.tet_vertices[v1_id].conn_tets.clear(); + // + // cnt_suc++; } -// if (cnt_suc > 0) -// cout << "cnt_suc = " << cnt_suc << endl; + // if (cnt_suc > 0) + // cout << "cnt_suc = " << cnt_suc << endl; } -void floatTetWild::find_cutting_tets(int f_id, const std::vector &input_vertices, const std::vector &input_faces, - const std::array& vs, Mesh &mesh, std::vector &cut_t_ids, bool is_again) { +void floatTetWild::find_cutting_tets(int f_id, + const std::vector& input_vertices, + const std::vector& input_faces, + const std::array& vs, + Mesh& mesh, + std::vector& cut_t_ids, + bool is_again) +{ std::vector is_visited(mesh.tets.size(), false); - std::queue queue_t_ids; + std::queue queue_t_ids; if (!is_again) { std::vector n_t_ids; for (int j = 0; j < 3; j++) { - n_t_ids.insert(n_t_ids.end(), mesh.tet_vertices[input_faces[f_id][j]].conn_tets.begin(), + n_t_ids.insert(n_t_ids.end(), + mesh.tet_vertices[input_faces[f_id][j]].conn_tets.begin(), mesh.tet_vertices[input_faces[f_id][j]].conn_tets.end()); } vector_unique(n_t_ids); - for (int t_id: n_t_ids) { + for (int t_id : n_t_ids) { is_visited[t_id] = true; queue_t_ids.push(t_id); } - } else { + } + else { Vector3 min_f, max_f; - get_bbox_face(input_vertices[input_faces[f_id][0]], input_vertices[input_faces[f_id][1]], - input_vertices[input_faces[f_id][2]], min_f, max_f); + get_bbox_face(input_vertices[input_faces[f_id][0]], + input_vertices[input_faces[f_id][1]], + input_vertices[input_faces[f_id][2]], + min_f, + max_f); #ifdef FLOAT_TETWILD_USE_TBB tbb::concurrent_vector tbb_t_ids; - tbb::parallel_for(size_t(0), mesh.tets.size(), [&](size_t t_id){ + tbb::parallel_for(size_t(0), mesh.tets.size(), [&](size_t t_id) { if (mesh.tets[t_id].is_removed) return; Vector3 min_t, max_t; - get_bbox_tet(mesh.tet_vertices[mesh.tets[t_id][0]].pos, mesh.tet_vertices[mesh.tets[t_id][1]].pos, - mesh.tet_vertices[mesh.tets[t_id][2]].pos, mesh.tet_vertices[mesh.tets[t_id][3]].pos, - min_t, max_t); + get_bbox_tet(mesh.tet_vertices[mesh.tets[t_id][0]].pos, + mesh.tet_vertices[mesh.tets[t_id][1]].pos, + mesh.tet_vertices[mesh.tets[t_id][2]].pos, + mesh.tet_vertices[mesh.tets[t_id][3]].pos, + min_t, + max_t); if (!is_bbox_intersected(min_f, max_f, min_t, max_t)) return; tbb_t_ids.push_back(t_id); - }); - for(int t_id: tbb_t_ids) { + for (int t_id : tbb_t_ids) { queue_t_ids.push(t_id); is_visited[t_id] = true; } @@ -957,9 +1121,12 @@ void floatTetWild::find_cutting_tets(int f_id, const std::vector &input continue; Vector3 min_t, max_t; - get_bbox_tet(mesh.tet_vertices[mesh.tets[t_id][0]].pos, mesh.tet_vertices[mesh.tets[t_id][1]].pos, - mesh.tet_vertices[mesh.tets[t_id][2]].pos, mesh.tet_vertices[mesh.tets[t_id][3]].pos, - min_t, max_t); + get_bbox_tet(mesh.tet_vertices[mesh.tets[t_id][0]].pos, + mesh.tet_vertices[mesh.tets[t_id][1]].pos, + mesh.tet_vertices[mesh.tets[t_id][2]].pos, + mesh.tet_vertices[mesh.tets[t_id][3]].pos, + min_t, + max_t); if (!is_bbox_intersected(min_f, max_f, min_t, max_t)) continue; @@ -969,12 +1136,10 @@ void floatTetWild::find_cutting_tets(int f_id, const std::vector &input #endif } -// const int CUT_UNKNOWN = INT_MIN; -// std::vector> visited_results(mesh.tets.size(), {{CUT_UNKNOWN, CUT_UNKNOWN, CUT_UNKNOWN, CUT_UNKNOWN}}); -// const int test_f_id = 771; -// const int test_f_id = -1; -// const int test_j = 1; -// const int test_v_id = input_faces[test_f_id][test_j]; + // const int CUT_UNKNOWN = INT_MIN; + // std::vector> visited_results(mesh.tets.size(), {{CUT_UNKNOWN, + // CUT_UNKNOWN, CUT_UNKNOWN, CUT_UNKNOWN}}); const int test_f_id = 771; const int test_f_id = + // -1; const int test_j = 1; const int test_v_id = input_faces[test_f_id][test_j]; while (!queue_t_ids.empty()) { int t_id = queue_t_ids.front(); queue_t_ids.pop(); @@ -991,10 +1156,10 @@ void floatTetWild::find_cutting_tets(int f_id, const std::vector &input break; } } - if(is_cut) { + if (is_cut) { cut_t_ids.push_back(t_id); for (int j = 0; j < 4; j++) { - for (int n_t_id: mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets) { + for (int n_t_id : mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets) { if (!is_visited[n_t_id]) { is_visited[n_t_id] = true; queue_t_ids.push(n_t_id); @@ -1005,29 +1170,29 @@ void floatTetWild::find_cutting_tets(int f_id, const std::vector &input } } - std::array oris; -// int cnt_pos = 0; -// int cnt_neg = 0; -// int cnt_on = 0; + // int cnt_pos = 0; + // int cnt_neg = 0; + // int cnt_on = 0; for (int j = 0; j < 4; j++) { - oris[j] = Predicates::orient_3d(vs[0], vs[1], vs[2], mesh.tet_vertices[mesh.tets[t_id][j]].pos); -// if (oris[j] == Predicates::ORI_ZERO) -// cnt_on++; -// else if (oris[j] == Predicates::ORI_POSITIVE) -// cnt_pos++; -// else -// cnt_neg++; - } -// if (cnt_pos == 0 && cnt_neg == 0 && cnt_on < 3) -// continue; - - bool is_cutted = false; - std::vector is_cut_vs = {{false, false, false, false}}; /// is v on cut face + oris[j] = + Predicates::orient_3d(vs[0], vs[1], vs[2], mesh.tet_vertices[mesh.tets[t_id][j]].pos); + // if (oris[j] == Predicates::ORI_ZERO) + // cnt_on++; + // else if (oris[j] == Predicates::ORI_POSITIVE) + // cnt_pos++; + // else + // cnt_neg++; + } + // if (cnt_pos == 0 && cnt_neg == 0 && cnt_on < 3) + // continue; + + bool is_cutted = false; + std::vector is_cut_vs = {{false, false, false, false}}; /// is v on cut face for (int j = 0; j < 4; j++) { int cnt_pos = 0; int cnt_neg = 0; - int cnt_on = 0; + int cnt_on = 0; for (int k = 0; k < 3; k++) { if (oris[(j + k + 1) % 4] == Predicates::ORI_ZERO) cnt_on++; @@ -1037,203 +1202,226 @@ void floatTetWild::find_cutting_tets(int f_id, const std::vector &input cnt_neg++; } - int result = CUT_EMPTY; - auto &tp1 = mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos; - auto &tp2 = mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos; - auto &tp3 = mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos; - -// if (cnt_on == 3) { -// result = is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_COPLANAR); -// } else if (cnt_pos > 0 && cnt_neg > 0) { -// result = is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_FACE); -// } -// if (result == CUT_EMPTY) -// continue; -// -// is_cutted = true; -// is_cut_vs[(j + 1) % 4] = true; -// is_cut_vs[(j + 2) % 4] = true; -// is_cut_vs[(j + 3) % 4] = true; - -// //fortest -// if(t_id == 1016 && f_id == test_f_id) { -// cout<<"1016"< 0 && cnt_neg > 0) { + // result = is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, + // CUT_FACE); + // } + // if (result == CUT_EMPTY) + // continue; + // + // is_cutted = true; + // is_cut_vs[(j + 1) % 4] = true; + // is_cut_vs[(j + 2) % 4] = true; + // is_cut_vs[(j + 3) % 4] = true; + + // //fortest + // if(t_id == 1016 && f_id == test_f_id) { + // cout<<"1016"< 0 && cnt_neg > 0) { -// //fortest -// if(t_id == 3976 && f_id == test_f_id) { -// mesh.tets[t_id].print(); -// cout << oris[0] << " " << oris[1] << " " << oris[2] << " " << oris[3] << endl; -// std::vector tmp; -// set_intersection(mesh.tet_vertices[mesh.tets[t_id][1]].conn_tets, -// mesh.tet_vertices[mesh.tets[t_id][2]].conn_tets, -// mesh.tet_vertices[mesh.tets[t_id][3]].conn_tets, tmp); -// vector_print(tmp); -// is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_FACE, true); -// is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp3, tp2, CUT_FACE, true); -// is_tri_tri_cutted_hint(vs[0], vs[2], vs[1], tp1, tp2, tp3, CUT_FACE, true); -// is_tri_tri_cutted_hint(vs[0], vs[2], vs[1], tp1, tp3, tp2, CUT_FACE, true); -// for (int k = 0; k < 3; k++) { -// cout << Predicates::orient_3d(tp1, tp2, tp3, vs[k]) << " " -// << Predicates::orient_3d(tp1, tp3, tp2, vs[k]) << " " -// << Predicates::orient_3d(tp3, tp2, tp1, vs[k]) << endl; -// } -// pausee(); -// } -// //fortest - - if (is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_FACE) == CUT_FACE) { - result = CUT_FACE; - is_cutted = true; + } + else if (cnt_pos > 0 && cnt_neg > 0) { + // //fortest + // if(t_id == 3976 && f_id == test_f_id) { + // mesh.tets[t_id].print(); + // cout << oris[0] << " " << oris[1] << " " << oris[2] << " " << + // oris[3] << endl; std::vector tmp; + // set_intersection(mesh.tet_vertices[mesh.tets[t_id][1]].conn_tets, + // mesh.tet_vertices[mesh.tets[t_id][2]].conn_tets, + // mesh.tet_vertices[mesh.tets[t_id][3]].conn_tets, + // tmp); + // vector_print(tmp); + // is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, + // CUT_FACE, true); is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], + // tp1, tp3, tp2, CUT_FACE, true); is_tri_tri_cutted_hint(vs[0], + // vs[2], vs[1], tp1, tp2, tp3, CUT_FACE, true); + // is_tri_tri_cutted_hint(vs[0], vs[2], vs[1], tp1, tp3, tp2, + // CUT_FACE, true); for (int k = 0; k < 3; k++) { + // cout << Predicates::orient_3d(tp1, tp2, tp3, vs[k]) << " " + // << Predicates::orient_3d(tp1, tp3, tp2, vs[k]) << " " + // << Predicates::orient_3d(tp3, tp2, tp1, vs[k]) << + // endl; + // } + // pausee(); + // } + // //fortest + + if (is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_FACE) == + CUT_FACE) { + result = CUT_FACE; + is_cutted = true; is_cut_vs[(j + 1) % 4] = true; is_cut_vs[(j + 2) % 4] = true; is_cut_vs[(j + 3) % 4] = true; } - } else if (cnt_on == 2 && oris[(j + 1) % 4] == Predicates::ORI_ZERO - && oris[(j + 2) % 4] == Predicates::ORI_ZERO) { - if (is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_EDGE_0) == CUT_EDGE_0) { - result = CUT_EDGE_0; + } + else if (cnt_on == 2 && oris[(j + 1) % 4] == Predicates::ORI_ZERO && + oris[(j + 2) % 4] == Predicates::ORI_ZERO) { + if (is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_EDGE_0) == + CUT_EDGE_0) { + result = CUT_EDGE_0; is_cut_vs[(j + 1) % 4] = true; is_cut_vs[(j + 2) % 4] = true; } - } else if (cnt_on == 2 && oris[(j + 2) % 4] == Predicates::ORI_ZERO - && oris[(j + 3) % 4] == Predicates::ORI_ZERO) { - if (is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_EDGE_1) == CUT_EDGE_1) { - result = CUT_EDGE_1; + } + else if (cnt_on == 2 && oris[(j + 2) % 4] == Predicates::ORI_ZERO && + oris[(j + 3) % 4] == Predicates::ORI_ZERO) { + if (is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_EDGE_1) == + CUT_EDGE_1) { + result = CUT_EDGE_1; is_cut_vs[(j + 2) % 4] = true; is_cut_vs[(j + 3) % 4] = true; } - } else if (cnt_on == 2 && oris[(j + 3) % 4] == Predicates::ORI_ZERO - && oris[(j + 1) % 4] == Predicates::ORI_ZERO) { - if (is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_EDGE_2) == CUT_EDGE_2) { - result = CUT_EDGE_2; + } + else if (cnt_on == 2 && oris[(j + 3) % 4] == Predicates::ORI_ZERO && + oris[(j + 1) % 4] == Predicates::ORI_ZERO) { + if (is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_EDGE_2) == + CUT_EDGE_2) { + result = CUT_EDGE_2; is_cut_vs[(j + 3) % 4] = true; is_cut_vs[(j + 1) % 4] = true; } } -// if (is_cut_vs[0] && is_cut_vs[1] && is_cut_vs[2] && is_cut_vs[3]) -// break; - -// //fortest -// if (f_id == test_f_id && mesh.tets[t_id].find(test_v_id) >= 0) { -// cout << "input_f " << input_faces[f_id].transpose() << endl; -//// cout << input_vertices[input_faces[f_id][0]].transpose() << endl; -//// cout << input_vertices[input_faces[f_id][1]].transpose() << endl; -//// cout << input_vertices[input_faces[f_id][2]].transpose() << endl; -// cout << "t " << t_id << ": "; -// mesh.tets[t_id].print(); -// cout << "j " << j << endl; -// cout << "cnt_on = " << cnt_on << endl; -// cout << "cnt_pos = " << cnt_pos << endl; -// cout << "cnt_neg = " << cnt_neg << endl; -// cout << "result = " << result << endl; -//// if (cnt_pos > 0 && cnt_neg > 0) { -// if(t_id == 3976 || t_id == 1016){ -// cout<<"//////"< tet_vr; -// std::array tri_vr; -// std::array tet_vf; -// std::array tri_vf; -// std::array tet_vids; -// std::array tri_vids; -// for(int k=0;k<4;k++){ -// for(int r=0;r<3;r++) { -// tet_vr[k][r] = mesh.tet_vertices[mesh.tets[t_id][k]].pos[r]; -// tet_vf[k][r] = mesh.tet_vertices[mesh.tets[t_id][k]].pos[r]; -// } -// tet_vids[k] = mesh.tets[t_id][k]; -// } -// for(int k=0;k<3;k++){ -// for(int r=0;r<3;r++) { -// tri_vr[k][r] = input_vertices[input_faces[f_id][k]][r]; -// tri_vf[k][r] = input_vertices[input_faces[f_id][k]][r]; -// } -// tri_vids[k] = input_faces[f_id][k]; -// } -// for(int k=0;k<4;k++) { -// cout << "tet " << t_id << " face" << k << endl; -// cout<<"plane of tet face:"<= 0) { + // cout << "input_f " << input_faces[f_id].transpose() << endl; + //// cout << input_vertices[input_faces[f_id][0]].transpose() << endl; + //// cout << input_vertices[input_faces[f_id][1]].transpose() << endl; + //// cout << input_vertices[input_faces[f_id][2]].transpose() << endl; + // cout << "t " << t_id << ": "; + // mesh.tets[t_id].print(); + // cout << "j " << j << endl; + // cout << "cnt_on = " << cnt_on << endl; + // cout << "cnt_pos = " << cnt_pos << endl; + // cout << "cnt_neg = " << cnt_neg << endl; + // cout << "result = " << result << endl; + //// if (cnt_pos > 0 && cnt_neg > 0) { + // if(t_id == 3976 || t_id == 1016){ + // cout<<"//////"< tet_vr; + // std::array tri_vr; + // std::array tet_vf; + // std::array tri_vf; + // std::array tet_vids; + // std::array tri_vids; + // for(int k=0;k<4;k++){ + // for(int r=0;r<3;r++) { + // tet_vr[k][r] = + // mesh.tet_vertices[mesh.tets[t_id][k]].pos[r]; tet_vf[k][r] + // = mesh.tet_vertices[mesh.tets[t_id][k]].pos[r]; + // } + // tet_vids[k] = mesh.tets[t_id][k]; + // } + // for(int k=0;k<3;k++){ + // for(int r=0;r<3;r++) { + // tri_vr[k][r] = input_vertices[input_faces[f_id][k]][r]; + // tri_vf[k][r] = input_vertices[input_faces[f_id][k]][r]; + // } + // tri_vids[k] = input_faces[f_id][k]; + // } + // for(int k=0;k<4;k++) { + // cout << "tet " << t_id << " face" << k << endl; + // cout<<"plane of tet face:"< &input for (int j = 0; j < 4; j++) { if (!is_cut_vs[j]) continue; - for (int n_t_id: mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets) { + for (int n_t_id : mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets) { if (!is_visited[n_t_id]) { is_visited[n_t_id] = true; queue_t_ids.push(n_t_id); @@ -1250,124 +1438,143 @@ void floatTetWild::find_cutting_tets(int f_id, const std::vector &input } } -// //fortest -// if (cut_t_ids.empty()) { -// cout << "cut_t_ids.empty()" << endl; -// cout << "f" << f_id << ": " << input_faces[f_id][0] << " " << input_faces[f_id][1] << " " -// << input_faces[f_id][2] << endl; -// std::vector all_cut_t_ids; -// for (int t_id = 0; t_id < mesh.tets.size(); t_id++) { -// std::array oris; -// for (int j = 0; j < 4; j++) { -// oris[j] = Predicates::orient_3d(vs[0], vs[1], vs[2], mesh.tet_vertices[mesh.tets[t_id][j]].pos); -// } -// -// for (int j = 0; j < 4; j++) { -// int cnt_pos = 0; -// int cnt_neg = 0; -// int cnt_on = 0; -// for (int k = 0; k < 3; k++) { -// if (oris[(j + k + 1) % 4] == Predicates::ORI_ZERO) -// cnt_on++; -// else if (oris[(j + k + 1) % 4] == Predicates::ORI_POSITIVE) -// cnt_pos++; -// else -// cnt_neg++; -// } -// -// int result = CUT_EMPTY; -// auto &tp1 = mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos; -// auto &tp2 = mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos; -// auto &tp3 = mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos; -// if (cnt_on == 3) { -// result = is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_COPLANAR); -// } else if (cnt_pos > 0 && cnt_neg > 0) { -// result = is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, CUT_FACE); -// } -// if (result == CUT_EMPTY) -// continue; -// -// all_cut_t_ids.push_back(t_id); -// break; -// } -// } -// cout << all_cut_t_ids.size() << endl; -// for (int t_id:all_cut_t_ids) { -// cout << "t" << t_id << ": "; -// mesh.tets[t_id].print(); -// } -// pausee(); -// } -// //fortest + // //fortest + // if (cut_t_ids.empty()) { + // cout << "cut_t_ids.empty()" << endl; + // cout << "f" << f_id << ": " << input_faces[f_id][0] << " " << input_faces[f_id][1] << + // " " + // << input_faces[f_id][2] << endl; + // std::vector all_cut_t_ids; + // for (int t_id = 0; t_id < mesh.tets.size(); t_id++) { + // std::array oris; + // for (int j = 0; j < 4; j++) { + // oris[j] = Predicates::orient_3d(vs[0], vs[1], vs[2], + // mesh.tet_vertices[mesh.tets[t_id][j]].pos); + // } + // + // for (int j = 0; j < 4; j++) { + // int cnt_pos = 0; + // int cnt_neg = 0; + // int cnt_on = 0; + // for (int k = 0; k < 3; k++) { + // if (oris[(j + k + 1) % 4] == Predicates::ORI_ZERO) + // cnt_on++; + // else if (oris[(j + k + 1) % 4] == Predicates::ORI_POSITIVE) + // cnt_pos++; + // else + // cnt_neg++; + // } + // + // int result = CUT_EMPTY; + // auto &tp1 = mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos; + // auto &tp2 = mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos; + // auto &tp3 = mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos; + // if (cnt_on == 3) { + // result = is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, + // CUT_COPLANAR); + // } else if (cnt_pos > 0 && cnt_neg > 0) { + // result = is_tri_tri_cutted_hint(vs[0], vs[1], vs[2], tp1, tp2, tp3, + // CUT_FACE); + // } + // if (result == CUT_EMPTY) + // continue; + // + // all_cut_t_ids.push_back(t_id); + // break; + // } + // } + // cout << all_cut_t_ids.size() << endl; + // for (int t_id:all_cut_t_ids) { + // cout << "t" << t_id << ": "; + // mesh.tets[t_id].print(); + // } + // pausee(); + // } + // //fortest } -bool floatTetWild::subdivide_tets(int insert_f_id, Mesh& mesh, CutMesh& cut_mesh, - std::vector& points, std::map, int>& map_edge_to_intersecting_point, - std::vector, 4>>& track_surface_fs, - std::vector& subdivide_t_ids, std::vector& is_mark_surface, - std::vector& new_tets, std::vector, 4>>& new_track_surface_fs, - std::vector& modified_t_ids) { - - static const std::array, 6> t_es = {{{{0, 1}}, {{1, 2}}, {{2, 0}}, {{0, 3}}, {{1, 3}}, {{2, 3}}}}; - static const std::array, 4> t_f_es = {{{{1, 5, 4}}, {{5, 3, 2}}, {{3, 0, 4}}, {{0, 1, 2}}}}; - static const std::array, 4> t_f_vs = {{{{3, 1, 2}}, {{0, 2, 3}}, {{1, 3, 0}}, {{2, 0, 1}}}}; - - //fortest -// for (auto m: map_edge_to_intersecting_point) -// cout << (m.first[0]) << " " << (m.first[1]) << ": " << mesh.tet_vertices.size() + m.second << endl; - //fortest +bool floatTetWild::subdivide_tets( + int insert_f_id, + Mesh& mesh, + CutMesh& cut_mesh, + std::vector& points, + std::map, int>& map_edge_to_intersecting_point, + std::vector, 4>>& track_surface_fs, + std::vector& subdivide_t_ids, + std::vector& is_mark_surface, + std::vector& new_tets, + std::vector, 4>>& new_track_surface_fs, + std::vector& modified_t_ids) +{ + static const std::array, 6> t_es = { + {{{0, 1}}, {{1, 2}}, {{2, 0}}, {{0, 3}}, {{1, 3}}, {{2, 3}}}}; + static const std::array, 4> t_f_es = { + {{{1, 5, 4}}, {{5, 3, 2}}, {{3, 0, 4}}, {{0, 1, 2}}}}; + static const std::array, 4> t_f_vs = { + {{{3, 1, 2}}, {{0, 2, 3}}, {{1, 3, 0}}, {{2, 0, 1}}}}; + + // fortest + // for (auto m: map_edge_to_intersecting_point) + // cout << (m.first[0]) << " " << (m.first[1]) << ": " << mesh.tet_vertices.size() + + // m.second << endl; + // fortest covered_tet_fs.clear(); for (int I = 0; I < subdivide_t_ids.size(); I++) { - int t_id = subdivide_t_ids[I]; + int t_id = subdivide_t_ids[I]; bool is_mark_sf = is_mark_surface[I]; - //fortest -// cout << endl << "t_id = " << t_id << endl; -// cout << "is_mark_sf = " << is_mark_sf << endl; -// cout << mesh.tets[t_id][0] << " " << mesh.tets[t_id][1] << " " << mesh.tets[t_id][2] << " " -// << mesh.tets[t_id][3] << endl; - //fortest + // fortest + // cout << endl << "t_id = " << t_id << endl; + // cout << "is_mark_sf = " << is_mark_sf << endl; + // cout << mesh.tets[t_id][0] << " " << mesh.tets[t_id][1] << " " << + // mesh.tets[t_id][2] << " " + // << mesh.tets[t_id][3] << endl; + // fortest ///// - std::bitset<6> config_bit; + std::bitset<6> config_bit; std::array, 6> on_edge_p_ids; - int cnt = 4; + int cnt = 4; for (int i = 0; i < t_es.size(); i++) { - const auto &le = t_es[i]; - std::array e = {{mesh.tets[t_id][le[0]], mesh.tets[t_id][le[1]]}}; + const auto& le = t_es[i]; + std::array e = {{mesh.tets[t_id][le[0]], mesh.tets[t_id][le[1]]}}; if (e[0] > e[1]) std::swap(e[0], e[1]); if (map_edge_to_intersecting_point.find(e) == map_edge_to_intersecting_point.end()) { - on_edge_p_ids[i].first = -1; + on_edge_p_ids[i].first = -1; on_edge_p_ids[i].second = -1; - } else { - on_edge_p_ids[i].first = cnt++; + } + else { + on_edge_p_ids[i].first = cnt++; on_edge_p_ids[i].second = map_edge_to_intersecting_point[e]; config_bit.set(i); } } int config_id = config_bit.to_ulong(); -// cout << "config_id = " << config_id << endl;//fortest - if (config_id == 0) { //no intersection + // cout << "config_id = " << config_id << endl;//fortest + if (config_id == 0) { // no intersection if (is_mark_sf) { -// cout << "is_mark_surface" << endl;//fortest + // cout << "is_mark_surface" << endl;//fortest for (int j = 0; j < 4; j++) { int cnt_on = 0; for (int k = 0; k < 3; k++) { - myassert(cut_mesh.map_v_ids.find(mesh.tets[t_id][(j + k + 1) % 4]) != cut_mesh.map_v_ids.end(), - "cut_mesh.map_v_ids.find(mesh.tets[t_id][(j + k + 1) % 4]) != cut_mesh.map_v_ids.end()!!");//fortest - if (cut_mesh.is_v_on_plane(cut_mesh.map_v_ids[mesh.tets[t_id][(j + k + 1) % 4]])) { + myassert(cut_mesh.map_v_ids.find(mesh.tets[t_id][(j + k + 1) % 4]) != + cut_mesh.map_v_ids.end(), + "cut_mesh.map_v_ids.find(mesh.tets[t_id][(j + k + 1) % 4]) != " + "cut_mesh.map_v_ids.end()!!"); // fortest + if (cut_mesh.is_v_on_plane( + cut_mesh.map_v_ids[mesh.tets[t_id][(j + k + 1) % 4]])) { cnt_on++; -// cout << (j + k + 1) % 4 << endl;//fortest + // cout << (j + k + 1) % 4 << endl;//fortest } } -// cout << "cnt_on = " << cnt_on << endl;//fortest - //fortest - if(cnt_on == 4){ - cout<<"cnt_on==4!!"< my_diags; @@ -1415,27 +1629,29 @@ bool floatTetWild::subdivide_tets(int insert_f_id, Mesh& mesh, CutMesh& cut_mesh continue; le_ids.push_back(k); } - if (le_ids.size() != 2)//no ambiguity + if (le_ids.size() != 2) // no ambiguity continue; my_diags.emplace_back(); - auto &diag = my_diags.back(); - if (on_edge_p_ids[t_f_es[j][le_ids[0]]].second > on_edge_p_ids[t_f_es[j][le_ids[1]]].second) { + auto& diag = my_diags.back(); + if (on_edge_p_ids[t_f_es[j][le_ids[0]]].second > + on_edge_p_ids[t_f_es[j][le_ids[1]]].second) { diag << on_edge_p_ids[t_f_es[j][le_ids[0]]].first, t_f_vs[j][le_ids[0]]; - } else { + } + else { diag << on_edge_p_ids[t_f_es[j][le_ids[1]]].first, t_f_vs[j][le_ids[1]]; } if (diag[0] > diag[1]) std::swap(diag[0], diag[1]); } - std::sort(my_diags.begin(), my_diags.end(), [](const Vector2i &a, const Vector2i &b) { + std::sort(my_diags.begin(), my_diags.end(), [](const Vector2i& a, const Vector2i& b) { return std::make_tuple(a[0], a[1]) < std::make_tuple(b[0], b[1]); }); ///// std::map map_lv_to_v_id; - const int v_size = mesh.tet_vertices.size(); - const int vp_size = mesh.tet_vertices.size() + points.size(); + const int v_size = mesh.tet_vertices.size(); + const int vp_size = mesh.tet_vertices.size() + points.size(); for (int i = 0; i < 4; i++) map_lv_to_v_id[i] = mesh.tets[t_id][i]; cnt = 0; @@ -1447,9 +1663,9 @@ bool floatTetWild::subdivide_tets(int insert_f_id, Mesh& mesh, CutMesh& cut_mesh } ///// - auto get_centroid = [&](const std::vector &config, int lv_id, Vector3 &c) { + auto get_centroid = [&](const std::vector& config, int lv_id, Vector3& c) { std::vector n_ids; - for (const auto &tet: config) { + for (const auto& tet : config) { std::vector tmp; for (int j = 0; j < 4; j++) { if (tet[j] != lv_id) @@ -1461,7 +1677,7 @@ bool floatTetWild::subdivide_tets(int insert_f_id, Mesh& mesh, CutMesh& cut_mesh } vector_unique(n_ids); c << 0, 0, 0; - for (int n_id:n_ids) { + for (int n_id : n_ids) { int v_id = map_lv_to_v_id[n_id]; if (v_id < v_size) c += mesh.tet_vertices[v_id].pos; @@ -1471,12 +1687,13 @@ bool floatTetWild::subdivide_tets(int insert_f_id, Mesh& mesh, CutMesh& cut_mesh c /= n_ids.size(); }; - auto check_config = [&](int diag_config_id, std::vector> ¢roids) { - const std::vector &config = CutTable::get_tet_conf(config_id, diag_config_id); - Scalar min_q = -666; - int cnt = 0; - std::map map_lv_to_c; - for (const auto &tet: config) { + auto check_config = [&](int diag_config_id, + std::vector>& centroids) { + const std::vector& config = CutTable::get_tet_conf(config_id, diag_config_id); + Scalar min_q = -666; + int cnt = 0; + std::map map_lv_to_c; + for (const auto& tet : config) { std::array vs; for (int j = 0; j < 4; j++) { if (map_lv_to_v_id.find(tet[j]) == map_lv_to_v_id.end()) { @@ -1486,7 +1703,8 @@ bool floatTetWild::subdivide_tets(int insert_f_id, Mesh& mesh, CutMesh& cut_mesh centroids.push_back(std::make_pair(tet[j], vs[j])); } vs[j] = centroids[map_lv_to_c[tet[j]]].second; - } else { + } + else { int v_id = map_lv_to_v_id[tet[j]]; if (v_id < v_size) vs[j] = mesh.tet_vertices[v_id].pos; @@ -1497,52 +1715,64 @@ bool floatTetWild::subdivide_tets(int insert_f_id, Mesh& mesh, CutMesh& cut_mesh Scalar volume = Predicates::orient_3d_volume(vs[0], vs[1], vs[2], vs[3]); -// //fortest -// if(volume==0) { -// cout< e = {{mesh.tets[t_id][le[0]], mesh.tets[t_id][le[1]]}}; -// if (e[0] > e[1]) -// std::swap(e[0], e[1]); -// if (map_edge_to_intersecting_point.find(e) != map_edge_to_intersecting_point.end()) { -// cout << e[0] << " " << e[1] << ": p" << map_edge_to_intersecting_point[e] << " " -// << points[map_edge_to_intersecting_point[e]].transpose() << endl; -// cout<<"is_mark_sf = "< e = {{mesh.tets[t_id][le[0]], + // mesh.tets[t_id][le[1]]}}; if (e[0] > e[1]) + // std::swap(e[0], e[1]); + // if (map_edge_to_intersecting_point.find(e) != + // map_edge_to_intersecting_point.end()) { + // cout << e[0] << " " << e[1] << ": p" << + // map_edge_to_intersecting_point[e] << " " + // << + // points[map_edge_to_intersecting_point[e]].transpose() + // << endl; + // cout<<"is_mark_sf = "<> centroids; if (!my_diags.empty()) { - const auto &all_diags = CutTable::get_diag_confs(config_id); + const auto& all_diags = CutTable::get_diag_confs(config_id); std::vector> min_qualities(all_diags.size()); std::vector>> all_centroids(all_diags.size()); for (int i = 0; i < all_diags.size(); i++) { @@ -1567,28 +1797,31 @@ bool floatTetWild::subdivide_tets(int insert_f_id, Mesh& mesh, CutMesh& cut_mesh } std::vector> tmp_centroids; - Scalar min_q = check_config(i, tmp_centroids); -// if (min_q < SCALAR_ZERO_3) -// continue; + Scalar min_q = check_config(i, tmp_centroids); + // if (min_q < SCALAR_ZERO_3) + // continue; min_qualities[i] = std::make_pair(i, min_q); all_centroids[i] = tmp_centroids; } - std::sort(min_qualities.begin(), min_qualities.end(), - [](const std::pair &a, const std::pair &b) { + std::sort(min_qualities.begin(), + min_qualities.end(), + [](const std::pair& a, const std::pair& b) { return a.second < b.second; }); - if (min_qualities.back().second < SCALAR_ZERO_3) { // if tet quality is too bad -// cout< mesh.params.eps_2_coplanar " << dist << endl; -// pausee(); -// } -// } -// //fortest + covered_tet_fs.push_back({{new_tets.back()[(j + 1) % 4], + new_tets.back()[(j + 3) % 4], + new_tets.back()[(j + 2) % 4]}}); + // //fortest + // cout << "sf " << i << " " << j << endl; + // for (int k = 0; k < 3; k++) { + // int v_id = new_tets.back()[(j + k + 1) % 4]; + // Vector3 p; + // if (v_id < v_size) + // p = mesh.tet_vertices[v_id].pos; + // else + // p = points[v_id - v_size]; + // double dist = cut_mesh.get_to_plane_dist(p); + // cout << "v_id = " << v_id << endl; + // if (dist > mesh.params.eps_2_coplanar) { + // cout << "dist > mesh.params.eps_2_coplanar " << + // dist << endl; pausee(); + // } + // } + // //fortest } int old_local_f_id = new_local_f_ids[i][j]; if (old_local_f_id < 0) continue; - (new_track_surface_fs.back())[j].insert((new_track_surface_fs.back())[j].end(), - track_surface_fs[t_id][old_local_f_id].begin(), - track_surface_fs[t_id][old_local_f_id].end()); - (new_tets.back()).is_bbox_fs[j] = mesh.tets[t_id].is_bbox_fs[old_local_f_id]; + (new_track_surface_fs.back())[j].insert( + (new_track_surface_fs.back())[j].end(), + track_surface_fs[t_id][old_local_f_id].begin(), + track_surface_fs[t_id][old_local_f_id].end()); + (new_tets.back()).is_bbox_fs[j] = mesh.tets[t_id].is_bbox_fs[old_local_f_id]; (new_tets.back()).is_surface_fs[j] = mesh.tets[t_id].is_surface_fs[old_local_f_id]; - (new_tets.back()).surface_tags[j] = mesh.tets[t_id].surface_tags[old_local_f_id]; + (new_tets.back()).surface_tags[j] = mesh.tets[t_id].surface_tags[old_local_f_id]; } } modified_t_ids.push_back(t_id); @@ -1654,8 +1892,12 @@ bool floatTetWild::subdivide_tets(int insert_f_id, Mesh& mesh, CutMesh& cut_mesh return true; } -void floatTetWild::pair_track_surface_fs(Mesh &mesh, std::vector, 4>> &track_surface_fs) { - std::vector> is_visited(track_surface_fs.size(), {{false, false, false, false}}); +void floatTetWild::pair_track_surface_fs( + Mesh& mesh, + std::vector, 4>>& track_surface_fs) +{ + std::vector> is_visited(track_surface_fs.size(), + {{false, false, false, false}}); for (int t_id = 0; t_id < track_surface_fs.size(); t_id++) { for (int j = 0; j < 4; j++) { // @@ -1668,46 +1910,55 @@ void floatTetWild::pair_track_surface_fs(Mesh &mesh, std::vector f_ids; if (track_surface_fs[t_id][j] != track_surface_fs[opp_t_id][k]) { - std::set_union(track_surface_fs[t_id][j].begin(), track_surface_fs[t_id][j].end(), - track_surface_fs[opp_t_id][k].begin(), track_surface_fs[opp_t_id][k].end(), + std::set_union(track_surface_fs[t_id][j].begin(), + track_surface_fs[t_id][j].end(), + track_surface_fs[opp_t_id][k].begin(), + track_surface_fs[opp_t_id][k].end(), std::back_inserter(f_ids)); - track_surface_fs[t_id][j] = f_ids; + track_surface_fs[t_id][j] = f_ids; track_surface_fs[opp_t_id][k] = f_ids; } } } } -void floatTetWild::find_boundary_edges(const std::vector &input_vertices, const std::vector &input_faces, - const std::vector &is_face_inserted, const std::vector& old_is_face_inserted, - std::vector, std::vector>> &b_edge_infos, - std::vector& is_on_cut_edges, - std::vector>& b_edges) { +void floatTetWild::find_boundary_edges( + const std::vector& input_vertices, + const std::vector& input_faces, + const std::vector& is_face_inserted, + const std::vector& old_is_face_inserted, + std::vector, std::vector>>& b_edge_infos, + std::vector& is_on_cut_edges, + std::vector>& b_edges) +{ std::vector> edges; - std::vector> conn_tris(input_vertices.size()); - std::vector> uninserted_conn_tris(input_vertices.size()); + std::vector> conn_tris(input_vertices.size()); + std::vector> uninserted_conn_tris(input_vertices.size()); for (int i = 0; i < input_faces.size(); i++) { - if(!is_face_inserted[i]) {///use currently inserted faces as mesh + if (!is_face_inserted[i]) { /// use currently inserted faces as mesh for (int j = 0; j < 3; j++) uninserted_conn_tris[input_faces[i][j]].push_back(i); continue; } - const auto &f = input_faces[i]; + const auto& f = input_faces[i]; for (int j = 0; j < 3; j++) { - //edges + // edges std::array e = {{f[j], f[(j + 1) % 3]}}; if (e[0] > e[1]) std::swap(e[0], e[1]); edges.push_back(e); - //conn_tris + // conn_tris conn_tris[input_faces[i][j]].push_back(i); } } @@ -1715,45 +1966,53 @@ void floatTetWild::find_boundary_edges(const std::vector &input_vertice int cnt1 = 0; int cnt2 = 0; - for (const auto &e: edges) { + for (const auto& e : edges) { std::vector n12_f_ids; - std::set_intersection(conn_tris[e[0]].begin(), conn_tris[e[0]].end(), - conn_tris[e[1]].begin(), conn_tris[e[1]].end(), std::back_inserter(n12_f_ids)); + std::set_intersection(conn_tris[e[0]].begin(), + conn_tris[e[0]].end(), + conn_tris[e[1]].begin(), + conn_tris[e[1]].end(), + std::back_inserter(n12_f_ids)); std::vector uninserted_n12_f_ids; - std::set_intersection(uninserted_conn_tris[e[0]].begin(), uninserted_conn_tris[e[0]].end(), - uninserted_conn_tris[e[1]].begin(), uninserted_conn_tris[e[1]].end(), + std::set_intersection(uninserted_conn_tris[e[0]].begin(), + uninserted_conn_tris[e[0]].end(), + uninserted_conn_tris[e[1]].begin(), + uninserted_conn_tris[e[1]].end(), std::back_inserter(uninserted_n12_f_ids)); bool needs_preserve = false; - for(int f_id: n12_f_ids){ - if(!old_is_face_inserted[f_id]) { + for (int f_id : n12_f_ids) { + if (!old_is_face_inserted[f_id]) { needs_preserve = true; break; } } - if (n12_f_ids.size() == 1) {//open boundary + if (n12_f_ids.size() == 1) { // open boundary b_edges.push_back(e); - if(needs_preserve) { + if (needs_preserve) { b_edge_infos.push_back(std::make_pair(e, n12_f_ids)); - if(!uninserted_n12_f_ids.empty()) + if (!uninserted_n12_f_ids.empty()) is_on_cut_edges.push_back(true); else is_on_cut_edges.push_back(false); } cnt1++; - } else { + } + else { int f_id = n12_f_ids[0]; - int j = 0; + int j = 0; for (; j < 3; j++) { - if ((input_faces[f_id][j] == e[0] && input_faces[f_id][mod3(j + 1)] == e[1]) - || (input_faces[f_id][j] == e[1] && input_faces[f_id][mod3(j + 1)] == e[0])) + if ((input_faces[f_id][j] == e[0] && input_faces[f_id][mod3(j + 1)] == e[1]) || + (input_faces[f_id][j] == e[1] && input_faces[f_id][mod3(j + 1)] == e[0])) break; } - Vector3 n = get_normal(input_vertices[input_faces[f_id][0]], input_vertices[input_faces[f_id][1]], + Vector3 n = get_normal(input_vertices[input_faces[f_id][0]], + input_vertices[input_faces[f_id][1]], input_vertices[input_faces[f_id][2]]); - int t = get_t(input_vertices[input_faces[f_id][0]], input_vertices[input_faces[f_id][1]], + int t = get_t(input_vertices[input_faces[f_id][0]], + input_vertices[input_faces[f_id][1]], input_vertices[input_faces[f_id][2]]); bool is_fine = false; @@ -1778,15 +2037,16 @@ void floatTetWild::find_boundary_edges(const std::vector &input_vertice if (input_faces[n12_f_ids[k]][r] != input_faces[f_id][j] && input_faces[n12_f_ids[k]][r] != input_faces[f_id][mod3(j + 1)]) { if (k == 0) { - ori = Predicates::orient_2d(to_2d(input_vertices[input_faces[f_id][j]], t), - to_2d(input_vertices[input_faces[f_id][mod3(j + 1)]], t), - to_2d(input_vertices[input_faces[n12_f_ids[k]][r]], t)); + ori = Predicates::orient_2d( + to_2d(input_vertices[input_faces[f_id][j]], t), + to_2d(input_vertices[input_faces[f_id][mod3(j + 1)]], t), + to_2d(input_vertices[input_faces[n12_f_ids[k]][r]], t)); break; } - int new_ori = Predicates::orient_2d(to_2d(input_vertices[input_faces[f_id][j]], t), - to_2d(input_vertices[input_faces[f_id][mod3(j + 1)]], - t), - to_2d(input_vertices[input_faces[n12_f_ids[k]][r]], t)); + int new_ori = Predicates::orient_2d( + to_2d(input_vertices[input_faces[f_id][j]], t), + to_2d(input_vertices[input_faces[f_id][mod3(j + 1)]], t), + to_2d(input_vertices[input_faces[n12_f_ids[k]][r]], t)); if (new_ori != ori) is_fine = true; break; @@ -1800,9 +2060,9 @@ void floatTetWild::find_boundary_edges(const std::vector &input_vertice cnt2++; b_edges.push_back(e); - if(needs_preserve) { + if (needs_preserve) { b_edge_infos.push_back(std::make_pair(e, n12_f_ids)); - if(!uninserted_n12_f_ids.empty()) + if (!uninserted_n12_f_ids.empty()) is_on_cut_edges.push_back(true); else is_on_cut_edges.push_back(false); @@ -1813,30 +2073,35 @@ void floatTetWild::find_boundary_edges(const std::vector &input_vertice cout << "#boundary_e1 = " << cnt1 << endl; cout << "#boundary_e2 = " << cnt2 << endl; } -//double time_e1 = 0; -//double time_e2 = 0; -//double time_e3 = 0; -//double time_e4 = 0; - -bool floatTetWild::insert_boundary_edges(const std::vector &input_vertices, const std::vector &input_faces, - std::vector, std::vector>>& b_edge_infos, - std::vector& is_on_cut_edges, - std::vector, 4>> &track_surface_fs, Mesh& mesh, - AABBWrapper &tree, - std::vector &is_face_inserted, bool is_again, - std::vector>& known_surface_fs, - std::vector>& known_not_surface_fs) { -// time_e1 = 0; -// time_e2 = 0; -// time_e3 = 0; -// time_e4 = 0; +// double time_e1 = 0; +// double time_e2 = 0; +// double time_e3 = 0; +// double time_e4 = 0; + +bool floatTetWild::insert_boundary_edges( + const std::vector& input_vertices, + const std::vector& input_faces, + std::vector, std::vector>>& b_edge_infos, + std::vector& is_on_cut_edges, + std::vector, 4>>& track_surface_fs, + Mesh& mesh, + AABBWrapper& tree, + std::vector& is_face_inserted, + bool is_again, + std::vector>& known_surface_fs, + std::vector>& known_not_surface_fs) +{ + // time_e1 = 0; + // time_e2 = 0; + // time_e3 = 0; + // time_e4 = 0; igl::Timer timer; - //fortest - auto check_corvered_area = [&](int I, const std::vector>& cut_fs){ + // fortest + auto check_corvered_area = [&](int I, const std::vector>& cut_fs) { int f_id = b_edge_infos[I].second[0]; { - auto &infos = cut_fs; + auto& infos = cut_fs; Eigen::MatrixXd V(infos.size() * 3, 3), C(infos.size() * 3, 3); Eigen::MatrixXi F(infos.size(), 3); for (int i = 0; i < infos.size(); i++) { @@ -1860,87 +2125,90 @@ bool floatTetWild::insert_boundary_edges(const std::vector &input_verti } pausee(); }; - //fortest + // fortest - auto mark_known_surface_fs = [&](const std::array &f, int tag) { + auto mark_known_surface_fs = [&](const std::array& f, int tag) { std::vector n_t_ids; - set_intersection(mesh.tet_vertices[f[0]].conn_tets, mesh.tet_vertices[f[1]].conn_tets, - mesh.tet_vertices[f[2]].conn_tets, n_t_ids); - if (n_t_ids.size() != 2)//todo:????? + set_intersection(mesh.tet_vertices[f[0]].conn_tets, + mesh.tet_vertices[f[1]].conn_tets, + mesh.tet_vertices[f[2]].conn_tets, + n_t_ids); + if (n_t_ids.size() != 2) // todo:????? return; - for (int t_id:n_t_ids) { - int j = get_local_f_id(t_id, f[0], f[1], f[2], mesh); + for (int t_id : n_t_ids) { + int j = get_local_f_id(t_id, f[0], f[1], f[2], mesh); mesh.tets[t_id].is_surface_fs[j] = tag; } }; - - auto record_boundary_info = [&](const std::vector &points, const std::vector &snapped_v_ids, - const std::array &e, bool is_on_cut) { + auto record_boundary_info = [&](const std::vector& points, + const std::vector& snapped_v_ids, + const std::array& e, + bool is_on_cut) { const int tet_vertices_size = mesh.tet_vertices.size(); for (int i = points.size(); i > 0; i--) { mesh.tet_vertices[tet_vertices_size - i].is_on_boundary = true; - mesh.tet_vertices[tet_vertices_size - i].is_on_cut = is_on_cut; + mesh.tet_vertices[tet_vertices_size - i].is_on_cut = is_on_cut; } - for (int v_id: snapped_v_ids) { - Scalar dis_2 = p_seg_squared_dist_3d(mesh.tet_vertices[v_id].pos, input_vertices[e[0]], - input_vertices[e[1]]); + for (int v_id : snapped_v_ids) { + Scalar dis_2 = p_seg_squared_dist_3d( + mesh.tet_vertices[v_id].pos, input_vertices[e[0]], input_vertices[e[1]]); if (dis_2 <= mesh.params.eps_2) { mesh.tet_vertices[v_id].is_on_boundary = true; - mesh.tet_vertices[v_id].is_on_cut = is_on_cut; + mesh.tet_vertices[v_id].is_on_cut = is_on_cut; } } -// b_edges.push_back(e); + // b_edges.push_back(e); -// //fortest -// for (int v_id: snapped_v_ids) { -// Scalar dis_2 = p_seg_squared_dist_3d(mesh.tet_vertices[v_id].pos, input_vertices[e[0]], -// input_vertices[e[1]]); -// if (dis_2 <= mesh.params.eps_2) -// fout_v << mesh.tet_vertices[v_id].pos[0] << " " -// << mesh.tet_vertices[v_id].pos[1] << " " -// << mesh.tet_vertices[v_id].pos[2] << endl; -// } -// //fortest + // //fortest + // for (int v_id: snapped_v_ids) { + // Scalar dis_2 = p_seg_squared_dist_3d(mesh.tet_vertices[v_id].pos, + // input_vertices[e[0]], + // input_vertices[e[1]]); + // if (dis_2 <= mesh.params.eps_2) + // fout_v << mesh.tet_vertices[v_id].pos[0] << " " + // << mesh.tet_vertices[v_id].pos[1] << " " + // << mesh.tet_vertices[v_id].pos[2] << endl; + // } + // //fortest }; - timer.start(); std::vector>> covered_fs_infos(input_faces.size()); for (int i = 0; i < track_surface_fs.size(); i++) { if (mesh.tets[i].is_removed) continue; for (int j = 0; j < 4; j++) { - for (int f_id: track_surface_fs[i][j]) + for (int f_id : track_surface_fs[i][j]) covered_fs_infos[f_id].push_back(std::make_pair(i, j)); } } logger().info("time1 = {}", timer.getElapsedTime()); - bool is_all_inserted = true; - int cnt = 0; - double time2 = 0;//fortest - double time3 = 0; - double time4 = 0; - double time5 = 0; - double time6 = 0; + bool is_all_inserted = true; + int cnt = 0; + double time2 = 0; // fortest + double time3 = 0; + double time4 = 0; + double time5 = 0; + double time6 = 0; for (int I = 0; I < b_edge_infos.size(); I++) { - const auto &e = b_edge_infos[I].first; - auto &n_f_ids = b_edge_infos[I].second;///it is sorted - bool is_on_cut = is_on_cut_edges[I]; - if(!is_again) { + const auto& e = b_edge_infos[I].first; + auto& n_f_ids = b_edge_infos[I].second; /// it is sorted + bool is_on_cut = is_on_cut_edges[I]; + if (!is_again) { mesh.tet_vertices[e[0]].is_on_boundary = true; mesh.tet_vertices[e[1]].is_on_boundary = true; - mesh.tet_vertices[e[0]].is_on_cut = is_on_cut; - mesh.tet_vertices[e[1]].is_on_cut = is_on_cut; + mesh.tet_vertices[e[0]].is_on_cut = is_on_cut; + mesh.tet_vertices[e[1]].is_on_cut = is_on_cut; } -// b_edges.push_back(e); + // b_edges.push_back(e); timer.start(); - ///double check neighbors + /// double check neighbors for (int i = 0; i < n_f_ids.size(); i++) { if (!is_face_inserted[n_f_ids[i]]) { n_f_ids.erase(n_f_ids.begin() + i); @@ -1948,114 +2216,141 @@ bool floatTetWild::insert_boundary_edges(const std::vector &input_verti break; } } - time2+=timer.getElapsedTime(); + time2 += timer.getElapsedTime(); if (n_f_ids.empty()) { cout << "FAIL n_f_ids.empty()" << endl; continue; } timer.start(); - ///compute intersection - std::vector points; + /// compute intersection + std::vector points; std::map, int> map_edge_to_intersecting_point; - std::vector snapped_v_ids; - std::vector> cut_fs; + std::vector snapped_v_ids; + std::vector> cut_fs; if (!insert_boundary_edges_get_intersecting_edges_and_points(covered_fs_infos, - input_vertices, input_faces, e, n_f_ids, + input_vertices, + input_faces, + e, + n_f_ids, track_surface_fs, - mesh, points, map_edge_to_intersecting_point, - snapped_v_ids, cut_fs, + mesh, + points, + map_edge_to_intersecting_point, + snapped_v_ids, + cut_fs, is_again)) { - for (int f_id: n_f_ids) + for (int f_id : n_f_ids) is_face_inserted[f_id] = false; is_all_inserted = false; cout << "FAIL insert_boundary_edges_get_intersecting_edges_and_points" << endl; - time3+=timer.getElapsedTime(); + time3 += timer.getElapsedTime(); continue; } - time3+=timer.getElapsedTime(); - if (points.empty()) { ///if all snapped + time3 += timer.getElapsedTime(); + if (points.empty()) { /// if all snapped record_boundary_info(points, snapped_v_ids, e, is_on_cut); cnt++; continue; } timer.start(); - ///subdivision + /// subdivision std::vector cut_t_ids; - for (const auto &m: map_edge_to_intersecting_point) { - const auto &tet_e = m.first; + for (const auto& m : map_edge_to_intersecting_point) { + const auto& tet_e = m.first; std::vector tmp; - set_intersection(mesh.tet_vertices[tet_e[0]].conn_tets, mesh.tet_vertices[tet_e[1]].conn_tets, tmp); + set_intersection( + mesh.tet_vertices[tet_e[0]].conn_tets, mesh.tet_vertices[tet_e[1]].conn_tets, tmp); cut_t_ids.insert(cut_t_ids.end(), tmp.begin(), tmp.end()); } vector_unique(cut_t_ids); std::vector is_mark_surface(cut_t_ids.size(), false); - CutMesh empty_cut_mesh(mesh, Vector3(0, 0, 0), std::array()); + CutMesh empty_cut_mesh(mesh, Vector3(0, 0, 0), std::array()); // - std::vector new_tets; + std::vector new_tets; std::vector, 4>> new_track_surface_fs; - std::vector modified_t_ids; - if (!subdivide_tets(-1, mesh, empty_cut_mesh, points, map_edge_to_intersecting_point, track_surface_fs, - cut_t_ids, is_mark_surface, - new_tets, new_track_surface_fs, modified_t_ids)) { + std::vector modified_t_ids; + if (!subdivide_tets(-1, + mesh, + empty_cut_mesh, + points, + map_edge_to_intersecting_point, + track_surface_fs, + cut_t_ids, + is_mark_surface, + new_tets, + new_track_surface_fs, + modified_t_ids)) { bool is_inside_envelope = true; - for (auto &f: cut_fs) { + for (auto& f : cut_fs) { #ifdef NEW_ENVELOPE - if(tree.is_out_sf_envelope_exact({{mesh.tet_vertices[f[0]].pos, mesh.tet_vertices[f[1]].pos, - mesh.tet_vertices[f[2]].pos}})){ + if (tree.is_out_sf_envelope_exact({{mesh.tet_vertices[f[0]].pos, + mesh.tet_vertices[f[1]].pos, + mesh.tet_vertices[f[2]].pos}})) { is_inside_envelope = false; break; } #else - #ifdef STORE_SAMPLE_POINTS - std::vector ps; - sample_triangle({{mesh.tet_vertices[f[0]].pos, mesh.tet_vertices[f[1]].pos, - mesh.tet_vertices[f[2]].pos}}, ps, mesh.params.dd); - if (tree.is_out_sf_envelope(ps, mesh.params.eps_2)) { - #else - GEO::index_t prev_facet = GEO::NO_FACET; - if(sample_triangle_and_check_is_out({{mesh.tet_vertices[f[0]].pos, mesh.tet_vertices[f[1]].pos, - mesh.tet_vertices[f[2]].pos}}, mesh.params.dd, mesh.params.eps_2, tree, prev_facet)){ - #endif - is_inside_envelope = false; - break; - } +#ifdef STORE_SAMPLE_POINTS + std::vector ps; + sample_triangle({{mesh.tet_vertices[f[0]].pos, + mesh.tet_vertices[f[1]].pos, + mesh.tet_vertices[f[2]].pos}}, + ps, + mesh.params.dd); + if (tree.is_out_sf_envelope(ps, mesh.params.eps_2)) { +#else + GEO::index_t prev_facet = GEO::NO_FACET; + if (sample_triangle_and_check_is_out({{mesh.tet_vertices[f[0]].pos, + mesh.tet_vertices[f[1]].pos, + mesh.tet_vertices[f[2]].pos}}, + mesh.params.dd, + mesh.params.eps_2, + tree, + prev_facet)) { +#endif + is_inside_envelope = false; + break; + } #endif } if (!is_inside_envelope) { - for (int f_id: n_f_ids) + for (int f_id : n_f_ids) is_face_inserted[f_id] = false; - for (auto &f: cut_fs) { + for (auto& f : cut_fs) { mark_known_surface_fs(f, KNOWN_NOT_SURFACE); } - known_not_surface_fs.insert(known_not_surface_fs.end(), cut_fs.begin(), cut_fs.end()); + known_not_surface_fs.insert( + known_not_surface_fs.end(), cut_fs.begin(), cut_fs.end()); cout << "FAIL subdivide_tets" << endl; - } else { - for (auto &f: cut_fs) + } + else { + for (auto& f : cut_fs) mark_known_surface_fs(f, KNOWN_SURFACE); known_surface_fs.insert(known_surface_fs.end(), cut_fs.begin(), cut_fs.end()); cout << "SEMI-FAIL subdivide_tets" << endl; } - is_all_inserted = false;//unless now - time4+=timer.getElapsedTime(); + is_all_inserted = false; // unless now + time4 += timer.getElapsedTime(); continue; } - time4+=timer.getElapsedTime(); + time4 += timer.getElapsedTime(); // timer.start(); - push_new_tets(mesh, track_surface_fs, points, new_tets, new_track_surface_fs, modified_t_ids, is_again); - time5+=timer.getElapsedTime(); + push_new_tets( + mesh, track_surface_fs, points, new_tets, new_track_surface_fs, modified_t_ids, is_again); + time5 += timer.getElapsedTime(); // - ///mark boundary vertices - ///notice, here we assume points list is inserted in the end of mesh.tet_vertices + /// mark boundary vertices + /// notice, here we assume points list is inserted in the end of mesh.tet_vertices timer.start(); record_boundary_info(points, snapped_v_ids, e, is_on_cut); - time6+=timer.getElapsedTime(); + time6 += timer.getElapsedTime(); cnt++; } @@ -2066,100 +2361,113 @@ bool floatTetWild::insert_boundary_edges(const std::vector &input_verti logger().info("time5 = {}", time5); logger().info("time6 = {}", time6); -// logger().info("time_e1 = {}", time_e1); -// logger().info("time_e2 = {}", time_e2); -// logger().info("time_e3 = {}", time_e3); -// //fortest -// std::ofstream fout_e("b_edges1.obj"); -//// std::ofstream fout_v("b_edges1_points.xyz"); -// for (auto &e: b_edges) { -// fout_e << "v " << input_vertices[e[0]][0] << " " -// << input_vertices[e[0]][1] << " " -// << input_vertices[e[0]][2] << endl; -// fout_e << "v " << input_vertices[e[1]][0] << " " -// << input_vertices[e[1]][1] << " " -// << input_vertices[e[1]][2] << endl; -// } -// for (int i = 0; i < b_edges.size(); i++) { -// fout_e << "l " << i * 2 + 1 << " " << i * 2 + 2 << endl; -// } -// fout_e.close(); -//// fout_v.close(); -// //fortest - -// cout << "b_edges.size = " << b_edges.size() << endl; + // logger().info("time_e1 = {}", time_e1); + // logger().info("time_e2 = {}", time_e2); + // logger().info("time_e3 = {}", time_e3); + // //fortest + // std::ofstream fout_e("b_edges1.obj"); + //// std::ofstream fout_v("b_edges1_points.xyz"); + // for (auto &e: b_edges) { + // fout_e << "v " << input_vertices[e[0]][0] << " " + // << input_vertices[e[0]][1] << " " + // << input_vertices[e[0]][2] << endl; + // fout_e << "v " << input_vertices[e[1]][0] << " " + // << input_vertices[e[1]][1] << " " + // << input_vertices[e[1]][2] << endl; + // } + // for (int i = 0; i < b_edges.size(); i++) { + // fout_e << "l " << i * 2 + 1 << " " << i * 2 + 2 << endl; + // } + // fout_e.close(); + //// fout_v.close(); + // //fortest + + // cout << "b_edges.size = " << b_edges.size() << endl; return is_all_inserted; } bool floatTetWild::insert_boundary_edges_get_intersecting_edges_and_points( - const std::vector>>& covered_fs_infos, - const std::vector &input_vertices, const std::vector &input_faces, - const std::array &e, const std::vector &n_f_ids, - std::vector, 4>> &track_surface_fs, Mesh &mesh, - std::vector& points, std::map, int>& map_edge_to_intersecting_point, - std::vector& snapped_v_ids, std::vector>& cut_fs, - bool is_again) { - -// igl::Timer timer; + const std::vector>>& covered_fs_infos, + const std::vector& input_vertices, + const std::vector& input_faces, + const std::array& e, + const std::vector& n_f_ids, + std::vector, 4>>& track_surface_fs, + Mesh& mesh, + std::vector& points, + std::map, int>& map_edge_to_intersecting_point, + std::vector& snapped_v_ids, + std::vector>& cut_fs, + bool is_again) +{ + // igl::Timer timer; auto is_cross = [](int a, int b) { - if ((a == Predicates::ORI_POSITIVE && b == Predicates::ORI_NEGATIVE) - || (a == Predicates::ORI_NEGATIVE && b == Predicates::ORI_POSITIVE)) + if ((a == Predicates::ORI_POSITIVE && b == Predicates::ORI_NEGATIVE) || + (a == Predicates::ORI_NEGATIVE && b == Predicates::ORI_POSITIVE)) return true; return false; }; - int t = get_t(input_vertices[input_faces[n_f_ids.front()][0]], + int t = get_t(input_vertices[input_faces[n_f_ids.front()][0]], input_vertices[input_faces[n_f_ids.front()][1]], input_vertices[input_faces[n_f_ids.front()][2]]); - std::array evs_2d = {{to_2d(input_vertices[e[0]], t), to_2d(input_vertices[e[1]], t)}}; + std::array evs_2d = { + {to_2d(input_vertices[e[0]], t), to_2d(input_vertices[e[1]], t)}}; Vector3 n = (input_vertices[input_faces[n_f_ids.front()][1]] - - input_vertices[input_faces[n_f_ids.front()][0]]).cross( - input_vertices[input_faces[n_f_ids.front()][2]] - input_vertices[input_faces[n_f_ids.front()][0]]); + input_vertices[input_faces[n_f_ids.front()][0]]) + .cross(input_vertices[input_faces[n_f_ids.front()][2]] - + input_vertices[input_faces[n_f_ids.front()][0]]); n.normalize(); - const Vector3 &pp = input_vertices[input_faces[n_f_ids.front()][0]]; + const Vector3& pp = input_vertices[input_faces[n_f_ids.front()][0]]; -// timer.start(); + // timer.start(); std::vector is_visited(mesh.tets.size(), false); - std::queue t_ids_queue; - ///find seed t_ids + std::queue t_ids_queue; + /// find seed t_ids if (!is_again) { std::vector t_ids; - for (int f_id: n_f_ids) { - for (const auto &info: covered_fs_infos[f_id]) + for (int f_id : n_f_ids) { + for (const auto& info : covered_fs_infos[f_id]) t_ids.push_back(info.first); } - for (int v_id: e) - t_ids.insert(t_ids.end(), mesh.tet_vertices[v_id].conn_tets.begin(), + for (int v_id : e) + t_ids.insert(t_ids.end(), + mesh.tet_vertices[v_id].conn_tets.begin(), mesh.tet_vertices[v_id].conn_tets.end()); vector_unique(t_ids); - for (int t_id: t_ids) { + for (int t_id : t_ids) { t_ids_queue.push(t_id); is_visited[t_id] = true; } - } else { + } + else { Vector3 min_e, max_e; - get_bbox_face(input_vertices[e[0]], input_vertices[e[0]], input_vertices[e[1]], min_e, max_e); + get_bbox_face( + input_vertices[e[0]], input_vertices[e[0]], input_vertices[e[1]], min_e, max_e); std::vector t_ids; - for (int f_id: n_f_ids) { - for (const auto &info: covered_fs_infos[f_id]) + for (int f_id : n_f_ids) { + for (const auto& info : covered_fs_infos[f_id]) t_ids.push_back(info.first); } #ifdef FLOAT_TETWILD_USE_TBB tbb::concurrent_vector tbb_t_ids; - tbb::parallel_for(size_t(0), mesh.tets.size(), [&](size_t t_id){ + tbb::parallel_for(size_t(0), mesh.tets.size(), [&](size_t t_id) { if (mesh.tets[t_id].is_removed) return; - if (track_surface_fs[t_id][0].empty() && track_surface_fs[t_id][1].empty() - && track_surface_fs[t_id][2].empty() && track_surface_fs[t_id][3].empty()) + if (track_surface_fs[t_id][0].empty() && track_surface_fs[t_id][1].empty() && + track_surface_fs[t_id][2].empty() && track_surface_fs[t_id][3].empty()) return; Vector3 min_t, max_t; - get_bbox_tet(mesh.tet_vertices[mesh.tets[t_id][0]].pos, mesh.tet_vertices[mesh.tets[t_id][1]].pos, - mesh.tet_vertices[mesh.tets[t_id][2]].pos, mesh.tet_vertices[mesh.tets[t_id][3]].pos, - min_t, max_t); + get_bbox_tet(mesh.tet_vertices[mesh.tets[t_id][0]].pos, + mesh.tet_vertices[mesh.tets[t_id][1]].pos, + mesh.tet_vertices[mesh.tets[t_id][2]].pos, + mesh.tet_vertices[mesh.tets[t_id][3]].pos, + min_t, + max_t); if (!is_bbox_intersected(min_e, max_e, min_t, max_t)) return; tbb_t_ids.push_back(t_id); @@ -2169,14 +2477,17 @@ bool floatTetWild::insert_boundary_edges_get_intersecting_edges_and_points( for (int t_id = 0; t_id < mesh.tets.size(); t_id++) { if (mesh.tets[t_id].is_removed) continue; - if (track_surface_fs[t_id][0].empty() && track_surface_fs[t_id][1].empty() - && track_surface_fs[t_id][2].empty() && track_surface_fs[t_id][3].empty()) + if (track_surface_fs[t_id][0].empty() && track_surface_fs[t_id][1].empty() && + track_surface_fs[t_id][2].empty() && track_surface_fs[t_id][3].empty()) continue; Vector3 min_t, max_t; - get_bbox_tet(mesh.tet_vertices[mesh.tets[t_id][0]].pos, mesh.tet_vertices[mesh.tets[t_id][1]].pos, - mesh.tet_vertices[mesh.tets[t_id][2]].pos, mesh.tet_vertices[mesh.tets[t_id][3]].pos, - min_t, max_t); + get_bbox_tet(mesh.tet_vertices[mesh.tets[t_id][0]].pos, + mesh.tet_vertices[mesh.tets[t_id][1]].pos, + mesh.tet_vertices[mesh.tets[t_id][2]].pos, + mesh.tet_vertices[mesh.tets[t_id][3]].pos, + min_t, + max_t); if (!is_bbox_intersected(min_e, max_e, min_t, max_t)) continue; @@ -2185,14 +2496,14 @@ bool floatTetWild::insert_boundary_edges_get_intersecting_edges_and_points( #endif vector_unique(t_ids); - for (int t_id: t_ids) { + for (int t_id : t_ids) { t_ids_queue.push(t_id); is_visited[t_id] = true; } } -// time_e1+=timer.getElapsedTimeInSec(); + // time_e1+=timer.getElapsedTimeInSec(); -// timer.start(); + // timer.start(); std::vector v_oris(mesh.tet_vertices.size(), Predicates::ORI_UNKNOWN); while (!t_ids_queue.empty()) { int t_id = t_ids_queue.front(); @@ -2200,37 +2511,46 @@ bool floatTetWild::insert_boundary_edges_get_intersecting_edges_and_points( std::array is_cut_vs = {{false, false, false, false}}; for (int j = 0; j < 4; j++) { - ///check if contains + /// check if contains if (track_surface_fs[t_id][j].empty()) continue; std::sort(track_surface_fs[t_id][j].begin(), track_surface_fs[t_id][j].end()); std::vector tmp; - std::set_intersection(track_surface_fs[t_id][j].begin(), track_surface_fs[t_id][j].end(), - n_f_ids.begin(), n_f_ids.end(), std::back_inserter(tmp)); + std::set_intersection(track_surface_fs[t_id][j].begin(), + track_surface_fs[t_id][j].end(), + n_f_ids.begin(), + n_f_ids.end(), + std::back_inserter(tmp)); if (tmp.empty()) continue; - ///check if cut through - //check tri side of seg - std::array f_v_ids = {{mesh.tets[t_id][(j + 1) % 4], mesh.tets[t_id][(j + 2) % 4], - mesh.tets[t_id][(j + 3) % 4]}}; -// std::array fvs_2d = {{to_2d(mesh.tet_vertices[f_v_ids[0]].pos, t), -// to_2d(mesh.tet_vertices[f_v_ids[1]].pos, t), -// to_2d(mesh.tet_vertices[f_v_ids[2]].pos, t)}}; - std::array fvs_2d = {{to_2d(mesh.tet_vertices[f_v_ids[0]].pos, n, pp, t), - to_2d(mesh.tet_vertices[f_v_ids[1]].pos, n, pp, t), - to_2d(mesh.tet_vertices[f_v_ids[2]].pos, n, pp, t)}}; - int cnt_pos = 0; - int cnt_neg = 0; - int cnt_on = 0; + /// check if cut through + // check tri side of seg + std::array f_v_ids = {{mesh.tets[t_id][(j + 1) % 4], + mesh.tets[t_id][(j + 2) % 4], + mesh.tets[t_id][(j + 3) % 4]}}; + // std::array fvs_2d = {{to_2d(mesh.tet_vertices[f_v_ids[0]].pos, + // t), + // to_2d(mesh.tet_vertices[f_v_ids[1]].pos, + // t), + // to_2d(mesh.tet_vertices[f_v_ids[2]].pos, + // t)}}; + std::array fvs_2d = {{to_2d(mesh.tet_vertices[f_v_ids[0]].pos, n, pp, t), + to_2d(mesh.tet_vertices[f_v_ids[1]].pos, n, pp, t), + to_2d(mesh.tet_vertices[f_v_ids[2]].pos, n, pp, t)}}; + int cnt_pos = 0; + int cnt_neg = 0; + int cnt_on = 0; for (int k = 0; k < 3; k++) { - int &ori = v_oris[f_v_ids[k]]; + int& ori = v_oris[f_v_ids[k]]; if (ori == Predicates::ORI_UNKNOWN) ori = Predicates::orient_2d(evs_2d[0], evs_2d[1], fvs_2d[k]); if (ori == Predicates::ORI_ZERO) { cnt_on++; - } else { - Scalar dis_2 = p_seg_squared_dist_3d(mesh.tet_vertices[f_v_ids[k]].pos, input_vertices[e[0]], + } + else { + Scalar dis_2 = p_seg_squared_dist_3d(mesh.tet_vertices[f_v_ids[k]].pos, + input_vertices[e[0]], input_vertices[e[1]]); if (dis_2 < mesh.params.eps_2_coplanar) { ori = Predicates::ORI_ZERO; @@ -2251,53 +2571,55 @@ bool floatTetWild::insert_boundary_edges_get_intersecting_edges_and_points( if (cnt_neg == 0 || cnt_pos == 0) continue; - //check tri edge - seg intersection + // check tri edge - seg intersection bool is_intersected = false; - for (auto &p: evs_2d) { ///first check if endpoints are contained inside the triangle + for (auto& p : evs_2d) { /// first check if endpoints are contained inside the triangle if (is_p_inside_tri_2d(p, fvs_2d)) { is_intersected = true; break; } } - if (!is_intersected) { ///then check if there's intersection + if (!is_intersected) { /// then check if there's intersection for (int k = 0; k < 3; k++) { - //if cross + // if cross if (!is_cross(v_oris[f_v_ids[k]], v_oris[f_v_ids[(k + 1) % 3]])) continue; - //if already know intersect + // if already know intersect std::array tri_e = {{f_v_ids[k], f_v_ids[(k + 1) % 3]}}; if (tri_e[0] > tri_e[1]) std::swap(tri_e[0], tri_e[1]); - if (map_edge_to_intersecting_point.find(tri_e) != map_edge_to_intersecting_point.end()) { + if (map_edge_to_intersecting_point.find(tri_e) != + map_edge_to_intersecting_point.end()) { is_intersected = true; break; } - //if intersect + // if intersect double t2 = -1; if (seg_seg_intersection_2d(evs_2d, {{fvs_2d[k], fvs_2d[(k + 1) % 3]}}, t2)) { - Vector3 p = (1 - t2) * mesh.tet_vertices[f_v_ids[k]].pos - + t2 * mesh.tet_vertices[f_v_ids[(k + 1) % 3]].pos; + Vector3 p = (1 - t2) * mesh.tet_vertices[f_v_ids[k]].pos + + t2 * mesh.tet_vertices[f_v_ids[(k + 1) % 3]].pos; double dis1 = (p - mesh.tet_vertices[f_v_ids[k]].pos).squaredNorm(); - double dis2 = (p - mesh.tet_vertices[f_v_ids[(k + 1) % 3]].pos).squaredNorm(); -// if (dis1 < SCALAR_ZERO_2) { + double dis2 = + (p - mesh.tet_vertices[f_v_ids[(k + 1) % 3]].pos).squaredNorm(); + // if (dis1 < SCALAR_ZERO_2) { if (dis1 < mesh.params.eps_2_coplanar) { v_oris[f_v_ids[k]] = Predicates::ORI_ZERO; - is_intersected = true; + is_intersected = true; break; } -// if (dis2 < SCALAR_ZERO_2) { + // if (dis2 < SCALAR_ZERO_2) { if (dis2 < mesh.params.eps_2_coplanar) { v_oris[f_v_ids[k]] = Predicates::ORI_ZERO; - is_intersected = true; + is_intersected = true; break; } points.push_back(p); map_edge_to_intersecting_point[tri_e] = points.size() - 1; - is_intersected = true; + is_intersected = true; break; } } - if (!is_intersected) /// no need to return false here + if (!is_intersected) /// no need to return false here continue; } @@ -2310,7 +2632,7 @@ bool floatTetWild::insert_boundary_edges_get_intersecting_edges_and_points( for (int j = 0; j < 4; j++) { if (!is_cut_vs[j]) continue; - for (int n_t_id: mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets) { + for (int n_t_id : mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets) { if (!is_visited[n_t_id]) { t_ids_queue.push(n_t_id); is_visited[n_t_id] = true; @@ -2319,11 +2641,11 @@ bool floatTetWild::insert_boundary_edges_get_intersecting_edges_and_points( } } vector_unique(cut_fs); -// time_e2+=timer.getElapsedTimeInSec(); + // time_e2+=timer.getElapsedTimeInSec(); -// timer.start(); + // timer.start(); std::vector> tet_edges; - for (const auto &f:cut_fs) { + for (const auto& f : cut_fs) { for (int j = 0; j < 3; j++) { if (f[j] < f[(j + 1) % 3]) tet_edges.push_back({{f[j], f[(j + 1) % 3]}}); @@ -2333,7 +2655,7 @@ bool floatTetWild::insert_boundary_edges_get_intersecting_edges_and_points( } vector_unique(tet_edges); // - for (const auto &tet_e:tet_edges) { + for (const auto& tet_e : tet_edges) { bool is_snapped = false; for (int j = 0; j < 2; j++) { if (v_oris[tet_e[j]] == Predicates::ORI_ZERO) { @@ -2346,59 +2668,61 @@ bool floatTetWild::insert_boundary_edges_get_intersecting_edges_and_points( if (map_edge_to_intersecting_point.find(tet_e) != map_edge_to_intersecting_point.end()) continue; std::array tri_evs_2d = {{to_2d(mesh.tet_vertices[tet_e[0]].pos, n, pp, t), - to_2d(mesh.tet_vertices[tet_e[1]].pos, n, pp, t)}}; - Scalar t_seg = -1; + to_2d(mesh.tet_vertices[tet_e[1]].pos, n, pp, t)}}; + Scalar t_seg = -1; if (seg_line_intersection_2d(tri_evs_2d, evs_2d, t_seg)) { - points.push_back((1 - t_seg) * mesh.tet_vertices[tet_e[0]].pos - + t_seg * mesh.tet_vertices[tet_e[1]].pos); + points.push_back((1 - t_seg) * mesh.tet_vertices[tet_e[0]].pos + + t_seg * mesh.tet_vertices[tet_e[1]].pos); map_edge_to_intersecting_point[tet_e] = points.size() - 1; } } vector_unique(snapped_v_ids); -// time_e3+=timer.getElapsedTimeInSec(); - -// //fortest -// Eigen::MatrixXd V(cut_fs.size() * 3, 3), C(cut_fs.size() * 3, 3); -// Eigen::MatrixXi F(cut_fs.size(), 3); -// for (int i = 0; i < cut_fs.size(); i++) { -// for (int j = 0; j < 3; j++) { -// V.row(i * 3 + j) = mesh.tet_vertices[cut_fs[i][j]].pos; -// C.row(i * 3 + j) << 0, 0, 1; -// } -// F.row(i) << i * 3, i * 3 + 1, i * 3 + 2; -// } -// igl::writeOFF("test_f.off", V, F, C); -//// Eigen::MatrixXd V(3, 3), C(3, 3); -//// Eigen::MatrixXi F(1, 3); -//// for (int j = 0; j < 3; j++) { -//// V.row(j) = mesh.tet_vertices[cut_fs[i][j]].pos; -//// C.row(j) << 0, 0, 1; -//// } -//// F.row(i) << 0, 1, 2; -//// igl::writeOFF("test_f.off", V, F, C); -// // -// std::ofstream fout("test_e.obj"); -// fout << "v " << input_vertices[e[0]].transpose() << endl; -// fout << "v " << input_vertices[e[1]].transpose() << endl; -// fout << "l 1 2" << endl; -// fout.close(); -// // -// pausee(); -// //fortest + // time_e3+=timer.getElapsedTimeInSec(); + + // //fortest + // Eigen::MatrixXd V(cut_fs.size() * 3, 3), C(cut_fs.size() * 3, 3); + // Eigen::MatrixXi F(cut_fs.size(), 3); + // for (int i = 0; i < cut_fs.size(); i++) { + // for (int j = 0; j < 3; j++) { + // V.row(i * 3 + j) = mesh.tet_vertices[cut_fs[i][j]].pos; + // C.row(i * 3 + j) << 0, 0, 1; + // } + // F.row(i) << i * 3, i * 3 + 1, i * 3 + 2; + // } + // igl::writeOFF("test_f.off", V, F, C); + //// Eigen::MatrixXd V(3, 3), C(3, 3); + //// Eigen::MatrixXi F(1, 3); + //// for (int j = 0; j < 3; j++) { + //// V.row(j) = mesh.tet_vertices[cut_fs[i][j]].pos; + //// C.row(j) << 0, 0, 1; + //// } + //// F.row(i) << 0, 1, 2; + //// igl::writeOFF("test_f.off", V, F, C); + // // + // std::ofstream fout("test_e.obj"); + // fout << "v " << input_vertices[e[0]].transpose() << endl; + // fout << "v " << input_vertices[e[1]].transpose() << endl; + // fout << "l 1 2" << endl; + // fout.close(); + // // + // pausee(); + // //fortest return true; } -void floatTetWild::mark_surface_fs(const std::vector &input_vertices, const std::vector &input_faces, - const std::vector &input_tags, - std::vector, 4>> &track_surface_fs, - const std::vector &is_face_inserted, - const std::vector>& known_surface_fs, +void floatTetWild::mark_surface_fs(const std::vector& input_vertices, + const std::vector& input_faces, + const std::vector& input_tags, + std::vector, 4>>& track_surface_fs, + const std::vector& is_face_inserted, + const std::vector>& known_surface_fs, const std::vector>& known_not_surface_fs, - std::vector>& b_edges, - Mesh &mesh, AABBWrapper &tree) { - - auto is_on_bounded_side = [&](const std::array &ps_2d, const Vector2 &c) { + std::vector>& b_edges, + Mesh& mesh, + AABBWrapper& tree) +{ + auto is_on_bounded_side = [&](const std::array& ps_2d, const Vector2& c) { int cnt_pos = 0; int cnt_neg = 0; for (int j = 0; j < 3; j++) { @@ -2414,190 +2738,206 @@ void floatTetWild::mark_surface_fs(const std::vector &input_vertices, c return true; }; - std::vector> is_visited(track_surface_fs.size(), {{false, false, false, false}}); + std::vector> is_visited(track_surface_fs.size(), + {{false, false, false, false}}); for (int t_id = 0; t_id < track_surface_fs.size(); t_id++) { for (int j = 0; j < 4; j++) { -// //fortest -// if (track_surface_fs[t_id][j].size() > 0) -//// if (std::find(track_surface_fs[t_id][j].begin(), track_surface_fs[t_id][j].end(), III) != track_surface_fs[t_id][j].end()) -// mesh.tets[t_id].is_surface_fs[j] = -1; -// continue; -// //fortest + // //fortest + // if (track_surface_fs[t_id][j].size() > 0) + //// if (std::find(track_surface_fs[t_id][j].begin(), + /// track_surface_fs[t_id][j].end(), III) != track_surface_fs[t_id][j].end()) + // mesh.tets[t_id].is_surface_fs[j] = -1; + // continue; + // //fortest // -// if (mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE || is_visited[t_id][j]) -// continue; -// is_visited[t_id][j] = true; -// if (track_surface_fs[t_id][j].empty()) -// continue; -// // -// int opp_t_id = get_opp_t_id(t_id, j, mesh); -// if (opp_t_id < 0) -// continue; -// int k = get_local_f_id(opp_t_id, mesh.tets[t_id][(j + 1) % 4], mesh.tets[t_id][(j + 2) % 4], -// mesh.tets[t_id][(j + 3) % 4], mesh); -// is_visited[opp_t_id][k] = true; -// // -// std::sort(track_surface_fs[t_id][j].begin(), track_surface_fs[t_id][j].end()); -// std::sort(track_surface_fs[opp_t_id][k].begin(), track_surface_fs[opp_t_id][k].end()); -// std::vector f_ids; -// if (track_surface_fs[t_id][j] != track_surface_fs[opp_t_id][k]) -// std::set_union(track_surface_fs[t_id][j].begin(), track_surface_fs[t_id][j].end(), -// track_surface_fs[opp_t_id][k].begin(), track_surface_fs[opp_t_id][k].end(), -// std::back_inserter(f_ids)); -// else -// f_ids = track_surface_fs[t_id][j]; - - int ff_id = -1; + // if (mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE || + // is_visited[t_id][j]) + // continue; + // is_visited[t_id][j] = true; + // if (track_surface_fs[t_id][j].empty()) + // continue; + // // + // int opp_t_id = get_opp_t_id(t_id, j, mesh); + // if (opp_t_id < 0) + // continue; + // int k = get_local_f_id(opp_t_id, mesh.tets[t_id][(j + 1) % 4], + // mesh.tets[t_id][(j + 2) % 4], + // mesh.tets[t_id][(j + 3) % 4], mesh); + // is_visited[opp_t_id][k] = true; + // // + // std::sort(track_surface_fs[t_id][j].begin(), + // track_surface_fs[t_id][j].end()); + // std::sort(track_surface_fs[opp_t_id][k].begin(), + // track_surface_fs[opp_t_id][k].end()); std::vector f_ids; if + // (track_surface_fs[t_id][j] != track_surface_fs[opp_t_id][k]) + // std::set_union(track_surface_fs[t_id][j].begin(), + // track_surface_fs[t_id][j].end(), + // track_surface_fs[opp_t_id][k].begin(), + // track_surface_fs[opp_t_id][k].end(), + // std::back_inserter(f_ids)); + // else + // f_ids = track_surface_fs[t_id][j]; + + int ff_id = -1; int opp_t_id = -1; - int k = -1; - if (mesh.tets[t_id].is_surface_fs[j] == KNOWN_SURFACE - || mesh.tets[t_id].is_surface_fs[j] == KNOWN_NOT_SURFACE) { + int k = -1; + if (mesh.tets[t_id].is_surface_fs[j] == KNOWN_SURFACE || + mesh.tets[t_id].is_surface_fs[j] == KNOWN_NOT_SURFACE) { opp_t_id = get_opp_t_id(t_id, j, mesh); if (opp_t_id < 0) { mesh.tets[t_id].is_surface_fs[j] = NOT_SURFACE; continue; } - k = get_local_f_id(opp_t_id, mesh.tets[t_id][(j + 1) % 4], mesh.tets[t_id][(j + 2) % 4], - mesh.tets[t_id][(j + 3) % 4], mesh); - is_visited[t_id][j] = true; + k = get_local_f_id(opp_t_id, + mesh.tets[t_id][(j + 1) % 4], + mesh.tets[t_id][(j + 2) % 4], + mesh.tets[t_id][(j + 3) % 4], + mesh); + is_visited[t_id][j] = true; is_visited[opp_t_id][k] = true; - if (mesh.tets[t_id].is_surface_fs[j] == KNOWN_NOT_SURFACE || track_surface_fs[t_id][j].empty()) { - mesh.tets[t_id].is_surface_fs[j] = NOT_SURFACE; + if (mesh.tets[t_id].is_surface_fs[j] == KNOWN_NOT_SURFACE || + track_surface_fs[t_id][j].empty()) { + mesh.tets[t_id].is_surface_fs[j] = NOT_SURFACE; mesh.tets[opp_t_id].is_surface_fs[k] = NOT_SURFACE; continue; - } else + } + else ff_id = track_surface_fs[t_id][j].front(); - } else { + } + else { if (mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE || is_visited[t_id][j]) continue; is_visited[t_id][j] = true; if (track_surface_fs[t_id][j].empty()) continue; - auto &f_ids = track_surface_fs[t_id][j]; + auto& f_ids = track_surface_fs[t_id][j]; - auto &tp1_3d = mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos; - auto &tp2_3d = mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos; - auto &tp3_3d = mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos; + auto& tp1_3d = mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos; + auto& tp2_3d = mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos; + auto& tp3_3d = mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos; // -// static const Scalar dist_2_max = mesh.params.bbox_diag_length * mesh.params.bbox_diag_length; -// std::array min_dist_2 = {{dist_2_max, dist_2_max, dist_2_max}}; -// std::array t_vs_geo = {{GEO::vec3(tp1_3d[0], tp1_3d[1], tp1_3d[2]), -// GEO::vec3(tp2_3d[0], tp2_3d[1], tp2_3d[2]), -// GEO::vec3(tp3_3d[0], tp3_3d[1], tp3_3d[2])}}; -// for (int f_id: f_ids) { -// std::array f_vs_geo; -// for (int k = 0; k < 3; k++) { -// f_vs_geo[k] = GEO::vec3(input_vertices[input_faces[f_id][k]][0], -// input_vertices[input_faces[f_id][k]][1], -// input_vertices[input_faces[f_id][k]][2]); -// } -// for (int k = 0; k < 3; k++) { -// double dist_2 = GEO::Geom::point_triangle_squared_distance(t_vs_geo[k], f_vs_geo[0], -// f_vs_geo[1], f_vs_geo[2]); -// if (dist_2 < min_dist_2[k]) -// min_dist_2[k] = dist_2; -// } -// } -// double eps = mesh.params.eps * mesh.params.eps; -// if (min_dist_2[0] <= eps && min_dist_2[1] <= eps && min_dist_2[2] <= eps) -// ff_id = track_surface_fs[t_id][j].front(); -// else { -// //fortest -//// int t = get_t(tp1_3d, tp2_3d, tp3_3d); -//// std::array tps_2d = {{to_2d(tp1_3d, t), to_2d(tp2_3d, t), to_2d(tp3_3d, t)}}; -//// std::array cs = {{(tps_2d[0] + tps_2d[1] + tps_2d[2]) / 3}}; -//// for (int k = 0; k < 3; k++) -//// cs[k + 1] = (tps_2d[k] + cs[0]) / 3; -//// -//// std::array ps_2d; -//// for (int f_id: f_ids) { -//// if (!is_face_inserted[f_id]) -//// continue; -//// -//// ps_2d = {{to_2d(input_vertices[input_faces[f_id][0]], t), -//// to_2d(input_vertices[input_faces[f_id][1]], t), -//// to_2d(input_vertices[input_faces[f_id][2]], t)}}; -//// -//// bool is_in = false; -//// for (auto &c:cs) { -//// if (is_on_bounded_side(ps_2d, c)) { -//// is_in = true; -//// break; -//// } -//// } -//// if (is_in) { -//// ff_id = f_id; -//// break; -//// } -//// } -//// if(ff_id>0) { -//// cout< min_dist_2 = + // {{dist_2_max, dist_2_max, dist_2_max}}; std::array + // t_vs_geo = {{GEO::vec3(tp1_3d[0], tp1_3d[1], tp1_3d[2]), + // GEO::vec3(tp2_3d[0], + // tp2_3d[1], + // tp2_3d[2]), + // GEO::vec3(tp3_3d[0], + // tp3_3d[1], + // tp3_3d[2])}}; + // for (int f_id: f_ids) { + // std::array f_vs_geo; + // for (int k = 0; k < 3; k++) { + // f_vs_geo[k] = + // GEO::vec3(input_vertices[input_faces[f_id][k]][0], + // input_vertices[input_faces[f_id][k]][1], + // input_vertices[input_faces[f_id][k]][2]); + // } + // for (int k = 0; k < 3; k++) { + // double dist_2 = + // GEO::Geom::point_triangle_squared_distance(t_vs_geo[k], + // f_vs_geo[0], + // f_vs_geo[1], f_vs_geo[2]); + // if (dist_2 < min_dist_2[k]) + // min_dist_2[k] = dist_2; + // } + // } + // double eps = mesh.params.eps * mesh.params.eps; + // if (min_dist_2[0] <= eps && min_dist_2[1] <= eps && min_dist_2[2] + // <= eps) + // ff_id = track_surface_fs[t_id][j].front(); + // else { + // //fortest + //// int t = get_t(tp1_3d, tp2_3d, tp3_3d); + //// std::array tps_2d = {{to_2d(tp1_3d, t), + /// to_2d(tp2_3d, t), to_2d(tp3_3d, t)}}; / std::array cs = {{(tps_2d[0] + tps_2d[1] + tps_2d[2]) / 3}}; / for + /// (int k = 0; k < 3; k++) / cs[k + 1] = (tps_2d[k] + cs[0]) + //// 3; + //// + //// std::array ps_2d; + //// for (int f_id: f_ids) { + //// if (!is_face_inserted[f_id]) + //// continue; + //// + //// ps_2d = {{to_2d(input_vertices[input_faces[f_id][0]], + /// t), / to_2d(input_vertices[input_faces[f_id][1]], t), / + /// to_2d(input_vertices[input_faces[f_id][2]], t)}}; + //// + //// bool is_in = false; + //// for (auto &c:cs) { + //// if (is_on_bounded_side(ps_2d, c)) { + //// is_in = true; + //// break; + //// } + //// } + //// if (is_in) { + //// ff_id = f_id; + //// break; + //// } + //// } + //// if(ff_id>0) { + //// cout< tps_2d = {{to_2d(tp1_3d, t), to_2d(tp2_3d, t), to_2d(tp3_3d, t)}}; -// std::array cs = {{(tps_2d[0] + tps_2d[1] + tps_2d[2]) / 3}}; -// for (int k = 0; k < 3; k++) -// cs[k + 1] = (tps_2d[k] + cs[0]) / 3; -// std::array ps_2d; -// bool is_all_out = true; -// for (int f_id: f_ids) { -// if (!is_face_inserted[f_id]) -// continue; -// -// ps_2d = {{to_2d(input_vertices[input_faces[f_id][0]], t), -// to_2d(input_vertices[input_faces[f_id][1]], t), -// to_2d(input_vertices[input_faces[f_id][2]], t)}}; -// -// bool is_in = false; -// for (auto &c:cs) { -// if (is_on_bounded_side(ps_2d, c)) { -// is_in = true; -// break; -// } -// } -// if (is_in) { -// ff_id = f_id; -// is_all_out = false; -// break; -// } -// } -// if(is_all_out) -// continue; -// // + // int t = get_t(tp1_3d, tp2_3d, tp3_3d); + // std::array tps_2d = {{to_2d(tp1_3d, t), to_2d(tp2_3d, + // t), to_2d(tp3_3d, t)}}; std::array cs = {{(tps_2d[0] + + // tps_2d[1] + tps_2d[2]) / 3}}; for (int k = 0; k < 3; k++) + // cs[k + 1] = (tps_2d[k] + cs[0]) / 3; + // std::array ps_2d; + // bool is_all_out = true; + // for (int f_id: f_ids) { + // if (!is_face_inserted[f_id]) + // continue; + // + // ps_2d = {{to_2d(input_vertices[input_faces[f_id][0]], t), + // to_2d(input_vertices[input_faces[f_id][1]], + // t), + // to_2d(input_vertices[input_faces[f_id][2]], + // t)}}; + // + // bool is_in = false; + // for (auto &c:cs) { + // if (is_on_bounded_side(ps_2d, c)) { + // is_in = true; + // break; + // } + // } + // if (is_in) { + // ff_id = f_id; + // is_all_out = false; + // break; + // } + // } + // if(is_all_out) + // continue; + // // #ifdef NEW_ENVELOPE if (tree.is_out_sf_envelope_exact({{tp1_3d, tp2_3d, tp3_3d}})) @@ -2605,101 +2945,109 @@ void floatTetWild::mark_surface_fs(const std::vector &input_vertices, c else ff_id = track_surface_fs[t_id][j].front(); #else - double eps_2 = (mesh.params.eps + mesh.params.eps_simplification) / 2; - double dd = (mesh.params.dd + mesh.params.dd_simplification) / 2; - eps_2 *= eps_2; - #ifdef STORE_SAMPLE_POINTS - std::vector ps; - sample_triangle({{tp1_3d, tp2_3d, tp3_3d}}, ps, dd); - if (tree.is_out_sf_envelope(ps, eps_2)) - #else - GEO::index_t prev_facet = GEO::NO_FACET; - if(sample_triangle_and_check_is_out({{tp1_3d, tp2_3d, tp3_3d}}, dd, eps_2, tree, prev_facet)) - #endif - continue; - else - ff_id = track_surface_fs[t_id][j].front(); + double eps_2 = (mesh.params.eps + mesh.params.eps_simplification) / 2; + double dd = (mesh.params.dd + mesh.params.dd_simplification) / 2; + eps_2 *= eps_2; +#ifdef STORE_SAMPLE_POINTS + std::vector ps; + sample_triangle({{tp1_3d, tp2_3d, tp3_3d}}, ps, dd); + if (tree.is_out_sf_envelope(ps, eps_2)) +#else + GEO::index_t prev_facet = GEO::NO_FACET; + if (sample_triangle_and_check_is_out( + {{tp1_3d, tp2_3d, tp3_3d}}, dd, eps_2, tree, prev_facet)) +#endif + continue; + else + ff_id = track_surface_fs[t_id][j].front(); #endif -// int t = get_t(tp1_3d, tp2_3d, tp3_3d); -// std::array tps_2d = {{to_2d(tp1_3d, t), to_2d(tp2_3d, t), to_2d(tp3_3d, t)}}; -// std::array cs = {{(tps_2d[0] + tps_2d[1] + tps_2d[2]) / 3}}; -// for(int k=0;k<3;k++) -// cs[k+1] = (tps_2d[k] + cs[0]) / 3; -// -// std::array ps_2d; -// for (int f_id: f_ids) { -// if (!is_face_inserted[f_id]) -// continue; -// -// ps_2d = {{to_2d(input_vertices[input_faces[f_id][0]], t), -// to_2d(input_vertices[input_faces[f_id][1]], t), -// to_2d(input_vertices[input_faces[f_id][2]], t)}}; -// -// bool is_in = false; -// for(auto& c:cs) { -// if (is_on_bounded_side(ps_2d, c)){ -// is_in = true; -// break; -// } -// } -// if(is_in) { -// ff_id = f_id; -// break; -// } -// } -// if (ff_id < 0) { -// continue; -//// std::vector ps; -//// sample_triangle({{tp1_3d, tp2_3d, tp3_3d}}, ps, mesh.params.dd); -//// if (tree.is_out_sf_envelope(ps, mesh.params.eps_2)) -//// continue; -//// else -//// ff_id = track_surface_fs[t_id][j].front(); -// } -// else { -// std::vector ps; -// sample_triangle({{tp1_3d, tp2_3d, tp3_3d}}, ps, mesh.params.dd); -// if (tree.is_out_sf_envelope(ps, mesh.params.eps_2)) -// continue; -// } + // int t = get_t(tp1_3d, tp2_3d, tp3_3d); + // std::array tps_2d = {{to_2d(tp1_3d, t), to_2d(tp2_3d, + // t), to_2d(tp3_3d, t)}}; std::array cs = {{(tps_2d[0] + + // tps_2d[1] + tps_2d[2]) / 3}}; for(int k=0;k<3;k++) + // cs[k+1] = (tps_2d[k] + cs[0]) / 3; + // + // std::array ps_2d; + // for (int f_id: f_ids) { + // if (!is_face_inserted[f_id]) + // continue; + // + // ps_2d = {{to_2d(input_vertices[input_faces[f_id][0]], t), + // to_2d(input_vertices[input_faces[f_id][1]], + // t), + // to_2d(input_vertices[input_faces[f_id][2]], + // t)}}; + // + // bool is_in = false; + // for(auto& c:cs) { + // if (is_on_bounded_side(ps_2d, c)){ + // is_in = true; + // break; + // } + // } + // if(is_in) { + // ff_id = f_id; + // break; + // } + // } + // if (ff_id < 0) { + // continue; + //// std::vector ps; + //// sample_triangle({{tp1_3d, tp2_3d, tp3_3d}}, ps, + /// mesh.params.dd); / if (tree.is_out_sf_envelope(ps, + /// mesh.params.eps_2)) / continue; / else + //// ff_id = track_surface_fs[t_id][j].front(); + // } + // else { + // std::vector ps; + // sample_triangle({{tp1_3d, tp2_3d, tp3_3d}}, ps, + // mesh.params.dd); if (tree.is_out_sf_envelope(ps, + // mesh.params.eps_2)) + // continue; + // } opp_t_id = get_opp_t_id(t_id, j, mesh); if (opp_t_id < 0) { mesh.tets[t_id].is_surface_fs[j] = NOT_SURFACE; continue; } - k = get_local_f_id(opp_t_id, mesh.tets[t_id][(j + 1) % 4], mesh.tets[t_id][(j + 2) % 4], - mesh.tets[t_id][(j + 3) % 4], mesh); + k = get_local_f_id(opp_t_id, + mesh.tets[t_id][(j + 1) % 4], + mesh.tets[t_id][(j + 2) % 4], + mesh.tets[t_id][(j + 3) % 4], + mesh); is_visited[opp_t_id][k] = true; } - myassert(ff_id>=0, "ff_id<0!!!");//fortest + myassert(ff_id >= 0, "ff_id<0!!!"); // fortest - mesh.tets[t_id].surface_tags[j] = input_tags[ff_id]; + mesh.tets[t_id].surface_tags[j] = input_tags[ff_id]; mesh.tets[opp_t_id].surface_tags[k] = input_tags[ff_id]; - auto &fv1 = input_vertices[input_faces[ff_id][0]]; - auto &fv2 = input_vertices[input_faces[ff_id][1]]; - auto &fv3 = input_vertices[input_faces[ff_id][2]]; + auto& fv1 = input_vertices[input_faces[ff_id][0]]; + auto& fv2 = input_vertices[input_faces[ff_id][1]]; + auto& fv3 = input_vertices[input_faces[ff_id][2]]; // - int ori = Predicates::orient_3d(fv1, fv2, fv3, mesh.tet_vertices[mesh.tets[t_id][j]].pos); - int opp_ori = Predicates::orient_3d(fv1, fv2, fv3, mesh.tet_vertices[mesh.tets[opp_t_id][k]].pos); + int ori = + Predicates::orient_3d(fv1, fv2, fv3, mesh.tet_vertices[mesh.tets[t_id][j]].pos); + int opp_ori = + Predicates::orient_3d(fv1, fv2, fv3, mesh.tet_vertices[mesh.tets[opp_t_id][k]].pos); // - if (ori == Predicates::ORI_POSITIVE && opp_ori == Predicates::ORI_NEGATIVE - || ori == Predicates::ORI_NEGATIVE && opp_ori == Predicates::ORI_POSITIVE) { - mesh.tets[t_id].is_surface_fs[j] = ori; + if (ori == Predicates::ORI_POSITIVE && opp_ori == Predicates::ORI_NEGATIVE || + ori == Predicates::ORI_NEGATIVE && opp_ori == Predicates::ORI_POSITIVE) { + mesh.tets[t_id].is_surface_fs[j] = ori; mesh.tets[opp_t_id].is_surface_fs[k] = opp_ori; continue; } // if (ori == Predicates::ORI_ZERO && opp_ori != Predicates::ORI_ZERO) { - mesh.tets[t_id].is_surface_fs[j] = -opp_ori; + mesh.tets[t_id].is_surface_fs[j] = -opp_ori; mesh.tets[opp_t_id].is_surface_fs[k] = opp_ori; continue; } if (opp_ori == Predicates::ORI_ZERO && ori != Predicates::ORI_ZERO) { - mesh.tets[t_id].is_surface_fs[j] = ori; + mesh.tets[t_id].is_surface_fs[j] = ori; mesh.tets[opp_t_id].is_surface_fs[k] = -ori; continue; } @@ -2707,40 +3055,46 @@ void floatTetWild::mark_surface_fs(const std::vector &input_vertices, c if (ori == opp_ori) { Vector3 n = (fv2 - fv1).cross(fv3 - fv1); n.normalize(); - Scalar dist = n.dot(mesh.tet_vertices[mesh.tets[t_id][j]].pos - fv1); + Scalar dist = n.dot(mesh.tet_vertices[mesh.tets[t_id][j]].pos - fv1); Scalar opp_dist = n.dot(mesh.tet_vertices[mesh.tets[opp_t_id][k]].pos - fv1); if (ori == Predicates::ORI_ZERO) { -// cout << "impossible!! " << dist << " " << opp_dist << endl; -// cout << (mesh.tet_vertices[mesh.tets[t_id][j]].pos == mesh.tet_vertices[mesh.tets[opp_t_id][k]].pos) -// << endl; -// cout << t_id << " " << j << " " << mesh.tets[t_id][j] << endl; -// cout << opp_t_id << " " << k << " " << mesh.tets[opp_t_id][k] << endl; -// cout << "n = " << n << endl; - - auto &tv1 = mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos; - auto &tv2 = mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos; - auto &tv3 = mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos; + // cout << "impossible!! " << dist << " " << opp_dist << + // endl; cout << (mesh.tet_vertices[mesh.tets[t_id][j]].pos + // == mesh.tet_vertices[mesh.tets[opp_t_id][k]].pos) + // << endl; + // cout << t_id << " " << j << " " << mesh.tets[t_id][j] << + // endl; cout << opp_t_id << " " << k << " " << + // mesh.tets[opp_t_id][k] << endl; cout << "n = " << n << + // endl; + + auto& tv1 = mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos; + auto& tv2 = mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos; + auto& tv3 = mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos; Vector3 nt; - if (Predicates::orient_3d(tv1, tv2, tv3, mesh.tet_vertices[mesh.tets[t_id][j]].pos) - == Predicates::ORI_POSITIVE) + if (Predicates::orient_3d( + tv1, tv2, tv3, mesh.tet_vertices[mesh.tets[t_id][j]].pos) == + Predicates::ORI_POSITIVE) nt = (tv2 - tv1).cross(tv3 - tv1); else nt = (tv3 - tv1).cross(tv2 - tv1); nt.normalize(); if (n.dot(nt) > 0) { mesh.tets[opp_t_id].is_surface_fs[k] = 1; - mesh.tets[t_id].is_surface_fs[j] = -1; - } else { + mesh.tets[t_id].is_surface_fs[j] = -1; + } + else { mesh.tets[opp_t_id].is_surface_fs[k] = -1; - mesh.tets[t_id].is_surface_fs[j] = 1; + mesh.tets[t_id].is_surface_fs[j] = 1; } - } else { + } + else { if (dist < opp_dist) { mesh.tets[opp_t_id].is_surface_fs[k] = opp_ori; - mesh.tets[t_id].is_surface_fs[j] = -ori; - } else { + mesh.tets[t_id].is_surface_fs[j] = -ori; + } + else { mesh.tets[opp_t_id].is_surface_fs[k] = -opp_ori; - mesh.tets[t_id].is_surface_fs[j] = ori; + mesh.tets[t_id].is_surface_fs[j] = ori; } } } @@ -2748,25 +3102,24 @@ void floatTetWild::mark_surface_fs(const std::vector &input_vertices, c } } - cout<<"known_surface_fs.size = "<> tmp_edges; - for (const auto &f: known_surface_fs) { + for (const auto& f : known_surface_fs) { for (int j = 0; j < 3; j++) { if (f[j] < f[(j + 1) % 3]) tmp_edges.push_back({{f[j], f[(j + 1) % 3]}}); @@ -2774,7 +3127,7 @@ void floatTetWild::mark_surface_fs(const std::vector &input_vertices, c tmp_edges.push_back({{f[(j + 1) % 3], f[j]}}); } } - for (const auto &f: known_not_surface_fs) { + for (const auto& f : known_not_surface_fs) { for (int j = 0; j < 3; j++) { if (f[j] < f[(j + 1) % 3]) tmp_edges.push_back({{f[j], f[(j + 1) % 3]}}); @@ -2784,11 +3137,12 @@ void floatTetWild::mark_surface_fs(const std::vector &input_vertices, c } vector_unique(tmp_edges); - for (auto &e: tmp_edges) { - int cnt = 0; + for (auto& e : tmp_edges) { + int cnt = 0; std::vector n_t_ids; - set_intersection(mesh.tet_vertices[e[0]].conn_tets, mesh.tet_vertices[e[1]].conn_tets, n_t_ids); - for (int t_id: n_t_ids) { + set_intersection( + mesh.tet_vertices[e[0]].conn_tets, mesh.tet_vertices[e[1]].conn_tets, n_t_ids); + for (int t_id : n_t_ids) { for (int j = 0; j < 4; j++) { if (mesh.tets[t_id][j] != e[0] && mesh.tets[t_id][j] != e[1]) { if (mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE) { @@ -2801,232 +3155,253 @@ void floatTetWild::mark_surface_fs(const std::vector &input_vertices, c break; } } -// cout<<"cnt = "< &input_vertices, const std::vector &input_faces, - const std::vector& cut_t_ids, Mesh &mesh){ - +bool floatTetWild::is_uninserted_face_covered(int uninserted_f_id, + const std::vector& input_vertices, + const std::vector& input_faces, + const std::vector& cut_t_ids, + Mesh& mesh) +{ std::array vs = {{input_vertices[input_faces[uninserted_f_id][0]], - input_vertices[input_faces[uninserted_f_id][1]], - input_vertices[input_faces[uninserted_f_id][2]]}}; + input_vertices[input_faces[uninserted_f_id][1]], + input_vertices[input_faces[uninserted_f_id][2]]}}; std::vector ps; sample_triangle(vs, ps, mesh.params.dd); std::vector n_t_ids; - for(int t_id: cut_t_ids) { + for (int t_id : cut_t_ids) { for (int j = 0; j < 4; j++) - n_t_ids.insert(n_t_ids.end(), mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets.begin(), + n_t_ids.insert(n_t_ids.end(), + mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets.begin(), mesh.tet_vertices[mesh.tets[t_id][j]].conn_tets.end()); } vector_unique(n_t_ids); std::vector> faces; - for(int t_id: n_t_ids) { - for (int j = 0; j < 4; j++){ - if(mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE) { - faces.push_back( - {{mesh.tets[t_id][(j + 1) % 4], mesh.tets[t_id][(j + 2) % 4], mesh.tets[t_id][(j + 3) % 4]}}); + for (int t_id : n_t_ids) { + for (int j = 0; j < 4; j++) { + if (mesh.tets[t_id].is_surface_fs[j] != NOT_SURFACE) { + faces.push_back({{mesh.tets[t_id][(j + 1) % 4], + mesh.tets[t_id][(j + 2) % 4], + mesh.tets[t_id][(j + 3) % 4]}}); std::sort(faces.back().begin(), faces.back().end()); } } } vector_unique(faces); - for(auto& p: ps){ + for (auto& p : ps) { bool is_valid = false; - for(auto& f: faces) { - double dis_2 = GEO::Geom::point_triangle_squared_distance(p, to_geo_p(mesh.tet_vertices[f[0]].pos), - to_geo_p(mesh.tet_vertices[f[1]].pos), - to_geo_p(mesh.tet_vertices[f[2]].pos)); + for (auto& f : faces) { + double dis_2 = + GEO::Geom::point_triangle_squared_distance(p, + to_geo_p(mesh.tet_vertices[f[0]].pos), + to_geo_p(mesh.tet_vertices[f[1]].pos), + to_geo_p(mesh.tet_vertices[f[2]].pos)); if (dis_2 < mesh.params.eps_2) { is_valid = true; break; } } - if(!is_valid) + if (!is_valid) return false; } - cout<<"covered!!!!!!!"< tmp; set_intersection(mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].conn_tets, mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].conn_tets, mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].conn_tets, tmp); -// //fortest -// if(tmp.size() != 1 && tmp.size() != 2) { -// cout << "tmp.size() = " << tmp.size() << endl; -// cout << "t_id = " << t_id << ", j = " << j << endl; -// vector_print(mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].conn_tets); -// vector_print(mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].conn_tets); -// vector_print(mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].conn_tets); -// vector_print(tmp); -// for(int i: tmp){ -// mesh.tets[i].print(); -// } -// pausee(); -// } -// //fortest + // //fortest + // if(tmp.size() != 1 && tmp.size() != 2) { + // cout << "tmp.size() = " << tmp.size() << endl; + // cout << "t_id = " << t_id << ", j = " << j << endl; + // vector_print(mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].conn_tets); + // vector_print(mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].conn_tets); + // vector_print(mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].conn_tets); + // vector_print(tmp); + // for(int i: tmp){ + // mesh.tets[i].print(); + // } + // pausee(); + // } + // //fortest if (tmp.size() == 2) return tmp[0] == t_id ? tmp[1] : tmp[0]; else return -1; } -void floatTetWild::myassert(bool b, const std::string& s) { +void floatTetWild::myassert(bool b, const std::string& s) +{ if (b == false) { cout << "myassert fail: " << s << endl; pausee(); } } -void floatTetWild::check_track_surface_fs(Mesh &mesh, std::vector, 4>> &track_surface_fs, - const std::vector &input_vertices, const std::vector &input_faces, - const std::vector &sorted_f_ids) { +void floatTetWild::check_track_surface_fs( + Mesh& mesh, + std::vector, 4>>& track_surface_fs, + const std::vector& input_vertices, + const std::vector& input_faces, + const std::vector& sorted_f_ids) +{ return; -// //check connection -// std::vector> conn_tets(mesh.tet_vertices.size()); -// for (int i = 0; i < mesh.tets.size(); i++) { -// for (int j = 0; j < 4; j++) -// conn_tets[mesh.tets[i][j]].push_back(i); -// } -// for (int i = 0; i < mesh.tet_vertices.size(); i++) { -// std::sort(mesh.tet_vertices[i].conn_tets.begin(), mesh.tet_vertices[i].conn_tets.end()); -// if (mesh.tet_vertices[i].conn_tets != conn_tets[i]) { -// cout << "mesh.tet_vertices[i].conn_tets!=conn_tets[i]" << endl; -// pausee(); -// } -// } -// cout<<"check 1 done"<> conn_tets(mesh.tet_vertices.size()); + // for (int i = 0; i < mesh.tets.size(); i++) { + // for (int j = 0; j < 4; j++) + // conn_tets[mesh.tets[i][j]].push_back(i); + // } + // for (int i = 0; i < mesh.tet_vertices.size(); i++) { + // std::sort(mesh.tet_vertices[i].conn_tets.begin(), + // mesh.tet_vertices[i].conn_tets.end()); if (mesh.tet_vertices[i].conn_tets != + // conn_tets[i]) { + // cout << "mesh.tet_vertices[i].conn_tets!=conn_tets[i]" << endl; + // pausee(); + // } + // } + // cout<<"check 1 done"<>> covered_fs_infos(input_faces.size()); for (int i = 0; i < track_surface_fs.size(); i++) { for (int j = 0; j < 4; j++) { - for (int f_id: track_surface_fs[i][j]) + for (int f_id : track_surface_fs[i][j]) covered_fs_infos[f_id].push_back(std::make_pair(i, j)); } } - //check is covered + // check is covered for (int i = 0; i < sorted_f_ids.size(); i++) { int f_id = sorted_f_ids[i]; - if (covered_fs_infos[f_id].empty())//not inserted + if (covered_fs_infos[f_id].empty()) // not inserted continue; - std::array f_vs = {{input_vertices[input_faces[f_id][0]], - input_vertices[input_faces[f_id][1]], - input_vertices[input_faces[f_id][2]]}}; - int t = get_t(f_vs[0], f_vs[1], f_vs[2]); + std::array f_vs = {{input_vertices[input_faces[f_id][0]], + input_vertices[input_faces[f_id][1]], + input_vertices[input_faces[f_id][2]]}}; + int t = get_t(f_vs[0], f_vs[1], f_vs[2]); std::array f_vs_2d = {{to_2d(input_vertices[input_faces[f_id][0]], t), - to_2d(input_vertices[input_faces[f_id][1]], t), - to_2d(input_vertices[input_faces[f_id][2]], t)}}; + to_2d(input_vertices[input_faces[f_id][1]], t), + to_2d(input_vertices[input_faces[f_id][2]], t)}}; // -// cout<<"covered_fs_infos[f_id].size = "<"; -// cout<<"f_id = "<"; + // cout<<"f_id = "< t_vs = {{mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos, - mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos, - mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos}}; - std::array t_vs_2d = {{to_2d(mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos, t), - to_2d(mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos, t), - to_2d(mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos, t)}}; -// int k = -1; -// for (int r = 0; r < 3; r++) { -// if(is_p_inside_tri_2d(t_vs_2d[r], f_vs_2d)) -// continue; -// double dist_2 = GEO::Geom::point_triangle_squared_distance( -// GEO::vec3(t_vs[r][0], t_vs[r][1], t_vs[r][2]), -// GEO::vec3(f_vs[0][0], f_vs[0][1], f_vs[0][2]), -// GEO::vec3(f_vs[1][0], f_vs[1][1], f_vs[1][2]), -// GEO::vec3(f_vs[2][0], f_vs[2][1], f_vs[2][2])); -// if (dist_2 > mesh.params.eps_2) { -//// cout << "r = " << r << endl; -//// cout << "dist_2 = " << dist_2 << endl; -// k = r; -// break; -// } -// } -// if (k < 0) -// continue; -// bool is_out = true; -// for (int j = 0; j < 3; j++) { -// int ori_out = Predicates::orient_2d(f_vs_2d[j], f_vs_2d[(j + 1) % 3], t_vs_2d[k]); -//// cout << "ori_out = " << ori_out << endl; -// is_out = true; -// for (int r = 0; r < 3; r++) { -// int ori_r = Predicates::orient_2d(f_vs_2d[j], f_vs_2d[(j + 1) % 3], t_vs_2d[r]); -//// cout << "ori_r = " << ori_r << endl; -// if (ori_r == ori_out || ori_r == Predicates::ORI_ZERO) -// continue; -// double dist_2 = p_line_squared_dist_3d(t_vs[r], f_vs[j], f_vs[(j + 1) % 3]); -//// cout << "dist_2 = " << dist_2 << "; " << mesh.params.eps_2_coplanar << endl; -// if (dist_2 <= mesh.params.eps_2_coplanar) -// continue; -// is_out = false; -// break; -// } -// if (is_out) { -// break; -// } -// } - Vector2 c = (t_vs_2d[0]+t_vs_2d[1]+t_vs_2d[2])/3; - if(!is_p_inside_tri_2d(c, f_vs_2d)){ + int t_id = covered_fs_infos[f_id][n].first; + int j = covered_fs_infos[f_id][n].second; + std::array t_vs = {{mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos, + mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos, + mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos}}; + std::array t_vs_2d = { + {to_2d(mesh.tet_vertices[mesh.tets[t_id][(j + 1) % 4]].pos, t), + to_2d(mesh.tet_vertices[mesh.tets[t_id][(j + 2) % 4]].pos, t), + to_2d(mesh.tet_vertices[mesh.tets[t_id][(j + 3) % 4]].pos, t)}}; + // int k = -1; + // for (int r = 0; r < 3; r++) { + // if(is_p_inside_tri_2d(t_vs_2d[r], f_vs_2d)) + // continue; + // double dist_2 = GEO::Geom::point_triangle_squared_distance( + // GEO::vec3(t_vs[r][0], t_vs[r][1], t_vs[r][2]), + // GEO::vec3(f_vs[0][0], f_vs[0][1], f_vs[0][2]), + // GEO::vec3(f_vs[1][0], f_vs[1][1], f_vs[1][2]), + // GEO::vec3(f_vs[2][0], f_vs[2][1], f_vs[2][2])); + // if (dist_2 > mesh.params.eps_2) { + //// cout << "r = " << r << endl; + //// cout << "dist_2 = " << dist_2 << endl; + // k = r; + // break; + // } + // } + // if (k < 0) + // continue; + // bool is_out = true; + // for (int j = 0; j < 3; j++) { + // int ori_out = Predicates::orient_2d(f_vs_2d[j], f_vs_2d[(j + 1) % 3], + // t_vs_2d[k]); + //// cout << "ori_out = " << ori_out << endl; + // is_out = true; + // for (int r = 0; r < 3; r++) { + // int ori_r = Predicates::orient_2d(f_vs_2d[j], f_vs_2d[(j + 1) % + // 3], t_vs_2d[r]); + //// cout << "ori_r = " << ori_r << endl; + // if (ori_r == ori_out || ori_r == Predicates::ORI_ZERO) + // continue; + // double dist_2 = p_line_squared_dist_3d(t_vs[r], f_vs[j], f_vs[(j + + // 1) % 3]); + //// cout << "dist_2 = " << dist_2 << "; " << + /// mesh.params.eps_2_coplanar << endl; + // if (dist_2 <= mesh.params.eps_2_coplanar) + // continue; + // is_out = false; + // break; + // } + // if (is_out) { + // break; + // } + // } + Vector2 c = (t_vs_2d[0] + t_vs_2d[1] + t_vs_2d[2]) / 3; + if (!is_p_inside_tri_2d(c, f_vs_2d)) { bool is_crossed = false; - for (int k = 0; k < 3; k++) {//edges of input face + for (int k = 0; k < 3; k++) { // edges of input face std::array oris; - for (int r = 0; r < 3; r++) {//vertices of tet face - oris[r] = Predicates::orient_2d(f_vs_2d[k], f_vs_2d[(k + 1) % 3], t_vs_2d[r]); + for (int r = 0; r < 3; r++) { // vertices of tet face + oris[r] = + Predicates::orient_2d(f_vs_2d[k], f_vs_2d[(k + 1) % 3], t_vs_2d[r]); if (oris[r] == Predicates::ORI_ZERO) continue; double dist_2 = p_line_squared_dist_3d(t_vs[r], f_vs[k], f_vs[(k + 1) % 3]); @@ -3042,8 +3417,8 @@ void floatTetWild::check_track_surface_fs(Mesh &mesh, std::vector ps; sample_triangle(f_vs, ps, mesh.params.dd); @@ -3069,16 +3444,18 @@ void floatTetWild::check_track_surface_fs(Mesh &mesh, std::vector f = {{mesh.tets[t_id][(j + 1) % 4], mesh.tets[t_id][(j + 2) % 4], - mesh.tets[t_id][(j + 3) % 4]}}; + for (const auto& info : covered_fs_infos[f_id]) { + int t_id = info.first; + int j = info.second; + std::array f = {{mesh.tets[t_id][(j + 1) % 4], + mesh.tets[t_id][(j + 2) % 4], + mesh.tets[t_id][(j + 3) % 4]}}; std::array vs; for (int k = 0; k < 3; k++) { - vs[k] = GEO::vec3(mesh.tet_vertices[f[k]].pos[0], mesh.tet_vertices[f[k]].pos[1], + vs[k] = GEO::vec3(mesh.tet_vertices[f[k]].pos[0], + mesh.tet_vertices[f[k]].pos[1], mesh.tet_vertices[f[k]].pos[2]); } double dis_2 = GEO::Geom::point_triangle_squared_distance(p, vs[0], vs[1], vs[2]); @@ -3096,27 +3473,30 @@ void floatTetWild::check_track_surface_fs(Mesh &mesh, std::vector #include +#include #include #ifdef FLOAT_TETWILD_USE_TBB -#include -#include -#include +#include #endif -void floatTetWild::vertex_smoothing(Mesh& mesh, const AABBWrapper& tree){ - auto &tets = mesh.tets; - auto &tet_vertices = mesh.tet_vertices; +void floatTetWild::vertex_smoothing(Mesh& mesh, const AABBWrapper& tree) +{ + auto& tets = mesh.tets; + auto& tet_vertices = mesh.tet_vertices; #ifdef FLOAT_TETWILD_USE_TBB - //TODO atomic conunter - int counter = 0; - int suc_counter = 0; + // TODO atomic conunter + int counter = 0; + int suc_counter = 0; int suc_counter_sf = 0; #else - int counter = 0; - int suc_counter = 0; + int counter = 0; + int suc_counter = 0; int suc_counter_sf = 0; #endif - const auto smooth_one = [&](const int v_id){ + const auto smooth_one = [&](const int v_id) { if (tet_vertices[v_id].is_removed) return; if (tet_vertices[v_id].is_freezed) @@ -45,63 +44,71 @@ void floatTetWild::vertex_smoothing(Mesh& mesh, const AABBWrapper& tree){ if (!find_new_pos(mesh, v_id, p)) return; -// for (int t_id: tet_vertices[v_id].conn_tets) { -//// if (is_inverted(mesh, t_id)) { -// int j = mesh.tets[t_id].find(v_id); -// if(is_inverted(mesh, t_id, j, p)){ -// cout << "smoothing " << v_id << endl; -// cout << t_id << endl; -// cout<> Ts; -// std::vector js; -// for (int t_id:tet_vertices[v_id].conn_tets) { -// int j = tets[t_id].find(v_id); -// -// bool is_inv = false; -// if (is_inverted(tet_vertices[tets[t_id][j]], tet_vertices[tets[t_id][(j + 1) % 4]], -// tet_vertices[tets[t_id][(j + 2) % 4]], tet_vertices[tets[t_id][(j + 3) % 4]])) { -// is_inv = true; -// } -// -// cout<> Ts; + // std::vector js; + // for (int t_id:tet_vertices[v_id].conn_tets) { + // int j = tets[t_id].find(v_id); + // + // bool is_inv = false; + // if (is_inverted(tet_vertices[tets[t_id][j]], + // tet_vertices[tets[t_id][(j + 1) % 4]], + // tet_vertices[tets[t_id][(j + 2) % 4]], + // tet_vertices[tets[t_id][(j + 3) % 4]])) { + // is_inv = true; + // } + // + // cout< new_qs; if (tet_vertices[v_id].is_on_boundary) { if (!project_and_check(mesh, v_id, p, tree, false, new_qs)) @@ -111,7 +118,8 @@ void floatTetWild::vertex_smoothing(Mesh& mesh, const AABBWrapper& tree){ else if (is_out_envelope(mesh, v_id, p, tree)) return; suc_counter_sf++; - } else if (tet_vertices[v_id].is_on_surface) { + } + else if (tet_vertices[v_id].is_on_surface) { if (!project_and_check(mesh, v_id, p, tree, true, new_qs)) return; if (is_out_envelope(mesh, v_id, p, tree)) @@ -120,13 +128,12 @@ void floatTetWild::vertex_smoothing(Mesh& mesh, const AABBWrapper& tree){ } suc_counter++; - ////real update tet_vertices[v_id].pos = p; - //quality + // quality int cnt = 0; - for (int t_id: tet_vertices[v_id].conn_tets) { + for (int t_id : tet_vertices[v_id].conn_tets) { if (!new_qs.empty()) tets[t_id].quality = new_qs[cnt++]; else @@ -136,13 +143,14 @@ void floatTetWild::vertex_smoothing(Mesh& mesh, const AABBWrapper& tree){ #ifdef FLOAT_TETWILD_USE_TBB std::vector> concurrent_sets; - std::vector serial_set; - // mesh.one_ring_vertex_sets(tbb::task_scheduler_init::default_num_threads()*2, concurrent_sets, serial_set); - mesh.one_ring_vertex_sets(mesh.params.num_threads*2, concurrent_sets, serial_set); - - for(const auto &s : concurrent_sets){ - tbb::parallel_for( size_t(0), size_t(s.size()), [&]( size_t i ){ - // for(int i = 0; i < s.size(); ++i) + std::vector serial_set; + // mesh.one_ring_vertex_sets(tbb::task_scheduler_init::default_num_threads()*2, concurrent_sets, + // serial_set); + mesh.one_ring_vertex_sets(mesh.params.num_threads * 2, concurrent_sets, serial_set); + + for (const auto& s : concurrent_sets) { + tbb::parallel_for(size_t(0), size_t(s.size()), [&](size_t i) { + // for(int i = 0; i < s.size(); ++i) smooth_one(s[i]); }); } @@ -154,39 +162,47 @@ void floatTetWild::vertex_smoothing(Mesh& mesh, const AABBWrapper& tree){ smooth_one(v_id); #endif - cout<<"success = "<& new_qs) { - //project to surface - if(is_sf) +bool floatTetWild::project_and_check(Mesh& mesh, + int v_id, + Vector3& p, + const AABBWrapper& tree, + bool is_sf, + std::vector& new_qs) +{ + // project to surface + if (is_sf) tree.project_to_sf(p); else { - if(mesh.is_input_all_inserted) + if (mesh.is_input_all_inserted) tree.project_to_b(p); else tree.project_to_tmp_b(p); } -// GEO::vec3 np_; -// double _; -// tree.nearest_facet(GEO::vec3(p[0], p[1], p[2]), np_, _); -// np[0] = np_[0]; -// np[1] = np_[1]; -// np[2] = np_[2]; + // GEO::vec3 np_; + // double _; + // tree.nearest_facet(GEO::vec3(p[0], p[1], p[2]), np_, _); + // np[0] = np_[0]; + // np[1] = np_[1]; + // np[2] = np_[2]; - //check inversion & quality + // check inversion & quality double max_q = 0; - for (int t_id: mesh.tet_vertices[v_id].conn_tets) { + for (int t_id : mesh.tet_vertices[v_id].conn_tets) { if (mesh.tets[t_id].quality > max_q) max_q = mesh.tets[t_id].quality; } - for (int t_id: mesh.tet_vertices[v_id].conn_tets) { - auto &t = mesh.tets[t_id]; - int j = t.find(v_id); - if(is_inverted(mesh, t_id, j, p)) + for (int t_id : mesh.tet_vertices[v_id].conn_tets) { + auto& t = mesh.tets[t_id]; + int j = t.find(v_id); + if (is_inverted(mesh, t_id, j, p)) return false; - Scalar new_q = get_quality(p, mesh.tet_vertices[t[(j + 1) % 4]].pos, mesh.tet_vertices[t[(j + 2) % 4]].pos, + Scalar new_q = get_quality(p, + mesh.tet_vertices[t[(j + 1) % 4]].pos, + mesh.tet_vertices[t[(j + 2) % 4]].pos, mesh.tet_vertices[t[(j + 3) % 4]].pos); if (new_q > max_q) return false; @@ -196,25 +212,28 @@ bool floatTetWild::project_and_check(Mesh& mesh, int v_id, Vector3& p, const AAB return true; } -bool floatTetWild::find_new_pos(Mesh& mesh, const int v_id, Vector3& x) { - auto &tets = mesh.tets; - auto &tet_vertices = mesh.tet_vertices; +bool floatTetWild::find_new_pos(Mesh& mesh, const int v_id, Vector3& x) +{ + auto& tets = mesh.tets; + auto& tet_vertices = mesh.tet_vertices; std::vector js; js.reserve(tet_vertices[v_id].conn_tets.size()); std::vector> Ts; - for (int t_id:tet_vertices[v_id].conn_tets) { + for (int t_id : tet_vertices[v_id].conn_tets) { int j = tets[t_id].find(v_id); js.push_back(j); std::array loop_ids = {{0, 1, 2, 3}}; - if (is_inverted(tet_vertices[tets[t_id][j]], tet_vertices[tets[t_id][(j + 1) % 4]], - tet_vertices[tets[t_id][(j + 2) % 4]], tet_vertices[tets[t_id][(j + 3) % 4]])) + if (is_inverted(tet_vertices[tets[t_id][j]], + tet_vertices[tets[t_id][(j + 1) % 4]], + tet_vertices[tets[t_id][(j + 2) % 4]], + tet_vertices[tets[t_id][(j + 3) % 4]])) std::swap(loop_ids[2], loop_ids[3]); std::array T; for (int k = 0; k < loop_ids.size(); k++) { - T[k * 3] = tet_vertices[tets[t_id][(j + loop_ids[k]) % 4]].pos[0]; + T[k * 3] = tet_vertices[tets[t_id][(j + loop_ids[k]) % 4]].pos[0]; T[k * 3 + 1] = tet_vertices[tets[t_id][(j + loop_ids[k]) % 4]].pos[1]; T[k * 3 + 2] = tet_vertices[tets[t_id][(j + loop_ids[k]) % 4]].pos[2]; } @@ -222,53 +241,53 @@ bool floatTetWild::find_new_pos(Mesh& mesh, const int v_id, Vector3& x) { } ////newton - const int max_newton_it = 15; - const int max_search_it = 10; - const Scalar f_delta = 1e-8; - const Scalar J_delta = 1e-8; + const int max_newton_it = 15; + const int max_search_it = 10; + const Scalar f_delta = 1e-8; + const Scalar J_delta = 1e-8; x = tet_vertices[v_id].pos; Vector3 J; Matrix3 H; -// Scalar f_old, f_new; -// int it; + // Scalar f_old, f_new; + // int it; for (int newton_it = 0; newton_it < max_newton_it; newton_it++) { if (newton_it > 0) { - for (auto &T:Ts) { + for (auto& T : Ts) { T[0] = x(0); T[1] = x(1); T[2] = x(2); } } - //f + // f Scalar f = 0; - for (auto &T:Ts) { + for (auto& T : Ts) { f += AMIPS_energy(T); } -// if(newton_it == 0) -// f_old = f; -// f_new = f; -// it = newton_it; -// cout<= f) { a /= 2; continue; @@ -330,4 +349,4 @@ bool floatTetWild::find_new_pos(Mesh& mesh, const int v_id, Vector3& x) { if (x != tet_vertices[v_id].pos) return true; return false; -} \ No newline at end of file +} diff --git a/src/main.cpp b/src/main.cpp index 7649e475..e260618f 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,7 +9,7 @@ #include #ifdef FLOAT_TETWILD_USE_TBB -#include +#include #include #endif @@ -268,13 +268,8 @@ int main(int argc, char** argv) } #ifdef FLOAT_TETWILD_USE_TBB - const size_t MB = 1024 * 1024; - const size_t stack_size = 64 * MB; - unsigned int num_threads = std::max(1u, std::thread::hardware_concurrency()); - num_threads = std::min(max_threads, num_threads); - params.num_threads = num_threads; - std::cout << "TBB threads " << num_threads << std::endl; - tbb::task_scheduler_init scheduler(num_threads, stack_size); + const size_t MB = 1024 * 1024; + const size_t stack_size = 64 * MB; #endif // if(params.is_quiet){ @@ -321,47 +316,11 @@ int main(int argc, char** argv) values = mshLoader.get_node_field("values"); } if (V_in.rows() != 0 && T_in.rows() != 0 && values.rows() != 0) { - params.apply_sizing_field = true; - params.get_sizing_field_value = [&V_in, &T_in, &values](const Vector3& p) { - GEO::Mesh bg_mesh; - bg_mesh.vertices.clear(); - bg_mesh.vertices.create_vertices((int)V_in.rows() / 3); - for (int i = 0; i < V_in.rows() / 3; i++) { - GEO::vec3& p = bg_mesh.vertices.point(i); - for (int j = 0; j < 3; j++) - p[j] = V_in(i * 3 + j); - } - bg_mesh.cells.clear(); - bg_mesh.cells.create_tets((int)T_in.rows() / 4); - for (int i = 0; i < T_in.rows() / 4; i++) { - for (int j = 0; j < 4; j++) - bg_mesh.cells.set_vertex(i, j, T_in(i * 4 + j)); - } + params.apply_sizing_field = true; - GEO::MeshCellsAABB bg_aabb(bg_mesh, false); - GEO::vec3 geo_p(p[0], p[1], p[2]); - int bg_t_id = bg_aabb.containing_tet(geo_p); - if (bg_t_id == GEO::MeshCellsAABB::NO_TET) - return -1.; - - // compute barycenter - std::array vs; - for (int j = 0; j < 4; j++) { - vs[j] = Vector3(V_in(T_in(bg_t_id * 4 + j) * 3), - V_in(T_in(bg_t_id * 4 + j) * 3 + 1), - V_in(T_in(bg_t_id * 4 + j) * 3 + 2)); - } - double value = 0; - for (int j = 0; j < 4; j++) { - Vector3 n = ((vs[(j + 1) % 4] - vs[j]).cross(vs[(j + 2) % 4] - vs[j])).normalized(); - double d = (vs[(j + 3) % 4] - vs[j]).dot(n); - if (d == 0) - continue; - double weight = abs((p - vs[j]).dot(n) / d); - value += weight * values(T_in(bg_t_id * 4 + (j + 3) % 4)); - } - return value; // / mesh.params.ideal_edge_length; - }; + params.V_sizing_field = V_in; + params.T_sizing_field = T_in; + params.values_sizing_field = values; } /// set input tage @@ -677,26 +636,26 @@ int main(int argc, char** argv) return EXIT_SUCCESS; } -//#include -//#include -//#include -// void connect_2_meshes(std::string m1, std::string m2, std::string m) { -// Eigen::MatrixXd v1, v2, _; -// Eigen::MatrixXi f1, f2; +// #include +// #include +// #include +// void connect_2_meshes(std::string m1, std::string m2, std::string m) { +// Eigen::MatrixXd v1, v2, _; +// Eigen::MatrixXi f1, f2; // -// igl::readSTL(m1, v1, f1, _); -// igl::readSTL(m2, v2, f2, _); +// igl::readSTL(m1, v1, f1, _); +// igl::readSTL(m2, v2, f2, _); // -// MatrixXd V(v1.rows() + v2.rows(), v1.cols()); -// V << v1, v2; +// MatrixXd V(v1.rows() + v2.rows(), v1.cols()); +// V << v1, v2; // -// int v1_rows = v1.rows(); -// for (int i = 0; i < f2.rows(); i++) { -// for (int j = 0; j < 3; j++) -// f2(i, j) += v1_rows; -// } -// MatrixXi F(f1.rows() + f2.rows(), f1.cols()); -// F << f1, f2; +// int v1_rows = v1.rows(); +// for (int i = 0; i < f2.rows(); i++) { +// for (int j = 0; j < 3; j++) +// f2(i, j) += v1_rows; +// } +// MatrixXi F(f1.rows() + f2.rows(), f1.cols()); +// F << f1, f2; // //// igl::writeOFF(m+".off", V, F); // igl::writeSTL(m+".stl", V, F); @@ -710,7 +669,7 @@ int main(int argc, char** argv) // //pausee(); //} // -//#include +// #include // void test_manifold(std::string& file_name){ // Eigen::MatrixXd V; // Eigen::MatrixXi T, F; @@ -721,4 +680,4 @@ int main(int argc, char** argv) // Eigen::MatrixXd V_sf; // Eigen::MatrixXi F_sf; // manifold_surface(mesh, V_sf, F_sf); -//} +//} \ No newline at end of file From 4996d6716391c8009e4e4ff7f93b930f617524ad Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sat, 21 Dec 2024 21:24:58 +0100 Subject: [PATCH 05/70] remove -Wfatal-errors --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe69b6d7..69b27a68 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,8 +22,6 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -add_compile_options(-Wfatal-errors) - # Color output include(UseColors) From dc2412be7eb343e85eb12289859ec7910dee7832 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Sat, 4 Jan 2025 23:55:35 +0100 Subject: [PATCH 06/70] set c++11 --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69b27a68..27272064 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,6 +102,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR}/include) target_link_libraries(${PROJECT_NAME} PRIVATE warnings::all) # Use C++11 +set(CMAKE_CXX_STANDARD 11) # C++11... target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) # if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") # target_compile_options(${PROJECT_NAME} PUBLIC "/Zc:__cplusplus") endif() From 725fdc3abfacfde2096496eb0b16f9db5e9b6293 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Mon, 6 Jan 2025 15:10:26 +0100 Subject: [PATCH 07/70] make c++17 conforming --- src/TriangleInsertion.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/TriangleInsertion.cpp b/src/TriangleInsertion.cpp index 66a77a98..bc4b1689 100644 --- a/src/TriangleInsertion.cpp +++ b/src/TriangleInsertion.cpp @@ -9,6 +9,8 @@ // // Created by Yixin Hu on 2019-08-27. // +#include // for std::shuffle +#include // for std::random_device and std::mt19937 #include @@ -143,8 +145,11 @@ void floatTetWild::sort_input_faces(const std::vector& input_vertices, if (mesh.params.not_sort_input) return; + std::random_device rd; // obtain a random number from hardware + std::mt19937 g(rd()); // seed the generator + + std::shuffle(sorted_f_ids.begin(), sorted_f_ids.end(), g); - std::random_shuffle(sorted_f_ids.begin(), sorted_f_ids.end()); // std::sort(sorted_f_ids.begin(), sorted_f_ids.end(), [&weights](int a, int b) { // return weights[a] < weights[b]; // }); From 0be11bd66d9283bafdff8ac7ef7490cec5eb560e Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Fri, 17 Jan 2025 13:40:40 +0100 Subject: [PATCH 08/70] use windingnumber from (updated) libigl --- CMakeLists.txt | 3 +- cmake/FloatTetwildDependencies.cmake | 2 +- cmake/FloatTetwildDownloadExternal.cmake | 13 +- src/external/CMakeLists.txt | 3 - src/external/FastWindingNumber.cpp | 2 +- src/external/WindingNumber.h | 7401 ---------------------- 6 files changed, 11 insertions(+), 7413 deletions(-) delete mode 100644 src/external/WindingNumber.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 27272064..40d20e25 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ endif() # Setup dependencies include(FloatTetwildDependencies) +igl_include(predicates) # ############################################################################## # FloatTetwild library @@ -89,7 +90,7 @@ endif() # MPFR") ENDIF() # add_library() can only be called without any source since CMake 3.11 ... -add_library(${PROJECT_NAME} src/Logger.cpp src/external/WindingNumber.h) +add_library(${PROJECT_NAME} src/Logger.cpp) # Public include directory for FloatTetwild target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR}/include) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index 861e074e..a47799e5 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -71,7 +71,7 @@ if(FLOAT_TETWILD_ENABLE_TBB AND NOT TARGET TBB::tbb) set(TBB_BUILD_TBBMALLOC_PROXY OFF CACHE BOOL " " FORCE) - set(TBB_BUILD_TESTS + set(TBB_TEST OFF CACHE BOOL " " FORCE) set(TBB_NO_DATE diff --git a/cmake/FloatTetwildDownloadExternal.cmake b/cmake/FloatTetwildDownloadExternal.cmake index f9a5167f..574fced4 100644 --- a/cmake/FloatTetwildDownloadExternal.cmake +++ b/cmake/FloatTetwildDownloadExternal.cmake @@ -26,12 +26,13 @@ endfunction() # ############################################################################## -# libigl -function(float_tetwild_download_libigl) - float_tetwild_download_project( - libigl GIT_REPOSITORY https://github.com/libigl/libigl.git GIT_TAG - 45cfc79fede992ea3923ded9de3c21d1c4faced1) -endfunction() +include(FetchContent) +FetchContent_Declare( + libigl + GIT_REPOSITORY https://github.com/libigl/libigl.git GIT_TAG + 687530283c01b91de5795959281d4cdc36f7ca1b +) +FetchContent_MakeAvailable(libigl) # Json function(float_tetwild_download_json) diff --git a/src/external/CMakeLists.txt b/src/external/CMakeLists.txt index c610ba34..1e2b4e5c 100644 --- a/src/external/CMakeLists.txt +++ b/src/external/CMakeLists.txt @@ -27,8 +27,6 @@ if(FLOAT_TETWILD_WITH_EXACT_ENVELOPE ) FastWindingNumber.cpp Rational.h - - WindingNumber.h ) else() set(SOURCES @@ -55,7 +53,6 @@ else() bfs_orient.h bfs_orient.cpp - WindingNumber.h FastWindingNumber.hpp FastWindingNumber.cpp diff --git a/src/external/FastWindingNumber.cpp b/src/external/FastWindingNumber.cpp index f18bd29f..a47d12f2 100644 --- a/src/external/FastWindingNumber.cpp +++ b/src/external/FastWindingNumber.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include //#include #include diff --git a/src/external/WindingNumber.h b/src/external/WindingNumber.h deleted file mode 100644 index 9755f6ba..00000000 --- a/src/external/WindingNumber.h +++ /dev/null @@ -1,7401 +0,0 @@ -// This header created by issuing: `echo "// This header created by issuing: \`$BASH_COMMAND\` $(echo "" | cat - LICENSE README.md | sed -e "s#^..*#\/\/ &#") $(echo "" | cat - SYS_Types.h SYS_Math.h VM_SSEFunc.h VM_SIMD.h UT_Array.h UT_ArrayImpl.h UT_SmallArray.h UT_FixedVector.h UT_ParallelUtil.h UT_BVH.h UT_BVHImpl.h UT_SolidAngle.h UT_Array.cpp UT_SolidAngle.cpp | sed -e "s/^#.*include *\".*$//g")"` -// MIT License - -// Copyright (c) 2018 Side Effects Software Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// # Fast Winding Numbers for Soups - -// https://github.com/alecjacobson/WindingNumber - -// Implementation of the _ACM SIGGRAPH_ 2018 paper, - -// "Fast Winding Numbers for Soups and Clouds" - -// Gavin Barill¹, Neil Dickson², Ryan Schmidt³, David I.W. Levin¹, Alec Jacobson¹ - -// ¹University of Toronto, ²SideFX, ³Gradient Space - - -// _Note: this implementation is for triangle soups only, not point clouds._ - -// This version does _not_ depend on Intel TBB. Instead it depends on -// [libigl](https://github.com/libigl/libigl)'s simpler `igl::parallel_for` (which -// uses `std::thread`) - -// This code, as written, depends on Intel's Threading Building Blocks (TBB) library for parallelism, but it should be fairly easy to change it to use any other means of threading, since it only uses parallel for loops with simple partitioning. - -// The main class of interest is UT_SolidAngle and its init and computeSolidAngle functions, which you can use by including UT_SolidAngle.h, and whose implementation is mostly in UT_SolidAngle.cpp, using a 4-way bounding volume hierarchy (BVH) implemented in the UT_BVH.h and UT_BVHImpl.h headers. The rest of the files are mostly various supporting code. UT_SubtendedAngle, for computing angles subtended by 2D curves, can also be found in UT_SolidAngle.h and UT_SolidAngle.cpp . - -// An example of very similar code and how to use it to create a geometry operator (SOP) in Houdini can be found in the HDK examples (toolkit/samples/SOP/SOP_WindingNumber) for Houdini 16.5.121 and later. Query points go in the first input and the mesh geometry goes in the second input. - - -// Create a single header using: - -// echo "// This header created by issuing: \`$BASH_COMMAND\` $(echo "" | cat - LICENSE README.md | sed -e "s#^..*#\/\/ &#") $(echo "" | cat - SYS_Types.h SYS_Math.h VM_SSEFunc.h VM_SIMD.h UT_Array.h UT_ArrayImpl.h UT_SmallArray.h UT_FixedVector.h UT_ParallelUtil.h UT_BVH.h UT_BVHImpl.h UT_SolidAngle.h UT_Array.cpp UT_SolidAngle.cpp | sed -e "s/^#.*include *\".*$//g")" -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * Common type definitions. - */ - -#pragma once - -#ifndef __SYS_Types__ -#define __SYS_Types__ - -/* Include system types */ -#include -#include -#include -#include - -namespace igl { namespace FastWindingNumber { - -/* - * Integer types - */ - typedef signed char int8; - typedef unsigned char uint8; - typedef short int16; - typedef unsigned short uint16; - typedef int int32; - typedef unsigned int uint32; - -#ifndef MBSD - typedef unsigned int uint; -#endif - -/* - * Avoid using uint64. - * The extra bit of precision is NOT worth the cost in pain and suffering - * induced by use of unsigned. - */ -#if defined(_WIN32) - typedef __int64 int64; - typedef unsigned __int64 uint64; -#elif defined(MBSD) - // On MBSD, int64/uint64 are also defined in the system headers so we must - // declare these in the same way or else we get conflicts. - typedef int64_t int64; - typedef uint64_t uint64; -#elif defined(AMD64) - typedef long int64; - typedef unsigned long uint64; -#else - typedef long long int64; - typedef unsigned long long uint64; -#endif - -/// The problem with int64 is that it implies that it is a fixed 64-bit quantity -/// that is saved to disk. Therefore, we need another integral type for -/// indexing our arrays. - typedef int64 exint; - -/// Mark function to be inlined. If this is done, taking the address of such -/// a function is not allowed. -#if defined(__GNUC__) || defined(__clang__) -#define SYS_FORCE_INLINE __attribute__ ((always_inline)) inline -#elif defined(_MSC_VER) -#define SYS_FORCE_INLINE __forceinline -#else -#define SYS_FORCE_INLINE inline -#endif - -/// Floating Point Types - typedef float fpreal32; - typedef double fpreal64; - -/// SYS_FPRealUnionT for type-safe casting with integral types - template - union SYS_FPRealUnionT; - - template <> - union SYS_FPRealUnionT - { - typedef int32 int_type; - typedef uint32 uint_type; - typedef fpreal32 fpreal_type; - - enum { - EXPONENT_BITS = 8, - MANTISSA_BITS = 23, - EXPONENT_BIAS = 127 }; - - int_type ival; - uint_type uval; - fpreal_type fval; - - struct - { - uint_type mantissa_val: 23; - uint_type exponent_val: 8; - uint_type sign_val: 1; - }; - }; - - template <> - union SYS_FPRealUnionT - { - typedef int64 int_type; - typedef uint64 uint_type; - typedef fpreal64 fpreal_type; - - enum { - EXPONENT_BITS = 11, - MANTISSA_BITS = 52, - EXPONENT_BIAS = 1023 }; - - int_type ival; - uint_type uval; - fpreal_type fval; - - struct - { - uint_type mantissa_val: 52; - uint_type exponent_val: 11; - uint_type sign_val: 1; - }; - }; - - typedef union SYS_FPRealUnionT SYS_FPRealUnionF; - typedef union SYS_FPRealUnionT SYS_FPRealUnionD; - -/// Asserts are disabled -/// @{ -#define UT_ASSERT_P(ZZ) ((void)0) -#define UT_ASSERT(ZZ) ((void)0) -#define UT_ASSERT_MSG_P(ZZ, MM) ((void)0) -#define UT_ASSERT_MSG(ZZ, MM) ((void)0) -/// @} - }} - -#endif -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * Miscellaneous math functions. - */ - -#pragma once - -#ifndef __SYS_Math__ -#define __SYS_Math__ - - - -#include -#include -#include - -namespace igl { namespace FastWindingNumber { - -// NOTE: -// These have been carefully written so that in the case of equality -// we always return the first parameter. This is so that NANs in -// in the second parameter are suppressed. -#define h_min(a, b) (((a) > (b)) ? (b) : (a)) -#define h_max(a, b) (((a) < (b)) ? (b) : (a)) -// DO NOT CHANGE THE ABOVE WITHOUT READING THE COMMENT -#define h_abs(a) (((a) > 0) ? (a) : -(a)) - - static constexpr inline int16 SYSmin(int16 a, int16 b) { return h_min(a,b); } - static constexpr inline int16 SYSmax(int16 a, int16 b) { return h_max(a,b); } - static constexpr inline int16 SYSabs(int16 a) { return h_abs(a); } - static constexpr inline int32 SYSmin(int32 a, int32 b) { return h_min(a,b); } - static constexpr inline int32 SYSmax(int32 a, int32 b) { return h_max(a,b); } - static constexpr inline int32 SYSabs(int32 a) { return h_abs(a); } - static constexpr inline int64 SYSmin(int64 a, int64 b) { return h_min(a,b); } - static constexpr inline int64 SYSmax(int64 a, int64 b) { return h_max(a,b); } - static constexpr inline int64 SYSmin(int32 a, int64 b) { return h_min(a,b); } - static constexpr inline int64 SYSmax(int32 a, int64 b) { return h_max(a,b); } - static constexpr inline int64 SYSmin(int64 a, int32 b) { return h_min(a,b); } - static constexpr inline int64 SYSmax(int64 a, int32 b) { return h_max(a,b); } - static constexpr inline int64 SYSabs(int64 a) { return h_abs(a); } - static constexpr inline uint16 SYSmin(uint16 a, uint16 b) { return h_min(a,b); } - static constexpr inline uint16 SYSmax(uint16 a, uint16 b) { return h_max(a,b); } - static constexpr inline uint32 SYSmin(uint32 a, uint32 b) { return h_min(a,b); } - static constexpr inline uint32 SYSmax(uint32 a, uint32 b) { return h_max(a,b); } - static constexpr inline uint64 SYSmin(uint64 a, uint64 b) { return h_min(a,b); } - static constexpr inline uint64 SYSmax(uint64 a, uint64 b) { return h_max(a,b); } - static constexpr inline fpreal32 SYSmin(fpreal32 a, fpreal32 b) { return h_min(a,b); } - static constexpr inline fpreal32 SYSmax(fpreal32 a, fpreal32 b) { return h_max(a,b); } - static constexpr inline fpreal64 SYSmin(fpreal64 a, fpreal64 b) { return h_min(a,b); } - static constexpr inline fpreal64 SYSmax(fpreal64 a, fpreal64 b) { return h_max(a,b); } - -// Some systems have size_t as a seperate type from uint. Some don't. -#if (defined(LINUX) && defined(IA64)) || defined(MBSD) - static constexpr inline size_t SYSmin(size_t a, size_t b) { return h_min(a,b); } -static constexpr inline size_t SYSmax(size_t a, size_t b) { return h_max(a,b); } -#endif - -#undef h_min -#undef h_max -#undef h_abs - -#define h_clamp(val, min, max, tol) \ - ((val <= min+tol) ? min : ((val >= max-tol) ? max : val)) - - static constexpr inline int - SYSclamp(int v, int min, int max) - { return h_clamp(v, min, max, 0); } - - static constexpr inline uint - SYSclamp(uint v, uint min, uint max) - { return h_clamp(v, min, max, 0); } - - static constexpr inline int64 - SYSclamp(int64 v, int64 min, int64 max) - { return h_clamp(v, min, max, int64(0)); } - - static constexpr inline uint64 - SYSclamp(uint64 v, uint64 min, uint64 max) - { return h_clamp(v, min, max, uint64(0)); } - - static constexpr inline fpreal32 - SYSclamp(fpreal32 v, fpreal32 min, fpreal32 max, fpreal32 tol=(fpreal32)0) - { return h_clamp(v, min, max, tol); } - - static constexpr inline fpreal64 - SYSclamp(fpreal64 v, fpreal64 min, fpreal64 max, fpreal64 tol=(fpreal64)0) - { return h_clamp(v, min, max, tol); } - -#undef h_clamp - - static inline fpreal64 SYSsqrt(fpreal64 arg) - { return ::sqrt(arg); } - static inline fpreal32 SYSsqrt(fpreal32 arg) - { return ::sqrtf(arg); } - static inline fpreal64 SYSatan2(fpreal64 a, fpreal64 b) - { return ::atan2(a, b); } - static inline fpreal32 SYSatan2(fpreal32 a, fpreal32 b) - { return ::atan2(a, b); } - - static inline fpreal32 SYSabs(fpreal32 a) { return ::fabsf(a); } - static inline fpreal64 SYSabs(fpreal64 a) { return ::fabs(a); } - - }} - -#endif -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * SIMD wrapper functions for SSE instructions - */ - -#pragma once - -#ifndef __VM_SSEFunc__ -#define __VM_SSEFunc__ - - - -#if defined(_MSC_VER) -#pragma warning(push) - #pragma warning(disable:4799) -#endif - -#define CPU_HAS_SIMD_INSTR 1 -#define VM_SSE_STYLE 1 - -#include - -#if defined(__SSE4_1__) -#define VM_SSE41_STYLE 1 -#include -#endif - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -namespace igl { namespace FastWindingNumber { - - typedef __m128 v4sf; - typedef __m128i v4si; - -// Plain casting (no conversion) -// MSVC has problems casting between __m128 and __m128i, so we implement a -// custom casting routine specifically for windows. - -#if defined(_MSC_VER) - - static SYS_FORCE_INLINE v4sf -vm_v4sf(const v4si &a) -{ - union { - v4si ival; - v4sf fval; - }; - ival = a; - return fval; -} - -static SYS_FORCE_INLINE v4si -vm_v4si(const v4sf &a) -{ - union { - v4si ival; - v4sf fval; - }; - fval = a; - return ival; -} - -#define V4SF(A) vm_v4sf(A) -#define V4SI(A) vm_v4si(A) - -#else - -#define V4SF(A) (v4sf)A -#define V4SI(A) (v4si)A - -#endif - -#define VM_SHUFFLE_MASK(a0,a1, b0,b1) ((b1)<<6|(b0)<<4 | (a1)<<2|(a0)) - - template - static SYS_FORCE_INLINE v4sf - vm_shuffle(const v4sf &a, const v4sf &b) - { - return _mm_shuffle_ps(a, b, mask); - } - - template - static SYS_FORCE_INLINE v4si - vm_shuffle(const v4si &a, const v4si &b) - { - return V4SI(_mm_shuffle_ps(V4SF(a), V4SF(b), mask)); - } - - template - static SYS_FORCE_INLINE T - vm_shuffle(const T &a, const T &b) - { - return vm_shuffle(a, b); - } - - template - static SYS_FORCE_INLINE T - vm_shuffle(const T &a) - { - return vm_shuffle(a, a); - } - - template - static SYS_FORCE_INLINE T - vm_shuffle(const T &a) - { - return vm_shuffle(a, a); - } - -#if defined(VM_SSE41_STYLE) - - static SYS_FORCE_INLINE v4si -vm_insert(const v4si v, int32 a, int n) -{ - switch (n) - { - case 0: return _mm_insert_epi32(v, a, 0); - case 1: return _mm_insert_epi32(v, a, 1); - case 2: return _mm_insert_epi32(v, a, 2); - case 3: return _mm_insert_epi32(v, a, 3); - } - return v; -} - -static SYS_FORCE_INLINE v4sf -vm_insert(const v4sf v, float a, int n) -{ - switch (n) - { - case 0: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,0,0)); - case 1: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,1,0)); - case 2: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,2,0)); - case 3: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,3,0)); - } - return v; -} - -static SYS_FORCE_INLINE int -vm_extract(const v4si v, int n) -{ - switch (n) - { - case 0: return _mm_extract_epi32(v, 0); - case 1: return _mm_extract_epi32(v, 1); - case 2: return _mm_extract_epi32(v, 2); - case 3: return _mm_extract_epi32(v, 3); - } - return 0; -} - -static SYS_FORCE_INLINE float -vm_extract(const v4sf v, int n) -{ - SYS_FPRealUnionF tmp; - switch (n) - { - case 0: tmp.ival = _mm_extract_ps(v, 0); break; - case 1: tmp.ival = _mm_extract_ps(v, 1); break; - case 2: tmp.ival = _mm_extract_ps(v, 2); break; - case 3: tmp.ival = _mm_extract_ps(v, 3); break; - } - return tmp.fval; -} - -#else - - static SYS_FORCE_INLINE v4si - vm_insert(const v4si v, int32 a, int n) - { - union { v4si vector; int32 comp[4]; }; - vector = v; - comp[n] = a; - return vector; - } - - static SYS_FORCE_INLINE v4sf - vm_insert(const v4sf v, float a, int n) - { - union { v4sf vector; float comp[4]; }; - vector = v; - comp[n] = a; - return vector; - } - - static SYS_FORCE_INLINE int - vm_extract(const v4si v, int n) - { - union { v4si vector; int32 comp[4]; }; - vector = v; - return comp[n]; - } - - static SYS_FORCE_INLINE float - vm_extract(const v4sf v, int n) - { - union { v4sf vector; float comp[4]; }; - vector = v; - return comp[n]; - } - -#endif - - static SYS_FORCE_INLINE v4sf - vm_splats(float a) - { - return _mm_set1_ps(a); - } - - static SYS_FORCE_INLINE v4si - vm_splats(uint32 a) - { - SYS_FPRealUnionF tmp; - tmp.uval = a; - return V4SI(vm_splats(tmp.fval)); - } - - static SYS_FORCE_INLINE v4si - vm_splats(int32 a) - { - SYS_FPRealUnionF tmp; - tmp.ival = a; - return V4SI(vm_splats(tmp.fval)); - } - - static SYS_FORCE_INLINE v4sf - vm_splats(float a, float b, float c, float d) - { - return vm_shuffle<0,2,0,2>( - vm_shuffle<0>(_mm_set_ss(a), _mm_set_ss(b)), - vm_shuffle<0>(_mm_set_ss(c), _mm_set_ss(d))); - } - - static SYS_FORCE_INLINE v4si - vm_splats(uint32 a, uint32 b, uint32 c, uint32 d) - { - SYS_FPRealUnionF af, bf, cf, df; - af.uval = a; - bf.uval = b; - cf.uval = c; - df.uval = d; - return V4SI(vm_splats(af.fval, bf.fval, cf.fval, df.fval)); - } - - static SYS_FORCE_INLINE v4si - vm_splats(int32 a, int32 b, int32 c, int32 d) - { - SYS_FPRealUnionF af, bf, cf, df; - af.ival = a; - bf.ival = b; - cf.ival = c; - df.ival = d; - return V4SI(vm_splats(af.fval, bf.fval, cf.fval, df.fval)); - } - - static SYS_FORCE_INLINE v4si - vm_load(const int32 v[4]) - { - return V4SI(_mm_loadu_ps((const float *)v)); - } - - static SYS_FORCE_INLINE v4sf - vm_load(const float v[4]) - { - return _mm_loadu_ps(v); - } - - static SYS_FORCE_INLINE void - vm_store(float dst[4], v4sf value) - { - _mm_storeu_ps(dst, value); - } - - static SYS_FORCE_INLINE v4sf - vm_negate(v4sf a) - { - return _mm_sub_ps(_mm_setzero_ps(), a); - } - - static SYS_FORCE_INLINE v4sf - vm_abs(v4sf a) - { - return _mm_max_ps(a, vm_negate(a)); - } - - static SYS_FORCE_INLINE v4sf - vm_fdiv(v4sf a, v4sf b) - { - return _mm_mul_ps(a, _mm_rcp_ps(b)); - } - - static SYS_FORCE_INLINE v4sf - vm_fsqrt(v4sf a) - { - return _mm_rcp_ps(_mm_rsqrt_ps(a)); - } - - static SYS_FORCE_INLINE v4sf - vm_madd(v4sf a, v4sf b, v4sf c) - { - return _mm_add_ps(_mm_mul_ps(a, b), c); - } - - static const v4si theSSETrue = vm_splats(0xFFFFFFFF); - - static SYS_FORCE_INLINE bool - vm_allbits(const v4si &a) - { - return _mm_movemask_ps(V4SF(_mm_cmpeq_epi32(a, theSSETrue))) == 0xF; - } - - -#define VM_EXTRACT vm_extract -#define VM_INSERT vm_insert -#define VM_SPLATS vm_splats -#define VM_LOAD vm_load -#define VM_STORE vm_store - -#define VM_CMPLT(A,B) V4SI(_mm_cmplt_ps(A,B)) -#define VM_CMPLE(A,B) V4SI(_mm_cmple_ps(A,B)) -#define VM_CMPGT(A,B) V4SI(_mm_cmpgt_ps(A,B)) -#define VM_CMPGE(A,B) V4SI(_mm_cmpge_ps(A,B)) -#define VM_CMPEQ(A,B) V4SI(_mm_cmpeq_ps(A,B)) -#define VM_CMPNE(A,B) V4SI(_mm_cmpneq_ps(A,B)) - -#define VM_ICMPLT _mm_cmplt_epi32 -#define VM_ICMPGT _mm_cmpgt_epi32 -#define VM_ICMPEQ _mm_cmpeq_epi32 - -#define VM_IADD _mm_add_epi32 -#define VM_ISUB _mm_sub_epi32 - -#define VM_ADD _mm_add_ps -#define VM_SUB _mm_sub_ps -#define VM_MUL _mm_mul_ps -#define VM_DIV _mm_div_ps -#define VM_SQRT _mm_sqrt_ps -#define VM_ISQRT _mm_rsqrt_ps -#define VM_INVERT _mm_rcp_ps -#define VM_ABS vm_abs - -#define VM_FDIV vm_fdiv -#define VM_NEG vm_negate -#define VM_FSQRT vm_fsqrt -#define VM_MADD vm_madd - -#define VM_MIN _mm_min_ps -#define VM_MAX _mm_max_ps - -#define VM_AND _mm_and_si128 -#define VM_ANDNOT _mm_andnot_si128 -#define VM_OR _mm_or_si128 -#define VM_XOR _mm_xor_si128 - -#define VM_ALLBITS vm_allbits - -#define VM_SHUFFLE vm_shuffle - -// Integer to float conversions -#define VM_SSE_ROUND_MASK 0x6000 -#define VM_SSE_ROUND_ZERO 0x6000 -#define VM_SSE_ROUND_UP 0x4000 -#define VM_SSE_ROUND_DOWN 0x2000 -#define VM_SSE_ROUND_NEAR 0x0000 - -#define GETROUND() (_mm_getcsr()&VM_SSE_ROUND_MASK) -#define SETROUND(x) (_mm_setcsr(x|(_mm_getcsr()&~VM_SSE_ROUND_MASK))) - -// The P functions must be invoked before FLOOR, the E functions invoked -// afterwards to reset the state. - -#define VM_P_FLOOR() uint rounding = GETROUND(); \ - SETROUND(VM_SSE_ROUND_DOWN); -#define VM_FLOOR _mm_cvtps_epi32 -#define VM_INT _mm_cvttps_epi32 -#define VM_E_FLOOR() SETROUND(rounding); - -// Float to integer conversion -#define VM_IFLOAT _mm_cvtepi32_ps - }} - -#endif -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * SIMD wrapper classes for 4 floats or 4 ints - */ - -#pragma once - -#ifndef __HDK_VM_SIMD__ -#define __HDK_VM_SIMD__ - - -#include - -//#define FORCE_NON_SIMD - - -namespace igl { namespace FastWindingNumber { - - class v4uf; - - class v4uu { - public: - SYS_FORCE_INLINE v4uu() {} - SYS_FORCE_INLINE v4uu(const v4si &v) : vector(v) {} - SYS_FORCE_INLINE v4uu(const v4uu &v) : vector(v.vector) {} - explicit SYS_FORCE_INLINE v4uu(int32 v) { vector = VM_SPLATS(v); } - explicit SYS_FORCE_INLINE v4uu(const int32 v[4]) - { vector = VM_LOAD(v); } - SYS_FORCE_INLINE v4uu(int32 a, int32 b, int32 c, int32 d) - { vector = VM_SPLATS(a, b, c, d); } - - // Assignment - SYS_FORCE_INLINE v4uu operator=(int32 v) - { vector = v4uu(v).vector; return *this; } - SYS_FORCE_INLINE v4uu operator=(v4si v) - { vector = v; return *this; } - SYS_FORCE_INLINE v4uu operator=(const v4uu &v) - { vector = v.vector; return *this; } - - SYS_FORCE_INLINE void condAssign(const v4uu &val, const v4uu &c) - { *this = (c & val) | ((!c) & *this); } - - // Comparison - SYS_FORCE_INLINE v4uu operator == (const v4uu &v) const - { return v4uu(VM_ICMPEQ(vector, v.vector)); } - SYS_FORCE_INLINE v4uu operator != (const v4uu &v) const - { return ~(*this == v); } - SYS_FORCE_INLINE v4uu operator > (const v4uu &v) const - { return v4uu(VM_ICMPGT(vector, v.vector)); } - SYS_FORCE_INLINE v4uu operator < (const v4uu &v) const - { return v4uu(VM_ICMPLT(vector, v.vector)); } - SYS_FORCE_INLINE v4uu operator >= (const v4uu &v) const - { return ~(*this < v); } - SYS_FORCE_INLINE v4uu operator <= (const v4uu &v) const - { return ~(*this > v); } - - SYS_FORCE_INLINE v4uu operator == (int32 v) const { return *this == v4uu(v); } - SYS_FORCE_INLINE v4uu operator != (int32 v) const { return *this != v4uu(v); } - SYS_FORCE_INLINE v4uu operator > (int32 v) const { return *this > v4uu(v); } - SYS_FORCE_INLINE v4uu operator < (int32 v) const { return *this < v4uu(v); } - SYS_FORCE_INLINE v4uu operator >= (int32 v) const { return *this >= v4uu(v); } - SYS_FORCE_INLINE v4uu operator <= (int32 v) const { return *this <= v4uu(v); } - - // Basic math - SYS_FORCE_INLINE v4uu operator+(const v4uu &r) const - { return v4uu(VM_IADD(vector, r.vector)); } - SYS_FORCE_INLINE v4uu operator-(const v4uu &r) const - { return v4uu(VM_ISUB(vector, r.vector)); } - SYS_FORCE_INLINE v4uu operator+=(const v4uu &r) { return (*this = *this + r); } - SYS_FORCE_INLINE v4uu operator-=(const v4uu &r) { return (*this = *this - r); } - SYS_FORCE_INLINE v4uu operator+(int32 r) const { return *this + v4uu(r); } - SYS_FORCE_INLINE v4uu operator-(int32 r) const { return *this - v4uu(r); } - SYS_FORCE_INLINE v4uu operator+=(int32 r) { return (*this = *this + r); } - SYS_FORCE_INLINE v4uu operator-=(int32 r) { return (*this = *this - r); } - - // logical/bitwise - - SYS_FORCE_INLINE v4uu operator||(const v4uu &r) const - { return v4uu(VM_OR(vector, r.vector)); } - SYS_FORCE_INLINE v4uu operator&&(const v4uu &r) const - { return v4uu(VM_AND(vector, r.vector)); } - SYS_FORCE_INLINE v4uu operator^(const v4uu &r) const - { return v4uu(VM_XOR(vector, r.vector)); } - SYS_FORCE_INLINE v4uu operator!() const - { return *this == v4uu(0); } - - SYS_FORCE_INLINE v4uu operator|(const v4uu &r) const { return *this || r; } - SYS_FORCE_INLINE v4uu operator&(const v4uu &r) const { return *this && r; } - SYS_FORCE_INLINE v4uu operator~() const - { return *this ^ v4uu(0xFFFFFFFF); } - - // component - SYS_FORCE_INLINE int32 operator[](int idx) const { return VM_EXTRACT(vector, idx); } - SYS_FORCE_INLINE void setComp(int idx, int32 v) { vector = VM_INSERT(vector, v, idx); } - - v4uf toFloat() const; - - public: - v4si vector; - }; - - class v4uf { - public: - SYS_FORCE_INLINE v4uf() {} - SYS_FORCE_INLINE v4uf(const v4sf &v) : vector(v) {} - SYS_FORCE_INLINE v4uf(const v4uf &v) : vector(v.vector) {} - explicit SYS_FORCE_INLINE v4uf(float v) { vector = VM_SPLATS(v); } - explicit SYS_FORCE_INLINE v4uf(const float v[4]) - { vector = VM_LOAD(v); } - SYS_FORCE_INLINE v4uf(float a, float b, float c, float d) - { vector = VM_SPLATS(a, b, c, d); } - - // Assignment - SYS_FORCE_INLINE v4uf operator=(float v) - { vector = v4uf(v).vector; return *this; } - SYS_FORCE_INLINE v4uf operator=(v4sf v) - { vector = v; return *this; } - SYS_FORCE_INLINE v4uf operator=(const v4uf &v) - { vector = v.vector; return *this; } - - SYS_FORCE_INLINE void condAssign(const v4uf &val, const v4uu &c) - { *this = (val & c) | (*this & ~c); } - - // Comparison - SYS_FORCE_INLINE v4uu operator == (const v4uf &v) const - { return v4uu(VM_CMPEQ(vector, v.vector)); } - SYS_FORCE_INLINE v4uu operator != (const v4uf &v) const - { return v4uu(VM_CMPNE(vector, v.vector)); } - SYS_FORCE_INLINE v4uu operator > (const v4uf &v) const - { return v4uu(VM_CMPGT(vector, v.vector)); } - SYS_FORCE_INLINE v4uu operator < (const v4uf &v) const - { return v4uu(VM_CMPLT(vector, v.vector)); } - SYS_FORCE_INLINE v4uu operator >= (const v4uf &v) const - { return v4uu(VM_CMPGE(vector, v.vector)); } - SYS_FORCE_INLINE v4uu operator <= (const v4uf &v) const - { return v4uu(VM_CMPLE(vector, v.vector)); } - - SYS_FORCE_INLINE v4uu operator == (float v) const { return *this == v4uf(v); } - SYS_FORCE_INLINE v4uu operator != (float v) const { return *this != v4uf(v); } - SYS_FORCE_INLINE v4uu operator > (float v) const { return *this > v4uf(v); } - SYS_FORCE_INLINE v4uu operator < (float v) const { return *this < v4uf(v); } - SYS_FORCE_INLINE v4uu operator >= (float v) const { return *this >= v4uf(v); } - SYS_FORCE_INLINE v4uu operator <= (float v) const { return *this <= v4uf(v); } - - - // Basic math - SYS_FORCE_INLINE v4uf operator+(const v4uf &r) const - { return v4uf(VM_ADD(vector, r.vector)); } - SYS_FORCE_INLINE v4uf operator-(const v4uf &r) const - { return v4uf(VM_SUB(vector, r.vector)); } - SYS_FORCE_INLINE v4uf operator-() const - { return v4uf(VM_NEG(vector)); } - SYS_FORCE_INLINE v4uf operator*(const v4uf &r) const - { return v4uf(VM_MUL(vector, r.vector)); } - SYS_FORCE_INLINE v4uf operator/(const v4uf &r) const - { return v4uf(VM_DIV(vector, r.vector)); } - - SYS_FORCE_INLINE v4uf operator+=(const v4uf &r) { return (*this = *this + r); } - SYS_FORCE_INLINE v4uf operator-=(const v4uf &r) { return (*this = *this - r); } - SYS_FORCE_INLINE v4uf operator*=(const v4uf &r) { return (*this = *this * r); } - SYS_FORCE_INLINE v4uf operator/=(const v4uf &r) { return (*this = *this / r); } - - SYS_FORCE_INLINE v4uf operator+(float r) const { return *this + v4uf(r); } - SYS_FORCE_INLINE v4uf operator-(float r) const { return *this - v4uf(r); } - SYS_FORCE_INLINE v4uf operator*(float r) const { return *this * v4uf(r); } - SYS_FORCE_INLINE v4uf operator/(float r) const { return *this / v4uf(r); } - SYS_FORCE_INLINE v4uf operator+=(float r) { return (*this = *this + r); } - SYS_FORCE_INLINE v4uf operator-=(float r) { return (*this = *this - r); } - SYS_FORCE_INLINE v4uf operator*=(float r) { return (*this = *this * r); } - SYS_FORCE_INLINE v4uf operator/=(float r) { return (*this = *this / r); } - - // logical/bitwise - - SYS_FORCE_INLINE v4uf operator||(const v4uu &r) const - { return v4uf(V4SF(VM_OR(V4SI(vector), r.vector))); } - SYS_FORCE_INLINE v4uf operator&&(const v4uu &r) const - { return v4uf(V4SF(VM_AND(V4SI(vector), r.vector))); } - SYS_FORCE_INLINE v4uf operator^(const v4uu &r) const - { return v4uf(V4SF(VM_XOR(V4SI(vector), r.vector))); } - SYS_FORCE_INLINE v4uf operator!() const - { return v4uf(V4SF((*this == v4uf(0.0F)).vector)); } - - SYS_FORCE_INLINE v4uf operator||(const v4uf &r) const - { return v4uf(V4SF(VM_OR(V4SI(vector), V4SI(r.vector)))); } - SYS_FORCE_INLINE v4uf operator&&(const v4uf &r) const - { return v4uf(V4SF(VM_AND(V4SI(vector), V4SI(r.vector)))); } - SYS_FORCE_INLINE v4uf operator^(const v4uf &r) const - { return v4uf(V4SF(VM_XOR(V4SI(vector), V4SI(r.vector)))); } - - SYS_FORCE_INLINE v4uf operator|(const v4uu &r) const { return *this || r; } - SYS_FORCE_INLINE v4uf operator&(const v4uu &r) const { return *this && r; } - SYS_FORCE_INLINE v4uf operator~() const - { return *this ^ v4uu(0xFFFFFFFF); } - - SYS_FORCE_INLINE v4uf operator|(const v4uf &r) const { return *this || r; } - SYS_FORCE_INLINE v4uf operator&(const v4uf &r) const { return *this && r; } - - // component - SYS_FORCE_INLINE float operator[](int idx) const { return VM_EXTRACT(vector, idx); } - SYS_FORCE_INLINE void setComp(int idx, float v) { vector = VM_INSERT(vector, v, idx); } - - // more math - SYS_FORCE_INLINE v4uf abs() const { return v4uf(VM_ABS(vector)); } - SYS_FORCE_INLINE v4uf clamp(const v4uf &low, const v4uf &high) const - { return v4uf( - VM_MIN(VM_MAX(vector, low.vector), high.vector)); } - SYS_FORCE_INLINE v4uf clamp(float low, float high) const - { return v4uf(VM_MIN(VM_MAX(vector, - v4uf(low).vector), v4uf(high).vector)); } - SYS_FORCE_INLINE v4uf recip() const { return v4uf(VM_INVERT(vector)); } - - /// This is a lie, it is a signed int. - SYS_FORCE_INLINE v4uu toUnsignedInt() const { return VM_INT(vector); } - SYS_FORCE_INLINE v4uu toSignedInt() const { return VM_INT(vector); } - - v4uu floor() const - { - VM_P_FLOOR(); - v4uu result = VM_FLOOR(vector); - VM_E_FLOOR(); - return result; - } - - /// Returns the integer part of this float, this becomes the - /// 0..1 fractional component. - v4uu splitFloat() - { - v4uu base = toSignedInt(); - *this -= base.toFloat(); - return base; - } - - template - SYS_FORCE_INLINE v4uf swizzle() const - { - return VM_SHUFFLE(vector); - } - - SYS_FORCE_INLINE v4uu isFinite() const - { - // If the exponent is the maximum value, it's either infinite or NaN. - const v4si mask = VM_SPLATS(0x7F800000); - return ~v4uu(VM_ICMPEQ(VM_AND(V4SI(vector), mask), mask)); - } - - public: - v4sf vector; - }; - - SYS_FORCE_INLINE v4uf - v4uu::toFloat() const - { - return v4uf(VM_IFLOAT(vector)); - } - -// -// Custom vector operations -// - - static SYS_FORCE_INLINE v4uf - sqrt(const v4uf &a) - { - return v4uf(VM_SQRT(a.vector)); - } - - static SYS_FORCE_INLINE v4uf - fabs(const v4uf &a) - { - return a.abs(); - } - -// Use this operation to mask disabled values to 0 -// rval = !a ? b : 0; - - static SYS_FORCE_INLINE v4uf - andn(const v4uu &a, const v4uf &b) - { - return v4uf(V4SF(VM_ANDNOT(a.vector, V4SI(b.vector)))); - } - - static SYS_FORCE_INLINE v4uu - andn(const v4uu &a, const v4uu &b) - { - return v4uu(VM_ANDNOT(a.vector, b.vector)); - } - -// rval = a ? b : c; - static SYS_FORCE_INLINE v4uf - ternary(const v4uu &a, const v4uf &b, const v4uf &c) - { - return (b & a) | andn(a, c); - } - - static SYS_FORCE_INLINE v4uu - ternary(const v4uu &a, const v4uu &b, const v4uu &c) - { - return (b & a) | andn(a, c); - } - -// rval = !(a && b) - static SYS_FORCE_INLINE v4uu - nand(const v4uu &a, const v4uu &b) - { - return !v4uu(VM_AND(a.vector, b.vector)); - } - - static SYS_FORCE_INLINE v4uf - vmin(const v4uf &a, const v4uf &b) - { - return v4uf(VM_MIN(a.vector, b.vector)); - } - - static SYS_FORCE_INLINE v4uf - vmax(const v4uf &a, const v4uf &b) - { - return v4uf(VM_MAX(a.vector, b.vector)); - } - - static SYS_FORCE_INLINE v4uf - clamp(const v4uf &a, const v4uf &b, const v4uf &c) - { - return vmax(vmin(a, c), b); - } - - static SYS_FORCE_INLINE v4uf - clamp(const v4uf &a, float b, float c) - { - return vmax(vmin(a, v4uf(c)), v4uf(b)); - } - - static SYS_FORCE_INLINE bool - allbits(const v4uu &a) - { - return vm_allbits(a.vector); - } - - static SYS_FORCE_INLINE bool - anybits(const v4uu &a) - { - return !allbits(~a); - } - - static SYS_FORCE_INLINE v4uf - madd(const v4uf &v, const v4uf &f, const v4uf &a) - { - return v4uf(VM_MADD(v.vector, f.vector, a.vector)); - } - - static SYS_FORCE_INLINE v4uf - madd(const v4uf &v, float f, float a) - { - return v4uf(VM_MADD(v.vector, v4uf(f).vector, v4uf(a).vector)); - } - - static SYS_FORCE_INLINE v4uf - madd(const v4uf &v, float f, const v4uf &a) - { - return v4uf(VM_MADD(v.vector, v4uf(f).vector, a.vector)); - } - - static SYS_FORCE_INLINE v4uf - msub(const v4uf &v, const v4uf &f, const v4uf &s) - { - return madd(v, f, -s); - } - - static SYS_FORCE_INLINE v4uf - msub(const v4uf &v, float f, float s) - { - return madd(v, f, -s); - } - - static SYS_FORCE_INLINE v4uf - lerp(const v4uf &a, const v4uf &b, const v4uf &w) - { - v4uf w1 = v4uf(1.0F) - w; - return madd(a, w1, b*w); - } - - static SYS_FORCE_INLINE v4uf - luminance(const v4uf &r, const v4uf &g, const v4uf &b, - float rw, float gw, float bw) - { - return v4uf(madd(r, v4uf(rw), madd(g, v4uf(gw), b * bw))); - } - - static SYS_FORCE_INLINE float - dot3(const v4uf &a, const v4uf &b) - { - v4uf res = a*b; - return res[0] + res[1] + res[2]; - } - - static SYS_FORCE_INLINE float - dot4(const v4uf &a, const v4uf &b) - { - v4uf res = a*b; - return res[0] + res[1] + res[2] + res[3]; - } - - static SYS_FORCE_INLINE float - length(const v4uf &a) - { - return SYSsqrt(dot3(a, a)); - } - - static SYS_FORCE_INLINE v4uf - normalize(const v4uf &a) - { - return a / length(a); - } - - static SYS_FORCE_INLINE v4uf - cross(const v4uf &a, const v4uf &b) - { - return v4uf(a[1]*b[2] - a[2]*b[1], - a[2]*b[0] - a[0]*b[2], - a[0]*b[1] - a[1]*b[0], 0); - } - -// Currently there is no specific support for signed integers - typedef v4uu v4ui; - -// Assuming that ptr is an array of elements of type STYPE, this operation -// will return the index of the first element that is aligned to (1< -#include -#include -#include - -namespace igl { namespace FastWindingNumber { - - /// This routine describes how to change the size of an array. - /// It must increase the current_size by at least one! - /// - /// Current expected sequence of small sizes: - /// 4, 8, 16, 32, 48, 64, 80, 96, 112, - /// 128, 256, 384, 512, 640, 768, 896, 1024, - /// (increases by approx factor of 1.125 each time after this) - template - static inline T - UTbumpAlloc(T current_size) - { - // NOTE: These must be powers of two. See below. - constexpr T SMALL_ALLOC(16); - constexpr T BIG_ALLOC(128); - - // For small values, we increment by fixed amounts. For - // large values, we increment by one eighth of the current size. - // This prevents n^2 behaviour with allocation one element at a time. - // A factor of 1/8 will waste 1/16 the memory on average, and will - // double the size of the array in approximately 6 reallocations. - if (current_size < T(8)) - { - return (current_size < T(4)) ? T(4) : T(8); - } - if (current_size < T(BIG_ALLOC)) - { - // Snap up to next multiple of SMALL_ALLOC (must be power of 2) - return (current_size + T(SMALL_ALLOC)) & ~T(SMALL_ALLOC-1); - } - if (current_size < T(BIG_ALLOC * 8)) - { - // Snap up to next multiple of BIG_ALLOC (must be power of 2) - return (current_size + T(BIG_ALLOC)) & ~T(BIG_ALLOC-1); - } - - T bump = current_size >> 3; // Divided by 8. - current_size += bump; - return current_size; - } - - template - class UT_Array - { - public: - typedef T value_type; - - typedef int (*Comparator)(const T *, const T *); - - /// Copy constructor. It duplicates the data. - /// It's marked explicit so that it's not accidentally passed by value. - /// You can always pass by reference and then copy it, if needed. - /// If you have a line like: - /// UT_Array a = otherarray; - /// and it really does need to copy instead of referencing, - /// you can rewrite it as: - /// UT_Array a(otherarray); - inline explicit UT_Array(const UT_Array &a); - - /// Move constructor. Steals the working data from the original. - inline UT_Array(UT_Array &&a) noexcept; - - /// Construct based on given capacity and size - UT_Array(exint capacity, exint size) - { - myData = capacity ? allocateCapacity(capacity) : NULL; - if (capacity < size) - size = capacity; - mySize = size; - myCapacity = capacity; - trivialConstructRange(myData, mySize); - } - - /// Construct based on given capacity with a size of 0 - explicit UT_Array(exint capacity = 0) : myCapacity(capacity), mySize(0) - { - myData = capacity ? allocateCapacity(capacity) : NULL; - } - - /// Construct with the contents of an initializer list - inline explicit UT_Array(std::initializer_list init); - - inline ~UT_Array(); - - inline void swap(UT_Array &other); - - /// Append an element to the current elements and return its index in the - /// array, or insert the element at a specified position; if necessary, - /// insert() grows the array to accommodate the element. The insert - /// methods use the assignment operator '=' to place the element into the - /// right spot; be aware that '=' works differently on objects and pointers. - /// The test for duplicates uses the logical equal operator '=='; as with - /// '=', the behaviour of the equality operator on pointers versus objects - /// is not the same. - /// Use the subscript operators instead of insert() if you are appending - /// to the array, or if you don't mind overwriting the element already - /// inserted at the given index. - exint append(void) { return insert(mySize); } - exint append(const T &t) { return appendImpl(t); } - exint append(T &&t) { return appendImpl(std::move(t)); } - inline void append(const T *pt, exint count); - inline void appendMultiple(const T &t, exint count); - inline exint insert(exint index); - exint insert(const T &t, exint i) - { return insertImpl(t, i); } - exint insert(T &&t, exint i) - { return insertImpl(std::move(t), i); } - - /// Adds a new element to the array (resizing if necessary) and forwards - /// the given arguments to T's constructor. - /// NOTE: Unlike append(), the arguments cannot reference any existing - /// elements in the array. Checking for and handling such cases would - /// remove most of the performance gain versus append(T(...)). Debug builds - /// will assert that the arguments are valid. - template - inline exint emplace_back(S&&... s); - - /// Takes another T array and concatenate it onto my end - inline exint concat(const UT_Array &a); - - /// Insert an element "count" times at the given index. Return the index. - inline exint multipleInsert(exint index, exint count); - - /// An alias for unique element insertion at a certain index. Also used by - /// the other insertion methods. - exint insertAt(const T &t, exint index) - { return insertImpl(t, index); } - - /// Return true if given index is valid. - bool isValidIndex(exint index) const - { return (index >= 0 && index < mySize); } - - /// Remove one element from the array given its - /// position in the list, and fill the gap by shifting the elements down - /// by one position. Return the index of the element removed or -1 if - /// the index was out of bounds. - exint removeIndex(exint index) - { - return isValidIndex(index) ? removeAt(index) : -1; - } - void removeLast() - { - if (mySize) removeAt(mySize-1); - } - - /// Remove the range [begin_i,end_i) of elements from the array. - inline void removeRange(exint begin_i, exint end_i); - - /// Remove the range [begin_i, end_i) of elements from this array and place - /// them in the dest array, shrinking/growing the dest array as necessary. - inline void extractRange(exint begin_i, exint end_i, - UT_Array& dest); - - /// Removes all matching elements from the list, shuffling down and changing - /// the size appropriately. - /// Returns the number of elements left. - template - inline exint removeIf(IsEqual is_equal); - - /// Remove all matching elements. Also sets the capacity of the array. - template - void collapseIf(IsEqual is_equal) - { - removeIf(is_equal); - setCapacity(size()); - } - - /// Move howMany objects starting at index srcIndex to destIndex; - /// This method will remove the elements at [srcIdx, srcIdx+howMany) and - /// then insert them at destIdx. This method can be used in place of - /// the old shift() operation. - inline void move(exint srcIdx, exint destIdx, exint howMany); - - /// Cyclically shifts the entire array by howMany - inline void cycle(exint howMany); - - /// Quickly set the array to a single value. - inline void constant(const T &v); - /// Zeros the array if a POD type, else trivial constructs if a class type. - inline void zero(); - - /// The fastest search possible, which does pointer arithmetic to find the - /// index of the element. WARNING: index() does no out-of-bounds checking. - exint index(const T &t) const { return &t - myData; } - exint safeIndex(const T &t) const - { - return (&t >= myData && &t < (myData + mySize)) - ? &t - myData : -1; - } - - /// Set the capacity of the array, i.e. grow it or shrink it. The - /// function copies the data after reallocating space for the array. - inline void setCapacity(exint newcapacity); - void setCapacityIfNeeded(exint mincapacity) - { - if (capacity() < mincapacity) - setCapacity(mincapacity); - } - /// If the capacity is smaller than mincapacity, expand the array - /// to at least mincapacity and to at least a constant factor of the - /// array's previous capacity, to avoid having a linear number of - /// reallocations in a linear number of calls to bumpCapacity. - void bumpCapacity(exint mincapacity) - { - if (capacity() >= mincapacity) - return; - // The following 4 lines are just - // SYSmax(mincapacity, UTbumpAlloc(capacity())), avoiding SYSmax - exint bumped = UTbumpAlloc(capacity()); - exint newcapacity = mincapacity; - if (bumped > mincapacity) - newcapacity = bumped; - setCapacity(newcapacity); - } - - /// First bumpCapacity to ensure that there's space for newsize, - /// expanding either not at all or by at least a constant factor - /// of the array's previous capacity, - /// then set the size to newsize. - void bumpSize(exint newsize) - { - bumpCapacity(newsize); - setSize(newsize); - } - /// NOTE: bumpEntries() will be deprecated in favour of bumpSize() in a - /// future version. - void bumpEntries(exint newsize) - { - bumpSize(newsize); - } - - /// Query the capacity, i.e. the allocated length of the array. - /// NOTE: capacity() >= size(). - exint capacity() const { return myCapacity; } - /// Query the size, i.e. the number of occupied elements in the array. - /// NOTE: capacity() >= size(). - exint size() const { return mySize; } - /// Alias of size(). size() is preferred. - exint entries() const { return mySize; } - /// Returns true iff there are no occupied elements in the array. - bool isEmpty() const { return mySize==0; } - - /// Set the size, the number of occupied elements in the array. - /// NOTE: This will not do bumpCapacity, so if you call this - /// n times to increase the size, it may take - /// n^2 time. - void setSize(exint newsize) - { - if (newsize < 0) - newsize = 0; - if (newsize == mySize) - return; - setCapacityIfNeeded(newsize); - if (mySize > newsize) - trivialDestructRange(myData + newsize, mySize - newsize); - else // newsize > mySize - trivialConstructRange(myData + mySize, newsize - mySize); - mySize = newsize; - } - /// Alias of setSize(). setSize() is preferred. - void entries(exint newsize) - { - setSize(newsize); - } - /// Set the size, but unlike setSize(newsize), this function - /// will not initialize new POD elements to zero. Non-POD data types - /// will still have their constructors called. - /// This function is faster than setSize(ne) if you intend to fill in - /// data for all elements. - void setSizeNoInit(exint newsize) - { - if (newsize < 0) - newsize = 0; - if (newsize == mySize) - return; - setCapacityIfNeeded(newsize); - if (mySize > newsize) - trivialDestructRange(myData + newsize, mySize - newsize); - else if (!isPOD()) // newsize > mySize - trivialConstructRange(myData + mySize, newsize - mySize); - mySize = newsize; - } - - /// Decreases, but never expands, to the given maxsize. - void truncate(exint maxsize) - { - if (maxsize >= 0 && size() > maxsize) - setSize(maxsize); - } - /// Resets list to an empty list. - void clear() { - // Don't call setSize(0) since that would require a valid default - // constructor. - trivialDestructRange(myData, mySize); - mySize = 0; - } - - /// Assign array a to this array by copying each of a's elements with - /// memcpy for POD types, and with copy construction for class types. - inline UT_Array & operator=(const UT_Array &a); - - /// Replace the contents with those from the initializer_list ilist - inline UT_Array & operator=(std::initializer_list ilist); - - /// Move the contents of array a to this array. - inline UT_Array & operator=(UT_Array &&a); - - /// Compare two array and return true if they are equal and false otherwise. - /// Two elements are checked against each other using operator '==' or - /// compare() respectively. - /// NOTE: The capacities of the arrays are not checked when - /// determining whether they are equal. - inline bool operator==(const UT_Array &a) const; - inline bool operator!=(const UT_Array &a) const; - - /// Subscript operator - /// NOTE: This does NOT do any bounds checking unless paranoid - /// asserts are enabled. - T & operator()(exint i) - { - UT_ASSERT_P(i >= 0 && i < mySize); - return myData[i]; - } - /// Const subscript operator - /// NOTE: This does NOT do any bounds checking unless paranoid - /// asserts are enabled. - const T & operator()(exint i) const - { - UT_ASSERT_P(i >= 0 && i < mySize); - return myData[i]; - } - - /// Subscript operator - /// NOTE: This does NOT do any bounds checking unless paranoid - /// asserts are enabled. - T & operator[](exint i) - { - UT_ASSERT_P(i >= 0 && i < mySize); - return myData[i]; - } - /// Const subscript operator - /// NOTE: This does NOT do any bounds checking unless paranoid - /// asserts are enabled. - const T & operator[](exint i) const - { - UT_ASSERT_P(i >= 0 && i < mySize); - return myData[i]; - } - - /// forcedRef(exint) will grow the array if necessary, initializing any - /// new elements to zero for POD types and default constructing for - /// class types. - T & forcedRef(exint i) - { - UT_ASSERT_P(i >= 0); - if (i >= mySize) - bumpSize(i+1); - return myData[i]; - } - - /// forcedGet(exint) does NOT grow the array, and will return default - /// objects for out of bound array indices. - T forcedGet(exint i) const - { - return (i >= 0 && i < mySize) ? myData[i] : T(); - } - - T & last() - { - UT_ASSERT_P(mySize); - return myData[mySize-1]; - } - const T & last() const - { - UT_ASSERT_P(mySize); - return myData[mySize-1]; - } - - T * getArray() const { return myData; } - const T * getRawArray() const { return myData; } - - T * array() { return myData; } - const T * array() const { return myData; } - - T * data() { return myData; } - const T * data() const { return myData; } - - /// This method allows you to swap in a new raw T array, which must be - /// the same size as myCapacity. Use caution with this method. - T * aliasArray(T *newdata) - { T *data = myData; myData = newdata; return data; } - - template - class base_iterator : - public std::iterator - { - public: - typedef IT& reference; - typedef IT* pointer; - - // Note: When we drop gcc 4.4 support and allow range-based for - // loops, we should also drop atEnd(), which means we can drop - // myEnd here. - base_iterator() : myCurrent(NULL), myEnd(NULL) {} - - // Allow iterator to const_iterator conversion - template - base_iterator(const base_iterator &src) - : myCurrent(src.myCurrent), myEnd(src.myEnd) {} - - pointer operator->() const - { return FORWARD ? myCurrent : myCurrent - 1; } - - reference operator*() const - { return FORWARD ? *myCurrent : myCurrent[-1]; } - - reference item() const - { return FORWARD ? *myCurrent : myCurrent[-1]; } - - reference operator[](exint n) const - { return FORWARD ? myCurrent[n] : myCurrent[-n - 1]; } - - /// Pre-increment operator - base_iterator &operator++() - { - if (FORWARD) ++myCurrent; else --myCurrent; - return *this; - } - /// Post-increment operator - base_iterator operator++(int) - { - base_iterator tmp = *this; - if (FORWARD) ++myCurrent; else --myCurrent; - return tmp; - } - /// Pre-decrement operator - base_iterator &operator--() - { - if (FORWARD) --myCurrent; else ++myCurrent; - return *this; - } - /// Post-decrement operator - base_iterator operator--(int) - { - base_iterator tmp = *this; - if (FORWARD) --myCurrent; else ++myCurrent; - return tmp; - } - - base_iterator &operator+=(exint n) - { - if (FORWARD) - myCurrent += n; - else - myCurrent -= n; - return *this; - } - base_iterator operator+(exint n) const - { - if (FORWARD) - return base_iterator(myCurrent + n, myEnd); - else - return base_iterator(myCurrent - n, myEnd); - } - - base_iterator &operator-=(exint n) - { return (*this) += (-n); } - base_iterator operator-(exint n) const - { return (*this) + (-n); } - - bool atEnd() const { return myCurrent == myEnd; } - void advance() { this->operator++(); } - - // Comparators - template - bool operator==(const base_iterator &r) const - { return myCurrent == r.myCurrent; } - - template - bool operator!=(const base_iterator &r) const - { return myCurrent != r.myCurrent; } - - template - bool operator<(const base_iterator &r) const - { - if (FORWARD) - return myCurrent < r.myCurrent; - else - return r.myCurrent < myCurrent; - } - - template - bool operator>(const base_iterator &r) const - { - if (FORWARD) - return myCurrent > r.myCurrent; - else - return r.myCurrent > myCurrent; - } - - template - bool operator<=(const base_iterator &r) const - { - if (FORWARD) - return myCurrent <= r.myCurrent; - else - return r.myCurrent <= myCurrent; - } - - template - bool operator>=(const base_iterator &r) const - { - if (FORWARD) - return myCurrent >= r.myCurrent; - else - return r.myCurrent >= myCurrent; - } - - // Difference operator for std::distance - template - exint operator-(const base_iterator &r) const - { - if (FORWARD) - return exint(myCurrent - r.myCurrent); - else - return exint(r.myCurrent - myCurrent); - } - - - protected: - friend class UT_Array; - base_iterator(IT *c, IT *e) : myCurrent(c), myEnd(e) {} - private: - - IT *myCurrent; - IT *myEnd; - }; - - typedef base_iterator iterator; - typedef base_iterator const_iterator; - typedef base_iterator reverse_iterator; - typedef base_iterator const_reverse_iterator; - typedef const_iterator traverser; // For backward compatibility - - /// Begin iterating over the array. The contents of the array may be - /// modified during the traversal. - iterator begin() - { - return iterator(myData, myData + mySize); - } - /// End iterator. - iterator end() - { - return iterator(myData + mySize, - myData + mySize); - } - - /// Begin iterating over the array. The array may not be modified during - /// the traversal. - const_iterator begin() const - { - return const_iterator(myData, myData + mySize); - } - /// End const iterator. Consider using it.atEnd() instead. - const_iterator end() const - { - return const_iterator(myData + mySize, - myData + mySize); - } - - /// Begin iterating over the array in reverse. - reverse_iterator rbegin() - { - return reverse_iterator(myData + mySize, - myData); - } - /// End reverse iterator. - reverse_iterator rend() - { - return reverse_iterator(myData, myData); - } - /// Begin iterating over the array in reverse. - const_reverse_iterator rbegin() const - { - return const_reverse_iterator(myData + mySize, - myData); - } - /// End reverse iterator. Consider using it.atEnd() instead. - const_reverse_iterator rend() const - { - return const_reverse_iterator(myData, myData); - } - - /// Remove item specified by the reverse_iterator. - void removeItem(const reverse_iterator &it) - { - removeAt(&it.item() - myData); - } - - - /// Very dangerous methods to share arrays. - /// The array is not aware of the sharing, so ensure you clear - /// out the array prior a destructor or setCapacity operation. - void unsafeShareData(UT_Array &src) - { - myData = src.myData; - myCapacity = src.myCapacity; - mySize = src.mySize; - } - void unsafeShareData(T *src, exint srcsize) - { - myData = src; - myCapacity = srcsize; - mySize = srcsize; - } - void unsafeShareData(T *src, exint size, exint capacity) - { - myData = src; - mySize = size; - myCapacity = capacity; - } - void unsafeClearData() - { - myData = NULL; - myCapacity = 0; - mySize = 0; - } - - /// Returns true if the data used by the array was allocated on the heap. - inline bool isHeapBuffer() const - { - return (myData != (T *)(((char*)this) + sizeof(*this))); - } - inline bool isHeapBuffer(T* data) const - { - return (data != (T *)(((char*)this) + sizeof(*this))); - } - - protected: - // Check whether T may have a constructor, destructor, or copy - // constructor. This test is conservative in that some POD types will - // not be recognized as POD by this function. To mark your type as POD, - // use the SYS_DECLARE_IS_POD() macro in SYS_TypeDecorate.h. - static constexpr SYS_FORCE_INLINE bool isPOD() - { - return std::is_pod::value; - } - - /// Implements both append(const T &) and append(T &&) via perfect - /// forwarding. Unlike the variadic emplace_back(), its argument may be a - /// reference to another element in the array. - template - inline exint appendImpl(S &&s); - - /// Similar to appendImpl() but for insertion. - template - inline exint insertImpl(S &&s, exint index); - - // Construct the given type - template - static void construct(T &dst, S&&... s) - { - new (&dst) T(std::forward(s)...); - } - - // Copy construct the given type - static void copyConstruct(T &dst, const T &src) - { - if (isPOD()) - dst = src; - else - new (&dst) T(src); - } - static void copyConstructRange(T *dst, const T *src, exint n) - { - if (isPOD()) - { - if (n > 0) - { - ::memcpy((void *)dst, (const void *)src, - n * sizeof(T)); - } - } - else - { - for (exint i = 0; i < n; i++) - new (&dst[i]) T(src[i]); - } - } - - /// Element Constructor - static void trivialConstruct(T &dst) - { - if (!isPOD()) - new (&dst) T(); - else - memset((void *)&dst, 0, sizeof(T)); - } - static void trivialConstructRange(T *dst, exint n) - { - if (!isPOD()) - { - for (exint i = 0; i < n; i++) - new (&dst[i]) T(); - } - else if (n == 1) - { - // Special case for n == 1. If the size parameter - // passed to memset is known at compile time, this - // function call will be inlined. This results in - // much faster performance than a real memset - // function call which is required in the case - // below, where n is not known until runtime. - // This makes calls to append() much faster. - memset((void *)dst, 0, sizeof(T)); - } - else - memset((void *)dst, 0, sizeof(T) * n); - } - - /// Element Destructor - static void trivialDestruct(T &dst) - { - if (!isPOD()) - dst.~T(); - } - static void trivialDestructRange(T *dst, exint n) - { - if (!isPOD()) - { - for (exint i = 0; i < n; i++) - dst[i].~T(); - } - } - - private: - /// Pointer to the array of elements of type T - T *myData; - - /// The number of elements for which we have allocated memory - exint myCapacity; - - /// The actual number of valid elements in the array - exint mySize; - - // The guts of the remove() methods. - inline exint removeAt(exint index); - - inline T * allocateCapacity(exint num_items); - }; - }} - - - -#endif // __UT_ARRAY_H_INCLUDED__ -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * This is meant to be included by UT_Array.h and includes - * the template implementations needed by external code. - */ - -#pragma once - -#ifndef __UT_ARRAYIMPL_H_INCLUDED__ -#define __UT_ARRAYIMPL_H_INCLUDED__ - - - - -#include -#include -#include -#include - -namespace igl { namespace FastWindingNumber { - -// Implemented in UT_Array.C - extern void ut_ArrayImplFree(void *p); - - - template - inline UT_Array::UT_Array(const UT_Array &a) - : myCapacity(a.size()), mySize(a.size()) - { - if (myCapacity) - { - myData = allocateCapacity(myCapacity); - copyConstructRange(myData, a.array(), mySize); - } - else - { - myData = nullptr; - } - } - - template - inline UT_Array::UT_Array(std::initializer_list init) - : myCapacity(init.size()), mySize(init.size()) - { - if (myCapacity) - { - myData = allocateCapacity(myCapacity); - copyConstructRange(myData, init.begin(), mySize); - } - else - { - myData = nullptr; - } - } - - template - inline UT_Array::UT_Array(UT_Array &&a) noexcept - { - if (!a.isHeapBuffer()) - { - myData = nullptr; - myCapacity = 0; - mySize = 0; - operator=(std::move(a)); - return; - } - - myCapacity = a.myCapacity; - mySize = a.mySize; - myData = a.myData; - a.myCapacity = a.mySize = 0; - a.myData = nullptr; - } - - - template - inline UT_Array::~UT_Array() - { - // NOTE: We call setCapacity to ensure that we call trivialDestructRange, - // then call free on myData. - setCapacity(0); - } - - template - inline T * - UT_Array::allocateCapacity(exint capacity) - { - T *data = (T *)malloc(capacity * sizeof(T)); - // Avoid degenerate case if we happen to be aliased the wrong way - if (!isHeapBuffer(data)) - { - T *prev = data; - data = (T *)malloc(capacity * sizeof(T)); - ut_ArrayImplFree(prev); - } - return data; - } - - template - inline void - UT_Array::swap( UT_Array &other ) - { - std::swap( myData, other.myData ); - std::swap( myCapacity, other.myCapacity ); - std::swap( mySize, other.mySize ); - } - - - template - inline exint - UT_Array::insert(exint index) - { - if (index >= mySize) - { - bumpCapacity(index + 1); - - trivialConstructRange(myData + mySize, index - mySize + 1); - - mySize = index+1; - return index; - } - bumpCapacity(mySize + 1); - - UT_ASSERT_P(index >= 0); - ::memmove((void *)&myData[index+1], (void *)&myData[index], - ((mySize-index)*sizeof(T))); - - trivialConstruct(myData[index]); - - mySize++; - return index; - } - - template - template - inline exint - UT_Array::appendImpl(S &&s) - { - if (mySize == myCapacity) - { - exint idx = safeIndex(s); - - // NOTE: UTbumpAlloc always returns a strictly larger value. - setCapacity(UTbumpAlloc(myCapacity)); - if (idx >= 0) - construct(myData[mySize], std::forward(myData[idx])); - else - construct(myData[mySize], std::forward(s)); - } - else - { - construct(myData[mySize], std::forward(s)); - } - return mySize++; - } - - template - template - inline exint - UT_Array::emplace_back(S&&... s) - { - if (mySize == myCapacity) - setCapacity(UTbumpAlloc(myCapacity)); - - construct(myData[mySize], std::forward(s)...); - return mySize++; - } - - template - inline void - UT_Array::append(const T *pt, exint count) - { - bumpCapacity(mySize + count); - copyConstructRange(myData + mySize, pt, count); - mySize += count; - } - - template - inline void - UT_Array::appendMultiple(const T &t, exint count) - { - UT_ASSERT_P(count >= 0); - if (count <= 0) - return; - if (mySize + count >= myCapacity) - { - exint tidx = safeIndex(t); - - bumpCapacity(mySize + count); - - for (exint i = 0; i < count; i++) - copyConstruct(myData[mySize+i], tidx >= 0 ? myData[tidx] : t); - } - else - { - for (exint i = 0; i < count; i++) - copyConstruct(myData[mySize+i], t); - } - mySize += count; - } - - template - inline exint - UT_Array::concat(const UT_Array &a) - { - bumpCapacity(mySize + a.mySize); - copyConstructRange(myData + mySize, a.myData, a.mySize); - mySize += a.mySize; - - return mySize; - } - - template - inline exint - UT_Array::multipleInsert(exint beg_index, exint count) - { - exint end_index = beg_index + count; - - if (beg_index >= mySize) - { - bumpCapacity(end_index); - - trivialConstructRange(myData + mySize, end_index - mySize); - - mySize = end_index; - return beg_index; - } - bumpCapacity(mySize+count); - - ::memmove((void *)&myData[end_index], (void *)&myData[beg_index], - ((mySize-beg_index)*sizeof(T))); - mySize += count; - - trivialConstructRange(myData + beg_index, count); - - return beg_index; - } - - template - template - inline exint - UT_Array::insertImpl(S &&s, exint index) - { - if (index == mySize) - { - // This case avoids an extraneous call to trivialConstructRange() - // which the compiler may not optimize out. - (void) appendImpl(std::forward(s)); - } - else if (index > mySize) - { - exint src_i = safeIndex(s); - - bumpCapacity(index + 1); - - trivialConstructRange(myData + mySize, index - mySize); - - if (src_i >= 0) - construct(myData[index], std::forward(myData[src_i])); - else - construct(myData[index], std::forward(s)); - - mySize = index + 1; - } - else // (index < mySize) - { - exint src_i = safeIndex(s); - - bumpCapacity(mySize + 1); - - ::memmove((void *)&myData[index+1], (void *)&myData[index], - ((mySize-index)*sizeof(T))); - - if (src_i >= index) - ++src_i; - - if (src_i >= 0) - construct(myData[index], std::forward(myData[src_i])); - else - construct(myData[index], std::forward(s)); - - ++mySize; - } - - return index; - } - - template - inline exint - UT_Array::removeAt(exint idx) - { - trivialDestruct(myData[idx]); - if (idx != --mySize) - { - ::memmove((void *)&myData[idx], (void *)&myData[idx+1], - ((mySize-idx)*sizeof(T))); - } - - return idx; - } - - template - inline void - UT_Array::removeRange(exint begin_i, exint end_i) - { - UT_ASSERT(begin_i <= end_i); - UT_ASSERT(end_i <= size()); - if (end_i < size()) - { - trivialDestructRange(myData + begin_i, end_i - begin_i); - ::memmove((void *)&myData[begin_i], (void *)&myData[end_i], - (mySize - end_i)*sizeof(T)); - } - setSize(mySize - (end_i - begin_i)); - } - - template - inline void - UT_Array::extractRange(exint begin_i, exint end_i, UT_Array& dest) - { - UT_ASSERT_P(begin_i >= 0); - UT_ASSERT_P(begin_i <= end_i); - UT_ASSERT_P(end_i <= size()); - UT_ASSERT(this != &dest); - - exint nelements = end_i - begin_i; - - // grow the raw array if necessary. - dest.setCapacityIfNeeded(nelements); - - ::memmove((void*)dest.myData, (void*)&myData[begin_i], - nelements * sizeof(T)); - dest.mySize = nelements; - - // we just asserted this was true, but just in case - if (this != &dest) - { - if (end_i < size()) - { - ::memmove((void*)&myData[begin_i], (void*)&myData[end_i], - (mySize - end_i) * sizeof(T)); - } - setSize(mySize - nelements); - } - } - - template - inline void - UT_Array::move(exint srcIdx, exint destIdx, exint howMany) - { - // Make sure all the parameters are valid. - if( srcIdx < 0 ) - srcIdx = 0; - if( destIdx < 0 ) - destIdx = 0; - // If we are told to move a set of elements that would extend beyond the - // end of the current array, trim the group. - if( srcIdx + howMany > size() ) - howMany = size() - srcIdx; - // If the destIdx would have us move the source beyond the end of the - // current array, move the destIdx back. - if( destIdx + howMany > size() ) - destIdx = size() - howMany; - if( srcIdx != destIdx && howMany > 0 ) - { - void **tmp = 0; - exint savelen; - - savelen = SYSabs(srcIdx - destIdx); - tmp = (void **)::malloc(savelen*sizeof(T)); - if( srcIdx > destIdx && howMany > 0 ) - { - // We're moving the group backwards. Save all the stuff that - // we would overwrite, plus everything beyond that to the - // start of the source group. Then move the source group, then - // tack the saved data onto the end of the moved group. - ::memcpy(tmp, (void *)&myData[destIdx], (savelen*sizeof(T))); - ::memmove((void *)&myData[destIdx], (void *)&myData[srcIdx], - (howMany*sizeof(T))); - ::memcpy((void *)&myData[destIdx+howMany], tmp, (savelen*sizeof(T))); - } - if( srcIdx < destIdx && howMany > 0 ) - { - // We're moving the group forwards. Save from the end of the - // group being moved to the end of the where the destination - // group will end up. Then copy the source to the destination. - // Then move back up to the original source location and drop - // in our saved data. - ::memcpy(tmp, (void *)&myData[srcIdx+howMany], (savelen*sizeof(T))); - ::memmove((void *)&myData[destIdx], (void *)&myData[srcIdx], - (howMany*sizeof(T))); - ::memcpy((void *)&myData[srcIdx], tmp, (savelen*sizeof(T))); - } - ::free(tmp); - } - } - - template - template - inline exint - UT_Array::removeIf(IsEqual is_equal) - { - // Move dst to the first element to remove. - exint dst; - for (dst = 0; dst < mySize; dst++) - { - if (is_equal(myData[dst])) - break; - } - // Now start looking at all the elements past the first one to remove. - for (exint idx = dst+1; idx < mySize; idx++) - { - if (!is_equal(myData[idx])) - { - UT_ASSERT(idx != dst); - myData[dst] = myData[idx]; - dst++; - } - // On match, ignore. - } - // New size - mySize = dst; - return mySize; - } - - template - inline void - UT_Array::cycle(exint howMany) - { - char *tempPtr; - exint numShift; // The number of items we shift - exint remaining; // mySize - numShift - - if (howMany == 0 || mySize < 1) return; - - numShift = howMany % (exint)mySize; - if (numShift < 0) numShift += mySize; - remaining = mySize - numShift; - tempPtr = new char[numShift*sizeof(T)]; - - ::memmove(tempPtr, (void *)&myData[remaining], (numShift * sizeof(T))); - ::memmove((void *)&myData[numShift], (void *)&myData[0], (remaining * sizeof(T))); - ::memmove((void *)&myData[0], tempPtr, (numShift * sizeof(T))); - - delete [] tempPtr; - } - - template - inline void - UT_Array::constant(const T &value) - { - for (exint i = 0; i < mySize; i++) - { - myData[i] = value; - } - } - - template - inline void - UT_Array::zero() - { - if (isPOD()) - ::memset((void *)myData, 0, mySize*sizeof(T)); - else - trivialConstructRange(myData, mySize); - } - - template - inline void - UT_Array::setCapacity(exint capacity) - { - // Do nothing when new capacity is the same as the current - if (capacity == myCapacity) - return; - - // Special case for non-heap buffers - if (!isHeapBuffer()) - { - if (capacity < mySize) - { - // Destroy the extra elements without changing myCapacity - trivialDestructRange(myData + capacity, mySize - capacity); - mySize = capacity; - } - else if (capacity > myCapacity) - { - T *prev = myData; - myData = (T *)malloc(sizeof(T) * capacity); - // myData is safe because we're already a stack buffer - UT_ASSERT_P(isHeapBuffer()); - if (mySize > 0) - memcpy((void *)myData, (void *)prev, sizeof(T) * mySize); - myCapacity = capacity; - } - else - { - // Keep myCapacity unchanged in this case - UT_ASSERT_P(capacity >= mySize && capacity <= myCapacity); - } - return; - } - - if (capacity == 0) - { - if (myData) - { - trivialDestructRange(myData, mySize); - free(myData); - } - myData = 0; - myCapacity = 0; - mySize = 0; - return; - } - - if (capacity < mySize) - { - trivialDestructRange(myData + capacity, mySize - capacity); - mySize = capacity; - } - - if (myData) - myData = (T *)realloc(myData, capacity*sizeof(T)); - else - myData = (T *)malloc(sizeof(T) * capacity); - - // Avoid degenerate case if we happen to be aliased the wrong way - if (!isHeapBuffer()) - { - T *prev = myData; - myData = (T *)malloc(sizeof(T) * capacity); - if (mySize > 0) - memcpy((void *)myData, (void *)prev, sizeof(T) * mySize); - ut_ArrayImplFree(prev); - } - - myCapacity = capacity; - UT_ASSERT(myData); - } - - template - inline UT_Array & - UT_Array::operator=(const UT_Array &a) - { - if (this == &a) - return *this; - - // Grow the raw array if necessary. - setCapacityIfNeeded(a.size()); - - // Make sure destructors and constructors are called on all elements - // being removed/added. - trivialDestructRange(myData, mySize); - copyConstructRange(myData, a.myData, a.size()); - - mySize = a.size(); - - return *this; - } - - template - inline UT_Array & - UT_Array::operator=(std::initializer_list a) - { - const exint new_size = a.size(); - - // Grow the raw array if necessary. - setCapacityIfNeeded(new_size); - - // Make sure destructors and constructors are called on all elements - // being removed/added. - trivialDestructRange(myData, mySize); - - copyConstructRange(myData, a.begin(), new_size); - - mySize = new_size; - - return *this; - } - - template - inline UT_Array & - UT_Array::operator=(UT_Array &&a) - { - if (!a.isHeapBuffer()) - { - // Cannot steal from non-heap buffers - clear(); - const exint n = a.size(); - setCapacityIfNeeded(n); - if (isPOD()) - { - if (n > 0) - memcpy(myData, a.myData, n * sizeof(T)); - } - else - { - for (exint i = 0; i < n; ++i) - new (&myData[i]) T(std::move(a.myData[i])); - } - mySize = a.mySize; - a.mySize = 0; - return *this; - } - // else, just steal even if we're a small buffer - - // Destroy all the elements we're currently holding. - if (myData) - { - trivialDestructRange(myData, mySize); - if (isHeapBuffer()) - ::free(myData); - } - - // Move the contents of the other array to us and empty the other container - // so that it destructs cleanly. - myCapacity = a.myCapacity; - mySize = a.mySize; - myData = a.myData; - a.myCapacity = a.mySize = 0; - a.myData = nullptr; - - return *this; - } - - - template - inline bool - UT_Array::operator==(const UT_Array &a) const - { - if (this == &a) return true; - if (mySize != a.size()) return false; - for (exint i = 0; i < mySize; i++) - if (!(myData[i] == a(i))) return false; - return true; - } - - template - inline bool - UT_Array::operator!=(const UT_Array &a) const - { - return (!operator==(a)); - } - - }} - -#endif // __UT_ARRAYIMPL_H_INCLUDED__ -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * Special case for arrays that are usually small, - * to avoid a heap allocation when the array really is small. - */ - -#pragma once - -#ifndef __UT_SMALLARRAY_H_INCLUDED__ -#define __UT_SMALLARRAY_H_INCLUDED__ - - - -#include -#include -namespace igl { namespace FastWindingNumber { - -/// An array class with the small buffer optimization, making it ideal for -/// cases when you know it will only contain a few elements at the expense of -/// increasing the object size by MAX_BYTES (subject to alignment). - template - class UT_SmallArray : public UT_Array - { - // As many elements that fit into MAX_BYTES with 1 item minimum - enum { MAX_ELEMS = MAX_BYTES/sizeof(T) < 1 ? 1 : MAX_BYTES/sizeof(T) }; - - public: - -// gcc falsely warns about our use of offsetof() on non-POD types. We can't -// easily suppress this because it has to be done in the caller at -// instantiation time. Instead, punt to a runtime check instead. -#if defined(__clang__) || defined(_MSC_VER) - #define UT_SMALL_ARRAY_SIZE_ASSERT() \ - using ThisT = UT_SmallArray; \ - static_assert(offsetof(ThisT, myBuffer) == sizeof(UT_Array), \ - "In order for UT_Array's checks for whether it needs to free the buffer to work, " \ - "the buffer must be exactly following the base class memory.") -#else -#define UT_SMALL_ARRAY_SIZE_ASSERT() \ - UT_ASSERT_P(!UT_Array::isHeapBuffer()); -#endif - - /// Default construction - UT_SmallArray() - : UT_Array(/*capacity*/0) - { - UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); - UT_SMALL_ARRAY_SIZE_ASSERT(); - } - - /// Copy constructor - /// @{ - explicit UT_SmallArray(const UT_Array ©) - : UT_Array(/*capacity*/0) - { - UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); - UT_SMALL_ARRAY_SIZE_ASSERT(); - UT_Array::operator=(copy); - } - explicit UT_SmallArray(const UT_SmallArray ©) - : UT_Array(/*capacity*/0) - { - UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); - UT_SMALL_ARRAY_SIZE_ASSERT(); - UT_Array::operator=(copy); - } - /// @} - - /// Move constructor - /// @{ - UT_SmallArray(UT_Array &&movable) noexcept - { - UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); - UT_SMALL_ARRAY_SIZE_ASSERT(); - UT_Array::operator=(std::move(movable)); - } - UT_SmallArray(UT_SmallArray &&movable) noexcept - { - UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); - UT_SMALL_ARRAY_SIZE_ASSERT(); - UT_Array::operator=(std::move(movable)); - } - /// @} - - /// Initializer list constructor - explicit UT_SmallArray(std::initializer_list init) - { - UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); - UT_SMALL_ARRAY_SIZE_ASSERT(); - UT_Array::operator=(init); - } - -#undef UT_SMALL_ARRAY_SIZE_ASSERT - - /// Assignment operator - /// @{ - UT_SmallArray & - operator=(const UT_SmallArray ©) - { - UT_Array::operator=(copy); - return *this; - } - UT_SmallArray & - operator=(const UT_Array ©) - { - UT_Array::operator=(copy); - return *this; - } - /// @} - - /// Move operator - /// @{ - UT_SmallArray & - operator=(UT_SmallArray &&movable) - { - UT_Array::operator=(std::move(movable)); - return *this; - } - UT_SmallArray & - operator=(UT_Array &&movable) - { - UT_Array::operator=(std::move(movable)); - return *this; - } - /// @} - - UT_SmallArray & - operator=(std::initializer_list src) - { - UT_Array::operator=(src); - return *this; - } - private: - alignas(T) char myBuffer[MAX_ELEMS*sizeof(T)]; - }; - }} - -#endif // __UT_SMALLARRAY_H_INCLUDED__ -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * A vector class templated on its size and data type. - */ - -#pragma once - -#ifndef __UT_FixedVector__ -#define __UT_FixedVector__ - - - - -namespace igl { namespace FastWindingNumber { - - template - class UT_FixedVector - { - public: - typedef UT_FixedVector ThisType; - typedef T value_type; - typedef T theType; - static const exint theSize = SIZE; - - T vec[SIZE]; - - SYS_FORCE_INLINE UT_FixedVector() = default; - - /// Initializes every component to the same value - SYS_FORCE_INLINE explicit UT_FixedVector(T that) noexcept - { - for (exint i = 0; i < SIZE; ++i) - vec[i] = that; - } - - SYS_FORCE_INLINE UT_FixedVector(const ThisType &that) = default; - SYS_FORCE_INLINE UT_FixedVector(ThisType &&that) = default; - - /// Converts vector of S into vector of T, - /// or just copies if same type. - template - SYS_FORCE_INLINE UT_FixedVector(const UT_FixedVector &that) noexcept - { - for (exint i = 0; i < SIZE; ++i) - vec[i] = that[i]; - } - - template - SYS_FORCE_INLINE UT_FixedVector(const S that[SIZE]) noexcept - { - for (exint i = 0; i < SIZE; ++i) - vec[i] = that[i]; - } - - SYS_FORCE_INLINE const T &operator[](exint i) const noexcept - { - UT_ASSERT_P(i >= 0 && i < SIZE); - return vec[i]; - } - SYS_FORCE_INLINE T &operator[](exint i) noexcept - { - UT_ASSERT_P(i >= 0 && i < SIZE); - return vec[i]; - } - - SYS_FORCE_INLINE constexpr const T *data() const noexcept - { - return vec; - } - SYS_FORCE_INLINE T *data() noexcept - { - return vec; - } - - SYS_FORCE_INLINE ThisType &operator=(const ThisType &that) = default; - SYS_FORCE_INLINE ThisType &operator=(ThisType &&that) = default; - - template - SYS_FORCE_INLINE ThisType &operator=(const UT_FixedVector &that) noexcept - { - for (exint i = 0; i < SIZE; ++i) - vec[i] = that[i]; - return *this; - } - SYS_FORCE_INLINE const ThisType &operator=(T that) noexcept - { - for (exint i = 0; i < SIZE; ++i) - vec[i] = that; - return *this; - } - template - SYS_FORCE_INLINE void operator+=(const UT_FixedVector &that) - { - for (exint i = 0; i < SIZE; ++i) - vec[i] += that[i]; - } - SYS_FORCE_INLINE void operator+=(T that) - { - for (exint i = 0; i < SIZE; ++i) - vec[i] += that; - } - template - SYS_FORCE_INLINE auto operator+(const UT_FixedVector &that) const -> UT_FixedVector - { - using Type = decltype(vec[0]+that[0]); - UT_FixedVector result; - for (exint i = 0; i < SIZE; ++i) - result[i] = vec[i] + that[i]; - return result; - } - template - SYS_FORCE_INLINE void operator-=(const UT_FixedVector &that) - { - for (exint i = 0; i < SIZE; ++i) - vec[i] -= that[i]; - } - SYS_FORCE_INLINE void operator-=(T that) - { - for (exint i = 0; i < SIZE; ++i) - vec[i] -= that; - } - template - SYS_FORCE_INLINE auto operator-(const UT_FixedVector &that) const -> UT_FixedVector - { - using Type = decltype(vec[0]-that[0]); - UT_FixedVector result; - for (exint i = 0; i < SIZE; ++i) - result[i] = vec[i] - that[i]; - return result; - } - template - SYS_FORCE_INLINE void operator*=(const UT_FixedVector &that) - { - for (exint i = 0; i < SIZE; ++i) - vec[i] *= that[i]; - } - template - SYS_FORCE_INLINE auto operator*(const UT_FixedVector &that) const -> UT_FixedVector - { - using Type = decltype(vec[0]*that[0]); - UT_FixedVector result; - for (exint i = 0; i < SIZE; ++i) - result[i] = vec[i] * that[i]; - return result; - } - SYS_FORCE_INLINE void operator*=(T that) - { - for (exint i = 0; i < SIZE; ++i) - vec[i] *= that; - } - SYS_FORCE_INLINE UT_FixedVector operator*(T that) const - { - UT_FixedVector result; - for (exint i = 0; i < SIZE; ++i) - result[i] = vec[i] * that; - return result; - } - template - SYS_FORCE_INLINE void operator/=(const UT_FixedVector &that) - { - for (exint i = 0; i < SIZE; ++i) - vec[i] /= that[i]; - } - template - SYS_FORCE_INLINE auto operator/(const UT_FixedVector &that) const -> UT_FixedVector - { - using Type = decltype(vec[0]/that[0]); - UT_FixedVector result; - for (exint i = 0; i < SIZE; ++i) - result[i] = vec[i] / that[i]; - return result; - } - - SYS_FORCE_INLINE void operator/=(T that) - { - if (std::is_integral::value) - { - for (exint i = 0; i < SIZE; ++i) - vec[i] /= that; - } - else - { - that = 1/that; - for (exint i = 0; i < SIZE; ++i) - vec[i] *= that; - } - } - SYS_FORCE_INLINE UT_FixedVector operator/(T that) const - { - UT_FixedVector result; - if (std::is_integral::value) - { - for (exint i = 0; i < SIZE; ++i) - result[i] = vec[i] / that; - } - else - { - that = 1/that; - for (exint i = 0; i < SIZE; ++i) - result[i] = vec[i] * that; - } - return result; - } - SYS_FORCE_INLINE void negate() - { - for (exint i = 0; i < SIZE; ++i) - vec[i] = -vec[i]; - } - - SYS_FORCE_INLINE UT_FixedVector operator-() const - { - UT_FixedVector result; - for (exint i = 0; i < SIZE; ++i) - result[i] = -vec[i]; - return result; - } - - template - SYS_FORCE_INLINE bool operator==(const UT_FixedVector &that) const noexcept - { - for (exint i = 0; i < SIZE; ++i) - { - if (vec[i] != T(that[i])) - return false; - } - return true; - } - template - SYS_FORCE_INLINE bool operator!=(const UT_FixedVector &that) const noexcept - { - return !(*this==that); - } - SYS_FORCE_INLINE bool isZero() const noexcept - { - for (exint i = 0; i < SIZE; ++i) - { - if (vec[i] != T(0)) - return false; - } - return true; - } - SYS_FORCE_INLINE T maxComponent() const - { - T v = vec[0]; - for (exint i = 1; i < SIZE; ++i) - v = (vec[i] > v) ? vec[i] : v; - return v; - } - SYS_FORCE_INLINE T minComponent() const - { - T v = vec[0]; - for (exint i = 1; i < SIZE; ++i) - v = (vec[i] < v) ? vec[i] : v; - return v; - } - SYS_FORCE_INLINE T avgComponent() const - { - T v = vec[0]; - for (exint i = 1; i < SIZE; ++i) - v += vec[i]; - return v / SIZE; - } - - SYS_FORCE_INLINE T length2() const noexcept - { - T a0(vec[0]); - T result(a0*a0); - for (exint i = 1; i < SIZE; ++i) - { - T ai(vec[i]); - result += ai*ai; - } - return result; - } - SYS_FORCE_INLINE T length() const - { - T len2 = length2(); - return SYSsqrt(len2); - } - template - SYS_FORCE_INLINE auto dot(const UT_FixedVector &that) const -> decltype(vec[0]*that[0]) - { - using TheType = decltype(vec[0]*that.vec[0]); - TheType result(vec[0]*that[0]); - for (exint i = 1; i < SIZE; ++i) - result += vec[i]*that[i]; - return result; - } - template - SYS_FORCE_INLINE auto distance2(const UT_FixedVector &that) const -> decltype(vec[0]-that[0]) - { - using TheType = decltype(vec[0]-that[0]); - TheType v(vec[0] - that[0]); - TheType result(v*v); - for (exint i = 1; i < SIZE; ++i) - { - v = vec[i] - that[i]; - result += v*v; - } - return result; - } - template - SYS_FORCE_INLINE auto distance(const UT_FixedVector &that) const -> decltype(vec[0]-that[0]) - { - auto dist2 = distance2(that); - return SYSsqrt(dist2); - } - - SYS_FORCE_INLINE T normalize() - { - T len2 = length2(); - if (len2 == T(0)) - return T(0); - if (len2 == T(1)) - return T(1); - T len = SYSsqrt(len2); - // Check if the square root is equal 1. sqrt(1+dx) ~ 1+dx/2, - // so it may get rounded to 1 when it wasn't 1 before. - if (len != T(1)) - (*this) /= len; - return len; - } - }; - -/// NOTE: Strictly speaking, this should use decltype(that*a[0]), -/// but in the interests of avoiding accidental precision escalation, -/// it uses T. - template - SYS_FORCE_INLINE UT_FixedVector operator*(const S &that,const UT_FixedVector &a) - { - T t(that); - UT_FixedVector result; - for (exint i = 0; i < SIZE; ++i) - result[i] = t * a[i]; - return result; - } - - template - SYS_FORCE_INLINE auto - dot(const UT_FixedVector &a, const UT_FixedVector &b) -> decltype(a[0]*b[0]) - { - return a.dot(b); - } - - template - SYS_FORCE_INLINE auto - SYSmin(const UT_FixedVector &a, const UT_FixedVector &b) -> UT_FixedVector - { - using Type = decltype(a[0]+b[1]); - UT_FixedVector result; - for (exint i = 0; i < SIZE; ++i) - result[i] = SYSmin(Type(a[i]), Type(b[i])); - return result; - } - - template - SYS_FORCE_INLINE auto - SYSmax(const UT_FixedVector &a, const UT_FixedVector &b) -> UT_FixedVector - { - using Type = decltype(a[0]+b[1]); - UT_FixedVector result; - for (exint i = 0; i < SIZE; ++i) - result[i] = SYSmax(Type(a[i]), Type(b[i])); - return result; - } - - template - struct UT_FixedVectorTraits - { - typedef UT_FixedVector FixedVectorType; - typedef T DataType; - static const exint TupleSize = 1; - static const bool isVectorType = false; - }; - - template - struct UT_FixedVectorTraits > - { - typedef UT_FixedVector FixedVectorType; - typedef T DataType; - static const exint TupleSize = SIZE; - static const bool isVectorType = true; - }; - }} - -#endif -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * Simple wrappers on tbb interface - */ - -#ifndef __UT_ParallelUtil__ -#define __UT_ParallelUtil__ - - - -#include // This is just included for std::thread::hardware_concurrency() -namespace igl { namespace FastWindingNumber { - namespace UT_Thread { inline int getNumProcessors() { - return std::thread::hardware_concurrency(); - }} - -//#include "tbb/blocked_range.h" -//#include "tbb/parallel_for.h" -////namespace tbb { class split; } -// -///// Declare prior to use. -//template -//using UT_BlockedRange = tbb::blocked_range; -// -//// Default implementation that calls range.size() -//template< typename RANGE > -//struct UT_EstimatorNumItems -//{ -// UT_EstimatorNumItems() {} -// -// size_t operator()(const RANGE& range) const -// { -// return range.size(); -// } -//}; -// -///// This is needed by UT_CoarsenedRange -//template -//inline size_t UTestimatedNumItems(const RANGE& range) -//{ -// return UT_EstimatorNumItems()(range); -//} -// -///// UT_CoarsenedRange: This should be used only inside -///// UT_ParallelFor and UT_ParallelReduce -///// This class wraps an existing range with a new range. -///// This allows us to use simple_partitioner, rather than -///// auto_partitioner, which has disastrous performance with -///// the default grain size in ttb 4. -//template< typename RANGE > -//class UT_CoarsenedRange : public RANGE -//{ -//public: -// // Compiler-generated versions are fine: -// // ~UT_CoarsenedRange(); -// // UT_CoarsenedRange(const UT_CoarsenedRange&); -// -// // Split into two sub-ranges: -// UT_CoarsenedRange(UT_CoarsenedRange& range, tbb::split spl) : -// RANGE(range, spl), -// myGrainSize(range.myGrainSize) -// { -// } -// -// // Inherited: bool empty() const -// -// bool is_divisible() const -// { -// return -// RANGE::is_divisible() && -// (UTestimatedNumItems(static_cast(*this)) > myGrainSize); -// } -// -//private: -// size_t myGrainSize; -// -// UT_CoarsenedRange(const RANGE& base_range, const size_t grain_size) : -// RANGE(base_range), -// myGrainSize(grain_size) -// { -// } -// -// template -// friend void UTparallelFor( -// const Range &range, const Body &body, -// const int subscribe_ratio, const int min_grain_size -// ); -//}; -// -///// Run the @c body function over a range in parallel. -///// UTparallelFor attempts to spread the range out over at most -///// subscribe_ratio * num_processor tasks. -///// The factor subscribe_ratio can be used to help balance the load. -///// UTparallelFor() uses tbb for its implementation. -///// The used grain size is the maximum of min_grain_size and -///// if UTestimatedNumItems(range) / (subscribe_ratio * num_processor). -///// If subscribe_ratio == 0, then a grain size of min_grain_size will be used. -///// A range can be split only when UTestimatedNumItems(range) exceeds the -///// grain size the range is divisible. -// -///// -///// Requirements for the Range functor are: -///// - the requirements of the tbb Range Concept -///// - UT_estimatorNumItems must return the the estimated number of work items -///// for the range. When Range::size() is not the correct estimate, then a -///// (partial) specialization of UT_estimatorNumItemsimatorRange must be provided -///// for the type Range. -///// -///// Requirements for the Body function are: -///// - @code Body(const Body &); @endcode @n -///// Copy Constructor -///// - @code Body()::~Body(); @endcode @n -///// Destructor -///// - @code void Body::operator()(const Range &range) const; @endcode -///// Function call to perform operation on the range. Note the operator is -///// @b const. -///// -///// The requirements for a Range object are: -///// - @code Range::Range(const Range&); @endcode @n -///// Copy constructor -///// - @code Range::~Range(); @endcode @n -///// Destructor -///// - @code bool Range::is_divisible() const; @endcode @n -///// True if the range can be partitioned into two sub-ranges -///// - @code bool Range::empty() const; @endcode @n -///// True if the range is empty -///// - @code Range::Range(Range &r, UT_Split) const; @endcode @n -///// Split the range @c r into two sub-ranges (i.e. modify @c r and *this) -///// -///// Example: @code -///// class Square { -///// public: -///// Square(double *data) : myData(data) {} -///// ~Square(); -///// void operator()(const UT_BlockedRange &range) const -///// { -///// for (int64 i = range.begin(); i != range.end(); ++i) -///// myData[i] *= myData[i]; -///// } -///// double *myData; -///// }; -///// ... -///// -///// void -///// parallel_square(double *array, int64 length) -///// { -///// UTparallelFor(UT_BlockedRange(0, length), Square(array)); -///// } -///// @endcode -///// -///// @see UTparallelReduce(), UT_BlockedRange() -// -//template -//void UTparallelFor( -// const Range &range, const Body &body, -// const int subscribe_ratio = 2, -// const int min_grain_size = 1 -//) -//{ -// const size_t num_processors( UT_Thread::getNumProcessors() ); -// -// UT_ASSERT( num_processors >= 1 ); -// UT_ASSERT( min_grain_size >= 1 ); -// UT_ASSERT( subscribe_ratio >= 0 ); -// -// const size_t est_range_size( UTestimatedNumItems(range) ); -// -// // Don't run on an empty range! -// if (est_range_size == 0) -// return; -// -// // Avoid tbb overhead if entire range needs to be single threaded -// if (num_processors == 1 || est_range_size <= min_grain_size) -// { -// body(range); -// return; -// } -// -// size_t grain_size(min_grain_size); -// if( subscribe_ratio > 0 ) -// grain_size = std::max( -// grain_size, -// est_range_size / (subscribe_ratio * num_processors) -// ); -// -// UT_CoarsenedRange< Range > coarsened_range(range, grain_size); -// -// tbb::parallel_for(coarsened_range, body, tbb::simple_partitioner()); -//} -// -///// Version of UTparallelFor that is tuned for the case where the range -///// consists of lightweight items, for example, -///// float additions or matrix-vector multiplications. -//template -//void -//UTparallelForLightItems(const Range &range, const Body &body) -//{ -// UTparallelFor(range, body, 2, 1024); -//} -// -///// UTserialFor can be used as a debugging tool to quickly replace a parallel -///// for with a serial for. -//template -//void UTserialFor(const Range &range, const Body &body) -// { body(range); } -// - }} -#endif -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * Bounding Volume Hierarchy (BVH) implementation. - * To call functions not implemented here, also include UT_BVHImpl.h - */ - -#pragma once - -#ifndef __HDK_UT_BVH_h__ -#define __HDK_UT_BVH_h__ - - - - -#include -#include -namespace igl { namespace FastWindingNumber { - - template class UT_Array; - class v4uf; - class v4uu; - - namespace HDK_Sample { - - namespace UT { - - template - struct Box { - T vals[NAXES][2]; - - SYS_FORCE_INLINE Box() noexcept = default; - SYS_FORCE_INLINE constexpr Box(const Box &other) noexcept = default; - SYS_FORCE_INLINE constexpr Box(Box &&other) noexcept = default; - SYS_FORCE_INLINE Box& operator=(const Box &other) noexcept = default; - SYS_FORCE_INLINE Box& operator=(Box &&other) noexcept = default; - - template - SYS_FORCE_INLINE Box(const Box& other) noexcept { - static_assert((std::is_pod>::value) || !std::is_pod::value, - "UT::Box should be POD, for better performance in UT_Array, etc."); - - for (uint axis = 0; axis < NAXES; ++axis) { - vals[axis][0] = T(other.vals[axis][0]); - vals[axis][1] = T(other.vals[axis][1]); - } - } - template - SYS_FORCE_INLINE Box(const UT_FixedVector& pt) noexcept { - for (uint axis = 0; axis < NAXES; ++axis) { - vals[axis][0] = pt[axis]; - vals[axis][1] = pt[axis]; - } - } - template - SYS_FORCE_INLINE Box& operator=(const Box& other) noexcept { - for (uint axis = 0; axis < NAXES; ++axis) { - vals[axis][0] = T(other.vals[axis][0]); - vals[axis][1] = T(other.vals[axis][1]); - } - return *this; - } - - SYS_FORCE_INLINE const T* operator[](const size_t axis) const noexcept { - UT_ASSERT_P(axis < NAXES); - return vals[axis]; - } - SYS_FORCE_INLINE T* operator[](const size_t axis) noexcept { - UT_ASSERT_P(axis < NAXES); - return vals[axis]; - } - - SYS_FORCE_INLINE void initBounds() noexcept { - for (uint axis = 0; axis < NAXES; ++axis) { - vals[axis][0] = std::numeric_limits::max(); - vals[axis][1] = -std::numeric_limits::max(); - } - } - /// Copy the source box. - /// NOTE: This is so that in templated code that may have a Box or a - /// UT_FixedVector, it can call initBounds and still work. - SYS_FORCE_INLINE void initBounds(const Box& src) noexcept { - for (uint axis = 0; axis < NAXES; ++axis) { - vals[axis][0] = src.vals[axis][0]; - vals[axis][1] = src.vals[axis][1]; - } - } - /// Initialize with the union of the source boxes. - /// NOTE: This is so that in templated code that may have Box's or a - /// UT_FixedVector's, it can call initBounds and still work. - SYS_FORCE_INLINE void initBoundsUnordered(const Box& src0, const Box& src1) noexcept { - for (uint axis = 0; axis < NAXES; ++axis) { - vals[axis][0] = SYSmin(src0.vals[axis][0], src1.vals[axis][0]); - vals[axis][1] = SYSmax(src0.vals[axis][1], src1.vals[axis][1]); - } - } - SYS_FORCE_INLINE void combine(const Box& src) noexcept { - for (uint axis = 0; axis < NAXES; ++axis) { - T& minv = vals[axis][0]; - T& maxv = vals[axis][1]; - const T curminv = src.vals[axis][0]; - const T curmaxv = src.vals[axis][1]; - minv = (minv < curminv) ? minv : curminv; - maxv = (maxv > curmaxv) ? maxv : curmaxv; - } - } - SYS_FORCE_INLINE void enlargeBounds(const Box& src) noexcept { - combine(src); - } - - template - SYS_FORCE_INLINE - void initBounds(const UT_FixedVector& pt) noexcept { - for (uint axis = 0; axis < NAXES; ++axis) { - vals[axis][0] = pt[axis]; - vals[axis][1] = pt[axis]; - } - } - template - SYS_FORCE_INLINE - void initBounds(const UT_FixedVector& min, const UT_FixedVector& max) noexcept { - for (uint axis = 0; axis < NAXES; ++axis) { - vals[axis][0] = min[axis]; - vals[axis][1] = max[axis]; - } - } - template - SYS_FORCE_INLINE - void initBoundsUnordered(const UT_FixedVector& p0, const UT_FixedVector& p1) noexcept { - for (uint axis = 0; axis < NAXES; ++axis) { - vals[axis][0] = SYSmin(p0[axis], p1[axis]); - vals[axis][1] = SYSmax(p0[axis], p1[axis]); - } - } - template - SYS_FORCE_INLINE - void enlargeBounds(const UT_FixedVector& pt) noexcept { - for (uint axis = 0; axis < NAXES; ++axis) { - vals[axis][0] = SYSmin(vals[axis][0], pt[axis]); - vals[axis][1] = SYSmax(vals[axis][1], pt[axis]); - } - } - - SYS_FORCE_INLINE - UT_FixedVector getMin() const noexcept { - UT_FixedVector v; - for (uint axis = 0; axis < NAXES; ++axis) { - v[axis] = vals[axis][0]; - } - return v; - } - - SYS_FORCE_INLINE - UT_FixedVector getMax() const noexcept { - UT_FixedVector v; - for (uint axis = 0; axis < NAXES; ++axis) { - v[axis] = vals[axis][1]; - } - return v; - } - - T diameter2() const noexcept { - T diff = (vals[0][1]-vals[0][0]); - T sum = diff*diff; - for (uint axis = 1; axis < NAXES; ++axis) { - diff = (vals[axis][1]-vals[axis][0]); - sum += diff*diff; - } - return sum; - } - T volume() const noexcept { - T product = (vals[0][1]-vals[0][0]); - for (uint axis = 1; axis < NAXES; ++axis) { - product *= (vals[axis][1]-vals[axis][0]); - } - return product; - } - T half_surface_area() const noexcept { - if (NAXES==1) { - // NOTE: Although this should technically be 1, - // that doesn't make any sense as a heuristic, - // so we fall back to the "volume" of this box. - return (vals[0][1]-vals[0][0]); - } - if (NAXES==2) { - const T d0 = (vals[0][1]-vals[0][0]); - const T d1 = (vals[1][1]-vals[1][0]); - return d0 + d1; - } - if (NAXES==3) { - const T d0 = (vals[0][1]-vals[0][0]); - const T d1 = (vals[1][1]-vals[1][0]); - const T d2 = (vals[2][1]-vals[2][0]); - return d0*d1 + d1*d2 + d2*d0; - } - if (NAXES==4) { - const T d0 = (vals[0][1]-vals[0][0]); - const T d1 = (vals[1][1]-vals[1][0]); - const T d2 = (vals[2][1]-vals[2][0]); - const T d3 = (vals[3][1]-vals[3][0]); - // This is just d0d1d2 + d1d2d3 + d2d3d0 + d3d0d1 refactored. - const T d0d1 = d0*d1; - const T d2d3 = d2*d3; - return d0d1*(d2+d3) + d2d3*(d0+d1); - } - - T sum = 0; - for (uint skipped_axis = 0; skipped_axis < NAXES; ++skipped_axis) { - T product = 1; - for (uint axis = 0; axis < NAXES; ++axis) { - if (axis != skipped_axis) { - product *= (vals[axis][1]-vals[axis][0]); - } - } - sum += product; - } - return sum; - } - T axis_sum() const noexcept { - T sum = (vals[0][1]-vals[0][0]); - for (uint axis = 1; axis < NAXES; ++axis) { - sum += (vals[axis][1]-vals[axis][0]); - } - return sum; - } - template - SYS_FORCE_INLINE void intersect( - T &box_tmin, - T &box_tmax, - const UT_FixedVector &signs, - const UT_FixedVector &origin, - const UT_FixedVector &inverse_direction - ) const noexcept { - for (int axis = 0; axis < NAXES; ++axis) - { - uint sign = signs[axis]; - T t1 = (vals[axis][sign] - origin[axis]) * inverse_direction[axis]; - T t2 = (vals[axis][sign^1] - origin[axis]) * inverse_direction[axis]; - box_tmin = SYSmax(t1, box_tmin); - box_tmax = SYSmin(t2, box_tmax); - } - } - SYS_FORCE_INLINE void intersect(const Box& other, Box& dest) const noexcept { - for (int axis = 0; axis < NAXES; ++axis) - { - dest.vals[axis][0] = SYSmax(vals[axis][0], other.vals[axis][0]); - dest.vals[axis][1] = SYSmin(vals[axis][1], other.vals[axis][1]); - } - } - template - SYS_FORCE_INLINE T minDistance2( - const UT_FixedVector &p - ) const noexcept { - T diff = SYSmax(SYSmax(vals[0][0]-p[0], p[0]-vals[0][1]), T(0.0f)); - T d2 = diff*diff; - for (int axis = 1; axis < NAXES; ++axis) - { - diff = SYSmax(SYSmax(vals[axis][0]-p[axis], p[axis]-vals[axis][1]), T(0.0f)); - d2 += diff*diff; - } - return d2; - } - template - SYS_FORCE_INLINE T maxDistance2( - const UT_FixedVector &p - ) const noexcept { - T diff = SYSmax(p[0]-vals[0][0], vals[0][1]-p[0]); - T d2 = diff*diff; - for (int axis = 1; axis < NAXES; ++axis) - { - diff = SYSmax(p[axis]-vals[axis][0], vals[axis][1]-p[axis]); - d2 += diff*diff; - } - return d2; - } - }; - -/// Used by BVH::init to specify the heuristic to use for choosing between different box splits. -/// I tried putting this inside the BVH class, but I had difficulty getting it to compile. - enum class BVH_Heuristic { - /// Tries to minimize the sum of axis lengths of the boxes. - /// This is useful for applications where the probability of a box being applicable to a - /// query is proportional to the "length", e.g. the probability of a random infinite plane - /// intersecting the box. - BOX_PERIMETER, - - /// Tries to minimize the "surface area" of the boxes. - /// In 3D, uses the surface area; in 2D, uses the perimeter; in 1D, uses the axis length. - /// This is what most applications, e.g. ray tracing, should use, particularly when the - /// probability of a box being applicable to a query is proportional to the surface "area", - /// e.g. the probability of a random ray hitting the box. - /// - /// NOTE: USE THIS ONE IF YOU ARE UNSURE! - BOX_AREA, - - /// Tries to minimize the "volume" of the boxes. - /// Uses the product of all axis lengths as a heuristic, (volume in 3D, area in 2D, length in 1D). - /// This is useful for applications where the probability of a box being applicable to a - /// query is proportional to the "volume", e.g. the probability of a random point being inside the box. - BOX_VOLUME, - - /// Tries to minimize the "radii" of the boxes (i.e. the distance from the centre to a corner). - /// This is useful for applications where the probability of a box being applicable to a - /// query is proportional to the distance to the box centre, e.g. the probability of a random - /// infinite plane being within the "radius" of the centre. - BOX_RADIUS, - - /// Tries to minimize the squared "radii" of the boxes (i.e. the squared distance from the centre to a corner). - /// This is useful for applications where the probability of a box being applicable to a - /// query is proportional to the squared distance to the box centre, e.g. the probability of a random - /// ray passing within the "radius" of the centre. - BOX_RADIUS2, - - /// Tries to minimize the cubed "radii" of the boxes (i.e. the cubed distance from the centre to a corner). - /// This is useful for applications where the probability of a box being applicable to a - /// query is proportional to the cubed distance to the box centre, e.g. the probability of a random - /// point being within the "radius" of the centre. - BOX_RADIUS3, - - /// Tries to minimize the depth of the tree by primarily splitting at the median of the max axis. - /// It may fall back to minimizing the area, but the tree depth should be unaffected. - /// - /// FIXME: This is not fully implemented yet. - MEDIAN_MAX_AXIS - }; - - template - class BVH { - public: - using INT_TYPE = uint; - struct Node { - INT_TYPE child[N]; - - static constexpr INT_TYPE theN = N; - static constexpr INT_TYPE EMPTY = INT_TYPE(-1); - static constexpr INT_TYPE INTERNAL_BIT = (INT_TYPE(1)<<(sizeof(INT_TYPE)*8 - 1)); - SYS_FORCE_INLINE static INT_TYPE markInternal(INT_TYPE internal_node_num) noexcept { - return internal_node_num | INTERNAL_BIT; - } - SYS_FORCE_INLINE static bool isInternal(INT_TYPE node_int) noexcept { - return (node_int & INTERNAL_BIT) != 0; - } - SYS_FORCE_INLINE static INT_TYPE getInternalNum(INT_TYPE node_int) noexcept { - return node_int & ~INTERNAL_BIT; - } - }; - private: - struct FreeDeleter { - SYS_FORCE_INLINE void operator()(Node* p) const { - if (p) { - // The pointer was allocated with malloc by UT_Array, - // so it must be freed with free. - free(p); - } - } - }; - - std::unique_ptr myRoot; - INT_TYPE myNumNodes; - public: - SYS_FORCE_INLINE BVH() noexcept : myRoot(nullptr), myNumNodes(0) {} - - template - inline void init(const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices=nullptr, bool reorder_indices=false, INT_TYPE max_items_per_leaf=1) noexcept; - - template - inline void init(Box axes_minmax, const BOX_TYPE* boxes, INT_TYPE nboxes, SRC_INT_TYPE* indices=nullptr, bool reorder_indices=false, INT_TYPE max_items_per_leaf=1) noexcept; - - SYS_FORCE_INLINE - INT_TYPE getNumNodes() const noexcept - { - return myNumNodes; - } - SYS_FORCE_INLINE - const Node *getNodes() const noexcept - { - return myRoot.get(); - } - - SYS_FORCE_INLINE - void clear() noexcept { - myRoot.reset(); - myNumNodes = 0; - } - - /// For each node, this effectively does: - /// LOCAL_DATA local_data[MAX_ORDER]; - /// bool descend = functors.pre(nodei, parent_data); - /// if (!descend) - /// return; - /// for each child { - /// if (isitem(child)) - /// functors.item(getitemi(child), nodei, local_data[child]); - /// else if (isnode(child)) - /// recurse(getnodei(child), local_data); - /// } - /// functors.post(nodei, parent_nodei, data_for_parent, num_children, local_data); - template - inline void traverse( - FUNCTORS &functors, - LOCAL_DATA *data_for_parent=nullptr) const noexcept; - - /// This acts like the traverse function, except if the number of nodes in two subtrees - /// of a node contain at least parallel_threshold nodes, they may be executed in parallel. - /// If parallel_threshold is 0, even item_functor may be executed on items in parallel. - /// NOTE: Make sure that your functors don't depend on the order that they're executed in, - /// e.g. don't add values from sibling nodes together except in post functor, - /// else they might have nondeterministic roundoff or miss some values entirely. - template - inline void traverseParallel( - INT_TYPE parallel_threshold, - FUNCTORS &functors, - LOCAL_DATA *data_for_parent=nullptr) const noexcept; - - /// For each node, this effectively does: - /// LOCAL_DATA local_data[MAX_ORDER]; - /// uint descend = functors.pre(nodei, parent_data); - /// if (!descend) - /// return; - /// for each child { - /// if (!(descend & (1< - inline void traverseVector( - FUNCTORS &functors, - LOCAL_DATA *data_for_parent=nullptr) const noexcept; - - /// Prints a text representation of the tree to stdout. - inline void debugDump() const; - - template - static inline void createTrivialIndices(SRC_INT_TYPE* indices, const INT_TYPE n) noexcept; - - private: - template - inline void traverseHelper( - INT_TYPE nodei, - INT_TYPE parent_nodei, - FUNCTORS &functors, - LOCAL_DATA *data_for_parent=nullptr) const noexcept; - - template - inline void traverseParallelHelper( - INT_TYPE nodei, - INT_TYPE parent_nodei, - INT_TYPE parallel_threshold, - INT_TYPE next_node_id, - FUNCTORS &functors, - LOCAL_DATA *data_for_parent=nullptr) const noexcept; - - template - inline void traverseVectorHelper( - INT_TYPE nodei, - INT_TYPE parent_nodei, - FUNCTORS &functors, - LOCAL_DATA *data_for_parent=nullptr) const noexcept; - - template - static inline void computeFullBoundingBox(Box& axes_minmax, const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices) noexcept; - - template - static inline void initNode(UT_Array& nodes, Node &node, const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes) noexcept; - - template - static inline void initNodeReorder(UT_Array& nodes, Node &node, const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes, const INT_TYPE indices_offset, const INT_TYPE max_items_per_leaf) noexcept; - - template - static inline void multiSplit(const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE* sub_indices[N+1], Box sub_boxes[N]) noexcept; - - template - static inline void split(const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE*& split_indices, Box* split_boxes) noexcept; - - template - static inline void adjustParallelChildNodes(INT_TYPE nparallel, UT_Array& nodes, Node& node, UT_Array* parallel_nodes, SRC_INT_TYPE* sub_indices) noexcept; - - template - static inline void nthElement(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const SRC_INT_TYPE* indices_end, const uint axis, SRC_INT_TYPE*const nth) noexcept; - - template - static inline void partitionByCentre(const BOX_TYPE* boxes, SRC_INT_TYPE*const indices, const SRC_INT_TYPE*const indices_end, const uint axis, const T pivotx2, SRC_INT_TYPE*& ppivot_start, SRC_INT_TYPE*& ppivot_end) noexcept; - - /// An overestimate of the number of nodes needed. - /// At worst, we could have only 2 children in every leaf, and - /// then above that, we have a geometric series with r=1/N and a=(sub_nboxes/2)/N - /// The true worst case might be a little worst than this, but - /// it's probably fairly unlikely. - SYS_FORCE_INLINE static INT_TYPE nodeEstimate(const INT_TYPE nboxes) noexcept { - return nboxes/2 + nboxes/(2*(N-1)); - } - - template - SYS_FORCE_INLINE static T unweightedHeuristic(const Box& box) noexcept { - if (H == BVH_Heuristic::BOX_PERIMETER) { - return box.axis_sum(); - } - if (H == BVH_Heuristic::BOX_AREA) { - return box.half_surface_area(); - } - if (H == BVH_Heuristic::BOX_VOLUME) { - return box.volume(); - } - if (H == BVH_Heuristic::BOX_RADIUS) { - T diameter2 = box.diameter2(); - return SYSsqrt(diameter2); - } - if (H == BVH_Heuristic::BOX_RADIUS2) { - return box.diameter2(); - } - if (H == BVH_Heuristic::BOX_RADIUS3) { - T diameter2 = box.diameter2(); - return diameter2*SYSsqrt(diameter2); - } - UT_ASSERT_MSG(0, "BVH_Heuristic::MEDIAN_MAX_AXIS should be handled separately by caller!"); - return T(1); - } - - /// 16 equal-length spans (15 evenly-spaced splits) should be enough for a decent heuristic - static constexpr INT_TYPE NSPANS = 16; - static constexpr INT_TYPE NSPLITS = NSPANS-1; - - /// At least 1/16 of all boxes must be on each side, else we could end up with a very deep tree - static constexpr INT_TYPE MIN_FRACTION = 16; - }; - - } // UT namespace - - template - using UT_BVH = UT::BVH; - - } // End HDK_Sample namespace - }} -#endif -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * Bounding Volume Hierarchy (BVH) implementation. - * The main file is UT_BVH.h; this file is separate so that - * files that don't actually need to call functions on the BVH - * won't have unnecessary headers and functions included. - */ - -#pragma once - -#ifndef __HDK_UT_BVHImpl_h__ -#define __HDK_UT_BVHImpl_h__ - - - - - - - - -#include - -#include -#include - -namespace igl { namespace FastWindingNumber { - namespace HDK_Sample { - - namespace UT { - - template - SYS_FORCE_INLINE bool utBoxExclude(const UT::Box& box) noexcept { - bool has_nan_or_inf = !SYSisFinite(box[0][0]); - has_nan_or_inf |= !SYSisFinite(box[0][1]); - for (uint axis = 1; axis < NAXES; ++axis) - { - has_nan_or_inf |= !SYSisFinite(box[axis][0]); - has_nan_or_inf |= !SYSisFinite(box[axis][1]); - } - return has_nan_or_inf; - } - template - SYS_FORCE_INLINE bool utBoxExclude(const UT::Box& box) noexcept { - const int32 *pboxints = reinterpret_cast(&box); - // Fast check for NaN or infinity: check if exponent bits are 0xFF. - bool has_nan_or_inf = ((pboxints[0] & 0x7F800000) == 0x7F800000); - has_nan_or_inf |= ((pboxints[1] & 0x7F800000) == 0x7F800000); - for (uint axis = 1; axis < NAXES; ++axis) - { - has_nan_or_inf |= ((pboxints[2*axis] & 0x7F800000) == 0x7F800000); - has_nan_or_inf |= ((pboxints[2*axis + 1] & 0x7F800000) == 0x7F800000); - } - return has_nan_or_inf; - } - template - SYS_FORCE_INLINE T utBoxCenter(const UT::Box& box, uint axis) noexcept { - const T* v = box.vals[axis]; - return v[0] + v[1]; - } - template - struct ut_BoxCentre { - constexpr static uint scale = 2; - }; - template - SYS_FORCE_INLINE T utBoxExclude(const UT_FixedVector& position) noexcept { - bool has_nan_or_inf = !SYSisFinite(position[0]); - for (uint axis = 1; axis < NAXES; ++axis) - has_nan_or_inf |= !SYSisFinite(position[axis]); - return has_nan_or_inf; - } - template - SYS_FORCE_INLINE bool utBoxExclude(const UT_FixedVector& position) noexcept { - const int32 *ppositionints = reinterpret_cast(&position); - // Fast check for NaN or infinity: check if exponent bits are 0xFF. - bool has_nan_or_inf = ((ppositionints[0] & 0x7F800000) == 0x7F800000); - for (uint axis = 1; axis < NAXES; ++axis) - has_nan_or_inf |= ((ppositionints[axis] & 0x7F800000) == 0x7F800000); - return has_nan_or_inf; - } - template - SYS_FORCE_INLINE T utBoxCenter(const UT_FixedVector& position, uint axis) noexcept { - return position[axis]; - } - template - struct ut_BoxCentre> { - constexpr static uint scale = 1; - }; - - template - inline INT_TYPE utExcludeNaNInfBoxIndices(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE& nboxes) noexcept - { - constexpr INT_TYPE PARALLEL_THRESHOLD = 65536; - INT_TYPE ntasks = 1; - //if (nboxes >= PARALLEL_THRESHOLD) - //{ - // INT_TYPE nprocessors = UT_Thread::getNumProcessors(); - // ntasks = (nprocessors > 1) ? SYSmin(4*nprocessors, nboxes/(PARALLEL_THRESHOLD/2)) : 1; - //} - //if (ntasks == 1) - { - // Serial: easy case; just loop through. - - const SRC_INT_TYPE* indices_end = indices + nboxes; - - // Loop through forward once - SRC_INT_TYPE* psrc_index = indices; - for (; psrc_index != indices_end; ++psrc_index) - { - const bool exclude = utBoxExclude(boxes[*psrc_index]); - if (exclude) - break; - } - if (psrc_index == indices_end) - return 0; - - // First NaN or infinite box - SRC_INT_TYPE* nan_start = psrc_index; - for (++psrc_index; psrc_index != indices_end; ++psrc_index) - { - const bool exclude = utBoxExclude(boxes[*psrc_index]); - if (!exclude) - { - *nan_start = *psrc_index; - ++nan_start; - } - } - nboxes = nan_start-indices; - return indices_end - nan_start; - } - - } - - template - template - inline void BVH::init(const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices, bool reorder_indices, INT_TYPE max_items_per_leaf) noexcept { - Box axes_minmax; - computeFullBoundingBox(axes_minmax, boxes, nboxes, indices); - - init(axes_minmax, boxes, nboxes, indices, reorder_indices, max_items_per_leaf); - } - - template - template - inline void BVH::init(Box axes_minmax, const BOX_TYPE* boxes, INT_TYPE nboxes, SRC_INT_TYPE* indices, bool reorder_indices, INT_TYPE max_items_per_leaf) noexcept { - // Clear the tree in advance to save memory. - myRoot.reset(); - - if (nboxes == 0) { - myNumNodes = 0; - return; - } - - UT_Array local_indices; - if (!indices) { - local_indices.setSizeNoInit(nboxes); - indices = local_indices.array(); - createTrivialIndices(indices, nboxes); - } - - // Exclude any boxes with NaNs or infinities by shifting down indices - // over the bad box indices and updating nboxes. - INT_TYPE nexcluded = utExcludeNaNInfBoxIndices(boxes, indices, nboxes); - if (nexcluded != 0) { - if (nboxes == 0) { - myNumNodes = 0; - return; - } - computeFullBoundingBox(axes_minmax, boxes, nboxes, indices); - } - - UT_Array nodes; - // Preallocate an overestimate of the number of nodes needed. - nodes.setCapacity(nodeEstimate(nboxes)); - nodes.setSize(1); - if (reorder_indices) - initNodeReorder(nodes, nodes[0], axes_minmax, boxes, indices, nboxes, 0, max_items_per_leaf); - else - initNode(nodes, nodes[0], axes_minmax, boxes, indices, nboxes); - - // If capacity is more than 12.5% over the size, rellocate. - if (8*nodes.capacity() > 9*nodes.size()) { - nodes.setCapacity(nodes.size()); - } - // Steal ownership of the array from the UT_Array - myRoot.reset(nodes.array()); - myNumNodes = nodes.size(); - nodes.unsafeClearData(); - } - - template - template - inline void BVH::traverse( - FUNCTORS &functors, - LOCAL_DATA* data_for_parent) const noexcept - { - if (!myRoot) - return; - - // NOTE: The root is always index 0. - traverseHelper(0, INT_TYPE(-1), functors, data_for_parent); - } - template - template - inline void BVH::traverseHelper( - INT_TYPE nodei, - INT_TYPE parent_nodei, - FUNCTORS &functors, - LOCAL_DATA* data_for_parent) const noexcept - { - const Node &node = myRoot[nodei]; - bool descend = functors.pre(nodei, data_for_parent); - if (!descend) - return; - LOCAL_DATA local_data[N]; - INT_TYPE s; - for (s = 0; s < N; ++s) { - const INT_TYPE node_int = node.child[s]; - if (Node::isInternal(node_int)) { - if (node_int == Node::EMPTY) { - // NOTE: Anything after this will be empty too, so we can break. - break; - } - traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]); - } - else { - functors.item(node_int, nodei, local_data[s]); - } - } - // NOTE: s is now the number of non-empty entries in this node. - functors.post(nodei, parent_nodei, data_for_parent, s, local_data); - } - - template - template - inline void BVH::traverseParallel( - INT_TYPE parallel_threshold, - FUNCTORS& functors, - LOCAL_DATA* data_for_parent) const noexcept - { - if (!myRoot) - return; - - // NOTE: The root is always index 0. - traverseParallelHelper(0, INT_TYPE(-1), parallel_threshold, myNumNodes, functors, data_for_parent); - } - template - template - inline void BVH::traverseParallelHelper( - INT_TYPE nodei, - INT_TYPE parent_nodei, - INT_TYPE parallel_threshold, - INT_TYPE next_node_id, - FUNCTORS& functors, - LOCAL_DATA* data_for_parent) const noexcept - { - const Node &node = myRoot[nodei]; - bool descend = functors.pre(nodei, data_for_parent); - if (!descend) - return; - - // To determine the number of nodes in a child's subtree, we take the next - // node ID minus the current child's node ID. - INT_TYPE next_nodes[N]; - INT_TYPE nnodes[N]; - INT_TYPE nchildren = N; - INT_TYPE nparallel = 0; - // s is currently unsigned, so we check s < N for bounds check. - // The s >= 0 check is in case s ever becomes signed, and should be - // automatically removed by the compiler for unsigned s. - for (INT_TYPE s = N-1; (std::is_signed::value ? (s >= 0) : (s < N)); --s) { - const INT_TYPE node_int = node.child[s]; - if (node_int == Node::EMPTY) { - --nchildren; - continue; - } - next_nodes[s] = next_node_id; - if (Node::isInternal(node_int)) { - // NOTE: This depends on BVH::initNode appending the child nodes - // in between their content, instead of all at once. - INT_TYPE child_node_id = Node::getInternalNum(node_int); - nnodes[s] = next_node_id - child_node_id; - next_node_id = child_node_id; - } - else { - nnodes[s] = 0; - } - nparallel += (nnodes[s] >= parallel_threshold); - } - - LOCAL_DATA local_data[N]; - if (nparallel >= 2) { - // Do any non-parallel ones first - if (nparallel < nchildren) { - for (INT_TYPE s = 0; s < N; ++s) { - if (nnodes[s] >= parallel_threshold) { - continue; - } - const INT_TYPE node_int = node.child[s]; - if (Node::isInternal(node_int)) { - if (node_int == Node::EMPTY) { - // NOTE: Anything after this will be empty too, so we can break. - break; - } - traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]); - } - else { - functors.item(node_int, nodei, local_data[s]); - } - } - } - // Now do the parallel ones - igl::parallel_for( - nparallel, - [this,nodei,&node,&nnodes,&next_nodes,¶llel_threshold,&functors,&local_data](int taski) - { - INT_TYPE parallel_count = 0; - // NOTE: The check for s < N is just so that the compiler can - // (hopefully) figure out that it can fully unroll the loop. - INT_TYPE s; - for (s = 0; s < N; ++s) { - if (nnodes[s] < parallel_threshold) { - continue; - } - if (parallel_count == taski) { - break; - } - ++parallel_count; - } - const INT_TYPE node_int = node.child[s]; - if (Node::isInternal(node_int)) { - UT_ASSERT_MSG_P(node_int != Node::EMPTY, "Empty entries should have been excluded above."); - traverseParallelHelper(Node::getInternalNum(node_int), nodei, parallel_threshold, next_nodes[s], functors, &local_data[s]); - } - else { - functors.item(node_int, nodei, local_data[s]); - } - }); - } - else { - // All in serial - for (INT_TYPE s = 0; s < N; ++s) { - const INT_TYPE node_int = node.child[s]; - if (Node::isInternal(node_int)) { - if (node_int == Node::EMPTY) { - // NOTE: Anything after this will be empty too, so we can break. - break; - } - traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]); - } - else { - functors.item(node_int, nodei, local_data[s]); - } - } - } - functors.post(nodei, parent_nodei, data_for_parent, nchildren, local_data); - } - - template - template - inline void BVH::traverseVector( - FUNCTORS &functors, - LOCAL_DATA* data_for_parent) const noexcept - { - if (!myRoot) - return; - - // NOTE: The root is always index 0. - traverseVectorHelper(0, INT_TYPE(-1), functors, data_for_parent); - } - template - template - inline void BVH::traverseVectorHelper( - INT_TYPE nodei, - INT_TYPE parent_nodei, - FUNCTORS &functors, - LOCAL_DATA* data_for_parent) const noexcept - { - const Node &node = myRoot[nodei]; - INT_TYPE descend = functors.pre(nodei, data_for_parent); - if (!descend) - return; - LOCAL_DATA local_data[N]; - INT_TYPE s; - for (s = 0; s < N; ++s) { - if ((descend>>s) & 1) { - const INT_TYPE node_int = node.child[s]; - if (Node::isInternal(node_int)) { - if (node_int == Node::EMPTY) { - // NOTE: Anything after this will be empty too, so we can break. - descend &= (INT_TYPE(1)< - template - inline void BVH::createTrivialIndices(SRC_INT_TYPE* indices, const INT_TYPE n) noexcept { - igl::parallel_for(n, [indices,n](INT_TYPE i) { indices[i] = i; }, 65536); - } - - template - template - inline void BVH::computeFullBoundingBox(Box& axes_minmax, const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices) noexcept { - if (!nboxes) { - axes_minmax.initBounds(); - return; - } - INT_TYPE ntasks = 1; - if (nboxes >= 2*4096) { - INT_TYPE nprocessors = UT_Thread::getNumProcessors(); - ntasks = (nprocessors > 1) ? SYSmin(4*nprocessors, nboxes/4096) : 1; - } - if (ntasks == 1) { - Box box; - if (indices) { - box.initBounds(boxes[indices[0]]); - for (INT_TYPE i = 1; i < nboxes; ++i) { - box.combine(boxes[indices[i]]); - } - } - else { - box.initBounds(boxes[0]); - for (INT_TYPE i = 1; i < nboxes; ++i) { - box.combine(boxes[i]); - } - } - axes_minmax = box; - } - else { - UT_SmallArray> parallel_boxes; - Box box; - igl::parallel_for( - nboxes, - [¶llel_boxes](int n){parallel_boxes.setSize(n);}, - [¶llel_boxes,indices,&boxes](int i, int t) - { - if(indices) - { - parallel_boxes[t].combine(boxes[indices[i]]); - }else - { - parallel_boxes[t].combine(boxes[i]); - } - }, - [¶llel_boxes,&box](int t) - { - if(t == 0) - { - box = parallel_boxes[0]; - }else - { - box.combine(parallel_boxes[t]); - } - }); - - axes_minmax = box; - } - } - - template - template - inline void BVH::initNode(UT_Array& nodes, Node &node, const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes) noexcept { - if (nboxes <= N) { - // Fits in one node - for (INT_TYPE i = 0; i < nboxes; ++i) { - node.child[i] = indices[i]; - } - for (INT_TYPE i = nboxes; i < N; ++i) { - node.child[i] = Node::EMPTY; - } - return; - } - - SRC_INT_TYPE* sub_indices[N+1]; - Box sub_boxes[N]; - - if (N == 2) { - sub_indices[0] = indices; - sub_indices[2] = indices+nboxes; - split(axes_minmax, boxes, indices, nboxes, sub_indices[1], &sub_boxes[0]); - } - else { - multiSplit(axes_minmax, boxes, indices, nboxes, sub_indices, sub_boxes); - } - - // Count the number of nodes to run in parallel and fill in single items in this node - INT_TYPE nparallel = 0; - static constexpr INT_TYPE PARALLEL_THRESHOLD = 1024; - for (INT_TYPE i = 0; i < N; ++i) { - INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; - if (sub_nboxes == 1) { - node.child[i] = sub_indices[i][0]; - } - else if (sub_nboxes >= PARALLEL_THRESHOLD) { - ++nparallel; - } - } - - // NOTE: Child nodes of this node need to be placed just before the nodes in - // their corresponding subtree, in between the subtrees, because - // traverseParallel uses the difference between the child node IDs - // to determine the number of nodes in the subtree. - - // Recurse - if (nparallel >= 2) { - UT_SmallArray> parallel_nodes; - UT_SmallArray parallel_parent_nodes; - parallel_nodes.setSize(nparallel); - parallel_parent_nodes.setSize(nparallel); - igl::parallel_for( - nparallel, - [¶llel_nodes,¶llel_parent_nodes,&sub_indices,boxes,&sub_boxes](int taski) - { - // First, find which child this is - INT_TYPE counted_parallel = 0; - INT_TYPE sub_nboxes; - INT_TYPE childi; - for (childi = 0; childi < N; ++childi) { - sub_nboxes = sub_indices[childi+1]-sub_indices[childi]; - if (sub_nboxes >= PARALLEL_THRESHOLD) { - if (counted_parallel == taski) { - break; - } - ++counted_parallel; - } - } - UT_ASSERT_P(counted_parallel == taski); - - UT_Array& local_nodes = parallel_nodes[taski]; - // Preallocate an overestimate of the number of nodes needed. - // At worst, we could have only 2 children in every leaf, and - // then above that, we have a geometric series with r=1/N and a=(sub_nboxes/2)/N - // The true worst case might be a little worst than this, but - // it's probably fairly unlikely. - local_nodes.setCapacity(nodeEstimate(sub_nboxes)); - Node& parent_node = parallel_parent_nodes[taski]; - - // We'll have to fix the internal node numbers in parent_node and local_nodes later - initNode(local_nodes, parent_node, sub_boxes[childi], boxes, sub_indices[childi], sub_nboxes); - }); - - INT_TYPE counted_parallel = 0; - for (INT_TYPE i = 0; i < N; ++i) { - INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; - if (sub_nboxes != 1) { - INT_TYPE local_nodes_start = nodes.size(); - node.child[i] = Node::markInternal(local_nodes_start); - if (sub_nboxes >= PARALLEL_THRESHOLD) { - // First, adjust the root child node - Node child_node = parallel_parent_nodes[counted_parallel]; - ++local_nodes_start; - for (INT_TYPE childi = 0; childi < N; ++childi) { - INT_TYPE child_child = child_node.child[childi]; - if (Node::isInternal(child_child) && child_child != Node::EMPTY) { - child_child += local_nodes_start; - child_node.child[childi] = child_child; - } - } - - // Make space in the array for the sub-child nodes - const UT_Array& local_nodes = parallel_nodes[counted_parallel]; - ++counted_parallel; - INT_TYPE n = local_nodes.size(); - nodes.bumpCapacity(local_nodes_start + n); - nodes.setSizeNoInit(local_nodes_start + n); - nodes[local_nodes_start-1] = child_node; - } - else { - nodes.bumpCapacity(local_nodes_start + 1); - nodes.setSizeNoInit(local_nodes_start + 1); - initNode(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes); - } - } - } - - // Now, adjust and copy all sub-child nodes that were made in parallel - adjustParallelChildNodes(nparallel, nodes, node, parallel_nodes.array(), sub_indices); - } - else { - for (INT_TYPE i = 0; i < N; ++i) { - INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; - if (sub_nboxes != 1) { - INT_TYPE local_nodes_start = nodes.size(); - node.child[i] = Node::markInternal(local_nodes_start); - nodes.bumpCapacity(local_nodes_start + 1); - nodes.setSizeNoInit(local_nodes_start + 1); - initNode(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes); - } - } - } - } - - template - template - inline void BVH::initNodeReorder(UT_Array& nodes, Node &node, const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, const INT_TYPE indices_offset, const INT_TYPE max_items_per_leaf) noexcept { - if (nboxes <= N) { - // Fits in one node - for (INT_TYPE i = 0; i < nboxes; ++i) { - node.child[i] = indices_offset+i; - } - for (INT_TYPE i = nboxes; i < N; ++i) { - node.child[i] = Node::EMPTY; - } - return; - } - - SRC_INT_TYPE* sub_indices[N+1]; - Box sub_boxes[N]; - - if (N == 2) { - sub_indices[0] = indices; - sub_indices[2] = indices+nboxes; - split(axes_minmax, boxes, indices, nboxes, sub_indices[1], &sub_boxes[0]); - } - else { - multiSplit(axes_minmax, boxes, indices, nboxes, sub_indices, sub_boxes); - } - - // Move any children with max_items_per_leaf or fewer indices before any children with more, - // for better cache coherence when we're accessing data in a corresponding array. - INT_TYPE nleaves = 0; - UT_SmallArray leaf_indices; - SRC_INT_TYPE leaf_sizes[N]; - INT_TYPE sub_nboxes0 = sub_indices[1]-sub_indices[0]; - if (sub_nboxes0 <= max_items_per_leaf) { - leaf_sizes[0] = sub_nboxes0; - for (int j = 0; j < sub_nboxes0; ++j) - leaf_indices.append(sub_indices[0][j]); - ++nleaves; - } - INT_TYPE sub_nboxes1 = sub_indices[2]-sub_indices[1]; - if (sub_nboxes1 <= max_items_per_leaf) { - leaf_sizes[nleaves] = sub_nboxes1; - for (int j = 0; j < sub_nboxes1; ++j) - leaf_indices.append(sub_indices[1][j]); - ++nleaves; - } - for (INT_TYPE i = 2; i < N; ++i) { - INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; - if (sub_nboxes <= max_items_per_leaf) { - leaf_sizes[nleaves] = sub_nboxes; - for (int j = 0; j < sub_nboxes; ++j) - leaf_indices.append(sub_indices[i][j]); - ++nleaves; - } - } - if (nleaves > 0) { - // NOTE: i < N condition is because INT_TYPE is unsigned. - // i >= 0 condition is in case INT_TYPE is changed to signed. - INT_TYPE move_distance = 0; - INT_TYPE index_move_distance = 0; - for (INT_TYPE i = N-1; (std::is_signed::value ? (i >= 0) : (i < N)); --i) { - INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; - if (sub_nboxes <= max_items_per_leaf) { - ++move_distance; - index_move_distance += sub_nboxes; - } - else if (move_distance > 0) { - SRC_INT_TYPE *start_src_index = sub_indices[i]; - for (SRC_INT_TYPE *src_index = sub_indices[i+1]-1; src_index >= start_src_index; --src_index) { - src_index[index_move_distance] = src_index[0]; - } - sub_indices[i+move_distance] = sub_indices[i]+index_move_distance; - } - } - index_move_distance = 0; - for (INT_TYPE i = 0; i < nleaves; ++i) { - INT_TYPE sub_nboxes = leaf_sizes[i]; - sub_indices[i] = indices+index_move_distance; - for (int j = 0; j < sub_nboxes; ++j) - indices[index_move_distance+j] = leaf_indices[index_move_distance+j]; - index_move_distance += sub_nboxes; - } - } - - // Count the number of nodes to run in parallel and fill in single items in this node - INT_TYPE nparallel = 0; - static constexpr INT_TYPE PARALLEL_THRESHOLD = 1024; - for (INT_TYPE i = 0; i < N; ++i) { - INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; - if (sub_nboxes <= max_items_per_leaf) { - node.child[i] = indices_offset+(sub_indices[i]-sub_indices[0]); - } - else if (sub_nboxes >= PARALLEL_THRESHOLD) { - ++nparallel; - } - } - - // NOTE: Child nodes of this node need to be placed just before the nodes in - // their corresponding subtree, in between the subtrees, because - // traverseParallel uses the difference between the child node IDs - // to determine the number of nodes in the subtree. - - // Recurse - if (nparallel >= 2 && false) { - assert(false && "Not implemented; should never get here"); - exit(1); - // // Do the parallel ones first, so that they can be inserted in the right place. - // // Although the choice may seem somewhat arbitrary, we need the results to be - // // identical whether we choose to parallelize or not, and in case we change the - // // threshold later. - // UT_SmallArray,4*sizeof(UT_Array)> parallel_nodes; - // parallel_nodes.setSize(nparallel); - // UT_SmallArray parallel_parent_nodes; - // parallel_parent_nodes.setSize(nparallel); - // UTparallelFor(UT_BlockedRange(0,nparallel), [¶llel_nodes,¶llel_parent_nodes,&sub_indices,boxes,&sub_boxes,indices_offset,max_items_per_leaf](const UT_BlockedRange& r) { - // for (INT_TYPE taski = r.begin(), end = r.end(); taski < end; ++taski) { - // // First, find which child this is - // INT_TYPE counted_parallel = 0; - // INT_TYPE sub_nboxes; - // INT_TYPE childi; - // for (childi = 0; childi < N; ++childi) { - // sub_nboxes = sub_indices[childi+1]-sub_indices[childi]; - // if (sub_nboxes >= PARALLEL_THRESHOLD) { - // if (counted_parallel == taski) { - // break; - // } - // ++counted_parallel; - // } - // } - // UT_ASSERT_P(counted_parallel == taski); - - // UT_Array& local_nodes = parallel_nodes[taski]; - // // Preallocate an overestimate of the number of nodes needed. - // // At worst, we could have only 2 children in every leaf, and - // // then above that, we have a geometric series with r=1/N and a=(sub_nboxes/2)/N - // // The true worst case might be a little worst than this, but - // // it's probably fairly unlikely. - // local_nodes.setCapacity(nodeEstimate(sub_nboxes)); - // Node& parent_node = parallel_parent_nodes[taski]; - - // // We'll have to fix the internal node numbers in parent_node and local_nodes later - // initNodeReorder(local_nodes, parent_node, sub_boxes[childi], boxes, sub_indices[childi], sub_nboxes, - // indices_offset+(sub_indices[childi]-sub_indices[0]), max_items_per_leaf); - // } - // }, 0, 1); - - // INT_TYPE counted_parallel = 0; - // for (INT_TYPE i = 0; i < N; ++i) { - // INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; - // if (sub_nboxes > max_items_per_leaf) { - // INT_TYPE local_nodes_start = nodes.size(); - // node.child[i] = Node::markInternal(local_nodes_start); - // if (sub_nboxes >= PARALLEL_THRESHOLD) { - // // First, adjust the root child node - // Node child_node = parallel_parent_nodes[counted_parallel]; - // ++local_nodes_start; - // for (INT_TYPE childi = 0; childi < N; ++childi) { - // INT_TYPE child_child = child_node.child[childi]; - // if (Node::isInternal(child_child) && child_child != Node::EMPTY) { - // child_child += local_nodes_start; - // child_node.child[childi] = child_child; - // } - // } - - // // Make space in the array for the sub-child nodes - // const UT_Array& local_nodes = parallel_nodes[counted_parallel]; - // ++counted_parallel; - // INT_TYPE n = local_nodes.size(); - // nodes.bumpCapacity(local_nodes_start + n); - // nodes.setSizeNoInit(local_nodes_start + n); - // nodes[local_nodes_start-1] = child_node; - // } - // else { - // nodes.bumpCapacity(local_nodes_start + 1); - // nodes.setSizeNoInit(local_nodes_start + 1); - // initNodeReorder(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes, - // indices_offset+(sub_indices[i]-sub_indices[0]), max_items_per_leaf); - // } - // } - // } - - // // Now, adjust and copy all sub-child nodes that were made in parallel - // adjustParallelChildNodes(nparallel, nodes, node, parallel_nodes.array(), sub_indices); - } - else { - for (INT_TYPE i = 0; i < N; ++i) { - INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; - if (sub_nboxes > max_items_per_leaf) { - INT_TYPE local_nodes_start = nodes.size(); - node.child[i] = Node::markInternal(local_nodes_start); - nodes.bumpCapacity(local_nodes_start + 1); - nodes.setSizeNoInit(local_nodes_start + 1); - initNodeReorder(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes, - indices_offset+(sub_indices[i]-sub_indices[0]), max_items_per_leaf); - } - } - } - } - - template - template - inline void BVH::multiSplit(const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE* sub_indices[N+1], Box sub_boxes[N]) noexcept { - sub_indices[0] = indices; - sub_indices[2] = indices+nboxes; - split(axes_minmax, boxes, indices, nboxes, sub_indices[1], &sub_boxes[0]); - - if (N == 2) { - return; - } - - if (H == BVH_Heuristic::MEDIAN_MAX_AXIS) { - SRC_INT_TYPE* sub_indices_startend[2*N]; - Box sub_boxes_unsorted[N]; - sub_boxes_unsorted[0] = sub_boxes[0]; - sub_boxes_unsorted[1] = sub_boxes[1]; - sub_indices_startend[0] = sub_indices[0]; - sub_indices_startend[1] = sub_indices[1]; - sub_indices_startend[2] = sub_indices[1]; - sub_indices_startend[3] = sub_indices[2]; - for (INT_TYPE nsub = 2; nsub < N; ++nsub) { - SRC_INT_TYPE* selected_start = sub_indices_startend[0]; - SRC_INT_TYPE* selected_end = sub_indices_startend[1]; - Box sub_box = sub_boxes_unsorted[0]; - - // Shift results back. - for (INT_TYPE i = 0; i < nsub-1; ++i) { - sub_indices_startend[2*i ] = sub_indices_startend[2*i+2]; - sub_indices_startend[2*i+1] = sub_indices_startend[2*i+3]; - } - for (INT_TYPE i = 0; i < nsub-1; ++i) { - sub_boxes_unsorted[i] = sub_boxes_unsorted[i-1]; - } - - // Do the split - split(sub_box, boxes, selected_start, selected_end-selected_start, sub_indices_startend[2*nsub-1], &sub_boxes_unsorted[nsub]); - sub_indices_startend[2*nsub-2] = selected_start; - sub_indices_startend[2*nsub] = sub_indices_startend[2*nsub-1]; - sub_indices_startend[2*nsub+1] = selected_end; - - // Sort pointers so that they're in the correct order - sub_indices[N] = indices+nboxes; - for (INT_TYPE i = 0; i < N; ++i) { - SRC_INT_TYPE* prev_pointer = (i != 0) ? sub_indices[i-1] : nullptr; - SRC_INT_TYPE* min_pointer = nullptr; - Box box; - for (INT_TYPE j = 0; j < N; ++j) { - SRC_INT_TYPE* cur_pointer = sub_indices_startend[2*j]; - if ((cur_pointer > prev_pointer) && (!min_pointer || (cur_pointer < min_pointer))) { - min_pointer = cur_pointer; - box = sub_boxes_unsorted[j]; - } - } - UT_ASSERT_P(min_pointer); - sub_indices[i] = min_pointer; - sub_boxes[i] = box; - } - } - } - else { - T sub_box_areas[N]; - sub_box_areas[0] = unweightedHeuristic(sub_boxes[0]); - sub_box_areas[1] = unweightedHeuristic(sub_boxes[1]); - for (INT_TYPE nsub = 2; nsub < N; ++nsub) { - // Choose which one to split - INT_TYPE split_choice = INT_TYPE(-1); - T max_heuristic; - for (INT_TYPE i = 0; i < nsub; ++i) { - const INT_TYPE index_count = (sub_indices[i+1]-sub_indices[i]); - if (index_count > 1) { - const T heuristic = sub_box_areas[i]*index_count; - if (split_choice == INT_TYPE(-1) || heuristic > max_heuristic) { - split_choice = i; - max_heuristic = heuristic; - } - } - } - UT_ASSERT_MSG_P(split_choice != INT_TYPE(-1), "There should always be at least one that can be split!"); - - SRC_INT_TYPE* selected_start = sub_indices[split_choice]; - SRC_INT_TYPE* selected_end = sub_indices[split_choice+1]; - - // Shift results over; we can skip the one we selected. - for (INT_TYPE i = nsub; i > split_choice; --i) { - sub_indices[i+1] = sub_indices[i]; - } - for (INT_TYPE i = nsub-1; i > split_choice; --i) { - sub_boxes[i+1] = sub_boxes[i]; - } - for (INT_TYPE i = nsub-1; i > split_choice; --i) { - sub_box_areas[i+1] = sub_box_areas[i]; - } - - // Do the split - split(sub_boxes[split_choice], boxes, selected_start, selected_end-selected_start, sub_indices[split_choice+1], &sub_boxes[split_choice]); - sub_box_areas[split_choice] = unweightedHeuristic(sub_boxes[split_choice]); - sub_box_areas[split_choice+1] = unweightedHeuristic(sub_boxes[split_choice+1]); - } - } - } - - template - template - inline void BVH::split(const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE*& split_indices, Box* split_boxes) noexcept { - if (nboxes == 2) { - split_boxes[0].initBounds(boxes[indices[0]]); - split_boxes[1].initBounds(boxes[indices[1]]); - split_indices = indices+1; - return; - } - UT_ASSERT_MSG_P(nboxes > 2, "Cases with less than 3 boxes should have already been handled!"); - - if (H == BVH_Heuristic::MEDIAN_MAX_AXIS) { - UT_ASSERT_MSG(0, "FIXME: Implement this!!!"); - } - - constexpr INT_TYPE SMALL_LIMIT = 6; - if (nboxes <= SMALL_LIMIT) { - // Special case for a small number of boxes: check all (2^(n-1))-1 partitions. - // Without loss of generality, we assume that box 0 is in partition 0, - // and that not all boxes are in partition 0. - Box local_boxes[SMALL_LIMIT]; - for (INT_TYPE box = 0; box < nboxes; ++box) { - local_boxes[box].initBounds(boxes[indices[box]]); - //printf("Box %u: (%f-%f)x(%f-%f)x(%f-%f)\n", uint(box), local_boxes[box].vals[0][0], local_boxes[box].vals[0][1], local_boxes[box].vals[1][0], local_boxes[box].vals[1][1], local_boxes[box].vals[2][0], local_boxes[box].vals[2][1]); - } - const INT_TYPE partition_limit = (INT_TYPE(1)<<(nboxes-1)); - INT_TYPE best_partition = INT_TYPE(-1); - T best_heuristic; - for (INT_TYPE partition_bits = 1; partition_bits < partition_limit; ++partition_bits) { - Box sub_boxes[2]; - sub_boxes[0] = local_boxes[0]; - sub_boxes[1].initBounds(); - INT_TYPE sub_counts[2] = {1,0}; - for (INT_TYPE bit = 0; bit < nboxes-1; ++bit) { - INT_TYPE dest = (partition_bits>>bit)&1; - sub_boxes[dest].combine(local_boxes[bit+1]); - ++sub_counts[dest]; - } - //printf("Partition bits %u: sub_box[0]: (%f-%f)x(%f-%f)x(%f-%f)\n", uint(partition_bits), sub_boxes[0].vals[0][0], sub_boxes[0].vals[0][1], sub_boxes[0].vals[1][0], sub_boxes[0].vals[1][1], sub_boxes[0].vals[2][0], sub_boxes[0].vals[2][1]); - //printf("Partition bits %u: sub_box[1]: (%f-%f)x(%f-%f)x(%f-%f)\n", uint(partition_bits), sub_boxes[1].vals[0][0], sub_boxes[1].vals[0][1], sub_boxes[1].vals[1][0], sub_boxes[1].vals[1][1], sub_boxes[1].vals[2][0], sub_boxes[1].vals[2][1]); - const T heuristic = - unweightedHeuristic(sub_boxes[0])*sub_counts[0] + - unweightedHeuristic(sub_boxes[1])*sub_counts[1]; - //printf("Partition bits %u: heuristic = %f (= %f*%u + %f*%u)\n",uint(partition_bits),heuristic, unweightedHeuristic(sub_boxes[0]), uint(sub_counts[0]), unweightedHeuristic(sub_boxes[1]), uint(sub_counts[1])); - if (best_partition == INT_TYPE(-1) || heuristic < best_heuristic) { - //printf(" New best\n"); - best_partition = partition_bits; - best_heuristic = heuristic; - split_boxes[0] = sub_boxes[0]; - split_boxes[1] = sub_boxes[1]; - } - } - -#if 0 // This isn't actually necessary with the current design, because I changed how the number of subtree nodes is determined. - // If best_partition is partition_limit-1, there's only 1 box - // in partition 0. We should instead put this in partition 1, - // so that we can help always have the internal node indices first - // in each node. That gets used to (fairly) quickly determine - // the number of nodes in a sub-tree. - if (best_partition == partition_limit - 1) { - // Put the first index last. - SRC_INT_TYPE last_index = indices[0]; - SRC_INT_TYPE* dest_indices = indices; - SRC_INT_TYPE* local_split_indices = indices + nboxes-1; - for (; dest_indices != local_split_indices; ++dest_indices) { - dest_indices[0] = dest_indices[1]; - } - *local_split_indices = last_index; - split_indices = local_split_indices; - - // Swap the boxes - const Box temp_box = sub_boxes[0]; - sub_boxes[0] = sub_boxes[1]; - sub_boxes[1] = temp_box; - return; - } -#endif - - // Reorder the indices. - // NOTE: Index 0 is always in partition 0, so can stay put. - SRC_INT_TYPE local_indices[SMALL_LIMIT-1]; - for (INT_TYPE box = 0; box < nboxes-1; ++box) { - local_indices[box] = indices[box+1]; - } - SRC_INT_TYPE* dest_indices = indices+1; - SRC_INT_TYPE* src_indices = local_indices; - // Copy partition 0 - for (INT_TYPE bit = 0; bit < nboxes-1; ++bit, ++src_indices) { - if (!((best_partition>>bit)&1)) { - //printf("Copying %u into partition 0\n",uint(*src_indices)); - *dest_indices = *src_indices; - ++dest_indices; - } - } - split_indices = dest_indices; - // Copy partition 1 - src_indices = local_indices; - for (INT_TYPE bit = 0; bit < nboxes-1; ++bit, ++src_indices) { - if ((best_partition>>bit)&1) { - //printf("Copying %u into partition 1\n",uint(*src_indices)); - *dest_indices = *src_indices; - ++dest_indices; - } - } - return; - } - - uint max_axis = 0; - T max_axis_length = axes_minmax.vals[0][1] - axes_minmax.vals[0][0]; - for (uint axis = 1; axis < NAXES; ++axis) { - const T axis_length = axes_minmax.vals[axis][1] - axes_minmax.vals[axis][0]; - if (axis_length > max_axis_length) { - max_axis = axis; - max_axis_length = axis_length; - } - } - - if (!(max_axis_length > T(0))) { - // All boxes are a single point or NaN. - // Pick an arbitrary split point. - split_indices = indices + nboxes/2; - split_boxes[0] = axes_minmax; - split_boxes[1] = axes_minmax; - return; - } - - const INT_TYPE axis = max_axis; - - constexpr INT_TYPE MID_LIMIT = 2*NSPANS; - if (nboxes <= MID_LIMIT) { - // Sort along axis, and try all possible splits. - -#if 1 - // First, compute midpoints - T midpointsx2[MID_LIMIT]; - for (INT_TYPE i = 0; i < nboxes; ++i) { - midpointsx2[i] = utBoxCenter(boxes[indices[i]], axis); - } - SRC_INT_TYPE local_indices[MID_LIMIT]; - for (INT_TYPE i = 0; i < nboxes; ++i) { - local_indices[i] = i; - } - - const INT_TYPE chunk_starts[5] = {0, nboxes/4, nboxes/2, INT_TYPE((3*uint64(nboxes))/4), nboxes}; - - // For sorting, insertion sort 4 chunks and merge them - for (INT_TYPE chunk = 0; chunk < 4; ++chunk) { - const INT_TYPE start = chunk_starts[chunk]; - const INT_TYPE end = chunk_starts[chunk+1]; - for (INT_TYPE i = start+1; i < end; ++i) { - SRC_INT_TYPE indexi = local_indices[i]; - T vi = midpointsx2[indexi]; - for (INT_TYPE j = start; j < i; ++j) { - SRC_INT_TYPE indexj = local_indices[j]; - T vj = midpointsx2[indexj]; - if (vi < vj) { - do { - local_indices[j] = indexi; - indexi = indexj; - ++j; - if (j == i) { - local_indices[j] = indexi; - break; - } - indexj = local_indices[j]; - } while (true); - break; - } - } - } - } - // Merge chunks into another buffer - SRC_INT_TYPE local_indices_temp[MID_LIMIT]; - std::merge(local_indices, local_indices+chunk_starts[1], - local_indices+chunk_starts[1], local_indices+chunk_starts[2], - local_indices_temp, [&midpointsx2](const SRC_INT_TYPE a, const SRC_INT_TYPE b)->bool { - return midpointsx2[a] < midpointsx2[b]; - }); - std::merge(local_indices+chunk_starts[2], local_indices+chunk_starts[3], - local_indices+chunk_starts[3], local_indices+chunk_starts[4], - local_indices_temp+chunk_starts[2], [&midpointsx2](const SRC_INT_TYPE a, const SRC_INT_TYPE b)->bool { - return midpointsx2[a] < midpointsx2[b]; - }); - std::merge(local_indices_temp, local_indices_temp+chunk_starts[2], - local_indices_temp+chunk_starts[2], local_indices_temp+chunk_starts[4], - local_indices, [&midpointsx2](const SRC_INT_TYPE a, const SRC_INT_TYPE b)->bool { - return midpointsx2[a] < midpointsx2[b]; - }); - - // Translate local_indices into indices - for (INT_TYPE i = 0; i < nboxes; ++i) { - local_indices[i] = indices[local_indices[i]]; - } - // Copy back - for (INT_TYPE i = 0; i < nboxes; ++i) { - indices[i] = local_indices[i]; - } -#else - std::stable_sort(indices, indices+nboxes, [boxes,max_axis](SRC_INT_TYPE a, SRC_INT_TYPE b)->bool { - return utBoxCenter(boxes[a], max_axis) < utBoxCenter(boxes[b], max_axis); - }); -#endif - - // Accumulate boxes - Box left_boxes[MID_LIMIT-1]; - Box right_boxes[MID_LIMIT-1]; - const INT_TYPE nsplits = nboxes-1; - Box box_accumulator(boxes[local_indices[0]]); - left_boxes[0] = box_accumulator; - for (INT_TYPE i = 1; i < nsplits; ++i) { - box_accumulator.combine(boxes[local_indices[i]]); - left_boxes[i] = box_accumulator; - } - box_accumulator.initBounds(boxes[local_indices[nsplits-1]]); - right_boxes[nsplits-1] = box_accumulator; - for (INT_TYPE i = nsplits-1; i > 0; --i) { - box_accumulator.combine(boxes[local_indices[i]]); - right_boxes[i-1] = box_accumulator; - } - - INT_TYPE best_split = 0; - T best_local_heuristic = - unweightedHeuristic(left_boxes[0]) + - unweightedHeuristic(right_boxes[0])*(nboxes-1); - for (INT_TYPE split = 1; split < nsplits; ++split) { - const T heuristic = - unweightedHeuristic(left_boxes[split])*(split+1) + - unweightedHeuristic(right_boxes[split])*(nboxes-(split+1)); - if (heuristic < best_local_heuristic) { - best_split = split; - best_local_heuristic = heuristic; - } - } - split_indices = indices+best_split+1; - split_boxes[0] = left_boxes[best_split]; - split_boxes[1] = right_boxes[best_split]; - return; - } - - const T axis_min = axes_minmax.vals[max_axis][0]; - const T axis_length = max_axis_length; - Box span_boxes[NSPANS]; - for (INT_TYPE i = 0; i < NSPANS; ++i) { - span_boxes[i].initBounds(); - } - INT_TYPE span_counts[NSPANS]; - for (INT_TYPE i = 0; i < NSPANS; ++i) { - span_counts[i] = 0; - } - - const T axis_min_x2 = ut_BoxCentre::scale*axis_min; - // NOTE: Factor of 0.5 is factored out of the average when using the average value to determine the span that a box lies in. - const T axis_index_scale = (T(1.0/ut_BoxCentre::scale)*NSPANS)/axis_length; - constexpr INT_TYPE BOX_SPANS_PARALLEL_THRESHOLD = 2048; - INT_TYPE ntasks = 1; - if (nboxes >= BOX_SPANS_PARALLEL_THRESHOLD) { - INT_TYPE nprocessors = UT_Thread::getNumProcessors(); - ntasks = (nprocessors > 1) ? SYSmin(4*nprocessors, nboxes/(BOX_SPANS_PARALLEL_THRESHOLD/2)) : 1; - } - if (ntasks == 1) { - for (INT_TYPE indexi = 0; indexi < nboxes; ++indexi) { - const auto& box = boxes[indices[indexi]]; - const T sum = utBoxCenter(box, axis); - const uint span_index = SYSclamp(int((sum-axis_min_x2)*axis_index_scale), int(0), int(NSPANS-1)); - ++span_counts[span_index]; - Box& span_box = span_boxes[span_index]; - span_box.combine(box); - } - } - else { - UT_SmallArray> parallel_boxes; - UT_SmallArray parallel_counts; - igl::parallel_for( - nboxes, - [¶llel_boxes,¶llel_counts](int n) - { - parallel_boxes.setSize( NSPANS*n); - parallel_counts.setSize(NSPANS*n); - for(int t = 0;t& span_box = parallel_boxes[t*NSPANS+span_index]; - span_box.combine(box); - }, - [¶llel_boxes,¶llel_counts,&span_boxes,&span_counts](int t) - { - for(int i = 0;i left_boxes[NSPLITS]; - // Spans 1 to NSPANS-1 - Box right_boxes[NSPLITS]; - - // Accumulate boxes - Box box_accumulator = span_boxes[0]; - left_boxes[0] = box_accumulator; - for (INT_TYPE i = 1; i < NSPLITS; ++i) { - box_accumulator.combine(span_boxes[i]); - left_boxes[i] = box_accumulator; - } - box_accumulator = span_boxes[NSPANS-1]; - right_boxes[NSPLITS-1] = box_accumulator; - for (INT_TYPE i = NSPLITS-1; i > 0; --i) { - box_accumulator.combine(span_boxes[i]); - right_boxes[i-1] = box_accumulator; - } - - INT_TYPE left_counts[NSPLITS]; - - // Accumulate counts - INT_TYPE count_accumulator = span_counts[0]; - left_counts[0] = count_accumulator; - for (INT_TYPE spliti = 1; spliti < NSPLITS; ++spliti) { - count_accumulator += span_counts[spliti]; - left_counts[spliti] = count_accumulator; - } - - // Check which split is optimal, making sure that at least 1/MIN_FRACTION of all boxes are on each side. - const INT_TYPE min_count = nboxes/MIN_FRACTION; - UT_ASSERT_MSG_P(min_count > 0, "MID_LIMIT above should have been large enough that nboxes would be > MIN_FRACTION"); - const INT_TYPE max_count = ((MIN_FRACTION-1)*uint64(nboxes))/MIN_FRACTION; - UT_ASSERT_MSG_P(max_count < nboxes, "I'm not sure how this could happen mathematically, but it needs to be checked."); - T smallest_heuristic = std::numeric_limits::infinity(); - INT_TYPE split_index = -1; - for (INT_TYPE spliti = 0; spliti < NSPLITS; ++spliti) { - const INT_TYPE left_count = left_counts[spliti]; - if (left_count < min_count || left_count > max_count) { - continue; - } - const INT_TYPE right_count = nboxes-left_count; - const T heuristic = - left_count*unweightedHeuristic(left_boxes[spliti]) + - right_count*unweightedHeuristic(right_boxes[spliti]); - if (heuristic < smallest_heuristic) { - smallest_heuristic = heuristic; - split_index = spliti; - } - } - - SRC_INT_TYPE*const indices_end = indices+nboxes; - - if (split_index == -1) { - // No split was anywhere close to balanced, so we fall back to searching for one. - - // First, find the span containing the "balance" point, namely where left_counts goes from - // being less than min_count to more than max_count. - // If that's span 0, use max_count as the ordered index to select, - // if it's span NSPANS-1, use min_count as the ordered index to select, - // else use nboxes/2 as the ordered index to select. - //T min_pivotx2 = -std::numeric_limits::infinity(); - //T max_pivotx2 = std::numeric_limits::infinity(); - SRC_INT_TYPE* nth_index; - if (left_counts[0] > max_count) { - // Search for max_count ordered index - nth_index = indices+max_count; - //max_pivotx2 = max_axis_min_x2 + max_axis_length/(NSPANS/ut_BoxCentre::scale); - } - else if (left_counts[NSPLITS-1] < min_count) { - // Search for min_count ordered index - nth_index = indices+min_count; - //min_pivotx2 = max_axis_min_x2 + max_axis_length - max_axis_length/(NSPANS/ut_BoxCentre::scale); - } - else { - // Search for nboxes/2 ordered index - nth_index = indices+nboxes/2; - //for (INT_TYPE spliti = 1; spliti < NSPLITS; ++spliti) { - // // The second condition should be redundant, but is just in case. - // if (left_counts[spliti] > max_count || spliti == NSPLITS-1) { - // min_pivotx2 = max_axis_min_x2 + spliti*max_axis_length/(NSPANS/ut_BoxCentre::scale); - // max_pivotx2 = max_axis_min_x2 + (spliti+1)*max_axis_length/(NSPANS/ut_BoxCentre::scale); - // break; - // } - //} - } - nthElement(boxes,indices,indices+nboxes,max_axis,nth_index);//,min_pivotx2,max_pivotx2); - - split_indices = nth_index; - Box left_box(boxes[indices[0]]); - for (SRC_INT_TYPE* left_indices = indices+1; left_indices < nth_index; ++left_indices) { - left_box.combine(boxes[*left_indices]); - } - Box right_box(boxes[nth_index[0]]); - for (SRC_INT_TYPE* right_indices = nth_index+1; right_indices < indices_end; ++right_indices) { - right_box.combine(boxes[*right_indices]); - } - split_boxes[0] = left_box; - split_boxes[1] = right_box; - } - else { - const T pivotx2 = axis_min_x2 + (split_index+1)*axis_length/(NSPANS/ut_BoxCentre::scale); - SRC_INT_TYPE* ppivot_start; - SRC_INT_TYPE* ppivot_end; - partitionByCentre(boxes,indices,indices+nboxes,max_axis,pivotx2,ppivot_start,ppivot_end); - - split_indices = indices + left_counts[split_index]; - - // Ignoring roundoff error, we would have - // split_indices >= ppivot_start && split_indices <= ppivot_end, - // but it may not always be in practice. - if (split_indices >= ppivot_start && split_indices <= ppivot_end) { - split_boxes[0] = left_boxes[split_index]; - split_boxes[1] = right_boxes[split_index]; - return; - } - - // Roundoff error changed the split, so we need to recompute the boxes. - if (split_indices < ppivot_start) { - split_indices = ppivot_start; - } - else {//(split_indices > ppivot_end) - split_indices = ppivot_end; - } - - // Emergency checks, just in case - if (split_indices == indices) { - ++split_indices; - } - else if (split_indices == indices_end) { - --split_indices; - } - - Box left_box(boxes[indices[0]]); - for (SRC_INT_TYPE* left_indices = indices+1; left_indices < split_indices; ++left_indices) { - left_box.combine(boxes[*left_indices]); - } - Box right_box(boxes[split_indices[0]]); - for (SRC_INT_TYPE* right_indices = split_indices+1; right_indices < indices_end; ++right_indices) { - right_box.combine(boxes[*right_indices]); - } - split_boxes[0] = left_box; - split_boxes[1] = right_box; - } - } - - template - template - inline void BVH::adjustParallelChildNodes(INT_TYPE nparallel, UT_Array& nodes, Node& node, UT_Array* parallel_nodes, SRC_INT_TYPE* sub_indices) noexcept - { - // Alec: No need to parallelize this... - //UTparallelFor(UT_BlockedRange(0,nparallel), [&node,&nodes,¶llel_nodes,&sub_indices](const UT_BlockedRange& r) { - INT_TYPE counted_parallel = 0; - INT_TYPE childi = 0; - for(int taski = 0;taski < nparallel; taski++) - { - //for (INT_TYPE taski = r.begin(), end = r.end(); taski < end; ++taski) { - // First, find which child this is - INT_TYPE sub_nboxes; - for (; childi < N; ++childi) { - sub_nboxes = sub_indices[childi+1]-sub_indices[childi]; - if (sub_nboxes >= PARALLEL_THRESHOLD) { - if (counted_parallel == taski) { - break; - } - ++counted_parallel; - } - } - UT_ASSERT_P(counted_parallel == taski); - - const UT_Array& local_nodes = parallel_nodes[counted_parallel]; - INT_TYPE n = local_nodes.size(); - INT_TYPE local_nodes_start = Node::getInternalNum(node.child[childi])+1; - ++counted_parallel; - ++childi; - - for (INT_TYPE j = 0; j < n; ++j) { - Node local_node = local_nodes[j]; - for (INT_TYPE childj = 0; childj < N; ++childj) { - INT_TYPE local_child = local_node.child[childj]; - if (Node::isInternal(local_child) && local_child != Node::EMPTY) { - local_child += local_nodes_start; - local_node.child[childj] = local_child; - } - } - nodes[local_nodes_start+j] = local_node; - } - } - } - - template - template - void BVH::nthElement(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const SRC_INT_TYPE* indices_end, const uint axis, SRC_INT_TYPE*const nth) noexcept {//, const T min_pivotx2, const T max_pivotx2) noexcept { - while (true) { - // Choose median of first, middle, and last as the pivot - T pivots[3] = { - utBoxCenter(boxes[indices[0]], axis), - utBoxCenter(boxes[indices[(indices_end-indices)/2]], axis), - utBoxCenter(boxes[*(indices_end-1)], axis) - }; - if (pivots[0] < pivots[1]) { - const T temp = pivots[0]; - pivots[0] = pivots[1]; - pivots[1] = temp; - } - if (pivots[0] < pivots[2]) { - const T temp = pivots[0]; - pivots[0] = pivots[2]; - pivots[2] = temp; - } - if (pivots[1] < pivots[2]) { - const T temp = pivots[1]; - pivots[1] = pivots[2]; - pivots[2] = temp; - } - T mid_pivotx2 = pivots[1]; -#if 0 - // We limit the pivot, because we know that the true value is between min and max - if (mid_pivotx2 < min_pivotx2) { - mid_pivotx2 = min_pivotx2; - } - else if (mid_pivotx2 > max_pivotx2) { - mid_pivotx2 = max_pivotx2; - } -#endif - SRC_INT_TYPE* pivot_start; - SRC_INT_TYPE* pivot_end; - partitionByCentre(boxes,indices,indices_end,axis,mid_pivotx2,pivot_start,pivot_end); - if (nth < pivot_start) { - indices_end = pivot_start; - } - else if (nth < pivot_end) { - // nth is in the middle of the pivot range, - // which is in the right place, so we're done. - return; - } - else { - indices = pivot_end; - } - if (indices_end <= indices+1) { - return; - } - } - } - - template - template - void BVH::partitionByCentre(const BOX_TYPE* boxes, SRC_INT_TYPE*const indices, const SRC_INT_TYPE*const indices_end, const uint axis, const T pivotx2, SRC_INT_TYPE*& ppivot_start, SRC_INT_TYPE*& ppivot_end) noexcept { - // TODO: Consider parallelizing this! - - // First element >= pivot - SRC_INT_TYPE* pivot_start = indices; - // First element > pivot - SRC_INT_TYPE* pivot_end = indices; - - // Loop through forward once - for (SRC_INT_TYPE* psrc_index = indices; psrc_index != indices_end; ++psrc_index) { - const T srcsum = utBoxCenter(boxes[*psrc_index], axis); - if (srcsum < pivotx2) { - if (psrc_index != pivot_start) { - if (pivot_start == pivot_end) { - // Common case: nothing equal to the pivot - const SRC_INT_TYPE temp = *psrc_index; - *psrc_index = *pivot_start; - *pivot_start = temp; - } - else { - // Less common case: at least one thing equal to the pivot - const SRC_INT_TYPE temp = *psrc_index; - *psrc_index = *pivot_end; - *pivot_end = *pivot_start; - *pivot_start = temp; - } - } - ++pivot_start; - ++pivot_end; - } - else if (srcsum == pivotx2) { - // Add to the pivot area - if (psrc_index != pivot_end) { - const SRC_INT_TYPE temp = *psrc_index; - *psrc_index = *pivot_end; - *pivot_end = temp; - } - ++pivot_end; - } - } - ppivot_start = pivot_start; - ppivot_end = pivot_end; - } - -#if 0 - template -void BVH::debugDump() const { - printf("\nNode 0: {\n"); - UT_WorkBuffer indent; - indent.append(80, ' '); - UT_Array stack; - stack.append(0); - stack.append(0); - while (!stack.isEmpty()) { - int depth = stack.size()/2; - if (indent.length() < 4*depth) { - indent.append(4, ' '); - } - INT_TYPE cur_nodei = stack[stack.size()-2]; - INT_TYPE cur_i = stack[stack.size()-1]; - if (cur_i == N) { - printf(indent.buffer()+indent.length()-(4*(depth-1))); - printf("}\n"); - stack.removeLast(); - stack.removeLast(); - continue; - } - ++stack[stack.size()-1]; - Node& cur_node = myRoot[cur_nodei]; - INT_TYPE child_nodei = cur_node.child[cur_i]; - if (Node::isInternal(child_nodei)) { - if (child_nodei == Node::EMPTY) { - printf(indent.buffer()+indent.length()-(4*(depth-1))); - printf("}\n"); - stack.removeLast(); - stack.removeLast(); - continue; - } - INT_TYPE internal_node = Node::getInternalNum(child_nodei); - printf(indent.buffer()+indent.length()-(4*depth)); - printf("Node %u: {\n", uint(internal_node)); - stack.append(internal_node); - stack.append(0); - continue; - } - else { - printf(indent.buffer()+indent.length()-(4*depth)); - printf("Tri %u\n", uint(child_nodei)); - } - } -} -#endif - - } // UT namespace - } // End HDK_Sample namespace - }} -#endif -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * Functions and structures for computing solid angles. - */ - -#pragma once - -#ifndef __HDK_UT_SolidAngle_h__ -#define __HDK_UT_SolidAngle_h__ - - - - - -#include - -namespace igl { namespace FastWindingNumber { - namespace HDK_Sample { - - template - using UT_Vector2T = UT_FixedVector; - template - using UT_Vector3T = UT_FixedVector; - - template - SYS_FORCE_INLINE T cross(const UT_Vector2T &v1, const UT_Vector2T &v2) - { - return v1[0]*v2[1] - v1[1]*v2[0]; - } - - template - SYS_FORCE_INLINE - UT_Vector3T cross(const UT_Vector3T &v1, const UT_Vector3T &v2) - { - UT_Vector3T result; - // compute the cross product: - result[0] = v1[1]*v2[2] - v1[2]*v2[1]; - result[1] = v1[2]*v2[0] - v1[0]*v2[2]; - result[2] = v1[0]*v2[1] - v1[1]*v2[0]; - return result; - } - -/// Returns the signed solid angle subtended by triangle abc -/// from query point. -/// -/// WARNING: This uses the right-handed normal convention, whereas most of -/// Houdini uses the left-handed normal convention, so either -/// negate the output, or swap b and c if you want it to be -/// positive inside and negative outside. - template - inline T UTsignedSolidAngleTri( - const UT_Vector3T &a, - const UT_Vector3T &b, - const UT_Vector3T &c, - const UT_Vector3T &query) - { - // Make a, b, and c relative to query - UT_Vector3T qa = a-query; - UT_Vector3T qb = b-query; - UT_Vector3T qc = c-query; - - const T alength = qa.length(); - const T blength = qb.length(); - const T clength = qc.length(); - - // If any triangle vertices are coincident with query, - // query is on the surface, which we treat as no solid angle. - if (alength == 0 || blength == 0 || clength == 0) - return T(0); - - // Normalize the vectors - qa /= alength; - qb /= blength; - qc /= clength; - - // The formula on Wikipedia has roughly dot(qa,cross(qb,qc)), - // but that's unstable when qa, qb, and qc are very close, - // (e.g. if the input triangle was very far away). - // This should be equivalent, but more stable. - const T numerator = dot(qa, cross(qb-qa, qc-qa)); - - // If numerator is 0, regardless of denominator, query is on the - // surface, which we treat as no solid angle. - if (numerator == 0) - return T(0); - - const T denominator = T(1) + dot(qa,qb) + dot(qa,qc) + dot(qb,qc); - - return T(2)*SYSatan2(numerator, denominator); - } - - template - inline T UTsignedSolidAngleQuad( - const UT_Vector3T &a, - const UT_Vector3T &b, - const UT_Vector3T &c, - const UT_Vector3T &d, - const UT_Vector3T &query) - { - // Make a, b, c, and d relative to query - UT_Vector3T v[4] = { - a-query, - b-query, - c-query, - d-query - }; - - const T lengths[4] = { - v[0].length(), - v[1].length(), - v[2].length(), - v[3].length() - }; - - // If any quad vertices are coincident with query, - // query is on the surface, which we treat as no solid angle. - // We could add the contribution from the non-planar part, - // but in the context of a mesh, we'd still miss some, like - // we do in the triangle case. - if (lengths[0] == T(0) || lengths[1] == T(0) || lengths[2] == T(0) || lengths[3] == T(0)) - return T(0); - - // Normalize the vectors - v[0] /= lengths[0]; - v[1] /= lengths[1]; - v[2] /= lengths[2]; - v[3] /= lengths[3]; - - // Compute (unnormalized, but consistently-scaled) barycentric coordinates - // for the query point inside the tetrahedron of points. - // If 0 or 4 of the coordinates are positive, (or slightly negative), the - // query is (approximately) inside, so the choice of triangulation matters. - // Otherwise, the triangulation doesn't matter. - - const UT_Vector3T diag02 = v[2]-v[0]; - const UT_Vector3T diag13 = v[3]-v[1]; - const UT_Vector3T v01 = v[1]-v[0]; - const UT_Vector3T v23 = v[3]-v[2]; - - T bary[4]; - bary[0] = dot(v[3],cross(v23,diag13)); - bary[1] = -dot(v[2],cross(v23,diag02)); - bary[2] = -dot(v[1],cross(v01,diag13)); - bary[3] = dot(v[0],cross(v01,diag02)); - - const T dot01 = dot(v[0],v[1]); - const T dot12 = dot(v[1],v[2]); - const T dot23 = dot(v[2],v[3]); - const T dot30 = dot(v[3],v[0]); - - T omega = T(0); - - // Equation of a bilinear patch in barycentric coordinates of its - // tetrahedron is x0*x2 = x1*x3. Less is one side; greater is other. - if (bary[0]*bary[2] < bary[1]*bary[3]) - { - // Split 0-2: triangles 0,1,2 and 0,2,3 - const T numerator012 = bary[3]; - const T numerator023 = bary[1]; - const T dot02 = dot(v[0],v[2]); - - // If numerator is 0, regardless of denominator, query is on the - // surface, which we treat as no solid angle. - if (numerator012 != T(0)) - { - const T denominator012 = T(1) + dot01 + dot12 + dot02; - omega = SYSatan2(numerator012, denominator012); - } - if (numerator023 != T(0)) - { - const T denominator023 = T(1) + dot02 + dot23 + dot30; - omega += SYSatan2(numerator023, denominator023); - } - } - else - { - // Split 1-3: triangles 0,1,3 and 1,2,3 - const T numerator013 = -bary[2]; - const T numerator123 = -bary[0]; - const T dot13 = dot(v[1],v[3]); - - // If numerator is 0, regardless of denominator, query is on the - // surface, which we treat as no solid angle. - if (numerator013 != T(0)) - { - const T denominator013 = T(1) + dot01 + dot13 + dot30; - omega = SYSatan2(numerator013, denominator013); - } - if (numerator123 != T(0)) - { - const T denominator123 = T(1) + dot12 + dot23 + dot13; - omega += SYSatan2(numerator123, denominator123); - } - } - return T(2)*omega; - } - -/// Class for quickly approximating signed solid angle of a large mesh -/// from many query points. This is useful for computing the -/// generalized winding number at many points. -/// -/// NOTE: This is currently only instantiated for . - template - class UT_SolidAngle - { - public: - /// This is outlined so that we don't need to include UT_BVHImpl.h - inline UT_SolidAngle(); - /// This is outlined so that we don't need to include UT_BVHImpl.h - inline ~UT_SolidAngle(); - - /// NOTE: This does not take ownership over triangle_points or positions, - /// but does keep pointers to them, so the caller must keep them in - /// scope for the lifetime of this structure. - UT_SolidAngle( - const int ntriangles, - const int *const triangle_points, - const int npoints, - const UT_Vector3T *const positions, - const int order = 2) - : UT_SolidAngle() - { init(ntriangles, triangle_points, npoints, positions, order); } - - /// Initialize the tree and data. - /// NOTE: It is safe to call init on a UT_SolidAngle that has had init - /// called on it before, to re-initialize it. - inline void init( - const int ntriangles, - const int *const triangle_points, - const int npoints, - const UT_Vector3T *const positions, - const int order = 2); - - /// Frees myTree and myData, and clears the rest. - inline void clear(); - - /// Returns true if this is clear - bool isClear() const - { return myNTriangles == 0; } - - /// Returns an approximation of the signed solid angle of the mesh from the specified query_point - /// accuracy_scale is the value of (maxP/q) beyond which the approximation of the box will be used. - inline T computeSolidAngle(const UT_Vector3T &query_point, const T accuracy_scale = T(2.0)) const; - - private: - struct BoxData; - - static constexpr uint BVH_N = 4; - UT_BVH myTree; - int myNBoxes; - int myOrder; - std::unique_ptr myData; - int myNTriangles; - const int *myTrianglePoints; - int myNPoints; - const UT_Vector3T *myPositions; - }; - - template - inline T UTsignedAngleSegment( - const UT_Vector2T &a, - const UT_Vector2T &b, - const UT_Vector2T &query) - { - // Make a and b relative to query - UT_Vector2T qa = a-query; - UT_Vector2T qb = b-query; - - // If any segment vertices are coincident with query, - // query is on the segment, which we treat as no angle. - if (qa.isZero() || qb.isZero()) - return T(0); - - // numerator = |qa||qb|sin(theta) - const T numerator = cross(qa, qb); - - // If numerator is 0, regardless of denominator, query is on the - // surface, which we treat as no solid angle. - if (numerator == 0) - return T(0); - - // denominator = |qa||qb|cos(theta) - const T denominator = dot(qa,qb); - - // numerator/denominator = tan(theta) - return SYSatan2(numerator, denominator); - } - -/// Class for quickly approximating signed subtended angle of a large curve -/// from many query points. This is useful for computing the -/// generalized winding number at many points. -/// -/// NOTE: This is currently only instantiated for . - template - class UT_SubtendedAngle - { - public: - /// This is outlined so that we don't need to include UT_BVHImpl.h - inline UT_SubtendedAngle(); - /// This is outlined so that we don't need to include UT_BVHImpl.h - inline ~UT_SubtendedAngle(); - - /// NOTE: This does not take ownership over segment_points or positions, - /// but does keep pointers to them, so the caller must keep them in - /// scope for the lifetime of this structure. - UT_SubtendedAngle( - const int nsegments, - const int *const segment_points, - const int npoints, - const UT_Vector2T *const positions, - const int order = 2) - : UT_SubtendedAngle() - { init(nsegments, segment_points, npoints, positions, order); } - - /// Initialize the tree and data. - /// NOTE: It is safe to call init on a UT_SolidAngle that has had init - /// called on it before, to re-initialize it. - inline void init( - const int nsegments, - const int *const segment_points, - const int npoints, - const UT_Vector2T *const positions, - const int order = 2); - - /// Frees myTree and myData, and clears the rest. - inline void clear(); - - /// Returns true if this is clear - bool isClear() const - { return myNSegments == 0; } - - /// Returns an approximation of the signed solid angle of the mesh from the specified query_point - /// accuracy_scale is the value of (maxP/q) beyond which the approximation of the box will be used. - inline T computeAngle(const UT_Vector2T &query_point, const T accuracy_scale = T(2.0)) const; - - private: - struct BoxData; - - static constexpr uint BVH_N = 4; - UT_BVH myTree; - int myNBoxes; - int myOrder; - std::unique_ptr myData; - int myNSegments; - const int *mySegmentPoints; - int myNPoints; - const UT_Vector2T *myPositions; - }; - - } // End HDK_Sample namespace - }} -#endif -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * A wrapper function for the "free" function, used by UT_(Small)Array - */ - - - -#include - -namespace igl { namespace FastWindingNumber { - -// This needs to be here or else the warning suppression doesn't work because -// the templated calling code won't otherwise be compiled until after we've -// already popped the warning.state. So we just always disable this at file -// scope here. -#if defined(__GNUC__) && !defined(__clang__) - _Pragma("GCC diagnostic push") - _Pragma("GCC diagnostic ignored \"-Wfree-nonheap-object\"") -#endif - inline void ut_ArrayImplFree(void *p) - { - free(p); - } -#if defined(__GNUC__) && !defined(__clang__) - _Pragma("GCC diagnostic pop") -#endif - } } -/* - * Copyright (c) 2018 Side Effects Software Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * COMMENTS: - * Functions and structures for computing solid angles. - */ - - - - - - - - -#include -#include -#include - -#define SOLID_ANGLE_TIME_PRECOMPUTE 0 - -#if SOLID_ANGLE_TIME_PRECOMPUTE -#include -#endif - -#define SOLID_ANGLE_DEBUG 0 -#if SOLID_ANGLE_DEBUG -#include -#endif - -#define TAYLOR_SERIES_ORDER 2 - -namespace igl { namespace FastWindingNumber { - - namespace HDK_Sample { - - template - struct UT_SolidAngle::BoxData - { - void clear() - { - // Set everything to zero - memset(this,0,sizeof(*this)); - } - - using Type = typename std::conditional::value, v4uf, UT_FixedVector>::type; - using SType = typename std::conditional::value, v4uf, UT_FixedVector>::type; - - /// An upper bound on the squared distance from myAverageP to the farthest point in the box. - SType myMaxPDist2; - - /// Centre of mass of the mesh surface in this box - UT_FixedVector myAverageP; - - /// Unnormalized, area-weighted normal of the mesh in this box - UT_FixedVector myN; - -#if TAYLOR_SERIES_ORDER >= 1 - /// Values for Omega_1 - /// @{ - UT_FixedVector myNijDiag; // Nxx, Nyy, Nzz - Type myNxy_Nyx; // Nxy+Nyx - Type myNyz_Nzy; // Nyz+Nzy - Type myNzx_Nxz; // Nzx+Nxz - /// @} -#endif - -#if TAYLOR_SERIES_ORDER >= 2 - /// Values for Omega_2 - /// @{ - UT_FixedVector myNijkDiag; // Nxxx, Nyyy, Nzzz - Type mySumPermuteNxyz; // (Nxyz+Nxzy+Nyzx+Nyxz+Nzxy+Nzyx) = 2*(Nxyz+Nyzx+Nzxy) - Type my2Nxxy_Nyxx; // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx - Type my2Nxxz_Nzxx; // Nxxz+Nxzx+Nzxx = 2Nxxz+Nzxx - Type my2Nyyz_Nzyy; // Nyyz+Nyzy+Nzyy = 2Nyyz+Nzyy - Type my2Nyyx_Nxyy; // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy - Type my2Nzzx_Nxzz; // Nzzx+Nzxz+Nxzz = 2Nzzx+Nxzz - Type my2Nzzy_Nyzz; // Nzzy+Nzyz+Nyzz = 2Nzzy+Nyzz - /// @} -#endif - }; - - template - inline UT_SolidAngle::UT_SolidAngle() - : myTree() - , myNBoxes(0) - , myOrder(2) - , myData(nullptr) - , myNTriangles(0) - , myTrianglePoints(nullptr) - , myNPoints(0) - , myPositions(nullptr) - {} - - template - inline UT_SolidAngle::~UT_SolidAngle() - { - // Default destruction works, but this needs to be outlined - // to avoid having to include UT_BVHImpl.h in the header, - // (for the UT_UniquePtr destructor.) - } - - template - inline void UT_SolidAngle::init( - const int ntriangles, - const int *const triangle_points, - const int npoints, - const UT_Vector3T *const positions, - const int order) - { -#if SOLID_ANGLE_DEBUG - UTdebugFormat(""); - UTdebugFormat(""); - UTdebugFormat("Building BVH for {} ntriangles on {} points:", ntriangles, npoints); -#endif - myOrder = order; - myNTriangles = ntriangles; - myTrianglePoints = triangle_points; - myNPoints = npoints; - myPositions = positions; - -#if SOLID_ANGLE_TIME_PRECOMPUTE - UT_StopWatch timer; - timer.start(); -#endif - UT_SmallArray> triangle_boxes; - triangle_boxes.setSizeNoInit(ntriangles); - if (ntriangles < 16*1024) - { - const int *cur_triangle_points = triangle_points; - for (int i = 0; i < ntriangles; ++i, cur_triangle_points += 3) - { - UT::Box &box = triangle_boxes[i]; - box.initBounds(positions[cur_triangle_points[0]]); - box.enlargeBounds(positions[cur_triangle_points[1]]); - box.enlargeBounds(positions[cur_triangle_points[2]]); - } - } - else - { - igl::parallel_for(ntriangles, - [triangle_points,&triangle_boxes,positions](int i) - { - const int *cur_triangle_points = triangle_points + i*3; - UT::Box &box = triangle_boxes[i]; - box.initBounds(positions[cur_triangle_points[0]]); - box.enlargeBounds(positions[cur_triangle_points[1]]); - box.enlargeBounds(positions[cur_triangle_points[2]]); - }); - } -#if SOLID_ANGLE_TIME_PRECOMPUTE - double time = timer.stop(); - UTdebugFormat("{} s to create bounding boxes.", time); - timer.start(); -#endif - myTree.template init(triangle_boxes.array(), ntriangles); -#if SOLID_ANGLE_TIME_PRECOMPUTE - time = timer.stop(); - UTdebugFormat("{} s to initialize UT_BVH structure. {} nodes", time, myTree.getNumNodes()); -#endif - - //myTree.debugDump(); - - const int nnodes = myTree.getNumNodes(); - - myNBoxes = nnodes; - BoxData *box_data = new BoxData[nnodes]; - myData.reset(box_data); - - // Some data are only needed during initialization. - struct LocalData - { - // Bounding box - UT::Box myBox; - - // P and N are needed from each child for computing Nij. - UT_Vector3T myAverageP; - UT_Vector3T myAreaP; - UT_Vector3T myN; - - // Unsigned area is needed for computing the average position. - T myArea; - -#if TAYLOR_SERIES_ORDER >= 1 - // These are needed for computing Nijk. - UT_Vector3T myNijDiag; - T myNxy; T myNyx; - T myNyz; T myNzy; - T myNzx; T myNxz; -#endif - -#if TAYLOR_SERIES_ORDER >= 2 - UT_Vector3T myNijkDiag; // Nxxx, Nyyy, Nzzz - T mySumPermuteNxyz; // (Nxyz+Nxzy+Nyzx+Nyxz+Nzxy+Nzyx) = 2*(Nxyz+Nyzx+Nzxy) - T my2Nxxy_Nyxx; // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx - T my2Nxxz_Nzxx; // Nxxz+Nxzx+Nzxx = 2Nxxz+Nzxx - T my2Nyyz_Nzyy; // Nyyz+Nyzy+Nzyy = 2Nyyz+Nzyy - T my2Nyyx_Nxyy; // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy - T my2Nzzx_Nxzz; // Nzzx+Nzxz+Nxzz = 2Nzzx+Nxzz - T my2Nzzy_Nyzz; // Nzzy+Nzyz+Nyzz = 2Nzzy+Nyzz -#endif - }; - - struct PrecomputeFunctors - { - BoxData *const myBoxData; - const UT::Box *const myTriangleBoxes; - const int *const myTrianglePoints; - const UT_Vector3T *const myPositions; - const int myOrder; - - PrecomputeFunctors( - BoxData *box_data, - const UT::Box *triangle_boxes, - const int *triangle_points, - const UT_Vector3T *positions, - const int order) - : myBoxData(box_data) - , myTriangleBoxes(triangle_boxes) - , myTrianglePoints(triangle_points) - , myPositions(positions) - , myOrder(order) - {} - constexpr SYS_FORCE_INLINE bool pre(const int nodei, LocalData *data_for_parent) const - { - return true; - } - void item(const int itemi, const int parent_nodei, LocalData &data_for_parent) const - { - const UT_Vector3T *const positions = myPositions; - const int *const cur_triangle_points = myTrianglePoints + 3*itemi; - const UT_Vector3T a = positions[cur_triangle_points[0]]; - const UT_Vector3T b = positions[cur_triangle_points[1]]; - const UT_Vector3T c = positions[cur_triangle_points[2]]; - const UT_Vector3T ab = b-a; - const UT_Vector3T ac = c-a; - - const UT::Box &triangle_box = myTriangleBoxes[itemi]; - data_for_parent.myBox.initBounds(triangle_box.getMin(), triangle_box.getMax()); - - // Area-weighted normal (unnormalized) - const UT_Vector3T N = T(0.5)*cross(ab,ac); - const T area2 = N.length2(); - const T area = SYSsqrt(area2); - const UT_Vector3T P = (a+b+c)/3; - data_for_parent.myAverageP = P; - data_for_parent.myAreaP = P*area; - data_for_parent.myN = N; -#if SOLID_ANGLE_DEBUG - UTdebugFormat(""); - UTdebugFormat("Triangle {}: P = {}; N = {}; area = {}", itemi, P, N, area); - UTdebugFormat(" box = {}", data_for_parent.myBox); -#endif - - data_for_parent.myArea = area; -#if TAYLOR_SERIES_ORDER >= 1 - const int order = myOrder; - if (order < 1) - return; - - // NOTE: Due to P being at the centroid, triangles have Nij = 0 - // contributions to Nij. - data_for_parent.myNijDiag = T(0); - data_for_parent.myNxy = 0; data_for_parent.myNyx = 0; - data_for_parent.myNyz = 0; data_for_parent.myNzy = 0; - data_for_parent.myNzx = 0; data_for_parent.myNxz = 0; -#endif - -#if TAYLOR_SERIES_ORDER >= 2 - if (order < 2) - return; - - // If it's zero-length, the results are zero, so we can skip. - if (area == 0) - { - data_for_parent.myNijkDiag = T(0); - data_for_parent.mySumPermuteNxyz = 0; - data_for_parent.my2Nxxy_Nyxx = 0; - data_for_parent.my2Nxxz_Nzxx = 0; - data_for_parent.my2Nyyz_Nzyy = 0; - data_for_parent.my2Nyyx_Nxyy = 0; - data_for_parent.my2Nzzx_Nxzz = 0; - data_for_parent.my2Nzzy_Nyzz = 0; - return; - } - - // We need to use the NORMALIZED normal to multiply the integrals by. - UT_Vector3T n = N/area; - - // Figure out the order of a, b, and c in x, y, and z - // for use in computing the integrals for Nijk. - UT_Vector3T values[3] = {a, b, c}; - - int order_x[3] = {0,1,2}; - if (a[0] > b[0]) - std::swap(order_x[0],order_x[1]); - if (values[order_x[0]][0] > c[0]) - std::swap(order_x[0],order_x[2]); - if (values[order_x[1]][0] > values[order_x[2]][0]) - std::swap(order_x[1],order_x[2]); - T dx = values[order_x[2]][0] - values[order_x[0]][0]; - - int order_y[3] = {0,1,2}; - if (a[1] > b[1]) - std::swap(order_y[0],order_y[1]); - if (values[order_y[0]][1] > c[1]) - std::swap(order_y[0],order_y[2]); - if (values[order_y[1]][1] > values[order_y[2]][1]) - std::swap(order_y[1],order_y[2]); - T dy = values[order_y[2]][1] - values[order_y[0]][1]; - - int order_z[3] = {0,1,2}; - if (a[2] > b[2]) - std::swap(order_z[0],order_z[1]); - if (values[order_z[0]][2] > c[2]) - std::swap(order_z[0],order_z[2]); - if (values[order_z[1]][2] > values[order_z[2]][2]) - std::swap(order_z[1],order_z[2]); - T dz = values[order_z[2]][2] - values[order_z[0]][2]; - - auto &&compute_integrals = []( - const UT_Vector3T &a, - const UT_Vector3T &b, - const UT_Vector3T &c, - const UT_Vector3T &P, - T *integral_ii, - T *integral_ij, - T *integral_ik, - const int i) - { -#if SOLID_ANGLE_DEBUG - UTdebugFormat(" Splitting on {}; a = {}; b = {}; c = {}", char('x'+i), a, b, c); -#endif - // NOTE: a, b, and c must be in order of the i axis. - // We're splitting the triangle at the middle i coordinate. - const UT_Vector3T oab = b - a; - const UT_Vector3T oac = c - a; - const UT_Vector3T ocb = b - c; - UT_ASSERT_MSG_P(oac[i] > 0, "This should have been checked by the caller."); - const T t = oab[i]/oac[i]; - UT_ASSERT_MSG_P(t >= 0 && t <= 1, "Either sorting must have gone wrong, or there are input NaNs."); - - const int j = (i==2) ? 0 : (i+1); - const int k = (j==2) ? 0 : (j+1); - const T jdiff = t*oac[j] - oab[j]; - const T kdiff = t*oac[k] - oab[k]; - UT_Vector3T cross_a; - cross_a[0] = (jdiff*oab[k] - kdiff*oab[j]); - cross_a[1] = kdiff*oab[i]; - cross_a[2] = jdiff*oab[i]; - UT_Vector3T cross_c; - cross_c[0] = (jdiff*ocb[k] - kdiff*ocb[j]); - cross_c[1] = kdiff*ocb[i]; - cross_c[2] = jdiff*ocb[i]; - const T area_scale_a = cross_a.length(); - const T area_scale_c = cross_c.length(); - const T Pai = a[i] - P[i]; - const T Pci = c[i] - P[i]; - - // Integral over the area of the triangle of (pi^2)dA, - // by splitting the triangle into two at b, the a side - // and the c side. - const T int_ii_a = area_scale_a*(T(0.5)*Pai*Pai + T(2.0/3.0)*Pai*oab[i] + T(0.25)*oab[i]*oab[i]); - const T int_ii_c = area_scale_c*(T(0.5)*Pci*Pci + T(2.0/3.0)*Pci*ocb[i] + T(0.25)*ocb[i]*ocb[i]); - *integral_ii = int_ii_a + int_ii_c; -#if SOLID_ANGLE_DEBUG - UTdebugFormat(" integral_{}{}_a = {}; integral_{}{}_c = {}", char('x'+i), char('x'+i), int_ii_a, char('x'+i), char('x'+i), int_ii_c); -#endif - - int jk = j; - T *integral = integral_ij; - T diff = jdiff; - while (true) // This only does 2 iterations, one for j and one for k - { - if (integral) - { - T obmidj = b[jk] + T(0.5)*diff; - T oabmidj = obmidj - a[jk]; - T ocbmidj = obmidj - c[jk]; - T Paj = a[jk] - P[jk]; - T Pcj = c[jk] - P[jk]; - // Integral over the area of the triangle of (pi*pj)dA - const T int_ij_a = area_scale_a*(T(0.5)*Pai*Paj + T(1.0/3.0)*Pai*oabmidj + T(1.0/3.0)*Paj*oab[i] + T(0.25)*oab[i]*oabmidj); - const T int_ij_c = area_scale_c*(T(0.5)*Pci*Pcj + T(1.0/3.0)*Pci*ocbmidj + T(1.0/3.0)*Pcj*ocb[i] + T(0.25)*ocb[i]*ocbmidj); - *integral = int_ij_a + int_ij_c; -#if SOLID_ANGLE_DEBUG - UTdebugFormat(" integral_{}{}_a = {}; integral_{}{}_c = {}", char('x'+i), char('x'+jk), int_ij_a, char('x'+i), char('x'+jk), int_ij_c); -#endif - } - if (jk == k) - break; - jk = k; - integral = integral_ik; - diff = kdiff; - } - }; - - T integral_xx = 0; - T integral_xy = 0; - T integral_yy = 0; - T integral_yz = 0; - T integral_zz = 0; - T integral_zx = 0; - // Note that if the span of any axis is zero, the integral must be zero, - // since there's a factor of (p_i-P_i), i.e. value minus average, - // and every value must be equal to the average, giving zero. - if (dx > 0) - { - compute_integrals( - values[order_x[0]], values[order_x[1]], values[order_x[2]], P, - &integral_xx, ((dx >= dy && dy > 0) ? &integral_xy : nullptr), ((dx >= dz && dz > 0) ? &integral_zx : nullptr), 0); - } - if (dy > 0) - { - compute_integrals( - values[order_y[0]], values[order_y[1]], values[order_y[2]], P, - &integral_yy, ((dy >= dz && dz > 0) ? &integral_yz : nullptr), ((dx < dy && dx > 0) ? &integral_xy : nullptr), 1); - } - if (dz > 0) - { - compute_integrals( - values[order_z[0]], values[order_z[1]], values[order_z[2]], P, - &integral_zz, ((dx < dz && dx > 0) ? &integral_zx : nullptr), ((dy < dz && dy > 0) ? &integral_yz : nullptr), 2); - } - - UT_Vector3T Niii; - Niii[0] = integral_xx; - Niii[1] = integral_yy; - Niii[2] = integral_zz; - Niii *= n; - data_for_parent.myNijkDiag = Niii; - data_for_parent.mySumPermuteNxyz = 2*(n[0]*integral_yz + n[1]*integral_zx + n[2]*integral_xy); - T Nxxy = n[0]*integral_xy; - T Nxxz = n[0]*integral_zx; - T Nyyz = n[1]*integral_yz; - T Nyyx = n[1]*integral_xy; - T Nzzx = n[2]*integral_zx; - T Nzzy = n[2]*integral_yz; - data_for_parent.my2Nxxy_Nyxx = 2*Nxxy + n[1]*integral_xx; - data_for_parent.my2Nxxz_Nzxx = 2*Nxxz + n[2]*integral_xx; - data_for_parent.my2Nyyz_Nzyy = 2*Nyyz + n[2]*integral_yy; - data_for_parent.my2Nyyx_Nxyy = 2*Nyyx + n[0]*integral_yy; - data_for_parent.my2Nzzx_Nxzz = 2*Nzzx + n[0]*integral_zz; - data_for_parent.my2Nzzy_Nyzz = 2*Nzzy + n[1]*integral_zz; -#if SOLID_ANGLE_DEBUG - UTdebugFormat(" integral_xx = {}; yy = {}; zz = {}", integral_xx, integral_yy, integral_zz); - UTdebugFormat(" integral_xy = {}; yz = {}; zx = {}", integral_xy, integral_yz, integral_zx); -#endif -#endif - } - - void post(const int nodei, const int parent_nodei, LocalData *data_for_parent, const int nchildren, const LocalData *child_data_array) const - { - // NOTE: Although in the general case, data_for_parent may be null for the root call, - // this functor assumes that it's non-null, so the call below must pass a non-null pointer. - - BoxData ¤t_box_data = myBoxData[nodei]; - - UT_Vector3T N = child_data_array[0].myN; - ((T*)¤t_box_data.myN[0])[0] = N[0]; - ((T*)¤t_box_data.myN[1])[0] = N[1]; - ((T*)¤t_box_data.myN[2])[0] = N[2]; - UT_Vector3T areaP = child_data_array[0].myAreaP; - T area = child_data_array[0].myArea; - UT_Vector3T local_P = child_data_array[0].myAverageP; - ((T*)¤t_box_data.myAverageP[0])[0] = local_P[0]; - ((T*)¤t_box_data.myAverageP[1])[0] = local_P[1]; - ((T*)¤t_box_data.myAverageP[2])[0] = local_P[2]; - for (int i = 1; i < nchildren; ++i) - { - const UT_Vector3T local_N = child_data_array[i].myN; - N += local_N; - ((T*)¤t_box_data.myN[0])[i] = local_N[0]; - ((T*)¤t_box_data.myN[1])[i] = local_N[1]; - ((T*)¤t_box_data.myN[2])[i] = local_N[2]; - areaP += child_data_array[i].myAreaP; - area += child_data_array[i].myArea; - const UT_Vector3T local_P = child_data_array[i].myAverageP; - ((T*)¤t_box_data.myAverageP[0])[i] = local_P[0]; - ((T*)¤t_box_data.myAverageP[1])[i] = local_P[1]; - ((T*)¤t_box_data.myAverageP[2])[i] = local_P[2]; - } - for (int i = nchildren; i < BVH_N; ++i) - { - // Set to zero, just to avoid false positives for uses of uninitialized memory. - ((T*)¤t_box_data.myN[0])[i] = 0; - ((T*)¤t_box_data.myN[1])[i] = 0; - ((T*)¤t_box_data.myN[2])[i] = 0; - ((T*)¤t_box_data.myAverageP[0])[i] = 0; - ((T*)¤t_box_data.myAverageP[1])[i] = 0; - ((T*)¤t_box_data.myAverageP[2])[i] = 0; - } - data_for_parent->myN = N; - data_for_parent->myAreaP = areaP; - data_for_parent->myArea = area; - - UT::Box box(child_data_array[0].myBox); - for (int i = 1; i < nchildren; ++i) - box.enlargeBounds(child_data_array[i].myBox); - - // Normalize P - UT_Vector3T averageP; - if (area > 0) - averageP = areaP/area; - else - averageP = T(0.5)*(box.getMin() + box.getMax()); - data_for_parent->myAverageP = averageP; - - data_for_parent->myBox = box; - - for (int i = 0; i < nchildren; ++i) - { - const UT::Box &local_box(child_data_array[i].myBox); - const UT_Vector3T &local_P = child_data_array[i].myAverageP; - const UT_Vector3T maxPDiff = SYSmax(local_P-UT_Vector3T(local_box.getMin()), UT_Vector3T(local_box.getMax())-local_P); - ((T*)¤t_box_data.myMaxPDist2)[i] = maxPDiff.length2(); - } - for (int i = nchildren; i < BVH_N; ++i) - { - // This child is non-existent. If we set myMaxPDist2 to infinity, it will never - // use the approximation, and the traverseVector function can check for EMPTY. - ((T*)¤t_box_data.myMaxPDist2)[i] = std::numeric_limits::infinity(); - } - -#if TAYLOR_SERIES_ORDER >= 1 - const int order = myOrder; - if (order >= 1) - { - // We now have the current box's P, so we can adjust Nij and Nijk - data_for_parent->myNijDiag = child_data_array[0].myNijDiag; - data_for_parent->myNxy = 0; - data_for_parent->myNyx = 0; - data_for_parent->myNyz = 0; - data_for_parent->myNzy = 0; - data_for_parent->myNzx = 0; - data_for_parent->myNxz = 0; -#if TAYLOR_SERIES_ORDER >= 2 - data_for_parent->myNijkDiag = child_data_array[0].myNijkDiag; - data_for_parent->mySumPermuteNxyz = child_data_array[0].mySumPermuteNxyz; - data_for_parent->my2Nxxy_Nyxx = child_data_array[0].my2Nxxy_Nyxx; - data_for_parent->my2Nxxz_Nzxx = child_data_array[0].my2Nxxz_Nzxx; - data_for_parent->my2Nyyz_Nzyy = child_data_array[0].my2Nyyz_Nzyy; - data_for_parent->my2Nyyx_Nxyy = child_data_array[0].my2Nyyx_Nxyy; - data_for_parent->my2Nzzx_Nxzz = child_data_array[0].my2Nzzx_Nxzz; - data_for_parent->my2Nzzy_Nyzz = child_data_array[0].my2Nzzy_Nyzz; -#endif - - for (int i = 1; i < nchildren; ++i) - { - data_for_parent->myNijDiag += child_data_array[i].myNijDiag; -#if TAYLOR_SERIES_ORDER >= 2 - data_for_parent->myNijkDiag += child_data_array[i].myNijkDiag; - data_for_parent->mySumPermuteNxyz += child_data_array[i].mySumPermuteNxyz; - data_for_parent->my2Nxxy_Nyxx += child_data_array[i].my2Nxxy_Nyxx; - data_for_parent->my2Nxxz_Nzxx += child_data_array[i].my2Nxxz_Nzxx; - data_for_parent->my2Nyyz_Nzyy += child_data_array[i].my2Nyyz_Nzyy; - data_for_parent->my2Nyyx_Nxyy += child_data_array[i].my2Nyyx_Nxyy; - data_for_parent->my2Nzzx_Nxzz += child_data_array[i].my2Nzzx_Nxzz; - data_for_parent->my2Nzzy_Nyzz += child_data_array[i].my2Nzzy_Nyzz; -#endif - } - for (int j = 0; j < 3; ++j) - ((T*)¤t_box_data.myNijDiag[j])[0] = child_data_array[0].myNijDiag[j]; - ((T*)¤t_box_data.myNxy_Nyx)[0] = child_data_array[0].myNxy + child_data_array[0].myNyx; - ((T*)¤t_box_data.myNyz_Nzy)[0] = child_data_array[0].myNyz + child_data_array[0].myNzy; - ((T*)¤t_box_data.myNzx_Nxz)[0] = child_data_array[0].myNzx + child_data_array[0].myNxz; - for (int j = 0; j < 3; ++j) - ((T*)¤t_box_data.myNijkDiag[j])[0] = child_data_array[0].myNijkDiag[j]; - ((T*)¤t_box_data.mySumPermuteNxyz)[0] = child_data_array[0].mySumPermuteNxyz; - ((T*)¤t_box_data.my2Nxxy_Nyxx)[0] = child_data_array[0].my2Nxxy_Nyxx; - ((T*)¤t_box_data.my2Nxxz_Nzxx)[0] = child_data_array[0].my2Nxxz_Nzxx; - ((T*)¤t_box_data.my2Nyyz_Nzyy)[0] = child_data_array[0].my2Nyyz_Nzyy; - ((T*)¤t_box_data.my2Nyyx_Nxyy)[0] = child_data_array[0].my2Nyyx_Nxyy; - ((T*)¤t_box_data.my2Nzzx_Nxzz)[0] = child_data_array[0].my2Nzzx_Nxzz; - ((T*)¤t_box_data.my2Nzzy_Nyzz)[0] = child_data_array[0].my2Nzzy_Nyzz; - for (int i = 1; i < nchildren; ++i) - { - for (int j = 0; j < 3; ++j) - ((T*)¤t_box_data.myNijDiag[j])[i] = child_data_array[i].myNijDiag[j]; - ((T*)¤t_box_data.myNxy_Nyx)[i] = child_data_array[i].myNxy + child_data_array[i].myNyx; - ((T*)¤t_box_data.myNyz_Nzy)[i] = child_data_array[i].myNyz + child_data_array[i].myNzy; - ((T*)¤t_box_data.myNzx_Nxz)[i] = child_data_array[i].myNzx + child_data_array[i].myNxz; - for (int j = 0; j < 3; ++j) - ((T*)¤t_box_data.myNijkDiag[j])[i] = child_data_array[i].myNijkDiag[j]; - ((T*)¤t_box_data.mySumPermuteNxyz)[i] = child_data_array[i].mySumPermuteNxyz; - ((T*)¤t_box_data.my2Nxxy_Nyxx)[i] = child_data_array[i].my2Nxxy_Nyxx; - ((T*)¤t_box_data.my2Nxxz_Nzxx)[i] = child_data_array[i].my2Nxxz_Nzxx; - ((T*)¤t_box_data.my2Nyyz_Nzyy)[i] = child_data_array[i].my2Nyyz_Nzyy; - ((T*)¤t_box_data.my2Nyyx_Nxyy)[i] = child_data_array[i].my2Nyyx_Nxyy; - ((T*)¤t_box_data.my2Nzzx_Nxzz)[i] = child_data_array[i].my2Nzzx_Nxzz; - ((T*)¤t_box_data.my2Nzzy_Nyzz)[i] = child_data_array[i].my2Nzzy_Nyzz; - } - for (int i = nchildren; i < BVH_N; ++i) - { - // Set to zero, just to avoid false positives for uses of uninitialized memory. - for (int j = 0; j < 3; ++j) - ((T*)¤t_box_data.myNijDiag[j])[i] = 0; - ((T*)¤t_box_data.myNxy_Nyx)[i] = 0; - ((T*)¤t_box_data.myNyz_Nzy)[i] = 0; - ((T*)¤t_box_data.myNzx_Nxz)[i] = 0; - for (int j = 0; j < 3; ++j) - ((T*)¤t_box_data.myNijkDiag[j])[i] = 0; - ((T*)¤t_box_data.mySumPermuteNxyz)[i] = 0; - ((T*)¤t_box_data.my2Nxxy_Nyxx)[i] = 0; - ((T*)¤t_box_data.my2Nxxz_Nzxx)[i] = 0; - ((T*)¤t_box_data.my2Nyyz_Nzyy)[i] = 0; - ((T*)¤t_box_data.my2Nyyx_Nxyy)[i] = 0; - ((T*)¤t_box_data.my2Nzzx_Nxzz)[i] = 0; - ((T*)¤t_box_data.my2Nzzy_Nyzz)[i] = 0; - } - - for (int i = 0; i < nchildren; ++i) - { - const LocalData &child_data = child_data_array[i]; - UT_Vector3T displacement = child_data.myAverageP - UT_Vector3T(data_for_parent->myAverageP); - UT_Vector3T N = child_data.myN; - - // Adjust Nij for the change in centre P - data_for_parent->myNijDiag += N*displacement; - T Nxy = child_data.myNxy + N[0]*displacement[1]; - T Nyx = child_data.myNyx + N[1]*displacement[0]; - T Nyz = child_data.myNyz + N[1]*displacement[2]; - T Nzy = child_data.myNzy + N[2]*displacement[1]; - T Nzx = child_data.myNzx + N[2]*displacement[0]; - T Nxz = child_data.myNxz + N[0]*displacement[2]; - - data_for_parent->myNxy += Nxy; - data_for_parent->myNyx += Nyx; - data_for_parent->myNyz += Nyz; - data_for_parent->myNzy += Nzy; - data_for_parent->myNzx += Nzx; - data_for_parent->myNxz += Nxz; - -#if TAYLOR_SERIES_ORDER >= 2 - if (order >= 2) - { - // Adjust Nijk for the change in centre P - data_for_parent->myNijkDiag += T(2)*displacement*child_data.myNijDiag + displacement*displacement*child_data.myN; - data_for_parent->mySumPermuteNxyz += (displacement[0]*(Nyz+Nzy) + displacement[1]*(Nzx+Nxz) + displacement[2]*(Nxy+Nyx)); - data_for_parent->my2Nxxy_Nyxx += - 2*(displacement[1]*child_data.myNijDiag[0] + displacement[0]*child_data.myNxy + N[0]*displacement[0]*displacement[1]) - + 2*child_data.myNyx*displacement[0] + N[1]*displacement[0]*displacement[0]; - data_for_parent->my2Nxxz_Nzxx += - 2*(displacement[2]*child_data.myNijDiag[0] + displacement[0]*child_data.myNxz + N[0]*displacement[0]*displacement[2]) - + 2*child_data.myNzx*displacement[0] + N[2]*displacement[0]*displacement[0]; - data_for_parent->my2Nyyz_Nzyy += - 2*(displacement[2]*child_data.myNijDiag[1] + displacement[1]*child_data.myNyz + N[1]*displacement[1]*displacement[2]) - + 2*child_data.myNzy*displacement[1] + N[2]*displacement[1]*displacement[1]; - data_for_parent->my2Nyyx_Nxyy += - 2*(displacement[0]*child_data.myNijDiag[1] + displacement[1]*child_data.myNyx + N[1]*displacement[1]*displacement[0]) - + 2*child_data.myNxy*displacement[1] + N[0]*displacement[1]*displacement[1]; - data_for_parent->my2Nzzx_Nxzz += - 2*(displacement[0]*child_data.myNijDiag[2] + displacement[2]*child_data.myNzx + N[2]*displacement[2]*displacement[0]) - + 2*child_data.myNxz*displacement[2] + N[0]*displacement[2]*displacement[2]; - data_for_parent->my2Nzzy_Nyzz += - 2*(displacement[1]*child_data.myNijDiag[2] + displacement[2]*child_data.myNzy + N[2]*displacement[2]*displacement[1]) - + 2*child_data.myNyz*displacement[2] + N[1]*displacement[2]*displacement[2]; - } -#endif - } - } -#endif -#if SOLID_ANGLE_DEBUG - UTdebugFormat(""); - UTdebugFormat("Node {}: nchildren = {}; maxP = {}", nodei, nchildren, SYSsqrt(current_box_data.myMaxPDist2)); - UTdebugFormat(" P = {}; N = {}", current_box_data.myAverageP, current_box_data.myN); -#if TAYLOR_SERIES_ORDER >= 1 - UTdebugFormat(" Nii = {}", current_box_data.myNijDiag); - UTdebugFormat(" Nxy+Nyx = {}; Nyz+Nzy = {}; Nyz+Nzy = {}", current_box_data.myNxy_Nyx, current_box_data.myNyz_Nzy, current_box_data.myNzx_Nxz); -#if TAYLOR_SERIES_ORDER >= 2 - UTdebugFormat(" Niii = {}; 2(Nxyz+Nyzx+Nzxy) = {}", current_box_data.myNijkDiag, current_box_data.mySumPermuteNxyz); - UTdebugFormat(" 2Nxxy+Nyxx = {}; 2Nxxz+Nzxx = {}", current_box_data.my2Nxxy_Nyxx, current_box_data.my2Nxxz_Nzxx); - UTdebugFormat(" 2Nyyz+Nzyy = {}; 2Nyyx+Nxyy = {}", current_box_data.my2Nyyz_Nzyy, current_box_data.my2Nyyx_Nxyy); - UTdebugFormat(" 2Nzzx+Nxzz = {}; 2Nzzy+Nyzz = {}", current_box_data.my2Nzzx_Nxzz, current_box_data.my2Nzzy_Nyzz); -#endif -#endif -#endif - } - }; - -#if SOLID_ANGLE_TIME_PRECOMPUTE - timer.start(); -#endif - const PrecomputeFunctors functors(box_data, triangle_boxes.array(), triangle_points, positions, order); - // NOTE: post-functor relies on non-null data_for_parent, so we have to pass one. - LocalData local_data; - myTree.template traverseParallel(4096, functors, &local_data); - //myTree.template traverse(functors); -#if SOLID_ANGLE_TIME_PRECOMPUTE - time = timer.stop(); - UTdebugFormat("{} s to precompute coefficients.", time); -#endif - } - - template - inline void UT_SolidAngle::clear() - { - myTree.clear(); - myNBoxes = 0; - myOrder = 2; - myData.reset(); - myNTriangles = 0; - myTrianglePoints = nullptr; - myNPoints = 0; - myPositions = nullptr; - } - - template - inline T UT_SolidAngle::computeSolidAngle(const UT_Vector3T &query_point, const T accuracy_scale) const - { - const T accuracy_scale2 = accuracy_scale*accuracy_scale; - - struct SolidAngleFunctors - { - const BoxData *const myBoxData; - const UT_Vector3T myQueryPoint; - const T myAccuracyScale2; - const UT_Vector3T *const myPositions; - const int *const myTrianglePoints; - const int myOrder; - - SolidAngleFunctors( - const BoxData *const box_data, - const UT_Vector3T &query_point, - const T accuracy_scale2, - const int order, - const UT_Vector3T *const positions, - const int *const triangle_points) - : myBoxData(box_data) - , myQueryPoint(query_point) - , myAccuracyScale2(accuracy_scale2) - , myOrder(order) - , myPositions(positions) - , myTrianglePoints(triangle_points) - {} - uint pre(const int nodei, T *data_for_parent) const - { - const BoxData &data = myBoxData[nodei]; - const typename BoxData::Type maxP2 = data.myMaxPDist2; - UT_FixedVector q; - q[0] = typename BoxData::Type(myQueryPoint[0]); - q[1] = typename BoxData::Type(myQueryPoint[1]); - q[2] = typename BoxData::Type(myQueryPoint[2]); - q -= data.myAverageP; - const typename BoxData::Type qlength2 = q[0]*q[0] + q[1]*q[1] + q[2]*q[2]; - - // If the query point is within a factor of accuracy_scale of the box radius, - // it's assumed to be not a good enough approximation, so it needs to descend. - // TODO: Is there a way to estimate the error? - static_assert((std::is_same::value), "FIXME: Implement support for other tuple types!"); - v4uu descend_mask = (qlength2 <= maxP2*myAccuracyScale2); - uint descend_bitmask = _mm_movemask_ps(V4SF(descend_mask.vector)); - constexpr uint allchildbits = ((uint(1)<= 1 - const int order = myOrder; - if (order >= 1) - { - const UT_FixedVector q2 = q*q; - const typename BoxData::Type qlength_m3 = qlength_m2*qlength_m1; - const typename BoxData::Type Omega_1 = - qlength_m3*(data.myNijDiag[0] + data.myNijDiag[1] + data.myNijDiag[2] - -typename BoxData::Type(3.0)*(dot(q2,data.myNijDiag) + - q[0]*q[1]*data.myNxy_Nyx + - q[0]*q[2]*data.myNzx_Nxz + - q[1]*q[2]*data.myNyz_Nzy)); - Omega_approx += Omega_1; -#if TAYLOR_SERIES_ORDER >= 2 - if (order >= 2) - { - const UT_FixedVector q3 = q2*q; - const typename BoxData::Type qlength_m4 = qlength_m2*qlength_m2; - typename BoxData::Type temp0[3] = { - data.my2Nyyx_Nxyy+data.my2Nzzx_Nxzz, - data.my2Nzzy_Nyzz+data.my2Nxxy_Nyxx, - data.my2Nxxz_Nzxx+data.my2Nyyz_Nzyy - }; - typename BoxData::Type temp1[3] = { - q[1]*data.my2Nxxy_Nyxx + q[2]*data.my2Nxxz_Nzxx, - q[2]*data.my2Nyyz_Nzyy + q[0]*data.my2Nyyx_Nxyy, - q[0]*data.my2Nzzx_Nxzz + q[1]*data.my2Nzzy_Nyzz - }; - const typename BoxData::Type Omega_2 = - qlength_m4*(typename BoxData::Type(1.5)*dot(q, typename BoxData::Type(3)*data.myNijkDiag + UT_FixedVector(temp0)) - -typename BoxData::Type(7.5)*(dot(q3,data.myNijkDiag) + q[0]*q[1]*q[2]*data.mySumPermuteNxyz + dot(q2, UT_FixedVector(temp1)))); - Omega_approx += Omega_2; - } -#endif - } -#endif - - // If q is so small that we got NaNs and we just have a - // small bounding box, it needs to descend. - const v4uu mask = Omega_approx.isFinite() & ~descend_mask; - Omega_approx = Omega_approx & mask; - descend_bitmask = (~_mm_movemask_ps(V4SF(mask.vector))) & allchildbits; - - T sum = Omega_approx[0]; - for (int i = 1; i < BVH_N; ++i) - sum += Omega_approx[i]; - *data_for_parent = sum; - - return descend_bitmask; - } - void item(const int itemi, const int parent_nodei, T &data_for_parent) const - { - const UT_Vector3T *const positions = myPositions; - const int *const cur_triangle_points = myTrianglePoints + 3*itemi; - const UT_Vector3T a = positions[cur_triangle_points[0]]; - const UT_Vector3T b = positions[cur_triangle_points[1]]; - const UT_Vector3T c = positions[cur_triangle_points[2]]; - - data_for_parent = UTsignedSolidAngleTri(a, b, c, myQueryPoint); - } - SYS_FORCE_INLINE void post(const int nodei, const int parent_nodei, T *data_for_parent, const int nchildren, const T *child_data_array, const uint descend_bits) const - { - T sum = (descend_bits&1) ? child_data_array[0] : 0; - for (int i = 1; i < nchildren; ++i) - sum += ((descend_bits>>i)&1) ? child_data_array[i] : 0; - - *data_for_parent += sum; - } - }; - const SolidAngleFunctors functors(myData.get(), query_point, accuracy_scale2, myOrder, myPositions, myTrianglePoints); - - T sum; - myTree.traverseVector(functors, &sum); - return sum; - } - - template - struct UT_SubtendedAngle::BoxData - { - void clear() - { - // Set everything to zero - memset(this,0,sizeof(*this)); - } - - using Type = typename std::conditional::value, v4uf, UT_FixedVector>::type; - using SType = typename std::conditional::value, v4uf, UT_FixedVector>::type; - - /// An upper bound on the squared distance from myAverageP to the farthest point in the box. - SType myMaxPDist2; - - /// Centre of mass of the mesh surface in this box - UT_FixedVector myAverageP; - - /// Unnormalized, area-weighted normal of the mesh in this box - UT_FixedVector myN; - - /// Values for Omega_1 - /// @{ - UT_FixedVector myNijDiag; // Nxx, Nyy - Type myNxy_Nyx; // Nxy+Nyx - /// @} - - /// Values for Omega_2 - /// @{ - UT_FixedVector myNijkDiag; // Nxxx, Nyyy - Type my2Nxxy_Nyxx; // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx - Type my2Nyyx_Nxyy; // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy - /// @} - }; - - template - inline UT_SubtendedAngle::UT_SubtendedAngle() - : myTree() - , myNBoxes(0) - , myOrder(2) - , myData(nullptr) - , myNSegments(0) - , mySegmentPoints(nullptr) - , myNPoints(0) - , myPositions(nullptr) - {} - - template - inline UT_SubtendedAngle::~UT_SubtendedAngle() - { - // Default destruction works, but this needs to be outlined - // to avoid having to include UT_BVHImpl.h in the header, - // (for the UT_UniquePtr destructor.) - } - - template - inline void UT_SubtendedAngle::init( - const int nsegments, - const int *const segment_points, - const int npoints, - const UT_Vector2T *const positions, - const int order) - { -#if SOLID_ANGLE_DEBUG - UTdebugFormat(""); - UTdebugFormat(""); - UTdebugFormat("Building BVH for {} segments on {} points:", nsegments, npoints); -#endif - myOrder = order; - myNSegments = nsegments; - mySegmentPoints = segment_points; - myNPoints = npoints; - myPositions = positions; - -#if SOLID_ANGLE_TIME_PRECOMPUTE - UT_StopWatch timer; - timer.start(); -#endif - UT_SmallArray> segment_boxes; - segment_boxes.setSizeNoInit(nsegments); - if (nsegments < 16*1024) - { - const int *cur_segment_points = segment_points; - for (int i = 0; i < nsegments; ++i, cur_segment_points += 2) - { - UT::Box &box = segment_boxes[i]; - box.initBounds(positions[cur_segment_points[0]]); - box.enlargeBounds(positions[cur_segment_points[1]]); - } - } - else - { - igl::parallel_for(nsegments, - [segment_points,&segment_boxes,positions](int i) - { - const int *cur_segment_points = segment_points + i*2; - UT::Box &box = segment_boxes[i]; - box.initBounds(positions[cur_segment_points[0]]); - box.enlargeBounds(positions[cur_segment_points[1]]); - }); - } -#if SOLID_ANGLE_TIME_PRECOMPUTE - double time = timer.stop(); - UTdebugFormat("{} s to create bounding boxes.", time); - timer.start(); -#endif - myTree.template init(segment_boxes.array(), nsegments); -#if SOLID_ANGLE_TIME_PRECOMPUTE - time = timer.stop(); - UTdebugFormat("{} s to initialize UT_BVH structure. {} nodes", time, myTree.getNumNodes()); -#endif - - //myTree.debugDump(); - - const int nnodes = myTree.getNumNodes(); - - myNBoxes = nnodes; - BoxData *box_data = new BoxData[nnodes]; - myData.reset(box_data); - - // Some data are only needed during initialization. - struct LocalData - { - // Bounding box - UT::Box myBox; - - // P and N are needed from each child for computing Nij. - UT_Vector2T myAverageP; - UT_Vector2T myLengthP; - UT_Vector2T myN; - - // Unsigned length is needed for computing the average position. - T myLength; - - // These are needed for computing Nijk. - UT_Vector2T myNijDiag; - T myNxy; T myNyx; - - UT_Vector2T myNijkDiag; // Nxxx, Nyyy - T my2Nxxy_Nyxx; // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx - T my2Nyyx_Nxyy; // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy - }; - - struct PrecomputeFunctors - { - BoxData *const myBoxData; - const UT::Box *const mySegmentBoxes; - const int *const mySegmentPoints; - const UT_Vector2T *const myPositions; - const int myOrder; - - PrecomputeFunctors( - BoxData *box_data, - const UT::Box *segment_boxes, - const int *segment_points, - const UT_Vector2T *positions, - const int order) - : myBoxData(box_data) - , mySegmentBoxes(segment_boxes) - , mySegmentPoints(segment_points) - , myPositions(positions) - , myOrder(order) - {} - constexpr SYS_FORCE_INLINE bool pre(const int nodei, LocalData *data_for_parent) const - { - return true; - } - void item(const int itemi, const int parent_nodei, LocalData &data_for_parent) const - { - const UT_Vector2T *const positions = myPositions; - const int *const cur_segment_points = mySegmentPoints + 2*itemi; - const UT_Vector2T a = positions[cur_segment_points[0]]; - const UT_Vector2T b = positions[cur_segment_points[1]]; - const UT_Vector2T ab = b-a; - - const UT::Box &segment_box = mySegmentBoxes[itemi]; - data_for_parent.myBox = segment_box; - - // Length-weighted normal (unnormalized) - UT_Vector2T N; - N[0] = ab[1]; - N[1] = -ab[0]; - const T length2 = ab.length2(); - const T length = SYSsqrt(length2); - const UT_Vector2T P = T(0.5)*(a+b); - data_for_parent.myAverageP = P; - data_for_parent.myLengthP = P*length; - data_for_parent.myN = N; -#if SOLID_ANGLE_DEBUG - UTdebugFormat(""); - UTdebugFormat("Triangle {}: P = {}; N = {}; length = {}", itemi, P, N, length); - UTdebugFormat(" box = {}", data_for_parent.myBox); -#endif - - data_for_parent.myLength = length; - const int order = myOrder; - if (order < 1) - return; - - // NOTE: Due to P being at the centroid, segments have Nij = 0 - // contributions to Nij. - data_for_parent.myNijDiag = T(0); - data_for_parent.myNxy = 0; data_for_parent.myNyx = 0; - - if (order < 2) - return; - - // If it's zero-length, the results are zero, so we can skip. - if (length == 0) - { - data_for_parent.myNijkDiag = T(0); - data_for_parent.my2Nxxy_Nyxx = 0; - data_for_parent.my2Nyyx_Nxyy = 0; - return; - } - - T integral_xx = ab[0]*ab[0]/T(12); - T integral_xy = ab[0]*ab[1]/T(12); - T integral_yy = ab[1]*ab[1]/T(12); - data_for_parent.myNijkDiag[0] = integral_xx*N[0]; - data_for_parent.myNijkDiag[1] = integral_yy*N[1]; - T Nxxy = N[0]*integral_xy; - T Nyxx = N[1]*integral_xx; - T Nyyx = N[1]*integral_xy; - T Nxyy = N[0]*integral_yy; - data_for_parent.my2Nxxy_Nyxx = 2*Nxxy + Nyxx; - data_for_parent.my2Nyyx_Nxyy = 2*Nyyx + Nxyy; -#if SOLID_ANGLE_DEBUG - UTdebugFormat(" integral_xx = {}; yy = {}", integral_xx, integral_yy); - UTdebugFormat(" integral_xy = {}", integral_xy); -#endif - } - - void post(const int nodei, const int parent_nodei, LocalData *data_for_parent, const int nchildren, const LocalData *child_data_array) const - { - // NOTE: Although in the general case, data_for_parent may be null for the root call, - // this functor assumes that it's non-null, so the call below must pass a non-null pointer. - - BoxData ¤t_box_data = myBoxData[nodei]; - - UT_Vector2T N = child_data_array[0].myN; - ((T*)¤t_box_data.myN[0])[0] = N[0]; - ((T*)¤t_box_data.myN[1])[0] = N[1]; - UT_Vector2T lengthP = child_data_array[0].myLengthP; - T length = child_data_array[0].myLength; - const UT_Vector2T local_P = child_data_array[0].myAverageP; - ((T*)¤t_box_data.myAverageP[0])[0] = local_P[0]; - ((T*)¤t_box_data.myAverageP[1])[0] = local_P[1]; - for (int i = 1; i < nchildren; ++i) - { - const UT_Vector2T local_N = child_data_array[i].myN; - N += local_N; - ((T*)¤t_box_data.myN[0])[i] = local_N[0]; - ((T*)¤t_box_data.myN[1])[i] = local_N[1]; - lengthP += child_data_array[i].myLengthP; - length += child_data_array[i].myLength; - const UT_Vector2T local_P = child_data_array[i].myAverageP; - ((T*)¤t_box_data.myAverageP[0])[i] = local_P[0]; - ((T*)¤t_box_data.myAverageP[1])[i] = local_P[1]; - } - for (int i = nchildren; i < BVH_N; ++i) - { - // Set to zero, just to avoid false positives for uses of uninitialized memory. - ((T*)¤t_box_data.myN[0])[i] = 0; - ((T*)¤t_box_data.myN[1])[i] = 0; - ((T*)¤t_box_data.myAverageP[0])[i] = 0; - ((T*)¤t_box_data.myAverageP[1])[i] = 0; - } - data_for_parent->myN = N; - data_for_parent->myLengthP = lengthP; - data_for_parent->myLength = length; - - UT::Box box(child_data_array[0].myBox); - for (int i = 1; i < nchildren; ++i) - box.combine(child_data_array[i].myBox); - - // Normalize P - UT_Vector2T averageP; - if (length > 0) - averageP = lengthP/length; - else - averageP = T(0.5)*(box.getMin() + box.getMax()); - data_for_parent->myAverageP = averageP; - - data_for_parent->myBox = box; - - for (int i = 0; i < nchildren; ++i) - { - const UT::Box &local_box(child_data_array[i].myBox); - const UT_Vector2T &local_P = child_data_array[i].myAverageP; - const UT_Vector2T maxPDiff = SYSmax(local_P-UT_Vector2T(local_box.getMin()), UT_Vector2T(local_box.getMax())-local_P); - ((T*)¤t_box_data.myMaxPDist2)[i] = maxPDiff.length2(); - } - for (int i = nchildren; i < BVH_N; ++i) - { - // This child is non-existent. If we set myMaxPDist2 to infinity, it will never - // use the approximation, and the traverseVector function can check for EMPTY. - ((T*)¤t_box_data.myMaxPDist2)[i] = std::numeric_limits::infinity(); - } - - const int order = myOrder; - if (order >= 1) - { - // We now have the current box's P, so we can adjust Nij and Nijk - data_for_parent->myNijDiag = child_data_array[0].myNijDiag; - data_for_parent->myNxy = 0; - data_for_parent->myNyx = 0; - data_for_parent->myNijkDiag = child_data_array[0].myNijkDiag; - data_for_parent->my2Nxxy_Nyxx = child_data_array[0].my2Nxxy_Nyxx; - data_for_parent->my2Nyyx_Nxyy = child_data_array[0].my2Nyyx_Nxyy; - - for (int i = 1; i < nchildren; ++i) - { - data_for_parent->myNijDiag += child_data_array[i].myNijDiag; - data_for_parent->myNijkDiag += child_data_array[i].myNijkDiag; - data_for_parent->my2Nxxy_Nyxx += child_data_array[i].my2Nxxy_Nyxx; - data_for_parent->my2Nyyx_Nxyy += child_data_array[i].my2Nyyx_Nxyy; - } - for (int j = 0; j < 2; ++j) - ((T*)¤t_box_data.myNijDiag[j])[0] = child_data_array[0].myNijDiag[j]; - ((T*)¤t_box_data.myNxy_Nyx)[0] = child_data_array[0].myNxy + child_data_array[0].myNyx; - for (int j = 0; j < 2; ++j) - ((T*)¤t_box_data.myNijkDiag[j])[0] = child_data_array[0].myNijkDiag[j]; - ((T*)¤t_box_data.my2Nxxy_Nyxx)[0] = child_data_array[0].my2Nxxy_Nyxx; - ((T*)¤t_box_data.my2Nyyx_Nxyy)[0] = child_data_array[0].my2Nyyx_Nxyy; - for (int i = 1; i < nchildren; ++i) - { - for (int j = 0; j < 2; ++j) - ((T*)¤t_box_data.myNijDiag[j])[i] = child_data_array[i].myNijDiag[j]; - ((T*)¤t_box_data.myNxy_Nyx)[i] = child_data_array[i].myNxy + child_data_array[i].myNyx; - for (int j = 0; j < 2; ++j) - ((T*)¤t_box_data.myNijkDiag[j])[i] = child_data_array[i].myNijkDiag[j]; - ((T*)¤t_box_data.my2Nxxy_Nyxx)[i] = child_data_array[i].my2Nxxy_Nyxx; - ((T*)¤t_box_data.my2Nyyx_Nxyy)[i] = child_data_array[i].my2Nyyx_Nxyy; - } - for (int i = nchildren; i < BVH_N; ++i) - { - // Set to zero, just to avoid false positives for uses of uninitialized memory. - for (int j = 0; j < 2; ++j) - ((T*)¤t_box_data.myNijDiag[j])[i] = 0; - ((T*)¤t_box_data.myNxy_Nyx)[i] = 0; - for (int j = 0; j < 2; ++j) - ((T*)¤t_box_data.myNijkDiag[j])[i] = 0; - ((T*)¤t_box_data.my2Nxxy_Nyxx)[i] = 0; - ((T*)¤t_box_data.my2Nyyx_Nxyy)[i] = 0; - } - - for (int i = 0; i < nchildren; ++i) - { - const LocalData &child_data = child_data_array[i]; - UT_Vector2T displacement = child_data.myAverageP - UT_Vector2T(data_for_parent->myAverageP); - UT_Vector2T N = child_data.myN; - - // Adjust Nij for the change in centre P - data_for_parent->myNijDiag += N*displacement; - T Nxy = child_data.myNxy + N[0]*displacement[1]; - T Nyx = child_data.myNyx + N[1]*displacement[0]; - - data_for_parent->myNxy += Nxy; - data_for_parent->myNyx += Nyx; - - if (order >= 2) - { - // Adjust Nijk for the change in centre P - data_for_parent->myNijkDiag += T(2)*displacement*child_data.myNijDiag + displacement*displacement*child_data.myN; - data_for_parent->my2Nxxy_Nyxx += - 2*(displacement[1]*child_data.myNijDiag[0] + displacement[0]*child_data.myNxy + N[0]*displacement[0]*displacement[1]) - + 2*child_data.myNyx*displacement[0] + N[1]*displacement[0]*displacement[0]; - data_for_parent->my2Nyyx_Nxyy += - 2*(displacement[0]*child_data.myNijDiag[1] + displacement[1]*child_data.myNyx + N[1]*displacement[1]*displacement[0]) - + 2*child_data.myNxy*displacement[1] + N[0]*displacement[1]*displacement[1]; - } - } - } -#if SOLID_ANGLE_DEBUG - UTdebugFormat(""); - UTdebugFormat("Node {}: nchildren = {}; maxP = {}", nodei, nchildren, SYSsqrt(current_box_data.myMaxPDist2)); - UTdebugFormat(" P = {}; N = {}", current_box_data.myAverageP, current_box_data.myN); - UTdebugFormat(" Nii = {}", current_box_data.myNijDiag); - UTdebugFormat(" Nxy+Nyx = {}", current_box_data.myNxy_Nyx); - UTdebugFormat(" Niii = {}", current_box_data.myNijkDiag); - UTdebugFormat(" 2Nxxy+Nyxx = {}; 2Nyyx+Nxyy = {}", current_box_data.my2Nxxy_Nyxx, current_box_data.my2Nyyx_Nxyy); -#endif - } - }; - -#if SOLID_ANGLE_TIME_PRECOMPUTE - timer.start(); -#endif - const PrecomputeFunctors functors(box_data, segment_boxes.array(), segment_points, positions, order); - // NOTE: post-functor relies on non-null data_for_parent, so we have to pass one. - LocalData local_data; - myTree.template traverseParallel(4096, functors, &local_data); - //myTree.template traverse(functors); -#if SOLID_ANGLE_TIME_PRECOMPUTE - time = timer.stop(); - UTdebugFormat("{} s to precompute coefficients.", time); -#endif - } - - template - inline void UT_SubtendedAngle::clear() - { - myTree.clear(); - myNBoxes = 0; - myOrder = 2; - myData.reset(); - myNSegments = 0; - mySegmentPoints = nullptr; - myNPoints = 0; - myPositions = nullptr; - } - - template - inline T UT_SubtendedAngle::computeAngle(const UT_Vector2T &query_point, const T accuracy_scale) const - { - const T accuracy_scale2 = accuracy_scale*accuracy_scale; - - struct AngleFunctors - { - const BoxData *const myBoxData; - const UT_Vector2T myQueryPoint; - const T myAccuracyScale2; - const UT_Vector2T *const myPositions; - const int *const mySegmentPoints; - const int myOrder; - - AngleFunctors( - const BoxData *const box_data, - const UT_Vector2T &query_point, - const T accuracy_scale2, - const int order, - const UT_Vector2T *const positions, - const int *const segment_points) - : myBoxData(box_data) - , myQueryPoint(query_point) - , myAccuracyScale2(accuracy_scale2) - , myOrder(order) - , myPositions(positions) - , mySegmentPoints(segment_points) - {} - uint pre(const int nodei, T *data_for_parent) const - { - const BoxData &data = myBoxData[nodei]; - const typename BoxData::Type maxP2 = data.myMaxPDist2; - UT_FixedVector q; - q[0] = typename BoxData::Type(myQueryPoint[0]); - q[1] = typename BoxData::Type(myQueryPoint[1]); - q -= data.myAverageP; - const typename BoxData::Type qlength2 = q[0]*q[0] + q[1]*q[1]; - - // If the query point is within a factor of accuracy_scale of the box radius, - // it's assumed to be not a good enough approximation, so it needs to descend. - // TODO: Is there a way to estimate the error? - static_assert((std::is_same::value), "FIXME: Implement support for other tuple types!"); - v4uu descend_mask = (qlength2 <= maxP2*myAccuracyScale2); - uint descend_bitmask = _mm_movemask_ps(V4SF(descend_mask.vector)); - constexpr uint allchildbits = ((uint(1)<= 1) - { - const UT_FixedVector q2 = q*q; - const typename BoxData::Type Omega_1 = - qlength_m2*(data.myNijDiag[0] + data.myNijDiag[1] - -typename BoxData::Type(2.0)*(dot(q2,data.myNijDiag) + - q[0]*q[1]*data.myNxy_Nyx)); - Omega_approx += Omega_1; - if (order >= 2) - { - const UT_FixedVector q3 = q2*q; - const typename BoxData::Type qlength_m3 = qlength_m2*qlength_m1; - typename BoxData::Type temp0[2] = { - data.my2Nyyx_Nxyy, - data.my2Nxxy_Nyxx - }; - typename BoxData::Type temp1[2] = { - q[1]*data.my2Nxxy_Nyxx, - q[0]*data.my2Nyyx_Nxyy - }; - const typename BoxData::Type Omega_2 = - qlength_m3*(dot(q, typename BoxData::Type(3)*data.myNijkDiag + UT_FixedVector(temp0)) - -typename BoxData::Type(4.0)*(dot(q3,data.myNijkDiag) + dot(q2, UT_FixedVector(temp1)))); - Omega_approx += Omega_2; - } - } - - // If q is so small that we got NaNs and we just have a - // small bounding box, it needs to descend. - const v4uu mask = Omega_approx.isFinite() & ~descend_mask; - Omega_approx = Omega_approx & mask; - descend_bitmask = (~_mm_movemask_ps(V4SF(mask.vector))) & allchildbits; - - T sum = Omega_approx[0]; - for (int i = 1; i < BVH_N; ++i) - sum += Omega_approx[i]; - *data_for_parent = sum; - - return descend_bitmask; - } - void item(const int itemi, const int parent_nodei, T &data_for_parent) const - { - const UT_Vector2T *const positions = myPositions; - const int *const cur_segment_points = mySegmentPoints + 2*itemi; - const UT_Vector2T a = positions[cur_segment_points[0]]; - const UT_Vector2T b = positions[cur_segment_points[1]]; - - data_for_parent = UTsignedAngleSegment(a, b, myQueryPoint); - } - SYS_FORCE_INLINE void post(const int nodei, const int parent_nodei, T *data_for_parent, const int nchildren, const T *child_data_array, const uint descend_bits) const - { - T sum = (descend_bits&1) ? child_data_array[0] : 0; - for (int i = 1; i < nchildren; ++i) - sum += ((descend_bits>>i)&1) ? child_data_array[i] : 0; - - *data_for_parent += sum; - } - }; - const AngleFunctors functors(myData.get(), query_point, accuracy_scale2, myOrder, myPositions, mySegmentPoints); - - T sum; - myTree.traverseVector(functors, &sum); - return sum; - } - -// Instantiate our templates. -//template class UT_SolidAngle; -// FIXME: The SIMD parts will need to be handled differently in order to support fpreal64. -//template class UT_SolidAngle; -//template class UT_SolidAngle; -//template class UT_SubtendedAngle; -//template class UT_SubtendedAngle; -//template class UT_SubtendedAngle; - - } // End HDK_Sample namespace - } -} From 14ed5a19e8d51be1fafb5a0592fb1b8992731b85 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Fri, 17 Jan 2025 14:48:27 +0100 Subject: [PATCH 09/70] ensure new igl is used --- cmake/FloatTetwildDependencies.cmake | 20 ++++++++++++-------- cmake/FloatTetwildDownloadExternal.cmake | 8 -------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index a47799e5..5f001417 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -40,14 +40,18 @@ if(NOT TARGET spdlog::spdlog) target_compile_definitions(spdlog INTERFACE SPDLOG_FMT_EXTERNAL) endif() -# Libigl -if(NOT TARGET igl::core) - float_tetwild_download_libigl() - - # Import libigl targets - list(APPEND CMAKE_MODULE_PATH "${FLOAT_TETWILD_EXTERNAL}/libigl/cmake") - include(libigl) -endif() +# igl +include(FetchContent) +FetchContent_Declare( + libigl + GIT_REPOSITORY https://github.com/libigl/libigl.git GIT_TAG + a221faf1e4bd571529ca2101c08bc2458579b1da +) +FetchContent_MakeAvailable(libigl) + +# Import libigl targets +list(APPEND CMAKE_MODULE_PATH "${FLOAT_TETWILD_EXTERNAL}/libigl/cmake") +include(libigl) # Geogram if(NOT TARGET geogram::geogram) diff --git a/cmake/FloatTetwildDownloadExternal.cmake b/cmake/FloatTetwildDownloadExternal.cmake index 574fced4..aff9c7ce 100644 --- a/cmake/FloatTetwildDownloadExternal.cmake +++ b/cmake/FloatTetwildDownloadExternal.cmake @@ -26,14 +26,6 @@ endfunction() # ############################################################################## -include(FetchContent) -FetchContent_Declare( - libigl - GIT_REPOSITORY https://github.com/libigl/libigl.git GIT_TAG - 687530283c01b91de5795959281d4cdc36f7ca1b -) -FetchContent_MakeAvailable(libigl) - # Json function(float_tetwild_download_json) float_tetwild_download_project( From 5120c3ec2135b45bd2365fc200ab34c7e9d3fb19 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Fri, 17 Jan 2025 14:57:19 +0100 Subject: [PATCH 10/70] remove include --- cmake/FloatTetwildDependencies.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index 5f001417..a58e238b 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -51,7 +51,6 @@ FetchContent_MakeAvailable(libigl) # Import libigl targets list(APPEND CMAKE_MODULE_PATH "${FLOAT_TETWILD_EXTERNAL}/libigl/cmake") -include(libigl) # Geogram if(NOT TARGET geogram::geogram) From 0f1d0998d9b0ddc29424765660251e8ce06bb35f Mon Sep 17 00:00:00 2001 From: Yixin-Hu Date: Mon, 29 Nov 2021 16:14:16 -0500 Subject: [PATCH 11/70] handle sizing field better; rm fast winding number --- src/MeshImprovement.cpp | 88 +++++++++++++++++++++++++++---------- src/Parameters.h | 3 ++ src/external/CMakeLists.txt | 5 ++- src/main.cpp | 7 +-- 4 files changed, 75 insertions(+), 28 deletions(-) diff --git a/src/MeshImprovement.cpp b/src/MeshImprovement.cpp index 8d5f0fa4..764844ff 100644 --- a/src/MeshImprovement.cpp +++ b/src/MeshImprovement.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +//#include #include //#include @@ -1296,11 +1296,52 @@ void floatTetWild::apply_sizingfield(Mesh& mesh, AABBWrapper& tree) { auto &tet_vertices = mesh.tet_vertices; auto &tets = mesh.tets; + GEO::Mesh bg_mesh; + bg_mesh.vertices.clear(); + bg_mesh.vertices.create_vertices((int)mesh.params.V_sizing_field.rows() / 3); + for (int i = 0; i < mesh.params.V_sizing_field.rows() / 3; i++) { + GEO::vec3& p = bg_mesh.vertices.point(i); + for (int j = 0; j < 3; j++) + p[j] = mesh.params.V_sizing_field(i * 3 + j); + } + bg_mesh.cells.clear(); + bg_mesh.cells.create_tets((int)mesh.params.T_sizing_field.rows() / 4); + for (int i = 0; i < mesh.params.T_sizing_field.rows() / 4; i++) { + for (int j = 0; j < 4; j++) + bg_mesh.cells.set_vertex(i, j, mesh.params.T_sizing_field(i * 4 + j)); + } + GEO::MeshCellsAABB bg_aabb(bg_mesh, false); + + auto get_sizing_field_value = [&](const Vector3& p) { + GEO::vec3 geo_p(p[0], p[1], p[2]); + int bg_t_id = bg_aabb.containing_tet(geo_p); + if (bg_t_id == GEO::MeshCellsAABB::NO_TET) + return -1.; + + // compute barycenter + std::array vs; + for (int j = 0; j < 4; j++) { + vs[j] = Vector3(mesh.params.V_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + j) * 3), + mesh.params.V_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + j) * 3 + 1), + mesh.params.V_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + j) * 3 + 2)); + } + double value = 0; + for (int j = 0; j < 4; j++) { + Vector3 n = ((vs[(j + 1) % 4] - vs[j]).cross(vs[(j + 2) % 4] - vs[j])).normalized(); + double d = (vs[(j + 3) % 4] - vs[j]).dot(n); + if (d == 0) + continue; + double weight = abs((p - vs[j]).dot(n) / d); + value += weight * mesh.params.values_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + (j + 3) % 4)); + } + return value; // / mesh.params.ideal_edge_length; + }; + for (auto &p: tet_vertices) { if (p.is_removed) continue; p.sizing_scalar = 1; //reset - double value = mesh.params.get_sizing_field_value(p.pos); + double value = get_sizing_field_value(p.pos); if (value > 0) { p.sizing_scalar = value / mesh.params.ideal_edge_length; } @@ -1471,10 +1512,10 @@ void floatTetWild::boolean_operation(Mesh& mesh, const json& csg_tree_with_ids, for (int i = 0; i <= max_id; ++i) { get_tracked_surface(mesh, vs, fs, i); - if (!mesh.params.use_general_wn) - floatTetWild::fast_winding_number( - Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); - else +// if (!mesh.params.use_general_wn) +// floatTetWild::fast_winding_number( +// Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); +// else igl::winding_number( Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); } @@ -1505,10 +1546,10 @@ void floatTetWild::boolean_operation(Mesh& mesh, const json& csg_tree_with_ids, for (int k = 0; k < fs.rows(); ++k) fs.row(k) = Fs[i][k]; - if (!mesh.params.use_general_wn) - floatTetWild::fast_winding_number( - Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); - else +// if (!mesh.params.use_general_wn) +// floatTetWild::fast_winding_number( +// Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); +// else igl::winding_number( Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); } @@ -1572,10 +1613,11 @@ void floatTetWild::boolean_operation(Mesh& mesh, int op){ } Eigen::VectorXd w1, w2; - if(!mesh.params.use_general_wn) { - floatTetWild::fast_winding_number(Eigen::MatrixXd(v1.cast()), Eigen::MatrixXi(f1), C, w1); - floatTetWild::fast_winding_number(Eigen::MatrixXd(v2.cast()), Eigen::MatrixXi(f2), C, w2); - }else { +// if(!mesh.params.use_general_wn) { +// floatTetWild::fast_winding_number(Eigen::MatrixXd(v1.cast()), Eigen::MatrixXi(f1), C, w1); +// floatTetWild::fast_winding_number(Eigen::MatrixXd(v2.cast()), Eigen::MatrixXi(f2), C, w2); +// }else + { igl::winding_number(Eigen::MatrixXd(v1.cast()), Eigen::MatrixXi(f1), C, w1); igl::winding_number(Eigen::MatrixXd(v2.cast()), Eigen::MatrixXi(f2), C, w2); } @@ -1629,9 +1671,9 @@ void floatTetWild::filter_outside(Mesh& mesh, bool invert_faces) { F.col(1) = F.col(2).eval(); F.col(2) = tmp; } - if(!mesh.params.use_general_wn) - floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); - else +// if(!mesh.params.use_general_wn) +// floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); +// else igl::winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); index = 0; @@ -1706,9 +1748,9 @@ void floatTetWild::filter_outside(Mesh& mesh, const std::vector &input_ // F.col(1) = F.col(2).eval(); // F.col(2) = tmp; // } - if(!mesh.params.use_general_wn) - floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); - else +// if(!mesh.params.use_general_wn) +// floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); +// else igl::winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); index = 0; @@ -1820,9 +1862,9 @@ void floatTetWild::mark_outside(Mesh& mesh, bool invert_faces){ F.col(2) = tmp; } Eigen::VectorXd W; - if(!mesh.params.use_general_wn) - floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); - else +// if(!mesh.params.use_general_wn) +// floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); +// else igl::winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); index = 0; diff --git a/src/Parameters.h b/src/Parameters.h index 0209e09b..3805de7e 100644 --- a/src/Parameters.h +++ b/src/Parameters.h @@ -42,6 +42,9 @@ namespace floatTetWild { bool coarsen = false; bool apply_sizing_field = false; + Eigen::VectorXd V_sizing_field; + Eigen::VectorXi T_sizing_field; + Eigen::VectorXd values_sizing_field; std::function get_sizing_field_value;//get sizing field value for an point #ifdef NEW_ENVELOPE diff --git a/src/external/CMakeLists.txt b/src/external/CMakeLists.txt index 1e2b4e5c..1d542ae9 100644 --- a/src/external/CMakeLists.txt +++ b/src/external/CMakeLists.txt @@ -23,8 +23,9 @@ if(FLOAT_TETWILD_WITH_EXACT_ENVELOPE ) bfs_orient.h bfs_orient.cpp - FastWindingNumber.hpp - FastWindingNumber.cpp +# WindingNumber.h +# FastWindingNumber.hpp +# FastWindingNumber.cpp Rational.h ) diff --git a/src/main.cpp b/src/main.cpp index e260618f..1ca638ef 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -39,9 +40,9 @@ #include #include #include +#include using namespace floatTetWild; -using namespace Eigen; class GeoLoggerForward : public GEO::LoggerClient { @@ -318,8 +319,8 @@ int main(int argc, char** argv) if (V_in.rows() != 0 && T_in.rows() != 0 && values.rows() != 0) { params.apply_sizing_field = true; - params.V_sizing_field = V_in; - params.T_sizing_field = T_in; + params.V_sizing_field = V_in; + params.T_sizing_field = T_in; params.values_sizing_field = values; } From 7f2e76be786cb62540ede53764a14355b5412d79 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Fri, 17 Jan 2025 18:20:32 +0100 Subject: [PATCH 12/70] revert sizing field + WN due to crash --- src/MeshImprovement.cpp | 90 +++++++++++------------------------------ src/main.cpp | 7 ++-- 2 files changed, 27 insertions(+), 70 deletions(-) diff --git a/src/MeshImprovement.cpp b/src/MeshImprovement.cpp index 764844ff..f21f89aa 100644 --- a/src/MeshImprovement.cpp +++ b/src/MeshImprovement.cpp @@ -15,7 +15,7 @@ #include #include #include -//#include +#include #include //#include @@ -1296,52 +1296,11 @@ void floatTetWild::apply_sizingfield(Mesh& mesh, AABBWrapper& tree) { auto &tet_vertices = mesh.tet_vertices; auto &tets = mesh.tets; - GEO::Mesh bg_mesh; - bg_mesh.vertices.clear(); - bg_mesh.vertices.create_vertices((int)mesh.params.V_sizing_field.rows() / 3); - for (int i = 0; i < mesh.params.V_sizing_field.rows() / 3; i++) { - GEO::vec3& p = bg_mesh.vertices.point(i); - for (int j = 0; j < 3; j++) - p[j] = mesh.params.V_sizing_field(i * 3 + j); - } - bg_mesh.cells.clear(); - bg_mesh.cells.create_tets((int)mesh.params.T_sizing_field.rows() / 4); - for (int i = 0; i < mesh.params.T_sizing_field.rows() / 4; i++) { - for (int j = 0; j < 4; j++) - bg_mesh.cells.set_vertex(i, j, mesh.params.T_sizing_field(i * 4 + j)); - } - GEO::MeshCellsAABB bg_aabb(bg_mesh, false); - - auto get_sizing_field_value = [&](const Vector3& p) { - GEO::vec3 geo_p(p[0], p[1], p[2]); - int bg_t_id = bg_aabb.containing_tet(geo_p); - if (bg_t_id == GEO::MeshCellsAABB::NO_TET) - return -1.; - - // compute barycenter - std::array vs; - for (int j = 0; j < 4; j++) { - vs[j] = Vector3(mesh.params.V_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + j) * 3), - mesh.params.V_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + j) * 3 + 1), - mesh.params.V_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + j) * 3 + 2)); - } - double value = 0; - for (int j = 0; j < 4; j++) { - Vector3 n = ((vs[(j + 1) % 4] - vs[j]).cross(vs[(j + 2) % 4] - vs[j])).normalized(); - double d = (vs[(j + 3) % 4] - vs[j]).dot(n); - if (d == 0) - continue; - double weight = abs((p - vs[j]).dot(n) / d); - value += weight * mesh.params.values_sizing_field(mesh.params.T_sizing_field(bg_t_id * 4 + (j + 3) % 4)); - } - return value; // / mesh.params.ideal_edge_length; - }; - for (auto &p: tet_vertices) { if (p.is_removed) continue; p.sizing_scalar = 1; //reset - double value = get_sizing_field_value(p.pos); + double value = mesh.params.get_sizing_field_value(p.pos); if (value > 0) { p.sizing_scalar = value / mesh.params.ideal_edge_length; } @@ -1512,10 +1471,10 @@ void floatTetWild::boolean_operation(Mesh& mesh, const json& csg_tree_with_ids, for (int i = 0; i <= max_id; ++i) { get_tracked_surface(mesh, vs, fs, i); -// if (!mesh.params.use_general_wn) -// floatTetWild::fast_winding_number( -// Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); -// else + if (!mesh.params.use_general_wn) + floatTetWild::fast_winding_number( + Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); + else igl::winding_number( Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); } @@ -1546,10 +1505,10 @@ void floatTetWild::boolean_operation(Mesh& mesh, const json& csg_tree_with_ids, for (int k = 0; k < fs.rows(); ++k) fs.row(k) = Fs[i][k]; -// if (!mesh.params.use_general_wn) -// floatTetWild::fast_winding_number( -// Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); -// else + if (!mesh.params.use_general_wn) + floatTetWild::fast_winding_number( + Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); + else igl::winding_number( Eigen::MatrixXd(vs.cast()), Eigen::MatrixXi(fs), C, w[i]); } @@ -1613,11 +1572,10 @@ void floatTetWild::boolean_operation(Mesh& mesh, int op){ } Eigen::VectorXd w1, w2; -// if(!mesh.params.use_general_wn) { -// floatTetWild::fast_winding_number(Eigen::MatrixXd(v1.cast()), Eigen::MatrixXi(f1), C, w1); -// floatTetWild::fast_winding_number(Eigen::MatrixXd(v2.cast()), Eigen::MatrixXi(f2), C, w2); -// }else - { + if(!mesh.params.use_general_wn) { + floatTetWild::fast_winding_number(Eigen::MatrixXd(v1.cast()), Eigen::MatrixXi(f1), C, w1); + floatTetWild::fast_winding_number(Eigen::MatrixXd(v2.cast()), Eigen::MatrixXi(f2), C, w2); + }else { igl::winding_number(Eigen::MatrixXd(v1.cast()), Eigen::MatrixXi(f1), C, w1); igl::winding_number(Eigen::MatrixXd(v2.cast()), Eigen::MatrixXi(f2), C, w2); } @@ -1671,9 +1629,9 @@ void floatTetWild::filter_outside(Mesh& mesh, bool invert_faces) { F.col(1) = F.col(2).eval(); F.col(2) = tmp; } -// if(!mesh.params.use_general_wn) -// floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); -// else + if(!mesh.params.use_general_wn) + floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); + else igl::winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); index = 0; @@ -1748,9 +1706,9 @@ void floatTetWild::filter_outside(Mesh& mesh, const std::vector &input_ // F.col(1) = F.col(2).eval(); // F.col(2) = tmp; // } -// if(!mesh.params.use_general_wn) -// floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); -// else + if(!mesh.params.use_general_wn) + floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); + else igl::winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); index = 0; @@ -1862,9 +1820,9 @@ void floatTetWild::mark_outside(Mesh& mesh, bool invert_faces){ F.col(2) = tmp; } Eigen::VectorXd W; -// if(!mesh.params.use_general_wn) -// floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); -// else + if(!mesh.params.use_general_wn) + floatTetWild::fast_winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); + else igl::winding_number(Eigen::MatrixXd(V.cast()), Eigen::MatrixXi(F), C, W); index = 0; @@ -2771,4 +2729,4 @@ void floatTetWild::manifold_surface(Mesh& mesh, Eigen::MatrixXd& V, Eigen::Matri cout << cnt << endl; //fortest -} +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 1ca638ef..4724384c 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -40,9 +39,9 @@ #include #include #include -#include using namespace floatTetWild; +//using namespace Eigen; class GeoLoggerForward : public GEO::LoggerClient { @@ -319,8 +318,8 @@ int main(int argc, char** argv) if (V_in.rows() != 0 && T_in.rows() != 0 && values.rows() != 0) { params.apply_sizing_field = true; - params.V_sizing_field = V_in; - params.T_sizing_field = T_in; + params.V_sizing_field = V_in; + params.T_sizing_field = T_in; params.values_sizing_field = values; } From 4f4f1217713cd9e6238dcfdfd1cbf3571fcb24d6 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Fri, 26 Sep 2025 12:44:06 +0200 Subject: [PATCH 13/70] update geogram --- cmake/FloatTetwildDownloadExternal.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/FloatTetwildDownloadExternal.cmake b/cmake/FloatTetwildDownloadExternal.cmake index aff9c7ce..74cacf77 100644 --- a/cmake/FloatTetwildDownloadExternal.cmake +++ b/cmake/FloatTetwildDownloadExternal.cmake @@ -84,9 +84,9 @@ function(float_tetwild_download_geogram) # GIT_REPOSITORY https://github.com/polyfem/geogram.git GIT_TAG # e6b9612f1146370e40deaa341b4dd7ef90502102 GIT_REPOSITORY - https://github.com/Yixin-Hu/geogram + https://github.com/BrunoLevy/geogram GIT_TAG - b613750341a6cdd31ae8df80ecfc26ac7ca1a6ad) + c4d9a3eefe0e4bc3e09d37f28d032bf07e025350) endfunction() # aabbcc From 5d857e2052fbf9ea74476a16e4b9e5ebb58446e5 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Fri, 26 Sep 2025 13:50:36 +0200 Subject: [PATCH 14/70] update cmake --- CMakeLists.txt | 17 +-- cmake/FloatTetwildDependencies.cmake | 142 +++++++++++++---------- cmake/FloatTetwildDownloadExternal.cmake | 109 ----------------- cmake/Warnings.cmake | 2 +- cmake/geogram.cmake | 82 +++++++------ tests/CMakeLists.txt | 15 ++- 6 files changed, 138 insertions(+), 229 deletions(-) delete mode 100644 cmake/FloatTetwildDownloadExternal.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 40d20e25..20df19a5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,25 +86,20 @@ if(NOT ${GMP_FOUND}) message(FATAL_ERROR "Cannot find GMP") endif() -# find_package(MPFR) IF(NOT ${MPFR_FOUND}) MESSAGE(FATAL_ERROR "Cannot find -# MPFR") ENDIF() - # add_library() can only be called without any source since CMake 3.11 ... add_library(${PROJECT_NAME} src/Logger.cpp) # Public include directory for FloatTetwild target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR}/include) -# set(MESH_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests/") -# target_compile_definitions(${PROJECT_NAME} PUBLIC -# -DFLOAT_TETWILD_MESH_PATH=\"${MESH_PATH}\") - # Extra warnings target_link_libraries(${PROJECT_NAME} PRIVATE warnings::all) -# Use C++11 -set(CMAKE_CXX_STANDARD 11) # C++11... -target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) +# Use C++14 (minimum for modern CMake practices) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14) # if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") # target_compile_options(${PROJECT_NAME} PUBLIC "/Zc:__cplusplus") endif() # target_compile_definitions(${PROJECT_NAME} PUBLIC @@ -153,7 +148,7 @@ endif() # Main executable if(FLOAT_TETWILD_TOPLEVEL_PROJECT) add_executable(${PROJECT_NAME}_bin src/main.cpp) - target_compile_features(${PROJECT_NAME}_bin PUBLIC ${CXX14_FEATURES}) + target_compile_features(${PROJECT_NAME}_bin PUBLIC cxx_std_14) target_link_libraries(${PROJECT_NAME}_bin PUBLIC ${PROJECT_NAME} CLI11::CLI11 warnings::all) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index a58e238b..d3fd28a4 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -2,8 +2,12 @@ # Prepare dependencies # ############################################################################## -# Download external dependencies -include(FloatTetwildDownloadExternal) +# Use modern FetchContent for dependency management +include(FetchContent) + +# Set FetchContent properties for better performance +set(FETCHCONTENT_QUIET ON) +set(FETCHCONTENT_UPDATES_DISCONNECTED ON) # ############################################################################## # Required libraries @@ -11,85 +15,90 @@ include(FloatTetwildDownloadExternal) # Sanitizers if(FLOAT_TETWILD_WITH_SANITIZERS) - float_tetwild_download_sanitizers() + FetchContent_Declare( + sanitizers-cmake + GIT_REPOSITORY https://github.com/arsenm/sanitizers-cmake.git + GIT_TAG 6947cff3a9c9305eb9c16135dd81da3feb4bf87f + ) + FetchContent_MakeAvailable(sanitizers-cmake) + list(APPEND CMAKE_MODULE_PATH ${sanitizers-cmake_SOURCE_DIR}/cmake) find_package(Sanitizers) endif() -# CL11 +# CLI11 if(FLOAT_TETWILD_TOPLEVEL_PROJECT AND NOT TARGET CLI11::CLI11) - float_tetwild_download_cli11() - add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/cli11) + FetchContent_Declare( + cli11 + URL https://github.com/CLIUtils/CLI11/archive/v1.8.0.tar.gz + URL_HASH MD5=5e5470abcb76422360409297bfc446ac + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + FetchContent_MakeAvailable(cli11) endif() # fmt if(NOT TARGET fmt::fmt) - float_tetwild_download_fmt() - add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/fmt) + FetchContent_Declare( + fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt + GIT_TAG 40626af88bd7df9a5fb80be7b25ac85b122d6c21 + ) + FetchContent_MakeAvailable(fmt) endif() # spdlog if(NOT TARGET spdlog::spdlog) - float_tetwild_download_spdlog() - - # Create interface target - add_library(spdlog INTERFACE) - add_library(spdlog::spdlog ALIAS spdlog) - target_include_directories(spdlog - INTERFACE ${FLOAT_TETWILD_EXTERNAL}/spdlog/include) - target_link_libraries(spdlog INTERFACE fmt::fmt) - target_compile_definitions(spdlog INTERFACE SPDLOG_FMT_EXTERNAL) + FetchContent_Declare( + spdlog + GIT_REPOSITORY https://github.com/gabime/spdlog + GIT_TAG 6fa36017cfd5731d617e1a934f0e5ea9c4445b13 + ) + + # Configure spdlog to use external fmt + set(SPDLOG_FMT_EXTERNAL ON CACHE BOOL "" FORCE) + + FetchContent_MakeAvailable(spdlog) endif() -# igl -include(FetchContent) +# libigl FetchContent_Declare( libigl - GIT_REPOSITORY https://github.com/libigl/libigl.git GIT_TAG - a221faf1e4bd571529ca2101c08bc2458579b1da + GIT_REPOSITORY https://github.com/libigl/libigl.git + GIT_TAG a221faf1e4bd571529ca2101c08bc2458579b1da ) FetchContent_MakeAvailable(libigl) -# Import libigl targets -list(APPEND CMAKE_MODULE_PATH "${FLOAT_TETWILD_EXTERNAL}/libigl/cmake") +# Import libigl targets - use FetchContent source directory +list(APPEND CMAKE_MODULE_PATH "${libigl_SOURCE_DIR}/cmake") # Geogram if(NOT TARGET geogram::geogram) - float_tetwild_download_geogram() + FetchContent_Declare( + geogram + GIT_REPOSITORY https://github.com/BrunoLevy/geogram + GIT_TAG c4d9a3eefe0e4bc3e09d37f28d032bf07e025350 + ) + FetchContent_MakeAvailable(geogram) include(geogram) endif() # TBB if(FLOAT_TETWILD_ENABLE_TBB AND NOT TARGET TBB::tbb) - float_tetwild_download_tbb() - - set(TBB_BUILD_STATIC - ON - CACHE BOOL " " FORCE) - set(TBB_BUILD_SHARED - OFF - CACHE BOOL " " FORCE) - set(TBB_BUILD_TBBMALLOC - OFF - CACHE BOOL " " FORCE) - set(TBB_BUILD_TBBMALLOC_PROXY - OFF - CACHE BOOL " " FORCE) - set(TBB_TEST - OFF - CACHE BOOL " " FORCE) - set(TBB_NO_DATE - ON - CACHE BOOL " " FORCE) - - add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/tbb tbb) - # set_target_properties( tbb_static PROPERTIES INTERFACE_INCLUDE_DIRECTORIES - # "${FLOAT_TETWILD_EXTERNAL}/tbb/include") - if(NOT MSVC) - # set_target_properties( tbb_static PROPERTIES COMPILE_FLAGS - # "-Wno-implicit-fallthrough -Wno-missing-field-initializers - # -Wno-unused-parameter -Wno-keyword-macro" ) - # set_target_properties(tbb_static PROPERTIES POSITION_INDEPENDENT_CODE ON) - endif() + FetchContent_Declare( + tbb + GIT_REPOSITORY https://github.com/oneapi-src/oneTBB + GIT_TAG 9afd759b72c0c233cd5ea3c3c06b0894c9da9c54 + ) + + # Configure TBB build options + set(TBB_BUILD_STATIC ON CACHE BOOL "" FORCE) + set(TBB_BUILD_SHARED OFF CACHE BOOL "" FORCE) + set(TBB_BUILD_TBBMALLOC OFF CACHE BOOL "" FORCE) + set(TBB_BUILD_TBBMALLOC_PROXY OFF CACHE BOOL "" FORCE) + set(TBB_TEST OFF CACHE BOOL "" FORCE) + set(TBB_NO_DATE ON CACHE BOOL "" FORCE) + + FetchContent_MakeAvailable(tbb) endif() # C++11 threads @@ -97,10 +106,19 @@ find_package(Threads REQUIRED) # Json if(NOT TARGET json) - float_tetwild_download_json() - add_library(json INTERFACE) - target_include_directories(json SYSTEM - INTERFACE ${FLOAT_TETWILD_EXTERNAL}/json/include) + FetchContent_Declare( + json + GIT_REPOSITORY https://github.com/jdumas/json + GIT_TAG 0901d33bf6e7dfe6f70fd9d142c8f5c6695c6c5b + ) + FetchContent_MakeAvailable(json) + + # Create interface target if not provided by the library + if(NOT TARGET json) + add_library(json INTERFACE) + target_include_directories(json SYSTEM + INTERFACE ${json_SOURCE_DIR}/include) + endif() endif() # winding number float_tetwild_download_windingnumber() @@ -126,6 +144,10 @@ endif() # "${FLOAT_TETWILD_EXTERNAL}/") if(FLOAT_TETWILD_WITH_EXACT_ENVELOPE) - float_tetwild_download_exact_envelope() - add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/exact_envelope) + FetchContent_Declare( + exact_envelope + GIT_REPOSITORY https://github.com/wangbolun300/fast-envelope + GIT_TAG 520ee04b6c69a802db31d1fd3a3e6e382d10ef98 + ) + FetchContent_MakeAvailable(exact_envelope) endif() diff --git a/cmake/FloatTetwildDownloadExternal.cmake b/cmake/FloatTetwildDownloadExternal.cmake deleted file mode 100644 index 74cacf77..00000000 --- a/cmake/FloatTetwildDownloadExternal.cmake +++ /dev/null @@ -1,109 +0,0 @@ -# ############################################################################## - -include(DownloadProject) - -# With CMake 3.8 and above, we can hide warnings about git being in a detached -# head by passing an extra GIT_CONFIG option -if(NOT (${CMAKE_VERSION} VERSION_LESS "3.8.0")) - set(FLOAT_TETWILD_EXTRA_OPTIONS "GIT_CONFIG advice.detachedHead=false") -else() - set(FLOAT_TETWILD_EXTRA_OPTIONS "") -endif() - -# Shortcut function -function(float_tetwild_download_project name) - download_project( - PROJ - ${name} - SOURCE_DIR - ${FLOAT_TETWILD_EXTERNAL}/${name} - DOWNLOAD_DIR - ${FLOAT_TETWILD_EXTERNAL}/.cache/${name} - QUIET - ${FLOAT_TETWILD_EXTRA_OPTIONS} - ${ARGN}) -endfunction() - -# ############################################################################## - -# Json -function(float_tetwild_download_json) - float_tetwild_download_project( - json GIT_REPOSITORY https://github.com/jdumas/json GIT_TAG - 0901d33bf6e7dfe6f70fd9d142c8f5c6695c6c5b) -endfunction() - -# Catch2 -function(float_tetwild_download_catch2) - float_tetwild_download_project( - Catch2 URL - https://github.com/catchorg/Catch2/archive/refs/tags/v3.5.3.tar.gz URL_MD5 - 1f51d817ce81d54b12e87d06e159305f) -endfunction() - -# CLI11 -function(float_tetwild_download_cli11) - float_tetwild_download_project( - cli11 URL https://github.com/CLIUtils/CLI11/archive/v1.8.0.tar.gz URL_MD5 - 5e5470abcb76422360409297bfc446ac) -endfunction() - -# tbb -function(float_tetwild_download_tbb) - float_tetwild_download_project( - tbb GIT_REPOSITORY https://github.com/oneapi-src/oneTBB GIT_TAG - 9afd759b72c0c233cd5ea3c3c06b0894c9da9c54) -endfunction() - -# Sanitizers -function(float_tetwild_download_sanitizers) - float_tetwild_download_project( - sanitizers-cmake GIT_REPOSITORY - https://github.com/arsenm/sanitizers-cmake.git GIT_TAG - 6947cff3a9c9305eb9c16135dd81da3feb4bf87f) -endfunction() - -# fmt -function(float_tetwild_download_fmt) - float_tetwild_download_project( - fmt URL https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz URL_MD5 - 1015bf3ff2a140dfe03de50ee2469401) -endfunction() - -# spdlog -function(float_tetwild_download_spdlog) - float_tetwild_download_project( - spdlog URL https://github.com/gabime/spdlog/archive/v1.3.1.tar.gz URL_MD5 - 3c17dd6983de2a66eca8b5a0b213d29f) -endfunction() - -# Geogram LGPL -function(float_tetwild_download_geogram) - float_tetwild_download_project( - geogram - # GIT_REPOSITORY https://github.com/polyfem/geogram.git GIT_TAG - # e6b9612f1146370e40deaa341b4dd7ef90502102 - GIT_REPOSITORY - https://github.com/BrunoLevy/geogram - GIT_TAG - c4d9a3eefe0e4bc3e09d37f28d032bf07e025350) -endfunction() - -# aabbcc -function(float_tetwild_download_aabbcc) - float_tetwild_download_project( - aabbcc GIT_REPOSITORY https://github.com/lohedges/aabbcc.git GIT_TAG - 0c85e61362d384d70c71946826bfed0fb24a74ba) -endfunction() - -# winding number function(float_tetwild_download_windingnumber) -# float_tetwild_download_project(windingnumber GIT_REPOSITORY -# https://github.com/alecjacobson/WindingNumber.git GIT_TAG -# bde8780ec848fa71c1294a0af50347e968b19493 ) endfunction() - -# exact envelope -function(float_tetwild_download_exact_envelope) - float_tetwild_download_project( - exact_envelope GIT_REPOSITORY https://github.com/wangbolun300/fast-envelope - GIT_TAG 520ee04b6c69a802db31d1fd3a3e6e382d10ef98) -endfunction() diff --git a/cmake/Warnings.cmake b/cmake/Warnings.cmake index b88322f2..a633f801 100644 --- a/cmake/Warnings.cmake +++ b/cmake/Warnings.cmake @@ -1,5 +1,5 @@ ################################################################################ -cmake_minimum_required(VERSION 2.6.3) +cmake_minimum_required(VERSION 3.10) ################################################################################ # See comments and discussions here: # http://stackoverflow.com/questions/5088460/flags-to-enable-thorough-and-verbose-g-warnings diff --git a/cmake/geogram.cmake b/cmake/geogram.cmake index 03ef564a..9c2136e0 100644 --- a/cmake/geogram.cmake +++ b/cmake/geogram.cmake @@ -2,53 +2,49 @@ # Find Geogram and build it as part of the current build ################################################################################ -if(TARGET geogram) - return() -endif() - -################################################################################ - -set(GEOGRAM_SEARCH_PATHS ${FLOAT_TETWILD_EXTERNAL}/geogram) - -find_path(GEOGRAM_SOURCE_INCLUDE_DIR - geogram/basic/common.h - PATHS ${GEOGRAM_SEARCH_PATHS} - PATH_SUFFIXES src/lib - NO_DEFAULT_PATH -) +if(NOT TARGET geogram) + set(GEOGRAM_SEARCH_PATHS ${FLOAT_TETWILD_EXTERNAL}/geogram) + + find_path(GEOGRAM_SOURCE_INCLUDE_DIR + geogram/basic/common.h + PATHS ${GEOGRAM_SEARCH_PATHS} + PATH_SUFFIXES src/lib + NO_DEFAULT_PATH + ) + + set(GEOGRAM_ROOT ${GEOGRAM_SOURCE_INCLUDE_DIR}/../..) + + message(STATUS "Found Geogram here: ${GEOGRAM_ROOT}") + + ################################################################################ + + if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(VORPALINE_ARCH_64 TRUE CACHE BOOL "" FORCE) + set(VORPALINE_PLATFORM Win-vs-generic CACHE STRING "" FORCE) + set(VORPALINE_BUILD_DYNAMIC false CACHE STRING "" FORCE) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(VORPALINE_PLATFORM Linux64-gcc CACHE STRING "" FORCE) + set(VORPALINE_BUILD_DYNAMIC false CACHE STRING "" FORCE) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(VORPALINE_PLATFORM Darwin-clang CACHE STRING "" FORCE) + set(VORPALINE_BUILD_DYNAMIC false CACHE STRING "" FORCE) + endif() -set(GEOGRAM_ROOT ${GEOGRAM_SOURCE_INCLUDE_DIR}/../..) + option(GEOGRAM_WITH_GRAPHICS "Viewers and geogram_gfx library" OFF) + option(GEOGRAM_WITH_LEGACY_NUMERICS "Legacy numerical libraries" OFF) + option(GEOGRAM_WITH_HLBFGS "Non-linear solver (Yang Liu's HLBFGS)" OFF) + option(GEOGRAM_WITH_TETGEN "Tetrahedral mesher (Hang Si's TetGen)" OFF) + option(GEOGRAM_WITH_TRIANGLE "Triangle mesher (Jonathan Shewchuk's triangle)" OFF) + option(GEOGRAM_WITH_EXPLORAGRAM "Experimental code (hexahedral meshing vpipeline and optimal transport)" OFF) + option(GEOGRAM_WITH_LUA "Built-in LUA interpreter" OFF) + option(GEOGRAM_LIB_ONLY "Libraries only (no example programs/no viewer)" ON) + option(GEOGRAM_WITH_FPG "Predicate generator (Sylvain Pion's FPG)" OFF) + option(GEOGRAM_USE_SYSTEM_GLFW3 "Use the version of GLFW3 installed in the system if found" OFF) -message(STATUS "Found Geogram here: ${GEOGRAM_ROOT}") + ################################################################################ -################################################################################ - -if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") - set(VORPALINE_ARCH_64 TRUE CACHE BOOL "" FORCE) - set(VORPALINE_PLATFORM Win-vs-generic CACHE STRING "" FORCE) - set(VORPALINE_BUILD_DYNAMIC false CACHE STRING "" FORCE) -elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(VORPALINE_PLATFORM Linux64-gcc CACHE STRING "" FORCE) - set(VORPALINE_BUILD_DYNAMIC false CACHE STRING "" FORCE) -elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(VORPALINE_PLATFORM Darwin-clang CACHE STRING "" FORCE) - set(VORPALINE_BUILD_DYNAMIC false CACHE STRING "" FORCE) + add_subdirectory(${GEOGRAM_ROOT} geogram) endif() - -option(GEOGRAM_WITH_GRAPHICS "Viewers and geogram_gfx library" OFF) -option(GEOGRAM_WITH_LEGACY_NUMERICS "Legacy numerical libraries" OFF) -option(GEOGRAM_WITH_HLBFGS "Non-linear solver (Yang Liu's HLBFGS)" OFF) -option(GEOGRAM_WITH_TETGEN "Tetrahedral mesher (Hang Si's TetGen)" OFF) -option(GEOGRAM_WITH_TRIANGLE "Triangle mesher (Jonathan Shewchuk's triangle)" OFF) -option(GEOGRAM_WITH_EXPLORAGRAM "Experimental code (hexahedral meshing vpipeline and optimal transport)" OFF) -option(GEOGRAM_WITH_LUA "Built-in LUA interpreter" OFF) -option(GEOGRAM_LIB_ONLY "Libraries only (no example programs/no viewer)" ON) -option(GEOGRAM_WITH_FPG "Predicate generator (Sylvain Pion's FPG)" OFF) -option(GEOGRAM_USE_SYSTEM_GLFW3 "Use the version of GLFW3 installed in the system if found" OFF) - -################################################################################ - -add_subdirectory(${GEOGRAM_ROOT} geogram) target_include_directories(geogram SYSTEM PUBLIC ${GEOGRAM_SOURCE_INCLUDE_DIR}) if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5e6c2170..0417fcd5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,9 +1,14 @@ -# Download Catch2 unit test framework -float_tetwild_download_catch2() -list(APPEND CMAKE_MODULE_PATH ${FLOAT_TETWILD_EXTERNAL}/Catch2/contrib) +# Download Catch2 unit test framework using FetchContent +include(FetchContent) +FetchContent_Declare( + Catch2 + URL https://github.com/catchorg/Catch2/archive/refs/tags/v3.5.3.tar.gz + URL_HASH MD5=1f51d817ce81d54b12e87d06e159305f +) +FetchContent_MakeAvailable(Catch2) -# Add catch2 -add_subdirectory(${FLOAT_TETWILD_EXTERNAL}/Catch2 catch2) +# Add Catch2 to module path for test discovery +list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras) set(test_sources main.cpp From 0a4be94656df09a217b9e9abbb5098f7d27a1a8a Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Fri, 26 Sep 2025 14:00:46 +0200 Subject: [PATCH 15/70] revert libigl update --- cmake/FloatTetwildDependencies.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index d3fd28a4..bce02881 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -64,7 +64,7 @@ endif() FetchContent_Declare( libigl GIT_REPOSITORY https://github.com/libigl/libigl.git - GIT_TAG a221faf1e4bd571529ca2101c08bc2458579b1da + GIT_TAG ae8f959ea26d7059abad4c698aba8d6b7c3205e8 ) FetchContent_MakeAvailable(libigl) From 24d8e013fa02ad46592f6ed2e61397e0d229c7c7 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Fri, 26 Sep 2025 15:20:08 +0200 Subject: [PATCH 16/70] update CI --- .github/workflows/continuous.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index efe02cc3..2a7ea5bf 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -23,14 +23,16 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-18.04, macos-latest] + os: [ubuntu-22.04, macOS-13, macOS-14] config: [Debug, Release] envelope: [ON, OFF] include: - - os: macos-latest - name: macOS - - os: ubuntu-18.04 + - os: ubuntu-22.04 name: Linux + - os: macos-13 + name: macOS-13 + - os: macos-14 + name: macOS-14 ARM64 steps: - name: Checkout repository uses: actions/checkout@v1 From 241108d770bbfc106cef64b087590ec4af4e31e0 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 15:22:32 +0200 Subject: [PATCH 17/70] Update cache --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 2a7ea5bf..85f72020 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -59,7 +59,7 @@ jobs: - name: Cache Build id: cache-build - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.ccache key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.envelope }}-cache From 14168c299600ba038f6a353ab82d808f7dc8ef34 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 15:29:48 +0200 Subject: [PATCH 18/70] Update continuous.yml --- .github/workflows/continuous.yml | 139 +++++++------------------------ 1 file changed, 29 insertions(+), 110 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 85f72020..d22a88cd 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -23,7 +23,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, macOS-13, macOS-14] + os: [ubuntu-22.04, macOS-13, macOS-, windows-2019] config: [Debug, Release] envelope: [ON, OFF] include: @@ -33,48 +33,48 @@ jobs: name: macOS-13 - os: macos-14 name: macOS-14 ARM64 + - os: windows-2019 + name: Windows + steps: - name: Checkout repository - uses: actions/checkout@v1 + uses: actions/checkout@v4 with: fetch-depth: 10 + submodules: "recursive" - - 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 \ - libsuitesparse-dev \ - xorg-dev \ - ccache - - - name: Dependencies (macOS) - if: runner.os == 'macOS' - run: brew install suite-sparse ccache gmp + - name: Setup NMake (Windows) + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 - - name: Cache Build - id: cache-build - uses: actions/cache@v4 + - name: Setup Conda + uses: conda-incubator/setup-miniconda@v3 with: - path: ~/.ccache - key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.envelope }}-cache + channels: conda-forge + python-version: ${{ matrix.python-version }} + channel-priority: true + activate-environment: test-env - - name: Prepare ccache - run: | - ccache --max-size=1.0G - ccache -V && ccache --show-stats && ccache --zero-stats + - name: Install Dependencies + run: conda install numpy svgwrite cmake=3 git -y + + - name: Install Dependencies (Windows) + if: runner.os == 'Windows' + run: conda install mpir -y + + - name: Envs (Windows) + if: runner.os == 'Windows' + run: echo "CMAKE_GENERATOR=NMake Makefiles" >> $GITHUB_ENV + + - name: Configure ssl certificate + if : runner.os == 'Windows' + run: git config --global http.sslBackend schannel - name: Configure run: | mkdir -p build cd build cmake .. \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_BUILD_TYPE=${{ matrix.config }} \ -DFLOAT_TETWILD_WITH_EXACT_ENVELOPE=${{ matrix.envelope }} \ @@ -86,84 +86,3 @@ jobs: - name: Run Example run: cd build; ./FloatTetwild_bin --input ../tests/bunny.off --level 0 --stop-energy 100 - - #################### - # Windows - #################### - - Windows: - name: Windows-${{ matrix.envelope }} (${{ matrix.config }}) - runs-on: windows-2019 - env: - CC: cl.exe - CXX: cl.exe - SCCACHE_IDLE_TIMEOUT: "12000" - strategy: - fail-fast: false - matrix: - config: [Debug, Release] - envelope: [ON, OFF] - steps: - - name: Stetup Conda - uses: s-weigand/setup-conda@v1 - with: - conda-channels: anaconda, conda-forge - python-version: 3.6 - - - name: Install Dependencies - shell: powershell - run: | - conda install -c conda-forge mpir -y - - - name: Checkout repository - uses: actions/checkout@v1 - with: - fetch-depth: 10 - - uses: seanmiddleditch/gha-setup-ninja@master - # https://github.com/actions/cache/issues/101 - - name: Set env - run: | - echo "appdata=$env:LOCALAPPDATA" >> ${env:GITHUB_ENV} - echo "GMP_INC=C:\Miniconda\Library\include" >> ${env:GITHUB_ENV} - echo "GMP_LIB=C:\Miniconda\Library\lib" >> ${env:GITHUB_ENV} - - - name: Cache build - id: cache-build - uses: actions/cache@v1 - with: - path: ${{ env.appdata }}\Mozilla\sccache - key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.envelope }}-cache - - - name: Prepare sccache - run: | - Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh') - scoop install sccache --global - # Scoop modifies the PATH so we make it available for the next steps of the job - echo "${env:PATH}" >> ${env:GITHUB_PATH} - - - name: Configure and build - shell: cmd - run: | - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x64 - cmake --version - cmake -G Ninja ^ - -DCMAKE_CXX_COMPILER_LAUNCHER=sccache ^ - -DCMAKE_BUILD_TYPE=${{ matrix.config }} ^ - -DFLOAT_TETWILD_WITH_EXACT_ENVELOPE=${{ matrix.envelope }} ^ - -B build ^ - -S . - cd build - ninja -j1 - - - name: Tests - run: | - cd build - ctest --verbose --output-on-failure - - - name: Run Example - shell: powershell - run: | - cd build - cp C:\Miniconda\Library\bin\mpir.dll .\ - cp C:\Miniconda\Library\bin\gmp.dll .\ - .\FloatTetwild_bin.exe --input ..\tests\bunny.off --level 0 --stop-energy 200 From 78c25fe4268aafc30582c7d71319ac06a3612ff0 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 15:38:40 +0200 Subject: [PATCH 19/70] add libxrandr for geogram --- .github/workflows/continuous.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index d22a88cd..44ed9125 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -23,7 +23,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, macOS-13, macOS-, windows-2019] + os: [ubuntu-22.04, macOS-13, macOS-14, windows-2019] config: [Debug, Release] envelope: [ON, OFF] include: @@ -56,7 +56,11 @@ jobs: activate-environment: test-env - name: Install Dependencies - run: conda install numpy svgwrite cmake=3 git -y + run: conda install cmake=3 git -y + + - name: Install Dependencies (Linux) + if: runner.os == 'Linux' + run: conda install conda-forge::libxrandr-conda-x86_64 - name: Install Dependencies (Windows) if: runner.os == 'Windows' From 3b0571b68341663987dbbf5db96d5350f9ecb226 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 15:43:14 +0200 Subject: [PATCH 20/70] conda prefix --- .github/workflows/continuous.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 44ed9125..4d6c7feb 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -79,6 +79,7 @@ jobs: mkdir -p build cd build cmake .. \ + -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ -DCMAKE_BUILD_TYPE=${{ matrix.config }} \ -DFLOAT_TETWILD_WITH_EXACT_ENVELOPE=${{ matrix.envelope }} \ From 8b10b1985fa38a7d583f6631107f698e2ff200bd Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 15:46:17 +0200 Subject: [PATCH 21/70] add libxrandr devel --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 4d6c7feb..c0979706 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -60,7 +60,7 @@ jobs: - name: Install Dependencies (Linux) if: runner.os == 'Linux' - run: conda install conda-forge::libxrandr-conda-x86_64 + run: conda install conda-forge::libxrandr-devel-conda-x86_64 - name: Install Dependencies (Windows) if: runner.os == 'Windows' From ef38b35567e6521545d78cf46199f02c5fcc06c9 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 16:19:56 +0200 Subject: [PATCH 22/70] install cmake=3.29 --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index c0979706..18e72d9d 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -56,7 +56,7 @@ jobs: activate-environment: test-env - name: Install Dependencies - run: conda install cmake=3 git -y + run: conda install cmake=3.29 git -y - name: Install Dependencies (Linux) if: runner.os == 'Linux' From cb4dc553da76fc9a243352fe0d1091e768e216fe Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 16:22:14 +0200 Subject: [PATCH 23/70] install librandr apt-get --- .github/workflows/continuous.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 18e72d9d..6f218d69 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -42,6 +42,12 @@ jobs: with: fetch-depth: 10 submodules: "recursive" + + - name: Dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install libxrandr-dev - name: Setup NMake (Windows) if: runner.os == 'Windows' @@ -58,10 +64,6 @@ jobs: - name: Install Dependencies run: conda install cmake=3.29 git -y - - name: Install Dependencies (Linux) - if: runner.os == 'Linux' - run: conda install conda-forge::libxrandr-devel-conda-x86_64 - - name: Install Dependencies (Windows) if: runner.os == 'Windows' run: conda install mpir -y From 7e72b95a79d66acdc61a36815455b0ebf1599ffb Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Fri, 26 Sep 2025 16:23:17 +0200 Subject: [PATCH 24/70] update CLI and libigl --- cmake/FloatTetwildDependencies.cmake | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index bce02881..de0d1225 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -29,9 +29,8 @@ endif() if(FLOAT_TETWILD_TOPLEVEL_PROJECT AND NOT TARGET CLI11::CLI11) FetchContent_Declare( cli11 - URL https://github.com/CLIUtils/CLI11/archive/v1.8.0.tar.gz - URL_HASH MD5=5e5470abcb76422360409297bfc446ac - DOWNLOAD_EXTRACT_TIMESTAMP TRUE + GIT_REPOSITORY https://github.com/CLIUtils/CLI11 + GIT_TAG v2.5.0 ) FetchContent_MakeAvailable(cli11) endif() @@ -61,12 +60,14 @@ if(NOT TARGET spdlog::spdlog) endif() # libigl -FetchContent_Declare( - libigl - GIT_REPOSITORY https://github.com/libigl/libigl.git - GIT_TAG ae8f959ea26d7059abad4c698aba8d6b7c3205e8 -) -FetchContent_MakeAvailable(libigl) +if(NOT TARGET igl::core) + FetchContent_Declare( + libigl + GIT_REPOSITORY https://github.com/libigl/libigl.git + GIT_TAG v2.6.0 + ) + FetchContent_MakeAvailable(libigl) +endif() # Import libigl targets - use FetchContent source directory list(APPEND CMAKE_MODULE_PATH "${libigl_SOURCE_DIR}/cmake") From f38d5ba4fc0a19443777958e8bd6119e5912b392 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 16:31:13 +0200 Subject: [PATCH 25/70] use conda-run --- .github/workflows/continuous.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 6f218d69..62e5c5f2 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -80,14 +80,14 @@ jobs: run: | mkdir -p build cd build - cmake .. \ - -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ + conda run -n test-env cmake .. \ + -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ -DCMAKE_BUILD_TYPE=${{ matrix.config }} \ - -DFLOAT_TETWILD_WITH_EXACT_ENVELOPE=${{ matrix.envelope }} \ + -DFLOAT_TETWILD_WITH_EXACT_ENVELOPE=${{ matrix.envelope }} - name: Build - run: cd build; make -j2; ccache --show-stats - + run: cd build; conda run -n test-env cmake --build . --parallel 2 + - name: Tests run: cd build; ctest --verbose --output-on-failure From 0c13a681a463792485c48fa955f8c9f4e6e4795e Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 16:40:05 +0200 Subject: [PATCH 26/70] revert conda-run --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 62e5c5f2..7c4aafbd 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -80,7 +80,7 @@ jobs: run: | mkdir -p build cd build - conda run -n test-env cmake .. \ + cmake .. \ -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ -DCMAKE_BUILD_TYPE=${{ matrix.config }} \ -DFLOAT_TETWILD_WITH_EXACT_ENVELOPE=${{ matrix.envelope }} From 59457fe353c1ffaf5de6e373da475aaa48778297 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 16:44:12 +0200 Subject: [PATCH 27/70] allow populate(Eigen) via cmake policy --- .github/workflows/continuous.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 7c4aafbd..03af2f30 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -81,6 +81,7 @@ jobs: mkdir -p build cd build cmake .. \ + -DCMAKE_POLICY_DEFAULT_CMP0169=OLD \ -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ -DCMAKE_BUILD_TYPE=${{ matrix.config }} \ -DFLOAT_TETWILD_WITH_EXACT_ENVELOPE=${{ matrix.envelope }} From 1876ef148c7be8a35fbeeb64313b46181d9c37c4 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 17:09:30 +0200 Subject: [PATCH 28/70] force conda cmake --- .github/workflows/continuous.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 03af2f30..9b1c2ca4 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -80,8 +80,7 @@ jobs: run: | mkdir -p build cd build - cmake .. \ - -DCMAKE_POLICY_DEFAULT_CMP0169=OLD \ + $CONDA_PREFIX/bin/cmake .. \ -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ -DCMAKE_BUILD_TYPE=${{ matrix.config }} \ -DFLOAT_TETWILD_WITH_EXACT_ENVELOPE=${{ matrix.envelope }} From 792412040fef9ba1fe454a1cf042fd8824841d90 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 17:21:16 +0200 Subject: [PATCH 29/70] add default shell to activate condo --- .github/workflows/continuous.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 9b1c2ca4..1eec01e6 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -12,6 +12,10 @@ env: CTEST_OUTPUT_ON_FAILURE: ON CTEST_PARALLEL_LEVEL: 2 +defaults: + run: + shell: bash -el {0} + jobs: #################### # Linux / macOS @@ -80,7 +84,7 @@ jobs: run: | mkdir -p build cd build - $CONDA_PREFIX/bin/cmake .. \ + cmake .. \ -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ -DCMAKE_BUILD_TYPE=${{ matrix.config }} \ -DFLOAT_TETWILD_WITH_EXACT_ENVELOPE=${{ matrix.envelope }} From 6a263dec50185ee1affb8b9439e4fb0a21cddafd Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 17:25:09 +0200 Subject: [PATCH 30/70] add geogram dips --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 1eec01e6..51c04d4f 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -51,7 +51,7 @@ jobs: if: runner.os == 'Linux' run: | sudo apt-get update - sudo apt-get install libxrandr-dev + sudo apt-get install libxi-dev libxcursor-dev libxinerama-dev libxrandr-dev libx11-dev libxcb1-dev libxau-dev libxdmcp-dev - name: Setup NMake (Windows) if: runner.os == 'Windows' From 06475e1660bce11f5b2b532824d8f7f05f8c8850 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 17:34:23 +0200 Subject: [PATCH 31/70] disable exact envelope --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 51c04d4f..a05e9f84 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -29,7 +29,7 @@ jobs: matrix: os: [ubuntu-22.04, macOS-13, macOS-14, windows-2019] config: [Debug, Release] - envelope: [ON, OFF] + envelope: [OFF] include: - os: ubuntu-22.04 name: Linux From 1573d1b140681aea5db1d2f183ab21f6a8cb8d53 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Fri, 26 Sep 2025 17:46:12 +0200 Subject: [PATCH 32/70] Update windows runner --- .github/workflows/continuous.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index a05e9f84..b39de606 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, macOS-13, macOS-14, windows-2019] + os: [ubuntu-22.04, macOS-13, macOS-14, windows-2022] config: [Debug, Release] envelope: [OFF] include: @@ -37,7 +37,7 @@ jobs: name: macOS-13 - os: macos-14 name: macOS-14 ARM64 - - os: windows-2019 + - os: windows-2022 name: Windows steps: From 729261543ef39fc82596db64491c36395db4c295 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Sat, 27 Sep 2025 14:02:23 +0200 Subject: [PATCH 33/70] add lib dep for windows --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index b39de606..e1cb27c9 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -70,7 +70,7 @@ jobs: - name: Install Dependencies (Windows) if: runner.os == 'Windows' - run: conda install mpir -y + run: conda install mpir zlib -y - name: Envs (Windows) if: runner.os == 'Windows' From 721825d581b57f57a17025b52400e070334ee2a0 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Sun, 28 Sep 2025 00:00:19 +0200 Subject: [PATCH 34/70] make run with gcc13 --- cmake/Warnings.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/Warnings.cmake b/cmake/Warnings.cmake index a633f801..2d24f688 100644 --- a/cmake/Warnings.cmake +++ b/cmake/Warnings.cmake @@ -89,6 +89,8 @@ set(MY_FLAGS # GCC 6.1 # ########### + -Wno-error=stringop-overflow + -Wnull-dereference -fdelete-null-pointer-checks -Wduplicated-cond From 4137401f93473e8e5c30f8ba54e23ffb5bcc1158 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Sun, 28 Sep 2025 00:51:35 +0200 Subject: [PATCH 35/70] add latest OS --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index e1cb27c9..c4165887 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, macOS-13, macOS-14, windows-2022] + os: [ubuntu-22.04, ubuntu-latest, macOS-13, macOS-14, macOS-latest, windows-2022] config: [Debug, Release] envelope: [OFF] include: From f1242b8e2d031b0bd16838913956a0642e4ea384 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 16:10:30 +0200 Subject: [PATCH 36/70] bump TBB --- cmake/FloatTetwildDependencies.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index de0d1225..bc49fd14 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -40,7 +40,7 @@ if(NOT TARGET fmt::fmt) FetchContent_Declare( fmt GIT_REPOSITORY https://github.com/fmtlib/fmt - GIT_TAG 40626af88bd7df9a5fb80be7b25ac85b122d6c21 + GIT_TAG 11.2.0 ) FetchContent_MakeAvailable(fmt) endif() @@ -50,7 +50,7 @@ if(NOT TARGET spdlog::spdlog) FetchContent_Declare( spdlog GIT_REPOSITORY https://github.com/gabime/spdlog - GIT_TAG 6fa36017cfd5731d617e1a934f0e5ea9c4445b13 + GIT_TAG v1.15.3 ) # Configure spdlog to use external fmt @@ -77,7 +77,7 @@ if(NOT TARGET geogram::geogram) FetchContent_Declare( geogram GIT_REPOSITORY https://github.com/BrunoLevy/geogram - GIT_TAG c4d9a3eefe0e4bc3e09d37f28d032bf07e025350 + GIT_TAG v1.9.6 ) FetchContent_MakeAvailable(geogram) include(geogram) @@ -88,7 +88,7 @@ if(FLOAT_TETWILD_ENABLE_TBB AND NOT TARGET TBB::tbb) FetchContent_Declare( tbb GIT_REPOSITORY https://github.com/oneapi-src/oneTBB - GIT_TAG 9afd759b72c0c233cd5ea3c3c06b0894c9da9c54 + GIT_TAG v2021.8.0 ) # Configure TBB build options From 25e049bfd650bae994b671ed9aa1af8f52ef604b Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 16:13:11 +0200 Subject: [PATCH 37/70] build geogram static --- cmake/FloatTetwildDependencies.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index bc49fd14..1fc669a3 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -5,6 +5,9 @@ # Use modern FetchContent for dependency management include(FetchContent) +# Set a global preference for STATIC libraries over SHARED ones. +#set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries" FORCE) + # Set FetchContent properties for better performance set(FETCHCONTENT_QUIET ON) set(FETCHCONTENT_UPDATES_DISCONNECTED ON) @@ -79,6 +82,8 @@ if(NOT TARGET geogram::geogram) GIT_REPOSITORY https://github.com/BrunoLevy/geogram GIT_TAG v1.9.6 ) + set(GEOGRAM_BUILD_SHARED OFF CACHE BOOL "" FORCE) + set(GEOGRAM_BUILD_STATIC ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(geogram) include(geogram) endif() From a050fe1c2e79e3398b82de2333e39cf0b4b83ad1 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 16:16:36 +0200 Subject: [PATCH 38/70] update os names --- .github/workflows/continuous.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index c4165887..32204f3f 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -32,11 +32,15 @@ jobs: envelope: [OFF] include: - os: ubuntu-22.04 - name: Linux + name: ubuntu-22.04 + - os: ubuntu-latest + name: ubuntu-latest - os: macos-13 name: macOS-13 - os: macos-14 name: macOS-14 ARM64 + - os: macos-latest + name: macOS-latest ARM64 - os: windows-2022 name: Windows From 7b8c14eadead77e90f0c6fd3fc0cf9a4109bfc3c Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 16:56:37 +0200 Subject: [PATCH 39/70] update warnings --- cmake/Warnings.cmake | 268 ++++++++++++++++++++----------------------- 1 file changed, 126 insertions(+), 142 deletions(-) diff --git a/cmake/Warnings.cmake b/cmake/Warnings.cmake index 2d24f688..48360099 100644 --- a/cmake/Warnings.cmake +++ b/cmake/Warnings.cmake @@ -1,149 +1,133 @@ -################################################################################ +# ############################################################################## cmake_minimum_required(VERSION 3.10) -################################################################################ +# ############################################################################## # See comments and discussions here: # http://stackoverflow.com/questions/5088460/flags-to-enable-thorough-and-verbose-g-warnings -################################################################################ +# ############################################################################## if(TARGET warnings::all) - return() + return() endif() set(MY_FLAGS - -Wall - -Wextra - -pedantic - - # -Wconversion - #-Wunsafe-loop-optimizations # broken with C++11 loops - -Wunused - - -Wno-long-long - -Wpointer-arith - -Wformat=2 - -Wuninitialized - -Wcast-qual - -Wmissing-noreturn - -Wmissing-format-attribute - -Wredundant-decls - - -Werror=implicit - -Werror=nonnull - -Werror=init-self - -Werror=main - -Werror=missing-braces - -Werror=sequence-point - -Werror=return-type - -Werror=trigraphs - -Werror=array-bounds - -Werror=write-strings - -Werror=address - -Werror=int-to-pointer-cast - -Werror=pointer-to-int-cast - - -Wno-unused-variable - -Wunused-but-set-variable - -Wno-unused-parameter - - #-Weffc++ - -Wno-old-style-cast - # -Wno-sign-conversion - #-Wsign-conversion - - -Wshadow - - -Wstrict-null-sentinel - -Woverloaded-virtual - -Wsign-promo - -Wstack-protector - -Wstrict-aliasing - -Wstrict-aliasing=2 - -Wswitch-default - -Wswitch-enum - -Wswitch-unreachable - - -Wcast-align - -Wdisabled-optimization - #-Winline # produces warning on default implicit destructor - -Winvalid-pch - # -Wmissing-include-dirs - -Wpacked - -Wno-padded - -Wstrict-overflow - -Wstrict-overflow=2 - - -Wctor-dtor-privacy - -Wlogical-op - -Wnoexcept - -Woverloaded-virtual - # -Wundef - - -Wnon-virtual-dtor - -Wdelete-non-virtual-dtor - -Werror=non-virtual-dtor - -Werror=delete-non-virtual-dtor - - -Wno-sign-compare - - ########### - # GCC 6.1 # - ########### - - -Wno-error=stringop-overflow - - -Wnull-dereference - -fdelete-null-pointer-checks - -Wduplicated-cond - -Wmisleading-indentation - - #-Weverything - - ########################### - # Enabled by -Weverything # - ########################### - - #-Wdocumentation - #-Wdocumentation-unknown-command - #-Wfloat-equal - #-Wcovered-switch-default - - #-Wglobal-constructors - #-Wexit-time-destructors - #-Wmissing-variable-declarations - #-Wextra-semi - #-Wweak-vtables - #-Wno-source-uses-openmp - #-Wdeprecated - #-Wnewline-eof - #-Wmissing-prototypes - - #-Wno-c++98-compat - #-Wno-c++98-compat-pedantic - - ########################### - # Need to check if those are still valid today - ########################### - - #-Wimplicit-atomic-properties - #-Wmissing-declarations - #-Wmissing-prototypes - #-Wstrict-selector-match - #-Wundeclared-selector - #-Wunreachable-code - - # Not a warning, but enable link-time-optimization - # TODO: Check out modern CMake version of setting this flag - # https://cmake.org/cmake/help/latest/module/CheckIPOSupported.html - #-flto - - # Gives meaningful stack traces - -fno-omit-frame-pointer - -fno-optimize-sibling-calls + -Wall + -Wextra + -pedantic + + # -Wconversion + #-Wunsafe-loop-optimizations # broken with C++11 loops + -Wunused + + -Wno-long-long + -Wpointer-arith + -Wformat=2 + -Wuninitialized + -Wcast-qual + -Wmissing-noreturn + -Wmissing-format-attribute + -Wredundant-decls + + -Wno-unused-variable + -Wunused-but-set-variable + -Wno-unused-parameter + + #-Weffc++ + -Wno-old-style-cast + # -Wno-sign-conversion + #-Wsign-conversion + + -Wshadow + + -Wstrict-null-sentinel + -Woverloaded-virtual + -Wsign-promo + -Wstack-protector + -Wstrict-aliasing + -Wstrict-aliasing=2 + -Wswitch-default + -Wswitch-enum + -Wswitch-unreachable + + -Wcast-align + -Wdisabled-optimization + #-Winline # produces warning on default implicit destructor + -Winvalid-pch + # -Wmissing-include-dirs + -Wpacked + -Wno-padded + -Wstrict-overflow + -Wstrict-overflow=2 + + -Wctor-dtor-privacy + -Wlogical-op + -Wnoexcept + -Woverloaded-virtual + # -Wundef + + -Wnon-virtual-dtor + -Wdelete-non-virtual-dtor + + -Wno-sign-compare + + ########### + # GCC 6.1 # + ########### + + -Wno-error=stringop-overflow + + -Wnull-dereference + -fdelete-null-pointer-checks + -Wduplicated-cond + -Wmisleading-indentation + + #-Weverything + + ########################### + # Enabled by -Weverything # + ########################### + + #-Wdocumentation + #-Wdocumentation-unknown-command + #-Wfloat-equal + #-Wcovered-switch-default + + #-Wglobal-constructors + #-Wexit-time-destructors + #-Wmissing-variable-declarations + #-Wextra-semi + #-Wweak-vtables + #-Wno-source-uses-openmp + #-Wdeprecated + #-Wnewline-eof + #-Wmissing-prototypes + + #-Wno-c++98-compat + #-Wno-c++98-compat-pedantic + + ########################### + # Need to check if those are still valid today + ########################### + + #-Wimplicit-atomic-properties + #-Wmissing-declarations + #-Wmissing-prototypes + #-Wstrict-selector-match + #-Wundeclared-selector + #-Wunreachable-code + + # Not a warning, but enable link-time-optimization + # TODO: Check out modern CMake version of setting this flag + # https://cmake.org/cmake/help/latest/module/CheckIPOSupported.html + #-flto + + # Gives meaningful stack traces + -fno-omit-frame-pointer + -fno-optimize-sibling-calls ) # Flags above don't make sense for MSVC if(MSVC) - set(MY_FLAGS) + set(MY_FLAGS) endif() include(CheckCXXCompilerFlag) @@ -152,11 +136,11 @@ add_library(warnings_all INTERFACE) add_library(warnings::all ALIAS warnings_all) foreach(FLAG IN ITEMS ${MY_FLAGS}) - string(REPLACE "=" "-" FLAG_VAR "${FLAG}") - if(NOT DEFINED IS_SUPPORTED_${FLAG_VAR}) - check_cxx_compiler_flag("${FLAG}" IS_SUPPORTED_${FLAG_VAR}) - endif() - if(IS_SUPPORTED_${FLAG_VAR}) - target_compile_options(warnings_all INTERFACE ${FLAG}) - endif() -endforeach() + string(REPLACE "=" "-" FLAG_VAR "${FLAG}") + if(NOT DEFINED IS_SUPPORTED_${FLAG_VAR}) + check_cxx_compiler_flag("${FLAG}" IS_SUPPORTED_${FLAG_VAR}) + endif() + if(IS_SUPPORTED_${FLAG_VAR}) + target_compile_options(warnings_all INTERFACE ${FLAG}) + endif() +endforeach() \ No newline at end of file From 200051679b2301c4cbdd36926db1b192916217a0 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 17:21:54 +0200 Subject: [PATCH 40/70] bump TBB to 2022 --- cmake/FloatTetwildDependencies.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index 1fc669a3..74585082 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -93,7 +93,7 @@ if(FLOAT_TETWILD_ENABLE_TBB AND NOT TARGET TBB::tbb) FetchContent_Declare( tbb GIT_REPOSITORY https://github.com/oneapi-src/oneTBB - GIT_TAG v2021.8.0 + GIT_TAG v2022.2.0 ) # Configure TBB build options From ad0cd548eb6520f74b2c4e9ae671dbce63fdeb77 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 21:27:10 +0200 Subject: [PATCH 41/70] disable warning as error --- cmake/FloatTetwildDependencies.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index 74585082..e6343462 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -97,6 +97,7 @@ if(FLOAT_TETWILD_ENABLE_TBB AND NOT TARGET TBB::tbb) ) # Configure TBB build options + set(TBB_STRICT OFF CACHE BOOL "" FORCE) set(TBB_BUILD_STATIC ON CACHE BOOL "" FORCE) set(TBB_BUILD_SHARED OFF CACHE BOOL "" FORCE) set(TBB_BUILD_TBBMALLOC OFF CACHE BOOL "" FORCE) From 173c7247aa02e17a08b976e95cb78efe7cd5d6e9 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 21:30:19 +0200 Subject: [PATCH 42/70] build static libigl --- cmake/FloatTetwildDependencies.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index e6343462..db5ce773 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -69,6 +69,8 @@ if(NOT TARGET igl::core) GIT_REPOSITORY https://github.com/libigl/libigl.git GIT_TAG v2.6.0 ) + set(LIBIGL_BUILD_STATIC ON CACHE BOOL "" FORCE) + set(LIBIGL_BUILD_SHARED OFF CACHE BOOL "" FORCE) FetchContent_MakeAvailable(libigl) endif() From 417caf62e39049296056a53a1074639e09626d19 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 22:09:10 +0200 Subject: [PATCH 43/70] build static geogram --- cmake/FloatTetwildDependencies.cmake | 32 +++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index db5ce773..b87f1170 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -84,12 +84,42 @@ if(NOT TARGET geogram::geogram) GIT_REPOSITORY https://github.com/BrunoLevy/geogram GIT_TAG v1.9.6 ) + + # --- Final Recommended Configuration --- + # Set the platform to force a static build + if(MSVC) + set(GEO_PLATFORM "Win64-vs") + elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") + set(GEO_PLATFORM "Darwin-clang") + else() + set(GEO_PLATFORM "Linux64-gcc") + endif() set(GEOGRAM_BUILD_SHARED OFF CACHE BOOL "" FORCE) set(GEOGRAM_BUILD_STATIC ON CACHE BOOL "" FORCE) - FetchContent_MakeAvailable(geogram) + + # Pass all options directly to the Geogram sub-build. + # This keeps our project's configuration clean and isolated. + set(GEOGRAM_CMAKE_ARGS + -DVORPALINE_PLATFORM=${GEO_PLATFORM} + -DGEOGRAM_SUB_BUILD=ON + -DGEOGRAM_LIB_ONLY=ON + -DGEOGRAM_WITH_GRAPHICS=OFF + -DGEOGRAM_WITH_LUA=OFF + -DGEOGRAM_WITH_EXPLORAGRAM=OFF + -DGEOGRAM_WITH_LEGACY_NUMERICS=OFF + -DGEOGRAM_WITH_TRIANGLE=OFF + ) + + FetchContent_MakeAvailable( + geogram + CMAKE_ARGS ${GEOGRAM_CMAKE_ARGS} + ) + include(geogram) endif() + + # TBB if(FLOAT_TETWILD_ENABLE_TBB AND NOT TARGET TBB::tbb) FetchContent_Declare( From 62eb9c6574492d55aa961f4e7b78a6a508d2ab17 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 22:17:06 +0200 Subject: [PATCH 44/70] correctly set geogram options --- cmake/FloatTetwildDependencies.cmake | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index b87f1170..ed501b6c 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -97,24 +97,15 @@ if(NOT TARGET geogram::geogram) set(GEOGRAM_BUILD_SHARED OFF CACHE BOOL "" FORCE) set(GEOGRAM_BUILD_STATIC ON CACHE BOOL "" FORCE) - # Pass all options directly to the Geogram sub-build. - # This keeps our project's configuration clean and isolated. - set(GEOGRAM_CMAKE_ARGS - -DVORPALINE_PLATFORM=${GEO_PLATFORM} - -DGEOGRAM_SUB_BUILD=ON - -DGEOGRAM_LIB_ONLY=ON - -DGEOGRAM_WITH_GRAPHICS=OFF - -DGEOGRAM_WITH_LUA=OFF - -DGEOGRAM_WITH_EXPLORAGRAM=OFF - -DGEOGRAM_WITH_LEGACY_NUMERICS=OFF - -DGEOGRAM_WITH_TRIANGLE=OFF - ) - - FetchContent_MakeAvailable( - geogram - CMAKE_ARGS ${GEOGRAM_CMAKE_ARGS} - ) - + set(GEOGRAM_SUB_BUILD ON CACHE BOOL "Building as subproject" FORCE) + set(GEOGRAM_LIB_ONLY ON CACHE BOOL "Build geogram lib only" FORCE) + set(GEOGRAM_WITH_GRAPHICS OFF CACHE BOOL "Disable graphics" FORCE) + set(GEOGRAM_WITH_LUA OFF CACHE BOOL "Disable LUA" FORCE) + set(GEOGRAM_WITH_EXPLORAGRAM OFF CACHE BOOL "Disable exploragram" FORCE) + set(GEOGRAM_WITH_LEGACY_NUMERICS OFF CACHE BOOL "Disable legacy numerics" FORCE) + set(GEOGRAM_WITH_TRIANGLE OFF CACHE BOOL "Disable triangle" FORCE) + + FetchContent_MakeAvailable(geogram) include(geogram) endif() From ac6c5bfa39a6a72dd1d852f531f33338a9ebb5dd Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 22:25:33 +0200 Subject: [PATCH 45/70] set VORPALINE_PLATFORM --- cmake/FloatTetwildDependencies.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index ed501b6c..59828d92 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -94,6 +94,9 @@ if(NOT TARGET geogram::geogram) else() set(GEO_PLATFORM "Linux64-gcc") endif() + + set(VORPALINE_PLATFORM ${GEO_PLATFORM}) + set(GEOGRAM_BUILD_SHARED OFF CACHE BOOL "" FORCE) set(GEOGRAM_BUILD_STATIC ON CACHE BOOL "" FORCE) From 7a6bd8a482abb107f2d5997818acdff346778971 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Sun, 28 Sep 2025 22:51:20 +0200 Subject: [PATCH 46/70] set correct windows platform --- cmake/FloatTetwildDependencies.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FloatTetwildDependencies.cmake b/cmake/FloatTetwildDependencies.cmake index 59828d92..2893f6d6 100644 --- a/cmake/FloatTetwildDependencies.cmake +++ b/cmake/FloatTetwildDependencies.cmake @@ -88,7 +88,7 @@ if(NOT TARGET geogram::geogram) # --- Final Recommended Configuration --- # Set the platform to force a static build if(MSVC) - set(GEO_PLATFORM "Win64-vs") + set(GEO_PLATFORM "Win-vs-generic") elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(GEO_PLATFORM "Darwin-clang") else() From 08e569b3987c3104bc8c55ee39141977ed97943c Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Mon, 29 Sep 2025 10:03:43 +0200 Subject: [PATCH 47/70] fix run example on windows --- .github/workflows/continuous.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 32204f3f..5cd7daf2 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -99,5 +99,10 @@ jobs: - name: Tests run: cd build; ctest --verbose --output-on-failure - - name: Run Example + - name: Run Example (Unix) + if: runner.os != 'Windows' run: cd build; ./FloatTetwild_bin --input ../tests/bunny.off --level 0 --stop-energy 100 + + - name: Run Example (Windows) + if: runner.os == 'Windows' + run: cd build; ./FloatTetwild_bin.exe --input ../tests/bunny.off --level 0 --stop-energy 100 From 2badfbfd0c253e2707627855925ae661400372ab Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Mon, 29 Sep 2025 10:37:59 +0200 Subject: [PATCH 48/70] fix windows exe paths --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 5cd7daf2..d54b1b70 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -105,4 +105,4 @@ jobs: - name: Run Example (Windows) if: runner.os == 'Windows' - run: cd build; ./FloatTetwild_bin.exe --input ../tests/bunny.off --level 0 --stop-energy 100 + run: cd build; ./build/${{ matrix.config }}/FloatTetwild_bin.exe --input ../tests/bunny.off --level 0 --stop-energy 100 From a36ad500a06e74a5c15c36ea03bb8aa735f7f5c7 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Mon, 29 Sep 2025 10:52:59 +0200 Subject: [PATCH 49/70] try windows run example again --- .github/workflows/continuous.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index d54b1b70..b93e7147 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -105,4 +105,9 @@ jobs: - name: Run Example (Windows) if: runner.os == 'Windows' - run: cd build; ./build/${{ matrix.config }}/FloatTetwild_bin.exe --input ../tests/bunny.off --level 0 --stop-energy 100 + shell: powershell + run: | + cd build + cp C:\Miniconda\Library\bin\mpir.dll .\ + cp C:\Miniconda\Library\bin\gmp.dll .\ + .\FloatTetwild_bin.exe --input ..\tests\bunny.off --level 0 --stop-energy 200 From 83f12f3b829841905c878b25415848c60b32c6f1 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Mon, 29 Sep 2025 11:08:06 +0200 Subject: [PATCH 50/70] another attempt --- .github/workflows/continuous.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index b93e7147..a87754b9 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -108,6 +108,4 @@ jobs: shell: powershell run: | cd build - cp C:\Miniconda\Library\bin\mpir.dll .\ - cp C:\Miniconda\Library\bin\gmp.dll .\ .\FloatTetwild_bin.exe --input ..\tests\bunny.off --level 0 --stop-energy 200 From f69a2cf5d990487e526274733c134b6c76c0e0cf Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Mon, 29 Sep 2025 11:12:23 +0200 Subject: [PATCH 51/70] fix failing test --- tests/test_predicates.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_predicates.cpp b/tests/test_predicates.cpp index af793c7f..dad6b262 100644 --- a/tests/test_predicates.cpp +++ b/tests/test_predicates.cpp @@ -74,5 +74,6 @@ TEST_CASE("tri_tri_intersection_test_3d_floating", "[predicates]") { REQUIRE(coplanar == 0); - REQUIRE(res == 666); + // Accept either 0 or 666 as a correct "no intersection" result. + REQUIRE((res == 0 || res == 666)); } From 28a1d1595fab991d4cd969a429d3328211b11dea Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Mon, 29 Sep 2025 11:26:31 +0200 Subject: [PATCH 52/70] try windows again --- .github/workflows/continuous.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index a87754b9..a908c873 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -103,9 +103,11 @@ jobs: if: runner.os != 'Windows' run: cd build; ./FloatTetwild_bin --input ../tests/bunny.off --level 0 --stop-energy 100 + - name: List Build Directory (Windows) + if: runner.os == 'Windows' + run: ls -R build + - name: Run Example (Windows) if: runner.os == 'Windows' shell: powershell - run: | - cd build - .\FloatTetwild_bin.exe --input ..\tests\bunny.off --level 0 --stop-energy 200 + run: build\FloatTetwild_bin.exe --input tests\bunny.off --level 0 --stop-energy 200 From a6810678550c0c28568c93edb48e88a740bf4482 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Mon, 29 Sep 2025 11:34:42 +0200 Subject: [PATCH 53/70] remove geogram graphics deps --- .github/workflows/continuous.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index a908c873..72330812 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -51,12 +51,6 @@ jobs: fetch-depth: 10 submodules: "recursive" - - name: Dependencies (Linux) - if: runner.os == 'Linux' - run: | - sudo apt-get update - sudo apt-get install libxi-dev libxcursor-dev libxinerama-dev libxrandr-dev libx11-dev libxcb1-dev libxau-dev libxdmcp-dev - - name: Setup NMake (Windows) if: runner.os == 'Windows' uses: ilammy/msvc-dev-cmd@v1 From 005601b2795665d1fc94ec316757ff6bc4722f44 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Mon, 29 Sep 2025 12:26:54 +0200 Subject: [PATCH 54/70] and another --- .github/workflows/continuous.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 72330812..b8ec72ac 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -103,5 +103,7 @@ jobs: - name: Run Example (Windows) if: runner.os == 'Windows' - shell: powershell - run: build\FloatTetwild_bin.exe --input tests\bunny.off --level 0 --stop-energy 200 + run: conda run -n test-env ./build/FloatTetwild_bin.exe \ + --input tests/bunny.off \ + --level 0 \ + --stop-energy 100 From b4dc27f0fa015f39b3a1a0e610060da90d8e8df2 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Mon, 29 Sep 2025 12:41:58 +0200 Subject: [PATCH 55/70] yet again --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index b8ec72ac..e7126a8c 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -103,7 +103,7 @@ jobs: - name: Run Example (Windows) if: runner.os == 'Windows' - run: conda run -n test-env ./build/FloatTetwild_bin.exe \ + run: conda run -n test-env build/FloatTetwild_bin.exe \ --input tests/bunny.off \ --level 0 \ --stop-energy 100 From 3758f034be65c15b87dfe7eff58f44ef0b66746b Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Mon, 29 Sep 2025 12:58:22 +0200 Subject: [PATCH 56/70] one more time --- .github/workflows/continuous.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index e7126a8c..2be6f5de 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -103,7 +103,7 @@ jobs: - name: Run Example (Windows) if: runner.os == 'Windows' - run: conda run -n test-env build/FloatTetwild_bin.exe \ - --input tests/bunny.off \ + run: cd build; ./FloatTetwild_bin.exe \ + --input ../tests/bunny.off \ --level 0 \ --stop-energy 100 From f2ff13609368ac5ea24fba4db9ae086daf093036 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 12:08:35 +0200 Subject: [PATCH 57/70] add debug tux --- .github/workflows/continuous.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 2be6f5de..4bae19bd 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -101,6 +101,10 @@ jobs: if: runner.os == 'Windows' run: ls -R build + - name: Debug with tmate + # This step will pause the workflow and wait for your connection. + uses: tmate/setup-tmate@v1 + - name: Run Example (Windows) if: runner.os == 'Windows' run: cd build; ./FloatTetwild_bin.exe \ From 3d6c1ad9206e7ba019e1a702dac489b894bdd6ec Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 12:11:19 +0200 Subject: [PATCH 58/70] try mate again --- .github/workflows/continuous.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 4bae19bd..d672b379 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -101,9 +101,9 @@ jobs: if: runner.os == 'Windows' run: ls -R build - - name: Debug with tmate - # This step will pause the workflow and wait for your connection. - uses: tmate/setup-tmate@v1 + - uses: actions/checkout@v4 + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 - name: Run Example (Windows) if: runner.os == 'Windows' From 1c711949ea8b9641209b26544bcd06559cbe22b2 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 12:33:40 +0200 Subject: [PATCH 59/70] remove checkout --- .github/workflows/continuous.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index d672b379..4a7065b6 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -101,7 +101,6 @@ jobs: if: runner.os == 'Windows' run: ls -R build - - uses: actions/checkout@v4 - name: Setup tmate session uses: mxschmitt/action-tmate@v3 From 4596ec50f31345e4f6d1b0c0f92e4d505c26913b Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 13:10:15 +0200 Subject: [PATCH 60/70] fix win + add mate --- .github/workflows/continuous.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 4a7065b6..daec1987 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -50,6 +50,12 @@ jobs: with: fetch-depth: 10 submodules: "recursive" + + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 + timeout-minutes: 20 + with: + detached: true - name: Setup NMake (Windows) if: runner.os == 'Windows' @@ -97,16 +103,12 @@ jobs: if: runner.os != 'Windows' run: cd build; ./FloatTetwild_bin --input ../tests/bunny.off --level 0 --stop-energy 100 - - name: List Build Directory (Windows) - if: runner.os == 'Windows' - run: ls -R build - - - name: Setup tmate session - uses: mxschmitt/action-tmate@v3 - - name: Run Example (Windows) if: runner.os == 'Windows' - run: cd build; ./FloatTetwild_bin.exe \ + run: cd build; \ + cp ./msvc_19.44_cxx_64_md_release/tbb12.dll . \ + cp /c/Miniconda/envs/test-env/Library/bin/mpir.dll . \ + ./FloatTetwild_bin.exe \ --input ../tests/bunny.off \ --level 0 \ --stop-energy 100 From 16a1e82b5efc7eeb001d02594ccaedbe60813b75 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 13:27:11 +0200 Subject: [PATCH 61/70] add unix tools for win --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index daec1987..e3596071 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -74,7 +74,7 @@ jobs: - name: Install Dependencies (Windows) if: runner.os == 'Windows' - run: conda install mpir zlib -y + run: conda install mpir zlib m2-base -y - name: Envs (Windows) if: runner.os == 'Windows' From 39f8461683c37eb8c7ce08a11aabde1309580591 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 13:56:10 +0200 Subject: [PATCH 62/70] yet another attempt --- .github/workflows/continuous.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index e3596071..0a2e78ab 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -74,7 +74,7 @@ jobs: - name: Install Dependencies (Windows) if: runner.os == 'Windows' - run: conda install mpir zlib m2-base -y + run: conda install mpir zlib -y - name: Envs (Windows) if: runner.os == 'Windows' @@ -105,10 +105,8 @@ jobs: - name: Run Example (Windows) if: runner.os == 'Windows' - run: cd build; \ - cp ./msvc_19.44_cxx_64_md_release/tbb12.dll . \ - cp /c/Miniconda/envs/test-env/Library/bin/mpir.dll . \ - ./FloatTetwild_bin.exe \ - --input ../tests/bunny.off \ - --level 0 \ - --stop-energy 100 + run: | + cd build + copy ./msvc_*/tbb12.dll . + copy /c/Miniconda/envs/test-env/Library/bin/mpir.dll . + ./FloatTetwild_bin.exe --input ../tests/bunny.off --level 0 --stop-energy 100 From 143db824d242c38a95ce63e4c6740f9948d07e2d Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 14:20:35 +0200 Subject: [PATCH 63/70] yet again --- .github/workflows/continuous.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 0a2e78ab..a423a1dd 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -105,6 +105,7 @@ jobs: - name: Run Example (Windows) if: runner.os == 'Windows' + shell: cmd run: | cd build copy ./msvc_*/tbb12.dll . From d056096faaf7b8a3a612fa92f032609d31de0307 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 14:35:30 +0200 Subject: [PATCH 64/70] again --- .github/workflows/continuous.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index a423a1dd..3730d867 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -108,6 +108,6 @@ jobs: shell: cmd run: | cd build - copy ./msvc_*/tbb12.dll . + copy msvc_*/tbb12.dll . copy /c/Miniconda/envs/test-env/Library/bin/mpir.dll . - ./FloatTetwild_bin.exe --input ../tests/bunny.off --level 0 --stop-energy 100 + FloatTetwild_bin.exe --input ../tests/bunny.off --level 0 --stop-energy 100 From 55b11b0b4d43f6869d5051ddcb442fcffc305d51 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 14:49:39 +0200 Subject: [PATCH 65/70] yet again v3 --- .github/workflows/continuous.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 3730d867..75ba4d6a 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -105,9 +105,10 @@ jobs: - name: Run Example (Windows) if: runner.os == 'Windows' - shell: cmd + shell: cmd run: | cd build - copy msvc_*/tbb12.dll . - copy /c/Miniconda/envs/test-env/Library/bin/mpir.dll . - FloatTetwild_bin.exe --input ../tests/bunny.off --level 0 --stop-energy 100 + copy msvc_*\tbb12.dll . + rem Use the Windows-style absolute path + copy C:\Miniconda\envs\test-env\Library\bin\mpir.dll . + FloatTetwild_bin.exe --input ..\tests\bunny.off --level 0 --stop-energy 100 From 49a6b842571fed4bfd321cbbcc8e72f4567cffcc Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 15:06:41 +0200 Subject: [PATCH 66/70] yet again v4 --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 75ba4d6a..f327c848 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -108,7 +108,7 @@ jobs: shell: cmd run: | cd build - copy msvc_*\tbb12.dll . + copy msvc_19.44_cxx_64_md_release/tbb12.dll . rem Use the Windows-style absolute path copy C:\Miniconda\envs\test-env\Library\bin\mpir.dll . FloatTetwild_bin.exe --input ..\tests\bunny.off --level 0 --stop-energy 100 From c0f0da0cad4508965d1544c0d41e02c16a989cd2 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 19:14:33 +0200 Subject: [PATCH 67/70] yet again v5 --- .github/workflows/continuous.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index f327c848..39f4a864 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -108,7 +108,9 @@ jobs: shell: cmd run: | cd build - copy msvc_19.44_cxx_64_md_release/tbb12.dll . - rem Use the Windows-style absolute path + rem Find the msvc_* directory automatically and copy the DLL + for /d %%d in (msvc_*) do copy "%%d\tbb12.dll" . + rem Copy the other DLL copy C:\Miniconda\envs\test-env\Library\bin\mpir.dll . + rem Run the executable FloatTetwild_bin.exe --input ..\tests\bunny.off --level 0 --stop-energy 100 From 5a8bb08cd189cbdb5e8d43b81a6a240701dffe76 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Wed, 1 Oct 2025 20:33:29 +0200 Subject: [PATCH 68/70] yet again v6 --- .github/workflows/continuous.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 39f4a864..923e3093 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -109,7 +109,7 @@ jobs: run: | cd build rem Find the msvc_* directory automatically and copy the DLL - for /d %%d in (msvc_*) do copy "%%d\tbb12.dll" . + for /d %%d in (msvc_*) do copy "%%d\tbb*.dll" . rem Copy the other DLL copy C:\Miniconda\envs\test-env\Library\bin\mpir.dll . rem Run the executable From bbfdeb1b281eea653cc901dec7ff9f71b5d0fb57 Mon Sep 17 00:00:00 2001 From: Marius Causemann Date: Thu, 2 Oct 2025 11:41:55 +0200 Subject: [PATCH 69/70] add TBB thread and stack controls again --- src/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 4724384c..4acbc0a4 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,7 @@ #ifdef FLOAT_TETWILD_USE_TBB #include +#include #include #endif @@ -270,6 +271,12 @@ int main(int argc, char** argv) #ifdef FLOAT_TETWILD_USE_TBB const size_t MB = 1024 * 1024; const size_t stack_size = 64 * MB; + unsigned int num_threads = std::max(1u, std::thread::hardware_concurrency()); + num_threads = std::min(max_threads, num_threads); + params.num_threads = num_threads; + std::cout << "TBB threads " << num_threads << std::endl; + tbb::global_control parallelism_limit(tbb::global_control::max_allowed_parallelism, num_threads); + tbb::global_control stack_size_limit(tbb::global_control::thread_stack_size, stack_size); #endif // if(params.is_quiet){ From 71351e7ce044a7792c6a197dcc1258cf7643f096 Mon Sep 17 00:00:00 2001 From: MariusCausemann Date: Thu, 2 Oct 2025 16:44:23 +0200 Subject: [PATCH 70/70] initialization fix --- src/MeshImprovement.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MeshImprovement.cpp b/src/MeshImprovement.cpp index f21f89aa..530f24bd 100644 --- a/src/MeshImprovement.cpp +++ b/src/MeshImprovement.cpp @@ -2145,7 +2145,7 @@ void floatTetWild::smooth_open_boundary_aux(Mesh& mesh, const AABBWrapper& tree) // vertex_smoothing(mesh, tree); ///unfreeze - for (int v_id; v_id < tet_vertices.size(); v_id++) { + for (int v_id=0; v_id < tet_vertices.size(); v_id++) { // if (is_b_vs[v_id]) // if (!conn_b_fs[v_id].empty()) tet_vertices[v_id].is_freezed = false; @@ -2729,4 +2729,4 @@ void floatTetWild::manifold_surface(Mesh& mesh, Eigen::MatrixXd& V, Eigen::Matri cout << cnt << endl; //fortest -} \ No newline at end of file +}