mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 04:55:55 +08:00
ArcWelder: Improved resolution of arc discretization in G-code preview
This commit is contained in:
parent
95641d0269
commit
98c011d59b
@ -2902,9 +2902,10 @@ std::string GCodeGenerator::_extrude(
|
||||
Vec2d p = this->point_to_gcode_quantized(it->point);
|
||||
if (it->radius == 0) {
|
||||
// Extrude line segment.
|
||||
const double line_length = (p - prev).norm();
|
||||
path_length += line_length;
|
||||
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
||||
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 ||
|
||||
@ -2920,9 +2921,11 @@ std::string GCodeGenerator::_extrude(
|
||||
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);
|
||||
path_length += line_length;
|
||||
const double dE = e_per_mm * line_length;
|
||||
assert(dE > 0);
|
||||
gcode += emit_radius ?
|
||||
m_writer.extrude_to_xy_G2G3R(p, radius, it->ccw(), dE, comment) :
|
||||
m_writer.extrude_to_xy_G2G3IJ(p, ij, it->ccw(), dE, comment);
|
||||
|
@ -44,8 +44,6 @@ static const Slic3r::Vec3f DEFAULT_EXTRUDER_OFFSET = Slic3r::Vec3f::Zero();
|
||||
// taken from PrusaResearch.ini - [printer:Original Prusa i3 MK2.5 MMU2]
|
||||
static const std::vector<std::string> DEFAULT_EXTRUDER_COLORS = { "#FF8000", "#DB5182", "#3EC0FF", "#FF4F4F", "#FBEB7D" };
|
||||
|
||||
static const std::string INTERNAL_G2G3_TAG = "!#!#! internal only - from G2/G3 expansion !#!#!";
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
const std::vector<std::string> GCodeProcessor::Reserved_Tags = {
|
||||
@ -2364,13 +2362,10 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
||||
if (line.has_e()) g1_axes[E] = (double)line.e();
|
||||
std::optional<double> g1_feedrate = std::nullopt;
|
||||
if (line.has_f()) g1_feedrate = (double)line.f();
|
||||
std::optional<std::string> g1_cmt = std::nullopt;
|
||||
if (!line.comment().empty()) g1_cmt = line.comment();
|
||||
|
||||
process_G1(g1_axes, g1_feedrate, g1_cmt);
|
||||
process_G1(g1_axes, g1_feedrate);
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes, std::optional<double> feedrate, std::optional<std::string> cmt)
|
||||
void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes, std::optional<double> feedrate, G1DiscretizationOrigin origin)
|
||||
{
|
||||
const float filament_diameter = (static_cast<size_t>(m_extruder_id) < m_result.filament_diameters.size()) ? m_result.filament_diameters[m_extruder_id] : m_result.filament_diameters.back();
|
||||
const float filament_radius = 0.5f * filament_diameter;
|
||||
@ -2453,7 +2448,7 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
|
||||
m_height = m_forced_height;
|
||||
else if (m_layer_id == 0)
|
||||
m_height = m_first_layer_height + m_z_offset;
|
||||
else if (!cmt.has_value() || *cmt != INTERNAL_G2G3_TAG) {
|
||||
else if (origin == G1DiscretizationOrigin::G1) {
|
||||
if (m_end_position[Z] > m_extruded_last_z + EPSILON && delta_pos[Z] == 0.0)
|
||||
m_height = m_end_position[Z] - m_extruded_last_z;
|
||||
}
|
||||
@ -2464,7 +2459,7 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
|
||||
if (m_end_position[Z] == 0.0f || (m_extrusion_role == GCodeExtrusionRole::Custom && m_layer_id == 0))
|
||||
m_end_position[Z] = m_height;
|
||||
|
||||
if (!cmt.has_value() || *cmt != INTERNAL_G2G3_TAG)
|
||||
if (origin == G1DiscretizationOrigin::G1)
|
||||
m_extruded_last_z = m_end_position[Z];
|
||||
m_options_z_corrector.update(m_height);
|
||||
|
||||
@ -2694,7 +2689,7 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
|
||||
}
|
||||
|
||||
// store move
|
||||
store_move_vertex(type, cmt.has_value() && *cmt == INTERNAL_G2G3_TAG);
|
||||
store_move_vertex(type, origin == G1DiscretizationOrigin::G2G3);
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line, bool clockwise)
|
||||
@ -2836,9 +2831,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line, bool cloc
|
||||
g1_feedrate = (double)*feedrate;
|
||||
if (extrusion.has_value())
|
||||
g1_axes[E] = target[E];
|
||||
std::optional<std::string> g1_cmt = INTERNAL_G2G3_TAG;
|
||||
|
||||
process_G1(g1_axes, g1_feedrate, g1_cmt);
|
||||
process_G1(g1_axes, g1_feedrate, G1DiscretizationOrigin::G2G3);
|
||||
};
|
||||
|
||||
// calculate arc segments
|
||||
@ -2847,8 +2840,13 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line, bool cloc
|
||||
// https://github.com/prusa3d/Prusa-Firmware/blob/MK3/Firmware/motion_control.cpp
|
||||
|
||||
// segments count
|
||||
#if 0
|
||||
static const double MM_PER_ARC_SEGMENT = 1.0;
|
||||
const size_t segments = std::max<size_t>(std::floor(travel_length / MM_PER_ARC_SEGMENT), 1);
|
||||
#else
|
||||
static const double gcode_arc_tolerance = 0.0125;
|
||||
const size_t segments = Geometry::ArcWelder::arc_discretization_steps(arc.start_radius(), std::abs(arc.angle), gcode_arc_tolerance);
|
||||
#endif
|
||||
|
||||
const double inv_segment = 1.0 / double(segments);
|
||||
const double theta_per_segment = arc.angle * inv_segment;
|
||||
|
@ -56,9 +56,13 @@ namespace Slic3r {
|
||||
time = 0.0f;
|
||||
travel_time = 0.0f;
|
||||
custom_gcode_times.clear();
|
||||
custom_gcode_times.shrink_to_fit();
|
||||
moves_times.clear();
|
||||
moves_times.shrink_to_fit();
|
||||
roles_times.clear();
|
||||
roles_times.shrink_to_fit();
|
||||
layers_times.clear();
|
||||
layers_times.shrink_to_fit();
|
||||
}
|
||||
};
|
||||
|
||||
@ -76,6 +80,7 @@ namespace Slic3r {
|
||||
m.reset();
|
||||
}
|
||||
volumes_per_color_change.clear();
|
||||
volumes_per_color_change.shrink_to_fit();
|
||||
volumes_per_extruder.clear();
|
||||
used_filaments_per_role.clear();
|
||||
cost_per_extruder.clear();
|
||||
@ -680,8 +685,12 @@ namespace Slic3r {
|
||||
// Move
|
||||
void process_G0(const GCodeReader::GCodeLine& line);
|
||||
void process_G1(const GCodeReader::GCodeLine& line);
|
||||
enum class G1DiscretizationOrigin {
|
||||
G1,
|
||||
G2G3,
|
||||
};
|
||||
void process_G1(const std::array<std::optional<double>, 4>& axes = { std::nullopt, std::nullopt, std::nullopt, std::nullopt },
|
||||
std::optional<double> feedrate = std::nullopt, std::optional<std::string> cmt = std::nullopt);
|
||||
std::optional<double> feedrate = std::nullopt, G1DiscretizationOrigin origin = G1DiscretizationOrigin::G1);
|
||||
|
||||
// Arc Move
|
||||
void process_G2_G3(const GCodeReader::GCodeLine& line, bool clockwise);
|
||||
|
@ -274,6 +274,12 @@ std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string_view
|
||||
|
||||
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.);
|
||||
assert(std::abs(point.y()) < 1200.);
|
||||
assert(std::abs(ij.x()) < 1200.);
|
||||
assert(std::abs(ij.y()) < 1200.);
|
||||
assert(std::abs(ij.x()) >= 0.001 || std::abs(ij.y()) >= 0.001);
|
||||
|
||||
m_pos.head<2>() = point.head<2>();
|
||||
|
||||
GCodeG2G3Formatter w(ccw);
|
||||
@ -285,6 +291,11 @@ std::string GCodeWriter::travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij
|
||||
|
||||
std::string GCodeWriter::travel_to_xy_G2G3R(const Vec2d &point, const double radius, const bool ccw, const std::string_view comment)
|
||||
{
|
||||
assert(std::abs(point.x()) < 1200.);
|
||||
assert(std::abs(point.y()) < 1200.);
|
||||
assert(std::abs(radius) >= 0.001);
|
||||
assert(std::abs(radius) < 1800.);
|
||||
|
||||
m_pos.head<2>() = point.head<2>();
|
||||
|
||||
GCodeG2G3Formatter w(ccw);
|
||||
@ -395,6 +406,8 @@ std::string GCodeWriter::extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &i
|
||||
assert(std::abs(point.y()) < 1200.);
|
||||
assert(std::abs(ij.x()) < 1200.);
|
||||
assert(std::abs(ij.y()) < 1200.);
|
||||
assert(std::abs(ij.x()) >= 0.001 || std::abs(ij.y()) >= 0.001);
|
||||
|
||||
m_pos.head<2>() = point.head<2>();
|
||||
|
||||
GCodeG2G3Formatter w(ccw);
|
||||
@ -411,7 +424,9 @@ std::string GCodeWriter::extrude_to_xy_G2G3R(const Vec2d &point, const double ra
|
||||
assert(std::abs(dE) < 1000.0);
|
||||
assert(std::abs(point.x()) < 1200.);
|
||||
assert(std::abs(point.y()) < 1200.);
|
||||
assert(std::abs(radius) >= 0.001);
|
||||
assert(std::abs(radius) < 1800.);
|
||||
|
||||
m_pos.head<2>() = point.head<2>();
|
||||
|
||||
GCodeG2G3Formatter w(ccw);
|
||||
|
@ -181,8 +181,10 @@ public:
|
||||
}
|
||||
|
||||
void emit_ij(const Vec2d &point) {
|
||||
this->emit_axis('I', point.x(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_axis('J', point.y(), XYZF_EXPORT_DIGITS);
|
||||
if (point.x() != 0)
|
||||
this->emit_axis('I', point.x(), XYZF_EXPORT_DIGITS);
|
||||
if (point.y() != 0)
|
||||
this->emit_axis('J', point.y(), XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
// Positive radius means a smaller arc,
|
||||
|
@ -128,6 +128,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
double radius = emit_radius ? GCodeFormatter::quantize_xyzf(radius_in) : radius_in;
|
||||
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);
|
||||
double segment_length = angle * std::abs(radius);
|
||||
double dE = GCodeFormatter::quantize_e(xy_to_e * segment_length);
|
||||
bool done = false;
|
||||
@ -146,6 +147,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
done = true;
|
||||
} else
|
||||
p = p_quantized;
|
||||
assert(dE > 0);
|
||||
if (emit_radius) {
|
||||
gcode += gcodegen.writer().extrude_to_xy_G2G3R(p, radius, ccw, -dE, wipe_retract_comment);
|
||||
} else {
|
||||
|
@ -41,10 +41,11 @@ Points arc_discretize(const Point &p1, const Point &p2, const double radius, con
|
||||
{
|
||||
Vec2d center = arc_center(p1.cast<double>(), p2.cast<double>(), radius, ccw);
|
||||
double angle = arc_angle(p1.cast<double>(), p2.cast<double>(), radius);
|
||||
assert(angle > 0);
|
||||
|
||||
double r = std::abs(radius);
|
||||
double angle_step = 2. * acos((r - deviation) / r);
|
||||
size_t num_steps = size_t(ceil(angle / angle_step));
|
||||
size_t num_steps = arc_discretization_steps(r, angle, deviation);
|
||||
double angle_step = angle / num_steps;
|
||||
|
||||
Points out;
|
||||
out.reserve(num_steps + 1);
|
||||
|
@ -54,8 +54,10 @@ inline typename Derived::Scalar arc_angle(
|
||||
using Float = typename Derived::Scalar;
|
||||
Float a = Float(0.5) * (end_pos - start_pos).norm() / radius;
|
||||
return radius > Float(0) ?
|
||||
(a > Float( 1.) ? Float( M_PI) : Float(2.) * std::asin(a)) :
|
||||
(a < Float(-1.) ? Float( - M_PI) : Float(2. * M_PI) + Float(2.) * std::asin(a));
|
||||
// acute angle:
|
||||
(a > Float( 1.) ? Float(M_PI) : Float(2.) * std::asin(a)) :
|
||||
// obtuse angle:
|
||||
(a < Float(-1.) ? Float(M_PI) : Float(2. * M_PI) + Float(2.) * std::asin(a));
|
||||
}
|
||||
|
||||
// Calculate positive length of an arc given two points and a radius.
|
||||
@ -164,6 +166,30 @@ inline bool inside_arc_wedge(
|
||||
radius > 0, ccw, query_pt);
|
||||
}
|
||||
|
||||
// Return number of linear segments necessary to interpolate arc of a given positive radius and positive angle to satisfy
|
||||
// maximum deviation of an interpolating polyline from an analytic arc.
|
||||
template<typename FloatType>
|
||||
size_t arc_discretization_steps(const FloatType radius, const FloatType angle, const FloatType deviation)
|
||||
{
|
||||
assert(radius > 0);
|
||||
assert(angle > 0);
|
||||
assert(angle <= FloatType(2. * M_PI));
|
||||
assert(deviation > 0);
|
||||
|
||||
FloatType d = radius - deviation;
|
||||
return d < EPSILON ?
|
||||
// Radius smaller than deviation.
|
||||
( // Acute angle: a single segment interpolates the arc with sufficient accuracy.
|
||||
angle < M_PI ||
|
||||
// Obtuse angle: Test whether the furthest point (center) of an arc is closer than deviation to the center of a line segment.
|
||||
radius * (FloatType(1.) + cos(M_PI - FloatType(.5) * angle)) < deviation ?
|
||||
// Single segment is sufficient
|
||||
1 :
|
||||
// Two segments are necessary, the middle point is at the center of the arc.
|
||||
2) :
|
||||
size_t(ceil(angle / (2. * acos(d / radius))));
|
||||
}
|
||||
|
||||
// Discretize arc given the radius, orientation and maximum deviation from the arc.
|
||||
// Returned polygon starts with p1, ends with p2 and it is discretized to guarantee the maximum deviation.
|
||||
Points arc_discretize(const Point &p1, const Point &p2, const double radius, const bool ccw, const double deviation);
|
||||
|
Loading…
x
Reference in New Issue
Block a user