Fixed a bug that caused curled edge detection not to work as expected for left facing edges when using Arachne. Enabled fan speed control for curled overhangs (#3034)

* Update malformation distance factors (curled edge detection)

* Updated curled detection logic from latest prusa 2.7 release, including updated estimate_points_properties algorithm

Updated curled detection logic from latest prusa 2.7 release, including updated estimate_points_properties algorithm

* Curled distance expansion const introduction

* Enable overhang fan speed logic for curled edges slow downs

* Reverted erroneous change
This commit is contained in:
Ioannis Giannakas 2023-12-09 09:17:49 +00:00 committed by GitHub
parent 325009bc48
commit 7a8e1929ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 182 additions and 152 deletions

View file

@ -27,125 +27,81 @@
namespace Slic3r {
class SlidingWindowCurvatureAccumulator
{
float window_size;
float total_distance = 0; // accumulated distance
float total_curvature = 0; // accumulated signed ccw angles
deque<float> distances;
deque<float> angles;
public:
SlidingWindowCurvatureAccumulator(float window_size) : window_size(window_size) {}
void add_point(float distance, float angle)
{
total_distance += distance;
total_curvature += angle;
distances.push_back(distance);
angles.push_back(angle);
while (distances.size() > 1 && total_distance > window_size) {
total_distance -= distances.front();
total_curvature -= angles.front();
distances.pop_front();
angles.pop_front();
}
}
float get_curvature() const
{
return total_curvature / window_size;
}
void reset()
{
total_curvature = 0;
total_distance = 0;
distances.clear();
angles.clear();
}
};
class CurvatureEstimator
{
static const size_t sliders_count = 3;
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{3.0},{9.0}, {16.0}};
public:
void add_point(float distance, float angle)
{
if (distance < EPSILON)
return;
for (SlidingWindowCurvatureAccumulator &slider : sliders) {
slider.add_point(distance, angle);
}
}
float get_curvature()
{
float max_curvature = 0.0f;
for (const SlidingWindowCurvatureAccumulator &slider : sliders) {
if (abs(slider.get_curvature()) > abs(max_curvature)) {
max_curvature = slider.get_curvature();
}
}
return max_curvature;
}
void reset()
{
for (SlidingWindowCurvatureAccumulator &slider : sliders) {
slider.reset();
}
}
};
struct ExtendedPoint
{
ExtendedPoint(Vec2d position, float distance = 0.0, size_t nearest_prev_layer_line = size_t(-1), float curvature = 0.0)
: position(position), distance(distance), nearest_prev_layer_line(nearest_prev_layer_line), curvature(curvature)
{}
Vec2d position;
float distance;
size_t nearest_prev_layer_line;
float curvature;
Vec2d position;
float distance;
float curvature;
};
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_OFFSET, bool SIGNED_DISTANCE, typename P, typename L>
std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &input_points,
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_OFFSET, bool SIGNED_DISTANCE, typename POINTS, typename L>
std::vector<ExtendedPoint> estimate_points_properties(const POINTS &input_points,
const AABBTreeLines::LinesDistancer<L> &unscaled_prev_layer,
float flow_width,
float max_line_length = -1.0f)
{
bool looped = input_points.front() == input_points.back();
std::function<size_t(size_t,size_t)> get_prev_index = [](size_t idx, size_t count) {
if (idx > 0) {
return idx - 1;
} else
return idx;
};
if (looped) {
get_prev_index = [](size_t idx, size_t count) {
if (idx == 0)
idx = count;
return --idx;
};
};
std::function<size_t(size_t,size_t)> get_next_index = [](size_t idx, size_t size) {
if (idx + 1 < size) {
return idx + 1;
} else
return idx;
};
if (looped) {
get_next_index = [](size_t idx, size_t count) {
if (++idx == count)
idx = 0;
return idx;
};
};
using P = typename POINTS::value_type;
using AABBScalar = typename AABBTreeLines::LinesDistancer<L>::Scalar;
if (input_points.empty())
return {};
float boundary_offset = PREV_LAYER_BOUNDARY_OFFSET ? 0.5 * flow_width : 0.0f;
CurvatureEstimator cestim;
auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); };
float boundary_offset = PREV_LAYER_BOUNDARY_OFFSET ? 0.5 * flow_width : 0.0f;
auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); };
std::vector<ExtendedPoint> points;
points.reserve(input_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1));
{
ExtendedPoint start_point{maybe_unscale(input_points.front())};
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(start_point.position.cast<AABBScalar>());
start_point.distance = distance + boundary_offset;
start_point.nearest_prev_layer_line = nearest_line;
auto [distance, nearest_line,
x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(start_point.position.cast<AABBScalar>());
start_point.distance = distance + boundary_offset;
points.push_back(start_point);
}
for (size_t i = 1; i < input_points.size(); i++) {
ExtendedPoint next_point{maybe_unscale(input_points[i])};
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(next_point.position.cast<AABBScalar>());
next_point.distance = distance + boundary_offset;
next_point.nearest_prev_layer_line = nearest_line;
auto [distance, nearest_line,
x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(next_point.position.cast<AABBScalar>());
next_point.distance = distance + boundary_offset;
if (ADD_INTERSECTIONS &&
((points.back().distance > boundary_offset + EPSILON) != (next_point.distance > boundary_offset + EPSILON))) {
const ExtendedPoint &prev_point = points.back();
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(L{prev_point.position.cast<AABBScalar>(), next_point.position.cast<AABBScalar>()});
const ExtendedPoint &prev_point = points.back();
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(
L{prev_point.position.cast<AABBScalar>(), next_point.position.cast<AABBScalar>()});
for (const auto &intersection : intersections) {
points.emplace_back(intersection.first.template cast<double>(), boundary_offset, intersection.second);
ExtendedPoint p{};
p.position = intersection.first.template cast<double>();
p.distance = boundary_offset;
points.push_back(p);
}
}
points.push_back(next_point);
@ -153,41 +109,49 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
if (PREV_LAYER_BOUNDARY_OFFSET && ADD_INTERSECTIONS) {
std::vector<ExtendedPoint> new_points;
new_points.reserve(points.size()*2);
new_points.reserve(points.size() * 2);
new_points.push_back(points.front());
for (int point_idx = 0; point_idx < int(points.size()) - 1; ++point_idx) {
const ExtendedPoint &curr = points[point_idx];
const ExtendedPoint &next = points[point_idx + 1];
if ((curr.distance > 0 && curr.distance < boundary_offset + 2.0f) ||
(next.distance > 0 && next.distance < boundary_offset + 2.0f)) {
if ((curr.distance > -boundary_offset && curr.distance < boundary_offset + 2.0f) ||
(next.distance > -boundary_offset && next.distance < boundary_offset + 2.0f)) {
double line_len = (next.position - curr.position).norm();
if (line_len > 4.0f) {
double a0 = std::clamp((curr.distance + 2 * boundary_offset) / line_len, 0.0, 1.0);
double a1 = std::clamp(1.0f - (next.distance + 2 * boundary_offset) / line_len, 0.0, 1.0);
double a0 = std::clamp((curr.distance + 3 * boundary_offset) / line_len, 0.0, 1.0);
double a1 = std::clamp(1.0f - (next.distance + 3 * boundary_offset) / line_len, 0.0, 1.0);
double t0 = std::min(a0, a1);
double t1 = std::max(a0, a1);
if (t0 < 1.0) {
auto p0 = curr.position + t0 * (next.position - curr.position);
auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p0.cast<AABBScalar>());
new_points.push_back(ExtendedPoint{p0, float(p0_dist + boundary_offset), p0_near_l});
auto p0 = curr.position + t0 * (next.position - curr.position);
auto [p0_dist, p0_near_l,
p0_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p0.cast<AABBScalar>());
ExtendedPoint new_p{};
new_p.position = p0;
new_p.distance = float(p0_dist + boundary_offset);
new_points.push_back(new_p);
}
if (t1 > 0.0) {
auto p1 = curr.position + t1 * (next.position - curr.position);
auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p1.cast<AABBScalar>());
new_points.push_back(ExtendedPoint{p1, float(p1_dist + boundary_offset), p1_near_l});
auto p1 = curr.position + t1 * (next.position - curr.position);
auto [p1_dist, p1_near_l,
p1_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p1.cast<AABBScalar>());
ExtendedPoint new_p{};
new_p.position = p1;
new_p.distance = float(p1_dist + boundary_offset);
new_points.push_back(new_p);
}
}
}
new_points.push_back(next);
}
points = new_points;
points = std::move(new_points);
}
if (max_line_length > 0) {
std::vector<ExtendedPoint> new_points;
new_points.reserve(points.size()*2);
new_points.reserve(points.size() * 2);
{
for (size_t i = 0; i + 1 < points.size(); i++) {
const ExtendedPoint &curr = points[i];
@ -200,39 +164,79 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
Vec2d pos = curr.position * (1.0 - j * t) + next.position * (j * t);
auto [p_dist, p_near_l,
p_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(pos.cast<AABBScalar>());
new_points.push_back(ExtendedPoint{pos, float(p_dist + boundary_offset), p_near_l});
ExtendedPoint new_p{};
new_p.position = pos;
new_p.distance = float(p_dist + boundary_offset);
new_points.push_back(new_p);
}
}
new_points.push_back(points.back());
}
points = new_points;
points = std::move(new_points);
}
for (int point_idx = 0; point_idx < int(points.size()); ++point_idx) {
ExtendedPoint &a = points[point_idx];
ExtendedPoint &prev = points[point_idx > 0 ? point_idx - 1 : point_idx];
float accumulated_distance = 0;
std::vector<float> distances_for_curvature(points.size());
for (size_t point_idx = 0; point_idx < points.size(); ++point_idx) {
const ExtendedPoint &a = points[point_idx];
const ExtendedPoint &b = points[get_prev_index(point_idx, points.size())];
int prev_point_idx = point_idx;
while (prev_point_idx > 0) {
prev_point_idx--;
if ((a.position - points[prev_point_idx].position).squaredNorm() > EPSILON) { break; }
}
int next_point_index = point_idx;
while (next_point_index < int(points.size()) - 1) {
next_point_index++;
if ((a.position - points[next_point_index].position).squaredNorm() > EPSILON) { break; }
}
if (prev_point_idx != point_idx && next_point_index != point_idx) {
float distance = (prev.position - a.position).norm();
float alfa = angle(a.position - points[prev_point_idx].position, points[next_point_index].position - a.position);
cestim.add_point(distance, alfa);
}
a.curvature = cestim.get_curvature();
distances_for_curvature[point_idx] = (b.position - a.position).norm();
accumulated_distance += distances_for_curvature[point_idx];
}
if (accumulated_distance > EPSILON)
for (float window_size : {3.0f, 9.0f, 16.0f}) {
for (int point_idx = 0; point_idx < int(points.size()); ++point_idx) {
ExtendedPoint &current = points[point_idx];
Vec2d back_position = current.position;
{
size_t back_point_index = point_idx;
float dist_backwards = 0;
while (dist_backwards < window_size * 0.5 && back_point_index != get_prev_index(back_point_index, points.size())) {
float line_dist = distances_for_curvature[get_prev_index(back_point_index, points.size())];
if (dist_backwards + line_dist > window_size * 0.5) {
back_position = points[back_point_index].position +
(window_size * 0.5 - dist_backwards) *
(points[get_prev_index(back_point_index, points.size())].position -
points[back_point_index].position)
.normalized();
dist_backwards += window_size * 0.5 - dist_backwards + EPSILON;
} else {
dist_backwards += line_dist;
back_point_index = get_prev_index(back_point_index, points.size());
}
}
}
Vec2d front_position = current.position;
{
size_t front_point_index = point_idx;
float dist_forwards = 0;
while (dist_forwards < window_size * 0.5 && front_point_index != get_next_index(front_point_index, points.size())) {
float line_dist = distances_for_curvature[front_point_index];
if (dist_forwards + line_dist > window_size * 0.5) {
front_position = points[front_point_index].position +
(window_size * 0.5 - dist_forwards) *
(points[get_next_index(front_point_index, points.size())].position -
points[front_point_index].position)
.normalized();
dist_forwards += window_size * 0.5 - dist_forwards + EPSILON;
} else {
dist_forwards += line_dist;
front_point_index = get_next_index(front_point_index, points.size());
}
}
}
float new_curvature = angle(current.position - back_position, front_position - current.position) / window_size;
if (abs(current.curvature) < abs(new_curvature)) {
current.curvature = new_curvature;
}
}
}
return points;
}
@ -377,11 +381,11 @@ public:
float extrusion_speed = std::min(calculate_speed(curr.distance), calculate_speed(next.distance));
if(slowdown_for_curled_edges) {
float curled_speed = calculate_speed(artificial_distance_to_curled_lines);
float curled_speed = calculate_speed(artificial_distance_to_curled_lines);
extrusion_speed = std::min(curled_speed, extrusion_speed); // adjust extrusion speed based on what is smallest - the calculated overhang speed or the artificial curled speed
}
float overlap = std::min(1 - curr.distance * width_inv, 1 - next.distance * width_inv);
float overlap = std::min(1 - (curr.distance+artificial_distance_to_curled_lines) * width_inv, 1 - (next.distance+artificial_distance_to_curled_lines) * width_inv);
processed_points.push_back({ scaled(curr.position), extrusion_speed, overlap });
}

View file

@ -105,15 +105,10 @@ float estimate_curled_up_height(
float curled_up_height = 0;
if (fabs(distance) < 3.0 * flow_width) {
curled_up_height = std::max(prev_line_curled_height - layer_height * 0.75f, 0.0f);
//printf("If 1 %d\n",curled_up_height);
}
//printf("distance %f, params.malformation_distance_factors.first %f, params.malformation_distance_factors.second %f, flow_width %f\n", distance, params.malformation_distance_factors.first, params.malformation_distance_factors.second, flow_width);
//printf("distance %f,params.malformation_distance_factors.first * flow_width %f, params.malformation_distance_factors.second * flow_width %f\n", distance, params.malformation_distance_factors.first * flow_width, params.malformation_distance_factors.second * flow_width);
if (distance > params.malformation_distance_factors.first * flow_width &&
distance < params.malformation_distance_factors.second * flow_width) {
// imagine the extrusion profile. The part that has been glued (melted) with the previous layer will be called anchored section
// and the rest will be called curling section
// float anchored_section = flow_width - point.distance;
@ -145,49 +140,79 @@ float estimate_curled_up_height(
void estimate_malformations(LayerPtrs &layers, const Params &params)
{
LD prev_layer_lines{};
for (Layer *l : layers) {
#ifdef DEBUG_FILES
FILE *debug_file = boost::nowide::fopen(debug_out_path("object_malformations.obj").c_str(), "w");
FILE *full_file = boost::nowide::fopen(debug_out_path("object_full.obj").c_str(), "w");
#endif
LD prev_layer_lines{};
for (Layer *l : layers) {
l->curled_lines.clear();
std::vector<Linef> boundary_lines = l->lower_layer != nullptr ? to_unscaled_linesf(l->lower_layer->lslices) : std::vector<Linef>();
AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary{std::move(boundary_lines)};
std::vector<ExtrusionLine> current_layer_lines;
for (const LayerRegion *layer_region : l->regions()) {
for (const ExtrusionEntity *extrusion : layer_region->perimeters.flatten().entities) {
if (extrusion->role() != Slic3r::erExternalPerimeter)
for (const ExtrusionEntity *extrusion : layer_region->perimeters.flatten().entities) {
if (extrusion->role() != Slic3r::erExternalPerimeter)
continue;
Points extrusion_pts;
Points extrusion_pts;
extrusion->collect_points(extrusion_pts);
float flow_width = get_flow_width(layer_region, extrusion->role());
auto annotated_points = estimate_points_properties<true, true, false, false>(extrusion_pts, prev_layer_lines, flow_width,
params.bridge_distance);
float flow_width = get_flow_width(layer_region, extrusion->role());
auto annotated_points = estimate_points_properties<true, true, false, false>(extrusion_pts,
prev_layer_lines,
flow_width,
params.bridge_distance);
for (size_t i = 0; i < annotated_points.size(); ++i) {
const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
const ExtendedPoint &b = annotated_points[i];
ExtrusionLine line_out{a.position.cast<float>(), b.position.cast<float>(), float((a.position - b.position).norm()),
extrusion};
Vec2f middle = 0.5 * (line_out.a + line_out.b);
auto [middle_distance, bottom_line_idx, x] = prev_layer_lines.distance_from_lines_extra<false>(middle);
ExtrusionLine bottom_line = prev_layer_lines.get_lines().empty() ? ExtrusionLine{} :
prev_layer_lines.get_line(bottom_line_idx);
// correctify the distance sign using slice polygons
float sign = (prev_layer_boundary.distance_from_lines<true>(middle.cast<double>()) + 0.5f * flow_width) < 0.0f ? -1.0f : 1.0f;
float sign = (prev_layer_boundary.distance_from_lines<true>(middle.cast<double>()) + 0.5f * flow_width) < 0.0f ? -1.0f :
1.0f;
line_out.curled_up_height = estimate_curled_up_height(middle_distance * sign, 0.5 * (a.curvature + b.curvature),
line_out.curled_up_height = estimate_curled_up_height(middle_distance * sign * params.curled_distance_expansion, 0.5 * (a.curvature + b.curvature),
l->height, flow_width, bottom_line.curled_up_height, params);
current_layer_lines.push_back(line_out);
}
}
}
}
for (const ExtrusionLine &line : current_layer_lines) {
if (line.curled_up_height > params.curling_tolerance_limit) {
l->curled_lines.push_back(CurledLine{Point::new_scale(line.a), Point::new_scale(line.b), line.curled_up_height});
}
}
#ifdef DEBUG_FILES
for (const ExtrusionLine &line : current_layer_lines) {
if (line.curled_up_height > params.curling_tolerance_limit) {
Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
fprintf(debug_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]);
}
}
for (const ExtrusionLine &line : current_layer_lines) {
Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
fprintf(full_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]);
}
#endif
prev_layer_lines = LD{current_layer_lines};
}
#ifdef DEBUG_FILES
fclose(debug_file);
fclose(full_file);
#endif
}
/*

View file

@ -43,8 +43,9 @@ struct Params
BrimType brim_type;
const float brim_width;
const std::pair<float,float> malformation_distance_factors = std::pair<float, float> { 0.33, 0.7 };
const std::pair<float,float> malformation_distance_factors = std::pair<float, float> { 0.2, 1.1 };
const float max_curled_height_factor = 10.0f;
const float curled_distance_expansion = 1.0f; // controls the spread of the area where slow down for curled overhangs is applied
const float curling_tolerance_limit = 0.1f;
const float min_distance_between_support_points = 3.0f; //mm