From 11e20327e49cc5f9541e61cbc3ff2d13767edaba Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Thu, 2 Jan 2025 16:05:05 +0100 Subject: [PATCH] Testing version (commented out autogenerator parameters) Edit configuration svg to change values to 160 percent of the density --- resources/data/sla_support.svg | 24 ++-- src/libslic3r/SLA/SupportPointGenerator.cpp | 121 ++++++++++++++++++- src/libslic3r/SLA/SupportPointGenerator.hpp | 4 + src/libslic3r/SLAPrintSteps.cpp | 19 ++- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 112 +++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 1 + 6 files changed, 214 insertions(+), 67 deletions(-) diff --git a/resources/data/sla_support.svg b/resources/data/sla_support.svg index 7fef16f080..d131315194 100644 --- a/resources/data/sla_support.svg +++ b/resources/data/sla_support.svg @@ -26,13 +26,13 @@ showgrid="false" showborder="true" borderlayer="true" - inkscape:zoom="19.02887" - inkscape:cx="14.845863" - inkscape:cy="132.29897" - inkscape:window-width="2400" - inkscape:window-height="1261" - inkscape:window-x="-9" - inkscape:window-y="-9" + inkscape:zoom="3.3638608" + inkscape:cx="115.78957" + inkscape:cy="88.588685" + inkscape:window-width="1920" + inkscape:window-height="1129" + inkscape:window-x="1912" + inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="layer1" /> island supports interface /// Struct to store support points in KD tree to fast search for nearest ones. @@ -799,6 +801,105 @@ std::vector load_curve_from_file() { return {}; } +#ifdef PERMANENT_SUPPORTS +// Processing permanent support points +// Permanent are manualy edited points by user +namespace { +struct LayerSupport +{ + SupportPoint point; + Point layer_position; + size_t part_index; +}; +using LayerSupports = std::vector; + +size_t get_index_of_closest_part(const Point &coor, const LayerParts &parts) { + size_t count_lines = 0; + std::vector part_lines_ends; + part_lines_ends.reserve(parts.size()); + for (const LayerPart &part : parts) { + count_lines += count_points(*part.shape); + part_lines_ends.push_back(count_lines); + } + Linesf lines; + lines.reserve(count_lines); + for (const LayerPart &part : parts) + append(lines, to_linesf({*part.shape})); + AABBTreeIndirect::Tree<2, double> tree = + AABBTreeLines::build_aabb_tree_over_indexed_lines(lines); + + size_t line_idx = std::numeric_limits::max(); + Vec2d coor_d = coor.cast(); + Vec2d hit_point; + [[maybe_unused]] double distance_sq = + AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, coor_d, line_idx, hit_point); + + // Find part index of closest line + for (size_t part_index = 0; part_index < part_lines_ends.size(); ++part_index) + if (line_idx < part_lines_ends[part_index]) { + // check point lais inside prev or next part shape + // When assert appear check that part index is really the correct one + assert(union_ex( + get_polygons(parts[part_index].prev_parts), + get_polygons(parts[part_index].next_parts)).contains(coor)); + return part_index; + } + + assert(false); // not found + return 0; +} + +LayerSupports supports_for_layer(const SupportPoints &points, size_t index, + float print_z, const LayerParts &parts) { + if (index >= points.size()) + return {}; + + LayerSupports result; + for (const SupportPoint &point = points[index]; point.pos.z() < print_z; ++index) { + // find layer part for support + size_t part_index = parts.size(); + Point coor(static_cast(scale_(point.pos.x())), + static_cast(scale_(point.pos.y()))); + + // find part for support point + for (const LayerPart &part : parts) { + if (part.shape_extent.contains(coor) && + part.shape->contains(coor)) { + // parts do not overlap each other + assert(part_index >= parts.size()); + part_index = &part - &parts.front(); + } + } + if (part_index >= parts.size()) // support point is not in any part + part_index = get_index_of_closest_part(coor, parts); + result.push_back(LayerSupport{point, coor, part_index}); + } + return {}; +} + +/// +/// Guess range of layers by its centers +/// NOTE: not valid range for variable layer height but divide space +/// +/// +/// +/// Range of layers +MinMax get_layer_range(const Layers &layers, size_t layer_id) { + assert(layer_id < layers.size()); + if (layer_id >= layers.size()) + return MinMax{0., 0.}; + + float print_z = layers[layer_id].print_z; + float min = (layer_id == 0) ? 0.f : (layers[layer_id - 1].print_z + print_z) / 2.f; + float max = ((layer_id + 1) < layers.size()) ? + (layers[layer_id + 1].print_z + print_z) / 2.f : + print_z + (print_z - min); // last layer guess height by prev layer center + return MinMax{min, max}; +} + +} // namespace +#endif // PERMANENT_SUPPORTS + LayerSupportPoints Slic3r::sla::generate_support_points( const SupportPointGeneratorData &data, const SupportPointGeneratorConfig &config, @@ -822,17 +923,33 @@ LayerSupportPoints Slic3r::sla::generate_support_points( // Storage for support points used by grid LayerSupportPoints result; + // permanent supports MUST be sorted by z + assert(std::is_sorted(data.permanent_supports.begin(), data.permanent_supports.end(), + [](const SupportPoint &a, const SupportPoint &b) { return a.pos.z() < b.pos.z(); })); + // Index into data.permanent_supports + size_t permanent_index = 0; + // How to propagate permanent support position into previous layers? and how deep? requirements are chained. + // IMHO it should start togetjer from islands and permanent than propagate over surface + // grid index == part in layer index std::vector prev_grids; // same count as previous layer item size for (size_t layer_id = 0; layer_id < layers.size(); ++layer_id) { const Layer &layer = layers[layer_id]; - prepare_supports_for_layer(result, layer.print_z, config); // grid index == part in layer index std::vector grids; grids.reserve(layer.parts.size()); + +#ifdef PERMANENT_SUPPORTS + float layer_max_z = get_layer_range(layers, layer_id).max; + if (data.permanent_supports[permanent_index].pos.z() < layer_max_z){ + LayerSupports permanent = + supports_for_layer(data.permanent_supports, permanent_index, layer_max_z, layer.parts); + } +#endif // PERMANENT_SUPPORTS + for (const LayerPart &part : layer.parts) { if (part.prev_parts.empty()) { // Island ? // only island add new grid diff --git a/src/libslic3r/SLA/SupportPointGenerator.hpp b/src/libslic3r/SLA/SupportPointGenerator.hpp index 26fb305e08..1d24881324 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.hpp +++ b/src/libslic3r/SLA/SupportPointGenerator.hpp @@ -145,6 +145,7 @@ using LayerSupportPoints = std::vector; struct Layer { // Absolute distance from Zero - copy value from heights + // It represents center of layer(range of layer is half layer size above and belowe) float print_z; // [in mm] // data for one expolygon @@ -165,6 +166,9 @@ struct SupportPointGeneratorData // and connection between layers for its part // NOTE: contain links into slices Layers layers; + + // Manualy edited supports by user should be permanent + SupportPoints permanent_supports; }; // call during generation of support points to check cancel event diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 84c6132c3c..9fabd8136e 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -702,8 +702,19 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po) ThrowOnCancel cancel = [this]() { throw_if_canceled(); }; StatusFunction status = statuscb; - LayerSupportPoints layer_support_points = - generate_support_points(po.m_support_point_generator_data, config, cancel, status); + // update permanent support points + SupportPointGeneratorData &data = po.m_support_point_generator_data; + + data.permanent_supports.clear(); + for (const SupportPoint &p : po.model_object()->sla_support_points) + if (p.type == SupportPointType::manual_add) { + data.permanent_supports.push_back(p); + data.permanent_supports.back().pos = + po.trafo().cast() * data.permanent_supports.back().pos; + } + std::sort(data.permanent_supports.begin(), data.permanent_supports.end(), + [](const SupportPoint& p1,const SupportPoint& p2){ return p1.pos.z() < p2.pos.z(); }); + LayerSupportPoints layer_support_points = generate_support_points(data, config, cancel, status); const AABBMesh& emesh = po.m_supportdata->input.emesh; // Maximal move of support point to mesh surface, @@ -714,6 +725,10 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po) SupportPoints support_points = move_on_mesh_surface(layer_support_points, emesh, allowed_move, cancel); + // Naive implementation only append permanent supports to the result + support_points.insert(support_points.end(), + data.permanent_supports.begin(), data.permanent_supports.end()); + throw_if_canceled(); MeshSlicingParamsEx params; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 3db393d502..987ab631eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -33,9 +33,8 @@ namespace Slic3r { namespace GUI { GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) -: GLGizmoSlaBase(parent, icon_filename, sprite_id, slaposDrillHoles) -{ - show_sla_supports(true); + : GLGizmoSlaBase(parent, icon_filename, sprite_id, slaposDrillHoles /*slaposSupportPoints*/) { + show_sla_supports(false); } bool GLGizmoSlaSupports::on_init() @@ -144,8 +143,6 @@ void GLGizmoSlaSupports::on_render() glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); - show_sla_supports(!m_editing_mode); - render_volumes(); render_points(selection); @@ -198,10 +195,15 @@ void GLGizmoSlaSupports::render_points(const Selection& selection) const Transform3d& view_matrix = camera.get_view_matrix(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + const ColorRGBA selected_color = ColorRGBA::REDISH(); + const ColorRGBA hovered_color = ColorRGBA::CYAN(); + const ColorRGBA island_color = ColorRGBA::BLUEISH(); + const ColorRGBA inactive_color = ColorRGBA::LIGHT_GRAY(); + const ColorRGBA manual_color = ColorRGBA::ORANGE(); + ColorRGBA render_color; for (size_t i = 0; i < cache_size; ++i) { const sla::SupportPoint& support_point = m_editing_mode ? m_editing_cache[i].support_point : m_normal_cache[i]; - const bool point_selected = m_editing_mode ? m_editing_cache[i].selected : false; const bool clipped = is_mesh_point_clipped(support_point.pos.cast()); if (i < m_point_raycasters.size()) { @@ -211,22 +213,18 @@ void GLGizmoSlaSupports::render_points(const Selection& selection) if (clipped) continue; + render_color = support_point.type == sla::SupportPointType::manual_add ? + manual_color : inactive_color; // First decide about the color of the point. - if (size_t(m_hover_id) == i && m_editing_mode) // ignore hover state unless editing mode is active - render_color = { 0.f, 1.f, 1.f, 1.f }; - else { // neigher hover nor picking - bool supports_new_island = m_lock_unique_islands && support_point.type == sla::SupportPointType::island; - if (m_editing_mode) { - if (point_selected) - render_color = { 1.f, 0.3f, 0.3f, 1.f}; - else - if (supports_new_island) - render_color = { 0.3f, 0.3f, 1.f, 1.f }; - else - render_color = { 0.7f, 0.7f, 0.7f, 1.f }; + if (m_editing_mode) { + if (size_t(m_hover_id) == i) // ignore hover state unless editing mode is active + render_color = hovered_color; + else if (m_editing_cache[i].selected) + render_color = selected_color; + else if (m_lock_unique_islands) { + render_color = support_point.type == sla::SupportPointType::island? + island_color : ColorRGBA{ 0.7f, 0.7f, 0.7f, 1.f }; } - else - render_color = { 0.5f, 0.5f, 0.5f, 1.f }; } m_cone.model.set_color(render_color); @@ -680,10 +678,16 @@ RENDER_AGAIN: } else { // not in editing mode: m_imgui->disabled_begin(!is_input_enabled()); - //ImGui::AlignTextToFramePadding(); - ImGuiPureWrap::text(m_desc.at("points_density")); - //ImGui::SameLine(settings_sliders_left); + ImGui::SameLine(); + + if (ImGui::Checkbox("##ShowSupportStructure", &m_show_support_structure)){ + show_sla_supports(m_show_support_structure); + if (m_show_support_structure) + reslice_until_step(slaposPad); + } else if (ImGui::IsItemHovered()) + ImGui::SetTooltip("%s", _u8L("Show/Hide supporting structure").c_str()); + const char *support_points_density = "support_points_density_relative"; float density = static_cast(get_config_options({support_points_density})[0])->value; if (m_imgui->slider_float("##density", &density, 0.f, 200.f, "%.f %%")){ @@ -711,7 +715,7 @@ RENDER_AGAIN: wxGetApp().obj_list()->update_and_show_object_settings_item(); auto_generate(); } - + const sla::SupportPoints &supports = m_normal_cache; int count_user_edited = 0; int count_island = 0; @@ -734,22 +738,26 @@ RENDER_AGAIN: } ImVec4 light_gray{0.4f, 0.4f, 0.4f, 1.0f}; ImGui::TextColored(light_gray, stats.c_str()); + if (supports.empty()){ + ImGui::SameLine(); + if (ImGuiPureWrap::button(m_desc.at("auto_generate"))) + auto_generate(); + } - ImGui::Separator(); // START temporary debug - ImGui::Text("Between delimiters is temporary GUI"); - sla::SampleConfig &sample_config = sla::SampleConfigFactory::get_sample_config(); - if (float overhang_sample_distance = sample_config.prepare_config.discretize_overhang_step; - m_imgui->slider_float("overhang discretization", &overhang_sample_distance, 2e-5f, 10.f, "%.2f mm")){ - sample_config.prepare_config.discretize_overhang_step = overhang_sample_distance; - } else if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Smaller will slow down. Step for discretization overhang outline for test of support need"); - - draw_island_config(); - ImGui::Text("Distribution depends on './resources/data/sla_support.svg'\ninstruction for edit are in file"); - ImGui::Separator(); - - if (ImGuiPureWrap::button(m_desc.at("auto_generate"))) - auto_generate(); + //ImGui::Separator(); // START temporary debug + //ImGui::Text("Between delimiters is temporary GUI"); + //sla::SampleConfig &sample_config = sla::SampleConfigFactory::get_sample_config(); + //if (float overhang_sample_distance = sample_config.prepare_config.discretize_overhang_step; + // m_imgui->slider_float("overhang discretization", &overhang_sample_distance, 2e-5f, 10.f, "%.2f mm")){ + // sample_config.prepare_config.discretize_overhang_step = overhang_sample_distance; + //} else if (ImGui::IsItemHovered()) + // ImGui::SetTooltip("Smaller will slow down. Step for discretization overhang outline for test of support need"); + // + //draw_island_config(); + //ImGui::Text("Distribution depends on './resources/data/sla_support.svg'\ninstruction for edit are in file"); + //ImGui::Separator(); + //if (ImGuiPureWrap::button(m_desc.at("auto_generate"))) + // auto_generate(); ImGui::Separator(); if (ImGuiPureWrap::button(m_desc.at("manual_editing"))) @@ -1180,7 +1188,7 @@ void GLGizmoSlaSupports::editing_mode_apply_changes() mo->sla_support_points.clear(); mo->sla_support_points = m_normal_cache; - reslice_until_step(slaposPad); + reslice_until_step(m_show_support_structure ? slaposPad : slaposSupportPoints); } } @@ -1280,7 +1288,8 @@ void GLGizmoSlaSupports::get_data_from_backend() for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { if (po->model_object()->id() == mo->id()) { m_normal_cache.clear(); - auto mat = po->trafo().inverse().cast(); + + auto mat = po->trafo().inverse().cast(); // TODO: WTF trafo????? !!!!!! for (const sla::SupportPoint &p : po->get_support_points()) m_normal_cache.emplace_back(sla::SupportPoint{mat * p.pos, p.head_front_radius, p.type}); @@ -1298,25 +1307,25 @@ void GLGizmoSlaSupports::auto_generate() { //wxMessageDialog dlg(GUI::wxGetApp().plater(), MessageDialog dlg(GUI::wxGetApp().plater(), - _L("Autogeneration will erase all manually edited points.") + "\n\n" + - _L("Are you sure you want to do it?") + "\n", + _L("Autogeneration with manually edited points is inperfect but preserve wanted postion of supports.") + "\n\n" + + _L("Do you want to remove manually edited points?") + "\n", _L("Warning"), wxICON_WARNING | wxYES | wxNO); - ModelObject* mo = m_c->selection_info()->model_object(); - - if (mo->sla_points_status != sla::PointsStatus::UserModified || m_normal_cache.empty() || dlg.ShowModal() == wxID_YES) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Autogenerate support points")); - wxGetApp().CallAfter([this]() { reslice_until_step(slaposSupportPoints); }); - mo->sla_points_status = sla::PointsStatus::Generating; + if (mo->sla_points_status == sla::PointsStatus::UserModified && + dlg.ShowModal() == wxID_YES) { + mo->sla_support_points.clear(); } + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Autogenerate support points")); + wxGetApp().CallAfter([this]() { reslice_until_step( + m_show_support_structure ? slaposPad : slaposSupportPoints); }); + mo->sla_points_status = sla::PointsStatus::Generating; } - - void GLGizmoSlaSupports::switch_to_editing_mode() { wxGetApp().plater()->enter_gizmos_stack(); m_editing_mode = true; + show_sla_supports(false); m_editing_cache.clear(); for (const sla::SupportPoint& sp : m_normal_cache) m_editing_cache.emplace_back(sp); @@ -1330,6 +1339,7 @@ void GLGizmoSlaSupports::disable_editing_mode() { if (m_editing_mode) { m_editing_mode = false; + show_sla_supports(m_show_support_structure); wxGetApp().plater()->leave_gizmos_stack(); m_parent.set_as_dirty(); unregister_point_raycasters_for_picking(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index eff8f09483..4fe62a378c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -93,6 +93,7 @@ private: void draw_island_config(); + bool m_show_support_structure = false; 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.