mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-04 16:40:38 +08:00
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:
parent
c24e9fdfed
commit
87a1fe8c65
@ -1602,7 +1602,10 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume
|
|||||||
for (const ModelVolume* vol : this->volumes)
|
for (const ModelVolume* vol : this->volumes)
|
||||||
if (vol->is_model_part()) {
|
if (vol->is_model_part()) {
|
||||||
const Transform3d matrix = model_instance->get_matrix() * vol->get_matrix();
|
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)
|
if (state == BuildVolume::ObjectState::Inside)
|
||||||
// Volume is completely inside.
|
// Volume is completely inside.
|
||||||
inside_outside |= 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;
|
inside_outside == INSIDE ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside;
|
||||||
if (inside_outside == INSIDE)
|
if (inside_outside == INSIDE)
|
||||||
++num_printable;
|
++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;
|
return num_printable;
|
||||||
}
|
}
|
||||||
|
@ -14,37 +14,42 @@ bool s_reload_preview_after_switching_beds = false;
|
|||||||
|
|
||||||
Vec3d MultipleBeds::get_bed_translation(int id) const
|
Vec3d MultipleBeds::get_bed_translation(int id) const
|
||||||
{
|
{
|
||||||
// TODO: Arrange defines this in LogicalBedGap in SceneBuilder.cpp
|
// The x value is bed gap as multiples of the actual printable area bounding box,
|
||||||
// TODO: It should be defined as multiple of bed size.
|
// 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)
|
if (id == 0)
|
||||||
return Vec3d::Zero();
|
return Vec3d::Zero();
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
#if 0
|
if (m_layout_linear)
|
||||||
// Linear layout
|
x = id;
|
||||||
x = id;
|
else {
|
||||||
#else
|
// Grid layout.
|
||||||
// Grid layout.
|
++id;
|
||||||
++id;
|
int a = 1;
|
||||||
int a = 1;
|
while ((a+1)*(a+1) < id)
|
||||||
while ((a+1)*(a+1) < id)
|
++a;
|
||||||
++a;
|
id = id - a*a;
|
||||||
id = id - a*a;
|
x=a;
|
||||||
x=a;
|
y=a;
|
||||||
y=a;
|
if (id <= a)
|
||||||
if (id <= a)
|
y = id-1;
|
||||||
y = id-1;
|
else
|
||||||
else
|
x=id-a-1;
|
||||||
x=id-a-1;
|
}
|
||||||
#endif
|
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.);
|
||||||
return 300. * Vec3d(x, y, 0.);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void MultipleBeds::clear_inst_map()
|
void MultipleBeds::clear_inst_map()
|
||||||
{
|
{
|
||||||
m_inst_to_bed.clear();
|
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<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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,8 +39,15 @@ public:
|
|||||||
int get_thumbnail_bed_idx() const { return m_bed_for_thumbnails_generation; }
|
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;
|
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; }
|
void set_last_hovered_bed(int i) { m_last_hovered_bed = i; }
|
||||||
int get_last_hovered_bed() const { return m_last_hovered_bed; }
|
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<ObjectID, int> m_inst_to_bed;
|
std::map<ObjectID, int> m_inst_to_bed;
|
||||||
std::map<PrintBase*, size_t> m_printbase_to_texture;
|
std::map<PrintBase*, size_t> m_printbase_to_texture;
|
||||||
int m_last_hovered_bed = -1;
|
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;
|
extern MultipleBeds s_multiple_beds;
|
||||||
|
@ -84,6 +84,8 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c
|
|||||||
m_model_filename = model_filename;
|
m_model_filename = model_filename;
|
||||||
m_extended_bounding_box = this->calc_extended_bounding_box();
|
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));
|
m_contour = ExPolygon(Polygon::new_scale(bed_shape));
|
||||||
const BoundingBox bbox = m_contour.contour.bounding_box();
|
const BoundingBox bbox = m_contour.contour.bounding_box();
|
||||||
if (!bbox.defined)
|
if (!bbox.defined)
|
||||||
@ -228,6 +230,13 @@ void Bed3D::init_triangles()
|
|||||||
|
|
||||||
m_triangles.init_from(std::move(init_data));
|
m_triangles.init_from(std::move(init_data));
|
||||||
m_triangles.set_color(DEFAULT_MODEL_COLOR);
|
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()
|
void Bed3D::init_gridlines()
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include "Gizmos/GLGizmoCut.hpp"
|
#include "Gizmos/GLGizmoCut.hpp"
|
||||||
#include "Gizmos/GLGizmoScale.hpp"
|
#include "Gizmos/GLGizmoScale.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/MultipleBeds.hpp"
|
||||||
|
|
||||||
#include "OptionsGroup.hpp"
|
#include "OptionsGroup.hpp"
|
||||||
#include "Tab.hpp"
|
#include "Tab.hpp"
|
||||||
#include "wxExtensions.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();
|
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
|
#ifdef _DEBUG
|
||||||
check_model_ids_validity(model);
|
check_model_ids_validity(model);
|
||||||
#endif /* _DEBUG */
|
#endif /* _DEBUG */
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#include <libslic3r/BuildVolume.hpp> // create object
|
#include <libslic3r/BuildVolume.hpp> // create object
|
||||||
#include <libslic3r/SLA/ReprojectPointsOnMesh.hpp>
|
#include <libslic3r/SLA/ReprojectPointsOnMesh.hpp>
|
||||||
|
|
||||||
|
#include "libslic3r/MultipleBeds.hpp"
|
||||||
|
|
||||||
#include "slic3r/GUI/Plater.hpp"
|
#include "slic3r/GUI/Plater.hpp"
|
||||||
#include "slic3r/GUI/NotificationManager.hpp"
|
#include "slic3r/GUI/NotificationManager.hpp"
|
||||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||||
@ -373,6 +375,7 @@ void CreateObjectJob::finalize(bool canceled, std::exception_ptr &eptr)
|
|||||||
// set transformation
|
// set transformation
|
||||||
Slic3r::Geometry::Transformation tr(m_transformation);
|
Slic3r::Geometry::Transformation tr(m_transformation);
|
||||||
new_object->instances.front()->set_transformation(tr);
|
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();
|
new_object->ensure_on_bed();
|
||||||
|
|
||||||
// Actualize right panel and set inside of selection
|
// Actualize right panel and set inside of selection
|
||||||
|
@ -1599,6 +1599,9 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||||||
GLGizmoSimplify::add_simplify_suggestion_notification(
|
GLGizmoSimplify::add_simplify_suggestion_notification(
|
||||||
obj_idxs, model.objects, *notification_manager);
|
obj_idxs, model.objects, *notification_manager);
|
||||||
|
|
||||||
|
if (s_multiple_beds.rearrange_linear_to_grid_if_possible(model, q->build_volume()))
|
||||||
|
update();
|
||||||
|
|
||||||
return obj_idxs;
|
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);
|
instance->set_scaling_factor(instance->get_scaling_factor() / max_ratio);
|
||||||
scaled_down = true;
|
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);
|
object->ensure_on_bed(allow_negative_z);
|
||||||
@ -4159,6 +4165,9 @@ void Plater::load_project(const wxString& filename)
|
|||||||
// Take the Undo / Redo snapshot.
|
// Take the Undo / Redo snapshot.
|
||||||
Plater::TakeSnapshot snapshot(this, _L("Load Project") + ": " + wxString::FromUTF8(into_path(filename).stem().string().c_str()), UndoRedo::SnapshotType::ProjectSeparator);
|
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();
|
p->reset();
|
||||||
|
|
||||||
if (! load_files({ into_path(filename) }).empty()) {
|
if (! load_files({ into_path(filename) }).empty()) {
|
||||||
@ -6734,6 +6743,8 @@ void Plater::arrange(Worker &w, bool selected)
|
|||||||
concat_strings(names, "\n")));
|
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));
|
update(static_cast<unsigned int>(UpdateParams::FORCE_FULL_SCREEN_REFRESH));
|
||||||
wxGetApp().obj_manipul()->set_dirty();
|
wxGetApp().obj_manipul()->set_dirty();
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user