Skip to content

Commit

Permalink
Scarf joint seam enhancement: conditional scarf joint and slowdown fo…
Browse files Browse the repository at this point in the history
…r scarf joint only (#4317)

* Allow apply scarf joint seams to perimeters without sharp corners only

* 1. Fix an error when detect whether a loop is smooth
2. Expose scarf_angle_threshold to UI

* fix linux build error

* minor code changes

* Support slowdown speed for scarf joint only

* update tips

* improve the logic a bit

* Fixed a bug that scarf speed may not respected for overhangs

* Add a new scarf flow ratio option
  • Loading branch information
SoftFever committed Mar 8, 2024
1 parent 6264fe6 commit a4bf3da
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 4 deletions.
60 changes: 60 additions & 0 deletions src/libslic3r/ExtrusionEntity.cpp
Expand Up @@ -7,6 +7,7 @@
#include <cmath>
#include <limits>
#include <sstream>
#include "Utils.hpp"

#define L(s) (s)

Expand Down Expand Up @@ -340,6 +341,65 @@ double ExtrusionLoop::min_mm3_per_mm() const
return min_mm3_per_mm;
}

// Orca: This function is used to check if the loop is smooth(continuous) or not.
// TODO: the main logic is largly copied from the calculate_polygon_angles_at_vertices function in SeamPlacer file. Need to refactor the code in the future.
bool ExtrusionLoop::is_smooth(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<float> 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];
}

for (size_t _i = 0; _i < points.size(); ++_i) {
// pull idx_prev to current as much as possible, while respecting the min_arm_length
while (distance_to_prev - lengths[idx_prev] > min_arm_length) {
distance_to_prev -= lengths[idx_prev];
idx_prev = Slic3r::next_idx_modulo(idx_prev, points.size());
}

// 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;
}

// increase idx_curr by one
float curr_distance = lengths[idx_curr];
idx_curr++;
distance_to_prev += curr_distance;
distance_to_next -= curr_distance;
}

return true;
}

ExtrusionLoopSloped::ExtrusionLoopSloped(ExtrusionPaths& original_paths,
double seam_gap,
double slope_min_length,
Expand Down
3 changes: 2 additions & 1 deletion src/libslic3r/ExtrusionEntity.hpp
Expand Up @@ -479,7 +479,8 @@ class ExtrusionLoop : public ExtrusionEntity
append(dst, p.polyline.points);
}
double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }

// check if the loop is smooth, angle_threshold is in radians, default is 10 degrees
bool is_smooth(double angle_threshold = 0.174, double min_arm_length = 0.025) const;
//static inline std::string role_to_string(ExtrusionLoopRole role);

#ifndef NDEBUG
Expand Down
21 changes: 20 additions & 1 deletion src/libslic3r/GCode.cpp
Expand Up @@ -4557,11 +4557,14 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
loop.split_at(last_pos, false);

const auto seam_scarf_type = m_config.seam_slope_type.value;
const bool enable_seam_slope = ((seam_scarf_type == SeamScarfType::External && !is_hole) || seam_scarf_type == SeamScarfType::All) &&
bool enable_seam_slope = ((seam_scarf_type == SeamScarfType::External && !is_hole) || seam_scarf_type == SeamScarfType::All) &&
!m_config.spiral_mode &&
(loop.role() == erExternalPerimeter || (loop.role() == erPerimeter && m_config.seam_slope_inner_walls)) &&
layer_id() > 0;

if (enable_seam_slope && m_config.seam_slope_conditional.value) {
enable_seam_slope = loop.is_smooth(m_config.scarf_angle_threshold.value * M_PI / 180., EXTRUDER_CONFIG(nozzle_diameter));
}
// clip the path to avoid the extruder to get exactly on the first point of the loop;
// if polyline was shorter than the clipping distance we'd get a null polyline, so
// we discard it in that case
Expand Down Expand Up @@ -5068,6 +5071,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
_mm3_per_mm *= m_config.bottom_solid_infill_flow_ratio;
else if (path.role() == erInternalBridgeInfill)
_mm3_per_mm *= m_config.internal_bridge_flow;
else if(sloped)
_mm3_per_mm *= m_config.scarf_joint_flow_ratio;


double e_per_mm = m_writer.extruder()->e_per_mm3() * _mm3_per_mm;
Expand All @@ -5082,13 +5087,20 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
double new_speed = m_config.get_abs_value(overhang_speed_key_map[overhang_degree].c_str());
speed = new_speed == 0.0 ? speed : new_speed;
}

