Fix arrange on virtual beds

Also fixes repeated bed filling issue
This commit is contained in:
tamasmeszaros 2023-06-05 15:04:27 +02:00
parent ed410efab4
commit 5154a7f8b3
6 changed files with 89 additions and 33 deletions

View File

@ -755,5 +755,21 @@ void arrange(ArrangePolygons &items,
}
}
BoundingBox bounding_box(const InfiniteBed &bed)
{
BoundingBox ret;
using C = coord_t;
// It is important for Mx and My to be strictly less than half of the
// range of type C. width(), height() and area() will not overflow this way.
C Mx = C((std::numeric_limits<C>::lowest() + 2 * bed.center.x()) / 4.01);
C My = C((std::numeric_limits<C>::lowest() + 2 * bed.center.y()) / 4.01);
ret.max = bed.center - Point{Mx, My};
ret.min = bed.center + Point{Mx, My};
return ret;
}
} // namespace arr
} // namespace Slic3r

View File

@ -55,6 +55,25 @@ struct IrregularBed {
using ArrangeBed = boost::variant<InfiniteBed, RectangleBed, CircleBed, SegmentedRectangleBed, IrregularBed>;
BoundingBox bounding_box(const InfiniteBed &bed);
inline BoundingBox bounding_box(const RectangleBed &b) { return b.bb; }
inline BoundingBox bounding_box(const SegmentedRectangleBed &b) { return b.bb; }
inline BoundingBox bounding_box(const CircleBed &b)
{
auto r = static_cast<coord_t>(std::round(b.radius()));
Point R{r, r};
return {b.center() - R, b.center() + R};
}
inline BoundingBox bounding_box(const ArrangeBed &b)
{
BoundingBox ret;
auto visitor = [&ret](const auto &b) { ret = bounding_box(b); };
boost::apply_visitor(visitor, b);
return ret;
}
ArrangeBed to_arrange_bed(const Points &bedpts);
/// A logical bed representing an object not being arranged. Either the arrange

View File

@ -99,7 +99,6 @@ void ArrangeJob::prepare_selected() {
clear_input();
Model &model = m_plater->model();
double stride = bed_stride(m_plater);
std::vector<const Selection::InstanceIdxsList *>
obj_sel(model.objects.size(), nullptr);
@ -143,12 +142,6 @@ void ArrangeJob::prepare_selected() {
// If the selection was empty arrange everything
if (m_selected.empty())
m_selected.swap(m_unselected);
// The strides have to be removed from the fixed items. For the
// arrangeable (selected) items bed_idx is ignored and the
// translation is irrelevant.
for (auto &p : m_unselected)
p.translation(X) -= p.bed_idx * stride;
}
static void update_arrangepoly_slaprint(arrangement::ArrangePolygon &ret,
@ -261,6 +254,10 @@ void ArrangeJob::prepare()
}
m_min_bed_inset = min_offset;
}
double stride = bed_stride(m_plater);
get_bed_shape(*m_plater->config(), m_bed);
assign_logical_beds(m_unselected, m_bed, stride);
}
void ArrangeJob::process(Ctl &ctl)
@ -268,11 +265,9 @@ void ArrangeJob::process(Ctl &ctl)
static const auto arrangestr = _u8L("Arranging");
arrangement::ArrangeParams params;
arrangement::ArrangeBed bed;
ctl.call_on_main_thread([this, &params, &bed]{
ctl.call_on_main_thread([this, &params]{
prepare();
params = get_arrange_params(m_plater);
get_bed_shape(*m_plater->config(), bed);
coord_t min_inset = get_skirt_offset(m_plater) + m_min_bed_inset;
params.min_bed_distance = std::max(params.min_bed_distance, min_inset);
}).wait();
@ -293,13 +288,13 @@ void ArrangeJob::process(Ctl &ctl)
ctl.update_status(0, arrangestr);
arrangement::arrange(m_selected, m_unselected, bed, params);
arrangement::arrange(m_selected, m_unselected, m_bed, params);
params.progressind = [this, count, &ctl](unsigned st) {
if (st > 0) ctl.update_status(int(count - st) * 100 / status_range(), arrangestr);
};
arrangement::arrange(m_unprintable, {}, bed, params);
arrangement::arrange(m_unprintable, {}, m_bed, params);
// finalize just here.
ctl.update_status(int(count) * 100 / status_range(), ctl.was_canceled() ?
@ -358,7 +353,9 @@ void ArrangeJob::finalize(bool canceled, std::exception_ptr &eptr) {
ap.apply();
}
m_plater->update((unsigned int)Plater::UpdateParams::FORCE_FULL_SCREEN_REFRESH);
m_plater->update(static_cast<unsigned int>(
Plater::UpdateParams::FORCE_FULL_SCREEN_REFRESH));
wxGetApp().obj_manipul()->set_dirty();
if (!m_unarranged.empty()) {
@ -442,4 +439,26 @@ arrangement::ArrangeParams get_arrange_params(Plater *p)
return params;
}
void assign_logical_beds(std::vector<arrangement::ArrangePolygon> &items,
const arrangement::ArrangeBed &bed,
double stride)
{
// The strides have to be removed from the fixed items. For the
// arrangeable (selected) items bed_idx is ignored and the
// translation is irrelevant.
coord_t bedx = bounding_box(bed).min.x();
for (auto &itm : items) {
auto bedidx = std::max(arrangement::UNARRANGED,
static_cast<int>(std::floor(
(get_extents(itm.transformed_poly()).min.x() - bedx) /
stride)));
itm.bed_idx = bedidx;
if (bedidx >= 0)
itm.translation.x() -= bedidx * stride;
}
}
}} // namespace Slic3r::GUI

View File

@ -21,6 +21,7 @@ class ArrangeJob : public Job
ArrangePolygons m_selected, m_unselected, m_unprintable;
std::vector<ModelInstance*> m_unarranged;
arrangement::ArrangeBed m_bed;
coord_t m_min_bed_inset = 0.;
Plater *m_plater;
@ -89,7 +90,6 @@ arrangement::ArrangePolygon get_arrange_poly(T obj, const Plater *plater)
using ArrangePolygon = arrangement::ArrangePolygon;
ArrangePolygon ap = obj.get_arrange_polygon();
ap.bed_idx = get_extents(ap.transformed_poly()).min.x() / bed_stride(plater);
ap.setter = [obj, plater](const ArrangePolygon &p) {
if (p.is_arranged()) {
Vec2d t = p.translation.cast<double>();
@ -109,6 +109,10 @@ arrangement::ArrangeParams get_arrange_params(Plater *p);
coord_t get_skirt_offset(const Plater* plater);
void assign_logical_beds(std::vector<arrangement::ArrangePolygon> &items,
const arrangement::ArrangeBed &bed,
double stride);
}} // namespace Slic3r::GUI
#endif // ARRANGEJOB_HPP

View File

@ -17,7 +17,6 @@ void FillBedJob::prepare()
{
m_selected.clear();
m_unselected.clear();
m_bedpts.clear();
m_min_bed_inset = 0.;
m_object_idx = m_plater->get_selected_object_idx();
@ -41,10 +40,10 @@ void FillBedJob::prepare()
if (m_selected.empty())
return;
m_bedpts = get_bed_shape(*m_plater->config());
Points bedpts = get_bed_shape(*m_plater->config());
auto &objects = m_plater->model().objects;
BoundingBox bedbb = get_extents(m_bedpts);
BoundingBox bedbb = get_extents(bedpts);
for (size_t idx = 0; idx < objects.size(); ++idx)
if (int(idx) != m_object_idx)
@ -72,7 +71,7 @@ void FillBedJob::prepare()
}) / sc;
double fixed_area = unsel_area + m_selected.size() * poly_area;
double bed_area = Polygon{m_bedpts}.area() / sc;
double bed_area = Polygon{bedpts}.area() / sc;
// This is the maximum number of items, the real number will always be close but less.
int needed_items = (bed_area - fixed_area) / poly_area;
@ -85,13 +84,11 @@ void FillBedJob::prepare()
for (int i = 0; i < needed_items; ++i) {
ArrangePolygon ap = template_ap;
ap.poly = m_selected.front().poly;
ap.bed_idx = arrangement::UNARRANGED;
auto m = mi->get_transformation();
ap.setter = [this, mi, m](const ArrangePolygon &p) {
ap.setter = [this, m](const ArrangePolygon &p) {
ModelObject *mo = m_plater->model().objects[m_object_idx];
ModelInstance *inst = mo->add_instance(*mi);
inst->set_transformation(m);
ModelInstance *inst = mo->add_instance(m);
inst->apply_arrange_result(p.translation.cast<double>(), p.rotation);
};
m_selected.emplace_back(ap);
@ -99,14 +96,6 @@ void FillBedJob::prepare()
m_status_range = m_selected.size();
// The strides have to be removed from the fixed items. For the
// arrangeable (selected) items bed_idx is ignored and the
// translation is irrelevant.
double stride = bed_stride(m_plater);
for (auto &p : m_unselected)
if (p.bed_idx > 0)
p.translation(X) -= p.bed_idx * stride;
coord_t min_offset = 0;
for (auto &ap : m_selected) {
min_offset = std::max(ap.inflation, min_offset);
@ -123,6 +112,14 @@ void FillBedJob::prepare()
}
m_min_bed_inset = min_offset;
}
// The strides have to be removed from the fixed items. For the
// arrangeable (selected) items bed_idx is ignored and the
// translation is irrelevant.
double stride = bed_stride(m_plater);
m_bed = arrangement::to_arrange_bed(bedpts);
assign_logical_beds(m_unselected, m_bed, stride);
}
void FillBedJob::process(Ctl &ctl)
@ -154,7 +151,7 @@ void FillBedJob::process(Ctl &ctl)
do_stop = ap.bed_idx > 0 && ap.priority == 0;
};
arrangement::arrange(m_selected, m_unselected, m_bedpts, params);
arrangement::arrange(m_selected, m_unselected, m_bed, params);
// finalize just here.
ctl.update_status(100, ctl.was_canceled() ?
@ -191,7 +188,8 @@ void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr)
model_object->ensure_on_bed();
m_plater->update();
m_plater->update(static_cast<unsigned int>(
Plater::UpdateParams::FORCE_FULL_SCREEN_REFRESH));
// FIXME: somebody explain why this is needed for increase_object_instances
if (inst_cnt == 1)

View File

@ -18,7 +18,7 @@ class FillBedJob : public Job
ArrangePolygons m_unselected;
coord_t m_min_bed_inset = 0.;
Points m_bedpts;
arrangement::ArrangeBed m_bed;
int m_status_range = 0;
Plater *m_plater;