mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-16 12:15:51 +08:00
Thin_wall / medial axis:
- reworked thin_variable_width (discretization into segments of constant width) - bugfix taper_ends - add setting thin_walls_overlap to control the perimeter/thin wall overlap
This commit is contained in:
parent
bc0b249803
commit
75775bc909
@ -111,6 +111,7 @@ void Layer::make_perimeters()
|
|||||||
&& config.serialize("perimeter_extrusion_width").compare(other_config.serialize("perimeter_extrusion_width")) == 0
|
&& config.serialize("perimeter_extrusion_width").compare(other_config.serialize("perimeter_extrusion_width")) == 0
|
||||||
&& config.thin_walls == other_config.thin_walls
|
&& config.thin_walls == other_config.thin_walls
|
||||||
&& config.thin_walls_min_width == other_config.thin_walls_min_width
|
&& config.thin_walls_min_width == other_config.thin_walls_min_width
|
||||||
|
&& config.thin_walls_overlap == other_config.thin_walls_overlap
|
||||||
&& config.external_perimeters_first == other_config.external_perimeters_first
|
&& config.external_perimeters_first == other_config.external_perimeters_first
|
||||||
&& config.perimeter_loop == other_config.perimeter_loop) {
|
&& config.perimeter_loop == other_config.perimeter_loop) {
|
||||||
layerms.push_back(other_layerm);
|
layerms.push_back(other_layerm);
|
||||||
|
@ -343,13 +343,8 @@ add_point_same_percent(ThickPolyline* pattern, ThickPolyline* to_modify)
|
|||||||
double percent_dist = (percent_length - percent_length_other_before) / (percent_length_other - percent_length_other_before);
|
double percent_dist = (percent_length - percent_length_other_before) / (percent_length_other - percent_length_other_before);
|
||||||
coordf_t new_width = to_modify->width[idx_other - 1] * (1 - percent_dist);
|
coordf_t new_width = to_modify->width[idx_other - 1] * (1 - percent_dist);
|
||||||
new_width += to_modify->width[idx_other] * (percent_dist);
|
new_width += to_modify->width[idx_other] * (percent_dist);
|
||||||
Point new_point;
|
|
||||||
new_point.x() = (coord_t)((double)(to_modify->points[idx_other - 1].x()) * (1 - percent_dist));
|
|
||||||
new_point.x() += (coord_t)((double)(to_modify->points[idx_other].x()) * (percent_dist));
|
|
||||||
new_point.y() = (coord_t)((double)(to_modify->points[idx_other - 1].y()) * (1 - percent_dist));
|
|
||||||
new_point.y() += (coord_t)((double)(to_modify->points[idx_other].y()) * (percent_dist));
|
|
||||||
to_modify->width.insert(to_modify->width.begin() + idx_other, new_width);
|
to_modify->width.insert(to_modify->width.begin() + idx_other, new_width);
|
||||||
to_modify->points.insert(to_modify->points.begin() + idx_other, new_point);
|
to_modify->points.insert(to_modify->points.begin() + idx_other, to_modify->points[idx_other - 1].interpolate(percent_dist, to_modify->points[idx_other]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1049,14 +1044,11 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp)
|
|||||||
while (polyline.points.size() > 1 && polyline.width.front() < this->min_width && polyline.endpoints.first) {
|
while (polyline.points.size() > 1 && polyline.width.front() < this->min_width && polyline.endpoints.first) {
|
||||||
//try to split if possible
|
//try to split if possible
|
||||||
if (polyline.width[1] > min_width) {
|
if (polyline.width[1] > min_width) {
|
||||||
double percent_can_keep = 1 - (min_width - polyline.width[0]) / (polyline.width[1] - polyline.width[0]);
|
double percent_can_keep = (min_width - polyline.width[0]) / (polyline.width[1] - polyline.width[0]);
|
||||||
if (polyline.points.front().distance_to(polyline.points[1]) * percent_can_keep > SCALED_RESOLUTION) {
|
if (polyline.points.front().distance_to(polyline.points[1]) * (1-percent_can_keep) > SCALED_RESOLUTION) {
|
||||||
//Can split => move the first point and assign a new weight.
|
//Can split => move the first point and assign a new weight.
|
||||||
//the update of endpoints wil be performed in concatThickPolylines
|
//the update of endpoints wil be performed in concatThickPolylines
|
||||||
polyline.points.front().x() = polyline.points.front().x() +
|
polyline.points.front() = polyline.points.front().interpolate(percent_can_keep, polyline.points[1]);
|
||||||
(coord_t)((polyline.points[1].x() - polyline.points.front().x()) * (1 - percent_can_keep));
|
|
||||||
polyline.points.front().y() = polyline.points.front().y() +
|
|
||||||
(coord_t)((polyline.points[1].y() - polyline.points.front().y()) * (1 - percent_can_keep));
|
|
||||||
polyline.width.front() = min_width;
|
polyline.width.front() = min_width;
|
||||||
} else {
|
} else {
|
||||||
/// almost 0-length, Remove
|
/// almost 0-length, Remove
|
||||||
@ -1073,14 +1065,11 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp)
|
|||||||
while (polyline.points.size() > 1 && polyline.width.back() < this->min_width && polyline.endpoints.second) {
|
while (polyline.points.size() > 1 && polyline.width.back() < this->min_width && polyline.endpoints.second) {
|
||||||
//try to split if possible
|
//try to split if possible
|
||||||
if (polyline.width[polyline.points.size() - 2] > min_width) {
|
if (polyline.width[polyline.points.size() - 2] > min_width) {
|
||||||
double percent_can_keep = 1 - (min_width - polyline.width.back()) / (polyline.width[polyline.points.size() - 2] - polyline.width.back());
|
double percent_can_keep = (min_width - polyline.width.back()) / (polyline.width[polyline.points.size() - 2] - polyline.width.back());
|
||||||
if (polyline.points.back().distance_to(polyline.points[polyline.points.size() - 2]) * percent_can_keep > SCALED_RESOLUTION) {
|
if (polyline.points.back().distance_to(polyline.points[polyline.points.size() - 2]) * (1 - percent_can_keep) > SCALED_RESOLUTION) {
|
||||||
//Can split => move the first point and assign a new weight.
|
//Can split => move the first point and assign a new weight.
|
||||||
//the update of endpoints wil be performed in concatThickPolylines
|
//the update of endpoints wil be performed in concatThickPolylines
|
||||||
polyline.points.back().x() = polyline.points.back().x() +
|
polyline.points.back() = polyline.points.back().interpolate(percent_can_keep, polyline.points[polyline.points.size() - 2]);
|
||||||
(coord_t)((polyline.points[polyline.points.size() - 2].x() - polyline.points.back().x()) * (1 - percent_can_keep));
|
|
||||||
polyline.points.back().y() = polyline.points.back().y() +
|
|
||||||
(coord_t)((polyline.points[polyline.points.size() - 2].y() - polyline.points.back().y()) * (1 - percent_can_keep));
|
|
||||||
polyline.width.back() = min_width;
|
polyline.width.back() = min_width;
|
||||||
} else {
|
} else {
|
||||||
/// almost 0-length, Remove
|
/// almost 0-length, Remove
|
||||||
@ -1108,6 +1097,7 @@ void
|
|||||||
MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
|
MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// concatenate, but even where multiple thickpolyline join, to create nice long strait polylines
|
// concatenate, but even where multiple thickpolyline join, to create nice long strait polylines
|
||||||
/* If we removed any short polylines we now try to connect consecutive polylines
|
/* If we removed any short polylines we now try to connect consecutive polylines
|
||||||
in order to allow loop detection. Note that this algorithm is greedier than
|
in order to allow loop detection. Note that this algorithm is greedier than
|
||||||
@ -1155,7 +1145,11 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
|
|||||||
best_dot = other_dot;
|
best_dot = other_dot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (best_candidate != nullptr) {
|
if (best_candidate != nullptr && best_candidate->size() > 1) {
|
||||||
|
//intersections may create ever-ertusion because the included circle can be a bit larger. We have to make it short again.
|
||||||
|
if (polyline.width.back() > polyline.width[polyline.width.size() - 2] && polyline.width.back() > best_candidate->width[1]) {
|
||||||
|
polyline.width.back() = std::min(polyline.width[polyline.width.size() - 2], best_candidate->width[1]);
|
||||||
|
}
|
||||||
polyline.points.insert(polyline.points.end(), best_candidate->points.begin() + 1, best_candidate->points.end());
|
polyline.points.insert(polyline.points.end(), best_candidate->points.begin() + 1, best_candidate->points.end());
|
||||||
polyline.width.insert(polyline.width.end(), best_candidate->width.begin() + 1, best_candidate->width.end());
|
polyline.width.insert(polyline.width.end(), best_candidate->width.begin() + 1, best_candidate->width.end());
|
||||||
polyline.endpoints.second = best_candidate->endpoints.second;
|
polyline.endpoints.second = best_candidate->endpoints.second;
|
||||||
@ -1455,7 +1449,6 @@ MedialAxis::build(ThickPolylines* polylines_out) {
|
|||||||
// svg.draw(pp);
|
// svg.draw(pp);
|
||||||
// svg.Close();
|
// svg.Close();
|
||||||
//}
|
//}
|
||||||
|
|
||||||
concatenate_polylines_with_crossing(pp);
|
concatenate_polylines_with_crossing(pp);
|
||||||
//{
|
//{
|
||||||
// stringstream stri;
|
// stringstream stri;
|
||||||
@ -1518,26 +1511,49 @@ MedialAxis::grow_to_nozzle_diameter(ThickPolylines& pp, const ExPolygons& anchor
|
|||||||
|
|
||||||
void
|
void
|
||||||
MedialAxis::taper_ends(ThickPolylines& pp) {
|
MedialAxis::taper_ends(ThickPolylines& pp) {
|
||||||
|
const coord_t min_size = this->nozzle_diameter * 0.1;
|
||||||
|
const coordf_t length = std::min(this->anchor_size, (this->nozzle_diameter - min_size) / 2);
|
||||||
|
if (length <= SCALED_RESOLUTION) return;
|
||||||
//ensure the width is not lower than 0.4.
|
//ensure the width is not lower than 0.4.
|
||||||
for (ThickPolyline& polyline : pp) {
|
for (ThickPolyline& polyline : pp) {
|
||||||
if (polyline.length() < nozzle_diameter * 2) continue;
|
if (polyline.length() < length * 2.2) continue;
|
||||||
if (polyline.endpoints.first) {
|
if (polyline.endpoints.first) {
|
||||||
polyline.width[0] = min_width;
|
polyline.width[0] = min_size;
|
||||||
coord_t current_dist = min_width;
|
coord_t current_dist = min_size;
|
||||||
|
coord_t last_dist = min_size;
|
||||||
for (size_t i = 1; i<polyline.width.size(); ++i) {
|
for (size_t i = 1; i<polyline.width.size(); ++i) {
|
||||||
current_dist += (coord_t) polyline.points[i - 1].distance_to(polyline.points[i]);
|
current_dist += (coord_t) polyline.points[i - 1].distance_to(polyline.points[i]);
|
||||||
if (current_dist > polyline.width[i]) break;
|
if (current_dist > length) {
|
||||||
polyline.width[i] = current_dist;
|
//create new point if not near enough
|
||||||
|
if (current_dist > polyline.width[i] + SCALED_RESOLUTION) {
|
||||||
|
coordf_t percent_dist = (polyline.width[i] - polyline.width[i - 1]) / (current_dist - last_dist);
|
||||||
|
polyline.points.insert(polyline.points.begin() + i, polyline.points[i - 1].interpolate(percent_dist, polyline.points[i]));
|
||||||
|
polyline.width.insert(polyline.width.begin() + i, polyline.width[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
polyline.width[i] = std::max((coordf_t)min_size, min_size + (polyline.width[i] - min_size) * current_dist / length);
|
||||||
|
last_dist = current_dist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (polyline.endpoints.second) {
|
if (polyline.endpoints.second) {
|
||||||
size_t last_idx = polyline.width.size() - 1;
|
const size_t back_idx = polyline.width.size() - 1;
|
||||||
polyline.width[last_idx] = min_width;
|
polyline.width[back_idx] = min_size;
|
||||||
coord_t current_dist = min_width;
|
coord_t current_dist = min_size;
|
||||||
|
coord_t last_dist = min_size;
|
||||||
for (size_t i = 1; i<polyline.width.size(); ++i) {
|
for (size_t i = 1; i<polyline.width.size(); ++i) {
|
||||||
current_dist += (coord_t) polyline.points[last_idx - i + 1].distance_to(polyline.points[last_idx - i]);
|
current_dist += (coord_t)polyline.points[back_idx - i + 1].distance_to(polyline.points[back_idx - i]);
|
||||||
if (current_dist > polyline.width[last_idx - i]) break;
|
if (current_dist > length) {
|
||||||
polyline.width[last_idx - i] = current_dist;
|
//create new point if not near enough
|
||||||
|
if (current_dist > polyline.width[back_idx - i] + SCALED_RESOLUTION) {
|
||||||
|
coordf_t percent_dist = (polyline.width[back_idx - i] - polyline.width[back_idx - i + 1]) / (current_dist - last_dist);
|
||||||
|
polyline.points.insert(polyline.points.begin() + back_idx - i + 1, polyline.points[back_idx - i + 1].interpolate(percent_dist, polyline.points[back_idx - i]));
|
||||||
|
polyline.width.insert(polyline.width.begin() + back_idx - i + 1, polyline.width[back_idx - i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
polyline.width[back_idx - i] = std::max((coordf_t)min_size, min_size + (polyline.width[back_idx - i] - min_size) * current_dist / length);
|
||||||
|
last_dist = current_dist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1547,65 +1563,67 @@ ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, E
|
|||||||
// this value determines granularity of adaptive width, as G-code does not allow
|
// 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
|
// 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
|
// of segments, and any pruning shall be performed before we apply this tolerance
|
||||||
const double tolerance = scale_(0.05);
|
const double tolerance = 4*SCALED_RESOLUTION;//scale_(0.05);
|
||||||
|
|
||||||
int id_line = 0;
|
|
||||||
ExtrusionEntityCollection coll;
|
ExtrusionEntityCollection coll;
|
||||||
for (const ThickPolyline &p : polylines) {
|
for (const ThickPolyline &p : polylines) {
|
||||||
id_line++;
|
|
||||||
ExtrusionPaths paths;
|
ExtrusionPaths paths;
|
||||||
ExtrusionPath path(role);
|
ExtrusionPath path(role);
|
||||||
ThickLines lines = p.thicklines();
|
ThickLines lines = p.thicklines();
|
||||||
|
|
||||||
for (int i = 0; i < (int)lines.size(); ++i) {
|
for (int i = 0; i < (int)lines.size(); ++i) {
|
||||||
const ThickLine& line = lines[i];
|
ThickLine& line = lines[i];
|
||||||
|
|
||||||
const coordf_t line_len = line.length();
|
const coordf_t line_len = line.length();
|
||||||
if (line_len < SCALED_EPSILON) continue;
|
if (line_len < SCALED_EPSILON) continue;
|
||||||
|
|
||||||
double thickness_delta = fabs(line.a_width - line.b_width);
|
double thickness_delta = fabs(line.a_width - line.b_width);
|
||||||
if (thickness_delta > tolerance) {
|
if (thickness_delta > tolerance && ceil(thickness_delta / tolerance) > 2) {
|
||||||
const uint16_t segments = (uint16_t) std::min(16000.0, ceil(thickness_delta / tolerance));
|
const uint16_t segments = 1+(uint16_t) std::min(16000.0, ceil(thickness_delta / tolerance));
|
||||||
const coordf_t seg_len = line_len / segments;
|
|
||||||
Points pp;
|
Points pp;
|
||||||
std::vector<coordf_t> width;
|
std::vector<coordf_t> width;
|
||||||
{
|
{
|
||||||
pp.push_back(line.a);
|
for (size_t j = 0; j < segments; ++j) {
|
||||||
width.push_back(line.a_width);
|
pp.push_back(line.a.interpolate(((double)j) / segments, line.b));
|
||||||
for (size_t j = 1; j < segments; ++j) {
|
double percent_width = ((double)j) / (segments-1);
|
||||||
pp.push_back(line.point_at(j*seg_len));
|
width.push_back(line.a_width*(1 - percent_width) + line.b_width*percent_width);
|
||||||
|
|
||||||
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);
|
pp.push_back(line.b);
|
||||||
width.push_back(line.b_width);
|
|
||||||
|
|
||||||
assert(pp.size() == segments + 1);
|
assert(pp.size() == segments + 1);
|
||||||
assert(width.size() == segments * 2);
|
assert(width.size() == segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete this line and insert new ones
|
// delete this line and insert new ones
|
||||||
lines.erase(lines.begin() + i);
|
lines.erase(lines.begin() + i);
|
||||||
for (size_t j = 0; j < segments; ++j) {
|
for (size_t j = 0; j < segments; ++j) {
|
||||||
ThickLine new_line(pp[j], pp[j + 1]);
|
ThickLine new_line(pp[j], pp[j + 1]);
|
||||||
new_line.a_width = width[2 * j];
|
new_line.a_width = width[j];
|
||||||
new_line.b_width = width[2 * j + 1];
|
new_line.b_width = width[j];
|
||||||
lines.insert(lines.begin() + i + j, new_line);
|
lines.insert(lines.begin() + i + j, new_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--i;
|
||||||
|
continue;
|
||||||
|
} else if (thickness_delta > 0) {
|
||||||
|
//create a middle point
|
||||||
|
ThickLine new_line(line.a.interpolate(0.5, line.b), line.b);
|
||||||
|
new_line.a_width = line.b_width;
|
||||||
|
new_line.b_width = line.b_width;
|
||||||
|
line.b = new_line.a;
|
||||||
|
line.b_width = line.a_width;
|
||||||
|
lines.insert(lines.begin() + i + 1, new_line);
|
||||||
|
|
||||||
--i;
|
--i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const double w = std::fmax(line.a_width, line.b_width);
|
|
||||||
if (path.polyline.points.empty()) {
|
if (path.polyline.points.empty()) {
|
||||||
path.polyline.append(line.a);
|
path.polyline.append(line.a);
|
||||||
path.polyline.append(line.b);
|
path.polyline.append(line.b);
|
||||||
// Convert from spacing to extrusion width based on the extrusion model
|
// Convert from spacing to extrusion width based on the extrusion model
|
||||||
// of a square extrusion ended with semi circles.
|
// of a square extrusion ended with semi circles.
|
||||||
flow.width = (float)unscaled(w) + flow.height * (1. - 0.25 * PI);
|
flow.width = (float)unscaled(line.a_width) + flow.height * (1. - 0.25 * PI);
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
printf(" filling %f gap\n", flow.width);
|
printf(" filling %f gap\n", flow.width);
|
||||||
#endif
|
#endif
|
||||||
@ -1613,7 +1631,7 @@ ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, E
|
|||||||
path.width = flow.width;
|
path.width = flow.width;
|
||||||
path.height = flow.height;
|
path.height = flow.height;
|
||||||
} else {
|
} else {
|
||||||
thickness_delta = fabs(scale_(flow.width) - w);
|
thickness_delta = fabs(flow.scaled_spacing() - line.a_width);
|
||||||
if (thickness_delta <= tolerance / 2) {
|
if (thickness_delta <= tolerance / 2) {
|
||||||
// the width difference between this line and the current flow width is
|
// the width difference between this line and the current flow width is
|
||||||
// within the accepted tolerance
|
// within the accepted tolerance
|
||||||
|
@ -25,10 +25,12 @@ namespace Slic3r {
|
|||||||
const coord_t min_width;
|
const coord_t min_width;
|
||||||
const coord_t height;
|
const coord_t height;
|
||||||
coord_t nozzle_diameter;
|
coord_t nozzle_diameter;
|
||||||
|
coord_t anchor_size;
|
||||||
bool stop_at_min_width = true;
|
bool stop_at_min_width = true;
|
||||||
MedialAxis(const ExPolygon &_expolygon, const ExPolygon &_bounds, const coord_t _max_width, const coord_t _min_width, const coord_t _height)
|
MedialAxis(const ExPolygon &_expolygon, const ExPolygon &_bounds, const coord_t _max_width, const coord_t _min_width, const coord_t _height)
|
||||||
: surface(_expolygon), bounds(_bounds), max_width(_max_width), min_width(_min_width), height(_height) {
|
: surface(_expolygon), bounds(_bounds), max_width(_max_width), min_width(_min_width), height(_height) {
|
||||||
nozzle_diameter = _min_width;
|
nozzle_diameter = _min_width;
|
||||||
|
anchor_size = 0;
|
||||||
};
|
};
|
||||||
void build(ThickPolylines* polylines_out);
|
void build(ThickPolylines* polylines_out);
|
||||||
void build(Polylines* polylines);
|
void build(Polylines* polylines);
|
||||||
|
@ -228,7 +228,7 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate next onion shell of perimeters.
|
// Calculate next onion shell of perimeters.
|
||||||
//this variable stored the nexyt onion
|
//this variable stored the next onion
|
||||||
ExPolygons next_onion;
|
ExPolygons next_onion;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
// compute next onion, without taking care of thin_walls : destroy too thin areas.
|
// compute next onion, without taking care of thin_walls : destroy too thin areas.
|
||||||
@ -240,23 +240,21 @@ void PerimeterGenerator::process()
|
|||||||
if (this->config->thin_walls) {
|
if (this->config->thin_walls) {
|
||||||
// the minimum thickness of a single loop is:
|
// the minimum thickness of a single loop is:
|
||||||
// ext_width/2 + ext_spacing/2 + spacing/2 + width/2
|
// ext_width/2 + ext_spacing/2 + spacing/2 + width/2
|
||||||
|
|
||||||
next_onion = offset2_ex(
|
next_onion = offset2_ex(
|
||||||
last,
|
last,
|
||||||
-(float)(ext_perimeter_width / 2 + ext_min_spacing / 2 - 1),
|
-(float)(ext_perimeter_width / 2 + ext_min_spacing / 2 - 1),
|
||||||
+(float)(ext_min_spacing / 2 - 1));
|
+(float)(ext_min_spacing / 2 - 1));
|
||||||
|
|
||||||
// detect edge case where a curve can be split in multiple small chunks.
|
// detect edge case where a curve can be split in multiple small chunks.
|
||||||
ExPolygons no_thin_onion = offset_ex(last, -(float)(ext_perimeter_width / 2));
|
ExPolygons no_thin_onion = offset_ex(last, -(float)(ext_perimeter_width / 2));
|
||||||
float div = 2;
|
float div = 2;
|
||||||
while (no_thin_onion.size() > 0 && next_onion.size() > no_thin_onion.size() && no_thin_onion.size() + next_onion.size() > 3) {
|
while (no_thin_onion.size() > 0 && next_onion.size() > no_thin_onion.size() && no_thin_onion.size() + next_onion.size() > 3) {
|
||||||
div += 0.5;
|
div += 0.5;
|
||||||
//use a sightly smaller spacing to try to drastically improve the split
|
//use a sightly smaller spacing to try to drastically improve the split, but with a little bit of over-extrusion
|
||||||
ExPolygons next_onion_secondTry = offset2_ex(
|
ExPolygons next_onion_secondTry = offset2_ex(
|
||||||
last,
|
last,
|
||||||
-(float)(ext_perimeter_width / 2 + ext_min_spacing / div - 1),
|
-(float)(ext_perimeter_width / 2 + ext_min_spacing / div - 1),
|
||||||
+(float)(ext_min_spacing / div - 1));
|
+(float)(ext_min_spacing / div - 1));
|
||||||
if (next_onion.size() > next_onion_secondTry.size()) {
|
if (next_onion.size() > next_onion_secondTry.size() * 1.1) {
|
||||||
next_onion = next_onion_secondTry;
|
next_onion = next_onion_secondTry;
|
||||||
}
|
}
|
||||||
if (div > 3) break;
|
if (div > 3) break;
|
||||||
@ -281,13 +279,13 @@ void PerimeterGenerator::process()
|
|||||||
no_thin_zone = diff_ex(last, offset_ex(half_thins, (float)(min_width / 2) - (float) SCALED_EPSILON), true);
|
no_thin_zone = diff_ex(last, offset_ex(half_thins, (float)(min_width / 2) - (float) SCALED_EPSILON), true);
|
||||||
}
|
}
|
||||||
// compute a bit of overlap to anchor thin walls inside the print.
|
// compute a bit of overlap to anchor thin walls inside the print.
|
||||||
ExPolygons thin_zones_extruded;
|
|
||||||
for (ExPolygon &half_thin : half_thins) {
|
for (ExPolygon &half_thin : half_thins) {
|
||||||
//growing back the polygon
|
//growing back the polygon
|
||||||
ExPolygons thin = offset_ex(half_thin, (float)(min_width / 2));
|
ExPolygons thin = offset_ex(half_thin, (float)(min_width / 2));
|
||||||
assert(thin.size() == 1);
|
assert(thin.size() == 1);
|
||||||
|
coord_t overlap = (coord_t)scale_(this->config->thin_walls_overlap.get_abs_value(this->ext_perimeter_flow.nozzle_diameter));
|
||||||
ExPolygons anchor = intersection_ex(offset_ex(half_thin, (float)(min_width / 2) +
|
ExPolygons anchor = intersection_ex(offset_ex(half_thin, (float)(min_width / 2) +
|
||||||
(float)(ext_perimeter_width / 2), jtSquare), no_thin_zone, true);
|
(float)(overlap), jtSquare), no_thin_zone, true);
|
||||||
ExPolygons bounds = union_ex(thin, anchor, true);
|
ExPolygons bounds = union_ex(thin, anchor, true);
|
||||||
for (ExPolygon &bound : bounds) {
|
for (ExPolygon &bound : bounds) {
|
||||||
if (!intersection_ex(thin[0], bound).empty()) {
|
if (!intersection_ex(thin[0], bound).empty()) {
|
||||||
@ -298,14 +296,13 @@ void PerimeterGenerator::process()
|
|||||||
// the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop
|
// the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop
|
||||||
Slic3r::MedialAxis ma(thin[0], bound, ext_perimeter_width + ext_perimeter_spacing2, min_width, this->layer_height);
|
Slic3r::MedialAxis ma(thin[0], bound, ext_perimeter_width + ext_perimeter_spacing2, min_width, this->layer_height);
|
||||||
ma.nozzle_diameter = (coord_t)scale_(this->ext_perimeter_flow.nozzle_diameter);
|
ma.nozzle_diameter = (coord_t)scale_(this->ext_perimeter_flow.nozzle_diameter);
|
||||||
|
ma.anchor_size = overlap;
|
||||||
ma.build(&thin_walls);
|
ma.build(&thin_walls);
|
||||||
thin_zones_extruded.emplace_back(thin[0]);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next_onion = diff_ex(offset_ex(last, -(float)(ext_perimeter_width / 2)), thin_zones_extruded, true);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//FIXME Is this offset correct if the line width of the inner perimeters differs
|
//FIXME Is this offset correct if the line width of the inner perimeters differs
|
||||||
|
@ -209,6 +209,19 @@ Point Point::projection_onto(const Line &line) const
|
|||||||
return ((line.a - *this).cast<double>().squaredNorm() < (line.b - *this).cast<double>().squaredNorm()) ? line.a : line.b;
|
return ((line.a - *this).cast<double>().squaredNorm() < (line.b - *this).cast<double>().squaredNorm()) ? line.a : line.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This method create a new point on the line defined by this and p2.
|
||||||
|
/// The new point is place at position defined by |p2-this| * percent, starting from this
|
||||||
|
/// \param percent the proportion of the segment length to place the point
|
||||||
|
/// \param p2 the second point, forming a segment with this
|
||||||
|
/// \return a new point, == this if percent is 0 and == p2 if percent is 1
|
||||||
|
Point Point::interpolate(const double percent, const Point &p2) const
|
||||||
|
{
|
||||||
|
Point p_out;
|
||||||
|
p_out.x() = this->x()*(1 - percent) + p2.x()*(percent);
|
||||||
|
p_out.y() = this->y()*(1 - percent) + p2.y()*(percent);
|
||||||
|
return p_out;
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf)
|
std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf)
|
||||||
{
|
{
|
||||||
return stm << pointf(0) << "," << pointf(1);
|
return stm << pointf(0) << "," << pointf(1);
|
||||||
|
@ -121,6 +121,7 @@ public:
|
|||||||
double ccw_angle(const Point &p1, const Point &p2) const;
|
double ccw_angle(const Point &p1, const Point &p2) const;
|
||||||
Point projection_onto(const MultiPoint &poly) const;
|
Point projection_onto(const MultiPoint &poly) const;
|
||||||
Point projection_onto(const Line &line) const;
|
Point projection_onto(const Line &line) const;
|
||||||
|
Point interpolate(const double percent, const Point &p) const;
|
||||||
|
|
||||||
double distance_to(const Point &point) const { return (point - *this).cast<double>().norm(); }
|
double distance_to(const Point &point) const { return (point - *this).cast<double>().norm(); }
|
||||||
double distance_to_square(const Point &point) const {
|
double distance_to_square(const Point &point) const {
|
||||||
|
@ -2428,6 +2428,15 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->default_value = new ConfigOptionFloatOrPercent(33, true);
|
def->default_value = new ConfigOptionFloatOrPercent(33, true);
|
||||||
|
|
||||||
|
def = this->add("thin_walls_overlap", coFloatOrPercent);
|
||||||
|
def->label = L("overlap");
|
||||||
|
def->category = L("Layers and Perimeters");
|
||||||
|
def->tooltip = L("Overlap between the thin wall and the perimeters. Can be a % of the external perimeter width (default 50%)");
|
||||||
|
def->cli = "thin-walls-overlap=s";
|
||||||
|
def->mode = comExpert;
|
||||||
|
def->min = 0;
|
||||||
|
def->default_value = new ConfigOptionFloatOrPercent(50, true);
|
||||||
|
|
||||||
def = this->add("threads", coInt);
|
def = this->add("threads", coInt);
|
||||||
def->label = L("Threads");
|
def->label = L("Threads");
|
||||||
def->tooltip = L("Threads are used to parallelize long-running tasks. Optimal threads number "
|
def->tooltip = L("Threads are used to parallelize long-running tasks. Optimal threads number "
|
||||||
|
@ -573,6 +573,7 @@ public:
|
|||||||
// Detect thin walls.
|
// Detect thin walls.
|
||||||
ConfigOptionBool thin_walls;
|
ConfigOptionBool thin_walls;
|
||||||
ConfigOptionFloatOrPercent thin_walls_min_width;
|
ConfigOptionFloatOrPercent thin_walls_min_width;
|
||||||
|
ConfigOptionFloatOrPercent thin_walls_overlap;
|
||||||
ConfigOptionFloatOrPercent top_infill_extrusion_width;
|
ConfigOptionFloatOrPercent top_infill_extrusion_width;
|
||||||
ConfigOptionInt top_solid_layers;
|
ConfigOptionInt top_solid_layers;
|
||||||
ConfigOptionFloatOrPercent top_solid_infill_speed;
|
ConfigOptionFloatOrPercent top_solid_infill_speed;
|
||||||
@ -629,6 +630,7 @@ protected:
|
|||||||
OPT_PTR(solid_infill_speed);
|
OPT_PTR(solid_infill_speed);
|
||||||
OPT_PTR(thin_walls);
|
OPT_PTR(thin_walls);
|
||||||
OPT_PTR(thin_walls_min_width);
|
OPT_PTR(thin_walls_min_width);
|
||||||
|
OPT_PTR(thin_walls_overlap);
|
||||||
OPT_PTR(top_infill_extrusion_width);
|
OPT_PTR(top_infill_extrusion_width);
|
||||||
OPT_PTR(top_solid_infill_speed);
|
OPT_PTR(top_solid_infill_speed);
|
||||||
OPT_PTR(top_solid_layers);
|
OPT_PTR(top_solid_layers);
|
||||||
|
@ -463,6 +463,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
|||||||
|| opt_key == "infill_overlap"
|
|| opt_key == "infill_overlap"
|
||||||
|| opt_key == "thin_walls"
|
|| opt_key == "thin_walls"
|
||||||
|| opt_key == "thin_walls_min_width"
|
|| opt_key == "thin_walls_min_width"
|
||||||
|
|| opt_key == "thin_walls_overlap"
|
||||||
|| opt_key == "external_perimeters_first"
|
|| opt_key == "external_perimeters_first"
|
||||||
|| opt_key == "perimeter_loop"
|
|| opt_key == "perimeter_loop"
|
||||||
|| opt_key == "perimeter_loop_seam"
|
|| opt_key == "perimeter_loop_seam"
|
||||||
|
@ -360,6 +360,7 @@ const std::vector<std::string>& Preset::print_options()
|
|||||||
, "infill_not_connected"
|
, "infill_not_connected"
|
||||||
, "first_layer_infill_speed"
|
, "first_layer_infill_speed"
|
||||||
, "thin_walls_min_width"
|
, "thin_walls_min_width"
|
||||||
|
, "thin_walls_overlap"
|
||||||
};
|
};
|
||||||
return s_opts;
|
return s_opts;
|
||||||
}
|
}
|
||||||
|
@ -945,6 +945,7 @@ void TabPrint::build()
|
|||||||
line = { _(L("Thin walls")), "" };
|
line = { _(L("Thin walls")), "" };
|
||||||
line.append_option(optgroup->get_option("thin_walls"));
|
line.append_option(optgroup->get_option("thin_walls"));
|
||||||
line.append_option(optgroup->get_option("thin_walls_min_width"));
|
line.append_option(optgroup->get_option("thin_walls_min_width"));
|
||||||
|
line.append_option(optgroup->get_option("thin_walls_overlap"));
|
||||||
optgroup->append_line(line);
|
optgroup->append_line(line);
|
||||||
optgroup->append_single_option_line("overhangs");
|
optgroup->append_single_option_line("overhangs");
|
||||||
line = { _(L("Avoid unsupported perimeters")), "" };
|
line = { _(L("Avoid unsupported perimeters")), "" };
|
||||||
@ -1363,11 +1364,11 @@ void TabPrint::update()
|
|||||||
|
|
||||||
bool have_perimeters = m_config->opt_int("perimeters") > 0;
|
bool have_perimeters = m_config->opt_int("perimeters") > 0;
|
||||||
for (auto el : { "extra_perimeters", "only_one_perimeter_top", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
|
for (auto el : { "extra_perimeters", "only_one_perimeter_top", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
|
||||||
"seam_position", "external_perimeters_first", "external_perimeter_extrusion_width", "thin_walls_min_width",
|
"seam_position", "external_perimeters_first", "external_perimeter_extrusion_width",
|
||||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "perimeter_loop", "perimeter_loop_seam" })
|
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "perimeter_loop", "perimeter_loop_seam" })
|
||||||
get_field(el)->toggle(have_perimeters);
|
get_field(el)->toggle(have_perimeters);
|
||||||
|
|
||||||
get_field("thin_walls_min_width")->toggle(m_config->opt_bool("thin_walls"));
|
for (auto el : { "thin_walls_min_width", "thin_walls_overlap" }) get_field(el)->toggle(m_config->opt_bool("thin_walls"));
|
||||||
get_field("perimeter_loop_seam")->toggle(m_config->opt_bool("perimeter_loop"));
|
get_field("perimeter_loop_seam")->toggle(m_config->opt_bool("perimeter_loop"));
|
||||||
|
|
||||||
bool have_no_perimeter_unsupported = have_perimeters && m_config->opt_bool("no_perimeter_unsupported");
|
bool have_no_perimeter_unsupported = have_perimeters && m_config->opt_bool("no_perimeter_unsupported");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user