Browse Source

Implement ramping layer change using a tag in gcode

During layer change, instead of generating the gcode, generate a placeholder tag. Then at the end of layer processing replace this tag with a ramping travel move.
This solves the issue, that one does not know the starting point of the current layer where the layer change gcode would be originally generate.
The ramping layer changes uses smoothing of the ramping travel. Also it is adjusted in such a way that it increases the ramp angle when the travel is too short, to always reach the next layer.
SachCZ 1 year ago
parent
commit
7f397cd7b3

+ 0 - 2
src/libslic3r/CMakeLists.txt

@@ -193,8 +193,6 @@ set(SLIC3R_SOURCES
     GCode/AvoidCrossingPerimeters.hpp
     GCode/Travels.cpp
     GCode/Travels.hpp
-    GCode/LayerChanges.cpp
-    GCode/LayerChanges.hpp
     GCode.cpp
     GCode.hpp
     GCodeReader.cpp

+ 122 - 94
src/libslic3r/GCode.cpp

@@ -35,7 +35,6 @@
 #include "GCode/WipeTower.hpp"
 #include "GCode/WipeTowerIntegration.hpp"
 #include "GCode/Travels.hpp"
-#include "GCode/LayerChanges.hpp"
 #include "Point.hpp"
 #include "Polygon.hpp"
 #include "PrintConfig.hpp"
@@ -2081,6 +2080,50 @@ AABBTreeLines::LinesDistancer<Linef> get_previous_layer_distancer(
 }
 }
 
+std::string GCodeGenerator::get_layer_change_gcode(const Vec3d& from, const Vec3d& to, const unsigned extruder_id) {
+    const Polyline xy_path{
+        this->gcode_to_point(from.head<2>()),
+        this->gcode_to_point(to.head<2>())
+    };
+
+    using namespace GCode::Impl::Travels;
+
+    ElevatedTravelParams elevation_params{
+        get_elevated_traval_params(xy_path, this->m_config, extruder_id)};
+
+    const double initial_elevation = from.z();
+    const double z_change = to.z() - from.z();
+    elevation_params.lift_height = std::max(z_change, elevation_params.lift_height);
+
+    const double path_length = unscaled(xy_path.length());
+    const double lift_at_travel_end =
+        (elevation_params.lift_height / elevation_params.slope_end * path_length);
+    if (lift_at_travel_end < z_change) {
+        elevation_params.lift_height = z_change;
+        elevation_params.slope_end = path_length;
+    }
+
+    const std::vector<double> ensure_points_at_distances = linspace(
+        elevation_params.slope_end - elevation_params.blend_width / 2.0,
+        elevation_params.slope_end + elevation_params.blend_width / 2.0,
+        elevation_params.parabola_points_count
+    );
+
+    Points3 travel{generate_elevated_travel(
+        xy_path.points, ensure_points_at_distances, initial_elevation,
+        ElevatedTravelFormula{elevation_params}
+    )};
+
+    std::string travel_gcode;
+    Vec3d previous_point{this->point_to_gcode(travel.front())};
+    for (const Vec3crd& point : tcb::span{travel}.subspan(1)) {
+        const Vec3d gcode_point{this->point_to_gcode(point)};
+        travel_gcode += this->m_writer.get_travel_to_xyz_gcode(previous_point, gcode_point, "layer change");
+        previous_point = gcode_point;
+    }
+    return travel_gcode;
+}
+
 // In sequential mode, process_layer is called once per each object and its copy,
 // therefore layers will contain a single entry and single_object_instance_idx will point to the copy of the object.
 // In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated.
@@ -2150,6 +2193,7 @@ LayerResult GCodeGenerator::process_layer(
         m_enable_loop_clipping = !enable;
     }
 
+
     std::string gcode;
     assert(is_decimal_separator_point()); // for the sprintfs
 
