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.