From 00cc73f65f50a959d36fe3d4267d6086afd47532 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 2 Mar 2023 15:17:05 +0100 Subject: [PATCH] Raft improvements: 1) Object 1st layer fill direction is locked if printing on raft. 2) Object fill direction is referenced to object layer ignoring the raft layers, thus the fill direction depends no more on number of raft layers. 2) Raft contact perpendicular to object 1st layer fill direction. 3) Raft interface / contact layers are produced with alternating directions. --- src/libslic3r/Fill/Fill.cpp | 12 ++++- src/libslic3r/PrintObject.cpp | 10 ++++ src/libslic3r/SupportMaterial.cpp | 87 +++++++++++++++++-------------- src/libslic3r/SupportMaterial.hpp | 8 +++ 4 files changed, 75 insertions(+), 42 deletions(-) diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 082cf93cc..e0e2e0ca8 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -441,11 +441,15 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: } #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ + size_t first_object_layer_id = this->object()->get_layer(0)->id(); for (SurfaceFill &surface_fill : surface_fills) { // Create the filler object. std::unique_ptr f = std::unique_ptr(Fill::new_from_type(surface_fill.params.pattern)); f->set_bounding_box(bbox); - f->layer_id = this->id(); + // Layer ID is used for orienting the infill in alternating directions. + // Layer::id() returns layer ID including raft layers, subtract them to make the infill direction independent + // from raft. + f->layer_id = this->id() - first_object_layer_id; f->z = this->print_z; f->angle = surface_fill.params.angle; f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree; @@ -698,7 +702,11 @@ void Layer::make_ironing() FillRectilinear fill; FillParams fill_params; fill.set_bounding_box(this->object()->bounding_box()); - fill.layer_id = this->id(); + // Layer ID is used for orienting the infill in alternating directions. + // Layer::id() returns layer ID including raft layers, subtract them to make the infill direction independent + // from raft. + //FIXME ironing does not take fill angle into account. Shall it? Does it matter? + fill.layer_id = this->id() - this->object()->get_layer(0)->id(); fill.z = this->print_z; fill.overlap = 0; fill_params.density = 1.; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index efdcb4fc6..65deb8261 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -20,6 +20,7 @@ #include "Fill/FillAdaptive.hpp" #include "Fill/FillLightning.hpp" #include "Format/STL.hpp" +#include "SupportMaterial.hpp" #include "SupportSpotsGenerator.hpp" #include "TriangleSelectorWrapper.hpp" #include "format.hpp" @@ -1129,6 +1130,15 @@ void PrintObject::process_external_surfaces() m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - end"; } + + if (this->has_raft() && ! m_layers.empty()) { + // Adjust bridge direction of 1st object layer over raft to be perpendicular to the raft contact layer direction. + Layer &layer = *m_layers.front(); + assert(layer.id() > 0); + for (LayerRegion *layerm : layer.regions()) + for (Surface &fill : layerm->m_fill_surfaces) + fill.bridge_angle = -1; + } } // void PrintObject::process_external_surfaces() void PrintObject::discover_vertical_shells() diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 6be62c4b3..965a9398f 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -376,8 +376,6 @@ 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.)); 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(); @@ -401,6 +399,39 @@ SupportParameters::SupportParameters(const PrintObject &object) object_config.support_material_interface_pattern == smipConcentric ? ipConcentric : (this->interface_density > 0.95 ? ipRectilinear : ipSupportBase); + + 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->raft_angle_1st_layer = 0.f; + this->raft_angle_base = 0.f; + this->raft_angle_interface = 0.f; + if (slicing_params.base_raft_layers > 1) { + assert(slicing_params.raft_layers() >= 4); + // There are all raft layer types (1st layer, base, interface & contact layers) available. + this->raft_angle_1st_layer = this->interface_angle; + this->raft_angle_base = this->base_angle; + this->raft_angle_interface = this->interface_angle; + if ((slicing_params.interface_raft_layers & 1) == 0) + // Allign the 1st raft interface layer so that the object 1st layer is hatched perpendicularly to the raft contact interface. + this->raft_angle_interface += float(0.5 * M_PI); + } else if (slicing_params.base_raft_layers == 1 || slicing_params.interface_raft_layers > 1) { + assert(slicing_params.raft_layers() == 2 || slicing_params.raft_layers() == 3); + // 1st layer, interface & contact layers available. + this->raft_angle_1st_layer = this->base_angle; + this->raft_angle_interface = this->interface_angle + 0.5 * M_PI; + } else if (slicing_params.interface_raft_layers == 1) { + // Only the contact raft layer is non-empty, which will be printed as the 1st layer. + assert(slicing_params.base_raft_layers == 0); + assert(slicing_params.interface_raft_layers == 1); + assert(slicing_params.raft_layers() == 1); + this->raft_angle_1st_layer = float(0.5 * M_PI); + this->raft_angle_interface = this->raft_angle_1st_layer; + } else { + // No raft. + assert(slicing_params.base_raft_layers == 0); + assert(slicing_params.interface_raft_layers == 0); + assert(slicing_params.raft_layers() == 0); + } } PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params) : @@ -4207,38 +4238,12 @@ void generate_support_toolpaths( // const coordf_t link_max_length_factor = 3.; const coordf_t link_max_length_factor = 0.; - float raft_angle_1st_layer = 0.f; - float raft_angle_base = 0.f; - float raft_angle_interface = 0.f; - if (slicing_params.base_raft_layers > 1) { - // There are all raft layer types (1st layer, base, interface & contact layers) available. - raft_angle_1st_layer = support_params.interface_angle; - raft_angle_base = support_params.base_angle; - raft_angle_interface = support_params.interface_angle; - } else if (slicing_params.base_raft_layers == 1 || slicing_params.interface_raft_layers > 1) { - // 1st layer, interface & contact layers available. - raft_angle_1st_layer = support_params.base_angle; - if (config.support_material || config.support_material_enforce_layers > 0) - // Print 1st layer at 45 degrees from both the interface and base angles as both can land on the 1st layer. - raft_angle_1st_layer += 0.7854f; - raft_angle_interface = support_params.interface_angle; - } else if (slicing_params.interface_raft_layers == 1) { - // Only the contact raft layer is non-empty, which will be printed as the 1st layer. - assert(slicing_params.base_raft_layers == 0); - assert(slicing_params.interface_raft_layers == 1); - assert(slicing_params.raft_layers() == 1 && raft_layers.size() == 0); - } else { - // No raft. - assert(slicing_params.base_raft_layers == 0); - assert(slicing_params.interface_raft_layers == 0); - assert(slicing_params.raft_layers() == 0 && raft_layers.size() == 0); - } - // Insert the raft base layers. auto n_raft_layers = std::min(support_layers.size(), std::max(0, int(slicing_params.raft_layers()) - 1)); + tbb::parallel_for(tbb::blocked_range(0, n_raft_layers), [&support_layers, &raft_layers, &intermediate_layers, &config, &support_params, &slicing_params, - &bbox_object, raft_angle_1st_layer, raft_angle_base, raft_angle_interface, link_max_length_factor] + &bbox_object, link_max_length_factor] (const tbb::blocked_range& range) { for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) { @@ -4270,7 +4275,7 @@ void generate_support_toolpaths( assert(!raft_layer.bridging); if (! to_infill_polygons.empty()) { Fill *filler = filler_support.get(); - filler->angle = raft_angle_base; + filler->angle = support_params.raft_angle_base; filler->spacing = support_params.support_material_flow.spacing(); filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.support_density)); fill_expolygons_with_sheath_generate_paths( @@ -4293,11 +4298,11 @@ void generate_support_toolpaths( float density = 0.f; if (support_layer_id == 0) { // Base flange. - filler->angle = raft_angle_1st_layer; + filler->angle = support_params.raft_angle_1st_layer; filler->spacing = support_params.first_layer_flow.spacing(); density = float(config.raft_first_layer_density.value * 0.01); } else if (support_layer_id >= slicing_params.base_raft_layers) { - filler->angle = raft_angle_interface; + filler->angle = support_params.raft_interface_angle(support_layer.interface_id()); // We don't use $base_flow->spacing because we need a constant spacing // value that guarantees that all layers are correctly aligned. filler->spacing = support_params.support_material_flow.spacing(); @@ -4345,7 +4350,7 @@ void generate_support_toolpaths( std::vector layer_caches(support_layers.size()); 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, + [&config, &slicing_params, &support_params, &support_layers, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &base_interface_layers, &layer_caches, &loop_interface_processor, &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. @@ -4381,9 +4386,8 @@ void generate_support_toolpaths( { SupportLayer &support_layer = *support_layers[support_layer_id]; LayerCache &layer_cache = layer_caches[support_layer_id]; - float interface_angle_delta = config.support_material_style.value != smsGrid ? - (support_layer.interface_id() & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.) : - 0; + const float support_interface_angle = config.support_material_style.value == smsGrid ? + support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id()); // Find polygons with the same print_z. SupportGeneratorLayerExtruded &bottom_contact_layer = layer_cache.bottom_contact_layer; @@ -4412,7 +4416,8 @@ 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; + // This layer is a raft contact layer. Any contact polygons at this layer are raft contacts. + bool raft_layer = slicing_params.interface_raft_layers && top_contact_layer.layer && is_approx(top_contact_layer.layer->print_z, slicing_params.raft_contact_top_z); 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. // Don't merge the raft contact layer though. @@ -4470,7 +4475,9 @@ void generate_support_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. - support_params.interface_angle + interface_angle_delta; + raft_contact ? + support_params.raft_interface_angle(support_layer.interface_id()) : + support_interface_angle; 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(); @@ -4499,7 +4506,7 @@ void generate_support_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 = support_params.support_material_flow.with_height(float(base_interface_layer.layer->height)); - filler->angle = support_params.interface_angle + interface_angle_delta; + filler->angle = support_interface_angle; filler->spacing = support_params.support_material_interface_flow.spacing(); filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.interface_density)); fill_expolygons_generate_paths( diff --git a/src/libslic3r/SupportMaterial.hpp b/src/libslic3r/SupportMaterial.hpp index eda70517f..2bd321144 100644 --- a/src/libslic3r/SupportMaterial.hpp +++ b/src/libslic3r/SupportMaterial.hpp @@ -161,6 +161,14 @@ struct SupportParameters { InfillPattern contact_fill_pattern; // Shall the sparse (base) layers be printed with a single perimeter line (sheath) for robustness? bool with_sheath; + + float raft_angle_1st_layer; + float raft_angle_base; + float raft_angle_interface; + + // Produce a raft interface angle for a given SupportLayer::interface_id() + float raft_interface_angle(size_t interface_id) const + { return this->raft_angle_interface + ((interface_id & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)); } }; // Remove bridges from support contact areas.