From 04d90ac16d3abc481860a46b2d8bc8cd2f599aed Mon Sep 17 00:00:00 2001 From: "xun.zhang" Date: Wed, 28 May 2025 21:38:27 +0800 Subject: [PATCH] FIX: collision caused by pick safe pos in object mode jira:NONE Signed-off-by: xun.zhang Change-Id: Ic9a45e314ffa1115854736516cc06dfd976c28f9 --- src/libslic3r/GCode/TimelapsePosPicker.cpp | 106 +++++++++++++-------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/src/libslic3r/GCode/TimelapsePosPicker.cpp b/src/libslic3r/GCode/TimelapsePosPicker.cpp index 27d5c4f93..8f2c35c02 100644 --- a/src/libslic3r/GCode/TimelapsePosPicker.cpp +++ b/src/libslic3r/GCode/TimelapsePosPicker.cpp @@ -2,6 +2,7 @@ #include "Layer.hpp" constexpr int FILTER_THRESHOLD = 5; +constexpr int MAX_CANDIDATE_SIZE = 5; namespace Slic3r { void TimelapsePosPicker::init(const Print* print_, const Point& plate_offset) @@ -209,7 +210,7 @@ namespace Slic3r { object_y_ranges.emplace_back(m_plate_height, m_plate_height); int lower_y_pos = -1, upper_y_pos =-1; - auto unscaled_curr_pos = unscale(ctx.curr_pos); + Point unscaled_curr_pos = {unscale_(ctx.curr_pos.x())-m_plate_offset.x(), unscale_(ctx.curr_pos.y()) - m_plate_offset.y()}; for (size_t idx = 1; idx < object_y_ranges.size(); ++idx) { if (unscaled_curr_pos.y() >= object_y_ranges[idx - 1].second && unscaled_curr_pos.y() <= object_y_ranges[idx].first) { @@ -353,31 +354,28 @@ namespace Slic3r { * @param safe_areas A collection of extended polygons defining the safe areas. * @return Point The nearest point within the safe areas or the default timelapse position if no safe areas exist. */ - Point pick_pos_internal(const Point& curr_pos, const ExPolygons& safe_areas) + Point pick_pos_internal(const Point& curr_pos, const ExPolygons& safe_areas, const ExPolygons& path_collision_area, bool detect_path_collision) { - if (std::any_of(safe_areas.begin(), safe_areas.end(), [&curr_pos](const ExPolygon& p) { return p.contains(curr_pos);})) + struct CandidatePoint + { + double dist; + Point point; + bool operator<(const CandidatePoint& other) const { + return dist < other.dist; + } + }; + + if (std::any_of(safe_areas.begin(), safe_areas.end(), [&curr_pos](const ExPolygon& p) { return p.contains(curr_pos); })) return curr_pos; if (safe_areas.empty()) return DefaultTimelapsePos; + std::priority_queue max_heap; + double min_distance = std::numeric_limits::max(); - Point nearest_point =DefaultTimelapsePos; -#if 0 - for (const auto& expoly : safe_areas) { - Polygons polys = to_polygons(expoly); - for (auto& poly : polys) { - auto nearest_point_ptr = poly.closest_point(curr_pos); - if (nearest_point_ptr) { - double dist = (*nearest_point_ptr - curr_pos).cast().norm(); - if (min_distance > dist) { - min_distance = dist; - nearest_point = *nearest_point_ptr; - } - } - } - } -#else + Point nearest_point = DefaultTimelapsePos; + for (const auto& expoly : safe_areas) { Polygons polys = to_polygons(expoly); for (auto& poly : polys) { @@ -385,15 +383,31 @@ namespace Slic3r { Line line(poly.points[idx], poly.points[next_idx_modulo(idx, poly.points)]); Point candidate; double dist = line.distance_to_squared(curr_pos, &candidate); - if (min_distance > dist) { - min_distance = dist; - nearest_point = candidate; - } + max_heap.push({ dist,candidate }); + if (max_heap.size() > MAX_CANDIDATE_SIZE) + max_heap.pop(); } } } -#endif - return nearest_point; + + std::vector top_candidates; + while (!max_heap.empty()) { + top_candidates.push_back(max_heap.top().point); + max_heap.pop(); + } + std::reverse(top_candidates.begin(), top_candidates.end()); + + for (auto& p : top_candidates) { + if (!detect_path_collision) + return p; + + Polyline path(curr_pos, p); + + if (intersection_pl(path, path_collision_area).empty()) + return p; + } + + return DefaultTimelapsePos; } Point TimelapsePosPicker::pick_pos(const PosPickCtx& ctx) @@ -418,7 +432,7 @@ namespace Slic3r { Point min_p{ instance_bbox.min.x(),instance_bbox.min.y() }; Point max_p{ instance_bbox.max.x(),instance_bbox.max.y() }; - return { scale_((min_p.x() + max_p.x()) / 2),scale_(min_p.y() + max_p.y() / 2) }; + return { scale_((min_p.x() + max_p.x()) / 2),scale_((min_p.y() + max_p.y()) / 2) }; } // scaled data @@ -444,7 +458,7 @@ namespace Slic3r { { float height_gap = 0; if (ctx.curr_extruder_id != ctx.picture_extruder_id) { - if(m_liftable_extruder_id.has_value() && ctx.picture_extruder_id != m_liftable_extruder_id && m_extruder_height_gap.has_value()) + if (m_liftable_extruder_id.has_value() && ctx.picture_extruder_id != m_liftable_extruder_id && m_extruder_height_gap.has_value()) height_gap = -*m_extruder_height_gap; } @@ -454,16 +468,32 @@ namespace Slic3r { ExPolygons layer_slices = collect_object_slices_data(ctx.curr_layer, height_gap, object_list, by_object); Polygons camera_limit_areas = collect_limit_areas_for_camera(object_list); Polygons rod_limit_areas; - if (m_print_seq == PrintSequence::ByObject) { - rod_limit_areas = collect_limit_areas_for_rod(object_list,ctx); + if (by_object) { + rod_limit_areas = collect_limit_areas_for_rod(object_list, ctx); } - ExPolygons unplacable_area = union_ex(union_ex(layer_slices, camera_limit_areas),rod_limit_areas); + ExPolygons unplacable_area = union_ex(union_ex(layer_slices, camera_limit_areas), rod_limit_areas); ExPolygons extruder_printable_area = m_extruder_printable_area[ctx.picture_extruder_id]; ExPolygons safe_area = diff_ex(extruder_printable_area, unplacable_area); safe_area = opening_ex(safe_area, scale_(FILTER_THRESHOLD)); - Point objs_center = get_objects_center(object_list); - return pick_pos_internal(objs_center, safe_area); + + Point center_p; + if (by_object && ctx.printed_objects && !ctx.printed_objects->empty()) + center_p = get_object_center(ctx.printed_objects->back()); + else + center_p = get_objects_center(object_list); + + ExPolygons path_collision_area; + if (by_object) { + auto object_without_curr = ctx.printed_objects; + if (object_without_curr && !object_without_curr->empty()) + object_without_curr->pop_back(); + + ExPolygons layer_slices_without_curr = collect_object_slices_data(ctx.curr_layer, height_gap, get_object_list(object_without_curr), by_object); + path_collision_area = union_ex(layer_slices_without_curr, rod_limit_areas); + } + + return pick_pos_internal(center_p, safe_area,path_collision_area, by_object); } /** @@ -498,6 +528,10 @@ namespace Slic3r { Point TimelapsePosPicker::pick_pos_for_all_layer(const PosPickCtx& ctx) { + bool by_object = m_print_seq == PrintSequence::ByObject; + if (by_object) + return DefaultTimelapsePos; + float height_gap = 0; if (ctx.curr_extruder_id != ctx.picture_extruder_id) { if (m_liftable_extruder_id.has_value() && ctx.picture_extruder_id != m_liftable_extruder_id && m_extruder_height_gap.has_value()) @@ -508,8 +542,6 @@ namespace Slic3r { if (m_all_layer_pos) return *m_all_layer_pos; - bool by_object = m_print_seq == PrintSequence::ByObject; - Polygons object_projections; auto object_list = get_object_list(std::nullopt); @@ -517,10 +549,6 @@ namespace Slic3r { for (auto& obj : object_list) { for (auto& instance : obj->instances()) { const auto& bbox = get_real_instance_bbox(instance); - if (m_print_seq == PrintSequence::ByObject && bbox.max.z() >= m_nozzle_height_to_rod) { - m_all_layer_pos = DefaultTimelapsePos; - return *m_all_layer_pos; - } Point min_p{ scale_(bbox.min.x()),scale_(bbox.min.y()) }; Point max_p{ scale_(bbox.max.x()),scale_(bbox.max.y()) }; Polygon obj_proj{ { min_p.x(),min_p.y() }, @@ -548,7 +576,7 @@ namespace Slic3r { Point starting_pos = get_objects_center(object_list); - m_all_layer_pos = pick_pos_internal(starting_pos, safe_area); + m_all_layer_pos = pick_pos_internal(starting_pos, safe_area, {}, by_object); return *m_all_layer_pos; }