Merge branch 'lm_fdm_custom_supports_polishing'

This commit is contained in:
Lukas Matena 2020-05-11 17:03:43 +02:00
commit 3a6bc2e31a
11 changed files with 307 additions and 144 deletions

View File

@ -411,6 +411,11 @@ public:
return timestamp == other.get_timestamp(); return timestamp == other.get_timestamp();
} }
template<class Archive> void serialize(Archive &ar)
{
ar(m_data);
}
private: private:
std::map<int, FacetSupportType> m_data; std::map<int, FacetSupportType> m_data;
@ -613,7 +618,8 @@ private:
} }
template<class Archive> void load(Archive &ar) { template<class Archive> void load(Archive &ar) {
bool has_convex_hull; bool has_convex_hull;
ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
m_is_splittable, has_convex_hull, m_supported_facets);
cereal::load_by_value(ar, config); cereal::load_by_value(ar, config);
assert(m_mesh); assert(m_mesh);
if (has_convex_hull) { if (has_convex_hull) {
@ -626,7 +632,8 @@ private:
} }
template<class Archive> void save(Archive &ar) const { template<class Archive> void save(Archive &ar) const {
bool has_convex_hull = m_convex_hull.get() != nullptr; bool has_convex_hull = m_convex_hull.get() != nullptr;
ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
m_is_splittable, has_convex_hull, m_supported_facets);
cereal::save_by_value(ar, config); cereal::save_by_value(ar, config);
if (has_convex_hull) if (has_convex_hull)
cereal::save_optional(ar, m_convex_hull); cereal::save_optional(ar, m_convex_hull);

View File

@ -1434,7 +1434,7 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas
#if ENABLE_SLOPE_RENDERING #if ENABLE_SLOPE_RENDERING
void GLCanvas3D::Slope::render() const void GLCanvas3D::Slope::render() const
{ {
if (is_shown()) if (m_dialog_shown)
{ {
const std::array<float, 2>& z_range = m_volumes.get_slope_z_range(); const std::array<float, 2>& z_range = m_volumes.get_slope_z_range();
std::array<float, 2> angle_range = { Geometry::rad2deg(::acos(z_range[0])) - 90.0f, Geometry::rad2deg(::acos(z_range[1])) - 90.0f }; std::array<float, 2> angle_range = { Geometry::rad2deg(::acos(z_range[0])) - 90.0f, Geometry::rad2deg(::acos(z_range[1])) - 90.0f };
@ -1445,29 +1445,41 @@ void GLCanvas3D::Slope::render() const
imgui.set_next_window_pos((float)cnv_size.get_width(), (float)cnv_size.get_height(), ImGuiCond_Always, 1.0f, 1.0f); imgui.set_next_window_pos((float)cnv_size.get_width(), (float)cnv_size.get_height(), ImGuiCond_Always, 1.0f, 1.0f);
imgui.begin(_(L("Slope visualization")), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); imgui.begin(_(L("Slope visualization")), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
imgui.text(_(L("Facets' normal angle range (degrees)")) + ":"); imgui.text(_(L("Facets' slope range (degrees)")) + ":");
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.75f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f));
if (ImGui::SliderFloat("##yellow", &angle_range[0], 0.0f, 90.0f, "%.1f"))
{
modified = true;
if (angle_range[1] < angle_range[0])
angle_range[1] = angle_range[0];
}
ImGui::PopStyleColor(4);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.0f, 0.0f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.0f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.0f, 0.0f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.0f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.0f, 0.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.0f, 0.0f, 1.0f));
if (ImGui::SliderFloat("##red", &angle_range[1], 0.0f, 90.0f, "%.1f"))
// angle_range is range of normal angle, GUI should
// show facet slope angle
float slope_bound = 90.f - angle_range[1];
bool mod = ImGui::SliderFloat("##red", &slope_bound, 0.0f, 90.0f, "%.1f");
angle_range[1] = 90.f - slope_bound;
if (mod)
{ {
modified = true; modified = true;
if (angle_range[0] > angle_range[1]) if (angle_range[0] > angle_range[1])
angle_range[0] = angle_range[1]; angle_range[0] = angle_range[1];
} }
ImGui::PopStyleColor(4);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.75f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f));
slope_bound = 90.f - angle_range[0];
mod = ImGui::SliderFloat("##yellow", &slope_bound, 0.0f, 90.0f, "%.1f");
angle_range[0] = 90.f - slope_bound;
if (mod)
{
modified = true;
if (angle_range[1] < angle_range[0])
angle_range[1] = angle_range[0];
}
ImGui::PopStyleColor(4); ImGui::PopStyleColor(4);
ImGui::Separator(); ImGui::Separator();
@ -1482,7 +1494,7 @@ void GLCanvas3D::Slope::render() const
imgui.end(); imgui.end();
if (modified) if (modified)
m_volumes.set_slope_z_range({ -::cos(Geometry::deg2rad(90.0f - angle_range[0])), -::cos(Geometry::deg2rad(90.0f - angle_range[1])) }); set_range(angle_range);
} }
} }
#endif // ENABLE_SLOPE_RENDERING #endif // ENABLE_SLOPE_RENDERING
@ -1854,8 +1866,8 @@ bool GLCanvas3D::is_reload_delayed() const
void GLCanvas3D::enable_layers_editing(bool enable) void GLCanvas3D::enable_layers_editing(bool enable)
{ {
#if ENABLE_SLOPE_RENDERING #if ENABLE_SLOPE_RENDERING
if (enable && m_slope.is_shown()) if (enable && m_slope.is_dialog_shown())
m_slope.show(false); m_slope.show_dialog(false);
#endif // ENABLE_SLOPE_RENDERING #endif // ENABLE_SLOPE_RENDERING
m_layers_editing.set_enabled(enable); m_layers_editing.set_enabled(enable);
@ -3019,7 +3031,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case 'd': { case 'd': {
if (!is_layers_editing_enabled()) if (!is_layers_editing_enabled())
{ {
m_slope.show(!m_slope.is_shown()); m_slope.show_dialog(!m_slope.is_dialog_shown());
m_dirty = true; m_dirty = true;
} }
break; break;
@ -3589,7 +3601,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
} }
else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled) else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled)
{ {
if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports) if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports
&& m_gizmos.get_current_type() != GLGizmosManager::FdmSupports)
{ {
m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect);
m_dirty = true; m_dirty = true;

View File

@ -409,6 +409,7 @@ private:
class Slope class Slope
{ {
bool m_enabled{ false }; bool m_enabled{ false };
bool m_dialog_shown{ false };
GLCanvas3D& m_canvas; GLCanvas3D& m_canvas;
GLVolumeCollection& m_volumes; GLVolumeCollection& m_volumes;
@ -417,9 +418,14 @@ private:
void enable(bool enable) { m_enabled = enable; } void enable(bool enable) { m_enabled = enable; }
bool is_enabled() const { return m_enabled; } bool is_enabled() const { return m_enabled; }
void show(bool show) { m_volumes.set_slope_active(m_enabled ? show : false); } void use(bool use) { m_volumes.set_slope_active(m_enabled ? use : false); }
bool is_shown() const { return m_volumes.is_slope_active(); } bool is_used() const { return m_volumes.is_slope_active(); }
void show_dialog(bool show) { if (show && is_used()) return; use(show); m_dialog_shown = show; }
bool is_dialog_shown() const { return m_dialog_shown; }
void render() const; void render() const;
void set_range(const std::array<float, 2>& range) const {
m_volumes.set_slope_z_range({ -::cos(Geometry::deg2rad(90.0f - range[0])), -::cos(Geometry::deg2rad(90.0f - range[1])) });
}
}; };
#endif // ENABLE_SLOPE_RENDERING #endif // ENABLE_SLOPE_RENDERING
@ -713,8 +719,10 @@ public:
void show_labels(bool show) { m_labels.show(show); } void show_labels(bool show) { m_labels.show(show); }
#if ENABLE_SLOPE_RENDERING #if ENABLE_SLOPE_RENDERING
bool is_slope_shown() const { return m_slope.is_shown(); } bool is_slope_shown() const { return m_slope.is_dialog_shown(); }
void show_slope(bool show) { m_slope.show(show); } void use_slope(bool use) { m_slope.use(use); }
void show_slope(bool show) { m_slope.show_dialog(show); }
void set_slope_range(const std::array<float, 2>& range) { m_slope.set_range(range); }
#endif // ENABLE_SLOPE_RENDERING #endif // ENABLE_SLOPE_RENDERING
private: private:

View File

@ -2771,6 +2771,7 @@ void ObjectList::delete_all_objects_from_list()
void ObjectList::increase_object_instances(const size_t obj_idx, const size_t num) void ObjectList::increase_object_instances(const size_t obj_idx, const size_t num)
{ {
select_item(m_objects_model->AddInstanceChild(m_objects_model->GetItemById(obj_idx), num)); select_item(m_objects_model->AddInstanceChild(m_objects_model->GetItemById(obj_idx), num));
selection_changed();
} }
void ObjectList::decrease_object_instances(const size_t obj_idx, const size_t num) void ObjectList::decrease_object_instances(const size_t obj_idx, const size_t num)

View File

@ -58,10 +58,10 @@ void GLGizmoFdmSupports::set_fdm_support_data(ModelObject* model_object, const S
return; return;
if (mo && selection.is_from_single_instance() if (mo && selection.is_from_single_instance()
&& (mo != m_old_mo || mo->volumes.size() != m_old_volumes_size)) && (mo->id() != m_old_mo_id || mo->volumes.size() != m_old_volumes_size))
{ {
update_mesh(); update_from_model_object();
m_old_mo = mo; m_old_mo_id = mo->id();
m_old_volumes_size = mo->volumes.size(); m_old_volumes_size = mo->volumes.size();
} }
} }
@ -84,12 +84,29 @@ void GLGizmoFdmSupports::on_render() const
void GLGizmoFdmSupports::render_triangles(const Selection& selection) const void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
{ {
if (m_setting_angle)
return;
const ModelObject* mo = m_c->selection_info()->model_object(); const ModelObject* mo = m_c->selection_info()->model_object();
glsafe(::glEnable(GL_POLYGON_OFFSET_FILL)); glsafe(::glEnable(GL_POLYGON_OFFSET_FILL));
ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); } ); ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); } );
glsafe(::glPolygonOffset(-1.0, 1.0)); glsafe(::glPolygonOffset(-1.0, 1.0));
// Take care of the clipping plane. The normal of the clipping plane is
// saved with opposite sign than we need to pass to OpenGL (FIXME)
bool clipping_plane_active = m_c->object_clipper()->get_position() != 0.;
if (clipping_plane_active) {
const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane();
double clp_data[4];
memcpy(clp_data, clp->get_data(), 4 * sizeof(double));
for (int i=0; i<3; ++i)
clp_data[i] = -1. * clp_data[i];
glsafe(::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)clp_data));
glsafe(::glEnable(GL_CLIP_PLANE0));
}
int mesh_id = -1; int mesh_id = -1;
for (const ModelVolume* mv : mo->volumes) { for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part()) if (! mv->is_model_part())
@ -113,6 +130,8 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
} }
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
} }
if (clipping_plane_active)
glsafe(::glDisable(GL_CLIP_PLANE0));
} }
@ -161,14 +180,21 @@ void GLGizmoFdmSupports::render_cursor_circle() const
} }
void GLGizmoFdmSupports::on_render_for_picking() const void GLGizmoFdmSupports::update_model_object() const
{ {
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
++idx;
if (! mv->is_model_part())
continue;
for (int i=0; i<int(m_selected_facets[idx].size()); ++i)
mv->m_supported_facets.set_facet(i, m_selected_facets[idx][i]);
}
} }
void GLGizmoFdmSupports::update_from_model_object()
void GLGizmoFdmSupports::update_mesh()
{ {
wxBusyCursor wait; wxBusyCursor wait;
@ -177,7 +203,6 @@ void GLGizmoFdmSupports::update_mesh()
for (const ModelVolume* mv : mo->volumes) for (const ModelVolume* mv : mo->volumes)
if (mv->is_model_part()) if (mv->is_model_part())
++num_of_volumes; ++num_of_volumes;
m_selected_facets.resize(num_of_volumes); m_selected_facets.resize(num_of_volumes);
m_neighbors.resize(num_of_volumes); m_neighbors.resize(num_of_volumes);
m_ivas.clear(); m_ivas.clear();
@ -218,6 +243,21 @@ void GLGizmoFdmSupports::update_mesh()
bool GLGizmoFdmSupports::is_mesh_point_clipped(const Vec3d& point) const
{
if (m_c->object_clipper()->get_position() == 0.)
return false;
auto sel_info = m_c->selection_info();
int active_inst = m_c->selection_info()->get_active_instance();
const ModelInstance* mi = sel_info->model_object()->instances[active_inst];
const Transform3d& trafo = mi->get_transformation().get_matrix();
Vec3d transformed_point = trafo * point;
transformed_point(2) += sel_info->get_sla_shift();
return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point);
}
bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSupports::NeighborData& b) { bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSupports::NeighborData& b) {
return a.first < b.first; return a.first < b.first;
@ -310,6 +350,12 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
m_clipping_plane.get(), m_clipping_plane.get(),
&facet)) &facet))
{ {
// In case this hit is clipped, skip it.
if (is_mesh_point_clipped(hit.cast<double>())) {
some_mesh_was_hit = true;
continue;
}
// Is this hit the closest to the camera so far? // Is this hit the closest to the camera so far?
double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast<double>()).squaredNorm(); double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast<double>()).squaredNorm();
if (hit_squared_distance < closest_hit_squared_distance) { if (hit_squared_distance < closest_hit_squared_distance) {
@ -430,19 +476,16 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp) if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp)
&& m_button_down != Button::None) { && m_button_down != Button::None) {
// Take snapshot and update ModelVolume data.
wxString action_name = shift_down
? _L("Remove selection")
: (m_button_down == Button::Left
? _L("Add supports")
: _L("Block supports"));
Plater::TakeSnapshot(wxGetApp().plater(), action_name);
update_model_object();
m_button_down = Button::None; m_button_down = Button::None;
// Synchronize gizmo with ModelVolume data.
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
++idx;
if (! mv->is_model_part())
continue;
for (int i=0; i<int(m_selected_facets[idx].size()); ++i)
mv->m_supported_facets.set_facet(i, m_selected_facets[idx][i]);
}
return true; return true;
} }
@ -481,6 +524,46 @@ void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv,
} }
void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool overwrite, bool block)
{
float threshold = (M_PI/180.)*threshold_deg;
const Selection& selection = m_parent.get_selection();
const ModelObject* mo = m_c->selection_info()->model_object();
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
int mesh_id = -1;
for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part())
continue;
++mesh_id;
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true);
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized();
Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized();
float dot_limit = limit.dot(down);
// Now calculate dot product of vert_direction and facets' normals.
int idx = -1;
for (const stl_facet& facet : mv->mesh().stl.facet_start) {
++idx;
if (facet.normal.dot(down) > dot_limit && (overwrite || m_selected_facets[mesh_id][idx] == FacetSupportType::NONE))
m_selected_facets[mesh_id][idx] = block
? FacetSupportType::BLOCKER
: FacetSupportType::ENFORCER;
}
update_vertex_buffers(mv, mesh_id, true, true);
}
Plater::TakeSnapshot(wxGetApp().plater(), block ? _L("Block supports by angle")
: _L("Add supports by angle"));
update_model_object();
m_parent.set_as_dirty();
m_setting_angle = false;
}
void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit) void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit)
{ {
if (! m_c->selection_info()->model_object()) if (! m_c->selection_info()->model_object())
@ -489,6 +572,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
const float approx_height = m_imgui->scaled(18.0f); const float approx_height = m_imgui->scaled(18.0f);
y = std::min(y, bottom_limit - approx_height); y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
if (! m_setting_angle) {
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
@ -524,6 +609,12 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
m_imgui->text(""); m_imgui->text("");
if (m_imgui->button("Autoset by angle...")) {
m_setting_angle = true;
}
ImGui::SameLine();
if (m_imgui->button(m_desc.at("remove_all"))) { if (m_imgui->button(m_desc.at("remove_all"))) {
ModelObject* mo = m_c->selection_info()->model_object(); ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1; int idx = -1;
@ -576,9 +667,36 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
m_imgui->end(); m_imgui->end();
if (m_setting_angle) {
m_parent.show_slope(false);
m_parent.set_slope_range({90.f - m_angle_threshold_deg, 90.f - m_angle_threshold_deg});
m_parent.use_slope(true);
m_parent.set_as_dirty();
}
}
else {
std::string name = "Autoset custom supports";
m_imgui->begin(wxString(name), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
m_imgui->text("Threshold:");
ImGui::SameLine();
if (m_imgui->slider_float("", &m_angle_threshold_deg, 0.f, 90.f, "%.f"))
m_parent.set_slope_range({90.f - m_angle_threshold_deg, 90.f - m_angle_threshold_deg});
m_imgui->checkbox(wxString("Overwrite already selected facets"), m_overwrite_selected);
if (m_imgui->button("Enforce"))
select_facets_by_angle(m_angle_threshold_deg, m_overwrite_selected, false);
ImGui::SameLine();
if (m_imgui->button("Block"))
select_facets_by_angle(m_angle_threshold_deg, m_overwrite_selected, true);
ImGui::SameLine();
if (m_imgui->button("Cancel"))
m_setting_angle = false;
m_imgui->end();
if (! m_setting_angle) {
m_parent.use_slope(false);
m_parent.set_as_dirty();
}
}
} }
bool GLGizmoFdmSupports::on_is_activable() const bool GLGizmoFdmSupports::on_is_activable() const
@ -627,12 +745,24 @@ void GLGizmoFdmSupports::on_set_state()
return; return;
if (m_state == On && m_old_state != On) { // the gizmo was just turned on if (m_state == On && m_old_state != On) { // the gizmo was just turned on
{
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on"))); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on")));
} }
if (! m_parent.get_gizmos_manager().is_serializing()) {
wxGetApp().CallAfter([]() {
wxGetApp().plater()->enter_gizmos_stack();
});
}
}
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
// we are actually shutting down // we are actually shutting down
m_setting_angle = false;
m_parent.use_slope(false);
wxGetApp().plater()->leave_gizmos_stack();
{
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off"))); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off")));
m_old_mo = nullptr; }
m_old_mo_id = -1;
m_ivas.clear(); m_ivas.clear();
m_neighbors.clear(); m_neighbors.clear();
m_selected_facets.clear(); m_selected_facets.clear();
@ -657,7 +787,7 @@ void GLGizmoFdmSupports::on_stop_dragging()
void GLGizmoFdmSupports::on_load(cereal::BinaryInputArchive& ar) void GLGizmoFdmSupports::on_load(cereal::BinaryInputArchive& ar)
{ {
update_from_model_object();
} }

