Skip to content

Commit

Permalink
Fix of crash when using raft with modified Shape-Box with height 0.5mm
Browse files Browse the repository at this point in the history
…#5652

Reworked skirt generator to only generate skirt at non-empty layers
(layers that actually extruder object or support) and to respect minimum
layer height. Skirt generator stops at the first layer where those both
conditions cannot be met.
  • Loading branch information
bubnikv committed Feb 25, 2021
1 parent 1e33b95 commit 43c05d3
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 42 deletions.
36 changes: 17 additions & 19 deletions src/libslic3r/GCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1803,15 +1803,15 @@ namespace Skirt {

static std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_1st_layer(
const Print &print,
const std::vector<GCode::LayerToPrint> & /*layers */,
const LayerTools &layer_tools,
// Heights (print_z) at which the skirt has already been extruded.
std::vector<coordf_t> &skirt_done)
{
// 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.
std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder_out;
if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty()) {
assert(skirt_done.empty());
if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty() && layer_tools.has_skirt) {
skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
skirt_done.emplace_back(layer_tools.print_z);
}
Expand All @@ -1820,36 +1820,34 @@ namespace Skirt {

static std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_other_layers(
const Print &print,
const std::vector<GCode::LayerToPrint> &layers,
const LayerTools &layer_tools,
// First non-empty support layer.
const SupportLayer *support_layer,
// Heights (print_z) at which the skirt has already been extruded.
std::vector<coordf_t> &skirt_done)
{
// 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.
std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder_out;
if (print.has_skirt() && ! print.skirt().entities.empty() &&
if (print.has_skirt() && ! print.skirt().entities.empty() && layer_tools.has_skirt &&
// Not enough skirt layers printed yet.
//FIXME infinite or high skirt does not make sense for sequential print!
(skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) &&
(skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt())) {
bool valid = ! skirt_done.empty() && skirt_done.back() < layer_tools.print_z - EPSILON;
assert(valid);
// This print_z has not been extruded yet (sequential print)
// FIXME: The skirt_done should not be empty at this point. The check is a workaround
// of https://github.com/prusa3d/PrusaSlicer/issues/5652, but it deserves a real fix.
(! skirt_done.empty() && skirt_done.back() < layer_tools.print_z - EPSILON) &&
// and this layer is an object layer, or it is a raft layer.
(layer_tools.has_object || support_layer->id() < (size_t)support_layer->object()->config().raft_layers.value)) {
if (valid) {
#if 0
// Prime just the first printing extruder. This is original Slic3r's implementation.
skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair<size_t, size_t>(0, print.config().skirts.value);
// Prime just the first printing extruder. This is original Slic3r's implementation.
skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair<size_t, size_t>(0, print.config().skirts.value);
#else
// Prime all extruders planned for this layer, see
// https://github.com/prusa3d/PrusaSlicer/issues/469#issuecomment-322450619
skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
// Prime all extruders planned for this layer, see
// https://github.com/prusa3d/PrusaSlicer/issues/469#issuecomment-322450619
skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
#endif
assert(!skirt_done.empty());
skirt_done.emplace_back(layer_tools.print_z);
assert(!skirt_done.empty());
skirt_done.emplace_back(layer_tools.print_z);
}
}
return skirt_loops_per_extruder_out;
}
Expand Down Expand Up @@ -1992,8 +1990,8 @@ void GCode::process_layer(
// 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.
skirt_loops_per_extruder = first_layer ?
Skirt::make_skirt_loops_per_extruder_1st_layer(print, layers, layer_tools, m_skirt_done) :
Skirt::make_skirt_loops_per_extruder_other_layers(print, layers, layer_tools, support_layer, m_skirt_done);
Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) :
Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done);

// Group extrusions by an extruder, then by an object, an island and a region.
std::map<unsigned int, std::vector<ObjectByExtruder>> by_extruder;
Expand Down
77 changes: 64 additions & 13 deletions src/libslic3r/GCode/ToolOrdering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@ unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, c
return (extruder == 0) ? 0 : extruder - 1;
}

static double calc_max_layer_height(const PrintConfig &config, double max_object_layer_height)
{
double max_layer_height = std::numeric_limits<double>::max();
for (size_t i = 0; i < config.nozzle_diameter.values.size(); ++ i) {
double mlh = config.max_layer_height.values[i];
if (mlh == 0.)
mlh = 0.75 * config.nozzle_diameter.values[i];
max_layer_height = std::min(max_layer_height, mlh);
}
// The Prusa3D Fast (0.35mm layer height) print profile sets a higher layer height than what is normally allowed
// by the nozzle. This is a hack and it works by increasing extrusion width. See GH #3919.
return std::max(max_layer_height, max_object_layer_height);
}

// For the use case when each object is printed separately
// (print.config().complete_objects is true).
ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material)
Expand All @@ -87,16 +101,19 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
zs.emplace_back(layer->print_z);
this->initialize_layers(zs);
}
double max_layer_height = calc_max_layer_height(object.print()->config(), object.config().layer_height);

// Collect extruders reuqired to print the layers.
this->collect_extruders(object, std::vector<std::pair<double, unsigned int>>());

// Reorder the extruders to minimize tool switches.
this->reorder_extruders(first_extruder);

this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, object.config().layer_height);
this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, max_layer_height);

this->collect_extruder_statistics(prime_multi_material);

this->mark_skirt_layers(object.print()->config(), max_layer_height);
}

// For the use case when all objects are printed at once.
Expand Down Expand Up @@ -128,6 +145,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
}
this->initialize_layers(zs);
}
max_layer_height = calc_max_layer_height(print.config(), max_layer_height);

// Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object.
// Do it only if all the objects were configured to be printed with a single extruder.
Expand All @@ -150,6 +168,8 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height);

this->collect_extruder_statistics(prime_multi_material);

this->mark_skirt_layers(print.config(), max_layer_height);
}

void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs)
Expand Down Expand Up @@ -321,7 +341,7 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
}
}

void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_object_layer_height)
void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height)
{
if (m_layer_tools.empty())
return;
Expand All @@ -347,17 +367,6 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
lt.has_wipe_tower = (lt.has_object && lt.wipe_tower_partitions > 0) || lt.print_z < object_bottom_z + EPSILON;

// Test for a raft, insert additional wipe tower layer to fill in the raft separation gap.
double max_layer_height = std::numeric_limits<double>::max();
for (size_t i = 0; i < config.nozzle_diameter.values.size(); ++ i) {
double mlh = config.max_layer_height.values[i];
if (mlh == 0.)
mlh = 0.75 * config.nozzle_diameter.values[i];
max_layer_height = std::min(max_layer_height, mlh);
}
// The Prusa3D Fast (0.35mm layer height) print profile sets a higher layer height than what is normally allowed
// by the nozzle. This is a hack and it works by increasing extrusion width. See GH #3919.
max_layer_height = std::max(max_layer_height, max_object_layer_height);

for (size_t i = 0; i + 1 < m_layer_tools.size(); ++ i) {
const LayerTools &lt = m_layer_tools[i];
const LayerTools &lt_next = m_layer_tools[i + 1];
Expand Down Expand Up @@ -460,6 +469,48 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material)
}
}

// Layers are marked for infinite skirt aka draft shield. Not all the layers have to be printed.
void ToolOrdering::mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height)
{
if (m_layer_tools.empty())
return;

if (m_layer_tools.front().extruders.empty()) {
// Empty first layer, no skirt will be printed.
//FIXME throw an exception?
return;
}

size_t i = 0;
for (;;) {
m_layer_tools[i].has_skirt = true;
size_t j = i + 1;
for (; j < m_layer_tools.size() && ! m_layer_tools[j].has_object; ++ j);
// i and j are two successive layers printing an object.
if (j == m_layer_tools.size())
// Don't print skirt above the last object layer.
break;
// Mark some printing intermediate layers as having skirt.
double last_z = m_layer_tools[i].print_z;
for (size_t k = i + 1; k < j; ++ k) {
if (m_layer_tools[k + 1].print_z - last_z > max_layer_height + EPSILON) {
// Layer k is the last one not violating the maximum layer height.
// Don't extrude skirt on empty layers.
while (m_layer_tools[k].extruders.empty())
-- k;
if (m_layer_tools[k].has_skirt) {
// Skirt cannot be generated due to empty layers, there would be a missing layer in the skirt.
//FIXME throw an exception?
break;
}
m_layer_tools[k].has_skirt = true;
last_z = m_layer_tools[k].print_z;
}
}
i = j;
}
}

// Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools.
// Ignore color changes, which are performed on a layer and for such an extruder, that the extruder will not be printing above that layer.
// If multiple events are planned over a span of a single layer, use the last one.
Expand Down
14 changes: 5 additions & 9 deletions src/libslic3r/GCode/ToolOrdering.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ class LayerTools;
namespace CustomGCode { struct Item; }
class PrintRegion;



// Object of this class holds information about whether an extrusion is printed immediately
// after a toolchange (as part of infill/perimeter wiping) or not. One extrusion can be a part
// of several copies - this has to be taken into account.
Expand Down Expand Up @@ -69,8 +67,6 @@ class WipingExtrusions
const LayerTools* m_layer_tools = nullptr; // so we know which LayerTools object this belongs to
};



class LayerTools
{
public:
Expand Down Expand Up @@ -99,6 +95,9 @@ class LayerTools
// If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with.
// If not overriden, it is set to 0.
unsigned int extruder_override = 0;
// Should a skirt be printed at this layer?
// Layers are marked for infinite skirt aka draft shield. Not all the layers have to be printed.
bool has_skirt = false;
// Will there be anything extruded on this layer for the wipe tower?
// Due to the support layers possibly interleaving the object layers,
// wipe tower will be disabled for some support only layers.
Expand All @@ -120,12 +119,10 @@ class LayerTools
WipingExtrusions m_wiping_extrusions;
};



class ToolOrdering
{
public:
ToolOrdering() {}
ToolOrdering() = default;

// For the use case when each object is printed separately
// (print.config.complete_objects is true).
Expand Down Expand Up @@ -169,6 +166,7 @@ class ToolOrdering
void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches);
void reorder_extruders(unsigned int last_extruder_id);
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height);
void mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height);
void collect_extruder_statistics(bool prime_multi_material);

std::vector<LayerTools> m_layer_tools;
Expand All @@ -182,8 +180,6 @@ class ToolOrdering
const PrintConfig* m_print_config_ptr = nullptr;
};



} // namespace SLic3r

#endif /* slic3r_ToolOrdering_hpp_ */
2 changes: 1 addition & 1 deletion src/libslic3r/PrintObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ void PrintObject::generate_support_material()
{
if (this->set_started(posSupportMaterial)) {
this->clear_support_layers();
if (this->has_support_material() && m_layers.size() > 1) {
if ((this->has_support() && m_layers.size() > 1) || (this->has_raft() && ! m_layers.empty())) {
m_print->set_status(85, L("Generating support material"));
this->_generate_support_material();
m_print->throw_if_canceled();
Expand Down

0 comments on commit 43c05d3

Please sign in to comment.