Merge branch 'lh_different_nozzle_diameters'

This commit is contained in:
Lukas Matena 2024-12-11 16:38:19 +01:00
commit f7a88d4ee1
11 changed files with 214 additions and 45 deletions

View File

@ -230,37 +230,64 @@ double Flow::mm3_per_mm() const
return res; return res;
} }
static float min_nozzle_diameter(const PrintObject &print_object)
{
const ConfigOptionFloats &nozzle_diameters = print_object.print()->config().nozzle_diameter;
float min_nozzle_diameter = std::numeric_limits<float>::max();
for (const double nozzle_diameter : nozzle_diameters.values) {
min_nozzle_diameter = std::min(min_nozzle_diameter, static_cast<float>(nozzle_diameter));
}
return min_nozzle_diameter;
}
Flow support_material_flow(const PrintObject *object, float layer_height) Flow support_material_flow(const PrintObject *object, float layer_height)
{ {
const PrintConfig &print_config = object->print()->config();
const int extruder = object->config().support_material_extruder - 1;
// If object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), use the smallest nozzle diameter.
const float nozzle_diameter = extruder >= 0 ? static_cast<float>(print_config.nozzle_diameter.get_at(extruder)) : min_nozzle_diameter(*object);
return Flow::new_from_config_width( return Flow::new_from_config_width(
frSupportMaterial, frSupportMaterial,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(object->config().support_material_extrusion_width.value > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width, (object->config().support_material_extrusion_width.value > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
// if object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. nozzle_diameter,
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value)); (layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
} }
Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height) Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height)
{ {
const PrintConfig &print_config = object->print()->config(); const PrintConfig &print_config = object->print()->config();
const auto &width = (print_config.first_layer_extrusion_width.value > 0) ? print_config.first_layer_extrusion_width : object->config().support_material_extrusion_width; const int extruder = object->config().support_material_extruder - 1;
// If object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), use the smallest nozzle diameter.
const float nozzle_diameter = extruder >= 0 ? static_cast<float>(print_config.nozzle_diameter.get_at(extruder)) : min_nozzle_diameter(*object);
const auto &width = (print_config.first_layer_extrusion_width.value > 0) ? print_config.first_layer_extrusion_width : object->config().support_material_extrusion_width;
return Flow::new_from_config_width( return Flow::new_from_config_width(
frSupportMaterial, frSupportMaterial,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(width.value > 0) ? width : object->config().extrusion_width, (width.value > 0) ? width : object->config().extrusion_width,
float(print_config.nozzle_diameter.get_at(object->config().support_material_extruder-1)), nozzle_diameter,
(layer_height > 0.f) ? layer_height : float(print_config.first_layer_height.get_abs_value(object->config().layer_height.value))); (layer_height > 0.f) ? layer_height : float(print_config.first_layer_height.get_abs_value(object->config().layer_height.value)));
} }
Flow support_material_interface_flow(const PrintObject *object, float layer_height) Flow support_material_interface_flow(const PrintObject *object, float layer_height)
{ {
const PrintConfig &print_config = object->print()->config();
const int extruder = object->config().support_material_interface_extruder - 1;
// If object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), use the smallest nozzle diameter.
const float nozzle_diameter = extruder >= 0 ? static_cast<float>(print_config.nozzle_diameter.get_at(extruder)) : min_nozzle_diameter(*object);
return Flow::new_from_config_width( return Flow::new_from_config_width(
frSupportMaterialInterface, frSupportMaterialInterface,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(object->config().support_material_extrusion_width > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width, (object->config().support_material_extrusion_width > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
// if object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. nozzle_diameter,
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_interface_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value)); (layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
} }

View File

@ -510,6 +510,7 @@ static std::vector<std::string> s_Preset_print_options {
"perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", "perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
"wall_distribution_count", "min_feature_size", "min_bead_width", "wall_distribution_count", "min_feature_size", "min_bead_width",
"top_one_perimeter_type", "only_one_perimeter_first_layer", "top_one_perimeter_type", "only_one_perimeter_first_layer",
"automatic_extrusion_widths", "automatic_infill_combination", "automatic_infill_combination_max_layer_height",
}; };
static std::vector<std::string> s_Preset_filament_options { static std::vector<std::string> s_Preset_filament_options {

View File

@ -283,6 +283,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
steps.emplace_back(psSkirtBrim); steps.emplace_back(psSkirtBrim);
} else if (opt_key == "avoid_crossing_curled_overhangs") { } else if (opt_key == "avoid_crossing_curled_overhangs") {
osteps.emplace_back(posEstimateCurledExtrusions); osteps.emplace_back(posEstimateCurledExtrusions);
} else if (opt_key == "automatic_extrusion_widths") {
osteps.emplace_back(posPerimeters);
} else { } else {
// for legacy, if we can't handle this option let's invalidate all steps // for legacy, if we can't handle this option let's invalidate all steps
//FIXME invalidate all steps of all objects as well? //FIXME invalidate all steps of all objects as well?
@ -627,15 +629,19 @@ std::string Print::validate(std::vector<std::string>* warnings) const
if (this->has_wipe_tower() && ! m_objects.empty()) { if (this->has_wipe_tower() && ! m_objects.empty()) {
// Make sure all extruders use same diameter filament and have the same nozzle diameter // Make sure all extruders use same diameter filament and have the same nozzle diameter
// EPSILON comparison is used for nozzles and 10 % tolerance is used for filaments // EPSILON comparison is used for nozzles and 10 % tolerance is used for filaments
double first_nozzle_diam = m_config.nozzle_diameter.get_at(extruders.front()); double first_nozzle_diam = m_config.nozzle_diameter.get_at(extruders.front());
double first_filament_diam = m_config.filament_diameter.get_at(extruders.front()); double first_filament_diam = m_config.filament_diameter.get_at(extruders.front());
bool allow_nozzle_diameter_differ_warning = (warnings != nullptr);
for (const auto& extruder_idx : extruders) { for (const auto& extruder_idx : extruders) {
double nozzle_diam = m_config.nozzle_diameter.get_at(extruder_idx); double nozzle_diam = m_config.nozzle_diameter.get_at(extruder_idx);
double filament_diam = m_config.filament_diameter.get_at(extruder_idx); double filament_diam = m_config.filament_diameter.get_at(extruder_idx);
if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam if (allow_nozzle_diameter_differ_warning && (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam)) {
|| std::abs((filament_diam-first_filament_diam)/first_filament_diam) > 0.1) allow_nozzle_diameter_differ_warning = false;
return _u8L("The wipe tower is only supported if all extruders have the same nozzle diameter " warnings->emplace_back("_WIPE_TOWER_NOZZLE_DIAMETER_DIFFER");
"and use filaments of the same diameter."); } else if (std::abs((filament_diam - first_filament_diam) / first_filament_diam) > 0.1) {
return _u8L("The wipe tower is only supported if all extruders use filaments of the same diameter.");
}
} }
if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware && if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware &&
@ -738,13 +744,11 @@ std::string Print::validate(std::vector<std::string>* warnings) const
}; };
for (PrintObject *object : m_objects) { for (PrintObject *object : m_objects) {
if (object->has_support_material()) { if (object->has_support_material()) {
if ((object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) { if (warnings != nullptr && (object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) {
// The object has some form of support and either support_material_extruder or support_material_interface_extruder // The object has some form of support and either support_material_extruder or support_material_interface_extruder
// will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles // will be printed with the current tool without a forced tool change.
// are of the same diameter. // Notify the user that printing supports with different nozzle diameters is experimental and requires caution.
return _u8L("Printing with multiple extruders of differing nozzle diameters. " warnings->emplace_back("_SUPPORT_NOZZLE_DIAMETER_DIFFER");
"If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), "
"all nozzles have to be of the same diameter.");
} }
if (this->has_wipe_tower() && object->config().support_material_style != smsOrganic) { if (this->has_wipe_tower() && object->config().support_material_style != smsOrganic) {
if (object->config().support_material_contact_distance == 0) { if (object->config().support_material_contact_distance == 0) {

View File

@ -527,6 +527,31 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<ArcFittingType>(ArcFittingType::Disabled)); def->set_default_value(new ConfigOptionEnum<ArcFittingType>(ArcFittingType::Disabled));
def = this->add("automatic_extrusion_widths", coBool);
def->label = L("Automatic extrusion widths calculation");
def->category = L("Extrusion Width");
def->tooltip = L("Automatically calculates extrusion widths based on the nozzle diameter of the currently used extruder. "
"This setting is essential for printing with different nozzle diameters.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("automatic_infill_combination", coBool);
def->label = L("Automatic infill combination");
def->category = L("Infill");
def->tooltip = L("This feature automatically combine infill of several layers and speeds up your print by extruding thicker "
"infill layers while preserving thin perimeters, thus accuracy.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("automatic_infill_combination_max_layer_height", coFloatOrPercent);
def->label = L("Automatic infill combination - Max layer height");
def->category = L("Infill");
def->tooltip = L("Maximum layer height for combining infill when automatic infill combining is enabled. "
"Maximum layer height could be specified either as an absolute in millimeters value or as a percentage of nozzle diameter. "
"For printing with different nozzle diameters, it is recommended to use percentage value over absolute value.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(100., true));
// Maximum extruder temperature, bumped to 1500 to support printing of glass. // Maximum extruder temperature, bumped to 1500 to support printing of glass.
const int max_temp = 1500; const int max_temp = 1500;
def = this->add("avoid_crossing_curled_overhangs", coBool); def = this->add("avoid_crossing_curled_overhangs", coBool);

View File

@ -685,6 +685,8 @@ PRINT_CONFIG_CLASS_DEFINE(
PRINT_CONFIG_CLASS_DEFINE( PRINT_CONFIG_CLASS_DEFINE(
PrintRegionConfig, PrintRegionConfig,
((ConfigOptionBool, automatic_infill_combination))
((ConfigOptionFloatOrPercent, automatic_infill_combination_max_layer_height))
((ConfigOptionFloat, bridge_angle)) ((ConfigOptionFloat, bridge_angle))
((ConfigOptionInt, bottom_solid_layers)) ((ConfigOptionInt, bottom_solid_layers))
((ConfigOptionFloat, bottom_solid_min_thickness)) ((ConfigOptionFloat, bottom_solid_min_thickness))
@ -898,6 +900,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
PrintConfig, PrintConfig,
(MachineEnvelopeConfig, GCodeConfig), (MachineEnvelopeConfig, GCodeConfig),
((ConfigOptionBool, automatic_extrusion_widths))
((ConfigOptionBool, avoid_crossing_curled_overhangs)) ((ConfigOptionBool, avoid_crossing_curled_overhangs))
((ConfigOptionBool, avoid_crossing_perimeters)) ((ConfigOptionBool, avoid_crossing_perimeters))
((ConfigOptionFloatOrPercent, avoid_crossing_perimeters_max_detour)) ((ConfigOptionFloatOrPercent, avoid_crossing_perimeters_max_detour))

View File

@ -808,6 +808,8 @@ bool PrintObject::invalidate_state_by_config_options(
opt_key == "interface_shells" opt_key == "interface_shells"
|| opt_key == "infill_only_where_needed" || opt_key == "infill_only_where_needed"
|| opt_key == "infill_every_layers" || opt_key == "infill_every_layers"
|| opt_key == "automatic_infill_combination"
|| opt_key == "automatic_infill_combination_max_layer_height"
|| opt_key == "solid_infill_every_layers" || opt_key == "solid_infill_every_layers"
|| opt_key == "ensure_vertical_shell_thickness" || opt_key == "ensure_vertical_shell_thickness"
|| opt_key == "bottom_solid_min_thickness" || opt_key == "bottom_solid_min_thickness"
@ -3053,16 +3055,24 @@ void PrintObject::discover_horizontal_shells()
void PrintObject::combine_infill() void PrintObject::combine_infill()
{ {
// Work on each region separately. // Work on each region separately.
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) { for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
const PrintRegion &region = this->printing_region(region_id); const PrintRegion &region = this->printing_region(region_id);
const size_t every = region.config().infill_every_layers.value; const size_t combine_infill_every_n_layers = region.config().infill_every_layers.value;
if (every < 2 || region.config().fill_density == 0.) const bool automatic_infill_combination = region.config().automatic_infill_combination;
const bool enable_combine_infill = automatic_infill_combination || combine_infill_every_n_layers >= 2;
if (!enable_combine_infill || region.config().fill_density == 0.) {
continue; continue;
}
// Limit the number of combined layers to the maximum height allowed by this regions' nozzle. // Limit the number of combined layers to the maximum height allowed by this regions' nozzle.
//FIXME limit the layer height to max_layer_height //FIXME limit the layer height to max_layer_height
double nozzle_diameter = std::min( const double nozzle_diameter = std::min(this->print()->config().nozzle_diameter.get_at(region.config().infill_extruder.value - 1),
this->print()->config().nozzle_diameter.get_at(region.config().infill_extruder.value - 1), this->print()->config().nozzle_diameter.get_at(region.config().solid_infill_extruder.value - 1));
this->print()->config().nozzle_diameter.get_at(region.config().solid_infill_extruder.value - 1));
const double automatic_infill_combination_max_layer_height = region.config().automatic_infill_combination_max_layer_height.get_abs_value(nozzle_diameter);
const double max_combine_layer_height = automatic_infill_combination ? std::min(automatic_infill_combination_max_layer_height, nozzle_diameter) : nozzle_diameter;
// define the combinations // define the combinations
std::vector<size_t> combine(m_layers.size(), 0); std::vector<size_t> combine(m_layers.size(), 0);
{ {
@ -3070,19 +3080,21 @@ void PrintObject::combine_infill()
size_t num_layers = 0; size_t num_layers = 0;
for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) { for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) {
m_print->throw_if_canceled(); m_print->throw_if_canceled();
const Layer *layer = m_layers[layer_idx]; const Layer &layer = *m_layers[layer_idx];
if (layer->id() == 0) if (layer.id() == 0)
// Skip first print layer (which may not be first layer in array because of raft). // Skip first print layer (which may not be first layer in array because of raft).
continue; continue;
// Check whether the combination of this layer with the lower layers' buffer // Check whether the combination of this layer with the lower layers' buffer
// would exceed max layer height or max combined layer count. // would exceed max layer height or max combined layer count.
if (current_height + layer->height >= nozzle_diameter + EPSILON || num_layers >= every) { if (current_height + layer.height >= max_combine_layer_height + EPSILON || (!automatic_infill_combination && num_layers >= combine_infill_every_n_layers)) {
// Append combination to lower layer. // Append combination to lower layer.
combine[layer_idx - 1] = num_layers; combine[layer_idx - 1] = num_layers;
current_height = 0.; current_height = 0.;
num_layers = 0; num_layers = 0;
} }
current_height += layer->height;
current_height += layer.height;
++ num_layers; ++ num_layers;
} }

View File

@ -38,6 +38,64 @@ void ConfigManipulation::toggle_field(const std::string& opt_key, const bool tog
cb_toggle_field(opt_key, toggle, opt_index); cb_toggle_field(opt_key, toggle, opt_index);
} }
std::optional<DynamicPrintConfig> handle_automatic_extrusion_widths(const DynamicPrintConfig &config, const bool is_global_config, wxWindow *msg_dlg_parent)
{
const std::vector<std::string> extrusion_width_parameters = {"extrusion_width", "external_perimeter_extrusion_width", "first_layer_extrusion_width",
"infill_extrusion_width", "perimeter_extrusion_width", "solid_infill_extrusion_width",
"support_material_extrusion_width", "top_infill_extrusion_width"};
auto is_zero_width = [](const ConfigOptionFloatOrPercent &opt) -> bool {
return opt.value == 0. && !opt.percent;
};
auto is_parameters_adjustment_needed = [&is_zero_width, &config, &extrusion_width_parameters]() -> bool {
if (!config.opt_bool("automatic_extrusion_widths")) {
return false;
}
for (const std::string &extrusion_width_parameter : extrusion_width_parameters) {
if (!is_zero_width(*config.option<ConfigOptionFloatOrPercent>(extrusion_width_parameter))) {
return true;
}
}
return false;
};
if (is_parameters_adjustment_needed()) {
wxString msg_text = _(L("The automatic extrusion widths calculation requires:\n"
"- Default extrusion width: 0\n"
"- First layer extrusion width: 0\n"
"- Perimeter extrusion width: 0\n"
"- External perimeter extrusion width: 0\n"
"- Infill extrusion width: 0\n"
"- Solid infill extrusion width: 0\n"
"- Top infill extrusion width: 0\n"
"- Support material extrusion width: 0"));
if (is_global_config) {
msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable automatic extrusion widths calculation?"));
}
MessageDialog dialog(msg_dlg_parent, msg_text, _(L("Automatic extrusion widths calculation")),
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
const int answer = dialog.ShowModal();
DynamicPrintConfig new_conf = config;
if (!is_global_config || answer == wxID_YES) {
for (const std::string &extrusion_width_parameter : extrusion_width_parameters) {
new_conf.set_key_value(extrusion_width_parameter, new ConfigOptionFloatOrPercent(0., false));
}
} else {
new_conf.set_key_value("automatic_extrusion_widths", new ConfigOptionBool(false));
}
return new_conf;
}
return std::nullopt;
}
void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config) void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config)
{ {
// #ys_FIXME_to_delete // #ys_FIXME_to_delete
@ -76,7 +134,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
double fill_density = config->option<ConfigOptionPercent>("fill_density")->value; double fill_density = config->option<ConfigOptionPercent>("fill_density")->value;
if (config->opt_bool("spiral_vase") && if (config->opt_bool("spiral_vase") &&
! (config->opt_int("perimeters") == 1 && ! (config->opt_int("perimeters") == 1 &&
config->opt_int("top_solid_layers") == 0 && config->opt_int("top_solid_layers") == 0 &&
fill_density == 0 && fill_density == 0 &&
! config->opt_bool("support_material") && ! config->opt_bool("support_material") &&
@ -102,7 +160,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); new_conf.set_key_value("fill_density", new ConfigOptionPercent(0));
new_conf.set_key_value("support_material", new ConfigOptionBool(false)); new_conf.set_key_value("support_material", new ConfigOptionBool(false));
new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0)); new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0));
new_conf.set_key_value("thin_walls", new ConfigOptionBool(false)); new_conf.set_key_value("thin_walls", new ConfigOptionBool(false));
fill_density = 0; fill_density = 0;
support = false; support = false;
} }
@ -213,6 +271,13 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
} }
} }
} }
if (config->opt_bool("automatic_extrusion_widths")) {
std::optional<DynamicPrintConfig> new_config = handle_automatic_extrusion_widths(*config, is_global_config, m_msg_dlg_parent);
if (new_config.has_value()) {
apply(config, &(*new_config));
}
}
} }
void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
@ -227,11 +292,17 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
toggle_field("overhang_speed_" + std::to_string(i), config->opt_bool("enable_dynamic_overhang_speeds")); toggle_field("overhang_speed_" + std::to_string(i), config->opt_bool("enable_dynamic_overhang_speeds"));
} }
bool have_infill = config->option<ConfigOptionPercent>("fill_density")->value > 0; const bool have_infill = config->option<ConfigOptionPercent>("fill_density")->value > 0;
const bool has_automatic_infill_combination = config->option<ConfigOptionBool>("automatic_infill_combination")->value;
// infill_extruder uses the same logic as in Print::extruders() // infill_extruder uses the same logic as in Print::extruders()
for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed", for (auto el : { "fill_pattern","solid_infill_every_layers", "solid_infill_below_area", "infill_extruder",
"solid_infill_every_layers", "solid_infill_below_area", "infill_extruder", "infill_anchor_max" }) "infill_anchor_max", "automatic_infill_combination" }) {
toggle_field(el, have_infill); toggle_field(el, have_infill);
}
toggle_field("infill_every_layers", have_infill && !has_automatic_infill_combination);
toggle_field("automatic_infill_combination_max_layer_height", have_infill && has_automatic_infill_combination);
// Only allow configuration of open anchors if the anchoring is enabled. // Only allow configuration of open anchors if the anchoring is enabled.
bool has_infill_anchors = have_infill && config->option<ConfigOptionFloatOrPercent>("infill_anchor_max")->value > 0; bool has_infill_anchors = have_infill && config->option<ConfigOptionFloatOrPercent>("infill_anchor_max")->value > 0;
toggle_field("infill_anchor", has_infill_anchors); toggle_field("infill_anchor", has_infill_anchors);

View File

@ -133,7 +133,7 @@ void NotificationManager::NotificationIDProvider::release_id(int) {}
#endif #endif
//------PopNotification-------- //------PopNotification--------
NotificationManager::PopNotification::PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler) : NotificationManager::PopNotification::PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler, const bool multiline) :
m_data (n) m_data (n)
, m_id_provider (id_provider) , m_id_provider (id_provider)
, m_text1 (n.text1) , m_text1 (n.text1)
@ -141,6 +141,7 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n,
, m_text2 (n.text2) , m_text2 (n.text2)
, m_evt_handler (evt_handler) , m_evt_handler (evt_handler)
, m_notification_start (GLCanvas3D::timestamp_now()) , m_notification_start (GLCanvas3D::timestamp_now())
, m_multiline (multiline)
{} {}
void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width) void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width)
@ -2157,10 +2158,11 @@ void NotificationManager::push_notification(NotificationType type,
const std::string& hypertext, const std::string& hypertext,
std::function<bool(wxEvtHandler*)> callback, std::function<bool(wxEvtHandler*)> callback,
const std::string& text_after, const std::string& text_after,
int timestamp) const int timestamp,
const bool multiline)
{ {
int duration = get_standard_duration(level); int duration = get_standard_duration(level);
push_notification_data({ type, level, duration, text, hypertext, callback, text_after }, timestamp); push_notification_data({ type, level, duration, text, hypertext, callback, text_after }, timestamp, multiline);
} }
void NotificationManager::push_delayed_notification(const NotificationType type, std::function<bool(void)> condition_callback, int64_t initial_delay, int64_t delay_interval) void NotificationManager::push_delayed_notification(const NotificationType type, std::function<bool(void)> condition_callback, int64_t initial_delay, int64_t delay_interval)
@ -2839,9 +2841,9 @@ void NotificationManager::push_updated_item_info_notification(InfoItemType type)
} }
} }
bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp) bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp, const bool multiline)
{ {
return push_notification_data(std::make_unique<PopNotification>(notification_data, m_id_provider, m_evt_handler), timestamp); return push_notification_data(std::make_unique<PopNotification>(notification_data, m_id_provider, m_evt_handler, multiline), timestamp);
} }
bool NotificationManager::push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp) bool NotificationManager::push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp)
{ {

View File

@ -140,6 +140,10 @@ enum class NotificationType
BedTemperaturesDiffer, BedTemperaturesDiffer,
// Notification that shrinkage compensations for the used filaments differ. // Notification that shrinkage compensations for the used filaments differ.
ShrinkageCompensationsDiffer, ShrinkageCompensationsDiffer,
// Notification about using wipe tower with different nozzle diameters.
WipeTowerNozzleDiameterDiffer,
// Notification about using supports with different nozzle diameters.
SupportNozzleDiameterDiffer,
}; };
class NotificationManager class NotificationManager
@ -179,7 +183,7 @@ public:
// Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotificationLevel. // Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotificationLevel.
// ErrorNotificationLevel are never faded out. // ErrorNotificationLevel are never faded out.
void push_notification(NotificationType type, NotificationLevel level, const std::string& text, const std::string& hypertext = "", void push_notification(NotificationType type, NotificationLevel level, const std::string& text, const std::string& hypertext = "",
std::function<bool(wxEvtHandler*)> callback = std::function<bool(wxEvtHandler*)>(), const std::string& text_after = "", int timestamp = 0); std::function<bool(wxEvtHandler*)> callback = std::function<bool(wxEvtHandler*)>(), const std::string& text_after = "", int timestamp = 0, bool multiline = false);
// Pushes basic_notification with delay. See push_delayed_notification_data. // Pushes basic_notification with delay. See push_delayed_notification_data.
void push_delayed_notification(const NotificationType type, std::function<bool(void)> condition_callback, int64_t initial_delay, int64_t delay_interval); void push_delayed_notification(const NotificationType type, std::function<bool(void)> condition_callback, int64_t initial_delay, int64_t delay_interval);
// Removes all notifications of type from m_waiting_notifications // Removes all notifications of type from m_waiting_notifications
@ -342,7 +346,7 @@ private:
Paused Paused
}; };
PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler); PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler, bool multiline = false);
virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); } virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); }
virtual void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width); virtual void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width);
// close will dissapear notification on next render // close will dissapear notification on next render
@ -853,7 +857,7 @@ private:
//pushes notification into the queue of notifications that are rendered //pushes notification into the queue of notifications that are rendered
//can be used to create custom notification //can be used to create custom notification
bool push_notification_data(const NotificationData& notification_data, int timestamp); bool push_notification_data(const NotificationData& notification_data, int timestamp, bool multiline = false);
bool push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp); bool push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp);
// Delayed notifications goes first to the m_waiting_notifications vector and only after remaining time is <= 0 // Delayed notifications goes first to the m_waiting_notifications vector and only after remaining time is <= 0
// and condition callback is success, notification is regular pushed from update function. // and condition callback is success, notification is regular pushed from update function.

