mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-12 01:07:57 -06:00
Initial integration of the Prusa MultiMatrial Wipe Tower.
This commit is contained in:
parent
74346efccb
commit
c22b6edeeb
11 changed files with 922 additions and 439 deletions
|
@ -558,6 +558,7 @@ sub build {
|
||||||
top_infill_extrusion_width support_material_extrusion_width
|
top_infill_extrusion_width support_material_extrusion_width
|
||||||
infill_overlap bridge_flow_ratio
|
infill_overlap bridge_flow_ratio
|
||||||
clip_multipart_objects xy_size_compensation threads resolution
|
clip_multipart_objects xy_size_compensation threads resolution
|
||||||
|
wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe
|
||||||
));
|
));
|
||||||
$self->{config}->set('print_settings_id', '');
|
$self->{config}->set('print_settings_id', '');
|
||||||
|
|
||||||
|
@ -720,6 +721,14 @@ sub build {
|
||||||
$optgroup->append_single_option_line('ooze_prevention');
|
$optgroup->append_single_option_line('ooze_prevention');
|
||||||
$optgroup->append_single_option_line('standby_temperature_delta');
|
$optgroup->append_single_option_line('standby_temperature_delta');
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
my $optgroup = $page->new_optgroup('Wipe tower');
|
||||||
|
$optgroup->append_single_option_line('wipe_tower');
|
||||||
|
$optgroup->append_single_option_line('wipe_tower_x');
|
||||||
|
$optgroup->append_single_option_line('wipe_tower_y');
|
||||||
|
$optgroup->append_single_option_line('wipe_tower_width');
|
||||||
|
$optgroup->append_single_option_line('wipe_tower_per_color_wipe');
|
||||||
|
}
|
||||||
{
|
{
|
||||||
my $optgroup = $page->new_optgroup('Advanced');
|
my $optgroup = $page->new_optgroup('Advanced');
|
||||||
$optgroup->append_single_option_line('interface_shells');
|
$optgroup->append_single_option_line('interface_shells');
|
||||||
|
@ -955,6 +964,10 @@ sub _update {
|
||||||
my $have_ooze_prevention = $config->ooze_prevention;
|
my $have_ooze_prevention = $config->ooze_prevention;
|
||||||
$self->get_field($_)->toggle($have_ooze_prevention)
|
$self->get_field($_)->toggle($have_ooze_prevention)
|
||||||
for qw(standby_temperature_delta);
|
for qw(standby_temperature_delta);
|
||||||
|
|
||||||
|
my $have_wipe_tower = $config->wipe_tower;
|
||||||
|
$self->get_field($_)->toggle($have_wipe_tower)
|
||||||
|
for qw(wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub hidden_options { !$Slic3r::have_threads ? qw(threads) : () }
|
sub hidden_options { !$Slic3r::have_threads ? qw(threads) : () }
|
||||||
|
@ -969,7 +982,7 @@ sub build {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
$self->init_config_options(qw(
|
$self->init_config_options(qw(
|
||||||
filament_colour filament_diameter filament_notes filament_max_volumetric_speed extrusion_multiplier filament_density filament_cost
|
filament_colour filament_diameter filament_type filament_soluble filament_notes filament_max_volumetric_speed extrusion_multiplier filament_density filament_cost
|
||||||
temperature first_layer_temperature bed_temperature first_layer_bed_temperature
|
temperature first_layer_temperature bed_temperature first_layer_bed_temperature
|
||||||
fan_always_on cooling
|
fan_always_on cooling
|
||||||
min_fan_speed max_fan_speed bridge_fan_speed disable_fan_first_layers
|
min_fan_speed max_fan_speed bridge_fan_speed disable_fan_first_layers
|
||||||
|
@ -984,6 +997,8 @@ sub build {
|
||||||
$optgroup->append_single_option_line('filament_colour', 0);
|
$optgroup->append_single_option_line('filament_colour', 0);
|
||||||
$optgroup->append_single_option_line('filament_diameter', 0);
|
$optgroup->append_single_option_line('filament_diameter', 0);
|
||||||
$optgroup->append_single_option_line('extrusion_multiplier', 0);
|
$optgroup->append_single_option_line('extrusion_multiplier', 0);
|
||||||
|
$optgroup->append_single_option_line('filament_type', 0);
|
||||||
|
$optgroup->append_single_option_line('filament_soluble', 0);
|
||||||
$optgroup->append_single_option_line('filament_density', 0);
|
$optgroup->append_single_option_line('filament_density', 0);
|
||||||
$optgroup->append_single_option_line('filament_cost', 0);
|
$optgroup->append_single_option_line('filament_cost', 0);
|
||||||
}
|
}
|
||||||
|
@ -1137,7 +1152,7 @@ sub build {
|
||||||
octoprint_host octoprint_apikey
|
octoprint_host octoprint_apikey
|
||||||
use_firmware_retraction
|
use_firmware_retraction
|
||||||
use_volumetric_e variable_layer_height
|
use_volumetric_e variable_layer_height
|
||||||
start_gcode end_gcode before_layer_gcode layer_gcode toolchange_gcode
|
single_extruder_multi_material start_gcode end_gcode before_layer_gcode layer_gcode toolchange_gcode
|
||||||
nozzle_diameter extruder_offset
|
nozzle_diameter extruder_offset
|
||||||
retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe
|
retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe
|
||||||
retract_length_toolchange retract_restart_extra_toolchange
|
retract_length_toolchange retract_restart_extra_toolchange
|
||||||
|
@ -1198,6 +1213,7 @@ sub build {
|
||||||
min => 1,
|
min => 1,
|
||||||
);
|
);
|
||||||
$optgroup->append_single_option_line($option);
|
$optgroup->append_single_option_line($option);
|
||||||
|
$optgroup->append_single_option_line('single_extruder_multi_material');
|
||||||
}
|
}
|
||||||
$optgroup->on_change(sub {
|
$optgroup->on_change(sub {
|
||||||
my ($opt_id) = @_;
|
my ($opt_id) = @_;
|
||||||
|
@ -1538,6 +1554,7 @@ sub _update {
|
||||||
|
|
||||||
my $have_multiple_extruders = $self->{extruders_count} > 1;
|
my $have_multiple_extruders = $self->{extruders_count} > 1;
|
||||||
$self->get_field('toolchange_gcode')->toggle($have_multiple_extruders);
|
$self->get_field('toolchange_gcode')->toggle($have_multiple_extruders);
|
||||||
|
$self->get_field('single_extruder_multi_material')->toggle($have_multiple_extruders);
|
||||||
|
|
||||||
for my $i (0 .. ($self->{extruders_count}-1)) {
|
for my $i (0 .. ($self->{extruders_count}-1)) {
|
||||||
my $have_retract_length = $config->get_at('retract_length', $i) > 0;
|
my $have_retract_length = $config->get_at('retract_length', $i) > 0;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "ExtrusionEntity.hpp"
|
#include "ExtrusionEntity.hpp"
|
||||||
#include "EdgeGrid.hpp"
|
#include "EdgeGrid.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
|
#include "GCode/WipeTowerPrusaMM.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
@ -384,6 +385,8 @@ bool GCode::do_export(FILE *file, Print &print)
|
||||||
// Set first layer extruder.
|
// Set first layer extruder.
|
||||||
this->_print_first_layer_extruder_temperatures(file, print, false);
|
this->_print_first_layer_extruder_temperatures(file, print, false);
|
||||||
}
|
}
|
||||||
|
// Get optimal tool ordering to minimize tool switches of a multi-exruder print.
|
||||||
|
std::vector<ToolOrdering::LayerTools> tool_ordering = ToolOrdering::tool_ordering(*object);
|
||||||
// Pair the object layers with the support layers by z, extrude them.
|
// Pair the object layers with the support layers by z, extrude them.
|
||||||
size_t idx_object_layer = 0;
|
size_t idx_object_layer = 0;
|
||||||
size_t idx_support_layer = 0;
|
size_t idx_support_layer = 0;
|
||||||
|
@ -401,7 +404,9 @@ bool GCode::do_export(FILE *file, Print &print)
|
||||||
-- idx_object_layer;
|
-- idx_object_layer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->process_layer(file, print, layers_to_print, © - object->_shifted_copies.data());
|
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), ToolOrdering::LayerTools(layer_to_print.layer()->print_z));
|
||||||
|
assert(it_layer_tools != tool_ordering.end() && it_layer_tools->print_z == layer_to_print.layer()->print_z);
|
||||||
|
this->process_layer(file, print, layers_to_print, *it_layer_tools, © - object->_shifted_copies.data());
|
||||||
}
|
}
|
||||||
write(file, this->filter(m_cooling_buffer->flush(), true));
|
write(file, this->filter(m_cooling_buffer->flush(), true));
|
||||||
++ finished_objects;
|
++ finished_objects;
|
||||||
|
@ -437,15 +442,57 @@ bool GCode::do_export(FILE *file, Print &print)
|
||||||
}
|
}
|
||||||
++ object_order;
|
++ object_order;
|
||||||
}
|
}
|
||||||
|
// Get optimal tool ordering to minimize tool switches of a multi-exruder print.
|
||||||
|
std::vector<ToolOrdering::LayerTools> tool_ordering = ToolOrdering::tool_ordering(print);
|
||||||
|
// Prusa Multi-Material wipe tower.
|
||||||
|
if (print.config.single_extruder_multi_material.value && print.config.wipe_tower.value &&
|
||||||
|
! tool_ordering.empty() && tool_ordering.front().wipe_tower_partitions > 0) {
|
||||||
|
// Initialize the wipe tower.
|
||||||
|
auto *wipe_tower = new WipeTowerPrusaMM(
|
||||||
|
float(print.config.wipe_tower_x.value), float(print.config.wipe_tower_y.value),
|
||||||
|
float(print.config.wipe_tower_width.value), float(print.config.wipe_tower_per_color_wipe.value));
|
||||||
|
//wipe_tower->set_retract();
|
||||||
|
//wipe_tower->set_zhop();
|
||||||
|
//wipe_tower->set_zhop();
|
||||||
|
// Set the extruder & material properties at the wipe tower object.
|
||||||
|
for (size_t i = 0; i < 4; ++ i)
|
||||||
|
wipe_tower->set_extruder(
|
||||||
|
i,
|
||||||
|
WipeTowerPrusaMM::parse_material(print.config.filament_type.get_at(i).c_str()),
|
||||||
|
print.config.temperature.get_at(i),
|
||||||
|
print.config.first_layer_temperature.get_at(i));
|
||||||
|
m_wipe_tower.reset(wipe_tower);
|
||||||
|
}
|
||||||
// Extrude the layers.
|
// Extrude the layers.
|
||||||
for (auto &layer : layers)
|
for (auto &layer : layers) {
|
||||||
// layer.second is of type std::vector<LayerToPrint>,
|
// layer.second is of type std::vector<LayerToPrint>,
|
||||||
// wher the objects are sorted by their sorted order given by object_indices.
|
// wher the objects are sorted by their sorted order given by object_indices.
|
||||||
this->process_layer(file, print, layer.second);
|
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), ToolOrdering::LayerTools(layer.first));
|
||||||
|
assert(it_layer_tools != tool_ordering.end() && layer.first);
|
||||||
|
if (m_wipe_tower) {
|
||||||
|
bool first_layer = layer.first == layers.begin()->first;
|
||||||
|
auto it_layer_tools_next = it_layer_tools;
|
||||||
|
++ it_layer_tools_next;
|
||||||
|
m_wipe_tower->set_layer(
|
||||||
|
layer.first,
|
||||||
|
first_layer ?
|
||||||
|
print.objects.front()->config.first_layer_height.get_abs_value(print.objects.front()->config.layer_height.value) :
|
||||||
|
print.objects.front()->config.layer_height.value,
|
||||||
|
it_layer_tools->wipe_tower_partitions,
|
||||||
|
first_layer,
|
||||||
|
it_layer_tools->wipe_tower_partitions == 0 || (it_layer_tools_next == tool_ordering.end() || it_layer_tools_next->wipe_tower_partitions == 0));
|
||||||
|
}
|
||||||
|
this->process_layer(file, print, layer.second, *it_layer_tools, size_t(-1));
|
||||||
|
}
|
||||||
write(file, this->filter(m_cooling_buffer->flush(), true));
|
write(file, this->filter(m_cooling_buffer->flush(), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// write end commands to file
|
// write end commands to file
|
||||||
|
if (m_wipe_tower) {
|
||||||
|
// Unload the current filament over the purge tower.
|
||||||
|
write(file, this->wipe_tower_tool_change(-1));
|
||||||
|
m_wipe_tower.release();
|
||||||
|
} else
|
||||||
write(file, this->retract()); // TODO: process this retract through PressureRegulator in order to discharge fully
|
write(file, this->retract()); // TODO: process this retract through PressureRegulator in order to discharge fully
|
||||||
write(file, m_writer.set_fan(false));
|
write(file, m_writer.set_fan(false));
|
||||||
writeln(file, m_placeholder_parser.process(print.config.end_gcode));
|
writeln(file, m_placeholder_parser.process(print.config.end_gcode));
|
||||||
|
@ -543,6 +590,7 @@ void GCode::process_layer(
|
||||||
const Print &print,
|
const Print &print,
|
||||||
// Set of object & print layers of the same PrintObject and with the same print_z.
|
// Set of object & print layers of the same PrintObject and with the same print_z.
|
||||||
const std::vector<LayerToPrint> &layers,
|
const std::vector<LayerToPrint> &layers,
|
||||||
|
const ToolOrdering::LayerTools &layer_tools,
|
||||||
// If set to size_t(-1), then print all copies of all objects.
|
// If set to size_t(-1), then print all copies of all objects.
|
||||||
// Otherwise print a single copy of a single object.
|
// Otherwise print a single copy of a single object.
|
||||||
const size_t single_object_idx)
|
const size_t single_object_idx)
|
||||||
|
@ -562,7 +610,8 @@ void GCode::process_layer(
|
||||||
}
|
}
|
||||||
const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer;
|
const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer;
|
||||||
coordf_t print_z = layer.print_z;
|
coordf_t print_z = layer.print_z;
|
||||||
bool first_layer = print_z < m_config.first_layer_height.get_abs_value(m_config.layer_height.value) + EPSILON;
|
bool first_layer = layer.id() == 0;
|
||||||
|
unsigned int first_extruder_id = layer_tools.extruders.empty() ? 0 : layer_tools.extruders.front();
|
||||||
|
|
||||||
// Initialize config with the 1st object to be printed at this layer.
|
// Initialize config with the 1st object to be printed at this layer.
|
||||||
m_config.apply(layer.object()->config, true);
|
m_config.apply(layer.object()->config, true);
|
||||||
|
@ -620,7 +669,7 @@ void GCode::process_layer(
|
||||||
if (! m_brim_done)
|
if (! m_brim_done)
|
||||||
// Switch the extruder to the extruder of the perimeters, so the perimeters extruder will be primed
|
// Switch the extruder to the extruder of the perimeters, so the perimeters extruder will be primed
|
||||||
// by the skirt before the brim is extruded with the same extruder.
|
// by the skirt before the brim is extruded with the same extruder.
|
||||||
gcode += this->set_extruder(print.regions.front()->config.perimeter_extruder.value - 1);
|
gcode += this->set_extruder(layer_tools.extruders.front());
|
||||||
|
|
||||||
// Extrude skirt at the print_z of the raft layers and normal object layers
|
// Extrude skirt at the print_z of the raft layers and normal object layers
|
||||||
// not at the print_z of the interlaced support material layers.
|
// not at the print_z of the interlaced support material layers.
|
||||||
|
@ -643,10 +692,10 @@ void GCode::process_layer(
|
||||||
std::vector<unsigned int> extruder_ids = m_writer.extruder_ids();
|
std::vector<unsigned int> extruder_ids = m_writer.extruder_ids();
|
||||||
// Reorder the extruders, so that the last used extruder is at the front.
|
// Reorder the extruders, so that the last used extruder is at the front.
|
||||||
for (size_t i = 1; i < extruder_ids.size(); ++ i)
|
for (size_t i = 1; i < extruder_ids.size(); ++ i)
|
||||||
if (extruder_ids[i] == m_writer.extruder()->id) {
|
if (extruder_ids[i] == first_extruder_id) {
|
||||||
// Move the last extruder to the front.
|
// Move the last extruder to the front.
|
||||||
memmove(extruder_ids.data() + 1, extruder_ids.data(), i * sizeof(unsigned int));
|
memmove(extruder_ids.data() + 1, extruder_ids.data(), i * sizeof(unsigned int));
|
||||||
extruder_ids.front() = m_writer.extruder()->id;
|
extruder_ids.front() = first_extruder_id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
size_t n_loops = print.skirt.entities.size();
|
size_t n_loops = print.skirt.entities.size();
|
||||||
|
@ -668,7 +717,7 @@ void GCode::process_layer(
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
// Extrude all skirts with the current extruder.
|
// Extrude all skirts with the current extruder.
|
||||||
skirt_loops_per_extruder[m_writer.extruder()->id] = std::pair<size_t, size_t>(0, print.config.skirts.value);
|
skirt_loops_per_extruder[first_extruder_id] = std::pair<size_t, size_t>(0, print.config.skirts.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group extrusions by an extruder, then by an object, an island and a region.
|
// Group extrusions by an extruder, then by an object, an island and a region.
|
||||||
|
@ -684,12 +733,12 @@ void GCode::process_layer(
|
||||||
// Don't change extruder if the extruder is set to 0. Use the current extruder instead.
|
// Don't change extruder if the extruder is set to 0. Use the current extruder instead.
|
||||||
bool single_extruder =
|
bool single_extruder =
|
||||||
(object.config.support_material_extruder.value == object.config.support_material_interface_extruder.value ||
|
(object.config.support_material_extruder.value == object.config.support_material_interface_extruder.value ||
|
||||||
(object.config.support_material_extruder.value == int(m_writer.extruder()->id) && object.config.support_material_interface_extruder.value == 0) ||
|
(object.config.support_material_extruder.value == int(first_extruder_id) && object.config.support_material_interface_extruder.value == 0) ||
|
||||||
(object.config.support_material_interface_extruder.value == int(m_writer.extruder()->id) && object.config.support_material_extruder.value == 0));
|
(object.config.support_material_interface_extruder.value == int(first_extruder_id) && object.config.support_material_extruder.value == 0));
|
||||||
// Assign an extruder to the base.
|
// Assign an extruder to the base.
|
||||||
ObjectByExtruder &obj = object_by_extruder(
|
ObjectByExtruder &obj = object_by_extruder(
|
||||||
by_extruder,
|
by_extruder,
|
||||||
(object.config.support_material_extruder == 0) ? m_writer.extruder()->id : (object.config.support_material_extruder - 1),
|
(object.config.support_material_extruder == 0) ? first_extruder_id : (object.config.support_material_extruder - 1),
|
||||||
&layer_to_print - layers.data(),
|
&layer_to_print - layers.data(),
|
||||||
layers.size());
|
layers.size());
|
||||||
obj.support = &support_layer.support_fills;
|
obj.support = &support_layer.support_fills;
|
||||||
|
@ -697,7 +746,7 @@ void GCode::process_layer(
|
||||||
if (! single_extruder) {
|
if (! single_extruder) {
|
||||||
ObjectByExtruder &obj_interface = object_by_extruder(
|
ObjectByExtruder &obj_interface = object_by_extruder(
|
||||||
by_extruder,
|
by_extruder,
|
||||||
(object.config.support_material_interface_extruder == 0) ? m_writer.extruder()->id : (object.config.support_material_interface_extruder - 1),
|
(object.config.support_material_interface_extruder == 0) ? first_extruder_id : (object.config.support_material_interface_extruder - 1),
|
||||||
&layer_to_print - layers.data(),
|
&layer_to_print - layers.data(),
|
||||||
layers.size());
|
layers.size());
|
||||||
obj_interface.support = &support_layer.support_fills;
|
obj_interface.support = &support_layer.support_fills;
|
||||||
|
@ -793,31 +842,14 @@ void GCode::process_layer(
|
||||||
}
|
}
|
||||||
} // for objects
|
} // for objects
|
||||||
|
|
||||||
// Tweak extruder ordering to save toolchanges.
|
|
||||||
std::vector<unsigned int> extruders;
|
|
||||||
extruders.reserve(by_extruder.size());
|
|
||||||
for (const auto &ex : by_extruder)
|
|
||||||
extruders.push_back(ex.first);
|
|
||||||
if (extrude_skirt) {
|
|
||||||
// Merge with the skirt extruders.
|
|
||||||
for (const auto &ex : skirt_loops_per_extruder)
|
|
||||||
extruders.push_back(ex.first);
|
|
||||||
sort_remove_duplicates(extruders);
|
|
||||||
}
|
|
||||||
// Reorder the extruders, so that the last used extruder is at the front.
|
|
||||||
for (size_t i = 1; i < extruders.size(); ++ i)
|
|
||||||
if (extruders[i] == m_writer.extruder()->id) {
|
|
||||||
// Move the last extruder to the front.
|
|
||||||
memmove(extruders.data() + 1, extruders.data(), i * sizeof(unsigned int));
|
|
||||||
extruders.front() = m_writer.extruder()->id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
|
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
|
||||||
std::vector<std::unique_ptr<EdgeGrid::Grid>> lower_layer_edge_grids(layers.size());
|
std::vector<std::unique_ptr<EdgeGrid::Grid>> lower_layer_edge_grids(layers.size());
|
||||||
for (unsigned int extruder_id : extruders)
|
for (unsigned int extruder_id : layer_tools.extruders)
|
||||||
{
|
{
|
||||||
gcode += this->set_extruder(extruder_id);
|
gcode += this->set_extruder(extruder_id);
|
||||||
//FIXME here will come the priming tower call.
|
if (m_wipe_tower && ! m_wipe_tower->finished() && extruder_id == layer_tools.extruders.back())
|
||||||
|
// Last extruder change on the layer or no extruder change at all.
|
||||||
|
m_wipe_tower->close_layer();
|
||||||
|
|
||||||
if (extrude_skirt) {
|
if (extrude_skirt) {
|
||||||
auto loops_it = skirt_loops_per_extruder.find(extruder_id);
|
auto loops_it = skirt_loops_per_extruder.find(extruder_id);
|
||||||
|
@ -1675,7 +1707,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
this->set_last_pos(path.last_point());
|
this->set_last_pos(path.last_point());
|
||||||
|
|
||||||
if (m_config.cooling)
|
if (m_config.cooling)
|
||||||
m_elapsed_time += path_length / F * 60;
|
m_elapsed_time += path_length / F * 60.f;
|
||||||
|
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
@ -1814,21 +1846,39 @@ std::string GCode::set_extruder(unsigned int extruder_id)
|
||||||
gcode += pp.process(m_config.toolchange_gcode.value) + '\n';
|
gcode += pp.process(m_config.toolchange_gcode.value) + '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_wipe_tower) {
|
||||||
|
assert(! m_wipe_tower->finished());
|
||||||
|
if (! m_wipe_tower->finished())
|
||||||
|
gcode += this->wipe_tower_tool_change(extruder_id);
|
||||||
|
} else {
|
||||||
// if ooze prevention is enabled, park current extruder in the nearest
|
// if ooze prevention is enabled, park current extruder in the nearest
|
||||||
// standby point and set it to the standby temperature
|
// standby point and set it to the standby temperature
|
||||||
if (m_ooze_prevention.enable && m_writer.extruder() != NULL)
|
if (m_ooze_prevention.enable && m_writer.extruder() != NULL)
|
||||||
gcode += m_ooze_prevention.pre_toolchange(*this);
|
gcode += m_ooze_prevention.pre_toolchange(*this);
|
||||||
|
|
||||||
// append the toolchange command
|
// append the toolchange command
|
||||||
gcode += m_writer.toolchange(extruder_id);
|
gcode += m_writer.toolchange(extruder_id);
|
||||||
|
|
||||||
// set the new extruder to the operating temperature
|
// set the new extruder to the operating temperature
|
||||||
if (m_ooze_prevention.enable)
|
if (m_ooze_prevention.enable)
|
||||||
gcode += m_ooze_prevention.post_toolchange(*this);
|
gcode += m_ooze_prevention.post_toolchange(*this);
|
||||||
|
}
|
||||||
|
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GCode::wipe_tower_tool_change(int extruder_id)
|
||||||
|
{
|
||||||
|
// Move over the wipe tower.
|
||||||
|
std::string gcode = m_writer.travel_to_xy(Pointf3(m_wipe_tower->position().x, m_wipe_tower->position().y));
|
||||||
|
gcode += m_writer.unlift();
|
||||||
|
// Let the tool change be executed by the wipe tower class.
|
||||||
|
std::pair<std::string, WipeTower::xy> code_and_pos = m_wipe_tower->tool_change(extruder_id);
|
||||||
|
// Inform the G-code writer about the changes done behind its back.
|
||||||
|
gcode += code_and_pos.first;
|
||||||
|
// A phony move to the end position at the wipe tower.
|
||||||
|
m_writer.travel_to_xy(Pointf(code_and_pos.second.x, code_and_pos.second.y));
|
||||||
|
return gcode;
|
||||||
|
}
|
||||||
|
|
||||||
// convert a model-space scaled point into G-code coordinates
|
// convert a model-space scaled point into G-code coordinates
|
||||||
Pointf GCode::point_to_gcode(const Point &point) const
|
Pointf GCode::point_to_gcode(const Point &point) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include "GCode/CoolingBuffer.hpp"
|
#include "GCode/CoolingBuffer.hpp"
|
||||||
#include "GCode/PressureEqualizer.hpp"
|
#include "GCode/PressureEqualizer.hpp"
|
||||||
#include "GCode/SpiralVase.hpp"
|
#include "GCode/SpiralVase.hpp"
|
||||||
|
#include "GCode/ToolOrdering.hpp"
|
||||||
|
#include "GCode/WipeTower.hpp"
|
||||||
#include "EdgeGrid.hpp"
|
#include "EdgeGrid.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -129,6 +131,7 @@ private:
|
||||||
const Print &print,
|
const Print &print,
|
||||||
// Set of object & print layers of the same PrintObject and with the same print_z.
|
// Set of object & print layers of the same PrintObject and with the same print_z.
|
||||||
const std::vector<LayerToPrint> &layers,
|
const std::vector<LayerToPrint> &layers,
|
||||||
|
const ToolOrdering::LayerTools &layer_tools,
|
||||||
// If set to size_t(-1), then print all copies of all objects.
|
// If set to size_t(-1), then print all copies of all objects.
|
||||||
// Otherwise print a single copy of a single object.
|
// Otherwise print a single copy of a single object.
|
||||||
const size_t single_object_idx = size_t(-1));
|
const size_t single_object_idx = size_t(-1));
|
||||||
|
@ -172,6 +175,7 @@ private:
|
||||||
std::string retract(bool toolchange = false);
|
std::string retract(bool toolchange = false);
|
||||||
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }
|
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }
|
||||||
std::string set_extruder(unsigned int extruder_id);
|
std::string set_extruder(unsigned int extruder_id);
|
||||||
|
std::string wipe_tower_tool_change(int extruder_id);
|
||||||
|
|
||||||
/* Origin of print coordinates expressed in unscaled G-code coordinates.
|
/* Origin of print coordinates expressed in unscaled G-code coordinates.
|
||||||
This affects the input arguments supplied to the extrude*() and travel_to()
|
This affects the input arguments supplied to the extrude*() and travel_to()
|
||||||
|
@ -218,6 +222,7 @@ private:
|
||||||
std::unique_ptr<CoolingBuffer> m_cooling_buffer;
|
std::unique_ptr<CoolingBuffer> m_cooling_buffer;
|
||||||
std::unique_ptr<SpiralVase> m_spiral_vase;
|
std::unique_ptr<SpiralVase> m_spiral_vase;
|
||||||
std::unique_ptr<PressureEqualizer> m_pressure_equalizer;
|
std::unique_ptr<PressureEqualizer> m_pressure_equalizer;
|
||||||
|
std::unique_ptr<WipeTower> m_wipe_tower;
|
||||||
|
|
||||||
// Heights at which the skirt has already been extruded.
|
// Heights at which the skirt has already been extruded.
|
||||||
std::vector<coordf_t> m_skirt_done;
|
std::vector<coordf_t> m_skirt_done;
|
||||||
|
|
194
xs/src/libslic3r/GCode/ToolOrdering.cpp
Normal file
194
xs/src/libslic3r/GCode/ToolOrdering.cpp
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
#include "ToolOrdering.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace ToolOrdering {
|
||||||
|
|
||||||
|
// Collect extruders reuqired to print layers.
|
||||||
|
static void collect_extruders(const PrintObject &object, std::vector<LayerTools> &layers)
|
||||||
|
{
|
||||||
|
// Collect the support extruders.
|
||||||
|
for (auto support_layer : object.support_layers) {
|
||||||
|
auto it_layer = std::find(layers.begin(), layers.end(), LayerTools(support_layer->print_z));
|
||||||
|
assert(it_layer != layers.end());
|
||||||
|
ExtrusionRole role = support_layer->support_fills.role();
|
||||||
|
bool has_support = role == erMixed || role == erSupportMaterial;
|
||||||
|
bool has_interface = role == erMixed || role == erSupportMaterialInterface;
|
||||||
|
unsigned int extruder_support = object.config.support_material_extruder.value;
|
||||||
|
unsigned int extruder_interface = object.config.support_material_interface_extruder.value;
|
||||||
|
if (has_support && has_interface) {
|
||||||
|
// If both base and interface supports are to be extruded and one of them will be extruded with a "don't care" extruder,
|
||||||
|
// print both with the same extruder to minimize extruder switches.
|
||||||
|
if (extruder_support == 0)
|
||||||
|
extruder_support = extruder_interface;
|
||||||
|
else if (extruder_interface == 0)
|
||||||
|
extruder_interface = extruder_support;
|
||||||
|
}
|
||||||
|
if (has_support)
|
||||||
|
it_layer->extruders.push_back(extruder_support);
|
||||||
|
if (has_interface)
|
||||||
|
it_layer->extruders.push_back(extruder_interface);
|
||||||
|
}
|
||||||
|
// Collect the object extruders.
|
||||||
|
for (auto layer : object.layers) {
|
||||||
|
auto it_layer = std::find(layers.begin(), layers.end(), LayerTools(layer->print_z));
|
||||||
|
assert(it_layer != layers.end());
|
||||||
|
// What extruders are required to print this object layer?
|
||||||
|
for (size_t region_id = 0; region_id < object.print()->regions.size(); ++ region_id) {
|
||||||
|
const LayerRegion *layerm = layer->regions[region_id];
|
||||||
|
if (layerm == nullptr)
|
||||||
|
continue;
|
||||||
|
const PrintRegion ®ion = *object.print()->regions[region_id];
|
||||||
|
if (! layerm->perimeters.entities.empty())
|
||||||
|
it_layer->extruders.push_back(region.config.perimeter_extruder.value);
|
||||||
|
bool has_infill = false;
|
||||||
|
bool has_solid_infill = false;
|
||||||
|
for (const ExtrusionEntity *ee : layerm->fills.entities) {
|
||||||
|
// fill represents infill extrusions of a single island.
|
||||||
|
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||||
|
ExtrusionRole role = fill->entities.empty() ? erNone : fill->entities.front()->role();
|
||||||
|
if (is_solid_infill(role))
|
||||||
|
has_solid_infill = true;
|
||||||
|
else if (role != erNone)
|
||||||
|
has_infill = true;
|
||||||
|
}
|
||||||
|
if (has_solid_infill)
|
||||||
|
it_layer->extruders.push_back(region.config.solid_infill_extruder);
|
||||||
|
if (has_infill)
|
||||||
|
it_layer->extruders.push_back(region.config.infill_extruder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort and remove duplicates
|
||||||
|
for (LayerTools < : layers)
|
||||||
|
sort_remove_duplicates(lt.extruders);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reorder extruders to minimize layer changes.
|
||||||
|
static void reorder_extruders(std::vector<LayerTools> &layers)
|
||||||
|
{
|
||||||
|
if (layers.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Initialize the last_extruder_id with the first non-zero extruder id used for the print.
|
||||||
|
unsigned int last_extruder_id = 0;
|
||||||
|
for (size_t i = 0; i < layers.size() && last_extruder_id == 0; ++ i) {
|
||||||
|
const LayerTools < = layers[i];
|
||||||
|
for (unsigned int extruder_id : lt.extruders)
|
||||||
|
if (extruder_id > 0) {
|
||||||
|
last_extruder_id = extruder_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (last_extruder_id == 0)
|
||||||
|
last_extruder_id = 1;
|
||||||
|
|
||||||
|
for (LayerTools < : layers) {
|
||||||
|
if (lt.extruders.empty())
|
||||||
|
continue;
|
||||||
|
if (lt.extruders.size() == 1 && lt.extruders.front() == 0)
|
||||||
|
lt.extruders.front() = last_extruder_id;
|
||||||
|
else {
|
||||||
|
if (lt.extruders.front() == 0)
|
||||||
|
// Pop the "don't care" extruder, the "don't care" region will be merged with the next one.
|
||||||
|
lt.extruders.erase(lt.extruders.begin());
|
||||||
|
// Reorder the extruders to start with the last one.
|
||||||
|
for (size_t i = 1; i < lt.extruders.size(); ++ i)
|
||||||
|
if (lt.extruders[i] == last_extruder_id) {
|
||||||
|
// Move the last extruder to the front.
|
||||||
|
memmove(lt.extruders.data() + 1, lt.extruders.data(), i * sizeof(unsigned int));
|
||||||
|
lt.extruders.front() = last_extruder_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_extruder_id = lt.extruders.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reindex the extruders, so they are zero based, not 1 based.
|
||||||
|
for (LayerTools < : layers)
|
||||||
|
for (unsigned int &extruder_id : lt.extruders) {
|
||||||
|
assert(extruder_id > 0);
|
||||||
|
-- extruder_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_wipe_tower_partitions(std::vector<LayerTools> &layers)
|
||||||
|
{
|
||||||
|
if (layers.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Count the minimum number of tool changes per layer.
|
||||||
|
for (LayerTools < : layers)
|
||||||
|
lt.wipe_tower_partitions = std::max<int>(0, int(layers.front().extruders.size()) - 1);
|
||||||
|
|
||||||
|
// In case a distinct set of tools are used between two layers, there will be an additional tool change at the start of a layer.
|
||||||
|
//FIXME this does not minimize the number of tool changes in worst case.
|
||||||
|
for (size_t i = 1; i < layers.size(); ++ i)
|
||||||
|
if (layers[i-1].extruders.back() != layers[i].extruders.front())
|
||||||
|
++ layers[i].wipe_tower_partitions;
|
||||||
|
|
||||||
|
// Propagate the wipe tower partitions down to support the upper partitions by the lower partitions.
|
||||||
|
for (int i = int(layers.size()) - 2; i >= 0; -- i)
|
||||||
|
layers[i].wipe_tower_partitions = std::max(layers[i + 1].wipe_tower_partitions, layers[i].wipe_tower_partitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the use case when each object is printed separately
|
||||||
|
// (print.config.complete_objects is true).
|
||||||
|
std::vector<LayerTools> tool_ordering(PrintObject &object)
|
||||||
|
{
|
||||||
|
// Initialize the print layers for just a single object.
|
||||||
|
std::vector<LayerTools> layers;
|
||||||
|
{
|
||||||
|
std::vector<coordf_t> zs;
|
||||||
|
zs.reserve(zs.size() + object.layers.size() + object.support_layers.size());
|
||||||
|
for (auto layer : object.layers)
|
||||||
|
zs.emplace_back(layer->print_z);
|
||||||
|
for (auto layer : object.support_layers)
|
||||||
|
zs.emplace_back(layer->print_z);
|
||||||
|
sort_remove_duplicates(zs);
|
||||||
|
for (coordf_t z : zs)
|
||||||
|
layers.emplace_back(LayerTools(z));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect extruders reuqired to print the layers.
|
||||||
|
collect_extruders(object, layers);
|
||||||
|
|
||||||
|
// Reorder the extruders to minimize tool switches.
|
||||||
|
reorder_extruders(layers);
|
||||||
|
|
||||||
|
fill_wipe_tower_partitions(layers);
|
||||||
|
return layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the use case when all objects are printed at once.
|
||||||
|
// (print.config.complete_objects is false).
|
||||||
|
std::vector<LayerTools> tool_ordering(const Print &print)
|
||||||
|
{
|
||||||
|
// Initialize the print layers for all objects and all layers.
|
||||||
|
std::vector<LayerTools> layers;
|
||||||
|
{
|
||||||
|
std::vector<coordf_t> zs;
|
||||||
|
for (auto object : print.objects) {
|
||||||
|
zs.reserve(zs.size() + object->layers.size() + object->support_layers.size());
|
||||||
|
for (auto layer : object->layers)
|
||||||
|
zs.emplace_back(layer->print_z);
|
||||||
|
for (auto layer : object->support_layers)
|
||||||
|
zs.emplace_back(layer->print_z);
|
||||||
|
}
|
||||||
|
sort_remove_duplicates(zs);
|
||||||
|
for (coordf_t z : zs)
|
||||||
|
layers.emplace_back(LayerTools(z));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect extruders reuqired to print the layers.
|
||||||
|
for (auto object : print.objects)
|
||||||
|
collect_extruders(*object, layers);
|
||||||
|
|
||||||
|
// Reorder the extruders to minimize tool switches.
|
||||||
|
reorder_extruders(layers);
|
||||||
|
|
||||||
|
fill_wipe_tower_partitions(layers);
|
||||||
|
return layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ToolOrdering
|
||||||
|
} // namespace Slic3r
|
38
xs/src/libslic3r/GCode/ToolOrdering.hpp
Normal file
38
xs/src/libslic3r/GCode/ToolOrdering.hpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// Ordering of the tools to minimize tool switches.
|
||||||
|
|
||||||
|
#ifndef slic3r_ToolOrdering_hpp_
|
||||||
|
#define slic3r_ToolOrdering_hpp_
|
||||||
|
|
||||||
|
#include "libslic3r.h"
|
||||||
|
#include "Print.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace ToolOrdering {
|
||||||
|
|
||||||
|
struct LayerTools
|
||||||
|
{
|
||||||
|
LayerTools(const coordf_t z) : print_z(z), wipe_tower_partitions(0) {}
|
||||||
|
|
||||||
|
bool operator< (const LayerTools &rhs) const { return print_z < rhs.print_z; }
|
||||||
|
bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; }
|
||||||
|
|
||||||
|
coordf_t print_z;
|
||||||
|
// Zero based extruder IDs, ordered to minimize tool switches.
|
||||||
|
std::vector<unsigned int> extruders;
|
||||||
|
// Number of wipe tower partitions to support the required number of tool switches
|
||||||
|
// and to support the wipe tower partitions above this one.
|
||||||
|
size_t wipe_tower_partitions;
|
||||||
|
};
|
||||||
|
|
||||||
|
// For the use case when each object is printed separately
|
||||||
|
// (print.config.complete_objects is true).
|
||||||
|
extern std::vector<LayerTools> tool_ordering(PrintObject &object);
|
||||||
|
|
||||||
|
// For the use case when all objects are printed at once.
|
||||||
|
// (print.config.complete_objects is false).
|
||||||
|
extern std::vector<LayerTools> tool_ordering(const Print &print);
|
||||||
|
|
||||||
|
} // namespace ToolOrdering
|
||||||
|
} // namespace SLic3r
|
||||||
|
|
||||||
|
#endif /* slic3r_ToolOrdering_hpp_ */
|
59
xs/src/libslic3r/GCode/WipeTower.hpp
Normal file
59
xs/src/libslic3r/GCode/WipeTower.hpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef slic3r_WipeTower_hpp_
|
||||||
|
#define slic3r_WipeTower_hpp_
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Slic3r
|
||||||
|
{
|
||||||
|
|
||||||
|
// A pure virtual WipeTower definition.
|
||||||
|
class WipeTower
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Internal point class, to make the wipe tower independent from other slic3r modules.
|
||||||
|
// This is important for Prusa Research as we want to build the wipe tower post-processor independently from slic3r.
|
||||||
|
struct xy
|
||||||
|
{
|
||||||
|
xy(float x = 0.f, float y = 0.f) : x(x), y(y) {}
|
||||||
|
xy operator+(const xy &rhs) const { xy out(*this); out.x += rhs.x; out.y += rhs.y; return out; }
|
||||||
|
xy operator-(const xy &rhs) const { xy out(*this); out.x -= rhs.x; out.y -= rhs.y; return out; }
|
||||||
|
xy& operator+=(const xy &rhs) { x += rhs.x; y += rhs.y; return *this; }
|
||||||
|
xy& operator-=(const xy &rhs) { x -= rhs.x; y -= rhs.y; return *this; }
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
|
||||||
|
WipeTower() {}
|
||||||
|
virtual ~WipeTower() {}
|
||||||
|
|
||||||
|
// Return the wipe tower position.
|
||||||
|
virtual const xy& position() const = 0;
|
||||||
|
|
||||||
|
// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
|
||||||
|
virtual bool finished() const = 0;
|
||||||
|
|
||||||
|
// Switch to a next layer.
|
||||||
|
virtual void set_layer(
|
||||||
|
// Print height of this layer.
|
||||||
|
float print_z,
|
||||||
|
// Layer height, used to calculate extrusion the rate.
|
||||||
|
float layer_height,
|
||||||
|
// Maximum number of tool changes on this layer or the layers below.
|
||||||
|
size_t max_tool_changes,
|
||||||
|
// Is this the first layer of the print? In that case print the brim first.
|
||||||
|
bool is_first_layer,
|
||||||
|
// Is this the last layer of the wipe tower?
|
||||||
|
bool is_last_layer) = 0;
|
||||||
|
|
||||||
|
// Returns gcode for toolchange and the end position.
|
||||||
|
// if new_tool == -1, just unload the current filament over the wipe tower.
|
||||||
|
virtual std::pair<std::string, xy> tool_change(int new_tool) = 0;
|
||||||
|
|
||||||
|
// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
|
||||||
|
virtual std::pair<std::string, xy> close_layer() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Slic3r
|
||||||
|
|
||||||
|
#endif /* slic3r_WipeTower_hpp_ */
|
|
@ -1,4 +1,4 @@
|
||||||
#include "WipeTower.hpp"
|
#include "WipeTowerPrusaMM.hpp"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -13,9 +13,11 @@
|
||||||
#define strcasecmp _stricmp
|
#define strcasecmp _stricmp
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace PrusaSingleExtruderMM
|
namespace Slic3r
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace PrusaMultiMaterial {
|
||||||
|
|
||||||
class Writer
|
class Writer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -171,18 +173,18 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
Writer& comment_material(WipeTower::material_type material)
|
Writer& comment_material(WipeTowerPrusaMM::material_type material)
|
||||||
{
|
{
|
||||||
m_gcode += "; material : ";
|
m_gcode += "; material : ";
|
||||||
switch (material)
|
switch (material)
|
||||||
{
|
{
|
||||||
case WipeTower::PVA:
|
case WipeTowerPrusaMM::PVA:
|
||||||
m_gcode += "#8 (PVA)";
|
m_gcode += "#8 (PVA)";
|
||||||
break;
|
break;
|
||||||
case WipeTower::SCAFF:
|
case WipeTowerPrusaMM::SCAFF:
|
||||||
m_gcode += "#5 (Scaffold)";
|
m_gcode += "#5 (Scaffold)";
|
||||||
break;
|
break;
|
||||||
case WipeTower::FLEX:
|
case WipeTowerPrusaMM::FLEX:
|
||||||
m_gcode += "#4 (Flex)";
|
m_gcode += "#4 (Flex)";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -236,6 +238,8 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace PrusaMultiMaterial
|
||||||
|
|
||||||
static inline int randi(int lo, int hi)
|
static inline int randi(int lo, int hi)
|
||||||
{
|
{
|
||||||
int n = hi - lo + 1;
|
int n = hi - lo + 1;
|
||||||
|
@ -244,7 +248,7 @@ static inline int randi(int lo, int hi)
|
||||||
return lo + i;
|
return lo + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
WipeTower::material_type WipeTower::parse_material(const char *name)
|
WipeTowerPrusaMM::material_type WipeTowerPrusaMM::parse_material(const char *name)
|
||||||
{
|
{
|
||||||
if (strcasecmp(name, "PLA") == 0)
|
if (strcasecmp(name, "PLA") == 0)
|
||||||
return PLA;
|
return PLA;
|
||||||
|
@ -267,116 +271,58 @@ WipeTower::material_type WipeTower::parse_material(const char *name)
|
||||||
return INVALID;
|
return INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string WipeTower::FirstLayer(bool sideOnly, float y_offset)
|
std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::tool_change(int tool)
|
||||||
{
|
{
|
||||||
const box_coordinates wipeTower_box(
|
// Either it is the last tool unload,
|
||||||
m_wipe_tower_pos,
|
// or there must be a nonzero wipe tower partitions available.
|
||||||
m_wipe_tower_width,
|
assert(tool < 0 || it_layer_tools->wipe_tower_partitions > 0);
|
||||||
m_wipe_area * float(m_color_changes) - perimeterWidth / 2);
|
|
||||||
|
|
||||||
Writer writer;
|
if (m_layer_change_in_layer == size_t(-1))
|
||||||
writer.set_extrusion_flow(extrusion_flow * 1.1f)
|
// First layer, prime the extruder.
|
||||||
// Let the writer know the current Z position as a base for Z-hop.
|
return toolchange_Brim(tool);
|
||||||
.set_z(m_z_pos)
|
|
||||||
.append(
|
|
||||||
";-------------------------------------\n"
|
|
||||||
"; CP WIPE TOWER FIRST LAYER BRIM START\n");
|
|
||||||
|
|
||||||
// Move with Z hop and prime the extruder 10*perimeterWidth left along the vertical edge of the wipe tower.
|
|
||||||
writer.z_hop(zHop, 7200)
|
|
||||||
.travel(wipeTower_box.lu - xy(perimeterWidth * 10.f, 0), 6000)
|
|
||||||
.z_hop(0, 7200)
|
|
||||||
.extrude_explicit(wipeTower_box.ld - xy(perimeterWidth * 10.f, 0), retract, 2400)
|
|
||||||
.feedrate(2100);
|
|
||||||
|
|
||||||
if (sideOnly) {
|
|
||||||
float x_offset = 0.f;
|
|
||||||
for (size_t i = 0; i < 4; ++ i, x_offset += perimeterWidth)
|
|
||||||
writer.travel (wipeTower_box.ld + xy(- x_offset, y_offset))
|
|
||||||
.extrude(wipeTower_box.lu + xy(- x_offset, - y_offset));
|
|
||||||
writer.travel(wipeTower_box.rd + xy(x_offset, y_offset), 7000)
|
|
||||||
.feedrate(2100);
|
|
||||||
x_offset = 0.f;
|
|
||||||
for (size_t i = 0; i < 4; ++ i, x_offset += perimeterWidth)
|
|
||||||
writer.travel (wipeTower_box.rd + xy(x_offset, y_offset))
|
|
||||||
.extrude(wipeTower_box.ru + xy(x_offset, - y_offset));
|
|
||||||
} else {
|
|
||||||
// Extrude 4 rounds of a brim around the future wipe tower.
|
|
||||||
box_coordinates box(wipeTower_box);
|
|
||||||
box.ld += xy(- perimeterWidth / 2, 0);
|
|
||||||
box.lu += xy(- perimeterWidth / 2, perimeterWidth);
|
|
||||||
box.rd += xy( perimeterWidth / 2, 0);
|
|
||||||
box.ru += xy( perimeterWidth / 2, perimeterWidth);
|
|
||||||
for (size_t i = 0; i < 4; ++ i) {
|
|
||||||
writer.travel(box.ld)
|
|
||||||
.extrude(box.lu) .extrude(box.ru)
|
|
||||||
.extrude(box.rd) .extrude(box.ld);
|
|
||||||
box.expand(perimeterWidth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to the front left corner and wipe along the front edge.
|
|
||||||
writer.travel(wipeTower_box.ld, 7000)
|
|
||||||
.travel(wipeTower_box.rd)
|
|
||||||
.travel(wipeTower_box.ld)
|
|
||||||
.append("; CP WIPE TOWER FIRST LAYER BRIM END\n"
|
|
||||||
";-----------------------------------\n");
|
|
||||||
|
|
||||||
return writer.gcode();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<std::string, WipeTower::xy> WipeTower::Toolchange(
|
|
||||||
const int tool,
|
|
||||||
const material_type current_material,
|
|
||||||
const material_type new_material,
|
|
||||||
const int temperature,
|
|
||||||
const wipe_shape shape,
|
|
||||||
const int count,
|
|
||||||
const float spaceAvailable,
|
|
||||||
const float wipeStartY,
|
|
||||||
const bool lastInFile,
|
|
||||||
const bool colorInit)
|
|
||||||
{
|
|
||||||
box_coordinates cleaning_box(
|
box_coordinates cleaning_box(
|
||||||
m_wipe_tower_pos.x,
|
m_wipe_tower_pos.x,
|
||||||
m_wipe_tower_pos.y + wipeStartY,
|
m_wipe_tower_pos.y + m_current_wipe_start_y,
|
||||||
m_wipe_tower_width,
|
m_wipe_tower_width,
|
||||||
spaceAvailable - perimeterWidth / 2);
|
m_wipe_area - m_perimeter_width / 2);
|
||||||
|
|
||||||
Writer writer;
|
PrusaMultiMaterial::Writer writer;
|
||||||
writer.set_extrusion_flow(extrusion_flow)
|
writer.set_extrusion_flow(m_extrusion_flow)
|
||||||
.set_z(m_z_pos)
|
.set_z(m_z_pos)
|
||||||
.append(";--------------------\n"
|
.append(";--------------------\n"
|
||||||
"; CP TOOLCHANGE START\n")
|
"; CP TOOLCHANGE START\n")
|
||||||
.comment_with_value(" toolchange #", count)
|
.comment_with_value(" toolchange #", m_layer_change_total)
|
||||||
.comment_material(current_material)
|
.comment_material(m_current_material)
|
||||||
.append(";--------------------\n")
|
.append(";--------------------\n")
|
||||||
.speed_override(100)
|
.speed_override(100)
|
||||||
// Lift for a Z hop.
|
// Lift for a Z hop.
|
||||||
.z_hop(zHop, 7200)
|
.z_hop(m_zhop, 7200)
|
||||||
// additional retract on move to tower
|
// additional retract on move to tower
|
||||||
.retract(retract/2, 3600)
|
.retract(m_retract/2, 3600)
|
||||||
.travel(((shape == SHAPE_NORMAL) ? cleaning_box.ld : cleaning_box.rd) + xy(perimeterWidth, shape * perimeterWidth), 7200)
|
.travel(((m_current_shape == SHAPE_NORMAL) ? cleaning_box.ld : cleaning_box.rd) + xy(m_perimeter_width, m_current_shape * m_perimeter_width), 7200)
|
||||||
// Unlift for a Z hop.
|
// Unlift for a Z hop.
|
||||||
.z_hop(0, 7200)
|
.z_hop(0, 7200)
|
||||||
// Additional retract on move to tower.
|
// Additional retract on move to tower.
|
||||||
.deretract(retract/2, 3600)
|
.deretract(m_retract/2, 3600)
|
||||||
.deretract(retract, 1500)
|
.deretract(m_retract, 1500)
|
||||||
// Increase extruder current for ramming.
|
// Increase extruder current for ramming.
|
||||||
.set_extruder_trimpot(750)
|
.set_extruder_trimpot(750)
|
||||||
.flush_planner_queue();
|
.flush_planner_queue();
|
||||||
|
|
||||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||||
toolchange_Unload(writer, cleaning_box, current_material, shape, temperature);
|
toolchange_Unload(writer, cleaning_box, m_current_material, m_current_shape,
|
||||||
|
m_is_first_layer ? m_first_layer_temperature[tool] : m_temperature[tool]);
|
||||||
|
|
||||||
if (! lastInFile) {
|
if (tool >= 0) {
|
||||||
|
// This is not the last change.
|
||||||
// Change the tool, set a speed override for solube and flex materials.
|
// Change the tool, set a speed override for solube and flex materials.
|
||||||
toolchange_Change(writer, tool, current_material, new_material);
|
toolchange_Change(writer, tool, m_current_material, m_material[tool]);
|
||||||
toolchange_Load(writer, cleaning_box, current_material, shape, colorInit);
|
toolchange_Load(writer, cleaning_box);
|
||||||
// Wipe the newly loaded filament until the end of the assigned wipe area.
|
// Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||||
toolchange_Wipe(writer, cleaning_box, current_material, shape);
|
toolchange_Wipe(writer, cleaning_box, m_current_material);
|
||||||
// Draw a perimeter around cleaning_box and wipe.
|
// Draw a perimeter around cleaning_box and wipe.
|
||||||
toolchange_Done(writer, cleaning_box, current_material, shape);
|
toolchange_Done(writer, cleaning_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the extruder current to a normal value.
|
// Reset the extruder current to a normal value.
|
||||||
|
@ -387,20 +333,83 @@ std::pair<std::string, WipeTower::xy> WipeTower::Toolchange(
|
||||||
";------------------\n"
|
";------------------\n"
|
||||||
"\n\n");
|
"\n\n");
|
||||||
|
|
||||||
|
++ m_layer_change_in_layer;
|
||||||
|
m_current_wipe_start_y += m_wipe_area;
|
||||||
|
m_current_material = m_material[tool];
|
||||||
|
return std::pair<std::string, xy>(writer.gcode(), writer.pos());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::toolchange_Brim(size_t tool, bool sideOnly, float y_offset)
|
||||||
|
{
|
||||||
|
const box_coordinates wipeTower_box(
|
||||||
|
m_wipe_tower_pos,
|
||||||
|
m_wipe_tower_width,
|
||||||
|
m_wipe_area * float(m_max_color_changes) - m_perimeter_width / 2);
|
||||||
|
|
||||||
|
PrusaMultiMaterial::Writer writer;
|
||||||
|
writer.set_extrusion_flow(m_extrusion_flow * 1.1f)
|
||||||
|
// Let the writer know the current Z position as a base for Z-hop.
|
||||||
|
.set_z(m_z_pos)
|
||||||
|
.append(
|
||||||
|
";-------------------------------------\n"
|
||||||
|
"; CP WIPE TOWER FIRST LAYER BRIM START\n");
|
||||||
|
|
||||||
|
// Move with Z hop and prime the extruder 10*m_perimeter_width left along the vertical edge of the wipe tower.
|
||||||
|
writer.z_hop(m_zhop, 7200)
|
||||||
|
.travel(wipeTower_box.lu - xy(m_perimeter_width * 10.f, 0), 6000)
|
||||||
|
.z_hop(0, 7200)
|
||||||
|
.extrude_explicit(wipeTower_box.ld - xy(m_perimeter_width * 10.f, 0), m_retract, 2400)
|
||||||
|
.feedrate(2100);
|
||||||
|
|
||||||
|
toolchange_Change(writer, tool, m_current_material, m_material[tool]);
|
||||||
|
|
||||||
|
if (sideOnly) {
|
||||||
|
float x_offset = 0.f;
|
||||||
|
for (size_t i = 0; i < 4; ++ i, x_offset += m_perimeter_width)
|
||||||
|
writer.travel (wipeTower_box.ld + xy(- x_offset, y_offset))
|
||||||
|
.extrude(wipeTower_box.lu + xy(- x_offset, - y_offset));
|
||||||
|
writer.travel(wipeTower_box.rd + xy(x_offset, y_offset), 7000)
|
||||||
|
.feedrate(2100);
|
||||||
|
x_offset = 0.f;
|
||||||
|
for (size_t i = 0; i < 4; ++ i, x_offset += m_perimeter_width)
|
||||||
|
writer.travel (wipeTower_box.rd + xy(x_offset, y_offset))
|
||||||
|
.extrude(wipeTower_box.ru + xy(x_offset, - y_offset));
|
||||||
|
} else {
|
||||||
|
// Extrude 4 rounds of a brim around the future wipe tower.
|
||||||
|
box_coordinates box(wipeTower_box);
|
||||||
|
box.ld += xy(- m_perimeter_width / 2, 0);
|
||||||
|
box.lu += xy(- m_perimeter_width / 2, m_perimeter_width);
|
||||||
|
box.rd += xy( m_perimeter_width / 2, 0);
|
||||||
|
box.ru += xy( m_perimeter_width / 2, m_perimeter_width);
|
||||||
|
for (size_t i = 0; i < 4; ++ i) {
|
||||||
|
writer.travel(box.ld)
|
||||||
|
.extrude(box.lu) .extrude(box.ru)
|
||||||
|
.extrude(box.rd) .extrude(box.ld);
|
||||||
|
box.expand(m_perimeter_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the front left corner and wipe along the front edge.
|
||||||
|
writer.travel(wipeTower_box.ld, 7000)
|
||||||
|
.travel(wipeTower_box.rd)
|
||||||
|
.travel(wipeTower_box.ld)
|
||||||
|
.append("; CP WIPE TOWER FIRST LAYER BRIM END\n"
|
||||||
|
";-----------------------------------\n");
|
||||||
|
|
||||||
return std::pair<std::string, xy>(writer.gcode(), writer.pos());
|
return std::pair<std::string, xy>(writer.gcode(), writer.pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||||
void WipeTower::toolchange_Unload(
|
void WipeTowerPrusaMM::toolchange_Unload(
|
||||||
Writer &writer,
|
PrusaMultiMaterial::Writer &writer,
|
||||||
const box_coordinates &cleaning_box,
|
const box_coordinates &cleaning_box,
|
||||||
const material_type material,
|
const material_type material,
|
||||||
const wipe_shape shape,
|
const wipe_shape shape,
|
||||||
const int temperature)
|
const int temperature)
|
||||||
{
|
{
|
||||||
float xl = cleaning_box.ld.x + (perimeterWidth / 2);
|
float xl = cleaning_box.ld.x + (m_perimeter_width / 2);
|
||||||
float xr = cleaning_box.rd.x - (perimeterWidth / 2);
|
float xr = cleaning_box.rd.x - (m_perimeter_width / 2);
|
||||||
float y_step = shape * perimeterWidth;
|
float y_step = shape * m_perimeter_width;
|
||||||
|
|
||||||
writer.append("; CP TOOLCHANGE UNLOAD");
|
writer.append("; CP TOOLCHANGE UNLOAD");
|
||||||
|
|
||||||
|
@ -409,20 +418,20 @@ void WipeTower::toolchange_Unload(
|
||||||
{
|
{
|
||||||
case PVA:
|
case PVA:
|
||||||
// ramming start end y increment amount feedrate
|
// ramming start end y increment amount feedrate
|
||||||
writer.ram(xl + perimeterWidth * 2, xr - perimeterWidth, y_step * 1.2f, 3, 4000)
|
writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 1.2f, 3, 4000)
|
||||||
.ram(xr - perimeterWidth, xl + perimeterWidth, y_step * 1.5f, 3, 4500)
|
.ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 1.5f, 3, 4500)
|
||||||
.ram(xl + perimeterWidth * 2, xr - perimeterWidth * 2, y_step * 1.5f, 3, 4800)
|
.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 1.5f, 3, 4800)
|
||||||
.ram(xr - perimeterWidth, xl + perimeterWidth, y_step * 1.5f, 3, 5000);
|
.ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 1.5f, 3, 5000);
|
||||||
break;
|
break;
|
||||||
case SCAFF:
|
case SCAFF:
|
||||||
writer.ram(xl + perimeterWidth * 2, xr - perimeterWidth, y_step * 3.f, 3, 4000)
|
writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 3.f, 3, 4000)
|
||||||
.ram(xr - perimeterWidth, xl + perimeterWidth, y_step * 3.f, 4, 4600)
|
.ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 3.f, 4, 4600)
|
||||||
.ram(xl + perimeterWidth * 2, xr - perimeterWidth * 2, y_step * 3.f, 4.5, 5200);
|
.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 3.f, 4.5, 5200);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
writer.ram(xl + perimeterWidth * 2, xr - perimeterWidth, y_step * 1.2f, 1.6f, 4000)
|
writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 1.2f, 1.6f, 4000)
|
||||||
.ram(xr - perimeterWidth, xl + perimeterWidth, y_step * 1.2f, 1.65f, 4600)
|
.ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 1.2f, 1.65f, 4600)
|
||||||
.ram(xl + perimeterWidth * 2, xr - perimeterWidth * 2, y_step * 1.2f, 1.74f, 5200);
|
.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 1.2f, 1.74f, 5200);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull the filament end into a cooling tube.
|
// Pull the filament end into a cooling tube.
|
||||||
|
@ -462,8 +471,8 @@ void WipeTower::toolchange_Unload(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the tool, set a speed override for solube and flex materials.
|
// Change the tool, set a speed override for solube and flex materials.
|
||||||
void WipeTower::toolchange_Change(
|
void WipeTowerPrusaMM::toolchange_Change(
|
||||||
Writer &writer,
|
PrusaMultiMaterial::Writer &writer,
|
||||||
const int tool,
|
const int tool,
|
||||||
material_type /* current_material */,
|
material_type /* current_material */,
|
||||||
material_type new_material)
|
material_type new_material)
|
||||||
|
@ -481,15 +490,12 @@ void WipeTower::toolchange_Change(
|
||||||
.flush_planner_queue();
|
.flush_planner_queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WipeTower::toolchange_Load(
|
void WipeTowerPrusaMM::toolchange_Load(
|
||||||
Writer &writer,
|
PrusaMultiMaterial::Writer &writer,
|
||||||
const box_coordinates &cleaning_box,
|
const box_coordinates &cleaning_box)
|
||||||
const material_type /* material */,
|
|
||||||
const wipe_shape shape,
|
|
||||||
const bool colorInit)
|
|
||||||
{
|
{
|
||||||
float xl = cleaning_box.ld.x + perimeterWidth;
|
float xl = cleaning_box.ld.x + m_perimeter_width;
|
||||||
float xr = cleaning_box.rd.x - perimeterWidth;
|
float xr = cleaning_box.rd.x - m_perimeter_width;
|
||||||
|
|
||||||
writer.append("; CP TOOLCHANGE LOAD\n")
|
writer.append("; CP TOOLCHANGE LOAD\n")
|
||||||
// Load the filament while moving left / right,
|
// Load the filament while moving left / right,
|
||||||
|
@ -501,11 +507,12 @@ void WipeTower::toolchange_Load(
|
||||||
|
|
||||||
// Extrude first five lines (just three lines if colorInit is set).
|
// Extrude first five lines (just three lines if colorInit is set).
|
||||||
writer.extrude(xr, writer.y(), 1600);
|
writer.extrude(xr, writer.y(), 1600);
|
||||||
|
bool colorInit = false;
|
||||||
size_t pass = colorInit ? 1 : 2;
|
size_t pass = colorInit ? 1 : 2;
|
||||||
for (int i = 0; i < pass; ++ i)
|
for (int i = 0; i < pass; ++ i)
|
||||||
writer.travel (xr, writer.y() + shape * perimeterWidth * 0.85f, 2200)
|
writer.travel (xr, writer.y() + m_current_shape * m_perimeter_width * 0.85f, 2200)
|
||||||
.extrude(xl, writer.y())
|
.extrude(xl, writer.y())
|
||||||
.travel (xl, writer.y() + shape * perimeterWidth * 0.85f)
|
.travel (xl, writer.y() + m_current_shape * m_perimeter_width * 0.85f)
|
||||||
.extrude(xr, writer.y());
|
.extrude(xr, writer.y());
|
||||||
|
|
||||||
// Reset the extruder current to the normal value.
|
// Reset the extruder current to the normal value.
|
||||||
|
@ -513,52 +520,49 @@ void WipeTower::toolchange_Load(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wipe the newly loaded filament until the end of the assigned wipe area.
|
// Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||||
void WipeTower::toolchange_Wipe(
|
void WipeTowerPrusaMM::toolchange_Wipe(
|
||||||
Writer &writer,
|
PrusaMultiMaterial::Writer &writer,
|
||||||
const box_coordinates &cleaning_box,
|
const box_coordinates &cleaning_box,
|
||||||
const material_type material,
|
const material_type material)
|
||||||
const wipe_shape shape)
|
|
||||||
{
|
{
|
||||||
// Increase flow on first layer, slow down print.
|
// Increase flow on first layer, slow down print.
|
||||||
writer.set_extrusion_flow(extrusion_flow * (is_first_layer() ? 1.18f : 1.f))
|
writer.set_extrusion_flow(m_extrusion_flow * (m_is_first_layer ? 1.18f : 1.f))
|
||||||
.append("; CP TOOLCHANGE WIPE\n");
|
.append("; CP TOOLCHANGE WIPE\n");
|
||||||
float wipe_coeff = is_first_layer() ? 0.5f : 1.f;
|
float wipe_coeff = m_is_first_layer ? 0.5f : 1.f;
|
||||||
float xl = cleaning_box.ld.x + 2.f * perimeterWidth;
|
float xl = cleaning_box.ld.x + 2.f * m_perimeter_width;
|
||||||
float xr = cleaning_box.rd.x - 2.f * perimeterWidth;
|
float xr = cleaning_box.rd.x - 2.f * m_perimeter_width;
|
||||||
// Wipe speed will increase up to 4800.
|
// Wipe speed will increase up to 4800.
|
||||||
float wipe_speed = 4200;
|
float wipe_speed = 4200;
|
||||||
// Y increment per wipe line.
|
// Y increment per wipe line.
|
||||||
float dy = shape * perimeterWidth * 0.7f;
|
float dy = m_current_shape * m_perimeter_width * 0.7f;
|
||||||
for (bool p = true; ; p = ! p) {
|
for (bool p = true; ; p = ! p) {
|
||||||
writer.feedrate((wipe_speed = std::min(4800.f, wipe_speed + 50.f)) * wipe_coeff);
|
writer.feedrate((wipe_speed = std::min(4800.f, wipe_speed + 50.f)) * wipe_coeff);
|
||||||
if (p)
|
if (p)
|
||||||
writer.extrude(xl - perimeterWidth/2, writer.y() + dy)
|
writer.extrude(xl - m_perimeter_width/2, writer.y() + dy)
|
||||||
.extrude(xr + perimeterWidth, writer.y());
|
.extrude(xr + m_perimeter_width, writer.y());
|
||||||
else
|
else
|
||||||
writer.extrude(xl - perimeterWidth, writer.y() + dy)
|
writer.extrude(xl - m_perimeter_width, writer.y() + dy)
|
||||||
.extrude(xr + perimeterWidth*2, writer.y());
|
.extrude(xr + m_perimeter_width*2, writer.y());
|
||||||
writer.feedrate((wipe_speed = std::min(4800.f, wipe_speed + 50.f)) * wipe_coeff)
|
writer.feedrate((wipe_speed = std::min(4800.f, wipe_speed + 50.f)) * wipe_coeff)
|
||||||
.extrude(xr + perimeterWidth, writer.y() + dy)
|
.extrude(xr + m_perimeter_width, writer.y() + dy)
|
||||||
.extrude(xl - perimeterWidth, writer.y());
|
.extrude(xl - m_perimeter_width, writer.y());
|
||||||
if ((shape == SHAPE_NORMAL) ?
|
if ((m_current_shape == SHAPE_NORMAL) ?
|
||||||
(writer.y() > cleaning_box.lu.y - perimeterWidth) :
|
(writer.y() > cleaning_box.lu.y - m_perimeter_width) :
|
||||||
(writer.y() < cleaning_box.ld.y + perimeterWidth))
|
(writer.y() < cleaning_box.ld.y + m_perimeter_width))
|
||||||
// Next wipe line does not fit the cleaning box.
|
// Next wipe line does not fit the cleaning box.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Reset the extrusion flow.
|
// Reset the extrusion flow.
|
||||||
writer.set_extrusion_flow(extrusion_flow);
|
writer.set_extrusion_flow(m_extrusion_flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw a perimeter around cleaning_box and wipe.
|
// Draw a perimeter around cleaning_box and wipe.
|
||||||
void WipeTower::toolchange_Done(
|
void WipeTowerPrusaMM::toolchange_Done(
|
||||||
Writer &writer,
|
PrusaMultiMaterial::Writer &writer,
|
||||||
const box_coordinates &cleaning_box,
|
const box_coordinates &cleaning_box)
|
||||||
const material_type /* material */,
|
|
||||||
const wipe_shape shape)
|
|
||||||
{
|
{
|
||||||
box_coordinates box = cleaning_box;
|
box_coordinates box = cleaning_box;
|
||||||
if (shape == SHAPE_REVERSED) {
|
if (m_current_shape == SHAPE_REVERSED) {
|
||||||
std::swap(box.lu, box.ld);
|
std::swap(box.lu, box.ld);
|
||||||
std::swap(box.ru, box.rd);
|
std::swap(box.ru, box.rd);
|
||||||
}
|
}
|
||||||
|
@ -572,82 +576,86 @@ void WipeTower::toolchange_Done(
|
||||||
.feedrate(6000);
|
.feedrate(6000);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string WipeTower::Perimeter(int order, int total, int Layer, bool afterToolchange, int firstLayerOffset)
|
std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::close_layer()
|
||||||
{
|
{
|
||||||
Writer writer;
|
PrusaMultiMaterial::Writer writer;
|
||||||
writer.set_extrusion_flow(extrusion_flow)
|
writer.set_extrusion_flow(m_extrusion_flow)
|
||||||
.set_z(m_z_pos)
|
.set_z(m_z_pos)
|
||||||
.append(";--------------------\n"
|
.append(";--------------------\n"
|
||||||
"; CP EMPTY GRID START\n")
|
"; CP EMPTY GRID START\n")
|
||||||
.comment_with_value(" layer #", Layer);
|
.comment_with_value(" layer #", m_layer_change_total ++);
|
||||||
|
|
||||||
// Slow down on the 1st layer.
|
// Slow down on the 1st layer.
|
||||||
float speed_factor = is_first_layer() ? 0.5f : 1.f;
|
float speed_factor = m_is_first_layer ? 0.5f : 1.f;
|
||||||
|
|
||||||
box_coordinates _p = _boxForColor(order);
|
box_coordinates _p = _boxForColor(m_layer_change_in_layer);
|
||||||
{
|
{
|
||||||
box_coordinates _to = _boxForColor(total);
|
box_coordinates _to = _boxForColor(m_max_color_changes);
|
||||||
|
float firstLayerOffset = 0.f;
|
||||||
_p.ld.y += firstLayerOffset;
|
_p.ld.y += firstLayerOffset;
|
||||||
_p.rd.y += firstLayerOffset;
|
_p.rd.y += firstLayerOffset;
|
||||||
_p.lu = _to.lu; _p.ru = _to.ru;
|
_p.lu = _to.lu; _p.ru = _to.ru;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! afterToolchange)
|
if (m_layer_change_in_layer == 0)
|
||||||
|
// There were no tool changes at all in this layer.
|
||||||
// Jump with retract to _p.ld + a random shift in +x.
|
// Jump with retract to _p.ld + a random shift in +x.
|
||||||
writer.retract(retract * 1.5f, 3600)
|
writer.retract(m_retract * 1.5f, 3600)
|
||||||
.z_hop(zHop, 7200)
|
.z_hop(m_zhop, 7200)
|
||||||
.travel(_p.ld.x + randi(5, 20), _p.ld.y, 7000)
|
.travel(_p.ld.x + randi(5, 20), _p.ld.y, 7000)
|
||||||
.z_hop(0, 7200)
|
.z_hop(0, 7200)
|
||||||
.extrude_explicit(_p.ld, retract * 1.5f, 3600);
|
.extrude_explicit(_p.ld, m_retract * 1.5f, 3600);
|
||||||
|
|
||||||
box_coordinates box = _p;
|
box_coordinates box = _p;
|
||||||
writer.extrude(box.lu, 2400 * speed_factor)
|
writer.extrude(box.lu, 2400 * speed_factor)
|
||||||
.extrude(box.ru)
|
.extrude(box.ru)
|
||||||
.extrude(box.rd)
|
.extrude(box.rd)
|
||||||
.extrude(box.ld + xy(perimeterWidth / 2, 0));
|
.extrude(box.ld + xy(m_perimeter_width / 2, 0));
|
||||||
|
|
||||||
box.expand(- perimeterWidth / 2);
|
box.expand(- m_perimeter_width / 2);
|
||||||
writer.extrude(box.lu, 3200 * speed_factor)
|
writer.extrude(box.lu, 3200 * speed_factor)
|
||||||
.extrude(box.ru)
|
.extrude(box.ru)
|
||||||
.extrude(box.rd)
|
.extrude(box.rd)
|
||||||
.extrude(box.ld + xy(perimeterWidth / 2, 0))
|
.extrude(box.ld + xy(m_perimeter_width / 2, 0))
|
||||||
.extrude(box.ld + xy(perimeterWidth / 2, perimeterWidth / 2));
|
.extrude(box.ld + xy(m_perimeter_width / 2, m_perimeter_width / 2));
|
||||||
|
|
||||||
writer.extrude(_p.ld + xy(perimeterWidth * 3, perimeterWidth), 2900 * speed_factor)
|
writer.extrude(_p.ld + xy(m_perimeter_width * 3, m_perimeter_width), 2900 * speed_factor)
|
||||||
.extrude(_p.lu + xy(perimeterWidth * 3, - perimeterWidth))
|
.extrude(_p.lu + xy(m_perimeter_width * 3, - m_perimeter_width))
|
||||||
.extrude(_p.lu + xy(perimeterWidth * 6, - perimeterWidth))
|
.extrude(_p.lu + xy(m_perimeter_width * 6, - m_perimeter_width))
|
||||||
.extrude(_p.ld + xy(perimeterWidth * 6, perimeterWidth));
|
.extrude(_p.ld + xy(m_perimeter_width * 6, m_perimeter_width));
|
||||||
|
|
||||||
if (_p.lu.y - _p.ld.y > 4) {
|
if (_p.lu.y - _p.ld.y > 4) {
|
||||||
// Extrude three zig-zags.
|
// Extrude three zig-zags.
|
||||||
writer.feedrate(3200 * speed_factor);
|
writer.feedrate(3200 * speed_factor);
|
||||||
float step = (m_wipe_tower_width - perimeterWidth * 12.f) / 12.f;
|
float step = (m_wipe_tower_width - m_perimeter_width * 12.f) / 12.f;
|
||||||
for (size_t i = 0; i < 3; ++ i) {
|
for (size_t i = 0; i < 3; ++ i) {
|
||||||
writer.extrude(writer.x() + step, _p.ld.y + perimeterWidth * 8);
|
writer.extrude(writer.x() + step, _p.ld.y + m_perimeter_width * 8);
|
||||||
writer.extrude(writer.x() , _p.lu.y - perimeterWidth * 8);
|
writer.extrude(writer.x() , _p.lu.y - m_perimeter_width * 8);
|
||||||
writer.extrude(writer.x() + step, _p.lu.y - perimeterWidth );
|
writer.extrude(writer.x() + step, _p.lu.y - m_perimeter_width );
|
||||||
writer.extrude(writer.x() + step, _p.lu.y - perimeterWidth * 8);
|
writer.extrude(writer.x() + step, _p.lu.y - m_perimeter_width * 8);
|
||||||
writer.extrude(writer.x() , _p.ld.y + perimeterWidth * 8);
|
writer.extrude(writer.x() , _p.ld.y + m_perimeter_width * 8);
|
||||||
writer.extrude(writer.x() + step, _p.ld.y + perimeterWidth );
|
writer.extrude(writer.x() + step, _p.ld.y + m_perimeter_width );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.extrude(_p.ru + xy(- perimeterWidth * 6, - perimeterWidth), 2900 * speed_factor)
|
// Extrude the perimeter.
|
||||||
.extrude(_p.ru + xy(- perimeterWidth * 3, - perimeterWidth))
|
writer.extrude(_p.ru + xy(- m_perimeter_width * 6, - m_perimeter_width), 2900 * speed_factor)
|
||||||
.extrude(_p.rd + xy(- perimeterWidth * 3, perimeterWidth))
|
.extrude(_p.ru + xy(- m_perimeter_width * 3, - m_perimeter_width))
|
||||||
.extrude(_p.rd + xy(- perimeterWidth, perimeterWidth))
|
.extrude(_p.rd + xy(- m_perimeter_width * 3, m_perimeter_width))
|
||||||
|
.extrude(_p.rd + xy(- m_perimeter_width, m_perimeter_width))
|
||||||
// Wipe along the front side of the current wiping box.
|
// Wipe along the front side of the current wiping box.
|
||||||
.travel(_p.ld + xy( perimeterWidth, perimeterWidth / 2), 7200)
|
.travel(_p.ld + xy( m_perimeter_width, m_perimeter_width / 2), 7200)
|
||||||
.travel(_p.rd + xy(- perimeterWidth, perimeterWidth / 2))
|
.travel(_p.rd + xy(- m_perimeter_width, m_perimeter_width / 2))
|
||||||
.append("; CP EMPTY GRID END\n"
|
.append("; CP EMPTY GRID END\n"
|
||||||
";------------------\n\n\n\n\n\n\n");
|
";------------------\n\n\n\n\n\n\n");
|
||||||
|
|
||||||
return writer.gcode();
|
m_current_shape = wipe_shape(- m_current_shape);
|
||||||
|
return std::pair<std::string, xy>(writer.gcode(), writer.pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
WipeTower::box_coordinates WipeTower::_boxForColor(int order) const
|
WipeTowerPrusaMM::box_coordinates WipeTowerPrusaMM::_boxForColor(int order) const
|
||||||
{
|
{
|
||||||
return box_coordinates(m_wipe_tower_pos.x, m_wipe_tower_pos.y + m_wipe_area * order - perimeterWidth / 2, m_wipe_tower_width, perimeterWidth);
|
return box_coordinates(m_wipe_tower_pos.x, m_wipe_tower_pos.y + m_wipe_area * order - m_perimeter_width / 2, m_wipe_tower_width, m_perimeter_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace PrusaSingleExtruderMM
|
}; // namespace Slic3r
|
217
xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp
Normal file
217
xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
#ifndef WipeTowerPrusaMM_hpp_
|
||||||
|
#define WipeTowerPrusaMM_hpp_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "WipeTower.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace PrusaMultiMaterial {
|
||||||
|
class Writer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WipeTowerPrusaMM : public WipeTower
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum material_type
|
||||||
|
{
|
||||||
|
INVALID = -1,
|
||||||
|
PLA = 0, // E:210C B:55C
|
||||||
|
ABS = 1, // E:255C B:100C
|
||||||
|
PET = 2, // E:240C B:90C
|
||||||
|
HIPS = 3, // E:220C B:100C
|
||||||
|
FLEX = 4, // E:245C B:80C
|
||||||
|
SCAFF = 5, // E:215C B:55C
|
||||||
|
EDGE = 6, // E:240C B:80C
|
||||||
|
NGEN = 7, // E:230C B:80C
|
||||||
|
PVA = 8 // E:210C B:80C
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse material name into material_type.
|
||||||
|
static material_type parse_material(const char *name);
|
||||||
|
|
||||||
|
// x -- x coordinates of wipe tower in mm ( left bottom corner )
|
||||||
|
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
||||||
|
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
|
||||||
|
// wipe_area -- space available for one toolchange in mm
|
||||||
|
WipeTowerPrusaMM(float x, float y, float width, float wipe_area) :
|
||||||
|
m_wipe_tower_pos(x, y),
|
||||||
|
m_wipe_tower_width(width),
|
||||||
|
m_wipe_area(wipe_area),
|
||||||
|
m_z_pos(0.f) {
|
||||||
|
for (size_t i = 0; i < 4; ++ i) {
|
||||||
|
// Extruder specific parameters.
|
||||||
|
m_material[i] = PLA;
|
||||||
|
m_temperature[i] = 0;
|
||||||
|
m_first_layer_temperature[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual ~WipeTowerPrusaMM() {}
|
||||||
|
|
||||||
|
// _retract - retract value in mm
|
||||||
|
void set_retract(float retract) { m_retract = retract; }
|
||||||
|
|
||||||
|
// _zHop - z hop value in mm
|
||||||
|
void set_zhop(float zhop) { m_zhop = zhop; }
|
||||||
|
|
||||||
|
// Set the extruder properties.
|
||||||
|
void set_extruder(size_t idx, material_type material, int temp, int first_layer_temp)
|
||||||
|
{
|
||||||
|
m_material[idx] = material;
|
||||||
|
m_temperature[idx] = temp;
|
||||||
|
m_first_layer_temperature[idx] = first_layer_temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch to a next layer.
|
||||||
|
virtual void set_layer(
|
||||||
|
// Print height of this layer.
|
||||||
|
float print_z,
|
||||||
|
// Layer height, used to calculate extrusion the rate.
|
||||||
|
float layer_height,
|
||||||
|
// Maximum number of tool changes on this layer or the layers below.
|
||||||
|
size_t max_tool_changes,
|
||||||
|
// Is this the first layer of the print? In that case print the brim first.
|
||||||
|
bool is_first_layer,
|
||||||
|
// Is this the last layer of the waste tower?
|
||||||
|
bool is_last_layer)
|
||||||
|
{
|
||||||
|
m_z_pos = print_z;
|
||||||
|
m_max_color_changes = max_tool_changes;
|
||||||
|
m_is_first_layer = is_first_layer;
|
||||||
|
m_is_last_layer = is_last_layer;
|
||||||
|
// Start counting the color changes from zero.
|
||||||
|
m_layer_change_in_layer = is_first_layer ? size_t(-1) : 0;
|
||||||
|
m_current_wipe_start_y = 0.f;
|
||||||
|
|
||||||
|
int layer_idx = int(floor(layer_height * 100) + 0.5f);
|
||||||
|
switch (layer_idx)
|
||||||
|
{
|
||||||
|
case 15:
|
||||||
|
m_extrusion_flow = (float)0.024;
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
default:
|
||||||
|
m_extrusion_flow = (float)0.029;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the wipe tower position.
|
||||||
|
virtual const xy& position() const { return m_wipe_tower_pos; }
|
||||||
|
// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
|
||||||
|
virtual bool finished() const { return m_max_color_changes == 0; }
|
||||||
|
|
||||||
|
// Returns gcode for toolchange
|
||||||
|
virtual std::pair<std::string, xy> tool_change(int new_tool);
|
||||||
|
|
||||||
|
// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
|
||||||
|
virtual std::pair<std::string, xy> close_layer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
WipeTowerPrusaMM();
|
||||||
|
|
||||||
|
enum wipe_shape
|
||||||
|
{
|
||||||
|
SHAPE_NORMAL = 1,
|
||||||
|
SHAPE_REVERSED = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
// Left front corner of the wipe tower in mm.
|
||||||
|
xy m_wipe_tower_pos;
|
||||||
|
// Width of the wipe tower.
|
||||||
|
float m_wipe_tower_width;
|
||||||
|
// Per color Y span.
|
||||||
|
float m_wipe_area;
|
||||||
|
// Current Z position.
|
||||||
|
float m_z_pos = 0.f;
|
||||||
|
// Maximum number of color changes per layer.
|
||||||
|
size_t m_max_color_changes = 0;
|
||||||
|
// Is this the 1st layer of the print? If so, print the brim around the waste tower.
|
||||||
|
bool m_is_first_layer = false;
|
||||||
|
// Is this the last layer of this waste tower?
|
||||||
|
bool m_is_last_layer = false;
|
||||||
|
|
||||||
|
// G-code generator parameters.
|
||||||
|
float m_zhop = 0.5f;
|
||||||
|
float m_retract = 4.f;
|
||||||
|
float m_perimeter_width = 0.5f;
|
||||||
|
float m_extrusion_flow = 0.029f;
|
||||||
|
|
||||||
|
// Extruder specific parameters.
|
||||||
|
material_type m_material[4];
|
||||||
|
int m_temperature[4];
|
||||||
|
int m_first_layer_temperature[4];
|
||||||
|
|
||||||
|
// State of the wiper tower generator.
|
||||||
|
// Layer change counter for the output statistics.
|
||||||
|
unsigned int m_layer_change_total = 0;
|
||||||
|
// Layer change counter in this layer. Counting up to m_max_color_changes.
|
||||||
|
unsigned int m_layer_change_in_layer = 0;
|
||||||
|
wipe_shape m_current_shape = SHAPE_NORMAL;
|
||||||
|
material_type m_current_material = PLA;
|
||||||
|
// Current y position at the wipe tower.
|
||||||
|
float m_current_wipe_start_y = 0.f;
|
||||||
|
|
||||||
|
struct box_coordinates
|
||||||
|
{
|
||||||
|
box_coordinates(float left, float bottom, float width, float height) :
|
||||||
|
ld(left , bottom ),
|
||||||
|
lu(left , bottom + height),
|
||||||
|
rd(left + width, bottom ),
|
||||||
|
ru(left + width, bottom + height) {}
|
||||||
|
box_coordinates(const xy &pos, float width, float height) : box_coordinates(pos.x, pos.y, width, height) {}
|
||||||
|
void expand(const float offset) {
|
||||||
|
ld += xy(- offset, - offset);
|
||||||
|
lu += xy(- offset, offset);
|
||||||
|
rd += xy( offset, - offset);
|
||||||
|
ru += xy( offset, offset);
|
||||||
|
}
|
||||||
|
xy ld; // left down
|
||||||
|
xy lu; // left upper
|
||||||
|
xy ru; // right upper
|
||||||
|
xy rd; // right lower
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns gcode for wipe tower brim
|
||||||
|
// sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
|
||||||
|
// offset -- set to 0 -- experimental, offset to replace brim in front / rear of wipe tower
|
||||||
|
std::pair<std::string, WipeTower::xy> toolchange_Brim(size_t tool, bool sideOnly = false, float y_offset = 0.f);
|
||||||
|
|
||||||
|
void toolchange_Unload(
|
||||||
|
PrusaMultiMaterial::Writer &writer,
|
||||||
|
const box_coordinates &cleaning_box,
|
||||||
|
const material_type material,
|
||||||
|
const wipe_shape shape,
|
||||||
|
const int temperature);
|
||||||
|
|
||||||
|
void toolchange_Change(
|
||||||
|
PrusaMultiMaterial::Writer &writer,
|
||||||
|
int tool,
|
||||||
|
material_type current_material,
|
||||||
|
material_type new_material);
|
||||||
|
|
||||||
|
void toolchange_Load(
|
||||||
|
PrusaMultiMaterial::Writer &writer,
|
||||||
|
const box_coordinates &cleaning_box);
|
||||||
|
|
||||||
|
void toolchange_Wipe(
|
||||||
|
PrusaMultiMaterial::Writer &writer,
|
||||||
|
const box_coordinates &cleaning_box,
|
||||||
|
const material_type material);
|
||||||
|
|
||||||
|
void toolchange_Done(
|
||||||
|
PrusaMultiMaterial::Writer &writer,
|
||||||
|
const box_coordinates &cleaning_box);
|
||||||
|
|
||||||
|
void toolchange_Perimeter();
|
||||||
|
|
||||||
|
box_coordinates _boxForColor(int order) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Slic3r
|
||||||
|
|
||||||
|
#endif /* WipeTowerPrusaMM_hpp_ */
|
|
@ -354,6 +354,37 @@ PrintConfigDef::PrintConfigDef()
|
||||||
def->default_value = opt;
|
def->default_value = opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def = this->add("filament_type", coStrings);
|
||||||
|
def->label = "Filament type";
|
||||||
|
def->tooltip = "If you want to process the output G-code through custom scripts, just list their absolute paths here. Separate multiple scripts with a semicolon. Scripts will be passed the absolute path to the G-code file as the first argument, and they can access the Slic3r config settings by reading environment variables.";
|
||||||
|
def->cli = "filament_type=s@";
|
||||||
|
def->gui_type = "f_enum_open";
|
||||||
|
def->gui_flags = "show_value";
|
||||||
|
def->enum_values.push_back("PLA");
|
||||||
|
def->enum_values.push_back("ABS");
|
||||||
|
def->enum_values.push_back("PET");
|
||||||
|
def->enum_values.push_back("HIPS");
|
||||||
|
def->enum_values.push_back("FLEX");
|
||||||
|
def->enum_values.push_back("SCAFF");
|
||||||
|
def->enum_values.push_back("EDGE");
|
||||||
|
def->enum_values.push_back("NGEN");
|
||||||
|
def->enum_values.push_back("PVA");
|
||||||
|
{
|
||||||
|
ConfigOptionStrings* opt = new ConfigOptionStrings();
|
||||||
|
opt->values.push_back("PLA");
|
||||||
|
def->default_value = opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
def = this->add("filament_soluble", coBools);
|
||||||
|
def->label = "Soluble material";
|
||||||
|
def->tooltip = "Soluble material is most likely used for a soluble support.";
|
||||||
|
def->cli = "filament-soluble!";
|
||||||
|
{
|
||||||
|
ConfigOptionBools* opt = new ConfigOptionBools();
|
||||||
|
opt->values.push_back(false);
|
||||||
|
def->default_value = opt;
|
||||||
|
}
|
||||||
|
|
||||||
def = this->add("filament_cost", coFloats);
|
def = this->add("filament_cost", coFloats);
|
||||||
def->label = "Cost";
|
def->label = "Cost";
|
||||||
def->tooltip = "Enter your filament cost per kg here. This is only for statistical information.";
|
def->tooltip = "Enter your filament cost per kg here. This is only for statistical information.";
|
||||||
|
@ -1168,6 +1199,12 @@ PrintConfigDef::PrintConfigDef()
|
||||||
def->height = 120;
|
def->height = 120;
|
||||||
def->default_value = new ConfigOptionString("G28 ; home all axes\nG1 Z5 F5000 ; lift nozzle\n");
|
def->default_value = new ConfigOptionString("G28 ; home all axes\nG1 Z5 F5000 ; lift nozzle\n");
|
||||||
|
|
||||||
|
def = this->add("single_extruder_multi_material", coBool);
|
||||||
|
def->label = "Single Extruder Multi Material";
|
||||||
|
def->tooltip = "The printer multiplexes filaments into a single hot end.";
|
||||||
|
def->cli = "single-extruder-multi-material!";
|
||||||
|
def->default_value = new ConfigOptionBool(false);
|
||||||
|
|
||||||
def = this->add("support_material", coBool);
|
def = this->add("support_material", coBool);
|
||||||
def->label = "Generate support material";
|
def->label = "Generate support material";
|
||||||
def->category = "Support material";
|
def->category = "Support material";
|
||||||
|
@ -1454,6 +1491,40 @@ PrintConfigDef::PrintConfigDef()
|
||||||
def->default_value = opt;
|
def->default_value = opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def = this->add("wipe_tower", coBool);
|
||||||
|
def->label = "Enable";
|
||||||
|
def->tooltip = "Multi material printers may need to prime or purge extruders on tool changes. Extrude the excess material into the wipe tower.";
|
||||||
|
def->cli = "wipe-tower!";
|
||||||
|
def->default_value = new ConfigOptionBool(false);
|
||||||
|
|
||||||
|
def = this->add("wipe_tower_x", coFloat);
|
||||||
|
def->label = "Position X";
|
||||||
|
def->tooltip = "X coordinate of the left front corner of a wipe tower";
|
||||||
|
def->sidetext = "mm";
|
||||||
|
def->cli = "wipe-tower-x=f";
|
||||||
|
def->default_value = new ConfigOptionFloat(180.);
|
||||||
|
|
||||||
|
def = this->add("wipe_tower_y", coFloat);
|
||||||
|
def->label = "Position Y";
|
||||||
|
def->tooltip = "Y coordinate of the left front corner of a wipe tower";
|
||||||
|
def->sidetext = "mm";
|
||||||
|
def->cli = "wipe-tower-y=f";
|
||||||
|
def->default_value = new ConfigOptionFloat(140.);
|
||||||
|
|
||||||
|
def = this->add("wipe_tower_width", coFloat);
|
||||||
|
def->label = "Width";
|
||||||
|
def->tooltip = "Width of a wipe tower";
|
||||||
|
def->sidetext = "mm";
|
||||||
|
def->cli = "wipe-tower-width=f";
|
||||||
|
def->default_value = new ConfigOptionFloat(60.);
|
||||||
|
|
||||||
|
def = this->add("wipe_tower_per_color_wipe", coFloat);
|
||||||
|
def->label = "Per color change depth";
|
||||||
|
def->tooltip = "Depth of a wipe color per color change. For N colors, there will be maximum (N-1) tool switches performed, therefore the total depth of the wipe tower will be (N-1) times this value.";
|
||||||
|
def->sidetext = "mm";
|
||||||
|
def->cli = "wipe-tower-per-color-wipe=f";
|
||||||
|
def->default_value = new ConfigOptionFloat(15.);
|
||||||
|
|
||||||
def = this->add("xy_size_compensation", coFloat);
|
def = this->add("xy_size_compensation", coFloat);
|
||||||
def->label = "XY Size Compensation";
|
def->label = "XY Size Compensation";
|
||||||
def->category = "Advanced";
|
def->category = "Advanced";
|
||||||
|
|
|
@ -42,6 +42,10 @@ enum SeamPosition {
|
||||||
spRandom, spNearest, spAligned, spRear
|
spRandom, spNearest, spAligned, spRear
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum FilamentType {
|
||||||
|
ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA
|
||||||
|
};
|
||||||
|
|
||||||
template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
|
template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
|
||||||
t_config_enum_values keys_map;
|
t_config_enum_values keys_map;
|
||||||
keys_map["reprap"] = gcfRepRap;
|
keys_map["reprap"] = gcfRepRap;
|
||||||
|
@ -91,6 +95,20 @@ template<> inline t_config_enum_values ConfigOptionEnum<SeamPosition>::get_enum_
|
||||||
return keys_map;
|
return keys_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> inline t_config_enum_values ConfigOptionEnum<FilamentType>::get_enum_values() {
|
||||||
|
t_config_enum_values keys_map;
|
||||||
|
keys_map["PLA"] = ftPLA;
|
||||||
|
keys_map["ABS"] = ftABS;
|
||||||
|
keys_map["PET"] = ftPET;
|
||||||
|
keys_map["HIPS"] = ftHIPS;
|
||||||
|
keys_map["FLEX"] = ftFLEX;
|
||||||
|
keys_map["SCAFF"] = ftSCAFF;
|
||||||
|
keys_map["EDGE"] = ftEDGE;
|
||||||
|
keys_map["NGEN"] = ftNGEN;
|
||||||
|
keys_map["PVA"] = ftPVA;
|
||||||
|
return keys_map;
|
||||||
|
}
|
||||||
|
|
||||||
// Defines each and every confiuration option of Slic3r, including the properties of the GUI dialogs.
|
// Defines each and every confiuration option of Slic3r, including the properties of the GUI dialogs.
|
||||||
// Does not store the actual values, but defines default values.
|
// Does not store the actual values, but defines default values.
|
||||||
class PrintConfigDef : public ConfigDef
|
class PrintConfigDef : public ConfigDef
|
||||||
|
@ -297,13 +315,15 @@ class PrintRegionConfig : public virtual StaticPrintConfig
|
||||||
// This object is mapped to Perl as Slic3r::Config::GCode.
|
// This object is mapped to Perl as Slic3r::Config::GCode.
|
||||||
class GCodeConfig : public virtual StaticPrintConfig
|
class GCodeConfig : public virtual StaticPrintConfig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConfigOptionString before_layer_gcode;
|
ConfigOptionString before_layer_gcode;
|
||||||
ConfigOptionString end_gcode;
|
ConfigOptionString end_gcode;
|
||||||
ConfigOptionString extrusion_axis;
|
ConfigOptionString extrusion_axis;
|
||||||
ConfigOptionFloats extrusion_multiplier;
|
ConfigOptionFloats extrusion_multiplier;
|
||||||
ConfigOptionFloats filament_diameter;
|
ConfigOptionFloats filament_diameter;
|
||||||
ConfigOptionFloats filament_density;
|
ConfigOptionFloats filament_density;
|
||||||
|
ConfigOptionStrings filament_type;
|
||||||
|
ConfigOptionBools filament_soluble;
|
||||||
ConfigOptionFloats filament_cost;
|
ConfigOptionFloats filament_cost;
|
||||||
ConfigOptionFloats filament_max_volumetric_speed;
|
ConfigOptionFloats filament_max_volumetric_speed;
|
||||||
ConfigOptionBool gcode_comments;
|
ConfigOptionBool gcode_comments;
|
||||||
|
@ -322,6 +342,7 @@ class GCodeConfig : public virtual StaticPrintConfig
|
||||||
ConfigOptionFloats retract_restart_extra_toolchange;
|
ConfigOptionFloats retract_restart_extra_toolchange;
|
||||||
ConfigOptionFloats retract_speed;
|
ConfigOptionFloats retract_speed;
|
||||||
ConfigOptionString start_gcode;
|
ConfigOptionString start_gcode;
|
||||||
|
ConfigOptionBool single_extruder_multi_material;
|
||||||
ConfigOptionString toolchange_gcode;
|
ConfigOptionString toolchange_gcode;
|
||||||
ConfigOptionFloat travel_speed;
|
ConfigOptionFloat travel_speed;
|
||||||
ConfigOptionBool use_firmware_retraction;
|
ConfigOptionBool use_firmware_retraction;
|
||||||
|
@ -341,6 +362,8 @@ class GCodeConfig : public virtual StaticPrintConfig
|
||||||
OPT_PTR(extrusion_multiplier);
|
OPT_PTR(extrusion_multiplier);
|
||||||
OPT_PTR(filament_diameter);
|
OPT_PTR(filament_diameter);
|
||||||
OPT_PTR(filament_density);
|
OPT_PTR(filament_density);
|
||||||
|
OPT_PTR(filament_type);
|
||||||
|
OPT_PTR(filament_soluble);
|
||||||
OPT_PTR(filament_cost);
|
OPT_PTR(filament_cost);
|
||||||
OPT_PTR(filament_max_volumetric_speed);
|
OPT_PTR(filament_max_volumetric_speed);
|
||||||
OPT_PTR(gcode_comments);
|
OPT_PTR(gcode_comments);
|
||||||
|
@ -358,6 +381,7 @@ class GCodeConfig : public virtual StaticPrintConfig
|
||||||
OPT_PTR(retract_restart_extra);
|
OPT_PTR(retract_restart_extra);
|
||||||
OPT_PTR(retract_restart_extra_toolchange);
|
OPT_PTR(retract_restart_extra_toolchange);
|
||||||
OPT_PTR(retract_speed);
|
OPT_PTR(retract_speed);
|
||||||
|
OPT_PTR(single_extruder_multi_material);
|
||||||
OPT_PTR(start_gcode);
|
OPT_PTR(start_gcode);
|
||||||
OPT_PTR(toolchange_gcode);
|
OPT_PTR(toolchange_gcode);
|
||||||
OPT_PTR(travel_speed);
|
OPT_PTR(travel_speed);
|
||||||
|
@ -435,6 +459,11 @@ class PrintConfig : public GCodeConfig
|
||||||
ConfigOptionInts temperature;
|
ConfigOptionInts temperature;
|
||||||
ConfigOptionInt threads;
|
ConfigOptionInt threads;
|
||||||
ConfigOptionBools wipe;
|
ConfigOptionBools wipe;
|
||||||
|
ConfigOptionBool wipe_tower;
|
||||||
|
ConfigOptionFloat wipe_tower_x;
|
||||||
|
ConfigOptionFloat wipe_tower_y;
|
||||||
|
ConfigOptionFloat wipe_tower_width;
|
||||||
|
ConfigOptionFloat wipe_tower_per_color_wipe;
|
||||||
ConfigOptionFloat z_offset;
|
ConfigOptionFloat z_offset;
|
||||||
|
|
||||||
PrintConfig(bool initialize = true) : GCodeConfig(false) {
|
PrintConfig(bool initialize = true) : GCodeConfig(false) {
|
||||||
|
@ -494,6 +523,11 @@ class PrintConfig : public GCodeConfig
|
||||||
OPT_PTR(temperature);
|
OPT_PTR(temperature);
|
||||||
OPT_PTR(threads);
|
OPT_PTR(threads);
|
||||||
OPT_PTR(wipe);
|
OPT_PTR(wipe);
|
||||||
|
OPT_PTR(wipe_tower);
|
||||||
|
OPT_PTR(wipe_tower_x);
|
||||||
|
OPT_PTR(wipe_tower_y);
|
||||||
|
OPT_PTR(wipe_tower_width);
|
||||||
|
OPT_PTR(wipe_tower_per_color_wipe);
|
||||||
OPT_PTR(z_offset);
|
OPT_PTR(z_offset);
|
||||||
|
|
||||||
// look in parent class
|
// look in parent class
|
||||||
|
|
|
@ -1,210 +0,0 @@
|
||||||
#ifndef PrusaSingleExtruderMM_WipeTower_hpp_
|
|
||||||
#define PrusaSingleExtruderMM_WipeTower_hpp_
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace PrusaSingleExtruderMM
|
|
||||||
{
|
|
||||||
|
|
||||||
class Writer;
|
|
||||||
|
|
||||||
class WipeTower
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum material_type
|
|
||||||
{
|
|
||||||
INVALID = -1,
|
|
||||||
PLA = 0, // E:210C B:55C
|
|
||||||
ABS = 1, // E:255C B:100C
|
|
||||||
PET = 2, // E:240C B:90C
|
|
||||||
HIPS = 3, // E:220C B:100C
|
|
||||||
FLEX = 4, // E:245C B:80C
|
|
||||||
SCAFF = 5, // E:215C B:55C
|
|
||||||
EDGE = 6, // E:240C B:80C
|
|
||||||
NGEN = 7, // E:230C B:80C
|
|
||||||
PVA = 8 // E:210C B:80C
|
|
||||||
};
|
|
||||||
|
|
||||||
enum wipe_shape
|
|
||||||
{
|
|
||||||
SHAPE_NORMAL = 1,
|
|
||||||
SHAPE_REVERSED = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
struct xy
|
|
||||||
{
|
|
||||||
xy(float x = 0.f, float y = 0.f) : x(x), y(y) {}
|
|
||||||
xy operator+(const xy &rhs) const { xy out(*this); out.x += rhs.x; out.y += rhs.y; return out; }
|
|
||||||
xy operator-(const xy &rhs) const { xy out(*this); out.x -= rhs.x; out.y -= rhs.y; return out; }
|
|
||||||
xy& operator+=(const xy &rhs) { x += rhs.x; y += rhs.y; return *this; }
|
|
||||||
xy& operator-=(const xy &rhs) { x -= rhs.x; y -= rhs.y; return *this; }
|
|
||||||
float x;
|
|
||||||
float y;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse material name into material_type.
|
|
||||||
static material_type parse_material(const char *name);
|
|
||||||
|
|
||||||
// x -- x coordinates of wipe tower in mm ( left bottom corner )
|
|
||||||
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
|
||||||
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
|
|
||||||
// wipe_area -- space available for one toolchange in mm
|
|
||||||
// colors -- maximum colors for object
|
|
||||||
WipeTower(float x, float y, float width, float wipe_area, int color_changes) :
|
|
||||||
m_wipe_tower_pos(x, y),
|
|
||||||
m_wipe_tower_width(width),
|
|
||||||
m_wipe_area(wipe_area),
|
|
||||||
m_color_changes(color_changes),
|
|
||||||
m_z_pos(0.f) {}
|
|
||||||
|
|
||||||
// colors -- maximum color changes for layer
|
|
||||||
void setColors(int colors) { m_color_changes = colors; }
|
|
||||||
|
|
||||||
// Z height -- mm
|
|
||||||
void setZ(float z) { m_z_pos = z; }
|
|
||||||
bool is_first_layer() const { return m_z_pos < 0.205f; }
|
|
||||||
|
|
||||||
// _retract - retract value in mm
|
|
||||||
void setRetract(float _retract) { retract = _retract; }
|
|
||||||
|
|
||||||
// _zHop - z hop value in mm
|
|
||||||
void setZHop(float _zhop) { zHop = _zhop; }
|
|
||||||
|
|
||||||
void setExtrusion(int layerHeight)
|
|
||||||
{
|
|
||||||
// set extrusion coefficient for layer height
|
|
||||||
// layerHeight -- mm * 100
|
|
||||||
|
|
||||||
switch (layerHeight)
|
|
||||||
{
|
|
||||||
case 15:
|
|
||||||
extrusion_flow = (float)0.024;
|
|
||||||
break;
|
|
||||||
case 20:
|
|
||||||
extrusion_flow = (float)0.029;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Returns gcode for wipe tower brim
|
|
||||||
|
|
||||||
sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
|
|
||||||
offset -- set to 0 -- experimental, offset to replace brim in front / rear of wipe tower
|
|
||||||
*/
|
|
||||||
std::string FirstLayer(bool sideOnly = false, float y_offset = 0.f);
|
|
||||||
|
|
||||||
// Returns gcode for toolchange
|
|
||||||
std::pair<std::string, WipeTower::xy> Toolchange(
|
|
||||||
// extruder # 0 - 3
|
|
||||||
const int tool,
|
|
||||||
// filament type currently used to print and loaded in nozzle -- see enum material_type
|
|
||||||
const material_type current_material,
|
|
||||||
// filament type that will be loaded in to the nozzle -- see enum material_type
|
|
||||||
const material_type new_material,
|
|
||||||
// temperature in Celsius for new filament that will be loaded into the nozzle
|
|
||||||
const int temperature,
|
|
||||||
// orientation of purge / wipe shape (NORMAL / REVERSED)
|
|
||||||
const wipe_shape shape,
|
|
||||||
// total toolchanges done counter ( comment in header of toolchange only )
|
|
||||||
const int count,
|
|
||||||
// space available for toolchange ( purge / load / wipe ) - in mm
|
|
||||||
const float spaceAvailable,
|
|
||||||
// experimental, don't use, set to 0
|
|
||||||
const float wipeStartY,
|
|
||||||
// for last toolchange in object set to true to unload filament into cooling tube, for all other set to false
|
|
||||||
const bool lastInFile,
|
|
||||||
// experimental, set to false
|
|
||||||
const bool colorInit = false);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Returns gcode to draw empty pattern in place of a toolchange -> in case there are less toolchanges atm then what is required later
|
|
||||||
|
|
||||||
order -- total toolchanges done for current layer
|
|
||||||
total -- total colors in current z layer including empty ones
|
|
||||||
afterToolchange -- true - ignore some not neccesary moves | false - do whole move from object to wipe tower
|
|
||||||
firstLayerOffset -- experimental , set to 0
|
|
||||||
*/
|
|
||||||
std::string Perimeter(int order, int total, int Layer, bool afterToolchange, int firstLayerOffset = 0);
|
|
||||||
|
|
||||||
private:
|
|
||||||
WipeTower();
|
|
||||||
|
|
||||||
// Left front corner of the wipe tower in mm.
|
|
||||||
xy m_wipe_tower_pos;
|
|
||||||
// Width of the wipe tower.
|
|
||||||
float m_wipe_tower_width;
|
|
||||||
// Per color Y span.
|
|
||||||
float m_wipe_area;
|
|
||||||
// Current Z position.
|
|
||||||
float m_z_pos;
|
|
||||||
// Maximum number of color changes per layer.
|
|
||||||
int m_color_changes;
|
|
||||||
|
|
||||||
float zHop = 0.5f;
|
|
||||||
float retract = 4.f;
|
|
||||||
float perimeterWidth = 0.5f;
|
|
||||||
float extrusion_flow = 0.029f;
|
|
||||||
|
|
||||||
struct box_coordinates
|
|
||||||
{
|
|
||||||
box_coordinates(float left, float bottom, float width, float height) :
|
|
||||||
ld(left , bottom ),
|
|
||||||
lu(left , bottom + height),
|
|
||||||
rd(left + width, bottom ),
|
|
||||||
ru(left + width, bottom + height) {}
|
|
||||||
box_coordinates(const xy &pos, float width, float height) : box_coordinates(pos.x, pos.y, width, height) {}
|
|
||||||
void expand(const float offset) {
|
|
||||||
ld += xy(- offset, - offset);
|
|
||||||
lu += xy(- offset, offset);
|
|
||||||
rd += xy( offset, - offset);
|
|
||||||
ru += xy( offset, offset);
|
|
||||||
}
|
|
||||||
xy ld; // left down
|
|
||||||
xy lu; // left upper
|
|
||||||
xy ru; // right upper
|
|
||||||
xy rd; // right lower
|
|
||||||
};
|
|
||||||
|
|
||||||
void toolchange_Unload(
|
|
||||||
Writer &writer,
|
|
||||||
const box_coordinates &cleaning_box,
|
|
||||||
const material_type material,
|
|
||||||
const wipe_shape shape,
|
|
||||||
const int temperature);
|
|
||||||
|
|
||||||
void toolchange_Change(
|
|
||||||
Writer &writer,
|
|
||||||
int tool,
|
|
||||||
material_type current_material,
|
|
||||||
material_type new_material);
|
|
||||||
|
|
||||||
void toolchange_Load(
|
|
||||||
Writer &writer,
|
|
||||||
const box_coordinates &cleaning_box,
|
|
||||||
const material_type material,
|
|
||||||
const wipe_shape shape,
|
|
||||||
const bool colorInit);
|
|
||||||
|
|
||||||
void toolchange_Wipe(
|
|
||||||
Writer &writer,
|
|
||||||
const box_coordinates &cleaning_box,
|
|
||||||
const material_type material,
|
|
||||||
const wipe_shape shape);
|
|
||||||
|
|
||||||
void toolchange_Done(
|
|
||||||
Writer &writer,
|
|
||||||
const box_coordinates &cleaning_box,
|
|
||||||
const material_type material,
|
|
||||||
const wipe_shape shape);
|
|
||||||
|
|
||||||
box_coordinates _boxForColor(int order) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
}; // namespace PrusaSingleExtruderMM
|
|
||||||
|
|
||||||
#endif /* PrusaSingleExtruderMM_WipeTower_hpp_ */
|
|
Loading…
Add table
Add a link
Reference in a new issue