Advanced visualization to store island

This commit is contained in:
Filip Sykala - NTB T15p 2024-10-18 16:09:57 +02:00 committed by Lukas Matena
parent 35948c0361
commit 73f8583e18
5 changed files with 74 additions and 183 deletions

View File

@ -3,6 +3,8 @@
#include <libslic3r/libslic3r.h>
#define OPTION_TO_STORE_ISLAND
namespace Slic3r::sla {
/// <summary>
/// Configuration DTO
@ -77,8 +79,10 @@ struct SampleConfig
// (neighbor coordinate - create issue in voronoi)
double simplification_tolerance = scale_(0.05 /*mm*/);
#ifdef OPTION_TO_STORE_ISLAND
// Only for debug purposes
std::string path = ""; // when set to empty string, no debug output is generated
#endif // OPTION_TO_STORE_ISLAND
};
} // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_

View File

@ -21,9 +21,6 @@
// comment definition of NDEBUG to enable assert()
//#define NDEBUG
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG_PATH "C:/data/temp/align/island_<<COUNTER>>_graph.svg"
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG_PATH "C:/data/temp/align/island_<<COUNTER>>_init.svg"
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG_PATH "C:/data/temp/align/island_<<COUNTER>>_aligned.svg"
@ -117,21 +114,38 @@ ExPolygon get_simplified(const ExPolygon &island, const SampleConfig &config) {
island : get_expolygon_with_biggest_contour(simplified_expolygons);
}
#ifdef OPTION_TO_STORE_ISLAND
SVG draw_island(const std::string &path, const ExPolygon &island, const ExPolygon &simplified_island) {
SVG svg(path, BoundingBox{island.contour.points});
svg.draw_original(island);
svg.draw(island, "lightgray");
svg.draw(simplified_island, "gray");
return svg;
}
SVG draw_island_graph(const std::string &path, const ExPolygon &island,
const ExPolygon &simplified_island, const VoronoiGraph& skeleton,
const VoronoiGraph::ExPath& longest_path, const Lines& lines, coord_t width) {
SVG svg = draw_island(path, island, simplified_island);
VoronoiGraphUtils::draw(svg, skeleton, lines, width);
VoronoiGraphUtils::draw(svg, longest_path.nodes, width, "orange");
return svg;
}
#endif // OPTION_TO_STORE_ISLAND
} // namespace
SupportIslandPoints SampleIslandUtils::uniform_cover_island(
const ExPolygon &island, const SampleConfig &config
) {
ExPolygon simplified_island = get_simplified(island, config);
#ifdef OPTION_TO_STORE_ISLAND
std::string path;
if (!config.path.empty()) {
static int counter = 0;
std::string path = replace_first(config.path, "<<order>>", std::to_string(++counter));
SVG svg(path, BoundingBox{island.contour.points});
svg.draw_original(island);
svg.draw(island, "lightgray");
svg.draw(simplified_island, "gray");
path = replace_first(config.path, "<<order>>", std::to_string(++counter));
draw_island(path, island, simplified_island);
// need to save svg in case of infinite loop so no store SVG into variable
}
#endif // OPTION_TO_STORE_ISLAND
// When island is smaller than minimal-head diameter,
// it will be supported whole by support poin in center
@ -139,7 +153,14 @@ SupportIslandPoints SampleIslandUtils::uniform_cover_island(
SupportIslandPoints result;
result.push_back(std::make_unique<SupportIslandNoMovePoint>(
center, SupportIslandInnerPoint::Type::one_bb_center_point));
#ifdef OPTION_TO_STORE_ISLAND
if (!path.empty()){ // add center support point into image
SVG svg = draw_island(path, island, simplified_island);
svg.draw(center, "black", config.head_radius);
svg.draw_text(center, "Center of bounding box", "black");
}
return result;
#endif // OPTION_TO_STORE_ISLAND
}
Slic3r::Geometry::VoronoiDiagram vd;
@ -148,13 +169,39 @@ SupportIslandPoints SampleIslandUtils::uniform_cover_island(
Slic3r::Voronoi::annotate_inside_outside(vd, lines);
VoronoiGraph skeleton = VoronoiGraphUtils::create_skeleton(vd, lines);
VoronoiGraph::ExPath longest_path;
SupportIslandPoints samples =
SampleIslandUtils::sample_voronoi_graph(skeleton, lines, config, longest_path);
const VoronoiGraph::Node *start_node = VoronoiGraphUtils::getFirstContourNode(skeleton);
// every island has to have a point on contour
assert(start_node != nullptr);
longest_path = VoronoiGraphUtils::create_longest_path(start_node);
#ifdef OPTION_TO_STORE_ISLAND // add voronoi diagram with longest path into image
if (!path.empty()) draw_island_graph(path, island, simplified_island, skeleton, longest_path, lines, config.head_radius / 10);
#endif // OPTION_TO_STORE_ISLAND
SupportIslandPoints samples = sample_expath(longest_path, lines, config);
#ifdef OPTION_TO_STORE_ISLAND
Points samples_before_align = to_points(samples);
if (!path.empty()) {
SVG svg = draw_island_graph(path, island, simplified_island, skeleton, longest_path, lines, config.head_radius / 10);
draw(svg, samples, config.head_radius);
}
#endif // OPTION_TO_STORE_ISLAND
// allign samples
SampleIslandUtils::align_samples(samples, island, config);
#ifdef OPTION_TO_STORE_ISLAND
if (!path.empty()) {
SVG svg = draw_island_graph(path, island, simplified_island, skeleton, longest_path, lines, config.head_radius / 10);
draw(svg, samples, config.head_radius);
Lines align_moves;
align_moves.reserve(samples.size());
for (size_t i = 0; i < samples.size(); ++i)
align_moves.push_back(Line(samples[i]->point, samples_before_align[i]));
svg.draw(align_moves, "lightgray");
}
#endif // OPTION_TO_STORE_ISLAND
return samples;
}
@ -569,17 +616,6 @@ void SampleIslandUtils::align_samples(SupportIslandPoints &samples,
}
namespace {
Polygons create_voronoi_cells_boost(const Points &points, coord_t max_distance) {
using VD = Slic3r::Geometry::VoronoiDiagram;
VD vd;
vd.construct_voronoi(points.begin(), points.end());
assert(points.size() == vd.cells().size());
Polygons cells(points.size());
for (const VD::cell_type &cell : vd.cells())
cells[cell.source_index()] = VoronoiGraphUtils::to_polygon(cell, points, max_distance);
return cells;
}
bool is_points_in_distance(const Slic3r::Point & p,
const Slic3r::Points &points,
double max_distance)
@ -598,16 +634,12 @@ coord_t SampleIslandUtils::align_once(
const ExPolygon &island,
const SampleConfig &config)
{
// IMPROVE: Do not calculate voronoi diagram out of island(only triangulate island)
// https://stackoverflow.com/questions/23823345/how-to-construct-a-voronoi-diagram-inside-a-polygon
// IMPROVE1: add accessor to point coordinate do not copy points
// IMPROVE2: add filter for create cell polygon only for moveable samples
Slic3r::Points points = SampleIslandUtils::to_points(samples);
Polygons cell_polygons = /*
create_voronoi_cells_boost
/*/
create_voronoi_cells_cgal
//*/
(points, config.max_distance);
Slic3r::Points points = SampleIslandUtils::to_points(samples);
Polygons cell_polygons = create_voronoi_cells_cgal(points, config.max_distance);
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
std::string color_of_island = "#FF8080"; // LightRed. Should not be visible - cell color should overlap
@ -1032,43 +1064,6 @@ SupportIslandPoints SampleIslandUtils::sample_center_circle(
return result;
}
SupportIslandPoints SampleIslandUtils::sample_voronoi_graph(
const VoronoiGraph & graph,
const Lines & lines,
const SampleConfig & config,
VoronoiGraph::ExPath &longest_path)
{
const VoronoiGraph::Node *start_node =
VoronoiGraphUtils::getFirstContourNode(graph);
// every island has to have a point on contour
assert(start_node != nullptr);
longest_path = VoronoiGraphUtils::create_longest_path(start_node);
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG_PATH
{
static int counter = 0;
SVG svg(replace_first(SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG_PATH,
"<<COUNTER>>", std::to_string(counter++)).c_str(), LineUtils::create_bounding_box(lines));
VoronoiGraphUtils::draw(svg, graph, lines, config.head_radius / 10, true);
VoronoiGraphUtils::draw(svg, longest_path, config.head_radius / 10);
}
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG_PATH
SupportIslandPoints points = sample_expath(longest_path, lines, config);
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG_PATH
{
static int counter = 0;
SVG svg(replace_first(SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG_PATH,
"<<COUNTER>>", std::to_string(counter++)).c_str(),
LineUtils::create_bounding_box(lines));
svg.draw(lines, "gray", config.head_radius/ 10);
draw(svg, points, config.head_radius, "black", true);
}
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG_PATH
return points;
}
SupportIslandPoints SampleIslandUtils::sample_expath(
const VoronoiGraph::ExPath &path,
const Lines & lines,
@ -1796,7 +1791,6 @@ SupportIslandPoints SampleIslandUtils::sample_outline(
const double &line_length_double = restriction->lengths[index];
coord_t line_length = static_cast<coord_t>(std::round(line_length_double));
if (last_support + line_length > sample_distance) {
Point direction = LineUtils::direction(line);
do {
double ratio = (sample_distance - last_support) / line_length_double;
result.emplace_back(
@ -2036,12 +2030,6 @@ bool SampleIslandUtils::is_visualization_disabled()
#ifndef NDEBUG
return false;
#endif
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG_PATH
return false;
#endif
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG_PATH
return false;
#endif
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
return false;
#endif

View File

@ -183,21 +183,6 @@ public:
const CenterLineConfiguration & cfg,
SupportIslandPoints & result);
/// <summary>
/// Sample voronoi skeleton
/// </summary>
/// <param name="graph">Inside skeleton of island</param>
/// <param name="lines">Source lines for VG --> outline of island.</param>
/// <param name="config">Params for sampling</param>
/// <param name="longest_path">OUTPUT: longest path in graph</param>
/// <returns>Vector of sampled points or Empty when distance from edge is
/// bigger than max_distance</returns>
static SupportIslandPoints sample_voronoi_graph(
const VoronoiGraph & graph,
const Lines & lines,
const SampleConfig & config,
VoronoiGraph::ExPath &longest_path);
/// <summary>
/// Decide how to sample path
/// </summary>

View File

@ -813,6 +813,8 @@ void GLGizmoSlaSupports::draw_island_config() {
if (!ImGui::TreeNode("Support islands:"))
return; // no need to draw configuration for islands
sla::SampleConfig &sample_config = sla::SampleConfigFactory::get_sample_config();
#ifdef OPTION_TO_STORE_ISLAND
bool store_islands = !sample_config.path.empty();
if (ImGui::Checkbox("StoreIslands", &store_islands)) {
if (store_islands = true)
@ -824,6 +826,7 @@ void GLGizmoSlaSupports::draw_island_config() {
std::string path;
ImGui::InputText("path", &sample_config.path);
}
#endif // OPTION_TO_STORE_ISLAND
bool exist_change = false;
if (float simplification_tolerance = unscale<float>(sample_config.simplification_tolerance); // [in mm]

View File

@ -356,7 +356,7 @@ ExPolygons createTestIslands(double size)
bool useFrogLeg = false;
// need post reorganization of longest path
ExPolygons result = {
load_svg("C:/Users/Filip Sykala/Downloads/lm_issue.svg"),
//load_svg("C:/Users/Filip Sykala/Downloads/lm_issue.svg"),
// one support point
ExPolygon(PolygonUtils::create_equilateral_triangle(size)),
ExPolygon(PolygonUtils::create_square(size)),
@ -525,98 +525,8 @@ SampleConfig create_sample_config(double size) {
return cfg;
}
#include <libslic3r/Geometry.hpp>
#include <libslic3r/Geometry/VoronoiOffset.hpp>
TEST_CASE("Sampling speed test on FrogLegs", "[hide], [VoronoiSkeleton]")
{
TriangleMesh mesh = load_model("frog_legs.obj");
std::vector<float> grid({0.1f});
std::vector<ExPolygons> slices = slice_mesh_ex(mesh.its, {0.1f});
ExPolygon frog_leg = slices.front()[1];
SampleConfig cfg = create_sample_config(3e7);
using VD = Slic3r::Geometry::VoronoiDiagram;
VD vd;
Lines lines = to_lines(frog_leg);
vd.construct_voronoi(lines.begin(), lines.end());
Slic3r::Voronoi::annotate_inside_outside(vd, lines);
for (int i = 0; i < 100; ++i) {
VoronoiGraph::ExPath longest_path;
VoronoiGraph skeleton = VoronoiGraphUtils::create_skeleton(vd, lines);
auto samples = SampleIslandUtils::sample_voronoi_graph(skeleton, lines, cfg, longest_path);
}
}
TEST_CASE("Speed align", "[hide], [VoronoiSkeleton]")
{
SampleConfig cfg = create_sample_config(3e7);
cfg.max_align_distance = 1000;
cfg.count_iteration = 1000;
cfg.max_align_distance = 3e7;
double size = 3e7;
auto island = create_square_with_4holes(5 * size, 5 * size / 2 - size / 3);
using VD = Slic3r::Geometry::VoronoiDiagram;
VD vd;
Lines lines = to_lines(island);
vd.construct_voronoi(lines.begin(), lines.end());
Slic3r::Voronoi::annotate_inside_outside(vd, lines);
VoronoiGraph::ExPath longest_path;
VoronoiGraph skeleton = VoronoiGraphUtils::create_skeleton(vd, lines);
for (int i = 0; i < 100; ++i) {
auto samples = SampleIslandUtils::sample_voronoi_graph(skeleton, lines, cfg, longest_path);
SampleIslandUtils::align_samples(samples, island, cfg);
}
}
#include <libslic3r/SLA/SupportIslands/LineUtils.hpp>
/// <summary>
/// Check speed of sampling,
/// for be sure that code is not optimized out store result to svg or print count.
/// </summary>
TEST_CASE("speed sampling", "[hide], [SupGen]") {
double size = 3e7;
float samples_per_mm2 = 0.01f;
ExPolygons islands = createTestIslands(size);
std::random_device rd;
std::mt19937 m_rng;
m_rng.seed(rd());
size_t count = 1;
std::vector<std::vector<Vec2f>> result2;
result2.reserve(islands.size()*count);
for (size_t i = 0; i < count; ++i)
for (const auto &island : islands)
result2.emplace_back(SampleIslandUtils::sample_expolygon(island, samples_per_mm2)); //*/
/*size_t all = 0;
for (auto& result : result2) {
//std::cout << "case " << &result - &result1[0] << " points " << result.size() << std::endl;
all += result.size();
}
std::cout << "All points " << all << std::endl;*/
#ifdef STORE_SAMPLE_INTO_SVG_FILES
for (size_t i = 0; i < result2.size(); ++i) {
size_t island_index = i % islands.size();
ExPolygon &island = islands[island_index];
Lines lines = to_lines(island.contour);
std::string name = "sample_" + std::to_string(i) + ".svg";
SVG svg(name, LineUtils::create_bounding_box(lines));
svg.draw(island, "lightgray");
svg.draw_text({0., 5e6}, ("uniform samples " + std::to_string(result2[i].size())).c_str(), "green");
for (Vec2f &p : result2[i])
svg.draw((p * 1e6).cast<coord_t>(), "green", 1e6);
}
#endif // STORE_SAMPLE_INTO_SVG_FILES
}
namespace {
void store_sample(const SupportIslandPoints &samples, const ExPolygon &island) {
static int counter = 0;
BoundingBox bb(island.contour.points);
@ -639,8 +549,8 @@ void store_sample(const SupportIslandPoints &samples, const ExPolygon &island) {
for (int i=0; i<10;i+=2)
svg.draw(Line(start + Point(i*mm, 0.), start + Point((i+1)*mm, 0.)), "black", 1e6);
}
} // namespace
#endif // STORE_SAMPLE_INTO_SVG_FILES
/// <summary>
/// Check for correct sampling of island
@ -649,6 +559,7 @@ TEST_CASE("Uniform sample test islands", "[SupGen], [VoronoiSkeleton]")
{
float head_diameter = .4f;
SampleConfig cfg = SampleConfigFactory::create(head_diameter);
//cfg.path = "C:/data/temp/island<<order>>.svg";
ExPolygons islands = createTestIslands(7 * scale_(head_diameter));
for (ExPolygon &island : islands) {
// information for debug which island cause problem