@@ -2168,6 +2212,7 @@ LayerResult GCodeGenerator::process_layer(
     m_last_layer_z = static_cast<float>(print_z);
     m_max_layer_z  = std::max(m_max_layer_z, m_last_layer_z);
     m_last_height = height;
+    m_current_layer_first_position = std::nullopt;
 
     // Set new layer - this will change Z and force a retraction if retract_layer_change is enabled.
     if (! print.config().before_layer_gcode.value.empty()) {
@@ -2179,7 +2224,7 @@ LayerResult GCodeGenerator::process_layer(
             print.config().before_layer_gcode.value, m_writer.extruder()->id(), &config)
             + "\n";
     }
-    gcode += this->change_layer(previous_layer_z, print_z, result.spiral_vase_enable);  // this will increase m_layer_index
+    gcode += this->change_layer(previous_layer_z, print_z); // this will increase m_layer_index
     m_layer = &layer;
     if (this->line_distancer_is_required(layer_tools.extruders) && this->m_layer != nullptr && this->m_layer->lower_layer != nullptr) {
         this->m_previous_layer_distancer = GCode::Impl::get_previous_layer_distancer(layers, layer.lower_layer->lslices);
@@ -2305,6 +2350,33 @@ LayerResult GCodeGenerator::process_layer(
                 is_anything_overridden, false /* print_wipe_extrusions */);
     }
 
+
+    // During layer change the starting position of next layer is now known.
+    // The solution is thus to emplace a temporary tag to the gcode, cache the postion and
+    // replace the tag later. The tag is Layer_Change_Travel, the cached position is
+    // m_current_layer_first_position and it is replaced here.
+    const std::string tag = GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Travel);
+    std::string layer_change_gcode;
+    const bool do_ramping_layer_change = (
+        m_previous_layer_last_position
+        && m_current_layer_first_position
+        && m_layer_change_extruder_id
+        && !result.spiral_vase_enable
+        && print_z > previous_layer_z
+        && EXTRUDER_CONFIG(travel_ramping_lift)
+        && EXTRUDER_CONFIG(travel_slope) > 0 && EXTRUDER_CONFIG(travel_slope) < 90
+    );
+    if (do_ramping_layer_change) {
+        layer_change_gcode = this->get_layer_change_gcode(*m_previous_layer_last_position, *m_current_layer_first_position, *m_layer_change_extruder_id);
+    } else {
+        if (!m_current_layer_first_position) {
+            throw std::runtime_error("Destination is required for layer change!");
+        }
+        layer_change_gcode = this->writer().get_travel_to_z_gcode(m_current_layer_first_position->z(), "simple layer change");
+    }
+
+    boost::algorithm::replace_first(gcode, tag, layer_change_gcode);
+
     BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
     log_memory_info();
 
@@ -2604,63 +2676,10 @@ std::string GCodeGenerator::preamble()
     return gcode;
 }
 
