From 5b59785456bb8689695c4add9af925dbaa275cc8 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 31 Oct 2024 14:48:21 +0100 Subject: [PATCH] wipe towers volumes --- src/libslic3r/MultipleBeds.cpp | 18 ++++++ src/libslic3r/MultipleBeds.hpp | 2 + src/slic3r/GUI/3DScene.cpp | 8 +-- src/slic3r/GUI/3DScene.hpp | 4 +- src/slic3r/GUI/GCodeViewer.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 98 +++++++++++++++++++------------ src/slic3r/GUI/GLCanvas3D.hpp | 2 +- src/slic3r/GUI/Plater.cpp | 28 ++++----- src/slic3r/GUI/Plater.hpp | 2 + src/slic3r/GUI/SceneRaycaster.cpp | 2 +- src/slic3r/GUI/Selection.cpp | 3 +- 11 files changed, 107 insertions(+), 62 deletions(-) diff --git a/src/libslic3r/MultipleBeds.cpp b/src/libslic3r/MultipleBeds.cpp index 30919eccc1..2dd727e0aa 100644 --- a/src/libslic3r/MultipleBeds.cpp +++ b/src/libslic3r/MultipleBeds.cpp @@ -2,6 +2,7 @@ #include "BuildVolume.hpp" #include "Model.hpp" +#include "Print.hpp" #include @@ -214,5 +215,22 @@ bool MultipleBeds::update_after_load_or_arrange(Model& model, const BuildVolume& +void MultipleBeds::ensure_wipe_towers_on_beds(Model& model, const std::vector>& prints) +{ + for (size_t bed_idx = 0; bed_idx < get_number_of_beds(); ++bed_idx) { + ModelWipeTower& mwt = model.get_wipe_tower_vector()[bed_idx]; + double depth = prints[bed_idx]->wipe_tower_data().depth; + double width = prints[bed_idx]->wipe_tower_data().width; + double brim = prints[bed_idx]->wipe_tower_data().brim_width; + + Polygon plg(Points{Point::new_scale(-brim,-brim), Point::new_scale(brim+width, -brim), Point::new_scale(brim+width, brim+depth), Point::new_scale(-brim, brim+depth)}); + plg.rotate(Geometry::deg2rad(mwt.rotation)); + plg.translate(scaled(mwt.position)); + if (std::all_of(plg.points.begin(), plg.points.end(), [this](const Point& pt) { return !m_build_volume_bb.contains(unscale(pt)); })) + mwt.position = 2*brim*Vec2d(1.,1.); + } +} + + } diff --git a/src/libslic3r/MultipleBeds.hpp b/src/libslic3r/MultipleBeds.hpp index 86f8257cc6..1d341b21c5 100644 --- a/src/libslic3r/MultipleBeds.hpp +++ b/src/libslic3r/MultipleBeds.hpp @@ -12,6 +12,7 @@ namespace Slic3r { class Model; class BuildVolume; class PrintBase; +class Print; extern bool s_reload_preview_after_switching_beds; extern bool s_beds_just_switched; @@ -48,6 +49,7 @@ public: bool get_loading_project_flag() const { return m_loading_project; } void update_build_volume(const BoundingBoxf& build_volume_bb, const BoundingBoxf& build_volume_bb_incl_model) { m_build_volume_bb = build_volume_bb; m_build_volume_bb_incl_model = build_volume_bb_incl_model; } + void ensure_wipe_towers_on_beds(Model& model, const std::vector>& prints); diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 5b69de646a..0da4491bcd 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -502,11 +502,11 @@ int GLVolumeCollection::load_object_volume( #if SLIC3R_OPENGL_ES int GLVolumeCollection::load_wipe_tower_preview( float pos_x, float pos_y, float width, float depth, const std::vector>& z_and_depth_pairs, float height, float cone_angle, - float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh) + float rotation_angle, bool size_unknown, float brim_width, size_t idx, TriangleMesh* out_mesh) #else int GLVolumeCollection::load_wipe_tower_preview( float pos_x, float pos_y, float width, float depth, const std::vector>& z_and_depth_pairs, float height, float cone_angle, - float rotation_angle, bool size_unknown, float brim_width) + float rotation_angle, bool size_unknown, float brim_width, size_t idx) #endif // SLIC3R_OPENGL_ES { if (height == 0.0f) @@ -604,9 +604,9 @@ int GLVolumeCollection::load_wipe_tower_preview( v.set_convex_hull(mesh.convex_hull_3d()); v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle)); - v.composite_id = GLVolume::CompositeID(INT_MAX, 0, 0); + v.composite_id = GLVolume::CompositeID(INT_MAX - idx, 0, 0); v.geometry_id.first = 0; - v.geometry_id.second = wipe_tower_instance_id(0).id; + v.geometry_id.second = wipe_tower_instance_id(idx).id; v.is_wipe_tower = true; v.shader_outside_printer_detection_enabled = !size_unknown; return int(volumes.size() - 1); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 4edfaa2cab..05d3bb306d 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -426,10 +426,10 @@ public: #if SLIC3R_OPENGL_ES int load_wipe_tower_preview( - float pos_x, float pos_y, float width, float depth, const std::vector>& z_and_depth_pairs, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr); + float pos_x, float pos_y, float width, float depth, const std::vector>& z_and_depth_pairs, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, size_t idx, TriangleMesh* out_mesh = nullptr); #else int load_wipe_tower_preview( - float pos_x, float pos_y, float width, float depth, const std::vector>& z_and_depth_pairs, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width); + float pos_x, float pos_y, float width, float depth, const std::vector>& z_and_depth_pairs, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, size_t idx); #endif // SLIC3R_OPENGL_ES // Load SLA auxiliary GLVolumes (for support trees or pad). diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index e06b5426b7..e3191193a1 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1699,7 +1699,7 @@ void GCodeViewer::load_wipetower_shell(const Print& print) const float brim_width = wipe_tower_data.brim_width; if (depth != 0.) { m_shells.volumes.load_wipe_tower_preview(wxGetApp().plater()->model().wipe_tower().position.x(), wxGetApp().plater()->model().wipe_tower().position.y(), config.wipe_tower_width, depth, z_and_depth_pairs, - max_z, config.wipe_tower_cone_angle, wxGetApp().plater()->model().wipe_tower().rotation, false, brim_width); + max_z, config.wipe_tower_cone_angle, wxGetApp().plater()->model().wipe_tower().rotation, false, brim_width, 0); GLVolume* volume = m_shells.volumes.volumes.back(); volume->color.a(0.25f); volume->force_native_color = true; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 0a6913ff62..86252dcb41 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2211,7 +2211,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re m_reload_delayed = !m_canvas->IsShown() && !refresh_immediately && !force_full_scene_refresh; PrinterTechnology printer_technology = current_printer_technology(); - int volume_idx_wipe_tower_old = -1; + std::map volume_idxs_wipe_towers_old; // map from geometry_id.second to volume_id // Release invalidated volumes to conserve GPU memory in case of delayed refresh (see m_reload_delayed). // First initialize model_volumes_new_sorted & model_instances_new_sorted. @@ -2284,12 +2284,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (mvs == nullptr || force_full_scene_refresh) { // This GLVolume will be released. if (volume->is_wipe_tower) { - // There is only one wipe tower. - assert(volume_idx_wipe_tower_old == -1); #if SLIC3R_OPENGL_ES - m_wipe_tower_mesh.clear(); + m_wipe_tower_meshes.clear(); #endif // SLIC3R_OPENGL_ES - volume_idx_wipe_tower_old = (int)volume_id; + volume_idxs_wipe_towers_old.emplace(std::make_pair(volume->geometry_id.second, volume_id)); } if (!m_reload_delayed) { deleted_volumes.emplace_back(volume, volume_id); @@ -2451,37 +2449,45 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re const bool wt = dynamic_cast(m_config->option("wipe_tower"))->value; const bool co = dynamic_cast(m_config->option("complete_objects"))->value; + const float w = dynamic_cast(m_config->option("wipe_tower_width"))->value; + const float bw = dynamic_cast(m_config->option("wipe_tower_brim_width"))->value; + const float ca = dynamic_cast(m_config->option("wipe_tower_cone_angle"))->value; if (extruders_count > 1 && wt && !co) { + - const float x = m_model->wipe_tower().position.x(); - const float y = m_model->wipe_tower().position.y(); - const float w = dynamic_cast(m_config->option("wipe_tower_width"))->value; - const float a = m_model->wipe_tower().rotation; - const float bw = dynamic_cast(m_config->option("wipe_tower_brim_width"))->value; - const float ca = dynamic_cast(m_config->option("wipe_tower_cone_angle"))->value; + for (size_t bed_idx = 0; bed_idx < s_multiple_beds.get_number_of_beds(); ++bed_idx) { + const Print *print = wxGetApp().plater()->get_fff_prints()[bed_idx].get(); - const Print *print = m_process->fff_print(); - const float depth = print->wipe_tower_data(extruders_count).depth; - const std::vector> z_and_depth_pairs = print->wipe_tower_data(extruders_count).z_and_depth_pairs; - const float height_real = print->wipe_tower_data(extruders_count).height; // -1.f = unknown + const float x = m_model->get_wipe_tower_vector()[bed_idx].position.x(); + const float y = m_model->get_wipe_tower_vector()[bed_idx].position.y(); + const float a = m_model->get_wipe_tower_vector()[bed_idx].rotation; + const float depth = print->wipe_tower_data(extruders_count).depth; + const std::vector> z_and_depth_pairs = print->wipe_tower_data(extruders_count).z_and_depth_pairs; + const float height_real = print->wipe_tower_data(extruders_count).height; // -1.f = unknown + const bool is_wipe_tower_step_done = print->is_step_done(psWipeTower); - // Height of a print (Show at least a slab). - const double height = height_real < 0.f ? std::max(m_model->max_z(), 10.0) : height_real; - - if (depth != 0.) { + // Height of a print (Show at least a slab). + const double height = height_real < 0.f ? std::max(m_model->max_z(), 10.0) : height_real; + if (depth != 0.) { #if SLIC3R_OPENGL_ES - int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( - x, y, w, depth, z_and_depth_pairs, (float)height, ca, a, !print->is_step_done(psWipeTower), - bw, &m_wipe_tower_mesh); + if (bed_idx >= m_wipe_tower_meshes.size()) + m_wipe_tower_meshes.resize(bed_idx + 1); + int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( + x, y, w, depth, z_and_depth_pairs, (float)height, ca, a, !is_wipe_tower_step_done, + bw, bed_idx, &m_wipe_tower_meshes[bed_idx]); #else - int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( - x, y, w, depth, z_and_depth_pairs, (float)height, ca, a, !print->is_step_done(psWipeTower), - bw); + int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( + x, y, w, depth, z_and_depth_pairs, (float)height, ca, a, !is_wipe_tower_step_done, + bw, bed_idx); #endif // SLIC3R_OPENGL_ES - if (volume_idx_wipe_tower_old != -1) - map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; + auto it = volume_idxs_wipe_towers_old.find(m_volumes.volumes.back()->geometry_id.second); + if (it != volume_idxs_wipe_towers_old.end()) + map_glvolume_old_to_new[it->second] = volume_idx_wipe_tower_new; + m_volumes.volumes.back()->set_volume_offset(m_volumes.volumes.back()->get_volume_offset() + s_multiple_beds.get_bed_translation(bed_idx)); + } } + s_multiple_beds.ensure_wipe_towers_on_beds(wxGetApp().plater()->model(), wxGetApp().plater()->get_fff_prints()); } } @@ -3983,11 +3989,13 @@ void GLCanvas3D::do_move(const std::string& snapshot_type) std::set> done; // keeps track of modified instances bool object_moved = false; - Vec3d wipe_tower_origin = Vec3d::Zero(); + std::vector wipe_tower_origin = std::vector(s_multiple_beds.get_max_beds(), Vec3d::Zero()); Selection::EMode selection_mode = m_selection.get_mode(); + int vol_id = -1; for (const GLVolume* v : m_volumes.volumes) { + ++vol_id; int object_idx = v->object_idx(); int instance_idx = v->instance_idx(); int volume_idx = v->volume_idx(); @@ -4012,9 +4020,15 @@ void GLCanvas3D::do_move(const std::string& snapshot_type) model_object->invalidate_bounding_box(); } } - else if (m_selection.is_wipe_tower() && v->is_wipe_tower) + else if (m_selection.is_wipe_tower() && v->is_wipe_tower && m_selection.contains_volume(vol_id)) { // Move a wipe tower proxy. - wipe_tower_origin = v->get_volume_offset(); + for (size_t bed_idx = 0; bed_idx < s_multiple_beds.get_max_beds(); ++bed_idx) { + if (v->geometry_id.second == wipe_tower_instance_id(bed_idx).id) { + wipe_tower_origin[bed_idx] = v->get_volume_offset(); + break; + } + } + } } // Fixes flying instances @@ -4041,8 +4055,9 @@ void GLCanvas3D::do_move(const std::string& snapshot_type) if (object_moved) post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED)); - if (wipe_tower_origin != Vec3d::Zero()) { - m_model->wipe_tower().position = Vec2d(wipe_tower_origin[0], wipe_tower_origin[1]); + if (auto it = std::find_if(wipe_tower_origin.begin(), wipe_tower_origin.end(), [](const Vec3d& pos) { return pos != Vec3d::Zero(); }); it != wipe_tower_origin.end()) { + size_t bed_idx = it - wipe_tower_origin.begin(); + m_model->get_wipe_tower_vector()[bed_idx].position = Vec2d((*it)[0] - s_multiple_beds.get_bed_translation(bed_idx).x(), (*it)[1] - s_multiple_beds.get_bed_translation(bed_idx).y()); post_event(SimpleEvent(EVT_GLCANVAS_WIPETOWER_TOUCHED)); } @@ -4082,14 +4097,23 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) std::set> done; // keeps track of modified instances Selection::EMode selection_mode = m_selection.get_mode(); + int v_id = -1; for (const GLVolume* v : m_volumes.volumes) { + ++v_id; if (v->is_wipe_tower) { - const Vec3d offset = v->get_volume_offset(); - Vec3d rot_unit_x = v->get_volume_transformation().get_matrix().linear() * Vec3d::UnitX(); - double z_rot = std::atan2(rot_unit_x.y(), rot_unit_x.x()); - m_model->wipe_tower().position = Vec2d(offset.x(), offset.y()); - m_model->wipe_tower().rotation = (180. / M_PI) * z_rot; + if (m_selection.contains_volume(v_id)) { + for (size_t bed_idx = 0; bed_idx < s_multiple_beds.get_max_beds(); ++bed_idx) { + if (v->geometry_id.second == wipe_tower_instance_id(bed_idx).id) { + const Vec3d offset = v->get_volume_offset() - s_multiple_beds.get_bed_translation(bed_idx); + Vec3d rot_unit_x = v->get_volume_transformation().get_matrix().linear() * Vec3d::UnitX(); + double z_rot = std::atan2(rot_unit_x.y(), rot_unit_x.x()); + m_model->get_wipe_tower_vector()[bed_idx].position = Vec2d(offset.x(), offset.y()); + m_model->get_wipe_tower_vector()[bed_idx].rotation = (180. / M_PI) * z_rot; + break; + } + } + } } const int object_idx = v->object_idx(); if (object_idx < 0 || (int)m_model->objects.size() <= object_idx) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 715997437e..61a42ae5fb 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -510,7 +510,7 @@ private: GLVolumeCollection m_volumes; #if SLIC3R_OPENGL_ES - TriangleMesh m_wipe_tower_mesh; + std::vector m_wipe_tower_meshes; #endif // SLIC3R_OPENGL_ES GCodeViewer m_gcode_viewer; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c9b33b8db2..e0cc2acbe9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -528,8 +528,6 @@ struct Plater::priv void on_object_select(SimpleEvent&); void on_right_click(RBtnEvent&); - void on_wipetower_moved(Vec3dEvent&); - void on_wipetower_rotated(Vec3dEvent&); void on_update_geometry(Vec3dsEvent<2>&); void on_3dcanvas_mouse_dragging_started(SimpleEvent&); void on_3dcanvas_mouse_dragging_finished(SimpleEvent&); @@ -1599,7 +1597,10 @@ std::vector Plater::priv::load_files(const std::vector& input_ GLGizmoSimplify::add_simplify_suggestion_notification( obj_idxs, model.objects, *notification_manager); - if (s_multiple_beds.update_after_load_or_arrange(model, q->build_volume(), [this]() {q->canvas3D()->check_volumes_outside_state(); })) + if (s_multiple_beds.update_after_load_or_arrange(model, q->build_volume(), [this]() { + q->canvas3D()->check_volumes_outside_state(); + s_multiple_beds.ensure_wipe_towers_on_beds(model, fff_prints); + })) update(); return obj_idxs; @@ -3386,17 +3387,6 @@ void Plater::priv::on_right_click(RBtnEvent& evt) } } -void Plater::priv::on_wipetower_moved(Vec3dEvent &evt) -{ - model.wipe_tower().position = Vec2d(evt.data[0], evt.data[1]); -} - -void Plater::priv::on_wipetower_rotated(Vec3dEvent& evt) -{ - model.wipe_tower().position = Vec2d(evt.data[0], evt.data[1]); - model.wipe_tower().rotation = Geometry::rad2deg(evt.data(2)); -} - void Plater::priv::on_update_geometry(Vec3dsEvent<2>&) { // TODO @@ -6792,7 +6782,10 @@ void Plater::arrange(Worker &w, bool selected) concat_strings(names, "\n"))); } - s_multiple_beds.update_after_load_or_arrange(model(), build_volume(), [this]() { canvas3D()->check_volumes_outside_state(); }); + s_multiple_beds.update_after_load_or_arrange(model(), build_volume(), [this]() { + canvas3D()->check_volumes_outside_state(); + s_multiple_beds.ensure_wipe_towers_on_beds(model(), get_fff_prints()); + }); update(static_cast(UpdateParams::FORCE_FULL_SCREEN_REFRESH)); wxGetApp().obj_manipul()->set_dirty(); @@ -7289,6 +7282,11 @@ void Plater::bring_instance_forward() p->bring_instance_forward(); } +std::vector>& Plater::get_fff_prints() +{ + return p->fff_prints; +} + wxMenu* Plater::object_menu() { return p->menus.object_menu(); } wxMenu* Plater::part_menu() { return p->menus.part_menu(); } wxMenu* Plater::text_part_menu() { return p->menus.text_part_menu(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 65919d7e22..e489bb0bc0 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -100,6 +100,8 @@ public: Print& active_fff_print(); SLAPrint& active_sla_print(); + std::vector>& get_fff_prints(); + void new_project(); void load_project(); void load_project(const wxString& filename); diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index aeb65c826f..3a98c008a5 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -162,7 +162,7 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came const std::vector>* raycasters = get_raycasters(type); const Vec3f camera_forward = camera.get_dir_forward().cast(); HitResult current_hit = { type }; - for (std::shared_ptr item : *raycasters) { + for (const std::shared_ptr& item : *raycasters) { if (!item->is_active()) continue; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index db9f68377f..4cf5bdb566 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -23,6 +23,7 @@ #include "libslic3r/Model.hpp" #include "libslic3r/PresetBundle.hpp" #include "libslic3r/BuildVolume.hpp" +#include "libslic3r/MultipleBeds.hpp" #include @@ -147,7 +148,7 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec return; // wipe tower is already selected - if (is_wipe_tower() && volume->is_wipe_tower) + if (is_wipe_tower() && volume->is_wipe_tower && contains_volume(volume_idx)) return; bool keep_instance_mode = (m_mode == Instance) && !as_single_selection;