mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-04 22:31:02 +00:00
Wipe tower sparse layers combination (#15841)
This commit is contained in:
+28
-3
@@ -970,6 +970,27 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
return gcode;
|
||||
}
|
||||
|
||||
// A folded tower layer is thicker than the object layer it sits on, so the height process_layer
|
||||
// emitted is not the tower's. Both writers declare one, but each hardcodes a tag dialect - Type 1
|
||||
// forces s_IsBBLPrinter and writes "; LAYER_HEIGHT:", Type 2 writes ";HEIGHT:" - and the processor
|
||||
// reads only its printer's, so a Type 1 tower on a non-BBL printer loses it and the merged layer
|
||||
// is drawn and costed as a thin one. Declare it here, where the printer is known, unless the tower
|
||||
// already wrote the right tag. _extrude puts the object's height back on the next object path,
|
||||
// since process_layer forces the role to erWipeTower on any layer with a tower.
|
||||
std::string WipeTowerIntegration::tower_height_tag(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr,
|
||||
const std::string &tcr_gcode) const
|
||||
{
|
||||
const std::string tag = ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height);
|
||||
if (! m_sparse_layers_combined || std::abs(gcodegen.m_last_height - tcr.layer_height) <= EPSILON ||
|
||||
tcr_gcode.find(tag) != std::string::npos)
|
||||
return {};
|
||||
// Keep m_last_height what the G-code last declared, so a second visit does not repeat it.
|
||||
gcodegen.m_last_height = tcr.layer_height;
|
||||
char buf[64];
|
||||
sprintf(buf, "%s%g\n", tag.c_str(), tcr.layer_height);
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string WipeTowerIntegration::append_tcr(GCode& gcodegen, const WipeTower::ToolChangeResult& tcr, int new_filament_id, double z) const
|
||||
{
|
||||
if (new_filament_id != -1 && new_filament_id != tcr.new_tool)
|
||||
@@ -1467,6 +1488,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
config.set_key_value("filament_start_gcode", new ConfigOptionString(start_filament_gcode_str));
|
||||
std::string tcr_gcode, tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_filament_id, &config);
|
||||
unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode);
|
||||
gcode += tower_height_tag(gcodegen, tcr, tcr_gcode);
|
||||
gcode += tcr_gcode;
|
||||
// Count the toolchange only when the emitted block really changed the tool —
|
||||
// tower visits without a filament change must not advance the ordinal.
|
||||
@@ -1799,6 +1821,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
std::string tcr_gcode,
|
||||
tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_extruder_id, &config);
|
||||
unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode);
|
||||
gcode += tower_height_tag(gcodegen, tcr, tcr_gcode);
|
||||
gcode += tcr_gcode;
|
||||
check_add_eol(toolchange_gcode_str);
|
||||
|
||||
@@ -1946,7 +1969,8 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
// Calculate where the wipe tower layer will be printed. -1 means that print z will not change,
|
||||
// resulting in a wipe tower with sparse layers.
|
||||
double wipe_tower_z = -1;
|
||||
bool ignore_sparse = false;
|
||||
// Folded into a later, thicker layer that prints at its own z: nothing to emit.
|
||||
bool ignore_sparse = wipe_tower_layer_is_combined_away(m_tool_changes[m_layer_idx]);
|
||||
if (m_sparse_layers_skipped) {
|
||||
wipe_tower_z = m_last_wipe_tower_print_z;
|
||||
ignore_sparse = wipe_tower_layer_is_sparse(m_tool_changes[m_layer_idx]) && m_layer_idx != 0;
|
||||
@@ -1964,7 +1988,8 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
// Calculate where the wipe tower layer will be printed. -1 means that print z will not change,
|
||||
// resulting in a wipe tower with sparse layers.
|
||||
double wipe_tower_z = -1;
|
||||
bool ignore_sparse = false;
|
||||
// Folded into a later, thicker layer that prints at its own z: nothing to emit.
|
||||
bool ignore_sparse = wipe_tower_layer_is_combined_away(m_tool_changes[m_layer_idx]);
|
||||
if (m_sparse_layers_skipped) {
|
||||
ignore_sparse = wipe_tower_layer_is_sparse(m_tool_changes[m_layer_idx]);
|
||||
wipe_tower_z = m_compacted_tower_z[m_layer_idx];
|
||||
@@ -1994,7 +2019,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
if (m_layer_idx >= (int) m_tool_changes.size())
|
||||
return true;
|
||||
|
||||
bool ignore_sparse = false;
|
||||
bool ignore_sparse = wipe_tower_layer_is_combined_away(m_tool_changes[m_layer_idx]);
|
||||
if (m_sparse_layers_skipped)
|
||||
ignore_sparse = wipe_tower_layer_is_sparse(m_tool_changes[m_layer_idx]);
|
||||
|
||||
|
||||
@@ -107,7 +107,8 @@ public:
|
||||
m_is_first_print(true),
|
||||
m_print_config(&print_config),
|
||||
m_last_wipe_tower_print_z(print_config.z_offset.value),
|
||||
m_sparse_layers_skipped(wipe_tower_sparse_layers_skipped(print_config))
|
||||
m_sparse_layers_skipped(wipe_tower_sparse_layers_skipped(print_config)),
|
||||
m_sparse_layers_combined(wipe_tower_sparse_layers_combined(print_config))
|
||||
{
|
||||
// Precomputed rather than accumulated while emitting, so that the clearance validator and
|
||||
// the emitter cannot disagree about where the compacted tower sits on any given layer.
|
||||
@@ -138,6 +139,7 @@ public:
|
||||
private:
|
||||
WipeTowerIntegration& operator=(const WipeTowerIntegration&);
|
||||
std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const;
|
||||
std::string tower_height_tag(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, const std::string &tcr_gcode) const;
|
||||
Polyline generate_path_to_wipe_tower(const Point &start_pos, const Point &end_pos, const BoundingBox &avoid_polygon, const Polygons &bed_polygons) const;
|
||||
std::string append_tcr2(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const;
|
||||
std::string travel_to_tower_gap(GCode &gcodegen, const Point &route_start, const Point &start_wipe_pos) const;
|
||||
@@ -175,6 +177,9 @@ private:
|
||||
// wipe_tower_no_sparse_layers, as answered by the shared compaction rule rather than by the raw
|
||||
// option: smooth timelapse and wrapping detection keep a tower on every layer regardless.
|
||||
const bool m_sparse_layers_skipped;
|
||||
// Combined tower layers are thicker than the object layer they sit on, the only case where the
|
||||
// tower's height is not the one process_layer already declared.
|
||||
const bool m_sparse_layers_combined;
|
||||
// Print z of the compacted tower per planned layer. Empty when the tower is not compacted.
|
||||
std::vector<float> m_compacted_tower_z;
|
||||
};
|
||||
|
||||
@@ -49,6 +49,48 @@ std::vector<float> compute_compacted_wipe_tower_z(const std::vector<std::vector<
|
||||
return tower_z;
|
||||
}
|
||||
|
||||
bool wipe_tower_sparse_layers_combined(const PrintConfig &config)
|
||||
{
|
||||
return config.wipe_tower_sparse_layers_combination.value && ! wipe_tower_sparse_layers_skipped(config) &&
|
||||
config.timelapse_type.value != TimelapseType::tlSmooth && ! config.enable_wrapping_detection.value;
|
||||
}
|
||||
|
||||
bool wipe_tower_layer_is_combined_away(const std::vector<WipeTower::ToolChangeResult> &layer_tool_changes)
|
||||
{
|
||||
return ! layer_tool_changes.empty() && layer_tool_changes.front().combined_away;
|
||||
}
|
||||
|
||||
std::vector<char> combine_sparse_wipe_tower_layers(std::vector<float> &layer_height,
|
||||
const std::vector<char> &layer_is_sparse,
|
||||
const std::vector<float> &max_layer_height,
|
||||
size_t first_layer_idx)
|
||||
{
|
||||
assert(layer_is_sparse.size() == layer_height.size() && max_layer_height.size() == layer_height.size());
|
||||
std::vector<char> combined_away(layer_height.size(), 0);
|
||||
float pending_height = 0.f; // what the layers folded away so far add up to
|
||||
for (size_t i = 0; i < layer_height.size(); ++i) {
|
||||
// A toolchange has to purge at its own z, so it neither folds away nor takes over the run
|
||||
// below it - and a run always flushes on its own last layer, so nothing is ever pending here.
|
||||
if (! layer_is_sparse[i] || i <= first_layer_idx) {
|
||||
pending_height = 0.f;
|
||||
continue;
|
||||
}
|
||||
const float merged = pending_height + layer_height[i];
|
||||
// Hand the run on only if the next layer can swallow the whole thing; a layer already past
|
||||
// the cap is left alone rather than shrunk.
|
||||
const bool next_takes_it = i + 1 < layer_height.size() && layer_is_sparse[i + 1] &&
|
||||
merged + layer_height[i + 1] <= max_layer_height[i + 1] + float(EPSILON);
|
||||
if (next_takes_it) {
|
||||
combined_away[i] = 1;
|
||||
pending_height = merged;
|
||||
} else {
|
||||
layer_height[i] = merged;
|
||||
pending_height = 0.f;
|
||||
}
|
||||
}
|
||||
return combined_away;
|
||||
}
|
||||
|
||||
inline float align_round(float value, float base)
|
||||
{
|
||||
return std::round(value / base) * base;
|
||||
@@ -1904,6 +1946,7 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi
|
||||
//m_bridging(float(config.wipe_tower_bridging)),
|
||||
m_bridging(10.f),
|
||||
m_sparse_layers_skipped(wipe_tower_sparse_layers_skipped(config)),
|
||||
m_sparse_layers_combined(wipe_tower_sparse_layers_combined(config)),
|
||||
m_gcode_flavor(config.gcode_flavor),
|
||||
m_travel_speed(config.travel_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))),
|
||||
m_current_tool(initial_tool),
|
||||
@@ -2028,6 +2071,16 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config)
|
||||
float nozzle_diameter = float(config.nozzle_diameter.get_at(idx));
|
||||
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
|
||||
|
||||
// Orca: max_layer_height is per nozzle, so read it through the filament->nozzle map rather than
|
||||
// by filament id. Zero means three quarters of the nozzle diameter, as in Slicing.cpp.
|
||||
{
|
||||
const std::vector<int> &filament_map = config.filament_map.values; // 1 based nozzle indices
|
||||
const size_t nozzle_idx = idx < filament_map.size() && filament_map[idx] > 0 ? size_t(filament_map[idx] - 1) : 0;
|
||||
const float max_layer_height = float(config.max_layer_height.get_at(nozzle_idx));
|
||||
m_filpar[idx].max_layer_height = max_layer_height > 0.f ? max_layer_height
|
||||
: 0.75f * float(config.nozzle_diameter.get_at(nozzle_idx));
|
||||
}
|
||||
|
||||
float max_vol_speed = float(config.filament_max_volumetric_speed.get_at(idx));
|
||||
if (max_vol_speed!= 0.f)
|
||||
m_filpar[idx].max_e_speed = (max_vol_speed / filament_area());
|
||||
@@ -3001,7 +3054,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
|
||||
// Ask our writer about how much material was consumed.
|
||||
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
||||
if (! m_sparse_layers_skipped || toolchanges_on_layer)
|
||||
if (layer_is_printed(toolchanges_on_layer))
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
@@ -3898,7 +3951,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter,
|
||||
|
||||
// Ask our writer about how much material was consumed.
|
||||
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
||||
if (!m_sparse_layers_skipped || toolchanges_on_layer)
|
||||
if (layer_is_printed(toolchanges_on_layer))
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
@@ -4008,7 +4061,7 @@ WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block,
|
||||
|
||||
// Ask our writer about how much material was consumed.
|
||||
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
||||
if (!m_sparse_layers_skipped || toolchanges_on_layer)
|
||||
if (layer_is_printed(toolchanges_on_layer))
|
||||
if (filament_id < m_used_filament_length.size())
|
||||
m_used_filament_length[filament_id] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
@@ -4125,7 +4178,7 @@ WipeTower::ToolChangeResult WipeTower::finish_block_solid(const WipeTowerBlock &
|
||||
|
||||
// Ask our writer about how much material was consumed.
|
||||
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
||||
if (!m_sparse_layers_skipped || toolchanges_on_layer)
|
||||
if (layer_is_printed(toolchanges_on_layer))
|
||||
if (filament_id < m_used_filament_length.size())
|
||||
m_used_filament_length[filament_id] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
@@ -4668,6 +4721,15 @@ void WipeTower::calc_block_infill_gap()
|
||||
m_extra_spacing = 1.f;
|
||||
}
|
||||
|
||||
// A folded layer is generated like any other but thrown away by the emitter, so its extrusions must
|
||||
// not be charged to the filament used.
|
||||
bool WipeTower::layer_is_printed(bool toolchanges_on_layer) const
|
||||
{
|
||||
if (m_layer_info != m_plan.end() && m_layer_info->combined_away)
|
||||
return false;
|
||||
return ! m_sparse_layers_skipped || toolchanges_on_layer;
|
||||
}
|
||||
|
||||
void WipeTower::plan_tower_new()
|
||||
{
|
||||
if (m_wipe_tower_brim_width < 0) m_wipe_tower_brim_width = get_auto_brim_by_height(m_wipe_tower_height);
|
||||
@@ -4820,6 +4882,9 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
|
||||
if (m_plan.empty())
|
||||
return;
|
||||
//m_extra_spacing = 1.f;
|
||||
// Before planning: the layer heights this rewrites feed the extrusion flow of every later pass.
|
||||
if (m_sparse_layers_combined)
|
||||
combine_sparse_wipe_tower_plan(m_plan, m_filpar, m_first_layer_idx, m_current_tool);
|
||||
m_wipe_tower_height = m_plan.back().z;//real wipe_tower_height
|
||||
plan_tower_new();
|
||||
m_layer_info = m_plan.begin();
|
||||
@@ -5014,6 +5079,9 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
|
||||
if (only_generate_wall && !timelapse_wall.gcode.empty()) {
|
||||
layer_result.insert(layer_result.begin(), std::move(timelapse_wall));
|
||||
}
|
||||
if (layer.combined_away)
|
||||
for (WipeTower::ToolChangeResult &tcr : layer_result)
|
||||
tcr.combined_away = true;
|
||||
result.emplace_back(std::move(layer_result));
|
||||
}
|
||||
assert(m_outer_wall.size() == m_plan.size());
|
||||
@@ -5179,7 +5247,7 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall(bool is_new_mode)
|
||||
|
||||
// Ask our writer about how much material was consumed.
|
||||
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
||||
if (!m_sparse_layers_skipped || toolchanges_on_layer)
|
||||
if (layer_is_printed(toolchanges_on_layer))
|
||||
if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f, false);
|
||||
|
||||
@@ -152,6 +152,10 @@ public:
|
||||
bool is_contact = false;
|
||||
NozzleChangeResult nozzle_change_result;
|
||||
|
||||
// Orca: folded into a later, thicker layer, so the emitter drops it. Set by the tower, so
|
||||
// the two cannot disagree about which layers print.
|
||||
bool combined_away = false;
|
||||
|
||||
// Sum the total length of the extrusion.
|
||||
float total_extrusion_length_in_plane() {
|
||||
float e_length = 0.f;
|
||||
@@ -391,6 +395,8 @@ public:
|
||||
float filament_tower_interface_pre_extrusion_dist = 0;
|
||||
float filament_tower_interface_pre_extrusion_length = 0;
|
||||
float filament_petg_pre_extrusion_offset_dist = 0;
|
||||
// Tallest layer this filament's nozzle can lay down; caps the sparse layer combination.
|
||||
float max_layer_height = 0.f;
|
||||
};
|
||||
|
||||
|
||||
@@ -522,6 +528,7 @@ private:
|
||||
//float m_extra_loading_move = 0.f;
|
||||
float m_bridging = 0.f;
|
||||
bool m_sparse_layers_skipped = false;
|
||||
bool m_sparse_layers_combined = false;
|
||||
// BBS: remove useless config
|
||||
//bool m_set_extruder_trimpot = false;
|
||||
bool m_adhesion = true;
|
||||
@@ -595,6 +602,8 @@ private:
|
||||
}
|
||||
// Calculates depth for all layers and propagates them downwards
|
||||
void plan_tower();
|
||||
// Whether the layer reaches the G-code, and so whether its extrusions count as filament used.
|
||||
bool layer_is_printed(bool toolchanges_on_layer) const;
|
||||
|
||||
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
|
||||
void make_wipe_tower_square();
|
||||
@@ -634,6 +643,8 @@ private:
|
||||
float depth; // depth of the layer based on all layers above
|
||||
float extra_spacing;
|
||||
bool extruder_fill{true};
|
||||
// Folded into a later, thicker layer, so this one prints nothing at all.
|
||||
bool combined_away{false};
|
||||
float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; }
|
||||
|
||||
std::vector<ToolChange> tool_changes;
|
||||
@@ -700,6 +711,62 @@ std::vector<float> compute_compacted_wipe_tower_z(const std::vector<std::vector<
|
||||
float base_z = 0.f);
|
||||
|
||||
|
||||
// Combination rule for wipe_tower_sparse_layers_combination. Nothing is compacted - the tower keeps
|
||||
// following the object - but a run of consecutive toolchange-free layers prints as one thicker layer,
|
||||
// the way infill combination merges sparse infill. Shared so that neither tower generator nor the
|
||||
// G-code emitter can combine on its own.
|
||||
|
||||
// Whether sparse layers are really combined. Skipping them outright is the stronger answer to the
|
||||
// same problem and wins over this; smooth timelapse and wrapping detection need a tower on every
|
||||
// layer, so they rule it out too.
|
||||
bool wipe_tower_sparse_layers_combined(const PrintConfig &config);
|
||||
|
||||
// A planned layer folded into a later, thicker one prints nothing at all.
|
||||
bool wipe_tower_layer_is_combined_away(const std::vector<WipeTower::ToolChangeResult> &layer_tool_changes);
|
||||
|
||||
// Folds runs of sparse layers into one. layer_height is raised in place on the layer that prints a
|
||||
// run - always its last, so the merged extrusion lands on top of what it covers - and the returned
|
||||
// mask marks the layers that now print nothing. A run stops growing once one more layer would pass
|
||||
// max_layer_height of the nozzle that prints it. first_layer_idx and below never combine: the
|
||||
// tower's first layer carries the brim.
|
||||
std::vector<char> combine_sparse_wipe_tower_layers(std::vector<float> &layer_height,
|
||||
const std::vector<char> &layer_is_sparse,
|
||||
const std::vector<float> &max_layer_height,
|
||||
size_t first_layer_idx);
|
||||
|
||||
// Applies the rule above to a planned tower. Either generator's plan fits: both carry height,
|
||||
// tool_changes and combined_away per layer, and index their filament parameters by tool.
|
||||
template<class PlanLayers, class FilamentParams>
|
||||
void combine_sparse_wipe_tower_plan(PlanLayers &plan, const FilamentParams &filpar, size_t first_layer_idx, size_t initial_tool)
|
||||
{
|
||||
const size_t n = plan.size();
|
||||
std::vector<float> heights(n);
|
||||
std::vector<char> sparse(n);
|
||||
std::vector<float> caps(n);
|
||||
|
||||
// A layer with no toolchange prints with the filament the layer below left loaded.
|
||||
size_t tool = initial_tool;
|
||||
for (const auto &layer : plan)
|
||||
if (! layer.tool_changes.empty()) {
|
||||
tool = layer.tool_changes.front().old_tool;
|
||||
break;
|
||||
}
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
heights[i] = plan[i].height;
|
||||
sparse[i] = plan[i].tool_changes.empty() ? 1 : 0;
|
||||
caps[i] = tool < filpar.size() ? filpar[tool].max_layer_height : 0.f;
|
||||
if (! plan[i].tool_changes.empty())
|
||||
tool = plan[i].tool_changes.back().new_tool;
|
||||
}
|
||||
|
||||
const std::vector<char> combined_away = combine_sparse_wipe_tower_layers(heights, sparse, caps, first_layer_idx);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
plan[i].height = heights[i];
|
||||
plan[i].combined_away = combined_away[i] != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // WipeTowerPrusaMM_hpp_
|
||||
|
||||
@@ -1033,6 +1033,7 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau
|
||||
m_z_pos(0.f),
|
||||
m_bridging(float(config.wipe_tower_bridging)),
|
||||
m_sparse_layers_skipped(wipe_tower_sparse_layers_skipped(config)),
|
||||
m_sparse_layers_combined(wipe_tower_sparse_layers_combined(config)),
|
||||
m_gcode_flavor(config.gcode_flavor),
|
||||
m_travel_speed(config.travel_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))),
|
||||
m_infill_speed(default_region_config.sparse_infill_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))),
|
||||
@@ -1150,6 +1151,16 @@ void WipeTower2::set_extruder(size_t idx, const PrintConfig& config)
|
||||
float nozzle_diameter = float(config.nozzle_diameter.get_at(idx));
|
||||
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
|
||||
|
||||
// Orca: max_layer_height is per nozzle, so read it through the filament->nozzle map rather than
|
||||
// by filament id. Zero means three quarters of the nozzle diameter, as in Slicing.cpp.
|
||||
{
|
||||
const std::vector<int> &filament_map = config.filament_map.values; // 1 based nozzle indices
|
||||
const size_t nozzle_idx = idx < filament_map.size() && filament_map[idx] > 0 ? size_t(filament_map[idx] - 1) : 0;
|
||||
const float max_layer_height = float(config.max_layer_height.get_at(nozzle_idx));
|
||||
m_filpar[idx].max_layer_height = max_layer_height > 0.f ? max_layer_height
|
||||
: 0.75f * float(config.nozzle_diameter.get_at(nozzle_idx));
|
||||
}
|
||||
|
||||
float max_vol_speed = float(config.filament_max_volumetric_speed.get_at(idx));
|
||||
if (max_vol_speed!= 0.f)
|
||||
m_filpar[idx].max_e_speed = (max_vol_speed / filament_area());
|
||||
@@ -2103,7 +2114,9 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer()
|
||||
|
||||
// Ask our writer about how much material was consumed.
|
||||
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
||||
if (! m_sparse_layers_skipped || toolchanges_on_layer || first_layer) {
|
||||
// A folded layer prints nothing, so it consumes nothing and adds no height of its own.
|
||||
const bool combined_away = m_layer_info != m_plan.end() && m_layer_info->combined_away;
|
||||
if ((! m_sparse_layers_skipped || toolchanges_on_layer || first_layer) && ! combined_away) {
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
m_current_height += m_layer_info->height;
|
||||
@@ -2435,6 +2448,10 @@ void WipeTower2::generate(std::vector<std::vector<WipeTower::ToolChangeResult>>
|
||||
if (m_plan.empty())
|
||||
return;
|
||||
|
||||
// Before planning: the layer heights this rewrites feed the extrusion flow of every later pass.
|
||||
if (m_sparse_layers_combined)
|
||||
combine_sparse_wipe_tower_plan(m_plan, m_filpar, m_first_layer_idx, m_current_tool);
|
||||
|
||||
plan_tower();
|
||||
#if 1
|
||||
for (int i=0;i<5;++i) {
|
||||
@@ -2533,6 +2550,10 @@ void WipeTower2::generate(std::vector<std::vector<WipeTower::ToolChangeResult>>
|
||||
layer_result[idx] = merge_tcr(layer_result[idx], finish_layer_tcr);
|
||||
}
|
||||
|
||||
if (layer.combined_away)
|
||||
for (WipeTower::ToolChangeResult &tcr : layer_result)
|
||||
tcr.combined_away = true;
|
||||
|
||||
result.emplace_back(std::move(layer_result));
|
||||
|
||||
if (m_used_filament_length_until_layer.empty() || m_used_filament_length_until_layer.back().first != layer.z)
|
||||
|
||||
@@ -200,6 +200,8 @@ public:
|
||||
float tower_interface_pre_extrusion_length = 0.f;
|
||||
float tower_ironing_area = 4.f;
|
||||
float tower_interface_purge_length = 0.f;
|
||||
// Tallest layer this filament's nozzle can lay down; caps the sparse layer combination.
|
||||
float max_layer_height = 0.f;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -268,6 +270,7 @@ private:
|
||||
float m_extra_loading_move = 0.f;
|
||||
float m_bridging = 0.f;
|
||||
bool m_sparse_layers_skipped = false;
|
||||
bool m_sparse_layers_combined = false;
|
||||
bool m_set_extruder_trimpot = false;
|
||||
bool m_adhesion = true;
|
||||
GCodeFlavor m_gcode_flavor;
|
||||
@@ -368,6 +371,8 @@ private:
|
||||
float z; // z position of the layer
|
||||
float height; // layer height
|
||||
float depth; // depth of the layer based on all layers above
|
||||
// Folded into a later, thicker layer, so this one prints nothing at all.
|
||||
bool combined_away{false};
|
||||
float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; }
|
||||
|
||||
std::vector<ToolChange> tool_changes;
|
||||
|
||||
@@ -1199,6 +1199,7 @@ static std::vector<std::string> s_Preset_print_options{
|
||||
"enable_tower_interface_features",
|
||||
"enable_tower_interface_cooldown_during_tower",
|
||||
"wipe_tower_no_sparse_layers",
|
||||
"wipe_tower_sparse_layers_combination",
|
||||
"compatible_printers",
|
||||
"compatible_printers_condition",
|
||||
"inherits",
|
||||
|
||||
@@ -378,6 +378,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
|| opt_key == "wipe_tower_bridging"
|
||||
|| opt_key == "wipe_tower_extra_flow"
|
||||
|| opt_key == "wipe_tower_no_sparse_layers"
|
||||
|| opt_key == "wipe_tower_sparse_layers_combination"
|
||||
|| opt_key == "flush_volumes_matrix"
|
||||
|| opt_key == "prime_volume"
|
||||
|| opt_key == "flush_into_infill"
|
||||
|
||||
@@ -6705,6 +6705,20 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("wipe_tower_sparse_layers_combination", coBool);
|
||||
def->label = L("Combine sparse layers");
|
||||
def->tooltip = L("If enabled, consecutive layers on which the prime tower has no filament change are printed as a single "
|
||||
"thicker tower layer instead of one thin layer each, the same way infill combination merges sparse infill. "
|
||||
"The merged layer is printed at the top of the run, at the height of everything it covers.\n\n"
|
||||
"Only whole layers are merged, and never past the maximum layer height of the nozzle printing the tower "
|
||||
"(three quarters of the nozzle diameter when that is left at 0). Two or more layers therefore have to fit "
|
||||
"under that limit before anything changes at all: at a 0.2 mm layer height under a 0.3 mm maximum nothing "
|
||||
"is merged, while at 0.1 mm three layers become one.\n\n"
|
||||
"Unlike \"No sparse layers\" the tower keeps following the model, so the toolhead never has to reach down to it. "
|
||||
"Has no effect with \"No sparse layers\", smooth timelapse or clumping detection, which need a tower on every layer.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("single_extruder_multi_material_priming", coBool);
|
||||
def->label = L("Prime all printing extruders");
|
||||
def->tooltip = L("If enabled, all printing extruders will be primed at the front edge of the print bed at the start of the print.");
|
||||
|
||||
@@ -1632,6 +1632,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionString, toolchange_cyclic_order))
|
||||
((ConfigOptionBool, toolchange_cyclic_first_layer))
|
||||
((ConfigOptionBool, wipe_tower_no_sparse_layers))
|
||||
((ConfigOptionBool, wipe_tower_sparse_layers_combination))
|
||||
((ConfigOptionString, change_filament_gcode))
|
||||
((ConfigOptionString, change_extrusion_role_gcode))
|
||||
((ConfigOptionString, process_change_extrusion_role_gcode))
|
||||
|
||||
@@ -1046,6 +1046,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in
|
||||
|
||||
// Orca: both tower generators skip sparse layers, so this is not a wipe tower 2 exclusive.
|
||||
toggle_line("wipe_tower_no_sparse_layers", have_prime_tower);
|
||||
// Dropping the sparse layers outright leaves nothing to combine, so the two are exclusive.
|
||||
toggle_line("wipe_tower_sparse_layers_combination", have_prime_tower && !config->opt_bool("wipe_tower_no_sparse_layers"));
|
||||
|
||||
WipeTowerWallType wipe_tower_wall_type = config->opt_enum<WipeTowerWallType>("wipe_tower_wall_type");
|
||||
bool have_rib_wall = (wipe_tower_wall_type == WipeTowerWallType::wtwRib)&&have_prime_tower;
|
||||
|
||||
@@ -3069,6 +3069,7 @@ void TabPrint::build()
|
||||
optgroup->append_single_option_line("wipe_tower_rib_width", "multimaterial_settings_prime_tower#rib-width");
|
||||
optgroup->append_single_option_line("wipe_tower_fillet_wall", "multimaterial_settings_prime_tower#fillet-wall");
|
||||
optgroup->append_single_option_line("wipe_tower_no_sparse_layers", "multimaterial_settings_prime_tower#no-sparse-layers");
|
||||
optgroup->append_single_option_line("wipe_tower_sparse_layers_combination", "multimaterial_settings_prime_tower#combine-sparse-layers");
|
||||
optgroup->append_single_option_line("single_extruder_multi_material_priming", "multimaterial_settings_prime_tower");
|
||||
|
||||
optgroup = page->new_optgroup(L("Filament for Features"), L"param_filament_for_features");
|
||||
|
||||
Reference in New Issue
Block a user