Fix of Improve Support material adhesion by base type interface layers

under soluble supports. 
Implemented as a pull request  by @spiky2021
and reworked.

commit c7993e619225553a2c4078787907b9ebbd9ac759
Author: spiky2021 <77010315+spiky2021@users.noreply.github.com>
Date:   Thu Feb 11 12:39:25 2021 +0100

    Base type interfaces for soluble interface supports

    At the moment soluble support material adhesion is weak due to sparse support layers under soluble support layers. I reported as issue  with pictures, as well.
    I modified two methods to the SupportMaterial Class including their headers.
    The new methods add two base type interface layers to the support structure, in case the extruders are different and soluble support is choosen.
    Since it is conditionally activated, it in general doesn't need a GUI input. But a GUI option number of base interface layers may enabled users to adapt this feature to their needs.
    This is my second try to provide a pull request on this topic. Reset my fromer repository, because first I merged this and all other changes to my master and couldn't provide separate pull request anymore.
This commit is contained in:
Vojtech Bubnik 2021-02-15 18:07:44 +01:00
parent b166bd7845
commit 32db22b77c
3 changed files with 181 additions and 76 deletions

View file

@ -710,7 +710,7 @@ namespace Slic3r {
#endif // ENABLE_RELOAD_FROM_DISK_FOR_3MF #endif // ENABLE_RELOAD_FROM_DISK_FOR_3MF
for (const IdToModelObjectMap::value_type& object : m_objects) { for (const IdToModelObjectMap::value_type& object : m_objects) {
if (object.second >= m_model->objects.size()) { if (object.second >= int(m_model->objects.size())) {
add_error("Unable to find object"); add_error("Unable to find object");
return false; return false;
} }
@ -1395,7 +1395,7 @@ namespace Slic3r {
{ {
// deletes all non-built or non-instanced objects // deletes all non-built or non-instanced objects
for (const IdToModelObjectMap::value_type& object : m_objects) { for (const IdToModelObjectMap::value_type& object : m_objects) {
if (object.second >= m_model->objects.size()) { if (object.second >= int(m_model->objects.size())) {
add_error("Unable to find object"); add_error("Unable to find object");
return false; return false;
} }

View file

@ -291,7 +291,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
BOOST_LOG_TRIVIAL(info) << "Support generator - Creating base layers"; BOOST_LOG_TRIVIAL(info) << "Support generator - Creating base layers";
// Fill in intermediate layers between the top / bottom support contact layers, trimm them by the object. // Fill in intermediate layers between the top / bottom support contact layers, trim them by the object.
this->generate_base_layers(object, bottom_contacts, top_contacts, intermediate_layers, layer_support_areas); this->generate_base_layers(object, bottom_contacts, top_contacts, intermediate_layers, layer_support_areas);
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG
@ -312,9 +312,9 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
BOOST_LOG_TRIVIAL(info) << "Support generator - Creating interfaces"; BOOST_LOG_TRIVIAL(info) << "Support generator - Creating interfaces";
// Propagate top / bottom contact layers to generate interface layers. // Propagate top / bottom contact layers to generate interface layers
MyLayersPtr interface_layers = this->generate_interface_layers( // and base interface layers (for soluble interface / non souble base only)
bottom_contacts, top_contacts, intermediate_layers, layer_storage); auto [interface_layers, base_interface_layers] = this->generate_interface_layers(bottom_contacts, top_contacts, intermediate_layers, layer_storage);
BOOST_LOG_TRIVIAL(info) << "Support generator - Creating raft"; BOOST_LOG_TRIVIAL(info) << "Support generator - Creating raft";
@ -324,11 +324,15 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
MyLayersPtr raft_layers = this->generate_raft_base(top_contacts, interface_layers, intermediate_layers, layer_storage); MyLayersPtr raft_layers = this->generate_raft_base(top_contacts, interface_layers, intermediate_layers, layer_storage);
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG
for (MyLayersPtr::const_iterator it = interface_layers.begin(); it != interface_layers.end(); ++ it) for (const MyLayer *l : interface_layers)
Slic3r::SVG::export_expolygons( Slic3r::SVG::export_expolygons(
debug_out_path("support-interface-layers-%d-%lf.svg", iRun, (*it)->print_z), debug_out_path("support-interface-layers-%d-%lf.svg", iRun, l->print_z),
union_ex((*it)->polygons, false)); union_ex(l->polygons, false));
#endif /* SLIC3R_DEBUG */ for (const MyLayer *l : base_interface_layers)
Slic3r::SVG::export_expolygons(
debug_out_path("support-base-interface-layers-%d-%lf.svg", iRun, l->print_z),
union_ex(l->polygons, false));
#endif // SLIC3R_DEBUG
/* /*
// Clip with the pillars. // Clip with the pillars.
@ -350,12 +354,13 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
// Install support layers into the object. // Install support layers into the object.
// A support layer installed on a PrintObject has a unique print_z. // A support layer installed on a PrintObject has a unique print_z.
MyLayersPtr layers_sorted; MyLayersPtr layers_sorted;
layers_sorted.reserve(raft_layers.size() + bottom_contacts.size() + top_contacts.size() + intermediate_layers.size() + interface_layers.size()); layers_sorted.reserve(raft_layers.size() + bottom_contacts.size() + top_contacts.size() + intermediate_layers.size() + interface_layers.size() + base_interface_layers.size());
layers_append(layers_sorted, raft_layers); layers_append(layers_sorted, raft_layers);
layers_append(layers_sorted, bottom_contacts); layers_append(layers_sorted, bottom_contacts);
layers_append(layers_sorted, top_contacts); layers_append(layers_sorted, top_contacts);
layers_append(layers_sorted, intermediate_layers); layers_append(layers_sorted, intermediate_layers);
layers_append(layers_sorted, interface_layers); 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. // 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(), MyLayersPtrCompare());
int layer_id = 0; int layer_id = 0;
@ -388,7 +393,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
BOOST_LOG_TRIVIAL(info) << "Support generator - Generating tool paths"; BOOST_LOG_TRIVIAL(info) << "Support generator - Generating tool paths";
// Generate the actual toolpaths and save them into each layer. // Generate the actual toolpaths and save them into each layer.
this->generate_toolpaths(object.support_layers(), raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers); this->generate_toolpaths(object.support_layers(), raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers);
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG
{ {
@ -1661,13 +1666,13 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
// If no vec item with Z value >= of an internal threshold of fn_higher_equal is found, return vec.size() // If no vec item with Z value >= of an internal threshold of fn_higher_equal is found, return vec.size()
// If the initial idx is size_t(-1), then use binary search. // If the initial idx is size_t(-1), then use binary search.
// Otherwise search linearly upwards. // Otherwise search linearly upwards.
template<typename IT, typename FN_HIGHER_EQUAL> template<typename IteratorType, typename IndexType, typename FN_HIGHER_EQUAL>
size_t idx_higher_or_equal(IT begin, IT end, size_t idx, FN_HIGHER_EQUAL fn_higher_equal) IndexType idx_higher_or_equal(IteratorType begin, IteratorType end, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal)
{ {
auto size = int(end - begin); auto size = int(end - begin);
if (size == 0) { if (size == 0) {
idx = 0; idx = 0;
} else if (idx == size_t(-1)) { } else if (idx == IndexType(-1)) {
// First of the batch of layers per thread pool invocation. Use binary search. // First of the batch of layers per thread pool invocation. Use binary search.
int idx_low = 0; int idx_low = 0;
int idx_high = std::max(0, size - 1); int idx_high = std::max(0, size - 1);
@ -1687,8 +1692,8 @@ size_t idx_higher_or_equal(IT begin, IT end, size_t idx, FN_HIGHER_EQUAL fn_high
} }
return idx; return idx;
} }
template<typename T, typename FN_HIGHER_EQUAL> template<typename T, typename IndexType, typename FN_HIGHER_EQUAL>
size_t idx_higher_or_equal(const std::vector<T>& vec, size_t idx, FN_HIGHER_EQUAL fn_higher_equal) IndexType idx_higher_or_equal(const std::vector<T>& vec, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal)
{ {
return idx_higher_or_equal(vec.begin(), vec.end(), idx, fn_higher_equal); return idx_higher_or_equal(vec.begin(), vec.end(), idx, fn_higher_equal);
} }
@ -1983,7 +1988,7 @@ void PrintObjectSupportMaterial::generate_base_layers(
Polygons polygons_new; Polygons polygons_new;
// Use the precomputed layer_support_areas. // Use the precomputed layer_support_areas.
idx_object_layer_above = std::max(0, idx_lower_or_equal(object.layers().begin(), object.layers().end(), idx_object_layer_above, idx_object_layer_above = std::max(0, idx_lower_or_equal(object.layers().begin(), object.layers().end(), idx_object_layer_above,
[&layer_intermediate](const Layer *layer){ return layer->print_z <= layer_intermediate.print_z + EPSILON; })); [&layer_intermediate](const Layer *layer){ return layer->print_z <= layer_intermediate.print_z + EPSILON; }));
polygons_new = layer_support_areas[idx_object_layer_above]; polygons_new = layer_support_areas[idx_object_layer_above];
@ -2249,8 +2254,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
return raft_layers; return raft_layers;
} }
// Convert some of the intermediate layers into top/bottom interface layers. // Convert some of the intermediate layers into top/bottom interface layers as well as base interface layers.
PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_interface_layers( std::pair<PrintObjectSupportMaterial::MyLayersPtr, PrintObjectSupportMaterial::MyLayersPtr> PrintObjectSupportMaterial::generate_interface_layers(
const MyLayersPtr &bottom_contacts, const MyLayersPtr &bottom_contacts,
const MyLayersPtr &top_contacts, const MyLayersPtr &top_contacts,
MyLayersPtr &intermediate_layers, MyLayersPtr &intermediate_layers,
@ -2258,73 +2263,125 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_int
{ {
// my $area_threshold = $self->interface_flow->scaled_spacing ** 2; // my $area_threshold = $self->interface_flow->scaled_spacing ** 2;
MyLayersPtr interface_layers; std::pair<MyLayersPtr, MyLayersPtr> base_and_interface_layers;
MyLayersPtr &interface_layers = base_and_interface_layers.first;
MyLayersPtr &base_interface_layers = base_and_interface_layers.second;
// distinguish between interface and base interface layers
// Contact layer is considered an interface layer, therefore run the following block only if support_material_interface_layers > 1. // Contact layer is considered an interface layer, therefore run the following block only if support_material_interface_layers > 1.
if (! intermediate_layers.empty() && m_object_config->support_material_interface_layers.value > 1) { // Contact layer needs a base_interface layer, therefore run the following block if support_material_interface_layers > 0, has soluble support and extruders are different.
bool soluble_interface_non_soluble_base =
// Zero z-gap between the overhangs and the support interface.
m_slicing_params.soluble_interface &&
// Interface extruder soluble.
m_object_config->support_material_interface_extruder.value > 0 && m_print_config->filament_soluble.get_at(m_object_config->support_material_interface_extruder.value - 1) &&
// Base extruder: Either "print with active extruder" not soluble.
(m_object_config->support_material_extruder.value == 0 || ! m_print_config->filament_soluble.get_at(m_object_config->support_material_extruder.value - 1));
int num_interface_layers = m_object_config->support_material_interface_layers.value;
int num_base_interface_layers = soluble_interface_non_soluble_base ? std::min(num_interface_layers / 2, 2) : 0;
if (! intermediate_layers.empty() && num_interface_layers > 1) {
// For all intermediate layers, collect top contact surfaces, which are not further than support_material_interface_layers. // For all intermediate layers, collect top contact surfaces, which are not further than support_material_interface_layers.
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start"; BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start";
// Since the intermediate layer index starts at zero the number of interface layer needs to be reduced by 1.
-- num_interface_layers;
int num_interface_layers_only = num_interface_layers - num_base_interface_layers;
interface_layers.assign(intermediate_layers.size(), nullptr); interface_layers.assign(intermediate_layers.size(), nullptr);
if (num_base_interface_layers)
base_interface_layers.assign(intermediate_layers.size(), nullptr);
tbb::spin_mutex layer_storage_mutex; tbb::spin_mutex layer_storage_mutex;
tbb::parallel_for(tbb::blocked_range<size_t>(0, intermediate_layers.size()), // Insert a new layer into base_interface_layers, if intersection with base exists.
[this, &bottom_contacts, &top_contacts, &intermediate_layers, &layer_storage, &layer_storage_mutex, &interface_layers](const tbb::blocked_range<size_t>& range) { auto insert_layer = [&layer_storage, &layer_storage_mutex](MyLayer &intermediate_layer, Polygons &bottom, Polygons &&top, const Polygons *subtract, SupporLayerType type) {
assert(! bottom.empty() || ! top.empty());
MyLayer &layer_new = layer_allocate(layer_storage, layer_storage_mutex, type);
layer_new.print_z = intermediate_layer.print_z;
layer_new.bottom_z = intermediate_layer.bottom_z;
layer_new.height = intermediate_layer.height;
layer_new.bridging = intermediate_layer.bridging;
// Merge top into bottom, unite them with a safety offset.
append(bottom, std::move(top));
layer_new.polygons = union_(std::move(bottom), true);
// Subtract the interface from the base regions.
intermediate_layer.polygons = diff(intermediate_layer.polygons, layer_new.polygons, false);
if (subtract)
// Trim the base interface layer with the interface layer.
layer_new.polygons = diff(std::move(layer_new.polygons), *subtract);
//FIXME filter layer_new.polygons islands by a minimum area?
// $interface_area = [ grep abs($_->area) >= $area_threshold, @$interface_area ];
return &layer_new;
};
tbb::parallel_for(tbb::blocked_range<int>(0, int(intermediate_layers.size())),
[&bottom_contacts, &top_contacts, &intermediate_layers, &insert_layer, num_interface_layers, num_base_interface_layers, num_interface_layers_only,
&interface_layers, &base_interface_layers](const tbb::blocked_range<int>& range) {
// Gather the top / bottom contact layers intersecting with num_interface_layers resp. num_interface_layers_only intermediate layers above / below
// this intermediate layer.
// Index of the first top contact layer intersecting the current intermediate layer. // Index of the first top contact layer intersecting the current intermediate layer.
size_t idx_top_contact_first = size_t(-1); auto idx_top_contact_first = -1;
// Index of the first bottom contact layer intersecting the current intermediate layer. // Index of the first bottom contact layer intersecting the current intermediate layer.
size_t idx_bottom_contact_first = size_t(-1); auto idx_bottom_contact_first = -1;
for (size_t idx_intermediate_layer = range.begin(); idx_intermediate_layer < range.end(); ++ idx_intermediate_layer) { auto num_intermediate = int(intermediate_layers.size());
for (int idx_intermediate_layer = range.begin(); idx_intermediate_layer < range.end(); ++ idx_intermediate_layer) {
MyLayer &intermediate_layer = *intermediate_layers[idx_intermediate_layer]; MyLayer &intermediate_layer = *intermediate_layers[idx_intermediate_layer];
// Top / bottom Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces. // Top / bottom Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces
coordf_t top_z = intermediate_layers[std::min<int>(intermediate_layers.size()-1, idx_intermediate_layer + m_object_config->support_material_interface_layers - 1)]->print_z; coordf_t top_z = intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + num_interface_layers - 1)]->print_z;
coordf_t bottom_z = intermediate_layers[std::max<int>(0, int(idx_intermediate_layer) - int(m_object_config->support_material_interface_layers) + 1)]->bottom_z; coordf_t top_inteface_z = std::numeric_limits<coordf_t>::max();
coordf_t bottom_z = intermediate_layers[std::max(0, idx_intermediate_layer - num_interface_layers + 1)]->bottom_z;
coordf_t bottom_interface_z = - std::numeric_limits<coordf_t>::max();
if (num_base_interface_layers > 0) {
// Some base interface layers will be generated.
if (num_interface_layers_only == 0)
// Only base interface layers to generate.
std::swap(top_inteface_z, bottom_interface_z);
else {
top_inteface_z = intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + num_interface_layers_only - 1)]->print_z;
bottom_interface_z = intermediate_layers[std::max(0, idx_intermediate_layer - num_interface_layers_only)]->bottom_z;
}
}
// Move idx_top_contact_first up until above the current print_z. // Move idx_top_contact_first up until above the current print_z.
idx_top_contact_first = idx_higher_or_equal(top_contacts, idx_top_contact_first, [&intermediate_layer](const MyLayer *layer){ return layer->print_z >= intermediate_layer.print_z; }); // - EPSILON idx_top_contact_first = idx_higher_or_equal(top_contacts, idx_top_contact_first, [&intermediate_layer](const MyLayer *layer){ return layer->print_z >= intermediate_layer.print_z; }); // - EPSILON
// Collect the top contact areas above this intermediate layer, below top_z. // Collect the top contact areas above this intermediate layer, below top_z.
Polygons polygons_top_contact_projected; Polygons polygons_top_contact_projected_interface;
for (size_t idx_top_contact = idx_top_contact_first; idx_top_contact < top_contacts.size(); ++ idx_top_contact) { Polygons polygons_top_contact_projected_base;
for (int idx_top_contact = idx_top_contact_first; idx_top_contact < int(top_contacts.size()); ++ idx_top_contact) {
const MyLayer &top_contact_layer = *top_contacts[idx_top_contact]; const MyLayer &top_contact_layer = *top_contacts[idx_top_contact];
//FIXME maybe this adds one interface layer in excess? //FIXME maybe this adds one interface layer in excess?
if (top_contact_layer.bottom_z - EPSILON > top_z) if (top_contact_layer.bottom_z - EPSILON > top_z)
break; break;
polygons_append(polygons_top_contact_projected, top_contact_layer.polygons); polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface, top_contact_layer.polygons);
} }
// Move idx_bottom_contact_first up until touching bottom_z. // Move idx_bottom_contact_first up until touching bottom_z.
idx_bottom_contact_first = idx_higher_or_equal(bottom_contacts, idx_bottom_contact_first, [bottom_z](const MyLayer *layer){ return layer->print_z >= bottom_z - EPSILON; }); idx_bottom_contact_first = idx_higher_or_equal(bottom_contacts, idx_bottom_contact_first, [bottom_z](const MyLayer *layer){ return layer->print_z >= bottom_z - EPSILON; });
// Collect the top contact areas above this intermediate layer, below top_z. // Collect the top contact areas above this intermediate layer, below top_z.
Polygons polygons_bottom_contact_projected; Polygons polygons_bottom_contact_projected_interface;
for (size_t idx_bottom_contact = idx_bottom_contact_first; idx_bottom_contact < bottom_contacts.size(); ++ idx_bottom_contact) { Polygons polygons_bottom_contact_projected_base;
for (int idx_bottom_contact = idx_bottom_contact_first; idx_bottom_contact < int(bottom_contacts.size()); ++ idx_bottom_contact) {
const MyLayer &bottom_contact_layer = *bottom_contacts[idx_bottom_contact]; const MyLayer &bottom_contact_layer = *bottom_contacts[idx_bottom_contact];
if (bottom_contact_layer.print_z - EPSILON > intermediate_layer.bottom_z) if (bottom_contact_layer.print_z - EPSILON > intermediate_layer.bottom_z)
break; break;
polygons_append(polygons_bottom_contact_projected, bottom_contact_layer.polygons); polygons_append(bottom_contact_layer.print_z - EPSILON > bottom_interface_z ? polygons_bottom_contact_projected_interface : polygons_bottom_contact_projected_base, bottom_contact_layer.polygons);
} }
if (polygons_top_contact_projected.empty() && polygons_bottom_contact_projected.empty()) MyLayer *interface_layer = nullptr;
continue; if (! polygons_bottom_contact_projected_interface.empty() || ! polygons_top_contact_projected_interface.empty()) {
interface_layer = insert_layer(
// Insert a new layer into top_interface_layers. intermediate_layer, polygons_bottom_contact_projected_interface, std::move(polygons_top_contact_projected_interface), nullptr,
MyLayer &layer_new = layer_allocate(layer_storage, layer_storage_mutex, polygons_top_contact_projected_interface.empty() ? sltBottomInterface : sltTopInterface);
polygons_top_contact_projected.empty() ? sltBottomInterface : sltTopInterface); interface_layers[idx_intermediate_layer] = interface_layer;
layer_new.print_z = intermediate_layer.print_z; }
layer_new.bottom_z = intermediate_layer.bottom_z; if (! polygons_bottom_contact_projected_base.empty() || ! polygons_top_contact_projected_base.empty())
layer_new.height = intermediate_layer.height; base_interface_layers[idx_intermediate_layer] = insert_layer(
layer_new.bridging = intermediate_layer.bridging; intermediate_layer, polygons_bottom_contact_projected_base, std::move(polygons_top_contact_projected_base),
interface_layers[idx_intermediate_layer] = &layer_new; interface_layer ? &interface_layer->polygons : nullptr, sltBase);
polygons_append(polygons_top_contact_projected, polygons_bottom_contact_projected);
polygons_top_contact_projected = union_(polygons_top_contact_projected, true);
layer_new.polygons = intersection(intermediate_layer.polygons, polygons_top_contact_projected);
//FIXME filter layer_new.polygons islands by a minimum area?
// $interface_area = [ grep abs($_->area) >= $area_threshold, @$interface_area ];
intermediate_layer.polygons = diff(intermediate_layer.polygons, polygons_top_contact_projected, false);
} }
}); });
// Compress contact_out, remove the nullptr items. // Compress contact_out, remove the nullptr items.
remove_nulls(interface_layers); remove_nulls(interface_layers);
remove_nulls(base_interface_layers);
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start"; BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start";
} }
return interface_layers; return base_and_interface_layers;
} }
static inline void fill_expolygons_generate_paths( static inline void fill_expolygons_generate_paths(
@ -2373,9 +2430,9 @@ struct MyLayerExtruded
const Polygons& polygons_to_extrude() const { return (m_polygons_to_extrude == nullptr) ? layer->polygons : *m_polygons_to_extrude; } const Polygons& polygons_to_extrude() const { return (m_polygons_to_extrude == nullptr) ? layer->polygons : *m_polygons_to_extrude; }
bool could_merge(const MyLayerExtruded &other) const { bool could_merge(const MyLayerExtruded &other) const {
return ! this->empty() && ! other.empty() && return ! this->empty() && ! other.empty() &&
std::abs(this->layer->height - other.layer->height) < EPSILON && std::abs(this->layer->height - other.layer->height) < EPSILON &&
this->layer->bridging == other.layer->bridging; this->layer->bridging == other.layer->bridging;
} }
// Merge regions, perform boolean union over the merged polygons. // Merge regions, perform boolean union over the merged polygons.
@ -2921,7 +2978,8 @@ void PrintObjectSupportMaterial::generate_toolpaths(
const MyLayersPtr &bottom_contacts, const MyLayersPtr &bottom_contacts,
const MyLayersPtr &top_contacts, const MyLayersPtr &top_contacts,
const MyLayersPtr &intermediate_layers, const MyLayersPtr &intermediate_layers,
const MyLayersPtr &interface_layers) const const MyLayersPtr &interface_layers,
const MyLayersPtr &base_interface_layers) const
{ {
// Slic3r::debugf "Generating patterns\n"; // Slic3r::debugf "Generating patterns\n";
// loop_interface_processor with a given circle radius. // loop_interface_processor with a given circle radius.
@ -2985,7 +3043,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// Insert the raft base layers. // Insert the raft base layers.
size_t n_raft_layers = size_t(std::max(0, int(m_slicing_params.raft_layers()) - 1)); size_t n_raft_layers = size_t(std::max(0, int(m_slicing_params.raft_layers()) - 1));
tbb::parallel_for(tbb::blocked_range<size_t>(0, n_raft_layers), tbb::parallel_for(tbb::blocked_range<size_t>(0, n_raft_layers),
[this, &support_layers, &raft_layers, [this, &support_layers, &raft_layers,
infill_pattern, &bbox_object, support_density, interface_density, raft_angle_1st_layer, raft_angle_base, raft_angle_interface, link_max_length_factor, with_sheath] infill_pattern, &bbox_object, support_density, interface_density, raft_angle_1st_layer, raft_angle_base, raft_angle_interface, link_max_length_factor, with_sheath]
(const tbb::blocked_range<size_t>& range) { (const tbb::blocked_range<size_t>& range) {
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id)
@ -3085,22 +3143,27 @@ void PrintObjectSupportMaterial::generate_toolpaths(
MyLayerExtruded top_contact_layer; MyLayerExtruded top_contact_layer;
MyLayerExtruded base_layer; MyLayerExtruded base_layer;
MyLayerExtruded interface_layer; MyLayerExtruded interface_layer;
MyLayerExtruded base_interface_layer;
std::vector<LayerCacheItem> overlaps; std::vector<LayerCacheItem> overlaps;
}; };
std::vector<LayerCache> layer_caches(support_layers.size(), LayerCache()); std::vector<LayerCache> layer_caches(support_layers.size(), LayerCache());
tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, support_layers.size()), tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, support_layers.size()),
[this, &support_layers, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &layer_caches, &loop_interface_processor, [this, &support_layers, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &base_interface_layers, &layer_caches, &loop_interface_processor,
infill_pattern, &bbox_object, support_density, interface_density, interface_angle, &angles, link_max_length_factor, with_sheath] infill_pattern, &bbox_object, support_density, interface_density, interface_angle, &angles, link_max_length_factor, with_sheath]
(const tbb::blocked_range<size_t>& range) { (const tbb::blocked_range<size_t>& range) {
// Indices of the 1st layer in their respective container at the support layer height. // Indices of the 1st layer in their respective container at the support layer height.
size_t idx_layer_bottom_contact = size_t(-1); size_t idx_layer_bottom_contact = size_t(-1);
size_t idx_layer_top_contact = size_t(-1); size_t idx_layer_top_contact = size_t(-1);
size_t idx_layer_intermediate = size_t(-1); size_t idx_layer_intermediate = size_t(-1);
size_t idx_layer_inteface = size_t(-1); size_t idx_layer_interface = size_t(-1);
std::unique_ptr<Fill> filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(m_slicing_params.soluble_interface ? ipConcentric : ipRectilinear)); size_t idx_layer_base_interface = size_t(-1);
std::unique_ptr<Fill> filler_support = std::unique_ptr<Fill>(Fill::new_from_type(infill_pattern)); auto filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(m_slicing_params.soluble_interface ? ipConcentric : ipRectilinear));
auto filler_base_interface = std::unique_ptr<Fill>(base_interface_layers.empty() ? nullptr : Fill::new_from_type(ipRectilinear));
auto filler_support = std::unique_ptr<Fill>(Fill::new_from_type(infill_pattern));
filler_interface->set_bounding_box(bbox_object); filler_interface->set_bounding_box(bbox_object);
if (filler_base_interface)
filler_base_interface->set_bounding_box(bbox_object);
filler_support->set_bounding_box(bbox_object); filler_support->set_bounding_box(bbox_object);
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id)
{ {
@ -3112,21 +3175,25 @@ void PrintObjectSupportMaterial::generate_toolpaths(
MyLayerExtruded &top_contact_layer = layer_cache.top_contact_layer; MyLayerExtruded &top_contact_layer = layer_cache.top_contact_layer;
MyLayerExtruded &base_layer = layer_cache.base_layer; MyLayerExtruded &base_layer = layer_cache.base_layer;
MyLayerExtruded &interface_layer = layer_cache.interface_layer; MyLayerExtruded &interface_layer = layer_cache.interface_layer;
MyLayerExtruded &base_interface_layer = layer_cache.base_interface_layer;
// Increment the layer indices to find a layer at support_layer.print_z. // Increment the layer indices to find a layer at support_layer.print_z.
{ {
auto fun = [&support_layer](const MyLayer *l){ return l->print_z >= support_layer.print_z - EPSILON; }; auto fun = [&support_layer](const MyLayer *l){ return l->print_z >= support_layer.print_z - EPSILON; };
idx_layer_bottom_contact = idx_higher_or_equal(bottom_contacts, idx_layer_bottom_contact, fun); idx_layer_bottom_contact = idx_higher_or_equal(bottom_contacts, idx_layer_bottom_contact, fun);
idx_layer_top_contact = idx_higher_or_equal(top_contacts, idx_layer_top_contact, fun); idx_layer_top_contact = idx_higher_or_equal(top_contacts, idx_layer_top_contact, fun);
idx_layer_intermediate = idx_higher_or_equal(intermediate_layers, idx_layer_intermediate, fun); idx_layer_intermediate = idx_higher_or_equal(intermediate_layers, idx_layer_intermediate, fun);
idx_layer_inteface = idx_higher_or_equal(interface_layers, idx_layer_inteface, fun); idx_layer_interface = idx_higher_or_equal(interface_layers, idx_layer_interface, fun);
idx_layer_base_interface = idx_higher_or_equal(base_interface_layers, idx_layer_base_interface,fun);
} }
// Copy polygons from the layers. // Copy polygons from the layers.
if (idx_layer_bottom_contact < bottom_contacts.size() && bottom_contacts[idx_layer_bottom_contact]->print_z < support_layer.print_z + EPSILON) if (idx_layer_bottom_contact < bottom_contacts.size() && bottom_contacts[idx_layer_bottom_contact]->print_z < support_layer.print_z + EPSILON)
bottom_contact_layer.layer = bottom_contacts[idx_layer_bottom_contact]; bottom_contact_layer.layer = bottom_contacts[idx_layer_bottom_contact];
if (idx_layer_top_contact < top_contacts.size() && top_contacts[idx_layer_top_contact]->print_z < support_layer.print_z + EPSILON) if (idx_layer_top_contact < top_contacts.size() && top_contacts[idx_layer_top_contact]->print_z < support_layer.print_z + EPSILON)
top_contact_layer.layer = top_contacts[idx_layer_top_contact]; top_contact_layer.layer = top_contacts[idx_layer_top_contact];
if (idx_layer_inteface < interface_layers.size() && interface_layers[idx_layer_inteface]->print_z < support_layer.print_z + EPSILON) if (idx_layer_interface < interface_layers.size() && interface_layers[idx_layer_interface]->print_z < support_layer.print_z + EPSILON)
interface_layer.layer = interface_layers[idx_layer_inteface]; interface_layer.layer = interface_layers[idx_layer_interface];
if (idx_layer_base_interface < base_interface_layers.size() && base_interface_layers[idx_layer_base_interface]->print_z < support_layer.print_z + EPSILON)
base_interface_layer.layer = base_interface_layers[idx_layer_base_interface];
if (idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate]->print_z < support_layer.print_z + EPSILON) if (idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate]->print_z < support_layer.print_z + EPSILON)
base_layer.layer = intermediate_layers[idx_layer_intermediate]; base_layer.layer = intermediate_layers[idx_layer_intermediate];
@ -3151,7 +3218,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
top_contact_layer.merge(std::move(interface_layer)); top_contact_layer.merge(std::move(interface_layer));
} }
if (! interface_layer.empty() && ! base_layer.empty()) { if ( ! interface_layer.empty() && ! base_layer.empty()) {
// turn base support into interface when it's contained in our holes // turn base support into interface when it's contained in our holes
// (this way we get wider interface anchoring) // (this way we get wider interface anchoring)
//FIXME one wants to fill in the inner most holes of the interfaces, not all the holes. //FIXME one wants to fill in the inner most holes of the interfaces, not all the holes.
@ -3192,6 +3259,31 @@ void PrintObjectSupportMaterial::generate_toolpaths(
erSupportMaterialInterface, interface_flow); erSupportMaterialInterface, interface_flow);
} }
// Base interface layers under soluble interfaces
if ( ! base_interface_layer.empty() && ! base_interface_layer.polygons_to_extrude().empty()){
Fill *filler = filler_base_interface.get();
//FIXME Bottom interfaces are extruded with the briding flow. Some bridging layers have its height slightly reduced, therefore
// the bridging flow does not quite apply. Reduce the flow to area of an ellipse? (A = pi * a * b)
Flow interface_flow(
float(base_interface_layer.layer->bridging ? base_interface_layer.layer->height : m_support_material_flow.width), // m_support_material_interface_flow.width)),
float(base_interface_layer.layer->height),
m_support_material_flow.nozzle_diameter,
base_interface_layer.layer->bridging);
filler->angle = interface_angle;
filler->spacing = m_support_material_interface_flow.spacing();
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / interface_density));
fill_expolygons_generate_paths(
// Destination
base_interface_layer.extrusions,
//base_layer_interface.extrusions,
// Regions to fill
union_ex(base_interface_layer.polygons_to_extrude(), true),
// Filler and its parameters
filler, float(interface_density),
// Extrusion parameters
erSupportMaterial, interface_flow);
}
// Base support or flange. // Base support or flange.
if (! base_layer.empty() && ! base_layer.polygons_to_extrude().empty()) { if (! base_layer.empty() && ! base_layer.polygons_to_extrude().empty()) {
//FIXME When paralellizing, each thread shall have its own copy of the fillers. //FIXME When paralellizing, each thread shall have its own copy of the fillers.
@ -3245,13 +3337,20 @@ void PrintObjectSupportMaterial::generate_toolpaths(
erSupportMaterial, flow); erSupportMaterial, flow);
} }
layer_cache.overlaps.reserve(4); // Merge base_interface_layers to base_layers to avoid unneccessary retractions
if (! base_layer.empty() && ! base_interface_layer.empty() && ! base_layer.polygons_to_extrude().empty() && ! base_interface_layer.polygons_to_extrude().empty() &&
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()) if (! bottom_contact_layer.empty())
layer_cache.overlaps.push_back(&bottom_contact_layer); layer_cache.overlaps.push_back(&bottom_contact_layer);
if (! top_contact_layer.empty()) if (! top_contact_layer.empty())
layer_cache.overlaps.push_back(&top_contact_layer); layer_cache.overlaps.push_back(&top_contact_layer);
if (! interface_layer.empty()) if (! interface_layer.empty())
layer_cache.overlaps.push_back(&interface_layer); layer_cache.overlaps.push_back(&interface_layer);
if (! base_interface_layer.empty())
layer_cache.overlaps.push_back(&base_interface_layer);
if (! base_layer.empty()) if (! base_layer.empty())
layer_cache.overlaps.push_back(&base_layer); layer_cache.overlaps.push_back(&base_layer);
// Sort the layers with the same print_z coordinate by their heights, thickest first. // Sort the layers with the same print_z coordinate by their heights, thickest first.
@ -3272,7 +3371,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// where it overlaps with another support layer. // where it overlaps with another support layer.
//FIXME When printing a briging path, what is an equivalent height of the squished extrudate of the same width? //FIXME When printing a briging path, what is an equivalent height of the squished extrudate of the same width?
// Collect overlapping top/bottom surfaces. // Collect overlapping top/bottom surfaces.
layer_cache_item.overlapping.reserve(16); layer_cache_item.overlapping.reserve(20);
coordf_t bottom_z = layer_cache_item.layer_extruded->layer->bottom_print_z() + EPSILON; 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) 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]); layer_cache_item.overlapping.push_back(bottom_contacts[i]);
@ -3282,8 +3381,10 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// Bottom contact layer may overlap with a base layer, which may be changed to interface layer. // 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) 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]); layer_cache_item.overlapping.push_back(intermediate_layers[i]);
for (int i = int(idx_layer_inteface) - 1; i >= 0 && interface_layers[i]->print_z > bottom_z; -- 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]); 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]);
} }
std::sort(layer_cache_item.overlapping.begin(), layer_cache_item.overlapping.end(), MyLayersPtrCompare()); std::sort(layer_cache_item.overlapping.begin(), layer_cache_item.overlapping.end(), MyLayersPtrCompare());
} }
@ -3406,7 +3507,7 @@ sub clip_with_shape {
foreach my $i (keys %$support) { foreach my $i (keys %$support) {
// don't clip bottom layer with shape so that we // don't clip bottom layer with shape so that we
// can generate a continuous base flange // can generate a continuous base flange
// also don't clip raft layers // also don't clip raft layers
next if $i == 0; next if $i == 0;
next if $i < $self->object_config->raft_layers; next if $i < $self->object_config->raft_layers;

View file

@ -201,12 +201,15 @@ private:
const MyLayersPtr &base_layers, const MyLayersPtr &base_layers,
MyLayerStorage &layer_storage) const; MyLayerStorage &layer_storage) const;
// Turn some of the base layers into interface layers. // Turn some of the base layers into base interface layers.
MyLayersPtr generate_interface_layers( // For soluble interfaces with non-soluble bases, print maximum two first interface layers with the base
// extruder to improve adhesion of the soluble filament to the base.
std::pair<MyLayersPtr, MyLayersPtr> generate_interface_layers(
const MyLayersPtr &bottom_contacts, const MyLayersPtr &bottom_contacts,
const MyLayersPtr &top_contacts, const MyLayersPtr &top_contacts,
MyLayersPtr &intermediate_layers, MyLayersPtr &intermediate_layers,
MyLayerStorage &layer_storage) const; MyLayerStorage &layer_storage) const;
// Trim support layers by an object to leave a defined gap between // Trim support layers by an object to leave a defined gap between
// the support volume and the object. // the support volume and the object.
@ -224,12 +227,13 @@ private:
// Produce the actual G-code. // Produce the actual G-code.
void generate_toolpaths( void generate_toolpaths(
SupportLayerPtrs &support_layers, SupportLayerPtrs &support_layers,
const MyLayersPtr &raft_layers, const MyLayersPtr &raft_layers,
const MyLayersPtr &bottom_contacts, const MyLayersPtr &bottom_contacts,
const MyLayersPtr &top_contacts, const MyLayersPtr &top_contacts,
const MyLayersPtr &intermediate_layers, const MyLayersPtr &intermediate_layers,
const MyLayersPtr &interface_layers) const; const MyLayersPtr &interface_layers,
const MyLayersPtr &base_interface_layers) const;
// Following objects are not owned by SupportMaterial class. // Following objects are not owned by SupportMaterial class.
const PrintObject *m_object; const PrintObject *m_object;
@ -246,7 +250,7 @@ private:
bool m_can_merge_support_regions; bool m_can_merge_support_regions;
coordf_t m_support_layer_height_min; coordf_t m_support_layer_height_min;
// coordf_t m_support_layer_height_max; // coordf_t m_support_layer_height_max;
coordf_t m_gap_xy; coordf_t m_gap_xy;
}; };