diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 0baec5c16..d3ff0a8d1 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -335,6 +335,7 @@ SupportParameters::SupportParameters(const PrintObject &object) this->first_layer_flow = Slic3r::support_material_1st_layer_flow(&object, float(slicing_params.first_print_layer_height)); this->support_material_flow = Slic3r::support_material_flow(&object, float(slicing_params.layer_height)); this->support_material_interface_flow = Slic3r::support_material_interface_flow(&object, float(slicing_params.layer_height)); + this->raft_interface_flow = support_material_interface_flow; // Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um. this->support_layer_height_min = scaled(0.01); @@ -377,13 +378,14 @@ SupportParameters::SupportParameters(const PrintObject &object) this->base_angle = Geometry::deg2rad(float(object_config.support_material_angle.value)); this->interface_angle = Geometry::deg2rad(float(object_config.support_material_angle.value + 90.)); - this->interface_spacing = object_config.support_material_interface_spacing.value + this->support_material_interface_flow.spacing(); - this->interface_density = std::min(1., this->support_material_interface_flow.spacing() / this->interface_spacing); - this->support_spacing = object_config.support_material_spacing.value + this->support_material_flow.spacing(); - this->support_density = std::min(1., this->support_material_flow.spacing() / this->support_spacing); + double interface_spacing = object_config.support_material_interface_spacing.value + this->support_material_interface_flow.spacing(); + this->interface_density = std::min(1., this->support_material_interface_flow.spacing() / interface_spacing); + double raft_interface_spacing = object_config.support_material_interface_spacing.value + this->raft_interface_flow.spacing(); + this->raft_interface_density = std::min(1., this->raft_interface_flow.spacing() / raft_interface_spacing); + double support_spacing = object_config.support_material_spacing.value + this->support_material_flow.spacing(); + this->support_density = std::min(1., this->support_material_flow.spacing() / support_spacing); if (object_config.support_material_interface_layers.value == 0) { // No interface layers allowed, print everything with the base support pattern. - this->interface_spacing = this->support_spacing; this->interface_density = this->support_density; } @@ -393,6 +395,7 @@ SupportParameters::SupportParameters(const PrintObject &object) support_pattern == smpHoneycomb ? ipHoneycomb : this->support_density > 0.95 || this->with_sheath ? ipRectilinear : ipSupportBase; this->interface_fill_pattern = (this->interface_density > 0.95 ? ipRectilinear : ipSupportBase); + this->raft_interface_fill_pattern = this->raft_interface_density > 0.95 ? ipRectilinear : ipSupportBase; this->contact_fill_pattern = (object_config.support_material_interface_pattern == smipAuto && slicing_params.soluble_interface) || object_config.support_material_interface_pattern == smipConcentric ? @@ -4240,11 +4243,11 @@ void generate_support_toolpaths( for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) { assert(support_layer_id < raft_layers.size()); - SupportLayer &support_layer = *support_layers[support_layer_id]; + SupportLayer &support_layer = *support_layers[support_layer_id]; assert(support_layer.support_fills.entities.empty()); SupportGeneratorLayer &raft_layer = *raft_layers[support_layer_id]; - std::unique_ptr filler_interface = std::unique_ptr(Fill::new_from_type(support_params.interface_fill_pattern)); + std::unique_ptr filler_interface = std::unique_ptr(Fill::new_from_type(support_params.raft_interface_fill_pattern)); std::unique_ptr filler_support = std::unique_ptr(Fill::new_from_type(support_params.base_fill_pattern)); filler_interface->set_bounding_box(bbox_object); filler_support->set_bounding_box(bbox_object); @@ -4299,8 +4302,8 @@ void generate_support_toolpaths( // value that guarantees that all layers are correctly aligned. filler->spacing = support_params.support_material_flow.spacing(); assert(! raft_layer.bridging); - flow = Flow(float(support_params.support_material_interface_flow.width()), float(raft_layer.height), support_params.support_material_flow.nozzle_diameter()); - density = float(support_params.interface_density); + flow = Flow(float(support_params.raft_interface_flow.width()), float(raft_layer.height), support_params.raft_interface_flow.nozzle_diameter()); + density = float(support_params.raft_interface_density); } else continue; filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density)); @@ -4343,7 +4346,7 @@ void generate_support_toolpaths( tbb::parallel_for(tbb::blocked_range(n_raft_layers, support_layers.size()), [&config, &support_params, &support_layers, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &base_interface_layers, &layer_caches, &loop_interface_processor, - &bbox_object, &angles, link_max_length_factor] + &bbox_object, &angles, n_raft_layers, link_max_length_factor] (const tbb::blocked_range& range) { // Indices of the 1st layer in their respective container at the support layer height. size_t idx_layer_bottom_contact = size_t(-1); @@ -4357,6 +4360,11 @@ void generate_support_toolpaths( auto filler_first_layer_ptr = std::unique_ptr(range.begin() == 0 && support_params.contact_fill_pattern != fill_type_first_layer ? Fill::new_from_type(fill_type_first_layer) : nullptr); // Pointer to the 1st layer interface filler. auto filler_first_layer = filler_first_layer_ptr ? filler_first_layer_ptr.get() : filler_interface.get(); + // Filler for the 1st layer interface, if different from filler_interface. + auto filler_raft_contact_ptr = std::unique_ptr(range.begin() == n_raft_layers && config.support_material_interface_layers.value == 0 ? + Fill::new_from_type(support_params.raft_interface_fill_pattern) : nullptr); + // Pointer to the 1st layer interface filler. + auto filler_raft_contact = filler_raft_contact_ptr ? filler_raft_contact_ptr.get() : filler_interface.get(); // Filler for the base interface (to be used for soluble interface / non soluble base, to produce non soluble interface layer below soluble interface layer). auto filler_base_interface = std::unique_ptr(base_interface_layers.empty() ? nullptr : Fill::new_from_type(support_params.interface_density > 0.95 || support_params.with_sheath ? ipRectilinear : ipSupportBase)); @@ -4364,6 +4372,8 @@ void generate_support_toolpaths( filler_interface->set_bounding_box(bbox_object); if (filler_first_layer_ptr) filler_first_layer_ptr->set_bounding_box(bbox_object); + if (filler_raft_contact_ptr) + filler_raft_contact_ptr->set_bounding_box(bbox_object); if (filler_base_interface) filler_base_interface->set_bounding_box(bbox_object); filler_support->set_bounding_box(bbox_object); @@ -4402,10 +4412,12 @@ void generate_support_toolpaths( 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]; + bool raft_layer = support_layer_id == n_raft_layers; if (config.support_material_interface_layers == 0) { // If no top interface layers were requested, we treat the contact layer exactly as a generic base layer. - if (support_params.can_merge_support_regions) { - if (base_layer.could_merge(top_contact_layer)) + // Don't merge the raft contact layer though. + if (support_params.can_merge_support_regions && ! raft_layer) { + if (base_layer.could_merge(top_contact_layer)) base_layer.merge(std::move(top_contact_layer)); else if (base_layer.empty()) base_layer = std::move(top_contact_layer); @@ -4415,7 +4427,7 @@ void generate_support_toolpaths( // If no loops are allowed, we treat the contact layer exactly as a generic interface layer. // Merge interface_layer into top_contact_layer, as the top_contact_layer is not synchronized and therefore it will be used // to trim other layers. - if (top_contact_layer.could_merge(interface_layer)) + if (top_contact_layer.could_merge(interface_layer) && ! raft_layer) top_contact_layer.merge(std::move(interface_layer)); } if ((config.support_material_interface_layers == 0 || config.support_material_bottom_interface_layers == 0) && support_params.can_merge_support_regions) { @@ -4423,7 +4435,7 @@ void generate_support_toolpaths( base_layer.merge(std::move(bottom_contact_layer)); else if (base_layer.empty() && ! bottom_contact_layer.empty() && ! bottom_contact_layer.layer->bridging) base_layer = std::move(bottom_contact_layer); - } else if (bottom_contact_layer.could_merge(top_contact_layer)) + } else if (bottom_contact_layer.could_merge(top_contact_layer) && ! raft_layer) top_contact_layer.merge(std::move(bottom_contact_layer)); else if (bottom_contact_layer.could_merge(interface_layer)) bottom_contact_layer.merge(std::move(interface_layer)); @@ -4441,35 +4453,44 @@ void generate_support_toolpaths( #endif // Top and bottom contacts, interface layers. - for (size_t i = 0; i < 3; ++ i) { - SupportGeneratorLayerExtruded &layer_ex = (i == 0) ? top_contact_layer : (i == 1 ? bottom_contact_layer : interface_layer); - if (layer_ex.empty() || layer_ex.polygons_to_extrude().empty()) - continue; - bool interface_as_base = config.support_material_interface_layers.value == 0 || - (config.support_material_bottom_interface_layers == 0 && &layer_ex == &bottom_contact_layer); - //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) - auto interface_flow = layer_ex.layer->bridging ? - Flow::bridging_flow(layer_ex.layer->height, support_params.support_material_bottom_interface_flow.nozzle_diameter()) : - (interface_as_base ? &support_params.support_material_flow : &support_params.support_material_interface_flow)->with_height(float(layer_ex.layer->height)); - filler_interface->angle = interface_as_base ? - // 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. - support_params.interface_angle + interface_angle_delta; - double density = interface_as_base ? support_params.support_density : support_params.interface_density; - filler_interface->spacing = interface_as_base ? support_params.support_material_flow.spacing() : support_params.support_material_interface_flow.spacing(); - filler_interface->link_max_length = coord_t(scale_(filler_interface->spacing * link_max_length_factor / density)); - fill_expolygons_generate_paths( - // Destination - layer_ex.extrusions, - // Regions to fill - union_safety_offset_ex(layer_ex.polygons_to_extrude()), - // Filler and its parameters - filler_interface.get(), float(density), - // Extrusion parameters - ExtrusionRole::SupportMaterialInterface, interface_flow); - } + enum class InterfaceLayerType { TopContact, BottomContact, RaftContact, Interface, InterfaceAsBase }; + auto extrude_interface = [&](SupportGeneratorLayerExtruded &layer_ex, InterfaceLayerType interface_layer_type) { + if (! layer_ex.empty() && ! layer_ex.polygons_to_extrude().empty()) { + bool interface_as_base = interface_layer_type == InterfaceLayerType::InterfaceAsBase; + bool raft_contact = interface_layer_type == InterfaceLayerType::RaftContact; + //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) + auto *filler = raft_contact ? filler_raft_contact : filler_interface.get(); + auto interface_flow = layer_ex.layer->bridging ? + Flow::bridging_flow(layer_ex.layer->height, support_params.support_material_bottom_interface_flow.nozzle_diameter()) : + (raft_contact ? &support_params.raft_interface_flow : + interface_as_base ? &support_params.support_material_flow : &support_params.support_material_interface_flow) + ->with_height(float(layer_ex.layer->height)); + filler->angle = interface_as_base ? + // 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. + support_params.interface_angle + interface_angle_delta; + double density = raft_contact ? support_params.raft_interface_density : interface_as_base ? support_params.support_density : support_params.interface_density; + filler->spacing = raft_contact ? support_params.raft_interface_flow.spacing() : + interface_as_base ? support_params.support_material_flow.spacing() : support_params.support_material_interface_flow.spacing(); + filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density)); + fill_expolygons_generate_paths( + // Destination + layer_ex.extrusions, + // Regions to fill + union_safety_offset_ex(layer_ex.polygons_to_extrude()), + // Filler and its parameters + filler, float(density), + // Extrusion parameters + ExtrusionRole::SupportMaterialInterface, interface_flow); + } + }; + const bool top_interfaces = config.support_material_interface_layers.value != 0; + const bool bottom_interfaces = top_interfaces && config.support_material_bottom_interface_layers != 0; + extrude_interface(top_contact_layer, raft_layer ? InterfaceLayerType::RaftContact : top_interfaces ? InterfaceLayerType::TopContact : InterfaceLayerType::InterfaceAsBase); + extrude_interface(bottom_contact_layer, bottom_interfaces ? InterfaceLayerType::BottomContact : InterfaceLayerType::InterfaceAsBase); + extrude_interface(interface_layer, top_interfaces ? InterfaceLayerType::Interface : InterfaceLayerType::InterfaceAsBase); // Base interface layers under soluble interfaces if ( ! base_interface_layer.empty() && ! base_interface_layer.polygons_to_extrude().empty()) { diff --git a/src/libslic3r/SupportMaterial.hpp b/src/libslic3r/SupportMaterial.hpp index ecfb5a761..eda70517f 100644 --- a/src/libslic3r/SupportMaterial.hpp +++ b/src/libslic3r/SupportMaterial.hpp @@ -122,10 +122,17 @@ using SupportGeneratorLayersPtr = std::vector; struct SupportParameters { SupportParameters(const PrintObject &object); + // Flow at the 1st print layer. Flow first_layer_flow; + // Flow at the support base (neither top, nor bottom interface). + // Also flow at the raft base with the exception of raft interface and contact layers. Flow support_material_flow; + // Flow at the top interface and contact layers. Flow support_material_interface_flow; + // Flow at the bottom interfaces and contacts. Flow support_material_bottom_interface_flow; + // Flow at raft inteface & contact layers. + Flow raft_interface_flow; // Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder? bool can_merge_support_regions; @@ -136,14 +143,23 @@ struct SupportParameters { float base_angle; float interface_angle; - coordf_t interface_spacing; + + // Density of the top / bottom interface and contact layers. coordf_t interface_density; - coordf_t support_spacing; + // Density of the raft interface and contact layers. + coordf_t raft_interface_density; + // Density of the base support layers. coordf_t support_density; + // Pattern of the sparse infill including sparse raft layers. InfillPattern base_fill_pattern; + // Pattern of the top / bottom interface and contact layers. InfillPattern interface_fill_pattern; + // Pattern of the raft interface and contact layers. + InfillPattern raft_interface_fill_pattern; + // Pattern of the contact layers. InfillPattern contact_fill_pattern; + // Shall the sparse (base) layers be printed with a single perimeter line (sheath) for robustness? bool with_sheath; };