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 arr
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -55,6 +55,25 @@ struct IrregularBed {
|
|||||||
|
|
||||||
using ArrangeBed = boost::variant<InfiniteBed, RectangleBed, CircleBed, SegmentedRectangleBed, 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);
|
ArrangeBed to_arrange_bed(const Points &bedpts);
|
||||||
|
|
||||||
/// A logical bed representing an object not being arranged. Either the arrange
|
/// A logical bed representing an object not being arranged. Either the arrange
|
||||||
|
@ -99,7 +99,6 @@ void ArrangeJob::prepare_selected() {
|
|||||||
clear_input();
|
clear_input();
|
||||||
|
|
||||||
Model &model = m_plater->model();
|
Model &model = m_plater->model();
|
||||||
double stride = bed_stride(m_plater);
|
|
||||||
|
|
||||||
std::vector<const Selection::InstanceIdxsList *>
|
std::vector<const Selection::InstanceIdxsList *>
|
||||||
obj_sel(model.objects.size(), nullptr);
|
obj_sel(model.objects.size(), nullptr);
|
||||||
@ -143,12 +142,6 @@ void ArrangeJob::prepare_selected() {
|
|||||||
// If the selection was empty arrange everything
|
// If the selection was empty arrange everything
|
||||||
if (m_selected.empty())
|
if (m_selected.empty())
|
||||||
m_selected.swap(m_unselected);
|
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,
|
static void update_arrangepoly_slaprint(arrangement::ArrangePolygon &ret,
|
||||||
@ -261,6 +254,10 @@ void ArrangeJob::prepare()
|
|||||||
}
|
}
|
||||||
m_min_bed_inset = min_offset;
|
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)
|
void ArrangeJob::process(Ctl &ctl)
|
||||||
@ -268,11 +265,9 @@ void ArrangeJob::process(Ctl &ctl)
|
|||||||
static const auto arrangestr = _u8L("Arranging");
|
static const auto arrangestr = _u8L("Arranging");
|
||||||
|
|
||||||
arrangement::ArrangeParams params;
|
arrangement::ArrangeParams params;
|
||||||
arrangement::ArrangeBed bed;
|
ctl.call_on_main_thread([this, ¶ms]{
|
||||||
ctl.call_on_main_thread([this, ¶ms, &bed]{
|
|
||||||
prepare();
|
prepare();
|
||||||
params = get_arrange_params(m_plater);
|
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;
|
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);
|
params.min_bed_distance = std::max(params.min_bed_distance, min_inset);
|
||||||
}).wait();
|
}).wait();
|
||||||
@ -293,13 +288,13 @@ void ArrangeJob::process(Ctl &ctl)
|
|||||||
|
|
||||||
ctl.update_status(0, arrangestr);
|
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) {
|
params.progressind = [this, count, &ctl](unsigned st) {
|
||||||
if (st > 0) ctl.update_status(int(count - st) * 100 / status_range(), arrangestr);
|
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.
|
// finalize just here.
|
||||||
ctl.update_status(int(count) * 100 / status_range(), ctl.was_canceled() ?
|
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();
|
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();
|
wxGetApp().obj_manipul()->set_dirty();
|
||||||
|
|
||||||
if (!m_unarranged.empty()) {
|
if (!m_unarranged.empty()) {
|
||||||
@ -442,4 +439,26 @@ arrangement::ArrangeParams get_arrange_params(Plater *p)
|
|||||||
return params;
|
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
|
}} // namespace Slic3r::GUI
|
||||||
|
@ -21,6 +21,7 @@ class ArrangeJob : public Job
|
|||||||
|
|
||||||
ArrangePolygons m_selected, m_unselected, m_unprintable;
|
ArrangePolygons m_selected, m_unselected, m_unprintable;
|
||||||
std::vector<ModelInstance*> m_unarranged;
|
std::vector<ModelInstance*> m_unarranged;
|
||||||
|
arrangement::ArrangeBed m_bed;
|
||||||
coord_t m_min_bed_inset = 0.;
|
coord_t m_min_bed_inset = 0.;
|
||||||
|
|
||||||
Plater *m_plater;
|
Plater *m_plater;
|
||||||
@ -89,7 +90,6 @@ arrangement::ArrangePolygon get_arrange_poly(T obj, const Plater *plater)
|
|||||||
using ArrangePolygon = arrangement::ArrangePolygon;
|
using ArrangePolygon = arrangement::ArrangePolygon;
|
||||||
|
|
||||||
ArrangePolygon ap = obj.get_arrange_polygon();
|
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) {
|
ap.setter = [obj, plater](const ArrangePolygon &p) {
|
||||||
if (p.is_arranged()) {
|
if (p.is_arranged()) {
|
||||||
Vec2d t = p.translation.cast<double>();
|
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);
|
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
|
}} // namespace Slic3r::GUI
|
||||||
|
|
||||||
#endif // ARRANGEJOB_HPP
|
#endif // ARRANGEJOB_HPP
|
||||||
|
@ -17,7 +17,6 @@ void FillBedJob::prepare()
|
|||||||
{
|
{
|
||||||
m_selected.clear();
|
m_selected.clear();
|
||||||
m_unselected.clear();
|
m_unselected.clear();
|
||||||
m_bedpts.clear();
|
|
||||||
m_min_bed_inset = 0.;
|
m_min_bed_inset = 0.;
|
||||||
|
|
||||||
m_object_idx = m_plater->get_selected_object_idx();
|
m_object_idx = m_plater->get_selected_object_idx();
|
||||||
@ -41,10 +40,10 @@ void FillBedJob::prepare()
|
|||||||
if (m_selected.empty())
|
if (m_selected.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_bedpts = get_bed_shape(*m_plater->config());
|
Points bedpts = get_bed_shape(*m_plater->config());
|
||||||
|
|
||||||
auto &objects = m_plater->model().objects;
|
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)
|
for (size_t idx = 0; idx < objects.size(); ++idx)
|
||||||
if (int(idx) != m_object_idx)
|
if (int(idx) != m_object_idx)
|
||||||
@ -72,7 +71,7 @@ void FillBedJob::prepare()
|
|||||||
}) / sc;
|
}) / sc;
|
||||||
|
|
||||||
double fixed_area = unsel_area + m_selected.size() * poly_area;
|
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.
|
// 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;
|
int needed_items = (bed_area - fixed_area) / poly_area;
|
||||||
@ -85,13 +84,11 @@ void FillBedJob::prepare()
|
|||||||
|
|
||||||
for (int i = 0; i < needed_items; ++i) {
|
for (int i = 0; i < needed_items; ++i) {
|
||||||
ArrangePolygon ap = template_ap;
|
ArrangePolygon ap = template_ap;
|
||||||
ap.poly = m_selected.front().poly;
|
|
||||||
ap.bed_idx = arrangement::UNARRANGED;
|
ap.bed_idx = arrangement::UNARRANGED;
|
||||||
auto m = mi->get_transformation();
|
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];
|
ModelObject *mo = m_plater->model().objects[m_object_idx];
|
||||||
ModelInstance *inst = mo->add_instance(*mi);
|
ModelInstance *inst = mo->add_instance(m);
|
||||||
inst->set_transformation(m);
|
|
||||||
inst->apply_arrange_result(p.translation.cast<double>(), p.rotation);
|
inst->apply_arrange_result(p.translation.cast<double>(), p.rotation);
|
||||||
};
|
};
|
||||||
m_selected.emplace_back(ap);
|
m_selected.emplace_back(ap);
|
||||||
@ -99,14 +96,6 @@ void FillBedJob::prepare()
|
|||||||
|
|
||||||
m_status_range = m_selected.size();
|
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;
|
coord_t min_offset = 0;
|
||||||
for (auto &ap : m_selected) {
|
for (auto &ap : m_selected) {
|
||||||
min_offset = std::max(ap.inflation, min_offset);
|
min_offset = std::max(ap.inflation, min_offset);
|
||||||
@ -123,6 +112,14 @@ void FillBedJob::prepare()
|
|||||||
}
|
}
|
||||||
m_min_bed_inset = min_offset;
|
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)
|
void FillBedJob::process(Ctl &ctl)
|
||||||
@ -154,7 +151,7 @@ void FillBedJob::process(Ctl &ctl)
|
|||||||
do_stop = ap.bed_idx > 0 && ap.priority == 0;
|
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.
|
// finalize just here.
|
||||||
ctl.update_status(100, ctl.was_canceled() ?
|
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();
|
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
|
// FIXME: somebody explain why this is needed for increase_object_instances
|
||||||
if (inst_cnt == 1)
|
if (inst_cnt == 1)
|
||||||
|
@ -18,7 +18,7 @@ class FillBedJob : public Job
|
|||||||
ArrangePolygons m_unselected;
|
ArrangePolygons m_unselected;
|
||||||
coord_t m_min_bed_inset = 0.;
|
coord_t m_min_bed_inset = 0.;
|
||||||
|
|
||||||
Points m_bedpts;
|
arrangement::ArrangeBed m_bed;
|
||||||
|
|
||||||
int m_status_range = 0;
|
int m_status_range = 0;
|
||||||
Plater *m_plater;
|
Plater *m_plater;
|
||||||
|
Loading…
Reference in New Issue
Block a user