Merge branch 'lm_sla_supports_auto2' of https://github.com/prusa3d/Slic3r into lm_sla_supports_auto2

This commit is contained in:
bubnikv 2019-02-20 10:47:44 +01:00
commit 9a8a9bac28
13 changed files with 205 additions and 123 deletions

View File

@ -2630,28 +2630,19 @@ void PrintConfigDef::init_sla_params()
def->min = 0; def->min = 0;
def->default_value = new ConfigOptionFloat(5.0); def->default_value = new ConfigOptionFloat(5.0);
def = this->add("support_density_at_horizontal", coInt); def = this->add("support_points_density_relative", coInt);
def->label = L("Density on horizontal surfaces"); def->label = L("Support points density");
def->category = L("Supports"); def->category = L("Supports");
def->tooltip = L("How many support points (approximately) should be placed on horizontal surface."); def->tooltip = L("This is a relative measure of support points density.");
def->sidetext = L("points per square dm"); def->sidetext = L("%");
def->cli = ""; def->cli = "";
def->min = 0; def->min = 0;
def->default_value = new ConfigOptionInt(500); def->default_value = new ConfigOptionInt(100);
def = this->add("support_density_at_45", coInt); def = this->add("support_points_minimal_distance", coFloat);
def->label = L("Density on surfaces at 45 degrees"); def->label = L("Minimal distance of the support points");
def->category = L("Supports"); def->category = L("Supports");
def->tooltip = L("How many support points (approximately) should be placed on surface sloping at 45 degrees."); def->tooltip = L("No support points will be placed closer than this threshold.");
def->sidetext = L("points per square dm");
def->cli = "";
def->min = 0;
def->default_value = new ConfigOptionInt(250);
def = this->add("support_minimal_z", coFloat);
def->label = L("Minimal support point height");
def->category = L("Supports");
def->tooltip = L("No support points will be placed lower than this value from the bottom.");
def->sidetext = L("mm"); def->sidetext = L("mm");
def->cli = ""; def->cli = "";
def->min = 0; def->min = 0;

View File

@ -1002,9 +1002,8 @@ public:
ConfigOptionFloat support_object_elevation /*= 5.0*/; ConfigOptionFloat support_object_elevation /*= 5.0*/;
/////// Following options influence automatic support points placement: /////// Following options influence automatic support points placement:
ConfigOptionInt support_density_at_horizontal; ConfigOptionInt support_points_density_relative;
ConfigOptionInt support_density_at_45; ConfigOptionFloat support_points_minimal_distance;
ConfigOptionFloat support_minimal_z;
// Now for the base pool (pad) ///////////////////////////////////////////// // Now for the base pool (pad) /////////////////////////////////////////////
@ -1040,9 +1039,8 @@ protected:
OPT_PTR(support_base_height); OPT_PTR(support_base_height);
OPT_PTR(support_critical_angle); OPT_PTR(support_critical_angle);
OPT_PTR(support_max_bridge_length); OPT_PTR(support_max_bridge_length);
OPT_PTR(support_density_at_horizontal); OPT_PTR(support_points_density_relative);
OPT_PTR(support_density_at_45); OPT_PTR(support_points_minimal_distance);
OPT_PTR(support_minimal_z);
OPT_PTR(support_object_elevation); OPT_PTR(support_object_elevation);
OPT_PTR(pad_enable); OPT_PTR(pad_enable);
OPT_PTR(pad_wall_thickness); OPT_PTR(pad_wall_thickness);

View File

