diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ee8759102..94ea6e6b6 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2539,7 +2539,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser // and export G-code into file. tool_ordering.cal_most_used_extruder(print.config()); - m_printed_objects.insert(&object); + m_printed_objects.emplace_back(&object); this->process_layers(print, tool_ordering, collect_layers_to_print(object), *print_object_instance_sequential_active - object.instances().data(), file, prime_extruder); { @@ -4083,9 +4083,10 @@ GCode::LayerResult GCode::process_layer( ctx.curr_extruder_id = m_writer.filament()->extruder_id(); ctx.picture_extruder_id = most_used_extruder; if (m_config.nozzle_diameter.size() > 1) { - ctx.extruder_height_gap = m_config.extruder_printable_height.values[0] - m_config.extruder_printable_height.values[1]; - ctx.liftable_extruder_id = m_config.extruder_printable_height.values[0] < m_config.extruder_printable_height.values[0] ? 0 : 1; + ctx.extruder_height_gap = std::abs(m_config.extruder_printable_height.values[0] - m_config.extruder_printable_height.values[1]); + ctx.liftable_extruder_id = m_config.extruder_printable_height.values[0] < m_config.extruder_printable_height.values[1] ? 0 : 1; } + ctx.height_to_rod = m_config.extruder_clearance_height_to_rod; ctx.print_sequence = m_config.print_sequence; if (m_config.print_sequence == PrintSequence::ByObject) diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 80c3480ac..48e952036 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -558,7 +558,7 @@ private: Print *m_print{nullptr}; - std::set m_printed_objects; + std::vector m_printed_objects; // Processor GCodeProcessor m_processor; diff --git a/src/libslic3r/GCode/TimelapsePosPicker.cpp b/src/libslic3r/GCode/TimelapsePosPicker.cpp index a868e053b..f514bf735 100644 --- a/src/libslic3r/GCode/TimelapsePosPicker.cpp +++ b/src/libslic3r/GCode/TimelapsePosPicker.cpp @@ -1,6 +1,8 @@ #include "TimelapsePosPicker.hpp" #include "Layer.hpp" +constexpr int FILTER_THRESHOLD = 5; + namespace Slic3r { void TimelapsePosPicker::init(const Print* print_, const Point& plate_offset) { @@ -25,7 +27,7 @@ namespace Slic3r { * If the optional set of printed objects is provided, it converts the set into a vector. * Otherwise, it retrieves all objects from the print instance. */ - std::vector TimelapsePosPicker::get_object_list(const std::optional>& printed_objects) + std::vector TimelapsePosPicker::get_object_list(const std::optional>& printed_objects) { std::vector object_list; if (printed_objects.has_value()) { @@ -53,6 +55,10 @@ namespace Slic3r { for (size_t idx = 0; idx < config.printable_area.values.size(); ++idx) m_bed_polygon.points.emplace_back(coord_t(scale_(config.printable_area.values[idx].x())), coord_t(scale_(config.printable_area.values[idx].y()))); + auto bed_bbox = get_extents(m_bed_polygon); + m_plate_height = unscale_(bed_bbox.max.y()); + m_plate_width = unscale_(bed_bbox.max.x()); + Polygon bed_exclude_area; for (size_t idx = 0; idx < config.bed_exclude_area.values.size(); ++idx) bed_exclude_area.points.emplace_back(coord_t(scale_(config.bed_exclude_area.values[idx].x())), coord_t(scale_(config.bed_exclude_area.values[idx].y()))); @@ -72,6 +78,7 @@ namespace Slic3r { {transform_wt_pt({scale_(wt_box.max.x()),scale_(wt_box.max.y())})}, {transform_wt_pt({scale_(wt_box.min.x()),scale_(wt_box.max.y())})} }; + wipe_tower_area = expand_object_projection(wipe_tower_area); for (size_t idx = 0; idx < extruder_count; ++idx) { ExPolygons printable_area = diff_ex(diff(m_bed_polygon, bed_exclude_area), { wipe_tower_area }); @@ -139,12 +146,86 @@ namespace Slic3r { return ret; } + // scaled data + Polygons TimelapsePosPicker::collect_limit_areas_for_rod(const std::vector& object_list, const PosPickCtx& ctx) + { + double rod_limit_height = ctx.height_to_rod + ctx.curr_layer->print_z; + std::vector rod_collision_candidates; + for(auto& obj : object_list){ + if(ctx.printed_objects && obj == ctx.printed_objects->back()) + continue; + auto bbox = get_real_instance_bbox(obj->instances().front()); + if(bbox.max.z() >= rod_limit_height) + rod_collision_candidates.push_back(obj); + } + + std::sort(rod_collision_candidates.begin(), rod_collision_candidates.end(), [&](const PrintObject* lhs, const PrintObject* rhs) { + auto lbbox =get_real_instance_bbox(lhs->instances().front()); + auto rbbox =get_real_instance_bbox(rhs->instances().front()); + if(lbbox.min.y() == rbbox.min.y()) + return lbbox.max.y() < rbbox.max.y(); + return lbbox.min.y() < rbbox.min.y(); + }); + + std::vector> object_y_ranges = {{0,0}}; + for(auto& candidate : rod_collision_candidates){ + auto bbox = get_real_instance_bbox(candidate->instances().front()); + if( object_y_ranges.back().second >= bbox.min.y()) + object_y_ranges.back().second = bbox.max.y(); + else + object_y_ranges.emplace_back(bbox.min.y(), bbox.max.y()); + } + + if (object_y_ranges.back().second < m_plate_height) + 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); + + 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) { + lower_y_pos = object_y_ranges[idx - 1].second; + upper_y_pos = object_y_ranges[idx].first; + break; + } + } + + if(lower_y_pos == -1 && upper_y_pos == -1) + return { m_bed_polygon }; + + Polygons ret; + + ret.emplace_back( + Polygon{ + Point{scale_(0), scale_(0)}, + Point{scale_(m_plate_width), scale_(0)}, + Point{scale_(m_plate_width), scale_(lower_y_pos)}, + Point{scale_(0), scale_(lower_y_pos)} + } + ); + + ret.emplace_back( + Polygon{ + Point{scale_(0), scale_(upper_y_pos)}, + Point{scale_(m_plate_width), scale_(upper_y_pos)}, + Point{scale_(m_plate_width), scale_(m_plate_height)}, + Point{scale_(0), scale_(m_plate_height)} + } + ); + return ret; + } + + + // expand the object expolygon by safe distance Polygon TimelapsePosPicker::expand_object_projection(const Polygon& poly) { // the input poly is bounding box, so we get the first offseted polygon is ok float radius = scale_(print->config().extruder_clearance_max_radius.value / 2); - return offset(poly, radius)[0]; + auto ret = offset(poly, radius); + if (ret.empty()) + return {}; + return ret[0]; } double TimelapsePosPicker::get_raft_height(const PrintObject* obj) @@ -169,7 +250,7 @@ namespace Slic3r { return ret + slice_params.gap_raft_object; } - // get the real instance bounding box, remove the plate offset and add raft height + // get the real instance bounding box, remove the plate offset and add raft height , unscaled data BoundingBoxf3 TimelapsePosPicker::get_real_instance_bbox(const PrintInstance& instance) { auto iter = bbox_cache.find(&instance); @@ -198,11 +279,12 @@ namespace Slic3r { float radius = print->config().extruder_clearance_max_radius.value / 2; auto offset_bbox = bbox.inflated(sqrt(2) * radius); + // Constrain the coordinates to the first quadrant. Polygon ret = { DefaultCameraPos, - {scale_(offset_bbox.max.x()),scale_(offset_bbox.min.y())}, - {scale_(offset_bbox.max.x()),scale_(offset_bbox.max.y())}, - {scale_(offset_bbox.min.x()),scale_(offset_bbox.max.y())} + Point{std::max(scale_(offset_bbox.max.x()),0.),std::max(scale_(offset_bbox.min.y()),0.)}, + Point{std::max(scale_(offset_bbox.max.x()),0.),std::max(scale_(offset_bbox.max.y()),0.)}, + Point{std::max(scale_(offset_bbox.min.x()),0.),std::max(scale_(offset_bbox.max.y()),0.)} }; return ret; } @@ -272,7 +354,7 @@ namespace Slic3r { return { unscale_(res.x()), unscale_(res.y()) }; } - // get center point of curr object + // get center point of curr object, scaled data Point TimelapsePosPicker::get_object_center(const PrintObject* obj) { if (!obj) @@ -286,6 +368,7 @@ namespace Slic3r { return { scale_((min_p.x() + max_p.x()) / 2),scale_(min_p.y() + max_p.y() / 2) }; } + // scaled data Point TimelapsePosPicker::pick_nearest_object_center(const Point& curr_pos, const std::vector& object_list) { if (object_list.empty()) @@ -303,6 +386,7 @@ namespace Slic3r { return get_object_center(ptr); } + // scaled data Point TimelapsePosPicker::pick_pos_for_curr_layer(const PosPickCtx& ctx) { float height_gap = 0; @@ -315,10 +399,15 @@ namespace Slic3r { ExPolygons layer_slices = collect_object_slices_data(ctx.curr_layer,height_gap, object_list); Polygons camera_limit_areas = collect_limit_areas_for_camera(object_list); - ExPolygons unplacable_area = union_ex(layer_slices, camera_limit_areas); + Polygons rod_limit_areas; + if (ctx.print_sequence == PrintSequence::ByObject) { + 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 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); } @@ -329,7 +418,7 @@ namespace Slic3r { * This function computes the average center of all instances of the provided objects. * * @param object_list A vector of pointers to PrintObject instances. - * @return Point The average center of all objects. + * @return Point The average center of all objects.Scaled data */ Point TimelapsePosPicker::get_objects_center(const std::vector& object_list) { @@ -372,6 +461,10 @@ namespace Slic3r { for (auto& obj : object_list) { for (auto& instance : obj->instances()) { const auto& bbox = get_real_instance_bbox(instance); + if (ctx.print_sequence == PrintSequence::ByObject && bbox.max.z() >= ctx.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() }, @@ -383,6 +476,7 @@ namespace Slic3r { } }; + object_projections = union_(object_projections); Polygons camera_limit_areas = collect_limit_areas_for_camera(object_list); Polygons unplacable_area = union_(object_projections, camera_limit_areas); @@ -394,6 +488,7 @@ namespace Slic3r { extruder_printable_area = m_extruder_printable_area.front(); ExPolygons safe_area = diff_ex(extruder_printable_area, unplacable_area); + safe_area = opening_ex(safe_area, scale_(FILTER_THRESHOLD)); Point starting_pos = get_objects_center(object_list); diff --git a/src/libslic3r/GCode/TimelapsePosPicker.hpp b/src/libslic3r/GCode/TimelapsePosPicker.hpp index 446b79c9d..c1e8b4377 100644 --- a/src/libslic3r/GCode/TimelapsePosPicker.hpp +++ b/src/libslic3r/GCode/TimelapsePosPicker.hpp @@ -21,9 +21,10 @@ namespace Slic3r { const Layer* curr_layer; int picture_extruder_id; // the extruder id to take picture int curr_extruder_id; + int height_to_rod; bool based_on_all_layer; // whether to calculate the safe position based all layers PrintSequence print_sequence; // print sequence: by layer or by object - std::optional> printed_objects; // printed objects, only have value in by object mode + std::optional> printed_objects; // printed objects, only have value in by object mode std::optional liftable_extruder_id; // extruder id that can be lifted, cause bed height to change std::optional extruder_height_gap; // the height gap caused by extruder lift }; @@ -47,22 +48,26 @@ namespace Slic3r { ExPolygons collect_object_slices_data(const Layer* curr_layer, float height_range, const std::vector& object_list); Polygons collect_limit_areas_for_camera(const std::vector& object_list); + Polygons collect_limit_areas_for_rod(const std::vector& object_list, const PosPickCtx& ctx); + Polygon expand_object_projection(const Polygon& poly); Point pick_nearest_object_center(const Point& curr_pos, const std::vector& object_list); Point get_objects_center(const std::vector& object_list); Polygon get_limit_area_for_camera(const PrintObject* obj); - std::vector get_object_list(const std::optional>& printed_objects); + std::vector get_object_list(const std::optional>& printed_objects); double get_raft_height(const PrintObject* obj); BoundingBoxf3 get_real_instance_bbox(const PrintInstance& instance); Point get_object_center(const PrintObject* obj); private: const Print* print{ nullptr }; - std::vector m_extruder_printable_area; - Polygon m_bed_polygon; - Point m_plate_offset; + std::vector m_extruder_printable_area; //scaled data + Polygon m_bed_polygon; //scaled_data + Point m_plate_offset; // unscaled data + int m_plate_height; // unscaled data + int m_plate_width; // unscaled data std::unordered_map bbox_cache;