mirror of https://github.com/CGAL/cgal
Merge pull request #8744 from LeoValque/PMP_triangle_soup_rounding-GF
Add do_snap parameter to PMP::autorefine_triangle_soup
This commit is contained in:
commit
27a7cef2fb
|
|
@ -152087,6 +152087,18 @@ keywords = {polygonal surface mesh, Surface reconstruction, kinetic framework, s
|
||||||
publisher={Elsevier}
|
publisher={Elsevier}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@unpublished{lazard:hal-04907149,
|
||||||
|
TITLE = {{Removing self-intersections in 3D meshes while preserving floating-point coordinates}},
|
||||||
|
AUTHOR = {Lazard, Sylvain and Valque, Leo},
|
||||||
|
URL = {https://inria.hal.science/hal-04907149},
|
||||||
|
NOTE = {working paper or preprint},
|
||||||
|
YEAR = {2025},
|
||||||
|
MONTH = Jan,
|
||||||
|
KEYWORDS = {Snap rounding ; mesh intersection ; robustness},
|
||||||
|
PDF = {https://inria.hal.science/hal-04907149v1/file/Snap-HAL.pdf},
|
||||||
|
HAL_ID = {hal-04907149},
|
||||||
|
HAL_VERSION = {v1},
|
||||||
|
}
|
||||||
|
|
||||||
@inproceedings{si2005meshing,
|
@inproceedings{si2005meshing,
|
||||||
title={Meshing piecewise linear complexes by constrained {Delaunay} tetrahedralizations},
|
title={Meshing piecewise linear complexes by constrained {Delaunay} tetrahedralizations},
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
- New implementation of `CGAL::Polygon_mesh_processing::clip()` with a plane as clipper that is much faster and is now able to handle non-triangulated surface meshes.
|
- New implementation of `CGAL::Polygon_mesh_processing::clip()` with a plane as clipper that is much faster and is now able to handle non-triangulated surface meshes.
|
||||||
- New implementation of `CGAL::Polygon_mesh_processing::split()` with a plane as clipper that is much faster and is now able to handle non-triangulated surface meshes.
|
- New implementation of `CGAL::Polygon_mesh_processing::split()` with a plane as clipper that is much faster and is now able to handle non-triangulated surface meshes.
|
||||||
- Added the function `CGAL::Polygon_mesh_processing::refine_with_plane()`, which enables users to refine a mesh with their intersection with a plane.
|
- Added the function `CGAL::Polygon_mesh_processing::refine_with_plane()`, which enables users to refine a mesh with their intersection with a plane.
|
||||||
|
- Added the parameter `apply_iterative_snap_rounding` to the function `CGAL::Polygon_mesh_processing::autorefine_triangle_soup()`. When set to `true`, the coordinates are rounded to fit in double and may perform additional subdivisions to ensure the output is free of self-intersections.
|
||||||
|
|
||||||
### [Point Set Processing](https://doc.cgal.org/6.1/Manual/packages.html#PkgPointSetProcessing3)
|
### [Point Set Processing](https://doc.cgal.org/6.1/Manual/packages.html#PkgPointSetProcessing3)
|
||||||
- Added `poisson_eliminate()` to downsample a point cloud to a target size while providing Poisson disk property, i.e., a larger minimal distance between points.
|
- Added `poisson_eliminate()` to downsample a point cloud to a target size while providing Poisson disk property, i.e., a larger minimal distance between points.
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,21 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
create_single_source_cgal_program("fast.cpp")
|
create_single_source_cgal_program("fast.cpp")
|
||||||
|
create_single_source_cgal_program("rotated_cubes_autorefinement.cpp")
|
||||||
|
create_single_source_cgal_program("coplanar_cubes_autorefinement.cpp")
|
||||||
|
|
||||||
|
create_single_source_cgal_program("Performance/performance_snap_polygon_soup.cpp")
|
||||||
|
create_single_source_cgal_program("Robustness/robustness_snap_polygon_soup.cpp")
|
||||||
|
create_single_source_cgal_program("Quality/quality_snap_polygon_soup.cpp")
|
||||||
|
|
||||||
create_single_source_cgal_program("polygon_mesh_slicer.cpp")
|
create_single_source_cgal_program("polygon_mesh_slicer.cpp")
|
||||||
target_link_libraries(polygon_mesh_slicer PRIVATE CGAL::Eigen3_support)
|
target_link_libraries(polygon_mesh_slicer PRIVATE CGAL::Eigen3_support)
|
||||||
|
|
||||||
|
find_package(TBB QUIET)
|
||||||
|
include(CGAL_TBB_support)
|
||||||
|
if(TARGET CGAL::TBB_support)
|
||||||
|
target_link_libraries(rotated_cubes_autorefinement PRIVATE CGAL::TBB_support)
|
||||||
|
target_link_libraries(coplanar_cubes_autorefinement PRIVATE CGAL::TBB_support)
|
||||||
|
else()
|
||||||
|
message(STATUS "NOTICE: Intel TBB was not found. Sequential code will be used.")
|
||||||
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/autorefinement.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||||
|
#include <CGAL/IO/polygon_soup_io.h>
|
||||||
|
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||||
|
typedef typename Kernel::Point_3 Point_3;
|
||||||
|
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||||
|
|
||||||
|
enum EXIT_CODES { VALID_OUTPUT=0,
|
||||||
|
INVALID_INPUT=1,
|
||||||
|
ROUNDING_FAILED=2,
|
||||||
|
SIGSEGV=10,
|
||||||
|
SIGSABRT=11,
|
||||||
|
SIGFPE=12,
|
||||||
|
TIMEOUT=13
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if(argc<4){
|
||||||
|
std::cout << "Invalid argument" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string filename = std::string(argv[1]);
|
||||||
|
const int grid_size = std::stoi(std::string(argv[2]));
|
||||||
|
const bool erase_duplicate = std::stoi(argv[3])==1;
|
||||||
|
|
||||||
|
std::vector<Point_3> points;
|
||||||
|
std::vector<boost::container::small_vector<std::size_t, 3>> triangles;
|
||||||
|
|
||||||
|
if (!CGAL::IO::read_polygon_soup(filename, points, triangles))
|
||||||
|
{
|
||||||
|
std::cerr << "Cannot read " << filename << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PMP::repair_polygon_soup(points, triangles);
|
||||||
|
PMP::triangulate_polygons(points, triangles);
|
||||||
|
|
||||||
|
PMP::autorefine_triangle_soup(points, triangles, CGAL::parameters::apply_iterative_snap_rounding(true).erase_all_duplicates(erase_duplicate).concurrency_tag(CGAL::Parallel_if_available_tag()).snap_grid_size(grid_size).number_of_iterations(15));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$#" -lt 4 ]; then
|
||||||
|
echo "Usage: $0 <input_file> <timeout> [component_params...]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
INPUT_FILE=$1
|
||||||
|
TIMEOUT=$2
|
||||||
|
GRID_SIZE=$3
|
||||||
|
ERASE_ALL_DUPLICATE=$4
|
||||||
|
|
||||||
|
# Use /usr/bin/time for memory usage (maximum resident set size in KB)
|
||||||
|
TMP_LOG=$(mktemp)
|
||||||
|
|
||||||
|
# Run the benchmarked command
|
||||||
|
/usr/bin/time -f "TIME:%e\nMEM:%M" timeout "$TIMEOUT"s performance_snap_polygon_soup "$INPUT_FILE" "$GRID_SIZE" "$ERASE_ALL_DUPLICATE" 2> "$TMP_LOG"
|
||||||
|
|
||||||
|
# Parse time and memory
|
||||||
|
SECONDS=$(grep "TIME" "$TMP_LOG" | cut -d':' -f2)
|
||||||
|
MEMORY=$(grep "MEM" "$TMP_LOG" | cut -d':' -f2)
|
||||||
|
|
||||||
|
rm -f "$TMP_LOG"
|
||||||
|
|
||||||
|
# Output JSON
|
||||||
|
echo "{\"seconds\": \"$SECONDS\", \"memory_peaks\": \"$MEMORY\"}"
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/autorefinement.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/distance.h>
|
||||||
|
#include <CGAL/IO/polygon_soup_io.h>
|
||||||
|
|
||||||
|
#include <CGAL/Bbox_3.h>
|
||||||
|
#include <CGAL/boost/graph/helpers.h>
|
||||||
|
|
||||||
|
#include <CGAL/Surface_mesh.h>
|
||||||
|
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/orientation.h>
|
||||||
|
|
||||||
|
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||||
|
typedef typename Kernel::Point_3 Point_3;
|
||||||
|
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if(argc<4){
|
||||||
|
std::cout << "Invalid argument" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const std::string filename = std::string(argv[1]);
|
||||||
|
const int grid_size = std::stoi(std::string(argv[2]));
|
||||||
|
const bool erase_duplicate = std::stoi(argv[3])==1;
|
||||||
|
|
||||||
|
std::vector<Point_3> points;
|
||||||
|
std::vector<boost::container::small_vector<std::size_t, 3>> triangles;
|
||||||
|
|
||||||
|
CGAL::Bbox_3 bb = CGAL::bbox_3(points.begin(), points.end());
|
||||||
|
double diag_length=std::sqrt((bb.xmax()-bb.xmin())*(bb.xmax()-bb.xmin()) + (bb.ymax()-bb.ymin())*(bb.ymax()-bb.ymin()) + (bb.zmax()-bb.zmin())*(bb.zmax()-bb.zmin()));
|
||||||
|
if (!CGAL::IO::read_polygon_soup(filename, points, triangles))
|
||||||
|
{
|
||||||
|
std::cerr << "Cannot read " << filename << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Point_3> input_points(points.begin(), points.end());
|
||||||
|
|
||||||
|
PMP::autorefine_triangle_soup(points, triangles, CGAL::parameters::apply_iterative_snap_rounding(true).erase_all_duplicates(erase_duplicate).concurrency_tag(CGAL::Parallel_if_available_tag()).snap_grid_size(grid_size).number_of_iterations(15));
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << "{" <<
|
||||||
|
"\"Nb_output_points\": \"" << points.size() << "\",\n" <<
|
||||||
|
"\"Nb_output_triangles\": \"" << triangles.size() << "\",\n" <<
|
||||||
|
"\"Is_2_manifold\": \"" << (PMP::orient_polygon_soup(points, triangles)?"True":"False") << "\",\n";
|
||||||
|
CGAL::Surface_mesh<Point_3> sm;
|
||||||
|
PMP::polygon_soup_to_polygon_mesh(points, triangles, sm);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(17) <<
|
||||||
|
"\"Hausdorff_distance_output_to_input_(divide_by_bbox_diag)\": \"" << PMP::max_distance_to_triangle_mesh<CGAL::Parallel_if_available_tag>(input_points, sm) / diag_length << "\",\n" <<
|
||||||
|
"\"Closed_output\": \"" << (CGAL::is_closed(sm)?"True":"False") << "\",\n" <<
|
||||||
|
"\"Ouput_bound_a_volume\": \"" << (PMP::does_bound_a_volume(sm)?"True":"False") << "\"\n}"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$#" -lt 4 ]; then
|
||||||
|
echo "Usage: $0 <input_file> <timeout> [component_params...]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
INPUT_FILE=$1
|
||||||
|
TIMEOUT=$2
|
||||||
|
GRID_SIZE=$3
|
||||||
|
ERASE_ALL_DUPLICATE=$4
|
||||||
|
|
||||||
|
TMP_LOG=$(mktemp)
|
||||||
|
timeout "$TIMEOUT"s quality_snap_polygon_soup "$INPUT_FILE" "$GRID_SIZE" "$ERASE_ALL_DUPLICATE" > "$TMP_LOG"
|
||||||
|
|
||||||
|
cat $TMP_LOG
|
||||||
|
rm -f "$TMP_LOG"
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/autorefinement.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||||
|
#include <CGAL/IO/polygon_soup_io.h>
|
||||||
|
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||||
|
typedef typename Kernel::Point_3 Point_3;
|
||||||
|
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||||
|
|
||||||
|
enum EXIT_CODES { VALID_OUTPUT=0,
|
||||||
|
INVALID_INPUT=1,
|
||||||
|
ROUNDING_FAILED=2,
|
||||||
|
SELF_INTERSECTING_OUTPUT=3,
|
||||||
|
SIGSEGV=10,
|
||||||
|
SIGSABRT=11,
|
||||||
|
SIGFPE=12,
|
||||||
|
TIMEOUT=13
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if(argc<4){
|
||||||
|
std::cout << "Invalid argument" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string filename = std::string(argv[1]);
|
||||||
|
const int grid_size = std::stoi(std::string(argv[2]));
|
||||||
|
const bool erase_duplicate = std::stoi(argv[3])==1;
|
||||||
|
|
||||||
|
std::vector<Point_3> points;
|
||||||
|
std::vector<boost::container::small_vector<std::size_t, 3>> triangles;
|
||||||
|
|
||||||
|
if (!CGAL::IO::read_polygon_soup(filename, points, triangles) || points.size()==0 || triangles.size()==0)
|
||||||
|
{
|
||||||
|
return INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
PMP::repair_polygon_soup(points, triangles);
|
||||||
|
PMP::triangulate_polygons(points, triangles);
|
||||||
|
|
||||||
|
bool success=PMP::autorefine_triangle_soup(points, triangles, CGAL::parameters::apply_iterative_snap_rounding(true).erase_all_duplicates(erase_duplicate).concurrency_tag(CGAL::Parallel_if_available_tag()).snap_grid_size(grid_size).number_of_iterations(15));
|
||||||
|
|
||||||
|
if(!success)
|
||||||
|
return ROUNDING_FAILED;
|
||||||
|
if( PMP::does_triangle_soup_self_intersect<CGAL::Parallel_if_available_tag>(points, triangles) )
|
||||||
|
return SELF_INTERSECTING_OUTPUT;
|
||||||
|
|
||||||
|
return VALID_OUTPUT;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ "$#" -lt 4 ]; then
|
||||||
|
echo "Usage: $0 <input_file> <timeout> [component_params...]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
timeout_bis() {
|
||||||
|
timeout 5 sleep 10
|
||||||
|
}
|
||||||
|
|
||||||
|
INPUT_FILE=$1
|
||||||
|
TIMEOUT=$2
|
||||||
|
GRID_SIZE=$3
|
||||||
|
ERASE_ALL_DUPLICATE=$4
|
||||||
|
|
||||||
|
# Run with timeout, capture exit code
|
||||||
|
timeout "--foreground" "$TIMEOUT"s robustness_snap_polygon_soup "$INPUT_FILE" "$GRID_SIZE" "$ERASE_ALL_DUPLICATE"
|
||||||
|
EXIT_CODE=$?
|
||||||
|
|
||||||
|
# Interpret exit codes
|
||||||
|
declare -A TAGS
|
||||||
|
TAGS[0]="VALID_OUTPUT"
|
||||||
|
TAGS[1]="INPUT_IS_INVALID"
|
||||||
|
TAGS[2]="ROUNDING_FAILED"
|
||||||
|
TAGS[3]="SELF_INTERSECTING_OUTPUT"
|
||||||
|
TAGS[139]="SIGSEGV"
|
||||||
|
TAGS[11]="SIGSEGV"
|
||||||
|
TAGS[6]="SIGABRT"
|
||||||
|
TAGS[8]="SIGFPE"
|
||||||
|
TAGS[132]="SIGILL"
|
||||||
|
TAGS[124]="TIMEOUT"
|
||||||
|
|
||||||
|
TAG_NAME=${TAGS[$EXIT_CODE]:-UNKNOWN}
|
||||||
|
TAG_DESC=$([[ "$EXIT_CODE" -eq 0 ]] && echo "OK" || echo "Error")
|
||||||
|
|
||||||
|
# Output JSON
|
||||||
|
echo "{\"TAG_NAME\": \"$TAG_NAME\", \"TAG\": \"$TAG_DESC\"}"
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Temp directory for individual result JSONs
|
||||||
|
TMP_RESULT_DIR=$(mktemp -d)
|
||||||
|
|
||||||
|
# Job control
|
||||||
|
JOBS=0
|
||||||
|
MAX_JOBS=$NUM_THREADS
|
||||||
|
|
||||||
|
# Function to process a single file
|
||||||
|
process_file() {
|
||||||
|
INPUT_PATH="$1"
|
||||||
|
INPUT_ID=$(basename "$INPUT_PATH" | cut -d. -f1)
|
||||||
|
COMPONENT_NAME="$2"
|
||||||
|
PROJECT_DIR="$3"
|
||||||
|
TIMEOUT="$4"
|
||||||
|
OUTPUT_DIR="$5"
|
||||||
|
TMP_RESULT_FILE="$6"
|
||||||
|
GRID_SIZE="$7"
|
||||||
|
ERASE_ALL_DUPLICATE="$8"
|
||||||
|
{
|
||||||
|
echo " \"$INPUT_ID\": {"
|
||||||
|
echo " \"path\": \"$INPUT_PATH\","
|
||||||
|
|
||||||
|
PERF_OUTPUT=$(bash "$PROJECT_DIR/Performance/run_performance.sh" "$INPUT_PATH" "$TIMEOUT" "$GRID_SIZE" "$ERASE_ALL_DUPLICATE" 2>> "$OUTPUT_DIR/Logs/$COMPONENT_NAME/Performance/$INPUT_ID.log")
|
||||||
|
echo " \"Performance\": $PERF_OUTPUT,"
|
||||||
|
|
||||||
|
QUALITY_OUTPUT=$(bash "$PROJECT_DIR/Quality/run_quality.sh" "$INPUT_PATH" "$TIMEOUT" "$GRID_SIZE" "$ERASE_ALL_DUPLICATE" 2>> "$OUTPUT_DIR/Logs/$COMPONENT_NAME/Quality/$INPUT_ID.log")
|
||||||
|
echo " \"Quality\": $QUALITY_OUTPUT,"
|
||||||
|
|
||||||
|
ROBUST_OUTPUT=$(bash "$PROJECT_DIR/Robustness/run_robustness.sh" "$INPUT_PATH" "$TIMEOUT" "$GRID_SIZE" "$ERASE_ALL_DUPLICATE" 2>> "$OUTPUT_DIR/Logs/$COMPONENT_NAME/Robustness/$INPUT_ID.log")
|
||||||
|
echo " \"Robustness\": $ROBUST_OUTPUT"
|
||||||
|
|
||||||
|
echo " }"
|
||||||
|
} > "$TMP_RESULT_FILE"
|
||||||
|
}
|
||||||
|
export -f process_file
|
||||||
|
|
||||||
|
# Usage function
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 <project_dir> <input_data_dir> <output_results_dir> <timeout> <num_threads> [component_params...]"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check parameters
|
||||||
|
if [ "$#" -lt 5 ]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
PROJECT_DIR=$1
|
||||||
|
INPUT_DIR=$2
|
||||||
|
OUTPUT_DIR=$3
|
||||||
|
TIMEOUT=$4
|
||||||
|
NUM_THREADS=$5
|
||||||
|
GRID_SIZE=$6
|
||||||
|
ERASE_ALL_DUPLICATE=$7
|
||||||
|
|
||||||
|
# Get component name from the project directory name
|
||||||
|
COMPONENT_NAME=$(basename "$PROJECT_DIR")
|
||||||
|
DATE_TAG=$(date +"%Y-%m-%d")
|
||||||
|
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
|
||||||
|
RESULT_JSON="$OUTPUT_DIR/${COMPONENT_NAME}_results_${DATE_TAG}.json"
|
||||||
|
|
||||||
|
# Compile
|
||||||
|
# Do not forget to define CGAL_DIR
|
||||||
|
cmake "$PROJECT_DIR" "-DCMAKE_BUILD_TYPE=Release" "-DCMAKE_CXX_FLAGS=-O3"
|
||||||
|
make -j $NUM_THREADS
|
||||||
|
|
||||||
|
# Prepare log directories
|
||||||
|
mkdir -p "$OUTPUT_DIR/Logs/$COMPONENT_NAME/Performance"
|
||||||
|
mkdir -p "$OUTPUT_DIR/Logs/$COMPONENT_NAME/Quality"
|
||||||
|
mkdir -p "$OUTPUT_DIR/Logs/$COMPONENT_NAME/Robustness"
|
||||||
|
|
||||||
|
# Initialize JSON
|
||||||
|
echo "{" > "$RESULT_JSON"
|
||||||
|
echo " \"$COMPONENT_NAME\": {" >> "$RESULT_JSON"
|
||||||
|
echo " \"Thingi10K\": {" >> "$RESULT_JSON"
|
||||||
|
|
||||||
|
#process_file "$INPUT_DIR/100036.stl" "$COMPONENT_NAME" "$PROJECT_DIR" "$TIMEOUT" "$OUTPUT_DIR" "$TMP_RESULT_FILE" "$GRID_SIZE" "$ERASE_ALL_DUPLICATE"
|
||||||
|
# Loop input files and spawn parallel jobs
|
||||||
|
for INPUT_FILE in "$INPUT_DIR"/*; do
|
||||||
|
INPUT_ID=$(basename "$INPUT_FILE" | cut -d. -f1)
|
||||||
|
TMP_RESULT_FILE="$TMP_RESULT_DIR/$INPUT_ID.json"
|
||||||
|
|
||||||
|
process_file "$INPUT_FILE" "$COMPONENT_NAME" "$PROJECT_DIR" "$TIMEOUT" "$OUTPUT_DIR" "$TMP_RESULT_FILE" "$GRID_SIZE" "$ERASE_ALL_DUPLICATE"
|
||||||
|
|
||||||
|
((JOBS+=1))
|
||||||
|
if [ "$JOBS" -ge "$NUM_THREADS" ]; then
|
||||||
|
wait
|
||||||
|
JOBS=0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
wait
|
||||||
|
|
||||||
|
# Merge all partial JSONs
|
||||||
|
echo "{" > "$RESULT_JSON"
|
||||||
|
echo " \"$COMPONENT_NAME\": {" >> "$RESULT_JSON"
|
||||||
|
echo " \"Thingi10K\": {" >> "$RESULT_JSON"
|
||||||
|
|
||||||
|
FIRST_ENTRY=true
|
||||||
|
for FILE in "$TMP_RESULT_DIR"/*.json; do
|
||||||
|
if [ "$FIRST_ENTRY" = true ]; then
|
||||||
|
FIRST_ENTRY=false
|
||||||
|
else
|
||||||
|
echo "," >> "$RESULT_JSON"
|
||||||
|
fi
|
||||||
|
cat "$FILE" >> "$RESULT_JSON"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "" >> "$RESULT_JSON"
|
||||||
|
echo " }," >> "$RESULT_JSON"
|
||||||
|
echo " \"finished_at\": \"$TIMESTAMP\"" >> "$RESULT_JSON"
|
||||||
|
echo " }" >> "$RESULT_JSON"
|
||||||
|
echo "}" >> "$RESULT_JSON"
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
#include <CGAL/Simple_cartesian.h>
|
||||||
|
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Surface_mesh.h>
|
||||||
|
|
||||||
|
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/corefinement.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/autorefinement.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/transform.h>
|
||||||
|
#include <CGAL/Real_timer.h>
|
||||||
|
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||||
|
typedef Kernel K;
|
||||||
|
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||||
|
typedef K::Point_3 Point_3;
|
||||||
|
|
||||||
|
typedef CGAL::Simple_cartesian<double> Cartesian;
|
||||||
|
typedef Cartesian::Point_3 Double_Point_3;
|
||||||
|
|
||||||
|
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||||
|
namespace params = CGAL::parameters;
|
||||||
|
|
||||||
|
struct Sphere_function {
|
||||||
|
double radius;
|
||||||
|
Sphere_function(double r) : radius(r) {}
|
||||||
|
Kernel::FT operator()(const Kernel::Point_3& p) const {
|
||||||
|
return p.x()*p.x() + p.y()*p.y() + p.z()*p.z() - radius*radius;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Thanks Roberto!
|
||||||
|
K::Aff_transformation_3
|
||||||
|
random_rotation(CGAL::Random &gen)
|
||||||
|
{
|
||||||
|
double a=gen.get_double(0,2*CGAL_PI);
|
||||||
|
|
||||||
|
double ca = cos(a);
|
||||||
|
double sa = sin(a);
|
||||||
|
|
||||||
|
K::Aff_transformation_3 aff(1, 0, 0,
|
||||||
|
0, ca,-sa,
|
||||||
|
0, sa, ca);
|
||||||
|
std::cout << "Rotation by " << a << std::endl;
|
||||||
|
return aff;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
Mesh cube;
|
||||||
|
std::vector<Point_3> points;
|
||||||
|
std::vector<boost::container::small_vector<std::size_t, 3>> faces;
|
||||||
|
|
||||||
|
CGAL::make_hexahedron(
|
||||||
|
Point_3(-1,-1,-1),
|
||||||
|
Point_3(1,-1,-1),
|
||||||
|
Point_3(1,1,-1),
|
||||||
|
Point_3(-1,1,-1),
|
||||||
|
Point_3(-1,1,1),
|
||||||
|
Point_3(-1,-1,1),
|
||||||
|
Point_3(1,-1,1),
|
||||||
|
Point_3(1,1,1),
|
||||||
|
cube,
|
||||||
|
CGAL::parameters::do_not_triangulate_faces(false)
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << "Iterative intersection of rotative cubes with snapping" << std::endl;
|
||||||
|
|
||||||
|
int i=0;
|
||||||
|
CGAL::Random random_gen = argc == 1 ? CGAL::get_default_random() : CGAL::Random(std::stoi(argv[1]));
|
||||||
|
|
||||||
|
Mesh inter=cube;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
std::cout << "Iteration " << i << std::endl;
|
||||||
|
|
||||||
|
CGAL::Real_timer t;
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
std::cout << "Add a randomly rotated cube to the scene" << std::endl;
|
||||||
|
Mesh rotated_cube=cube;
|
||||||
|
PMP::transform(random_rotation(random_gen), rotated_cube);
|
||||||
|
|
||||||
|
std::cout << "compute_intersection" << std::endl;
|
||||||
|
bool OK = PMP::corefine_and_compute_intersection(inter, rotated_cube, inter);
|
||||||
|
|
||||||
|
if(!OK){
|
||||||
|
std::cout << "No manifold, stop experiment" << std::endl;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
points.clear();
|
||||||
|
faces.clear();
|
||||||
|
PMP::polygon_mesh_to_polygon_soup(inter, points, faces);
|
||||||
|
|
||||||
|
std::cout << "Snapped the points on double" << std::endl;
|
||||||
|
bool success=PMP::autorefine_triangle_soup(points, faces, CGAL::parameters::apply_iterative_snap_rounding(true).erase_all_duplicates(true).concurrency_tag(CGAL::Parallel_if_available_tag()));
|
||||||
|
t.stop();
|
||||||
|
if(!success){
|
||||||
|
std::cout << "Rounding failed" << std::endl;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//dump model every 100 iterations
|
||||||
|
if(i%100==0){
|
||||||
|
std::cout << "Dump model" << std::endl;
|
||||||
|
std::vector<Double_Point_3> double_points;
|
||||||
|
for(auto &p: points)
|
||||||
|
double_points.emplace_back(CGAL::to_double(p.x()),CGAL::to_double(p.y()),CGAL::to_double(p.z()));
|
||||||
|
std::ofstream outfile("cubes_"+std::to_string(i)+".off");
|
||||||
|
outfile.precision(17);
|
||||||
|
outfile << "OFF\n" << points.size() << " " << faces.size() << " 0\n";
|
||||||
|
for(auto p : points)
|
||||||
|
outfile << p.x() << " " << p.y() << " " << p.z() << std::endl;
|
||||||
|
|
||||||
|
for(auto &t : faces)
|
||||||
|
outfile << "3" << " " << t[0] << " " << t[1] << " " << t[2] << std::endl;
|
||||||
|
outfile.close();//
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "#points = " << points.size() << " and #triangles = " << faces.size() << " in " << t.time() << " sec.\n\n" << std::endl;
|
||||||
|
|
||||||
|
inter.clear();
|
||||||
|
PMP::polygon_soup_to_polygon_mesh(points, faces, inter);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
#include <CGAL/Simple_cartesian.h>
|
||||||
|
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Surface_mesh.h>
|
||||||
|
|
||||||
|
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/corefinement.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/autorefinement.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/transform.h>
|
||||||
|
#include <CGAL/Real_timer.h>
|
||||||
|
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||||
|
typedef Kernel K;
|
||||||
|
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||||
|
typedef K::Point_3 Point_3;
|
||||||
|
|
||||||
|
typedef CGAL::Simple_cartesian<double> Cartesian;
|
||||||
|
typedef Cartesian::Point_3 Double_Point_3;
|
||||||
|
|
||||||
|
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||||
|
namespace params = CGAL::parameters;
|
||||||
|
|
||||||
|
struct Sphere_function {
|
||||||
|
double radius;
|
||||||
|
Sphere_function(double r) : radius(r) {}
|
||||||
|
Kernel::FT operator()(const Kernel::Point_3& p) const {
|
||||||
|
return p.x()*p.x() + p.y()*p.y() + p.z()*p.z() - radius*radius;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Thanks Roberto!
|
||||||
|
K::Aff_transformation_3
|
||||||
|
random_rotation(CGAL::Random &gen)
|
||||||
|
{
|
||||||
|
double a=gen.get_double(0,2*CGAL_PI);
|
||||||
|
double b=gen.get_double(0,2*CGAL_PI);
|
||||||
|
double c=gen.get_double(0,2*CGAL_PI);
|
||||||
|
|
||||||
|
double ca = cos(a), cb = cos(b), cc = cos(c);
|
||||||
|
double sa = sin(a), sb = sin(b), sc = sin(c);
|
||||||
|
|
||||||
|
K::Aff_transformation_3 aff(cb * cc, cc* sa* sb - ca * sc, ca* cc* sb + sa * sc,
|
||||||
|
cb* sc, ca* cc + sa * sb * sc, ca* sb* sc - cc * sa,
|
||||||
|
-sb, cb* sa, ca* cb);
|
||||||
|
std::cout << "Rotation by " << a << " " << b << " " << c << std::endl;
|
||||||
|
return aff;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
Mesh cube;
|
||||||
|
std::vector<Point_3> points;
|
||||||
|
std::vector<boost::container::small_vector<std::size_t, 3>> faces;
|
||||||
|
|
||||||
|
CGAL::make_hexahedron(
|
||||||
|
Point_3(-1,-1,-1),
|
||||||
|
Point_3(1,-1,-1),
|
||||||
|
Point_3(1,1,-1),
|
||||||
|
Point_3(-1,1,-1),
|
||||||
|
Point_3(-1,1,1),
|
||||||
|
Point_3(-1,-1,1),
|
||||||
|
Point_3(1,-1,1),
|
||||||
|
Point_3(1,1,1),
|
||||||
|
cube,
|
||||||
|
CGAL::parameters::do_not_triangulate_faces(false)
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << "Iterative intersection of rotative cubes with snapping" << std::endl;
|
||||||
|
|
||||||
|
int i=0;
|
||||||
|
CGAL::Random random_gen = argc == 1 ? CGAL::get_default_random() : CGAL::Random(std::stoi(argv[1]));
|
||||||
|
|
||||||
|
Mesh inter=cube;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
std::cout << "Iteration " << i << std::endl;
|
||||||
|
|
||||||
|
CGAL::Real_timer t;
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
std::cout << "Add a randomly rotated cube to the scene" << std::endl;
|
||||||
|
Mesh rotated_cube=cube;
|
||||||
|
PMP::transform(random_rotation(random_gen), rotated_cube);
|
||||||
|
|
||||||
|
std::cout << "compute_intersection" << std::endl;
|
||||||
|
bool OK = PMP::corefine_and_compute_intersection(inter, rotated_cube, inter);
|
||||||
|
|
||||||
|
if(!OK){
|
||||||
|
std::cout << "No manifold, stop experiment" << std::endl;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
points.clear();
|
||||||
|
faces.clear();
|
||||||
|
PMP::polygon_mesh_to_polygon_soup(inter, points, faces);
|
||||||
|
|
||||||
|
std::cout << "Snapped the points on double" << std::endl;
|
||||||
|
bool success=PMP::autorefine_triangle_soup(points, faces, CGAL::parameters::apply_iterative_snap_rounding(true).erase_all_duplicates(true).concurrency_tag(CGAL::Parallel_if_available_tag()));
|
||||||
|
t.stop();
|
||||||
|
if(!success){
|
||||||
|
std::cout << "Rounding failed" << std::endl;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//dump model every 100 iterations
|
||||||
|
if(i%100==0){
|
||||||
|
std::cout << "Dump model" << std::endl;
|
||||||
|
std::vector<Double_Point_3> double_points;
|
||||||
|
for(auto &p: points)
|
||||||
|
double_points.emplace_back(CGAL::to_double(p.x()),CGAL::to_double(p.y()),CGAL::to_double(p.z()));
|
||||||
|
std::ofstream outfile("cubes_"+std::to_string(i)+".off");
|
||||||
|
outfile.precision(17);
|
||||||
|
outfile << "OFF\n" << points.size() << " " << faces.size() << " 0\n";
|
||||||
|
for(auto p : points)
|
||||||
|
outfile << p.x() << " " << p.y() << " " << p.z() << std::endl;
|
||||||
|
|
||||||
|
for(auto &t : faces)
|
||||||
|
outfile << "3" << " " << t[0] << " " << t[1] << " " << t[2] << std::endl;
|
||||||
|
outfile.close();//
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "#points = " << points.size() << " and #triangles = " << faces.size() << " in " << t.time() << " sec.\n\n" << std::endl;
|
||||||
|
|
||||||
|
inter.clear();
|
||||||
|
PMP::polygon_soup_to_polygon_mesh(points, faces, inter);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -23,5 +23,7 @@ public:
|
||||||
/// called for each subtriangle created from a triangle with intersection, `tgt_id` is the position in the triangle container after calling
|
/// called for each subtriangle created from a triangle with intersection, `tgt_id` is the position in the triangle container after calling
|
||||||
/// `autorefine_triangle_soup()` of the subtriangle, while `src_id` was the position of the original support triangle before calling the function.
|
/// `autorefine_triangle_soup()` of the subtriangle, while `src_id` was the position of the original support triangle before calling the function.
|
||||||
void new_subtriangle(std::size_t tgt_id, std::size_t src_id);
|
void new_subtriangle(std::size_t tgt_id, std::size_t src_id);
|
||||||
|
/// called for each input triangle absent in the output because it was degenerate. `src_id` is the position of that triangle in the input range. Additionally, if `apply_iterative_snap_rounding()` is set to `true`, some extra triangles might become degenerate and will be absent in the output. Those triangles are also reported by this function.
|
||||||
|
void delete_triangle(std::size_t src_id);
|
||||||
/// @}
|
/// @}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace CGAL {
|
||||||
\anchor Chapter_PolygonMeshProcessing
|
\anchor Chapter_PolygonMeshProcessing
|
||||||
|
|
||||||
\cgalAutoToc
|
\cgalAutoToc
|
||||||
\authors David Coeurjolly, Jaques-Olivier Lachaud, Konstantinos Katrioplas, Sébastien Loriot, Ivan Pađen, Mael Rouxel-Labbé, Hossam Saeed, Jane Tournois, Sébastien Valette, and Ilker %O. Yaz
|
\authors David Coeurjolly, Jaques-Olivier Lachaud, Konstantinos Katrioplas, Sébastien Loriot, Ivan Pađen, Mael Rouxel-Labbé, Hossam Saeed, Jane Tournois, Sébastien Valette, Léo Valque, and Ilker %O. Yaz
|
||||||
|
|
||||||
\image html neptun_head.jpg
|
\image html neptun_head.jpg
|
||||||
\image latex neptun_head.jpg
|
\image latex neptun_head.jpg
|
||||||
|
|
@ -911,8 +911,10 @@ would then also includes overlaps of duplicated points.
|
||||||
The function `CGAL::Polygon_mesh_processing::autorefine_triangle_soup()` provides a way to refine a triangle soup
|
The function `CGAL::Polygon_mesh_processing::autorefine_triangle_soup()` provides a way to refine a triangle soup
|
||||||
using the intersections of the triangles from the soup. In particular, if some points are duplicated they will be
|
using the intersections of the triangles from the soup. In particular, if some points are duplicated they will be
|
||||||
merged. Note that if a kernel with exact predicates but inexact constructions is used, some new self-intersections
|
merged. Note that if a kernel with exact predicates but inexact constructions is used, some new self-intersections
|
||||||
might be introduced due to rounding issues of points coordinates.
|
might be introduced due to the rounding of the coordinates of intersection points. The `apply_iterative_snap_rounding` option can be used to resolve this issue.
|
||||||
To guarantee that the triangle soup is free from self-intersections, a kernel with exact constructions must be used.
|
When set to `true`, it ensures that the coordinates are rounded to fit in `double` with potential additional subdivisions,
|
||||||
|
preventing any self-intersections from occurring.
|
||||||
|
|
||||||
|
|
||||||
\subsection PMPRemoveCapsNeedles Removal of Almost Degenerate Triangle Faces
|
\subsection PMPRemoveCapsNeedles Removal of Almost Degenerate Triangle Faces
|
||||||
Triangle faces of a mesh made up of almost collinear points are badly shaped elements that
|
Triangle faces of a mesh made up of almost collinear points are badly shaped elements that
|
||||||
|
|
@ -1477,6 +1479,7 @@ supervision of Sébastien Valette and Sébastien Loriot, who later finalized the
|
||||||
The implementation is based on \cgalCite{cgal:vcp-grtmmdvd-08}. and
|
The implementation is based on \cgalCite{cgal:vcp-grtmmdvd-08}. and
|
||||||
preceding work. <a href="https://www.creatis.insa-lyon.fr/~valette/public/project/acvd/">ACVD's implementation</a> was also
|
preceding work. <a href="https://www.creatis.insa-lyon.fr/~valette/public/project/acvd/">ACVD's implementation</a> was also
|
||||||
used as a reference during the project.
|
used as a reference during the project.
|
||||||
|
The `apply_iterative_snap_rounding` option for autorefinement was implemented in 2025, by Léo Valque, based on his work with Sylvain Lazard \cgalCite{lazard:hal-04907149}.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
} /* namespace CGAL */
|
} /* namespace CGAL */
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,5 @@
|
||||||
\example Polygon_mesh_processing/acvd_remeshing_example.cpp
|
\example Polygon_mesh_processing/acvd_remeshing_example.cpp
|
||||||
\example Polygon_mesh_processing/sample_example.cpp
|
\example Polygon_mesh_processing/sample_example.cpp
|
||||||
\example Polygon_mesh_processing/soup_autorefinement.cpp
|
\example Polygon_mesh_processing/soup_autorefinement.cpp
|
||||||
|
\example Polygon_mesh_processing/snap_polygon_soup.cpp
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ create_single_source_cgal_program("isotropic_remeshing_with_custom_sizing_exampl
|
||||||
create_single_source_cgal_program("isotropic_remeshing_with_allow_move.cpp")
|
create_single_source_cgal_program("isotropic_remeshing_with_allow_move.cpp")
|
||||||
create_single_source_cgal_program("triangle_mesh_autorefinement.cpp")
|
create_single_source_cgal_program("triangle_mesh_autorefinement.cpp")
|
||||||
create_single_source_cgal_program("soup_autorefinement.cpp")
|
create_single_source_cgal_program("soup_autorefinement.cpp")
|
||||||
|
create_single_source_cgal_program("snap_polygon_soup.cpp")
|
||||||
|
|
||||||
find_package(Eigen3 3.2.0 QUIET) #(requires 3.2.0 or greater)
|
find_package(Eigen3 3.2.0 QUIET) #(requires 3.2.0 or greater)
|
||||||
include(CGAL_Eigen3_support)
|
include(CGAL_Eigen3_support)
|
||||||
|
|
@ -140,6 +141,7 @@ if(TARGET CGAL::TBB_support)
|
||||||
target_link_libraries(hausdorff_distance_remeshing_example PRIVATE CGAL::TBB_support)
|
target_link_libraries(hausdorff_distance_remeshing_example PRIVATE CGAL::TBB_support)
|
||||||
target_link_libraries(hausdorff_bounded_error_distance_example PRIVATE CGAL::TBB_support)
|
target_link_libraries(hausdorff_bounded_error_distance_example PRIVATE CGAL::TBB_support)
|
||||||
target_link_libraries(soup_autorefinement PRIVATE CGAL::TBB_support)
|
target_link_libraries(soup_autorefinement PRIVATE CGAL::TBB_support)
|
||||||
|
target_link_libraries(snap_polygon_soup PRIVATE CGAL::TBB_support)
|
||||||
|
|
||||||
create_single_source_cgal_program("corefinement_parallel_union_meshes.cpp")
|
create_single_source_cgal_program("corefinement_parallel_union_meshes.cpp")
|
||||||
target_link_libraries(corefinement_parallel_union_meshes PRIVATE CGAL::TBB_support)
|
target_link_libraries(corefinement_parallel_union_meshes PRIVATE CGAL::TBB_support)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/autorefinement.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||||
|
#include <CGAL/IO/polygon_soup_io.h>
|
||||||
|
#include <CGAL/Real_timer.h>
|
||||||
|
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||||
|
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
const std::string filename = argc == 1 ? CGAL::data_file_path("meshes/elephant.off")
|
||||||
|
: std::string(argv[1]);
|
||||||
|
|
||||||
|
const int grid_size = argc <= 2 ? 23
|
||||||
|
: std::stoi(std::string(argv[2]));
|
||||||
|
|
||||||
|
const std::string out_file = "rounded_soup.off";
|
||||||
|
|
||||||
|
std::vector<typename Kernel::Point_3> points;
|
||||||
|
std::vector<boost::container::small_vector<std::size_t, 3>> triangles;
|
||||||
|
|
||||||
|
std::cout << "Snap rounding on " << filename << "\n";
|
||||||
|
if (!CGAL::IO::read_polygon_soup(filename, points, triangles))
|
||||||
|
{
|
||||||
|
std::cerr << "Cannot read " << filename << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PMP::repair_polygon_soup(points, triangles);
|
||||||
|
PMP::triangulate_polygons(points, triangles);
|
||||||
|
|
||||||
|
std::cout << "#points = " << points.size() << " and #triangles = " << triangles.size() << std::endl;
|
||||||
|
std::cout << "Is 2-manifold: " << PMP::is_polygon_soup_a_polygon_mesh(triangles) << std::endl;
|
||||||
|
|
||||||
|
std::vector<std::pair<std::size_t, std::size_t>> pairs_of_intersecting_triangles;
|
||||||
|
PMP::triangle_soup_self_intersections(points, triangles, std::back_inserter(pairs_of_intersecting_triangles));
|
||||||
|
std::cout << "Nb of pairs of intersecting triangles: " << pairs_of_intersecting_triangles.size() << std::endl;
|
||||||
|
|
||||||
|
CGAL::Real_timer t;
|
||||||
|
t.start();
|
||||||
|
bool success=PMP::autorefine_triangle_soup(points, triangles, CGAL::parameters::apply_iterative_snap_rounding(true).erase_all_duplicates(false).concurrency_tag(CGAL::Parallel_if_available_tag()).snap_grid_size(grid_size).number_of_iterations(15));
|
||||||
|
t.stop();
|
||||||
|
|
||||||
|
std::cout << "\nOutput:" << std::endl;
|
||||||
|
std::cout << "#points = " << points.size() << " and #triangles = " << triangles.size() << " in " << t.time() << " sec." << std::endl;
|
||||||
|
if(success)
|
||||||
|
std::cout << "Does self-intersect: " << PMP::does_triangle_soup_self_intersect<CGAL::Parallel_if_available_tag>(points, triangles) << std::endl;
|
||||||
|
else
|
||||||
|
std::cout << "ROUNDING FAILED" << std::endl;
|
||||||
|
|
||||||
|
CGAL::IO::write_polygon_soup(out_file, points, triangles, CGAL::parameters::stream_precision(17));
|
||||||
|
std::cout << "Is 2-manifold: " << PMP::orient_polygon_soup(points, triangles) << "\n\n" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h>
|
#include <CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h>
|
||||||
|
|
||||||
|
|
||||||
#ifdef CGAL_PMP_AUTOREFINE_USE_DEFAULT_VERBOSE
|
#ifdef CGAL_PMP_AUTOREFINE_USE_DEFAULT_VERBOSE
|
||||||
#define CGAL_PMP_AUTOREFINE_VERBOSE(X) std::cout << X << "\n";
|
#define CGAL_PMP_AUTOREFINE_VERBOSE(X) std::cout << X << "\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -90,6 +89,7 @@ struct Default_visitor
|
||||||
inline void number_of_output_triangles(std::size_t /*nbt*/) {}
|
inline void number_of_output_triangles(std::size_t /*nbt*/) {}
|
||||||
inline void verbatim_triangle_copy(std::size_t /*tgt_id*/, std::size_t /*src_id*/) {}
|
inline void verbatim_triangle_copy(std::size_t /*tgt_id*/, std::size_t /*src_id*/) {}
|
||||||
inline void new_subtriangle(std::size_t /*tgt_id*/, std::size_t /*src_id*/) {}
|
inline void new_subtriangle(std::size_t /*tgt_id*/, std::size_t /*src_id*/) {}
|
||||||
|
inline void delete_triangle(std::size_t /*src_id*/) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of Autorefinement visitor
|
} // end of Autorefinement visitor
|
||||||
|
|
@ -975,59 +975,19 @@ void generate_subtriangles(std::size_t ti,
|
||||||
} // end of autorefine_impl
|
} // end of autorefine_impl
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
namespace autorefine_impl{
|
||||||
* \ingroup PMP_corefinement_grp
|
// Forward declaration
|
||||||
*
|
struct Wrap_snap_visitor;
|
||||||
* refines a soup of triangles so that no pair of triangles intersects.
|
|
||||||
* Output triangles may share a common edge or a common vertex (but with the same indexed position in `points`).
|
template <typename PointRange, typename PolygonRange, class NamedParameters = parameters::Default_named_parameters>
|
||||||
* Note that points in `soup_points` can only be added (intersection points) at the end of the container, with the initial order preserved.
|
bool polygon_soup_snap_rounding(PointRange &points,
|
||||||
* Note that if `soup_points` contains two or more identical points then only the first copy (following the order in the `soup_points`)
|
PolygonRange &triangles,
|
||||||
* will be used in `soup_triangles`.
|
const NamedParameters& np = parameters::default_values());
|
||||||
* `soup_triangles` will be updated to contain both the input triangles and the new subdivided triangles. Degenerate triangles will be removed.
|
|
||||||
* Also triangles in `soup_triangles` will be triangles without intersection first, followed by triangles coming from a subdivision induced
|
|
||||||
* by an intersection. The named parameter `visitor()` can be used to track
|
|
||||||
*
|
|
||||||
* @tparam PointRange a model of the concept `RandomAccessContainer`
|
|
||||||
* whose value type is the point type
|
|
||||||
* @tparam TriangleRange a model of the concepts `RandomAccessContainer`, `BackInsertionSequence` and `Swappable`, whose
|
|
||||||
* value type is a model of the concept `RandomAccessContainer` whose value type is convertible to `std::size_t` and that
|
|
||||||
* is constructible from an `std::initializer_list<std::size_t>` of size 3.
|
|
||||||
* @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
|
|
||||||
*
|
|
||||||
* @param soup_points points of the soup of polygons
|
|
||||||
* @param soup_triangles each element in the range describes a triangle using the indexed position of the points in `soup_points`
|
|
||||||
* @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
|
|
||||||
*
|
|
||||||
* \cgalNamedParamsBegin
|
|
||||||
* \cgalParamNBegin{concurrency_tag}
|
|
||||||
* \cgalParamDescription{a tag indicating if the task should be done using one or several threads.}
|
|
||||||
* \cgalParamType{Either `CGAL::Sequential_tag`, or `CGAL::Parallel_tag`, or `CGAL::Parallel_if_available_tag`}
|
|
||||||
* \cgalParamDefault{`CGAL::Sequential_tag`}
|
|
||||||
* \cgalParamNEnd
|
|
||||||
* \cgalParamNBegin{point_map}
|
|
||||||
* \cgalParamDescription{a property map associating points to the elements of the range `soup_points`}
|
|
||||||
* \cgalParamType{a model of `ReadWritePropertyMap` whose value type is a point type}
|
|
||||||
* \cgalParamDefault{`CGAL::Identity_property_map`}
|
|
||||||
* \cgalParamNEnd
|
|
||||||
* \cgalParamNBegin{geom_traits}
|
|
||||||
* \cgalParamDescription{an instance of a geometric traits class}
|
|
||||||
* \cgalParamType{a class model of `Kernel`}
|
|
||||||
* \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`}
|
|
||||||
* \cgalParamExtra{The geometric traits class must be compatible with the point type.}
|
|
||||||
* \cgalParamNEnd
|
|
||||||
* \cgalParamNBegin{visitor}
|
|
||||||
* \cgalParamDescription{a visitor used to track the creation of new faces}
|
|
||||||
* \cgalParamType{a class model of `PMPAutorefinementVisitor`}
|
|
||||||
* \cgalParamDefault{`Autorefinement::Default_visitor`}
|
|
||||||
* \cgalParamExtra{The visitor will be copied.}
|
|
||||||
* \cgalParamNEnd
|
|
||||||
* \cgalNamedParamsEnd
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
template <class PointRange, class TriangleRange, class NamedParameters = parameters::Default_named_parameters>
|
template <class PointRange, class TriangleRange, class NamedParameters = parameters::Default_named_parameters>
|
||||||
void autorefine_triangle_soup(PointRange& soup_points,
|
bool autorefine_triangle_soup(PointRange& soup_points,
|
||||||
TriangleRange& soup_triangles,
|
TriangleRange& soup_triangles,
|
||||||
const NamedParameters& np = parameters::default_values())
|
const NamedParameters& np = parameters::default_values())
|
||||||
{
|
{
|
||||||
using parameters::choose_parameter;
|
using parameters::choose_parameter;
|
||||||
using parameters::get_parameter;
|
using parameters::get_parameter;
|
||||||
|
|
@ -1050,7 +1010,6 @@ void autorefine_triangle_soup(PointRange& soup_points,
|
||||||
> ::type Visitor;
|
> ::type Visitor;
|
||||||
Visitor visitor(choose_parameter<Visitor>(get_parameter(np, internal_np::visitor)));
|
Visitor visitor(choose_parameter<Visitor>(get_parameter(np, internal_np::visitor)));
|
||||||
|
|
||||||
|
|
||||||
constexpr bool parallel_execution = std::is_same_v<Parallel_tag, Concurrency_tag>;
|
constexpr bool parallel_execution = std::is_same_v<Parallel_tag, Concurrency_tag>;
|
||||||
|
|
||||||
#ifndef CGAL_LINKED_WITH_TBB
|
#ifndef CGAL_LINKED_WITH_TBB
|
||||||
|
|
@ -1077,7 +1036,7 @@ void autorefine_triangle_soup(PointRange& soup_points,
|
||||||
for(std::size_t i=0; i<soup_triangles.size(); ++i)
|
for(std::size_t i=0; i<soup_triangles.size(); ++i)
|
||||||
visitor.verbatim_triangle_copy(i, i);
|
visitor.verbatim_triangle_copy(i, i);
|
||||||
}
|
}
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark degenerate faces so that we can ignore them
|
// mark degenerate faces so that we can ignore them
|
||||||
|
|
@ -1455,15 +1414,17 @@ void autorefine_triangle_soup(PointRange& soup_points,
|
||||||
std::vector<std::size_t> tri_inter_ids_inverse(triangles.size());
|
std::vector<std::size_t> tri_inter_ids_inverse(triangles.size());
|
||||||
for (Input_TID f=0; f<soup_triangles.size(); ++f)
|
for (Input_TID f=0; f<soup_triangles.size(); ++f)
|
||||||
{
|
{
|
||||||
if (is_degen[f]) continue; //skip degenerate faces
|
if (is_degen[f])
|
||||||
|
{
|
||||||
|
visitor.delete_triangle(f);
|
||||||
|
continue; //skip degenerate faces
|
||||||
|
}
|
||||||
|
|
||||||
int tiid = tri_inter_ids[f];
|
int tiid = tri_inter_ids[f];
|
||||||
if (tiid == -1)
|
if (tiid == -1)
|
||||||
{
|
{
|
||||||
visitor.verbatim_triangle_copy(soup_triangles_out.size(), f);
|
visitor.verbatim_triangle_copy(soup_triangles_out.size(), f);
|
||||||
soup_triangles_out.push_back(
|
soup_triangles_out.push_back(soup_triangles[f]);
|
||||||
{soup_triangles[f][0], soup_triangles[f][1], soup_triangles[f][2]}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1529,22 +1490,41 @@ void autorefine_triangle_soup(PointRange& soup_points,
|
||||||
[&](const tbb::blocked_range<size_t>& r) {
|
[&](const tbb::blocked_range<size_t>& r) {
|
||||||
for (size_t ti = r.begin(); ti != r.end(); ++ti) {
|
for (size_t ti = r.begin(); ti != r.end(); ++ti) {
|
||||||
const std::array<EK::Point_3, 3>& t = new_triangles[ti].first;
|
const std::array<EK::Point_3, 3>& t = new_triangles[ti].first;
|
||||||
visitor.new_subtriangle(offset+ti, tri_inter_ids_inverse[new_triangles[ti].second]);
|
|
||||||
triangle_buffer[ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2]));
|
triangle_buffer[ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, new_triangles.size()),
|
|
||||||
[&](const tbb::blocked_range<size_t>& r) {
|
// The constexpr was initially inside the lambda, but that did not compile with VC 2017
|
||||||
for (size_t ti = r.begin(); ti != r.end(); ++ti)
|
if constexpr(std::is_same_v<Visitor, Wrap_snap_visitor>){
|
||||||
{
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, new_triangles.size()),
|
||||||
soup_triangles_out[offset + ti] =
|
[&](const tbb::blocked_range<size_t>& r) {
|
||||||
{ triangle_buffer[ti][0]->second,
|
for (size_t ti = r.begin(); ti != r.end(); ++ti)
|
||||||
triangle_buffer[ti][1]->second,
|
{
|
||||||
triangle_buffer[ti][2]->second };
|
soup_triangles_out[offset + ti] =
|
||||||
|
{ triangle_buffer[ti][0]->second,
|
||||||
|
triangle_buffer[ti][1]->second,
|
||||||
|
triangle_buffer[ti][2]->second };
|
||||||
|
visitor.new_subdivision(soup_triangles_out[offset + ti], soup_triangles[tri_inter_ids_inverse[new_triangles[ti].second]]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, new_triangles.size()),
|
||||||
|
[&](const tbb::blocked_range<size_t>& r) {
|
||||||
|
for (size_t ti = r.begin(); ti != r.end(); ++ti)
|
||||||
|
{
|
||||||
|
soup_triangles_out[offset + ti] =
|
||||||
|
{ triangle_buffer[ti][0]->second,
|
||||||
|
triangle_buffer[ti][1]->second,
|
||||||
|
triangle_buffer[ti][2]->second };
|
||||||
|
visitor.new_subtriangle(offset+ti, tri_inter_ids_inverse[new_triangles[ti].second]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
//option 2 (without mutex)
|
//option 2 (without mutex)
|
||||||
/// Lambda concurrent_get_point_id()
|
/// Lambda concurrent_get_point_id()
|
||||||
|
|
@ -1591,17 +1571,33 @@ void autorefine_triangle_soup(PointRange& soup_points,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, new_triangles.size()),
|
// The constexpr was initially inside the lambda, but that did not compile with VC 2017
|
||||||
[&](const tbb::blocked_range<size_t>& r) {
|
if constexpr(std::is_same_v<Visitor, Wrap_snap_visitor>){
|
||||||
for (size_t ti = r.begin(); ti != r.end(); ++ti)
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, new_triangles.size()),
|
||||||
{
|
[&](const tbb::blocked_range<size_t>& r) {
|
||||||
soup_triangles_out[offset + ti] =
|
for (size_t ti = r.begin(); ti != r.end(); ++ti)
|
||||||
{ triangle_buffer[ti][0]->second,
|
{
|
||||||
triangle_buffer[ti][1]->second,
|
soup_triangles_out[offset + ti] =
|
||||||
triangle_buffer[ti][2]->second };
|
{ triangle_buffer[ti][0]->second,
|
||||||
|
triangle_buffer[ti][1]->second,
|
||||||
|
triangle_buffer[ti][2]->second };
|
||||||
|
visitor.new_subdivision(soup_triangles_out[offset + ti], soup_triangles[tri_inter_ids_inverse[new_triangles[ti].second]]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
}else{
|
||||||
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, new_triangles.size()),
|
||||||
|
[&](const tbb::blocked_range<size_t>& r) {
|
||||||
|
for (size_t ti = r.begin(); ti != r.end(); ++ti)
|
||||||
|
{
|
||||||
|
soup_triangles_out[offset + ti] =
|
||||||
|
{ triangle_buffer[ti][0]->second,
|
||||||
|
triangle_buffer[ti][1]->second,
|
||||||
|
triangle_buffer[ti][2]->second };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1613,10 +1609,13 @@ void autorefine_triangle_soup(PointRange& soup_points,
|
||||||
soup_triangles_out.reserve(offset + new_triangles.size());
|
soup_triangles_out.reserve(offset + new_triangles.size());
|
||||||
for (const std::pair<std::array<EK::Point_3,3>, std::size_t>& t_and_id : new_triangles)
|
for (const std::pair<std::array<EK::Point_3,3>, std::size_t>& t_and_id : new_triangles)
|
||||||
{
|
{
|
||||||
visitor.new_subtriangle(soup_triangles_out.size(), tri_inter_ids_inverse[t_and_id.second]);
|
|
||||||
soup_triangles_out.push_back({ get_point_id(t_and_id.first[0]),
|
soup_triangles_out.push_back({ get_point_id(t_and_id.first[0]),
|
||||||
get_point_id(t_and_id.first[1]),
|
get_point_id(t_and_id.first[1]),
|
||||||
get_point_id(t_and_id.first[2]) });
|
get_point_id(t_and_id.first[2]) });
|
||||||
|
if constexpr(std::is_same_v<Visitor, Wrap_snap_visitor>)
|
||||||
|
visitor.new_subdivision(soup_triangles_out[soup_triangles_out.size()-1], soup_triangles[tri_inter_ids_inverse[t_and_id.second]]);
|
||||||
|
else
|
||||||
|
visitor.new_subtriangle(soup_triangles_out.size()-1, tri_inter_ids_inverse[t_and_id.second]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1642,8 +1641,108 @@ void autorefine_triangle_soup(PointRange& soup_points,
|
||||||
swap(soup_triangles, soup_triangles_out);
|
swap(soup_triangles, soup_triangles_out);
|
||||||
|
|
||||||
CGAL_PMP_AUTOREFINE_VERBOSE("done");
|
CGAL_PMP_AUTOREFINE_VERBOSE("done");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // end of autorefine_impl
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \ingroup PMP_corefinement_grp
|
||||||
|
*
|
||||||
|
* refines a soup of triangles so that no pair of triangles intersects.
|
||||||
|
* Output triangles may share a common edge or a common vertex (but with the same indexed position in `points`).
|
||||||
|
* Note that if `apply_iterative_snap_rounding` option is set to `false`, points in `soup_points` can only be added (intersection points) at the end of the container, with the initial order preserved.
|
||||||
|
* Note that if `soup_points` contains two or more identical points then only the first copy (following the order in the `soup_points`)
|
||||||
|
* will be used in `soup_triangles`. if `apply_iterative_snap_rounding` is set to `true`, all duplicates points are removed.
|
||||||
|
* `soup_triangles` will be updated to contain both the input triangles and the new subdivided triangles. Degenerate triangles will be removed.
|
||||||
|
* Also if `apply_iterative_snap_rounding` option is set to `false`, triangles in `soup_triangles` will be triangles without intersection first, followed by triangles coming from a subdivision induced
|
||||||
|
* by an intersection. The named parameter `visitor()` can be used to track the creation and removal of triangles independantly of
|
||||||
|
* the `apply_iterative_snap_rounding` option.
|
||||||
|
* If the `apply_iterative_snap_rounding` parameter is set to `true`, the coordinates of the vertices are rounded to fit within the precision of a double-precision floating point,
|
||||||
|
* while trying to make the triangle soup free of intersections. The `snap_grid_size()` parameter limits the drift of the snapped vertices.
|
||||||
|
* A smaller value is more likely to output an intersection free output and perform more vertex collapses, but it may increase the Hausdorff distance from the input.
|
||||||
|
*
|
||||||
|
* @tparam PointRange a model of the concept `RandomAccessContainer`
|
||||||
|
* whose value type is the point type
|
||||||
|
* @tparam TriangleRange a model of the concepts `RandomAccessContainer`, `BackInsertionSequence` and `Swappable`, whose
|
||||||
|
* value type is a model of the concept `RandomAccessContainer` whose value type is convertible to `std::size_t` and that
|
||||||
|
* is constructible from an `std::initializer_list<std::size_t>` of size 3.
|
||||||
|
* @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
|
||||||
|
*
|
||||||
|
* @param soup_points points of the soup of polygons
|
||||||
|
* @param soup_triangles each element in the range describes a triangle using the indexed position of the points in `soup_points`
|
||||||
|
* @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
|
||||||
|
*
|
||||||
|
* \cgalNamedParamsBegin
|
||||||
|
* \cgalParamNBegin{concurrency_tag}
|
||||||
|
* \cgalParamDescription{a tag indicating if the task should be done using one or several threads.}
|
||||||
|
* \cgalParamType{Either `CGAL::Sequential_tag`, or `CGAL::Parallel_tag`, or `CGAL::Parallel_if_available_tag`}
|
||||||
|
* \cgalParamDefault{`CGAL::Sequential_tag`}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalParamNBegin{point_map}
|
||||||
|
* \cgalParamDescription{a property map associating points to the elements of the range `soup_points`}
|
||||||
|
* \cgalParamType{a model of `ReadWritePropertyMap` whose value type is a point type}
|
||||||
|
* \cgalParamDefault{`CGAL::Identity_property_map`}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalParamNBegin{geom_traits}
|
||||||
|
* \cgalParamDescription{an instance of a geometric traits class}
|
||||||
|
* \cgalParamType{a class model of `Kernel`}
|
||||||
|
* \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`}
|
||||||
|
* \cgalParamExtra{The geometric traits class must be compatible with the point type.}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalParamNBegin{visitor}
|
||||||
|
* \cgalParamDescription{a visitor used to track the creation of new faces}
|
||||||
|
* \cgalParamType{a class model of `PMPAutorefinementVisitor`}
|
||||||
|
* \cgalParamDefault{`Autorefinement::Default_visitor`}
|
||||||
|
* \cgalParamExtra{The visitor will be copied.}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalParamNBegin{apply_iterative_snap_rounding}
|
||||||
|
* \cgalParamDescription{Enable the rounding of the coordinates so that they fit in doubles.}
|
||||||
|
* \cgalParamType{Boolean}
|
||||||
|
* \cgalParamDefault{false}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalParamNBegin{snap_grid_size}
|
||||||
|
* \cgalParamDescription{A value `gs` used to scale the points to `[-2^gs, 2^gs]` before rounding them on integers. Used only if `apply_iterative_snap_rounding()` is set to `true`}
|
||||||
|
* \cgalParamType{`unsigned int`}
|
||||||
|
* \cgalParamDefault{23}
|
||||||
|
* \cgalParamExtra{Must be lower than 52.}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalParamNBegin{number_of_iterations}
|
||||||
|
* \cgalParamDescription{Maximum number of iterations performed by the snap rounding algorithm. Used only if `apply_iterative_snap_rounding` is true.}
|
||||||
|
* \cgalParamType{unsigned int}
|
||||||
|
* \cgalParamDefault{5}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalNamedParamsEnd
|
||||||
|
*
|
||||||
|
* \return `true` if `apply_iterative_snap_rounding` is set to `false`.
|
||||||
|
* Otherwise, returns `true` if the modified triangle soup is free of self-intersections,
|
||||||
|
* or `false` if the algorithm was unable to produce such a result within the allowed number of iterations.
|
||||||
|
* In the latter case, the output triangle soup represents a partial result from the final iteration,
|
||||||
|
* with no guarantee of its validity.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template <class PointRange, class TriangleRange, class NamedParameters = parameters::Default_named_parameters>
|
||||||
|
bool autorefine_triangle_soup(PointRange& soup_points,
|
||||||
|
TriangleRange& soup_triangles,
|
||||||
|
const NamedParameters& np = parameters::default_values())
|
||||||
|
{
|
||||||
|
using parameters::choose_parameter;
|
||||||
|
using parameters::get_parameter;
|
||||||
|
|
||||||
|
//Dispatch the execution according the apply_iterative_snap_rounding parameter
|
||||||
|
const bool do_snap = choose_parameter(get_parameter(np, internal_np::apply_iterative_snap_rounding), false);
|
||||||
|
if(do_snap)
|
||||||
|
{
|
||||||
|
CGAL_PMP_AUTOREFINE_VERBOSE("Snap polygon soup");
|
||||||
|
return autorefine_impl::polygon_soup_snap_rounding(soup_points, soup_triangles, np);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return autorefine_impl::autorefine_triangle_soup(soup_points, soup_triangles, np);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \ingroup PMP_corefinement_grp
|
* \ingroup PMP_corefinement_grp
|
||||||
* refines a triangle mesh so that no triangles intersects in their interior.
|
* refines a triangle mesh so that no triangles intersects in their interior.
|
||||||
|
|
@ -1717,4 +1816,6 @@ autorefine( TriangleMesh& tm,
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <CGAL/Polygon_mesh_processing/internal/triangle_soup_snap_rounding.h>
|
||||||
|
|
||||||
#endif // CGAL_POLYGON_MESH_PROCESSING_AUTOREFINEMENT_H
|
#endif // CGAL_POLYGON_MESH_PROCESSING_AUTOREFINEMENT_H
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,585 @@
|
||||||
|
// Copyright (c) 2025 GeometryFactory (France).
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is part of CGAL (www.cgal.org).
|
||||||
|
//
|
||||||
|
// $URL$
|
||||||
|
// $Id$
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||||
|
//
|
||||||
|
// Author(s) : Léo Valque
|
||||||
|
|
||||||
|
#ifndef CGAL_POLYGON_MESH_PROCESSING_INTERNAL_POLYGON_SOUP_SNAP_ROUNDING_H
|
||||||
|
#define CGAL_POLYGON_MESH_PROCESSING_INTERNAL_POLYGON_SOUP_SNAP_ROUNDING_H
|
||||||
|
|
||||||
|
#include <CGAL/license/Polygon_mesh_processing/geometric_repair.h>
|
||||||
|
|
||||||
|
#include <CGAL/Algebraic_structure_traits.h>
|
||||||
|
#include <CGAL/number_utils.h>
|
||||||
|
|
||||||
|
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||||
|
#include <CGAL/boost/graph/named_params_helper.h>
|
||||||
|
|
||||||
|
#include <CGAL/Fraction_traits.h>
|
||||||
|
#include <CGAL/Lazy_exact_nt.h>
|
||||||
|
|
||||||
|
namespace CGAL
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace Polygon_mesh_processing
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace autorefine_impl
|
||||||
|
{
|
||||||
|
|
||||||
|
// Certified ceil function for exact number types
|
||||||
|
template <class NT> double double_ceil(const Lazy_exact_nt< NT > &x);
|
||||||
|
template <class NT> double double_ceil(const NT &x);
|
||||||
|
|
||||||
|
template <class NT>
|
||||||
|
double double_ceil(const Lazy_exact_nt< NT > &x){
|
||||||
|
// If both sides are in the same ceil, return this ceil
|
||||||
|
double ceil_left=std::ceil(to_interval(x).first);
|
||||||
|
if(ceil_left==std::ceil(to_interval(x).second))
|
||||||
|
return ceil_left;
|
||||||
|
// If not refine the interval by contracting the DAG and try again
|
||||||
|
x.exact();
|
||||||
|
ceil_left=std::ceil(to_interval(x).first);
|
||||||
|
if(ceil_left==std::ceil(to_interval(x).second))
|
||||||
|
return ceil_left;
|
||||||
|
// If not return the ceil of the exact value
|
||||||
|
return double_ceil( x.exact());
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class NT>
|
||||||
|
double double_ceil(const NT &x){
|
||||||
|
using FT = Fraction_traits<NT>;
|
||||||
|
if constexpr(FT::Is_fraction::value){
|
||||||
|
// If NT is a fraction, the ceil value is the result of the euclidian division of the numerator and the denominator.
|
||||||
|
typename FT::Numerator_type num, r, e;
|
||||||
|
typename FT::Denominator_type denom;
|
||||||
|
typename FT::Decompose()(x,num,denom);
|
||||||
|
div_mod(num, denom, r, e);
|
||||||
|
if((r>=0) && e!=0) //If the result is positive, the ceil value is one above
|
||||||
|
return to_double(r+1);
|
||||||
|
return to_double(r);
|
||||||
|
} else {
|
||||||
|
// Return the ceil of the approximation
|
||||||
|
return std::ceil(to_double(x));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Provides an index to the range, which is used by the visitor to track the correspondence between the input and the output
|
||||||
|
template <typename Range>
|
||||||
|
class Indexes_range : public Range{
|
||||||
|
typedef std::remove_cv_t<typename std::iterator_traits<typename Range::iterator>::value_type> Value_type;
|
||||||
|
public:
|
||||||
|
typedef typename Range::const_iterator const_iterator;
|
||||||
|
typedef typename Range::iterator iterator;
|
||||||
|
|
||||||
|
Indexes_range() = default;
|
||||||
|
Indexes_range(const std::initializer_list<std::size_t> &l): Range(l), m_id(0), modified(true){}
|
||||||
|
Indexes_range(Range &p): Range(p), modified(true){}
|
||||||
|
Indexes_range(Range &&p): Range(std::move(p)), modified(true){}
|
||||||
|
Indexes_range(Range &p, std::size_t id): Range(p), m_id(id),modified(false){}
|
||||||
|
Indexes_range(Range &&p, std::size_t id): Range(std::move(p)), m_id(id),modified(false){}
|
||||||
|
|
||||||
|
inline std::size_t id() const { return m_id; }
|
||||||
|
inline void set_id(std::size_t id){ m_id=id; }
|
||||||
|
inline bool was_modified() const { return modified; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t m_id;
|
||||||
|
bool modified;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Repair_polygon_soup without remove_pinched_polygons since our polygon are triangles
|
||||||
|
template <typename PointRange, typename PolygonRange,
|
||||||
|
typename Polygon = typename ::CGAL::internal::Polygon_types<PointRange, PolygonRange>::Polygon_3>
|
||||||
|
struct Triangle_soup_fixer
|
||||||
|
{
|
||||||
|
template <typename NamedParameters>
|
||||||
|
void operator()(PointRange& points,
|
||||||
|
PolygonRange& polygons,
|
||||||
|
const NamedParameters& np) const
|
||||||
|
{
|
||||||
|
using parameters::get_parameter;
|
||||||
|
using parameters::choose_parameter;
|
||||||
|
|
||||||
|
using Traits = typename GetPolygonGeomTraits<PointRange, PolygonRange, NamedParameters>::type;
|
||||||
|
Traits traits = choose_parameter<Traits>(get_parameter(np, internal_np::geom_traits));
|
||||||
|
|
||||||
|
CGAL::Polygon_mesh_processing::merge_duplicate_points_in_polygon_soup(points, polygons, np);
|
||||||
|
CGAL::Polygon_mesh_processing::internal::simplify_polygons_in_polygon_soup(points, polygons, traits);
|
||||||
|
CGAL::Polygon_mesh_processing::internal::remove_invalid_polygons_in_polygon_soup(points, polygons);
|
||||||
|
CGAL::Polygon_mesh_processing::merge_duplicate_polygons_in_polygon_soup(points, polygons, np);
|
||||||
|
CGAL::Polygon_mesh_processing::remove_isolated_points_in_polygon_soup(points, polygons);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization for array and Indexes_range of array
|
||||||
|
template <typename PointRange, typename PolygonRange, typename PID, std::size_t N>
|
||||||
|
struct Triangle_soup_fixer<PointRange, PolygonRange, std::array<PID, N> >
|
||||||
|
{
|
||||||
|
template <typename NamedParameters>
|
||||||
|
void operator()(PointRange& points,
|
||||||
|
PolygonRange& polygons,
|
||||||
|
const NamedParameters& np) const
|
||||||
|
{
|
||||||
|
repair_polygon_soup(points, polygons, np);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename PointRange, typename PolygonRange, typename PID, std::size_t N>
|
||||||
|
struct Triangle_soup_fixer<PointRange, PolygonRange, Indexes_range< std::array<PID, N> > >
|
||||||
|
{
|
||||||
|
template <typename NamedParameters>
|
||||||
|
void operator()(PointRange& points,
|
||||||
|
PolygonRange& polygons,
|
||||||
|
const NamedParameters& np) const
|
||||||
|
{
|
||||||
|
using parameters::get_parameter;
|
||||||
|
using parameters::choose_parameter;
|
||||||
|
|
||||||
|
using Traits = typename GetPolygonGeomTraits<PointRange, PolygonRange, NamedParameters>::type;
|
||||||
|
Traits traits = choose_parameter<Traits>(get_parameter(np, internal_np::geom_traits));
|
||||||
|
|
||||||
|
CGAL::Polygon_mesh_processing::merge_duplicate_points_in_polygon_soup(points, polygons, np);
|
||||||
|
CGAL::Polygon_mesh_processing::internal::remove_invalid_polygons_in_array_polygon_soup(points, polygons, traits);
|
||||||
|
CGAL::Polygon_mesh_processing::merge_duplicate_polygons_in_polygon_soup(points, polygons, np);
|
||||||
|
CGAL::Polygon_mesh_processing::remove_isolated_points_in_polygon_soup(points, polygons);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename PointRange, typename PolygonRange, typename NamedParameters>
|
||||||
|
void repair_triangle_soup(PointRange& points,
|
||||||
|
PolygonRange& polygons,
|
||||||
|
const NamedParameters& np)
|
||||||
|
{
|
||||||
|
Triangle_soup_fixer<PointRange, PolygonRange> fixer;
|
||||||
|
fixer(points, polygons, np);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A visitor of Autorefinement to track the correspondance between input and output triangles
|
||||||
|
struct Wrap_snap_visitor : public Autorefinement::Default_visitor
|
||||||
|
{
|
||||||
|
template< typename Triangle>
|
||||||
|
void new_subdivision(Triangle& new_t, const Triangle& old_t) {
|
||||||
|
new_t.set_id(old_t.id());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* rounds the coordinates of the points so that they fit in doubles while making and keeping the model intersection free by potentially subdividing the triangles.
|
||||||
|
* The input can be any triangle soup and the output is an intersection-free triangle soup with Hausdorff distance
|
||||||
|
* between the input and the output bounded by `M*2^-gs*k` where `M`is the maximum absolute coordinate in the model, `gs` the `snap_grid_size` (see below) and `k` the number of iterations
|
||||||
|
* performed by the algorithm.
|
||||||
|
*
|
||||||
|
* @tparam PointRange a model of the concept `RandomAccessContainer`
|
||||||
|
* whose value type is the point type
|
||||||
|
* @tparam TriangleRange a model of the concepts `RandomAccessContainer`, `BackInsertionSequence` and `Swappable`, whose
|
||||||
|
* value type is a model of the concept `RandomAccessContainer` whose value type is convertible to `std::size_t` and that
|
||||||
|
* is constructible from an `std::initializer_list<std::size_t>` of size 3.
|
||||||
|
* @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
|
||||||
|
*
|
||||||
|
* @param soup_points points of the soup of polygons
|
||||||
|
* @param soup_triangles each element in the range describes a triangle using the indexed position of the points in `soup_points`
|
||||||
|
* @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
|
||||||
|
*
|
||||||
|
* \cgalNamedParamsBegin
|
||||||
|
* \cgalParamNBegin{concurrency_tag}
|
||||||
|
* \cgalParamDescription{a tag indicating if the task should be done using one or several threads.}
|
||||||
|
* \cgalParamType{Either `CGAL::Sequential_tag`, or `CGAL::Parallel_tag`, or `CGAL::Parallel_if_available_tag`}
|
||||||
|
* \cgalParamDefault{`CGAL::Sequential_tag`}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalParamNBegin{point_map}
|
||||||
|
* \cgalParamDescription{a property map associating points to the elements of the range `soup_points`}
|
||||||
|
* \cgalParamType{a model of `ReadWritePropertyMap` whose value type is a point type}
|
||||||
|
* \cgalParamDefault{`CGAL::Identity_property_map`}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalParamNBegin{geom_traits}
|
||||||
|
* \cgalParamDescription{an instance of a geometric traits class}
|
||||||
|
* \cgalParamType{a class model of `Kernel`}
|
||||||
|
* \cgalParamDefault{a \cgal kernel deduced from the point type, using `CGAL::Kernel_traits`}
|
||||||
|
* \cgalParamExtra{The geometric traits class must be compatible with the point type.}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalParamNBegin{snap_grid_size}
|
||||||
|
* \cgalParamDescription{Scale the points to [-2^gs, 2^gs] where gs is the snap_grid_size before to round them on integer.}
|
||||||
|
* \cgalParamType{unsigned int}
|
||||||
|
* \cgalParamDefault{23}
|
||||||
|
* \cgalParamExtra{Must be lower than 52.}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalParamNBegin{number_of_iterations}
|
||||||
|
* \cgalParamDescription{Maximum number of iteration performed by the algorithm.}
|
||||||
|
* \cgalParamType{unsigned int}
|
||||||
|
* \cgalParamDefault{5}
|
||||||
|
* \cgalParamNEnd
|
||||||
|
* \cgalNamedParamsEnd
|
||||||
|
*
|
||||||
|
* \return `true` if the modified triangle soup is free from self-intersection, and `false` if the algorithm was not
|
||||||
|
* able to provide such a triangle soup within the number of iterations.
|
||||||
|
*/
|
||||||
|
template <typename PointRange, typename PolygonRange, class NamedParameters>
|
||||||
|
bool polygon_soup_snap_rounding_impl(PointRange &points,
|
||||||
|
PolygonRange &triangles,
|
||||||
|
const NamedParameters& np)
|
||||||
|
{
|
||||||
|
using parameters::choose_parameter;
|
||||||
|
using parameters::get_parameter;
|
||||||
|
|
||||||
|
// typedef typename GetPolygonSoupGeomTraits<PointRange, NamedParameters>::type GT;
|
||||||
|
typedef typename GetPointMap<PointRange, NamedParameters>::const_type Point_map;
|
||||||
|
Point_map pm = choose_parameter<Point_map>(get_parameter(np, internal_np::point_map));
|
||||||
|
|
||||||
|
typedef typename internal_np::Lookup_named_param_def <
|
||||||
|
internal_np::concurrency_tag_t,
|
||||||
|
NamedParameters,
|
||||||
|
Sequential_tag
|
||||||
|
> ::type Concurrency_tag;
|
||||||
|
|
||||||
|
// visitor
|
||||||
|
typedef typename internal_np::Lookup_named_param_def <
|
||||||
|
internal_np::visitor_t,
|
||||||
|
NamedParameters,
|
||||||
|
Autorefinement::Default_visitor
|
||||||
|
>::type Visitor;
|
||||||
|
Visitor visitor(choose_parameter<Visitor>(get_parameter(np, internal_np::visitor)));
|
||||||
|
|
||||||
|
constexpr bool has_visitor = !std::is_same_v<Autorefinement::Default_visitor, Visitor>;
|
||||||
|
constexpr bool parallel_execution = std::is_same_v<Parallel_tag, Concurrency_tag>;
|
||||||
|
const size_t number_of_input_triangles = triangles.size();
|
||||||
|
|
||||||
|
#ifndef CGAL_LINKED_WITH_TBB
|
||||||
|
static_assert (!parallel_execution,
|
||||||
|
"Parallel_tag is enabled but TBB is unavailable.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using Point_3 = std::remove_cv_t<typename std::iterator_traits<typename PointRange::const_iterator>::value_type>;
|
||||||
|
using Kernel = typename Kernel_traits<Point_3>::Kernel;
|
||||||
|
|
||||||
|
// Get the grid size from the named parameter, the grid size could not be greater than 52
|
||||||
|
const unsigned int grid_size = (std::min)(52,choose_parameter(get_parameter(np, internal_np::snap_grid_size), 23));
|
||||||
|
const unsigned int max_nb_of_iteration = choose_parameter(get_parameter(np, internal_np::number_of_iterations), 5);
|
||||||
|
|
||||||
|
#ifdef PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
|
||||||
|
std::cout << "Compute the scaling of the coordinates" << std::endl;
|
||||||
|
std::cout << grid_size << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto exp = [](const double v)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
frexp(v, &n);
|
||||||
|
return n;
|
||||||
|
};
|
||||||
|
auto pow_2 = [](const int k)
|
||||||
|
{
|
||||||
|
return (k>=0)?std::pow(2,k):1./std::pow(2,-k);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get max absolute value of each dimension
|
||||||
|
Bbox_3 bb = bbox_3(points.begin(), points.end());
|
||||||
|
std::array<double, 3> max_abs{(std::max)(-bb.xmin(), bb.xmax()),
|
||||||
|
(std::max)(-bb.ymin(), bb.ymax()),
|
||||||
|
(std::max)(-bb.zmin(), bb.zmax())};
|
||||||
|
// Compute scale so that the exponent of max absolute value are 52-1.
|
||||||
|
std::array<double, 3> scale{pow_2(grid_size - exp(max_abs[0]) - 1),
|
||||||
|
pow_2(grid_size - exp(max_abs[1]) - 1),
|
||||||
|
pow_2(grid_size - exp(max_abs[2]) - 1)};
|
||||||
|
|
||||||
|
#ifdef PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
|
||||||
|
std::cout << "Scaling: " << scale[0] << " " << scale[1] << " " << scale[2] << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto snap = [](typename Kernel::FT x, double scale)
|
||||||
|
{
|
||||||
|
// Scale the coordinate, round to nearest integer and scale back
|
||||||
|
return double_ceil((x * scale) - 0.5) / scale;
|
||||||
|
};
|
||||||
|
auto snap_p = [scale, snap](const Point_3 &p)
|
||||||
|
{
|
||||||
|
return Point_3( snap(p.x(),scale[0]),
|
||||||
|
snap(p.y(),scale[1]),
|
||||||
|
snap(p.z(),scale[2]) );
|
||||||
|
};
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < max_nb_of_iteration; ++i)
|
||||||
|
{
|
||||||
|
#ifdef PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
|
||||||
|
std::cout << "Start Iteration " << i << std::endl;
|
||||||
|
std::cout << "Model size: " << points.size() << " " << triangles.size() << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
|
||||||
|
std::cout << "Round all coordinates on doubles" << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
if constexpr (parallel_execution)
|
||||||
|
{
|
||||||
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, points.size()),
|
||||||
|
[&](const tbb::blocked_range<size_t>& r){
|
||||||
|
for(size_t pi = r.begin(); pi != r.end(); ++pi)
|
||||||
|
points[pi] = Point_3(to_double(points[pi].x()), to_double(points[pi].y()), to_double(points[pi].z()));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
for (Point_3 &p : points)
|
||||||
|
p = Point_3(to_double(p.x()), to_double(p.y()), to_double(p.z()));
|
||||||
|
repair_triangle_soup(points, triangles, np);
|
||||||
|
|
||||||
|
// Get all intersecting triangles
|
||||||
|
std::vector<std::pair<std::size_t, std::size_t>> pairs_of_intersecting_triangles;
|
||||||
|
triangle_soup_self_intersections<Concurrency_tag>(points, triangles, std::back_inserter(pairs_of_intersecting_triangles), np);
|
||||||
|
|
||||||
|
if (pairs_of_intersecting_triangles.empty())
|
||||||
|
{
|
||||||
|
#ifdef PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
|
||||||
|
std::cout << "End of the snapping" << std::endl;
|
||||||
|
#endif
|
||||||
|
if constexpr(has_visitor)
|
||||||
|
{
|
||||||
|
std::vector<std::vector<size_t> > map_io(number_of_input_triangles);
|
||||||
|
size_t id=0;
|
||||||
|
for(auto &t: triangles)
|
||||||
|
map_io[t.id()].push_back(id++);
|
||||||
|
|
||||||
|
visitor.number_of_output_triangles(triangles.size());
|
||||||
|
for(size_t src_id=0; src_id!=map_io.size(); ++src_id){
|
||||||
|
if(map_io[src_id].size()==0)
|
||||||
|
visitor.delete_triangle(src_id);
|
||||||
|
else if(map_io[src_id].size()==1 && !triangles[map_io[src_id][0]].was_modified())
|
||||||
|
visitor.verbatim_triangle_copy(map_io[src_id][0],src_id);
|
||||||
|
else
|
||||||
|
for(size_t new_id: map_io[src_id])
|
||||||
|
visitor.new_subtriangle(new_id,src_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
|
||||||
|
std::cout << "Number of pairs of intersecting triangles: " << pairs_of_intersecting_triangles.size() << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
|
||||||
|
std::cout << "Snap the coordinates of the vertices of the intersecting triangles" << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Variants of the rounding process depending of the macros defined
|
||||||
|
#if defined(PMP_ROUNDING_VERTICES_NAIVE_SNAP)
|
||||||
|
// Nothing
|
||||||
|
|
||||||
|
#elif defined(PMP_ROUNDING_VERTICES_CLOSEST_POINT_SNAP)
|
||||||
|
// Version where points in a voxel are rounded to the closest point
|
||||||
|
|
||||||
|
// Group the points of the vertices of the intersecting triangles by their voxel
|
||||||
|
std::map<Point_3, size_t> snap_points;
|
||||||
|
std::size_t index=0;
|
||||||
|
for (auto &pair : pairs_of_intersecting_triangles)
|
||||||
|
{
|
||||||
|
for (size_t pi : triangles[pair.first])
|
||||||
|
{
|
||||||
|
auto res=snap_points.emplace(snap_p(points[pi]), index);
|
||||||
|
if(res.second)
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
for (size_t pi : triangles[pair.second])
|
||||||
|
{
|
||||||
|
auto res=snap_points.emplace(snap_p(points[pi]), index);
|
||||||
|
if(res.second)
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<size_t>> identical_points(index);
|
||||||
|
for (size_t i=0; i!=points.size(); ++i)
|
||||||
|
{
|
||||||
|
Point_3 p_snap = snap_p(points[i]);
|
||||||
|
auto it=snap_points.find(p_snap);
|
||||||
|
if (it!=snap_points.end()){
|
||||||
|
identical_points[it->second].push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace all points in a voxel by the closest point
|
||||||
|
for(const auto &v: identical_points){
|
||||||
|
if(v.size()>1){
|
||||||
|
Point_3 center = snap_p(points[v[0]]);
|
||||||
|
size_t argmin(0);
|
||||||
|
for(size_t i=1; i!=v.size(); ++i){
|
||||||
|
if(Kernel().compare_distance_3_object()(center, points[v[i]], points[v[argmin]])==SMALLER)
|
||||||
|
{
|
||||||
|
argmin=i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(auto i: v){
|
||||||
|
points[i]=points[v[argmin]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(PMP_ROUNDING_VERTICES_BARYCENTER_SNAP)
|
||||||
|
// Version where points in a voxel are rounded to their barycenter.
|
||||||
|
|
||||||
|
// Group the points of the vertices of the intersecting triangles by their voxel
|
||||||
|
std::map<Point_3, size_t> snap_points;
|
||||||
|
std::size_t index=0;
|
||||||
|
for (const auto &pair : pairs_of_intersecting_triangles)
|
||||||
|
{
|
||||||
|
for (size_t pi : triangles[pair.first])
|
||||||
|
{
|
||||||
|
auto res=snap_points.emplace(snap_p(points[pi]), index);
|
||||||
|
if(res.second)
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
for (size_t pi : triangles[pair.second])
|
||||||
|
{
|
||||||
|
auto res=snap_points.emplace(snap_p(points[pi]), index);
|
||||||
|
if(res.second)
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<size_t>> identical_points(index);
|
||||||
|
for (size_t i=0; i!=points.size(); ++i)
|
||||||
|
{
|
||||||
|
Point_3 p_snap = snap_p(points[i]);
|
||||||
|
auto it=snap_points.find(p_snap);
|
||||||
|
if (it!=snap_points.end()){
|
||||||
|
identical_points[it->second].push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace all points in a voxel by their barycenter
|
||||||
|
for(const auto &v: identical_points){
|
||||||
|
if(v.size()>1){
|
||||||
|
std::array<double, 3> a{0,0,0};
|
||||||
|
for(auto i: v){
|
||||||
|
a[0]+=to_double(points[i].x());
|
||||||
|
a[1]+=to_double(points[i].y());
|
||||||
|
a[2]+=to_double(points[i].z());
|
||||||
|
}
|
||||||
|
a[0]/=v.size();
|
||||||
|
a[1]/=v.size();
|
||||||
|
a[2]/=v.size();
|
||||||
|
for(auto i: v){
|
||||||
|
points[i]=Point_3(a[0],a[1],a[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(PMP_ROUNDING_VERTICES_FLOAT_SNAP)
|
||||||
|
// Version where points are rounded to the closest simple precision float.
|
||||||
|
|
||||||
|
for (const auto &pair : pairs_of_intersecting_triangles)
|
||||||
|
{
|
||||||
|
for (size_t pi : triangles[pair.first])
|
||||||
|
points[pi]=Point_3( (float) to_double(points[pi].x()), (float) to_double(points[pi].y()), (float) to_double(points[pi].z()));
|
||||||
|
for (size_t pi : triangles[pair.second])
|
||||||
|
points[pi]=Point_3( (float) to_double(points[pi].x()), (float) to_double(points[pi].y()), (float) to_double(points[pi].z()));
|
||||||
|
}
|
||||||
|
#else // Default Version
|
||||||
|
// Version where points are rounded to the center of their voxel.
|
||||||
|
|
||||||
|
// Get all the snap version of the points of the vertices of the intersecting triangles
|
||||||
|
// Note: points will not be modified here, they will be modified in the next for loop
|
||||||
|
|
||||||
|
std::vector<Point_3> snap_points;
|
||||||
|
snap_points.reserve(pairs_of_intersecting_triangles.size() * 3);
|
||||||
|
|
||||||
|
for (const auto &pair : pairs_of_intersecting_triangles)
|
||||||
|
{
|
||||||
|
for (size_t pi : triangles[pair.first])
|
||||||
|
snap_points.emplace_back(snap_p(points[pi]));
|
||||||
|
for (size_t pi : triangles[pair.second])
|
||||||
|
snap_points.emplace_back(snap_p(points[pi]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
|
||||||
|
std::cout << "Snap the coordinates of the vertices close-by the previous ones" << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::sort(snap_points.begin(), snap_points.end());
|
||||||
|
snap_points.erase(std::unique(snap_points.begin(), snap_points.end()), snap_points.end());
|
||||||
|
|
||||||
|
// If the snapped version of a point correspond to one of the previous point, we snap it
|
||||||
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
if constexpr(parallel_execution)
|
||||||
|
{
|
||||||
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, points.size()),
|
||||||
|
[&](const tbb::blocked_range<size_t>& r){
|
||||||
|
for(size_t pi = r.begin(); pi != r.end(); ++pi){
|
||||||
|
Point_3 p_snap=snap_p(points[pi]);
|
||||||
|
if (std::binary_search(snap_points.begin(), snap_points.end(), p_snap))
|
||||||
|
points[pi] = p_snap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
for (Point_3 &p : points)
|
||||||
|
{
|
||||||
|
Point_3 p_snap = snap_p(p);
|
||||||
|
if (std::binary_search(snap_points.begin(), snap_points.end(), p_snap))
|
||||||
|
p = p_snap;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
repair_triangle_soup(points, triangles, np);
|
||||||
|
#ifdef PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
|
||||||
|
std::cout << "Model size: " << points.size() << " " << triangles.size() << std::endl;
|
||||||
|
std::cout << "Autorefine the soup" << std::endl;
|
||||||
|
#endif
|
||||||
|
if constexpr(has_visitor)
|
||||||
|
{
|
||||||
|
Wrap_snap_visitor visitor;
|
||||||
|
autorefine_triangle_soup(points, triangles, parameters::point_map(pm).concurrency_tag(Concurrency_tag()).visitor(visitor));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
autorefine_triangle_soup(points, triangles, parameters::point_map(pm).concurrency_tag(Concurrency_tag()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename PointRange, typename PolygonRange, class NamedParameters>
|
||||||
|
bool polygon_soup_snap_rounding(PointRange &soup_points,
|
||||||
|
PolygonRange &soup_triangles,
|
||||||
|
const NamedParameters& np)
|
||||||
|
{
|
||||||
|
typedef typename internal_np::Lookup_named_param_def <
|
||||||
|
internal_np::visitor_t,
|
||||||
|
NamedParameters,
|
||||||
|
Autorefinement::Default_visitor//default
|
||||||
|
> ::type Visitor;
|
||||||
|
|
||||||
|
constexpr bool has_visitor = !std::is_same_v<Autorefinement::Default_visitor, Visitor>;
|
||||||
|
if constexpr(has_visitor)
|
||||||
|
{
|
||||||
|
//If a visitor is provided, we color the triangles with the index of their source to correctly track the modification
|
||||||
|
using Triangle = std::remove_cv_t<typename std::iterator_traits<typename PolygonRange::iterator>::value_type>;
|
||||||
|
std::vector<Indexes_range<Triangle> > indexes_soup_triangles;
|
||||||
|
size_t id=0;
|
||||||
|
for(typename PolygonRange::iterator it=soup_triangles.begin(); it!=soup_triangles.end(); ++it)
|
||||||
|
indexes_soup_triangles.emplace_back((*it), id++);
|
||||||
|
|
||||||
|
bool res=polygon_soup_snap_rounding_impl(soup_points, indexes_soup_triangles, np);
|
||||||
|
|
||||||
|
soup_triangles.clear();
|
||||||
|
soup_triangles.reserve(indexes_soup_triangles.size());
|
||||||
|
for(const Indexes_range<Triangle> &t: indexes_soup_triangles)
|
||||||
|
soup_triangles.push_back({t[0],t[1],t[2]});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return polygon_soup_snap_rounding_impl(soup_points, soup_triangles, np);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} } } //end of CGAL::Polygon_mesh_processing::autorefine_impl namespace
|
||||||
|
|
||||||
|
#endif //CGAL_POLYGON_MESH_PROCESSING_POLYGON_SOUP_SNAP_ROUNDING_H
|
||||||
|
|
@ -43,6 +43,7 @@ create_single_source_cgal_program("test_coref_epic_points_identity.cpp")
|
||||||
create_single_source_cgal_program("test_does_bound_a_volume.cpp")
|
create_single_source_cgal_program("test_does_bound_a_volume.cpp")
|
||||||
create_single_source_cgal_program("test_pmp_clip.cpp")
|
create_single_source_cgal_program("test_pmp_clip.cpp")
|
||||||
create_single_source_cgal_program("test_autorefinement.cpp")
|
create_single_source_cgal_program("test_autorefinement.cpp")
|
||||||
|
create_single_source_cgal_program("test_snap_rounding.cpp")
|
||||||
create_single_source_cgal_program("autorefinement_sm.cpp")
|
create_single_source_cgal_program("autorefinement_sm.cpp")
|
||||||
create_single_source_cgal_program( "corefine_non_manifold.cpp" )
|
create_single_source_cgal_program( "corefine_non_manifold.cpp" )
|
||||||
create_single_source_cgal_program("triangulate_hole_polyline_test.cpp")
|
create_single_source_cgal_program("triangulate_hole_polyline_test.cpp")
|
||||||
|
|
@ -115,6 +116,7 @@ if(TARGET CGAL::TBB_support)
|
||||||
target_link_libraries(orient_polygon_soup_test PRIVATE CGAL::TBB_support)
|
target_link_libraries(orient_polygon_soup_test PRIVATE CGAL::TBB_support)
|
||||||
target_link_libraries(self_intersection_surface_mesh_test PRIVATE CGAL::TBB_support)
|
target_link_libraries(self_intersection_surface_mesh_test PRIVATE CGAL::TBB_support)
|
||||||
target_link_libraries(test_autorefinement PRIVATE CGAL::TBB_support)
|
target_link_libraries(test_autorefinement PRIVATE CGAL::TBB_support)
|
||||||
|
target_link_libraries(test_snap_rounding PRIVATE CGAL::TBB_support)
|
||||||
else()
|
else()
|
||||||
message(STATUS "NOTICE: Intel TBB was not found. Tests will use sequential code.")
|
message(STATUS "NOTICE: Intel TBB was not found. Tests will use sequential code.")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
OFF
|
||||||
|
8 4 0
|
||||||
|
|
||||||
|
0 0 0
|
||||||
|
0 1 0
|
||||||
|
1 1 0
|
||||||
|
1 0 0
|
||||||
|
0 0 1
|
||||||
|
0 1 1
|
||||||
|
1 1 -1e-10
|
||||||
|
1 0 -1e-10
|
||||||
|
3 0 1 2
|
||||||
|
3 0 2 3
|
||||||
|
3 4 5 7
|
||||||
|
3 5 6 7
|
||||||
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
OFF
|
||||||
|
12 4 0
|
||||||
|
|
||||||
|
-1 -1 -1
|
||||||
|
-1 -1 1
|
||||||
|
1 -1e-15 0
|
||||||
|
-1 1 -1
|
||||||
|
-1 1 1
|
||||||
|
1 1e-15 0
|
||||||
|
0 -1e-15 -1
|
||||||
|
0 -1e-15 1
|
||||||
|
0 -2 0
|
||||||
|
0 1e-15 -1
|
||||||
|
0 1e-15 1
|
||||||
|
0 2 0
|
||||||
|
3 0 1 2
|
||||||
|
3 3 4 5
|
||||||
|
3 6 7 8
|
||||||
|
3 9 10 11
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
OFF
|
||||||
|
12 4 0
|
||||||
|
|
||||||
|
-1 -1 -1
|
||||||
|
-1 -1 1
|
||||||
|
1 -1e-15 0
|
||||||
|
1 1 -1
|
||||||
|
1 1 1
|
||||||
|
1 1e-15 0
|
||||||
|
0 -1e-15 -1
|
||||||
|
0 -1e-15 1
|
||||||
|
0 -2 0
|
||||||
|
0 1e-15 -1
|
||||||
|
0 1e-15 1
|
||||||
|
0 2 0
|
||||||
|
3 0 1 2
|
||||||
|
3 3 4 5
|
||||||
|
3 6 7 8
|
||||||
|
3 9 10 11
|
||||||
|
|
@ -0,0 +1,202 @@
|
||||||
|
OFF
|
||||||
|
80 120 0
|
||||||
|
-1 -5.627423701743102e-06 1.4142135623618981
|
||||||
|
1 -5.627423701743102e-06 1.4142135623618981
|
||||||
|
1 -1.4142135623618981 -5.627423701743102e-06
|
||||||
|
-1 -1.4142135623618981 -5.627423701743102e-06
|
||||||
|
-1 5.627423701743102e-06 -1.4142135623618981
|
||||||
|
-1 1.4142135623618981 5.627423701743102e-06
|
||||||
|
1 1.4142135623618981 5.627423701743102e-06
|
||||||
|
1 5.627423701743102e-06 -1.4142135623618981
|
||||||
|
-1 -4.9339086289293424e-06 1.4142135623644878
|
||||||
|
1 -4.9339086289293424e-06 1.4142135623644878
|
||||||
|
1 -1.4142135623644878 -4.9339086289293424e-06
|
||||||
|
-1 -1.4142135623644878 -4.9339086289293424e-06
|
||||||
|
-1 4.9339086289293424e-06 -1.4142135623644878
|
||||||
|
-1 1.4142135623644878 4.9339086289293424e-06
|
||||||
|
1 1.4142135623644878 4.9339086289293424e-06
|
||||||
|
1 4.9339086289293424e-06 -1.4142135623644878
|
||||||
|
-1 -4.3072127542901049e-06 1.4142135623665355
|
||||||
|
1 -4.3072127542901049e-06 1.4142135623665355
|
||||||
|
1 -1.4142135623665355 -4.3072127542901049e-06
|
||||||
|
-1 -1.4142135623665355 -4.3072127542901049e-06
|
||||||
|
-1 4.3072127542901049e-06 -1.4142135623665355
|
||||||
|
-1 1.4142135623665355 4.3072127542901049e-06
|
||||||
|
1 1.4142135623665355 4.3072127542901049e-06
|
||||||
|
1 4.3072127542901049e-06 -1.4142135623665355
|
||||||
|
-1 -3.7949909043547426e-06 1.4142135623680028
|
||||||
|
1 -3.7949909043547426e-06 1.4142135623680028
|
||||||
|
1 -1.4142135623680028 -3.7949909043547426e-06
|
||||||
|
-1 -1.4142135623680028 -3.7949909043547426e-06
|
||||||
|
-1 3.7949909043547426e-06 -1.4142135623680028
|
||||||
|
-1 1.4142135623680028 3.7949909043547426e-06
|
||||||
|
1 1.4142135623680028 3.7949909043547426e-06
|
||||||
|
1 3.7949909043547426e-06 -1.4142135623680028
|
||||||
|
-1 -3.6070768958898969e-06 1.4142135623684944
|
||||||
|
1 -3.6070768958898969e-06 1.4142135623684944
|
||||||
|
1 -1.4142135623684944 -3.6070768958898969e-06
|
||||||
|
-1 -1.4142135623684944 -3.6070768958898969e-06
|
||||||
|
-1 3.6070768958898969e-06 -1.4142135623684944
|
||||||
|
-1 1.4142135623684944 3.6070768958898969e-06
|
||||||
|
1 1.4142135623684944 3.6070768958898969e-06
|
||||||
|
1 3.6070768958898969e-06 -1.4142135623684944
|
||||||
|
-1 -2.4904507319126939e-06 1.4142135623709018
|
||||||
|
1 -2.4904507319126939e-06 1.4142135623709018
|
||||||
|
1 -1.4142135623709018 -2.4904507319126939e-06
|
||||||
|
-1 -1.4142135623709018 -2.4904507319126939e-06
|
||||||
|
-1 2.4904507319126939e-06 -1.4142135623709018
|
||||||
|
-1 1.4142135623709018 2.4904507319126939e-06
|
||||||
|
1 1.4142135623709018 2.4904507319126939e-06
|
||||||
|
1 2.4904507319126939e-06 -1.4142135623709018
|
||||||
|
-1 0.99999891029865429 1.0000010897001574
|
||||||
|
1 0.99999891029865429 1.0000010897001574
|
||||||
|
1 -1.0000010897001574 0.99999891029865429
|
||||||
|
-1 -1.0000010897001574 0.99999891029865429
|
||||||
|
-1 -0.99999891029865429 -1.0000010897001574
|
||||||
|
-1 1.0000010897001574 -0.99999891029865429
|
||||||
|
1 1.0000010897001574 -0.99999891029865429
|
||||||
|
1 -0.99999891029865429 -1.0000010897001574
|
||||||
|
-1 1.4142135623724554 1.3448878106118537e-06
|
||||||
|
1 1.4142135623724554 1.3448878106118537e-06
|
||||||
|
1 -1.3448878106118537e-06 1.4142135623724554
|
||||||
|
-1 -1.3448878106118537e-06 1.4142135623724554
|
||||||
|
-1 -1.4142135623724554 -1.3448878106118537e-06
|
||||||
|
-1 1.3448878106118537e-06 -1.4142135623724554
|
||||||
|
1 1.3448878106118537e-06 -1.4142135623724554
|
||||||
|
1 -1.4142135623724554 -1.3448878106118537e-06
|
||||||
|
-1 1.0000000341206472 -0.99999996587935136
|
||||||
|
1 1.0000000341206472 -0.99999996587935136
|
||||||
|
1 0.99999996587935136 1.0000000341206472
|
||||||
|
-1 0.99999996587935136 1.0000000341206472
|
||||||
|
-1 -1.0000000341206472 0.99999996587935136
|
||||||
|
-1 -0.99999996587935136 -1.0000000341206472
|
||||||
|
1 -0.99999996587935136 -1.0000000341206472
|
||||||
|
1 -1.0000000341206472 0.99999996587935136
|
||||||
|
-1 1.5942993642314858e-08 -1.4142135623730947
|
||||||
|
1 1.5942993642314858e-08 -1.4142135623730947
|
||||||
|
1 1.4142135623730947 1.5942993642314858e-08
|
||||||
|
-1 1.4142135623730947 1.5942993642314858e-08
|
||||||
|
-1 -1.5942993642314858e-08 1.4142135623730947
|
||||||
|
-1 -1.4142135623730947 -1.5942993642314858e-08
|
||||||
|
1 -1.4142135623730947 -1.5942993642314858e-08
|
||||||
|
1 -1.5942993642314858e-08 1.4142135623730947
|
||||||
|
3 6 7 4
|
||||||
|
3 3 2 1
|
||||||
|
3 6 1 2
|
||||||
|
3 5 0 1
|
||||||
|
3 4 3 0
|
||||||
|
3 7 2 3
|
||||||
|
3 1 0 3
|
||||||
|
3 4 5 6
|
||||||
|
3 2 7 6
|
||||||
|
3 1 6 5
|
||||||
|
3 0 5 4
|
||||||
|
3 3 4 7
|
||||||
|
3 14 15 12
|
||||||
|
3 11 10 9
|
||||||
|
3 14 9 10
|
||||||
|
3 13 8 9
|
||||||
|
3 12 11 8
|
||||||
|
3 15 10 11
|
||||||
|
3 9 8 11
|
||||||
|
3 12 13 14
|
||||||
|
3 10 15 14
|
||||||
|
3 9 14 13
|
||||||
|
3 8 13 12
|
||||||
|
3 11 12 15
|
||||||
|
3 22 23 20
|
||||||
|
3 19 18 17
|
||||||
|
3 22 17 18
|
||||||
|
3 21 16 17
|
||||||
|
3 20 19 16
|
||||||
|
3 23 18 19
|
||||||
|
3 17 16 19
|
||||||
|
3 20 21 22
|
||||||
|
3 18 23 22
|
||||||
|
3 17 22 21
|
||||||
|
3 16 21 20
|
||||||
|
3 19 20 23
|
||||||
|
3 30 31 28
|
||||||
|
3 27 26 25
|
||||||
|
3 30 25 26
|
||||||
|
3 29 24 25
|
||||||
|
3 28 27 24
|
||||||
|
3 31 26 27
|
||||||
|
3 25 24 27
|
||||||
|
3 28 29 30
|
||||||
|
3 26 31 30
|
||||||
|
3 25 30 29
|
||||||
|
3 24 29 28
|
||||||
|
3 27 28 31
|
||||||
|
3 38 39 36
|
||||||
|
3 35 34 33
|
||||||
|
3 38 33 34
|
||||||
|
3 37 32 33
|
||||||
|
3 36 35 32
|
||||||
|
3 39 34 35
|
||||||
|
3 33 32 35
|
||||||
|
3 36 37 38
|
||||||
|
3 34 39 38
|
||||||
|
3 33 38 37
|
||||||
|
3 32 37 36
|
||||||
|
3 35 36 39
|
||||||
|
3 46 47 44
|
||||||
|
3 43 42 41
|
||||||
|
3 46 41 42
|
||||||
|
3 45 40 41
|
||||||
|
3 44 43 40
|
||||||
|
3 47 42 43
|
||||||
|
3 41 40 43
|
||||||
|
3 44 45 46
|
||||||
|
3 42 47 46
|
||||||
|
3 41 46 45
|
||||||
|
3 40 45 44
|
||||||
|
3 43 44 47
|
||||||
|
3 54 55 52
|
||||||
|
3 51 50 49
|
||||||
|
3 54 49 50
|
||||||
|
3 53 48 49
|
||||||
|
3 52 51 48
|
||||||
|
3 55 50 51
|
||||||
|
3 49 48 51
|
||||||
|
3 52 53 54
|
||||||
|
3 50 55 54
|
||||||
|
3 49 54 53
|
||||||
|
3 48 53 52
|
||||||
|
3 51 52 55
|
||||||
|
3 62 63 60
|
||||||
|
3 59 58 57
|
||||||
|
3 62 57 58
|
||||||
|
3 61 56 57
|
||||||
|
3 60 59 56
|
||||||
|
3 63 58 59
|
||||||
|
3 57 56 59
|
||||||
|
3 60 61 62
|
||||||
|
3 58 63 62
|
||||||
|
3 57 62 61
|
||||||
|
3 56 61 60
|
||||||
|
3 59 60 63
|
||||||
|
3 70 71 68
|
||||||
|
3 67 66 65
|
||||||
|
3 70 65 66
|
||||||
|
3 69 64 65
|
||||||
|
3 68 67 64
|
||||||
|
3 71 66 67
|
||||||
|
3 65 64 67
|
||||||
|
3 68 69 70
|
||||||
|
3 66 71 70
|
||||||
|
3 65 70 69
|
||||||
|
3 64 69 68
|
||||||
|
3 67 68 71
|
||||||
|
3 78 79 76
|
||||||
|
3 75 74 73
|
||||||
|
3 78 73 74
|
||||||
|
3 77 72 73
|
||||||
|
3 76 75 72
|
||||||
|
3 79 74 75
|
||||||
|
3 73 72 75
|
||||||
|
3 76 77 78
|
||||||
|
3 74 79 78
|
||||||
|
3 73 78 77
|
||||||
|
3 72 77 76
|
||||||
|
3 75 76 79
|
||||||
|
|
@ -0,0 +1,204 @@
|
||||||
|
OFF
|
||||||
|
80 120 0
|
||||||
|
|
||||||
|
-0.61594615543034026 -1.0701741879286757 -1.2146347356723264
|
||||||
|
1.0452131429007676 -1.3737111650653515 -0.14299342950741956
|
||||||
|
1.5883443594490732 0.52704573278436739 -0.44652546552251943
|
||||||
|
-0.072814938882034802 0.83058270992104299 -1.5181667716874265
|
||||||
|
-1.0452131429007676 1.3737111650653515 0.14299342950741956
|
||||||
|
-1.5883443594490732 -0.52704573278436739 0.44652546552251943
|
||||||
|
0.072814938882034802 -0.83058270992104299 1.5181667716874265
|
||||||
|
0.61594615543034026 1.0701741879286757 1.2146347356723264
|
||||||
|
-0.61594639934604423 -1.0701743934138028 -1.2146344309355146
|
||||||
|
1.0452122820086462 -1.3737119347288513 -0.14299232819208521
|
||||||
|
1.5883448836888012 0.52704444686667884 -0.44652511853937799
|
||||||
|
-0.072813797665889982 0.83058198818172735 -1.518167221282807
|
||||||
|
-1.0452122820086462 1.3737119347288513 0.14299232819208521
|
||||||
|
-1.5883448836888012 -0.52704444686667884 0.44652511853937799
|
||||||
|
0.072813797665889982 -0.83058198818172735 1.518167221282807
|
||||||
|
0.61594639934604423 1.0701743934138028 1.2146344309355146
|
||||||
|
-0.6159463762173395 -1.07017459735539 -1.2146342629779363
|
||||||
|
1.0452117929893034 -1.3737123992443807 -0.14299144015755649
|
||||||
|
1.5883452549553072 0.52704365666978259 -0.44652473058622827
|
||||||
|
-0.072812914251335584 0.83058145855877352 -1.518167553406609
|
||||||
|
-1.0452117929893034 1.3737123992443807 0.14299144015755649
|
||||||
|
-1.5883452549553072 -0.52704365666978259 0.44652473058622827
|
||||||
|
0.072812914251335584 -0.83058145855877352 1.518167553406609
|
||||||
|
0.6159463762173395 1.07017459735539 1.2146342629779363
|
||||||
|
-0.61594668912789197 -1.0701744000985252 -1.2146342780961472
|
||||||
|
1.0452104492672072 -1.3737135467380566 -0.14299023830665158
|
||||||
|
1.5883461040242048 0.52704182836364122 -0.44652386832759344
|
||||||
|
-0.072811034370893465 0.83058097500317263 -1.5181679081170896
|
||||||
|
-1.0452104492672072 1.3737135467380566 0.14299023830665158
|
||||||
|
-1.5883461040242048 -0.52704182836364122 0.44652386832759344
|
||||||
|
0.072811034370893465 -0.83058097500317263 1.5181679081170896
|
||||||
|
0.61594668912789197 1.0701744000985252 1.2146342780961472
|
||||||
|
-0.6159468868925585 -1.070174149353629 -1.2146343987318162
|
||||||
|
1.0452090174071582 -1.3737147790282049 -0.14298886603597585
|
||||||
|
1.5883470704382798 0.52703987181399814 -0.44652274001266495
|
||||||
|
-0.072808833861436925 0.83058050148857432 -1.5181682727085062
|
||||||
|
-1.0452090174071582 1.3737147790282049 0.14298886603597585
|
||||||
|
-1.5883470704382798 -0.52703987181399814 0.44652274001266495
|
||||||
|
0.072808833861436925 -0.83058050148857432 1.5181682727085062
|
||||||
|
0.6159468868925585 1.070174149353629 1.2146343987318162
|
||||||
|
-0.61594620872112704 -1.0701743005704609 -1.2146346094034179
|
||||||
|
1.0452091168725113 -1.3737147792450597 -0.14298813688653067
|
||||||
|
1.5883473052656241 0.52703984477504562 -0.44652193661109801
|
||||||
|
-0.072808020328014339 0.83058032344964505 -1.5181684091279861
|
||||||
|
-1.0452091168725113 1.3737147792450597 0.14298813688653067
|
||||||
|
-1.5883473052656241 -0.52703984477504562 0.44652193661109801
|
||||||
|
0.072808020328014339 -0.83058032344964505 1.5181684091279861
|
||||||
|
0.61594620872112704 1.0701743005704609 1.2146346094034179
|
||||||
|
0.015812704102963069 -1.4305657319567158 -0.97633582590218304
|
||||||
|
-0.063147971057831695 -1.3970994075162435 1.0218246323460018
|
||||||
|
1.3734324159237437 -0.0060147457399582988 1.0552948506097966
|
||||||
|
1.4523930910845384 -0.03948107018043074 -0.94286560763838845
|
||||||
|
0.063147971057831695 1.3970994075162435 -1.0218246323460018
|
||||||
|
-1.3734324159237437 0.0060147457399582988 -1.0552948506097966
|
||||||
|
-1.4523930910845384 0.03948107018043074 0.94286560763838845
|
||||||
|
-0.015812704102963069 1.4305657319567158 0.97633582590218304
|
||||||
|
-0.017005997503037738 -1.7115480160220284 -0.26516822000379986
|
||||||
|
-1.4526640017493855 -0.672335677974221 0.66161320584190753
|
||||||
|
-0.062496589720092359 0.32138030895690106 1.7008259385628288
|
||||||
|
1.3731614145262554 -0.71783202909090671 0.77404451271712071
|
||||||
|
1.4526640017493855 0.672335677974221 -0.66161320584190753
|
||||||
|
0.062496589720092359 -0.32138030895690106 -1.7008259385628288
|
||||||
|
-1.3731614145262554 0.71783202909090671 -0.77404451271712071
|
||||||
|
0.017005997503037738 1.7115480160220284 0.26516822000379986
|
||||||
|
-0.67677662809399264 -1.5909903432533568 0.10355251489119292
|
||||||
|
-1.5303314706074931 -0.030328946305495721 -0.81065760039877899
|
||||||
|
-1.0732219475484153 1.1338825933415291 0.75000327720449067
|
||||||
|
-0.21966710503491477 -0.42677880360633264 1.6642133924944624
|
||||||
|
1.5303314706074931 0.030328946305495721 0.81065760039877899
|
||||||
|
1.0732219475484153 -1.1338825933415291 -0.75000327720449067
|
||||||
|
0.21966710503491477 0.42677880360633264 -1.6642133924944624
|
||||||
|
0.67677662809399264 1.5909903432533568 -0.10355251489119292
|
||||||
|
-1.207106772440474 -1.2071067303442111 -0.29289346439627145
|
||||||
|
-0.20710789493838763 -0.20710532012834212 -1.7071068233208859
|
||||||
|
-0.50000073181889593 1.5000005345367655 -0.70710512978621964
|
||||||
|
-1.4999996093209822 0.4999991243208966 0.70710822913839488
|
||||||
|
0.20710789493838763 0.20710532012834212 1.7071068233208859
|
||||||
|
0.50000073181889593 -1.5000005345367655 0.70710512978621964
|
||||||
|
1.4999996093209822 -0.4999991243208966 -0.70710822913839488
|
||||||
|
1.207106772440474 1.2071067303442111 0.29289346439627145
|
||||||
|
3 6 7 4
|
||||||
|
3 3 2 1
|
||||||
|
3 6 1 2
|
||||||
|
3 5 0 1
|
||||||
|
3 4 3 0
|
||||||
|
3 7 2 3
|
||||||
|
3 1 0 3
|
||||||
|
3 4 5 6
|
||||||
|
3 2 7 6
|
||||||
|
3 1 6 5
|
||||||
|
3 0 5 4
|
||||||
|
3 3 4 7
|
||||||
|
3 14 15 12
|
||||||
|
3 11 10 9
|
||||||
|
3 14 9 10
|
||||||
|
3 13 8 9
|
||||||
|
3 12 11 8
|
||||||
|
3 15 10 11
|
||||||
|
3 9 8 11
|
||||||
|
3 12 13 14
|
||||||
|
3 10 15 14
|
||||||
|
3 9 14 13
|
||||||
|
3 8 13 12
|
||||||
|
3 11 12 15
|
||||||
|
3 22 23 20
|
||||||
|
3 19 18 17
|
||||||
|
3 22 17 18
|
||||||
|
3 21 16 17
|
||||||
|
3 20 19 16
|
||||||
|
3 23 18 19
|
||||||
|
3 17 16 19
|
||||||
|
3 20 21 22
|
||||||
|
3 18 23 22
|
||||||
|
3 17 22 21
|
||||||
|
3 16 21 20
|
||||||
|
3 19 20 23
|
||||||
|
3 30 31 28
|
||||||
|
3 27 26 25
|
||||||
|
3 30 25 26
|
||||||
|
3 29 24 25
|
||||||
|
3 28 27 24
|
||||||
|
3 31 26 27
|
||||||
|
3 25 24 27
|
||||||
|
3 28 29 30
|
||||||
|
3 26 31 30
|
||||||
|
3 25 30 29
|
||||||
|
3 24 29 28
|
||||||
|
3 27 28 31
|
||||||
|
3 38 39 36
|
||||||
|
3 35 34 33
|
||||||
|
3 38 33 34
|
||||||
|
3 37 32 33
|
||||||
|
3 36 35 32
|
||||||
|
3 39 34 35
|
||||||
|
3 33 32 35
|
||||||
|
3 36 37 38
|
||||||
|
3 34 39 38
|
||||||
|
3 33 38 37
|
||||||
|
3 32 37 36
|
||||||
|
3 35 36 39
|
||||||
|
3 46 47 44
|
||||||
|
3 43 42 41
|
||||||
|
3 46 41 42
|
||||||
|
3 45 40 41
|
||||||
|
3 44 43 40
|
||||||
|
3 47 42 43
|
||||||
|
3 41 40 43
|
||||||
|
3 44 45 46
|
||||||
|
3 42 47 46
|
||||||
|
3 41 46 45
|
||||||
|
3 40 45 44
|
||||||
|
3 43 44 47
|
||||||
|
3 54 55 52
|
||||||
|
3 51 50 49
|
||||||
|
3 54 49 50
|
||||||
|
3 53 48 49
|
||||||
|
3 52 51 48
|
||||||
|
3 55 50 51
|
||||||
|
3 49 48 51
|
||||||
|
3 52 53 54
|
||||||
|
3 50 55 54
|
||||||
|
3 49 54 53
|
||||||
|
3 48 53 52
|
||||||
|
3 51 52 55
|
||||||
|
3 62 63 60
|
||||||
|
3 59 58 57
|
||||||
|
3 62 57 58
|
||||||
|
3 61 56 57
|
||||||
|
3 60 59 56
|
||||||
|
3 63 58 59
|
||||||
|
3 57 56 59
|
||||||
|
3 60 61 62
|
||||||
|
3 58 63 62
|
||||||
|
3 57 62 61
|
||||||
|
3 56 61 60
|
||||||
|
3 59 60 63
|
||||||
|
3 70 71 68
|
||||||
|
3 67 66 65
|
||||||
|
3 70 65 66
|
||||||
|
3 69 64 65
|
||||||
|
3 68 67 64
|
||||||
|
3 71 66 67
|
||||||
|
3 65 64 67
|
||||||
|
3 68 69 70
|
||||||
|
3 66 71 70
|
||||||
|
3 65 70 69
|
||||||
|
3 64 69 68
|
||||||
|
3 67 68 71
|
||||||
|
3 78 79 76
|
||||||
|
3 75 74 73
|
||||||
|
3 78 73 74
|
||||||
|
3 77 72 73
|
||||||
|
3 76 75 72
|
||||||
|
3 79 74 75
|
||||||
|
3 73 72 75
|
||||||
|
3 76 77 78
|
||||||
|
3 74 79 78
|
||||||
|
3 73 78 77
|
||||||
|
3 72 77 76
|
||||||
|
3 75 76 79
|
||||||
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
OFF
|
||||||
|
7 3 0
|
||||||
|
|
||||||
|
0 0 0
|
||||||
|
1 2 0
|
||||||
|
1 0 0
|
||||||
|
0 1 0
|
||||||
|
1e-30 0 -8
|
||||||
|
1 2 16
|
||||||
|
2 2 2
|
||||||
|
3 0 1 3
|
||||||
|
3 0 2 3
|
||||||
|
3 4 5 6
|
||||||
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
OFF
|
||||||
|
9 3 0
|
||||||
|
|
||||||
|
0 1 0
|
||||||
|
0 0 0
|
||||||
|
2 1 0
|
||||||
|
1 1 0
|
||||||
|
2 0 0
|
||||||
|
1.00000000000002 0 0
|
||||||
|
1.00000000000001 1e-30 0
|
||||||
|
2 -1 0
|
||||||
|
1.00000000000002 -1 0
|
||||||
|
3 0 1 2
|
||||||
|
3 3 4 5
|
||||||
|
3 6 7 8
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
OFF
|
||||||
|
12 4 0
|
||||||
|
|
||||||
|
0 0 0
|
||||||
|
0 8.000000000001 0
|
||||||
|
8.000000000001 0 0
|
||||||
|
4.000000000002 4.000000000002 0
|
||||||
|
4 8.000000000001 0
|
||||||
|
8.000000000001 4 0
|
||||||
|
6.000000000002 6.000000000002 0
|
||||||
|
6 8.000000000001 0
|
||||||
|
8.000000000001 6 0
|
||||||
|
6.5 6.5 0
|
||||||
|
6.5 8.000000000001 0
|
||||||
|
8.000000000001 6.5 0
|
||||||
|
3 0 1 2
|
||||||
|
3 3 4 5
|
||||||
|
3 6 7 8
|
||||||
|
3 9 10 11
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
OFF
|
||||||
|
8 4 0
|
||||||
|
|
||||||
|
0 0 0
|
||||||
|
0 1 0
|
||||||
|
1 1 0
|
||||||
|
1 0 0
|
||||||
|
0 0 1
|
||||||
|
0 1 1
|
||||||
|
1 1 1e-10
|
||||||
|
1 0 1e-10
|
||||||
|
3 0 1 2
|
||||||
|
3 0 2 3
|
||||||
|
3 4 5 7
|
||||||
|
3 5 6 7
|
||||||
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
OFF
|
||||||
|
12 4 0
|
||||||
|
|
||||||
|
1 -1 -1
|
||||||
|
1 -1 1
|
||||||
|
3 -1e-15 0
|
||||||
|
1 1 -1
|
||||||
|
1 1 1
|
||||||
|
3 1e-15 0
|
||||||
|
0 -1e-15 -1
|
||||||
|
0 -1e-15 1
|
||||||
|
0 -2 0
|
||||||
|
0 1e-15 -1
|
||||||
|
0 1e-15 1
|
||||||
|
0 2 0
|
||||||
|
3 0 1 2
|
||||||
|
3 3 4 5
|
||||||
|
3 6 7 8
|
||||||
|
3 9 10 11
|
||||||
|
|
@ -30,7 +30,7 @@ struct My_exp_visitor :
|
||||||
std::shared_ptr<int> i;
|
std::shared_ptr<int> i;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct My_visitor
|
struct My_visitor : public PMP::Autorefinement::Default_visitor
|
||||||
{
|
{
|
||||||
My_visitor(std::size_t nb_input, std::size_t expected_nb_output)
|
My_visitor(std::size_t nb_input, std::size_t expected_nb_output)
|
||||||
: nb_input(nb_input)
|
: nb_input(nb_input)
|
||||||
|
|
@ -66,6 +66,11 @@ struct My_visitor
|
||||||
tgt_check[tgt_id]=1;
|
tgt_check[tgt_id]=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void delete_triangle(std::size_t src_id)
|
||||||
|
{
|
||||||
|
assert(src_id<nb_input);
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t nb_input;
|
std::size_t nb_input;
|
||||||
std::size_t expected_nb_output;
|
std::size_t expected_nb_output;
|
||||||
std::vector<int> tgt_check;
|
std::vector<int> tgt_check;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
data-autoref/test_01.off 4 2
|
||||||
|
data-autoref/test_02.off 10 17
|
||||||
|
data-autoref/test_03.off 13 20
|
||||||
|
data-autoref/test_04.off 12 20
|
||||||
|
data-autoref/test_05.off 12 20
|
||||||
|
data-autoref/test_06.off 89 248
|
||||||
|
data-autoref/test_07.off 8 12
|
||||||
|
data-autoref/test_08.off 57 148
|
||||||
|
data-autoref/test_09.off 4 3
|
||||||
|
data-autoref/test_10.off 10 13
|
||||||
|
data-autoref/test_11.off 9 12
|
||||||
|
data-autoref/test_12.off 9 6
|
||||||
|
data-autoref/test_13.off 12 22
|
||||||
|
data-autoref/test_14.off 12 22
|
||||||
|
data-autoref/test_15.off 12 22
|
||||||
|
data-autoref/test_16.off 4 2
|
||||||
|
data-autoref/test_17.off 4 2
|
||||||
|
data-autoref/triple_inter_exception/triple.off 15 18
|
||||||
|
data-autoref/triple_inter_exception/cubes_cpln_1.off 66 206
|
||||||
|
data-autoref/triple_inter_exception/cubes_cpln_2.off 54 158
|
||||||
|
data-autoref/triple_inter_exception/cubes_cpln_3.off 61 188
|
||||||
|
data-autoref/open_01.off 1313 2622
|
||||||
|
data-autoref/open_02.off 562 1056
|
||||||
|
data-autoref/cpln_01.off 30 78
|
||||||
|
data-autoref/cpln_02.off 24 56
|
||||||
|
data-autoref/cpln_03.off 27 68
|
||||||
|
data-autoref/four_cubes.off 106 352
|
||||||
|
data-autoref/spiral.off 19 31
|
||||||
|
data-snap/intersection_when_rounded_1.off 9 6
|
||||||
|
data-snap/intersection_when_rounded_2.off 10 7
|
||||||
|
data-snap/intersection_when_rounded_3.off 16 14
|
||||||
|
data-snap/collapse_1.off 6 4
|
||||||
|
data-snap/collapse_2.off 13 16
|
||||||
|
data-snap/collapse_3.off 11 10
|
||||||
|
data-snap/no_collapse_1.off 8 4
|
||||||
|
data-snap/no_collapse_2.off 12 4
|
||||||
|
data-snap/coplanar_cubes.off 1514 5544
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
|
||||||
|
#include <CGAL/Polygon_mesh_processing/intersection.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/corefinement.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/autorefinement.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||||
|
|
||||||
|
#include <CGAL/IO/polygon_soup_io.h>
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||||
|
|
||||||
|
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||||
|
|
||||||
|
struct My_visitor : public PMP::Autorefinement::Default_visitor
|
||||||
|
{
|
||||||
|
My_visitor(std::size_t nb_input, std::size_t expected_nb_output)
|
||||||
|
: nb_input(nb_input)
|
||||||
|
, expected_nb_output(expected_nb_output)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~My_visitor()
|
||||||
|
{
|
||||||
|
for(std::size_t i=0; i<tgt_check.size(); ++i)
|
||||||
|
{
|
||||||
|
assert( tgt_check[i]==1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void number_of_output_triangles(std::size_t nbt)
|
||||||
|
{
|
||||||
|
tgt_check.assign(expected_nb_output, 0);
|
||||||
|
assert(nbt==expected_nb_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void verbatim_triangle_copy(std::size_t tgt_id, std::size_t src_id)
|
||||||
|
{
|
||||||
|
assert(src_id<nb_input);
|
||||||
|
assert(tgt_id<expected_nb_output);
|
||||||
|
assert(tgt_check.size()==expected_nb_output && tgt_check[tgt_id]==0);
|
||||||
|
tgt_check[tgt_id]=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void new_subtriangle(std::size_t tgt_id, std::size_t src_id)
|
||||||
|
{
|
||||||
|
assert(src_id<nb_input);
|
||||||
|
assert(tgt_id<expected_nb_output);
|
||||||
|
assert(tgt_check.size()==expected_nb_output && tgt_check[tgt_id]==0);
|
||||||
|
tgt_check[tgt_id]=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_triangle(std::size_t src_id)
|
||||||
|
{
|
||||||
|
assert(src_id<nb_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t nb_input;
|
||||||
|
std::size_t expected_nb_output;
|
||||||
|
std::vector<int> tgt_check;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Tag>
|
||||||
|
void test(const char* fname, std::size_t nb_vertices_after_autorefine, std::size_t expected_nb_output, Tag tag)
|
||||||
|
{
|
||||||
|
std::cout << "Running tests on " << fname;
|
||||||
|
if (std::is_same_v<Tag, CGAL::Sequential_tag>)
|
||||||
|
std::cout << " (Sequential)\n";
|
||||||
|
else
|
||||||
|
std::cout << " (Parallel)\n";
|
||||||
|
|
||||||
|
std::vector<K::Point_3> points;
|
||||||
|
std::vector< std::vector<std::size_t> > triangles;
|
||||||
|
if (!CGAL::IO::read_polygon_soup(fname, points, triangles))
|
||||||
|
{
|
||||||
|
std::cerr << " Input mesh is not a valid file." << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Testing autorefine()
|
||||||
|
My_visitor visitor(triangles.size(), expected_nb_output);
|
||||||
|
PMP::autorefine_triangle_soup(points, triangles, CGAL::parameters::visitor(visitor).concurrency_tag(tag).apply_iterative_snap_rounding(true));
|
||||||
|
assert( nb_vertices_after_autorefine==points.size());
|
||||||
|
assert( expected_nb_output==triangles.size());
|
||||||
|
assert( !PMP::does_triangle_soup_self_intersect(points, triangles) );
|
||||||
|
// CGAL::IO::write_polygon_soup("/tmp/debug.off", points, triangles);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char** argv)
|
||||||
|
{
|
||||||
|
// file expected_nb_of_vertices expected_nb_of_faces (after repair)
|
||||||
|
for (int i=0;i<(argc-1)/3; ++i)
|
||||||
|
{
|
||||||
|
test(argv[1+3*i], atoi(argv[1+3*i+1]), atoi(argv[1+3*i+2]), CGAL::Sequential_tag());
|
||||||
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
test(argv[1+3*i], atoi(argv[1+3*i+1]), atoi(argv[1+3*i+2]), CGAL::Parallel_tag());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
data-autoref/test_01.off 4 2
|
||||||
|
data-autoref/test_02.off 10 17
|
||||||
|
data-autoref/test_03.off 13 20
|
||||||
|
data-autoref/test_04.off 12 20
|
||||||
|
data-autoref/test_05.off 12 20
|
||||||
|
data-autoref/test_06.off 89 248
|
||||||
|
data-autoref/test_07.off 8 12
|
||||||
|
data-autoref/test_08.off 57 148
|
||||||
|
data-autoref/test_09.off 4 3
|
||||||
|
data-autoref/test_10.off 10 13
|
||||||
|
data-autoref/test_11.off 9 12
|
||||||
|
data-autoref/test_12.off 9 6
|
||||||
|
data-autoref/test_13.off 12 22
|
||||||
|
data-autoref/test_14.off 12 22
|
||||||
|
data-autoref/test_15.off 12 22
|
||||||
|
data-autoref/test_16.off 4 2
|
||||||
|
data-autoref/test_17.off 4 2
|
||||||
|
data-autoref/triple_inter_exception/triple.off 15 18
|
||||||
|
data-autoref/triple_inter_exception/cubes_cpln_1.off 66 206
|
||||||
|
data-autoref/triple_inter_exception/cubes_cpln_2.off 54 158
|
||||||
|
data-autoref/triple_inter_exception/cubes_cpln_3.off 61 188
|
||||||
|
data-autoref/open_01.off 1313 2622
|
||||||
|
data-autoref/open_02.off 562 1056
|
||||||
|
data-autoref/cpln_01.off 30 78
|
||||||
|
data-autoref/cpln_02.off 24 56
|
||||||
|
data-autoref/cpln_03.off 27 68
|
||||||
|
data-autoref/four_cubes.off 106 352
|
||||||
|
data-autoref/spiral.off 19 31
|
||||||
|
data-snap/intersection_when_rounded_1.off 9 6
|
||||||
|
data-snap/intersection_when_rounded_2.off 10 7
|
||||||
|
data-snap/intersection_when_rounded_3.off 16 14
|
||||||
|
data-snap/collapse_1.off 6 4
|
||||||
|
data-snap/collapse_2.off 13 16
|
||||||
|
data-snap/collapse_3.off 11 10
|
||||||
|
data-snap/no_collapse_1.off 8 4
|
||||||
|
data-snap/no_collapse_2.off 12 4
|
||||||
|
data-snap/cubes.off 5042 26036
|
||||||
|
data-snap/coplanar_cubes.off 1514 5544
|
||||||
|
|
@ -177,7 +177,8 @@ CGAL_add_named_parameter(weight_limiting_t, weight_limiting, weight_limiting)
|
||||||
CGAL_add_named_parameter(progressive_t, progressive, progressive)
|
CGAL_add_named_parameter(progressive_t, progressive, progressive)
|
||||||
CGAL_add_named_parameter(tiling_t, tiling, tiling)
|
CGAL_add_named_parameter(tiling_t, tiling, tiling)
|
||||||
CGAL_add_named_parameter(dimension_t, dimension, dimension)
|
CGAL_add_named_parameter(dimension_t, dimension, dimension)
|
||||||
|
CGAL_add_named_parameter(apply_iterative_snap_rounding_t, apply_iterative_snap_rounding, apply_iterative_snap_rounding)
|
||||||
|
CGAL_add_named_parameter(snap_grid_size_t, snap_grid_size, snap_grid_size)
|
||||||
|
|
||||||
// List of named parameters that we use in the package 'Surface Mesh Simplification'
|
// List of named parameters that we use in the package 'Surface Mesh Simplification'
|
||||||
CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost)
|
CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue