Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
266 changes: 135 additions & 131 deletions src/libslic3r/GCode/ExtrusionProcessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,167 +27,131 @@

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);
}

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];
Expand All @@ -200,38 +164,78 @@ 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; }
}
distances_for_curvature[point_idx] = (b.position - a.position).norm();
accumulated_distance += distances_for_curvature[point_idx];
}

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 (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());
}
}
}

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);
}
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());
}
}
}

a.curvature = cestim.get_curvature();
}
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;
}
Expand Down Expand Up @@ -377,11 +381,11 @@ class ExtrusionQualityEstimator

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 });
}
Expand Down
Loading