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
This commit is contained in:
Lukas Matena 2024-10-07 15:14:31 +02:00
parent c24e9fdfed
commit 87a1fe8c65
7 changed files with 120 additions and 24 deletions

View File

@ -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<float>(), 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<float>(), 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,6 +1624,7 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume
inside_outside == INSIDE ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside;
if (inside_outside == INSIDE)
++num_printable;
if (bed_idx != -1)
s_multiple_beds.set_instance_bed(model_instance->id(), bed_idx);
}
return num_printable;

View File

@ -14,17 +14,20 @@ 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
if (m_layout_linear)
x = id;
#else
else {
// Grid layout.
++id;
int a = 1;
@ -37,9 +40,11 @@ Vec3d MultipleBeds::get_bed_translation(int id) const
y = id-1;
else
x=id-a-1;
#endif
return 300. * Vec3d(x, y, 0.);
}
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.);
}
@ -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<ObjectID, std::pair<ModelInstance*, int>> 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;
}
}

View File

@ -42,6 +42,13 @@ public:
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; }
private:
@ -56,6 +63,9 @@ private:
std::map<ObjectID, int> m_inst_to_bed;
std::map<PrintBase*, size_t> 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;

View File

@ -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()

View File

@ -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 */

View File

@ -14,6 +14,8 @@
#include <libslic3r/BuildVolume.hpp> // create object
#include <libslic3r/SLA/ReprojectPointsOnMesh.hpp>
#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

View File

@ -1599,6 +1599,9 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& 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<size_t> 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<unsigned int>(UpdateParams::FORCE_FULL_SCREEN_REFRESH));
wxGetApp().obj_manipul()->set_dirty();
};