FIX: avoid arrange to nonprefered region

Previously we assume the NFP of exclude regions are rectangle, which was
not always right. Now we calculate the NFP and find a best new position
to shift.

Change-Id: I02c075603cf71dd3c9146d7ac7a6706c0f850669
(cherry picked from commit 713ebd666c90d5dcfaf89914c37d211e9a470e99)
This commit is contained in:
manch1n 2023-04-11 16:49:02 +08:00 committed by Lane.Wei
parent 56f1a49232
commit f49c151611
5 changed files with 63 additions and 65 deletions

View file

@ -1099,42 +1099,43 @@ private:
auto d = cb - ci; auto d = cb - ci;
// BBS make sure the item won't clash with excluded regions // BBS make sure the item won't clash with excluded regions
if(1) // do we have wipe tower after arranging?
{ std::set<int> extruders;
// do we have wipe tower after arranging? for (const Item& item : items_) {
std::set<int> extruders; if (!item.is_virt_object) { extruders.insert(item.extrude_ids.begin(), item.extrude_ids.end()); }
for (const Item& item : items_) { }
if (!item.is_virt_object) { extruders.insert(item.extrude_ids.begin(), item.extrude_ids.end()); } bool need_wipe_tower = extruders.size() > 1;
}
bool need_wipe_tower = extruders.size() > 1;
std::vector<RawShape> objs,excludes; std::vector<RawShape> objs,excludes;
for (const Item &item : items_) { for (const Item &item : items_) {
if (item.isFixed()) continue; if (item.isFixed()) continue;
objs.push_back(item.transformedShape()); objs.push_back(item.transformedShape());
} }
if (objs.empty())
return;
{ // find a best position inside NFP of fixed items (excluded regions), so the center of pile is cloest to bed center
RawShape objs_convex_hull = sl::convexHull(objs); RawShape objs_convex_hull = sl::convexHull(objs);
if (objs.size() != 0) { for (const Item &item : config_.m_excluded_regions) { excludes.push_back(item.transformedShape()); }
for (const Item &item : config_.m_excluded_regions) { excludes.push_back(item.transformedShape()); } for (const Item &item : items_) {
for (const Item &item : items_) { if (item.isFixed()) {
if (item.isFixed()) { if (!(item.is_wipe_tower && !need_wipe_tower))
if (!(item.is_wipe_tower && !need_wipe_tower)) excludes.push_back(item.transformedShape());
excludes.push_back(item.transformedShape());
}
} }
Box binbb = sl::boundingBox(bin_); }
auto allowShifts = calcnfp(objs_convex_hull, excludes, binbb, Lvl<MaxNfpLevel::value>());
int maxAllowShiftX = 0; auto nfps = calcnfp(objs_convex_hull, excludes, bbin, Lvl<MaxNfpLevel::value>());
int maxAllowShiftY = 0; if (nfps.empty()) {
for (const auto &shiftShape : allowShifts) { return;
auto shiftBox = sl::boundingBox(shiftShape); // assume that the exclude region is box so that the nfp is box. }
maxAllowShiftX = shiftBox.width(); Item objs_convex_hull_item(objs_convex_hull);
maxAllowShiftY = shiftBox.height(); Vertex objs_convex_hull_ref = objs_convex_hull_item.referenceVertex();
} Vertex diff = objs_convex_hull_ref - sl::boundingBox(objs_convex_hull).center();
int finalShiftX = std::min(std::abs(maxAllowShiftX), std::abs(d.x())); Vertex ref_aligned = cb + diff; // reference point when pile center aligned with bed center
int finalShiftY = std::min(std::abs(maxAllowShiftY), std::abs(d.y())); bool ref_aligned_is_ok = std::any_of(nfps.begin(), nfps.end(), [&ref_aligned](auto& nfp) {return sl::isInside(ref_aligned, nfp); });
d.x() = d.x() > 0 ? finalShiftX : -finalShiftX; if (!ref_aligned_is_ok) {
d.y() = d.y() > 0 ? finalShiftY : -finalShiftY; // ref_aligned is not good, then find a nearest point on nfp boundary
Vertex ref_projected = projection_onto(nfps, ref_aligned);
d += (ref_projected - ref_aligned);
} }
} }
for(Item& item : items_) for(Item& item : items_)