-
-std::optional<std::string> GCodeGenerator::get_helical_layer_change_gcode(
-    const coordf_t previous_layer_z,
-    const coordf_t print_z,
-    const std::string& comment
-) {
-
-    if (!this->last_pos_defined()) {
-        return std::nullopt;
-    }
-
-    const double circle_radius{2};
-    const unsigned n_gon_points_count{16};
-
-    const Point n_gon_start_point{this->last_pos()};
-
-    GCode::Impl::LayerChanges::Bed bed{
-        this->m_config.bed_shape.values,
-        circle_radius * 2
-    };
-    if (!bed.contains_within_padding(this->point_to_gcode(n_gon_start_point))) {
-        return std::nullopt;
-    }
-
-    const Vec2crd n_gon_vector{scaled(Vec2d{
-        (bed.centroid - this->point_to_gcode(n_gon_start_point)).normalized() * circle_radius
-    })};
-    const Point n_gon_centeroid{n_gon_start_point + n_gon_vector};
-
-    const Polygon n_gon{GCode::Impl::LayerChanges::generate_regular_polygon(
-        n_gon_centeroid,
-        n_gon_start_point,
-        n_gon_points_count
-    )};
-
-    const double n_gon_circumference = unscaled(n_gon.length());
-
-    const double z_change{print_z - previous_layer_z};
-    Points3 helix{GCode::Impl::Travels::generate_elevated_travel(
-        n_gon.points,
-        {},
-        previous_layer_z,
-        [&](const double distance){
-            return distance / n_gon_circumference * z_change;
-        }
-    )};
-
-    helix.emplace_back(to_3d(this->last_pos(), scaled(print_z)));
-
-    return this->generate_travel_gcode(helix, comment);
-}
-
 // called by GCodeGenerator::process_layer()
 std::string GCodeGenerator::change_layer(
     coordf_t previous_layer_z,
-    coordf_t print_z,
-    const bool spiral_vase_enabled
+    coordf_t print_z
 ) {
     std::string gcode;
     if (m_layer_count > 0)
@@ -2670,31 +2689,16 @@ std::string GCodeGenerator::change_layer(
     if (EXTRUDER_CONFIG(retract_layer_change))
         gcode += this->retract_and_wipe();
 
-    const std::string comment{"move to next layer (" + std::to_string(m_layer_index) + ")"};
+    Vec3d new_position = this->writer().get_position();
+    new_position.z() = print_z;
+    this->writer().update_position(new_position);
 
-    bool do_helical_layer_change{
-        !spiral_vase_enabled
-        && print_z > previous_layer_z
-        && EXTRUDER_CONFIG(retract_layer_change)
-        && EXTRUDER_CONFIG(retract_length) > 0
-        && EXTRUDER_CONFIG(travel_ramping_lift)
-        && EXTRUDER_CONFIG(travel_slope) > 0 && EXTRUDER_CONFIG(travel_slope) < 90
-    };
+    m_previous_layer_last_position = this->m_last_pos_defined ?
+        std::optional{to_3d(this->point_to_gcode(this->last_pos()), previous_layer_z)} :
+        std::nullopt;
 
-    const std::optional<std::string> helix_gcode{
-        do_helical_layer_change ?
-        this->get_helical_layer_change_gcode(
-            m_config.z_offset.value + previous_layer_z,
-            m_config.z_offset.value + print_z,
-            comment
-        ) :
-        std::nullopt
-    };
-    gcode += (
-        helix_gcode ?
-        *helix_gcode :
-        m_writer.travel_to_z(m_config.z_offset.value + print_z, comment)
-    );
+    gcode += GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Travel);
+    this->m_layer_change_extruder_id = m_writer.extruder()->id();
 
     // forget last wiping path as wiping after raising Z is pointless
     m_wipe.reset_path();
@@ -2963,19 +2967,31 @@ std::string GCodeGenerator::_extrude(
     std::string gcode;
     const std::string_view description_bridge = path_attr.role.is_bridge() ? " (bridge)"sv : ""sv;
 
-    // go to first point of extrusion path
-    if (!m_last_pos_defined) {
-        const double z = this->m_last_layer_z + this->m_config.z_offset.value;
-        const std::string comment{"move to print after unknown position"};
-        gcode += this->retract_and_wipe();
-        gcode += this->m_writer.travel_to_xy(this->point_to_gcode(path.front().point), comment);
-        gcode += this->m_writer.get_travel_to_z_gcode(z, comment);
-    } else if ( m_last_pos != path.front().point) {
-        std::string comment = "move to first ";
-        comment += description;
-        comment += description_bridge;
-        comment += " point";
-        gcode += this->travel_to(path.front().point, path_attr.role, comment);
+    if (!m_current_layer_first_position) {
+        // Make the first travel just one G1.
+        const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z + this->m_config.z_offset.value));
+        const Vec3d gcode_point = to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z()));
+        this->set_last_pos(path.front().point);
+        this->writer().update_position(gcode_point);
+        gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), "move to first layer point");
+        gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), "move to first layer point");
+        m_current_layer_first_position = gcode_point;
+    } else {
+        // go to first point of extrusion path
+        if (!m_last_pos_defined) {
+            const double z = this->m_last_layer_z + this->m_config.z_offset.value;
+            const std::string comment{"move to print after unknown position"};
+            gcode += this->retract_and_wipe();
+            gcode += this->m_writer.travel_to_xy(this->point_to_gcode(path.front().point), comment);
+            gcode += this->m_writer.get_travel_to_z_gcode(z, comment);
+        } else if ( m_last_pos != path.front().point) {
+            std::string comment = "move to first ";
+            comment += description;
+            comment += description_bridge;
+            comment += " point";
+            const std::string travel_gcode{this->travel_to(path.front().point, path_attr.role, comment)};
+            gcode += travel_gcode;
+        }
     }
 
     // compensate retraction
