mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-07 06:57:36 -06:00
Seam: use scarf joint to minimize seam visiblity (#3839)
* Remember z of previous layer
* Support travel to middle of the layer z
* Support sloped extrusion
* Implement sloped seam
* Reduce extra movements
* Don't clip loop if sloped seam is enabled
* Fix wipe
* Ensure `slope_max_segment_length`
* Add options
* Limit slope length to perimeter length
* Fix slope segmentation
* Rename the option to scarf joint seam
* Don't modify the slope option when turning on spiral vase
* Add a few suggestions when turnning on scarf joint
* Add option to add scarf joint to inner walls
* Apply seam gap at the end of the slope
* Add option to explicitly use the entire loop as scarf length
* Fix layer number
* Increase default scarf length to 20mm
* Better way of storing the global scarf state
* Better vase mode layer height recognition
* Move id should exclude seams
* Fix slope height with independent support layer height
* Fix linux build
* Allow controlling the scarf with modifier
* Scarf start height default to 0
* Allow enable scarf seam on contour only
* Fix type error
* Move the creation of sloped loop into ExtrusionEntity.cpp
* Fix error "vector too long"
* Detect seams properly
* The correct way of calculating the rate limit
* The correct way of calculating the rate limit
(cherry picked from commit 05961f7c98
)
* Add pressure equalizer in print by object mode
* Remove the settings recommendation as it varies a lot depends on printer & filament
* Add a beta suffix
---------
Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
parent
ab1b0e0ebc
commit
924a2b4551
16 changed files with 533 additions and 54 deletions
|
@ -1080,7 +1080,11 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
|||
|
||||
const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_mode");
|
||||
if (spiral_vase != nullptr)
|
||||
m_spiral_vase_active = spiral_vase->value;
|
||||
m_detect_layer_based_on_tag = spiral_vase->value;
|
||||
|
||||
const ConfigOptionBool* has_scarf_joint_seam = config.option<ConfigOptionBool>("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 ConfigOptionBool* manual_filament_change = config.option<ConfigOptionBool>("manual_filament_change");
|
||||
if (manual_filament_change != nullptr)
|
||||
|
@ -1397,7 +1401,11 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
|||
|
||||
const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_mode");
|
||||
if (spiral_vase != nullptr)
|
||||
m_spiral_vase_active = spiral_vase->value;
|
||||
m_detect_layer_based_on_tag = spiral_vase->value;
|
||||
|
||||
const ConfigOptionBool* has_scarf_joint_seam = config.option<ConfigOptionBool>("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 ConfigOptionEnumGeneric *bed_type = config.option<ConfigOptionEnumGeneric>("curr_bed_type");
|
||||
if (bed_type != nullptr)
|
||||
|
@ -1479,7 +1487,9 @@ void GCodeProcessor::reset()
|
|||
|
||||
m_options_z_corrector.reset();
|
||||
|
||||
m_spiral_vase_active = false;
|
||||
m_detect_layer_based_on_tag = false;
|
||||
|
||||
m_seams_count = 0;
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
m_mm3_per_mm_compare.reset();
|
||||
|
@ -2344,12 +2354,12 @@ 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) {
|
||||
if (m_detect_layer_based_on_tag) {
|
||||
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;
|
||||
const size_t move_id = m_result.moves.size() - 1 - m_seams_count;
|
||||
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
|
||||
|
@ -3215,12 +3225,22 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
|||
machine.calculate_time(TimeProcessor::Planner::queue_size);
|
||||
}
|
||||
|
||||
const Vec3f plate_offset = {(float) m_x_offset, (float) m_y_offset, 0.0f};
|
||||
|
||||
if (m_seams_detector.is_active()) {
|
||||
// check for seam starting vertex
|
||||
if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && !m_seams_detector.has_first_vertex()) {
|
||||
if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) {
|
||||
//BBS: m_result.moves.back().position has plate offset, must minus plate offset before calculate the real seam position
|
||||
const Vec3f real_first_pos = Vec3f(m_result.moves.back().position.x() - m_x_offset, m_result.moves.back().position.y() - m_y_offset, m_result.moves.back().position.z());
|
||||
m_seams_detector.set_first_vertex(real_first_pos - m_extruder_offsets[m_extruder_id]);
|
||||
const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset;
|
||||
if (!m_seams_detector.has_first_vertex()) {
|
||||
m_seams_detector.set_first_vertex(new_pos);
|
||||
} else if (m_detect_layer_based_on_tag) {
|
||||
// We may have sloped loop, drop any previous start pos if we have z increment
|
||||
const std::optional<Vec3f> first_vertex = m_seams_detector.get_first_vertex();
|
||||
if (new_pos.z() > first_vertex->z()) {
|
||||
m_seams_detector.set_first_vertex(new_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
// check for seam ending vertex and store the resulting move
|
||||
else if ((type != EMoveType::Extrude || (m_extrusion_role != erExternalPerimeter && m_extrusion_role != erOverhangPerimeter)) && m_seams_detector.has_first_vertex()) {
|
||||
|
@ -3230,8 +3250,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
|||
|
||||
const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]);
|
||||
//BBS: m_result.moves.back().position has plate offset, must minus plate offset before calculate the real seam position
|
||||
const Vec3f real_last_pos = Vec3f(m_result.moves.back().position.x() - m_x_offset, m_result.moves.back().position.y() - m_y_offset, m_result.moves.back().position.z());
|
||||
const Vec3f new_pos = real_last_pos - m_extruder_offsets[m_extruder_id];
|
||||
const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset;
|
||||
const std::optional<Vec3f> first_vertex = m_seams_detector.get_first_vertex();
|
||||
// the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later
|
||||
|
||||
|
@ -3246,16 +3265,21 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
|||
}
|
||||
else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) {
|
||||
m_seams_detector.activate(true);
|
||||
Vec3f plate_offset = {(float) m_x_offset, (float) m_y_offset, 0.0f};
|
||||
m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset);
|
||||
}
|
||||
|
||||
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)
|
||||
if (m_detect_layer_based_on_tag && !m_result.spiral_vase_layers.empty()) {
|
||||
if (delta_pos[Z] >= 0.0 && type == EMoveType::Extrude) {
|
||||
const float current_z = static_cast<float>(m_end_position[Z]);
|
||||
// replace layer height placeholder with correct value
|
||||
m_result.spiral_vase_layers.back().first = static_cast<float>(m_end_position[Z]);
|
||||
if (m_result.spiral_vase_layers.back().first == FLT_MAX) {
|
||||
m_result.spiral_vase_layers.back().first = current_z;
|
||||
} else {
|
||||
m_result.spiral_vase_layers.back().first = std::max(m_result.spiral_vase_layers.back().first, current_z);
|
||||
}
|
||||
}
|
||||
if (!m_result.moves.empty())
|
||||
m_result.spiral_vase_layers.back().second.second = m_result.moves.size() - 1;
|
||||
m_result.spiral_vase_layers.back().second.second = m_result.moves.size() - 1 - m_seams_count;
|
||||
}
|
||||
|
||||
// store move
|
||||
|
@ -3637,8 +3661,17 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
|||
|
||||
if (m_seams_detector.is_active()) {
|
||||
//BBS: check for seam starting vertex
|
||||
if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && !m_seams_detector.has_first_vertex()) {
|
||||
m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset);
|
||||
if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) {
|
||||
const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset;
|
||||
if (!m_seams_detector.has_first_vertex()) {
|
||||
m_seams_detector.set_first_vertex(new_pos);
|
||||
} else if (m_detect_layer_based_on_tag) {
|
||||
// We may have sloped loop, drop any previous start pos if we have z increment
|
||||
const std::optional<Vec3f> first_vertex = m_seams_detector.get_first_vertex();
|
||||
if (new_pos.z() > first_vertex->z()) {
|
||||
m_seams_detector.set_first_vertex(new_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
//BBS: check for seam ending vertex and store the resulting move
|
||||
else if ((type != EMoveType::Extrude || (m_extrusion_role != erExternalPerimeter && m_extrusion_role != erOverhangPerimeter)) && m_seams_detector.has_first_vertex()) {
|
||||
|
@ -4267,6 +4300,10 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type)
|
|||
m_interpolation_points,
|
||||
});
|
||||
|
||||
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<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue