mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-20 22:18:30 +00:00
Arrange: place items that fill the printable area, and leave plates alone on failure
An item whose outline fits the printable area could still never be placed: the arrange bed is inset by bed_shrink (1 mm per side) and the item is inflated by its brim width, and the clamp meant to relax that only kicked in with more than 5 mm to spare. An item scaled to fit the print volume was therefore rejected every time. Give the bed margin back where the largest selected item needs it, never below the skirt distance, and cap the inflation at the printable area. When an item comes back UNARRANGED, the GUI parked it on a virtual bed that was never created, moving it a whole plate stride off the plate. Keep the instance where it is instead, and when nothing could be placed at all, skip the plate rebuild so a too large item cannot be re-homed to another plate. Arrange no longer recycles plates: it must not delete a plate the user created, even when the arrange leaves it empty.
This commit is contained in:
1 parent
6626377abc
commit
4c85d0e80a
5 files changed
+76
-24
No files matched your search
@@ -122,8 +122,8 @@ void update_arrange_params(ArrangeParams& params, const DynamicPrintConfig* prin
|
||||
|
||||
void update_selected_items_inflation(ArrangePolygons& selected, const DynamicPrintConfig* print_cfg, ArrangeParams& params) {
|
||||
// do not inflate brim_width. Objects are allowed to have overlapped brim.
|
||||
Points bedpts = get_shrink_bedpts(print_cfg, params);
|
||||
BoundingBox bedbb = Polygon(bedpts).bounding_box();
|
||||
// A brim reaching the printable area's edge is fine, so measure against the full bed.
|
||||
BoundingBox bedbb = Polygon(get_bed_shape(*print_cfg)).bounding_box();
|
||||
// set obj distance for auto seq_print
|
||||
if (params.is_seq_print) {
|
||||
bool all_objects_are_short = std::all_of(selected.begin(), selected.end(), [&](ArrangePolygon& ap) { return ap.height < params.nozzle_height; });
|
||||
@@ -144,14 +144,30 @@ void update_selected_items_inflation(ArrangePolygons& selected, const DynamicPri
|
||||
// 3. otherwise, use each object's own brim width
|
||||
ap.inflation = params.min_obj_distance != 0 ? params.min_obj_distance / 2 :
|
||||
plate_has_tree_support ? scaled(brim_max / 2) : scaled(ap.brim_width);
|
||||
BoundingBox apbb = ap.poly.contour.bounding_box();
|
||||
auto diffx = bedbb.size().x() - apbb.size().x() - 5;
|
||||
auto diffy = bedbb.size().y() - apbb.size().y() - 5;
|
||||
if (diffx > 0 && diffy > 0) {
|
||||
auto min_diff = std::min(diffx, diffy);
|
||||
ap.inflation = std::min(min_diff / 2, ap.inflation);
|
||||
}
|
||||
if (params.min_obj_distance != 0)
|
||||
return; // an explicit object distance is the user's call, not ours to shrink
|
||||
// An item cannot be larger than the printable area, inflation included. Inflating
|
||||
// an almost bed filling item would leave it too big to ever be placed.
|
||||
BoundingBox apbb = ap.poly.contour.bounding_box();
|
||||
auto diffx = bedbb.size().x() - apbb.size().x();
|
||||
auto diffy = bedbb.size().y() - apbb.size().y();
|
||||
ap.inflation = std::max<coord_t>(0, std::min({ ap.inflation, diffx / 2, diffy / 2 }));
|
||||
});
|
||||
|
||||
// Give the bed margin, which the arrange bed keeps from the printable area, back
|
||||
// where the largest item needs it. The skirt keeps its room: pushing a skirt off
|
||||
// the bed is worse than saying the item does not fit.
|
||||
if (!selected.empty()) {
|
||||
coord_t max_width = 0, max_height = 0;
|
||||
for (const ArrangePolygon &ap : selected) {
|
||||
BoundingBox apbb = ap.poly.contour.bounding_box();
|
||||
max_width = std::max(max_width, apbb.size().x() + 2 * ap.inflation);
|
||||
max_height = std::max(max_height, apbb.size().y() + 2 * ap.inflation);
|
||||
}
|
||||
auto margin = [](coord_t bed, coord_t item) { return std::max(0., unscale<double>(bed - item) / 2.); };
|
||||
params.bed_shrink_x = std::min<double>(params.bed_shrink_x, std::max<double>(params.brim_skirt_distance, margin(bedbb.size().x(), max_width)));
|
||||
params.bed_shrink_y = std::min<double>(params.bed_shrink_y, std::max<double>(params.brim_skirt_distance, margin(bedbb.size().y(), max_height)));
|
||||
}
|
||||
}
|
||||
|
||||
void update_unselected_items_inflation(ArrangePolygons& unselected, const DynamicPrintConfig* print_cfg, const ArrangeParams& params)
|
||||
|
||||
@@ -771,6 +771,17 @@ void ArrangeJob::finalize(bool canceled, std::exception_ptr &eptr) {
|
||||
if (canceled || eptr)
|
||||
return;
|
||||
|
||||
// Nothing could be placed: leave the plates and the instances exactly as they were.
|
||||
// Rebuilding the plates would only re-home the instances by their bounds, which moves
|
||||
// a too large item to whichever plate it happens to reach over.
|
||||
const bool nothing_arranged = !m_selected.empty() &&
|
||||
std::all_of(m_selected.begin(), m_selected.end(), [](const ArrangePolygon &ap) { return !ap.is_arranged(); });
|
||||
if (nothing_arranged) {
|
||||
m_plater->get_notification_manager()->close_notification_of_type(NotificationType::ArrangeOngoing);
|
||||
m_plater->m_arrange_running.store(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Unprintable items go to the last virtual bed
|
||||
int beds = 0;
|
||||
|
||||
@@ -870,12 +881,13 @@ void ArrangeJob::finalize(bool canceled, std::exception_ptr &eptr) {
|
||||
}
|
||||
m_plater->get_notification_manager()->close_notification_of_type(NotificationType::ArrangeOngoing);
|
||||
|
||||
//BBS: reload all objects due to arrange
|
||||
//BBS: reload all objects due to arrange. Plates are never recycled here: arranging
|
||||
// must not remove a plate the user created, even when the arrange left it empty.
|
||||
if (only_on_partplate) {
|
||||
plate_list.rebuild_plates_after_arrangement(!only_on_partplate, true, current_plate_index);
|
||||
plate_list.rebuild_plates_after_arrangement(false, true, current_plate_index);
|
||||
}
|
||||
else {
|
||||
plate_list.rebuild_plates_after_arrangement(!only_on_partplate, true);
|
||||
plate_list.rebuild_plates_after_arrangement(false, true);
|
||||
}
|
||||
|
||||
// unlock the plates we just locked
|
||||
|
||||
@@ -248,7 +248,6 @@ void FillBedJob::process(Ctl &ctl)
|
||||
if (m_object_idx == -1 || m_selected.empty()) return;
|
||||
|
||||
update_arrange_params(params, m_plater->config(), m_selected);
|
||||
m_bedpts = get_shrink_bedpts(m_plater->config(), params);
|
||||
|
||||
auto &partplate_list = m_plater->get_partplate_list();
|
||||
auto &print = wxGetApp().plater()->get_partplate_list().get_current_fff_print();
|
||||
@@ -260,6 +259,8 @@ void FillBedJob::process(Ctl &ctl)
|
||||
|
||||
update_selected_items_inflation(m_selected, m_plater->config(), params);
|
||||
update_unselected_items_inflation(m_unselected, m_plater->config(), params);
|
||||
// After the inflation, which may give back part of the bed margin.
|
||||
m_bedpts = get_shrink_bedpts(m_plater->config(), params);
|
||||
|
||||
bool do_stop = false;
|
||||
params.stopcondition = [&ctl, &do_stop]() {
|
||||
|
||||
@@ -7048,19 +7048,14 @@ void PartPlateList::postprocess_arrange_polygon(arrangement::ArrangePolygon& arr
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": bed_idx %1%, selected %2%, translation(x) %3%, (y) %4%") % arrange_polygon.bed_idx % selected % unscale<double>(arrange_polygon.translation(X)) % unscale<double>(arrange_polygon.translation(Y));
|
||||
|
||||
// UNARRANGED means the item could not be placed, so it has no bed to map onto and
|
||||
// must be left where the user had it. Moving it to a virtual bed here would shift
|
||||
// it off the plate, because no such plate is created for it afterwards.
|
||||
if (arrange_polygon.bed_idx == arrangement::UNARRANGED)
|
||||
return;
|
||||
|
||||
if ((selected) || (arrange_polygon.bed_idx != PartPlateList::MAX_PLATES_COUNT))
|
||||
{
|
||||
if (arrange_polygon.bed_idx == -1)
|
||||
{
|
||||
// outarea for large object
|
||||
arrange_polygon.bed_idx = m_plate_list.size();
|
||||
BoundingBox apbox = get_extents(arrange_polygon.transformed_poly()); // the item may have been rotated
|
||||
auto apbox_size = apbox.size();
|
||||
|
||||
arrange_polygon.translation(X) = 0.5 * apbox_size[0];
|
||||
arrange_polygon.translation(Y) = scaled<double>(static_cast<double>(m_plate_depth)) - 0.5 * apbox_size[1];
|
||||
}
|
||||
|
||||
arrange_polygon.row = arrange_polygon.bed_idx / m_plate_cols;
|
||||
arrange_polygon.col = arrange_polygon.bed_idx % m_plate_cols;
|
||||
arrange_polygon.translation(X) += scaled<double>(plate_stride_x() * arrange_polygon.col);
|
||||
|
||||
Reference in new issue
Block a user