mirror of
https://git.mirrors.martin98.com/https://github.com/bambulab/BambuStudio.git
synced 2025-08-20 20:09:10 +08:00
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:
parent
742efe2e3d
commit
156f390eea
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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= [¶ms](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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user