View file

@ -183,6 +183,25 @@ bool overlaps(const ExPolygons& expolys1, const ExPolygons& expolys2)
} }
} }
return false; return false;
}
Point projection_onto(const ExPolygons& polygons, const Point& from)
{
Point projected_pt;
double min_dist = std::numeric_limits<double>::max();
for (const auto& poly : polygons) {
for (int i = 0; i < poly.num_contours(); i++) {
Point p = from.projection_onto(poly.contour_or_hole(i));
double dist = (from - p).cast<double>().squaredNorm();
if (dist < min_dist) {
projected_pt = p;
min_dist = dist;
}
}
}
return projected_pt;
} }
void ExPolygon::simplify_p(double tolerance, Polygons* polygons) const void ExPolygon::simplify_p(double tolerance, Polygons* polygons) const

View file

@ -453,6 +453,8 @@ bool expolygons_match(const ExPolygon &l, const ExPolygon &r);
bool overlaps(const ExPolygons& expolys1, const ExPolygons& expolys2); bool overlaps(const ExPolygons& expolys1, const ExPolygons& expolys2);
Point projection_onto(const ExPolygons& expolys, const Point& pt);
BoundingBox get_extents(const ExPolygon &expolygon); BoundingBox get_extents(const ExPolygon &expolygon);
BoundingBox get_extents(const ExPolygons &expolygons); BoundingBox get_extents(const ExPolygons &expolygons);
BoundingBox get_extents_rotated(const ExPolygon &poly, double angle); BoundingBox get_extents_rotated(const ExPolygon &poly, double angle);

View file

