mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-03 20:30:44 +08:00
ArcWelder: Extended cooling buffer with G2/G3 IJ/R
This commit is contained in:
parent
5111a3d4cf
commit
7eca48b755
@ -33,36 +33,45 @@ CoolingBuffer::CoolingBuffer(GCodeGenerator &gcodegen) : m_config(gcodegen.confi
|
||||
|
||||
void CoolingBuffer::reset(const Vec3d &position)
|
||||
{
|
||||
m_current_pos.assign(5, 0.f);
|
||||
m_current_pos[0] = float(position.x());
|
||||
m_current_pos[1] = float(position.y());
|
||||
m_current_pos[2] = float(position.z());
|
||||
m_current_pos[4] = float(m_config.travel_speed.value);
|
||||
assert(m_current_pos.size() == 5);
|
||||
m_current_pos[AxisIdx::X] = float(position.x());
|
||||
m_current_pos[AxisIdx::Y] = float(position.y());
|
||||
m_current_pos[AxisIdx::Z] = float(position.z());
|
||||
m_current_pos[AxisIdx::E] = 0.f;
|
||||
m_current_pos[AxisIdx::F] = float(m_config.travel_speed.value);
|
||||
m_fan_speed = -1;
|
||||
}
|
||||
|
||||
struct CoolingLine
|
||||
{
|
||||
enum Type {
|
||||
enum Type : uint32_t {
|
||||
TYPE_SET_TOOL = 1 << 0,
|
||||
TYPE_EXTRUDE_END = 1 << 1,
|
||||
TYPE_BRIDGE_FAN_START = 1 << 2,
|
||||
TYPE_BRIDGE_FAN_END = 1 << 3,
|
||||
TYPE_G0 = 1 << 4,
|
||||
TYPE_G1 = 1 << 5,
|
||||
TYPE_ADJUSTABLE = 1 << 6,
|
||||
TYPE_EXTERNAL_PERIMETER = 1 << 7,
|
||||
// G2 or G3: Arc interpolation
|
||||
TYPE_G2G3 = 1 << 6,
|
||||
TYPE_ADJUSTABLE = 1 << 7,
|
||||
TYPE_EXTERNAL_PERIMETER = 1 << 8,
|
||||
// Arc interpolation, counter-clockwise.
|
||||
TYPE_G2G3_CCW = 1 << 9,
|
||||
// Arc interpolation, arc defined by IJ (offset of arc center from its start position).
|
||||
TYPE_G2G3_IJ = 1 << 10,
|
||||
// Arc interpolation, arc defined by R (arc radius, positive - smaller, negative - larger).
|
||||
TYPE_G2G3_R = 1 << 11,
|
||||
// The line sets a feedrate.
|
||||
TYPE_HAS_F = 1 << 8,
|
||||
TYPE_WIPE = 1 << 9,
|
||||
TYPE_G4 = 1 << 10,
|
||||
TYPE_G92 = 1 << 11,
|
||||
TYPE_HAS_F = 1 << 12,
|
||||
TYPE_WIPE = 1 << 13,
|
||||
TYPE_G4 = 1 << 14,
|
||||
TYPE_G92 = 1 << 15,
|
||||
// Would be TYPE_ADJUSTABLE, but the block of G-code lines has zero extrusion length, thus the block
|
||||
// cannot have its speed adjusted. This should not happen (sic!).
|
||||
TYPE_ADJUSTABLE_EMPTY = 1 << 12,
|
||||
TYPE_ADJUSTABLE_EMPTY = 1 << 16,
|
||||
// Custom fan speed (introduced for overhang fan speed)
|
||||
TYPE_SET_FAN_SPEED = 1 << 13,
|
||||
TYPE_RESET_FAN_SPEED = 1 << 14,
|
||||
TYPE_SET_FAN_SPEED = 1 << 17,
|
||||
TYPE_RESET_FAN_SPEED = 1 << 18,
|
||||
};
|
||||
|
||||
CoolingLine(unsigned int type, size_t line_start, size_t line_end) :
|
||||
@ -324,7 +333,7 @@ std::string CoolingBuffer::process_layer(std::string &&gcode, size_t layer_id, b
|
||||
|
||||
// Parse the layer G-code for the moves, which could be adjusted.
|
||||
// Return the list of parsed lines, bucketed by an extruder.
|
||||
std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::string &gcode, std::vector<float> ¤t_pos) const
|
||||
std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::string &gcode, std::array<float, 5> ¤t_pos) const
|
||||
{
|
||||
std::vector<PerExtruderAdjustments> per_extruder_adjustments(m_extruder_ids.size());
|
||||
std::vector<size_t> map_extruder_to_per_extruder_adjustment(m_num_extruders, 0);
|
||||
@ -347,7 +356,7 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
||||
// for a sequence of extrusion moves.
|
||||
size_t active_speed_modifier = size_t(-1);
|
||||
|
||||
std::vector<float> new_pos;
|
||||
std::array<float, AxisIdx::Count> new_pos;
|
||||
for (; *line_start != 0; line_start = line_end)
|
||||
{
|
||||
while (*line_end != '\n' && *line_end != 0)
|
||||
@ -362,12 +371,20 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
||||
line.type = CoolingLine::TYPE_G0;
|
||||
else if (boost::starts_with(sline, "G1 "))
|
||||
line.type = CoolingLine::TYPE_G1;
|
||||
else if (boost::starts_with(sline, "G2 "))
|
||||
// Arc, clockwise.
|
||||
line.type = CoolingLine::TYPE_G2G3;
|
||||
else if (boost::starts_with(sline, "G3 "))
|
||||
// Arc, counter-clockwise.
|
||||
line.type = CoolingLine::TYPE_G2G3 | CoolingLine::TYPE_G2G3_CCW;
|
||||
else if (boost::starts_with(sline, "G92 "))
|
||||
line.type = CoolingLine::TYPE_G92;
|
||||
if (line.type) {
|
||||
// G0, G1 or G92
|
||||
// G0, G1, G2, G3 or G92
|
||||
// Initialize current_pos from new_pos, set IJKR to zero.
|
||||
std::fill(std::copy(std::begin(current_pos), std::end(current_pos), std::begin(new_pos)),
|
||||
std::end(new_pos), 0.f);
|
||||
// Parse the G-code line.
|
||||
new_pos = current_pos;
|
||||
for (auto c = sline.begin() + 3;;) {
|
||||
// Skip whitespaces.
|
||||
for (; c != sline.end() && (*c == ' ' || *c == '\t'); ++ c);
|
||||
@ -376,21 +393,31 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
||||
|
||||
// Parse the axis.
|
||||
size_t axis = (*c >= 'X' && *c <= 'Z') ? (*c - 'X') :
|
||||
(*c == extrusion_axis) ? 3 : (*c == 'F') ? 4 : size_t(-1);
|
||||
(*c == extrusion_axis) ? AxisIdx::E : (*c == 'F') ? AxisIdx::F :
|
||||
(*c >= 'I' && *c <= 'K') ? int(AxisIdx::I) + (*c - 'I') :
|
||||
(*c == 'R') ? AxisIdx::R : size_t(-1);
|
||||
if (axis != size_t(-1)) {
|
||||
//auto [pend, ec] =
|
||||
fast_float::from_chars(&*(++ c), sline.data() + sline.size(), new_pos[axis]);
|
||||
if (axis == 4) {
|
||||
if (axis == AxisIdx::F) {
|
||||
// Convert mm/min to mm/sec.
|
||||
new_pos[4] /= 60.f;
|
||||
new_pos[AxisIdx::F] /= 60.f;
|
||||
if ((line.type & CoolingLine::TYPE_G92) == 0)
|
||||
// This is G0 or G1 line and it sets the feedrate. This mark is used for reducing the duplicate F calls.
|
||||
line.type |= CoolingLine::TYPE_HAS_F;
|
||||
}
|
||||
} else if (axis >= AxisIdx::I && axis <= AxisIdx::J)
|
||||
line.type |= CoolingLine::TYPE_G2G3_IJ;
|
||||
else if (axis == AxisIdx::R)
|
||||
line.type |= CoolingLine::TYPE_G2G3_R;
|
||||
}
|
||||
// Skip this word.
|
||||
for (; c != sline.end() && *c != ' ' && *c != '\t'; ++ c);
|
||||
}
|
||||
// If G2 or G3, then either center of the arc or radius has to be defined.
|
||||
assert(! (line.type & CoolingLine::TYPE_G2G3) ||
|
||||
(line.type & (CoolingLine::TYPE_G2G3_IJ | CoolingLine::TYPE_G2G3_R)));
|
||||
// Arc is defined either by IJ or by R, not by both.
|
||||
assert(! ((line.type & CoolingLine::TYPE_G2G3_IJ) && (line.type & CoolingLine::TYPE_G2G3_R)));
|
||||
bool external_perimeter = boost::contains(sline, ";_EXTERNAL_PERIMETER");
|
||||
bool wipe = boost::contains(sline, ";_WIPE");
|
||||
if (external_perimeter)
|
||||
@ -402,23 +429,40 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
||||
active_speed_modifier = adjustment->lines.size();
|
||||
}
|
||||
if ((line.type & CoolingLine::TYPE_G92) == 0) {
|
||||
// G0 or G1. Calculate the duration.
|
||||
// G0, G1, G2, G3. Calculate the duration.
|
||||
assert((line.type & CoolingLine::TYPE_G0) + (line.type & CoolingLine::TYPE_G1) + (line.type & CoolingLine::TYPE_G2G3) == 1);
|
||||
if (m_config.use_relative_e_distances.value)
|
||||
// Reset extruder accumulator.
|
||||
current_pos[3] = 0.f;
|
||||
current_pos[AxisIdx::E] = 0.f;
|
||||
float dif[4];
|
||||
for (size_t i = 0; i < 4; ++ i)
|
||||
dif[i] = new_pos[i] - current_pos[i];
|
||||
float dxy2 = dif[0] * dif[0] + dif[1] * dif[1];
|
||||
float dxyz2 = dxy2 + dif[2] * dif[2];
|
||||
float dxy2;
|
||||
if (line.type & CoolingLine::TYPE_G2G3) {
|
||||
// Measure arc length.
|
||||
if (line.type & CoolingLine::TYPE_G2G3_IJ) {
|
||||
dxy2 = sqr(Geometry::ArcWelder::arc_length(
|
||||
Vec2d(current_pos[AxisIdx::X], current_pos[AxisIdx::Y]),
|
||||
Vec2d(new_pos[AxisIdx::X], new_pos[AxisIdx::Y]),
|
||||
Vec2d(current_pos[AxisIdx::X] + current_pos[AxisIdx::I], current_pos[AxisIdx::Y] + current_pos[AxisIdx::J]),
|
||||
line.type & CoolingLine::TYPE_G2G3_CCW));
|
||||
} else if (line.type & CoolingLine::TYPE_G2G3_R) {
|
||||
dxy2 = sqr(Geometry::ArcWelder::arc_length(
|
||||
Vec2d(current_pos[AxisIdx::X], current_pos[AxisIdx::Y]),
|
||||
Vec2d(new_pos[AxisIdx::X], new_pos[AxisIdx::Y]),
|
||||
double(new_pos[AxisIdx::R])));
|
||||
}
|
||||
} else
|
||||
dxy2 = sqr(dif[AxisIdx::X]) + sqr(dif[AxisIdx::Y]);
|
||||
float dxyz2 = dxy2 + sqr(dif[AxisIdx::Z]);
|
||||
if (dxyz2 > 0.f) {
|
||||
// Movement in xyz, calculate time from the xyz Euclidian distance.
|
||||
line.length = sqrt(dxyz2);
|
||||
} else if (std::abs(dif[3]) > 0.f) {
|
||||
} else if (std::abs(dif[AxisIdx::E]) > 0.f) {
|
||||
// Movement in the extruder axis.
|
||||
line.length = std::abs(dif[3]);
|
||||
line.length = std::abs(dif[AxisIdx::E]);
|
||||
}
|
||||
line.feedrate = new_pos[4];
|
||||
line.feedrate = new_pos[AxisIdx::F];
|
||||
assert((line.type & CoolingLine::TYPE_ADJUSTABLE) == 0 || line.feedrate > 0.f);
|
||||
if (line.length > 0) {
|
||||
assert(line.feedrate > 0);
|
||||
@ -430,7 +474,7 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
||||
assert(adjustment->min_print_speed >= 0);
|
||||
line.time_max = (adjustment->min_print_speed == 0.f) ? FLT_MAX : std::max(line.time, line.length / adjustment->min_print_speed);
|
||||
}
|
||||
if (active_speed_modifier < adjustment->lines.size() && (line.type & CoolingLine::TYPE_G1)) {
|
||||
if (active_speed_modifier < adjustment->lines.size() && (line.type & (CoolingLine::TYPE_G1 | CoolingLine::TYPE_G2G3))) {
|
||||
// Inside the ";_EXTRUDE_SET_SPEED" blocks, there must not be a G1 Fxx entry.
|
||||
assert((line.type & CoolingLine::TYPE_HAS_F) == 0);
|
||||
CoolingLine &sm = adjustment->lines[active_speed_modifier];
|
||||
@ -447,7 +491,7 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
||||
line.type = 0;
|
||||
}
|
||||
}
|
||||
current_pos = std::move(new_pos);
|
||||
std::copy(std::begin(new_pos), std::begin(new_pos) + 5, std::begin(current_pos));
|
||||
} else if (boost::starts_with(sline, ";_EXTRUDE_END")) {
|
||||
// Closing a block of non-zero length extrusion moves.
|
||||
line.type = CoolingLine::TYPE_EXTRUDE_END;
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
|
||||
private:
|
||||
CoolingBuffer& operator=(const CoolingBuffer&) = delete;
|
||||
std::vector<PerExtruderAdjustments> parse_layer_gcode(const std::string &gcode, std::vector<float> ¤t_pos) const;
|
||||
std::vector<PerExtruderAdjustments> parse_layer_gcode(const std::string &gcode, std::array<float, 5> ¤t_pos) const;
|
||||
float calculate_layer_slowdown(std::vector<PerExtruderAdjustments> &per_extruder_adjustments);
|
||||
// Apply slow down over G-code lines stored in per_extruder_adjustments, enable fan if needed.
|
||||
// Returns the adjusted G-code.
|
||||
@ -40,9 +40,11 @@ private:
|
||||
// G-code snippet cached for the support layers preceding an object layer.
|
||||
std::string m_gcode;
|
||||
// Internal data.
|
||||
// X,Y,Z,E,F
|
||||
std::vector<char> m_axis;
|
||||
std::vector<float> m_current_pos;
|
||||
enum AxisIdx : int {
|
||||
X = 0, Y, Z, E, F, I, J, K, R, Count
|
||||
};
|
||||
std::array<float, 5> m_current_pos;
|
||||
// Current known fan speed or -1 if not known yet.
|
||||
int m_fan_speed;
|
||||
// Cached from GCodeWriter.
|
||||
|
@ -15,7 +15,7 @@ template<typename Derived, typename Derived2, typename Float>
|
||||
inline Eigen::Matrix<Float, 2, 1, Eigen::DontAlign> arc_center(
|
||||
const Eigen::MatrixBase<Derived> &start_pos,
|
||||
const Eigen::MatrixBase<Derived2> &end_pos,
|
||||
const typename Float radius,
|
||||
const Float radius,
|
||||
const bool is_ccw)
|
||||
{
|
||||
static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "arc_center(): first parameter is not a 2D vector");
|
||||
@ -73,6 +73,32 @@ inline typename Derived::Scalar arc_length(
|
||||
return arc_angle(start_pos, end_pos, radius) * std::abs(radius);
|
||||
}
|
||||
|
||||
// Calculate positive length of an arc given two points, center and orientation.
|
||||
template<typename Derived, typename Derived2, typename Derived3>
|
||||
inline typename Derived::Scalar arc_length(
|
||||
const Eigen::MatrixBase<Derived> &start_pos,
|
||||
const Eigen::MatrixBase<Derived2> &end_pos,
|
||||
const Eigen::MatrixBase<Derived3> ¢er_pos,
|
||||
const bool ccw)
|
||||
{
|
||||
static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "arc_length(): first parameter is not a 2D vector");
|
||||
static_assert(Derived2::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "arc_length(): second parameter is not a 2D vector");
|
||||
static_assert(Derived3::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "arc_length(): third parameter is not a 2D vector");
|
||||
static_assert(std::is_same<typename Derived::Scalar, typename Derived2::Scalar>::value &&
|
||||
std::is_same<typename Derived::Scalar, typename Derived3::Scalar>::value, "arc_length(): All third points must be of the same type.");
|
||||
using Float = typename Derived::Scalar;
|
||||
auto vstart = start_pos - center_pos;
|
||||
auto vend = end_pos - center_pos;
|
||||
Float radius = vstart.norm();
|
||||
Float angle = atan2(double(cross2(vstart, vend)), double(vstart.dot(vend)));
|
||||
if (! ccw)
|
||||
angle *= Float(-1.);
|
||||
if (angle < 0)
|
||||
angle += Float(2. * M_PI);
|
||||
assert(angle >= Float(0.) && angle < Float(2. * M_PI + EPSILON));
|
||||
return angle * radius;
|
||||
}
|
||||
|
||||
// Test whether a point is inside a wedge of an arc.
|
||||
template<typename Derived, typename Derived2, typename Derived3>
|
||||
inline bool inside_arc_wedge_vectors(
|
||||
|
Loading…
x
Reference in New Issue
Block a user