From a0d2c3ab2508d1e40ac5b3d85d5e167881e9f3b5 Mon Sep 17 00:00:00 2001 From: Emmett Lalish Date: Tue, 22 Oct 2024 22:09:50 -0700 Subject: [PATCH] remove CGAL comparisons (#1009) * remove CGAL * fix format --- CMakeLists.txt | 2 - README.md | 1 - extras/CMakeLists.txt | 29 ---- extras/merge_and_stats.py | 242 ---------------------------- extras/perf_test_cgal.cpp | 78 --------- extras/run.sh | 41 ----- extras/test_hull_performance.cpp | 268 ------------------------------- 7 files changed, 661 deletions(-) delete mode 100644 extras/merge_and_stats.py delete mode 100644 extras/perf_test_cgal.cpp delete mode 100755 extras/run.sh delete mode 100644 extras/test_hull_performance.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 624cb6dd6..f192d5f07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,10 +89,8 @@ set(MANIFOLD_FLAGS "" CACHE STRING "Manifold compiler flags") # Development options option(TRACY_ENABLE "Use tracy profiling" OFF) option(TRACY_MEMORY_USAGE "Track memory allocation with tracy (expensive)" OFF) -option(BUILD_TEST_CGAL "Build CGAL performance comparisons" OFF) mark_as_advanced(TRACY_ENABLE) mark_as_advanced(TRACY_MEMORY_USAGE) -mark_as_advanced(BUILD_TEST_CGAL) # fuzztest is a rather large dependency option(MANIFOLD_FUZZ "Enable fuzzing tests" OFF) diff --git a/README.md b/README.md index 10749d400..09ee448c2 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,6 @@ CMake flags (usage e.g. `-DMANIFOLD_DEBUG=ON`): - `MANIFOLD_TEST=[OFF, ]`: Build unittests. - `TRACY_ENABLE=[, ON]`: Enable integration with tracy profiler. See profiling section below. -- `BUILD_TEST_CGAL=[, ON]`: Builds a CGAL-based performance [comparison](https://github.com/elalish/manifold/tree/master/extras), requires `libcgal-dev` if enabled. Offline building (with missing dependencies): - `MANIFOLD_DOWNLOADS=[OFF, ]`: Automatically download missing dependencies. diff --git a/extras/CMakeLists.txt b/extras/CMakeLists.txt index ea9130cba..427d61d1c 100644 --- a/extras/CMakeLists.txt +++ b/extras/CMakeLists.txt @@ -46,32 +46,3 @@ if(MANIFOLD_EXPORT) target_compile_options(convertFile PRIVATE ${MANIFOLD_FLAGS}) target_compile_features(convertFile PUBLIC cxx_std_17) endif() - -if(BUILD_TEST_CGAL) - add_executable(perfTestCGAL perf_test_cgal.cpp) - find_package(CGAL REQUIRED COMPONENTS Core) - find_package(Boost REQUIRED COMPONENTS thread) - target_compile_definitions(perfTestCGAL PRIVATE CGAL_USE_GMPXX) - target_link_libraries( - perfTestCGAL - manifold - CGAL::CGAL - CGAL::CGAL_Core - Boost::thread - ) - target_compile_options(perfTestCGAL PRIVATE ${MANIFOLD_FLAGS}) - target_compile_features(perfTestCGAL PUBLIC cxx_std_17) - - add_executable(testHullPerformance test_hull_performance.cpp) - target_compile_definitions(testHullPerformance PRIVATE CGAL_USE_GMPXX) - target_link_libraries( - testHullPerformance - manifold - samples - CGAL::CGAL - CGAL::CGAL_Core - Boost::thread - ) - target_compile_options(testHullPerformance PRIVATE ${MANIFOLD_FLAGS}) - target_compile_features(testHullPerformance PUBLIC cxx_std_17) -endif() diff --git a/extras/merge_and_stats.py b/extras/merge_and_stats.py deleted file mode 100644 index 68a467a43..000000000 --- a/extras/merge_and_stats.py +++ /dev/null @@ -1,242 +0,0 @@ -import pandas as pd - - -# MERGING THE DATA - - -filenames=[] -# merged_data = {} -def parse_csv_and_merge(csv_files, output_file='merged_data.csv'): - """ - Merges CSV files, handling multiline entries and various error conditions. - - Args: - csv_files (list): List of tuples containing (filename, implementation_name). - output_file (str, optional): Name of the output CSV file. Defaults to 'merged_data.csv'. - """ - - # merged_data = pd.DataFrame(columns=['Filename']) - merged_data={} - is_multiline = False - multiline_data = [] - curr_file="" - for file, implementation in csv_files: - print(f"Starting File : {file}") - try: - df = pd.read_csv(file) - except FileNotFoundError: - print(f"Error: File '{file}' not found. Skipping...") - continue - - for i, row in df.iterrows(): - if is_multiline: - # Handling multiline entries (Before standard algorithm call) - if 'After standard algorithm call' in row.values[0]: - is_multiline = True - continue - elif row.values[1] == "Error": - row.fillna(0, inplace=True) - row['Status'] = 'Error' - row.values[0]= curr_file - row.values[1] = 0 - is_multiline=False - filename = row['Filename'] - if filename not in merged_data: - merged_data[filename] = row.to_dict() - else: - for col in df.columns: - if col != 'Filename' and not pd.isna(row[col]): - merged_data[filename][col+"_"+implementation] = row[col] - elif row.values[0] == "Invalid Output by algorithm": - is_multiline = True - continue - else: - is_multiline = False - prev_item=curr_file - filenames.append(curr_file) - temp_item=row.values[0] - temp_len=row.values.size - for i in range(1,temp_len): - # print(temp_item) - temp_item=row.values[i-1] - row.values[i-1]=prev_item - prev_item=temp_item - # print(row) - filename = row['Filename'] - if filename not in merged_data: - merged_data[filename] = row.to_dict() - else: - for col in df.columns: - if col != 'Filename' and not pd.isna(row[col]): - merged_data[filename][col+"_"+implementation] = row[col] - else: - # Handling single-line entries or first line of multiline entries - # Checking for timeout or error - if pd.isna(row['VolManifold']): - if (row['VolHull']=="Timeout"): - # if 'Timeout' in row['Status']: - row['VolHull']=0 - row['VolManifold'] = 0 - row.fillna(0, inplace=True) - row['Status'] = 'Timeout' - elif 'Error' in row['Status']: - row.fillna(0, inplace=True) - row['Status'] = 'Error' - elif (row['VolHull'] == "Error"): - row.fillna(0, inplace=True) - row['Status'] = 'Error' - pass - filename = row['Filename'] - if filename not in merged_data: - merged_data[filename] = row.to_dict() - else: - for col in df.columns: - if col != 'Filename' and not pd.isna(row[col]): - merged_data[filename][col+"_"+implementation] = row[col] - continue - # Converting Series to df for renaming columns - if 'Before standard algorithm call' in row.values[1]: - if row.values[2] == "Timeout": - row.fillna(0, inplace=True) - row['Status'] = 'Timeout' - row['VolHull']=0 - row['VolManifold'] = 0 - filename = row['Filename'] - if filename not in merged_data: - merged_data[filename] = row.to_dict() - else: - for col in df.columns: - if col != 'Filename' and not pd.isna(row[col]): - merged_data[filename][col+"_"+implementation] = row[col] - continue - is_multiline = True - curr_file=row.values[0] - else: - if (row['VolManifold']=="timeout: the monitored command dumped core"): - row.fillna(0, inplace=True) - row['VolManifold']=0 - row['VolHull'] = 0 - row['Status'] = 'Error' - filename = row['Filename'] - if filename not in merged_data: - merged_data[filename] = row.to_dict() - else: - # print(merged_data[filename]) - for col in df.columns: - if col != 'Filename' and not pd.isna(row[col]): - merged_data[filename][col+"_"+implementation] = row[col] - - # multiline_data.append(row.tolist()) - # print(merged_data) - - if not merged_data: - print("Warning: No valid data found in any CSV files.") - return - - # Creating df from the dictionary to store the merged data - merged_data = pd.DataFrame.from_dict(merged_data, orient='index') - - merged_data.to_csv(output_file, index=False) - -csv_files = [('Hull1.csv','hull1'),('CGAL.csv', 'CGAL')] -parse_csv_and_merge(csv_files) - - -# NORMALIZE THE DATA - - -file_path = 'merged_data.csv' -df = pd.read_csv(file_path) - -time_columns = [col for col in df.columns if 'Time' in col] -for col in time_columns: - df[col] = df[col].str.replace(' sec', '').astype(float) - -# List of base columns to normalize against -base_columns = ['VolManifold', 'VolHull', 'AreaManifold', 'AreaHull', 'ManifoldTri', 'HullTri', 'Time'] -# List of suffixes to normalize -suffixes = ['_CGAL'] -# for suffix in suffixes : -# For time metric avoiding cases with time less than 0.001 seconds -# df = df[(df['Time'] > 0.001)] -# Normalize the columns and check for zero base values -stl_files_with_diff = [] - -for base in base_columns: - base_col = base - if base_col in df.columns: - for suffix in suffixes: - col_name = f"{base}{suffix}" - if col_name in df.columns: - # Checking if base column is zero and suffix column is not zero - zero_base_nonzero_suffix = (df[base_col] == 0) & (df[col_name] != 0) - if zero_base_nonzero_suffix.any(): - raise ValueError(f"Error: {base_col} is zero while {col_name} is not zero in row(s): {df[zero_base_nonzero_suffix].index.tolist()}") - - # Setting col_name column in df to 1 if both are zero - both_zero = (df[base_col] == 0) & (df[col_name] == 0) - df.loc[both_zero, col_name] = 1 - - # Normalizing the column while handling division by zero - df[col_name] = df[col_name] / df[base_col].replace({0: 1}) - - df[base_col] = 1.0 - - -df.to_csv('normalized_output.csv', index=False) - - -# CALCULATE STATISTICS ON NORMALZIED OUTPUT - - -import pandas as pd - -file_path = 'normalized_output.csv' -df = pd.read_csv(file_path) - -# Columns for statistics calculation -columns = ['VolHull', 'AreaHull', 'HullTri', 'Time'] -# Columns suffixes to use -suffixes = ['', '_CGAL'] - -# Function to calculate statistics for each base and implementation -def calculate_stats(column, status,suffix): - filtered_df = df[(df['Status'+suffix] == status) & ~df[column].isnull()] - # filtered_df = df[(df['Status'+suffix] == status) & ~df[column].isnull() & (df['Time'+suffix] > 0.001) & (df['Time'] > 0.001)] - success_count = filtered_df.shape[0] - - if success_count > 0: - mean_val = filtered_df[column].mean() - median_val = filtered_df[column].median() - mode_val = filtered_df[column].mode().iloc[0] if not filtered_df[column].mode().empty else None - max_val = filtered_df[column].max() - min_val = filtered_df[column].min() - else: - mean_val = median_val = mode_val = max_val = min_val = None - - return mean_val, median_val, mode_val, max_val, min_val, success_count - -stats_dict = {} - -# Calculating stats for each column and their suffixes -for base in columns: - for suffix in suffixes: - col_name = f"{base}{suffix}" - if col_name in df.columns: - mean_val, median_val, mode_val, max_val, min_val, success_count = calculate_stats(col_name, 'Success',suffix) - stats_dict[col_name] = { - 'mean': mean_val, - 'median': median_val, - 'mode': mode_val, - 'max': max_val, - 'min': min_val, - 'Success_Count': success_count - } - -# Converting the stats dictionary to a df for better visualization -stats_df = pd.DataFrame(stats_dict).T - -stats_df.to_csv('statistics_output.csv') - -print("Statistics calculation complete. Output saved to 'statistics_output.csv'.") -print(stats_df) diff --git a/extras/perf_test_cgal.cpp b/extras/perf_test_cgal.cpp deleted file mode 100644 index 0f61e3e6c..000000000 --- a/extras/perf_test_cgal.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2022 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include - -#include -#include -#include - -#include "manifold/manifold.h" - -using namespace manifold; - -// Epick = Exact predicates Inexact constructions. Seems fair to use to compare -// to Manifold, which seems to store double coordinates. -typedef CGAL::Epick Kernel; - -// Epeck = Exact predicates Exact constructions. What OpenSCAD uses to guarantee -// geometry ends up where it should even after many operations. typedef -// CGAL::Epeck Kernel; - -typedef CGAL::Point_3 Point; -typedef CGAL::Surface_mesh TriangleMesh; -typedef CGAL::SM_Vertex_index Vertex; - -void manifoldToCGALSurfaceMesh(Manifold &manifold, TriangleMesh &cgalMesh) { - auto maniMesh = manifold.GetMesh(); - - const size_t n = maniMesh.vertPos.size(); - std::vector vertices(n); - for (size_t i = 0; i < n; i++) { - auto &vert = maniMesh.vertPos[i]; - vertices[i] = cgalMesh.add_vertex(Point(vert.x, vert.y, vert.z)); - } - - for (auto &triVert : maniMesh.triVerts) { - std::vector polygon{vertices[triVert[0]], vertices[triVert[1]], - vertices[triVert[2]]}; - cgalMesh.add_face(polygon); - } -} - -int main(int argc, char **argv) { - for (int i = 0; i < 8; ++i) { - Manifold sphere = Manifold::Sphere(1, (8 << i) * 4); - Manifold sphere2 = sphere.Translate(vec3(0.5)); - - TriangleMesh cgalSphere, cgalSphere2; - manifoldToCGALSurfaceMesh(sphere, cgalSphere); - manifoldToCGALSurfaceMesh(sphere2, cgalSphere2); - - auto start = std::chrono::high_resolution_clock::now(); - auto result = - CGAL::Polygon_mesh_processing::corefine_and_compute_difference( - // CGAL::Polygon_mesh_processing::corefine_and_compute_union( - // CGAL::Polygon_mesh_processing::corefine_and_compute_intersection( - cgalSphere, cgalSphere2, cgalSphere); - - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - std::cout << "nTri = " << sphere.NumTri() << ", time = " << elapsed.count() - << " sec" << std::endl; - } -} diff --git a/extras/run.sh b/extras/run.sh deleted file mode 100755 index 2b5eb8b6f..000000000 --- a/extras/run.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# Go to manifold/extras directory and run the command as `./run.sh {path_to_dataset_folder} {name_of_csv} {implementation(Hull,Hull_CGAL)}` -# example ./run.sh ./Thingi10K/raw_meshes/ Hull4.csv Hull - -# Checking if the correct number of arguments is provided -if [ "$#" -ne 3 ]; then - echo "Usage: $0 " - exit 1 -fi - -EXECUTABLE="../build/extras/testHullPerformance" -INPUT_FOLDER=$1 -OUTPUT_CSV=$2 -IMPLEMENTATION=$3 -TIME_LIMIT=10m # time limit in minutes -RAM_LIMIT=6000 # Memory limit in MB - -# Initializing the headers -echo "Filename,VolManifold,VolHull,AreaManifold,AreaHull,ManifoldTri,HullTri,Time,Status," > $OUTPUT_CSV - -# Iterate over all files in the input folder -for INPUT_FILE in "$INPUT_FOLDER"/*; do - FILE_NAME=$(basename "$INPUT_FILE") - - # Run the EXECUTABLE with the specified argument, time limit, and used to capture the output - OUTPUT=$(ulimit -v $((RAM_LIMIT * 1024)); timeout $TIME_LIMIT $EXECUTABLE "Input" "$IMPLEMENTATION" "0" "$INPUT_FILE" 2>&1) - STATUS=$? - - # Checking if the EXECUTABLE timed out - if [ $STATUS -eq 124 ]; then - STATUS="Timeout" - elif [ $STATUS -ne 0 ]; then - STATUS="Error" - else - STATUS="Success" - fi - - # Adding the result to the output file - echo "\"$FILE_NAME\",$OUTPUT,\"$STATUS\"" >> $OUTPUT_CSV -done diff --git a/extras/test_hull_performance.cpp b/extras/test_hull_performance.cpp deleted file mode 100644 index 8df799576..000000000 --- a/extras/test_hull_performance.cpp +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2022 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include // For string manipulation - -#include "manifold/manifold.h" -#include "manifold/meshIO.h" -#include "samples.h" -using namespace std; -using namespace manifold; - -// Epick = Exact predicates Inexact constructions. Seems fair to use to compare -// to Manifold, which seems to store double coordinates. -typedef CGAL::Epick Kernel; - -// Epeck = Exact predicates Exact constructions. What OpenSCAD uses to guarantee -// geometry ends up where it should even after many operations. typedef -// CGAL::Epeck Kernel; - -typedef CGAL::Point_3 Point; -typedef CGAL::Surface_mesh TriangleMesh; -typedef CGAL::SM_Vertex_index Vertex; - -class HullImpl { - public: - // actual hull operation, we will measure the time needed to evaluate this - // function. - virtual void hull(const manifold::Manifold &input, - const std::vector &pts) = 0; - virtual ~HullImpl() = default; - -#ifdef MANIFOLD_DEBUG - // Check if the mesh remains convex after adding new faces - bool isMeshConvex() { - // Get the mesh from the manifold - manifold::Mesh mesh = hullManifold.GetMesh(); - - const auto &vertPos = mesh.vertPos; - - // Iterate over each triangle - for (const auto &tri : mesh.triVerts) { - // Get the vertices of the triangle - vec3 v0 = vertPos[tri[0]]; - vec3 v1 = vertPos[tri[1]]; - vec3 v2 = vertPos[tri[2]]; - - // Compute the normal of the triangle - vec3 normal = la::normalize(la::cross(v1 - v0, v2 - v0)); - - // Check all other vertices - for (int i = 0; i < (int)vertPos.size(); ++i) { - if (i == tri[0] || i == tri[2] || i == tri[3]) - continue; // Skip vertices of the current triangle - - // Get the vertex - vec3 v = vertPos[i]; - - // Compute the signed distance from the plane - double distance = la::dot(normal, v - v0); - - // If any vertex lies on the opposite side of the normal direction - if (distance > 0) { - // The manifold is not convex - return false; - } - } - } - // If we didn't find any vertex on the opposite side for any triangle, it's - // convex - return true; - } -#endif - - protected: - manifold::Manifold hullManifold; - manifold::Manifold inputManifold; -}; - -class HullImplOriginal : public HullImpl { - public: - void hull(const manifold::Manifold &input, - const std::vector &pts) override { - inputManifold = input; - auto start = std::chrono::high_resolution_clock::now(); - hullManifold = Manifold::Hull(pts); - auto end = std::chrono::high_resolution_clock::now(); - PrintVolArea(); - std::chrono::duration elapsed = end - start; - std::cout << elapsed.count() << " sec"; - } - - private: - // Prints the volume and area of the manifold and the convex hull of our - // implementation, - void PrintVolArea() { - std::cout << inputManifold.GetProperties().volume << ","; - std::cout << hullManifold.GetProperties().volume << ","; - std::cout << inputManifold.GetProperties().surfaceArea << ","; - std::cout << hullManifold.GetProperties().surfaceArea << ","; - std::cout << inputManifold.NumTri() << ","; - std::cout << hullManifold.NumTri() << ","; - return; - } -}; - -class HullImplCGAL : public HullImpl { - private: - // Converts Manfiold to CGAL Surface Mesh - void manifoldToCGALSurfaceMesh(Manifold &manifold, TriangleMesh &cgalMesh) { - auto maniMesh = manifold.GetMesh(); - - const size_t n = maniMesh.vertPos.size(); - std::vector vertices(n); - for (size_t i = 0; i < n; i++) { - auto &vert = maniMesh.vertPos[i]; - vertices[i] = cgalMesh.add_vertex(Point(vert.x, vert.y, vert.z)); - } - - for (auto &triVert : maniMesh.triVerts) { - std::vector polygon{vertices[triVert[0]], vertices[triVert[1]], - vertices[triVert[2]]}; - cgalMesh.add_face(polygon); - } - } - // Converts CGAL Surface Mesh to Manifold - void CGALToManifoldSurfaceMesh(TriangleMesh &cgalMesh, Manifold &manifold) { - Mesh mesh; - mesh.triVerts.reserve(faces(cgalMesh).size() * 3); - for (auto v : vertices(cgalMesh)) { - auto pt = cgalMesh.point(v); - mesh.vertPos.push_back({pt.x(), pt.y(), pt.z()}); - } - for (auto f : faces(cgalMesh)) { - vector::size_type> verts; - for (auto v : vertices_around_face(cgalMesh.halfedge(f), cgalMesh)) { - verts.push_back(v.idx()); - } - mesh.triVerts.push_back({verts[0], verts[1], verts[2]}); - } - manifold = Manifold(mesh); - } - // Prints the volume and area of the manifold and Convex Hull of CGAL - // Implementation - void PrintVolAreaCGAL() { - std::cout << CGAL::Polygon_mesh_processing::volume(cgalInput) << ","; - std::cout << CGAL::Polygon_mesh_processing::volume(cgalHull) << ","; - std::cout << CGAL::Polygon_mesh_processing::area(cgalInput) << ","; - std::cout << CGAL::Polygon_mesh_processing::area(cgalHull) << ","; - std::cout << std::distance(cgalInput.faces_begin(), cgalInput.faces_end()) - << ","; - std::cout << std::distance(cgalHull.faces_begin(), cgalHull.faces_end()) - << ","; - return; - } - TriangleMesh cgalHull, cgalInput; - - public: - // This was the code where I converted the CGAL Hull back to manifold, but I - // thought that added overhead, so if needed we can also use the functions of - // the library to print the output as well void hull(const - // std::vector& pts) { - // std::vector points; - // for (const auto &vert : pts) { - // points.push_back(Point(vert.x, vert.y, vert.z)); - // } - // // Convex Hull - // CGAL::convex_hull_3(points.begin(), points.end(), cgalHull); - // CGALToManifoldSurfaceMesh(cgalHull, hullManifold); - // } - void hull(const manifold::Manifold &input, - const std::vector &pts) override { - inputManifold = input; - manifoldToCGALSurfaceMesh(inputManifold, cgalInput); - std::vector points; - for (const auto &vert : cgalInput.vertices()) { - points.push_back(cgalInput.point(vert)); - } - // Convex Hull - auto start = std::chrono::high_resolution_clock::now(); - CGAL::convex_hull_3(points.begin(), points.end(), cgalHull); - auto end = std::chrono::high_resolution_clock::now(); - PrintVolAreaCGAL(); - std::chrono::duration elapsed = end - start; - std::cout << elapsed.count() << " sec"; - } -}; - -// Constructs a Menger Sponge, and tests the convex hull implementation on it -// (you can pass the specific hull implementation to be tested). Comparing the -// volume and surface area with CGAL implementation, for various values of -// rotation -void MengerTestHull(HullImpl *impl, double rx, double ry, double rz, - char *implementation) { - if (impl == NULL) return; - Manifold sponge = MengerSponge(4); - sponge = sponge.Rotate(rx, ry, rz); - impl->hull(sponge, sponge.GetMesh().vertPos); -} - -// Constructs a high quality sphere, and tests the convex hull implementation on -// it (you can pass the specific hull implementation to be tested). Comparing -// the volume and surface area with CGAL implementation -void SphereTestHull(HullImpl *impl, char *implementation) { - if (impl == NULL) return; - Manifold sphere = Manifold::Sphere(1, 6000); - sphere = sphere.Translate(vec3(0.5)); - impl->hull(sphere, sphere.GetMesh().vertPos); -} - -int main(int argc, char **argv) { - if (argc < 4) { - std::cout << "Usage: ./test_hull_performance " - " " - " " - << std::endl; - return 0; - } - if (!strcmp(argv[3], "1")) - std::cout - << "VolManifold,VolHull,AreaManifold,AreaHull,ManifoldTri,HullTri,Time" - << std::endl; - - HullImpl *hullImpl = NULL; - if (!strcmp(argv[2], "Hull")) - hullImpl = new HullImplOriginal(); - else if (!strcmp(argv[2], "Hull_CGAL")) - hullImpl = new HullImplCGAL(); - else { - std::cout << "Invalid Implementation"; - return 0; - } - if (!strcmp(argv[1], "Sphere")) - SphereTestHull(hullImpl, argv[2]); - else if (!strcmp(argv[1], "Menger")) - MengerTestHull(hullImpl, 1, 2, 3, argv[2]); - else if (!strcmp(argv[1], "Input")) { - auto inputMesh = ImportMesh(argv[4], 1); - Manifold inputManifold = Manifold(inputMesh); - hullImpl->hull(inputManifold, inputManifold.GetMesh().vertPos); -#ifdef MANIFOLD_DEBUG - if (!hullImpl->isMeshConvex()) cout << "INVALID HULL" << endl; -#endif - } -}