mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-12 13:28:58 +08:00
Add option to store islands (some could make an issue this is tool to collect problematic islands)
This commit is contained in:
parent
d3d32c6d7d
commit
8794099682
@ -76,6 +76,9 @@ struct SampleConfig
|
||||
// NOTE: Slice of Cylinder bottom has tip of trinagles on contour
|
||||
// (neighbor coordinate - create issue in voronoi)
|
||||
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
|
||||
#endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_
|
||||
|
@ -124,6 +124,15 @@ SupportIslandPoints SampleIslandUtils::uniform_cover_island(
|
||||
) {
|
||||
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,
|
||||
// it will be supported whole by support poin in center
|
||||
if (Point center; get_center(simplified_island.contour.points, config.head_radius, center)) {
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "libslic3r/Line.hpp"
|
||||
#include "libslic3r/Surface.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
draw_outline(expolygon.contour, stroke_outer, stroke_width);
|
||||
|
@ -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_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();
|
||||
|
||||
private:
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "libslic3r/SLAPrint.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_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%)");
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Support islands:")) {
|
||||
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();
|
||||
}
|
||||
draw_island_config();
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
@ -91,6 +91,8 @@ private:
|
||||
void unregister_point_raycasters_for_picking();
|
||||
void update_point_raycasters_for_picking_transform();
|
||||
|
||||
void draw_island_config();
|
||||
|
||||
bool m_lock_unique_islands = false;
|
||||
bool m_editing_mode = false; // Is editing mode active?
|
||||
float m_new_point_head_diameter; // Size of a new point.
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp>
|
||||
#include <libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp>
|
||||
#include <libslic3r/SLA/SupportIslands/PolygonUtils.hpp>
|
||||
|
||||
#include "nanosvg/nanosvg.h" // load SVG file
|
||||
#include "sla_test_utils.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
@ -318,11 +318,45 @@ ExPolygon load_frog(){
|
||||
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)
|
||||
{
|
||||
bool useFrogLeg = false;
|
||||
// need post reorganization of longest path
|
||||
ExPolygons result = {
|
||||
load_svg("C:/Users/Filip Sykala/Downloads/lm_issue.svg"),
|
||||
// one support point
|
||||
ExPolygon(PolygonUtils::create_equilateral_triangle(size)),
|
||||
ExPolygon(PolygonUtils::create_square(size)),
|
||||
|
Loading…
x
Reference in New Issue
Block a user