Add overhang threshold for scarf joint seam (#4725)

add overhang threshold for scarf joint seam
This commit is contained in:
SoftFever 2024-03-27 22:02:20 +08:00 committed by GitHub
parent 116169ea03
commit dcb8d09af6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 41 additions and 12 deletions

View file

@ -4549,10 +4549,11 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
// find the point of the loop that is closest to the current extruder position // find the point of the loop that is closest to the current extruder position
// or randomize if requested // or randomize if requested
Point last_pos = this->last_pos(); Point last_pos = this->last_pos();
float seam_overhang = std::numeric_limits<float>::lowest();
if (!m_config.spiral_mode && description == "perimeter") { if (!m_config.spiral_mode && description == "perimeter") {
assert(m_layer != nullptr); assert(m_layer != nullptr);
bool is_outer_wall_first = m_config.wall_sequence == WallSequence::OuterInner; bool is_outer_wall_first = m_config.wall_sequence == WallSequence::OuterInner;
m_seam_placer.place_seam(m_layer, loop, is_outer_wall_first, this->last_pos()); m_seam_placer.place_seam(m_layer, loop, is_outer_wall_first, this->last_pos(), seam_overhang);
} else } else
loop.split_at(last_pos, false); loop.split_at(last_pos, false);
@ -4561,14 +4562,21 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
!m_config.spiral_mode && !m_config.spiral_mode &&
(loop.role() == erExternalPerimeter || (loop.role() == erPerimeter && m_config.seam_slope_inner_walls)) && (loop.role() == erExternalPerimeter || (loop.role() == erPerimeter && m_config.seam_slope_inner_walls)) &&
layer_id() > 0; layer_id() > 0;
const auto nozzle_diameter = EXTRUDER_CONFIG(nozzle_diameter);
if (enable_seam_slope && m_config.seam_slope_conditional.value) { 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)); enable_seam_slope = loop.is_smooth(m_config.scarf_angle_threshold.value * M_PI / 180., nozzle_diameter);
} }
if (enable_seam_slope && m_config.seam_slope_conditional.value && m_config.scarf_overhang_threshold.value > 0.0f) {
const auto _line_width = loop.role() == erExternalPerimeter ? m_config.outer_wall_line_width.get_abs_value(nozzle_diameter) :
m_config.inner_wall_line_width.get_abs_value(nozzle_diameter);
enable_seam_slope = seam_overhang < m_config.scarf_overhang_threshold.value * 0.01f * _line_width;
}
// clip the path to avoid the extruder to get exactly on the first point of the loop; // 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 // if polyline was shorter than the clipping distance we'd get a null polyline, so
// we discard it in that case // we discard it in that case
const double seam_gap = scale_(m_config.seam_gap.get_abs_value(EXTRUDER_CONFIG(nozzle_diameter))); const double seam_gap = scale_(m_config.seam_gap.get_abs_value(nozzle_diameter));
const double clip_length = m_enable_loop_clipping && !enable_seam_slope ? seam_gap : 0; const double clip_length = m_enable_loop_clipping && !enable_seam_slope ? seam_gap : 0;
// get paths // get paths
@ -4596,7 +4604,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
if (m_config.wipe_before_external_loop.value && !paths.empty() && paths.front().size() > 1 && paths.back().size() > 1 && paths.front().role() == erExternalPerimeter && region_perimeters.size() > 1) { if (m_config.wipe_before_external_loop.value && !paths.empty() && paths.front().size() > 1 && paths.back().size() > 1 && paths.front().role() == erExternalPerimeter && region_perimeters.size() > 1) {
const bool is_full_loop_ccw = loop.polygon().is_counter_clockwise(); const bool is_full_loop_ccw = loop.polygon().is_counter_clockwise();
bool is_hole_loop = (loop.loop_role() & ExtrusionLoopRole::elrHole) != 0; // loop.make_counter_clockwise(); bool is_hole_loop = (loop.loop_role() & ExtrusionLoopRole::elrHole) != 0; // loop.make_counter_clockwise();
const double nozzle_diam = EXTRUDER_CONFIG(nozzle_diameter); const double nozzle_diam = nozzle_diameter;
// note: previous & next are inverted to extrude "in the opposite direction, and we are "rewinding" // note: previous & next are inverted to extrude "in the opposite direction, and we are "rewinding"
Point previous_point = paths.front().polyline.points[1]; Point previous_point = paths.front().polyline.points[1];

View file

@ -1067,15 +1067,18 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po)
std::unique_ptr<PerimeterDistancer> current_layer_distancer = std::make_unique<PerimeterDistancer>( std::unique_ptr<PerimeterDistancer> current_layer_distancer = std::make_unique<PerimeterDistancer>(
to_unscaled_linesf(po->layers()[layer_idx]->lslices)); to_unscaled_linesf(po->layers()[layer_idx]->lslices));
for (SeamCandidate &perimeter_point : layers[layer_idx].points) { auto& layer_seams = layers[layer_idx];
for (SeamCandidate &perimeter_point : layer_seams.points) {
Vec2f point = Vec2f { perimeter_point.position.head<2>() }; Vec2f point = Vec2f { perimeter_point.position.head<2>() };
if (prev_layer_distancer.get() != nullptr) { if (prev_layer_distancer.get() != nullptr) {
perimeter_point.overhang = prev_layer_distancer->distance_from_lines<true>(point.cast<double>()) const auto _dist = prev_layer_distancer->distance_from_lines<true>(point.cast<double>());
perimeter_point.overhang = _dist
+ 0.6f * perimeter_point.perimeter.flow_width + 0.6f * perimeter_point.perimeter.flow_width
- tan(SeamPlacer::overhang_angle_threshold) - tan(SeamPlacer::overhang_angle_threshold)
* po->layers()[layer_idx]->height; * po->layers()[layer_idx]->height;
perimeter_point.overhang = perimeter_point.overhang =
perimeter_point.overhang < 0.0f ? 0.0f : perimeter_point.overhang; perimeter_point.overhang < 0.0f ? 0.0f : perimeter_point.overhang;
perimeter_point.unsupported_dist = _dist + 0.4f * perimeter_point.perimeter.flow_width;
} }
if (should_compute_layer_embedding) { // search for embedded perimeter points (points hidden inside the print ,e.g. multimaterial join, best position for seam) if (should_compute_layer_embedding) { // search for embedded perimeter points (points hidden inside the print ,e.g. multimaterial join, best position for seam)
@ -1484,7 +1487,7 @@ void SeamPlacer::init(const Print &print, std::function<void(void)> throw_if_can
} }
void SeamPlacer::place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, void SeamPlacer::place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first,
const Point &last_pos) const { const Point &last_pos, float& overhang) const {
using namespace SeamPlacerImpl; using namespace SeamPlacerImpl;
const PrintObject *po = layer->object(); const PrintObject *po = layer->object();
// Must not be called with supprot layer. // Must not be called with supprot layer.
@ -1546,6 +1549,7 @@ void SeamPlacer::place_seam(const Layer *layer, ExtrusionLoop &loop, bool extern
} }
Point seam_point = Point::new_scale(seam_position.x(), seam_position.y()); Point seam_point = Point::new_scale(seam_position.x(), seam_position.y());
overhang = layer_perimeters.points[seam_index].unsupported_dist;
if (loop.role() == ExtrusionRole::erPerimeter) { //Hopefully inner perimeter if (loop.role() == ExtrusionRole::erPerimeter) { //Hopefully inner perimeter
const SeamCandidate &perimeter_point = layer_perimeters.points[seam_index]; const SeamCandidate &perimeter_point = layer_perimeters.points[seam_index];

View file

@ -1,6 +1,7 @@
#ifndef libslic3r_SeamPlacer_hpp_ #ifndef libslic3r_SeamPlacer_hpp_
#define libslic3r_SeamPlacer_hpp_ #define libslic3r_SeamPlacer_hpp_
#include <limits>
#include <optional> #include <optional>
#include <vector> #include <vector>
#include <memory> #include <memory>
@ -66,6 +67,7 @@ struct SeamCandidate {
Perimeter &perimeter; Perimeter &perimeter;
float visibility; float visibility;
float overhang; float overhang;
float unsupported_dist;
// distance inside the merged layer regions, for detecting perimeter points which are hidden indside the print (e.g. multimaterial join) // distance inside the merged layer regions, for detecting perimeter points which are hidden indside the print (e.g. multimaterial join)
// Negative sign means inside the print, comes from EdgeGrid structure // Negative sign means inside the print, comes from EdgeGrid structure
float embedded_distance; float embedded_distance;
@ -141,8 +143,7 @@ public:
void init(const Print &print, std::function<void(void)> throw_if_canceled_func); void init(const Print &print, std::function<void(void)> throw_if_canceled_func);
void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point &last_pos) const; void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point &last_pos, float& overhang) const;
private: private:
void gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info); void gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info);
void calculate_candidates_visibility(const PrintObject *po, void calculate_candidates_visibility(const PrintObject *po,

View file

@ -188,6 +188,7 @@ void Layer::make_perimeters()
&& config.seam_slope_type == other_config.seam_slope_type && config.seam_slope_type == other_config.seam_slope_type
&& config.seam_slope_conditional == other_config.seam_slope_conditional && config.seam_slope_conditional == other_config.seam_slope_conditional
&& config.scarf_angle_threshold == other_config.scarf_angle_threshold && config.scarf_angle_threshold == other_config.scarf_angle_threshold
&& config.scarf_overhang_threshold == other_config.scarf_overhang_threshold
&& config.scarf_joint_speed == other_config.scarf_joint_speed && config.scarf_joint_speed == other_config.scarf_joint_speed
&& config.scarf_joint_flow_ratio == other_config.scarf_joint_flow_ratio && 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_start_height == other_config.seam_slope_start_height

View file

@ -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", "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", "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", "small_area_infill_flow_compensation", "small_area_infill_flow_compensation_model",
"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", "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", "scarf_overhang_threshold"
}; };
static std::vector<std::string> s_Preset_filament_options { static std::vector<std::string> s_Preset_filament_options {

View file

@ -3588,6 +3588,17 @@ def = this->add("filament_loading_speed", coFloats);
def->max = 180; def->max = 180;
def->set_default_value(new ConfigOptionInt(155)); def->set_default_value(new ConfigOptionInt(155));
def = this->add("scarf_overhang_threshold", coPercent);
def->label = L("Conditional overhang threshold");
def->category = L("Quality");
def->tooltip = L("This option determines the overhang threshold for the application of scarf joint seams. If the unsupported portion "
"of the perimeter is less than this threshold, scarf joint seams will be applied. The default threshold is set at 40% "
"of the external wall's width. Due to performance considerations, the degree of overhang is estimated.");
def->sidetext = L("%");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionPercent(40));
def = this->add("scarf_joint_speed", coFloatOrPercent); def = this->add("scarf_joint_speed", coFloatOrPercent);
def->label = L("Scarf joint speed"); def->label = L("Scarf joint speed");
def->category = L("Quality"); def->category = L("Quality");
@ -3605,7 +3616,7 @@ def = this->add("filament_loading_speed", coFloats);
def = this->add("scarf_joint_flow_ratio", coFloat); def = this->add("scarf_joint_flow_ratio", coFloat);
def->label = L("Scarf joint flow ratio"); def->label = L("Scarf joint flow ratio");
def->tooltip = L("This factor affects the amount of material for scarf joints."); def->tooltip = L("This factor affects the amount of material for scarf joints.");
def->mode = comAdvanced; def->mode = comDevelop;
def->max = 2; def->max = 2;
def->set_default_value(new ConfigOptionFloat(1)); def->set_default_value(new ConfigOptionFloat(1));

View file

@ -969,6 +969,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, seam_slope_inner_walls)) ((ConfigOptionBool, seam_slope_inner_walls))
((ConfigOptionFloatOrPercent, scarf_joint_speed)) ((ConfigOptionFloatOrPercent, scarf_joint_speed))
((ConfigOptionFloat, scarf_joint_flow_ratio)) ((ConfigOptionFloat, scarf_joint_flow_ratio))
((ConfigOptionPercent, scarf_overhang_threshold))
) )

View file

@ -1145,6 +1145,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "seam_slope_type" || opt_key == "seam_slope_type"
|| opt_key == "seam_slope_conditional" || opt_key == "seam_slope_conditional"
|| opt_key == "scarf_angle_threshold" || opt_key == "scarf_angle_threshold"
|| opt_key == "scarf_overhang_threshold"
|| opt_key == "scarf_joint_speed" || opt_key == "scarf_joint_speed"
|| opt_key == "scarf_joint_flow_ratio" || opt_key == "scarf_joint_flow_ratio"
|| opt_key == "seam_slope_start_height" || opt_key == "seam_slope_start_height"

View file

@ -764,6 +764,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_line("scarf_joint_flow_ratio", 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_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")); toggle_line("scarf_angle_threshold", has_seam_slope && config->opt_bool("seam_slope_conditional"));
toggle_line("scarf_overhang_threshold", has_seam_slope && config->opt_bool("seam_slope_conditional"));
} }
void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/)

View file

@ -1979,6 +1979,7 @@ void TabPrint::build()
optgroup->append_single_option_line("seam_slope_type", "seam#scarf-joint-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("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_angle_threshold", "seam#scarf-joint-seam");
optgroup->append_single_option_line("scarf_overhang_threshold", "seam#scarf-joint-seam");
optgroup->append_single_option_line("scarf_joint_speed", "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_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_entire_loop", "seam#scarf-joint-seam");