mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-12 04:49:01 +08:00
ArcWelder: Bugfixes & switchable G2/3 R vs. IJ
This commit is contained in:
parent
3df8da662e
commit
7551b4ffd3
@ -1263,7 +1263,7 @@ void GCodeGenerator::process_layers(
|
||||
size_t layer_to_print_idx = 0;
|
||||
const GCode::SmoothPathCache::InterpolationParameters interpolation_params {
|
||||
scaled<double>(print.config().gcode_resolution.value),
|
||||
print.config().arc_fitting && ! print.config().spiral_vase ?
|
||||
print.config().arc_fitting != ArcFittingType::Disabled && ! print.config().spiral_vase ?
|
||||
Geometry::ArcWelder::default_arc_length_percent_tolerance :
|
||||
0
|
||||
};
|
||||
@ -1362,7 +1362,7 @@ void GCodeGenerator::process_layers(
|
||||
size_t layer_to_print_idx = 0;
|
||||
const GCode::SmoothPathCache::InterpolationParameters interpolation_params {
|
||||
scaled<double>(print.config().gcode_resolution.value),
|
||||
print.config().arc_fitting && ! print.config().spiral_vase ?
|
||||
print.config().arc_fitting != ArcFittingType::Disabled && ! print.config().spiral_vase ?
|
||||
Geometry::ArcWelder::default_arc_length_percent_tolerance :
|
||||
0
|
||||
};
|
||||
@ -2828,6 +2828,7 @@ std::string GCodeGenerator::_extrude(
|
||||
Vec2d prev = this->point_to_gcode_quantized(path.front().point);
|
||||
auto it = path.begin();
|
||||
auto end = path.end();
|
||||
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) {
|
||||
@ -2837,12 +2838,25 @@ std::string GCodeGenerator::_extrude(
|
||||
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
||||
} else {
|
||||
// Extrude an arc.
|
||||
double radius = GCodeFormatter::quantize_xyzf(it->radius);
|
||||
Vec2f center = Geometry::ArcWelder::arc_center(prev.cast<float>(), p.cast<float>(), float(radius), it->ccw());
|
||||
float angle = Geometry::ArcWelder::arc_angle(prev.cast<float>(), p.cast<float>(), float(radius));
|
||||
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 = Vec2d{ GCodeFormatter::quantize_xyzf(center_raw.x()), GCodeFormatter::quantize_xyzf(center_raw.y()) };
|
||||
}
|
||||
double angle = Geometry::ArcWelder::arc_angle(prev.cast<double>(), p.cast<double>(), double(radius));
|
||||
const double line_length = angle * std::abs(radius);
|
||||
path_length += line_length;
|
||||
gcode += m_writer.extrude_to_xy_G2G3R(p, radius, it->ccw(), e_per_mm * line_length, comment);
|
||||
const double dE = e_per_mm * line_length;
|
||||
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);
|
||||
}
|
||||
prev = p;
|
||||
}
|
||||
|
@ -384,9 +384,13 @@ std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std:
|
||||
return w.string();
|
||||
}
|
||||
|
||||
std::string GCodeWriter::extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, double dE, const bool ccw, const std::string_view comment)
|
||||
std::string GCodeWriter::extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, double dE, const std::string_view comment)
|
||||
{
|
||||
assert(dE > 0);
|
||||
assert(dE != 0);
|
||||
assert(std::abs(point.x()) < 1200.);
|
||||
assert(std::abs(point.y()) < 1200.);
|
||||
assert(std::abs(ij.x()) < 1200.);
|
||||
assert(std::abs(ij.y()) < 1200.);
|
||||
m_pos.head<2>() = point.head<2>();
|
||||
|
||||
GCodeG2G3Formatter w(ccw);
|
||||
@ -397,9 +401,12 @@ std::string GCodeWriter::extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &i
|
||||
return w.string();
|
||||
}
|
||||
|
||||
std::string GCodeWriter::extrude_to_xy_G2G3R(const Vec2d &point, const double radius, double dE, const bool ccw, const std::string_view comment)
|
||||
std::string GCodeWriter::extrude_to_xy_G2G3R(const Vec2d &point, const double radius, const bool ccw, double dE, const std::string_view comment)
|
||||
{
|
||||
assert(dE > 0);
|
||||
assert(dE != 0);
|
||||
assert(std::abs(point.x()) < 1200.);
|
||||
assert(std::abs(point.y()) < 1200.);
|
||||
assert(std::abs(radius) < 1800.);
|
||||
m_pos.head<2>() = point.head<2>();
|
||||
|
||||
GCodeG2G3Formatter w(ccw);
|
||||
|
@ -66,8 +66,8 @@ public:
|
||||
std::string travel_to_z(double z, const std::string_view comment = {});
|
||||
bool will_move_z(double z) const;
|
||||
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, double dE, const bool ccw, const std::string_view comment);
|
||||
std::string extrude_to_xy_G2G3R(const Vec2d &point, const double radius, double dE, const bool ccw, 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);
|
||||
std::string extrude_to_xy_G2G3R(const Vec2d &point, const double radius, const bool ccw, double dE, const std::string_view comment);
|
||||
// std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string_view comment = {});
|
||||
std::string retract(bool before_wipe = false);
|
||||
std::string retract_for_toolchange(bool before_wipe = false);
|
||||
|
@ -76,6 +76,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
{
|
||||
std::string gcode;
|
||||
const Extruder &extruder = *gcodegen.writer().extruder();
|
||||
static constexpr const std::string_view wipe_retract_comment = "wipe and retract"sv;
|
||||
|
||||
// Remaining quantized retraction length.
|
||||
if (double retract_length = extruder.retract_to_go(toolchange ? extruder.retract_length_toolchange() : extruder.retract_length());
|
||||
@ -103,14 +104,16 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
dE = retract_length;
|
||||
done = true;
|
||||
}
|
||||
gcode += gcodegen.writer().extrude_to_xy(p, -dE, "wipe and retract"sv);
|
||||
gcode += gcodegen.writer().extrude_to_xy(p, -dE, wipe_retract_comment);
|
||||
retract_length -= dE;
|
||||
return done;
|
||||
};
|
||||
auto wipe_arc = [&gcode, &gcodegen, &retract_length, xy_to_e](const Vec2d &prev, Vec2d &p, float radius_in, const bool ccw) {
|
||||
double radius = GCodeFormatter::quantize_xyzf(radius_in);
|
||||
Vec2f center = Geometry::ArcWelder::arc_center(prev.cast<float>(), p.cast<float>(), float(radius), ccw);
|
||||
float angle = Geometry::ArcWelder::arc_angle(prev.cast<float>(), p.cast<float>(), float(radius));
|
||||
const bool emit_radius = gcodegen.config().arc_fitting == ArcFittingType::EmitRadius;
|
||||
auto wipe_arc = [&gcode, &gcodegen, &retract_length, xy_to_e, emit_radius](const Vec2d &prev, Vec2d &p, double radius_in, const bool ccw) {
|
||||
// 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;
|
||||
Vec2d center = Geometry::ArcWelder::arc_center(prev.cast<double>(), p.cast<double>(), double(radius), ccw);
|
||||
float angle = Geometry::ArcWelder::arc_angle(prev.cast<double>(), p.cast<double>(), double(radius));
|
||||
double segment_length = angle * std::abs(radius);
|
||||
double dE = GCodeFormatter::quantize_e(xy_to_e * segment_length);
|
||||
bool done = false;
|
||||
@ -121,7 +124,13 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
dE = retract_length;
|
||||
done = true;
|
||||
}
|
||||
gcode += gcodegen.writer().extrude_to_xy_G2G3R(p, radius, ccw, -dE, "wipe and retract"sv);
|
||||
if (emit_radius) {
|
||||
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_xyzf(center.x() - prev.x()), GCodeFormatter::quantize_xyzf(center.y() - prev.y()) };
|
||||
gcode += gcodegen.writer().extrude_to_xy_G2G3IJ(p, ij, ccw, -dE, wipe_retract_comment);
|
||||
}
|
||||
retract_length -= dE;
|
||||
return done;
|
||||
};
|
||||
@ -144,7 +153,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
start_wipe();
|
||||
if (it->linear() ?
|
||||
wipe_linear(prev, p) :
|
||||
wipe_arc(prev, p, it->radius, it->ccw()))
|
||||
wipe_arc(prev, p, unscaled<double>(it->radius), it->ccw()))
|
||||
break;
|
||||
prev = p;
|
||||
}
|
||||
|
@ -386,6 +386,14 @@ Path fit_path(const Points &src, double tolerance, double fit_circle_percent_tol
|
||||
out.erase(douglas_peucker_in_place(out.begin() + begin_pl_idx, out.end(), tolerance), out.end());
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Verify that all the source points are at tolerance distance from the interpolated path.
|
||||
for (const Point &p : src) {
|
||||
PathSegmentProjection proj = point_to_path_projection(out, p);
|
||||
assert(proj.distance2 < sqr(tolerance + SCALED_EPSILON));
|
||||
}
|
||||
#endif
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,10 @@ inline Eigen::Matrix<typename Derived::Scalar, 2, 1, Eigen::DontAlign> arc_cente
|
||||
auto v = end_pos - start_pos;
|
||||
Float q2 = v.squaredNorm();
|
||||
assert(q2 > 0);
|
||||
Float t = sqrt(sqr(radius) / q2 - Float(.25f));
|
||||
Float t2 = sqr(radius) / q2 - Float(.25f);
|
||||
// If the start_pos and end_pos are nearly antipodal, t2 may become slightly negative.
|
||||
// In that case return a centroid of start_point & end_point.
|
||||
Float t = t2 > 0 ? sqrt(t2) : Float(0);
|
||||
auto mid = Float(0.5) * (start_pos + end_pos);
|
||||
Vector vp{ -v.y() * t, v.x() * t };
|
||||
return (radius > Float(0)) == is_ccw ? (mid + vp).eval() : (mid - vp).eval();
|
||||
|
@ -34,6 +34,13 @@ static t_config_enum_names enum_names_from_keys_map(const t_config_enum_values &
|
||||
template<> const t_config_enum_values& ConfigOptionEnum<NAME>::get_enum_values() { return s_keys_map_##NAME; } \
|
||||
template<> const t_config_enum_names& ConfigOptionEnum<NAME>::get_enum_names() { return s_keys_names_##NAME; }
|
||||
|
||||
static const t_config_enum_values s_keys_map_ArcFittingType {
|
||||
{ "disabled", int(ArcFittingType::Disabled) },
|
||||
{ "emit_center", int(ArcFittingType::EmitCenter) },
|
||||
{ "emit_radius", int(ArcFittingType::EmitRadius) }
|
||||
};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(ArcFittingType)
|
||||
|
||||
static t_config_enum_values s_keys_map_PrinterTechnology {
|
||||
{ "FFF", ptFFF },
|
||||
{ "SLA", ptSLA }
|
||||
@ -397,12 +404,17 @@ void PrintConfigDef::init_fff_params()
|
||||
{
|
||||
ConfigOptionDef* def;
|
||||
|
||||
def = this->add("arc_fitting", coBool);
|
||||
def = this->add("arc_fitting", coEnum);
|
||||
def->label = L("Arc fitting");
|
||||
def->tooltip = L("Enable this to get a G-code file which has G2 and G3 moves. "
|
||||
"And the fitting tolerance is same with resolution");
|
||||
def->set_enum<ArcFittingType>({
|
||||
{ "disabled", "Disabled" },
|
||||
{ "emit_center", "Enabled: G2/3 I J" },
|
||||
{ "emit_radius", "Enabled: G2/3 R" }
|
||||
});
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
def->set_default_value(new ConfigOptionEnum<ArcFittingType>(ArcFittingType::Disabled));
|
||||
|
||||
def = this->add("arc_fitting_tolerance", coFloatOrPercent);
|
||||
def->label = L("Arc fitting tolerance");
|
||||
|
@ -31,6 +31,12 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
enum class ArcFittingType {
|
||||
Disabled,
|
||||
EmitCenter,
|
||||
EmitRadius,
|
||||
};
|
||||
|
||||
enum GCodeFlavor : unsigned char {
|
||||
gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinLegacy, gcfMarlinFirmware, gcfKlipper, gcfSailfish, gcfMach3, gcfMachinekit,
|
||||
gcfSmoothie, gcfNoExtrusion,
|
||||
@ -142,6 +148,7 @@ enum class GCodeThumbnailsFormat {
|
||||
template<> const t_config_enum_names& ConfigOptionEnum<NAME>::get_enum_names(); \
|
||||
template<> const t_config_enum_values& ConfigOptionEnum<NAME>::get_enum_values();
|
||||
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(ArcFittingType)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PrinterTechnology)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeFlavor)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(MachineLimitsUsage)
|
||||
@ -662,7 +669,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
PRINT_CONFIG_CLASS_DEFINE(
|
||||
GCodeConfig,
|
||||
|
||||
((ConfigOptionBool, arc_fitting))
|
||||
((ConfigOptionEnum<ArcFittingType>, arc_fitting))
|
||||
((ConfigOptionFloatOrPercent, arc_fitting_tolerance))
|
||||
((ConfigOptionBool, autoemit_temperature_commands))
|
||||
((ConfigOptionString, before_layer_gcode))
|
||||
|
Loading…
x
Reference in New Issue
Block a user