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_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)
|
||||
{
|
||||
return double(val) / m_norm;
|
||||
|
@ -318,6 +321,7 @@ public:
|
|||
m_pilebb = sl::boundingBox(merged_pile);
|
||||
|
||||
m_rtree.clear();
|
||||
// m_preload_idx.clear();
|
||||
m_smallsrtree.clear();
|
||||
|
||||
// We will treat big items (compared to the print bed) differently
|
||||
|
@ -341,7 +345,7 @@ public:
|
|||
}
|
||||
|
||||
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)...);
|
||||
}
|
||||
|
||||
|
@ -358,19 +362,25 @@ public:
|
|||
for(unsigned idx = 0; idx < fixeditems.size(); ++idx) {
|
||||
Item& itm = fixeditems[idx];
|
||||
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);
|
||||
}
|
||||
|
||||
bool is_colliding(const Item& item) {
|
||||
if(m_rtree.empty()) return false;
|
||||
std::vector<SpatElement> result;
|
||||
m_rtree.query(bgi::intersects(item.boundingBox()),
|
||||
std::back_inserter(result));
|
||||
return !result.empty();
|
||||
}
|
||||
// int is_colliding(const Item& item) {
|
||||
// size_t bedidx = item.binId() < 0 ? 0u : size_t(item.binId());
|
||||
// if (m_preload_idx.size() <= bedidx || m_preload_idx[bedidx].empty())
|
||||
// return false;
|
||||
|
||||
// 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()
|
||||
|
@ -534,24 +544,21 @@ void _arrange(
|
|||
++it : it = excludes.erase(it);
|
||||
|
||||
// If there is something on the plate
|
||||
if(!excludes.empty())
|
||||
{
|
||||
arranger.preload(excludes);
|
||||
auto binbb = sl::boundingBox(corrected_bin);
|
||||
if (!excludes.empty()) {
|
||||
arranger.preload(excludes);
|
||||
// auto binbb = sl::boundingBox(corrected_bin);
|
||||
|
||||
// Try to put the first item to the center, as the arranger
|
||||
// will not do this for us.
|
||||
for (Item &itm : shapes) {
|
||||
auto ibb = itm.boundingBox();
|
||||
auto d = binbb.center() - ibb.center();
|
||||
itm.translate(d);
|
||||
// // Try to put the first item to the center, as the arranger
|
||||
// // will not do this for us.
|
||||
// for (Item &itm : shapes) {
|
||||
// auto ibb = itm.boundingBox();
|
||||
// auto d = binbb.center() - ibb.center();
|
||||
// itm.translate(d);
|
||||
// itm.binId(UNARRANGED);
|
||||
|
||||
if (!arranger.is_colliding(itm)) {
|
||||
itm.markAsFixed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (!arranger.is_colliding(itm)) { itm.markAsFixed(); break; }
|
||||
// }
|
||||
}
|
||||
|
||||
std::vector<std::reference_wrapper<Item>> inp;
|
||||
inp.reserve(shapes.size() + excludes.size());
|
||||
|
|
|
@ -1421,8 +1421,9 @@ struct Plater::priv
|
|||
wxQueueEvent(this, evt);
|
||||
}
|
||||
|
||||
priv &plater() { return *m_plater; }
|
||||
bool was_canceled() const { return m_canceled.load(); }
|
||||
priv & plater() { return *m_plater; }
|
||||
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
|
||||
virtual void prepare() {}
|
||||
|
@ -1537,51 +1538,76 @@ struct Plater::priv
|
|||
|
||||
ArrangePolygons m_selected, m_unselected;
|
||||
|
||||
protected:
|
||||
|
||||
void prepare() override
|
||||
{
|
||||
// Get the selection map
|
||||
Selection& sel = plater().get_selection();
|
||||
const Selection::ObjectIdxsToInstanceIdxsMap &selmap =
|
||||
sel.get_content();
|
||||
|
||||
Model &model = plater().model;
|
||||
// clear m_selected and m_unselected, reserve space for next usage
|
||||
void clear_input() {
|
||||
const Model &model = plater().model;
|
||||
|
||||
size_t count = 0; // To know how much space to reserve
|
||||
for (auto obj : model.objects) count += obj->instances.size();
|
||||
|
||||
m_selected.clear(), m_unselected.clear();
|
||||
m_selected.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();
|
||||
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
|
||||
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];
|
||||
|
||||
std::vector<bool> inst_sel(mo->instances.size(), false);
|
||||
|
||||
if (oit != selmap.end())
|
||||
for (auto inst_id : oit->second) inst_sel[inst_id] = true;
|
||||
if (instlist)
|
||||
for (auto inst_id : *instlist) inst_sel[inst_id] = true;
|
||||
|
||||
for (size_t i = 0; i < inst_sel.size(); ++i) {
|
||||
ModelInstance *mi = mo->instances[i];
|
||||
ArrangePolygon ap = mi->get_arrange_polygon();
|
||||
ap.priority = 0;
|
||||
ap.bed_idx = ap.translation.x() / stride;
|
||||
ArrangePolygon &&ap = get_arrange_poly(mo->instances[i]);
|
||||
|
||||
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] ?
|
||||
m_selected.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();
|
||||
if (wti) {
|
||||
ArrangePolygon ap = wti.get_arrange_polygon();
|
||||
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);
|
||||
}
|
||||
};
|
||||
ArrangePolygon &&ap = get_arrange_poly(&wti);
|
||||
|
||||
sel.is_wipe_tower() ?
|
||||
plater().get_selection().is_wipe_tower() ?
|
||||
m_selected.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;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void prepare() override
|
||||
{
|
||||
wxGetKeyState(WXK_SHIFT) ? prepare_selected() : prepare_all();
|
||||
}
|
||||
|
||||
public:
|
||||
using Job::Job;
|
||||
|
||||
|
|
Loading…
Reference in a new issue