Various ZAA fixes.

- Handle z contouring in variable speed flow when emitting GCode
- Add logic to restore nominnal z height for regular extrusions
- preserve z_contoured flag when splitting extrusion paths
This commit is contained in:
Aleksandr Dobkin
2026-03-24 09:18:38 -07:00
parent 1cc82873f4
commit 95736445a4
10 changed files with 190 additions and 137 deletions

View File

@@ -1,5 +1,6 @@
#include "BoundingBox.hpp"
#include "Config.hpp"
#include "GCodeWriter.hpp"
#include "Polygon.hpp"
#include "PrintConfig.hpp"
#include "libslic3r.h"
@@ -5817,7 +5818,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop& loop_ref,
const Point3 &center3 = paths.front().polyline.points.front();
pt.rotate(angle, Point(center3.x(), center3.y()));
// generate the travel move
gcode += m_writer.extrude_to_xy(this->point_to_gcode(pt), 0,"move inwards before travel",true);
gcode += m_writer.extrude_to_xy(this->point_to_gcode(pt), 0, "move inwards before travel", true);
}
return gcode;
@@ -6150,19 +6151,13 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
// Move to first point of extrusion path
// path is 2D. But in slope lift case, lift z is done in travel_to function.
// Add m_need_change_layer_lift_z when change_layer in case of no lift if m_last_pos is equal to path.first_point() by chance
Point3 first_point = path.first_point3();
if (!m_last_pos_defined || m_last_pos != first_point || m_need_change_layer_lift_z || slope_need_z_travel) {
Point first_point = path.first_point();
if (!m_last_pos_defined || m_last_pos.to_point() != first_point || m_need_change_layer_lift_z || slope_need_z_travel) {
const bool _last_pos_undefined = !m_last_pos_defined;
double z = DBL_MAX;
if (sloped != nullptr) {
z = get_sloped_z(sloped->slope_begin.z_ratio);
} else if ((!m_last_pos_defined && first_point.z() != 0) || m_last_pos.z() != first_point.z()) {
z = m_nominal_z + unscale_(first_point.z());
if (z < 0.1) {
throw RuntimeError("GCode: very low z");
}
}
gcode += this->travel_to(path.first_point(), path.role(), "move to first " + description + " point", z);
gcode += this->travel_to(path.first_point(), path.role(), "move to first " + description + " point",
sloped == nullptr ? DBL_MAX : get_sloped_z(sloped->slope_begin.z_ratio));
m_need_change_layer_lift_z = false;
// Orca: ensure Z matches planned layer height
if (_last_pos_undefined && !slope_need_z_travel) {
@@ -6170,6 +6165,20 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
}
}
if (path.z_contoured && !path.polyline.lines().empty()) {
double current_z = m_writer.get_position().z();
;
double first_z = unscale_(path.polyline.lines().begin()->a.z()) + m_nominal_z;
if (GCodeFormatter::quantize_xyzf(first_z) != GCodeFormatter::quantize_xyzf(current_z)) {
gcode += m_writer.travel_to_z(first_z, "set Z for contouring", true);
}
}
if (!path.z_contoured) {
double current_z = m_writer.get_position().z();
if (GCodeFormatter::quantize_xyzf(current_z) != GCodeFormatter::quantize_xyzf(m_nominal_z)) {
gcode += this->writer().travel_to_z(m_nominal_z, "reset Z after contouring", true);
}
}
// if needed, write the gcode_label_objects_end then gcode_label_objects_start
// should be already done by travel_to, but just in case
@@ -6729,6 +6738,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
if (!m_config.enable_arc_fitting || path.polyline.fitting_result.empty() || m_config.spiral_mode || sloped != nullptr || path.z_contoured) {
double path_length = 0.;
double total_length = sloped == nullptr ? 0. : path.polyline.length() * SCALING_FACTOR;
double saved_z = m_writer.get_position().z();
for (const Line3& line : path.polyline.lines()) {
std::string tempDescription = description;
const double line_length = line.length() * SCALING_FACTOR;
@@ -6849,14 +6860,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
double total_length = 0;
if (sloped != nullptr) {
// Calculate total extrusion length
Points p;
Points3 p;
p.reserve(new_points.size());
std::transform(new_points.begin(), new_points.end(), std::back_inserter(p), [](const ProcessedPoint& pp) { return pp.p; });
Polyline l(p);
Polyline3 l(p);
total_length = l.length() * SCALING_FACTOR;
}
gcode += m_writer.set_speed(last_set_speed, "", comment);
Vec2d prev = this->point_to_gcode_quantized(new_points[0].p);
Vec3d prev = this->point_to_gcode_quantized(new_points[0].p);
bool pre_fan_enabled = false;
bool cur_fan_enabled = false;
if( m_enable_cooling_markers && enable_overhang_bridge_fan)
@@ -6870,7 +6881,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
std::string tempDescription = description;
const ProcessedPoint &processed_point = new_points[i];
const ProcessedPoint &pre_processed_point = new_points[i-1];
Vec2d p = this->point_to_gcode_quantized(processed_point.p);
Vec3d p = this->point_to_gcode_quantized(processed_point.p);
if (m_enable_cooling_markers) {
if (enable_overhang_bridge_fan) {
cur_fan_enabled = check_overhang_fan(processed_point.overlap, path.role());
@@ -6952,9 +6963,26 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
tempDescription += Slic3r::format(" | Old Flow Value: %0.5f Length: %0.5f",oldE, line_length);
}
}
if (sloped == nullptr) {
if (path.z_contoured) {
Vec2d dest2d = p.head<2>();
coordf_t z_diff = unscale_(processed_point.p.z());
double extrusion_ratio = 1;
if (path.role() != erIroning) {
extrusion_ratio = (path.height + z_diff) / path.height;
}
double e = dE * extrusion_ratio;
double z = m_nominal_z + z_diff;
if (z < 0.1) {
throw RuntimeError("GCode: very low z");
}
gcode += m_writer.extrude_to_xyz(Vec3d(dest2d.x(), dest2d.y(), z), e,
GCodeWriter::full_gcode_comment ? tempDescription : "");
} else if (sloped == nullptr) {
// Normal extrusion
gcode += m_writer.extrude_to_xy(p, dE, GCodeWriter::full_gcode_comment ? tempDescription : "");
gcode += m_writer.extrude_to_xy(p.head<2>(), dE, GCodeWriter::full_gcode_comment ? tempDescription : "");
} else {
// Sloped extrusion
const auto [z_ratio, e_ratio] = sloped->interpolate(path_length / total_length);
@@ -7811,6 +7839,13 @@ Vec2d GCode::point_to_gcode(const Point &point) const
return unscale(point) + m_origin - extruder_offset;
}
Vec3d GCode::point_to_gcode(const Point3& point) const
{
Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
Vec2d xy = unscale(point.to_point()) + m_origin - extruder_offset;
return Vec3d(xy.x(), xy.y(), unscale_(point.z()));
}
// convert a model-space scaled point into G-code coordinates
Point GCode::gcode_to_point(const Vec2d &point) const
{
@@ -7828,6 +7863,11 @@ Vec2d GCode::point_to_gcode_quantized(const Point& point) const
return { GCodeFormatter::quantize_xyzf(p.x()), GCodeFormatter::quantize_xyzf(p.y()) };
}
Vec3d GCode::point_to_gcode_quantized(const Point3& point) const
{
Vec3d p = this->point_to_gcode(point);
return {GCodeFormatter::quantize_xyzf(p.x()), GCodeFormatter::quantize_xyzf(p.y()), GCodeFormatter::quantize_xyzf(p.z())};
}
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)