@ -233,7 +233,7 @@ void SLAAutoSupports::process(const std::vector<ExPolygons>& slices, const std::
// s.supports_force_inherited /= std::max(1.f, (layer_height / 0.3f) * e_area / s.area); // s.supports_force_inherited /= std::max(1.f, (layer_height / 0.3f) * e_area / s.area);
s.supports_force_inherited /= std::max(1.f, 0.17f * (s.overhangs_area) / s.area); s.supports_force_inherited /= std::max(1.f, 0.17f * (s.overhangs_area) / s.area);
float force_deficit = s.support_force_deficit(m_config.tear_pressure); float force_deficit = s.support_force_deficit(m_config.tear_pressure());
if (s.islands_below.empty()) { // completely new island - needs support no doubt if (s.islands_below.empty()) { // completely new island - needs support no doubt
uniformly_cover({ *s.polygon }, s, point_grid, true); uniformly_cover({ *s.polygon }, s, point_grid, true);
} else if (! s.dangling_areas.empty()) { } else if (! s.dangling_areas.empty()) {
@ -439,16 +439,16 @@ void SLAAutoSupports::uniformly_cover(const ExPolygons& islands, Structure& stru
{ {
//int num_of_points = std::max(1, (int)((island.area()*pow(SCALING_FACTOR, 2) * m_config.tear_pressure)/m_config.support_force)); //int num_of_points = std::max(1, (int)((island.area()*pow(SCALING_FACTOR, 2) * m_config.tear_pressure)/m_config.support_force));
const float support_force_deficit = structure.support_force_deficit(m_config.tear_pressure); const float support_force_deficit = structure.support_force_deficit(m_config.tear_pressure());
if (support_force_deficit < 0) if (support_force_deficit < 0)
return; return;
// Number of newly added points. // Number of newly added points.
const size_t poisson_samples_target = size_t(ceil(support_force_deficit / m_config.support_force)); const size_t poisson_samples_target = size_t(ceil(support_force_deficit / m_config.support_force()));
const float density_horizontal = m_config.tear_pressure / m_config.support_force; const float density_horizontal = m_config.tear_pressure() / m_config.support_force();
//FIXME why? //FIXME why?
float poisson_radius = 1.f / (5.f * density_horizontal); float poisson_radius = std::max(m_config.minimal_distance, 1.f / (5.f * density_horizontal));
// const float poisson_radius = 1.f / (15.f * density_horizontal); // const float poisson_radius = 1.f / (15.f * density_horizontal);
const float samples_per_mm2 = 30.f / (float(M_PI) * poisson_radius * poisson_radius); const float samples_per_mm2 = 30.f / (float(M_PI) * poisson_radius * poisson_radius);
// Minimum distance between samples, in 3D space. // Minimum distance between samples, in 3D space.
@ -465,13 +465,13 @@ void SLAAutoSupports::uniformly_cover(const ExPolygons& islands, Structure& stru
[&structure, &grid3d, min_spacing](const Vec2f &pos) { [&structure, &grid3d, min_spacing](const Vec2f &pos) {
return grid3d.collides_with(pos, &structure, min_spacing); return grid3d.collides_with(pos, &structure, min_spacing);
}); });
if (poisson_samples.size() >= poisson_samples_target) if (poisson_samples.size() >= poisson_samples_target || m_config.minimal_distance > poisson_radius-EPSILON)
break; break;
float coeff = 0.5f; float coeff = 0.5f;
if (poisson_samples.size() * 2 > poisson_samples_target) if (poisson_samples.size() * 2 > poisson_samples_target)
coeff = float(poisson_samples.size()) / float(poisson_samples_target); coeff = float(poisson_samples.size()) / float(poisson_samples_target);
poisson_radius *= coeff; poisson_radius = std::max(m_config.minimal_distance, poisson_radius * coeff);
min_spacing *= coeff; min_spacing = std::max(m_config.minimal_distance, min_spacing * coeff);
} }
#ifdef SLA_AUTOSUPPORTS_DEBUG #ifdef SLA_AUTOSUPPORTS_DEBUG
@ -494,7 +494,7 @@ void SLAAutoSupports::uniformly_cover(const ExPolygons& islands, Structure& stru
} }
for (const Vec2f &pt : poisson_samples) { for (const Vec2f &pt : poisson_samples) {
m_output.emplace_back(float(pt(0)), float(pt(1)), structure.height, 0.2f, is_new_island); m_output.emplace_back(float(pt(0)), float(pt(1)), structure.height, 0.2f, is_new_island);
structure.supports_force_this_layer += m_config.support_force; structure.supports_force_this_layer += m_config.support_force();
grid3d.insert(pt, &structure); grid3d.insert(pt, &structure);
} }
} }

View File

@ -14,13 +14,11 @@ namespace Slic3r {
class SLAAutoSupports { class SLAAutoSupports {
public: public:
struct Config { struct Config {
float density_at_horizontal; float density_relative;
float density_at_45; float minimal_distance;
float minimal_z;
/////////////// ///////////////
// float support_force = 30.f; // a force one point can support (arbitrary force unit) inline float support_force() const { return 10.f / density_relative; } // a force one point can support (arbitrary force unit)
float support_force = 10.f; // a force one point can support (arbitrary force unit) inline float tear_pressure() const { return 1.f; } // pressure that the display exerts (the force unit per mm2)
float tear_pressure = 1.f; // pressure that the display exerts (the force unit per mm2)
}; };
SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector<ExPolygons>& slices, SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector<ExPolygons>& slices,

View File

@ -33,6 +33,7 @@ struct SupportPoint {
pos(data(0), data(1), data(2)), head_front_radius(data(3)), is_new_island(data(4) != 0.f) {} pos(data(0), data(1), data(2)), head_front_radius(data(3)), is_new_island(data(4) != 0.f) {}
bool operator==(const SupportPoint& sp) const { return (pos==sp.pos) && head_front_radius==sp.head_front_radius && is_new_island==sp.is_new_island; } bool operator==(const SupportPoint& sp) const { return (pos==sp.pos) && head_front_radius==sp.head_front_radius && is_new_island==sp.is_new_island; }
bool operator!=(const SupportPoint& sp) const { return !(sp == (*this)); }
}; };

View File

@ -532,9 +532,8 @@ void SLAPrint::process()
this->throw_if_canceled(); this->throw_if_canceled();
SLAAutoSupports::Config config; SLAAutoSupports::Config config;
const SLAPrintObjectConfig& cfg = po.config(); const SLAPrintObjectConfig& cfg = po.config();
config.minimal_z = float(cfg.support_minimal_z); config.density_relative = (float)cfg.support_points_density_relative / 100.f; // the config value is in percents
config.density_at_45 = cfg.support_density_at_45 / 10000.f; config.minimal_distance = cfg.support_points_minimal_distance;
config.density_at_horizontal = cfg.support_density_at_horizontal / 10000.f;
// Construction of this object does the calculation. // Construction of this object does the calculation.
this->throw_if_canceled(); this->throw_if_canceled();
@ -1064,7 +1063,10 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
for (const t_config_option_key &opt_key : opt_keys) { for (const t_config_option_key &opt_key : opt_keys) {
if (opt_key == "layer_height") { if (opt_key == "layer_height") {
steps.emplace_back(slaposObjectSlice); steps.emplace_back(slaposObjectSlice);
} else if (opt_key == "supports_enable") { } else if (
opt_key == "supports_enable"
|| opt_key == "support_points_density_relative"
|| opt_key == "support_points_minimal_distance") {
steps.emplace_back(slaposSupportPoints); steps.emplace_back(slaposSupportPoints);
} else if ( } else if (
opt_key == "support_head_front_diameter" opt_key == "support_head_front_diameter"

View File

@ -3158,6 +3158,7 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec
float cnv_h = (float)canvas.get_canvas_size().get_height(); float cnv_h = (float)canvas.get_canvas_size().get_height();
float height = _get_total_overlay_height(); float height = _get_total_overlay_height();
float top_y = 0.5f * (cnv_h - height) + m_overlay_border; float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{ {
if ((it->second == nullptr) || !it->second->is_selectable()) if ((it->second == nullptr) || !it->second->is_selectable())
@ -5448,10 +5449,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_dirty = true; m_dirty = true;
} }
/*else if ((selected_object_idx != -1) && m_gizmos.grabber_contains_mouse() && evt.RightDown()) { else if ((selected_object_idx != -1) && evt.RightDown() && m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::RightDown))
if (m_gizmos.get_current_type() == Gizmos::SlaSupports) {
m_gizmos.delete_current_grabber(); // event was taken care of by the SlaSupports gizmo
}*/ }
else if (view_toolbar_contains_mouse != -1) else if (view_toolbar_contains_mouse != -1)
{ {
if (m_view_toolbar != nullptr) if (m_view_toolbar != nullptr)
@ -5691,9 +5692,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
} }
else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging()
&& !is_layers_editing_enabled() && m_gizmos.get_current_type() != Gizmos::SlaSupports) && !is_layers_editing_enabled() && (m_gizmos.get_current_type() != Gizmos::SlaSupports || !m_gizmos.mouse_event(SLAGizmoEventType::LeftUp, Vec2d(pos(0), pos(1)), evt.ShiftDown())))
{ {
// SLA gizmo cannot be deselected by clicking in canvas area to avoid inadvertent unselection and losing manual changes // SLA gizmo cannot be deselected by clicking in canvas area to avoid inadvertent unselection and losing manual changes
// that's why the mouse_event function was called so that the gizmo can refuse the deselection in manual editing mode
// deselect and propagate event through callback // deselect and propagate event through callback
if (!evt.ShiftDown() && m_picking_enabled && !m_toolbar_action_running && !m_mouse.ignore_up_event) if (!evt.ShiftDown() && m_picking_enabled && !m_toolbar_action_running && !m_mouse.ignore_up_event)

View File

@ -136,6 +136,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
enum class SLAGizmoEventType { enum class SLAGizmoEventType {
LeftDown = 1, LeftDown = 1,
LeftUp, LeftUp,
RightDown,
Dragging, Dragging,
Delete, Delete,
SelectAll, SelectAll,

View File

@ -1784,23 +1784,15 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const G
m_active_instance = selection.get_instance_idx(); m_active_instance = selection.get_instance_idx();
if ((model_object != nullptr) && selection.is_from_single_instance()) if (model_object && selection.is_from_single_instance())
{ {
if (is_mesh_update_necessary()) if (is_mesh_update_necessary())
update_mesh(); update_mesh();
// If there are no points, let's ask the backend if it calculated some. // If there are no points, let's ask the backend if it calculated some.
if (m_editing_mode_cache.empty() && m_parent.sla_print()->is_step_done(slaposSupportPoints)) { if (m_editing_mode_cache.empty() && m_parent.sla_print()->is_step_done(slaposSupportPoints))
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { get_data_from_backend();
if (po->model_object()->id() == model_object->id()) {
const std::vector<sla::SupportPoint>& points = po->get_support_points();
auto mat = po->trafo().inverse().cast<float>();
for (unsigned int i=0; i<points.size();++i)
m_editing_mode_cache.emplace_back(sla::SupportPoint(mat * points[i].pos, points[i].head_front_radius, points[i].is_new_island), false);
break;
}
}
}
if (m_model_object != m_old_model_object) if (m_model_object != m_old_model_object)
m_editing_mode = false; m_editing_mode = false;
if (m_state == On) { if (m_state == On) {
@ -1919,7 +1911,7 @@ void GLGizmoSlaSupports::render_points(const GLCanvas3D::Selection& selection, b
} }
} }
::glColor3fv(render_color); ::glColor3fv(render_color);
float render_color_emissive[4] = { 0.5 * render_color[0], 0.5 * render_color[1], 0.5 * render_color[2], 1.f}; float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f};
::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive); ::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive);
// Now render the sphere. Inverse matrix of the instance scaling is applied so that the // Now render the sphere. Inverse matrix of the instance scaling is applied so that the
@ -1981,9 +1973,7 @@ void GLGizmoSlaSupports::update_mesh()
m_AABB.init(m_V, m_F); m_AABB.init(m_V, m_F);
// we'll now reload support points (selection might have changed): // we'll now reload support points (selection might have changed):
m_editing_mode_cache.clear(); editing_mode_reload_cache();
for (const sla::SupportPoint& point : m_model_object->sla_support_points)
m_editing_mode_cache.push_back(std::make_pair(point, false));
} }
Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
@ -2045,7 +2035,7 @@ bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mous
m_canvas_height = m_parent.get_canvas_size().get_height(); m_canvas_height = m_parent.get_canvas_size().get_height();
} }
else else
m_editing_mode_cache[m_hover_id].second = true; select_point(m_hover_id);
return true; return true;
} }
@ -2075,16 +2065,16 @@ bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mous
return false; return false;
// Regardless of whether the user clicked the object or not, we will unselect all points: // Regardless of whether the user clicked the object or not, we will unselect all points:
for (unsigned int i=0; i<m_editing_mode_cache.size(); ++i) select_point(NoPoints);
m_editing_mode_cache[i].second = false;
Vec3f new_pos; Vec3f new_pos;
try { try {
new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new point in that case new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new point in that case
m_editing_mode_cache.emplace_back(std::make_pair(sla::SupportPoint(new_pos, m_new_point_head_diameter/2.f, false), true)); m_editing_mode_cache.emplace_back(std::make_pair(sla::SupportPoint(new_pos, m_new_point_head_diameter/2.f, false), true));
m_unsaved_changes = true;
} }
catch (...) { // not clicked on object catch (...) { // not clicked on object
return false; // GLCanvas3D might want to deselect the gizmo return true; // prevents deselection of the gizmo by GLCanvas3D
} }
return true; return true;
} }
@ -2148,9 +2138,18 @@ bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mous
return true; return true;
} }
if (action == SLAGizmoEventType::RightDown) {
if (m_hover_id != -1) {
select_point(NoPoints);
select_point(m_hover_id);
delete_selected_points();
return true;
}
return false;
}
if (action == SLAGizmoEventType::SelectAll) { if (action == SLAGizmoEventType::SelectAll) {
for (auto& point_and_selection : m_editing_mode_cache) select_point(AllPoints);
point_and_selection.second = true;
return true; return true;
} }
@ -2163,8 +2162,10 @@ void GLGizmoSlaSupports::delete_selected_points()
return; return;
for (unsigned int idx=0; idx<m_editing_mode_cache.size(); ++idx) { for (unsigned int idx=0; idx<m_editing_mode_cache.size(); ++idx) {
if (m_editing_mode_cache[idx].second && (!m_editing_mode_cache[idx].first.is_new_island || !m_lock_unique_islands)) if (m_editing_mode_cache[idx].second && (!m_editing_mode_cache[idx].first.is_new_island || !m_lock_unique_islands)) {
m_editing_mode_cache.erase(m_editing_mode_cache.begin() + (idx--)); m_editing_mode_cache.erase(m_editing_mode_cache.begin() + (idx--));
m_unsaved_changes = true;
}
// This should trigger the support generation // This should trigger the support generation
// wxGetApp().plater()->reslice(); // wxGetApp().plater()->reslice();
} }
@ -2182,6 +2183,7 @@ void GLGizmoSlaSupports::on_update(const UpdateData& data, const GLCanvas3D::Sel
catch (...) { return; } catch (...) { return; }
m_editing_mode_cache[m_hover_id].first.pos = new_pos; m_editing_mode_cache[m_hover_id].first.pos = new_pos;
m_editing_mode_cache[m_hover_id].first.is_new_island = false; m_editing_mode_cache[m_hover_id].first.is_new_island = false;
m_unsaved_changes = true;
// Do not update immediately, wait until the mouse is released. // Do not update immediately, wait until the mouse is released.
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
} }
@ -2237,6 +2239,7 @@ RENDER_AGAIN:
if (m_editing_mode) { if (m_editing_mode) {
m_imgui->text(_(L("Left mouse click - add point"))); m_imgui->text(_(L("Left mouse click - add point")));
m_imgui->text(_(L("Right mouse click - remove point")));
m_imgui->text(_(L("Shift + Left (+ drag) - select point(s)"))); m_imgui->text(_(L("Shift + Left (+ drag) - select point(s)")));
m_imgui->text(" "); // vertical gap m_imgui->text(" "); // vertical gap
@ -2250,12 +2253,16 @@ RENDER_AGAIN:
force_refresh |= (old_combo_state != m_combo_box_open); force_refresh |= (old_combo_state != m_combo_box_open);
float current_number = atof(str); float current_number = atof(str);
if (old_combo_state && !m_combo_box_open) // closing the combo must always change the sizes (even if the selection did not change)
for (auto& point_and_selection : m_editing_mode_cache)
if (point_and_selection.second) {
point_and_selection.first.head_front_radius = current_number / 2.f;
m_unsaved_changes = true;
}
if (std::abs(current_number - m_new_point_head_diameter) > 0.001) { if (std::abs(current_number - m_new_point_head_diameter) > 0.001) {
force_refresh = true; force_refresh = true;
m_new_point_head_diameter = current_number; m_new_point_head_diameter = current_number;
for (auto& point_and_selection : m_editing_mode_cache)
if (point_and_selection.second)
point_and_selection.first.head_front_radius = current_number / 2.f;
} }
bool changed = m_lock_unique_islands; bool changed = m_lock_unique_islands;
@ -2268,30 +2275,25 @@ RENDER_AGAIN:
bool apply_changes = m_imgui->button(_(L("Apply changes"))); bool apply_changes = m_imgui->button(_(L("Apply changes")));
if (apply_changes) { if (apply_changes) {
m_model_object->sla_support_points.clear(); editing_mode_apply_changes();
for (const std::pair<sla::SupportPoint, bool>& point_and_selection : m_editing_mode_cache)
m_model_object->sla_support_points.push_back(point_and_selection.first);
m_editing_mode = false;
force_refresh = true; force_refresh = true;
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
} }
ImGui::SameLine(); ImGui::SameLine();
bool discard_changes = m_imgui->button(_(L("Discard changes"))); bool discard_changes = m_imgui->button(_(L("Discard changes")));
if (discard_changes) { if (discard_changes) {
m_editing_mode_cache.clear(); editing_mode_discard_changes();
for (const sla::SupportPoint& point : m_model_object->sla_support_points)
m_editing_mode_cache.push_back(std::make_pair(point, false));
m_editing_mode = false;
force_refresh = true; force_refresh = true;
} }
} }
else { else {
//m_imgui->text("Some settings could"); /* ImGui::PushItemWidth(50.0f);
//m_imgui->text("be exposed here..."); m_imgui->text(_(L("Minimal points distance: ")));
m_imgui->text(""); ImGui::SameLine();
m_imgui->text(""); bool value_changed = ImGui::InputDouble("mm", &m_minimal_point_distance, 0.0f, 0.0f, "%.2f");
m_imgui->text(_(L("Support points density: ")));
m_imgui->text(""); ImGui::SameLine();
value_changed |= ImGui::InputDouble("%", &m_density, 0.0f, 0.0f, "%.f");*/
bool generate = m_imgui->button(_(L("Auto-generate points"))); bool generate = m_imgui->button(_(L("Auto-generate points")));
@ -2302,10 +2304,10 @@ RENDER_AGAIN:
force_refresh = true; force_refresh = true;
#else #else
wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L( wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L(
"Autogeneration will erase all currently assigned points.\n\n" "Autogeneration will erase all manually edited points.\n\n"
"Are you sure you want to do it?\n" "Are you sure you want to do it?\n"
)), _(L("Warning")), wxICON_WARNING | wxYES | wxNO); )), _(L("Warning")), wxICON_WARNING | wxYES | wxNO);
if (dlg.ShowModal() == wxID_YES) { if (m_model_object->sla_support_points.empty() || dlg.ShowModal() == wxID_YES) {
m_model_object->sla_support_points.clear(); m_model_object->sla_support_points.clear();
m_editing_mode_cache.clear(); m_editing_mode_cache.clear();
wxGetApp().plater()->reslice(); wxGetApp().plater()->reslice();
@ -2316,7 +2318,7 @@ RENDER_AGAIN:
if (m_show_modal) { if (m_show_modal) {
if (ImGui::BeginPopupModal(_(L("Warning")), &m_show_modal/*, ImGuiWindowFlags_NoDecoration*/)) if (ImGui::BeginPopupModal(_(L("Warning")), &m_show_modal/*, ImGuiWindowFlags_NoDecoration*/))
{ {
m_imgui->text(_(L("Autogeneration will erase all currently assigned points."))); m_imgui->text(_(L("Autogeneration will erase all manually edited points.")));
m_imgui->text(""); m_imgui->text("");
m_imgui->text(_(L("Are you sure you want to do it?"))); m_imgui->text(_(L("Are you sure you want to do it?")));
@ -2341,12 +2343,11 @@ RENDER_AGAIN:
force_refresh = true; force_refresh = true;
} }
#endif #endif
ImGui::SameLine(); m_imgui->text("");
bool editing_clicked = m_imgui->button("Editing"); m_imgui->text("");
bool editing_clicked = m_imgui->button(_(L("Manual editing")));
if (editing_clicked) { if (editing_clicked) {
m_editing_mode_cache.clear(); editing_mode_reload_cache();
for (const sla::SupportPoint& point : m_model_object->sla_support_points)
m_editing_mode_cache.push_back(std::make_pair(point, false));
m_editing_mode = true; m_editing_mode = true;
} }
} }
@ -2376,8 +2377,17 @@ RENDER_AGAIN:
bool GLGizmoSlaSupports::on_is_activable(const GLCanvas3D::Selection& selection) const bool GLGizmoSlaSupports::on_is_activable(const GLCanvas3D::Selection& selection) const
{ {
return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA
&& selection.is_from_single_instance(); || !selection.is_from_single_instance())
return false;
// Check that none of the selected volumes is outside.
const GLCanvas3D::Selection::IndicesList& list = selection.get_volume_idxs();
for (const auto& idx : list)
if (selection.get_volume(idx)->is_outside)
return false;
return true;
} }
bool GLGizmoSlaSupports::on_is_selectable() const bool GLGizmoSlaSupports::on_is_selectable() const
@ -2401,12 +2411,19 @@ void GLGizmoSlaSupports::on_set_state()
m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
} }
if (m_state == Off) { if (m_state == Off) {
if (m_old_state != Off && m_model_object) { // the gizmo was just turned Off
if (m_unsaved_changes) {
wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L("Do you want to save your manually edited support points ?\n")),
_(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO);
if (dlg.ShowModal() == wxID_YES)
editing_mode_apply_changes();
else
editing_mode_discard_changes();
}
m_parent.toggle_model_objects_visibility(true); m_parent.toggle_model_objects_visibility(true);
m_editing_mode_cache.clear(); m_editing_mode = false; // so it is not active next time the gizmo opens
if (m_model_object)
for (const sla::SupportPoint& point : m_model_object->sla_support_points)
m_editing_mode_cache.push_back(std::make_pair(point, false));
m_editing_mode = false;
#if SLAGIZMO_IMGUI_MODAL #if SLAGIZMO_IMGUI_MODAL
if (m_show_modal) { if (m_show_modal) {
@ -2415,15 +2432,73 @@ void GLGizmoSlaSupports::on_set_state()
} }
#endif #endif
} }
}
m_old_state = m_state;
} }
void GLGizmoSlaSupports::on_start_dragging(const GLCanvas3D::Selection& selection) void GLGizmoSlaSupports::on_start_dragging(const GLCanvas3D::Selection& selection)
{ {
if (m_hover_id != -1) if (m_hover_id != -1) {
for (unsigned int i=0;i<m_editing_mode_cache.size();++i) select_point(NoPoints);
m_editing_mode_cache[i].second = ((int)i == m_hover_id); select_point(m_hover_id);
}
} }
void GLGizmoSlaSupports::select_point(int i)
{
if (i == AllPoints || i == NoPoints) {
for (auto& point_and_selection : m_editing_mode_cache)
point_and_selection.second = ( i == AllPoints ? true : false);
}
else
m_editing_mode_cache[i].second = true;
}
void GLGizmoSlaSupports::editing_mode_discard_changes()
{
m_editing_mode_cache.clear();
for (const sla::SupportPoint& point : m_model_object->sla_support_points)
m_editing_mode_cache.push_back(std::make_pair(point, false));
m_editing_mode = false;
m_unsaved_changes = false;
}
void GLGizmoSlaSupports::editing_mode_apply_changes()
{
// If there are no changes, don't touch the front-end. The data in the cache could have been
// taken from the backend and copying them to ModelObject would needlessly invalidate them.
if (m_unsaved_changes) {
m_model_object->sla_support_points.clear();
for (const std::pair<sla::SupportPoint, bool>& point_and_selection : m_editing_mode_cache)
m_model_object->sla_support_points.push_back(point_and_selection.first);
}
m_editing_mode = false;
m_unsaved_changes = false;
}
void GLGizmoSlaSupports::editing_mode_reload_cache()
{
m_editing_mode_cache.clear();
for (const sla::SupportPoint& point : m_model_object->sla_support_points)
m_editing_mode_cache.push_back(std::make_pair(point, false));
m_unsaved_changes = false;
}
void GLGizmoSlaSupports::get_data_from_backend()
{
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
if (po->model_object()->id() == m_model_object->id()) {
const std::vector<sla::SupportPoint>& points = po->get_support_points();
auto mat = po->trafo().inverse().cast<float>();
for (unsigned int i=0; i<points.size();++i)
m_editing_mode_cache.emplace_back(sla::SupportPoint(mat * points[i].pos, points[i].head_front_radius, points[i].is_new_island), false);
break;
}
}
m_unsaved_changes = false;
// We don't copy the data into ModelObject, as this would stop the background processing.
}
// GLGizmoCut // GLGizmoCut