View File

@ -19,7 +19,7 @@ enum class SLAGizmoEventType : unsigned char;
class GLGizmoFdmSupports : public GLGizmoBase class GLGizmoFdmSupports : public GLGizmoBase
{ {
private: private:
const ModelObject* m_old_mo = nullptr; ObjectID m_old_mo_id;
size_t m_old_volumes_size = 0; size_t m_old_volumes_size = 0;
GLUquadricObj* m_quadric; GLUquadricObj* m_quadric;
@ -53,14 +53,23 @@ public:
private: private:
bool on_init() override; bool on_init() override;
void on_render() const override; void on_render() const override;
void on_render_for_picking() const override; void on_render_for_picking() const override {}
void render_triangles(const Selection& selection) const; void render_triangles(const Selection& selection) const;
void render_cursor_circle() const; void render_cursor_circle() const;
void update_mesh();
void update_model_object() const;
void update_from_model_object();
void select_facets_by_angle(float threshold, bool overwrite, bool block);
bool m_overwrite_selected = false;
float m_angle_threshold_deg = 45.f;
bool is_mesh_point_clipped(const Vec3d& point) const;
float m_clipping_plane_distance = 0.f; float m_clipping_plane_distance = 0.f;
std::unique_ptr<ClippingPlane> m_clipping_plane; std::unique_ptr<ClippingPlane> m_clipping_plane;
bool m_setting_angle = false;
// This map holds all translated description texts, so they can be easily referenced during layout calculations // This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.

View File

@ -66,11 +66,10 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
ModelObject* mo = m_c->selection_info()->model_object(); ModelObject* mo = m_c->selection_info()->model_object();
if (mo != m_old_mo) { if (mo && mo->id() != m_old_mo_id) {
disable_editing_mode(); disable_editing_mode();
if (mo)
reload_cache(); reload_cache();
m_old_mo = mo; m_old_mo_id = mo->id();
} }
// If we triggered autogeneration before, check backend and fetch results if they are there // If we triggered autogeneration before, check backend and fetch results if they are there

View File

@ -83,7 +83,7 @@ private:
float m_density_stash = 0.f; // and again float m_density_stash = 0.f; // and again
mutable std::vector<CacheEntry> m_editing_cache; // a support point and whether it is currently selected mutable std::vector<CacheEntry> m_editing_cache; // a support point and whether it is currently selected
std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo
const ModelObject* m_old_mo = nullptr; ObjectID m_old_mo_id;
// This map holds all translated description texts, so they can be easily referenced during layout calculations // This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.

View File

@ -369,15 +369,6 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
|| wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
return; return;
/*m_common_gizmos_data->update_from_backend(m_parent, model_object);
auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get());
// note: sla support gizmo takes care of updating the common data.
// following lines are thus dependent
//gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection());
*/
auto* gizmo_hollow = dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get()); auto* gizmo_hollow = dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get());
auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get()); auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get());
gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection()); gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection());

