FIX: auto-arrange may crash due to clipper

1. Use nlopt and clipper offset togather seems not stable, very easy to
crash. We do the offset outside nlopt now.
2. Fix a bug with finalAlign where objects may be translated to overlap
   with excluded region.
3. change the words of support_expansion

Change-Id: I22e37b20e4ae16f47bde206de90845616e4cefad
(cherry picked from commit 1c26e5d2862fd3f3292971b5c749420bfb2cdf0e)
This commit is contained in:
Arthur 2022-11-25 21:56:08 +08:00 committed by Lane.Wei
parent 95ed039879
commit 4eba8a2a2d
6 changed files with 47 additions and 55 deletions

View File

@ -1034,51 +1034,50 @@ private:
if (!item.is_virt_object) if (!item.is_virt_object)
bb = sl::boundingBox(item.boundingBox(), bb); bb = sl::boundingBox(item.boundingBox(), bb);
// BBS TODO assume the nonprefered regions are at the bottom left corner // if move to center is infeasible, move to topright corner instead
Box bin_reduced = bbin; auto alignment = config_.alignment;
for (const auto& region : config_.m_nonprefered_regions) if (!config_.m_excluded_regions.empty() && alignment== Config::Alignment::CENTER) {
{ Box bb2 = bb;
Box bb1 = region.boundingBox(); auto d = bbin.center() - bb2.center();
if (bb1.maxCorner().y()<bbin.height()/5 && d.x() = std::max(d.x(), 0);
bbin.height() - bb1.maxCorner().y() > bb.height() && bb.height()>bbin.height()-2*bb1.maxCorner().y()) { d.y() = std::max(d.y(), 0);
// could use a tighter bound by moving bed center higher bb2.minCorner() += d;
bin_reduced.minCorner().y() = bb1.maxCorner().y(); bb2.maxCorner() += d;
continue; for (auto& region : config_.m_excluded_regions) {
auto region_bb = region.boundingBox();
if (bb2.intersection(region_bb).area()>0) {
alignment = Config::Alignment::TOP_RIGHT;
break;
} }
if (bb1.maxCorner().x()<bbin.width()/5 &&
bbin.width() - bb1.maxCorner().x() > bb.width() && bb.width()>bbin.width()-2*bb1.maxCorner().x()) {
// could use a tighter bound
bin_reduced.minCorner().x() = bb1.maxCorner().x();
continue;
} }
} }
Vertex ci, cb; Vertex ci, cb;
switch(config_.alignment) { switch(alignment) {
case Config::Alignment::CENTER: { case Config::Alignment::CENTER: {
ci = bb.center(); ci = bb.center();
cb = bin_reduced.center(); cb = bbin.center();
break; break;
} }
case Config::Alignment::BOTTOM_LEFT: { case Config::Alignment::BOTTOM_LEFT: {
ci = bb.minCorner(); ci = bb.minCorner();
cb = bin_reduced.minCorner(); cb = bbin.minCorner();
break; break;
} }
case Config::Alignment::BOTTOM_RIGHT: { case Config::Alignment::BOTTOM_RIGHT: {
ci = {getX(bb.maxCorner()), getY(bb.minCorner())}; ci = {getX(bb.maxCorner()), getY(bb.minCorner())};
cb = {getX(bin_reduced.maxCorner()), getY(bin_reduced.minCorner())}; cb = {getX(bbin.maxCorner()), getY(bbin.minCorner())};
break; break;
} }
case Config::Alignment::TOP_LEFT: { case Config::Alignment::TOP_LEFT: {
ci = {getX(bb.minCorner()), getY(bb.maxCorner())}; ci = {getX(bb.minCorner()), getY(bb.maxCorner())};
cb = {getX(bin_reduced.minCorner()), getY(bin_reduced.maxCorner())}; cb = {getX(bbin.minCorner()), getY(bbin.maxCorner())};
break; break;
} }
case Config::Alignment::TOP_RIGHT: { case Config::Alignment::TOP_RIGHT: {
ci = bb.maxCorner(); ci = bb.maxCorner();
cb = bin_reduced.maxCorner(); cb = bbin.maxCorner();
break; break;
} }
default: ; // DONT_ALIGN default: ; // DONT_ALIGN

View File

@ -137,8 +137,7 @@ static double fixed_overfit(const std::tuple<double, Box>& result, const Box &bi
} }
// useful for arranging big circle objects // useful for arranging big circle objects
template<class PConf> static double fixed_overfit_topright_sliding(const std::tuple<double, Box> &result, const Box &binbb, const std::vector<Box> &excluded_boxes)
static double fixed_overfit_topright_sliding(const std::tuple<double, Box> &result, const Box &binbb, const PConf &config)
{ {
double score = std::get<0>(result); double score = std::get<0>(result);
Box pilebb = std::get<1>(result); Box pilebb = std::get<1>(result);
@ -154,14 +153,8 @@ static double fixed_overfit_topright_sliding(const std::tuple<double, Box> &resu
if (diff > 0) score += diff; if (diff > 0) score += diff;
// excluded regions and nonprefered regions should not intersect the translated pilebb // excluded regions and nonprefered regions should not intersect the translated pilebb
for (auto &region : config.m_excluded_regions) { for (auto &bb : excluded_boxes) {
Box bb = region.boundingBox(); auto area_ = pilebb.intersection(bb).area();
auto area_ = bb.intersection(pilebb).area();
if (area_ > 0) score += area_;
}
for (auto &region : config.m_nonprefered_regions) {
Box bb = region.boundingBox();
auto area_ = bb.intersection(pilebb).area();
if (area_ > 0) score += area_; if (area_ > 0) score += area_;
} }
@ -203,6 +196,7 @@ protected:
Box m_pilebb; // The bounding box of the merged pile. Box m_pilebb; // The bounding box of the merged pile.
ItemGroup m_remaining; // Remaining items ItemGroup m_remaining; // Remaining items
ItemGroup m_items; // allready packed items ItemGroup m_items; // allready packed items
std::vector<Box> m_excluded_and_extruCali_regions; // excluded and extrusion calib regions
size_t m_item_count = 0; // Number of all items to be packed size_t m_item_count = 0; // Number of all items to be packed
ArrangeParams params; ArrangeParams params;
@ -489,6 +483,14 @@ public:
m_norm = std::sqrt(m_bin_area); m_norm = std::sqrt(m_bin_area);
fill_config(m_pconf, params); fill_config(m_pconf, params);
this->params = params; this->params = params;
for (auto& region : m_pconf.m_excluded_regions) {
Box bb = region.boundingBox();
m_excluded_and_extruCali_regions.emplace_back(bb);
}
for (auto& region : m_pconf.m_nonprefered_regions) {
Box bb = region.boundingBox();
m_excluded_and_extruCali_regions.emplace_back(bb);
}
// Set up a callback that is called just before arranging starts // Set up a callback that is called just before arranging starts
// This functionality is provided by the Nester class (m_pack). // This functionality is provided by the Nester class (m_pack).
@ -526,17 +528,6 @@ public:
m_pconf.object_function = get_objfn(); m_pconf.object_function = get_objfn();
auto bbox2expoly = [](Box bb) {
ExPolygon bin_poly;
auto c0 = bb.minCorner();
auto c1 = bb.maxCorner();
bin_poly.contour.points.emplace_back(c0);
bin_poly.contour.points.emplace_back(c1.x(), c0.y());
bin_poly.contour.points.emplace_back(c1);
bin_poly.contour.points.emplace_back(c0.x(), c1.y());
return bin_poly;
};
// preload fixed items (and excluded regions) on plate // preload fixed items (and excluded regions) on plate
m_pconf.on_preload = [this](const ItemGroup &items, PConfig &cfg) { m_pconf.on_preload = [this](const ItemGroup &items, PConfig &cfg) {
if (items.empty()) return; if (items.empty()) return;
@ -558,7 +549,7 @@ public:
} }
} }
cfg.object_function = [this, binbb, starting_point, &cfg](const Item &item, const ItemGroup &packed_items) { cfg.object_function = [this, binbb, starting_point](const Item &item, const ItemGroup &packed_items) {
// 在我们的摆盘中,没有天然的固定对象。固定对象只有:屏蔽区域、挤出补偿区域、料塔。 // 在我们的摆盘中,没有天然的固定对象。固定对象只有:屏蔽区域、挤出补偿区域、料塔。
// 对于屏蔽区域,摆入的对象仍然是可以向右上滑动的; // 对于屏蔽区域,摆入的对象仍然是可以向右上滑动的;
// 对挤出料塔,摆入的对象不能滑动(必须围绕料塔) // 对挤出料塔,摆入的对象不能滑动(必须围绕料塔)
@ -566,7 +557,7 @@ public:
if(pack_around_wipe_tower) if(pack_around_wipe_tower)
return fixed_overfit(objfunc(item, starting_point), binbb); return fixed_overfit(objfunc(item, starting_point), binbb);
else { else {
return fixed_overfit_topright_sliding(objfunc(item, starting_point), binbb, cfg); return fixed_overfit_topright_sliding(objfunc(item, starting_point), binbb, m_excluded_and_extruCali_regions);
} }
}; };
}; };