@ -625,32 +625,11 @@ static bool is_inside_ex(const ExPolygons &polygons, const Point &pt)
return false; return false;
} }
Point projection_onto_ex(const ExPolygons& polygons, Point from)
{
profiler.tic();
Point projected_pt;
double min_dist = std::numeric_limits<double>::max();
for (auto poly : polygons) {
for (int i = 0; i < poly.num_contours(); i++) {
Point p = from.projection_onto(poly.contour_or_hole(i));
double dist = (from - p).cast<double>().squaredNorm();
if (dist < min_dist) {
projected_pt = p;
min_dist = dist;
}
}
}
profiler.stage_add(STAGE_projection_onto_ex, true);
return projected_pt;
}
static bool move_out_expolys(const ExPolygons& polygons, Point& from, double distance, double max_move_distance) static bool move_out_expolys(const ExPolygons& polygons, Point& from, double distance, double max_move_distance)
{ {
Point from0 = from; Point from0 = from;
ExPolygons polys_dilated = union_ex(offset_ex(polygons, scale_(distance))); ExPolygons polys_dilated = union_ex(offset_ex(polygons, scale_(distance)));
Point pt = projection_onto_ex(polys_dilated, from);// find_closest_ex(from, polys_dilated); Point pt = projection_onto(polys_dilated, from);// find_closest_ex(from, polys_dilated);
Point outward_dir = pt - from; Point outward_dir = pt - from;
Point pt_max = from + normal(outward_dir, scale_(max_move_distance)); Point pt_max = from + normal(outward_dir, scale_(max_move_distance));
double dist2 = vsize2_with_unscale(outward_dir); double dist2 = vsize2_with_unscale(outward_dir);
@ -2790,7 +2769,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
if (group_index > 0 && is_inside_ex(m_ts_data->get_collision(m_ts_data->m_xy_distance, layer_nr), node.position)) if (group_index > 0 && is_inside_ex(m_ts_data->get_collision(m_ts_data->m_xy_distance, layer_nr), node.position))
{ {
const coordf_t branch_radius_node = calc_branch_radius(branch_radius, node.dist_mm_to_top, diameter_angle_scale_factor); const coordf_t branch_radius_node = calc_branch_radius(branch_radius, node.dist_mm_to_top, diameter_angle_scale_factor);
Point to_outside = projection_onto_ex(m_ts_data->get_collision(m_ts_data->m_xy_distance, layer_nr), node.position); Point to_outside = projection_onto(m_ts_data->get_collision(m_ts_data->m_xy_distance, layer_nr), node.position);
double dist2_to_outside = vsize2_with_unscale(node.position - to_outside); double dist2_to_outside = vsize2_with_unscale(node.position - to_outside);
if (dist2_to_outside >= branch_radius_node * branch_radius_node) //Too far inside. if (dist2_to_outside >= branch_radius_node * branch_radius_node) //Too far inside.
{ {
@ -2871,7 +2850,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
#endif #endif
auto avoid_layer = m_ts_data->get_avoidance(branch_radius_node, layer_nr_next); auto avoid_layer = m_ts_data->get_avoidance(branch_radius_node, layer_nr_next);
Point to_outside = projection_onto_ex(avoid_layer, node.position); Point to_outside = projection_onto(avoid_layer, node.position);
Point direction_to_outer = to_outside - node.position; Point direction_to_outer = to_outside - node.position;
double dist2_to_outer = vsize2_with_unscale(direction_to_outer); double dist2_to_outer = vsize2_with_unscale(direction_to_outer);
// don't move if // don't move if

View file

@ -301,21 +301,18 @@ void ArrangeJob::prepare_wipe_tower()
} }
// if wipe tower is not init yet (no wipe tower in any plate before arrangement) // if wipe tower is not init yet (no wipe tower in any plate before arrangement)
if (wipe_tower_ap.poly.empty()) { //if (wipe_tower_ap.poly.empty()) {
auto &print = wxGetApp().plater()->get_partplate_list().get_current_fff_print(); // auto &print = wxGetApp().plater()->get_partplate_list().get_current_fff_print();
wipe_tower_ap.poly.contour.points = print.first_layer_wipe_tower_corners(false); // wipe_tower_ap.poly.contour.points = print.first_layer_wipe_tower_corners(false);
wipe_tower_ap.name = "WipeTower"; wipe_tower_ap.name = "WipeTower";
wipe_tower_ap.is_virt_object = true; wipe_tower_ap.is_virt_object = true;
wipe_tower_ap.is_wipe_tower = true; wipe_tower_ap.is_wipe_tower = true;
} //}
const GLCanvas3D* canvas3D=static_cast<const GLCanvas3D *>(m_plater->canvas3D()); const GLCanvas3D* canvas3D=static_cast<const GLCanvas3D *>(m_plater->canvas3D());
for (int bedid = 0; bedid < MAX_NUM_PLATES; bedid++) { for (int bedid = 0; bedid < MAX_NUM_PLATES; bedid++) {
if (!plates_have_wipe_tower[bedid]) { if (!plates_have_wipe_tower[bedid]) {
wipe_tower_ap.translation = {0, 0}; wipe_tower_ap.translation = {0, 0};
bool global = true; wipe_tower_ap.poly.contour.points = canvas3D->estimate_wipe_tower_points(bedid, !only_on_partplate);
int state = m_plater->get_prepare_state();
if (state == Job::JobPrepareState::PREPARE_STATE_MENU) { global = false; }
wipe_tower_ap.poly.contour.points = canvas3D->estimate_wipe_tower_points(bedid, global);
wipe_tower_ap.bed_idx = bedid; wipe_tower_ap.bed_idx = bedid;
m_unselected.emplace_back(wipe_tower_ap); m_unselected.emplace_back(wipe_tower_ap);
} }