mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-12 20:19:09 +08:00
Merge branch 'lh_different_nozzle_diameters'
This commit is contained in:
commit
f7a88d4ee1
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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))
|
||||||
|
@ -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 ®ion = this->printing_region(region_id);
|
const PrintRegion ®ion = 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user