View File

@ -2588,9 +2588,9 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionFloat(2.5)); def->set_default_value(new ConfigOptionFloat(2.5));
def = this->add("support_expansion", coFloat); def = this->add("support_expansion", coFloat);
def->label = L("Support xy expansion distance"); def->label = L("Normal Support expansion");
def->category = L("Support"); def->category = L("Support");
def->tooltip = L("Expanding (+) or shrinking (-) support volume"); def->tooltip = L("Expand (+) or shrink (-) the horizontal span of normal support");
def->sidetext = L("mm"); def->sidetext = L("mm");
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0)); def->set_default_value(new ConfigOptionFloat(0));

View File

@ -540,15 +540,15 @@ void ArrangeJob::process()
// 屏蔽区域只需要膨胀brim宽度防止brim长过去挤出标定区域不需要膨胀brim可以长过去。 // 屏蔽区域只需要膨胀brim宽度防止brim长过去挤出标定区域不需要膨胀brim可以长过去。
// 以前我们认为还需要膨胀clearance_radius/2这其实是不需要的因为这些区域并不会真的摆放物体 // 以前我们认为还需要膨胀clearance_radius/2这其实是不需要的因为这些区域并不会真的摆放物体
// 其他物体的膨胀轮廓是可以跟它们重叠的。 // 其他物体的膨胀轮廓是可以跟它们重叠的。
double scaled_exclusion_gap = scale_(1);
std::for_each(m_unselected.begin(), m_unselected.end(), [&](auto &ap) { std::for_each(m_unselected.begin(), m_unselected.end(), [&](auto &ap) {
ap.inflation = !ap.is_virt_object ? ap.inflation = !ap.is_virt_object ?
params.min_obj_distance / 2 : params.min_obj_distance / 2 :
(ap.is_extrusion_cali_object ? 0 : scaled(params.brim_skirt_distance)); (ap.is_extrusion_cali_object ? 0 : scaled_exclusion_gap);
}); });
partplate_list.preprocess_exclude_areas(params.excluded_regions, 1); partplate_list.preprocess_exclude_areas(params.excluded_regions, 1, scaled_exclusion_gap);
partplate_list.preprocess_exclude_areas(params.nonprefered_regions, 1);
// shrink bed by moving to center by dist // shrink bed by moving to center by dist
Points bedpts = get_bed_shape(*m_plater->config()); Points bedpts = get_bed_shape(*m_plater->config());

