Add throw_on_cancel and statusfn into QEC

This commit is contained in:
Filip Sykala 2021-07-09 09:09:52 +02:00
parent c00dca7810
commit e26bffadd8
3 changed files with 52 additions and 22 deletions

View File

@ -126,21 +126,29 @@ bool check_new_vertex(const Vec3f& nv, const Vec3f& v0, const Vec3f& v1) {
#endif // NDEBUG
void Slic3r::its_quadric_edge_collapse(indexed_triangle_set &its,
uint32_t triangle_count,
float * max_error)
void Slic3r::its_quadric_edge_collapse(
indexed_triangle_set & its,
uint32_t triangle_count,
float * max_error,
std::function<void(void)> throw_on_cancel,
std::function<void(int)> statusfn)
{
// constants --> may be move to config
const int status_init_size = 10; // in percents
const int check_cancel_period = 16; // how many edge to reduce before call throw_on_cancel
// check input
if (triangle_count >= its.indices.size()) return;
float maximal_error = (max_error == nullptr)? std::numeric_limits<float>::max() : *max_error;
if (maximal_error <= 0.f) return;
TriangleInfos t_infos; // only normals with information about deleted triangle
VertexInfos v_infos;
EdgeInfos e_infos;
Errors errors;
std::tie(t_infos, v_infos, e_infos, errors) = init(its);
float max_float = std::numeric_limits<float>::max();
float last_collapsed_error = 0.f;
if (max_error == nullptr) {
max_error = &max_float;
}
throw_on_cancel();
statusfn(status_init_size);
// convert from triangle index to mutable priority queue index
std::vector<uint32_t> ti_2_mpqi(its.indices.size(), {0});
@ -159,10 +167,26 @@ void Slic3r::its_quadric_edge_collapse(indexed_triangle_set &its,
changed_triangle_indices.reserve(2 * max_triangle_count_for_one_vertex);
uint32_t actual_triangle_count = its.indices.size();
uint32_t count_triangle_to_reduce = actual_triangle_count - triangle_count;
auto increase_status = [&]() {
double reduced = (actual_triangle_count - triangle_count) /
(double) count_triangle_to_reduce;
double status = (100 - status_init_size) * (1. - reduced);
statusfn(static_cast<int>(std::round(status)));
};
// modulo for update status
uint32_t status_mod = std::max(uint32_t(16), count_triangle_to_reduce / 100);
uint32_t iteration_number = 0;
float last_collapsed_error = 0.f;
while (actual_triangle_count > triangle_count && !mpq.empty()) {
++iteration_number;
if (iteration_number % status_mod == 0) increase_status();
if (iteration_number % check_cancel_period == 0) throw_on_cancel();
// triangle index 0
Error e = mpq.top(); // copy
if (e.value >= *max_error) break; // Too big error
if (e.value >= maximal_error) break; // Too big error
mpq.pop();
uint32_t ti0 = e.triangle_index;
TriangleInfo &t_info0 = t_infos[ti0];
@ -258,7 +282,7 @@ void Slic3r::its_quadric_edge_collapse(indexed_triangle_set &its,
// compact triangle
compact(v_infos, t_infos, e_infos, its);
*max_error = last_collapsed_error;
if (max_error != nullptr) *max_error = last_collapsed_error;
}
Vec3f QuadricEdgeCollapse::create_normal(const Triangle &triangle,

View File

@ -3,6 +3,7 @@
// inspiration: https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification
#include <cstdint>
#include <functional>
#include "TriangleMesh.hpp"
namespace Slic3r {
@ -14,10 +15,14 @@ namespace Slic3r {
/// <param name="triangle_count">Wanted triangle count.</param>
/// <param name="max_error">Maximal Quadric for reduce.
/// When nullptr then max float is used
/// Output: Last used ErrorValue to collapse edge
/// </param>
void its_quadric_edge_collapse(indexed_triangle_set &its,
uint32_t triangle_count = 0,
float * max_error = nullptr);
/// Output: Last used ErrorValue to collapse edge</param>
/// <param name="throw_on_cancel">Could stop process of calculation.</param>
/// <param name="statusfn">Give a feed back to user about progress.</param>
void its_quadric_edge_collapse(
indexed_triangle_set & its,
uint32_t triangle_count = 0,
float * max_error = nullptr,
std::function<void(void)> throw_on_cancel = nullptr,
std::function<void(int)> statusfn = nullptr);
} // namespace Slic3r

View File

@ -167,8 +167,8 @@ std::vector<Vec3f> its_sample_surface(const indexed_triangle_set &its,
// return Average abs distance to original
float compare(const indexed_triangle_set &original,
const indexed_triangle_set &simplified,
double sample_per_mm2)
const indexed_triangle_set &simplified,
double sample_per_mm2)
{
// create ABBTree
auto tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(
@ -203,8 +203,8 @@ TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]")
indexed_triangle_set its_ = its; // copy
// its_write_obj(its, "tetrhedron_in.obj");
size_t wanted_count = its.indices.size() - 1;
CHECK(its_quadric_edge_collapse(its, wanted_count));
uint32_t wanted_count = its.indices.size() - 1;
its_quadric_edge_collapse(its, wanted_count);
// its_write_obj(its, "tetrhedron_out.obj");
CHECK(its.indices.size() == 4);
CHECK(its.vertices.size() == 4);
@ -235,11 +235,12 @@ TEST_CASE("Symplify mesh by Quadric edge collapse to 5%", "[its]")
{
TriangleMesh mesh = load_model("frog_legs.obj");
double original_volume = its_volume(mesh.its);
size_t wanted_count = mesh.its.indices.size() * 0.05;
uint32_t wanted_count = mesh.its.indices.size() * 0.05;
REQUIRE_FALSE(mesh.empty());
indexed_triangle_set its = mesh.its; // copy
its_quadric_edge_collapse(its, wanted_count);
// its_write_obj(its, "frog_legs_qec.obj");
float max_error = std::numeric_limits<float>::max();
its_quadric_edge_collapse(its, wanted_count, &max_error);
CHECK(its.indices.size() <= wanted_count);
double volume = its_volume(its);
CHECK(fabs(original_volume - volume) < 30.);