ArcWelder: Fixed NaN when exporting arches with nearly zero radii.

This commit is contained in:
Vojtech Bubnik 2023-09-01 13:05:22 +02:00
parent b39c33414f
commit 4580e69d86
4 changed files with 37 additions and 18 deletions

View File

@ -16,6 +16,7 @@ Extruder::Extruder(unsigned int id, GCodeConfig *config) :
std::pair<double, double> Extruder::extrude(double dE)
{
assert(! std::isnan(dE));
// in case of relative E distances we always reset to 0 before any output
if (m_config->use_relative_e_distances)
m_E = 0.;
@ -37,7 +38,8 @@ std::pair<double, double> Extruder::extrude(double dE)
value supplied will overwrite the previous one if any. */
std::pair<double, double> Extruder::retract(double retract_length, double restart_extra)
{
assert(restart_extra >= 0);
assert(! std::isnan(retract_length));
assert(! std::isnan(restart_extra) && restart_extra >= 0);
// in case of relative E distances we always reset to 0 before any output
if (m_config->use_relative_e_distances)
m_E = 0.;

View File

@ -3106,26 +3106,34 @@ std::string GCodeGenerator::_extrude(
const bool emit_radius = m_config.arc_fitting == ArcFittingType::EmitRadius;
for (++ it; it != end; ++ it) {
Vec2d p = this->point_to_gcode_quantized(it->point);
if (it->radius == 0) {
// Center of the radius to be emitted into the G-code: Either by radius or by center offset.
double radius = 0;
Vec2d ij;
if (it->radius != 0) {
// Extrude an arc.
assert(m_config.arc_fitting == ArcFittingType::EmitCenter ||
m_config.arc_fitting == ArcFittingType::EmitRadius);
radius = unscaled<double>(it->radius);
if (emit_radius) {
// Only quantize radius if emitting it directly into G-code. Otherwise use the exact radius for calculating the IJ values.
radius = GCodeFormatter::quantize_xyzf(radius);
} else {
// Calculate quantized IJ circle center offset.
ij = GCodeFormatter::quantize(
Geometry::ArcWelder::arc_center(prev.cast<double>(), p.cast<double>(), double(radius), it->ccw())
- prev);
if (ij == Vec2d::Zero())
// Don't extrude a degenerated circle.
radius = 0;
}
}
if (radius == 0) {
// Extrude line segment.
if (const double line_length = (p - prev).norm(); line_length > 0) {
path_length += line_length;
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
}
} else {
// Extrude an arc.
assert(m_config.arc_fitting == ArcFittingType::EmitCenter ||
m_config.arc_fitting == ArcFittingType::EmitRadius);
double radius = unscaled<double>(it->radius);
if (emit_radius)
// Only quantize radius if emitting it directly into G-code. Otherwise use the exact radius for calculating the IJ values.
radius = GCodeFormatter::quantize_xyzf(radius);
Vec2d ij;
if (! emit_radius) {
// Calculate quantized IJ circle center offset.
Vec2d center_raw = Geometry::ArcWelder::arc_center(prev.cast<double>(), p.cast<double>(), double(radius), it->ccw()) - prev;
ij = GCodeFormatter::quantize(center_raw);
}
double angle = Geometry::ArcWelder::arc_angle(prev.cast<double>(), p.cast<double>(), double(radius));
assert(angle > 0);
const double line_length = angle * std::abs(radius);

View File

@ -117,7 +117,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
return done;
};
const bool emit_radius = gcodegen.config().arc_fitting == ArcFittingType::EmitRadius;
auto wipe_arc = [&gcode, &gcodegen, &retract_length, xy_to_e, emit_radius](
auto wipe_arc = [&gcode, &gcodegen, &retract_length, xy_to_e, emit_radius, &wipe_linear](
const Vec2d &prev_quantized, Vec2d &p, double radius_in, const bool ccw) {
Vec2d p_quantized = GCodeFormatter::quantize(p);
if (p_quantized == prev_quantized) {
@ -126,6 +126,9 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
}
// Only quantize radius if emitting it directly into G-code. Otherwise use the exact radius for calculating the IJ values.
double radius = emit_radius ? GCodeFormatter::quantize_xyzf(radius_in) : radius_in;
if (radius == 0)
// Degenerated arc after quantization. Process it as if it was a line segment.
return wipe_linear(prev_quantized, p);
Vec2d center = Geometry::ArcWelder::arc_center(prev_quantized.cast<double>(), p_quantized.cast<double>(), double(radius), ccw);
float angle = Geometry::ArcWelder::arc_angle(prev_quantized.cast<double>(), p_quantized.cast<double>(), double(radius));
assert(angle > 0);
@ -152,8 +155,13 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
gcode += gcodegen.writer().extrude_to_xy_G2G3R(p, radius, ccw, -dE, wipe_retract_comment);
} else {
// Calculate quantized IJ circle center offset.
Vec2d ij = GCodeFormatter::quantize(Vec2d(center - prev_quantized));
if (ij == Vec2d::Zero())
// Degenerated arc after quantization. Process it as if it was a line segment.
return wipe_linear(prev_quantized, p);
// The arc is valid.
gcode += gcodegen.writer().extrude_to_xy_G2G3IJ(
p, GCodeFormatter::quantize(Vec2d(center - prev_quantized)), ccw, -dE, wipe_retract_comment);
p, ij, ccw, -dE, wipe_retract_comment);
}
retract_length -= dE;
return done;

View File

@ -1643,6 +1643,7 @@ namespace client
// Check whether the table X values are sorted.
double x = expr_x.as_d();
assert(! std::isnan(x));
bool evaluated = false;
for (size_t i = 1; i < table.table.size(); ++i) {
double x0 = table.table[i - 1].x;