Fix arrange on virtual beds
Also fixes repeated bed filling issue
This commit is contained in:
parent
ed410efab4
commit
5154a7f8b3
@ -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
|
||||
|
@ -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
|
||||
|
@ -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, ¶ms, &bed]{
|
||||
ctl.call_on_main_thread([this, ¶ms]{
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user