mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 11:31:58 +08:00
Polishing:
- virtual bed shows even when dragging which was already outside - when loading old-arranged project with more than max number of beds, a virtual bed would still be offered - loading a project file with multiple beds only showed 2 beds initially - nonprintable objects are not considered into the bed creation logic - drag and dropping an object does not change active bed - shells in preview are now shown correctly when switching between beds - spacing in x takes into account model size (except during the initial rearrange) - update volumes outside state after project loading - highlight of selected bed for default beds
This commit is contained in:
parent
cc73ff8f4f
commit
360f7a84b4
@ -292,8 +292,14 @@ BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& i
|
||||
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) {
|
||||
// When loading an old project with more than the maximum number of beds,
|
||||
// we still want to move the objects to the respective positions.
|
||||
// Max beds number is momentarily increased when doing the rearrange, so use it.
|
||||
const int max_bed = s_multiple_beds.get_loading_project_flag()
|
||||
? s_multiple_beds.get_number_of_beds() - 1
|
||||
: std::min(s_multiple_beds.get_number_of_beds(), s_multiple_beds.get_max_beds() - 1);
|
||||
|
||||
for (int bed_id = 0; bed_id <= max_bed; ++bed_id) {
|
||||
|
||||
|
||||
Transform3f trafo = trafo_orig;
|
||||
@ -336,10 +342,6 @@ BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& i
|
||||
}
|
||||
|
||||
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;
|
||||
@ -352,7 +354,7 @@ BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& i
|
||||
return out;
|
||||
}
|
||||
|
||||
BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3 volume_bbox_orig, bool ignore_bottom) const
|
||||
BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3 volume_bbox_orig, bool ignore_bottom, int* bed_idx) const
|
||||
{
|
||||
assert(m_type == Type::Rectangle);
|
||||
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(SceneEpsilon);
|
||||
@ -362,10 +364,10 @@ BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3 volu
|
||||
build_volume.min.z() = -std::numeric_limits<double>::max();
|
||||
|
||||
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) {
|
||||
int bed_id = 0;
|
||||
for (bed_id = 0; bed_id <= std::min(s_multiple_beds.get_number_of_beds(), s_multiple_beds.get_max_beds() - 1); ++bed_id) {
|
||||
BoundingBoxf3 volume_bbox = volume_bbox_orig;
|
||||
volume_bbox.translate(-s_multiple_beds.get_bed_translation(bed_idx));
|
||||
volume_bbox.translate(-s_multiple_beds.get_bed_translation(bed_id));
|
||||
|
||||
state = build_volume.max.z() <= -SceneEpsilon ? ObjectState::Below :
|
||||
build_volume.contains(volume_bbox) ? ObjectState::Inside :
|
||||
@ -374,10 +376,8 @@ BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3 volu
|
||||
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);
|
||||
}
|
||||
if (bed_idx)
|
||||
*bed_idx = bed_id;
|
||||
return state;
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ public:
|
||||
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(BoundingBoxf3 volume_bbox, bool ignore_bottom = true) const;
|
||||
ObjectState volume_state_bbox(BoundingBoxf3 volume_bbox, bool ignore_bottom, int* bed_idx) const;
|
||||
|
||||
// 2) Test called on G-code paths.
|
||||
// Using BedEpsilon for all tests.
|
||||
|
@ -1624,7 +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)
|
||||
if (bed_idx != -1 && model_instance->is_printable())
|
||||
s_multiple_beds.set_instance_bed(model_instance->id(), bed_idx);
|
||||
}
|
||||
return num_printable;
|
||||
|
@ -42,7 +42,7 @@ Vec3d MultipleBeds::get_bed_translation(int id) const
|
||||
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.);
|
||||
return Vec3d(x * m_build_volume_bb_incl_model.size().x() * (1. + bed_gap_x), y * m_build_volume_bb_incl_model.size().y() * (1. + bed_gap_y), 0.);
|
||||
}
|
||||
|
||||
|
||||
@ -137,15 +137,42 @@ 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)
|
||||
// Beware! This function is also needed for proper update of bed when normal grid project is loaded!
|
||||
bool MultipleBeds::update_after_load_or_arrange(Model& model, const BuildVolume& build_volume, std::function<void()> update_fn)
|
||||
{
|
||||
int original_number_of_beds = m_number_of_beds;
|
||||
int stash_active = get_active_bed();
|
||||
Slic3r::ScopeGuard guard([&]() {
|
||||
m_layout_linear = false;
|
||||
m_number_of_beds = get_max_beds();
|
||||
model.update_print_volume_state(build_volume);
|
||||
int max_bed = 0;
|
||||
for (const auto& [oid, bed_id] : m_inst_to_bed)
|
||||
max_bed = std::max(bed_id, max_bed);
|
||||
m_number_of_beds = std::min(get_max_beds(), max_bed + 1);
|
||||
model.update_print_volume_state(build_volume);
|
||||
request_next_bed(false);
|
||||
set_active_bed(m_number_of_beds != original_number_of_beds ? 0 : stash_active);
|
||||
update_fn();
|
||||
});
|
||||
|
||||
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;
|
||||
std::swap(m_build_volume_bb, m_build_volume_bb_incl_model);
|
||||
int abs_max = get_max_beds();
|
||||
while (true) {
|
||||
// This is to ensure that even objects on linear bed with higher than
|
||||
// allowed index will be rearranged.
|
||||
m_number_of_beds = abs_max;
|
||||
model.update_print_volume_state(build_volume);
|
||||
int max_bed = 0;
|
||||
for (const auto& [oid, bed_id] : m_inst_to_bed)
|
||||
max_bed = std::max(bed_id, max_bed);
|
||||
if (max_bed + 1 < abs_max)
|
||||
break;
|
||||
abs_max += get_max_beds();
|
||||
}
|
||||
m_number_of_beds = 1;
|
||||
std::swap(m_build_volume_bb, m_build_volume_bb_incl_model);
|
||||
|
||||
int max_bed = 0;
|
||||
|
||||
@ -163,17 +190,18 @@ bool MultipleBeds::rearrange_linear_to_grid_if_possible(Model& model, const Buil
|
||||
}
|
||||
}
|
||||
|
||||
if (max_bed == 0) {
|
||||
// All instances are on the first bed. No need to do anything.
|
||||
return false;
|
||||
}
|
||||
// Now do the rearrangement
|
||||
m_number_of_beds = max_bed + 1;
|
||||
assert(m_number_of_beds <= get_max_beds());
|
||||
if (m_number_of_beds == 1)
|
||||
return false;
|
||||
|
||||
// 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;
|
||||
std::swap(m_build_volume_bb, m_build_volume_bb_incl_model);
|
||||
mi->set_offset(mi->get_offset() - get_bed_translation(bed_idx));
|
||||
std::swap(m_build_volume_bb, m_build_volume_bb_incl_model);
|
||||
}
|
||||
|
||||
m_layout_linear = false;
|
||||
@ -181,7 +209,6 @@ bool MultipleBeds::rearrange_linear_to_grid_if_possible(Model& model, const Buil
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -43,11 +43,11 @@ 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);
|
||||
bool update_after_load_or_arrange(Model& model, const BuildVolume& build_volume, std::function<void()> update_fn);
|
||||
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; }
|
||||
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; }
|
||||
|
||||
|
||||
|
||||
@ -65,6 +65,7 @@ private:
|
||||
std::map<PrintBase*, size_t> m_printbase_to_texture;
|
||||
int m_last_hovered_bed = -1;
|
||||
BoundingBoxf m_build_volume_bb;
|
||||
BoundingBoxf m_build_volume_bb_incl_model;
|
||||
bool m_layout_linear = false;
|
||||
bool m_loading_project = false;
|
||||
};
|
||||
|
@ -33,6 +33,7 @@ static const Slic3r::ColorRGBA DEFAULT_MODEL_COLOR = Slic3r::ColorRG
|
||||
static const Slic3r::ColorRGBA PICKING_MODEL_COLOR = Slic3r::ColorRGBA::BLACK();
|
||||
static const Slic3r::ColorRGBA DEFAULT_SOLID_GRID_COLOR = { 0.9f, 0.9f, 0.9f, 1.0f };
|
||||
static const Slic3r::ColorRGBA DEFAULT_TRANSPARENT_GRID_COLOR = { 0.9f, 0.9f, 0.9f, 0.6f };
|
||||
static const Slic3r::ColorRGBA DISABLED_MODEL_COLOR = { 0.6f, 0.6f, 0.6f, 0.75f };
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
@ -84,8 +85,6 @@ 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)
|
||||
@ -97,13 +96,20 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c
|
||||
m_texture.reset();
|
||||
m_model.reset();
|
||||
|
||||
// unregister from picking
|
||||
wxGetApp().plater()->canvas3D()->remove_raycasters_for_picking(SceneRaycaster::EType::Bed);
|
||||
|
||||
init_internal_model_from_file();
|
||||
init_triangles();
|
||||
|
||||
BoundingBoxf bb = m_build_volume.bounding_volume2d();
|
||||
bb.max = Vec2d(bb.max.x() + std::max(0., m_model.model.get_bounding_box().size().x() - bb.size().x()), bb.max.y() + std::max(0., m_model.model.get_bounding_box().size().y() - bb.size().y()));
|
||||
s_multiple_beds.update_build_volume(m_build_volume.bounding_volume2d(), bb);
|
||||
|
||||
// Set the origin and size for rendering the coordinate system axes.
|
||||
m_axes.set_origin({ 0.0, 0.0, static_cast<double>(GROUND_Z) });
|
||||
m_axes.set_stem_length(0.1f * static_cast<float>(m_build_volume.bounding_volume().max_size()));
|
||||
|
||||
// unregister from picking
|
||||
wxGetApp().plater()->canvas3D()->remove_raycasters_for_picking(SceneRaycaster::EType::Bed);
|
||||
|
||||
// Let the calee to update the UI.
|
||||
return true;
|
||||
}
|
||||
@ -145,8 +151,11 @@ void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix,
|
||||
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));
|
||||
m_triangles.set_color(picking ? PICKING_MODEL_COLOR : DEFAULT_MODEL_COLOR);
|
||||
if (!picking && !active) {
|
||||
m_model.model.set_color(DISABLED_MODEL_COLOR);
|
||||
m_triangles.set_color(DISABLED_MODEL_COLOR);
|
||||
}
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
@ -229,14 +238,6 @@ void Bed3D::init_triangles()
|
||||
register_raycasters_for_picking(init_data, Transform3d::Identity());
|
||||
|
||||
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()
|
||||
@ -454,7 +455,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& v
|
||||
}
|
||||
}
|
||||
|
||||
void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix)
|
||||
void Bed3D::init_internal_model_from_file()
|
||||
{
|
||||
if (m_model_filename.empty())
|
||||
return;
|
||||
@ -479,6 +480,14 @@ void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& proj
|
||||
// update extended bounding box
|
||||
m_extended_bounding_box = this->calc_extended_bounding_box();
|
||||
}
|
||||
}
|
||||
|
||||
void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix)
|
||||
{
|
||||
if (m_model_filename.empty())
|
||||
return;
|
||||
|
||||
init_internal_model_from_file();
|
||||
|
||||
if (!m_model.model.get_filename().empty()) {
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
|
@ -84,6 +84,7 @@ private:
|
||||
void init_triangles();
|
||||
void init_gridlines();
|
||||
void init_contourlines();
|
||||
void init_internal_model_from_file();
|
||||
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 active);
|
||||
|
@ -1493,19 +1493,20 @@ bool GLCanvas3D::check_volumes_outside_state(GLVolumeCollection& volumes, ModelI
|
||||
GLVolume* volume = volumes.volumes[vol_idx];
|
||||
if (!volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (!volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) {
|
||||
BuildVolume::ObjectState state;
|
||||
int bed_idx = -1;
|
||||
if (volume_below(*volume))
|
||||
state = BuildVolume::ObjectState::Below;
|
||||
else {
|
||||
switch (build_volume.type()) {
|
||||
case BuildVolume::Type::Rectangle:
|
||||
//FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects.
|
||||
state = build_volume.volume_state_bbox(volume_bbox(*volume));
|
||||
state = build_volume.volume_state_bbox(volume_bbox(*volume), true, &bed_idx);
|
||||
break;
|
||||
case BuildVolume::Type::Circle:
|
||||
case BuildVolume::Type::Convex:
|
||||
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
|
||||
case BuildVolume::Type::Custom:
|
||||
state = build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast<float>(), volume_sinking(*volume));
|
||||
state = build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast<float>(), volume_sinking(*volume), true, &bed_idx);
|
||||
break;
|
||||
default:
|
||||
// Ignore, don't produce any collision.
|
||||
@ -1521,6 +1522,9 @@ bool GLCanvas3D::check_volumes_outside_state(GLVolumeCollection& volumes, ModelI
|
||||
if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && state == BuildVolume::ObjectState::Colliding)
|
||||
overall_state = ModelInstancePVS_Partly_Outside;
|
||||
contained_min_one |= !volume->is_outside;
|
||||
|
||||
if (! volume->is_outside && bed_idx != -1 && bed_idx == s_multiple_beds.get_number_of_beds())
|
||||
s_multiple_beds.request_next_bed(true);
|
||||
}
|
||||
}
|
||||
else if (volume->is_modifier)
|
||||
|
@ -1599,7 +1599,7 @@ 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()))
|
||||
if (s_multiple_beds.update_after_load_or_arrange(model, q->build_volume(), [this]() {q->canvas3D()->check_volumes_outside_state(); }))
|
||||
update();
|
||||
|
||||
return obj_idxs;
|
||||
@ -2966,8 +2966,7 @@ void Plater::priv::set_current_panel(wxPanel* panel)
|
||||
bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside;
|
||||
if (!model.objects.empty() && !export_in_progress && model_fits) {
|
||||
preview->get_canvas3d()->init_gcode_viewer();
|
||||
if (! this->background_process.finished())
|
||||
preview->load_gcode_shells();
|
||||
preview->load_gcode_shells();
|
||||
q->reslice();
|
||||
}
|
||||
// keeps current gcode preview, if any
|
||||
@ -6791,7 +6790,7 @@ void Plater::arrange(Worker &w, bool selected)
|
||||
concat_strings(names, "\n")));
|
||||
}
|
||||
|
||||
s_multiple_beds.rearrange_linear_to_grid_if_possible(model(), build_volume());
|
||||
s_multiple_beds.update_after_load_or_arrange(model(), build_volume(), [this]() { canvas3D()->check_volumes_outside_state(); });
|
||||
|
||||
update(static_cast<unsigned int>(UpdateParams::FORCE_FULL_SCREEN_REFRESH));
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
|
Loading…
x
Reference in New Issue
Block a user