View File

@ -2098,12 +2098,16 @@ void Plater::priv::process_validation_warning(const std::vector<std::string>& wa
if (warnings.empty()) if (warnings.empty())
notification_manager->close_notification_of_type(NotificationType::ValidateWarning); notification_manager->close_notification_of_type(NotificationType::ValidateWarning);
// Always close warnings BedTemperaturesDiffer and ShrinkageCompensationsDiffer before next processing. // Always close warnings BedTemperaturesDiffer, ShrinkageCompensationsDiffer, WipeTowerNozzleDiameterDiffer and SupportNozzleDiameterDiffer before next processing.
notification_manager->close_notification_of_type(NotificationType::BedTemperaturesDiffer); notification_manager->close_notification_of_type(NotificationType::BedTemperaturesDiffer);
notification_manager->close_notification_of_type(NotificationType::ShrinkageCompensationsDiffer); notification_manager->close_notification_of_type(NotificationType::ShrinkageCompensationsDiffer);
notification_manager->close_notification_of_type(NotificationType::WipeTowerNozzleDiameterDiffer);
notification_manager->close_notification_of_type(NotificationType::SupportNozzleDiameterDiffer);
for (std::string text : warnings) { for (std::string text : warnings) {
std::string hypertext = ""; std::string hypertext = "";
std::string text_after = "";
bool multiline = false;
NotificationType notification_type = NotificationType::ValidateWarning; NotificationType notification_type = NotificationType::ValidateWarning;
std::function<bool(wxEvtHandler*)> action_fn = [](wxEvtHandler*){ return false; }; std::function<bool(wxEvtHandler*)> action_fn = [](wxEvtHandler*){ return false; };
@ -2128,12 +2132,26 @@ void Plater::priv::process_validation_warning(const std::vector<std::string>& wa
text = _u8L("Filament shrinkage will not be used because filament shrinkage " text = _u8L("Filament shrinkage will not be used because filament shrinkage "
"for the used filaments differs significantly."); "for the used filaments differs significantly.");
notification_type = NotificationType::ShrinkageCompensationsDiffer; notification_type = NotificationType::ShrinkageCompensationsDiffer;
} else if (text == "_WIPE_TOWER_NOZZLE_DIAMETER_DIFFER") {
text = _u8L("Using the wipe tower for extruders with different nozzle diameters "
"is experimental, so proceed with caution.");
notification_type = NotificationType::WipeTowerNozzleDiameterDiffer;
} else if (text == "_SUPPORT_NOZZLE_DIAMETER_DIFFER") {
text = _u8L("Printing supports with different nozzle diameters "
"is experimental. For best results, switch to Organic supports and");
hypertext = _u8L("assign a specific extruder for supports.");
multiline = true;
notification_type = NotificationType::SupportNozzleDiameterDiffer;
action_fn = [](wxEvtHandler*) {
GUI::wxGetApp().jump_to_option("support_material_extruder", Preset::Type::TYPE_PRINT, boost::nowide::widen("Multiple Extruders"));
return false;
};
} }
notification_manager->push_notification( notification_manager->push_notification(
notification_type, notification_type,
NotificationManager::NotificationLevel::WarningNotificationLevel, NotificationManager::NotificationLevel::WarningNotificationLevel,
_u8L("WARNING:") + "\n" + text, hypertext, action_fn _u8L("WARNING:") + "\n" + text, hypertext, action_fn, text_after, 0, multiline
); );
} }
} }

View File

@ -1503,8 +1503,9 @@ void TabPrint::build()
optgroup = page->new_optgroup(L("Reducing printing time")); optgroup = page->new_optgroup(L("Reducing printing time"));
category_path = "infill_42#"; category_path = "infill_42#";
optgroup->append_single_option_line("automatic_infill_combination");
optgroup->append_single_option_line("automatic_infill_combination_max_layer_height");
optgroup->append_single_option_line("infill_every_layers", category_path + "combine-infill-every-x-layers"); optgroup->append_single_option_line("infill_every_layers", category_path + "combine-infill-every-x-layers");
// optgroup->append_single_option_line("infill_only_where_needed", category_path + "only-infill-where-needed");
optgroup = page->new_optgroup(L("Advanced")); optgroup = page->new_optgroup(L("Advanced"));
optgroup->append_single_option_line("solid_infill_every_layers", category_path + "solid-infill-every-x-layers"); optgroup->append_single_option_line("solid_infill_every_layers", category_path + "solid-infill-every-x-layers");
@ -1662,6 +1663,7 @@ void TabPrint::build()
optgroup->append_single_option_line("solid_infill_extrusion_width"); optgroup->append_single_option_line("solid_infill_extrusion_width");
optgroup->append_single_option_line("top_infill_extrusion_width"); optgroup->append_single_option_line("top_infill_extrusion_width");
optgroup->append_single_option_line("support_material_extrusion_width"); optgroup->append_single_option_line("support_material_extrusion_width");
optgroup->append_single_option_line("automatic_extrusion_widths");
optgroup = page->new_optgroup(L("Overlap")); optgroup = page->new_optgroup(L("Overlap"));
optgroup->append_single_option_line("infill_overlap"); optgroup->append_single_option_line("infill_overlap");