mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-08 07:27:41 -06:00
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:
parent
56f1a49232
commit
f49c151611
5 changed files with 63 additions and 65 deletions
|
@ -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_)
|
||||||
|
|
|
@ -185,6 +185,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
|
||||||
{
|
{
|
||||||
Polygons pp = this->simplify_p(tolerance);
|
Polygons pp = this->simplify_p(tolerance);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue