Splitting FDM support gap to top / bottom, introducing

support_material_bottom_contact_distance
Fixing Crash in support generation after fcb714c (repro attached) #6195
This commit is contained in:
Vojtech Bubnik 2021-03-10 12:14:45 +01:00
parent f3f10ff002
commit 73b88e6ce0
11 changed files with 144 additions and 118 deletions

View file

@ -429,7 +429,8 @@ const std::vector<std::string>& Preset::print_options()
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
"support_material_pattern", "support_material_with_sheath", "support_material_spacing",
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers",
"support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance",
"support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops",
"support_material_contact_distance", "support_material_bottom_contact_distance",
"support_material_buildplate_only", "dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius",
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder",
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",

View file

@ -1326,7 +1326,8 @@ std::string Print::validate(std::string* warning) const
return L("The Wipe Tower is only supported for multiple objects if they have equal layer heights");
if (slicing_params.raft_layers() != slicing_params0.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 != m_objects.front()->config().support_material_contact_distance)
if (slicing_params0.gap_object_support != slicing_params.gap_object_support ||
slicing_params0.gap_support_object != slicing_params.gap_support_object)
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 L("The Wipe Tower is only supported for multiple objects if they are sliced equally.");

View file

@ -2235,7 +2235,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("support_material_contact_distance", coFloat);
def->gui_type = "f_enum_open";
def->label = L("Contact Z distance");
def->label = L("Top contact Z distance");
def->category = L("Support material");
def->tooltip = L("The vertical distance between object and support material interface. "
"Setting this to 0 will also prevent Slic3r from using bridge flow and speed "
@ -2243,12 +2243,31 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm");
// def->min = 0;
def->enum_values.push_back("0");
def->enum_values.push_back("0.1");
def->enum_values.push_back("0.2");
def->enum_labels.push_back(L("0 (soluble)"));
def->enum_labels.push_back(L("0.1 (detachable)"));
def->enum_labels.push_back(L("0.2 (detachable)"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.2));
def = this->add("support_material_bottom_contact_distance", coFloat);
def->gui_type = "f_enum_open";
def->label = L("Bottom contact Z distance");
def->category = L("Support material");
def->tooltip = L("The vertical distance between the object top surface and the support material interface. "
"If set to zero, support_material_contact_distance will be used for both top and bottom contact Z distances.");
def->sidetext = L("mm");
// def->min = 0;
def->enum_values.push_back("0");
def->enum_values.push_back("0.1");
def->enum_values.push_back("0.2");
def->enum_labels.push_back(L("same as top"));
def->enum_labels.push_back(L("0.1"));
def->enum_labels.push_back(L("0.2"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("support_material_enforce_layers", coInt);
def->label = L("Enforce support for the first");
def->category = L("Support material");
@ -2298,22 +2317,36 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(1));
def = this->add("support_material_interface_layers", coInt);
auto support_material_interface_layers = def = this->add("support_material_interface_layers", coInt);
def->gui_type = "f_enum_open";
def->label = L("Top interface layers");
def->category = L("Support material");
def->tooltip = L("Number of interface layers to insert between the object(s) and support material.");
def->sidetext = L("layers");
def->min = 0;
def->enum_values.push_back("0");
def->enum_values.push_back("1");
def->enum_values.push_back("2");
def->enum_values.push_back("3");
def->enum_labels.push_back(L("0 (off)"));
def->enum_labels.push_back(L("1 (light)"));
def->enum_labels.push_back(L("2 (default)"));
def->enum_labels.push_back(L("3 (heavy)"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(3));
def = this->add("support_material_bottom_interface_layers", coInt);
def->gui_type = "f_enum_open";
def->label = L("Bottom interface layers");
def->category = L("Support material");
def->tooltip = L("Number of interface layers to insert between the object(s) and support material. "
"Set to -1 to use support_material_interface_layers");
def->sidetext = L("layers");
def->min = -1;
def->enum_values.push_back("-1");
append(def->enum_values, support_material_interface_layers->enum_values);
def->enum_labels.push_back(L("same as top"));
append(def->enum_labels, support_material_interface_layers->enum_labels);
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(-1));

View file

@ -503,6 +503,7 @@ public:
ConfigOptionFloat support_material_angle;
ConfigOptionBool support_material_buildplate_only;
ConfigOptionFloat support_material_contact_distance;
ConfigOptionFloat support_material_bottom_contact_distance;
ConfigOptionInt support_material_enforce_layers;
ConfigOptionInt support_material_extruder;
ConfigOptionFloatOrPercent support_material_extrusion_width;
@ -555,6 +556,7 @@ protected:
OPT_PTR(support_material_angle);
OPT_PTR(support_material_buildplate_only);
OPT_PTR(support_material_contact_distance);
OPT_PTR(support_material_bottom_contact_distance);
OPT_PTR(support_material_enforce_layers);
OPT_PTR(support_material_interface_contact_loops);
OPT_PTR(support_material_extruder);

View file

@ -546,15 +546,9 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "extra_perimeters"
|| opt_key == "gap_fill_enabled"
|| opt_key == "gap_fill_speed"
|| opt_key == "overhangs"
|| opt_key == "first_layer_extrusion_width"
|| opt_key == "fuzzy_skin"
|| opt_key == "fuzzy_skin_thickness"
|| opt_key == "fuzzy_skin_point_dist"
|| opt_key == "perimeter_extrusion_width"
|| opt_key == "infill_overlap"
|| opt_key == "thin_walls"
|| opt_key == "thick_bridges"
|| opt_key == "external_perimeters_first") {
steps.emplace_back(posPerimeters);
} else if (
@ -586,6 +580,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "support_material_enforce_layers"
|| opt_key == "support_material_extruder"
|| opt_key == "support_material_extrusion_width"
|| opt_key == "support_material_bottom_contact_distance"
|| opt_key == "support_material_interface_layers"
|| opt_key == "support_material_bottom_interface_layers"
|| opt_key == "support_material_interface_pattern"
@ -654,7 +649,13 @@ bool PrintObject::invalidate_state_by_config_options(
steps.emplace_back(posPrepareInfill);
} else if (
opt_key == "external_perimeter_extrusion_width"
|| opt_key == "perimeter_extruder") {
|| opt_key == "perimeter_extruder"
|| opt_key == "fuzzy_skin"
|| opt_key == "fuzzy_skin_thickness"
|| opt_key == "fuzzy_skin_point_dist"
|| opt_key == "overhangs"
|| opt_key == "thin_walls"
|| opt_key == "thick_bridges") {
steps.emplace_back(posPerimeters);
steps.emplace_back(posSupportMaterial);
} else if (opt_key == "bridge_flow_ratio") {

View file

@ -112,8 +112,10 @@ SlicingParameters SlicingParameters::create_from_config(
if (! soluble_interface) {
params.gap_raft_object = object_config.raft_contact_distance.value;
params.gap_object_support = object_config.support_material_contact_distance.value;
params.gap_object_support = object_config.support_material_bottom_contact_distance.value;
params.gap_support_object = object_config.support_material_contact_distance.value;
if (params.gap_object_support <= 0)
params.gap_object_support = params.gap_support_object;
}
if (params.base_raft_layers > 0) {

View file

@ -26,7 +26,7 @@ class DynamicPrintConfig;
// (using a normal flow over a soluble support, using a bridging flow over a non-soluble support).
struct SlicingParameters
{
SlicingParameters() { memset(this, 0, sizeof(SlicingParameters)); }
SlicingParameters() = default;
static SlicingParameters create_from_config(
const PrintConfig &print_config,
@ -44,58 +44,58 @@ struct SlicingParameters
// Height of the object to be printed. This value does not contain the raft height.
coordf_t object_print_z_height() const { return object_print_z_max - object_print_z_min; }
bool valid;
bool valid { false };
// Number of raft layers.
size_t base_raft_layers;
size_t base_raft_layers { 0 };
// Number of interface layers including the contact layer.
size_t interface_raft_layers;
size_t interface_raft_layers { 0 };
// Layer heights of the raft (base, interface and a contact layer).
coordf_t base_raft_layer_height;
coordf_t interface_raft_layer_height;
coordf_t contact_raft_layer_height;
coordf_t base_raft_layer_height { 0 };
coordf_t interface_raft_layer_height { 0 };
coordf_t contact_raft_layer_height { 0 };
// The regular layer height, applied for all but the first layer, if not overridden by layer ranges
// or by the variable layer thickness table.
coordf_t layer_height;
coordf_t layer_height { 0 };
// Minimum / maximum layer height, to be used for the automatic adaptive layer height algorithm,
// or by an interactive layer height editor.
coordf_t min_layer_height;
coordf_t max_layer_height;
coordf_t max_suport_layer_height;
coordf_t min_layer_height { 0 };
coordf_t max_layer_height { 0 };
coordf_t max_suport_layer_height { 0 };
// First layer height of the print, this may be used for the first layer of the raft
// or for the first layer of the print.
coordf_t first_print_layer_height;
coordf_t first_print_layer_height { 0 };
// Thickness of the first layer. This is either the first print layer thickness if printed without a raft,
// or a bridging flow thickness if printed over a non-soluble raft,
// or a normal layer height if printed over a soluble raft.
coordf_t first_object_layer_height;
coordf_t first_object_layer_height { 0 };
// If the object is printed over a non-soluble raft, the first layer may be printed with a briding flow.
bool first_object_layer_bridging;
bool first_object_layer_bridging { false };
// Soluble interface? (PLA soluble in water, HIPS soluble in lemonen)
// otherwise the interface must be broken off.
bool soluble_interface;
bool soluble_interface { false };
// Gap when placing object over raft.
coordf_t gap_raft_object;
coordf_t gap_raft_object { 0 };
// Gap when placing support over object.
coordf_t gap_object_support;
coordf_t gap_object_support { 0 };
// Gap when placing object over support.
coordf_t gap_support_object;
coordf_t gap_support_object { 0 };
// Bottom and top of the printed object.
// If printed without a raft, object_print_z_min = 0 and object_print_z_max = object height.
// Otherwise object_print_z_min is equal to the raft height.
coordf_t raft_base_top_z;
coordf_t raft_interface_top_z;
coordf_t raft_contact_top_z;
coordf_t raft_base_top_z { 0 };
coordf_t raft_interface_top_z { 0 };
coordf_t raft_contact_top_z { 0 };
// In case of a soluble interface, object_print_z_min == raft_contact_top_z, otherwise there is a gap between the raft and the 1st object layer.
coordf_t object_print_z_min;
coordf_t object_print_z_max;
coordf_t object_print_z_min { 0 };
coordf_t object_print_z_max { 0 };
};
static_assert(IsTriviallyCopyable<SlicingParameters>::value, "SlicingParameters class is not POD (and it should be - see constructor).");

View file

@ -10,6 +10,7 @@
#include <cmath>
#include <memory>
#include <boost/log/trivial.hpp>
#include <boost/container/static_vector.hpp>
#include <tbb/parallel_for.h>
#include <tbb/atomic.h>
@ -397,14 +398,6 @@ inline void layers_append(PrintObjectSupportMaterial::MyLayersPtr &dst, const Pr
dst.insert(dst.end(), src.begin(), src.end());
}
// Compare layers lexicographically.
struct MyLayersPtrCompare
{
bool operator()(const PrintObjectSupportMaterial::MyLayer* layer1, const PrintObjectSupportMaterial::MyLayer* layer2) const {
return *layer1 < *layer2;
}
};
void PrintObjectSupportMaterial::generate(PrintObject &object)
{
BOOST_LOG_TRIVIAL(info) << "Support generator - Start";
@ -467,10 +460,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
MyLayersPtr intermediate_layers = this->raft_and_intermediate_support_layers(
object, bottom_contacts, top_contacts, layer_storage);
// this->trim_support_layers_by_object(object, top_contacts, m_slicing_params.soluble_interface ? 0. : m_support_layer_height_min, 0., m_gap_xy);
this->trim_support_layers_by_object(object, top_contacts,
m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value,
m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value, m_gap_xy);
this->trim_support_layers_by_object(object, top_contacts, m_slicing_params.gap_support_object, m_slicing_params.gap_object_support, m_gap_xy);
#ifdef SLIC3R_DEBUG
for (const MyLayer *layer : top_contacts)
@ -552,7 +542,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
layers_append(layers_sorted, interface_layers);
layers_append(layers_sorted, base_interface_layers);
// Sort the layers lexicographically by a raising print_z and a decreasing height.
std::sort(layers_sorted.begin(), layers_sorted.end(), MyLayersPtrCompare());
std::sort(layers_sorted.begin(), layers_sorted.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
int layer_id = 0;
assert(object.support_layers().empty());
for (size_t i = 0; i < layers_sorted.size();) {
@ -1585,11 +1575,11 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
} else if (m_slicing_params.soluble_interface) {
// Align the contact surface height with a layer immediately below the supported layer.
// Interface layer will be synchronized with the object.
new_layer.print_z = layer.print_z - layer.height;
new_layer.print_z = layer.bottom_z();
new_layer.height = object.layers()[layer_id - 1]->height;
new_layer.bottom_z = (layer_id == 1) ? m_slicing_params.object_print_z_min : object.layers()[layer_id - 2]->print_z;
} else {
new_layer.print_z = layer.print_z - layer.height - m_object_config->support_material_contact_distance;
new_layer.print_z = layer.bottom_z() - m_slicing_params.gap_object_support;
new_layer.bottom_z = new_layer.print_z;
new_layer.height = 0.;
// Ignore this contact area if it's too low.
@ -1616,7 +1606,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
for (const LayerRegion *region : layer.regions())
bridging_height += region->region()->bridging_height_avg(*m_print_config);
bridging_height /= coordf_t(layer.regions().size());
coordf_t bridging_print_z = layer.print_z - bridging_height - m_object_config->support_material_contact_distance;
coordf_t bridging_print_z = layer.print_z - bridging_height - m_slicing_params.gap_support_object;
if (bridging_print_z >= m_slicing_params.first_print_layer_height - EPSILON) {
// Not below the first layer height means this layer is printable.
if (new_layer.print_z < m_slicing_params.first_print_layer_height + EPSILON) {
@ -1892,7 +1882,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
// Place a bridge flow interface layer or the normal flow interface layer over the top surface.
m_support_material_bottom_interface_flow.height();
layer_new.print_z = m_slicing_params.soluble_interface ? object.layers()[layer_id + 1]->print_z :
layer.print_z + layer_new.height + m_object_config->support_material_contact_distance.value;
layer.print_z + layer_new.height + m_slicing_params.gap_object_support;
layer_new.bottom_z = layer.print_z;
layer_new.idx_object_layer_below = layer_id;
layer_new.bridging = ! m_slicing_params.soluble_interface && m_object_config->thick_bridges;
@ -2039,11 +2029,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
task_group.wait();
}
std::reverse(bottom_contacts.begin(), bottom_contacts.end());
// trim_support_layers_by_object(object, bottom_contacts, 0., 0., m_gap_xy);
trim_support_layers_by_object(object, bottom_contacts,
m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value,
m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value, m_gap_xy);
trim_support_layers_by_object(object, bottom_contacts, m_slicing_params.gap_support_object, m_slicing_params.gap_object_support, m_gap_xy);
} // ! top_contacts.empty()
return bottom_contacts;
@ -2473,10 +2459,7 @@ void PrintObjectSupportMaterial::generate_base_layers(
++ iRun;
#endif /* SLIC3R_DEBUG */
// trim_support_layers_by_object(object, intermediate_layers, 0., 0., m_gap_xy);
this->trim_support_layers_by_object(object, intermediate_layers,
m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value,
m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value, m_gap_xy);
this->trim_support_layers_by_object(object, intermediate_layers, m_slicing_params.gap_support_object, m_slicing_params.gap_object_support, m_gap_xy);
}
void PrintObjectSupportMaterial::trim_support_layers_by_object(
@ -2510,7 +2493,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
// BOOST_LOG_TRIVIAL(trace) << "Support generator - trim_support_layers_by_object - trimmming non-empty layer " << idx_layer << " of " << nonempty_layers.size();
assert(! support_layer.polygons.empty() && support_layer.print_z >= m_slicing_params.raft_contact_top_z + EPSILON);
// Find the overlapping object layers including the extra above / below gap.
coordf_t z_threshold = support_layer.print_z - support_layer.height - gap_extra_below + EPSILON;
coordf_t z_threshold = support_layer.bottom_print_z() - gap_extra_below + EPSILON;
idx_object_layer_overlapping = idx_higher_or_equal(
object.layers().begin(), object.layers().end(), idx_object_layer_overlapping,
[z_threshold](const Layer *layer){ return layer->print_z >= z_threshold; });
@ -2519,7 +2502,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
size_t i = idx_object_layer_overlapping;
for (; i < object.layers().size(); ++ i) {
const Layer &object_layer = *object.layers()[i];
if (object_layer.print_z - object_layer.height > support_layer.print_z + gap_extra_above - EPSILON)
if (object_layer.bottom_z() > support_layer.print_z + gap_extra_above - EPSILON)
break;
polygons_append(polygons_trimming, offset(object_layer.lslices, gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
}
@ -2537,6 +2520,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
offset(to_expolygons(region->fill_surfaces.filter_by_type(stBottomBridge)),
gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
if (region->region()->config().overhangs.value)
// Add bridging perimeters.
SupportMaterialInternal::collect_bridging_perimeter_areas(region->perimeters, gap_xy_scaled, polygons_trimming);
}
if (! some_region_overlaps)
@ -2896,7 +2880,8 @@ static inline void fill_expolygons_with_sheath_generate_paths(
float density,
ExtrusionRole role,
const Flow &flow,
bool with_sheath)
bool with_sheath,
bool no_sort)
{
if (polygons.empty())
return;
@ -2916,8 +2901,12 @@ static inline void fill_expolygons_with_sheath_generate_paths(
for (ExPolygon &expoly : offset2_ex(polygons, float(SCALED_EPSILON), float(- SCALED_EPSILON - 0.5*flow.scaled_width()))) {
// Don't reorder the skirt and its infills.
auto eec = std::make_unique<ExtrusionEntityCollection>();
eec->no_sort = true;
std::unique_ptr<ExtrusionEntityCollection> eec;
if (no_sort) {
eec = std::make_unique<ExtrusionEntityCollection>();
eec->no_sort = true;
}
ExtrusionEntitiesPtr &out = no_sort ? eec->entities : dst;
// Draw the perimeters.
Polylines polylines;
polylines.reserve(expoly.holes.size() + 1);
@ -2927,10 +2916,11 @@ static inline void fill_expolygons_with_sheath_generate_paths(
pl.clip_end(clip_length);
polylines.emplace_back(std::move(pl));
}
extrusion_entities_append_paths(eec->entities, polylines, erSupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height());
extrusion_entities_append_paths(out, polylines, erSupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height());
// Fill in the rest.
fill_expolygons_generate_paths(eec->entities, offset_ex(expoly, float(-0.4 * spacing)), filler, fill_params, density, role, flow);
dst.emplace_back(eec.release());
fill_expolygons_generate_paths(out, offset_ex(expoly, float(-0.4 * spacing)), filler, fill_params, density, role, flow);
if (no_sort)
dst.emplace_back(eec.release());
}
}
@ -3255,6 +3245,9 @@ static std::string dbg_index_to_color(int idx)
// Therefore the bottom interface spots are expanded a bit. The expanded regions may overlap with another bottom interface layers,
// leading to over extrusion, where they overlap. The over extrusion is better avoided as it often makes the interface layers
// to stick too firmly to the object.
//
// Modulate thickness (increase bottom_z) of extrusions_in_out generated for this_layer
// if they overlap with overlapping_layers, whose print_z is above this_layer.bottom_z() and below this_layer.print_z.
void modulate_extrusion_by_overlapping_layers(
// Extrusions generated for this_layer.
ExtrusionEntitiesPtr &extrusions_in_out,
@ -3343,8 +3336,8 @@ void modulate_extrusion_by_overlapping_layers(
// Collect the paths of this_layer.
{
Polylines &polylines = path_fragments.back().polylines;
for (ExtrusionEntitiesPtr::const_iterator it = extrusions_in_out.begin(); it != extrusions_in_out.end(); ++ it) {
ExtrusionPath *path = dynamic_cast<ExtrusionPath*>(*it);
for (ExtrusionEntity *ee : extrusions_in_out) {
ExtrusionPath *path = dynamic_cast<ExtrusionPath*>(ee);
assert(path != nullptr);
polylines.emplace_back(Polyline(std::move(path->polyline)));
path_ends.emplace_back(std::pair<Point, Point>(polylines.back().points.front(), polylines.back().points.back()));
@ -3504,7 +3497,6 @@ void PrintObjectSupportMaterial::generate_toolpaths(
const MyLayersPtr &interface_layers,
const MyLayersPtr &base_interface_layers) const
{
// Slic3r::debugf "Generating patterns\n";
// loop_interface_processor with a given circle radius.
LoopInterfaceProcessor loop_interface_processor(1.5 * m_support_material_interface_flow.scaled_width());
loop_interface_processor.n_contact_loops = this->has_contact_loops() ? 1 : 0;
@ -3603,7 +3595,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
filler, float(support_density),
// Extrusion parameters
erSupportMaterial, flow,
with_sheath);
with_sheath, false);
}
}
@ -3636,7 +3628,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// Extrusion parameters
(support_layer_id < m_slicing_params.base_raft_layers) ? erSupportMaterial : erSupportMaterialInterface, flow,
// sheath at first layer
support_layer_id == 0);
support_layer_id == 0, support_layer_id == 0);
}
});
@ -3646,12 +3638,20 @@ void PrintObjectSupportMaterial::generate_toolpaths(
std::vector<MyLayer*> overlapping;
};
struct LayerCache {
MyLayerExtruded bottom_contact_layer;
MyLayerExtruded top_contact_layer;
MyLayerExtruded base_layer;
MyLayerExtruded interface_layer;
MyLayerExtruded base_interface_layer;
std::vector<LayerCacheItem> overlaps;
MyLayerExtruded bottom_contact_layer;
MyLayerExtruded top_contact_layer;
MyLayerExtruded base_layer;
MyLayerExtruded interface_layer;
MyLayerExtruded base_interface_layer;
boost::container::static_vector<LayerCacheItem, 5> nonempty;
void add_nonempty_and_sort() {
for (MyLayerExtruded *item : { &bottom_contact_layer, &top_contact_layer, &interface_layer, &base_interface_layer, &base_layer })
if (! item->empty())
this->nonempty.emplace_back(item);
// Sort the layers with the same print_z coordinate by their heights, thickest first.
std::stable_sort(this->nonempty.begin(), this->nonempty.end(), [](const LayerCacheItem &lc1, const LayerCacheItem &lc2) { return lc1.layer_extruded->layer->height > lc2.layer_extruded->layer->height; });
}
};
std::vector<LayerCache> layer_caches(support_layers.size(), LayerCache());
@ -3816,6 +3816,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_density));
float density = float(support_density);
bool sheath = with_sheath;
bool no_sort = false;
if (base_layer.layer->bottom_z < EPSILON) {
// Base flange (the 1st layer).
filler = filler_first_layer;
@ -3827,7 +3828,8 @@ void PrintObjectSupportMaterial::generate_toolpaths(
//FIXME When paralellizing, each thread shall have its own copy of the fillers.
filler->spacing = flow.spacing();
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
sheath = true;
sheath = true;
no_sort = true;
}
fill_expolygons_with_sheath_generate_paths(
// Destination
@ -3838,7 +3840,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
filler, density,
// Extrusion parameters
erSupportMaterial, flow,
sheath);
sheath, no_sort);
}
@ -3847,24 +3849,13 @@ void PrintObjectSupportMaterial::generate_toolpaths(
base_layer.could_merge(base_interface_layer))
base_layer.merge(std::move(base_interface_layer));
layer_cache.overlaps.reserve(5);
if (! bottom_contact_layer.empty())
layer_cache.overlaps.push_back(&bottom_contact_layer);
if (! top_contact_layer.empty())
layer_cache.overlaps.push_back(&top_contact_layer);
if (! interface_layer.empty())
layer_cache.overlaps.push_back(&interface_layer);
if (! base_interface_layer.empty())
layer_cache.overlaps.push_back(&base_interface_layer);
if (! base_layer.empty())
layer_cache.overlaps.push_back(&base_layer);
// Sort the layers with the same print_z coordinate by their heights, thickest first.
std::sort(layer_cache.overlaps.begin(), layer_cache.overlaps.end(), [](const LayerCacheItem &lc1, const LayerCacheItem &lc2) { return lc1.layer_extruded->layer->height > lc2.layer_extruded->layer->height; });
layer_cache.add_nonempty_and_sort();
// Collect the support areas with this print_z into islands, as there is no need
// for retraction over these islands.
Polygons polys;
// Collect the extrusions, sorted by the bottom extrusion height.
for (LayerCacheItem &layer_cache_item : layer_cache.overlaps) {
for (LayerCacheItem &layer_cache_item : layer_cache.nonempty) {
// Collect islands to polys.
layer_cache_item.layer_extruded->polygons_append(polys);
// The print_z of the top contact surfaces and bottom_z of the bottom contact surfaces are "free"
@ -3878,32 +3869,22 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// Collect overlapping top/bottom surfaces.
layer_cache_item.overlapping.reserve(20);
coordf_t bottom_z = layer_cache_item.layer_extruded->layer->bottom_print_z() + EPSILON;
for (int i = int(idx_layer_bottom_contact) - 1; i >= 0 && bottom_contacts[i]->print_z > bottom_z; -- i)
layer_cache_item.overlapping.push_back(bottom_contacts[i]);
for (int i = int(idx_layer_top_contact) - 1; i >= 0 && top_contacts[i]->print_z > bottom_z; -- i)
layer_cache_item.overlapping.push_back(top_contacts[i]);
auto add_overlapping = [&layer_cache_item, bottom_z](const MyLayersPtr &layers, size_t idx_top) {
for (int i = int(idx_top) - 1; i >= 0 && layers[i]->print_z > bottom_z; -- i)
layer_cache_item.overlapping.push_back(layers[i]);
};
add_overlapping(top_contacts, idx_layer_top_contact);
if (layer_cache_item.layer_extruded->layer->layer_type == sltBottomContact) {
// Bottom contact layer may overlap with a base layer, which may be changed to interface layer.
for (int i = int(idx_layer_intermediate) - 1; i >= 0 && intermediate_layers[i]->print_z > bottom_z; -- i)
layer_cache_item.overlapping.push_back(intermediate_layers[i]);
for (int i = int(idx_layer_interface) - 1; i >= 0 && interface_layers[i]->print_z > bottom_z; -- i)
layer_cache_item.overlapping.push_back(interface_layers[i]);
for (int i = int(idx_layer_base_interface) - 1; i >= 0 && base_interface_layers[i]->print_z > bottom_z; -- i)
layer_cache_item.overlapping.push_back(base_interface_layers[i]);
add_overlapping(intermediate_layers, idx_layer_intermediate);
add_overlapping(interface_layers, idx_layer_interface);
add_overlapping(base_interface_layers, idx_layer_base_interface);
}
std::sort(layer_cache_item.overlapping.begin(), layer_cache_item.overlapping.end(), MyLayersPtrCompare());
// Order the layers by lexicographically by an increasing print_z and a decreasing layer height.
std::stable_sort(layer_cache_item.overlapping.begin(), layer_cache_item.overlapping.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
}
if (! polys.empty())
expolygons_append(support_layer.support_islands.expolygons, union_ex(polys));
/* {
require "Slic3r/SVG.pm";
Slic3r::SVG::output("islands_" . $z . ".svg",
red_expolygons => union_ex($contact),
green_expolygons => union_ex($interface),
green_polylines => [ map $_->unpack->polyline, @{$layer->support_contact_fills} ],
polylines => [ map $_->unpack->polyline, @{$layer->support_fills} ],
);
} */
} // for each support_layer_id
});
@ -3914,7 +3895,9 @@ void PrintObjectSupportMaterial::generate_toolpaths(
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) {
SupportLayer &support_layer = *support_layers[support_layer_id];
LayerCache &layer_cache = layer_caches[support_layer_id];
for (LayerCacheItem &layer_cache_item : layer_cache.overlaps) {
// For all extrusion types at this print_z, ordered by decreasing layer height:
for (LayerCacheItem &layer_cache_item : layer_cache.nonempty) {
// Trim the extrusion height from the bottom by the overlapping layers.
modulate_extrusion_by_overlapping_layers(layer_cache_item.layer_extruded->extrusions, *layer_cache_item.layer_extruded->layer, layer_cache_item.overlapping);
support_layer.support_fills.append(std::move(layer_cache_item.layer_extruded->extrusions));
}

View file

@ -285,6 +285,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
"support_material_xy_spacing" })
toggle_field(el, have_support_material);
toggle_field("support_material_threshold", have_support_material_auto);
toggle_field("support_material_bottom_contact_distance", have_support_material && ! have_support_soluble);
for (auto el : { "support_material_bottom_interface_layers", "support_material_interface_spacing", "support_material_interface_extruder",
"support_material_interface_speed", "support_material_interface_contact_loops" })

View file

@ -1762,7 +1762,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.
"layer_height", "first_layer_height", "min_layer_height", "max_layer_height",
"brim_width", "perimeters", "perimeter_extruder", "fill_density", "infill_extruder", "top_solid_layers",
"support_material", "support_material_extruder", "support_material_interface_extruder", "support_material_contact_distance", "raft_layers"
"support_material", "support_material_extruder", "support_material_interface_extruder",
"support_material_contact_distance", "support_material_bottom_contact_distance", "raft_layers"
}))
, sidebar(new Sidebar(q))
, m_ui_jobs(this)

View file

@ -1507,6 +1507,7 @@ void TabPrint::build()
optgroup = page->new_optgroup(L("Options for support material and raft"));
optgroup->append_single_option_line("support_material_contact_distance", category_path + "contact-z-distance");
optgroup->append_single_option_line("support_material_bottom_contact_distance", category_path + "contact-z-distance");
optgroup->append_single_option_line("support_material_pattern", category_path + "pattern");
optgroup->append_single_option_line("support_material_with_sheath", category_path + "with-sheath-around-the-support");
optgroup->append_single_option_line("support_material_spacing", category_path + "pattern-spacing-0-inf");