@@ -3217,9 +3233,13 @@ std::string GCodeGenerator::generate_travel_gcode(
     // use G1 because we rely on paths being straight (G0 may make round paths)
     gcode += this->m_writer.set_travel_acceleration(acceleration);
 
-    for (const Vec3crd& point : travel) {
-        gcode += this->m_writer.travel_to_xyz(to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z())), comment);
+    Vec3d previous_point{this->point_to_gcode(travel.front())};
+    for (const Vec3crd& point : tcb::span{travel}.subspan(1)) {
+        const Vec3d gcode_point{this->point_to_gcode(point)};
+
+        gcode += this->m_writer.travel_to_xyz(previous_point, gcode_point, comment);
         this->set_last_pos(point.head<2>());
+        previous_point = gcode_point;
     }
 
     if (! GCodeWriter::supports_separate_travel_acceleration(config().gcode_flavor)) {
@@ -3351,6 +3371,14 @@ std::string GCodeGenerator::travel_to(const Point &point, ExtrusionRole role, st
     const double retract_length = this->m_config.retract_length.get_at(extruder_id);
     bool can_be_flat{!needs_retraction || retract_length == 0};
     const double initial_elevation = this->m_last_layer_z + this->m_config.z_offset.value;
+
+    const double upper_limit = this->m_config.retract_lift_below.get_at(extruder_id);
+    const double lower_limit = this->m_config.retract_lift_above.get_at(extruder_id);
+    if ((lower_limit > 0 && initial_elevation < lower_limit) ||
+        (upper_limit > 0 && initial_elevation > upper_limit)) {
+        can_be_flat = true;
+    }
+
     const Points3 travel = (
         can_be_flat ?
         GCode::Impl::Travels::generate_flat_travel(xy_path.points, initial_elevation) :

+ 26 - 12
src/libslic3r/GCode.hpp

@@ -127,11 +127,25 @@ public:
     const Point&    last_pos() const { return m_last_pos; }
     // Convert coordinates of the active object to G-code coordinates, possibly adjusted for extruder offset.
     template<typename Derived>
-    Vec2d           point_to_gcode(const Eigen::MatrixBase<Derived> &point) const {
-        static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "GCodeGenerator::point_to_gcode(): first parameter is not a 2D vector");
-        return Vec2d(unscaled<double>(point.x()), unscaled<double>(point.y())) + m_origin 
-            - m_config.extruder_offset.get_at(m_writer.extruder()->id());
+    Eigen::Matrix<double, Derived::SizeAtCompileTime, 1, Eigen::DontAlign> point_to_gcode(const Eigen::MatrixBase<Derived> &point) const {
+        static_assert(
+            Derived::IsVectorAtCompileTime,
+            "GCodeGenerator::point_to_gcode(): first parameter is not a vector"
+        );
+        static_assert(
+            int(Derived::SizeAtCompileTime) == 2 || int(Derived::SizeAtCompileTime) == 3,
+            "GCodeGenerator::point_to_gcode(): first parameter is not a 2D or 3D vector"
+        );
+
+        if constexpr (Derived::SizeAtCompileTime == 2) {
+            return Vec2d(unscaled<double>(point.x()), unscaled<double>(point.y())) + m_origin
+                - m_config.extruder_offset.get_at(m_writer.extruder()->id());
+        } else {
+            const Vec2d gcode_point_xy{this->point_to_gcode(point.template head<2>())};
+            return to_3d(gcode_point_xy, unscaled(point.z()));
+        }
     }
+
     // Convert coordinates of the active object to G-code coordinates, possibly adjusted for extruder offset and quantized to G-code resolution.
     template<typename Derived>
     Vec2d           point_to_gcode_quantized(const Eigen::MatrixBase<Derived> &point) const {
@@ -216,6 +230,9 @@ private:
     static ObjectsLayerToPrint         		                     collect_layers_to_print(const PrintObject &object);
     static std::vector<std::pair<coordf_t, ObjectsLayerToPrint>> collect_layers_to_print(const Print &print);
 
+    /** @brief Generates ramping travel gcode for layer change. */
+    std::string get_layer_change_gcode(const Vec3d& from, const Vec3d& to, const unsigned extruder_id);
+
     LayerResult process_layer(
         const Print                     &print,
         // Set of object & print layers of the same PrintObject and with the same print_z.
@@ -253,15 +270,9 @@ private:
     bool            last_pos_defined() const { return m_last_pos_defined; }
     void            set_extruders(const std::vector<unsigned int> &extruder_ids);
     std::string     preamble();
-    std::optional<std::string> get_helical_layer_change_gcode(
-        const coordf_t previous_layer_z,
-        const coordf_t print_z,
-        const std::string& comment
-    );
     std::string change_layer(
         coordf_t previous_layer_z,
-        coordf_t print_z,
-        const bool spiral_vase_enabled
+        coordf_t print_z
     );
     std::string     extrude_entity(const ExtrusionEntityReference &entity, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.);
     std::string     extrude_loop(const ExtrusionLoop &loop, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.);
@@ -412,7 +423,10 @@ private:
 
     Point                               m_last_pos;
     bool                                m_last_pos_defined;
-
+    std::optional<Vec3d>                m_previous_layer_last_position;
+    // This needs to be populated during the layer processing!
+    std::optional<Vec3d>                m_current_layer_first_position;
+    std::optional<unsigned>             m_layer_change_extruder_id;
     std::unique_ptr<CoolingBuffer>      m_cooling_buffer;
     std::unique_ptr<SpiralVase>         m_spiral_vase;
     std::unique_ptr<GCodeFindReplace>   m_find_replace;

+ 1 - 0
src/libslic3r/GCode/GCodeProcessor.cpp

@@ -57,6 +57,7 @@ const std::vector<std::string> GCodeProcessor::Reserved_Tags = {
     "HEIGHT:",
     "WIDTH:",
     "LAYER_CHANGE",
+    "LAYER_CHANGE_TRAVEL",
     "COLOR_CHANGE",
     "PAUSE_PRINT",
     "CUSTOM_GCODE",

+ 1 - 0
src/libslic3r/GCode/GCodeProcessor.hpp

@@ -192,6 +192,7 @@ namespace Slic3r {
             Height,
             Width,
             Layer_Change,
+            Layer_Change_Travel,
             Color_Change,
             Pause_Print,
             Custom_Code,

+ 39 - 21
src/libslic3r/GCode/GCodeWriter.cpp

@@ -275,10 +275,8 @@ std::string GCodeWriter::set_speed(double F, const std::string_view comment, con
     return w.string();
 }
 
-std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string_view comment)
+std::string GCodeWriter::get_travel_to_xy_gcode(const Vec2d &point, const std::string_view comment) const
 {
-    m_pos.head<2>() = point.head<2>();
-
     GCodeG1Formatter w;
     w.emit_xy(point);
     w.emit_f(this->config.travel_speed.value * 60.0);
@@ -286,6 +284,12 @@ std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string_view
     return w.string();
 }
 
+std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string_view comment)
+{
+    m_pos.head<2>() = point.head<2>();
+    return this->get_travel_to_xy_gcode(point, comment);
+}
+
 std::string GCodeWriter::travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, const std::string_view comment)
 {
     assert(std::abs(point.x()) < 1200.);
@@ -303,35 +307,49 @@ std::string GCodeWriter::travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij
     return w.string();
 }
 
-std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string_view comment)
+std::string GCodeWriter::travel_to_xyz(const Vec3d& from, const Vec3d &to, const std::string_view comment)
 {
-    if (std::abs(point.x() - m_pos.x()) < EPSILON && std::abs(point.y() - m_pos.y()) < EPSILON) {
-        return this->travel_to_z(point.z(), comment);
-    } else if (std::abs(point.z() - m_pos.z()) < EPSILON) {
-        return this->travel_to_xy(point.head<2>(), comment);
+    if (std::abs(to.x() - m_pos.x()) < EPSILON && std::abs(to.y() - m_pos.y()) < EPSILON) {
+        return this->travel_to_z(to.z(), comment);
+    } else if (std::abs(to.z() - m_pos.z()) < EPSILON) {
+        return this->travel_to_xy(to.head<2>(), comment);
     } else {
-        m_pos = point;
-
-        GCodeG1Formatter w;
-        w.emit_xyz(point);
-
-        Vec2f speed {this->config.travel_speed_z.value, this->config.travel_speed.value};
-        w.emit_f(speed.norm() * 60.0);
-        w.emit_comment(this->config.gcode_comments, comment);
-        return w.string();
+        m_pos = to;
+        return this->get_travel_to_xyz_gcode(from, to, comment);
     }
 }
 
+std::string GCodeWriter::get_travel_to_xyz_gcode(const Vec3d &from, const Vec3d &to, const std::string_view comment) const {
+    GCodeG1Formatter w;
+    w.emit_xyz(to);
+
+    const double distance_xy{(to.head<2>() - from.head<2>()).norm()};
+    const double distnace_z{std::abs(to.z() - from.z())};
+    const double time_z = distnace_z / this->config.travel_speed_z.value;
+    const double time_xy = distance_xy / this->config.travel_speed.value;
+    const double factor = time_z > 0 ? time_xy / time_z : 1;
+    if (factor < 1) {
+        w.emit_f((this->config.travel_speed.value * factor  + (1 - factor) * this->config.travel_speed_z.value) * 60.0);
+    } else {
+        w.emit_f(this->config.travel_speed.value * 60.0);
+    }
+
+    w.emit_comment(this->config.gcode_comments, comment);
+    return w.string();
+}
 
 std::string GCodeWriter::travel_to_z(double z, const std::string_view comment)
 {
-    return std::abs(m_pos.z() - z) < EPSILON ? "" : this->get_travel_to_z_gcode(z, comment);
+    if (std::abs(m_pos.z() - z) < EPSILON) {
+        return "";
+    } else {
+        m_pos.z() = z;
+        return this->get_travel_to_z_gcode(z, comment);
+    }
 }
 
-std::string GCodeWriter::get_travel_to_z_gcode(double z, const std::string_view comment)
+std::string GCodeWriter::get_travel_to_z_gcode(double z, const std::string_view comment) const
 {
-    m_pos.z() = z;
-
     double speed = this->config.travel_speed_z.value;
     if (speed == 0.)
         speed = this->config.travel_speed.value;

+ 15 - 2
src/libslic3r/GCode/GCodeWriter.hpp

@@ -66,10 +66,23 @@ public:
     std::string toolchange_prefix() const;
     std::string toolchange(unsigned int extruder_id);
     std::string set_speed(double F, const std::string_view comment = {}, const std::string_view cooling_marker = {}) const;
+
+    std::string get_travel_to_xy_gcode(const Vec2d &point, const std::string_view comment) const;
     std::string travel_to_xy(const Vec2d &point, const std::string_view comment = {});
     std::string travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, const std::string_view comment = {});
-    std::string travel_to_xyz(const Vec3d &point, const std::string_view comment = {});
-    std::string get_travel_to_z_gcode(double z, const std::string_view comment);
+
+    /**
+     * @brief Return gcode with all three axis defined. Optionally adds feedrate.
+     *
+     * Feedrate is added the starting point "from" is specified.
+     *
+     * @param from Optional starting point of the travel.
+     * @param to Where to travel to.
+     * @param comment Description of the travel purpose.
+     */
+    std::string get_travel_to_xyz_gcode(const Vec3d &from, const Vec3d &to, const std::string_view comment) const;
+    std::string travel_to_xyz(const Vec3d &from, const Vec3d &to, const std::string_view comment = {});
+    std::string get_travel_to_z_gcode(double z, const std::string_view comment) const;
     std::string travel_to_z(double z, const std::string_view comment = {});
     std::string extrude_to_xy(const Vec2d &point, double dE, const std::string_view comment = {});
     std::string extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, double dE, const std::string_view comment);

+ 0 - 53
src/libslic3r/GCode/LayerChanges.cpp

@@ -1,53 +0,0 @@
-#include "LayerChanges.hpp"
-#include "libslic3r/ClipperUtils.hpp"
-
-namespace Slic3r::GCode::Impl::LayerChanges {
-
-Polygon generate_regular_polygon(
-    const Point &centroid, const Point &start_point, const unsigned points_count
-) {
-    Points points;
-    points.reserve(points_count);
-    const double part_angle{2 * M_PI / points_count};
-    for (unsigned i = 0; i < points_count; ++i) {
-        const double current_angle{i * part_angle};
-        points.emplace_back(scaled(std::cos(current_angle)), scaled(std::sin(current_angle)));
-    }
-
-    Polygon regular_polygon{points};
-    const Vec2d current_vector{unscaled(regular_polygon.points.front())};
-    const Vec2d expected_vector{unscaled(start_point) - unscaled(centroid)};
-
-    const double current_scale = current_vector.norm();
-    const double expected_scale = expected_vector.norm();
-    regular_polygon.scale(expected_scale / current_scale);
-
-    regular_polygon.rotate(angle(current_vector, expected_vector));
-
-    regular_polygon.translate(centroid);
-
-    return regular_polygon;
-}
-
-Bed::Bed(const std::vector<Vec2d> &shape, const double padding)
-    : inner_offset(get_inner_offset(shape, padding)), centroid(unscaled(inner_offset.centroid())) {}
-
-bool Bed::contains_within_padding(const Vec2d &point) const {
-    return inner_offset.contains(scaled(point));
-}
-
-Polygon Bed::get_inner_offset(const std::vector<Vec2d> &shape, const double padding) {
-    Points shape_scaled;
-    shape_scaled.reserve(shape.size());
-    using std::begin, std::end, std::back_inserter, std::transform;
-    transform(begin(shape), end(shape), back_inserter(shape_scaled), [](const Vec2d &point) {
-        return scaled(point);
-    });
-    const Polygons inner_offset{shrink({Polygon{shape_scaled}}, scaled(padding))};
-    if (inner_offset.empty()) {
-        return Polygon{};
-    }
-    return inner_offset.front();
-}
-
-} // namespace Slic3r::GCode::Impl::LayerChanges

+ 0 - 52
src/libslic3r/GCode/LayerChanges.hpp

@@ -1,52 +0,0 @@
-/**
- * @file
- * @brief Utility functions for layer change gcode generation.
- */
-
-#ifndef slic3r_GCode_LayerChanges_hpp_
-#define slic3r_GCode_LayerChanges_hpp_
-
-#include "libslic3r/Point.hpp"
-#include "libslic3r/Polygon.hpp"
-
-namespace Slic3r::GCode::Impl::LayerChanges {
-/**
- * Generates a regular polygon - all angles are the same (e.g. typical hexagon).
- *
- * @param centroid Central point.
- * @param start_point The polygon point are ordered. This is the first point.
- * @param points_count Amount of nodes of the polygon (e.g. 6 for haxagon).
- *
- * Distance between centroid and start point sets the scale of the polygon.
- */
-Polygon generate_regular_polygon(
-    const Point &centroid, const Point &start_point, const unsigned points_count
-);
-
-/**
- * @brief A representation of the bed shape with inner padding.
- *
- * Its purpose is to facilitate the bed boundary checking.
- */
-class Bed
-{
-private:
-    Polygon inner_offset;
-    static Polygon get_inner_offset(const std::vector<Vec2d> &shape, const double padding);
-
-public:
-    /**
-     * Bed shape with inner padding.
-     */
-    Bed(const std::vector<Vec2d> &shape, const double padding);
-
-    Vec2d centroid;
-
-    /**
-     * Returns true if the point is within the bed shape including inner padding.
-     */
-    bool contains_within_padding(const Vec2d &point) const;
-};
-} // namespace Slic3r::GCode::Impl::LayerChanges
-
-#endif // slic3r_GCode_LayerChanges_hpp_

+ 7 - 24
src/libslic3r/GCode/Travels.cpp

@@ -43,8 +43,8 @@ double ElevatedTravelFormula::operator()(const double distance_from_start) const
 
 Points3 generate_flat_travel(tcb::span<const Point> xy_path, const float elevation) {
     Points3 result;
-    result.reserve(xy_path.size() - 1);
-    for (const Point &point : xy_path.subspan(1)) {
+    result.reserve(xy_path.size());
+    for (const Point &point : xy_path) {
         result.emplace_back(point.x(), point.y(), scaled(elevation));
     }
     return result;
@@ -140,21 +140,6 @@ std::optional<double> get_first_crossed_line_distance(
     return {};
 }
 
-std::optional<double> get_obstacle_adjusted_slope_end(
-    const Lines &xy_path,
-    const std::optional<AABBTreeLines::LinesDistancer<Linef>> &previous_layer_distancer
-) {
-    if (!previous_layer_distancer) {
-        return std::nullopt;
-    }
-    std::optional<double> first_obstacle_distance =
-        get_first_crossed_line_distance(xy_path, *previous_layer_distancer);
-    if (!first_obstacle_distance) {
-        return std::nullopt;
-    }
-    return *first_obstacle_distance;
-}
-
 struct SmoothingParams
 {
     double blend_width{};
@@ -212,7 +197,7 @@ SmoothingParams get_smoothing_params(
 }
 
 ElevatedTravelParams get_elevated_traval_params(
-    const Polyline &xy_path,
+    const Polyline& xy_path,
     const FullPrintConfig &config,
     const unsigned extruder_id,
     const std::optional<AABBTreeLines::LinesDistancer<Linef>> &previous_layer_distancer
@@ -236,7 +221,10 @@ ElevatedTravelParams get_elevated_traval_params(
     }
 
     std::optional<double> obstacle_adjusted_slope_end{
-        get_obstacle_adjusted_slope_end(xy_path.lines(), previous_layer_distancer)};
+        previous_layer_distancer ?
+        get_first_crossed_line_distance(xy_path.lines(), *previous_layer_distancer) :
+        std::nullopt
+    };
 
     if (obstacle_adjusted_slope_end && obstacle_adjusted_slope_end < elevation_params.slope_end) {
         elevation_params.slope_end = *obstacle_adjusted_slope_end;
@@ -252,11 +240,6 @@ ElevatedTravelParams get_elevated_traval_params(
     return elevation_params;
 }
 
-/**
- * @brief Generate regulary spaced points on 1 axis. Includes both from and to.
- *
- * If count is 1, the point is in the middle of the range.
- */
 std::vector<double> linspace(const double from, const double to, const unsigned count) {
     if (count == 0) {
         return {};

Some files were not shown because too many files changed in this diff