From f2a994543556c5c3dfa42978483619ede307f9f8 Mon Sep 17 00:00:00 2001 From: supermerill Date: Sun, 31 Oct 2021 00:08:11 +0200 Subject: Add lift_min: minimum height to travel between objects Also change other behaviors to be compliant: * At the first move don't split the travel * At the first move, if start_gcode_manual and no layer_gcode, don't lift the nozzle so the printer won't "z-dance", whatever where the nozzle is. Note:it's a hack, please redo it properly when reworking gcode-writer. * retract_lift_first_layer is gone back to the old simple behavior (revert b16ecbfc) * removed auto extra lift for first layer, now that lift_min exists. * with complete_object, don't unlift at object/first layer change, to avoid Z-dance * lift_min will be used between brims, skirts, objects but not between object-skirt, object-brim and their object supermerill/SuperSlicer#1783 supermerill/SuperSlicer#1775 supermerill/SuperSlicer#1575 supermerill/SuperSlicer#599 supermerill/SuperSlicer#429 supermerill/SuperSlicer#395 supermerill/SuperSlicer#241 --- src/libslic3r/GCode.cpp | 112 +++++++++++++++++++++++++++----------- src/libslic3r/GCode.hpp | 2 + src/libslic3r/GCodeWriter.cpp | 32 ++++++----- src/libslic3r/GCodeWriter.hpp | 11 ++-- src/libslic3r/Preset.cpp | 1 + src/libslic3r/PrintConfig.cpp | 17 +++++- src/libslic3r/PrintConfig.hpp | 2 + src/slic3r/GUI/DoubleSlider.cpp | 117 ++++++++++++++++++++-------------------- src/slic3r/GUI/Tab.cpp | 2 +- 9 files changed, 186 insertions(+), 110 deletions(-) (limited to 'src') diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 7fc592643..2b55f0af5 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -219,16 +219,23 @@ std::string Wipe::wipe(GCode& gcodegen, bool toolchange) } //if first layer, ask for a bigger lift for travel to object, to be on the safe side -static inline void set_extra_lift(const Layer& layer, const Print& print, GCodeWriter & writer, int extruder_id) { +static inline void set_extra_lift(const float previous_print_z, const int layer_id, const PrintConfig& print_config, GCodeWriter & writer, int extruder_id) { //if first layer, ask for a bigger lift for travel to object, to be on the safe side - if (layer.id() == 0 && - (print.config().retract_lift.get_at(extruder_id) != 0 || print.config().retract_lift_first_layer.get_at(extruder_id))) { - //get biggest first layer height and set extra lift for first travel, to be safe. - double extra_lift_value = 0; - for (const PrintObject* obj : print.objects()) - extra_lift_value = std::max(extra_lift_value, print.get_object_first_layer_height(*obj)); - writer.set_extra_lift(extra_lift_value * 2); + double extra_lift_value = 0; + if (print_config.lift_min.value > 0) { + double retract_lift = 0; + //get the current lift (imo, should be given by the writer... i'm duplicating stuff here) + if(//(previous_print_z == 0 && print_config.retract_lift_above.get_at(writer.tool()->id()) == 0) || + print_config.retract_lift_above.get_at(writer.tool()->id()) <= previous_print_z + EPSILON + || (layer_id == 0 && print_config.retract_lift_first_layer.get_at(writer.tool()->id()))) + retract_lift = writer.tool()->retract_lift(); + // see if it's positive + if (previous_print_z + extra_lift_value + retract_lift < print_config.lift_min.value) { + extra_lift_value = print_config.lift_min.value - previous_print_z - retract_lift; + } } + if(extra_lift_value > 0) + writer.set_extra_lift(extra_lift_value); } static inline Point wipe_tower_point_to_object_point(GCode &gcodegen, const Vec2f &wipe_tower_pt) @@ -1398,6 +1405,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu // Write the custom start G-code _writeln(file, start_gcode); + m_last_pos_defined = false; + //flush FanMover buffer to avoid modifying the start gcode if it's manual. if (this->config().start_gcode_manual && this->m_fan_mover.get() != nullptr) { std::string to_write = this->m_fan_mover.get()->process_gcode("", true); @@ -1514,8 +1523,10 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu // This happens before Z goes down to layer 0 again, so that no collision happens hopefully. m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer m_avoid_crossing_perimeters.use_external_mp_once(); + set_extra_lift(m_last_layer_z, 0, print.config(), m_writer, initial_extruder_id); _write(file, this->retract()); std::string gcode; + //go to origin of the next object (it's 0,0 because we shifted the origin to it) Polyline polyline = this->travel_to(gcode, Point(0, 0), erNone); this->write_travel_to(gcode, polyline, "move to origin position for next object"); _write(file, gcode); @@ -1531,6 +1542,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false); this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false); _writeln(file, between_objects_gcode); + } else { + set_extra_lift(0, 0, print.config(), m_writer, initial_extruder_id); } //reinit the seam placer on the new object m_seam_placer.init(print); @@ -1555,6 +1568,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu m_second_layer_things_done = false; prev_object = &object; } + set_extra_lift(m_last_layer_z, prev_object->layers().back()->id(), print.config(), m_writer, initial_extruder_id /* osef, it's only for the lift_min */); } else { // Sort layers by Z. // All extrusion moves with the same top layer height are extruded uninterrupted. @@ -2263,7 +2277,22 @@ void GCode::process_layer( print.config().before_layer_gcode.value, m_writer.tool()->id(), &config) + "\n"; } - gcode += this->change_layer(print_z); // this will increase m_layer_index + // print z move to next layer UNLESS + // if it's going to the first layer, then we may want to dealy the move in these condition: + // there is no "after layer change gcode" and it's the first move from the unknown + if (print.config().layer_gcode.value.empty() && !m_last_pos_defined && m_config.start_gcode_manual && ( + // there is a lift (on the first llyer, so the first move will bring us to the required height + (m_writer.tool()->retract_lift() > 0 && (m_config.retract_lift_above.get_at(m_writer.tool()->id()) == 0 || BOOL_EXTRUDER_CONFIG(retract_lift_first_layer))) + || // or lift_min is higher than the first layer height. + m_config.lift_min.value > layer.print_z + )) + m_delayed_layer_change = this->change_layer(print_z); //HACK for superslicer#1775 + else { + //extra lift on layer change if multiple objects + if(single_object_instance_idx == size_t(-1) && (support_layer != nullptr || layers.size() > 1)) + set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, first_extruder_id); + gcode += this->change_layer(print_z); // this will increase m_layer_index + } m_layer = &layer; if (! print.config().layer_gcode.value.empty()) { DynamicConfig config; @@ -2478,9 +2507,12 @@ void GCode::process_layer( m_last_processor_extrusion_role = erWipeTower; //if first layer, ask for a bigger lift for travel to object, to be on the safe side - set_extra_lift(layer, print, m_writer, extruder_id); + if(single_object_instance_idx == size_t(-1) && m_layer_index == 0) + set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id); if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) { + // before going to and from a global skirt, please ensure you are a a safe height + set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id); const std::pair loops = loops_it->second; this->set_origin(0., 0.); m_avoid_crossing_perimeters.use_external_mp(); @@ -2504,27 +2536,30 @@ void GCode::process_layer( // Allow a straight travel move to the first object point if this is the first layer (but don't in next layers). if (first_layer && loops.first == 0) m_avoid_crossing_perimeters.disable_once(); + // before going to and from a global skirt, please ensure you are a a safe height + set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id); } // Extrude brim with the extruder of the 1st region. if (! m_brim_done) { - //if first layer, ask for a bigger lift for travel to object, to be on the safe side - set_extra_lift(layer, print, m_writer, extruder_id); - this->set_origin(0., 0.); m_avoid_crossing_perimeters.use_external_mp(); - gcode += this->extrude_entity(print.brim(), "Brim", m_config.support_material_speed.value); + for (const ExtrusionEntity* brim_entity : print.brim().entities) { + //if first layer, ask for a bigger lift for travel to each brim, to be on the safe side + set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id); + gcode += this->extrude_entity(*brim_entity, "Brim", m_config.support_material_speed.value); + } m_brim_done = true; m_avoid_crossing_perimeters.use_external_mp(false); // Allow a straight travel move to the first object point. m_avoid_crossing_perimeters.disable_once(); + //to go to the object-only skirt or brim, or to the object (May be overriden here but I don't care) + set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id); } //extrude object-only skirt //TODO: use it also for wiping like the other one (as they are exlusiev) if (single_object_instance_idx != size_t(-1) && !layers.front().object()->skirt().empty() && extruder_id == layer_tools.extruders.front()) { - //if first layer, ask for a bigger lift for travel to object, to be on the safe side - set_extra_lift(layer, print, m_writer, extruder_id); const PrintObject *print_object = layers.front().object(); this->set_origin(unscale(print_object->instances()[single_object_instance_idx].shift)); @@ -2540,8 +2575,6 @@ void GCode::process_layer( //extrude object-only brim if (single_object_instance_idx != size_t(-1) && !layers.front().object()->brim().empty() && extruder_id == layer_tools.extruders.front()) { - //if first layer, ask for a bigger lift for travel to object, to be on the safe side - set_extra_lift(layer, print, m_writer, extruder_id); const PrintObject *print_object = layers.front().object(); this->set_origin(unscale(print_object->instances()[single_object_instance_idx].shift)); @@ -2566,7 +2599,7 @@ void GCode::process_layer( for (int print_wipe_extrusions = is_anything_overridden; print_wipe_extrusions>=0; --print_wipe_extrusions) { if (is_anything_overridden && print_wipe_extrusions == 0) gcode+="; PURGING FINISHED\n"; - + bool first_object = true; for (InstanceToPrint &instance_to_print : instances_to_print) { m_config.apply(instance_to_print.print_object.config(), true); m_layer = layers[instance_to_print.layer_id].layer(); @@ -2592,8 +2625,11 @@ void GCode::process_layer( m_gcode_label_objects_start += std::string("M486 S") + std::to_string(instance_plater_id) + "\n"; } } - //if first layer, ask for a bigger lift for travel to object, to be on the safe side - set_extra_lift(layer, print, m_writer, extruder_id); + // ask for a bigger lift for travel to object when moving to another object + if (single_object_instance_idx == size_t(-1) && !first_object) + set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id); + else + first_object = false; // When starting a new object, use the external motion planner for the first travel move. const Point &offset = instance_to_print.print_object.instances()[instance_to_print.instance_id].shift; std::pair this_object_copy(&instance_to_print.print_object, offset); @@ -3902,7 +3938,10 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string if (m_config.travel_acceleration.value > 0) travel_acceleration = m_config.travel_acceleration.get_abs_value(acceleration); } - + if (m_writer.get_max_acceleration() > 0) { + acceleration = std::min((double)m_writer.get_max_acceleration(), acceleration); + travel_acceleration = std::min((double)m_writer.get_max_acceleration(), travel_acceleration); + } if (travel_acceleration == acceleration) { m_writer.set_acceleration((uint32_t)floor(acceleration + 0.5)); // go to first point of extrusion path (stop at midpoint to let us set the decel speed) @@ -3915,7 +3954,10 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string if (!m_last_pos_defined || m_last_pos != path.first_point()) { Polyline poly_start = this->travel_to(gcode, path.first_point(), path.role()); coordf_t length = poly_start.length(); - if (length > SCALED_EPSILON) { + // if length is enough, it's not the hack for first move, and the travel accel is different than the normal accel + // then cut the travel in two to change the accel in-between + // TODO: compute the real point where it should be cut, considering an infinite max speed. + if (length > std::max(scale_d(EPSILON), scale_d(m_config.min_length)) && m_last_pos_defined && floor(travel_acceleration) != floor(acceleration)) { Polyline poly_end; coordf_t min_length = scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.5)) * 20; if (poly_start.size() > 2 && length > min_length * 3) { @@ -3954,7 +3996,18 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string _add_object_change_labels(gcode); // compensate retraction - gcode += this->unretract(); + if (m_delayed_layer_change.empty()) { + gcode += m_writer.unlift();//this->unretract(); + } else { + //check if an unlift happens + std::string unlift = m_writer.unlift(); + if (unlift.empty()) { + unlift = m_delayed_layer_change; + } + m_delayed_layer_change.clear(); + gcode += unlift; + } + gcode += m_writer.unretract(); speed = _compute_speed_mm_per_sec(path, speed); double F = speed * 60; // convert mm/sec to mm/min @@ -4185,7 +4238,9 @@ std::string GCode::retract(bool toolchange) methods even if we performed wipe, since this will ensure the entire retraction length is honored in case wipe path was too short. */ gcode += toolchange ? m_writer.retract_for_toolchange() : m_writer.retract(); - bool need_lift = !m_writer.tool_is_extruder() || toolchange || (BOOL_EXTRUDER_CONFIG(retract_lift_first_layer) && m_config.print_retract_lift.value != 0 && this->m_layer_index == 0); + bool need_lift = !m_writer.tool_is_extruder() || toolchange + || (BOOL_EXTRUDER_CONFIG(retract_lift_first_layer) && m_config.print_retract_lift.value != 0 && this->m_layer_index == 0) + || this->m_writer.get_extra_lift() > 0; bool last_fill_extusion_role_top_infill = (this->m_last_extrusion_role == ExtrusionRole::erTopSolidInfill || this->m_last_extrusion_role == ExtrusionRole::erIroning); if(this->m_last_extrusion_role == ExtrusionRole::erGapFill) last_fill_extusion_role_top_infill = (this->m_last_notgapfill_extrusion_role == ExtrusionRole::erTopSolidInfill || this->m_last_notgapfill_extrusion_role == ExtrusionRole::erIroning); @@ -4198,12 +4253,7 @@ std::string GCode::retract(bool toolchange) need_lift = true; } if (need_lift) - if (m_writer.tool()->retract_length() > 0 - || m_config.use_firmware_retraction - || (!m_writer.tool_is_extruder() && m_writer.tool()->retract_lift() != 0) - || (BOOL_EXTRUDER_CONFIG(retract_lift_first_layer) && this->m_layer_index == 0) - ) - gcode += m_writer.lift(); + gcode += m_writer.lift(this->m_layer_index); return gcode; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index a5bfb881e..27b016b4e 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -349,6 +349,8 @@ private: // Markers for the Pressure Equalizer to recognize the extrusion type. // The Pressure Equalizer removes the markers from the final G-code. bool m_enable_extrusion_role_markers; + // HACK to avoid multiple Z move. + std::string m_delayed_layer_change; // Keeps track of the last extrusion role passed to the processor ExtrusionRole m_last_processor_extrusion_role; // How many times will change_layer() be called? diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 2ed093492..bce90d4a6 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -510,14 +510,14 @@ std::string GCodeWriter::travel_to_z(double z, const std::string &comment) /* If target Z is lower than current Z but higher than nominal Z we don't perform the move but we only adjust the nominal Z by reducing the lift amount that will be used for unlift. */ - if (!this->will_move_z(z)) { + // note that if we move but it's lower and we are lifted, we can wait a bit for unlifting, to avoid possible dance on layer change. + if (!this->will_move_z(z) || z < m_pos.z() && m_lifted > EPSILON) { double nominal_z = m_pos.z() - m_lifted; m_lifted -= (z - nominal_z); if (std::abs(m_lifted) < EPSILON) m_lifted = 0.; return ""; } - /* In all the other cases, we perform an actual Z move and cancel the lift. */ m_lifted = 0; @@ -548,7 +548,7 @@ bool GCodeWriter::will_move_z(double z) const we don't perform an actual Z move. */ if (m_lifted > 0) { double nominal_z = m_pos.z() - m_lifted; - if (z >= nominal_z && z <= m_pos.z()) + if (z >= nominal_z + EPSILON && z <= m_pos.z() - EPSILON) return false; } return true; @@ -698,15 +698,19 @@ std::string GCodeWriter::unretract() /* If this method is called more than once before calling unlift(), it will not perform subsequent lifts, even if Z was raised manually (i.e. with travel_to_z()) and thus _lifted was reduced. */ -std::string GCodeWriter::lift() +std::string GCodeWriter::lift(int layer_id) { // check whether the above/below conditions are met double target_lift = 0; if(this->tool_is_extruder()){ - //these two should be in the Tool class methods.... - double above = this->config.retract_lift_above.get_at(m_tool->id()); - double below = this->config.retract_lift_below.get_at(m_tool->id()); - if (m_pos.z() >= above && (below == 0 || m_pos.z() <= below)) + bool can_lift = this->config.retract_lift_first_layer.get_at(m_tool->id()) && layer_id == 0; + if (!can_lift) { + //these two should be in the Tool class methods.... + double above = this->config.retract_lift_above.get_at(m_tool->id()); + double below = this->config.retract_lift_below.get_at(m_tool->id()); + can_lift = (m_pos.z() >= above - EPSILON && (below == 0 || m_pos.z() <= below + EPSILON)); + } + if(can_lift) target_lift = m_tool->retract_lift(); } else { target_lift = m_tool->retract_lift(); @@ -717,17 +721,19 @@ std::string GCodeWriter::lift() target_lift = config_region->print_retract_lift.value; } - if (this->extra_lift > 0) { - target_lift += this->extra_lift; - this->extra_lift = 0; + // one-time extra lift (often for dangerous travels) + if (this->m_extra_lift > 0) { + target_lift += this->m_extra_lift; + this->m_extra_lift = 0; } // compare against epsilon because travel_to_z() does math on it // and subtracting layer_height from retract_lift might not give // exactly zero - if (std::abs(m_lifted) < EPSILON && target_lift > 0) { + if (std::abs(m_lifted) < target_lift - EPSILON && target_lift > 0) { + std::string str = this->_travel_to_z(m_pos.z() + target_lift - m_lifted, "lift Z"); m_lifted = target_lift; - return this->_travel_to_z(m_pos.z() + target_lift, "lift Z"); + return str; } return ""; } diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 72264aac3..71def452d 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -51,6 +51,7 @@ public: std::string set_fan(uint8_t speed, bool dont_save = false, uint16_t default_tool = 0); void set_acceleration(uint32_t acceleration); uint32_t get_acceleration() const; + uint32_t get_max_acceleration() { return this->m_max_acceleration; } std::string write_acceleration(); std::string reset_e(bool force = false); std::string update_progress(uint32_t num, uint32_t tot, bool allow_100 = false) const; @@ -73,11 +74,12 @@ public: std::string retract(bool before_wipe = false); std::string retract_for_toolchange(bool before_wipe = false); std::string unretract(); - std::string lift(); + void set_extra_lift(double extra_zlift) { this->m_extra_lift = extra_zlift; } + double get_extra_lift() { return this->m_extra_lift; } + std::string lift(int layer_id); std::string unlift(); Vec3d get_position() const { return m_pos; } - void set_extra_lift(double extra_zlift) { this->extra_lift = extra_zlift; } private: // Extruders are sorted by their ID, so that binary search is possible. std::vector m_extruders; @@ -96,14 +98,15 @@ private: int16_t m_last_temperature_with_offset; int16_t m_last_bed_temperature; bool m_last_bed_temperature_reached; + // if positive, it's set, and the next lift wil have this extra lift + double m_extra_lift = 0; + // current lift, to remove from m_pos to have the current height. double m_lifted; Vec3d m_pos = Vec3d::Zero(); std::string _travel_to_z(double z, const std::string &comment); std::string _retract(double length, double restart_extra, double restart_extra_toolchange, const std::string &comment); - // if positive, it's set, and the next lift wil have this extra lift - double extra_lift = 0; }; } /* namespace Slic3r */ diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 888a74d88..a133254fc 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -735,6 +735,7 @@ const std::vector& Preset::printer_options() "gcode_precision_e", "use_relative_e_distances", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", + "lift_min", "min_length", "max_gcode_per_second", //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 13cc79c72..36cd55d22 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2590,6 +2590,18 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0)); + def = this->add("lift_min", coFloat); + def->label = L("Min height for travel"); + def->category = OptionCategory::extruders; + def->tooltip = L("When an extruder travels to an object (from the start position or from an object to another), the nozzle height is guaranteed to be at least at this value." + "\nIt's made to ensure the nozzle won't hit clips or things you have on your bed. But be careful to not put a clip in the 'convex shape' of an object." + "\nSet to 0 to disable."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comExpert; + def->is_vector_extruder = true; + def->set_default_value(new ConfigOptionFloat(0)); + def = this->add("machine_limits_usage", coEnum); def->label = L("How to apply limits"); def->full_label = L("Purpose of Machine Limits"); @@ -4036,7 +4048,7 @@ void PrintConfigDef::init_fff_params() "(1+, 0 to use the current extruder to minimize tool changes)."); def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionInt(1)); + def->set_default_value(new ConfigOptionInt(0)); def = this->add("support_material_extrusion_width", coFloatOrPercent); def->label = L("Support material"); @@ -4068,7 +4080,7 @@ void PrintConfigDef::init_fff_params() "(1+, 0 to use the current extruder to minimize tool changes). This affects raft too."); def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionInt(1)); + def->set_default_value(new ConfigOptionInt(0)); def = this->add("support_material_interface_layers", coInt); def->label = L("Interface layers"); @@ -5915,6 +5927,7 @@ std::unordered_set prusa_export_to_remove_keys = { "infill_dense_algo", "infill_dense", "infill_extrusion_spacing", +"lift_min", "machine_max_acceleration_travel", "max_speed_reduction", "milling_after_z", diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index f8b0984b1..0672cdced 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1338,6 +1338,7 @@ public: ConfigOptionInts first_layer_temperature; ConfigOptionInts full_fan_speed_layer; ConfigOptionFloatOrPercent infill_acceleration; + ConfigOptionFloat lift_min; ConfigOptionInts max_fan_speed; ConfigOptionFloatsOrPercents max_layer_height; ConfigOptionFloat max_print_height; @@ -1442,6 +1443,7 @@ protected: OPT_PTR(first_layer_temperature); OPT_PTR(full_fan_speed_layer); OPT_PTR(infill_acceleration); + OPT_PTR(lift_min); OPT_PTR(max_fan_speed); OPT_PTR(max_layer_height); OPT_PTR(max_print_height); diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 42f24a601..175757b1a 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -986,71 +986,70 @@ void Control::draw_ruler(wxDC& dc) wxCoord pos = get_position_from_value(tick); draw_ticks_pair(dc, pos, mid, 5); draw_tick_text(dc, wxPoint(mid, pos), tick); - } - else { - auto draw_short_ticks = [this, mid](wxDC& dc, double& current_tick, int max_tick) { - while (current_tick < max_tick) { - wxCoord pos = get_position_from_value(lround(current_tick)); - draw_ticks_pair(dc, pos, mid, 2); - current_tick += m_ruler.short_step; - if (current_tick > m_max_value) - break; - } - }; - - double short_tick = std::nan(""); - int tick = 0; - double value = 0.0; - int sequence = 0; - - int prev_y_pos = -1; - wxCoord label_height = dc.GetMultiLineTextExtent("0").y - 2; - int values_size = (int)m_values.size(); - - while (tick <= m_max_value) { - value += m_ruler.long_step; - if (value > m_values.back() && sequence < m_ruler.count) { - value = m_ruler.long_step; - for (; tick < values_size; tick++) - if (m_values[tick] < value) + } else { + auto draw_short_ticks = [this, mid](wxDC& dc, double& current_tick, int max_tick) { + while (current_tick < max_tick) { + wxCoord pos = get_position_from_value(lround(current_tick)); + draw_ticks_pair(dc, pos, mid, 2); + current_tick += m_ruler.short_step; + if (current_tick > m_max_value) break; - // short ticks from the last tick to the end of current sequence - assert(! std::isnan(short_tick)); - draw_short_ticks(dc, short_tick, tick); - sequence++; - } - short_tick = tick; + } + }; + + double short_tick = std::nan(""); + int tick = 0; + double value = 0.0; + int sequence = 0; + + int prev_y_pos = -1; + wxCoord label_height = dc.GetMultiLineTextExtent("0").y - 2; + int values_size = (int)m_values.size(); + + while (tick <= m_max_value) { + value += m_ruler.long_step; + if (value > m_values.back() && sequence < m_ruler.count) { + value = m_ruler.long_step; + for (; tick < values_size; tick++) + if (m_values[tick] < value) + break; + // short ticks from the last tick to the end of current sequence + //assert(!std::isnan(short_tick)); + draw_short_ticks(dc, short_tick, tick); + sequence++; + } + short_tick = tick; - for (; tick < values_size; tick++) { - if (m_values[tick] == value) - break; - if (m_values[tick] > value) { - if (tick > 0) - tick--; - break; - } - } - if (tick > m_max_value) - break; + for (; tick < values_size; tick++) { + if (m_values[tick] == value) + break; + if (m_values[tick] > value) { + if (tick > 0) + tick--; + break; + } + } + if (tick > m_max_value) + break; - wxCoord pos = get_position_from_value(tick); - draw_ticks_pair(dc, pos, mid, 5); - if (prev_y_pos < 0 || prev_y_pos - pos >= label_height) { - draw_tick_text(dc, wxPoint(mid, pos), tick); - prev_y_pos = pos; - } + wxCoord pos = get_position_from_value(tick); + draw_ticks_pair(dc, pos, mid, 5); + if (prev_y_pos < 0 || prev_y_pos - pos >= label_height) { + draw_tick_text(dc, wxPoint(mid, pos), tick); + prev_y_pos = pos; + } - draw_short_ticks(dc, short_tick, tick); + draw_short_ticks(dc, short_tick, tick); - if (value == m_values.back() && sequence < m_ruler.count) { - value = 0.0; - sequence++; - tick++; + if (value == m_values.back() && sequence < m_ruler.count) { + value = 0.0; + sequence++; + tick++; + } + } + // short ticks from the last tick to the end + draw_short_ticks(dc, short_tick, m_max_value); } - } - // short ticks from the last tick to the end - draw_short_ticks(dc, short_tick, m_max_value); - } dc.SetTextForeground(old_clr); } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 9db946043..0e3375df3 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2965,7 +2965,7 @@ void TabPrinter::toggle_options() // retract lift above / below only applies if using retract lift vec.resize(0); - vec = { "retract_lift_above", "retract_lift_below", "retract_lift_top" }; + vec = { "retract_lift_above", "retract_lift_below", "retract_lift_top", "retract_lift_first_layer" }; for (auto el : vec) { field = get_field(el, i); if (field) -- cgit v1.2.3