diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index e6bf4b4fc0..60440de97f 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -188,17 +188,23 @@ public: // Extrusion paths for the support base and for the support interface and contacts. ExtrusionEntityCollection support_fills; + // Is there any valid extrusion assigned to this LayerRegion? virtual bool has_extrusions() const { return ! support_fills.empty(); } + // Zero based index of an interface layer, used for alternating direction of interface / contact layers. + size_t interface_id() const { return m_interface_id; } + protected: friend class PrintObject; // The constructor has been made public to be able to insert additional support layers for the skirt or a wipe tower // between the raft and the object first layer. - SupportLayer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) : - Layer(id, object, height, print_z, slice_z) {} + SupportLayer(size_t id, size_t interface_id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) : + Layer(id, object, height, print_z, slice_z), m_interface_id(interface_id) {} virtual ~SupportLayer() = default; + + size_t m_interface_id; }; template diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index b33e8bda23..03a3d1e575 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1139,7 +1139,7 @@ void Print::_make_wipe_tower() // Insert the new support layer. double height = lt.print_z - (i == 0 ? 0. : m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z); //FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway. - it_layer = m_objects.front()->insert_support_layer(it_layer, -1, height, lt.print_z, lt.print_z - 0.5 * height); + it_layer = m_objects.front()->insert_support_layer(it_layer, -1, 0, height, lt.print_z, lt.print_z - 0.5 * height); ++ it_layer; } } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 0056aee333..ac986216e5 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -300,8 +300,8 @@ public: size_t support_layer_count() const { return m_support_layers.size(); } void clear_support_layers(); SupportLayer* get_support_layer(int idx) { return m_support_layers[idx]; } - SupportLayer* add_support_layer(int id, coordf_t height, coordf_t print_z); - SupportLayerPtrs::iterator insert_support_layer(SupportLayerPtrs::iterator pos, size_t id, coordf_t height, coordf_t print_z, coordf_t slice_z); + SupportLayer* add_support_layer(int id, int interface_id, coordf_t height, coordf_t print_z); + SupportLayerPtrs::iterator insert_support_layer(SupportLayerPtrs::iterator pos, size_t id, size_t interface_id, coordf_t height, coordf_t print_z, coordf_t slice_z); void delete_support_layer(int idx); // Initialize the layer_height_profile from the model_object's layer_height_profile, from model_object's layer height table, or from slicing parameters. diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 2350131433..dd5a2b5731 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -461,15 +461,15 @@ void PrintObject::clear_support_layers() m_support_layers.clear(); } -SupportLayer* PrintObject::add_support_layer(int id, coordf_t height, coordf_t print_z) +SupportLayer* PrintObject::add_support_layer(int id, int interface_id, coordf_t height, coordf_t print_z) { - m_support_layers.emplace_back(new SupportLayer(id, this, height, print_z, -1)); + m_support_layers.emplace_back(new SupportLayer(id, interface_id, this, height, print_z, -1)); return m_support_layers.back(); } -SupportLayerPtrs::iterator PrintObject::insert_support_layer(SupportLayerPtrs::iterator pos, size_t id, coordf_t height, coordf_t print_z, coordf_t slice_z) +SupportLayerPtrs::iterator PrintObject::insert_support_layer(SupportLayerPtrs::iterator pos, size_t id, size_t interface_id, coordf_t height, coordf_t print_z, coordf_t slice_z) { - return m_support_layers.insert(pos, new SupportLayer(id, this, height, print_z, slice_z)); + return m_support_layers.insert(pos, new SupportLayer(id, interface_id, this, height, print_z, slice_z)); } // Called by Print::apply(). diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 167aedcc2b..1322b40711 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -420,6 +420,11 @@ inline void layers_append(PrintObjectSupportMaterial::MyLayersPtr &dst, const Pr dst.insert(dst.end(), src.begin(), src.end()); } +// Support layer that is covered by some form of dense interface. +static constexpr const std::initializer_list support_types_interface { + PrintObjectSupportMaterial::sltRaftInterface, PrintObjectSupportMaterial::sltBottomContact, PrintObjectSupportMaterial::sltBottomInterface, PrintObjectSupportMaterial::sltTopContact, PrintObjectSupportMaterial::sltTopInterface +}; + void PrintObjectSupportMaterial::generate(PrintObject &object) { BOOST_LOG_TRIVIAL(info) << "Support generator - Start"; @@ -569,6 +574,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) // Sort the layers lexicographically by a raising print_z and a decreasing height. std::sort(layers_sorted.begin(), layers_sorted.end(), [](auto *l1, auto *l2) { return *l1 < *l2; }); int layer_id = 0; + int layer_id_interface = 0; assert(object.support_layers().empty()); for (size_t i = 0; i < layers_sorted.size();) { // Find the last layer with roughly the same print_z, find the minimum layer height of all. @@ -580,17 +586,43 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) coordf_t zavg = 0.5 * (layers_sorted[i]->print_z + layers_sorted[j - 1]->print_z); coordf_t height_min = layers_sorted[i]->height; bool empty = true; + // For snug supports, layers where the direction of the support interface shall change are accounted for. + size_t num_interfaces = 0; + size_t num_top_contacts = 0; + double top_contact_bottom_z = 0; for (size_t u = i; u < j; ++u) { MyLayer &layer = *layers_sorted[u]; - if (! layer.polygons.empty()) - empty = false; + if (! layer.polygons.empty()) { + empty = false; + num_interfaces += one_of(layer.layer_type, support_types_interface); + if (layer.layer_type == sltTopContact) { + ++ num_top_contacts; + assert(num_top_contacts <= 1); + // All top contact layers sharing this print_z shall also share bottom_z. + //assert(num_top_contacts == 1 || (top_contact_bottom_z - layer.bottom_z) < EPSILON); + top_contact_bottom_z = layer.bottom_z; + } + } layer.print_z = zavg; height_min = std::min(height_min, layer.height); } if (! empty) { // Here the upper_layer and lower_layer pointers are left to null at the support layers, // as they are never used. These pointers are candidates for removal. - object.add_support_layer(layer_id ++, height_min, zavg); + bool this_layer_contacts_only = num_top_contacts > 0 && num_top_contacts == num_interfaces; + size_t this_layer_id_interface = layer_id_interface; + if (this_layer_contacts_only) { + // Find a supporting layer for its interface ID. + for (auto it = object.support_layers().rbegin(); it != object.support_layers().rend(); ++ it) + if (const SupportLayer &other_layer = **it; std::abs(other_layer.print_z - top_contact_bottom_z) < EPSILON) { + // other_layer supports this top contact layer. Assign a different support interface direction to this layer + // from the layer that supports it. + this_layer_id_interface = other_layer.interface_id() + 1; + } + } + object.add_support_layer(layer_id ++, this_layer_id_interface, height_min, zavg); + if (num_interfaces && ! this_layer_contacts_only) + ++ layer_id_interface; } i = j; } @@ -2507,14 +2539,16 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int // or the bottom of the first intermediate layer is aligned with the bottom of the raft contact layer. // Intermediate layers are always printed with a normal etrusion flow (non-bridging). size_t idx_layer_object = 0; - for (size_t idx_extreme = 0; idx_extreme < extremes.size(); ++ idx_extreme) { + size_t idx_extreme_first = 0; + if (! extremes.empty() && std::abs(extremes.front()->extreme_z() - m_slicing_params.raft_interface_top_z) < EPSILON) { + // This is a raft contact layer, its height has been decided in this->top_contact_layers(). + // Ignore this layer when calculating the intermediate support layers. + assert(extremes.front()->layer_type == sltTopContact); + ++ idx_extreme_first; + } + for (size_t idx_extreme = idx_extreme_first; idx_extreme < extremes.size(); ++ idx_extreme) { MyLayer *extr2 = extremes[idx_extreme]; coordf_t extr2z = extr2->extreme_z(); - if (std::abs(extr2z - m_slicing_params.raft_interface_top_z) < EPSILON) { - // This is a raft contact layer, its height has been decided in this->top_contact_layers(). - assert(extr2->layer_type == sltTopContact); - continue; - } if (std::abs(extr2z - m_slicing_params.first_print_layer_height) < EPSILON) { // This is a bottom of a synchronized (or soluble) top contact layer, its height has been decided in this->top_contact_layers(). assert(extr2->layer_type == sltTopContact); @@ -2531,7 +2565,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int } assert(extr2z >= m_slicing_params.raft_interface_top_z + EPSILON); assert(extr2z >= m_slicing_params.first_print_layer_height + EPSILON); - MyLayer *extr1 = (idx_extreme == 0) ? nullptr : extremes[idx_extreme - 1]; + MyLayer *extr1 = (idx_extreme == idx_extreme_first) ? nullptr : extremes[idx_extreme - 1]; // Fuse a support layer firmly to the raft top interface (not to the raft contacts). coordf_t extr1z = (extr1 == nullptr) ? m_slicing_params.raft_interface_top_z : extr1->extreme_z(); assert(extr2z >= extr1z); @@ -3056,7 +3090,6 @@ std::pairsupport_material_style.value == smsSnug; auto smoothing_distance = m_support_params.support_material_interface_flow.scaled_spacing() * 1.5; auto minimum_island_radius = m_support_params.support_material_interface_flow.scaled_spacing() / m_support_params.interface_density; auto closing_distance = smoothing_distance; // scaled(m_object_config->support_material_closing_radius.value); @@ -4027,6 +4060,9 @@ void PrintObjectSupportMaterial::generate_toolpaths( { SupportLayer &support_layer = *support_layers[support_layer_id]; LayerCache &layer_cache = layer_caches[support_layer_id]; + float interface_angle_delta = m_object_config->support_material_style.value == smsSnug ? + (support_layer.interface_id() & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.) : + 0; // Find polygons with the same print_z. MyLayerExtruded &bottom_contact_layer = layer_cache.bottom_contact_layer; @@ -4106,7 +4142,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // If zero interface layers are configured, use the same angle as for the base layers. angles[support_layer_id % angles.size()] : // Use interface angle for the interface layers. - m_support_params.interface_angle; + m_support_params.interface_angle + interface_angle_delta; double density = interface_as_base ? m_support_params.support_density : m_support_params.interface_density; filler_interface->spacing = interface_as_base ? m_support_params.support_material_flow.spacing() : m_support_params.support_material_interface_flow.spacing(); filler_interface->link_max_length = coord_t(scale_(filler_interface->spacing * link_max_length_factor / density)); @@ -4128,7 +4164,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // the bridging flow does not quite apply. Reduce the flow to area of an ellipse? (A = pi * a * b) assert(! base_interface_layer.layer->bridging); Flow interface_flow = m_support_params.support_material_flow.with_height(float(base_interface_layer.layer->height)); - filler->angle = m_support_params.interface_angle; + filler->angle = m_support_params.interface_angle + interface_angle_delta; filler->spacing = m_support_params.support_material_interface_flow.spacing(); filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / m_support_params.interface_density)); fill_expolygons_generate_paths(