diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 412dbc6785..7dac343429 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -429,7 +429,8 @@ const std::vector& Preset::print_options() "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", "support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers", - "support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance", + "support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops", + "support_material_contact_distance", "support_material_bottom_contact_distance", "support_material_buildplate_only", "dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius", "extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder", "infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 79c4e72a7d..e39fd8685e 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1326,7 +1326,8 @@ std::string Print::validate(std::string* warning) const return L("The Wipe Tower is only supported for multiple objects if they have equal layer heights"); if (slicing_params.raft_layers() != slicing_params0.raft_layers()) return L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers"); - if (object->config().support_material_contact_distance != m_objects.front()->config().support_material_contact_distance) + if (slicing_params0.gap_object_support != slicing_params.gap_object_support || + slicing_params0.gap_support_object != slicing_params.gap_support_object) return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance"); if (! equal_layering(slicing_params, slicing_params0)) return L("The Wipe Tower is only supported for multiple objects if they are sliced equally."); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index d744cb2a75..5fa4dfb013 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2235,7 +2235,7 @@ void PrintConfigDef::init_fff_params() def = this->add("support_material_contact_distance", coFloat); def->gui_type = "f_enum_open"; - def->label = L("Contact Z distance"); + def->label = L("Top contact Z distance"); def->category = L("Support material"); def->tooltip = L("The vertical distance between object and support material interface. " "Setting this to 0 will also prevent Slic3r from using bridge flow and speed " @@ -2243,12 +2243,31 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm"); // def->min = 0; def->enum_values.push_back("0"); + def->enum_values.push_back("0.1"); def->enum_values.push_back("0.2"); def->enum_labels.push_back(L("0 (soluble)")); + def->enum_labels.push_back(L("0.1 (detachable)")); def->enum_labels.push_back(L("0.2 (detachable)")); def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.2)); + def = this->add("support_material_bottom_contact_distance", coFloat); + def->gui_type = "f_enum_open"; + def->label = L("Bottom contact Z distance"); + def->category = L("Support material"); + def->tooltip = L("The vertical distance between the object top surface and the support material interface. " + "If set to zero, support_material_contact_distance will be used for both top and bottom contact Z distances."); + def->sidetext = L("mm"); +// def->min = 0; + def->enum_values.push_back("0"); + def->enum_values.push_back("0.1"); + def->enum_values.push_back("0.2"); + def->enum_labels.push_back(L("same as top")); + def->enum_labels.push_back(L("0.1")); + def->enum_labels.push_back(L("0.2")); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0)); + def = this->add("support_material_enforce_layers", coInt); def->label = L("Enforce support for the first"); def->category = L("Support material"); @@ -2298,22 +2317,36 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(1)); - def = this->add("support_material_interface_layers", coInt); + auto support_material_interface_layers = def = this->add("support_material_interface_layers", coInt); + def->gui_type = "f_enum_open"; def->label = L("Top interface layers"); def->category = L("Support material"); def->tooltip = L("Number of interface layers to insert between the object(s) and support material."); def->sidetext = L("layers"); def->min = 0; + def->enum_values.push_back("0"); + def->enum_values.push_back("1"); + def->enum_values.push_back("2"); + def->enum_values.push_back("3"); + def->enum_labels.push_back(L("0 (off)")); + def->enum_labels.push_back(L("1 (light)")); + def->enum_labels.push_back(L("2 (default)")); + def->enum_labels.push_back(L("3 (heavy)")); def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(3)); def = this->add("support_material_bottom_interface_layers", coInt); + def->gui_type = "f_enum_open"; def->label = L("Bottom interface layers"); def->category = L("Support material"); def->tooltip = L("Number of interface layers to insert between the object(s) and support material. " "Set to -1 to use support_material_interface_layers"); def->sidetext = L("layers"); def->min = -1; + def->enum_values.push_back("-1"); + append(def->enum_values, support_material_interface_layers->enum_values); + def->enum_labels.push_back(L("same as top")); + append(def->enum_labels, support_material_interface_layers->enum_labels); def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(-1)); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 4a4647b736..abeb29d4b8 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -503,6 +503,7 @@ public: ConfigOptionFloat support_material_angle; ConfigOptionBool support_material_buildplate_only; ConfigOptionFloat support_material_contact_distance; + ConfigOptionFloat support_material_bottom_contact_distance; ConfigOptionInt support_material_enforce_layers; ConfigOptionInt support_material_extruder; ConfigOptionFloatOrPercent support_material_extrusion_width; @@ -555,6 +556,7 @@ protected: OPT_PTR(support_material_angle); OPT_PTR(support_material_buildplate_only); OPT_PTR(support_material_contact_distance); + OPT_PTR(support_material_bottom_contact_distance); OPT_PTR(support_material_enforce_layers); OPT_PTR(support_material_interface_contact_loops); OPT_PTR(support_material_extruder); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index a3b0fb787d..e86eb2c9ce 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -546,15 +546,9 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "extra_perimeters" || opt_key == "gap_fill_enabled" || opt_key == "gap_fill_speed" - || opt_key == "overhangs" || opt_key == "first_layer_extrusion_width" - || opt_key == "fuzzy_skin" - || opt_key == "fuzzy_skin_thickness" - || opt_key == "fuzzy_skin_point_dist" || opt_key == "perimeter_extrusion_width" || opt_key == "infill_overlap" - || opt_key == "thin_walls" - || opt_key == "thick_bridges" || opt_key == "external_perimeters_first") { steps.emplace_back(posPerimeters); } else if ( @@ -586,6 +580,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "support_material_enforce_layers" || opt_key == "support_material_extruder" || opt_key == "support_material_extrusion_width" + || opt_key == "support_material_bottom_contact_distance" || opt_key == "support_material_interface_layers" || opt_key == "support_material_bottom_interface_layers" || opt_key == "support_material_interface_pattern" @@ -654,7 +649,13 @@ bool PrintObject::invalidate_state_by_config_options( steps.emplace_back(posPrepareInfill); } else if ( opt_key == "external_perimeter_extrusion_width" - || opt_key == "perimeter_extruder") { + || opt_key == "perimeter_extruder" + || opt_key == "fuzzy_skin" + || opt_key == "fuzzy_skin_thickness" + || opt_key == "fuzzy_skin_point_dist" + || opt_key == "overhangs" + || opt_key == "thin_walls" + || opt_key == "thick_bridges") { steps.emplace_back(posPerimeters); steps.emplace_back(posSupportMaterial); } else if (opt_key == "bridge_flow_ratio") { diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 083b41202d..d0b1e9ce26 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -112,8 +112,10 @@ SlicingParameters SlicingParameters::create_from_config( if (! soluble_interface) { params.gap_raft_object = object_config.raft_contact_distance.value; - params.gap_object_support = object_config.support_material_contact_distance.value; + params.gap_object_support = object_config.support_material_bottom_contact_distance.value; params.gap_support_object = object_config.support_material_contact_distance.value; + if (params.gap_object_support <= 0) + params.gap_object_support = params.gap_support_object; } if (params.base_raft_layers > 0) { diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index 8b3d5c917e..489b2768fb 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -26,7 +26,7 @@ class DynamicPrintConfig; // (using a normal flow over a soluble support, using a bridging flow over a non-soluble support). struct SlicingParameters { - SlicingParameters() { memset(this, 0, sizeof(SlicingParameters)); } + SlicingParameters() = default; static SlicingParameters create_from_config( const PrintConfig &print_config, @@ -44,58 +44,58 @@ struct SlicingParameters // Height of the object to be printed. This value does not contain the raft height. coordf_t object_print_z_height() const { return object_print_z_max - object_print_z_min; } - bool valid; + bool valid { false }; // Number of raft layers. - size_t base_raft_layers; + size_t base_raft_layers { 0 }; // Number of interface layers including the contact layer. - size_t interface_raft_layers; + size_t interface_raft_layers { 0 }; // Layer heights of the raft (base, interface and a contact layer). - coordf_t base_raft_layer_height; - coordf_t interface_raft_layer_height; - coordf_t contact_raft_layer_height; + coordf_t base_raft_layer_height { 0 }; + coordf_t interface_raft_layer_height { 0 }; + coordf_t contact_raft_layer_height { 0 }; // The regular layer height, applied for all but the first layer, if not overridden by layer ranges // or by the variable layer thickness table. - coordf_t layer_height; + coordf_t layer_height { 0 }; // Minimum / maximum layer height, to be used for the automatic adaptive layer height algorithm, // or by an interactive layer height editor. - coordf_t min_layer_height; - coordf_t max_layer_height; - coordf_t max_suport_layer_height; + coordf_t min_layer_height { 0 }; + coordf_t max_layer_height { 0 }; + coordf_t max_suport_layer_height { 0 }; // First layer height of the print, this may be used for the first layer of the raft // or for the first layer of the print. - coordf_t first_print_layer_height; + coordf_t first_print_layer_height { 0 }; // Thickness of the first layer. This is either the first print layer thickness if printed without a raft, // or a bridging flow thickness if printed over a non-soluble raft, // or a normal layer height if printed over a soluble raft. - coordf_t first_object_layer_height; + coordf_t first_object_layer_height { 0 }; // If the object is printed over a non-soluble raft, the first layer may be printed with a briding flow. - bool first_object_layer_bridging; + bool first_object_layer_bridging { false }; // Soluble interface? (PLA soluble in water, HIPS soluble in lemonen) // otherwise the interface must be broken off. - bool soluble_interface; + bool soluble_interface { false }; // Gap when placing object over raft. - coordf_t gap_raft_object; + coordf_t gap_raft_object { 0 }; // Gap when placing support over object. - coordf_t gap_object_support; + coordf_t gap_object_support { 0 }; // Gap when placing object over support. - coordf_t gap_support_object; + coordf_t gap_support_object { 0 }; // Bottom and top of the printed object. // If printed without a raft, object_print_z_min = 0 and object_print_z_max = object height. // Otherwise object_print_z_min is equal to the raft height. - coordf_t raft_base_top_z; - coordf_t raft_interface_top_z; - coordf_t raft_contact_top_z; + coordf_t raft_base_top_z { 0 }; + coordf_t raft_interface_top_z { 0 }; + coordf_t raft_contact_top_z { 0 }; // In case of a soluble interface, object_print_z_min == raft_contact_top_z, otherwise there is a gap between the raft and the 1st object layer. - coordf_t object_print_z_min; - coordf_t object_print_z_max; + coordf_t object_print_z_min { 0 }; + coordf_t object_print_z_max { 0 }; }; static_assert(IsTriviallyCopyable::value, "SlicingParameters class is not POD (and it should be - see constructor)."); diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 7747559e63..8dc939aed1 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -397,14 +398,6 @@ inline void layers_append(PrintObjectSupportMaterial::MyLayersPtr &dst, const Pr dst.insert(dst.end(), src.begin(), src.end()); } -// Compare layers lexicographically. -struct MyLayersPtrCompare -{ - bool operator()(const PrintObjectSupportMaterial::MyLayer* layer1, const PrintObjectSupportMaterial::MyLayer* layer2) const { - return *layer1 < *layer2; - } -}; - void PrintObjectSupportMaterial::generate(PrintObject &object) { BOOST_LOG_TRIVIAL(info) << "Support generator - Start"; @@ -467,10 +460,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) MyLayersPtr intermediate_layers = this->raft_and_intermediate_support_layers( object, bottom_contacts, top_contacts, layer_storage); -// this->trim_support_layers_by_object(object, top_contacts, m_slicing_params.soluble_interface ? 0. : m_support_layer_height_min, 0., m_gap_xy); - this->trim_support_layers_by_object(object, top_contacts, - m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value, - m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value, m_gap_xy); + this->trim_support_layers_by_object(object, top_contacts, m_slicing_params.gap_support_object, m_slicing_params.gap_object_support, m_gap_xy); #ifdef SLIC3R_DEBUG for (const MyLayer *layer : top_contacts) @@ -552,7 +542,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) layers_append(layers_sorted, interface_layers); layers_append(layers_sorted, base_interface_layers); // Sort the layers lexicographically by a raising print_z and a decreasing height. - std::sort(layers_sorted.begin(), layers_sorted.end(), MyLayersPtrCompare()); + std::sort(layers_sorted.begin(), layers_sorted.end(), [](auto *l1, auto *l2) { return *l1 < *l2; }); int layer_id = 0; assert(object.support_layers().empty()); for (size_t i = 0; i < layers_sorted.size();) { @@ -1585,11 +1575,11 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ } else if (m_slicing_params.soluble_interface) { // Align the contact surface height with a layer immediately below the supported layer. // Interface layer will be synchronized with the object. - new_layer.print_z = layer.print_z - layer.height; + new_layer.print_z = layer.bottom_z(); new_layer.height = object.layers()[layer_id - 1]->height; new_layer.bottom_z = (layer_id == 1) ? m_slicing_params.object_print_z_min : object.layers()[layer_id - 2]->print_z; } else { - new_layer.print_z = layer.print_z - layer.height - m_object_config->support_material_contact_distance; + new_layer.print_z = layer.bottom_z() - m_slicing_params.gap_object_support; new_layer.bottom_z = new_layer.print_z; new_layer.height = 0.; // Ignore this contact area if it's too low. @@ -1616,7 +1606,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ for (const LayerRegion *region : layer.regions()) bridging_height += region->region()->bridging_height_avg(*m_print_config); bridging_height /= coordf_t(layer.regions().size()); - coordf_t bridging_print_z = layer.print_z - bridging_height - m_object_config->support_material_contact_distance; + coordf_t bridging_print_z = layer.print_z - bridging_height - m_slicing_params.gap_support_object; if (bridging_print_z >= m_slicing_params.first_print_layer_height - EPSILON) { // Not below the first layer height means this layer is printable. if (new_layer.print_z < m_slicing_params.first_print_layer_height + EPSILON) { @@ -1892,7 +1882,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta // Place a bridge flow interface layer or the normal flow interface layer over the top surface. m_support_material_bottom_interface_flow.height(); layer_new.print_z = m_slicing_params.soluble_interface ? object.layers()[layer_id + 1]->print_z : - layer.print_z + layer_new.height + m_object_config->support_material_contact_distance.value; + layer.print_z + layer_new.height + m_slicing_params.gap_object_support; layer_new.bottom_z = layer.print_z; layer_new.idx_object_layer_below = layer_id; layer_new.bridging = ! m_slicing_params.soluble_interface && m_object_config->thick_bridges; @@ -2039,11 +2029,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta task_group.wait(); } std::reverse(bottom_contacts.begin(), bottom_contacts.end()); -// trim_support_layers_by_object(object, bottom_contacts, 0., 0., m_gap_xy); - trim_support_layers_by_object(object, bottom_contacts, - m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value, - m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value, m_gap_xy); - + trim_support_layers_by_object(object, bottom_contacts, m_slicing_params.gap_support_object, m_slicing_params.gap_object_support, m_gap_xy); } // ! top_contacts.empty() return bottom_contacts; @@ -2473,10 +2459,7 @@ void PrintObjectSupportMaterial::generate_base_layers( ++ iRun; #endif /* SLIC3R_DEBUG */ -// trim_support_layers_by_object(object, intermediate_layers, 0., 0., m_gap_xy); - this->trim_support_layers_by_object(object, intermediate_layers, - m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value, - m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value, m_gap_xy); + this->trim_support_layers_by_object(object, intermediate_layers, m_slicing_params.gap_support_object, m_slicing_params.gap_object_support, m_gap_xy); } void PrintObjectSupportMaterial::trim_support_layers_by_object( @@ -2510,7 +2493,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object( // BOOST_LOG_TRIVIAL(trace) << "Support generator - trim_support_layers_by_object - trimmming non-empty layer " << idx_layer << " of " << nonempty_layers.size(); assert(! support_layer.polygons.empty() && support_layer.print_z >= m_slicing_params.raft_contact_top_z + EPSILON); // Find the overlapping object layers including the extra above / below gap. - coordf_t z_threshold = support_layer.print_z - support_layer.height - gap_extra_below + EPSILON; + coordf_t z_threshold = support_layer.bottom_print_z() - gap_extra_below + EPSILON; idx_object_layer_overlapping = idx_higher_or_equal( object.layers().begin(), object.layers().end(), idx_object_layer_overlapping, [z_threshold](const Layer *layer){ return layer->print_z >= z_threshold; }); @@ -2519,7 +2502,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object( size_t i = idx_object_layer_overlapping; for (; i < object.layers().size(); ++ i) { const Layer &object_layer = *object.layers()[i]; - if (object_layer.print_z - object_layer.height > support_layer.print_z + gap_extra_above - EPSILON) + if (object_layer.bottom_z() > support_layer.print_z + gap_extra_above - EPSILON) break; polygons_append(polygons_trimming, offset(object_layer.lslices, gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS)); } @@ -2537,6 +2520,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object( offset(to_expolygons(region->fill_surfaces.filter_by_type(stBottomBridge)), gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS)); if (region->region()->config().overhangs.value) + // Add bridging perimeters. SupportMaterialInternal::collect_bridging_perimeter_areas(region->perimeters, gap_xy_scaled, polygons_trimming); } if (! some_region_overlaps) @@ -2896,7 +2880,8 @@ static inline void fill_expolygons_with_sheath_generate_paths( float density, ExtrusionRole role, const Flow &flow, - bool with_sheath) + bool with_sheath, + bool no_sort) { if (polygons.empty()) return; @@ -2916,8 +2901,12 @@ static inline void fill_expolygons_with_sheath_generate_paths( for (ExPolygon &expoly : offset2_ex(polygons, float(SCALED_EPSILON), float(- SCALED_EPSILON - 0.5*flow.scaled_width()))) { // Don't reorder the skirt and its infills. - auto eec = std::make_unique(); - eec->no_sort = true; + std::unique_ptr eec; + if (no_sort) { + eec = std::make_unique(); + eec->no_sort = true; + } + ExtrusionEntitiesPtr &out = no_sort ? eec->entities : dst; // Draw the perimeters. Polylines polylines; polylines.reserve(expoly.holes.size() + 1); @@ -2927,10 +2916,11 @@ static inline void fill_expolygons_with_sheath_generate_paths( pl.clip_end(clip_length); polylines.emplace_back(std::move(pl)); } - extrusion_entities_append_paths(eec->entities, polylines, erSupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height()); + extrusion_entities_append_paths(out, polylines, erSupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height()); // Fill in the rest. - fill_expolygons_generate_paths(eec->entities, offset_ex(expoly, float(-0.4 * spacing)), filler, fill_params, density, role, flow); - dst.emplace_back(eec.release()); + fill_expolygons_generate_paths(out, offset_ex(expoly, float(-0.4 * spacing)), filler, fill_params, density, role, flow); + if (no_sort) + dst.emplace_back(eec.release()); } } @@ -3255,6 +3245,9 @@ static std::string dbg_index_to_color(int idx) // Therefore the bottom interface spots are expanded a bit. The expanded regions may overlap with another bottom interface layers, // leading to over extrusion, where they overlap. The over extrusion is better avoided as it often makes the interface layers // to stick too firmly to the object. +// +// Modulate thickness (increase bottom_z) of extrusions_in_out generated for this_layer +// if they overlap with overlapping_layers, whose print_z is above this_layer.bottom_z() and below this_layer.print_z. void modulate_extrusion_by_overlapping_layers( // Extrusions generated for this_layer. ExtrusionEntitiesPtr &extrusions_in_out, @@ -3343,8 +3336,8 @@ void modulate_extrusion_by_overlapping_layers( // Collect the paths of this_layer. { Polylines &polylines = path_fragments.back().polylines; - for (ExtrusionEntitiesPtr::const_iterator it = extrusions_in_out.begin(); it != extrusions_in_out.end(); ++ it) { - ExtrusionPath *path = dynamic_cast(*it); + for (ExtrusionEntity *ee : extrusions_in_out) { + ExtrusionPath *path = dynamic_cast(ee); assert(path != nullptr); polylines.emplace_back(Polyline(std::move(path->polyline))); path_ends.emplace_back(std::pair(polylines.back().points.front(), polylines.back().points.back())); @@ -3504,7 +3497,6 @@ void PrintObjectSupportMaterial::generate_toolpaths( const MyLayersPtr &interface_layers, const MyLayersPtr &base_interface_layers) const { -// Slic3r::debugf "Generating patterns\n"; // loop_interface_processor with a given circle radius. LoopInterfaceProcessor loop_interface_processor(1.5 * m_support_material_interface_flow.scaled_width()); loop_interface_processor.n_contact_loops = this->has_contact_loops() ? 1 : 0; @@ -3603,7 +3595,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( filler, float(support_density), // Extrusion parameters erSupportMaterial, flow, - with_sheath); + with_sheath, false); } } @@ -3636,7 +3628,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // Extrusion parameters (support_layer_id < m_slicing_params.base_raft_layers) ? erSupportMaterial : erSupportMaterialInterface, flow, // sheath at first layer - support_layer_id == 0); + support_layer_id == 0, support_layer_id == 0); } }); @@ -3646,12 +3638,20 @@ void PrintObjectSupportMaterial::generate_toolpaths( std::vector overlapping; }; struct LayerCache { - MyLayerExtruded bottom_contact_layer; - MyLayerExtruded top_contact_layer; - MyLayerExtruded base_layer; - MyLayerExtruded interface_layer; - MyLayerExtruded base_interface_layer; - std::vector overlaps; + MyLayerExtruded bottom_contact_layer; + MyLayerExtruded top_contact_layer; + MyLayerExtruded base_layer; + MyLayerExtruded interface_layer; + MyLayerExtruded base_interface_layer; + boost::container::static_vector nonempty; + + void add_nonempty_and_sort() { + for (MyLayerExtruded *item : { &bottom_contact_layer, &top_contact_layer, &interface_layer, &base_interface_layer, &base_layer }) + if (! item->empty()) + this->nonempty.emplace_back(item); + // Sort the layers with the same print_z coordinate by their heights, thickest first. + std::stable_sort(this->nonempty.begin(), this->nonempty.end(), [](const LayerCacheItem &lc1, const LayerCacheItem &lc2) { return lc1.layer_extruded->layer->height > lc2.layer_extruded->layer->height; }); + } }; std::vector layer_caches(support_layers.size(), LayerCache()); @@ -3816,6 +3816,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_density)); float density = float(support_density); bool sheath = with_sheath; + bool no_sort = false; if (base_layer.layer->bottom_z < EPSILON) { // Base flange (the 1st layer). filler = filler_first_layer; @@ -3827,7 +3828,8 @@ void PrintObjectSupportMaterial::generate_toolpaths( //FIXME When paralellizing, each thread shall have its own copy of the fillers. filler->spacing = flow.spacing(); filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density)); - sheath = true; + sheath = true; + no_sort = true; } fill_expolygons_with_sheath_generate_paths( // Destination @@ -3838,7 +3840,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( filler, density, // Extrusion parameters erSupportMaterial, flow, - sheath); + sheath, no_sort); } @@ -3847,24 +3849,13 @@ void PrintObjectSupportMaterial::generate_toolpaths( base_layer.could_merge(base_interface_layer)) base_layer.merge(std::move(base_interface_layer)); - layer_cache.overlaps.reserve(5); - if (! bottom_contact_layer.empty()) - layer_cache.overlaps.push_back(&bottom_contact_layer); - if (! top_contact_layer.empty()) - layer_cache.overlaps.push_back(&top_contact_layer); - if (! interface_layer.empty()) - layer_cache.overlaps.push_back(&interface_layer); - if (! base_interface_layer.empty()) - layer_cache.overlaps.push_back(&base_interface_layer); - if (! base_layer.empty()) - layer_cache.overlaps.push_back(&base_layer); - // Sort the layers with the same print_z coordinate by their heights, thickest first. - std::sort(layer_cache.overlaps.begin(), layer_cache.overlaps.end(), [](const LayerCacheItem &lc1, const LayerCacheItem &lc2) { return lc1.layer_extruded->layer->height > lc2.layer_extruded->layer->height; }); + layer_cache.add_nonempty_and_sort(); + // Collect the support areas with this print_z into islands, as there is no need // for retraction over these islands. Polygons polys; // Collect the extrusions, sorted by the bottom extrusion height. - for (LayerCacheItem &layer_cache_item : layer_cache.overlaps) { + for (LayerCacheItem &layer_cache_item : layer_cache.nonempty) { // Collect islands to polys. layer_cache_item.layer_extruded->polygons_append(polys); // The print_z of the top contact surfaces and bottom_z of the bottom contact surfaces are "free" @@ -3878,32 +3869,22 @@ void PrintObjectSupportMaterial::generate_toolpaths( // Collect overlapping top/bottom surfaces. layer_cache_item.overlapping.reserve(20); coordf_t bottom_z = layer_cache_item.layer_extruded->layer->bottom_print_z() + EPSILON; - for (int i = int(idx_layer_bottom_contact) - 1; i >= 0 && bottom_contacts[i]->print_z > bottom_z; -- i) - layer_cache_item.overlapping.push_back(bottom_contacts[i]); - for (int i = int(idx_layer_top_contact) - 1; i >= 0 && top_contacts[i]->print_z > bottom_z; -- i) - layer_cache_item.overlapping.push_back(top_contacts[i]); + auto add_overlapping = [&layer_cache_item, bottom_z](const MyLayersPtr &layers, size_t idx_top) { + for (int i = int(idx_top) - 1; i >= 0 && layers[i]->print_z > bottom_z; -- i) + layer_cache_item.overlapping.push_back(layers[i]); + }; + add_overlapping(top_contacts, idx_layer_top_contact); if (layer_cache_item.layer_extruded->layer->layer_type == sltBottomContact) { // Bottom contact layer may overlap with a base layer, which may be changed to interface layer. - for (int i = int(idx_layer_intermediate) - 1; i >= 0 && intermediate_layers[i]->print_z > bottom_z; -- i) - layer_cache_item.overlapping.push_back(intermediate_layers[i]); - for (int i = int(idx_layer_interface) - 1; i >= 0 && interface_layers[i]->print_z > bottom_z; -- i) - layer_cache_item.overlapping.push_back(interface_layers[i]); - for (int i = int(idx_layer_base_interface) - 1; i >= 0 && base_interface_layers[i]->print_z > bottom_z; -- i) - layer_cache_item.overlapping.push_back(base_interface_layers[i]); + add_overlapping(intermediate_layers, idx_layer_intermediate); + add_overlapping(interface_layers, idx_layer_interface); + add_overlapping(base_interface_layers, idx_layer_base_interface); } - std::sort(layer_cache_item.overlapping.begin(), layer_cache_item.overlapping.end(), MyLayersPtrCompare()); + // Order the layers by lexicographically by an increasing print_z and a decreasing layer height. + std::stable_sort(layer_cache_item.overlapping.begin(), layer_cache_item.overlapping.end(), [](auto *l1, auto *l2) { return *l1 < *l2; }); } if (! polys.empty()) expolygons_append(support_layer.support_islands.expolygons, union_ex(polys)); - /* { - require "Slic3r/SVG.pm"; - Slic3r::SVG::output("islands_" . $z . ".svg", - red_expolygons => union_ex($contact), - green_expolygons => union_ex($interface), - green_polylines => [ map $_->unpack->polyline, @{$layer->support_contact_fills} ], - polylines => [ map $_->unpack->polyline, @{$layer->support_fills} ], - ); - } */ } // for each support_layer_id }); @@ -3914,7 +3895,9 @@ void PrintObjectSupportMaterial::generate_toolpaths( for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) { SupportLayer &support_layer = *support_layers[support_layer_id]; LayerCache &layer_cache = layer_caches[support_layer_id]; - for (LayerCacheItem &layer_cache_item : layer_cache.overlaps) { + // For all extrusion types at this print_z, ordered by decreasing layer height: + for (LayerCacheItem &layer_cache_item : layer_cache.nonempty) { + // Trim the extrusion height from the bottom by the overlapping layers. modulate_extrusion_by_overlapping_layers(layer_cache_item.layer_extruded->extrusions, *layer_cache_item.layer_extruded->layer, layer_cache_item.overlapping); support_layer.support_fills.append(std::move(layer_cache_item.layer_extruded->extrusions)); } diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 80ebe6ea80..6e0f135284 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -285,6 +285,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) "support_material_xy_spacing" }) toggle_field(el, have_support_material); toggle_field("support_material_threshold", have_support_material_auto); + toggle_field("support_material_bottom_contact_distance", have_support_material && ! have_support_soluble); for (auto el : { "support_material_bottom_interface_layers", "support_material_interface_spacing", "support_material_interface_extruder", "support_material_interface_speed", "support_material_interface_contact_loops" }) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c6b3ed89f8..65b4b7b283 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1762,7 +1762,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) // These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor. "layer_height", "first_layer_height", "min_layer_height", "max_layer_height", "brim_width", "perimeters", "perimeter_extruder", "fill_density", "infill_extruder", "top_solid_layers", - "support_material", "support_material_extruder", "support_material_interface_extruder", "support_material_contact_distance", "raft_layers" + "support_material", "support_material_extruder", "support_material_interface_extruder", + "support_material_contact_distance", "support_material_bottom_contact_distance", "raft_layers" })) , sidebar(new Sidebar(q)) , m_ui_jobs(this) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 472db49761..7b3f23eb46 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1507,6 +1507,7 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Options for support material and raft")); optgroup->append_single_option_line("support_material_contact_distance", category_path + "contact-z-distance"); + optgroup->append_single_option_line("support_material_bottom_contact_distance", category_path + "contact-z-distance"); optgroup->append_single_option_line("support_material_pattern", category_path + "pattern"); optgroup->append_single_option_line("support_material_with_sheath", category_path + "with-sheath-around-the-support"); optgroup->append_single_option_line("support_material_spacing", category_path + "pattern-spacing-0-inf");