ENH: smooth overhang degree in arachne mode

jira: STUDIO-12110,STUDIO-11630

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I4e430dd2cea4bd4ad206e699d574abed3a656ce2
This commit is contained in:
xun.zhang 2025-05-10 16:41:38 +08:00 committed by lane.wei
parent f2304fe1fc
commit 4b022b8287
9 changed files with 52 additions and 34 deletions

View File

@ -278,7 +278,17 @@ double ExtrusionLine::area() const
} // namespace Slic3r::Arachne
namespace Slic3r {
void extrusion_paths_append(ExtrusionPaths &dst, const ClipperLib_Z::Paths &extrusion_paths, const ExtrusionRole role, const Flow &flow, int overhang)
void extrusion_paths_append(std::list<ExtrusionPath> &dst, const ClipperLib_Z::Paths &extrusion_paths, const ExtrusionRole role, const Flow &flow, double overhang)
{
for (const ClipperLib_Z::Path &extrusion_path : extrusion_paths) {
ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion_path);
ExtrusionPaths path = thick_polyline_to_multi_path(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON), overhang).paths;
dst.insert(dst.end(), std::make_move_iterator(path.begin()), std::make_move_iterator(path.end()));
}
}
void extrusion_paths_append(ExtrusionPaths &dst, const ClipperLib_Z::Paths &extrusion_paths, const ExtrusionRole role, const Flow &flow, double overhang)
{
for (const ClipperLib_Z::Path &extrusion_path : extrusion_paths) {
ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion_path);
@ -286,13 +296,13 @@ void extrusion_paths_append(ExtrusionPaths &dst, const ClipperLib_Z::Paths &extr
}
}
void extrusion_paths_append(ExtrusionPaths &dst, const Arachne::ExtrusionLine &extrusion, const ExtrusionRole role, const Flow &flow, int overhang)
void extrusion_paths_append(ExtrusionPaths &dst, const Arachne::ExtrusionLine &extrusion, const ExtrusionRole role, const Flow &flow, double overhang)
{
ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion);
Slic3r::append(dst, thick_polyline_to_multi_path(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON), overhang).paths);
}
void extrusion_path_append(ExtrusionPaths &dst, const ThickPolyline &thick_polyline, const ExtrusionRole role, const Flow &flow, int overhang)
void extrusion_path_append(ExtrusionPaths &dst, const ThickPolyline &thick_polyline, const ExtrusionRole role, const Flow &flow, double overhang)
{
Slic3r::append(dst, thick_polyline_to_multi_path(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON), overhang).paths);
}

View File

@ -301,9 +301,10 @@ using VariableWidthLines = std::vector<ExtrusionLine>; //<! The ExtrusionLines g
namespace Slic3r {
void extrusion_paths_append(ExtrusionPaths &dst, const ClipperLib_Z::Paths &extrusion_paths, const ExtrusionRole role, const Flow &flow, int overhang = 0);
void extrusion_paths_append(ExtrusionPaths &dst, const Arachne::ExtrusionLine &extrusion, const ExtrusionRole role, const Flow &flow, int overhang = 0);
void extrusion_path_append(ExtrusionPaths &dst, const ThickPolyline &thick_polyline, const ExtrusionRole role, const Flow &flow, int overhang = 0);
void extrusion_paths_append(std::list<ExtrusionPath> &dst, const ClipperLib_Z::Paths &extrusion_paths, const ExtrusionRole role, const Flow &flow, double overhang = 0);
void extrusion_paths_append(ExtrusionPaths &dst, const ClipperLib_Z::Paths &extrusion_paths, const ExtrusionRole role, const Flow &flow, double overhang = 0);
void extrusion_paths_append(ExtrusionPaths &dst, const Arachne::ExtrusionLine &extrusion, const ExtrusionRole role, const Flow &flow, double overhang = 0);
void extrusion_path_append(ExtrusionPaths &dst, const ThickPolyline &thick_polyline, const ExtrusionRole role, const Flow &flow, double overhang = 0);
} // namespace Slic3r
#endif // UTILS_EXTRUSION_LINE_H

View File

@ -19,11 +19,12 @@ public:
MultiPoint() {}
MultiPoint(const MultiPoint &other) : points(other.points) {}
MultiPoint(MultiPoint &&other) : points(std::move(other.points)) {}
MultiPoint(MultiPoint &&other) noexcept : points(std::move(other.points)) {}
MultiPoint(std::initializer_list<Point> list) : points(list) {}
explicit MultiPoint(const Points &_points) : points(_points) {}
MultiPoint(Points&& _points) noexcept: points(std::move(_points)){}
MultiPoint& operator=(const MultiPoint &other) { points = other.points; return *this; }
MultiPoint& operator=(MultiPoint &&other) { points = std::move(other.points); return *this; }
MultiPoint& operator=(MultiPoint &&other) noexcept { points = std::move(other.points); return *this; }
void scale(double factor);
void scale(double factor_x, double factor_y);
void translate(double x, double y) { this->translate(Point(coord_t(x), coord_t(y))); }

View File

@ -173,6 +173,7 @@ namespace Slic3r {
const double nozzle_diameter)
{
ExtrusionPaths ret_paths;
std::list<ExtrusionPath> ret_path_list;
ZPaths paths_in_range = clip_extrusion(extrusion_path, clip_paths, ClipperLib_Z::ctIntersection); //doing intersection first would be faster.
paths_in_range = add_sampling_points(paths_in_range, scale_(2));// enough?
@ -184,13 +185,15 @@ namespace Slic3r {
for (auto& p : path) { assert(p.z() != 0); }
}
auto in_same_degree_range = [](double a, double b) -> bool {
int ceil_a = std::ceil(a);
int floor_a = std::floor(a);
int ceil_b = std::ceil(b);
int floor_b = std::floor(b);
return ceil_a == ceil_b && floor_a == floor_b;
};
auto get_base_degree = [](double d){
return std::floor(d/min_degree_gap_arachne) * min_degree_gap_arachne;
};
auto in_same_degree_range = [&](double a, double b) -> bool {
double base_a = get_base_degree(a);
double base_b = get_base_degree(b);
return std::abs(base_a - base_b) < EPSILON;
};
struct SplitPoint
{
@ -199,11 +202,10 @@ namespace Slic3r {
double degree;
};
auto get_split_points = [](const Point& pa, const Point& pb, const coord_t wa, const coord_t wb, const double da, const double db) -> std::vector<SplitPoint> {
auto get_split_points = [&](const Point& pa, const Point& pb, const coord_t wa, const coord_t wb, const double da, const double db) -> std::vector<SplitPoint> {
std::vector<SplitPoint> ret;
int start_d = (int)(std::ceil(std::min(da, db)));
int end_d = (int)(std::floor(std::max(da, db)));
double start_d = get_base_degree(std::min(da, db)) + min_degree_gap_arachne;
double end_d = get_base_degree(std::max(da, db));
if (start_d > end_d) return ret;
@ -211,7 +213,7 @@ namespace Slic3r {
if (std::abs(delta_d) < 1e-6) return ret;
if (da < db) {
for (int k = start_d; k <= end_d; ++k) {
for (double k = start_d; k <= end_d; k+=min_degree_gap_arachne) {
const double t = (k - da) / delta_d;
const Point pt = pa + (pb - pa) * t;
const coord_t w = wa + coord_t((wb - wa) * t);
@ -219,14 +221,13 @@ namespace Slic3r {
}
}
else {
for (int k = end_d; k >= start_d; --k) {
for (double k = end_d; k >= start_d; k-=min_degree_gap_arachne) {
const double t = (k - da) / delta_d;
const Point pt = pa + (pb - pa) * t;
const coord_t w = wa + coord_t((wb - wa) * t);
ret.emplace_back(SplitPoint{ pt, w, (double)k });
}
}
return ret;
};
@ -287,11 +288,11 @@ namespace Slic3r {
for (auto& split_point : split_points) {
prev_line.push_back({ split_point.p.x(), split_point.p.y(), split_point.w });
double target_degree = 0;
if (prev_d < curr_d)
target_degree = split_point.degree - 1;
if( prev_d < curr_d)
target_degree = split_point.degree - min_degree_gap_arachne;
else
target_degree = split_point.degree;
extrusion_paths_append(ret_paths, { prev_line }, role, flow, target_degree);
extrusion_paths_append(ret_path_list , { prev_line }, role, flow, target_degree);
prev_line.clear();
prev_line.push_back({ split_point.p.x(), split_point.p.y(), split_point.w });
}
@ -301,8 +302,12 @@ namespace Slic3r {
prev_line.push_back(path[idx]);
}
}
if (prev_line.size() > 1) { extrusion_paths_append(ret_paths, { prev_line }, role, flow, std::floor(prev_d)); }
if (prev_line.size() > 1) { extrusion_paths_append(ret_path_list, { prev_line }, role, flow, get_base_degree(prev_d)); }
}
ret_paths.reserve(ret_path_list.size());
ret_paths.insert(ret_paths.end(), std::make_move_iterator(ret_path_list.begin()), std::make_move_iterator(ret_path_list.end()));
return ret_paths;
}

View File

@ -10,7 +10,8 @@ using ZPath = ClipperLib_Z::Path;
using ZPaths = ClipperLib_Z::Paths;
static const int overhang_sampling_number = 6;
static const double min_degree_gap = 0.1;
static const double min_degree_gap_classic = 0.1;
static const double min_degree_gap_arachne = 0.25;
static const int max_overhang_degree = overhang_sampling_number - 1;
static const std::vector<double> non_uniform_degree_map = { 0, 10, 25, 50, 75, 100};
static const int insert_point_count = 3;

View File

@ -243,14 +243,14 @@ static std::deque<PolylineWithDegree> split_polyline_by_degree(const Polyline &p
size_t poly_size = polyline_with_insert_points.size();
// BBS: merge degree in limited range
//find first degee base
double degree_base = int(points_overhang[points_overhang.size() - 1] / min_degree_gap) * min_degree_gap + min_degree_gap;
double degree_base = int(points_overhang[points_overhang.size() - 1] / min_degree_gap_classic) * min_degree_gap_classic + min_degree_gap_classic;
degree_base = degree_base > max_overhang_degree ? max_overhang_degree : degree_base;
double short_poly_len = 0;
for (int point_idx = points_overhang.size() - 2; point_idx > 0; --point_idx) {
double degree = points_overhang[point_idx];
if ( degree <= degree_base && degree >= degree_base - min_degree_gap )
if ( degree <= degree_base && degree >= degree_base - min_degree_gap_classic )
continue;
temp_copy.split_at_index(point_idx, &left, &right);
@ -258,7 +258,7 @@ static std::deque<PolylineWithDegree> split_polyline_by_degree(const Polyline &p
temp_copy = std::move(left);
out.push_back(PolylineWithDegree(right, degree_base));
degree_base = int(degree / min_degree_gap) * min_degree_gap + min_degree_gap;
degree_base = int(degree / min_degree_gap_classic) * min_degree_gap_classic + min_degree_gap_classic;
degree_base = degree_base > max_overhang_degree ? max_overhang_degree : degree_base;
}
@ -279,7 +279,7 @@ static void insert_point_to_line( double left_point_degree,
{
Line line_temp(left_point, right_point);
double line_length = line_temp.length();
if (std::abs(left_point_degree - right_point_degree) <= 0.5 * min_degree_gap || line_length<scale_(1.5))
if (std::abs(left_point_degree - right_point_degree) <= 0.5 * min_degree_gap_classic || line_length<scale_(1.5))
return;
Point middle_pt((left_point + right_point) / 2);

View File

@ -20,7 +20,7 @@ class Polyline : public MultiPoint {
public:
Polyline() {};
Polyline(const Polyline& other) : MultiPoint(other.points), fitting_result(other.fitting_result) {}
Polyline(Polyline &&other) : MultiPoint(std::move(other.points)), fitting_result(std::move(other.fitting_result)) {}
Polyline(Polyline &&other) noexcept : MultiPoint(std::move(other.points)), fitting_result(std::move(other.fitting_result)) {}
Polyline(std::initializer_list<Point> list) : MultiPoint(list) {
fitting_result.clear();
}

View File

@ -2,7 +2,7 @@
namespace Slic3r {
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline& thick_polyline, ExtrusionRole role, const Flow& flow, const float tolerance, const float merge_tolerance, int overhang)
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline& thick_polyline, ExtrusionRole role, const Flow& flow, const float tolerance, const float merge_tolerance, double overhang)
{
ExtrusionMultiPath multi_path;
ExtrusionPath path(role);

View File

@ -6,7 +6,7 @@
#include "Flow.hpp"
namespace Slic3r {
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline& thick_polyline, ExtrusionRole role, const Flow& flow, const float tolerance, const float merge_tolerance, int overhang);
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline& thick_polyline, ExtrusionRole role, const Flow& flow, const float tolerance, const float merge_tolerance, double overhang);
void variable_width(const ThickPolylines& polylines, ExtrusionRole role, const Flow& flow, std::vector<ExtrusionEntity*>& out);
}