diff --git a/Isosurfacing_3/doc/Isosurfacing_3/Isosurfacing_3.txt b/Isosurfacing_3/doc/Isosurfacing_3/Isosurfacing_3.txt index ae6c369494d..9778d0ccf99 100644 --- a/Isosurfacing_3/doc/Isosurfacing_3/Isosurfacing_3.txt +++ b/Isosurfacing_3/doc/Isosurfacing_3/Isosurfacing_3.txt @@ -261,9 +261,19 @@ run both methods on different types of input data. The following example illustrates a basic run of the Marching Cubes algorithm, and in particular the free function to create a domain from a %Cartesian grid, and the named parameter that enables the user to switch from Marching Cubes to Topologically Correct Marching Cubes. +The resulting triangle soup is converted to a triangle mesh, and is remeshed using +the isotropic remeshing algorithm. \cgalExample{Isosurfacing_3/marching_cubes.cpp} +\cgalFigureAnchor{IsosurfacingMC} +
+ +
+\cgalFigureCaptionBegin{IsosurfacingMC} +Results of the Marching Cubes algorithm, and the final result after remeshing. +\cgalFigureCaptionEnd + \subsection SubSecDCExample Dual Contouring The following example illustrates a basic run of the %Dual Contouring algorithm, and in particular diff --git a/Isosurfacing_3/doc/Isosurfacing_3/fig/MC.png b/Isosurfacing_3/doc/Isosurfacing_3/fig/MC.png new file mode 100644 index 00000000000..9f0a930c7c0 Binary files /dev/null and b/Isosurfacing_3/doc/Isosurfacing_3/fig/MC.png differ diff --git a/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes.cpp b/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes.cpp index 2ca5984a58a..d1a23d92201 100644 --- a/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes.cpp +++ b/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes.cpp @@ -1,12 +1,18 @@ #include +#include #include #include #include #include -#include +#include +#include +#include +#include +#include +#include #include using Kernel = CGAL::Simple_cartesian; @@ -21,25 +27,32 @@ using Domain = CGAL::Isosurfacing::Marching_cubes_domain_3; using Point_range = std::vector; using Polygon_range = std::vector >; +using Mesh = CGAL::Surface_mesh; + +auto value_fn = [](const Point& p) -> FT +{ + const FT& x = p.x(), y = p.y(), z = p.z(); + + // "Klein Bottle" - https://www-sop.inria.fr/galaad/surface/ + return -1-4*y*z*z*x*x-2*y+6*z*z*x*x*y*y-16*x*z+16*x*z*y*y+3*x*x+7*y*y+11*z*z-11*z*z*z*z+z*z*z*z*z*z-3*x*x*x*x-7*y*y*y*y+x*x*x*x*x*x+y*y*y*y*y*y-14*z*z*x*x-18*z*z*y*y+3*z*z*z*z*x*x+3*z*z*z*z*y*y-10*x*x*y*y-4*y*y*y*z*z+3*z*z*x*x*x*x+3*z*z*y*y*y*y+16*x*x*x*z+3*x*x*x*x*y*y+3*x*x*y*y*y*y+4*x*x*y-12*z*z*y-2*x*x*x*x*y-4*x*x*y*y*y-2*z*z*z*z*y+16*x*z*z*z+12*y*y*y-2*y*y*y*y*y-32*x*z*y; +}; + int main(int argc, char** argv) { - const FT isovalue = (argc > 1) ? std::stod(argv[1]) : 0.8; + const FT isovalue = (argc > 1) ? std::stod(argv[1]) : 0.1; + const FT box_c = (argc > 2) ? std::abs(std::stod(argv[2])) : 5.; + const std::size_t grid_n = (argc > 3) ? std::stoi(argv[3]) : 50; // create bounding box and grid - const CGAL::Bbox_3 bbox { -1., -1., -1., 1., 1., 1. }; - Grid grid { bbox, CGAL::make_array(30, 30, 30) }; + const CGAL::Bbox_3 bbox { -box_c, -box_c, -box_c, box_c, box_c, box_c }; + Grid grid { bbox, CGAL::make_array(grid_n, grid_n, grid_n) }; std::cout << "Span: " << grid.span() << std::endl; std::cout << "Cell dimensions: " << grid.spacing()[0] << " " << grid.spacing()[1] << " " << grid.spacing()[2] << std::endl; std::cout << "Cell #: " << grid.xdim() << ", " << grid.ydim() << ", " << grid.zdim() << std::endl; // fill up values - auto sphere_value_fn = [](const Point& p) -> FT - { - return sqrt(p.x()*p.x() + p.y()*p.y() + p.z()*p.z()); - }; - - Values values { sphere_value_fn, grid }; + Values values { value_fn, grid }; // Below is equivalent to: // Domain domain { grid, values }; @@ -53,9 +66,28 @@ int main(int argc, char** argv) CGAL::Isosurfacing::marching_cubes(domain, isovalue, points, triangles, CGAL::parameters::use_topologically_correct_marching_cubes(true)); - std::cout << "Output #vertices: " << points.size() << std::endl; - std::cout << "Output #triangles: " << triangles.size() << std::endl; - CGAL::IO::write_polygon_soup("marching_cubes.off", points, triangles); + std::cout << "Soup #vertices: " << points.size() << std::endl; + std::cout << "Soup #triangles: " << triangles.size() << std::endl; + + if(!CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh(triangles)) { + std::cerr << "Warning: the soup is not a 2-manifold surface, non-manifoldness?..." << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Convert the soup to a triangle mesh..." << std::endl; + Mesh mesh; + CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, triangles, mesh); + + CGAL::IO::write_polygon_mesh("marching_cubes.off", mesh, CGAL::parameters::stream_precision(17)); + + // Let's remesh it to something nicer looking + std::cout << "Remeshing..." << std::endl; + const FT target_edge_length = box_c / 50; + CGAL::Polygon_mesh_processing::isotropic_remeshing(faces(mesh), target_edge_length, mesh, + CGAL::parameters::number_of_iterations(5) + .number_of_relaxation_steps(5)); + + CGAL::IO::write_polygon_mesh("marching_cubes-remeshed.off", mesh, CGAL::parameters::stream_precision(17)); std::cout << "Done" << std::endl;