View File

@ -492,6 +492,8 @@ private:
bool m_lock_unique_islands = false; bool m_lock_unique_islands = false;
bool m_editing_mode = false; bool m_editing_mode = false;
float m_new_point_head_diameter = 0.4f; float m_new_point_head_diameter = 0.4f;
double m_minimal_point_distance = 20.;
double m_density = 100.;
std::vector<std::pair<sla::SupportPoint, bool>> m_editing_mode_cache; // a support point and whether it is currently selected std::vector<std::pair<sla::SupportPoint, bool>> m_editing_mode_cache; // a support point and whether it is currently selected
bool m_selection_rectangle_active = false; bool m_selection_rectangle_active = false;
@ -499,12 +501,26 @@ private:
Vec2d m_selection_rectangle_end_corner; Vec2d m_selection_rectangle_end_corner;
bool m_ignore_up_event = false; bool m_ignore_up_event = false;
bool m_combo_box_open = false; bool m_combo_box_open = false;
bool m_unsaved_changes = false;
EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state)
#if SLAGIZMO_IMGUI_MODAL #if SLAGIZMO_IMGUI_MODAL
bool m_show_modal = false; bool m_show_modal = false;
#endif #endif
int m_canvas_width; int m_canvas_width;
int m_canvas_height; int m_canvas_height;
// Methods that do the model_object and editing cache synchronization,
// editing mode selection, etc:
enum {
AllPoints = -2,
NoPoints,
};
void select_point(int i);
void editing_mode_apply_changes();
void editing_mode_discard_changes();
void editing_mode_reload_cache();
void get_data_from_backend();
protected: protected:
void on_set_state() override; void on_set_state() override;
void on_start_dragging(const GLCanvas3D::Selection& selection) override; void on_start_dragging(const GLCanvas3D::Selection& selection) override;

