diff --git a/CMakeLists.txt b/CMakeLists.txt index 77e214a..7bd3ccd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,15 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) +option(WITH_3RD_PARTY_LIBS "Include 3rd party libraries" ON) + +if(WITH_3RD_PARTY_LIBS) + add_compile_definitions(WITH_3RD_PARTY_LIBS=1) +else() + set(DISABLE_SPDLOG ON) + add_compile_definitions(WITH_3RD_PARTY_LIBS=0) +endif() + if (MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W0 -fpermissive -D_USE_MATH_DEFINES") set(CMAKE_SHARED_LIBRARY_PREFIX "lib") @@ -23,17 +32,26 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=address") endif() -include(zlib) -include(boost) -include(openvdb) -include(eigen) -include(spdlog) +if(WITH_3RD_PARTY_LIBS) + include(zlib) + include(boost) + include(openvdb) + include(spdlog) +endif() file(GLOB_RECURSE COACD_SRC "src/*.cc" "src/*.cpp") +if(NOT WITH_3RD_PARTY_LIBS) + # Exclude files that match the pattern "preprocess*" + list(FILTER COACD_SRC EXCLUDE REGEX ".*preprocess.*") +endif() + add_library(coacd STATIC ${COACD_SRC}) target_include_directories(coacd PUBLIC public) target_include_directories(coacd PRIVATE 3rd/cdt/CDT) -target_link_libraries(coacd PRIVATE openvdb_static spdlog::spdlog) + +if(WITH_3RD_PARTY_LIBS) + target_link_libraries(coacd PRIVATE openvdb_static spdlog::spdlog) +endif() find_package(OpenMP) if (OpenMP_CXX_FOUND) @@ -45,7 +63,17 @@ target_link_libraries(coacd PRIVATE Threads::Threads) set_target_properties(coacd PROPERTIES POSITION_INDEPENDENT_CODE TRUE) add_library(_coacd SHARED "public/coacd.cpp") -target_link_libraries(_coacd PRIVATE coacd spdlog::spdlog openvdb_static) + +if(WITH_3RD_PARTY_LIBS) + target_link_libraries(_coacd PRIVATE coacd spdlog::spdlog openvdb_static) +else() + target_link_libraries(_coacd PRIVATE coacd) +endif() add_executable(main main.cpp) -target_link_libraries(main coacd spdlog::spdlog openvdb_static) + +if(WITH_3RD_PARTY_LIBS) + target_link_libraries(main coacd spdlog::spdlog openvdb_static) +else() + target_link_libraries(main coacd) +endif() \ No newline at end of file diff --git a/main.cpp b/main.cpp index 0fb9351..7aaca22 100644 --- a/main.cpp +++ b/main.cpp @@ -4,7 +4,9 @@ #include #include -#include "src/preprocess.h" +#if WITH_3RD_PARTY_LIBS + #include "src/preprocess.h" +#endif #include "src/process.h" #include "src/logger.h" @@ -135,15 +137,26 @@ int main(int argc, char *argv[]) vector bbox = m.Normalize(); // m.SaveOBJ("normalized.obj"); - if (params.preprocess_mode == "auto") - { + #if WITH_3RD_PARTY_LIBS + if (params.preprocess_mode == "auto") + { + bool is_manifold = IsManifold(m); + logger::info("Mesh Manifoldness: {}", is_manifold); + if (!is_manifold) + ManifoldPreprocess(params, m); + } + else if (params.preprocess_mode == "on") + ManifoldPreprocess(params, m); + #else bool is_manifold = IsManifold(m); logger::info("Mesh Manifoldness: {}", is_manifold); if (!is_manifold) - ManifoldPreprocess(params, m); - } - else if (params.preprocess_mode == "on") - ManifoldPreprocess(params, m); + { + logger::critical("The mesh is not a 2-manifold! Please enable WITH_3RD_PARTY_LIBS during compilation, or use third-party libraries to preprocess the mesh."); + exit(0); + } + + #endif m.SaveOBJ(params.remesh_output_name); diff --git a/src/preprocess.cpp b/src/preprocess.cpp index 9a23bf3..b756eb4 100644 --- a/src/preprocess.cpp +++ b/src/preprocess.cpp @@ -55,94 +55,11 @@ namespace coacd logger::info("Preprocess Time: {}s", double(end - start) / CLOCKS_PER_SEC); } - bool IsManifold(Model &input) + void ManifoldPreprocess(Params ¶ms, Model &m) { - logger::info(" - Manifold Check"); - clock_t start, end; - start = clock(); - // Check all edges are shared by exactly two triangles (watertight manifold) - vector> edges; - map, int> edge_num; - for (int i = 0; i < (int)input.triangles.size(); i++) - { - int idx0 = input.triangles[i][0]; - int idx1 = input.triangles[i][1]; - int idx2 = input.triangles[i][2]; - edges.push_back({idx0, idx1}); - edges.push_back({idx1, idx2}); - edges.push_back({idx2, idx0}); - - if (!edge_num.contains({idx0, idx1})) - edge_num[{idx0, idx1}] = 1; - else - { - logger::info("\tWrong triangle orientation"); - end = clock(); - logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); - return false; - } - if (!edge_num.contains({idx1, idx2})) - edge_num[{idx1, idx2}] = 1; - else - { - logger::info("\tWrong triangle orientation"); - end = clock(); - logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); - return false; - } - if (!edge_num.contains({idx2, idx0})) - edge_num[{idx2, idx0}] = 1; - else - { - logger::info("\tWrong triangle orientation"); - end = clock(); - logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); - return false; - } - } - - for (int i = 0; i < (int)edges.size(); i++) - { - pair oppo_edge = {edges[i].second, edges[i].first}; - if (!edge_num.contains(oppo_edge)) - { - logger::info("\tUnclosed mesh"); - end = clock(); - logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); - return false; - } - } - logger::info("[1/3] Edge check finish"); - - // Check self-intersection - BVH bvhTree(input); - for (int i = 0; i < (int)input.triangles.size(); i++) - { - bool is_intersect = bvhTree.IntersectBVH(input.triangles[i], 0); - if (is_intersect) - { - logger::info("\tTriangle self-intersection"); - end = clock(); - logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); - return false; - } - } - logger::info("[2/3] Self-intersection check finish"); - - // Check triange orientation - double mesh_vol = MeshVolume(input); - if (mesh_vol < 0) - { - // Reverse all the triangles - for (int i = 0; i < (int)input.triangles.size(); i++) - std::swap(input.triangles[i][0], input.triangles[i][1]); - } - end = clock(); - - logger::info("[3/3] Triangle orientation check finish. Reversed: {}", mesh_vol < 0); - logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); - - return true; + Model tmp = m; + m.Clear(); + SDFManifold(tmp, m, params.prep_resolution, params.dmc_thres); } } \ No newline at end of file diff --git a/src/preprocess.h b/src/preprocess.h index ab38d37..2093e9b 100644 --- a/src/preprocess.h +++ b/src/preprocess.h @@ -14,13 +14,11 @@ #include "model_obj.h" #include "logger.h" -#include "bvh.h" using namespace openvdb; namespace coacd { - void SDFManifold(Model &input, Model &output, double scale = 50.0f, double level_set = 0.55f); - bool IsManifold(Model &input); + void ManifoldPreprocess(Params ¶ms, Model &m); } diff --git a/src/process.cpp b/src/process.cpp index 05fed27..86ba731 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -1,7 +1,7 @@ #include "./process.h" #include "mcts.h" #include "config.h" -#include "./preprocess.h" +#include "bvh.h" #include #include @@ -10,11 +10,94 @@ namespace coacd { thread_local std::mt19937 random_engine; - void ManifoldPreprocess(Params ¶ms, Model &m) + bool IsManifold(Model &input) { - Model tmp = m; - m.Clear(); - SDFManifold(tmp, m, params.prep_resolution, params.dmc_thres); + logger::info(" - Manifold Check"); + clock_t start, end; + start = clock(); + // Check all edges are shared by exactly two triangles (watertight manifold) + vector> edges; + map, int> edge_num; + for (int i = 0; i < (int)input.triangles.size(); i++) + { + int idx0 = input.triangles[i][0]; + int idx1 = input.triangles[i][1]; + int idx2 = input.triangles[i][2]; + edges.push_back({idx0, idx1}); + edges.push_back({idx1, idx2}); + edges.push_back({idx2, idx0}); + + if (!edge_num.contains({idx0, idx1})) + edge_num[{idx0, idx1}] = 1; + else + { + logger::info("\tWrong triangle orientation"); + end = clock(); + logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); + return false; + } + if (!edge_num.contains({idx1, idx2})) + edge_num[{idx1, idx2}] = 1; + else + { + logger::info("\tWrong triangle orientation"); + end = clock(); + logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); + return false; + } + if (!edge_num.contains({idx2, idx0})) + edge_num[{idx2, idx0}] = 1; + else + { + logger::info("\tWrong triangle orientation"); + end = clock(); + logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); + return false; + } + } + + for (int i = 0; i < (int)edges.size(); i++) + { + pair oppo_edge = {edges[i].second, edges[i].first}; + if (!edge_num.contains(oppo_edge)) + { + logger::info("\tUnclosed mesh"); + end = clock(); + logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); + return false; + } + } + logger::info("[1/3] Edge check finish"); + + // Check self-intersection + BVH bvhTree(input); + for (int i = 0; i < (int)input.triangles.size(); i++) + { + bool is_intersect = bvhTree.IntersectBVH(input.triangles[i], 0); + if (is_intersect) + { + logger::info("\tTriangle self-intersection"); + end = clock(); + logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); + return false; + } + } + logger::info("[2/3] Self-intersection check finish"); + + // Check triange orientation + double mesh_vol = MeshVolume(input); + if (mesh_vol < 0) + { + // Reverse all the triangles + for (int i = 0; i < (int)input.triangles.size(); i++) + std::swap(input.triangles[i][0], input.triangles[i][1]); + } + end = clock(); + + logger::info("[3/3] Triangle orientation check finish. Reversed: {}", mesh_vol < 0); + logger::info("Manifold Check Time: {}s", double(end - start) / CLOCKS_PER_SEC); + + return true; } void MergeCH(Model &ch1, Model &ch2, Model &ch) diff --git a/src/process.h b/src/process.h index 4d2a66f..2c8214a 100644 --- a/src/process.h +++ b/src/process.h @@ -11,6 +11,9 @@ #include #include #include +#ifdef _OPENMP +#include +#endif #include "./io.h" #include "clip.h" @@ -22,10 +25,10 @@ namespace coacd { extern thread_local std::mt19937 random_engine; - void ManifoldPreprocess(Params ¶ms, Model &m); void MergeCH(Model &ch1, Model &ch2, Model &ch); double MergeConvexHulls(Model &m, vector &meshs, vector &cvxs, Params ¶ms, double epsilon = 0.02, double threshold = 0.01); vector Compute(Model &mesh, Params ¶ms); + bool IsManifold(Model &input); inline void addNeighbor(map, pair> &edge_map, pair &edge, vector &neighbors, int idx) {