Arrange selection if shift is pressed. Remove first item centering
This commit is contained in:
parent
72ed8c034e
commit
63fada9469
2 changed files with 97 additions and 65 deletions
|
@ -136,6 +136,9 @@ protected:
|
||||||
ItemGroup m_remaining; // Remaining items (m_items at the beginning)
|
ItemGroup m_remaining; // Remaining items (m_items at the beginning)
|
||||||
ItemGroup m_items; // The items to be packed
|
ItemGroup m_items; // The items to be packed
|
||||||
|
|
||||||
|
// Used only for preloading objects before arrange
|
||||||
|
// std::vector<SpatIndex> m_preload_idx; // spatial index for preloaded beds
|
||||||
|
|
||||||
template<class T> ArithmeticOnly<T, double> norm(T val)
|
template<class T> ArithmeticOnly<T, double> norm(T val)
|
||||||
{
|
{
|
||||||
return double(val) / m_norm;
|
return double(val) / m_norm;
|
||||||
|
@ -318,6 +321,7 @@ public:
|
||||||
m_pilebb = sl::boundingBox(merged_pile);
|
m_pilebb = sl::boundingBox(merged_pile);
|
||||||
|
|
||||||
m_rtree.clear();
|
m_rtree.clear();
|
||||||
|
// m_preload_idx.clear();
|
||||||
m_smallsrtree.clear();
|
m_smallsrtree.clear();
|
||||||
|
|
||||||
// We will treat big items (compared to the print bed) differently
|
// We will treat big items (compared to the print bed) differently
|
||||||
|
@ -341,7 +345,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class...Args> inline void operator()(Args&&...args) {
|
template<class...Args> inline void operator()(Args&&...args) {
|
||||||
m_rtree.clear();
|
m_rtree.clear(); /*m_preload_idx.clear();*/
|
||||||
m_pck.execute(std::forward<Args>(args)...);
|
m_pck.execute(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,19 +362,25 @@ public:
|
||||||
for(unsigned idx = 0; idx < fixeditems.size(); ++idx) {
|
for(unsigned idx = 0; idx < fixeditems.size(); ++idx) {
|
||||||
Item& itm = fixeditems[idx];
|
Item& itm = fixeditems[idx];
|
||||||
itm.markAsFixed();
|
itm.markAsFixed();
|
||||||
m_rtree.insert({itm.boundingBox(), idx});
|
// size_t bedidx = itm.binId() < 0 ? 0u : size_t(itm.binId());
|
||||||
|
|
||||||
|
// while (m_preload_idx.size() <= bedidx) m_preload_idx.emplace_back();
|
||||||
|
// m_preload_idx[bedidx].insert({itm.boundingBox(), idx});
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pck.configure(m_pconf);
|
m_pck.configure(m_pconf);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_colliding(const Item& item) {
|
// int is_colliding(const Item& item) {
|
||||||
if(m_rtree.empty()) return false;
|
// size_t bedidx = item.binId() < 0 ? 0u : size_t(item.binId());
|
||||||
std::vector<SpatElement> result;
|
// if (m_preload_idx.size() <= bedidx || m_preload_idx[bedidx].empty())
|
||||||
m_rtree.query(bgi::intersects(item.boundingBox()),
|
// return false;
|
||||||
std::back_inserter(result));
|
|
||||||
return !result.empty();
|
// std::vector<SpatElement> result;
|
||||||
}
|
// m_preload_idx[bedidx].query(bgi::intersects(item.boundingBox()),
|
||||||
|
// std::back_inserter(result));
|
||||||
|
// return !result.empty();
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> std::function<double(const Item&)> AutoArranger<Box>::get_objfn()
|
template<> std::function<double(const Item&)> AutoArranger<Box>::get_objfn()
|
||||||
|
@ -534,24 +544,21 @@ void _arrange(
|
||||||
++it : it = excludes.erase(it);
|
++it : it = excludes.erase(it);
|
||||||
|
|
||||||
// If there is something on the plate
|
// If there is something on the plate
|
||||||
if(!excludes.empty())
|
if (!excludes.empty()) {
|
||||||
{
|
arranger.preload(excludes);
|
||||||
arranger.preload(excludes);
|
// auto binbb = sl::boundingBox(corrected_bin);
|
||||||
auto binbb = sl::boundingBox(corrected_bin);
|
|
||||||
|
|
||||||
// Try to put the first item to the center, as the arranger
|
// // Try to put the first item to the center, as the arranger
|
||||||
// will not do this for us.
|
// // will not do this for us.
|
||||||
for (Item &itm : shapes) {
|
// for (Item &itm : shapes) {
|
||||||
auto ibb = itm.boundingBox();
|
// auto ibb = itm.boundingBox();
|
||||||
auto d = binbb.center() - ibb.center();
|
// auto d = binbb.center() - ibb.center();
|
||||||
itm.translate(d);
|
// itm.translate(d);
|
||||||
|
// itm.binId(UNARRANGED);
|
||||||
|
|
||||||
if (!arranger.is_colliding(itm)) {
|
// if (!arranger.is_colliding(itm)) { itm.markAsFixed(); break; }
|
||||||
itm.markAsFixed();
|
// }
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::reference_wrapper<Item>> inp;
|
std::vector<std::reference_wrapper<Item>> inp;
|
||||||
inp.reserve(shapes.size() + excludes.size());
|
inp.reserve(shapes.size() + excludes.size());
|
||||||
|
|
|
@ -1421,8 +1421,9 @@ struct Plater::priv
|
||||||
wxQueueEvent(this, evt);
|
wxQueueEvent(this, evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
priv &plater() { return *m_plater; }
|
priv & plater() { return *m_plater; }
|
||||||
bool was_canceled() const { return m_canceled.load(); }
|
const priv &plater() const { return *m_plater; }
|
||||||
|
bool was_canceled() const { return m_canceled.load(); }
|
||||||
|
|
||||||
// Launched just before start(), a job can use it to prepare internals
|
// Launched just before start(), a job can use it to prepare internals
|
||||||
virtual void prepare() {}
|
virtual void prepare() {}
|
||||||
|
@ -1537,51 +1538,76 @@ struct Plater::priv
|
||||||
|
|
||||||
ArrangePolygons m_selected, m_unselected;
|
ArrangePolygons m_selected, m_unselected;
|
||||||
|
|
||||||
protected:
|
// clear m_selected and m_unselected, reserve space for next usage
|
||||||
|
void clear_input() {
|
||||||
void prepare() override
|
const Model &model = plater().model;
|
||||||
{
|
|
||||||
// Get the selection map
|
|
||||||
Selection& sel = plater().get_selection();
|
|
||||||
const Selection::ObjectIdxsToInstanceIdxsMap &selmap =
|
|
||||||
sel.get_content();
|
|
||||||
|
|
||||||
Model &model = plater().model;
|
|
||||||
|
|
||||||
size_t count = 0; // To know how much space to reserve
|
size_t count = 0; // To know how much space to reserve
|
||||||
for (auto obj : model.objects) count += obj->instances.size();
|
for (auto obj : model.objects) count += obj->instances.size();
|
||||||
|
|
||||||
m_selected.clear(), m_unselected.clear();
|
m_selected.clear(), m_unselected.clear();
|
||||||
m_selected.reserve(count + 1 /* for optional wti */);
|
m_selected.reserve(count + 1 /* for optional wti */);
|
||||||
m_unselected.reserve(count + 1 /* for optional wti */);
|
m_unselected.reserve(count + 1 /* for optional wti */);
|
||||||
|
}
|
||||||
// Stride between logical beds
|
|
||||||
|
// Stride between logical beds
|
||||||
|
coord_t bed_stride() const {
|
||||||
double bedwidth = plater().bed_shape_bb().size().x();
|
double bedwidth = plater().bed_shape_bb().size().x();
|
||||||
coord_t stride = scaled((1. + LOGICAL_BED_GAP) * bedwidth);
|
return scaled((1. + LOGICAL_BED_GAP) * bedwidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up arrange polygon for a ModelInstance and Wipe tower
|
||||||
|
template<class T> ArrangePolygon get_arrange_poly(T *obj) const {
|
||||||
|
ArrangePolygon ap = obj->get_arrange_polygon();
|
||||||
|
ap.priority = 0;
|
||||||
|
ap.bed_idx = ap.translation.x() / bed_stride();
|
||||||
|
ap.setter = [obj, this](const ArrangePolygon &p) {
|
||||||
|
if (p.is_arranged()) {
|
||||||
|
auto t = p.translation; t.x() += p.bed_idx * bed_stride();
|
||||||
|
obj->apply_arrange_result(t, p.rotation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return ap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare all objects on the bed regardless of the selection
|
||||||
|
void prepare_all() {
|
||||||
|
clear_input();
|
||||||
|
|
||||||
|
for (ModelObject *obj: plater().model.objects)
|
||||||
|
for (ModelInstance *mi : obj->instances)
|
||||||
|
m_selected.emplace_back(get_arrange_poly(mi));
|
||||||
|
|
||||||
|
auto& wti = plater().updated_wipe_tower();
|
||||||
|
if (wti) m_selected.emplace_back(get_arrange_poly(&wti));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the selected and unselected items separately. If nothing is
|
||||||
|
// selected, behaves as if everything would be selected.
|
||||||
|
void prepare_selected() {
|
||||||
|
clear_input();
|
||||||
|
|
||||||
|
Model &model = plater().model;
|
||||||
|
coord_t stride = bed_stride();
|
||||||
|
|
||||||
|
std::vector<const Selection::InstanceIdxsList *>
|
||||||
|
obj_sel(model.objects.size(), nullptr);
|
||||||
|
|
||||||
|
for (auto &s : plater().get_selection().get_content())
|
||||||
|
if (s.first < int(obj_sel.size())) obj_sel[s.first] = &s.second;
|
||||||
|
|
||||||
// Go through the objects and check if inside the selection
|
// Go through the objects and check if inside the selection
|
||||||
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) {
|
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) {
|
||||||
auto oit = selmap.find(int(oidx));
|
const Selection::InstanceIdxsList * instlist = obj_sel[oidx];
|
||||||
ModelObject *mo = model.objects[oidx];
|
ModelObject *mo = model.objects[oidx];
|
||||||
|
|
||||||
std::vector<bool> inst_sel(mo->instances.size(), false);
|
std::vector<bool> inst_sel(mo->instances.size(), false);
|
||||||
|
|
||||||
if (oit != selmap.end())
|
if (instlist)
|
||||||
for (auto inst_id : oit->second) inst_sel[inst_id] = true;
|
for (auto inst_id : *instlist) inst_sel[inst_id] = true;
|
||||||
|
|
||||||
for (size_t i = 0; i < inst_sel.size(); ++i) {
|
for (size_t i = 0; i < inst_sel.size(); ++i) {
|
||||||
ModelInstance *mi = mo->instances[i];
|
ArrangePolygon &&ap = get_arrange_poly(mo->instances[i]);
|
||||||
ArrangePolygon ap = mi->get_arrange_polygon();
|
|
||||||
ap.priority = 0;
|
|
||||||
ap.bed_idx = ap.translation.x() / stride;
|
|
||||||
|
|
||||||
ap.setter = [mi, stride](const ArrangePolygon &p) {
|
|
||||||
if (p.is_arranged()) {
|
|
||||||
auto t = p.translation; t.x() += p.bed_idx * stride;
|
|
||||||
mi->apply_arrange_result(t, p.rotation);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inst_sel[i] ?
|
inst_sel[i] ?
|
||||||
m_selected.emplace_back(std::move(ap)) :
|
m_selected.emplace_back(std::move(ap)) :
|
||||||
m_unselected.emplace_back(std::move(ap));
|
m_unselected.emplace_back(std::move(ap));
|
||||||
|
@ -1590,17 +1616,9 @@ struct Plater::priv
|
||||||
|
|
||||||
auto& wti = plater().updated_wipe_tower();
|
auto& wti = plater().updated_wipe_tower();
|
||||||
if (wti) {
|
if (wti) {
|
||||||
ArrangePolygon ap = wti.get_arrange_polygon();
|
ArrangePolygon &&ap = get_arrange_poly(&wti);
|
||||||
ap.bed_idx = ap.translation.x() / stride;
|
|
||||||
ap.priority = 1; // Wipe tower should be on physical bed
|
|
||||||
ap.setter = [&wti, stride](const ArrangePolygon &p) {
|
|
||||||
if (p.is_arranged()) {
|
|
||||||
auto t = p.translation; t.x() += p.bed_idx * stride;
|
|
||||||
wti.apply_arrange_result(t, p.rotation);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
sel.is_wipe_tower() ?
|
plater().get_selection().is_wipe_tower() ?
|
||||||
m_selected.emplace_back(std::move(ap)) :
|
m_selected.emplace_back(std::move(ap)) :
|
||||||
m_unselected.emplace_back(std::move(ap));
|
m_unselected.emplace_back(std::move(ap));
|
||||||
}
|
}
|
||||||
|
@ -1614,6 +1632,13 @@ struct Plater::priv
|
||||||
for (auto &p : m_unselected) p.translation(X) -= p.bed_idx * stride;
|
for (auto &p : m_unselected) p.translation(X) -= p.bed_idx * stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void prepare() override
|
||||||
|
{
|
||||||
|
wxGetKeyState(WXK_SHIFT) ? prepare_selected() : prepare_all();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Job::Job;
|
using Job::Job;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue