Add throw_on_cancel and statusfn into QEC
This commit is contained in:
parent
c00dca7810
commit
e26bffadd8
3 changed files with 52 additions and 22 deletions
|
@ -126,21 +126,29 @@ bool check_new_vertex(const Vec3f& nv, const Vec3f& v0, const Vec3f& v1) {
|
||||||
|
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
void Slic3r::its_quadric_edge_collapse(indexed_triangle_set &its,
|
void Slic3r::its_quadric_edge_collapse(
|
||||||
|
indexed_triangle_set & its,
|
||||||
uint32_t triangle_count,
|
uint32_t triangle_count,
|
||||||
float * max_error)
|
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
|
TriangleInfos t_infos; // only normals with information about deleted triangle
|
||||||
VertexInfos v_infos;
|
VertexInfos v_infos;
|
||||||
EdgeInfos e_infos;
|
EdgeInfos e_infos;
|
||||||
Errors errors;
|
Errors errors;
|
||||||
std::tie(t_infos, v_infos, e_infos, errors) = init(its);
|
std::tie(t_infos, v_infos, e_infos, errors) = init(its);
|
||||||
|
throw_on_cancel();
|
||||||
float max_float = std::numeric_limits<float>::max();
|
statusfn(status_init_size);
|
||||||
float last_collapsed_error = 0.f;
|
|
||||||
if (max_error == nullptr) {
|
|
||||||
max_error = &max_float;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert from triangle index to mutable priority queue index
|
// convert from triangle index to mutable priority queue index
|
||||||
std::vector<uint32_t> ti_2_mpqi(its.indices.size(), {0});
|
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);
|
changed_triangle_indices.reserve(2 * max_triangle_count_for_one_vertex);
|
||||||
|
|
||||||
uint32_t actual_triangle_count = its.indices.size();
|
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()) {
|
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
|
// triangle index 0
|
||||||
Error e = mpq.top(); // copy
|
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();
|
mpq.pop();
|
||||||
uint32_t ti0 = e.triangle_index;
|
uint32_t ti0 = e.triangle_index;
|
||||||
TriangleInfo &t_info0 = t_infos[ti0];
|
TriangleInfo &t_info0 = t_infos[ti0];
|
||||||
|
@ -258,7 +282,7 @@ void Slic3r::its_quadric_edge_collapse(indexed_triangle_set &its,
|
||||||
|
|
||||||
// compact triangle
|
// compact triangle
|
||||||
compact(v_infos, t_infos, e_infos, its);
|
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,
|
Vec3f QuadricEdgeCollapse::create_normal(const Triangle &triangle,
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// inspiration: https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification
|
// inspiration: https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
#include "TriangleMesh.hpp"
|
#include "TriangleMesh.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
@ -14,10 +15,14 @@ namespace Slic3r {
|
||||||
/// <param name="triangle_count">Wanted triangle count.</param>
|
/// <param name="triangle_count">Wanted triangle count.</param>
|
||||||
/// <param name="max_error">Maximal Quadric for reduce.
|
/// <param name="max_error">Maximal Quadric for reduce.
|
||||||
/// When nullptr then max float is used
|
/// When nullptr then max float is used
|
||||||
/// Output: Last used ErrorValue to collapse edge
|
/// Output: Last used ErrorValue to collapse edge</param>
|
||||||
/// </param>
|
/// <param name="throw_on_cancel">Could stop process of calculation.</param>
|
||||||
void its_quadric_edge_collapse(indexed_triangle_set &its,
|
/// <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,
|
uint32_t triangle_count = 0,
|
||||||
float * max_error = nullptr);
|
float * max_error = nullptr,
|
||||||
|
std::function<void(void)> throw_on_cancel = nullptr,
|
||||||
|
std::function<void(int)> statusfn = nullptr);
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -203,8 +203,8 @@ TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]")
|
||||||
|
|
||||||
indexed_triangle_set its_ = its; // copy
|
indexed_triangle_set its_ = its; // copy
|
||||||
// its_write_obj(its, "tetrhedron_in.obj");
|
// its_write_obj(its, "tetrhedron_in.obj");
|
||||||
size_t wanted_count = its.indices.size() - 1;
|
uint32_t wanted_count = its.indices.size() - 1;
|
||||||
CHECK(its_quadric_edge_collapse(its, wanted_count));
|
its_quadric_edge_collapse(its, wanted_count);
|
||||||
// its_write_obj(its, "tetrhedron_out.obj");
|
// its_write_obj(its, "tetrhedron_out.obj");
|
||||||
CHECK(its.indices.size() == 4);
|
CHECK(its.indices.size() == 4);
|
||||||
CHECK(its.vertices.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");
|
TriangleMesh mesh = load_model("frog_legs.obj");
|
||||||
double original_volume = its_volume(mesh.its);
|
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());
|
REQUIRE_FALSE(mesh.empty());
|
||||||
indexed_triangle_set its = mesh.its; // copy
|
indexed_triangle_set its = mesh.its; // copy
|
||||||
its_quadric_edge_collapse(its, wanted_count);
|
|
||||||
// its_write_obj(its, "frog_legs_qec.obj");
|
// 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);
|
CHECK(its.indices.size() <= wanted_count);
|
||||||
double volume = its_volume(its);
|
double volume = its_volume(its);
|
||||||
CHECK(fabs(original_volume - volume) < 30.);
|
CHECK(fabs(original_volume - volume) < 30.);
|
||||||
|
|
Loading…
Reference in a new issue