OrcaSlicer/src/libslic3r/VariableWidth.cpp
salt.wei aab8a12801 ENH: add arachne engine for narrow internal solid infill
ConcentricGapFill pattern was used for internal narrow
solid infill. Use arachne engine instead to remove
gap fill inside the pattern and improve the extrusion path

Signed-off-by: salt.wei <salt.wei@bambulab.com>
Change-Id: I758d7c72eb71cc37026b7cebf746cc345014c3f5
(cherry picked from commit 0b6bacd21a091afc13d7b36a69e5b10f155bc6f8)
2022-08-26 09:25:59 +08:00

225 lines
9.3 KiB
C++

#include "VariableWidth.hpp"
namespace Slic3r {
ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, const float tolerance, const float merge_tolerance)
{
ExtrusionPaths paths;
ExtrusionPath path(role);
ThickLines lines = thick_polyline.thicklines();
for (int i = 0; i < (int)lines.size(); ++i) {
const ThickLine& line = lines[i];
assert(line.a_width >= SCALED_EPSILON && line.b_width >= SCALED_EPSILON);
const coordf_t line_len = line.length();
if (line_len < SCALED_EPSILON) continue;
double thickness_delta = fabs(line.a_width - line.b_width);
if (thickness_delta > tolerance) {
const auto segments = (unsigned int)ceil(thickness_delta / tolerance);
const coordf_t seg_len = line_len / segments;
Points pp;
std::vector<coordf_t> width;
{
pp.push_back(line.a);
width.push_back(line.a_width);
for (size_t j = 1; j < segments; ++j) {
pp.push_back((line.a.cast<double>() + (line.b - line.a).cast<double>().normalized() * (j * seg_len)).cast<coord_t>());
coordf_t w = line.a_width + (j*seg_len) * (line.b_width-line.a_width) / line_len;
width.push_back(w);
width.push_back(w);
}
pp.push_back(line.b);
width.push_back(line.b_width);
assert(pp.size() == segments + 1u);
assert(width.size() == segments*2);
}
// delete this line and insert new ones
lines.erase(lines.begin() + i);
for (size_t j = 0; j < segments; ++j) {
ThickLine new_line(pp[j], pp[j+1]);
new_line.a_width = width[2*j];
new_line.b_width = width[2*j+1];
lines.insert(lines.begin() + i + j, new_line);
}
-- i;
continue;
}
const double w = fmax(line.a_width, line.b_width);
const Flow new_flow = (role == erOverhangPerimeter && flow.bridge()) ? flow : flow.with_width(unscale<float>(w) + flow.height() * float(1. - 0.25 * PI));
if (path.polyline.points.empty()) {
path.polyline.append(line.a);
path.polyline.append(line.b);
// Convert from spacing to extrusion width based on the extrusion model
// of a square extrusion ended with semi circles.
#ifdef SLIC3R_DEBUG
printf(" filling %f gap\n", flow.width);
#endif
path.mm3_per_mm = new_flow.mm3_per_mm();
path.width = new_flow.width();
path.height = new_flow.height();
} else {
assert(path.width >= EPSILON);
thickness_delta = scaled<double>(fabs(path.width - new_flow.width()));
if (thickness_delta <= merge_tolerance) {
// the width difference between this line and the current flow
// (of the previous line) width is within the accepted tolerance
path.polyline.append(line.b);
} else {
// we need to initialize a new line
paths.emplace_back(std::move(path));
path = ExtrusionPath(role);
-- i;
}
}
}
if (path.polyline.is_valid())
paths.emplace_back(std::move(path));
return paths;
}
//BBS: new function to filter width to avoid too fragmented segments
static ExtrusionPaths thick_polyline_to_extrusion_paths_2(const ThickPolyline& thick_polyline, ExtrusionRole role, const Flow& flow, const float tolerance)
{
ExtrusionPaths paths;
ExtrusionPath path(role);
ThickLines lines = thick_polyline.thicklines();
size_t start_index = 0;
double max_width, min_width;
for (int i = 0; i < (int)lines.size(); ++i) {
const ThickLine& line = lines[i];
if (i == 0) {
max_width = line.a_width;
min_width = line.a_width;
}
const coordf_t line_len = line.length();
if (line_len < SCALED_EPSILON) continue;
double thickness_delta = std::max(fabs(max_width - line.b_width), fabs(min_width - line.b_width));
//BBS: has large difference in width
if (thickness_delta > tolerance) {
//BBS: 1 generate path from start_index to i(not included)
if (start_index != i){
path = ExtrusionPath(role);
double length = lines[start_index].length();
double sum = lines[start_index].length() * lines[start_index].a_width;
path.polyline.append(lines[start_index].a);
for (int idx = start_index + 1; idx < i; idx++) {
length += lines[idx].length();
sum += lines[idx].length() * lines[idx].a_width;
path.polyline.append(lines[idx].a);
}
path.polyline.append(lines[i].a);
if (length > SCALED_EPSILON) {
double w = sum / length;
Flow new_flow = flow.with_width(unscale<float>(w) + flow.height() * float(1. - 0.25 * PI));
path.mm3_per_mm = new_flow.mm3_per_mm();
path.width = new_flow.width();
path.height = new_flow.height();
paths.emplace_back(std::move(path));
}
}
start_index = i;
max_width = line.a_width;
min_width = line.a_width;
//BBS: 2 handle the i-th segment
thickness_delta = fabs(line.a_width - line.b_width);
if (thickness_delta > tolerance){
const unsigned int segments = (unsigned int)ceil(thickness_delta / tolerance);
const coordf_t seg_len = line_len / segments;
Points pp;
std::vector<coordf_t> width;
{
pp.push_back(line.a);
width.push_back(line.a_width);
for (size_t j = 1; j < segments; ++j) {
pp.push_back((line.a.cast<double>() + (line.b - line.a).cast<double>().normalized() * (j * seg_len)).cast<coord_t>());
coordf_t w = line.a_width + (j * seg_len) * (line.b_width - line.a_width) / line_len;
width.push_back(w);
width.push_back(w);
}
pp.push_back(line.b);
width.push_back(line.b_width);
assert(pp.size() == segments + 1u);
assert(width.size() == segments * 2);
}
// delete this line and insert new ones
lines.erase(lines.begin() + i);
for (size_t j = 0; j < segments; ++j) {
ThickLine new_line(pp[j], pp[j + 1]);
new_line.a_width = width[2 * j];
new_line.b_width = width[2 * j + 1];
lines.insert(lines.begin() + i + j, new_line);
}
--i;
continue;
}
}
//BBS: just update the max and min width and continue
else {
max_width = std::max(max_width, std::max(line.a_width, line.b_width));
min_width = std::min(min_width, std::min(line.a_width, line.b_width));
}
}
//BBS: handle the remaining segment
size_t final_size = lines.size();
if (start_index < final_size) {
path = ExtrusionPath(role);
double length = lines[start_index].length();
double sum = lines[start_index].length() * lines[start_index].a_width;
path.polyline.append(lines[start_index].a);
for (int idx = start_index + 1; idx < final_size; idx++) {
length += lines[idx].length();
sum += lines[idx].length() * lines[idx].a_width;
path.polyline.append(lines[idx].a);
}
path.polyline.append(lines[final_size - 1].b);
if (length > SCALED_EPSILON) {
double w = sum / length;
Flow new_flow = flow.with_width(unscale<float>(w) + flow.height() * float(1. - 0.25 * PI));
path.mm3_per_mm = new_flow.mm3_per_mm();
path.width = new_flow.width();
path.height = new_flow.height();
paths.emplace_back(std::move(path));
}
}
return paths;
}
void variable_width(const ThickPolylines& polylines, ExtrusionRole role, const Flow& flow, std::vector<ExtrusionEntity*>& out)
{
// This value determines granularity of adaptive width, as G-code does not allow
// variable extrusion within a single move; this value shall only affect the amount
// of segments, and any pruning shall be performed before we apply this tolerance.
const float tolerance = float(scale_(0.05));
for (const ThickPolyline& p : polylines) {
ExtrusionPaths paths = thick_polyline_to_extrusion_paths_2(p, role, flow, tolerance);
// Append paths to collection.
if (!paths.empty()) {
if (paths.front().first_point() == paths.back().last_point())
out.emplace_back(new ExtrusionLoop(std::move(paths)));
else {
for (ExtrusionPath& path : paths)
out.emplace_back(new ExtrusionPath(std::move(path)));
}
}
}
}
}