From 04e13200aa46532f5d887d0168081801b8dcadb9 Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Mon, 27 Jul 2026 01:16:19 +0300 Subject: [PATCH] Support bugfixes (#14678) --- src/libslic3r/Support/SupportCommon.cpp | 82 ++++++++++++------ src/libslic3r/Support/SupportParameters.hpp | 60 +++++++++---- src/libslic3r/Support/TreeModelVolumes.cpp | 2 +- src/libslic3r/Support/TreeSupport.cpp | 94 +++++++++------------ src/libslic3r/Support/TreeSupport3D.cpp | 2 +- src/libslic3r/Support/TreeSupportCommon.hpp | 4 +- src/slic3r/Utils/Bonjour.cpp | 2 +- 7 files changed, 145 insertions(+), 101 deletions(-) diff --git a/src/libslic3r/Support/SupportCommon.cpp b/src/libslic3r/Support/SupportCommon.cpp index 571f61e661..15640cb0f2 100644 --- a/src/libslic3r/Support/SupportCommon.cpp +++ b/src/libslic3r/Support/SupportCommon.cpp @@ -65,6 +65,15 @@ std::pair generate_interfa const bool smooth_supports = support_params.support_style != smsGrid; SupportGeneratorLayersPtr &interface_layers = base_and_interface_layers.first; SupportGeneratorLayersPtr &base_interface_layers = base_and_interface_layers.second; + // The user-facing interface layer counts include the contact layer. Internally, + // contact layers are generated separately, so only the remaining layers are + // projected into intermediate interface/base-interface layers here. + const size_t num_top_interface_layers = support_params.has_top_contacts ? support_params.num_top_interface_layers - 1 : 0; + const size_t num_bottom_interface_layers = support_params.has_bottom_contacts ? support_params.num_bottom_interface_layers - 1 : 0; + const size_t num_top_base_interface_layers = std::min(support_params.num_top_base_interface_layers, num_top_interface_layers); + const size_t num_bottom_base_interface_layers = std::min(support_params.num_bottom_base_interface_layers, num_bottom_interface_layers); + const size_t num_top_interface_layers_only = num_top_interface_layers - num_top_base_interface_layers; + const size_t num_bottom_interface_layers_only = num_bottom_interface_layers - num_bottom_base_interface_layers; interface_layers.assign(intermediate_layers.size(), nullptr); if (support_params.has_base_interfaces()) @@ -124,6 +133,8 @@ std::pair generate_interfa }; tbb::parallel_for(tbb::blocked_range(0, int(intermediate_layers.size())), [&bottom_contacts, &top_contacts, &top_interface_layers, &top_base_interface_layers, &intermediate_layers, &insert_layer, &support_params, + num_top_interface_layers, num_bottom_interface_layers, num_top_base_interface_layers, num_bottom_base_interface_layers, + num_top_interface_layers_only, num_bottom_interface_layers_only, snug_supports, &interface_layers, &base_interface_layers](const tbb::blocked_range& range) { // Gather the top / bottom contact layers intersecting with num_interface_layers resp. num_interface_layers_only intermediate layers above / below // this intermediate layer. @@ -142,16 +153,16 @@ std::pair generate_interfa Polygons polygons_top_contact_projected_base; Polygons polygons_bottom_contact_projected_interface; Polygons polygons_bottom_contact_projected_base; - if (support_params.num_top_interface_layers > 0) { + if (num_top_interface_layers > 0) { // Top 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 + int(support_params.num_top_interface_layers) - 1)]->print_z; - coordf_t top_inteface_z = std::numeric_limits::max(); - if (support_params.num_top_base_interface_layers > 0) + coordf_t top_z = intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(num_top_interface_layers) - 1)]->print_z; + coordf_t top_interface_z = std::numeric_limits::max(); + if (num_top_base_interface_layers > 0) // Some top base interface layers will be generated. - top_inteface_z = support_params.num_top_interface_layers_only() == 0 ? + top_interface_z = num_top_interface_layers_only == 0 ? // Only base interface layers to generate. - std::numeric_limits::max() : - intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(support_params.num_top_interface_layers_only()) - 1)]->print_z; + intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(num_top_interface_layers_only) - 1)]->print_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 SupportGeneratorLayer *layer){ return layer->print_z >= intermediate_layer.print_z; }); // - EPSILON // Collect the top contact areas above this intermediate layer, below top_z. @@ -160,22 +171,22 @@ std::pair generate_interfa //FIXME maybe this adds one interface layer in excess? if (top_contact_layer.bottom_z - EPSILON > top_z) break; - polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface, + polygons_append(top_contact_layer.bottom_z - EPSILON > top_interface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface, // For snug supports, project the overhang polygons covering the whole overhang, so that they will merge without a gap with support polygons of the other layers. // For grid supports, merging of support regions will be performed by the projection into grid. snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons); } } - if (support_params.num_bottom_interface_layers > 0) { + if (num_bottom_interface_layers > 0) { // Bottom Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces - coordf_t bottom_z = intermediate_layers[std::max(0, idx_intermediate_layer - int(support_params.num_bottom_interface_layers) + 1)]->bottom_z; + coordf_t bottom_z = intermediate_layers[std::max(0, idx_intermediate_layer - int(num_bottom_interface_layers) + 1)]->bottom_z; coordf_t bottom_interface_z = - std::numeric_limits::max(); - if (support_params.num_bottom_base_interface_layers > 0) + if (num_bottom_base_interface_layers > 0) // Some bottom base interface layers will be generated. - bottom_interface_z = support_params.num_bottom_interface_layers_only() == 0 ? + bottom_interface_z = num_bottom_interface_layers_only == 0 ? // Only base interface layers to generate. std::numeric_limits::max() : - intermediate_layers[std::max(0, idx_intermediate_layer - int(support_params.num_bottom_interface_layers_only()))]->bottom_z; + intermediate_layers[std::max(0, idx_intermediate_layer - int(num_bottom_interface_layers_only))]->bottom_z; // 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 SupportGeneratorLayer *layer){ return layer->print_z >= bottom_z - EPSILON; }); // Collect the top contact areas above this intermediate layer, below top_z. @@ -1563,13 +1574,17 @@ void generate_support_toolpaths( // 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_interface_top_layers.value == 0 ? + const bool top_interfaces_enabled = support_params.num_top_interface_layers > 0; + const bool bottom_interfaces_enabled = support_params.num_bottom_interface_layers > 0; + const coordf_t base_interface_density = top_interfaces_enabled || !bottom_interfaces_enabled ? + support_params.top_interface_density : support_params.bottom_interface_density; + auto filler_raft_contact_ptr = std::unique_ptr(range.begin() == n_raft_layers && !top_interfaces_enabled ? 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.top_interface_density > 0.95 || support_params.with_sheath ? ipRectilinear : ipSupportBase)); + Fill::new_from_type(base_interface_density > 0.95 || support_params.with_sheath ? ipRectilinear : ipSupportBase)); auto filler_support = std::unique_ptr(Fill::new_from_type(support_params.base_fill_pattern)); filler_interface->set_bounding_box(bbox_object); if (filler_first_layer_ptr) @@ -1583,10 +1598,7 @@ void generate_support_toolpaths( { SupportLayer &support_layer = *support_layers[support_layer_id]; LayerCache &layer_cache = layer_caches[support_layer_id]; - const float support_interface_angle = (config.support_interface_pattern == smipRectilinearInterlaced) ? - support_params.raft_interface_angle(support_layer.interface_id()) : - ((support_params.support_style == smsGrid || config.support_interface_pattern == smipRectilinear) ? - support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id())); + const float support_interface_angle = support_params.support_interface_angle(support_layer.interface_id()); // Find polygons with the same print_z. SupportGeneratorLayerExtruded &bottom_contact_layer = layer_cache.bottom_contact_layer; @@ -1619,7 +1631,9 @@ void generate_support_toolpaths( 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); // ORCA: Organic tree uses projected contacts to build the interface stack; avoid extra bottom-contact extrusion. const bool organic_tree = support_params.support_style == SupportMaterialStyle::smsTreeOrganic; - if (config.support_interface_top_layers == 0) { + const bool top_interfaces = support_params.num_top_interface_layers > 0; + const bool bottom_interfaces = support_params.num_bottom_interface_layers > 0; + if (!top_interfaces) { // 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. if (support_params.can_merge_support_regions && ! raft_layer) { @@ -1642,15 +1656,29 @@ void generate_support_toolpaths( if (top_contact_layer.could_merge(interface_layer) && ! raft_layer) top_contact_layer.merge(std::move(interface_layer)); } - if ((config.support_interface_top_layers == 0 || config.support_interface_bottom_layers == 0) && support_params.can_merge_support_regions) { + if (!bottom_interfaces && support_params.can_merge_support_regions) { if (base_layer.could_merge(bottom_contact_layer)) 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) && ! raft_layer) { - top_contact_layer.merge(std::move(bottom_contact_layer)); + if (top_interfaces && bottom_interfaces) { + top_contact_layer.merge(std::move(bottom_contact_layer)); + } else if (bottom_interfaces) { + top_contact_layer.set_polygons_to_extrude( + diff(top_contact_layer.polygons_to_extrude(), bottom_contact_layer.polygons_to_extrude())); + } else { + bottom_contact_layer.set_polygons_to_extrude( + diff(bottom_contact_layer.polygons_to_extrude(), top_contact_layer.polygons_to_extrude())); + } } else if (bottom_contact_layer.could_merge(interface_layer) && ! organic_tree) { - bottom_contact_layer.merge(std::move(interface_layer)); + const bool interface_layer_is_bottom = interface_layer.layer->layer_type == SupporLayerType::BottomInterface; + if (bottom_interfaces && interface_layer_is_bottom) { + bottom_contact_layer.merge(std::move(interface_layer)); + } else { + bottom_contact_layer.set_polygons_to_extrude( + diff(bottom_contact_layer.polygons_to_extrude(), interface_layer.polygons_to_extrude())); + } } // Orca: For organic trees the support-material regions are generated from @@ -1730,12 +1758,12 @@ void generate_support_toolpaths( interface_as_base ? ExtrusionRole::erSupportMaterial : ExtrusionRole::erSupportMaterialInterface, interface_flow); } }; - const bool top_interfaces = support_params.num_top_interface_layers > 0; - const bool bottom_interfaces = top_interfaces && support_params.num_bottom_interface_layers > 0; extrude_interface(top_contact_layer, raft_layer ? InterfaceLayerType::RaftContact : top_interfaces ? InterfaceLayerType::TopContact : InterfaceLayerType::InterfaceAsBase); if (!organic_tree) extrude_interface(bottom_contact_layer, bottom_interfaces ? InterfaceLayerType::BottomContact : InterfaceLayerType::InterfaceAsBase); - extrude_interface(interface_layer, top_interfaces ? InterfaceLayerType::Interface : InterfaceLayerType::InterfaceAsBase); + const bool interface_layer_enabled = !interface_layer.empty() && + (interface_layer.layer->layer_type == SupporLayerType::BottomInterface ? bottom_interfaces : top_interfaces); + extrude_interface(interface_layer, interface_layer_enabled ? InterfaceLayerType::Interface : InterfaceLayerType::InterfaceAsBase); // Base interface layers under soluble interfaces if ( ! base_interface_layer.empty() && ! base_interface_layer.polygons_to_extrude().empty()) { Fill *filler = filler_base_interface.get(); @@ -1745,7 +1773,7 @@ void generate_support_toolpaths( Flow interface_flow = support_params.support_material_flow.with_height(float(base_interface_layer.layer->height)); 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.top_interface_density)); + filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / base_interface_density)); fill_expolygons_generate_paths( // Destination base_interface_layer.extrusions, @@ -1753,7 +1781,7 @@ void generate_support_toolpaths( // Regions to fill union_safety_offset_ex(base_interface_layer.polygons_to_extrude()), // Filler and its parameters - filler, float(support_params.top_interface_density), + filler, float(base_interface_density), // Extrusion parameters ExtrusionRole::erSupportMaterial, interface_flow); } diff --git a/src/libslic3r/Support/SupportParameters.hpp b/src/libslic3r/Support/SupportParameters.hpp index 9e099e7db5..dc0e94ed03 100644 --- a/src/libslic3r/Support/SupportParameters.hpp +++ b/src/libslic3r/Support/SupportParameters.hpp @@ -34,7 +34,7 @@ struct SupportParameters { { this->num_top_interface_layers = std::max(0, object_config.support_interface_top_layers.value); - this->num_bottom_interface_layers = number_of_support_interface_bottom_layers(object_config); + this->num_bottom_interface_layers = std::max(0, number_of_support_interface_bottom_layers(object_config)); this->has_top_contacts = num_top_interface_layers > 0; this->has_bottom_contacts = num_bottom_interface_layers > 0; // BBS: if support interface and support base do not use the same filament, add a base layer to improve their adhesion @@ -46,15 +46,15 @@ struct SupportParameters { if (non_soluble_base_top) { // ORCA: Try to support soluble dense interfaces with non-soluble dense interfaces. this->num_top_base_interface_layers = size_t(std::min(int(num_top_interface_layers) / 2, 2)); } else { - this->num_top_base_interface_layers = - (different_support_interface_filament && this->zero_gap_interface_top) ? 1 : 0; + // Keep at least one configured layer on the interface filament. + this->num_top_base_interface_layers = different_support_interface_filament && num_top_interface_layers > 1 ? 1 : 0; } if (non_soluble_base_bottom) { // ORCA: Try to support soluble dense interfaces with non-soluble dense interfaces. this->num_bottom_base_interface_layers = size_t(std::min(int(num_bottom_interface_layers) / 2, 2)); } else { - this->num_bottom_base_interface_layers = - (different_support_interface_filament && this->zero_gap_interface_bottom) ? 1 : 0; + // Keep at least one configured layer on the interface filament. + this->num_bottom_base_interface_layers = different_support_interface_filament && num_bottom_interface_layers > 1 ? 1 : 0; } } this->first_layer_flow = Slic3r::support_material_1st_layer_flow(&object, float(slicing_params.first_print_layer_height)); @@ -74,7 +74,7 @@ struct SupportParameters { for (auto layer : object.layers()) this->support_layer_height_min = std::min(this->support_layer_height_min, std::max(0.01, layer->height)); - if (object_config.support_interface_top_layers.value == 0) { + if (this->num_top_interface_layers == 0 && this->num_bottom_interface_layers == 0) { // No interface layers allowed, print everything with the base support pattern. this->support_material_interface_flow = this->support_material_flow; } @@ -120,8 +120,8 @@ struct SupportParameters { this->raft_interface_density = std::min(1., this->raft_interface_flow.spacing() / raft_interface_spacing); this->support_spacing = object_config.support_base_pattern_spacing.value + this->support_material_flow.spacing(); this->support_density = std::min(1., this->support_material_flow.spacing() / this->support_spacing); - if (object_config.support_interface_top_layers.value == 0) { - // No interface layers allowed, print everything with the base support pattern. + if (this->num_top_interface_layers == 0) { + // No top interface layers allowed; keep unused top interface parameters aligned with base support. this->top_interface_spacing = this->support_spacing; this->top_interface_density = this->support_density; } @@ -133,16 +133,20 @@ struct SupportParameters { this->support_density > 0.95 || this->with_sheath ? ipRectilinear : ipSupportBase; this->interface_fill_pattern = (this->top_interface_density > 0.95 ? ipRectilinear : ipSupportBase); this->raft_interface_fill_pattern = this->raft_interface_density > 0.95 ? ipRectilinear : ipSupportBase; + const coordf_t contact_interface_density = this->num_top_interface_layers > 0 ? + this->top_interface_density : this->bottom_interface_density; + const bool zero_gap_contact_interface = this->num_top_interface_layers > 0 ? + this->zero_gap_interface_top : this->zero_gap_interface_bottom; if (object_config.support_interface_pattern == smipGrid) this->contact_fill_pattern = ipGrid; else if (object_config.support_interface_pattern == smipRectilinearInterlaced) this->contact_fill_pattern = ipRectilinear; else this->contact_fill_pattern = - (object_config.support_interface_pattern == smipAuto && this->zero_gap_interface_top) || + (object_config.support_interface_pattern == smipAuto && zero_gap_contact_interface) || object_config.support_interface_pattern == smipConcentric ? ipConcentric : - (this->top_interface_density > 0.95 ? ipRectilinear : ipSupportBase); + (contact_interface_density > 0.95 ? ipRectilinear : ipSupportBase); this->raft_angle_1st_layer = 0.f; this->raft_angle_base = 0.f; @@ -188,6 +192,7 @@ struct SupportParameters { std::numeric_limits::max(); support_style = object_config.support_style; + support_interface_pattern = object_config.support_interface_pattern; if (support_style != smsDefault) { if ((support_style == smsSnug || support_style == smsGrid) && is_tree(object_config.support_type)) support_style = smsDefault; if ((support_style == smsTreeSlim || support_style == smsTreeStrong || support_style == smsTreeHybrid || support_style == smsTreeOrganic) && @@ -211,9 +216,9 @@ struct SupportParameters { bool has_top_contacts; // Is there at least a bottom contact layer extruded below support base? bool has_bottom_contacts; - // Number of top interface layers without counting the contact layer. + // User-configured number of top interface layers, including the contact layer. size_t num_top_interface_layers; - // Number of bottom interface layers without counting the contact layer. + // User-configured number of bottom interface layers, including the contact layer. size_t num_bottom_interface_layers; // Number of top base interface layers. size_t num_top_base_interface_layers; @@ -235,7 +240,7 @@ struct SupportParameters { 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 at raft interface & contact layers. Flow raft_interface_flow; coordf_t support_extrusion_width; // Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder? @@ -262,6 +267,7 @@ struct SupportParameters { // Density of the base support layers. coordf_t support_density; SupportMaterialStyle support_style = smsDefault; + SupportMaterialInterfacePattern support_interface_pattern = smipAuto; // Pattern of the sparse infill including sparse raft layers. InfillPattern base_fill_pattern; @@ -280,9 +286,33 @@ struct SupportParameters { float raft_angle_base; float raft_angle_interface; - // Produce a raft interface angle for a given SupportLayer::interface_id() + // Produce a +/-45deg alternating 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.)); } + { return this->raft_angle_interface + ((interface_id & 1) ? float(- M_PI_4) : float(+ M_PI_4)); } + + // Produce support interface angle for a given SupportLayer::interface_id(). + // Angle will be shifted/rotated based on interface pattern. + float support_interface_angle(size_t interface_id) const + { + float angle; + + switch (this->support_interface_pattern) { + case SupportMaterialInterfacePattern::smipRectilinear: + angle = support_style == SupportMaterialStyle::smsSnug ? this->interface_angle - float(M_PI_4) : this->interface_angle; + break; + case SupportMaterialInterfacePattern::smipRectilinearInterlaced: + angle = this->interface_angle + ((interface_id & 1) ? float(M_PI_4) : float(-M_PI_4)); + break; + case SupportMaterialInterfacePattern::smipGrid: + angle = this->base_angle; + break; + default: + angle = this->interface_angle; + break; + } + + return angle; + } bool independent_layer_height = false; const double thresh_big_overhang = Slic3r::sqr(scale_(10)); diff --git a/src/libslic3r/Support/TreeModelVolumes.cpp b/src/libslic3r/Support/TreeModelVolumes.cpp index 0267c0c327..7a769c77d1 100644 --- a/src/libslic3r/Support/TreeModelVolumes.cpp +++ b/src/libslic3r/Support/TreeModelVolumes.cpp @@ -469,7 +469,7 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex }); // 2) Sum over top / bottom ranges. - const bool processing_last_mesh = outline_idx == layer_outline_indices.size(); + const bool processing_last_mesh = outline_idx == layer_outline_indices.back(); tbb::parallel_for(tbb::blocked_range(data.begin(), data.end()), [&collision_areas_offsetted, &outlines, &machine_border = m_machine_border, &anti_overhang = m_anti_overhang, radius, xy_distance, z_distance_bottom_layers, z_distance_top_layers, min_resolution = m_min_resolution, &data, processing_last_mesh, &throw_on_cancel] diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index 0a8cda619d..d4a43a4767 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -1511,7 +1511,9 @@ void TreeSupport::generate_toolpaths() // ORCA: reset interface Fill state per area group to keep angles deterministic. filler_interface->fixed_angle = false; filler_interface->layer_id = size_t(-1); - filler_interface->angle = base_support_angle + M_PI_2; // default interface angle is perpendicular to support angle + filler_Roof1stLayer->fixed_angle = false; + filler_Roof1stLayer->layer_id = size_t(-1); + filler_interface->angle = m_support_params.support_interface_angle(area_group.interface_id); if (area_group.type != SupportLayer::BaseType) { // interface if (layer_id == 0) { @@ -1537,8 +1539,10 @@ void TreeSupport::generate_toolpaths() fill_params.density = interface_density; // Note: spacing means the separation between two lines as if they are tightly extruded filler_Roof1stLayer->spacing = interface_flow.spacing(); - filler_Roof1stLayer->angle = base_support_angle; + filler_Roof1stLayer->angle = m_support_params.support_interface_angle(area_group.interface_id); fill_params.dont_sort = true; + filler_Roof1stLayer->fixed_angle = (m_object_config->support_interface_pattern == smipRectilinearInterlaced || + m_object_config->support_interface_pattern == smipRectilinear); Flow interface_base_flow = interface_as_base ? support_flow : interface_flow; ExtrusionRole interface_role = interface_as_base ? erSupportMaterial : erSupportMaterialInterface; // generate a perimeter first to support interface better @@ -1556,18 +1560,11 @@ void TreeSupport::generate_toolpaths() fill_params.density = bottom_interface_density; filler_interface->spacing = interface_flow.spacing(); - if (m_object_config->support_interface_pattern == smipGrid) { - filler_interface->angle = base_support_angle; - fill_params.dont_sort = true; - } - - if (m_object_config->support_interface_pattern == smipRectilinearInterlaced) { - // ORCA: explicit 0/90 alternation for rectilinear interlaced interfaces. - filler_interface->fixed_angle = true; - filler_interface->angle = base_support_angle + ((area_group.interface_id & 1) * M_PI_2); - fill_params.dont_sort = true; - } + fill_params.dont_sort = (m_object_config->support_interface_pattern == smipGrid || + m_object_config->support_interface_pattern == smipRectilinearInterlaced); + filler_interface->fixed_angle = (m_object_config->support_interface_pattern == smipRectilinearInterlaced || + m_object_config->support_interface_pattern == smipRectilinear); Flow interface_base_flow = interface_as_base ? support_flow : interface_flow; ExtrusionRole interface_role = interface_as_base ? erSupportMaterial : erSupportMaterialInterface; @@ -1579,17 +1576,11 @@ void TreeSupport::generate_toolpaths() fill_params.density = interface_density; filler_interface->spacing = interface_flow.spacing(); - if (m_object_config->support_interface_pattern == smipGrid) { - filler_interface->angle = base_support_angle; - fill_params.dont_sort = true; - } + fill_params.dont_sort = (m_object_config->support_interface_pattern == smipGrid || + m_object_config->support_interface_pattern == smipRectilinearInterlaced); - if (m_object_config->support_interface_pattern == smipRectilinearInterlaced) { - // ORCA: explicit 0/90 alternation for rectilinear interlaced interfaces. - filler_interface->fixed_angle = true; - filler_interface->angle = base_support_angle + ((area_group.interface_id & 1) * M_PI_2); - fill_params.dont_sort = true; - } + filler_interface->fixed_angle = (m_object_config->support_interface_pattern == smipRectilinearInterlaced || + m_object_config->support_interface_pattern == smipRectilinear); Flow interface_base_flow = interface_as_base ? support_flow : interface_flow; ExtrusionRole interface_role = interface_as_base ? erSupportMaterial : erSupportMaterialInterface; @@ -2014,6 +2005,9 @@ void TreeSupport::draw_circles() // generate areas const coordf_t layer_height = config.layer_height.value; const size_t top_interface_layers = m_support_params.num_top_interface_layers; + const int top_base_interface_layers = std::min( + int(m_support_params.num_top_base_interface_layers), + top_interface_layers > 0 ? int(top_interface_layers) - 1 : 0); const size_t bottom_interface_layers = number_of_support_interface_bottom_layers(config); const double nozzle_diameter = m_object->print()->config().nozzle_diameter.get_at(0); const coordf_t line_width = config.get_abs_value("support_line_width", nozzle_diameter); @@ -2054,12 +2048,14 @@ void TreeSupport::draw_circles() ExPolygons& base_areas = ts_layer->base_areas; ExPolygons& roof_areas = ts_layer->roof_areas; + ExPolygons roof_base_areas; ExPolygons& roof_1st_layer = ts_layer->roof_1st_layer; ExPolygons& floor_areas = ts_layer->floor_areas; ExPolygons& roof_gap_areas = ts_layer->roof_gap_areas; coordf_t max_layers_above_base = 0; coordf_t max_layers_above_roof = 0; coordf_t max_layers_above_roof1 = 0; + size_t first_base_roof_area = 0; bool floor_interface_as_base = false; bool has_circle_node = false; bool need_extra_wall = false; @@ -2094,8 +2090,6 @@ void TreeSupport::draw_circles() break; const SupportNode& node = *p_node; - // ORCA: Cap top interface height in mm based on per-node support layer height. - const coordf_t top_interface_height = coordf_t(top_interface_layers) * node.height; ExPolygons area; // Generate directly from overhang polygon if one of the following is true: // 1) node is a normal part of hybrid support @@ -2159,18 +2153,16 @@ void TreeSupport::draw_circles() if (obj_layer_nr>0 && node.distance_to_top < 0) append(roof_gap_areas, area); - // ORCA: Roof1stLayer must also fit inside the mm cap. else if (obj_layer_nr > 0 && node.support_roof_layers_below == 1 && - (node.dist_mm_to_top - this->top_z_distance) < top_interface_height + EPSILON && node.is_sharp_tail==false) + node.is_sharp_tail == false) { append(roof_1st_layer, area); max_layers_above_roof1 = std::max(max_layers_above_roof1, node.dist_mm_to_top); } - // ORCA: Roof layers must also fit inside the mm cap. else if (obj_layer_nr > 0 && node.support_roof_layers_below > 1 && - (node.dist_mm_to_top - this->top_z_distance) < top_interface_height + EPSILON && node.is_sharp_tail == false) + node.is_sharp_tail == false) { - append(roof_areas, area); + append(node.support_roof_layers_below <= top_base_interface_layers ? roof_base_areas : roof_areas, area); max_layers_above_roof = std::max(max_layers_above_roof, node.dist_mm_to_top); } else @@ -2184,9 +2176,17 @@ void TreeSupport::draw_circles() //m_object->print()->set_status(65, (boost::format( _u8L("Support: generate polygons at layer %d")) % layer_nr).str()); // join roof segments - roof_areas = diff_clipped(offset2_ex(roof_areas, line_width_scaled, -line_width_scaled), get_collision(false)); + roof_areas = diff_clipped(closing_ex(roof_areas, line_width_scaled), get_collision(false)); roof_areas = intersection_ex(roof_areas, m_machine_border); - roof_1st_layer = diff_clipped(offset2_ex(roof_1st_layer, line_width_scaled, -line_width_scaled), get_collision(false)); + roof_base_areas = diff_clipped(closing_ex(roof_base_areas, line_width_scaled), get_collision(false)); + roof_base_areas = intersection_ex(roof_base_areas, m_machine_border); + if (!roof_base_areas.empty() && !roof_areas.empty()) + roof_base_areas = diff_ex(roof_base_areas, + ClipperUtils::clip_clipper_polygons_with_subject_bbox(roof_areas, get_extents(roof_base_areas))); + + first_base_roof_area = roof_areas.size(); + append(roof_areas, std::move(roof_base_areas)); + roof_1st_layer = diff_clipped(closing_ex(roof_1st_layer, line_width_scaled), get_collision(false)); // roof_1st_layer and roof_areas may intersect, so need to subtract roof_areas from roof_1st_layer roof_1st_layer = diff_ex(roof_1st_layer, ClipperUtils::clip_clipper_polygons_with_subject_bbox(roof_areas,get_extents(roof_1st_layer))); @@ -2366,9 +2366,11 @@ void TreeSupport::draw_circles() area_groups.back().need_infill = overlaps({ expoly }, area_poly); area_groups.back().need_extra_wall = need_extra_wall && !area_groups.back().need_infill; } - for (auto& expoly : ts_layer->roof_areas) { + for (size_t roof_idx = 0; roof_idx < ts_layer->roof_areas.size(); ++roof_idx) { + auto &expoly = ts_layer->roof_areas[roof_idx]; //if (area(expoly) < SQ(scale_(1))) continue; area_groups.emplace_back(&expoly, SupportLayer::RoofType, max_layers_above_roof); + area_groups.back().interface_as_base = roof_idx >= first_base_roof_area; } for (auto &expoly : ts_layer->floor_areas) { //if (area(expoly) < SQ(scale_(1))) continue; @@ -2378,6 +2380,7 @@ void TreeSupport::draw_circles() for (auto &expoly : ts_layer->roof_1st_layer) { //if (area(expoly) < SQ(scale_(1))) continue; area_groups.emplace_back(&expoly, SupportLayer::Roof1stLayer, max_layers_above_roof1); + area_groups.back().interface_as_base = top_base_interface_layers > 0; } for (auto &area_group : area_groups) { @@ -2406,7 +2409,6 @@ void TreeSupport::draw_circles() } }); // ORCA: normalize interface_id sequencing to follow printed interface layers only. - const int top_base_layers = int(m_support_params.num_top_base_interface_layers); const bool interlaced = m_object_config->support_interface_pattern == smipRectilinearInterlaced; int roof_interface_id = 0; int floor_interface_id = 0; @@ -2425,7 +2427,6 @@ void TreeSupport::draw_circles() if (area_group.type == SupportLayer::RoofType || area_group.type == SupportLayer::Roof1stLayer) { if (interlaced) area_group.interface_id = roof_interface_id; - area_group.interface_as_base = top_base_layers > 0 && roof_interface_id < top_base_layers; has_roof_interface = true; } else if (area_group.type == SupportLayer::FloorType) { if (interlaced) @@ -2897,7 +2898,7 @@ void TreeSupport::drop_nodes() node_parent->merged_neighbours.push_front(node_parent == p_node ? neighbour : p_node); const bool to_buildplate = !is_inside_ex(get_collision(0, obj_layer_nr_next), next_position); SupportNode* next_node = m_ts_data->create_node(next_position, node_parent->distance_to_top + 1, obj_layer_nr_next, - node_parent->support_roof_layers_below - (node_parent->distance_to_top > 0 ? 1 : 0), + node_parent->support_roof_layers_below - (node_parent->distance_to_top >= 0 ? 1 : 0), to_buildplate, node_parent, print_z_next, height_next); get_max_move_dist(next_node); m_ts_data->m_mutex.lock(); @@ -2949,7 +2950,7 @@ void TreeSupport::drop_nodes() for(auto& overhang:overhangs_next) { Point next_pt = overhang.contour.centroid(); SupportNode *next_node = m_ts_data->create_node(next_pt, p_node->distance_to_top + 1, obj_layer_nr_next, - p_node->support_roof_layers_below - (p_node->distance_to_top > 0 ? 1 : 0), + p_node->support_roof_layers_below - (p_node->distance_to_top >= 0 ? 1 : 0), to_buildplate, p_node, print_z_next, height_next); next_node->max_move_dist = 0; next_node->overhang = std::move(overhang); @@ -3096,7 +3097,7 @@ void TreeSupport::drop_nodes() auto next_collision = get_collision(0, obj_layer_nr_next); const bool to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[obj_layer_nr_next], next_layer_vertex); SupportNode * next_node = m_ts_data->create_node(next_layer_vertex, node.distance_to_top + 1, obj_layer_nr_next, - node.support_roof_layers_below - (node.distance_to_top > 0 ? 1 : 0), + node.support_roof_layers_below - (node.distance_to_top >= 0 ? 1 : 0), to_buildplate, p_node, print_z_next, height_next); // don't increase radius if next node will collide partially with the object (STUDIO-7883) to_outside = projection_onto(next_collision, next_node->position); @@ -3376,21 +3377,6 @@ std::vector TreeSupport::plan_layer_heights() } } - // ORCA: Recompute support_roof_layers_below from remaining interface height (independent heights). - const int top_layers = m_object->config().support_interface_top_layers.value; - if (m_support_params.independent_layer_height && top_layers > 0) { - const coordf_t interface_height_mm = coordf_t(top_layers) * m_slicing_params.layer_height; - for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) { - if (contact_nodes[layer_nr].empty()) continue; - for (SupportNode *node : contact_nodes[layer_nr]) { - if (node->height <= EPSILON) continue; - const coordf_t remaining_mm = interface_height_mm - (node->dist_mm_to_top - this->top_z_distance); - const int layers_fit = remaining_mm < -EPSILON ? 0 : int(std::floor((remaining_mm + EPSILON) / node->height)); - node->support_roof_layers_below = std::min(layers_fit, top_layers); - } - } - } - // log layer_heights for (size_t i = 0; i < layer_heights.size(); i++) { //if (layer_heights[i].height > EPSILON) @@ -3498,7 +3484,7 @@ void TreeSupport::generate_contact_points() if (force_add || !already_inserted.count(hash_pos)) { already_inserted.emplace(hash_pos); bool to_buildplate = true; - size_t roof_layers = add_interface ? (support_roof_layers > 0 ? support_roof_layers - 1 : 0) : 0; // subtract 1 because the contact node itself counts as one layer + size_t roof_layers = add_interface ? support_roof_layers : 0; // add a new node as a virtual node which acts as the invisible gap between support and object // distance_to_top=-1: it's virtual // print_z=object_layer->bottom_z: it directly contacts the bottom diff --git a/src/libslic3r/Support/TreeSupport3D.cpp b/src/libslic3r/Support/TreeSupport3D.cpp index 8242bd3f24..29131502d2 100644 --- a/src/libslic3r/Support/TreeSupport3D.cpp +++ b/src/libslic3r/Support/TreeSupport3D.cpp @@ -706,7 +706,7 @@ static std::optional> polyline_sample_next_point_at_dis filler->spacing = flow.spacing(); filler->angle = roof ? //fixme support_layer.interface_id() instead of layer_idx - (support_params.interface_angle + (layer_idx & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)) : + (support_params.interface_angle + ((layer_idx & 1) ? float(- M_PI_4) : float(+ M_PI_4))) : support_params.base_angle; // ORCA: use top-specific interface density after separating top/bottom settings. diff --git a/src/libslic3r/Support/TreeSupportCommon.hpp b/src/libslic3r/Support/TreeSupportCommon.hpp index c23de84404..07dcb324b8 100644 --- a/src/libslic3r/Support/TreeSupportCommon.hpp +++ b/src/libslic3r/Support/TreeSupportCommon.hpp @@ -62,7 +62,7 @@ struct TreeSupportMeshGroupSettings { this->support_line_width = support_material_flow(&print_object, config.layer_height).scaled_width(); this->support_roof_line_width = support_material_interface_flow(&print_object, config.layer_height).scaled_width(); const int bottom_interface_layers = number_of_support_interface_bottom_layers(config); - this->support_bottom_enable = config.support_interface_top_layers.value > 0 && bottom_interface_layers > 0; + this->support_bottom_enable = bottom_interface_layers > 0; this->support_bottom_height = this->support_bottom_enable ? bottom_interface_layers * this->layer_height : 0; @@ -705,7 +705,7 @@ public: SupportGeneratorLayersPtr& top_contacts_mutable() { return this->top_contacts; } public: - // Insert the contact layer and some of the inteface and base interface layers below. + // Insert the contact layer and some of the interface and base interface layers below. void add_roofs(std::vector &&new_roofs, const size_t insert_layer_idx) { if (! new_roofs.empty()) { diff --git a/src/slic3r/Utils/Bonjour.cpp b/src/slic3r/Utils/Bonjour.cpp index 0701695eff..0bff5b526c 100644 --- a/src/slic3r/Utils/Bonjour.cpp +++ b/src/slic3r/Utils/Bonjour.cpp @@ -871,7 +871,7 @@ void Bonjour::priv::lookup_perform() std::vector sockets; - // resolve intefaces - from PR#6646 + // resolve interfaces - from PR#6646 std::vector interfaces; asio::ip::udp::resolver resolver(*io_service); boost::system::error_code ec;