diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 15edff5920..ae0fcb36ec 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -1099,42 +1099,43 @@ private: auto d = cb - ci; // BBS make sure the item won't clash with excluded regions - if(1) - { - // do we have wipe tower after arranging? - std::set extruders; - 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; + // do we have wipe tower after arranging? + std::set extruders; + 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; - std::vector objs,excludes; - for (const Item &item : items_) { - if (item.isFixed()) continue; - objs.push_back(item.transformedShape()); - } + std::vector objs,excludes; + for (const Item &item : items_) { + if (item.isFixed()) continue; + 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); - if (objs.size() != 0) { - for (const Item &item : config_.m_excluded_regions) { excludes.push_back(item.transformedShape()); } - for (const Item &item : items_) { - if (item.isFixed()) { - if (!(item.is_wipe_tower && !need_wipe_tower)) - excludes.push_back(item.transformedShape()); - } + for (const Item &item : config_.m_excluded_regions) { excludes.push_back(item.transformedShape()); } + for (const Item &item : items_) { + if (item.isFixed()) { + if (!(item.is_wipe_tower && !need_wipe_tower)) + excludes.push_back(item.transformedShape()); } - Box binbb = sl::boundingBox(bin_); - auto allowShifts = calcnfp(objs_convex_hull, excludes, binbb, Lvl()); - int maxAllowShiftX = 0; - int maxAllowShiftY = 0; - for (const auto &shiftShape : allowShifts) { - auto shiftBox = sl::boundingBox(shiftShape); // assume that the exclude region is box so that the nfp is box. - maxAllowShiftX = shiftBox.width(); - maxAllowShiftY = shiftBox.height(); - } - int finalShiftX = std::min(std::abs(maxAllowShiftX), std::abs(d.x())); - int finalShiftY = std::min(std::abs(maxAllowShiftY), std::abs(d.y())); - d.x() = d.x() > 0 ? finalShiftX : -finalShiftX; - d.y() = d.y() > 0 ? finalShiftY : -finalShiftY; + } + + auto nfps = calcnfp(objs_convex_hull, excludes, bbin, Lvl()); + if (nfps.empty()) { + return; + } + Item objs_convex_hull_item(objs_convex_hull); + Vertex objs_convex_hull_ref = objs_convex_hull_item.referenceVertex(); + Vertex diff = objs_convex_hull_ref - sl::boundingBox(objs_convex_hull).center(); + Vertex ref_aligned = cb + diff; // reference point when pile center aligned with bed center + bool ref_aligned_is_ok = std::any_of(nfps.begin(), nfps.end(), [&ref_aligned](auto& nfp) {return sl::isInside(ref_aligned, nfp); }); + if (!ref_aligned_is_ok) { + // 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_) diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 53b4414cf6..a1b5691ff1 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -183,6 +183,25 @@ bool overlaps(const ExPolygons& expolys1, const ExPolygons& expolys2) } } return false; +} + +Point projection_onto(const ExPolygons& polygons, const Point& from) +{ + Point projected_pt; + double min_dist = std::numeric_limits::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().squaredNorm(); + if (dist < min_dist) { + projected_pt = p; + min_dist = dist; + } + } + } + + return projected_pt; } void ExPolygon::simplify_p(double tolerance, Polygons* polygons) const diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 72bfc7865d..d213d991f4 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -453,6 +453,8 @@ bool expolygons_match(const ExPolygon &l, const ExPolygon &r); 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 ExPolygons &expolygons); BoundingBox get_extents_rotated(const ExPolygon &poly, double angle); diff --git a/src/libslic3r/TreeSupport.cpp b/src/libslic3r/TreeSupport.cpp index 2b7c2cbfb4..8e941ad017 100644 --- a/src/libslic3r/TreeSupport.cpp +++ b/src/libslic3r/TreeSupport.cpp @@ -625,32 +625,11 @@ static bool is_inside_ex(const ExPolygons &polygons, const Point &pt) return false; } -Point projection_onto_ex(const ExPolygons& polygons, Point from) -{ - profiler.tic(); - Point projected_pt; - double min_dist = std::numeric_limits::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().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) { Point from0 = from; 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 pt_max = from + normal(outward_dir, scale_(max_move_distance)); double dist2 = vsize2_with_unscale(outward_dir); @@ -2790,7 +2769,7 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) 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); - 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); if (dist2_to_outside >= branch_radius_node * branch_radius_node) //Too far inside. { @@ -2871,7 +2850,7 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) #endif 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; double dist2_to_outer = vsize2_with_unscale(direction_to_outer); // don't move if diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index 773d257697..da55f3eae1 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -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_ap.poly.empty()) { - auto &print = wxGetApp().plater()->get_partplate_list().get_current_fff_print(); - wipe_tower_ap.poly.contour.points = print.first_layer_wipe_tower_corners(false); + //if (wipe_tower_ap.poly.empty()) { + // 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.name = "WipeTower"; wipe_tower_ap.is_virt_object = true; wipe_tower_ap.is_wipe_tower = true; - } + //} const GLCanvas3D* canvas3D=static_cast(m_plater->canvas3D()); for (int bedid = 0; bedid < MAX_NUM_PLATES; bedid++) { if (!plates_have_wipe_tower[bedid]) { wipe_tower_ap.translation = {0, 0}; - bool global = true; - 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.poly.contour.points = canvas3D->estimate_wipe_tower_points(bedid, !only_on_partplate); wipe_tower_ap.bed_idx = bedid; m_unselected.emplace_back(wipe_tower_ap); }