View File

@ -3557,7 +3557,7 @@ bool PartPlateList::preprocess_arrange_polygon_other_locked(int obj_index, int i
return locked; return locked;
} }
bool PartPlateList::preprocess_exclude_areas(arrangement::ArrangePolygons& unselected, int num_plates) bool PartPlateList::preprocess_exclude_areas(arrangement::ArrangePolygons& unselected, int num_plates, float inflation)
{ {
bool added = false; bool added = false;
@ -3585,6 +3585,7 @@ bool PartPlateList::preprocess_exclude_areas(arrangement::ArrangePolygons& unsel
ret.bed_idx = j; ret.bed_idx = j;
ret.height = 1; ret.height = 1;
ret.name = "ExcludedRegion" + std::to_string(index); ret.name = "ExcludedRegion" + std::to_string(index);
ret.inflation = inflation;
unselected.emplace_back(std::move(ret)); unselected.emplace_back(std::move(ret));
} }
@ -3595,7 +3596,7 @@ bool PartPlateList::preprocess_exclude_areas(arrangement::ArrangePolygons& unsel
return added; return added;
} }
bool PartPlateList::preprocess_nonprefered_areas(arrangement::ArrangePolygons& regions, int num_plates) bool PartPlateList::preprocess_nonprefered_areas(arrangement::ArrangePolygons& regions, int num_plates, float inflation)
{ {
bool added = false; bool added = false;
@ -3619,6 +3620,7 @@ bool PartPlateList::preprocess_nonprefered_areas(arrangement::ArrangePolygons& r
ret.bed_idx = j; ret.bed_idx = j;
ret.height = 1; ret.height = 1;
ret.name = "NonpreferedRegion" + std::to_string(index); ret.name = "NonpreferedRegion" + std::to_string(index);
ret.inflation = inflation;
regions.emplace_back(std::move(ret)); regions.emplace_back(std::move(ret));
} }

View File

@ -625,8 +625,8 @@ public:
//preprocess an arrangement::ArrangePolygon, return true if it is in a locked plate //preprocess an arrangement::ArrangePolygon, return true if it is in a locked plate
bool preprocess_arrange_polygon(int obj_index, int instance_index, arrangement::ArrangePolygon& arrange_polygon, bool selected); bool preprocess_arrange_polygon(int obj_index, int instance_index, arrangement::ArrangePolygon& arrange_polygon, bool selected);
bool preprocess_arrange_polygon_other_locked(int obj_index, int instance_index, arrangement::ArrangePolygon& arrange_polygon, bool selected); bool preprocess_arrange_polygon_other_locked(int obj_index, int instance_index, arrangement::ArrangePolygon& arrange_polygon, bool selected);
bool preprocess_exclude_areas(arrangement::ArrangePolygons& unselected, int num_plates = 16); bool preprocess_exclude_areas(arrangement::ArrangePolygons& unselected, int num_plates = 16, float inflation = 0);
bool preprocess_nonprefered_areas(arrangement::ArrangePolygons& regions, int num_plates = 1); bool preprocess_nonprefered_areas(arrangement::ArrangePolygons& regions, int num_plates = 1, float inflation=0);
void postprocess_bed_index_for_selected(arrangement::ArrangePolygon& arrange_polygon); void postprocess_bed_index_for_selected(arrangement::ArrangePolygon& arrange_polygon);
void postprocess_bed_index_for_unselected(arrangement::ArrangePolygon& arrange_polygon); void postprocess_bed_index_for_unselected(arrangement::ArrangePolygon& arrange_polygon);