Skip to content

Commit

Permalink
issue-7932: add option to repeat last layer while reducing extrusion …
Browse files Browse the repository at this point in the history
…to get a flush last layer in vase mode closes prusa3d#7932
  • Loading branch information
b3n3d1k7 committed Nov 26, 2023
1 parent c54c4d0 commit 173a693
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 49 deletions.
9 changes: 7 additions & 2 deletions src/libslic3r/GCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1504,11 +1504,16 @@ void GCodeGenerator::process_layers(
});
// The pipeline is variable: The vase mode filter is optional.
const auto spiral_vase = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
[spiral_vase = this->m_spiral_vase.get()](LayerResult in) -> LayerResult {
[spiral_vase = this->m_spiral_vase.get(), &layers_to_print](LayerResult in) -> LayerResult {
if (in.nop_layer_result)
return in;
spiral_vase->enable(in.spiral_vase_enable);
return { spiral_vase->process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush};

if (in.layer_id == layers_to_print.size() - 1) {
spiral_vase->setLastLayer();
}

return {spiral_vase->process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush};
});
const auto pressure_equalizer = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
[pressure_equalizer = this->m_pressure_equalizer.get()](LayerResult in) -> LayerResult {
Expand Down
115 changes: 80 additions & 35 deletions src/libslic3r/GCode/SpiralVase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,52 +21,59 @@ std::string SpiralVase::process_layer(const std::string &gcode)
at the beginning
- each layer is composed by suitable geometry (i.e. a single complete loop)
- loops were not clipped before calling this method */

// If we're not going to modify G-code, just feed it to the reader
// in order to update positions.
if (! m_enabled) {
if (!m_enabled) {
m_reader.parse_buffer(gcode);
return gcode;
}

// Get total XY length for this layer by summing all extrusion moves.
float total_layer_length = 0;
float layer_height = 0;
float z = 0.f;
float layer_height = 0;
float layer_z = 0.f;

{
//FIXME Performance warning: This copies the GCodeConfig of the reader.
GCodeReader r = m_reader; // clone
bool set_z = false;
r.parse_buffer(gcode, [&total_layer_length, &layer_height, &z, &set_z]
(GCodeReader &reader, const GCodeReader::GCodeLine &line) {
if (line.cmd_is("G1")) {
if (line.extruding(reader)) {
total_layer_length += line.dist_XY(reader);
} else if (line.has(Z)) {
layer_height += line.dist_Z(reader);
if (!set_z) {
z = line.new_Z(reader);
set_z = true;
}
}
}
});
// FIXME Performance warning: This copies the GCodeConfig of the reader.
GCodeReader r = m_reader; // clone
bool set_z = false;
r.parse_buffer(gcode,
[&total_layer_length, &layer_height, &layer_z, &set_z](GCodeReader &reader, const GCodeReader::GCodeLine &line) {
if (line.cmd_is("G1")) {
if (line.extruding(reader)) {
total_layer_length += line.dist_XY(reader);
} else if (line.has(Z)) {
layer_height += line.dist_Z(reader);
if (!set_z) {
layer_z = line.new_Z(reader);
set_z = true;
}
}
}
});
}

// get a copy of the reader in case a last_layer_transition should be done
bool last_layer_transition = m_config.spiral_vase_flush_finish && m_last_layer && m_config.use_relative_e_distances.value;
GCodeReader last_layer_reader;
if (last_layer_transition) {
last_layer_reader = m_reader; // clone
}
// Remove layer height from initial Z.
z -= layer_height;

// Remove layer height from initial Z.
float z = layer_z - layer_height;

std::string new_gcode;
//FIXME Tapering of the transition layer only works reliably with relative extruder distances.
// FIXME Tapering of the transition layer only works reliably with relative extruder distances.
// For absolute extruder distances it will be switched off.
// Tapering the absolute extruder distances requires to process every extrusion value after the first transition
// layer.
bool transition = m_transition_layer && m_config.use_relative_e_distances.value;
bool transition = m_transition_layer && m_config.use_relative_e_distances.value;
float layer_height_factor = layer_height / total_layer_length;
float len = 0.f;
m_reader.parse_buffer(gcode, [&new_gcode, &z, total_layer_length, layer_height_factor, transition, &len]
(GCodeReader &reader, GCodeReader::GCodeLine line) {
float len = 0.f;
m_reader.parse_buffer(gcode, [&new_gcode, &z, total_layer_length, layer_height_factor, transition, &len](GCodeReader &reader,
GCodeReader::GCodeLine line) {
if (line.cmd_is("G1")) {
if (line.has_z()) {
// If this is the initial Z move of the layer, replace it with a
Expand All @@ -87,7 +94,7 @@ std::string SpiralVase::process_layer(const std::string &gcode)
new_gcode += line.raw() + '\n';
}
return;

/* Skip travel moves: the move to first perimeter point will
cause a visible seam when loops are not aligned in XY; by skipping
it we blend the first loop move in the XY plane (although the smoothness
Expand All @@ -98,8 +105,46 @@ std::string SpiralVase::process_layer(const std::string &gcode)
}
new_gcode += line.raw() + '\n';
});


if (last_layer_transition) {
// Repeat last layer on final height while reducing extrusion to zero to get a flush last layer.
len = 0.f;

last_layer_reader.parse_buffer(gcode, [&new_gcode, &layer_z, total_layer_length, layer_height_factor, transition,
last_layer_transition, &len](GCodeReader &reader, GCodeReader::GCodeLine line) {
if (line.cmd_is("G1")) {
if (line.has_z()) {
// Set z to final layer_z.
// We should actually already be at this height.
line.set(reader, Z, layer_z);
new_gcode += line.raw() + '\n';
return;
} else {
float dist_XY = line.dist_XY(reader);
if (dist_XY > 0) {
if (line.extruding(reader)) {
len += dist_XY;
if (line.has(E))
// Transition layer, modulate the amount of extrusion to zero.
line.set(reader, E, line.value(E) * (1.f - len / total_layer_length));
new_gcode += line.raw() + '\n';
}
return;
}
}
}

// We need to remove the layer change comment before the last_layer_transition,
// as otherwise the gcode preview will not work properly. The transition layer will be part of the last layer.
// Note: we need to keep the other layer change commands though - e.g. resetting the relative E value.
if (last_layer_transition && line.comment() == GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change)) {
return;
}
new_gcode += line.raw() + '\n';
});
}

return new_gcode;
}

}
} // namespace Slic3r
27 changes: 16 additions & 11 deletions src/libslic3r/GCode/SpiralVase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,40 @@

namespace Slic3r {


class SpiralVase {
class SpiralVase
{
public:
SpiralVase(const PrintConfig &config) : m_config(config)
{
m_reader.z() = (float)m_config.z_offset;
m_reader.z() = (float) m_config.z_offset;
m_reader.apply_config(m_config);
};

void enable(bool en) {
m_transition_layer = en && ! m_enabled;
m_enabled = en;
void enable(bool en)
{
m_transition_layer = en && !m_enabled;
m_enabled = en;
}

bool is_enabled() const {
return m_enabled;
}

void setLastLayer() { m_last_layer = true; }

std::string process_layer(const std::string &gcode);

private:
const PrintConfig &m_config;
GCodeReader m_reader;
const PrintConfig &m_config;
GCodeReader m_reader;

bool m_enabled = false;
bool m_enabled = false;
// First spiral vase layer. Layer height has to be ramped up from zero to the target layer height.
bool m_transition_layer = false;
bool m_transition_layer = false;
// Last spiral vase layer. Repeat last layer on final height while reducing extrusion till zero.
bool m_last_layer = false;
};

}
} // namespace Slic3r

#endif // slic3r_SpiralVase_hpp_
2 changes: 1 addition & 1 deletion src/libslic3r/Preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
}

static std::vector<std::string> s_Preset_print_options {
"layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "slicing_mode",
"layer_height", "first_layer_height", "perimeters", "spiral_vase", "spiral_vase_flush_finish", "slice_closing_radius", "slicing_mode",
"top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness",
"extra_perimeters", "extra_perimeters_on_overhangs", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs",
"seam_position","staggered_inner_seams", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
Expand Down
7 changes: 7 additions & 0 deletions src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2607,6 +2607,13 @@ void PrintConfigDef::init_fff_params()
"It won't work when printing more than one single object.");
def->set_default_value(new ConfigOptionBool(false));

def = this->add("spiral_vase_flush_finish", coBool);
def->label = L("Spiral vase flush finish");
def->tooltip = L("End a spiral vase mode print with a flush layer. "
"Disable to restore the old behavior, which will end the print with a normal "
"vase mode layer - i.e. a slightly tilted layer.");
def->set_default_value(new ConfigOptionBool(true));

def = this->add("standby_temperature_delta", coInt);
def->label = L("Temperature variation");
// TRN PrintSettings : "Ooze prevention" > "Temperature variation"
Expand Down
1 change: 1 addition & 0 deletions src/libslic3r/PrintConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionInts, slowdown_below_layer_time))
((ConfigOptionFloat, solid_infill_acceleration))
((ConfigOptionBool, spiral_vase))
((ConfigOptionBool, spiral_vase_flush_finish))
((ConfigOptionInt, standby_temperature_delta))
((ConfigOptionInts, temperature))
((ConfigOptionInt, threads))
Expand Down
3 changes: 3 additions & 0 deletions src/slic3r/GUI/ConfigManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
toggle_field("infill_anchor", has_infill_anchors);

bool has_spiral_vase = config->opt_bool("spiral_vase");
bool have_spiral_vase_flush_finish = config->opt_bool("spiral_vase_flush_finish");
toggle_field("spiral_vase_flush_finish", has_spiral_vase);

bool has_top_solid_infill = config->opt_int("top_solid_layers") > 0;
bool has_bottom_solid_infill = config->opt_int("bottom_solid_layers") > 0;
bool has_solid_infill = has_top_solid_infill || has_bottom_solid_infill;
Expand Down
1 change: 1 addition & 0 deletions src/slic3r/GUI/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1445,6 +1445,7 @@ void TabPrint::build()
optgroup = page->new_optgroup(L("Vertical shells"));
optgroup->append_single_option_line("perimeters", category_path + "perimeters");
optgroup->append_single_option_line("spiral_vase", category_path + "spiral-vase");
optgroup->append_single_option_line("spiral_vase_flush_finish");

Line line { "", "" };
line.full_width = 1;
Expand Down

0 comments on commit 173a693

Please sign in to comment.