Skip to content

Commit

Permalink
Add benchmark for MCUT
Browse files Browse the repository at this point in the history
  • Loading branch information
unageek committed Sep 11, 2024
1 parent 43f41ba commit 7fb2b57
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 7 deletions.
10 changes: 9 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ option(KIGUMI_BUILD_CLI "Build the command-line interface" ON)
option(KIGUMI_BUILD_TESTS "Build the unit tests" ON)

if(KIGUMI_BUILD_BENCHES)
list(APPEND VCPKG_MANIFEST_FEATURES "bench-geogram" "bench-manifold")
list(APPEND VCPKG_MANIFEST_FEATURES "bench-geogram" "bench-manifold" "bench-mcut")
endif()

project(kigumi CXX)
Expand Down Expand Up @@ -76,6 +76,14 @@ if(KIGUMI_BUILD_BENCHES)
set(MANIFOLD_TEST OFF CACHE BOOL "")
FetchContent_MakeAvailable(manifold)

FetchContent_Declare(
mcut
GIT_REPOSITORY https://github.com/cutdigital/mcut.git
GIT_TAG master
GIT_SHALLOW ON
)
FetchContent_MakeAvailable(mcut)

add_subdirectory(benches)
endif()

Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ and [Boolean_region_builder.h](include/kigumi/Boolean_region_builder.h).

Here are the timings (in seconds) for computing the Boolean intersection between meshes, excluding I/O time:

| Test case | [coref.][coref] (seq.) | [geogram][geogram] (par.) | kigumi (seq.)¹ | kigumi (par.) | [manif.][manif] (seq.) | manif. (par.)² |
|-------------------|-----------------------:|--------------------------:|---------------:|--------------:|-----------------------:|---------------:|
| **Open** | 4.6 | FAILED | 2.4 | 1.3 | FAILED | FAILED |
| **Open & closed** | FAILED | 70.5 | 1.6 | 0.9 | FAILED | FAILED |
| **Closed** | 57.4 | FAILED | 5.3 | 2.7 | 8.9 | 1.7 |
| **Non-manifold** | FAILED | FAILED | 0.5 | 0.3 | FAILED | FAILED |
| Test case | [coref.][coref] (seq.) | [geogram][geogram] (par.) | kigumi (seq.)¹ | kigumi (par.) | [manif.][manif] (seq.) | manif. (par.)² | [MCUT][mcut] (par.) |
|-------------------|-----------------------:|--------------------------:|---------------:|--------------:|-----------------------:|---------------:|--------------------:|
| **Open** | 4.6 | FAILED | 2.4 | 1.3 | FAILED | FAILED | FAILED |
| **Open & closed** | FAILED | 70.5 | 1.6 | 0.9 | FAILED | FAILED | FAILED |
| **Closed** | 57.4 | FAILED | 5.3 | 2.7 | 8.9 | 1.7 | 24.5 |
| **Non-manifold** | FAILED | FAILED | 0.5 | 0.3 | FAILED | FAILED | FAILED |

¹ Ran with `KIGUMI_NUM_THREADS=1`. ² Configured with `-DMANIFOLD_PAR=TBB`.

Expand Down Expand Up @@ -101,3 +101,5 @@ An enhanced version of the algorithm described in [[1]](#1) is used.
[geogram]: https://github.com/BrunoLevy/geogram

[manif]: https://github.com/elalish/manifold

[mcut]: https://github.com/cutdigital/mcut
1 change: 1 addition & 0 deletions benches/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ add_subdirectory(corefinement)
add_subdirectory(geogram)
add_subdirectory(kigumi)
add_subdirectory(manifold)
add_subdirectory(mcut)
24 changes: 24 additions & 0 deletions benches/mcut/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
set(TARGET kigumi_bench_mcut)

add_executable(${TARGET}
main.cc
)

set_target_properties(${TARGET} PROPERTIES
OUTPUT_NAME mcut
)

if(UNIX)
target_compile_options(${TARGET} PRIVATE -Wall -Wextra -Werror)
elseif(MSVC)
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd4702)
endif()

target_include_directories(${TARGET} PRIVATE
${MCUT_INCLUDE_DIR}
)

target_link_libraries(${TARGET} PRIVATE
kigumi
mcut
)
157 changes: 157 additions & 0 deletions benches/mcut/main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/number_utils.h>
#include <kigumi/Mesh_indices.h>
#include <kigumi/Triangle_soup.h>
#include <kigumi/Triangle_soup_io.h>
#include <mcut/mcut.h>

#include <algorithm>
#include <chrono>
#include <exception>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

using K = CGAL::Exact_predicates_exact_constructions_kernel;
using Triangle_soup = kigumi::Triangle_soup<K>;
using kigumi::read_triangle_soup;
using kigumi::Vertex_index;
using kigumi::write_triangle_soup;

