Merge branch 'master' into fs_emboss

# Conflicts:
#	src/libslic3r/Technologies.hpp
#	src/slic3r/GUI/GLCanvas3D.cpp
#	src/slic3r/GUI/GUI_App.cpp
This commit is contained in:
Filip Sykala 2022-05-18 14:35:48 +02:00
commit 37961c36e8
38 changed files with 6137 additions and 5655 deletions

View file

@ -3,6 +3,7 @@
#include <libslic3r/TriangleMesh.hpp>
#include <libslic3r/AABBTreeIndirect.hpp>
#include <libslic3r/AABBTreeLines.hpp>
using namespace Slic3r;
@ -58,3 +59,287 @@ TEST_CASE("Building a tree over a box, ray caster and closest query", "[AABBIndi
REQUIRE(closest_point.y() == Approx(0.5));
REQUIRE(closest_point.z() == Approx(1.));
}
TEST_CASE("Creating a several 2d lines, testing closest point query", "[AABBIndirect]")
{
std::vector<Linef> lines { };
lines.push_back(Linef(Vec2d(0.0, 0.0), Vec2d(1.0, 0.0)));
lines.push_back(Linef(Vec2d(1.0, 0.0), Vec2d(1.0, 1.0)));
lines.push_back(Linef(Vec2d(1.0, 1.0), Vec2d(0.0, 1.0)));
lines.push_back(Linef(Vec2d(0.0, 1.0), Vec2d(0.0, 0.0)));
auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(lines);
size_t hit_idx_out;
Vec2d hit_point_out;
auto sqr_dist = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, Vec2d(0.0, 0.0), hit_idx_out,
hit_point_out);
REQUIRE(sqr_dist == Approx(0.0));
REQUIRE((hit_idx_out == 0 || hit_idx_out == 3));
REQUIRE(hit_point_out.x() == Approx(0.0));
REQUIRE(hit_point_out.y() == Approx(0.0));
sqr_dist = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, Vec2d(1.5, 0.5), hit_idx_out,
hit_point_out);
REQUIRE(sqr_dist == Approx(0.25));
REQUIRE(hit_idx_out == 1);
REQUIRE(hit_point_out.x() == Approx(1.0));
REQUIRE(hit_point_out.y() == Approx(0.5));
}
#if 0
#include "libslic3r/EdgeGrid.hpp"
#include <iostream>
#include <ctime>
#include <ratio>
#include <chrono>
TEST_CASE("AABBTreeLines vs SignedDistanceGrid time Benchmark", "[AABBIndirect]")
{
std::vector<Points> lines { Points { } };
std::vector<Linef> linesf { };
Vec2d prevf { };
// NOTE: max coord value of the lines is approx 83 mm
for (int r = 1; r < 1000; ++r) {
lines[0].push_back(Point::new_scale(Vec2d(exp(0.005f * r) * cos(r), exp(0.005f * r) * cos(r))));
linesf.emplace_back(prevf, Vec2d(exp(0.005f * r) * cos(r), exp(0.005f * r) * cos(r)));
prevf = linesf.back().b;
}
int build_num = 10000;
using namespace std::chrono;
{
std::cout << "building the tree " << build_num << " times..." << std::endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for (int i = 0; i < build_num; ++i) {
volatile auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(linesf);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
}
{
std::cout << "building the grid res 1mm ONLY " << build_num/100 << " !!! times..." << std::endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for (int i = 0; i < build_num/100; ++i) {
EdgeGrid::Grid grid { };
grid.create(lines, scaled(1.0), true);
grid.calculate_sdf();
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
}
{
std::cout << "building the grid res 10mm " << build_num << " times..." << std::endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for (int i = 0; i < build_num; ++i) {
EdgeGrid::Grid grid { };
grid.create(lines, scaled(10.0), true);
grid.calculate_sdf();
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
}
EdgeGrid::Grid grid10 { };
grid10.create(lines, scaled(10.0), true);
coord_t query10_res = scaled(10.0);
grid10.calculate_sdf();
EdgeGrid::Grid grid1 { };
grid1.create(lines, scaled(1.0), true);
coord_t query1_res = scaled(1.0);
grid1.calculate_sdf();
auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(linesf);
int query_num = 10000;
Points query_points { };
std::vector<Vec2d> query_pointsf { };
for (int x = 0; x < query_num; ++x) {
Vec2d qp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0
- 100.0 };
query_pointsf.push_back(qp);
query_points.push_back(Point::new_scale(qp));
}
{
std::cout << "querying tree " << query_num << " times..." << std::endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for (const Vec2d &qp : query_pointsf) {
size_t hit_idx_out;
Vec2d hit_point_out;
AABBTreeLines::squared_distance_to_indexed_lines(linesf, tree, qp, hit_idx_out, hit_point_out);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
}
{
std::cout << "querying grid res 1mm " << query_num << " times..." << std::endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for (const Point &qp : query_points) {
volatile auto dist = grid1.closest_point_signed_distance(qp, query1_res);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
}
{
std::cout << "querying grid res 10mm " << query_num << " times..." << std::endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for (const Point &qp : query_points) {
volatile auto dist = grid10.closest_point_signed_distance(qp, query10_res);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
}
std::cout << "Test build and queries together - same number of contour points and query points" << std::endl << std::endl;
std::vector<int> point_counts { 100, 300, 500, 1000, 3000 };
for (auto count : point_counts) {
std::vector<Points> lines { Points { } };
std::vector<Linef> linesf { };
Vec2d prevf { };
Points query_points { };
std::vector<Vec2d> query_pointsf { };
for (int x = 0; x < count; ++x) {
Vec2d cp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0
- 100.0 };
lines[0].push_back(Point::new_scale(cp));
linesf.emplace_back(prevf, cp);
prevf = linesf.back().b;
Vec2d qp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0
- 100.0 };
query_pointsf.push_back(qp);
query_points.push_back(Point::new_scale(qp));
}
std::cout << "Test for point count: " << count << std::endl;
{
high_resolution_clock::time_point t1 = high_resolution_clock::now();
auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(linesf);
for (const Vec2d &qp : query_pointsf) {
size_t hit_idx_out;
Vec2d hit_point_out;
AABBTreeLines::squared_distance_to_indexed_lines(linesf, tree, qp, hit_idx_out, hit_point_out);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << " Tree took " << time_span.count() << " seconds." << std::endl;
}
{
high_resolution_clock::time_point t1 = high_resolution_clock::now();
EdgeGrid::Grid grid1 { };
grid1.create(lines, scaled(1.0), true);
coord_t query1_res = scaled(1.0);
grid1.calculate_sdf();
for (const Point &qp : query_points) {
volatile auto dist = grid1.closest_point_signed_distance(qp, query1_res);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << " Grid 1mm took " << time_span.count() << " seconds." << std::endl;
}
{
high_resolution_clock::time_point t1 = high_resolution_clock::now();
EdgeGrid::Grid grid10 { };
grid10.create(lines, scaled(10.0), true);
coord_t query10_res = scaled(10.0);
grid10.calculate_sdf();
for (const Point &qp : query_points) {
volatile auto dist = grid10.closest_point_signed_distance(qp, query10_res);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << " Grid 10mm took " << time_span.count() << " seconds." << std::endl;
}
}
std::cout << "Test build and queries together - same number of contour points and query points" << std::endl <<
"And with limited contour edge length to 4mm " << std::endl;
for (auto count : point_counts) {
std::vector<Points> lines { Points { } };
std::vector<Linef> linesf { };
Vec2d prevf { };
Points query_points { };
std::vector<Vec2d> query_pointsf { };
for (int x = 0; x < count; ++x) {
Vec2d cp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0
- 100.0 };
Vec2d contour = prevf + cp.normalized()*4.0; // limits the cnotour edge len to 4mm
lines[0].push_back(Point::new_scale(contour));
linesf.emplace_back(prevf, contour);
prevf = linesf.back().b;
Vec2d qp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0
- 100.0 };
query_pointsf.push_back(qp);
query_points.push_back(Point::new_scale(qp));
}
std::cout << "Test for point count: " << count << std::endl;
{
high_resolution_clock::time_point t1 = high_resolution_clock::now();
auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(linesf);
for (const Vec2d &qp : query_pointsf) {
size_t hit_idx_out;
Vec2d hit_point_out;
AABBTreeLines::squared_distance_to_indexed_lines(linesf, tree, qp, hit_idx_out, hit_point_out);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << " Tree took " << time_span.count() << " seconds." << std::endl;
}
{
high_resolution_clock::time_point t1 = high_resolution_clock::now();
EdgeGrid::Grid grid1 { };
grid1.create(lines, scaled(1.0), true);
coord_t query1_res = scaled(1.0);
grid1.calculate_sdf();
for (const Point &qp : query_points) {
volatile auto dist = grid1.closest_point_signed_distance(qp, query1_res);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << " Grid 1mm took " << time_span.count() << " seconds." << std::endl;
}
{
high_resolution_clock::time_point t1 = high_resolution_clock::now();
EdgeGrid::Grid grid10 { };
grid10.create(lines, scaled(10.0), true);
coord_t query10_res = scaled(10.0);
grid10.calculate_sdf();
for (const Point &qp : query_points) {
volatile auto dist = grid10.closest_point_signed_distance(qp, query10_res);
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << " Grid 10mm took " << time_span.count() << " seconds." << std::endl;
}
}
}
#endif

View file

@ -54,18 +54,9 @@ TEST_CASE("astar algorithm test over 3D point grid", "[AStar]") {
auto pgrid = point_grid(ex_seq, vol, {0.1f, 0.1f, 0.1f});
size_t target = pgrid.point_count() - 1;
std::cout << "Tracing route to " << pgrid.get_coord(target).transpose() << std::endl;
PointGridTracer pgt{pgrid, pgrid.point_count() - 1};
std::vector<size_t> out;
bool found = astar::search_route(pgt, size_t(0), std::back_inserter(out));
std::cout << "Route taken: ";
for (size_t i : out) {
std::cout << "(" << pgrid.get_coord(i).transpose() << ") ";
}
std::cout << std::endl;
REQUIRE(found);
}

View file

@ -325,9 +325,9 @@ static void recreate_object_from_rasters(const std::string &objname, float lh) {
double disp_w = 120.96;
double disp_h = 68.04;
#ifndef NDEBUG
size_t cntr = 0;
#endif
//#ifndef NDEBUG
// size_t cntr = 0;
//#endif
for (ExPolygons &layer : layers) {
auto rst = create_raster(res, disp_w, disp_h);
@ -335,11 +335,11 @@ static void recreate_object_from_rasters(const std::string &objname, float lh) {
rst.draw(island);
}
#ifndef NDEBUG
std::fstream out(objname + std::to_string(cntr) + ".png", std::ios::out);
out << rst.encode(sla::PNGRasterEncoder{});
out.close();
#endif
//#ifndef NDEBUG
// std::fstream out(objname + std::to_string(cntr) + ".png", std::ios::out);
// out << rst.encode(sla::PNGRasterEncoder{});
// out.close();
//#endif
ExPolygons layer_ = sla::raster_to_polygons(rst);
// float delta = scaled(std::min(rst.pixel_dimensions().h_mm,
@ -347,19 +347,19 @@ static void recreate_object_from_rasters(const std::string &objname, float lh) {
// layer_ = expolygons_simplify(layer_, delta);
#ifndef NDEBUG
SVG svg(objname + std::to_string(cntr) + ".svg", BoundingBox(Point{0, 0}, Point{scaled(disp_w), scaled(disp_h)}));
svg.draw(layer_);
svg.draw(layer, "green");
svg.Close();
#endif
//#ifndef NDEBUG
// SVG svg(objname + std::to_string(cntr) + ".svg", BoundingBox(Point{0, 0}, Point{scaled(disp_w), scaled(disp_h)}));
// svg.draw(layer_);
// svg.draw(layer, "green");
// svg.Close();
//#endif
double layera = 0., layera_ = 0.;
for (auto &p : layer) layera += p.area();
for (auto &p : layer_) layera_ += p.area();
#ifndef NDEBUG
std::cout << cntr++ << std::endl;
#endif
//#ifndef NDEBUG
// std::cout << cntr++ << std::endl;
//#endif
double diff = std::abs(layera_ - layera);
REQUIRE((diff <= 0.1 * layera || diff < scaled<double>(1.) * scaled<double>(1.)));

View file

@ -346,25 +346,36 @@ TEST_CASE("Mutable priority queue - first pop", "[MutableSkipHeapPriorityQueue]"
size_t id;
float val;
};
size_t count = 50000;
static constexpr const size_t count = 50000;
std::vector<size_t> idxs(count, {0});
std::vector<bool> dels(count, false);
auto q = make_miniheap_mutable_priority_queue<MyValue, 16, true>(
[&](MyValue &v, size_t idx) {
idxs[v.id] = idx;
},
[&idxs](MyValue &v, size_t idx) { idxs[v.id] = idx; },
[](MyValue &l, MyValue &r) { return l.val < r.val; });
q.reserve(count);
for (size_t id = 0; id < count; id++) {
MyValue mv{ id, rand() / 100.f };
q.push(mv);
using QueueType = decltype(q);
THEN("Skip queue has 0th element unused, 1st element is the top of the queue.") {
CHECK(QueueType::address::is_padding(0));
CHECK(!QueueType::address::is_padding(1));
}
q.reserve(count);
for (size_t id = 0; id < count; ++ id)
q.push({ id, rand() / 100.f });
MyValue v = q.top(); // copy
THEN("Element at the top of the queue has a valid ID.") {
CHECK(v.id >= 0);
CHECK(v.id < count);
}
THEN("Element at the top of the queue has its position stored in idxs.") {
CHECK(idxs[v.id] == 1);
}
MyValue it = q.top(); // copy
q.pop();
// is valid id (no initial value default value)
CHECK(it.id != 0);
// is first item in queue valid value
CHECK(idxs[0] != std::numeric_limits<size_t>::max());
THEN("Element removed from the queue has its position in idxs reset to invalid.") {
CHECK(idxs[v.id] == q.invalid_id());
}
THEN("Element was removed from the queue, new top of the queue has its index set correctly.") {
CHECK(q.top().id >= 0);
CHECK(q.top().id < count);
CHECK(idxs[q.top().id] == 1);
}
}
TEST_CASE("Mutable priority queue complex", "[MutableSkipHeapPriorityQueue]")
@ -382,23 +393,23 @@ TEST_CASE("Mutable priority queue complex", "[MutableSkipHeapPriorityQueue]")
q.reserve(count);
auto rand_val = [&]()->float { return (rand() % 53) / 10.f; };
size_t ord = 0;
for (size_t id = 0; id < count; id++) {
MyValue mv;
mv.id = ord++;
mv.val = rand_val();
q.push(mv);
}
for (size_t id = 0; id < count; ++ id)
q.push({ id, rand_val() });
auto check = [&]()->bool{
for (size_t i = 0; i < idxs.size(); ++i) {
if (dels[i]) continue;
size_t qid = idxs[i];
if (qid > 3*count) {
return false;
}
MyValue &mv = q[qid];
if (mv.id != i) {
return false; // ERROR
if (dels[i]) {
if (idxs[i] != q.invalid_id())
return false; // ERROR
} else {
size_t qid = idxs[i];
if (qid >= q.heap_size()) {
return false; // ERROR
}
MyValue &mv = q[qid];
if (mv.id != i) {
return false; // ERROR
}
}
}
return true;
@ -406,6 +417,7 @@ TEST_CASE("Mutable priority queue complex", "[MutableSkipHeapPriorityQueue]")
CHECK(check()); // initial check
// Generate an element ID of an elmenet, which was not yet deleted, thus it is still valid.
auto get_valid_id = [&]()->int {
int id = 0;
do {
@ -413,23 +425,28 @@ TEST_CASE("Mutable priority queue complex", "[MutableSkipHeapPriorityQueue]")
} while (dels[id]);
return id;
};
// Remove first 100 elements from the queue of 5000 elements, cross-validate indices.
// Re-enter every 20th element back to the queue.
for (size_t i = 0; i < 100; i++) {
MyValue it = q.top(); // copy
MyValue v = q.top(); // copy
q.pop();
dels[it.id] = true;
dels[v.id] = true;
CHECK(check());
if (i % 20 == 0) {
it.val = rand_val();
q.push(it);
dels[it.id] = false;
v.val = rand_val();
q.push(v);
dels[v.id] = false;
CHECK(check());
continue;
}
// Remove some valid element from the queue.
int id = get_valid_id();
CHECK(idxs[id] != q.invalid_id());
q.remove(idxs[id]);
dels[id] = true;
CHECK(check());
// and change 5 random elements and reorder them in the queue.
for (size_t j = 0; j < 5; j++) {
int id = get_valid_id();
size_t qid = idxs[id];