diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index a42fae5677..2b29559f43 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -134,9 +134,12 @@ struct ExtrusionAttributes : ExtrusionFlow ExtrusionAttributes(ExtrusionRole role) : role{ role } {} ExtrusionAttributes(ExtrusionRole role, const Flow &flow) : role{ role }, ExtrusionFlow{ flow } {} ExtrusionAttributes(ExtrusionRole role, const ExtrusionFlow &flow) : role{ role }, ExtrusionFlow{ flow } {} + ExtrusionAttributes(ExtrusionRole role, const ExtrusionFlow &flow, const bool maybe_self_crossing) + : role{role}, ExtrusionFlow{flow}, maybe_self_crossing(maybe_self_crossing) {} // What is the role / purpose of this extrusion? ExtrusionRole role{ ExtrusionRole::None }; + bool maybe_self_crossing{false}; // OVerhangAttributes are currently computed for perimeters if dynamic overhangs are enabled. // They are used to control fan and print speed in export. std::optional overhang_attributes; diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index ecaf4a3337..df493ab40c 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -573,8 +573,10 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: // When prefer_clockwise_movements is true, we have to ensure that extrusion paths will not be reversed during path planning. extrusion_entities_append_paths( eec->entities, std::move(polylines), - ExtrusionAttributes{ surface_fill.params.extrusion_role, - ExtrusionFlow{ flow_mm3_per_mm, float(flow_width), surface_fill.params.flow.height() } + ExtrusionAttributes{ + surface_fill.params.extrusion_role, + ExtrusionFlow{ flow_mm3_per_mm, float(flow_width), surface_fill.params.flow.height() }, + f->is_self_crossing() }, !params.prefer_clockwise_movements); layerm.m_fills.entities.push_back(eec); } diff --git a/src/libslic3r/Fill/Fill3DHoneycomb.hpp b/src/libslic3r/Fill/Fill3DHoneycomb.hpp index 662f6bb5f1..53a80539e9 100644 --- a/src/libslic3r/Fill/Fill3DHoneycomb.hpp +++ b/src/libslic3r/Fill/Fill3DHoneycomb.hpp @@ -22,6 +22,7 @@ public: // require bridge flow since most of this pattern hangs in air bool use_bridge_flow() const override { return true; } + bool is_self_crossing() override { return false; } protected: void _fill_surface_single( diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp index d6458de9e8..7e2df90c15 100644 --- a/src/libslic3r/Fill/FillAdaptive.hpp +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -75,6 +75,7 @@ protected: // may not be optimal as the internal infill lines may get extruded before the long infill // lines to which the short infill lines are supposed to anchor. bool no_sort() const override { return false; } + bool is_self_crossing() override { return true; } }; } // namespace FillAdaptive diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index fd0c47a89c..04b39e1441 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -123,6 +123,8 @@ public: // Do not sort the fill lines to optimize the print head path? virtual bool no_sort() const { return false; } + virtual bool is_self_crossing() = 0; + // Perform the fill. virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms); virtual ThickPolylines fill_surface_arachne(const Surface *surface, const FillParams ¶ms); diff --git a/src/libslic3r/Fill/FillConcentric.hpp b/src/libslic3r/Fill/FillConcentric.hpp index f22f781bf6..a2e53e1df2 100644 --- a/src/libslic3r/Fill/FillConcentric.hpp +++ b/src/libslic3r/Fill/FillConcentric.hpp @@ -19,6 +19,7 @@ class FillConcentric : public Fill { public: ~FillConcentric() override = default; + bool is_self_crossing() override { return false; } protected: Fill* clone() const override { return new FillConcentric(*this); }; diff --git a/src/libslic3r/Fill/FillEnsuring.hpp b/src/libslic3r/Fill/FillEnsuring.hpp index 537e950b39..152f9772ef 100644 --- a/src/libslic3r/Fill/FillEnsuring.hpp +++ b/src/libslic3r/Fill/FillEnsuring.hpp @@ -23,6 +23,7 @@ public: { return make_fill_polylines(this, surface, params, true, true, true); }; + bool is_self_crossing() override { return false; } protected: void fill_surface_single_arachne(const Surface &surface, const FillParams ¶ms, ThickPolylines &thick_polylines_out); diff --git a/src/libslic3r/Fill/FillGyroid.hpp b/src/libslic3r/Fill/FillGyroid.hpp index 6cb227eba5..8c031b8a80 100644 --- a/src/libslic3r/Fill/FillGyroid.hpp +++ b/src/libslic3r/Fill/FillGyroid.hpp @@ -20,6 +20,7 @@ public: // require bridge flow since most of this pattern hangs in air bool use_bridge_flow() const override { return false; } + bool is_self_crossing() override { return false; } // Correction applied to regular infill angle to maximize printing // speed in default configuration (degrees) diff --git a/src/libslic3r/Fill/FillHoneycomb.hpp b/src/libslic3r/Fill/FillHoneycomb.hpp index b7a604f458..c2283ef329 100644 --- a/src/libslic3r/Fill/FillHoneycomb.hpp +++ b/src/libslic3r/Fill/FillHoneycomb.hpp @@ -22,6 +22,7 @@ class FillHoneycomb : public Fill { public: ~FillHoneycomb() override {} + bool is_self_crossing() override { return false; } protected: Fill* clone() const override { return new FillHoneycomb(*this); }; diff --git a/src/libslic3r/Fill/FillLightning.hpp b/src/libslic3r/Fill/FillLightning.hpp index 1fb95ddb11..48a5da624a 100644 --- a/src/libslic3r/Fill/FillLightning.hpp +++ b/src/libslic3r/Fill/FillLightning.hpp @@ -24,8 +24,10 @@ class Filler : public Slic3r::Fill { public: ~Filler() override = default; + bool is_self_crossing() override { return false; } Generator *generator { nullptr }; + protected: Fill* clone() const override { return new Filler(*this); } diff --git a/src/libslic3r/Fill/FillLine.hpp b/src/libslic3r/Fill/FillLine.hpp index e9072263de..d8b39d2cd1 100644 --- a/src/libslic3r/Fill/FillLine.hpp +++ b/src/libslic3r/Fill/FillLine.hpp @@ -19,6 +19,7 @@ class FillLine : public Fill public: Fill* clone() const override { return new FillLine(*this); }; ~FillLine() override = default; + bool is_self_crossing() override { return false; } protected: void _fill_surface_single( diff --git a/src/libslic3r/Fill/FillPlanePath.hpp b/src/libslic3r/Fill/FillPlanePath.hpp index 31c986b3c1..ed8420f552 100644 --- a/src/libslic3r/Fill/FillPlanePath.hpp +++ b/src/libslic3r/Fill/FillPlanePath.hpp @@ -26,6 +26,7 @@ class FillPlanePath : public Fill { public: ~FillPlanePath() override = default; + bool is_self_crossing() override { return false; } protected: void _fill_surface_single( diff --git a/src/libslic3r/Fill/FillRectilinear.hpp b/src/libslic3r/Fill/FillRectilinear.hpp index e009d686fd..f2ea955fe6 100644 --- a/src/libslic3r/Fill/FillRectilinear.hpp +++ b/src/libslic3r/Fill/FillRectilinear.hpp @@ -26,6 +26,7 @@ public: Fill* clone() const override { return new FillRectilinear(*this); } ~FillRectilinear() override = default; Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override; + bool is_self_crossing() override { return false; } protected: // Fill by single directional lines, interconnect the lines along perimeters. @@ -75,6 +76,7 @@ public: Fill* clone() const override { return new FillGrid(*this); } ~FillGrid() override = default; Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override; + bool is_self_crossing() override { return true; } protected: // The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill. @@ -87,6 +89,7 @@ public: Fill* clone() const override { return new FillTriangles(*this); } ~FillTriangles() override = default; Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override; + bool is_self_crossing() override { return true; } protected: // The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill. @@ -99,6 +102,7 @@ public: Fill* clone() const override { return new FillStars(*this); } ~FillStars() override = default; Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override; + bool is_self_crossing() override { return true; } protected: // The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill. @@ -111,6 +115,7 @@ public: Fill* clone() const override { return new FillCubic(*this); } ~FillCubic() override = default; Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override; + bool is_self_crossing() override { return true; } protected: // The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill. diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ee223884fe..493a756c0f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3270,16 +3270,26 @@ std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point, const } double cap_speed( - double speed, const double mm3_per_mm, const FullPrintConfig &config, int extruder_id + double speed, const FullPrintConfig &config, int extruder_id, const ExtrusionAttributes &path_attr ) { - const double general_cap{config.max_volumetric_speed.value}; - if (general_cap > 0) { - speed = std::min(speed, general_cap / mm3_per_mm); + const double general_volumetric_cap{config.max_volumetric_speed.value}; + if (general_volumetric_cap > 0) { + speed = std::min(speed, general_volumetric_cap / path_attr.mm3_per_mm); } - const double filament_cap{config.filament_max_volumetric_speed.get_at(extruder_id)}; - if (filament_cap > 0) { - speed = std::min(speed, filament_cap / mm3_per_mm); + const double filament_volumetric_cap{config.filament_max_volumetric_speed.get_at(extruder_id)}; + if (filament_volumetric_cap > 0) { + speed = std::min(speed, filament_volumetric_cap / path_attr.mm3_per_mm); } + if (path_attr.role == ExtrusionRole::InternalInfill) { + const double infill_cap{ + path_attr.maybe_self_crossing ? + config.filament_infill_max_crossing_speed.get_at(extruder_id) : + config.filament_infill_max_speed.get_at(extruder_id)}; + if (infill_cap > 0) { + speed = std::min(speed, infill_cap); + } + } + return speed; } @@ -3411,7 +3421,7 @@ std::string GCodeGenerator::_extrude( if (external_perim_reference_speed == 0) external_perim_reference_speed = m_volumetric_speed / path_attr.mm3_per_mm; external_perim_reference_speed = cap_speed( - external_perim_reference_speed, path_attr.mm3_per_mm, m_config, m_writer.extruder()->id() + external_perim_reference_speed, m_config, m_writer.extruder()->id(), path_attr ); dynamic_speed_and_fan_speed = ExtrusionProcessor::calculate_overhang_speed(path_attr, this->m_config, m_writer.extruder()->id(), @@ -3423,7 +3433,7 @@ std::string GCodeGenerator::_extrude( } // cap speed with max_volumetric_speed anyway (even if user is not using autospeed) - speed = cap_speed(speed, path_attr.mm3_per_mm, m_config, m_writer.extruder()->id()); + speed = cap_speed(speed, m_config, m_writer.extruder()->id(), path_attr); double F = speed * 60; // convert mm/sec to mm/min diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index cb5e86fb32..1df3b342d3 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -486,7 +486,7 @@ static std::vector s_Preset_print_options { }; static std::vector s_Preset_filament_options { - "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed", + "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed", "filament_infill_max_speed", "filament_infill_max_crossing_speed", "extrusion_multiplier", "filament_density", "filament_cost", "filament_spool_weight", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time", "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", "filament_stamping_loading_speed", "filament_stamping_distance", "filament_cooling_initial_speed", "filament_purge_multiplier", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 62dc11d0a7..edfb1715cc 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -235,6 +235,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "filament_multitool_ramming_volume" || opt_key == "filament_multitool_ramming_flow" || opt_key == "filament_max_volumetric_speed" + || opt_key == "filament_infill_max_speed" + || opt_key == "filament_infill_max_crossing_speed" || opt_key == "gcode_flavor" || opt_key == "high_current_on_filament_swap" || opt_key == "infill_first" diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 264454adac..13c100f3a9 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1137,6 +1137,26 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats { 0. }); + def = this->add("filament_infill_max_speed", coFloats); + def->label = L("Max simple infill speed"); + def->tooltip = L("Maximum speed allowed for this filament while printing simple infill. " + "The term \"simple infill\" means infill without any self intersections in a single layer. " + "Set to zero for no limit."); + def->sidetext = L("mm/s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 0. }); + + def = this->add("filament_infill_max_crossing_speed", coFloats); + def->label = L("Max crossing infill speed"); + def->tooltip = L("Maximum speed allowed for this filament while printing crossing infill. " + "The term \"crossing infill\" means infill with self intersections in a single layer. " + "Set to zero for no limit."); + def->sidetext = L("mm/s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 0. }); + def = this->add("filament_loading_speed", coFloats); def->label = L("Loading speed"); def->tooltip = L("Speed used for loading the filament on the wipe tower."); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 7cd88fd6ff..ebd63716c9 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -762,6 +762,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloats, filament_cost)) ((ConfigOptionFloats, filament_spool_weight)) ((ConfigOptionFloats, filament_max_volumetric_speed)) + ((ConfigOptionFloats, filament_infill_max_speed)) + ((ConfigOptionFloats, filament_infill_max_crossing_speed)) ((ConfigOptionFloats, filament_loading_speed)) ((ConfigOptionFloats, filament_loading_speed_start)) ((ConfigOptionFloats, filament_load_time)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index fb084e14b7..cfecb623ad 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2238,6 +2238,9 @@ void TabFilament::build() }; optgroup->append_line(line); + optgroup->append_single_option_line("filament_infill_max_speed", "max-simple-infill-speed"); + optgroup->append_single_option_line("filament_infill_max_crossing_speed", "max-crossing-infill-speed"); + optgroup = page->new_optgroup(L("Shrinkage compensation")); optgroup->append_single_option_line("filament_shrinkage_compensation_xy"); optgroup->append_single_option_line("filament_shrinkage_compensation_z");