Skip to content

Add do_snap parameter to PMP::autorefine_triangle_soup #8744

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 58 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
3787d4b
Add snap polygon soup to PMP
LeoValque Feb 4, 2025
14ccffc
Doc, verbose and named parameter of snap_polygon_soup
LeoValque Feb 4, 2025
3a64fe3
add number_of_iterations as a named parameter for snap_polygon_soup
LeoValque Feb 4, 2025
3811271
add more verbose in snap_polygon_soup
LeoValque Feb 4, 2025
3dc12cd
New alternative version of snap_polygon_soup for testing
LeoValque Feb 4, 2025
4d4763f
Fig a bug when the scaling have a negative exponent
LeoValque Feb 7, 2025
aef30f0
Write a generic ceil function to use snap_polygon_soup with various n…
LeoValque Feb 11, 2025
64c4fd2
ceil for negative rational and comments
LeoValque Feb 12, 2025
8079f69
Add some parallellisation
LeoValque Feb 12, 2025
d4e6675
made snap polygon soup an option of autorefine_triangle_soup
LeoValque Feb 17, 2025
ac7bf3c
Doc modification of autorefine and Polygon mesh processing
LeoValque Feb 17, 2025
9b84d4c
rename do_snap to apply_iterative_snap_rounding, remove trailing whit…
LeoValque Feb 17, 2025
139e047
remove trailing whitespace
LeoValque Feb 17, 2025
09239da
rename snap_polygon_soup to triangle_soup_snap_rounding and fix bug i…
LeoValque Feb 19, 2025
0bbaa2a
replace #ifdef CGAL_LINED_WITH_TBB by constexpr
LeoValque Feb 19, 2025
20e54eb
reintroduced #ifdef CGAL_LINKED_WITH_TBB
LeoValque Feb 20, 2025
5d3ec39
Add more soup information in snap_polygon_soup.cpp
LeoValque Feb 24, 2025
3b29156
Bug solved: Shift before ceil was in the wrong direction
LeoValque Feb 25, 2025
04d5d74
Clean doc autorefine
LeoValque Feb 28, 2025
174d48f
Clean doc autorefine return description
LeoValque Feb 28, 2025
0a478a4
Clean doc autorefine snap_grid_size description
LeoValque Feb 28, 2025
6130b4a
solved conflict
LeoValque Mar 3, 2025
30ece15
missing word in the doc
LeoValque Mar 3, 2025
be1ada2
Reduce default number of iterations
LeoValque Mar 3, 2025
1467842
Modify soup_triangles_snap_rounding to support a visitor
LeoValque Mar 13, 2025
1f5d17a
correct typo in function name
LeoValque Mar 13, 2025
b891987
Add variant where cluster of points are round to the closest of them …
LeoValque Mar 14, 2025
b49c696
Update Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/a…
LeoValque Mar 18, 2025
a8c3c28
Merge branch 'CGAL:master' into PMP_triangle_soup_rounding-GF
LeoValque Mar 18, 2025
16da2a2
add delete_triangle function to the visitor of test_autorefinement
LeoValque Mar 18, 2025
dc6d7b1
Debug the visitor of triangle_soup_snap_rounding
LeoValque Mar 19, 2025
3e884c8
Move the mutex inside the class Indexes_range who using it
LeoValque Mar 19, 2025
8c59129
Change name of internal functions
LeoValque Mar 19, 2025
bfc9f5b
Solve bug with macro that skip repair_polygon_soup
LeoValque Apr 3, 2025
f81f5ab
factorize snap_polygon_soup
LeoValque Apr 3, 2025
290610f
add zhou and naive version
LeoValque Apr 3, 2025
7cb154f
add internal_new_subtriangle to Visistor of autorefinement
LeoValque Apr 3, 2025
4995634
use the new internal function of the visitor of autorefinement for th…
LeoValque Apr 3, 2025
da86f44
clone test_autorefinement.cmd to test_snap_rounding.cpp to test snap_…
LeoValque Apr 3, 2025
625299b
Update Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/P…
LeoValque Apr 8, 2025
5126371
Update Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_me…
LeoValque Apr 8, 2025
cc32efa
Update Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_me…
LeoValque Apr 8, 2025
5b4e02b
use macro to define snap version
LeoValque Apr 8, 2025
06951ab
add missing reserve for the visitor
LeoValque Apr 8, 2025
f3abba4
Experiment with iterative rotated around x cubes
LeoValque Apr 25, 2025
e44ffbf
Experiment with iterative rotated along all axis cubes
LeoValque Apr 25, 2025
465183f
remove visitor of example snap_polygon_soup
LeoValque Apr 25, 2025
b8a0ab4
add data for snap rounding test
LeoValque Apr 25, 2025
2e24464
Test for snap rounding
LeoValque Apr 25, 2025
f4d46b8
update cmakelist to compile examples with rotated cubes
LeoValque Apr 25, 2025
3409446
Solve mistake in test_snap_rounding.cmd
LeoValque Apr 25, 2025
afa80c2
simplify the example code of snap_rounding
LeoValque Apr 28, 2025
d56fe48
less verbose test and add another test file
LeoValque Apr 28, 2025
a5f5e82
add specialization of repair_triangle_soup for indexes_range of array
LeoValque Apr 28, 2025
8301f15
some cleaning
LeoValque Apr 28, 2025
484ade6
move experiments with rotated cubes in benchmark
LeoValque Apr 28, 2025
b7fe173
modified example of cmd
LeoValque Apr 28, 2025
3bfe64e
reduce running time of test_snap_rounding, add a full test version
LeoValque Apr 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Documentation/doc/biblio/geom.bib
Original file line number Diff line number Diff line change
Expand Up @@ -152085,3 +152085,16 @@ @article{ledoux2014triangulation
year={2014},
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},
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@ class PMPAutorefinementVisitor{
/// 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.
void new_subtriangle(std::size_t tgt_id, std::size_t src_id);
/// called for each triangle delete because it was or became degenerated, `src_id` was its position before calling `autorefine_triangle_soup()`.
/// A triangle may degenerate inside `autorefine_triangle_soup()` if and only if `apply_iterative_snap_rounding` is set to `true`.
void delete_triangle(std::size_t src_id);
/// @}
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace CGAL {
\anchor Chapter_PolygonMeshProcessing

\cgalAutoToc
\authors David Coeurjolly, Jaques-Olivier Lachaud, Konstantinos Katrioplas, Sébastien Loriot, Ivan Pađen, Mael Rouxel-Labbé, Hossam Saeed, Jane Tournois, and Ilker %O. Yaz
\authors David Coeurjolly, Jaques-Olivier Lachaud, Sylvain Lazard, Konstantinos Katrioplas, Sébastien Loriot, Ivan Pađen, Mael Rouxel-Labbé, Hossam Saeed, Jane Tournois, Léo Valque and Ilker %O. Yaz

\image html neptun_head.jpg
\image latex neptun_head.jpg
Expand Down Expand Up @@ -889,8 +889,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
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
might be introduced due to rounding issues of points coordinates.
To guarantee that the triangle soup is free from self-intersections, a kernel with exact constructions must be used.
might be introduced due to rounding issues of points coordinates. The `apply_iterative_snap_rounding` option can be used to resolve this issue.
When set to `true`, it ensures 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
Triangle faces of a mesh made up of almost collinear points are badly shaped elements that
Expand Down Expand Up @@ -1450,5 +1452,7 @@ used as a reference during the project.

The curvature-based sizing field version of isotropic remeshing was added by Ivan Pađen during GSoC 2023, under the supervision of Sébastien Loriot and Jane Tournois.

The `apply_iterative_snap_rounding` option for autorefinement were implemented during 2025. This was implemented by Léo Valque and Sylvain Lazard. The implementation is based on \cgalCite{lazard:hal-04907149}.

*/
} /* namespace CGAL */
Original file line number Diff line number Diff line change
Expand Up @@ -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("triangle_mesh_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)
include(CGAL_Eigen3_support)
Expand Down Expand Up @@ -138,6 +139,7 @@ if(TARGET 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(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")
target_link_libraries(corefinement_parallel_union_meshes PRIVATE CGAL::TBB_support)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#define PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
// #define CGAL_PMP_AUTOREFINE_USE_DEFAULT_VERBOSE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define PMP_ROUNDING_VERTICES_IN_POLYGON_SOUP_VERBOSE
// #define CGAL_PMP_AUTOREFINE_USE_DEFAULT_VERBOSE


#include <CGAL/Simple_cartesian.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#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 EPICK;
typedef CGAL::Exact_predicates_exact_constructions_kernel EPECK;
typedef CGAL::Simple_cartesian<double> Cartesian;

namespace PMP = CGAL::Polygon_mesh_processing;

struct Track_visitor
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move the visitor to a test. The example is meant to be minimalistic

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it seems that a lot of stuff from this example should be in a test.

{
// inline void number_of_output_triangles(std::size_t nbt) { std::cout << "total number of triangles: " << nbt << std::endl;}
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) { std::cout << src_id << " goes to " << tgt_id << std::endl;}
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) { std::cout << src_id << " subdivides to " << tgt_id << std::endl;}
inline void new_subtriangle(std::size_t /*tgt_id*/, std::size_t /*src_id*/) {}

// inline void delete_triangle(std::size_t src_id) { std::cout << src_id << " deleted" << std::endl;}
inline void delete_triangle(std::size_t /*src_id*/) {}
};

int main(int argc, char** argv)
{
const std::string filename = argc == 1 ? CGAL::data_file_path("meshes/elephant.off")
: std::string(argv[1]);

// const std::string out_file = argc <= 2 ? "rounded_soup.off"
// : std::string(argv[2]);
const std::string out_file = "rounded_soup.off";

const int grid_size = argc <= 2 ? 23
: std::stoi(std::string(argv[2]));

const bool epeck = argc <= 3 ? false
: std::string(argv[3])=="EPECK";

if(epeck)
{
std::vector<EPECK::Point_3> input_points;
std::vector<boost::container::small_vector<std::size_t, 3>> input_triangles;

std::cout << "Snap rounding apply on " << filename << " with EPECK\n";
if (!CGAL::IO::read_polygon_soup(filename, input_points, input_triangles))
{
std::cerr << "Cannot read " << filename << "\n";
return 1;
}
std::cout << "#points = " << input_points.size() << " and #triangles = " << input_triangles.size() << std::endl;
std::cout << "Is 2-manifold: " << PMP::is_polygon_soup_a_polygon_mesh(input_triangles) << std::endl;

PMP::repair_polygon_soup(input_points, input_triangles);
PMP::triangulate_polygons(input_points, input_triangles);

CGAL::Real_timer t;
t.start();
PMP::autorefine_triangle_soup(input_points, input_triangles, CGAL::parameters::apply_iterative_snap_rounding(true).erase_all_duplicates(true).concurrency_tag(CGAL::Parallel_if_available_tag()).snap_grid_size(grid_size));
t.stop();
std::cout << "#points = " << input_points.size() << " and #triangles = " << input_triangles.size() << " in " << t.time() << " sec." << std::endl;
std::cout << "Does self-intersect: " << PMP::does_triangle_soup_self_intersect(input_points, input_triangles) << std::endl;
std::cout << "Is 2-manifold: " << PMP::orient_polygon_soup(input_points, input_triangles) << "\n\n" << std::endl;

std::vector<Cartesian::Point_3> output_points;
for(auto &p: input_points)
output_points.emplace_back(CGAL::to_double(p.x()),CGAL::to_double(p.y()),CGAL::to_double(p.z()));

CGAL::IO::write_polygon_soup(out_file, output_points, input_triangles, CGAL::parameters::stream_precision(17));
}
else
{
std::vector<EPICK::Point_3> input_points;
std::vector<boost::container::small_vector<std::size_t, 3>> input_triangles;
std::cout << "Snap rounding on " << filename << " with EPICK\n";
if (!CGAL::IO::read_polygon_soup(filename, input_points, input_triangles))
{
std::cerr << "Cannot read " << filename << "\n";
return 1;
}
std::cout << "#points = " << input_points.size() << " and #triangles = " << input_triangles.size() << std::endl;
std::cout << "Is 2-manifold: " << PMP::is_polygon_soup_a_polygon_mesh(input_triangles) << std::endl;

std::vector<std::pair<std::size_t, std::size_t>> pairs_of_intersecting_triangles;
PMP::triangle_soup_self_intersections(input_points, input_triangles, std::back_inserter(pairs_of_intersecting_triangles));
std::cout << "Nb of pairs of intersecting triangles: " << pairs_of_intersecting_triangles.size() << std::endl;

PMP::repair_polygon_soup(input_points, input_triangles);
PMP::triangulate_polygons(input_points, input_triangles);

CGAL::Real_timer t;
t.start();
#if 1
Track_visitor visitor;
bool success=PMP::autorefine_triangle_soup(input_points, input_triangles, CGAL::parameters::apply_iterative_snap_rounding(true).erase_all_duplicates(true).concurrency_tag(CGAL::Parallel_if_available_tag()).snap_grid_size(grid_size).visitor(visitor));
#else
bool success=PMP::autorefine_triangle_soup(input_points, input_triangles, CGAL::parameters::apply_iterative_snap_rounding(true).erase_all_duplicates(true).concurrency_tag(CGAL::Parallel_if_available_tag()).snap_grid_size(grid_size).number_of_iterations(15));
#endif
t.stop();
std::cout << "\nOutput:" << std::endl;
std::cout << "#points = " << input_points.size() << " and #triangles = " << input_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>(input_points, input_triangles) << std::endl;
else
std::cout << "ROUNDING FAILED" << std::endl;
CGAL::IO::write_polygon_soup(out_file, input_points, input_triangles, CGAL::parameters::stream_precision(17));
std::cout << "Is 2-manifold: " << PMP::orient_polygon_soup(input_points, input_triangles) << "\n\n" << std::endl;
}
return 0;
}
Loading