Merge remote-tracking branch 'origin/master' into feature_slice_to_png

This commit is contained in:
tamasmeszaros 2018-07-18 10:14:15 +02:00
commit 9559ad77e5
121 changed files with 18093 additions and 3459 deletions

View file

@ -4,6 +4,7 @@
#include "Extruder.hpp"
#include "Flow.hpp"
#include "Geometry.hpp"
#include "I18N.hpp"
#include "SupportMaterial.hpp"
#include "GCode/WipeTowerPrusaMM.hpp"
#include <algorithm>
@ -15,6 +16,10 @@
#include "slic3r/IProgressIndicator.hpp"
#include "PrintExport.hpp"
//! macro used to mark string used at localization,
//! return same string
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r {
template class PrintState<PrintStep, psCount>;
@ -164,6 +169,11 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
std::vector<PrintStep> steps;
std::vector<PrintObjectStep> osteps;
bool invalidated = false;
// Always invalidate the wipe tower. This is probably necessary because of the wipe_into_infill / wipe_into_objects
// features - nearly anything can influence what should (and could) be wiped into.
steps.emplace_back(psWipeTower);
for (const t_config_option_key &opt_key : opt_keys) {
if (steps_ignore.find(opt_key) != steps_ignore.end()) {
// These options only affect G-code export or they are just notes without influence on the generated G-code,
@ -190,6 +200,9 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|| opt_key == "filament_loading_speed"
|| opt_key == "filament_unloading_speed"
|| opt_key == "filament_toolchange_delay"
|| opt_key == "filament_cooling_moves"
|| opt_key == "filament_cooling_initial_speed"
|| opt_key == "filament_cooling_final_speed"
|| opt_key == "filament_ramming_parameters"
|| opt_key == "gcode_flavor"
|| opt_key == "single_extruder_multi_material"
@ -205,6 +218,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|| opt_key == "parking_pos_retraction"
|| opt_key == "cooling_tube_retraction"
|| opt_key == "cooling_tube_length"
|| opt_key == "extra_loading_move"
|| opt_key == "z_offset") {
steps.emplace_back(psWipeTower);
} else if (
@ -216,7 +230,6 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
osteps.emplace_back(posSupportMaterial);
steps.emplace_back(psSkirt);
steps.emplace_back(psBrim);
steps.emplace_back(psWipeTower);
} else {
// for legacy, if we can't handle this option let's invalidate all steps
//FIXME invalidate all steps of all objects as well?
@ -527,7 +540,7 @@ std::string Print::validate() const
print_volume.min.z = -1e10;
for (PrintObject *po : this->objects) {
if (!print_volume.contains(po->model_object()->tight_bounding_box(false)))
return "Some objects are outside of the print volume.";
return L("Some objects are outside of the print volume.");
}
if (this->config.complete_objects) {
@ -554,7 +567,7 @@ std::string Print::validate() const
Polygon p = convex_hull;
p.translate(copy);
if (! intersection(convex_hulls_other, p).empty())
return "Some objects are too close; your extruder will collide with them.";
return L("Some objects are too close; your extruder will collide with them.");
polygons_append(convex_hulls_other, p);
}
}
@ -569,7 +582,7 @@ std::string Print::validate() const
// it will be printed as last one so its height doesn't matter.
object_height.pop_back();
if (! object_height.empty() && object_height.back() > scale_(this->config.extruder_clearance_height.value))
return "Some objects are too tall and cannot be printed without extruder collisions.";
return L("Some objects are too tall and cannot be printed without extruder collisions.");
}
} // end if (this->config.complete_objects)
@ -579,27 +592,22 @@ std::string Print::validate() const
total_copies_count += object->copies().size();
// #4043
if (total_copies_count > 1 && ! this->config.complete_objects.value)
return "The Spiral Vase option can only be used when printing a single object.";
return L("The Spiral Vase option can only be used when printing a single object.");
if (this->regions.size() > 1)
return "The Spiral Vase option can only be used when printing single material objects.";
return L("The Spiral Vase option can only be used when printing single material objects.");
}
if (this->config.single_extruder_multi_material) {
for (size_t i=1; i<this->config.nozzle_diameter.values.size(); ++i)
if (this->config.nozzle_diameter.values[i] != this->config.nozzle_diameter.values[i-1])
return "All extruders must have the same diameter for single extruder multimaterial printer.";
return L("All extruders must have the same diameter for single extruder multimaterial printer.");
}
if (this->has_wipe_tower() && ! this->objects.empty()) {
#if 0
for (auto dmr : this->config.nozzle_diameter.values)
if (std::abs(dmr - 0.4) > EPSILON)
return "The Wipe Tower is currently only supported for the 0.4mm nozzle diameter.";
#endif
if (this->config.gcode_flavor != gcfRepRap && this->config.gcode_flavor != gcfMarlin)
return "The Wipe Tower is currently only supported for the Marlin and RepRap/Sprinter G-code flavors.";
return L("The Wipe Tower is currently only supported for the Marlin and RepRap/Sprinter G-code flavors.");
if (! this->config.use_relative_e_distances)
return "The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).";
return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).");
SlicingParameters slicing_params0 = this->objects.front()->slicing_parameters();
const PrintObject* tallest_object = this->objects.front(); // let's find the tallest object
@ -611,13 +619,13 @@ std::string Print::validate() const
SlicingParameters slicing_params = object->slicing_parameters();
if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON ||
std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON)
return "The Wipe Tower is only supported for multiple objects if they have equal layer heigths";
return L("The Wipe Tower is only supported for multiple objects if they have equal layer heigths");
if (slicing_params.raft_layers() != slicing_params0.raft_layers())
return "The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers";
return L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers");
if (object->config.support_material_contact_distance != this->objects.front()->config.support_material_contact_distance)
return "The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance";
return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance");
if (! equal_layering(slicing_params, slicing_params0))
return "The Wipe Tower is only supported for multiple objects if they are sliced equally.";
return L("The Wipe Tower is only supported for multiple objects if they are sliced equally.");
bool was_layer_height_profile_valid = object->layer_height_profile_valid;
object->update_layer_height_profile();
object->layer_height_profile_valid = was_layer_height_profile_valid;
@ -641,13 +649,8 @@ std::string Print::validate() const
failed = true;
if (failed)
return "The Wipe tower is only supported if all objects have the same layer height profile";
return L("The Wipe tower is only supported if all objects have the same layer height profile");
}
/*for (size_t i = 5; i < object->layer_height_profile.size(); i += 2)
if (object->layer_height_profile[i-1] > slicing_params.object_print_z_min + EPSILON &&
std::abs(object->layer_height_profile[i] - object->config.layer_height) > EPSILON)
return "The Wipe Tower is currently only supported with constant Z layer spacing. Layer editing is not allowed.";*/
}
}
@ -655,7 +658,7 @@ std::string Print::validate() const
// find the smallest nozzle diameter
std::vector<unsigned int> extruders = this->extruders();
if (extruders.empty())
return "The supplied settings will cause an empty print.";
return L("The supplied settings will cause an empty print.");
std::vector<double> nozzle_diameters;
for (unsigned int extruder_id : extruders)
@ -665,7 +668,7 @@ std::string Print::validate() const
unsigned int total_extruders_count = this->config.nozzle_diameter.size();
for (const auto& extruder_idx : extruders)
if ( extruder_idx >= total_extruders_count )
return "One or more object were assigned an extruder that the printer does not have.";
return L("One or more object were assigned an extruder that the printer does not have.");
for (PrintObject *object : this->objects) {
if ((object->config.support_material_extruder == -1 || object->config.support_material_interface_extruder == -1) &&
@ -674,13 +677,13 @@ std::string Print::validate() const
// will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles
// are of the same diameter.
if (nozzle_diameters.size() > 1)
return "Printing with multiple extruders of differing nozzle diameters. "
return L("Printing with multiple extruders of differing nozzle diameters. "
"If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), "
"all nozzles have to be of the same diameter.";
"all nozzles have to be of the same diameter.");
}
// validate first_layer_height
double first_layer_height = object->config.get_abs_value("first_layer_height");
double first_layer_height = object->config.get_abs_value(L("first_layer_height"));
double first_layer_min_nozzle_diameter;
if (object->config.raft_layers > 0) {
// if we have raft layers, only support material extruder is used on first layer
@ -695,11 +698,11 @@ std::string Print::validate() const
first_layer_min_nozzle_diameter = min_nozzle_diameter;
}
if (first_layer_height > first_layer_min_nozzle_diameter)
return "First layer height can't be greater than nozzle diameter";
return L("First layer height can't be greater than nozzle diameter");
// validate layer_height
if (object->config.layer_height.value > min_nozzle_diameter)
return "Layer height can't be greater than nozzle diameter";
return L("Layer height can't be greater than nozzle diameter");
}
}
@ -1037,6 +1040,14 @@ void Print::_make_wipe_tower()
if (! this->has_wipe_tower())
return;
// Get wiping matrix to get number of extruders and convert vector<double> to vector<float>:
std::vector<float> wiping_matrix((this->config.wiping_volumes_matrix.values).begin(),(this->config.wiping_volumes_matrix.values).end());
// Extract purging volumes for each extruder pair:
std::vector<std::vector<float>> wipe_volumes;
const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON);
for (unsigned int i = 0; i<number_of_extruders; ++i)
wipe_volumes.push_back(std::vector<float>(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders));
// Let the ToolOrdering class know there will be initial priming extrusions at the start of the print.
m_tool_ordering = ToolOrdering(*this, (unsigned int)-1, true);
if (! m_tool_ordering.has_wipe_tower())
@ -1052,7 +1063,7 @@ void Print::_make_wipe_tower()
size_t idx_end = m_tool_ordering.layer_tools().size();
// Find the first wipe tower layer, which does not have a counterpart in an object or a support layer.
for (size_t i = 0; i < idx_end; ++ i) {
const ToolOrdering::LayerTools &lt = m_tool_ordering.layer_tools()[i];
const LayerTools &lt = m_tool_ordering.layer_tools()[i];
if (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support) {
idx_begin = i;
break;
@ -1066,7 +1077,7 @@ void Print::_make_wipe_tower()
for (; it_layer != it_end && (*it_layer)->print_z - EPSILON < wipe_tower_new_layer_print_z_first; ++ it_layer);
// Find the stopper of the sequence of wipe tower layers, which do not have a counterpart in an object or a support layer.
for (size_t i = idx_begin; i < idx_end; ++ i) {
ToolOrdering::LayerTools &lt = const_cast<ToolOrdering::LayerTools&>(m_tool_ordering.layer_tools()[i]);
LayerTools &lt = const_cast<LayerTools&>(m_tool_ordering.layer_tools()[i]);
if (! (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support))
break;
lt.has_support = true;
@ -1081,22 +1092,20 @@ void Print::_make_wipe_tower()
}
}
// Get wiping matrix to get number of extruders and convert vector<double> to vector<float>:
std::vector<float> wiping_volumes((this->config.wiping_volumes_matrix.values).begin(),(this->config.wiping_volumes_matrix.values).end());
// Initialize the wipe tower.
WipeTowerPrusaMM wipe_tower(
float(this->config.wipe_tower_x.value), float(this->config.wipe_tower_y.value),
float(this->config.wipe_tower_width.value),
float(this->config.wipe_tower_rotation_angle.value), float(this->config.cooling_tube_retraction.value),
float(this->config.cooling_tube_length.value), float(this->config.parking_pos_retraction.value),
float(this->config.wipe_tower_bridging), wiping_volumes, m_tool_ordering.first_extruder());
float(this->config.extra_loading_move.value), float(this->config.wipe_tower_bridging), wipe_volumes,
m_tool_ordering.first_extruder());
//wipe_tower.set_retract();
//wipe_tower.set_zhop();
// Set the extruder & material properties at the wipe tower object.
for (size_t i = 0; i < (int)(sqrt(wiping_volumes.size())+EPSILON); ++ i)
for (size_t i = 0; i < number_of_extruders; ++ i)
wipe_tower.set_extruder(
i,
WipeTowerPrusaMM::parse_material(this->config.filament_type.get_at(i).c_str()),
@ -1105,91 +1114,44 @@ void Print::_make_wipe_tower()
this->config.filament_loading_speed.get_at(i),
this->config.filament_unloading_speed.get_at(i),
this->config.filament_toolchange_delay.get_at(i),
this->config.filament_cooling_moves.get_at(i),
this->config.filament_cooling_initial_speed.get_at(i),
this->config.filament_cooling_final_speed.get_at(i),
this->config.filament_ramming_parameters.get_at(i),
this->config.nozzle_diameter.get_at(i));
// When printing the first layer's wipe tower, the first extruder is expected to be active and primed.
// Therefore the number of wipe sections at the wipe tower will be (m_tool_ordering.front().extruders-1) at the 1st layer.
// The following variable is true if the last priming section cannot be squeezed inside the wipe tower.
bool last_priming_wipe_full = m_tool_ordering.front().extruders.size() > m_tool_ordering.front().wipe_tower_partitions;
m_wipe_tower_priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full));
wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), false));
// Lets go through the wipe tower layers and determine pairs of extruder changes for each
// to pass to wipe_tower (so that it can use it for planning the layout of the tower)
{
unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
for (const auto &layer_tools : m_tool_ordering.layer_tools()) { // for all layers
for (auto &layer_tools : m_tool_ordering.layer_tools()) { // for all layers
if (!layer_tools.has_wipe_tower) continue;
bool first_layer = &layer_tools == &m_tool_ordering.front();
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false);
for (const auto extruder_id : layer_tools.extruders) {
if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) {
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back());
float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange
// try to assign some infills/objects for the wiping:
volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, extruder_id, wipe_volumes[current_extruder_id][extruder_id]);
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe);
current_extruder_id = extruder_id;
}
}
layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this);
if (&layer_tools == &m_tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0)
break;
}
}
// Generate the wipe tower layers.
m_wipe_tower_tool_changes.reserve(m_tool_ordering.layer_tools().size());
wipe_tower.generate(m_wipe_tower_tool_changes);
// Set current_extruder_id to the last extruder primed.
/*unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
for (const ToolOrdering::LayerTools &layer_tools : m_tool_ordering.layer_tools()) {
if (! layer_tools.has_wipe_tower)
// This is a support only layer, or the wipe tower does not reach to this height.
continue;
bool first_layer = &layer_tools == &m_tool_ordering.front();
bool last_layer = &layer_tools == &m_tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0;
wipe_tower.set_layer(
float(layer_tools.print_z),
float(layer_tools.wipe_tower_layer_height),
layer_tools.wipe_tower_partitions,
first_layer,
last_layer);
std::vector<WipeTower::ToolChangeResult> tool_changes;
for (unsigned int extruder_id : layer_tools.extruders)
// Call the wipe_tower.tool_change() at the first layer for the initial extruder
// to extrude the wipe tower brim,
if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) ||
// or when an extruder shall be switched.
extruder_id != current_extruder_id) {
tool_changes.emplace_back(wipe_tower.tool_change(extruder_id, extruder_id == layer_tools.extruders.back(), WipeTower::PURPOSE_EXTRUDE));
current_extruder_id = extruder_id;
}
if (! wipe_tower.layer_finished()) {
tool_changes.emplace_back(wipe_tower.finish_layer(WipeTower::PURPOSE_EXTRUDE));
if (tool_changes.size() > 1) {
// Merge the two last tool changes into one.
WipeTower::ToolChangeResult &tc1 = tool_changes[tool_changes.size() - 2];
WipeTower::ToolChangeResult &tc2 = tool_changes.back();
if (tc1.end_pos != tc2.start_pos) {
// Add a travel move from tc1.end_pos to tc2.start_pos.
char buf[2048];
sprintf(buf, "G1 X%.3f Y%.3f F7200\n", tc2.start_pos.x, tc2.start_pos.y);
tc1.gcode += buf;
}
tc1.gcode += tc2.gcode;
append(tc1.extrusions, tc2.extrusions);
tc1.end_pos = tc2.end_pos;
tool_changes.pop_back();
}
}
m_wipe_tower_tool_changes.emplace_back(std::move(tool_changes));
if (last_layer)
break;
}*/
// Unload the current filament over the purge tower.
coordf_t layer_height = this->objects.front()->config.layer_height.value;
if (m_tool_ordering.back().wipe_tower_partitions > 0) {
@ -1210,13 +1172,17 @@ void Print::_make_wipe_tower()
wipe_tower.tool_change((unsigned int)-1, false));
}
std::string Print::output_filename()
{
this->placeholder_parser.update_timestamp();
try {
return this->placeholder_parser.process(this->config.output_filename_format.value, 0);
} catch (std::runtime_error &err) {
throw std::runtime_error(std::string("Failed processing of the output_filename_format template.\n") + err.what());
throw std::runtime_error(L("Failed processing of the output_filename_format template.") + "\n" + err.what());
}
}
@ -1263,4 +1229,13 @@ void Print::print_to_png(std::string dirpath) {
float(this->config.exp_time_first.value));
}
// Returns extruder this eec should be printed with, according to PrintRegion config
int Print::get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion &region)
{
return is_infill(fill.role()) ? std::max<int>(0, (is_solid_infill(fill.entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) :
std::max<int>(region.config.perimeter_extruder.value - 1, 0);
}
}