diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 2a3d24274..2dc82df2b 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -590,7 +590,7 @@ static std::vector get_path_of_change_filament(const Print& print) auto transform_wt_pt = [&alpha, this](const Vec2f& pt) -> Vec2f { Vec2f out = Eigen::Rotation2Df(alpha) * pt; - out += m_wipe_tower_pos; + out += m_wipe_tower_pos + m_rib_offset; return out; }; @@ -605,7 +605,7 @@ static std::vector get_path_of_change_filament(const Print& print) tool_change_start_pos = transform_wt_pt(tool_change_start_pos); } - Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos; + Vec2f wipe_tower_offset = (tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos) + m_rib_offset; float wipe_tower_rotation = tcr.priming ? 0.f : alpha; std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation); @@ -2514,6 +2514,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get())); m_wipe_tower->set_wipe_tower_depth(print.get_wipe_tower_depth()); m_wipe_tower->set_wipe_tower_bbx(print.get_wipe_tower_bbx()); + m_wipe_tower->set_rib_offset(print.get_rib_offset()); // BBS // file.write(m_writer.travel_to_z(initial_layer_print_height + m_config.z_offset.value, "Move to the first layer height")); file.write(m_writer.travel_to_z(initial_layer_print_height, "Move to the first layer height")); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 20009ff21..4b0bdfd58 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -108,6 +108,7 @@ public: bool enable_timelapse_print() const { return m_enable_timelapse_print; } void set_wipe_tower_depth(float depth) { m_wipe_tower_depth = depth; } void set_wipe_tower_bbx(const BoundingBoxf & bbx) { m_wipe_tower_bbx = bbx; } + void set_rib_offset(const Vec2f &rib_offset) { m_rib_offset = rib_offset; } private: WipeTowerIntegration& operator=(const WipeTowerIntegration&); @@ -141,7 +142,7 @@ private: const PrintConfig * m_print_config; float m_wipe_tower_depth; BoundingBoxf m_wipe_tower_bbx; - + Vec2f m_rib_offset{Vec2f(0, 0)}; }; class ColorPrintColors diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 86c552294..2fb93c5f4 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -719,6 +719,7 @@ public: width += m_layer_height * float(1. - M_PI / 4.); if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) m_extrusions.emplace_back(WipeTower::Extrusion(rotated_current_pos, 0, m_current_tool)); { + float sample_angle = 5.f / 180.f * PI; int n = std::ceil(abs(arc.angle_radians) / sample_angle); for (int j = 0; j < n; j++) { @@ -887,6 +888,7 @@ public: segments.back().arcsegment = pl.fitting_result[i].arc_data; } } + int index_of_closest = get_closet_idx(segments); int i = index_of_closest; travel(segments[i].start); // travel to the closest points @@ -1119,6 +1121,7 @@ public: segments.back().is_arc = true; segments.back().arcsegment = pl.fitting_result[i].arc_data; } + } } int index_of_closest = get_closet_idx(segments); @@ -1268,6 +1271,42 @@ const std::map WipeTower::min_depth_per_height = { {10.f, 10.f}, {100.f, 20.f}, {180.f, 40.f}, {250.f, 50.f}, {350.f, 60.f} }; +float WipeTower::get_limit_depth_by_height(float max_height) +{ + float min_wipe_tower_depth = 0.f; + auto iter = WipeTower::min_depth_per_height.begin(); + while (iter != WipeTower::min_depth_per_height.end()) { + auto curr_height_to_depth = *iter; + + // This is the case that wipe tower height is lower than the first min_depth_to_height member. + if (curr_height_to_depth.first >= max_height) { + min_wipe_tower_depth = curr_height_to_depth.second; + break; + } + + iter++; + + // If curr_height_to_depth is the last member, use its min_depth. + if (iter == WipeTower::min_depth_per_height.end()) { + min_wipe_tower_depth = curr_height_to_depth.second; + break; + } + + // If wipe tower height is between the current and next member, set the min_depth as linear interpolation between them + auto next_height_to_depth = *iter; + if (next_height_to_depth.first > max_height) { + float height_base = curr_height_to_depth.first; + float height_diff = next_height_to_depth.first - curr_height_to_depth.first; + float min_depth_base = curr_height_to_depth.second; + float depth_diff = next_height_to_depth.second - curr_height_to_depth.second; + + min_wipe_tower_depth = min_depth_base + (max_height - curr_height_to_depth.first) / height_diff * depth_diff; + break; + } + } + return min_wipe_tower_depth; +} + WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origin, const float prime_volume, size_t initial_tool, const float wipe_tower_height) : m_semm(config.single_extruder_multi_material.value), m_wipe_tower_pos(config.wipe_tower_x.get_at(plate_idx), config.wipe_tower_y.get_at(plate_idx)), @@ -2322,37 +2361,7 @@ void WipeTower::plan_tower() for (auto& info : m_plan) max_depth = std::max(max_depth, info.toolchanges_depth()); - float min_wipe_tower_depth = 0.f; - auto iter = WipeTower::min_depth_per_height.begin(); - while (iter != WipeTower::min_depth_per_height.end()) { - auto curr_height_to_depth = *iter; - - // This is the case that wipe tower height is lower than the first min_depth_to_height member. - if (curr_height_to_depth.first >= m_wipe_tower_height) { - min_wipe_tower_depth = curr_height_to_depth.second; - break; - } - - iter++; - - // If curr_height_to_depth is the last member, use its min_depth. - if (iter == WipeTower::min_depth_per_height.end()) { - min_wipe_tower_depth = curr_height_to_depth.second; - break; - } - - // If wipe tower height is between the current and next member, set the min_depth as linear interpolation between them - auto next_height_to_depth = *iter; - if (next_height_to_depth.first > m_wipe_tower_height) { - float height_base = curr_height_to_depth.first; - float height_diff = next_height_to_depth.first - curr_height_to_depth.first; - float min_depth_base = curr_height_to_depth.second; - float depth_diff = next_height_to_depth.second - curr_height_to_depth.second; - - min_wipe_tower_depth = min_depth_base + (m_wipe_tower_height - curr_height_to_depth.first) / height_diff * depth_diff; - break; - } - } + float min_wipe_tower_depth = WipeTower::get_limit_depth_by_height(m_wipe_tower_height); { if (m_enable_timelapse_print && max_depth < EPSILON) @@ -2930,6 +2939,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter, outer_wall = offset(outer_wall, scaled(spacing)).front(); writer.polygon(outer_wall, feedrate); } + /*for (size_t i = 0; i < loops_num; ++i) { box.expand(spacing); writer.rectangle(box, feedrate); @@ -3455,7 +3465,7 @@ void WipeTower::plan_tower_new() float nozzle_change_depth = 0; if (!m_filament_map.empty() && m_filament_map[toolchange.old_tool] != m_filament_map[toolchange.new_tool]) { double e_flow = extrusion_flow(m_plan[idx].height); - double length = m_nozzle_change_length / e_flow; + double length = m_filaments_change_length[toolchange.old_tool] / e_flow; int nozzle_change_line_count = length / (m_wipe_tower_width - 2*m_perimeter_width) + 1; if (has_tpu_filament()) nozzle_change_depth = m_tpu_fixed_spacing * nozzle_change_line_count * m_perimeter_width; @@ -3558,6 +3568,7 @@ void WipeTower::plan_tower_new() update_all_layer_depth(max_depth); m_rib_length = std::max({m_rib_length, sqrt(m_wipe_tower_depth * m_wipe_tower_depth + m_wipe_tower_width * m_wipe_tower_width)}); m_rib_length += m_extra_rib_length; + } int WipeTower::get_wall_filament_for_all_layer() @@ -3934,8 +3945,10 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall(bool is_new_mode) // writer.rectangle(wt_box, feedrate); outer_wall = generate_support_wall_new(writer, wt_box, feedrate, first_layer, m_use_rib_wall, true, m_use_gap_wall); // Now prepare future wipe. box contains rectangle that was extruded last (ccw). + // Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd : (writer.pos() == wt_box.rd ? wt_box.ru : (writer.pos() == wt_box.ru ? wt_box.lu : wt_box.ld))); //writer.add_wipe_point(writer.pos()).add_wipe_point(target); + writer.add_wipe_path(outer_wall, m_filpar[m_current_tool].wipe_dist); writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n"); @@ -4022,6 +4035,11 @@ Polygon WipeTower::generate_support_wall_new(WipeTowerWriter &writer, const box_ insert_skip_polygon = wall_polygon; } writer.generate_path(result_wall, feedrate, retract_length, retract_speed,m_used_fillet); + if (m_cur_layer_id == 0) { + BoundingBox bbox = get_extents(result_wall); + m_rib_offset = Vec2f(-unscaled(bbox.min.x()), -unscaled(bbox.min.y())); + } + return insert_skip_polygon; } diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index ce0c25b72..9d4919a28 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -25,6 +25,7 @@ public: // WipeTower height to minimum depth map static const std::map min_depth_per_height; + static float get_limit_depth_by_height(float max_height); struct Extrusion { @@ -358,6 +359,7 @@ public: ToolChangeResult finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_fill = true); ToolChangeResult finish_block_solid(const WipeTowerBlock &block, int filament_id, bool extrude_fill = true); void toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_length); + Vec2f get_rib_offset() const { return m_rib_offset; } private: enum wipe_shape // A fill-in direction @@ -406,6 +408,7 @@ private: float m_rib_width=0.f; float m_extra_rib_length=0.f; bool m_used_fillet{false}; + Vec2f m_rib_offset{Vec2f(0.f, 0.f)}; // G-code generator parameters. // BBS: remove useless config diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 8c8a3ed41..901a7bd2e 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -932,6 +932,9 @@ static StringObjectException layered_print_cleareance_valid(const Print &print, float depth = print.wipe_tower_data(filaments_count).depth; //float brim_width = print.wipe_tower_data(filaments_count).brim_width; + if (config.prime_tower_rib_wall.value) + width = depth; + Polygons convex_hulls_temp; if (print.has_wipe_tower()) { Polygon wipe_tower_convex_hull; @@ -2528,16 +2531,40 @@ const WipeTowerData& Print::wipe_tower_data(size_t filaments_cnt) const { // If the wipe tower wasn't created yet, make sure the depth and brim_width members are set to default. if (! is_step_done(psWipeTower) && filaments_cnt !=0) { - // BBS - double width = m_config.prime_tower_width; - double layer_height = 0.2; // hard code layer height - double wipe_volume = m_config.prime_volume; - if (filaments_cnt == 1 && enable_timelapse_print()) { - const_cast(this)->m_wipe_tower_data.depth = wipe_volume / (layer_height * width); - } else { - const_cast(this)->m_wipe_tower_data.depth = wipe_volume * (filaments_cnt - 1) / (layer_height * width); + if (m_config.prime_tower_rib_wall.value) { + double layer_height = 0.08f; // hard code layer height + double wipe_volume = m_config.prime_volume; + double max_height = 0; + for (size_t obj_idx = 0; obj_idx < m_objects.size(); obj_idx++) { + double object_z = (double) m_objects[obj_idx]->size().z(); + max_height = std::max(unscale_(object_z), max_height); + } + if (max_height < EPSILON) + return m_wipe_tower_data; + + layer_height = m_objects.front()->config().layer_height.value; + int filament_depth_count = m_config.nozzle_diameter.values.size() == 2 ? filaments_cnt : filaments_cnt - 1; + if (filaments_cnt == 1 && enable_timelapse_print()) + filament_depth_count = 1; + double depth = std::sqrt(wipe_volume * filament_depth_count / layer_height); + + float min_wipe_tower_depth = WipeTower::get_limit_depth_by_height(max_height); + depth = std::max((double) min_wipe_tower_depth, depth); + const_cast(this)->m_wipe_tower_data.depth = depth; + const_cast(this)->m_wipe_tower_data.brim_width = m_config.prime_tower_brim_width; + } + else { + // BBS + double width = m_config.prime_tower_width; + double layer_height = 0.2; // hard code layer height + double wipe_volume = m_config.prime_volume; + if (filaments_cnt == 1 && enable_timelapse_print()) { + const_cast(this)->m_wipe_tower_data.depth = wipe_volume / (layer_height * width); + } else { + const_cast(this)->m_wipe_tower_data.depth = wipe_volume * (filaments_cnt - 1) / (layer_height * width); + } + const_cast(this)->m_wipe_tower_data.brim_width = m_config.prime_tower_brim_width; } - const_cast(this)->m_wipe_tower_data.brim_width = m_config.prime_tower_brim_width; } return m_wipe_tower_data; @@ -2699,6 +2726,7 @@ void Print::_make_wipe_tower() m_wipe_tower_data.depth = wipe_tower.get_depth(); m_wipe_tower_data.brim_width = wipe_tower.get_brim_width(); m_wipe_tower_data.bbx = wipe_tower.get_bbx(); + m_wipe_tower_data.rib_offset = wipe_tower.get_rib_offset(); // Unload the current filament over the purge tower. coordf_t layer_height = m_objects.front()->config().layer_height.value; @@ -2725,7 +2753,6 @@ void Print::_make_wipe_tower() m_fake_wipe_tower.set_fake_extrusion_data(wipe_tower.position(), wipe_tower.width(), wipe_tower.get_height(), wipe_tower.get_layer_height(), m_wipe_tower_data.depth, m_wipe_tower_data.brim_width, {scale_(origin.x()), scale_(origin.y())}); m_fake_wipe_tower.real_bbx = wipe_tower.get_bbx(); - m_config.prime_tower_width.set(new ConfigOptionFloat( wipe_tower.width())); } // Generate a recommended G-code output file name based on the format template, default extension, and template parameters diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 5a45c1409..81e2198a3 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -679,6 +679,7 @@ struct WipeTowerData float depth; float brim_width; BoundingBoxf bbx; + Vec2f rib_offset; void clear() { priming.reset(nullptr); @@ -949,6 +950,7 @@ public: Vec2d translate_to_print_space(const Vec2d& point) const; float get_wipe_tower_depth() const { return m_wipe_tower_data.depth; } BoundingBoxf get_wipe_tower_bbx() const { return m_wipe_tower_data.bbx; } + Vec2f get_rib_offset() const { return m_wipe_tower_data.rib_offset; } // scaled point Vec2d translate_to_print_space(const Point& point) const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1daaa6dea..f3d4b5d36 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2918,6 +2918,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re float brim_width = print->wipe_tower_data(filaments_count).brim_width; const DynamicPrintConfig &print_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; Vec3d wipe_tower_size = ppl.get_plate(plate_id)->estimate_wipe_tower_size(print_cfg, w, v); + if (dynamic_cast(m_config->option("prime_tower_rib_wall"))->value) + wipe_tower_size = ppl.get_plate(plate_id)->calculate_wipe_tower_size(print_cfg, w, v); { // update for wipe tower position part_plate->get_extruder_areas(); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 399887a68..24e3c1c74 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -1385,6 +1385,45 @@ bool PartPlate::check_mixture_of_pla_and_petg(const DynamicPrintConfig &config) return true; } +Vec3d PartPlate::calculate_wipe_tower_size(const DynamicPrintConfig &config, const double w, const double wipe_volume, int plate_extruder_size, bool use_global_objects) const +{ + Vec3d wipe_tower_size; + double layer_height = 0.08f; // hard code layer height + double max_height = 0.f; + wipe_tower_size.setZero(); + + const ConfigOption *layer_height_opt = config.option("layer_height"); + if (layer_height_opt) + layer_height = layer_height_opt->getFloat(); + + std::vector plate_extruders = get_extruders(true); + plate_extruder_size = plate_extruders.size(); + if (plate_extruder_size == 0) + return wipe_tower_size; + + for (int obj_idx = 0; obj_idx < m_model->objects.size(); obj_idx++) { + if (!use_global_objects && !contain_instance_totally(obj_idx, 0)) + continue; + + BoundingBoxf3 bbox = m_model->objects[obj_idx]->bounding_box(); + max_height = std::max(bbox.size().z(), max_height); + } + wipe_tower_size(2) = max_height; + + auto timelapse_type = config.option>("timelapse_type"); + bool timelapse_enabled = timelapse_type ? (timelapse_type->value == TimelapseType::tlSmooth) : false; + + int nozzle_nums = wxGetApp().preset_bundle->get_printer_extruder_count(); + double depth = std::sqrt(wipe_volume * (nozzle_nums == 2 ? plate_extruder_size : (plate_extruder_size - 1)) / layer_height); + if (timelapse_enabled || plate_extruder_size > 1) { + float min_wipe_tower_depth = WipeTower::get_limit_depth_by_height(max_height); + depth = std::max((double) min_wipe_tower_depth, depth); + wipe_tower_size(0) = wipe_tower_size(1) = depth; + } + + return wipe_tower_size; +} + Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double wipe_volume, int plate_extruder_size, bool use_global_objects) const { Vec3d wipe_tower_size; diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index bcb8e267a..f5aab6b27 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -304,6 +304,7 @@ public: BoundingBoxf3 get_objects_bounding_box(); Vec3d get_origin() { return m_origin; } + Vec3d calculate_wipe_tower_size(const DynamicPrintConfig &config, const double w, const double wipe_volume, int plate_extruder_size = 0, bool use_global_objects = false) const; Vec3d estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double wipe_volume, int plate_extruder_size = 0, bool use_global_objects = false) const; arrangement::ArrangePolygon estimate_wipe_tower_polygon(const DynamicPrintConfig & config, int plate_index, int plate_extruder_size = 0, bool use_global_objects = false) const; bool check_objects_empty_and_gcode3mf(std::vector &result) const;