View File

@ -2232,7 +2232,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
} }
} }
if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS) { if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS) {
// Update SLA gizmo // Update SLA gizmo (reload_scene calls update_gizmos_data)
q->canvas3D()->reload_scene(true); q->canvas3D()->reload_scene(true);
} }
} }

View File

@ -457,9 +457,8 @@ const std::vector<std::string>& Preset::sla_print_options()
"support_critical_angle", "support_critical_angle",
"support_max_bridge_length", "support_max_bridge_length",
"support_object_elevation", "support_object_elevation",
"support_density_at_horizontal", "support_points_density_relative",
"support_density_at_45", "support_points_minimal_distance",
"support_minimal_z",
"pad_enable", "pad_enable",
"pad_wall_thickness", "pad_wall_thickness",
"pad_wall_height", "pad_wall_height",

View File

@ -3202,9 +3202,8 @@ void TabSLAPrint::build()
optgroup->append_single_option_line("support_max_bridge_length"); optgroup->append_single_option_line("support_max_bridge_length");
optgroup = page->new_optgroup(_(L("Automatic generation"))); optgroup = page->new_optgroup(_(L("Automatic generation")));
optgroup->append_single_option_line("support_density_at_horizontal"); optgroup->append_single_option_line("support_points_density_relative");
optgroup->append_single_option_line("support_density_at_45"); optgroup->append_single_option_line("support_points_minimal_distance");
optgroup->append_single_option_line("support_minimal_z");
page = add_options_page(_(L("Pad")), "brick.png"); page = add_options_page(_(L("Pad")), "brick.png");
optgroup = page->new_optgroup(_(L("Pad"))); optgroup = page->new_optgroup(_(L("Pad")));