From 87a1fe8c655fd0072af4c77b89ab3ff8bb670c6e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 7 Oct 2024 15:14:31 +0200 Subject: [PATCH] Multiple beds (part 6): - arrange - bed spacing in multiples of bed size - newly loaded positions are loaded on active bed TODO: Fix results after convert, split and cut --- src/libslic3r/Model.cpp | 8 ++- src/libslic3r/MultipleBeds.cpp | 94 ++++++++++++++++++++++++------- src/libslic3r/MultipleBeds.hpp | 14 ++++- src/slic3r/GUI/3DBed.cpp | 9 +++ src/slic3r/GUI/GUI_ObjectList.cpp | 5 ++ src/slic3r/GUI/Jobs/EmbossJob.cpp | 3 + src/slic3r/GUI/Plater.cpp | 11 ++++ 7 files changed, 120 insertions(+), 24 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 04c14cace6..2e392b72ba 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1602,7 +1602,10 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume for (const ModelVolume* vol : this->volumes) if (vol->is_model_part()) { const Transform3d matrix = model_instance->get_matrix() * vol->get_matrix(); - BuildVolume::ObjectState state = build_volume.object_state(vol->mesh().its, matrix.cast(), true /* may be below print bed */, true /*ignore_bottom*/, &bed_idx); + int bed = -1; + BuildVolume::ObjectState state = build_volume.object_state(vol->mesh().its, matrix.cast(), true /* may be below print bed */, true /*ignore_bottom*/, &bed); + if (bed_idx == -1) // instance will be assigned to the bed the first volume is assigned to. + bed_idx = bed; if (state == BuildVolume::ObjectState::Inside) // Volume is completely inside. inside_outside |= INSIDE; @@ -1621,7 +1624,8 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume inside_outside == INSIDE ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside; if (inside_outside == INSIDE) ++num_printable; - s_multiple_beds.set_instance_bed(model_instance->id(), bed_idx); + if (bed_idx != -1) + s_multiple_beds.set_instance_bed(model_instance->id(), bed_idx); } return num_printable; } diff --git a/src/libslic3r/MultipleBeds.cpp b/src/libslic3r/MultipleBeds.cpp index 2289720899..cca72e2483 100644 --- a/src/libslic3r/MultipleBeds.cpp +++ b/src/libslic3r/MultipleBeds.cpp @@ -14,37 +14,42 @@ bool s_reload_preview_after_switching_beds = false; Vec3d MultipleBeds::get_bed_translation(int id) const { - // TODO: Arrange defines this in LogicalBedGap in SceneBuilder.cpp - // TODO: It should be defined as multiple of bed size. + // The x value is bed gap as multiples of the actual printable area bounding box, + // so it can be matched to how the old slicer arranged things (in SceneBuilder.cpp). + // The y value is a multiple of the larger of printable area BB and bed model BB - + // this is to make sure that the bed models do not overlap. + const double bed_gap_x = 2./10; + const double bed_gap_y = 2./10; if (id == 0) return Vec3d::Zero(); int x = 0; int y = 0; -#if 0 - // Linear layout - x = id; -#else - // Grid layout. - ++id; - int a = 1; - while ((a+1)*(a+1) < id) - ++a; - id = id - a*a; - x=a; - y=a; - if (id <= a) - y = id-1; - else - x=id-a-1; -#endif - return 300. * Vec3d(x, y, 0.); + if (m_layout_linear) + x = id; + else { + // Grid layout. + ++id; + int a = 1; + while ((a+1)*(a+1) < id) + ++a; + id = id - a*a; + x=a; + y=a; + if (id <= a) + y = id-1; + else + x=id-a-1; + } + return Vec3d(x * m_build_volume_bb.size().x() * (1. + bed_gap_x), y * m_build_volume_bb.size().y() * (1. + bed_gap_y), 0.); } + + void MultipleBeds::clear_inst_map() { m_inst_to_bed.clear(); @@ -132,5 +137,54 @@ bool MultipleBeds::is_glvolume_on_thumbnail_bed(const Model& model, int obj_idx, +bool MultipleBeds::rearrange_linear_to_grid_if_possible(Model& model, const BuildVolume& build_volume) +{ + m_layout_linear = true; + int old_number_of_beds = m_number_of_beds; + m_number_of_beds = get_max_beds(); + Slic3r::ScopeGuard guard([this]() { m_layout_linear = false; }); + model.update_print_volume_state(build_volume); + m_number_of_beds = old_number_of_beds; + + int max_bed = 0; + + std::map> id_to_ptr_and_bed; + for (ModelObject* mo : model.objects) { + for (ModelInstance* mi : mo->instances) { + auto it = m_inst_to_bed.find(mi->id()); + if (it == m_inst_to_bed.end()) { + // An instance is outside. Do not rearrange anything, + // that could create collisions. + return false; + } + id_to_ptr_and_bed[mi->id()] = std::make_pair(mi, it->second); + max_bed = std::max(max_bed, it->second); + } + } + + if (max_bed == 0) { + // All instances are on the first bed. No need to do anything. + return false; + } + m_number_of_beds = max_bed + 1; + assert(m_number_of_beds <= get_max_beds()); + + // All instances are on some bed, at least two are used. + for (auto& [oid, mi_and_bed] : id_to_ptr_and_bed) { + auto& [mi, bed_idx] = mi_and_bed; + mi->set_offset(mi->get_offset() - get_bed_translation(bed_idx)); + } + + m_layout_linear = false; + for (auto& [oid, mi_and_bed] : id_to_ptr_and_bed) { + auto& [mi, bed_idx] = mi_and_bed; + mi->set_offset(mi->get_offset() + get_bed_translation(bed_idx)); + } + model.update_print_volume_state(build_volume); + return true; +} + + + } diff --git a/src/libslic3r/MultipleBeds.hpp b/src/libslic3r/MultipleBeds.hpp index e1b77e5f00..5527b8f65a 100644 --- a/src/libslic3r/MultipleBeds.hpp +++ b/src/libslic3r/MultipleBeds.hpp @@ -39,8 +39,15 @@ public: int get_thumbnail_bed_idx() const { return m_bed_for_thumbnails_generation; } bool is_glvolume_on_thumbnail_bed(const Model& model, int obj_idx, int instance_idx) const; - void set_last_hovered_bed(int i) { m_last_hovered_bed = i; } - int get_last_hovered_bed() const { return m_last_hovered_bed; } + void set_last_hovered_bed(int i) { m_last_hovered_bed = i; } + int get_last_hovered_bed() const { return m_last_hovered_bed; } + + bool rearrange_linear_to_grid_if_possible(Model& model, const BuildVolume& build_volume); + void set_loading_project_flag(bool project) { m_loading_project = project; } + bool get_loading_project_flag() const { return m_loading_project; } + + void update_build_volume(const BoundingBoxf& build_volume_bb) { m_build_volume_bb = build_volume_bb; } + @@ -56,6 +63,9 @@ private: std::map m_inst_to_bed; std::map m_printbase_to_texture; int m_last_hovered_bed = -1; + BoundingBoxf m_build_volume_bb; + bool m_layout_linear = false; + bool m_loading_project = false; }; extern MultipleBeds s_multiple_beds; diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 0d556d0f5f..0346d07a90 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -84,6 +84,8 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c m_model_filename = model_filename; m_extended_bounding_box = this->calc_extended_bounding_box(); + s_multiple_beds.update_build_volume(m_build_volume.bounding_volume2d()); + m_contour = ExPolygon(Polygon::new_scale(bed_shape)); const BoundingBox bbox = m_contour.contour.bounding_box(); if (!bbox.defined) @@ -228,6 +230,13 @@ void Bed3D::init_triangles() m_triangles.init_from(std::move(init_data)); m_triangles.set_color(DEFAULT_MODEL_COLOR); + + BoundingBoxf bb = m_build_volume.bounding_volume2d(); + double y = bb.size().y(); + double ym = m_model.model.get_bounding_box().size().y(); + double diff = std::max(0., ym - y); + bb.max = Vec2d(bb.max.x(), bb.max.y() + diff); + s_multiple_beds.update_build_volume(bb); } void Bed3D::init_gridlines() diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 5fb3a7ca9e..f83b2403e7 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -22,6 +22,8 @@ #include "Gizmos/GLGizmoCut.hpp" #include "Gizmos/GLGizmoScale.hpp" +#include "libslic3r/MultipleBeds.hpp" + #include "OptionsGroup.hpp" #include "Tab.hpp" #include "wxExtensions.hpp" @@ -1835,6 +1837,9 @@ void ObjectList::load_mesh_object(const TriangleMesh &mesh, const std::string &n new_object->ensure_on_bed(); + if (! s_multiple_beds.get_loading_project_flag()) + new_object->instances.front()->set_offset(new_object->instances.front()->get_offset() + s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed())); + #ifdef _DEBUG check_model_ids_validity(model); #endif /* _DEBUG */ diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 3c330c49bc..b3caa01c82 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -14,6 +14,8 @@ #include // create object #include +#include "libslic3r/MultipleBeds.hpp" + #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/NotificationManager.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" @@ -373,6 +375,7 @@ void CreateObjectJob::finalize(bool canceled, std::exception_ptr &eptr) // set transformation Slic3r::Geometry::Transformation tr(m_transformation); new_object->instances.front()->set_transformation(tr); + new_object->instances.front()->set_offset(new_object->instances.front()->get_offset() + s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed())); new_object->ensure_on_bed(); // Actualize right panel and set inside of selection diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e485302d09..a7e64a77e0 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1599,6 +1599,9 @@ 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.rearrange_linear_to_grid_if_possible(model, q->build_volume())) + update(); + return obj_idxs; } @@ -1658,6 +1661,9 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& mode instance->set_scaling_factor(instance->get_scaling_factor() / max_ratio); scaled_down = true; } + + if (! s_multiple_beds.get_loading_project_flag()) + instance->set_offset(instance->get_offset() + s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed())); } object->ensure_on_bed(allow_negative_z); @@ -4159,6 +4165,9 @@ void Plater::load_project(const wxString& filename) // Take the Undo / Redo snapshot. Plater::TakeSnapshot snapshot(this, _L("Load Project") + ": " + wxString::FromUTF8(into_path(filename).stem().string().c_str()), UndoRedo::SnapshotType::ProjectSeparator); + s_multiple_beds.set_loading_project_flag(true); + ScopeGuard guard([](){ s_multiple_beds.set_loading_project_flag(false);}); + p->reset(); if (! load_files({ into_path(filename) }).empty()) { @@ -6734,6 +6743,8 @@ void Plater::arrange(Worker &w, bool selected) concat_strings(names, "\n"))); } + s_multiple_beds.rearrange_linear_to_grid_if_possible(model(), build_volume()); + update(static_cast(UpdateParams::FORCE_FULL_SCREEN_REFRESH)); wxGetApp().obj_manipul()->set_dirty(); };