Add option to store islands (some could make an issue this is tool to collect problematic islands)

This commit is contained in:
Filip Sykala - NTB T15p 2024-10-17 14:39:32 +02:00 committed by Lukas Matena
parent d3d32c6d7d
commit 8794099682
7 changed files with 165 additions and 81 deletions

View File

@ -76,6 +76,9 @@ struct SampleConfig
// NOTE: Slice of Cylinder bottom has tip of trinagles on contour // NOTE: Slice of Cylinder bottom has tip of trinagles on contour
// (neighbor coordinate - create issue in voronoi) // (neighbor coordinate - create issue in voronoi)
double simplification_tolerance = scale_(0.05 /*mm*/); double simplification_tolerance = scale_(0.05 /*mm*/);
// Only for debug purposes
std::string path = ""; // when set to empty string, no debug output is generated
}; };
} // namespace Slic3r::sla } // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_ #endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_

View File

@ -124,6 +124,15 @@ SupportIslandPoints SampleIslandUtils::uniform_cover_island(
) { ) {
ExPolygon simplified_island = get_simplified(island, config); ExPolygon simplified_island = get_simplified(island, config);
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");
}
// When island is smaller than minimal-head diameter, // When island is smaller than minimal-head diameter,
// it will be supported whole by support poin in center // it will be supported whole by support poin in center
if (Point center; get_center(simplified_island.contour.points, config.head_radius, center)) { if (Point center; get_center(simplified_island.contour.points, config.head_radius, center)) {

View File

@ -19,6 +19,7 @@
#include "libslic3r/Line.hpp" #include "libslic3r/Line.hpp"
#include "libslic3r/Surface.hpp" #include "libslic3r/Surface.hpp"
#include "libslic3r/libslic3r.h" #include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
namespace Slic3r { namespace Slic3r {
@ -110,6 +111,19 @@ void SVG::draw(const ExPolygon &expolygon, std::string fill, const float fill_op
this->path(d, true, 0, fill_opacity); this->path(d, true, 0, fill_opacity);
} }
void SVG::draw_original(const ExPolygon &expolygon) {
std::ostringstream d;
auto write_d = [&d](const Points &pts) {
d << "M ";
for (const Point& p: pts)
d << p.x() << " " << p.y() << " ";
d << "z "; // closed path
};
for (const Polygon &p : to_polygons(expolygon))
write_d(p.points);
path(d.str(), false /*fill*/, 1 /*stroke_width*/, 0.f /*fill opacity*/);
}
void SVG::draw_outline(const ExPolygon &expolygon, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width) void SVG::draw_outline(const ExPolygon &expolygon, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
{ {
draw_outline(expolygon.contour, stroke_outer, stroke_width); draw_outline(expolygon.contour, stroke_outer, stroke_width);

View File

@ -96,6 +96,9 @@ public:
void draw_text(const Point &pt, const char *text, const char *color, coordf_t font_size = 20.f); void draw_text(const Point &pt, const char *text, const char *color, coordf_t font_size = 20.f);
void draw_legend(const Point &pt, const char *text, const char *color, coordf_t font_size = 10.f); void draw_legend(const Point &pt, const char *text, const char *color, coordf_t font_size = 10.f);
// Draw no scaled expolygon coordinates
void draw_original(const ExPolygon &exPoly);
void Close(); void Close();
private: private:

View File

@ -23,7 +23,7 @@
#include "libslic3r/SLAPrint.hpp" #include "libslic3r/SLAPrint.hpp"
#include "libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp" #include "libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp"
#include "imgui/imgui_stdlib.h" // string input for ImGui
static const double CONE_RADIUS = 0.25; static const double CONE_RADIUS = 0.25;
static const double CONE_HEIGHT = 0.75; static const double CONE_HEIGHT = 0.75;
@ -686,85 +686,8 @@ RENDER_AGAIN:
ImGui::SetTooltip("Divider for the supported radius\nSmaller mean less point(75% -> supported radius is enlaged to 133%, for 50% it is 200% of radius)\nLarger mean more points(125% -> supported radius is reduced to 80%, for value 150% it is 66% of radius, for 200% -> 50%)"); ImGui::SetTooltip("Divider for the supported radius\nSmaller mean less point(75% -> supported radius is enlaged to 133%, for 50% it is 200% of radius)\nLarger mean more points(125% -> supported radius is reduced to 80%, for value 150% it is 66% of radius, for 200% -> 50%)");
} }
if (ImGui::TreeNode("Support islands:")) { draw_island_config();
sla::SampleConfig &sample_config = sla::SampleConfigFactory::get_sample_config();
bool exist_change = false;
if (float simplification_tolerance = unscale<float>(sample_config.simplification_tolerance); // [in mm]
ImGui::InputFloat("input simplify", &simplification_tolerance, .1f, 1.f, "%.2f mm")) {
sample_config.simplification_tolerance = scale_(simplification_tolerance);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("There is no need to calculate with precisse island\nNOTE: Slice of Cylinder bottom has tip of trinagles on contour\n(neighbor coordinate -> create issue in boost::voronoi)");
if (float max_distance = unscale<float>(sample_config.max_distance); // [in mm]
ImGui::InputFloat("Max dist", &max_distance, .1f, 1.f, "%.2f mm")) {
sample_config.max_distance = scale_(max_distance);
sample_config.half_distance = sample_config.max_distance / 2;
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Every support point on island has at least one support point in maximum distance\nMUST be bigger than zero");
ImGui::SameLine(); ImGui::Text("half is %.2f", unscale<float>(sample_config.half_distance));
if (float minimal_distance_from_outline = unscale<float>(sample_config.minimal_distance_from_outline); // [in mm]
ImGui::InputFloat("from outline", &minimal_distance_from_outline, .1f, 1.f, "%.2f mm")) {
sample_config.minimal_distance_from_outline = scale_(minimal_distance_from_outline);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("When it is possible, there will be this minimal distance from outline.\nZERO when head center should be on outline\nSHOULD be positive number");
ImGui::SameLine();
if (float maximal_distance_from_outline = unscale<float>(sample_config.maximal_distance_from_outline); // [in mm]
ImGui::InputFloat("max from outline", &maximal_distance_from_outline, .1f, 1.f, "%.2f mm")) {
sample_config.maximal_distance_from_outline = scale_(maximal_distance_from_outline);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Measured as sum of VD edge length from outline\nUsed only when there is no space for outline offset on first/last point\nMust be bigger than minimal_distance_from_outline");
ImGui::Text("max_interesting_angle is %.0f", float(sample_config.max_interesting_angle*180/M_PI));
if (ImGui::IsItemHovered()) ImGui::SetTooltip(" When angle on outline is smaller than max_interesting_angle\nthan create unmovable support point.\nShould be in range from 90 to 180");
if (float minimal_support_distance = unscale<float>(sample_config.minimal_support_distance); // [in mm]
ImGui::InputFloat("Thin dist", &minimal_support_distance, .1f, 1.f, "%.2f mm")) {
sample_config.minimal_support_distance = scale_(minimal_support_distance);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Distinguish when to add support point on Voronoi Diagram\nMUST be bigger than minimal_distance_from_outline\nSmaller -> more supports AND Larger -> less amount");
if (float min_side_branch_length = unscale<float>(sample_config.min_side_branch_length); // [in mm]
ImGui::InputFloat("min_side_branch_length", &min_side_branch_length, .1f, 1.f, "%.2f mm")) {
sample_config.min_side_branch_length = scale_(min_side_branch_length);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("minimal length of side branch to be sampled\nit is used for sampling in center only");
if (float max_for_one = unscale<float>(sample_config.max_length_for_one_support_point); // [in mm]
ImGui::InputFloat("Max len for one", &max_for_one, .1f, 1.f, "%.2f mm")) {
sample_config.max_length_for_one_support_point = scale_(max_for_one);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Maximal island length (longest voronoi path) for support by point in path center");
if (float max_for_two = unscale<float>(sample_config.max_length_for_two_support_points); // [in mm]
ImGui::InputFloat("Max len for two", &max_for_two, .1f, 1.f, "%.2f mm")) {
sample_config.max_length_for_two_support_points = scale_(max_for_two);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Maximal island length (longest voronoi path)\n for support by 2 points on path sides");
if (float max_width_for_center_support_line = unscale<float>(sample_config.max_width_for_center_support_line); // [in mm]
ImGui::InputFloat("thin max width", &max_width_for_center_support_line, .1f, 1.f, "%.2f mm")) {
sample_config.max_width_for_center_support_line = scale_(max_width_for_center_support_line);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Maximal width of line island supported in the middle of line\nMust be greater or equal to thick min width(to make hysteresis)");
if (float min_width_for_outline_support = unscale<float>(sample_config.min_width_for_outline_support); // [in mm]
ImGui::InputFloat("thick min width", &min_width_for_outline_support, .1f, 1.f, "%.2f mm")) {
sample_config.min_width_for_outline_support = scale_(min_width_for_outline_support);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Minimal width to be supported by outline\nMust be smaller or equal to thin max width(to make hysteresis)");
ImGui::Text("head radius is set to %.2f", unscale<float>(sample_config.head_radius));
ImGui::Text("Alignment stop criteria: min_move(%.0f um), iter(%d x), max_VD_move(%.2f mm)", unscale<float>(sample_config.minimal_move)*1000, sample_config.count_iteration,
unscale<float>(sample_config.max_align_distance)
);
if (exist_change){
sla::SampleConfigFactory::verify(sample_config);
}
ImGui::TreePop();
}
ImGui::Text("Distribution depends on './resources/data/sla_support.svg'\ninstruction for edit are in file"); ImGui::Text("Distribution depends on './resources/data/sla_support.svg'\ninstruction for edit are in file");
@ -886,6 +809,102 @@ RENDER_AGAIN:
m_parent.set_as_dirty(); m_parent.set_as_dirty();
} }
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();
bool store_islands = !sample_config.path.empty();
if (ImGui::Checkbox("StoreIslands", &store_islands)) {
if (store_islands = true)
sample_config.path = "C:/data/temp/island<<order>>.svg";
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Store islands in file\n<<order>> is replaced by island order number");
if (store_islands) {
ImGui::SameLine();
std::string path;
ImGui::InputText("path", &sample_config.path);
}
bool exist_change = false;
if (float simplification_tolerance = unscale<float>(sample_config.simplification_tolerance); // [in mm]
ImGui::InputFloat("input simplify", &simplification_tolerance, .1f, 1.f, "%.2f mm")) {
sample_config.simplification_tolerance = scale_(simplification_tolerance);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("There is no need to calculate with precisse island\nNOTE: Slice of Cylinder bottom has tip of trinagles on contour\n(neighbor coordinate -> create issue in boost::voronoi)");
if (float max_distance = unscale<float>(sample_config.max_distance); // [in mm]
ImGui::InputFloat("Max dist", &max_distance, .1f, 1.f, "%.2f mm")) {
sample_config.max_distance = scale_(max_distance);
sample_config.half_distance = sample_config.max_distance / 2;
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Every support point on island has at least one support point in maximum distance\nMUST be bigger than zero");
ImGui::SameLine(); ImGui::Text("half is %.2f", unscale<float>(sample_config.half_distance));
if (float minimal_distance_from_outline = unscale<float>(sample_config.minimal_distance_from_outline); // [in mm]
ImGui::InputFloat("from outline", &minimal_distance_from_outline, .1f, 1.f, "%.2f mm")) {
sample_config.minimal_distance_from_outline = scale_(minimal_distance_from_outline);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("When it is possible, there will be this minimal distance from outline.\nZERO when head center should be on outline\nSHOULD be positive number");
ImGui::SameLine();
if (float maximal_distance_from_outline = unscale<float>(sample_config.maximal_distance_from_outline); // [in mm]
ImGui::InputFloat("max from outline", &maximal_distance_from_outline, .1f, 1.f, "%.2f mm")) {
sample_config.maximal_distance_from_outline = scale_(maximal_distance_from_outline);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Measured as sum of VD edge length from outline\nUsed only when there is no space for outline offset on first/last point\nMust be bigger than minimal_distance_from_outline");
ImGui::Text("max_interesting_angle is %.0f", float(sample_config.max_interesting_angle*180/M_PI));
if (ImGui::IsItemHovered()) ImGui::SetTooltip(" When angle on outline is smaller than max_interesting_angle\nthan create unmovable support point.\nShould be in range from 90 to 180");
if (float minimal_support_distance = unscale<float>(sample_config.minimal_support_distance); // [in mm]
ImGui::InputFloat("Thin dist", &minimal_support_distance, .1f, 1.f, "%.2f mm")) {
sample_config.minimal_support_distance = scale_(minimal_support_distance);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Distinguish when to add support point on Voronoi Diagram\nMUST be bigger than minimal_distance_from_outline\nSmaller -> more supports AND Larger -> less amount");
if (float min_side_branch_length = unscale<float>(sample_config.min_side_branch_length); // [in mm]
ImGui::InputFloat("min_side_branch_length", &min_side_branch_length, .1f, 1.f, "%.2f mm")) {
sample_config.min_side_branch_length = scale_(min_side_branch_length);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("minimal length of side branch to be sampled\nit is used for sampling in center only");
if (float max_for_one = unscale<float>(sample_config.max_length_for_one_support_point); // [in mm]
ImGui::InputFloat("Max len for one", &max_for_one, .1f, 1.f, "%.2f mm")) {
sample_config.max_length_for_one_support_point = scale_(max_for_one);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Maximal island length (longest voronoi path) for support by point in path center");
if (float max_for_two = unscale<float>(sample_config.max_length_for_two_support_points); // [in mm]
ImGui::InputFloat("Max len for two", &max_for_two, .1f, 1.f, "%.2f mm")) {
sample_config.max_length_for_two_support_points = scale_(max_for_two);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Maximal island length (longest voronoi path)\n for support by 2 points on path sides");
if (float max_width_for_center_support_line = unscale<float>(sample_config.max_width_for_center_support_line); // [in mm]
ImGui::InputFloat("thin max width", &max_width_for_center_support_line, .1f, 1.f, "%.2f mm")) {
sample_config.max_width_for_center_support_line = scale_(max_width_for_center_support_line);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Maximal width of line island supported in the middle of line\nMust be greater or equal to thick min width(to make hysteresis)");
if (float min_width_for_outline_support = unscale<float>(sample_config.min_width_for_outline_support); // [in mm]
ImGui::InputFloat("thick min width", &min_width_for_outline_support, .1f, 1.f, "%.2f mm")) {
sample_config.min_width_for_outline_support = scale_(min_width_for_outline_support);
exist_change = true;
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("Minimal width to be supported by outline\nMust be smaller or equal to thin max width(to make hysteresis)");
ImGui::Text("head radius is set to %.2f", unscale<float>(sample_config.head_radius));
ImGui::Text("Alignment stop criteria: min_move(%.0f um), iter(%d x), max_VD_move(%.2f mm)", unscale<float>(sample_config.minimal_move)*1000, sample_config.count_iteration,
unscale<float>(sample_config.max_align_distance)
);
if (exist_change){
sla::SampleConfigFactory::verify(sample_config);
}
// end of tree node
ImGui::TreePop();
}
bool GLGizmoSlaSupports::on_is_activable() const bool GLGizmoSlaSupports::on_is_activable() const
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();

View File

@ -91,6 +91,8 @@ private:
void unregister_point_raycasters_for_picking(); void unregister_point_raycasters_for_picking();
void update_point_raycasters_for_picking_transform(); void update_point_raycasters_for_picking_transform();
void draw_island_config();
bool m_lock_unique_islands = false; bool m_lock_unique_islands = false;
bool m_editing_mode = false; // Is editing mode active? bool m_editing_mode = false; // Is editing mode active?
float m_new_point_head_diameter; // Size of a new point. float m_new_point_head_diameter; // Size of a new point.

View File

@ -12,7 +12,7 @@
#include <libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp> #include <libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp>
#include <libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp> #include <libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp>
#include <libslic3r/SLA/SupportIslands/PolygonUtils.hpp> #include <libslic3r/SLA/SupportIslands/PolygonUtils.hpp>
#include "nanosvg/nanosvg.h" // load SVG file
#include "sla_test_utils.hpp" #include "sla_test_utils.hpp"
using namespace Slic3r; using namespace Slic3r;
@ -318,11 +318,45 @@ ExPolygon load_frog(){
return slices.front()[1]; return slices.front()[1];
} }
ExPolygon load_svg(const std::string& svg_filepath) {
struct NSVGimage *image = nsvgParseFromFile(svg_filepath.c_str(), "px", 96);
ScopeGuard sg_image([&image] { nsvgDelete(image); });
auto to_polygon = [](NSVGpath *path) {
Polygon r;
r.points.reserve(path->npts);
for (size_t i = 0; i < path->npts; i++)
r.points.push_back(Point(path->pts[2 * i], path->pts[2 * i + 1]));
return r;
};
for (NSVGshape *shape_ptr = image->shapes; shape_ptr != NULL; shape_ptr = shape_ptr->next) {
const NSVGshape &shape = *shape_ptr;
if (!(shape.flags & NSVG_FLAGS_VISIBLE)) continue; // is visible
if (shape.fill.type != NSVG_PAINT_NONE) continue; // is not used fill
if (shape.stroke.type == NSVG_PAINT_NONE) continue; // exist stroke
//if (shape.strokeWidth < 1e-5f) continue; // is visible stroke width
//if (shape.stroke.color != 4278190261) continue; // is red
ExPolygon result;
for (NSVGpath *path = shape.paths; path != NULL; path = path->next) {
// Path order is reverse to path in file
if (path->next == NULL) // last path is contour
result.contour = to_polygon(path);
else
result.holes.push_back(to_polygon(path));
}
return result;
}
REQUIRE(false);
return {};
}
ExPolygons createTestIslands(double size) ExPolygons createTestIslands(double size)
{ {
bool useFrogLeg = false; bool useFrogLeg = false;
// need post reorganization of longest path // need post reorganization of longest path
ExPolygons result = { ExPolygons result = {
load_svg("C:/Users/Filip Sykala/Downloads/lm_issue.svg"),
// one support point // one support point
ExPolygon(PolygonUtils::create_equilateral_triangle(size)), ExPolygon(PolygonUtils::create_equilateral_triangle(size)),
ExPolygon(PolygonUtils::create_square(size)), ExPolygon(PolygonUtils::create_square(size)),