diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 64a716508..e10b26f38 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -710,7 +710,7 @@ namespace Slic3r { #endif // ENABLE_RELOAD_FROM_DISK_FOR_3MF 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"); return false; } @@ -1395,7 +1395,7 @@ namespace Slic3r { { // deletes all non-built or non-instanced 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"); return false; } diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 17e463b70..7ba0b5e8f 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -291,7 +291,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) 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); #ifdef SLIC3R_DEBUG @@ -312,9 +312,9 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) BOOST_LOG_TRIVIAL(info) << "Support generator - Creating interfaces"; - // Propagate top / bottom contact layers to generate interface layers. - MyLayersPtr interface_layers = this->generate_interface_layers( - bottom_contacts, top_contacts, intermediate_layers, layer_storage); + // Propagate top / bottom contact layers to generate interface layers + // and base interface layers (for soluble interface / non souble base only) + 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"; @@ -324,11 +324,15 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) MyLayersPtr raft_layers = this->generate_raft_base(top_contacts, interface_layers, intermediate_layers, layer_storage); #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( - debug_out_path("support-interface-layers-%d-%lf.svg", iRun, (*it)->print_z), - union_ex((*it)->polygons, false)); -#endif /* SLIC3R_DEBUG */ + debug_out_path("support-interface-layers-%d-%lf.svg", iRun, l->print_z), + union_ex(l->polygons, false)); + 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. @@ -350,12 +354,13 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) // Install support layers into the object. // A support layer installed on a PrintObject has a unique print_z. 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, bottom_contacts); layers_append(layers_sorted, top_contacts); layers_append(layers_sorted, intermediate_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. std::sort(layers_sorted.begin(), layers_sorted.end(), MyLayersPtrCompare()); int layer_id = 0; @@ -388,7 +393,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) BOOST_LOG_TRIVIAL(info) << "Support generator - Generating tool paths"; // 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 { @@ -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 the initial idx is size_t(-1), then use binary search. // Otherwise search linearly upwards. -template<typename IT, typename FN_HIGHER_EQUAL> -size_t idx_higher_or_equal(IT begin, IT end, size_t idx, FN_HIGHER_EQUAL fn_higher_equal) +template<typename IteratorType, typename IndexType, typename 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); if (size == 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. int idx_low = 0; 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; } -template<typename T, typename FN_HIGHER_EQUAL> -size_t idx_higher_or_equal(const std::vector<T>& vec, size_t idx, FN_HIGHER_EQUAL fn_higher_equal) +template<typename T, typename IndexType, typename 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); } @@ -1983,7 +1988,7 @@ void PrintObjectSupportMaterial::generate_base_layers( Polygons polygons_new; // 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; })); polygons_new = layer_support_areas[idx_object_layer_above]; @@ -2249,8 +2254,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf return raft_layers; } -// Convert some of the intermediate layers into top/bottom interface layers. -PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_interface_layers( +// Convert some of the intermediate layers into top/bottom interface layers as well as base interface layers. +std::pair<PrintObjectSupportMaterial::MyLayersPtr, PrintObjectSupportMaterial::MyLayersPtr> PrintObjectSupportMaterial::generate_interface_layers( const MyLayersPtr &bottom_contacts, const MyLayersPtr &top_contacts, MyLayersPtr &intermediate_layers, @@ -2258,73 +2263,125 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_int { // 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. - 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. 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); + if (num_base_interface_layers) + base_interface_layers.assign(intermediate_layers.size(), nullptr); tbb::spin_mutex layer_storage_mutex; - tbb::parallel_for(tbb::blocked_range<size_t>(0, intermediate_layers.size()), - [this, &bottom_contacts, &top_contacts, &intermediate_layers, &layer_storage, &layer_storage_mutex, &interface_layers](const tbb::blocked_range<size_t>& range) { + // Insert a new layer into base_interface_layers, if intersection with base exists. + 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. - 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. - size_t idx_bottom_contact_first = size_t(-1); - for (size_t idx_intermediate_layer = range.begin(); idx_intermediate_layer < range.end(); ++ idx_intermediate_layer) { + auto idx_bottom_contact_first = -1; + 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]; - // 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 bottom_z = intermediate_layers[std::max<int>(0, int(idx_intermediate_layer) - int(m_object_config->support_material_interface_layers) + 1)]->bottom_z; + // 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(num_intermediate - 1, idx_intermediate_layer + num_interface_layers - 1)]->print_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. 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. - Polygons polygons_top_contact_projected; - for (size_t idx_top_contact = idx_top_contact_first; idx_top_contact < top_contacts.size(); ++ idx_top_contact) { + Polygons polygons_top_contact_projected_interface; + 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]; //FIXME maybe this adds one interface layer in excess? if (top_contact_layer.bottom_z - EPSILON > top_z) 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. 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. - Polygons polygons_bottom_contact_projected; - for (size_t idx_bottom_contact = idx_bottom_contact_first; idx_bottom_contact < bottom_contacts.size(); ++ idx_bottom_contact) { + Polygons polygons_bottom_contact_projected_interface; + 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]; if (bottom_contact_layer.print_z - EPSILON > intermediate_layer.bottom_z) 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()) - continue; - - // Insert a new layer into top_interface_layers. - MyLayer &layer_new = layer_allocate(layer_storage, layer_storage_mutex, - polygons_top_contact_projected.empty() ? sltBottomInterface : sltTopInterface); - 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; - interface_layers[idx_intermediate_layer] = &layer_new; - - 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); + MyLayer *interface_layer = nullptr; + if (! polygons_bottom_contact_projected_interface.empty() || ! polygons_top_contact_projected_interface.empty()) { + interface_layer = insert_layer( + intermediate_layer, polygons_bottom_contact_projected_interface, std::move(polygons_top_contact_projected_interface), nullptr, + polygons_top_contact_projected_interface.empty() ? sltBottomInterface : sltTopInterface); + interface_layers[idx_intermediate_layer] = interface_layer; + } + if (! polygons_bottom_contact_projected_base.empty() || ! polygons_top_contact_projected_base.empty()) + base_interface_layers[idx_intermediate_layer] = insert_layer( + intermediate_layer, polygons_bottom_contact_projected_base, std::move(polygons_top_contact_projected_base), + interface_layer ? &interface_layer->polygons : nullptr, sltBase); } }); // Compress contact_out, remove the nullptr items. remove_nulls(interface_layers); + remove_nulls(base_interface_layers); 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( @@ -2373,9 +2430,9 @@ struct MyLayerExtruded 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 { - return ! this->empty() && ! other.empty() && + return ! this->empty() && ! other.empty() && 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. @@ -2921,7 +2978,8 @@ void PrintObjectSupportMaterial::generate_toolpaths( const MyLayersPtr &bottom_contacts, const MyLayersPtr &top_contacts, const MyLayersPtr &intermediate_layers, - const MyLayersPtr &interface_layers) const + const MyLayersPtr &interface_layers, + const MyLayersPtr &base_interface_layers) const { // Slic3r::debugf "Generating patterns\n"; // loop_interface_processor with a given circle radius. @@ -2985,7 +3043,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // Insert the raft base layers. 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), - [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] (const tbb::blocked_range<size_t>& range) { 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 base_layer; MyLayerExtruded interface_layer; + MyLayerExtruded base_interface_layer; std::vector<LayerCacheItem> overlaps; }; std::vector<LayerCache> layer_caches(support_layers.size(), LayerCache()); 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] (const tbb::blocked_range<size_t>& range) { // 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_top_contact = size_t(-1); size_t idx_layer_intermediate = size_t(-1); - size_t idx_layer_inteface = size_t(-1); - std::unique_ptr<Fill> filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(m_slicing_params.soluble_interface ? ipConcentric : ipRectilinear)); - std::unique_ptr<Fill> filler_support = std::unique_ptr<Fill>(Fill::new_from_type(infill_pattern)); + size_t idx_layer_interface = size_t(-1); + size_t idx_layer_base_interface = size_t(-1); + 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); + if (filler_base_interface) + filler_base_interface->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) { @@ -3112,21 +3175,25 @@ void PrintObjectSupportMaterial::generate_toolpaths( MyLayerExtruded &top_contact_layer = layer_cache.top_contact_layer; MyLayerExtruded &base_layer = layer_cache.base_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. { 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_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_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. 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]; 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]; - if (idx_layer_inteface < interface_layers.size() && interface_layers[idx_layer_inteface]->print_z < support_layer.print_z + EPSILON) - interface_layer.layer = interface_layers[idx_layer_inteface]; + 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_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) base_layer.layer = intermediate_layers[idx_layer_intermediate]; @@ -3151,7 +3218,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( 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 // (this way we get wider interface anchoring) //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); } + // 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. if (! base_layer.empty() && ! base_layer.polygons_to_extrude().empty()) { //FIXME When paralellizing, each thread shall have its own copy of the fillers. @@ -3245,13 +3337,20 @@ void PrintObjectSupportMaterial::generate_toolpaths( 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()) 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. @@ -3272,7 +3371,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // 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? // 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; 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]); @@ -3282,8 +3381,10 @@ void PrintObjectSupportMaterial::generate_toolpaths( // 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_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]); + 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()); } @@ -3406,7 +3507,7 @@ sub clip_with_shape { foreach my $i (keys %$support) { // 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 next if $i == 0; next if $i < $self->object_config->raft_layers; diff --git a/src/libslic3r/SupportMaterial.hpp b/src/libslic3r/SupportMaterial.hpp index e579fd66f..030d2219a 100644 --- a/src/libslic3r/SupportMaterial.hpp +++ b/src/libslic3r/SupportMaterial.hpp @@ -201,12 +201,15 @@ private: const MyLayersPtr &base_layers, MyLayerStorage &layer_storage) const; - // Turn some of the base layers into interface layers. - MyLayersPtr generate_interface_layers( + // Turn some of the base layers into base 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 &top_contacts, MyLayersPtr &intermediate_layers, MyLayerStorage &layer_storage) const; + // Trim support layers by an object to leave a defined gap between // the support volume and the object. @@ -224,12 +227,13 @@ private: // Produce the actual G-code. void generate_toolpaths( - SupportLayerPtrs &support_layers, + SupportLayerPtrs &support_layers, const MyLayersPtr &raft_layers, const MyLayersPtr &bottom_contacts, const MyLayersPtr &top_contacts, 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. const PrintObject *m_object; @@ -246,7 +250,7 @@ private: bool m_can_merge_support_regions; 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; };