mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-05 19:46:18 +08:00
Multiple beds (part 1):
- create new bed when a volume is dragged into it - limit maximum number of beds - keep track of which ModelInstances are on which bed - show list of beds and allow selecting an active one - move objects from active bed to the first bed when passing Model to Print::apply (and back)
This commit is contained in:
parent
9302cb10ae
commit
accc4ce266
@ -21,6 +21,8 @@
|
||||
#include "libslic3r/Geometry/Circle.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
|
||||
#include "MultipleBeds.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
BuildVolume::BuildVolume(const std::vector<Vec2d> &bed_shape, const double max_print_height) : m_bed_shape(bed_shape), m_max_print_height(max_print_height)
|
||||
@ -284,8 +286,19 @@ BuildVolume::ObjectState object_state_templ(const indexed_triangle_set &its, con
|
||||
return inside ? (outside ? BuildVolume::ObjectState::Colliding : BuildVolume::ObjectState::Inside) : BuildVolume::ObjectState::Outside;
|
||||
}
|
||||
|
||||
BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& its, const Transform3f& trafo, bool may_be_below_bed, bool ignore_bottom) const
|
||||
BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& its, const Transform3f& trafo_orig, bool may_be_below_bed, bool ignore_bottom, int* bed_idx) const
|
||||
{
|
||||
ObjectState out = ObjectState::Outside;
|
||||
if (bed_idx)
|
||||
*bed_idx = -1;
|
||||
|
||||
for (int bed_id = 0; bed_id <= std::min(s_multiple_beds.get_number_of_beds(), s_multiple_beds.get_max_beds() - 1); ++bed_id) {
|
||||
|
||||
|
||||
|
||||
Transform3f trafo = trafo_orig;
|
||||
trafo.pretranslate(-s_multiple_beds.get_bed_translation(bed_id).cast<float>());
|
||||
|
||||
switch (m_type) {
|
||||
case Type::Rectangle:
|
||||
{
|
||||
@ -298,28 +311,48 @@ BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& i
|
||||
// The following test correctly interprets intersection of a non-convex object with a rectangular build volume.
|
||||
//return rectangle_test(its, trafo, to_2d(build_volume.min), to_2d(build_volume.max), build_volume.max.z());
|
||||
//FIXME This test does NOT correctly interprets intersection of a non-convex object with a rectangular build volume.
|
||||
return object_state_templ(its, trafo, may_be_below_bed, [build_volumef](const Vec3f &pt) { return build_volumef.contains(pt); });
|
||||
out = object_state_templ(its, trafo, may_be_below_bed, [build_volumef](const Vec3f& pt) { return build_volumef.contains(pt); });
|
||||
break;
|
||||
}
|
||||
case Type::Circle:
|
||||
{
|
||||
Geometry::Circlef circle { unscaled<float>(m_circle.center), unscaled<float>(m_circle.radius + SceneEpsilon) };
|
||||
return m_max_print_height == 0.0 ?
|
||||
object_state_templ(its, trafo, may_be_below_bed, [circle](const Vec3f &pt) { return circle.contains(to_2d(pt)); }) :
|
||||
object_state_templ(its, trafo, may_be_below_bed, [circle, z = m_max_print_height + SceneEpsilon](const Vec3f &pt) { return pt.z() < z && circle.contains(to_2d(pt)); });
|
||||
out = m_max_print_height == 0.0 ?
|
||||
object_state_templ(its, trafo, may_be_below_bed, [circle](const Vec3f& pt) { return circle.contains(to_2d(pt)); }) :
|
||||
object_state_templ(its, trafo, may_be_below_bed, [circle, z = m_max_print_height + SceneEpsilon](const Vec3f& pt) { return pt.z() < z && circle.contains(to_2d(pt)); });
|
||||
break;
|
||||
}
|
||||
case Type::Convex:
|
||||
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
|
||||
case Type::Custom:
|
||||
return m_max_print_height == 0.0 ?
|
||||
object_state_templ(its, trafo, may_be_below_bed, [this](const Vec3f &pt) { return Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_scene, to_2d(pt).cast<double>()); }) :
|
||||
object_state_templ(its, trafo, may_be_below_bed, [this, z = m_max_print_height + SceneEpsilon](const Vec3f &pt) { return pt.z() < z && Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_scene, to_2d(pt).cast<double>()); });
|
||||
out = m_max_print_height == 0.0 ?
|
||||
object_state_templ(its, trafo, may_be_below_bed, [this](const Vec3f& pt) { return Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_scene, to_2d(pt).cast<double>()); }) :
|
||||
object_state_templ(its, trafo, may_be_below_bed, [this, z = m_max_print_height + SceneEpsilon](const Vec3f& pt) { return pt.z() < z && Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_scene, to_2d(pt).cast<double>()); });
|
||||
break;
|
||||
case Type::Invalid:
|
||||
default:
|
||||
return ObjectState::Inside;
|
||||
out = ObjectState::Inside;
|
||||
break;
|
||||
}
|
||||
|
||||
if (out != ObjectState::Outside) {
|
||||
if (bed_id == s_multiple_beds.get_number_of_beds()) {
|
||||
// The object is on the next bed to be added.
|
||||
s_multiple_beds.request_next_bed(true);
|
||||
}
|
||||
if (bed_idx)
|
||||
*bed_idx = bed_id;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3& volume_bbox, bool ignore_bottom) const
|
||||
BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3 volume_bbox_orig, bool ignore_bottom) const
|
||||
{
|
||||
assert(m_type == Type::Rectangle);
|
||||
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(SceneEpsilon);
|
||||
@ -327,9 +360,25 @@ BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3& vol
|
||||
build_volume.max.z() = std::numeric_limits<double>::max();
|
||||
if (ignore_bottom)
|
||||
build_volume.min.z() = -std::numeric_limits<double>::max();
|
||||
return build_volume.max.z() <= - SceneEpsilon ? ObjectState::Below :
|
||||
build_volume.contains(volume_bbox) ? ObjectState::Inside :
|
||||
build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside;
|
||||
|
||||
ObjectState state = ObjectState::Outside;
|
||||
int bed_idx = 0;
|
||||
for (bed_idx = 0; bed_idx <= std::min(s_multiple_beds.get_number_of_beds(), s_multiple_beds.get_max_beds() - 1); ++bed_idx) {
|
||||
BoundingBoxf3 volume_bbox = volume_bbox_orig;
|
||||
volume_bbox.translate(-s_multiple_beds.get_bed_translation(bed_idx));
|
||||
|
||||
state = build_volume.max.z() <= -SceneEpsilon ? ObjectState::Below :
|
||||
build_volume.contains(volume_bbox) ? ObjectState::Inside :
|
||||
build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside;
|
||||
if (state != ObjectState::Outside)
|
||||
break;
|
||||
}
|
||||
|
||||
if (bed_idx == s_multiple_beds.get_number_of_beds()) {
|
||||
// The object is on the next bed to be added.
|
||||
s_multiple_beds.request_next_bed(true);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const BoundingBoxf3& paths_bbox, bool ignore_bottom) const
|
||||
|
@ -89,10 +89,10 @@ public:
|
||||
// Called by Plater to update Inside / Colliding / Outside state of ModelObjects before slicing.
|
||||
// Called from Model::update_print_volume_state() -> ModelObject::update_instances_print_volume_state()
|
||||
// Using SceneEpsilon
|
||||
ObjectState object_state(const indexed_triangle_set &its, const Transform3f &trafo, bool may_be_below_bed, bool ignore_bottom = true) const;
|
||||
ObjectState object_state(const indexed_triangle_set &its, const Transform3f& trafo, bool may_be_below_bed, bool ignore_bottom = true, int* bed_idx = nullptr) const;
|
||||
// Called by GLVolumeCollection::check_outside_state() after an object is manipulated with gizmos for example.
|
||||
// Called for a rectangular bed:
|
||||
ObjectState volume_state_bbox(const BoundingBoxf3& volume_bbox, bool ignore_bottom = true) const;
|
||||
ObjectState volume_state_bbox(BoundingBoxf3 volume_bbox, bool ignore_bottom = true) const;
|
||||
|
||||
// 2) Test called on G-code paths.
|
||||
// Using BedEpsilon for all tests.
|
||||
|
@ -445,6 +445,8 @@ set(SLIC3R_SOURCES
|
||||
miniz_extension.hpp
|
||||
miniz_extension.cpp
|
||||
MarchingSquares.hpp
|
||||
MultipleBeds.cpp
|
||||
MultipleBeds.hpp
|
||||
Execution/Execution.hpp
|
||||
Execution/ExecutionSeq.hpp
|
||||
Execution/ExecutionTBB.hpp
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "MTUtils.hpp"
|
||||
#include "TriangleMeshSlicer.hpp"
|
||||
#include "TriangleSelector.hpp"
|
||||
#include "MultipleBeds.hpp"
|
||||
|
||||
#include "Format/AMF.hpp"
|
||||
#include "Format/OBJ.hpp"
|
||||
@ -374,8 +375,10 @@ double Model::max_z() const
|
||||
unsigned int Model::update_print_volume_state(const BuildVolume &build_volume)
|
||||
{
|
||||
unsigned int num_printable = 0;
|
||||
s_multiple_beds.clear_inst_map();
|
||||
for (ModelObject* model_object : this->objects)
|
||||
num_printable += model_object->update_instances_print_volume_state(build_volume);
|
||||
s_multiple_beds.inst_map_updated();
|
||||
return num_printable;
|
||||
}
|
||||
|
||||
@ -1594,11 +1597,12 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume
|
||||
OUTSIDE = 2
|
||||
};
|
||||
for (ModelInstance* model_instance : this->instances) {
|
||||
int bed_idx = -1;
|
||||
unsigned int inside_outside = 0;
|
||||
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 */);
|
||||
BuildVolume::ObjectState state = build_volume.object_state(vol->mesh().its, matrix.cast<float>(), true /* may be below print bed */, true /*ignore_bottom*/, &bed_idx);
|
||||
if (state == BuildVolume::ObjectState::Inside)
|
||||
// Volume is completely inside.
|
||||
inside_outside |= INSIDE;
|
||||
@ -1617,6 +1621,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;
|
||||
s_multiple_beds.set_instance_bed(model_instance->id(), bed_idx);
|
||||
}
|
||||
return num_printable;
|
||||
}
|
||||
|
117
src/libslic3r/MultipleBeds.cpp
Normal file
117
src/libslic3r/MultipleBeds.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include "MultipleBeds.hpp"
|
||||
|
||||
#include "BuildVolume.hpp"
|
||||
#include "Model.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
MultipleBeds s_multiple_beds;
|
||||
|
||||
|
||||
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.
|
||||
|
||||
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.);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void MultipleBeds::clear_inst_map()
|
||||
{
|
||||
m_inst_to_bed.clear();
|
||||
}
|
||||
|
||||
void MultipleBeds::set_instance_bed(ObjectID id, int bed_idx)
|
||||
{
|
||||
assert(bed_idx < get_max_beds());
|
||||
m_inst_to_bed[id] = bed_idx;
|
||||
}
|
||||
|
||||
void MultipleBeds::inst_map_updated()
|
||||
{
|
||||
int max_bed_idx = 0;
|
||||
for (const auto& [obj_id, bed_idx] : m_inst_to_bed)
|
||||
max_bed_idx = std::max(max_bed_idx, bed_idx);
|
||||
|
||||
if (m_number_of_beds != max_bed_idx + 1) {
|
||||
m_number_of_beds = max_bed_idx + 1;
|
||||
m_active_bed = m_number_of_beds - 1;
|
||||
request_next_bed(false);
|
||||
}
|
||||
if (m_active_bed >= m_number_of_beds)
|
||||
m_active_bed = m_number_of_beds - 1;
|
||||
}
|
||||
|
||||
void MultipleBeds::request_next_bed(bool show)
|
||||
{
|
||||
m_show_next_bed = (get_number_of_beds() < get_max_beds() ? show : false);
|
||||
}
|
||||
|
||||
void MultipleBeds::set_active_bed(int i)
|
||||
{
|
||||
assert(i < get_max_beds());
|
||||
if (i<m_number_of_beds)
|
||||
m_active_bed = i;
|
||||
}
|
||||
|
||||
void MultipleBeds::move_active_to_first_bed(Model& model, const BuildVolume& build_volume, bool to_or_from) const
|
||||
{
|
||||
static std::vector<std::pair<Vec3d, bool>> old_state;
|
||||
size_t i = 0;
|
||||
assert(! to_or_from || old_state.empty());
|
||||
|
||||
for (ModelObject* mo : model.objects) {
|
||||
for (ModelInstance* mi : mo->instances) {
|
||||
if (to_or_from) {
|
||||
old_state.resize(i+1);
|
||||
old_state[i] = std::make_pair(mi->get_offset(), mi->printable);
|
||||
if (this->is_instance_on_active_bed(mi->id()))
|
||||
mi->set_offset(mi->get_offset() - get_bed_translation(get_active_bed()));
|
||||
else
|
||||
mi->printable = false;
|
||||
} else {
|
||||
mi->set_offset(old_state[i].first);
|
||||
mi->printable = old_state[i].second;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if (! to_or_from)
|
||||
old_state.clear();
|
||||
}
|
||||
|
||||
|
||||
bool MultipleBeds::is_instance_on_active_bed(ObjectID id) const
|
||||
{
|
||||
auto it = m_inst_to_bed.find(id);
|
||||
return (it != m_inst_to_bed.end() && it->second == m_active_bed);
|
||||
}
|
||||
|
||||
}
|
56
src/libslic3r/MultipleBeds.hpp
Normal file
56
src/libslic3r/MultipleBeds.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef libslic3r_MultipleBeds_hpp_
|
||||
#define libslic3r_MultipleBeds_hpp_
|
||||
|
||||
#include "libslic3r/ObjectID.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Model;
|
||||
class BuildVolume;
|
||||
|
||||
|
||||
class MultipleBeds {
|
||||
public:
|
||||
MultipleBeds() = default;
|
||||
|
||||
static constexpr int get_max_beds() { return MAX_NUMBER_OF_BEDS; };
|
||||
Vec3d get_bed_translation(int id) const;
|
||||
|
||||
void clear_inst_map();
|
||||
void set_instance_bed(ObjectID id, int bed_idx);
|
||||
void inst_map_updated();
|
||||
|
||||
int get_number_of_beds() const { return m_number_of_beds; }
|
||||
bool should_show_next_bed() const { return m_show_next_bed; }
|
||||
void request_next_bed(bool show);
|
||||
int get_active_bed() const { return m_active_bed; }
|
||||
|
||||
void set_active_bed(int i);
|
||||
void move_active_to_first_bed(Model& model, const BuildVolume& build_volume, bool to_or_from) const;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
bool is_instance_on_active_bed(ObjectID id) const;
|
||||
|
||||
|
||||
|
||||
int m_number_of_beds = 1;
|
||||
int m_active_bed = 0;
|
||||
bool m_show_next_bed = false;
|
||||
std::map<ObjectID, int> m_inst_to_bed;
|
||||
|
||||
};
|
||||
|
||||
extern MultipleBeds s_multiple_beds;
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // libslic3r_MultipleBeds_hpp_
|
@ -115,6 +115,8 @@ using deque =
|
||||
template<typename T, typename Q>
|
||||
inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); }
|
||||
|
||||
constexpr size_t MAX_NUMBER_OF_BEDS = 9;
|
||||
|
||||
enum Axis {
|
||||
X=0,
|
||||
Y,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "libslic3r/Geometry/Circle.hpp"
|
||||
#include "libslic3r/Tesselate.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/MultipleBeds.hpp"
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
@ -105,22 +106,29 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c
|
||||
|
||||
void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_texture)
|
||||
{
|
||||
render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, show_texture, false);
|
||||
for (size_t i = 0; i < s_multiple_beds.get_number_of_beds() + int(s_multiple_beds.should_show_next_bed()); ++i) {
|
||||
Transform3d mat = view_matrix;
|
||||
mat.translate(s_multiple_beds.get_bed_translation(i));
|
||||
bool is_active = (i == s_multiple_beds.get_active_bed() && s_multiple_beds.get_number_of_beds() != 1);
|
||||
render_internal(canvas, mat, projection_matrix, bottom, scale_factor, show_texture, false, is_active);
|
||||
}
|
||||
}
|
||||
|
||||
void Bed3D::render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor)
|
||||
{
|
||||
render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, false, true);
|
||||
render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, false, true, false);
|
||||
}
|
||||
|
||||
void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor,
|
||||
bool show_texture, bool picking)
|
||||
bool show_texture, bool picking, bool active)
|
||||
{
|
||||
m_scale_factor = scale_factor;
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
m_model.model.set_color(picking ? PICKING_MODEL_COLOR : DEFAULT_MODEL_COLOR);
|
||||
if (!picking && ! active)
|
||||
m_model.model.set_color(ColorRGBA(.6f, .6f, 0.6f, 0.5f));
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
|
@ -86,7 +86,7 @@ private:
|
||||
void init_contourlines();
|
||||
static std::tuple<Type, std::string, std::string> detect_type(const Pointfs& shape);
|
||||
void render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor,
|
||||
bool show_texture, bool picking);
|
||||
bool show_texture, bool picking, bool active);
|
||||
void render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture);
|
||||
void render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||
void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
#include "libslic3r/MultipleBeds.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/Technologies.hpp"
|
||||
#include "libslic3r/Tesselate.hpp"
|
||||
@ -1457,6 +1458,7 @@ bool GLCanvas3D::check_volumes_outside_state(GLVolumeCollection& volumes, ModelI
|
||||
bool contained_min_one = false;
|
||||
|
||||
const Slic3r::BuildVolume& build_volume = m_bed.build_volume();
|
||||
s_multiple_beds.request_next_bed(false);
|
||||
|
||||
const std::vector<unsigned int> volumes_idxs = volumes_to_process_idxs();
|
||||
for (unsigned int vol_idx : volumes_idxs) {
|
||||
@ -1828,6 +1830,26 @@ void GLCanvas3D::render()
|
||||
if (show_imgui_demo_window) ImGui::ShowDemoWindow();
|
||||
#endif // SHOW_IMGUI_DEMO_WINDOW
|
||||
|
||||
|
||||
{
|
||||
if (s_multiple_beds.get_number_of_beds() != 1) {
|
||||
ImGui::SetNextWindowPos(ImVec2(10,10));
|
||||
ImGui::SetNextWindowSize(ImVec2(120., 150.));
|
||||
ImGui::Begin("Bed selector", 0, ImGuiWindowFlags_NoResize);
|
||||
for (int i = 0; i < s_multiple_beds.get_number_of_beds(); ++i) {
|
||||
bool inactive = i != s_multiple_beds.get_active_bed();
|
||||
if (inactive)
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0., 0., 0., .5));
|
||||
if (ImGui::Button((std::string("Bed number ") + std::to_string(i + 1)).c_str()))
|
||||
s_multiple_beds.set_active_bed(i);
|
||||
if (inactive)
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const bool is_looking_downward = camera.is_looking_downward();
|
||||
|
||||
// draw scene
|
||||
@ -5341,8 +5363,19 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be
|
||||
bb.merge(BoundingBoxf3(sel_bb_center - extend_by, sel_bb_center + extend_by));
|
||||
}
|
||||
|
||||
const BoundingBoxf3 bed_bb = include_bed_model ? m_bed.extended_bounding_box() : m_bed.build_volume().bounding_volume();
|
||||
|
||||
|
||||
const BoundingBoxf3 first_bed_bb = include_bed_model ? m_bed.extended_bounding_box() : m_bed.build_volume().bounding_volume();
|
||||
BoundingBoxf3 bed_bb = first_bed_bb;
|
||||
|
||||
for (int i = 0; i < s_multiple_beds.get_number_of_beds() + int(s_multiple_beds.should_show_next_bed()); ++i) {
|
||||
BoundingBoxf3 this_bed = first_bed_bb;
|
||||
this_bed.translate(s_multiple_beds.get_bed_translation(i));
|
||||
bed_bb.merge(this_bed);
|
||||
}
|
||||
bb.merge(bed_bb);
|
||||
|
||||
|
||||
|
||||
if (!m_main_toolbar.is_enabled())
|
||||
bb.merge(m_gcode_viewer.get_max_bounding_box());
|
||||
|
@ -73,6 +73,7 @@
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/miniz_extension.hpp"
|
||||
#include "libslic3r/MultipleBeds.hpp"
|
||||
|
||||
// For stl export
|
||||
#include "libslic3r/CSGMesh/ModelToCSGMesh.hpp"
|
||||
@ -2142,10 +2143,17 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
|
||||
background_process_timer.Stop();
|
||||
// Update the "out of print bed" state of ModelInstances.
|
||||
update_print_volume_state();
|
||||
|
||||
// Move all instances according to their active bed:
|
||||
s_multiple_beds.move_active_to_first_bed(q->model(), q->build_volume(), true);
|
||||
|
||||
// Apply new config to the possibly running background task.
|
||||
bool was_running = background_process.running();
|
||||
Print::ApplyStatus invalidated = background_process.apply(q->model(), full_config);
|
||||
|
||||
// Move all instances back to their respective beds.
|
||||
s_multiple_beds.move_active_to_first_bed(q->model(), q->build_volume(), false);
|
||||
|
||||
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
|
||||
if (view3D->is_layers_editing_enabled())
|
||||
view3D->get_wxglcanvas()->Refresh();
|
||||
|
Loading…
x
Reference in New Issue
Block a user