mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-10 06:09:09 +08:00
Merge branch 'lm_fdm_custom_supports_polishing'
This commit is contained in:
commit
3a6bc2e31a
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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());
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user