mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-07 23:17:35 -06:00
Scarf joint seam enhancement: conditional scarf joint and slowdown for 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
This commit is contained in:
parent
6264fe64b4
commit
a4bf3dabb4
10 changed files with 144 additions and 4 deletions
|
@ -7,6 +7,7 @@
|
|||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include "Utils.hpp"
|
||||
|
||||
#define L(s) (s)
|
||||
|
||||
|
@ -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,
|
||||
|
|
|
@ -479,7 +479,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; }
|
||||
|
||||
// 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
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -5082,6 +5087,10 @@ 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 &&
|
||||
|
@ -5089,6 +5098,9 @@ 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("outer_wall_speed")));
|
||||
}
|
||||
}
|
||||
else if(path.role() == erInternalBridgeInfill) {
|
||||
speed = m_config.get_abs_value("internal_bridge_speed");
|
||||
|
@ -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){
|
||||
|
@ -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()) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -3548,6 +3548,44 @@ def = this->add("filament_loading_speed", coFloats);
|
|||
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"
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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*/)
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue