diff --git a/resources/ui_layout/printer_fff.ui b/resources/ui_layout/printer_fff.ui index b98c42c99..b362632ac 100644 --- a/resources/ui_layout/printer_fff.ui +++ b/resources/ui_layout/printer_fff.ui @@ -4,6 +4,7 @@ group:Size and coordinates bed_shape setting:max_print_height setting:z_offset + setting:z_step group:extruders_count_event:milling_count_event:Capabilities extruders_count setting:single_extruder_multi_material diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index cf6dba3e2..33795038c 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3480,6 +3480,16 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0)); + def = this->add("z_step", coFloat); + def->label = L("Z full step"); + def->tooltip = L("Set this to the height moved when your Z motor (or equivalent) turns one step." + "If your motor needs 200 steps to move your head/plater by 1mm, this field have to be 1/200 = 0.005"); + def->cli = "z-step=f"; + def->sidetext = L("mm"); + def->min = 0.0001; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0.005)); + // Declare retract values for filament profile, overriding the printer's extruder profile. for (const char *opt_key : { // floats @@ -4349,6 +4359,10 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va float v = boost::lexical_cast(value); if (v > 0) value = boost::lexical_cast(-v); + } else if (opt_key == "z_steps_per_mm") { + opt_key = "z_step"; + float v = boost::lexical_cast(value); + value = boost::lexical_cast(1/v); } // Ignore the following obsolete configuration keys: diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 0117c2ac7..ecdbcf19a 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -914,7 +914,8 @@ public: ConfigOptionFloat wipe_advanced_nozzle_melted_volume; ConfigOptionFloat wipe_advanced_multiplier; ConfigOptionFloats wipe_extra_perimeter; - ConfigOptionEnum wipe_advanced_algo; + ConfigOptionEnum wipe_advanced_algo; + ConfigOptionFloat z_step; std::string get_extrusion_axis() const { @@ -1010,6 +1011,7 @@ protected: OPT_PTR(wipe_advanced_multiplier); OPT_PTR(wipe_advanced_algo); OPT_PTR(wipe_extra_perimeter); + OPT_PTR(z_step); } }; diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 1a5308f90..06080116c 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -24,11 +24,23 @@ namespace Slic3r static const coordf_t MIN_LAYER_HEIGHT = 0.01; static const coordf_t MIN_LAYER_HEIGHT_DEFAULT = 0.07; +inline coordf_t check_z_step(coordf_t val, coordf_t z_step) { + uint64_t valint = uint64_t(val * 100000. + 0.1); + uint64_t stepint = uint64_t(z_step * 100000. + 0.1); + return (((valint + (stepint/2)) / stepint) * stepint) / 100000.; + //return int((val + z_step * 0.5) / z_step) * z_step; +} +inline bool test_z_step(coordf_t val, coordf_t z_step) { + uint64_t valint = uint64_t(val * 100000. + 0.1); + uint64_t stepint = uint64_t(z_step * 100000. + 0.1); + return valint % stepint == 0; +} + // Minimum layer height for the variable layer height algorithm. inline coordf_t min_layer_height_from_nozzle(const PrintConfig &print_config, int idx_nozzle) { coordf_t min_layer_height = print_config.min_layer_height.get_at(idx_nozzle - 1); - return (min_layer_height == 0.) ? MIN_LAYER_HEIGHT_DEFAULT : std::max(MIN_LAYER_HEIGHT, min_layer_height); + return check_z_step( (min_layer_height == 0.) ? (MIN_LAYER_HEIGHT_DEFAULT) : std::max(MIN_LAYER_HEIGHT, min_layer_height), print_config.z_step); } // Maximum layer height for the variable layer height algorithm, 3/4 of a nozzle dimaeter by default, @@ -38,14 +50,14 @@ inline coordf_t max_layer_height_from_nozzle(const PrintConfig &print_config, in coordf_t min_layer_height = min_layer_height_from_nozzle(print_config, idx_nozzle); coordf_t max_layer_height = print_config.max_layer_height.get_at(idx_nozzle - 1); coordf_t nozzle_dmr = print_config.nozzle_diameter.get_at(idx_nozzle - 1); - return std::max(min_layer_height, (max_layer_height == 0.) ? (0.75 * nozzle_dmr) : max_layer_height); + return check_z_step(std::max(min_layer_height, (max_layer_height == 0.) ? (0.75 * nozzle_dmr) : max_layer_height), print_config.z_step); } // Minimum layer height for the variable layer height algorithm. coordf_t Slicing::min_layer_height_from_nozzle(const DynamicPrintConfig &print_config, int idx_nozzle) { coordf_t min_layer_height = print_config.opt_float("min_layer_height", idx_nozzle - 1); - return (min_layer_height == 0.) ? MIN_LAYER_HEIGHT_DEFAULT : std::max(MIN_LAYER_HEIGHT, min_layer_height); + return check_z_step((min_layer_height == 0.) ? (MIN_LAYER_HEIGHT_DEFAULT) : std::max(MIN_LAYER_HEIGHT, min_layer_height), print_config.opt_float("z_step")); } // Maximum layer height for the variable layer height algorithm, 3/4 of a nozzle dimaeter by default, @@ -55,7 +67,7 @@ coordf_t Slicing::max_layer_height_from_nozzle(const DynamicPrintConfig &print_c coordf_t min_layer_height = min_layer_height_from_nozzle(print_config, idx_nozzle); coordf_t max_layer_height = print_config.opt_float("max_layer_height", idx_nozzle - 1); coordf_t nozzle_dmr = print_config.opt_float("nozzle_diameter", idx_nozzle - 1); - return std::max(min_layer_height, (max_layer_height == 0.) ? (0.75 * nozzle_dmr) : max_layer_height); + return check_z_step(std::max(min_layer_height, (max_layer_height == 0.) ? (0.75 * nozzle_dmr) : max_layer_height), print_config.opt_float("z_step")); } SlicingParameters SlicingParameters::create_from_config( @@ -65,10 +77,11 @@ SlicingParameters SlicingParameters::create_from_config( const std::vector &object_extruders) { //first layer height is got from the first_layer_height setting unless the value was garbage. - // if the first_layer_height setting depends of the nozzle width, use the first one. + // if the first_layer_height setting depends of the nozzle width, use the first one. Apply the z_step coordf_t first_layer_height = (object_config.first_layer_height.get_abs_value(print_config.nozzle_diameter.empty() ? 0. : print_config.nozzle_diameter.get_at(0)) <= 0) ? object_config.layer_height.value : object_config.first_layer_height.get_abs_value(print_config.nozzle_diameter.get_at(0)); + first_layer_height = check_z_step(first_layer_height, print_config.z_step); // If object_config.support_material_extruder == 0 resp. object_config.support_material_interface_extruder == 0, // print_config.nozzle_diameter.get_at(size_t(-1)) returns the 0th nozzle diameter, // which is consistent with the requirement that if support_material_extruder == 0 resp. support_material_interface_extruder == 0, @@ -86,6 +99,12 @@ SlicingParameters SlicingParameters::create_from_config( params.object_print_z_max = object_height; params.base_raft_layers = object_config.raft_layers.value; params.soluble_interface = soluble_interface; + params.z_step = print_config.z_step; + + //apply z_step to layer_height + params.layer_height = check_z_step(params.layer_height , params.z_step); + params.object_print_z_max = check_z_step(params.object_print_z_max, params.z_step); + if (params.object_print_z_max < object_height) params.object_print_z_max += params.z_step; // Miniumum/maximum of the minimum layer height over all extruders. params.min_layer_height = MIN_LAYER_HEIGHT; @@ -112,10 +131,16 @@ SlicingParameters SlicingParameters::create_from_config( } params.min_layer_height = std::min(params.min_layer_height, params.layer_height); params.max_layer_height = std::max(params.max_layer_height, params.layer_height); + //apply z_step to min/max + params.min_layer_height = check_z_step(params.min_layer_height, params.z_step); + params.max_layer_height = check_z_step(params.max_layer_height, params.z_step); + params.max_suport_layer_height = check_z_step(params.max_suport_layer_height, params.z_step); if (! soluble_interface) { params.gap_raft_object = object_config.support_material_contact_distance_top.get_abs_value(support_material_interface_extruder_dmr); + params.gap_raft_object = check_z_step(params.gap_raft_object, params.z_step); params.gap_object_support = object_config.support_material_contact_distance_bottom.get_abs_value(support_material_interface_extruder_dmr); + params.gap_object_support = check_z_step(params.gap_object_support, params.z_step); params.gap_support_object = params.gap_raft_object; } @@ -124,11 +149,14 @@ SlicingParameters SlicingParameters::create_from_config( params.base_raft_layers -= params.interface_raft_layers; // Use as large as possible layer height for the intermediate raft layers. params.base_raft_layer_height = std::max(params.layer_height, 0.75 * support_material_extruder_dmr); + params.base_raft_layer_height = check_z_step(params.base_raft_layer_height, params.z_step); params.interface_raft_layer_height = std::max(params.layer_height, 0.75 * support_material_interface_extruder_dmr); + params.interface_raft_layer_height = check_z_step(params.interface_raft_layer_height, params.z_step); params.contact_raft_layer_height_bridging = false; params.first_object_layer_bridging = false; #if 1 params.contact_raft_layer_height = std::max(params.layer_height, 0.75 * support_material_interface_extruder_dmr); + params.contact_raft_layer_height = check_z_step(params.contact_raft_layer_height, params.z_step); if (! soluble_interface) { // Compute the average of all nozzles used for printing the object over a raft. //FIXME It is expected, that the 1st layer of the object is printed with a bridging flow over a full raft. Shall it not be vice versa? @@ -143,6 +171,7 @@ SlicingParameters SlicingParameters::create_from_config( } #else params.contact_raft_layer_height = soluble_interface ? support_material_interface_extruder_dmr : 0.75 * support_material_interface_extruder_dmr; + params.contact_raft_layer_height = check_z_step(params.contact_raft_layer_height, params.z_step); params.contact_raft_layer_height_bridging = ! soluble_interface; ... #endif @@ -169,6 +198,24 @@ SlicingParameters SlicingParameters::create_from_config( params.object_print_z_max += print_z; } + assert(test_z_step(params.interface_raft_layer_height , params.z_step)); + assert(test_z_step(params.base_raft_layer_height, params.z_step)); + assert(test_z_step(params.contact_raft_layer_height, params.z_step)); + assert(test_z_step(params.layer_height, params.z_step)); + assert(test_z_step(params.min_layer_height, params.z_step)); + assert(test_z_step(params.max_layer_height, params.z_step)); + assert(test_z_step(params.max_suport_layer_height, params.z_step)); + assert(test_z_step(params.first_print_layer_height, params.z_step)); + assert(test_z_step(params.first_object_layer_height, params.z_step)); + assert(test_z_step(params.gap_raft_object, params.z_step)); + assert(test_z_step(params.gap_object_support, params.z_step)); + assert(test_z_step(params.gap_support_object, params.z_step)); + assert(test_z_step(params.raft_base_top_z, params.z_step)); + assert(test_z_step(params.raft_interface_top_z, params.z_step)); + assert(test_z_step(params.raft_contact_top_z, params.z_step)); + assert(test_z_step(params.object_print_z_min, params.z_step)); + assert(test_z_step(params.object_print_z_max, params.z_step)); + params.valid = true; return params; } @@ -177,8 +224,12 @@ std::vector> layer_height_ranges(const { std::vector> out; out.reserve(config_ranges.size()); - for (const auto &kvp : config_ranges) - out.emplace_back(kvp.first, kvp.second.option("layer_height")->getFloat()); + for (const auto& kvp : config_ranges) { + coordf_t z_step = kvp.second.opt_float("z_step"); + coordf_t layer_height = kvp.second.opt_float("layer_height"); + out.emplace_back(kvp.first, check_z_step(layer_height, z_step)); + + } return out; } @@ -203,6 +254,9 @@ std::vector layer_height_profile_from_ranges( if (! ranges_non_overlapping.empty()) // Trim current low with the last high. lo = std::max(lo, ranges_non_overlapping.back().first.second); + lo = check_z_step(lo, slicing_params.z_step); + hi = check_z_step(hi, slicing_params.z_step); + height = check_z_step(height, slicing_params.z_step); if (lo + EPSILON < hi) // Ignore too narrow ranges. ranges_non_overlapping.push_back(std::pair(t_layer_height_range(lo, hi), height)); @@ -294,6 +348,7 @@ std::vector layer_height_profile_adaptive(const SlicingParameters& slici } } #endif + cusp_height = check_z_step(cusp_height, slicing_params.z_step); height = std::min((coordf_t)cusp_height, height); // apply z-gradation @@ -373,6 +428,7 @@ std::vector smooth_height_profile(const std::vector& profile, co for (size_t i = 0; i < skip_count; ++i) { ret.push_back(profile[i]); + ret[i] = check_z_step(ret[i], slicing_params.z_step); } // smooth the rest of the profile by biasing a gaussian blur @@ -384,6 +440,7 @@ std::vector smooth_height_profile(const std::vector& profile, co for (size_t i = skip_count; i < size; i += 2) { double zi = profile[i]; + zi = check_z_step(zi, slicing_params.z_step); double hi = profile[i + 1]; ret.push_back(zi); ret.push_back(0.0); @@ -407,6 +464,7 @@ std::vector smooth_height_profile(const std::vector& profile, co height = clamp(slicing_params.min_layer_height, slicing_params.max_layer_height, (weight_total != 0.0) ? height /= weight_total : hi); if (smoothing_params.keep_min) height = std::min(height, hi); + height = check_z_step(height, slicing_params.z_step); } return ret; @@ -482,7 +540,7 @@ void adjust_layer_height_profile( coordf_t lo = std::max(z_span_variable.first, z - 0.5 * band_width); // Do not limit the upper side of the band, so that the modifications to the top point of the profile will be allowed. coordf_t hi = z + 0.5 * band_width; - coordf_t z_step = 0.1; + coordf_t z_step_adjust = 0.1; size_t idx = 0; while (idx < layer_height_profile.size() && layer_height_profile[idx] < lo) idx += 2; @@ -548,7 +606,7 @@ void adjust_layer_height_profile( profile_new.push_back(height); } // Limit zz to the object height, so the next iteration the last profile point will be set. - zz = std::min(zz + z_step, z_span_variable.second); + zz = std::min(zz + z_step_adjust, z_span_variable.second); idx = next; while (idx < layer_height_profile.size() && layer_height_profile[idx] < zz) idx += 2; @@ -590,6 +648,10 @@ void adjust_layer_height_profile( } } + //i'm not sure it's needed. just in case. + for (size_t i = 0; i < layer_height_profile.size(); i ++) + layer_height_profile[i] = check_z_step(layer_height_profile[i], slicing_params.z_step); + assert(layer_height_profile.size() > 2); assert(layer_height_profile.size() % 2 == 0); assert(layer_height_profile[0] == 0.); @@ -638,10 +700,12 @@ std::vector generate_object_layers( coordf_t z1 = layer_height_profile[idx_layer_height_profile]; coordf_t h1 = layer_height_profile[idx_layer_height_profile + 1]; height = h1; + height = check_z_step(height, slicing_params.z_step); if (next < layer_height_profile.size()) { coordf_t z2 = layer_height_profile[next]; coordf_t h2 = layer_height_profile[next + 1]; height = lerp(h1, h2, (slice_z - z1) / (z2 - z1)); + height = check_z_step(height, slicing_params.z_step); assert(height >= slicing_params.min_layer_height - EPSILON && height <= slicing_params.max_layer_height + EPSILON); } } @@ -684,6 +748,10 @@ std::vector generate_object_layers( } } +#ifdef _DEBUG + for (size_t i = 0; i < out.size(); i++) + assert(test_z_step(out[i], slicing_params.z_step/2)); +#endif return out; } diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index d49790e5d..ab76c63c4 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -20,6 +20,8 @@ class PrintConfig; class PrintObjectConfig; class ModelObject; +coordf_t check_z_step(coordf_t val, coordf_t z_step); + // Parameters to guide object slicing and support generation. // The slicing parameters account for a raft and whether the 1st object layer is printed with a normal or a bridging flow // (using a normal flow over a soluble support, using a bridging flow over a non-soluble support). @@ -65,6 +67,8 @@ struct SlicingParameters coordf_t max_layer_height; coordf_t max_suport_layer_height; bool exact_last_layer_height; + // min common divisor for all layer height + coordf_t z_step; // First layer height of the print, this may be used for the first layer of the raft // or for the first layer of the print. diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index aea6ff964..f689773c8 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -606,7 +606,8 @@ const std::vector& Preset::printer_options() "machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e", "time_estimation_compensation", "print_machine_envelope", - "fan_speedup_time" + "fan_speedup_time", + "z_step" }; s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end()); s_opts.insert(s_opts.end(), Preset::milling_options().begin(), Preset::milling_options().end()); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 5a0ab0fc8..a86bc9862 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2576,6 +2576,33 @@ void TabPrinter::update_fff() field->toggle(have_advanced_wipe_volume); } } + + //z step checks + { + double z_step = m_config->opt_float("z_step"); + 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 ) + new_conf = *m_config; + new_conf.option("min_layer_height")->values[i] = std::max(z_step, 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) { + if (!has_changed) + new_conf = *m_config; + new_conf.option("max_layer_height")->values[i] = std::max(z_step, check_z_step(new_conf.option("max_layer_height")->values[i], z_step)); + has_changed = true; + } + if (has_changed) { + load_config(new_conf); + } + } + // Thaw(); }