FIX: don't rotate an object if it can't fit

even if "align to Y axis" is on.

github: #5794
Change-Id: I460003588a98aa9ff52fde1dc609d1ed54ea72c8
This commit is contained in:
Arthur 2025-01-27 15:05:18 +08:00 committed by lane.wei
parent 742efe2e3d
commit 156f390eea
4 changed files with 44 additions and 31 deletions

View File

@ -86,6 +86,7 @@ public:
bool is_virt_object{ false };
bool is_wipe_tower{ false };
bool has_tried_with_excluded{ false };
std::vector<double> allowed_rotations{0.};
/// The type of the shape which was handed over as the template argument.
using ShapeType = RawShape;

View File

@ -129,6 +129,9 @@ struct NfpPConfig {
//BBS: sort function for selector
std::function<bool(_Item<RawShape>& i1, _Item<RawShape>& i2)> sortfunc;
std::function<void(const std::string &)> progressFunc = {};
//BBS: excluded region for V4 bed
std::vector<_Item<RawShape> > m_excluded_regions;
_ItemGroup<RawShape> m_excluded_items;
@ -686,9 +689,7 @@ private:
using Edges = EdgeCache<RawShape>;
template<class Range = ConstItemRange<typename Base::DefaultIter>>
PackResult _trypack(
Item& item,
const Range& remaining = Range()) {
PackResult _trypack(Item& item, const Range& remaining = Range()) {
PackResult ret;
@ -772,7 +773,7 @@ private:
setInitialPosition(item);
auto best_tr = item.translation();
auto best_rot = item.rotation();
best_overfit = overfit(item.transformedShape(), bin_) + overlapWithVirtObject();
best_overfit = std::numeric_limits<double>::max();
// try normal inflation first, then 0 inflation if not fit. See STUDIO-5566.
// Note for by-object printing, bed is expanded by -config_.bed_shrink.x().
@ -780,7 +781,7 @@ private:
Coord inflations[2]={inflation_back, std::abs(config_.bed_shrink.x())};
for (size_t i = 0; i < 2; i++) {
item.inflation(inflations[i]);
for (auto rot : config_.rotations) {
for (auto rot : item.allowed_rotations) {
item.translation(initial_tr);
item.rotation(initial_rot + rot);
setInitialPosition(item);
@ -789,6 +790,10 @@ private:
best_overfit = of;
best_tr = item.translation();
best_rot = item.rotation();
if (best_overfit <= 0) {
config_.progressFunc("First object can fit with rot="+std::to_string(rot));
break;
}
}
}
can_pack = best_overfit <= 0;
@ -805,7 +810,7 @@ private:
Pile merged_pile = merged_pile_;
for(auto rot : config_.rotations) {
for(auto rot : item.allowed_rotations) {
item.translation(initial_tr);
item.rotation(initial_rot + rot);
@ -990,6 +995,7 @@ private:
final_rot = initial_rot + rot;
can_pack = true;
global_score = best_score;
break;
}
}

View File

@ -88,7 +88,8 @@ public:
for (auto it = store_.begin(); it != store_.end(); ++it) {
std::stringstream ss;
ss << "initial order: " << it->get().name << ", p=" << it->get().priority() << ", bed_temp=" << it->get().bed_temp << ", height=" << it->get().height
<< ", area=" << it->get().area();
<< ", area=" << it->get().area() << ", allowed_rotations=";
for(auto r: it->get().allowed_rotations) ss << r << ", ";
if (this->unfitindicator_)
this->unfitindicator_(ss.str());
}

View File

@ -682,6 +682,8 @@ public:
if (stopcond) m_pck.stopCondition(stopcond);
m_pconf.progressFunc = [](const std::string& name) { BOOST_LOG_TRIVIAL(debug) << "arrange progress in NFP: " + name; };
m_pconf.sortfunc= [&params](Item& i1, Item& i2) {
int p1 = i1.priority(), p2 = i2.priority();
if (p1 != p2)
@ -859,44 +861,27 @@ void _arrange(
std::function<void(unsigned,std::string)> progressfn,
std::function<bool()> stopfn)
{
// Integer ceiling the min distance from the bed perimeters
coord_t md = params.min_obj_distance;
md = md / 2;
auto corrected_bin = bin;
//sl::offset(corrected_bin, md);
ArrangeParams mod_params = params;
mod_params.min_obj_distance = 0; // items are already inflated
AutoArranger<BinT> arranger{corrected_bin, mod_params, progressfn, stopfn};
remove_large_items(excludes, corrected_bin);
// If there is something on the plate
if (!excludes.empty()) arranger.preload(excludes);
std::vector<std::reference_wrapper<Item>> inp;
inp.reserve(shapes.size() + excludes.size());
for (auto &itm : shapes ) inp.emplace_back(itm);
for (auto &itm : excludes) inp.emplace_back(itm);
ArrangeParams mod_params = params;
mod_params.min_obj_distance = 0; // items are already inflated
// Use the minimum bounding box rotation as a starting point.
// TODO: This only works for convex hull. If we ever switch to concave
// polygon nesting, a convex hull needs to be calculated.
if (params.align_to_y_axis) {
for (auto &itm : shapes) {
itm.allowed_rotations = {0.0};
// only rotate the object if its long axis is significanly larger than its short axis (more than 10%)
try {
auto bbox = minAreaBoundingBox<ExPolygon, TCompute<ExPolygon>, boost::rational<LargeInt>>(itm.transformedShape());
auto w = bbox.width(), h=bbox.height();
if (w > h * 1.1 || h > w * 1.1) { itm.rotate(bbox.angleToX() + PI / 2); }
auto w = bbox.width(), h = bbox.height();
if (w > h * 1.1 || h > w * 1.1) { itm.allowed_rotations = {bbox.angleToX() + PI / 2, 0.0};
}
} catch (const std::exception &e) {
// min_area_boundingbox_rotation may throw exception of dividing 0 if the object is already perfectly aligned to X
BOOST_LOG_TRIVIAL(error) << "arranging min_area_boundingbox_rotation fails, msg=" << e.what();
}
}
}
else if (params.allow_rotations) {
} else if (params.allow_rotations) {
for (auto &itm : shapes) {
auto angle = min_area_boundingbox_rotation(itm.transformedShape());
BOOST_LOG_TRIVIAL(debug) << itm.name << " min_area_boundingbox_rotation=" << angle << ", original angle=" << itm.rotation();
@ -910,9 +895,29 @@ void _arrange(
itm.rotate(fit_into_box_rotation(itm.transformedShape(), bin));
}
}
itm.allowed_rotations = {0., PI / 4., PI / 2, 3. * PI / 4.};
}
}
// Integer ceiling the min distance from the bed perimeters
coord_t md = params.min_obj_distance / 2;
auto corrected_bin = bin;
//sl::offset(corrected_bin, md);
AutoArranger<BinT> arranger{corrected_bin, mod_params, progressfn, stopfn};
remove_large_items(excludes, corrected_bin);
// If there is something on the plate
if (!excludes.empty()) arranger.preload(excludes);
std::vector<std::reference_wrapper<Item>> inp;
inp.reserve(shapes.size() + excludes.size());
for (auto &itm : shapes ) inp.emplace_back(itm);
for (auto &itm : excludes) inp.emplace_back(itm);
arranger(inp.begin(), inp.end());
for (Item &itm : inp) itm.inflation(0);
}