if (sloped) {
speed = std::min(speed, m_config.scarf_joint_speed.get_abs_value(m_config.get_abs_value("inner_wall_speed")));
}
} else if (path.role() == erExternalPerimeter) {
speed = m_config.get_abs_value("outer_wall_speed");
if (m_config.overhang_speed_classic.value && m_config.enable_overhang_speed.value &&
overhang_degree > 0 && overhang_degree <= 5) {
double new_speed = m_config.get_abs_value(overhang_speed_key_map[overhang_degree].c_str());
speed = new_speed == 0.0 ? speed : new_speed;
}
if (sloped) {
speed = std::min(speed, m_config.scarf_joint_speed.get_abs_value(m_config.get_abs_value("outer_wall_speed")));
}
}
else if(path.role() == erInternalBridgeInfill) {
speed = m_config.get_abs_value("internal_bridge_speed");
Expand Down Expand Up @@ -5172,6 +5184,9 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
(is_bridge(path.role()) || is_perimeter(path.role()))) {
bool is_external = is_external_perimeter(path.role());
double ref_speed = is_external ? m_config.get_abs_value("outer_wall_speed") : m_config.get_abs_value("inner_wall_speed");
if (sloped) {
ref_speed = std::min(ref_speed, m_config.scarf_joint_speed.get_abs_value(ref_speed));
}
ConfigOptionPercents overhang_overlap_levels({75, 50, 25, 13, 12.99, 0});

if (m_config.slowdown_for_curled_perimeters){
Expand Down Expand Up @@ -5235,6 +5250,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
}

double F = speed * 60; // convert mm/sec to mm/min
if(abs(F - 5753.504) < 0.002)
{
std::cout << "F: " << F << std::endl;
}

//Orca: process custom gcode for extrusion role change
if (path.role() != m_last_extrusion_role && !m_config.change_extrusion_role_gcode.value.empty()) {
Expand Down
4 changes: 4 additions & 0 deletions src/libslic3r/Layer.cpp
Expand Up @@ -186,6 +186,10 @@ void Layer::make_perimeters()
&& config.fuzzy_skin_point_distance == other_config.fuzzy_skin_point_distance
&& config.fuzzy_skin_first_layer == other_config.fuzzy_skin_first_layer
&& config.seam_slope_type == other_config.seam_slope_type
&& config.seam_slope_conditional == other_config.seam_slope_conditional
&& config.scarf_angle_threshold == other_config.scarf_angle_threshold
&& config.scarf_joint_speed == other_config.scarf_joint_speed
&& config.scarf_joint_flow_ratio == other_config.scarf_joint_flow_ratio
&& config.seam_slope_start_height == other_config.seam_slope_start_height
&& config.seam_slope_entire_loop == other_config.seam_slope_entire_loop
&& config.seam_slope_min_length == other_config.seam_slope_min_length
Expand Down
2 changes: 1 addition & 1 deletion src/libslic3r/Preset.cpp
Expand Up @@ -820,7 +820,7 @@ static std::vector<std::string> s_Preset_print_options {
"wipe_tower_rotation_angle", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_branch_angle_organic",
"hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth",
"small_area_infill_flow_compensation", "small_area_infill_flow_compensation_model",
"seam_slope_type", "seam_slope_start_height", "seam_slope_entire_loop", "seam_slope_min_length", "seam_slope_steps", "seam_slope_inner_walls",
"seam_slope_type", "seam_slope_conditional", "scarf_angle_threshold", "scarf_joint_speed", "scarf_joint_flow_ratio", "seam_slope_start_height", "seam_slope_entire_loop", "seam_slope_min_length", "seam_slope_steps", "seam_slope_inner_walls",
};

static std::vector<std::string> s_Preset_filament_options {
Expand Down
40 changes: 39 additions & 1 deletion src/libslic3r/PrintConfig.cpp
Expand Up @@ -3547,7 +3547,45 @@ def = this->add("filament_loading_speed", coFloats);
def->enum_labels.push_back(L("Contour and hole"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<SeamScarfType>(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(false));

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("scarf_joint_speed", coFloatOrPercent);
def->label = L("Scarf joint speed");
def->category = L("Quality");
def->tooltip = L(
"This option sets the printing speed for scarf joints. It is recommended to print scarf joints at a slow speed (less than 100 "
"mm/s). It's also advisable to enable 'Extrusion rate smoothing' if the set speed varies significantly from the speed of the "
"outer or inner walls. If the speed specified here is higher than the speed of the outer or inner walls, the printer will default "
"to the slower of the two speeds. When specified as a percentage (e.g., 80%), the speed is calculated based on the respective "
"outer or inner wall speed. The default value is set to 100%.");
def->sidetext = L("mm/s or %");
def->min = 1;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(100, true));

def = this->add("scarf_joint_flow_ratio", coFloat);
def->label = L("Scarf joint flow ratio");
def->tooltip = L("This factor affects the amount of material for scarf joints.");
def->mode = comAdvanced;
def->max = 2;
def->set_default_value(new ConfigOptionFloat(1));

def = this->add("seam_slope_start_height", coFloatOrPercent);
def->label = L("Scarf start height");
def->tooltip = L("Start height of the scarf.\n"
Expand Down
6 changes: 6 additions & 0 deletions src/libslic3r/PrintConfig.hpp
Expand Up @@ -953,11 +953,17 @@ PRINT_CONFIG_CLASS_DEFINE(

// Orca: seam slopes
((ConfigOptionEnum<SeamScarfType>, 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))
((ConfigOptionFloatOrPercent, scarf_joint_speed))
((ConfigOptionFloat, scarf_joint_flow_ratio))


)

PRINT_CONFIG_CLASS_DEFINE(
Expand Down
4 changes: 4 additions & 0 deletions src/libslic3r/PrintObject.cpp
Expand Up @@ -1143,6 +1143,10 @@ bool PrintObject::invalidate_state_by_config_options(
} else if (
opt_key == "seam_position"
|| opt_key == "seam_slope_type"
|| opt_key == "seam_slope_conditional"
|| opt_key == "scarf_angle_threshold"
|| opt_key == "scarf_joint_speed"
|| opt_key == "scarf_joint_flow_ratio"
|| opt_key == "seam_slope_start_height"
|| opt_key == "seam_slope_entire_loop"
|| opt_key == "seam_slope_min_length"
Expand Down
4 changes: 4 additions & 0 deletions src/slic3r/GUI/ConfigManipulation.cpp
Expand Up @@ -756,12 +756,16 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co

toggle_field("seam_slope_type", !has_spiral_vase);
bool has_seam_slope = !has_spiral_vase && config->opt_enum<SeamScarfType>("seam_slope_type") != SeamScarfType::None;
toggle_line("seam_slope_conditional", has_seam_slope);
toggle_line("seam_slope_start_height", has_seam_slope);
toggle_line("seam_slope_entire_loop", has_seam_slope);
toggle_line("seam_slope_min_length", has_seam_slope);
toggle_line("seam_slope_steps", has_seam_slope);
toggle_line("seam_slope_inner_walls", has_seam_slope);
toggle_line("scarf_joint_speed", has_seam_slope);
toggle_line("scarf_joint_flow_ratio", has_seam_slope);
toggle_field("seam_slope_min_length", !config->opt_bool("seam_slope_entire_loop"));
toggle_line("scarf_angle_threshold", has_seam_slope && config->opt_bool("seam_slope_conditional"));
}

void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/)
Expand Down
4 changes: 4 additions & 0 deletions src/slic3r/GUI/Tab.cpp
Expand Up @@ -1977,10 +1977,14 @@ void TabPrint::build()
optgroup->append_single_option_line("staggered_inner_seams", "seam");
optgroup->append_single_option_line("seam_gap","seam");
optgroup->append_single_option_line("seam_slope_type", "seam#scarf-joint-seam");
optgroup->append_single_option_line("seam_slope_conditional", "seam#scarf-joint-seam");
optgroup->append_single_option_line("scarf_angle_threshold", "seam#scarf-joint-seam");
optgroup->append_single_option_line("scarf_joint_speed", "seam#scarf-joint-seam");
optgroup->append_single_option_line("seam_slope_start_height", "seam#scarf-joint-seam");
optgroup->append_single_option_line("seam_slope_entire_loop", "seam#scarf-joint-seam");
optgroup->append_single_option_line("seam_slope_min_length", "seam#scarf-joint-seam");
optgroup->append_single_option_line("seam_slope_steps", "seam#scarf-joint-seam");
optgroup->append_single_option_line("scarf_joint_flow_ratio", "seam#scarf-joint-seam");
optgroup->append_single_option_line("seam_slope_inner_walls", "seam#scarf-joint-seam");
optgroup->append_single_option_line("role_based_wipe_speed","seam");
optgroup->append_single_option_line("wipe_speed", "seam");
Expand Down

0 comments on commit a4bf3da

Please sign in to comment.