View File

@ -139,6 +139,11 @@ public:
EType new_current = m_current; EType new_current = m_current;
m_current = old_current; m_current = old_current;
// Update common data. They should be updated when activate_gizmo is
// called, so it can be used in on_set_state which is called from there.
if (new_current != Undefined)
m_common_gizmos_data->update(m_gizmos[new_current]->get_requirements());
// activate_gizmo call sets m_current and calls set_state for the gizmo // activate_gizmo call sets m_current and calls set_state for the gizmo
// it does nothing in case the gizmo is already activated // it does nothing in case the gizmo is already activated
// it can safely be called for Undefined gizmo // it can safely be called for Undefined gizmo
@ -167,6 +172,7 @@ public:
void refresh_on_off_state(); void refresh_on_off_state();
void reset_all_states(); void reset_all_states();
bool is_serializing() const { return m_serializing; }
void set_hover_id(int id); void set_hover_id(int id);
void enable_grabber(EType type, unsigned int id, bool enable); void enable_grabber(EType type, unsigned int id, bool enable);

View File

@ -4450,8 +4450,6 @@ void Plater::increase_instances(size_t num)
// p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec)); // p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
} }
sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num);
if (p->get_config("autocenter") == "1") if (p->get_config("autocenter") == "1")
arrange(); arrange();
@ -4459,8 +4457,9 @@ void Plater::increase_instances(size_t num)
p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1); p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1);
p->selection_changed(); sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num);
p->selection_changed();
this->p->schedule_background_process(); this->p->schedule_background_process();
} }