mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-18 22:31:13 -06:00
ENH: improve auto-arrange in several ways
1. reduce expansion of exclusion regions 2. expand extrusion calib regions to let them touch bed boundary, to greately simplify auto-arranging with avoidance option on 3. improve dist_for_BOTTOM_LEFT to allow objects be put left to exclusion regions temporarily 4. improve on_preload for better handling objects around exclusion regions. 5. improve debug tools 6. fix a bug with wipe tower estimation (don't estimate if wipe tower is explicitly disabled) 7. use larger y-overlap threshold to estimate rod height confliction better in per-object print ordering (now we use half the clearance radius) Change-Id: Iab29d47a072d8515f28a09855432f92fcffa8c5f (cherry picked from commit 3a4f242a3a6fd2f82dcc8306cde4d1cb107a5099)
This commit is contained in:
parent
17bc464bac
commit
5fa771c6cb
8 changed files with 59 additions and 35 deletions
|
@ -202,14 +202,20 @@ protected:
|
|||
// 1) Y distance of item corner to bed corner. Must be put above bed corner. (high weight)
|
||||
// 2) X distance of item corner to bed corner (low weight)
|
||||
// 3) item row occupancy (useful when rotation is enabled)
|
||||
// 4)需要允许往屏蔽区域的左边或下边去一点,不然很多物体可能认为摆不进去,实际上我们最后是可以做平移的
|
||||
double dist_for_BOTTOM_LEFT(Box ibb, const ClipperLib::IntPoint& origin_pack)
|
||||
{
|
||||
double dist_corner_y = ibb.minCorner().y() - origin_pack.y();
|
||||
double dist_corner_x = ibb.minCorner().x() - origin_pack.x();
|
||||
if (dist_corner_y < 0 || dist_corner_x<0)
|
||||
return LARGE_COST_TO_REJECT;
|
||||
double bindist = norm(dist_corner_y + 1 * dist_corner_x
|
||||
+ 1 * double(ibb.maxCorner().y() - ibb.minCorner().y())); // occupy as few rows as possible
|
||||
// occupy as few rows as possible if we have rotations
|
||||
double bindist = double(ibb.maxCorner().y() - ibb.minCorner().y());
|
||||
if (dist_corner_x >= 0 && dist_corner_y >= 0)
|
||||
bindist += dist_corner_y + 1 * dist_corner_x;
|
||||
else {
|
||||
if (dist_corner_x < 0) bindist += 10 * (-dist_corner_x);
|
||||
if (dist_corner_y < 0) bindist += 10 * (-dist_corner_y);
|
||||
}
|
||||
bindist = norm(bindist);
|
||||
return bindist;
|
||||
}
|
||||
|
||||
|
@ -513,13 +519,15 @@ public:
|
|||
m_pconf.on_preload = [this](const ItemGroup &items, PConfig &cfg) {
|
||||
if (items.empty()) return;
|
||||
|
||||
auto bb = sl::boundingBox(m_bin);
|
||||
auto binbb = sl::boundingBox(m_bin);
|
||||
// BBS: excluded region (virtual object but not wipe tower) should not affect final alignment
|
||||
bool all_is_excluded_region = std::all_of(items.begin(), items.end(), [](Item &itm) { return itm.is_virt_object && !itm.is_wipe_tower; });
|
||||
if (!all_is_excluded_region)
|
||||
cfg.alignment = PConfig::Alignment::DONT_ALIGN;
|
||||
else
|
||||
cfg.alignment = PConfig::Alignment::CENTER;
|
||||
|
||||
auto starting_point = cfg.starting_point == PConfig::Alignment::BOTTOM_LEFT ? bb.minCorner() : bb.center();
|
||||
auto starting_point = cfg.starting_point == PConfig::Alignment::BOTTOM_LEFT ? binbb.minCorner() : binbb.center();
|
||||
// if we have wipe tower, items should be arranged around wipe tower
|
||||
for (Item itm : items) {
|
||||
if (itm.is_wipe_tower) {
|
||||
|
@ -528,12 +536,16 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
cfg.object_function = [this, bb, starting_point](const Item& item, const ItemGroup& packed_items) {
|
||||
bool packed_are_excluded_region = std::all_of(packed_items.begin(), packed_items.end(), [](Item& itm) { return itm.is_virt_object && !itm.is_wipe_tower; });
|
||||
if(packed_are_excluded_region)
|
||||
return fixed_overfit_topright_sliding(objfunc(item, starting_point), bb);
|
||||
else
|
||||
return fixed_overfit(objfunc(item, starting_point), bb);
|
||||
cfg.object_function = [this, binbb, starting_point](const Item& item, const ItemGroup& packed_items) {
|
||||
// 在我们的摆盘中,没有天然的固定对象。固定对象只有:屏蔽区域、挤出补偿区域、料塔。
|
||||
// 对于屏蔽区域,摆入的对象仍然是可以向右上滑动的;
|
||||
// 对挤出料塔,摆入的对象不能滑动(必须围绕料塔)
|
||||
bool pack_around_wipe_tower = std::any_of(packed_items.begin(), packed_items.end(), [](Item& itm) { return itm.is_wipe_tower; });
|
||||
if(pack_around_wipe_tower)
|
||||
return fixed_overfit(objfunc(item, starting_point), binbb);
|
||||
else {
|
||||
return fixed_overfit_topright_sliding(objfunc(item, starting_point), binbb);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -611,16 +623,18 @@ template<> std::function<double(const Item&, const ItemGroup&)> AutoArranger<Box
|
|||
double score = std::get<0>(result);
|
||||
auto& fullbb = std::get<1>(result);
|
||||
|
||||
if (m_pconf.starting_point == PConfig::Alignment::BOTTOM_LEFT)
|
||||
{
|
||||
if (!sl::isInside(fullbb, m_bin))
|
||||
score += LARGE_COST_TO_REJECT;
|
||||
}
|
||||
else
|
||||
//if (m_pconf.starting_point == PConfig::Alignment::BOTTOM_LEFT)
|
||||
//{
|
||||
// if (!sl::isInside(fullbb, m_bin))
|
||||
// score += LARGE_COST_TO_REJECT;
|
||||
//}
|
||||
//else
|
||||
{
|
||||
double miss = Placer::overfit(fullbb, m_bin);
|
||||
miss = miss > 0 ? miss : 0;
|
||||
score += miss * miss;
|
||||
if (score > LARGE_COST_TO_REJECT)
|
||||
score = 1.5 * LARGE_COST_TO_REJECT;
|
||||
}
|
||||
|
||||
return score;
|
||||
|
|
|
@ -529,12 +529,9 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
|
|||
auto inter_min = std::max(ly1, ry1);
|
||||
auto inter_max = std::min(ly2, ry2);
|
||||
auto inter_y = inter_max - inter_min;
|
||||
inter_min = std::max(lx1, rx1);
|
||||
inter_max = std::min(lx2, rx2);
|
||||
auto inter_x = inter_max - inter_min;
|
||||
|
||||
// 如果y方向的重合超过轮廓的膨胀量,说明两个物体在一行,应该先打左边的物体,即先比较二者的x坐标。
|
||||
if (inter_y > scale_(1)) {
|
||||
if (inter_y > scale_(0.5 * print.config().extruder_clearance_radius.value)) {
|
||||
if (std::max(rx1 - lx2, lx1 - rx2) < unsafe_dist) {
|
||||
if (lx1 > rx1) {
|
||||
left_right_pair.insert({j, i});
|
||||
|
@ -555,7 +552,8 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
|
|||
}
|
||||
else if (l.height > hc2 && l.height > r.height && l.arrange_score<r.arrange_score) {
|
||||
// 如果当前物体的高度超过滑杆,且比r高,就给它加一点代价,尽量让高的物体后打(只有物体高度超过滑杆时才有必要按高度来)
|
||||
l.arrange_score = std::max(l.arrange_score, r.arrange_score + bed_width/2);
|
||||
if (l.arrange_score < r.arrange_score)
|
||||
l.arrange_score = r.arrange_score + 10;
|
||||
BOOST_LOG_TRIVIAL(debug) << "height>hc2, print_instance " << inst.print_instance->model_instance->get_object()->name
|
||||
<< ", right=" << r.print_instance->model_instance->get_object()->name << ", l.score: " << l.arrange_score
|
||||
<< ", r.score: " << r.arrange_score;
|
||||
|
@ -563,7 +561,6 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
|
|||
}
|
||||
}
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(debug) << "bed width: " << bed_width << ", unsafe_dist:" << unsafe_dist;
|
||||
// 多做几次代价传播,因为前一次有些值没有更新。
|
||||
// TODO 更好的办法是建立一颗树,一步到位。不过我暂时没精力搞,先就这样吧
|
||||
for (int k=0;k<5;k++)
|
||||
|
@ -571,14 +568,15 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
|
|||
auto &l = print_instance_with_bounding_box[p(0)];
|
||||
auto &r = print_instance_with_bounding_box[p(1)];
|
||||
if(r.arrange_score<l.arrange_score)
|
||||
r.arrange_score = l.arrange_score + bed_width/2;
|
||||
r.arrange_score = l.arrange_score + 10;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "bed width: " << unscale_(bed_width) << ", unsafe_dist:" << unscale_(unsafe_dist) << ", height_to_lid: " << unscale_(hc1) << ", height_to_rod:" << unscale_(hc2) << ", final dependency:";
|
||||
for (auto p : left_right_pair) {
|
||||
auto &l = print_instance_with_bounding_box[p(0)];
|
||||
auto &r = print_instance_with_bounding_box[p(1)];
|
||||
BOOST_LOG_TRIVIAL(debug) << "print_instance " << l.print_instance->model_instance->get_object()->name << "(" << l.arrange_score << ")"
|
||||
<< " -> " << r.print_instance->model_instance->get_object()->name << "(" << r.arrange_score << ")";
|
||||
BOOST_LOG_TRIVIAL(debug) << "print_instance " << I18N::translate(l.print_instance->model_instance->get_object()->name) << "(" << l.arrange_score << ")"
|
||||
<< " -> " << I18N::translate(r.print_instance->model_instance->get_object()->name) << "(" << r.arrange_score << ")";
|
||||
}
|
||||
// sort the print instance
|
||||
std::sort(print_instance_with_bounding_box.begin(), print_instance_with_bounding_box.end(),
|
||||
|
|
|
@ -75,6 +75,7 @@ static constexpr double BRIDGE_INFILL_MARGIN = 1;
|
|||
//FIXME Better to use an inline function with an explicit return type.
|
||||
//inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); }
|
||||
#define scale_(val) ((val) / SCALING_FACTOR)
|
||||
#define unscale_(val) ((val) * SCALING_FACTOR)
|
||||
|
||||
//BBS: BBS only support relative E and can't been changed by user at the moment. because
|
||||
//BBS need to support skip object when printing.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue