mirror of https://github.com/CGAL/cgal
Add an example of pausing and restarting a wrapping process
This commit is contained in:
parent
18154a758b
commit
b1ffdb00e1
|
|
@ -12,5 +12,6 @@ create_single_source_cgal_program("triangle_soup_wrap.cpp")
|
||||||
create_single_source_cgal_program("point_set_wrap.cpp")
|
create_single_source_cgal_program("point_set_wrap.cpp")
|
||||||
create_single_source_cgal_program("wrap_from_cavity.cpp")
|
create_single_source_cgal_program("wrap_from_cavity.cpp")
|
||||||
create_single_source_cgal_program("mixed_inputs_wrap.cpp")
|
create_single_source_cgal_program("mixed_inputs_wrap.cpp")
|
||||||
create_single_source_cgal_program("successive_wraps.cpp")
|
|
||||||
create_single_source_cgal_program("volumetric_wrap.cpp")
|
create_single_source_cgal_program("volumetric_wrap.cpp")
|
||||||
|
create_single_source_cgal_program("successive_wraps.cpp")
|
||||||
|
create_single_source_cgal_program("pause_and_resume_wrapping.cpp")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
// This example demonstrates how to interrupt the wrapping process before it has terminated,
|
||||||
|
// and how to resume afterwards.
|
||||||
|
//
|
||||||
|
// -------------------------------- !! Warning !! --------------------------------------------------
|
||||||
|
// By default, the wrap uses an unsorted LIFO queue of faces to refine. This means that
|
||||||
|
// the intermediate result is not very useful because the algorithm carves deep and not wide
|
||||||
|
// (somewhat like a DFS vs a BFS).
|
||||||
|
//
|
||||||
|
// The sorted queue option is enabled with the macro below to make the refinement algorithm
|
||||||
|
// more uniform. The downside is that it is slower.
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
#define CGAL_AW3_USE_SORTED_PRIORITY_QUEUE
|
||||||
|
|
||||||
|
#include "output_helper.h"
|
||||||
|
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Surface_mesh.h>
|
||||||
|
|
||||||
|
#include <CGAL/alpha_wrap_3.h>
|
||||||
|
#include <CGAL/IO/polygon_soup_io.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/measure.h>
|
||||||
|
#include <CGAL/Random.h>
|
||||||
|
#include <CGAL/Timer.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace AW3 = CGAL::Alpha_wraps_3;
|
||||||
|
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||||
|
|
||||||
|
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||||
|
using Point_3 = K::Point_3;
|
||||||
|
|
||||||
|
using Points = std::vector<Point_3>;
|
||||||
|
using Polygon = std::array<std::size_t, 3>;
|
||||||
|
using Polygons = std::vector<Polygon>;
|
||||||
|
|
||||||
|
using Mesh = CGAL::Surface_mesh<Point_3>;
|
||||||
|
using face_descriptor = boost::graph_traits<Mesh>::face_descriptor;
|
||||||
|
|
||||||
|
struct Interrupter_visitor
|
||||||
|
: public AW3::internal::Wrapping_default_visitor
|
||||||
|
{
|
||||||
|
using Base = AW3::internal::Wrapping_default_visitor;
|
||||||
|
|
||||||
|
CGAL::Real_timer timer;
|
||||||
|
double max_time = -1; // in seconds
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_max_time(double t) { max_time = t; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename AlphaWrapper>
|
||||||
|
void on_flood_fill_begin(const AlphaWrapper&)
|
||||||
|
{
|
||||||
|
std::cout << "Starting timer..." << std::endl;
|
||||||
|
timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Wrapper>
|
||||||
|
bool go_further(const Wrapper&)
|
||||||
|
{
|
||||||
|
if(timer.time() > max_time)
|
||||||
|
{
|
||||||
|
timer.stop();
|
||||||
|
std::cout << "Paused after " << timer.time() << " s." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
std::cout.precision(17);
|
||||||
|
std::cerr.precision(17);
|
||||||
|
|
||||||
|
CGAL::Random rng;
|
||||||
|
std::cout << "Random seed = " << rng.get_seed() << std::endl;
|
||||||
|
|
||||||
|
const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/armadillo.off");
|
||||||
|
|
||||||
|
// = read the soup
|
||||||
|
Points points;
|
||||||
|
Polygons polygons;
|
||||||
|
if(!CGAL::IO::read_polygon_soup(filename, points, polygons) || polygons.empty())
|
||||||
|
{
|
||||||
|
std::cerr << "Invalid soup input: " << filename << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Input: " << points.size() << " points, " << polygons.size() << " faces" << std::endl;
|
||||||
|
|
||||||
|
// Compute the alpha and offset values
|
||||||
|
const double relative_alpha = (argc > 2) ? std::stod(argv[2]) : rng.get_double(150., 200.);
|
||||||
|
const double relative_offset = (argc > 3) ? std::stod(argv[3]) : 600.;
|
||||||
|
std::cout << "relative_alpha = " << relative_alpha << std::endl;
|
||||||
|
|
||||||
|
CGAL::Bbox_3 bbox;
|
||||||
|
for(const Point_3& p : points)
|
||||||
|
bbox += p.bbox();
|
||||||
|
|
||||||
|
const double diag_length = std::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) +
|
||||||
|
CGAL::square(bbox.ymax() - bbox.ymin()) +
|
||||||
|
CGAL::square(bbox.zmax() - bbox.zmin()));
|
||||||
|
|
||||||
|
const double alpha = diag_length / relative_alpha;
|
||||||
|
const double offset = diag_length / relative_offset;
|
||||||
|
|
||||||
|
// Build the wrapper
|
||||||
|
using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle<K>;
|
||||||
|
Oracle oracle(alpha);
|
||||||
|
oracle.add_triangle_soup(points, polygons, CGAL::parameters::default_values());
|
||||||
|
CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3<Oracle> aw3(oracle);
|
||||||
|
|
||||||
|
// --- Launch the wrapping, and pause when the algorithm has spent 1s flooding
|
||||||
|
Interrupter_visitor interrupter;
|
||||||
|
interrupter.set_max_time(1.);
|
||||||
|
|
||||||
|
Mesh wrap;
|
||||||
|
aw3(alpha, offset, wrap, CGAL::parameters::visitor(interrupter));
|
||||||
|
std::cout << ">>> The current wrap has " << num_vertices(wrap) << " vertices" << std::endl;
|
||||||
|
CGAL::IO::write_polygon_mesh("stopped_1.off", wrap, CGAL::parameters::stream_precision(17));
|
||||||
|
|
||||||
|
// --- Restart from the previous state, and pause a bit further
|
||||||
|
interrupter.set_max_time(2.);
|
||||||
|
aw3(alpha, offset, wrap, CGAL::parameters::visitor(interrupter)
|
||||||
|
.refine_triangulation(true));
|
||||||
|
std::cout << ">>> The current wrap has " << num_vertices(wrap) << " vertices" << std::endl;
|
||||||
|
CGAL::IO::write_polygon_mesh("stopped_2.off", wrap, CGAL::parameters::stream_precision(17));
|
||||||
|
|
||||||
|
// --- Restart from the previous state, and let it finish
|
||||||
|
aw3(alpha, offset, wrap, CGAL::parameters::refine_triangulation(true));
|
||||||
|
std::cout << ">>> The final (resumed) wrap has " << num_vertices(wrap) << " vertices" << std::endl;
|
||||||
|
std::string output_name = generate_output_name(filename, relative_alpha, relative_offset);
|
||||||
|
std::cout << "Writing to " << "resumed_" + output_name << std::endl;
|
||||||
|
CGAL::IO::write_polygon_mesh("resumed_" + output_name, wrap, CGAL::parameters::stream_precision(17));
|
||||||
|
|
||||||
|
// --- Get the final wrap, in one go:
|
||||||
|
Mesh single_pass_wrap;
|
||||||
|
CGAL::alpha_wrap_3(points, polygons, alpha, offset, single_pass_wrap);
|
||||||
|
std::cout << ">>> The final (from scratch) wrap has " << num_vertices(single_pass_wrap) << " vertices" << std::endl;
|
||||||
|
|
||||||
|
output_name = generate_output_name(filename, relative_alpha, relative_offset);
|
||||||
|
std::cout << "Writing to " << output_name << std::endl;
|
||||||
|
CGAL::IO::write_polygon_mesh(output_name, single_pass_wrap, CGAL::parameters::stream_precision(17));
|
||||||
|
|
||||||
|
// --- Compare the results to ensure both approaches yield identical meshes
|
||||||
|
std::vector<std::pair<face_descriptor, face_descriptor> > common;
|
||||||
|
std::vector<face_descriptor> m1_only;
|
||||||
|
std::vector<face_descriptor> m2_only;
|
||||||
|
PMP::match_faces(wrap, single_pass_wrap,
|
||||||
|
std::back_inserter(common),
|
||||||
|
std::back_inserter(m1_only),
|
||||||
|
std::back_inserter(m2_only));
|
||||||
|
if(!m1_only.empty() || !m2_only.empty())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: The two wraps should have been identical!" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue