diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 578c6df106..26952ae465 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -112,7 +112,7 @@ std::vector group_fills(const Layer &layer) FlowRole extrusion_role = surface.has_pos_top() ? frTopSolidInfill : (surface.has_fill_solid() ? frSolidInfill : frInfill); bool is_bridge = layer.id() > 0 && surface.has_mod_bridge(); bool is_denser = false; - params.extruder = layerm.region()->extruder(extrusion_role); + params.extruder = layerm.region()->extruder(extrusion_role, *layer.object()); params.pattern = region_config.fill_pattern.value; params.density = float(region_config.fill_density) / 100.f; params.dont_adjust = false; @@ -324,7 +324,7 @@ std::vector group_fills(const Layer &layer) } if (internal_solid_fill == nullptr) { // Produce another solid fill. - params.extruder = layerm.region()->extruder(frSolidInfill); + params.extruder = layerm.region()->extruder(frSolidInfill, *layer.object()); params.pattern = layerm.region()->config().solid_fill_pattern.value; params.density = 100.f; params.role = erInternalInfill; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 6cca950064..38883733d2 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1518,20 +1518,6 @@ std::pair Print::validate() const return L("One or more object were assigned an extruder that the printer does not have."); #endif - auto validate_extrusion_width = [min_nozzle_diameter, max_nozzle_diameter](const ConfigBase &config, const char *opt_key, double layer_height, std::string &err_msg) -> bool { - double extrusion_width_min = config.get_abs_value(opt_key, min_nozzle_diameter); - double extrusion_width_max = config.get_abs_value(opt_key, max_nozzle_diameter); - if (extrusion_width_min == 0) { - // Default "auto-generated" extrusion width is always valid. - } else if (extrusion_width_min <= layer_height) { - err_msg = (boost::format(L("%1%=%2% mm is too low to be printable at a layer height %3% mm")) % opt_key % extrusion_width_min % layer_height).str(); - return false; - } else if (extrusion_width_max >= max_nozzle_diameter * 4.) { - err_msg = (boost::format(L("Excessive %1%=%2% mm to be printable with a nozzle diameter %3% mm")) % opt_key % extrusion_width_max % max_nozzle_diameter).str(); - return false; - } - return true; - }; for (PrintObject *object : m_objects) { if (object->config().raft_layers > 0 || object->config().support_material.value) { if ((object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) { @@ -1555,40 +1541,62 @@ std::pair Print::validate() const } } } - - // validate first_layer_height - double first_layer_height = object->config().get_abs_value("first_layer_height", this->m_config.nozzle_diameter.get_at(0)); - double first_layer_min_nozzle_diameter; - if (object->config().raft_layers > 0) { - // if we have raft layers, only support material extruder is used on first layer - size_t first_layer_extruder = object->config().raft_layers == 1 - ? object->config().support_material_interface_extruder-1 - : object->config().support_material_extruder-1; - first_layer_min_nozzle_diameter = (first_layer_extruder == size_t(-1)) ? - min_nozzle_diameter : - m_config.nozzle_diameter.get_at(first_layer_extruder); - } else { - // if we don't have raft layers, any nozzle diameter is potentially used in first layer - first_layer_min_nozzle_diameter = min_nozzle_diameter; + + // validate layer_height for each region + for (size_t region_id = 0; region_id < object->region_volumes.size(); ++region_id) { + if (object->region_volumes[region_id].empty()) continue; + const PrintRegion* region = this->regions()[region_id]; + std::vector object_extruders; + PrintRegion::collect_object_printing_extruders(config(), object->config(), region->config(), object_extruders); + //object->region_volumes[region_id].front().first.second < object->layers() + double layer_height = object->config().layer_height.value; + for (uint16_t extruder_id : object_extruders) { + double min_layer_height = config().min_layer_height.values[extruder_id]; + double max_layer_height = config().max_layer_height.values[extruder_id]; + double nozzle_diameter = config().nozzle_diameter.values[extruder_id]; + double first_layer_height = object->config().first_layer_height.get_abs_value(nozzle_diameter); + if (max_layer_height < EPSILON) max_layer_height = nozzle_diameter * 0.75; + + //check first layer + if (object->region_volumes[region_id].front().first.first < first_layer_height) { + if (first_layer_height + EPSILON < min_layer_height) + return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("First layer height can't be greater than %s")) % "min layer height").str() }; + for (auto tuple : std::vector>{ + {nozzle_diameter, "nozzle diameter"}, + {max_layer_height, "max layer height"}, + {skirt_flow(extruder_id).width, "skirt extrusion width"}, + {region->width(FlowRole::frSupportMaterial, true, *object), "support material extrusion width"}, + {region->width(FlowRole::frPerimeter, true, *object), "perimeter extrusion width"}, + {region->width(FlowRole::frExternalPerimeter, true, *object), "perimeter extrusion width"}, + {region->width(FlowRole::frInfill, true, *object), "infill extrusion width"}, + {region->width(FlowRole::frSolidInfill, true, *object), "solid infill extrusion width"}, + {region->width(FlowRole::frTopSolidInfill, true, *object), "top solid infill extrusion width"}, + }) + if (first_layer_height > tuple.first + EPSILON) + return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("First layer height can't be greater than %s")) % tuple.second).str() }; + + } + //check not-first layer + if (object->region_volumes[region_id].front().first.second > layer_height) { + if (layer_height + EPSILON < min_layer_height) + return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("First layer height can't be greater than %s")) % "min layer height").str() }; + for (auto tuple : std::vector>{ + {nozzle_diameter, "nozzle diameter"}, + {max_layer_height, "max layer height"}, + {skirt_flow(extruder_id).width, "skirt extrusion width"}, + {region->width(FlowRole::frSupportMaterial, false, *object), "support material extrusion width"}, + {region->width(FlowRole::frPerimeter, false, *object), "perimeter extrusion width"}, + {region->width(FlowRole::frExternalPerimeter, false, *object), "perimeter extrusion width"}, + {region->width(FlowRole::frInfill, false, *object), "infill extrusion width"}, + {region->width(FlowRole::frSolidInfill, false, *object), "solid infill extrusion width"}, + {region->width(FlowRole::frTopSolidInfill, false, *object), "top solid infill extrusion width"}, + }) + if (layer_height > tuple.first + EPSILON) + return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("Layer height can't be greater than %s")) % tuple.second).str() }; + } + } } - if (first_layer_height > first_layer_min_nozzle_diameter) - return { PrintBase::PrintValidationError::pveWrongSettings,L("First layer height can't be greater than nozzle diameter") }; - - // validate layer_height - double layer_height = object->config().layer_height.value; - if (layer_height > min_nozzle_diameter) - return { PrintBase::PrintValidationError::pveWrongSettings,L("Layer height can't be greater than nozzle diameter") }; - - // Validate extrusion widths. - std::string err_msg; - if (! validate_extrusion_width(object->config(), "extrusion_width", layer_height, err_msg)) - return { PrintBase::PrintValidationError::pveWrongSettings,err_msg }; - if ((object->config().support_material || object->config().raft_layers > 0) && ! validate_extrusion_width(object->config(), "support_material_extrusion_width", layer_height, err_msg)) - return { PrintBase::PrintValidationError::pveWrongSettings,err_msg }; - for (const char *opt_key : { "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width" }) - for (size_t i = 0; i < object->region_volumes.size(); ++ i) - if (! object->region_volumes[i].empty() && ! validate_extrusion_width(this->get_region(i)->config(), opt_key, layer_height, err_msg)) - return { PrintBase::PrintValidationError::pveWrongSettings, err_msg }; + } } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 840b87f8f3..ba79a4db5d 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -65,8 +65,9 @@ class PrintRegion const Print* print() const { return m_print; } const PrintRegionConfig& config() const { return m_config; } // 1-based extruder identifier for this region and role. - uint16_t extruder(FlowRole role) const; - Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const; + uint16_t extruder(FlowRole role, const PrintObject& object) const; + Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject& object) const; + float width(FlowRole role, bool first_layer, const PrintObject& object) const; // Average diameter of nozzles participating on extruding this region. coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const; // Average diameter of nozzles participating on extruding this region. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 73926cec71..7fc8f40b59 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5945,7 +5945,13 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const double max_nozzle_diameter = 0; for (double dmr : nozzle_diameter_option->values) max_nozzle_diameter = std::max(max_nozzle_diameter, dmr); - Flow flow = Flow::new_from_spacing(spacing_option->get_abs_value(max_nozzle_diameter), max_nozzle_diameter, layer_height_option->value, false); + double spacing_value = spacing_option->get_abs_value(max_nozzle_diameter); + Flow flow = Flow::new_from_spacing(spacing_value, max_nozzle_diameter,layer_height_option->value, false); + //test for valid height. If too high, revert to round shape + if (flow.height > spacing_value / (1 - (1. - 0.25 * PI) * flow.spacing_ratio)) { + flow.width = spacing_value / (1 - (1. - 0.25 * PI) * flow.spacing_ratio); + flow.height = flow.width; + } if (opt_key == "extrusion_spacing") { ConfigOptionFloatOrPercent* width_option = this->option("extrusion_width"); if (width_option) { @@ -6055,6 +6061,7 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const width_option->set_phony(false); spacing_option->set_phony(true); Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0); + if (flow.width < flow.height) flow.height = flow.width; spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000); spacing_option->percent = width_option->percent; something_changed = true; @@ -6066,6 +6073,7 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const width_option->set_phony(false); spacing_option->set_phony(true); Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0); + if (flow.width < flow.height) flow.height = flow.width; spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000); spacing_option->percent = width_option->percent; something_changed = true; @@ -6078,6 +6086,7 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const width_option->set_phony(false); spacing_option->set_phony(true); Flow flow = Flow::new_from_config_width(FlowRole::frExternalPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0); + if (flow.width < flow.height) flow.height = flow.width; flow.spacing_ratio = perimeter_overlap_option->get_abs_value(1); spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000); spacing_option->percent = width_option->percent; @@ -6091,6 +6100,7 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const width_option->set_phony(false); spacing_option->set_phony(true); Flow ext_perimeter_flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0); + if (ext_perimeter_flow.width < ext_perimeter_flow.height) ext_perimeter_flow.height = ext_perimeter_flow.width; ext_perimeter_flow.spacing_ratio = external_perimeter_overlap_option->get_abs_value(0.5); spacing_option->value = (width_option->percent) ? std::round(100 * ext_perimeter_flow.spacing() / max_nozzle_diameter) : (std::round(ext_perimeter_flow.spacing() * 10000) / 10000); spacing_option->percent = width_option->percent; @@ -6103,6 +6113,7 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const width_option->set_phony(false); spacing_option->set_phony(true); Flow flow = Flow::new_from_config_width(FlowRole::frInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0); + if (flow.width < flow.height) flow.height = flow.width; spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000); spacing_option->percent = width_option->percent; something_changed = true; @@ -6114,6 +6125,7 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const width_option->set_phony(false); spacing_option->set_phony(true); Flow flow = Flow::new_from_config_width(FlowRole::frSolidInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0); + if (flow.width < flow.height) flow.height = flow.width; spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000); spacing_option->percent = width_option->percent; something_changed = true; @@ -6125,6 +6137,7 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const width_option->set_phony(false); spacing_option->set_phony(true); Flow flow = Flow::new_from_config_width(FlowRole::frTopSolidInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0); + if (flow.width < flow.height) flow.height = flow.width; spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000); spacing_option->percent = width_option->percent; something_changed = true; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index f58efd88ec..02c3d50575 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2171,7 +2171,7 @@ namespace Slic3r { static void apply_to_print_region_config(PrintRegionConfig& out, const DynamicPrintConfig& in) { - // 1) Copy the "extruder key to infill_extruder and perimeter_extruder. + // 1) Copy the "extruder" key to infill_extruder and perimeter_extruder. std::string sextruder = "extruder"; auto* opt_extruder = in.opt(sextruder); if (opt_extruder) { @@ -2381,7 +2381,7 @@ namespace Slic3r { } std::vector expolygons_by_layer = this->slice_region(region_id, slice_zs, slicing_mode, slicing_mode_normal_below_layer, SlicingMode::Regular); //scale for shrinkage - const size_t extruder_id = this->print()->regions()[region_id]->extruder(FlowRole::frPerimeter) - 1; + const size_t extruder_id = this->print()->regions()[region_id]->extruder(FlowRole::frPerimeter, *this) - 1; double scale = print()->config().filament_shrink.get_abs_value(extruder_id, 1); if (scale != 1) { scale = 1 / scale; @@ -2434,7 +2434,7 @@ namespace Slic3r { } //scale for shrinkage for (SlicedVolume& sv : sliced_volumes) { - double scale = print()->config().filament_shrink.get_abs_value(this->print()->regions()[sv.region_id]->extruder(FlowRole::frPerimeter) - 1, 1); + double scale = print()->config().filament_shrink.get_abs_value(this->print()->regions()[sv.region_id]->extruder(FlowRole::frPerimeter, *this) - 1, 1); if (scale != 1) { scale = 1 / scale; for (ExPolygons& polys : sv.expolygons_by_layer) diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index 21f5d55863..e62b34ea6b 100644 --- a/src/libslic3r/PrintRegion.cpp +++ b/src/libslic3r/PrintRegion.cpp @@ -4,7 +4,7 @@ namespace Slic3r { // 1-based extruder identifier for this region and role. -uint16_t PrintRegion::extruder(FlowRole role) const +uint16_t PrintRegion::extruder(FlowRole role, const PrintObject& object) const { size_t extruder = 0; if (role == frPerimeter || role == frExternalPerimeter) @@ -13,6 +13,10 @@ uint16_t PrintRegion::extruder(FlowRole role) const extruder = m_config.infill_extruder; else if (role == frSolidInfill || role == frTopSolidInfill) extruder = m_config.solid_infill_extruder; + else if (role == frSupportMaterial) + extruder = object.config().support_material_extruder; + else if (role == frSupportMaterialInterface) + extruder = object.config().support_material_interface_extruder; else throw Slic3r::InvalidArgument("Unknown role"); return extruder; @@ -50,10 +54,48 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir // Get the configured nozzle_diameter for the extruder associated to the flow role requested. // Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will follback to zero'th element, so everything is all right. - double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role) - 1); + double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role, object) - 1); return Flow::new_from_config_width(role, config_width, (float)nozzle_diameter, (float)layer_height, bridge ? (float)m_config.bridge_flow_ratio.get_abs_value(1) : 0.0f); } +float PrintRegion::width(FlowRole role, bool first_layer, const PrintObject& object) const +{ + const ConfigOptionFloatOrPercent* config_width = nullptr; + // otherwise, get extrusion width from configuration + // (might be an absolute value, or a percent value, or zero for auto) + if (first_layer && object.config().first_layer_extrusion_width.value > 0) { + config_width = &object.config().first_layer_extrusion_width; + } else if (role == frExternalPerimeter) { + config_width = &m_config.external_perimeter_extrusion_width; + } else if (role == frPerimeter) { + config_width = &m_config.perimeter_extrusion_width; + } else if (role == frInfill) { + config_width = &m_config.infill_extrusion_width; + } else if (role == frSolidInfill) { + config_width = &m_config.solid_infill_extrusion_width; + } else if (role == frTopSolidInfill) { + config_width = &m_config.top_infill_extrusion_width; + } else if (role == frSupportMaterial || role == frSupportMaterialInterface) { + config_width = &object.config().support_material_extrusion_width; + } else { + throw Slic3r::InvalidArgument("Unknown role"); + } + + if (!config_width || config_width->value == 0) + config_width = &object.config().extrusion_width; + + // Get the configured nozzle_diameter for the extruder associated to the flow role requested. + // Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will follback to zero'th element, so everything is all right. + double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role, object) - 1); + if (config_width->value <= 0.) { + // If user left option to 0, calculate a sane default width. + return Flow::auto_extrusion_width(role, nozzle_diameter); + } else { + // If user set a manual value, use it. + return float(config_width->get_abs_value(nozzle_diameter)); + } +} + coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const { return (print_config.nozzle_diameter.get_at(m_config.perimeter_extruder.value - 1) + diff --git a/src/slic3r/GUI/PresetHints.cpp b/src/slic3r/GUI/PresetHints.cpp index 0eb0b4d40f..459df570a7 100644 --- a/src/slic3r/GUI/PresetHints.cpp +++ b/src/slic3r/GUI/PresetHints.cpp @@ -227,18 +227,26 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle return (speed_normal > 0.) ? speed_normal : speed_max; }; if (perimeter_extruder_active) { - double external_perimeter_rate = Flow::new_from_config_width(frExternalPerimeter, - first_positive(first_layer_extrusion_width_ptr, external_perimeter_extrusion_width, extrusion_width), - nozzle_diameter, lh, bfr).mm3_per_mm() * + Flow external_flow = Flow::new_from_config_width(frExternalPerimeter, + first_positive(first_layer_extrusion_width_ptr, external_perimeter_extrusion_width, extrusion_width), + nozzle_diameter, lh, bfr); + if (external_flow.height > external_flow.width) + external_flow.height = external_flow.width; + external_flow.spacing_ratio = print_config.opt("external_perimeter_overlap")->get_abs_value(1); + double external_perimeter_rate = external_flow.mm3_per_mm() * (bridging ? bridge_speed : limit_by_first_layer_speed(std::max(external_perimeter_speed, small_perimeter_speed), max_print_speed)); if (max_flow < external_perimeter_rate) { max_flow = external_perimeter_rate; max_flow_extrusion_type = _utf8(L("external perimeters")); } - double perimeter_rate = Flow::new_from_config_width(frPerimeter, - first_positive(first_layer_extrusion_width_ptr, perimeter_extrusion_width, extrusion_width), - nozzle_diameter, lh, bfr).mm3_per_mm() * + Flow perimeter_flow = Flow::new_from_config_width(frPerimeter, + first_positive(first_layer_extrusion_width_ptr, perimeter_extrusion_width, extrusion_width), + nozzle_diameter, lh, bfr); + if (perimeter_flow.height > perimeter_flow.width) + perimeter_flow.height = perimeter_flow.width; + perimeter_flow.spacing_ratio = print_config.opt("perimeter_overlap")->get_abs_value(1); + double perimeter_rate = perimeter_flow.mm3_per_mm() * (bridging ? bridge_speed : limit_by_first_layer_speed(std::max(perimeter_speed, small_perimeter_speed), max_print_speed)); if (max_flow < perimeter_rate) { @@ -247,27 +255,36 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle } } if (! bridging && infill_extruder_active) { - double infill_rate = Flow::new_from_config_width(frInfill, - first_positive(first_layer_extrusion_width_ptr, infill_extrusion_width, extrusion_width), - nozzle_diameter, lh, bfr).mm3_per_mm() * limit_infill_by_first_layer_speed(infill_speed, max_print_speed); + Flow infill_flow = Flow::new_from_config_width(frInfill, + first_positive(first_layer_extrusion_width_ptr, infill_extrusion_width, extrusion_width), + nozzle_diameter, lh, bfr); + if (infill_flow.height > infill_flow.width) + infill_flow.height = infill_flow.width; + double infill_rate = infill_flow.mm3_per_mm() * limit_infill_by_first_layer_speed(infill_speed, max_print_speed); if (max_flow < infill_rate) { max_flow = infill_rate; max_flow_extrusion_type = _utf8(L("infill")); } } if (solid_infill_extruder_active) { - double solid_infill_rate = Flow::new_from_config_width(frInfill, - first_positive(first_layer_extrusion_width_ptr, solid_infill_extrusion_width, extrusion_width), - nozzle_diameter, lh, 0).mm3_per_mm() * + Flow solid_infill_flow = Flow::new_from_config_width(frInfill, + first_positive(first_layer_extrusion_width_ptr, solid_infill_extrusion_width, extrusion_width), + nozzle_diameter, lh, 0); + if (solid_infill_flow.height > solid_infill_flow.width) + solid_infill_flow.height = solid_infill_flow.width; + double solid_infill_rate = solid_infill_flow.mm3_per_mm() * (bridging ? bridge_speed : limit_infill_by_first_layer_speed(solid_infill_speed, max_print_speed)); if (max_flow < solid_infill_rate) { max_flow = solid_infill_rate; max_flow_extrusion_type = _utf8(L("solid infill")); } if (! bridging) { - double top_solid_infill_rate = Flow::new_from_config_width(frInfill, - first_positive(first_layer_extrusion_width_ptr, top_infill_extrusion_width, extrusion_width), - nozzle_diameter, lh, bfr).mm3_per_mm() * limit_infill_by_first_layer_speed(top_solid_infill_speed, max_print_speed); + Flow top_solid_infill_flow = Flow::new_from_config_width(frInfill, + first_positive(first_layer_extrusion_width_ptr, top_infill_extrusion_width, extrusion_width), + nozzle_diameter, lh, bfr); + if (top_solid_infill_flow.height > top_solid_infill_flow.width) + top_solid_infill_flow.height = top_solid_infill_flow.width; + double top_solid_infill_rate = top_solid_infill_flow.mm3_per_mm() * limit_infill_by_first_layer_speed(top_solid_infill_speed, max_print_speed); if (max_flow < top_solid_infill_rate) { max_flow = top_solid_infill_rate; max_flow_extrusion_type = _utf8(L("top solid infill")); @@ -275,9 +292,12 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle } } if (support_material_extruder_active) { - double support_material_rate = Flow::new_from_config_width(frSupportMaterial, - first_positive(first_layer_extrusion_width_ptr, support_material_extrusion_width, extrusion_width), - nozzle_diameter, lh, bfr).mm3_per_mm() * + Flow support_material_flow = Flow::new_from_config_width(frSupportMaterial, + first_positive(first_layer_extrusion_width_ptr, support_material_extrusion_width, extrusion_width), + nozzle_diameter, lh, bfr); + if (support_material_flow.height > support_material_flow.width) + support_material_flow.height = support_material_flow.width; + double support_material_rate = support_material_flow.mm3_per_mm() * (bridging ? bridge_speed : limit_by_first_layer_speed(support_material_speed, max_print_speed)); if (max_flow < support_material_rate) { max_flow = support_material_rate; @@ -285,9 +305,12 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle } } if (support_material_interface_extruder_active) { - double support_material_interface_rate = Flow::new_from_config_width(frSupportMaterialInterface, + Flow support_material_interface_flow = Flow::new_from_config_width(frSupportMaterialInterface, first_positive(first_layer_extrusion_width_ptr, support_material_extrusion_width, extrusion_width), - nozzle_diameter, lh, bfr).mm3_per_mm() * + nozzle_diameter, lh, bfr); + if (support_material_interface_flow.height > support_material_interface_flow.width) + support_material_interface_flow.height = support_material_interface_flow.width; + double support_material_interface_rate = support_material_interface_flow.mm3_per_mm() * (bridging ? bridge_speed : limit_by_first_layer_speed(support_material_interface_speed, max_print_speed)); if (max_flow < support_material_interface_rate) { max_flow = support_material_interface_rate; @@ -340,7 +363,17 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle& pre *print_config.opt("perimeter_extrusion_width"), nozzle_diameter, layer_height, false); - //set spacing + // failsafe for too big height + if (external_perimeter_flow.height > external_perimeter_flow.width) + external_perimeter_flow.height = external_perimeter_flow.width; + if (perimeter_flow.height > perimeter_flow.width) + perimeter_flow.height = perimeter_flow.width; + if (external_perimeter_flow.height != perimeter_flow.height) { + perimeter_flow.height = std::min(perimeter_flow.height, external_perimeter_flow.height); + external_perimeter_flow.height = perimeter_flow.height; + } + + // set spacing external_perimeter_flow.spacing_ratio = print_config.opt("external_perimeter_overlap")->get_abs_value(1); perimeter_flow.spacing_ratio = print_config.opt("perimeter_overlap")->get_abs_value(1); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b996c327d7..6f11719775 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1186,6 +1186,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) } //wxGetApp().preset_bundle->value_changed(opt_key); + // update phony fields if (m_config->value_changed(opt_key, { wxGetApp().plater()->config() })) { update_dirty(); //# Initialize UI components with the config values. @@ -2979,24 +2980,30 @@ void TabPrinter::toggle_options() //z step checks { double z_step = m_config->opt_float("z_step"); + int64_t z_step_Mlong = (int64_t)(z_step * 1000000.); DynamicPrintConfig new_conf; bool has_changed = false; const std::vector& min_layer_height = m_config->option("min_layer_height")->values; - for (int i = 0; i < min_layer_height.size(); i++) - if (min_layer_height[i] / z_step != 0) { - if(!has_changed ) + for (int i = 0; i < min_layer_height.size(); i++) { + if (min_layer_height[i] != 0 && (int64_t)(min_layer_height[i] * 1000000.) % z_step_Mlong != 0) { + if (!has_changed) new_conf = *m_config; new_conf.option("min_layer_height")->values[i] = std::max(z_step, Slic3r::check_z_step(new_conf.option("min_layer_height")->values[i], z_step)); has_changed = true; } - const std::vector& max_layer_height = m_config->option("max_layer_height")->values; - for (int i = 0; i < max_layer_height.size(); i++) - if (max_layer_height[i] / z_step != 0) { + } + const std::vector& nozzle_diameters = m_config->option("nozzle_diameter")->values; + std::vector max_layer_height = m_config->option("max_layer_height")->values; + for (int i = 0; i < max_layer_height.size(); i++) { + if (max_layer_height[i] == 0) + max_layer_height[i] = nozzle_diameters[i] * 0.75; + if ((int64_t)(max_layer_height[i] * 1000000.) % z_step_Mlong != 0) { if (!has_changed) new_conf = *m_config; new_conf.option("max_layer_height")->values[i] = std::max(z_step, Slic3r::check_z_step(new_conf.option("max_layer_height")->values[i], z_step)); has_changed = true; } + } if (has_changed) { load_config(new_conf); }