From e77259c80bcbf5ac7ed684d15c7c3f8ce4bd98e6 Mon Sep 17 00:00:00 2001 From: Wang YB <94800665+Gradbb@users.noreply.github.com> Date: Tue, 21 May 2024 11:32:40 +0800 Subject: [PATCH] add scarf seam --- src/libslic3r/ExtrusionEntity.cpp | 47 +++++ src/libslic3r/ExtrusionEntity.hpp | 2 + src/libslic3r/GCode.cpp | 261 ++++++++++++++++++++++++- src/libslic3r/GCode.hpp | 46 ++++- src/libslic3r/GCode/GCodeProcessor.cpp | 36 +++- src/libslic3r/GCode/GCodeProcessor.hpp | 9 +- src/libslic3r/GCode/GCodeWriter.cpp | 8 +- src/libslic3r/GCode/GCodeWriter.hpp | 3 +- src/libslic3r/Model.hpp | 10 + src/libslic3r/Preset.cpp | 3 + src/libslic3r/PrintApply.cpp | 22 +++ src/libslic3r/PrintConfig.cpp | 76 +++++++ src/libslic3r/PrintConfig.hpp | 20 ++ src/libslic3r/PrintObject.cpp | 10 + src/slic3r/GUI/ConfigManipulation.cpp | 11 ++ src/slic3r/GUI/Tab.cpp | 12 ++ 16 files changed, 555 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp index 5e69e12..2f01c59 100644 --- a/src/libslic3r/ExtrusionEntity.cpp +++ b/src/libslic3r/ExtrusionEntity.cpp @@ -9,6 +9,9 @@ #include #include +//w37 +#include "libslic3r/Utils.hpp" + namespace Slic3r { void ExtrusionPath::intersect_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const @@ -334,4 +337,48 @@ double ExtrusionLoop::min_mm3_per_mm() const return min_mm3_per_mm; } +//w37 +bool ExtrusionLoop::check_seam_point_angle(double angle_threshold, double min_arm_length) const +{ + // go through all the points in the loop and check if the angle between two segments(AB and BC) is less than the threshold + size_t idx_prev = 0; + size_t idx_curr = 0; + size_t idx_next = 0; + + float distance_to_prev = 0; + float distance_to_next = 0; + + const auto _polygon = polygon(); + const Points &points = _polygon.points; + + std::vector lengths{}; + for (size_t point_idx = 0; point_idx < points.size() - 1; ++point_idx) { + lengths.push_back((unscale(points[point_idx]) - unscale(points[point_idx + 1])).norm()); + } + lengths.push_back(std::max((unscale(points[0]) - unscale(points[points.size() - 1])).norm(), 0.1)); + + // push idx_prev far enough back as initialization + while (distance_to_prev < min_arm_length) { + idx_prev = Slic3r::prev_idx_modulo(idx_prev, points.size()); + distance_to_prev += lengths[idx_prev]; + } + + // push idx_next forward as far as needed + while (distance_to_next < min_arm_length) { + distance_to_next += lengths[idx_next]; + idx_next = Slic3r::next_idx_modulo(idx_next, points.size()); + } + + // Calculate angle between idx_prev, idx_curr, idx_next. + const Point &p0 = points[idx_prev]; + const Point &p1 = points[idx_curr]; + const Point &p2 = points[idx_next]; + const auto a = angle(p0 - p1, p2 - p1); + if (a > 0 ? a < angle_threshold : a > -angle_threshold) { + return false; + } + + return true; +} + } diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index bd1dbce..9d08d17 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -326,6 +326,8 @@ public: append(dst, p.polyline.points); } double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } + //w37 + bool check_seam_point_angle(double angle_threshold = 0.174, double min_arm_length = 0.025) const; #ifndef NDEBUG bool validate() const { diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 5372a82..bb3e3a9 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2952,10 +2952,12 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC // Extrude all loops CCW. bool is_hole = loop_src.is_clockwise(); Point seam_point = this->last_position.has_value() ? *this->last_position : Point::Zero(); - if (! m_config.spiral_vase && comment_is_perimeter(description)) { + //w37 + if ((!m_config.spiral_vase && comment_is_perimeter(description)) || (this->config().seam_slope_type == SeamScarfType::None) &&comment_is_perimeter(description) ) { assert(m_layer != nullptr); seam_point = m_seam_placer.place_seam(m_layer, loop_src, m_config.external_perimeters_first, seam_point); } + // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns, // thus empty path segments will not be produced by G-code export. GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit_split_with_seam( @@ -2978,8 +2980,95 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC // Extrude along the smooth path. std::string gcode; - for (const GCode::SmoothPathElement &el : smooth_path) - gcode += this->_extrude(el.path_attributes, el.path, description, speed); + + //w37 + double ext_length = 0; + double inner_length = 0; + double start_height = 0; + bool enable_seam_slope = loop_src.check_seam_point_angle(m_config.scarf_angle_threshold.value * M_PI / 180.0); + if (this->config().seam_slope_start_height.percent) + start_height = this->config().seam_slope_start_height * this->config().layer_height / 100; + else + start_height = this->config().seam_slope_start_height; + double height_for_lift = this->config().layer_height - start_height; + if (enable_seam_slope) + for (const GCode::SmoothPathElement &el : smooth_path) { + Vec2d prev_exact = this->point_to_gcode(el.path.front().point); + Vec2d prev = GCodeFormatter::quantize(prev_exact); + auto it = el.path.begin(); + auto end = el.path.end(); + double sum_lift = 0; + for (++it; it != end; ++it) { + Vec2d p_exact = this->point_to_gcode(it->point); + Vec2d p = GCodeFormatter::quantize(p_exact); + double line_length = (p - prev).norm(); + /* if (el.path_attributes.role.is_external_perimeter()) + ext_length += line_length; + if (el.path_attributes.role.is_perimeter()) + inner_length += line_length;*/ + double x1 = prev.x(); + double x2 = p.x(); + double y1 = prev.y(); + double y2 = p.y(); + double temp_length = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + if (el.path_attributes.role.is_external_perimeter()) + ext_length += temp_length; + if (el.path_attributes.role.is_perimeter()) + inner_length += temp_length; + prev = p; + prev_exact = p_exact; + } + + + /* for (int i = 0; i < el.path.size() - 1; i++) { + double x1 = el.path[i].point.x(); + double x2 = el.path[i + 1].point.x(); + double y1 = el.path[i].point.y(); + double y2 = el.path[i+1].point.y(); + double temp_length = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + if (el.path_attributes.role.is_external_perimeter()) + ext_length += temp_length; + if (el.path_attributes.role.is_perimeter()) + inner_length += temp_length; + }*/ + } + //w37 + double ext_ratio = 0; + if (ext_length != 0) + ext_ratio = height_for_lift / ext_length; + double inner_ratio = 0; + if (inner_length != 0) + inner_ratio = height_for_lift / inner_length; + if (!this->config().seam_slope_entire_loop && ext_length > this->config().seam_slope_min_length) { + ext_ratio = height_for_lift / this->config().seam_slope_min_length; + } + if (!this->config().seam_slope_entire_loop && inner_length > this->config().seam_slope_min_length) { + inner_ratio = height_for_lift / this->config().seam_slope_min_length; + } + //GCode::SmoothPath new_path = smooth_path; + //if (this->config().seam_slope_type != SeamScarfType::None) { + //GCode::SmoothPath new_path = smooth_path; + // set_step_path(new_path, this->config().seam_slope_steps); + //} + //w37 + for (const GCode::SmoothPathElement &el : smooth_path) { + if (((this->config().seam_slope_type == SeamScarfType::None) || (this->config().seam_slope_type == SeamScarfType::External && is_hole))|| !enable_seam_slope) + gcode += this->_extrude(el.path_attributes, el.path, description, speed); + else { + if (el.path_attributes.role.is_external_perimeter() && this->config().seam_slope_type != SeamScarfType::None) + gcode += this->_extrude(el.path_attributes, el.path, description, speed, ext_ratio); + else if (el.path_attributes.role.is_perimeter() && this->config().seam_slope_type != SeamScarfType::None && + this->config().seam_slope_inner_walls) + gcode += this->_extrude(el.path_attributes, el.path, description, speed, inner_ratio); + else if (el.path_attributes.role.is_perimeter() && this->config().seam_slope_type != SeamScarfType::None && + !this->config().seam_slope_inner_walls) + gcode += this->_extrude(el.path_attributes, el.path, description, speed); + } + //this->sum_lift_z = 0; + //this->sum_lift_z_ext = 0; + } + this->sum_lift_z = 0; + this->sum_lift_z_ext = 0; // reset acceleration gcode += m_writer.set_print_acceleration(fast_round_up(m_config.default_acceleration.value)); @@ -3220,7 +3309,19 @@ std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point, const gcode += insert_gcode(); gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), comment); - gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), comment); + //w37 + //gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), comment); + //w37 + double start_height = 0; + if (this->config().seam_slope_start_height.percent) + start_height = this->config().seam_slope_start_height * this->config().layer_height / 100; + else + start_height = this->config().seam_slope_start_height; + double height_for_lift = this->config().layer_height - start_height; + if (this->config().seam_slope_type != SeamScarfType::None && (role.is_external_perimeter() ||role.is_perimeter())&& !this->on_first_layer()) + gcode += this->writer().get_travel_to_z_gcode(gcode_point.z() - height_for_lift, comment); + else + gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), comment); this->m_avoid_crossing_perimeters.reset_once_modifiers(); this->last_position = point.head<2>(); @@ -3247,7 +3348,9 @@ std::string GCodeGenerator::_extrude( const ExtrusionAttributes &path_attr, const Geometry::ArcWelder::Path &path, const std::string_view description, - double speed) + double speed, + //w37 + double radio) { std::string gcode; const std::string_view description_bridge = path_attr.role.is_bridge() ? " (bridge)"sv : ""sv; @@ -3281,6 +3384,18 @@ std::string GCodeGenerator::_extrude( return m_writer.multiple_extruders ? "" : m_label_objects.maybe_change_instance(m_writer); })}; gcode += travel_gcode; + //w37 + if (this->config().seam_slope_type != SeamScarfType::None && + (path_attr.role.is_external_perimeter() || path_attr.role.is_perimeter()) && !this->on_first_layer()) { + double start_height = 0; + if (this->config().seam_slope_start_height.percent) + start_height = this->config().seam_slope_start_height * this->config().layer_height / 100; + else + start_height = this->config().seam_slope_start_height; + double height_for_lift = this->config().layer_height - start_height; + + gcode += this->m_writer.get_travel_to_z_gcode(this->m_last_layer_z - height_for_lift, comment); + } } } @@ -3483,10 +3598,30 @@ std::string GCodeGenerator::_extrude( comment = description; comment += description_bridge; } + //w37 + //Geometry::ArcWelder::Path new_path = path; + int seam_slope_steps = this->config().seam_slope_steps; + // if (path.size() < seam_slope_steps) + // set_step_path(&new_path, seam_slope_steps); Vec2d prev_exact = this->point_to_gcode(path.front().point); Vec2d prev = GCodeFormatter::quantize(prev_exact); - auto it = path.begin(); - auto end = path.end(); + auto it = path.begin(); + auto end = path.end(); + + //w37 + double sum_lift = 0; + double start_height = 0; + if (this->config().seam_slope_start_height.percent) + start_height = this->config().seam_slope_start_height * this->config().layer_height / 100; + else + start_height = this->config().seam_slope_start_height; + double height_for_lift = this->config().layer_height - start_height; + std::vector point_lift; + std::vector length_vec; + std::vector radio_vec; + bool is_first_loop = true ; + Vec2d first_point ; + Vec2d end_point; for (++ it; it != end; ++ it) { Vec2d p_exact = this->point_to_gcode(it->point); Vec2d p = GCodeFormatter::quantize(p_exact); @@ -3511,8 +3646,57 @@ std::string GCodeGenerator::_extrude( } if (radius == 0) { // Extrude line segment. - if (const double line_length = (p - prev).norm(); line_length > 0) - gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); + //w37 + double curt_length = 0; + if (radio!=0) { + double x1 = p.x(); + double x2 = prev.x(); + double y1 = p.y(); + double y2 = prev.y(); + curt_length = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + } + if (const double line_length = (p - prev).norm(); line_length > 0) { + if (curt_length == 0 || this->on_first_layer() || this->sum_lift_z >= height_for_lift) + gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); + else { + /* if (path_attr.role.is_external_perimeter()) { + double cur_lift = curt_length * radio; + if (this->sum_lift_z_ext + cur_lift >= height_for_lift) + cur_lift = height_for_lift - this->sum_lift_z_ext; + Vec3d new_p(p.x(), p.y(), this->m_last_layer_z - height_for_lift + this->sum_lift_z_ext + cur_lift); + gcode += m_writer.extrude_to_xyz(new_p, e_per_mm * line_length, comment); + this->sum_lift_z_ext += cur_lift; + } + if (path_attr.role.is_perimeter()) { + double cur_lift = curt_length * radio; + if (this->sum_lift_z + cur_lift >= height_for_lift) + cur_lift = height_for_lift - this->sum_lift_z; + Vec3d new_p(p.x(), p.y(), this->m_last_layer_z - height_for_lift + this->sum_lift_z + cur_lift); + gcode += m_writer.extrude_to_xyz(new_p, e_per_mm * line_length, comment); + this->sum_lift_z += cur_lift; + }*/ + double cur_lift = curt_length * radio; + if (this->sum_lift_z + cur_lift >= height_for_lift) + cur_lift = height_for_lift - this->sum_lift_z; + double lift_radio = 0; + lift_radio = (start_height + this->sum_lift_z + cur_lift) / this->config().layer_height; + + Vec3d new_p(p.x(), p.y(), this->m_last_layer_z - height_for_lift + this->sum_lift_z + cur_lift); + if (is_first_loop) { + first_point = prev; + is_first_loop = false; + } + end_point = p; + point_lift.emplace_back(new_p); + length_vec.emplace_back(line_length); + radio_vec.emplace_back(lift_radio); + //lift_radio += 0.2; + //if (lift_radio > 1) + // lift_radio = 1; + gcode += m_writer.extrude_to_xyz(new_p, e_per_mm * line_length * lift_radio , comment); + this->sum_lift_z += cur_lift; + } + } } else { double angle = Geometry::ArcWelder::arc_angle(prev.cast(), p.cast(), double(radius)); assert(angle > 0); @@ -3525,6 +3709,65 @@ std::string GCodeGenerator::_extrude( prev_exact = p_exact; } } + + //w37 + if (this->config().seam_slope_type != SeamScarfType::None && + (path_attr.role.is_external_perimeter() || path_attr.role.is_perimeter()) && !this->on_first_layer() && radio != 0) { + prev_exact = this->point_to_gcode(path.front().point); + prev = GCodeFormatter::quantize(prev_exact); + it = path.begin(); + end = path.end(); + length_vec[0] += (first_point - end_point).norm(); + for (int i = 0; i < point_lift.size(); i++) { + Vec3d cur_point = point_lift[i]; + double line_length = length_vec[i]; + double wipe_radio = radio_vec[i]; + Vec2d cur_point2d(cur_point.x(), cur_point.y()); + gcode += m_writer.extrude_to_xy(cur_point2d, e_per_mm * line_length * (1 - wipe_radio), comment); + } + /* for (++it; it != end; ++it) { + Vec2d p_exact = this->point_to_gcode(it->point); + Vec2d p = GCodeFormatter::quantize(p_exact); + assert(p != prev); + if (p != prev) { + // Center of the radius to be emitted into the G-code: Either by radius or by center offset. + double radius = 0; + Vec2d ij; + if (it->radius != 0) { + // Extrude an arc. + assert(m_config.arc_fitting == ArcFittingType::EmitCenter); + radius = unscaled(it->radius); + { + // Calculate quantized IJ circle center offset. + ij = GCodeFormatter::quantize(Vec2d( + Geometry::ArcWelder::arc_center(prev_exact.cast(), p_exact.cast(), double(radius), it->ccw()) - + prev)); + if (ij == Vec2d::Zero()) + // Don't extrude a degenerated circle. + radius = 0; + } + } + if (radius == 0) { + // Extrude line segment. + double curt_length = 0; + if (radio != 0) { + double x1 = p.x(); + double x2 = prev.x(); + double y1 = p.y(); + double y2 = prev.y(); + curt_length = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + } + if (const double line_length = (p - prev).norm(); line_length > 0) { + if (curt_length != 0 || !this->on_first_layer()) + gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length/10, comment); + + } + } + prev = p; + prev_exact = p_exact; + } + }*/ + } if (m_enable_cooling_markers) gcode += path_attr.role.is_bridge() ? ";_BRIDGE_FAN_END\n" : ";_EXTRUDE_END\n"; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index db66349..7472fee 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -166,6 +166,10 @@ public: std::optional last_position; + //w37 + double sum_lift_z_ext = 0; + double sum_lift_z = 0; + private: class GCodeOutputStream { public: @@ -267,6 +271,45 @@ private: std::string extrude_multi_path(const ExtrusionMultiPath &multipath, bool reverse, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.); std::string extrude_path(const ExtrusionPath &path, bool reverse, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.); + //w37 + void set_step_path(GCode::SmoothPath &path, const int steps) + { + double max_line_length =0; + double nums_line = 0; + int p1_i_index=-1; + int p1_j_index=-1; + Line max_line; + for (int i = 0; i < path.size(); i++) { + nums_line += path[i].path.size() - 1; + } + while (nums_line < steps) { + for (int i = 0; i < path.size(); i++) { + for (int j = 0; j < path[i].path.size() - 1; j++) { + Point p1 = path[i].path[j].point; + Point p2 = path[i].path[j + 1].point; + Line cur_l(p1, p2); + if (cur_l.length() > max_line_length) { + max_line_length = cur_l.length(); + p1_i_index = i; + p1_j_index = j; + max_line = cur_l; + } + } + } + if (p1_i_index >= 0 && p1_j_index >= 0) { + Point midpt = max_line.midpoint(); + Geometry::ArcWelder::Segment temp_val; + temp_val.point = midpt; + path[p1_i_index].path.insert(path[p1_i_index].path.begin() +1+ p1_j_index, temp_val); + } + nums_line = 0; + for (int i = 0; i < path.size(); i++) { + nums_line += path[i].path.size() - 1; + } + } + + + } struct InstanceToPrint { InstanceToPrint(size_t object_layer_to_print_id, const PrintObject &print_object, size_t instance_id) : @@ -457,8 +500,9 @@ private: // Back-pointer to Print (const). const Print* m_print; + //w37 std::string _extrude( - const ExtrusionAttributes &attribs, const Geometry::ArcWelder::Path &path, const std::string_view description, double speed = -1); + const ExtrusionAttributes &attribs, const Geometry::ArcWelder::Path &path, const std::string_view description, double speed = -1,double ratio = 0); void print_machine_envelope(GCodeOutputStream &file, const Print &print); void _print_first_layer_bed_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait); void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, const Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait); diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 7948afc..06143b8 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -668,8 +668,14 @@ for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode:: m_result.max_print_height = config.max_print_height; const ConfigOptionBool* spiral_vase = config.option("spiral_vase"); + //w37 if (spiral_vase != nullptr) - m_spiral_vase_active = spiral_vase->value; + m_detect_layer_based_on_tag = spiral_vase->value;//m_spiral_vase_active = spiral_vase->value; + + //w37 + const ConfigOptionBool *has_scarf_joint_seam = config.option("has_scarf_joint_seam"); + if (has_scarf_joint_seam != nullptr) + m_detect_layer_based_on_tag = m_detect_layer_based_on_tag || has_scarf_joint_seam->value; const ConfigOptionFloat* z_offset = config.option("z_offset"); if (z_offset != nullptr) @@ -950,8 +956,14 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_result.max_print_height = max_print_height->value; const ConfigOptionBool* spiral_vase = config.option("spiral_vase"); + //w37 if (spiral_vase != nullptr) - m_spiral_vase_active = spiral_vase->value; + m_detect_layer_based_on_tag = spiral_vase->value;//m_spiral_vase_active = spiral_vase->value; + + //w37 + const ConfigOptionBool *has_scarf_joint_seam = config.option("has_scarf_joint_seam"); + if (has_scarf_joint_seam != nullptr) + m_detect_layer_based_on_tag = m_detect_layer_based_on_tag || has_scarf_joint_seam->value; const ConfigOptionFloat* z_offset = config.option("z_offset"); if (z_offset != nullptr) @@ -1022,7 +1034,11 @@ void GCodeProcessor::reset() m_options_z_corrector.reset(); - m_spiral_vase_active = false; + //w37 + //m_spiral_vase_active = false; + m_detect_layer_based_on_tag = false; + m_seams_count = 0; + m_kissslicer_toolchange_time_correction = 0.0f; m_single_extruder_multi_material = false; @@ -1989,12 +2005,14 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers // layer change tag if (comment == reserved_tag(ETags::Layer_Change)) { ++m_layer_id; - if (m_spiral_vase_active) { + //w37 + if (m_detect_layer_based_on_tag) { // if (m_spiral_vase_active) { if (m_result.moves.empty() || m_result.spiral_vase_layers.empty()) // add a placeholder for layer height. the actual value will be set inside process_G1() method m_result.spiral_vase_layers.push_back({ FLT_MAX, { 0, 0 } }); else { - const size_t move_id = m_result.moves.size() - 1; + //w37 + const size_t move_id = m_result.moves.size() - 1 - m_seams_count;//const size_t move_id = m_result.moves.size() - 1; if (!m_result.spiral_vase_layers.empty()) m_result.spiral_vase_layers.back().second.second = move_id; // add a placeholder for layer height. the actual value will be set inside process_G1() method @@ -2880,7 +2898,8 @@ void GCodeProcessor::process_G1(const std::array, 4>& axes m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); } - if (m_spiral_vase_active && !m_result.spiral_vase_layers.empty()) { + //w37 + if (m_detect_layer_based_on_tag && !m_result.spiral_vase_layers.empty()) {//if (m_spiral_vase_active && !m_result.spiral_vase_layers.empty()) { if (m_result.spiral_vase_layers.back().first == FLT_MAX && delta_pos[Z] >= 0.0) // replace layer height placeholder with correct value m_result.spiral_vase_layers.back().first = static_cast(m_end_position[Z]); @@ -4437,6 +4456,11 @@ void GCodeProcessor::store_move_vertex(EMoveType type, bool internal_only) internal_only }); + //w37 + if (type == EMoveType::Seam) { + m_seams_count++; + } + // stores stop time placeholders for later use if (type == EMoveType::Color_change || type == EMoveType::Pause_Print) { for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 3664437..58eb2e1 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -596,7 +596,10 @@ namespace Slic3r { SeamsDetector m_seams_detector; OptionsZCorrector m_options_z_corrector; size_t m_last_default_color_id; - bool m_spiral_vase_active; + //w37 + //bool m_spiral_vase_active; + bool m_detect_layer_based_on_tag{false}; + int m_seams_count; float m_kissslicer_toolchange_time_correction; #if ENABLE_GCODE_VIEWER_STATISTICS std::chrono::time_point m_start_time; @@ -676,6 +679,10 @@ namespace Slic3r { std::vector> get_moves_time(PrintEstimatedStatistics::ETimeMode mode) const; std::vector> get_roles_time(PrintEstimatedStatistics::ETimeMode mode) const; std::vector get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const; + //w37 + void detect_layer_based_on_tag(bool enabled) { + m_detect_layer_based_on_tag = enabled; + } private: void apply_config(const DynamicPrintConfig& config); diff --git a/src/libslic3r/GCode/GCodeWriter.cpp b/src/libslic3r/GCode/GCodeWriter.cpp index 5fc08a3..daf6520 100644 --- a/src/libslic3r/GCode/GCodeWriter.cpp +++ b/src/libslic3r/GCode/GCodeWriter.cpp @@ -444,7 +444,8 @@ std::string GCodeWriter::extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &i return w.string(); } -#if 0 +//w37 +//#if 0 std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std::string_view comment) { m_pos = point; @@ -453,11 +454,12 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std GCodeG1Formatter w; w.emit_xyz(point); - w.emit_e(m_extrusion_axis, m_extruder->E()); + //w37 + w.emit_e(m_extrusion_axis, m_extruder->extrude(dE).second); w.emit_comment(this->config.gcode_comments, comment); return w.string(); } -#endif +//#endif std::string GCodeWriter::retract(bool before_wipe) { diff --git a/src/libslic3r/GCode/GCodeWriter.hpp b/src/libslic3r/GCode/GCodeWriter.hpp index 22b592e..f6d036a 100644 --- a/src/libslic3r/GCode/GCodeWriter.hpp +++ b/src/libslic3r/GCode/GCodeWriter.hpp @@ -84,7 +84,8 @@ public: std::string travel_to_z(double z, const std::string_view comment = {}); std::string extrude_to_xy(const Vec2d &point, double dE, const std::string_view comment = {}); std::string extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, double dE, const std::string_view comment); -// std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string_view comment = {}); + //w37 + std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string_view comment = {}); std::string retract(bool before_wipe = false); std::string retract_for_toolchange(bool before_wipe = false); std::string unretract(); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 9de4f72..314b45b 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -367,6 +367,16 @@ public: Model* get_model() { return m_model; } const Model* get_model() const { return m_model; } + //w37 + int get_backup_id() const; + template const T *get_config_value(const DynamicPrintConfig &global_config, const std::string &config_option) + { + if (config.has(config_option)) + return static_cast(config.option(config_option)); + else + return global_config.option(config_option); + } + ModelVolume* add_volume(const TriangleMesh &mesh); ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART); ModelVolume* add_volume(const ModelVolume &volume, ModelVolumeType type = ModelVolumeType::INVALID); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 66f36ee..778b7ee 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -495,6 +495,9 @@ static std::vector s_Preset_print_options { ,"top_solid_infill_flow_ratio", "bottom_solid_infill_flow_ratio" //w33 ,"ironing_pattern" + //w37 + ,"seam_slope_type", "seam_slope_conditional", "scarf_angle_threshold", "seam_slope_start_height", "seam_slope_entire_loop", "seam_slope_min_length", + "seam_slope_steps", "seam_slope_inner_walls" }; static std::vector s_Preset_filament_options { diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index efdc5ac..3efcc5f 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -980,6 +980,28 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ new_full_config.option("physical_printer_settings_id", true); new_full_config.normalize_fdm(); + //w37 + { + const auto &o = model.objects; + const auto opt_has_scarf_joint_seam = [](const DynamicConfig &c) { + return c.has("seam_slope_type") && c.opt_enum("seam_slope_type") != SeamScarfType::None; + }; + const bool has_scarf_joint_seam = std::any_of(o.begin(), o.end(), [&new_full_config, &opt_has_scarf_joint_seam](ModelObject *obj) { + return obj->get_config_value>(new_full_config, "seam_slope_type")->value != + SeamScarfType::None || + std::any_of(obj->volumes.begin(), obj->volumes.end(), + [&opt_has_scarf_joint_seam](const ModelVolume *v) { return opt_has_scarf_joint_seam(v->config.get()); }) || + std::any_of(obj->layer_config_ranges.begin(), obj->layer_config_ranges.end(), + [&opt_has_scarf_joint_seam](const auto &r) { return opt_has_scarf_joint_seam(r.second.get()); }); + }); + + if (has_scarf_joint_seam) { + new_full_config.set("has_scarf_joint_seam", true); + } + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", has_scarf_joint_seam:" << has_scarf_joint_seam; + } + // Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles. DynamicPrintConfig filament_overrides; t_config_option_keys print_diff = print_config_diffs(m_config, new_full_config, filament_overrides); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 7859580..ff94f6c 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -170,6 +170,14 @@ static const t_config_enum_values s_keys_map_SeamPosition { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SeamPosition) +//w37 +static t_config_enum_values s_keys_map_SeamScarfType{ + {"none", int(SeamScarfType::None)}, + {"external", int(SeamScarfType::External)}, + {"all", int(SeamScarfType::All)}, +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SeamScarfType) + static const t_config_enum_values s_keys_map_SLADisplayOrientation = { { "landscape", sladoLandscape}, { "portrait", sladoPortrait} @@ -1984,6 +1992,11 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(MachineLimitsUsage::TimeEstimateOnly)); + //w37 + def = this->add("has_scarf_joint_seam", coBool); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + { struct AxisDefault { std::string name; @@ -2679,6 +2692,69 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionPercent(15)); + //w37 + def = this->add("seam_slope_type", coEnum); + def->label = L("Scarf joint seam (beta)"); + def->tooltip = L("Use scarf joint to minimize seam visibility and increase seam strength."); + def->set_enum({{"none", L("None")}, {"external", L("Contour")}, {"all", L("Contour and hole")}}); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionEnum(SeamScarfType::None)); + + def = this->add("seam_slope_conditional", coBool); + def->label = L("Conditional scarf joint"); + def->tooltip = L( + "Apply scarf joints only to smooth perimeters where traditional seams do not conceal the seams at sharp corners effectively."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(true)); + + def = this->add("scarf_angle_threshold", coInt); + def->label = L("Conditional angle threshold"); + def->tooltip = L( + "This option sets the threshold angle for applying a conditional scarf joint seam.\nIf the maximum angle within the perimeter loop " + "exceeds this value (indicating the absence of sharp corners), a scarf joint seam will be used. The default value is 155°."); + def->mode = comAdvanced; + def->sidetext = L("°"); + def->min = 0; + def->max = 180; + def->set_default_value(new ConfigOptionInt(155)); + + def = this->add("seam_slope_start_height", coFloatOrPercent); + def->label = L("Scarf start height"); + def->tooltip = L("Start height of the scarf.\n" + "This amount can be specified in millimeters or as a percentage of the current layer height. The default value for " + "this parameter is 0."); + def->sidetext = L("mm or %"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloatOrPercent(0.1, false)); + + def = this->add("seam_slope_entire_loop", coBool); + def->label = L("Scarf around entire wall"); + def->tooltip = L("The scarf extends to the entire length of the wall."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("seam_slope_min_length", coFloat); + def->label = L("Scarf length"); + def->tooltip = L("Length of the scarf. Setting this parameter to zero effectively disables the scarf."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(10)); + + def = this->add("seam_slope_steps", coInt); + def->label = L("Scarf steps"); + def->tooltip = L("Minimum number of segments of each scarf."); + def->min = 1; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionInt(10)); + + def = this->add("seam_slope_inner_walls", coBool); + def->label = L("Scarf joint for inner walls"); + def->tooltip = L("Use scarf joint for inner walls as well."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(true)); + def = this->add("staggered_inner_seams", coBool); def->label = L("Staggered inner seams"); // TRN PrintSettings: "Staggered inner seams" diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 327b596..9885271 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -106,6 +106,13 @@ enum SeamPosition { spRandom, spNearest, spAligned, spRear }; +//w37 +enum class SeamScarfType { + None, + External, + All, +}; + enum SLAMaterial { slamTough, slamFlex, @@ -168,6 +175,8 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialPattern) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialStyle) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialInterfacePattern) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SeamPosition) +//w37 +CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SeamScarfType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLADisplayOrientation) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLAPillarConnectionMode) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLASupportTreeType) @@ -607,6 +616,15 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, only_one_wall_first_layer)) //w27 ((ConfigOptionBool, precise_z_height)) + //w37 + ((ConfigOptionEnum, seam_slope_type)) + ((ConfigOptionBool, seam_slope_conditional)) + ((ConfigOptionInt, scarf_angle_threshold)) + ((ConfigOptionFloatOrPercent, seam_slope_start_height)) + ((ConfigOptionBool, seam_slope_entire_loop)) + ((ConfigOptionFloat, seam_slope_min_length)) + ((ConfigOptionInt, seam_slope_steps)) + ((ConfigOptionBool, seam_slope_inner_walls)) ) PRINT_CONFIG_CLASS_DEFINE( @@ -707,6 +725,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloats, machine_min_travel_rate)) // M205 S... [mm/sec] ((ConfigOptionFloats, machine_min_extruding_rate)) + //w37 + ((ConfigOptionBool, has_scarf_joint_seam)) ) PRINT_CONFIG_CLASS_DEFINE( diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 69dc0d3..f76dbe7 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -884,6 +884,16 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "seam_gap" || opt_key == "seam_preferred_direction" || opt_key == "seam_preferred_direction_jitter" + //w37 + || opt_key == "seam_slope_type" + || opt_key == "seam_slope_conditional" + || opt_key == "scarf_angle_threshold" + || opt_key == "seam_slope_start_height" + || opt_key == "seam_slope_entire_loop" + || opt_key == "seam_slope_min_length" + || opt_key == "seam_slope_steps" + || opt_key == "seam_slope_inner_walls" + || opt_key == "support_material_speed" || opt_key == "support_material_interface_speed" || opt_key == "bridge_speed" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index b9b9a88..d49adc0 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -380,6 +380,17 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) bool is_top_one_wall = config->opt_enum("top_one_wall_type") != TopOneWallType::Disable; toggle_field("top_area_threshold", is_top_one_wall); + //w37 + toggle_field("seam_slope_type", !has_spiral_vase); + bool has_seam_slope = !has_spiral_vase && config->opt_enum("seam_slope_type") != SeamScarfType::None; + toggle_field("seam_slope_conditional", has_seam_slope); + toggle_field("scarf_angle_threshold", has_seam_slope && config->opt_bool("seam_slope_conditional")); + toggle_field("seam_slope_start_height", has_seam_slope); + toggle_field("seam_slope_entire_loop", has_seam_slope); + toggle_field("seam_slope_min_length", has_seam_slope); + toggle_field("seam_slope_steps", has_seam_slope); + toggle_field("seam_slope_inner_walls", has_seam_slope); + toggle_field("seam_slope_min_length", !config->opt_bool("seam_slope_entire_loop")); } void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index e87057e..915d544 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1465,6 +1465,18 @@ void TabPrint::build() //Y21 optgroup->append_single_option_line("seam_gap", category_path + "seam-gap"); optgroup->append_single_option_line("staggered_inner_seams", category_path + "staggered-inner-seams"); + + //w37 + optgroup->append_single_option_line("seam_slope_type"); + optgroup->append_single_option_line("seam_slope_conditional"); + optgroup->append_single_option_line("scarf_angle_threshold"); + optgroup->append_single_option_line("seam_slope_start_height"); + optgroup->append_single_option_line("seam_slope_entire_loop"); + optgroup->append_single_option_line("seam_slope_min_length"); + //optgroup->append_single_option_line("seam_slope_steps"); + optgroup->append_single_option_line("seam_slope_inner_walls"); + + optgroup->append_single_option_line("external_perimeters_first", category_path + "external-perimeters-first"); optgroup->append_single_option_line("gap_fill_enabled", category_path + "fill-gaps"); optgroup->append_single_option_line("perimeter_generator");