namespace {

struct Mesh {
std::vector<double> vertices;
std::vector<McUint32> vertex_indices;
std::vector<McUint32> face_sizes;
McUint32 num_vertices;
McUint32 num_faces;
};

bool read_mesh(const std::string& filename, Mesh& mesh) {
Triangle_soup soup;
if (!read_triangle_soup(filename, soup)) {
return false;
}

for (auto vi : soup.vertices()) {
const auto& p = soup.point(vi);
mesh.vertices.push_back(CGAL::to_double(p.x()));
mesh.vertices.push_back(CGAL::to_double(p.y()));
mesh.vertices.push_back(CGAL::to_double(p.z()));
}
for (auto fi : soup.faces()) {
const auto& f = soup.face(fi);
mesh.vertex_indices.push_back(f[0].idx());
mesh.vertex_indices.push_back(f[1].idx());
mesh.vertex_indices.push_back(f[2].idx());
mesh.face_sizes.push_back(3);
}
mesh.num_vertices = soup.num_vertices();
mesh.num_faces = soup.num_faces();

return true;
}

bool write_mesh(const std::string& filename, const Mesh& mesh) {
Triangle_soup soup;
for (McUint32 i = 0; i < mesh.num_vertices; ++i) {
soup.add_vertex(
{mesh.vertices.at(3 * i), mesh.vertices.at(3 * i + 1), mesh.vertices.at(3 * i + 2)});
}
for (McUint32 i = 0; i < mesh.num_faces; ++i) {
soup.add_face({Vertex_index(mesh.vertex_indices.at(3 * i)),
Vertex_index(mesh.vertex_indices.at(3 * i + 1)),
Vertex_index(mesh.vertex_indices.at(3 * i + 2))});
}

return write_triangle_soup(filename, soup);
}

void check(McResult result) {
if (result != MC_NO_ERROR) {
throw std::runtime_error("mcut failed");
}
}

} // namespace

int main(int argc, char* argv[]) {
try {
std::vector<std::string> args(argv + 1, argv + argc);

Mesh first;
Mesh second;

read_mesh(args.at(0), first);
read_mesh(args.at(1), second);

McContext context = MC_NULL_HANDLE;
check(mcCreateContext(&context, MC_NULL_HANDLE));

McFlags dispatch_flags =
MC_DISPATCH_VERTEX_ARRAY_DOUBLE | MC_DISPATCH_ENFORCE_GENERAL_POSITION |
MC_DISPATCH_FILTER_FRAGMENT_SEALING_INSIDE | MC_DISPATCH_FILTER_FRAGMENT_LOCATION_BELOW;

auto start = std::chrono::high_resolution_clock::now();
check(mcDispatch(context, dispatch_flags, first.vertices.data(), first.vertex_indices.data(),
first.face_sizes.data(), first.num_vertices, first.num_faces,
second.vertices.data(), second.vertex_indices.data(), second.face_sizes.data(),
second.num_vertices, second.num_faces));
auto end = std::chrono::high_resolution_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start) << std::endl;

McUint32 num_ccs = 0;
McConnectedComponentType cc_types = static_cast<McConnectedComponentType>(
MC_CONNECTED_COMPONENT_TYPE_FRAGMENT | MC_CONNECTED_COMPONENT_TYPE_PATCH);
check(mcGetConnectedComponents(context, cc_types, 0, nullptr, &num_ccs));
std::vector<McConnectedComponent> ccs(num_ccs, MC_NULL_HANDLE);
check(mcGetConnectedComponents(context, cc_types, num_ccs, ccs.data(), nullptr));

Mesh result;

for (McUint32 i = 0; i < num_ccs; ++i) {
McConnectedComponent cc = ccs.at(i);
McSize num_bytes = 0;

check(mcGetConnectedComponentData(context, cc, MC_CONNECTED_COMPONENT_DATA_VERTEX_DOUBLE, 0,
nullptr, &num_bytes));
McUint32 num_vertices = num_bytes / (3 * sizeof(double));
result.vertices.resize(3 * (result.num_vertices + num_vertices));
check(mcGetConnectedComponentData(context, cc, MC_CONNECTED_COMPONENT_DATA_VERTEX_DOUBLE,
num_bytes, result.vertices.data() + 3 * result.num_vertices,
nullptr));

check(mcGetConnectedComponentData(context, cc, MC_CONNECTED_COMPONENT_DATA_FACE_TRIANGULATION,
0, nullptr, &num_bytes));
McUint32 num_faces = num_bytes / (3 * sizeof(McUint32));
result.vertex_indices.resize(3 * (result.num_faces + num_faces));
check(mcGetConnectedComponentData(
context, cc, MC_CONNECTED_COMPONENT_DATA_FACE_TRIANGULATION, num_bytes,
result.vertex_indices.data() + 3 * result.num_faces, nullptr));
std::transform(result.vertex_indices.begin() + 3 * result.num_faces,
result.vertex_indices.end(),
result.vertex_indices.begin() + 3 * result.num_faces,
[offset = result.num_vertices](McUint32 idx) { return offset + idx; });

result.num_vertices += num_vertices;
result.num_faces += num_faces;
}

result.face_sizes.resize(result.num_faces, 3);

mcReleaseConnectedComponents(context, 0, nullptr);
mcReleaseContext(context);

write_mesh(args.at(2), result);

return 0;
} catch (const std::exception& e) {
std::cerr << "error: " << e.what() << std::endl;
return 1;
} catch (...) {
std::cerr << "unknown error" << std::endl;
return 1;
}
}
1 change: 1 addition & 0 deletions tools/bench_methods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ corefinement
geogram
kigumi
manifold
mcut
3 changes: 3 additions & 0 deletions vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
},
"tbb"
]
},
"bench-mcut": {
"description": "Build the benchmark for MCUT"
}
}
}

0 comments on commit 7fb2b57

Please sign in to comment.