mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 04:15:51 +08:00
Fix gap - infill voids
This commit is contained in:
parent
08cd7ebe26
commit
5c0bf45bc1
@ -363,22 +363,22 @@ void PerimeterGenerator::process()
|
|||||||
|
|
||||||
surface_idx = 0;
|
surface_idx = 0;
|
||||||
const int extra_odd_perimeter = (config->extra_perimeters_odd_layers && layer->id() % 2 == 1 ? 1:0);
|
const int extra_odd_perimeter = (config->extra_perimeters_odd_layers && layer->id() % 2 == 1 ? 1:0);
|
||||||
for (const Surface &surface : all_surfaces) {
|
for (const Surface& surface : all_surfaces) {
|
||||||
// detect how many perimeters must be generated for this island
|
// detect how many perimeters must be generated for this island
|
||||||
int loop_number = this->config->perimeters + surface.extra_perimeters - 1 + extra_odd_perimeter; // 0-indexed loops
|
int loop_number = this->config->perimeters + surface.extra_perimeters - 1 + extra_odd_perimeter; // 0-indexed loops
|
||||||
surface_idx++;
|
surface_idx++;
|
||||||
|
|
||||||
if ((layer->id() == 0 && this->config->only_one_perimeter_first_layer) || (this->config->only_one_perimeter_top && loop_number > 0 && this->upper_slices == NULL)){
|
if ((layer->id() == 0 && this->config->only_one_perimeter_first_layer) || (this->config->only_one_perimeter_top && loop_number > 0 && this->upper_slices == NULL)) {
|
||||||
loop_number = 0;
|
loop_number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExPolygons gaps;
|
ExPolygons gaps;
|
||||||
//this var store infill surface removed from last to not add any more perimeters to it.
|
//this var store infill surface removed from last to not add any more perimeters to it.
|
||||||
ExPolygons top_fills;
|
ExPolygons top_fills;
|
||||||
ExPolygons fill_clip;
|
ExPolygons fill_clip;
|
||||||
// simplification already done at slicing
|
// simplification already done at slicing
|
||||||
//ExPolygons last = union_ex(surface.expolygon.simplify_p(SCALED_RESOLUTION));
|
//ExPolygons last = union_ex(surface.expolygon.simplify_p(SCALED_RESOLUTION));
|
||||||
ExPolygons last = union_ex(surface.expolygon);
|
ExPolygons last = union_ex(surface.expolygon);
|
||||||
double last_area = -1;
|
double last_area = -1;
|
||||||
|
|
||||||
if (loop_number >= 0) {
|
if (loop_number >= 0) {
|
||||||
@ -397,11 +397,11 @@ void PerimeterGenerator::process()
|
|||||||
|
|
||||||
// Add perimeters on overhangs : initialization
|
// Add perimeters on overhangs : initialization
|
||||||
ExPolygons overhangs_unsupported;
|
ExPolygons overhangs_unsupported;
|
||||||
if ( (this->config->extra_perimeters_overhangs || (this->config->overhangs_reverse && this->layer->id() % 2 == 1))
|
if ((this->config->extra_perimeters_overhangs || (this->config->overhangs_reverse && this->layer->id() % 2 == 1))
|
||||||
&& !last.empty() && this->lower_slices != NULL && !this->lower_slices->empty()) {
|
&& !last.empty() && this->lower_slices != NULL && !this->lower_slices->empty()) {
|
||||||
//remove holes from lower layer, we only ant that for overhangs, not bridges!
|
//remove holes from lower layer, we only ant that for overhangs, not bridges!
|
||||||
ExPolygons lower_without_holes;
|
ExPolygons lower_without_holes;
|
||||||
for (const ExPolygon &exp : *this->lower_slices)
|
for (const ExPolygon& exp : *this->lower_slices)
|
||||||
lower_without_holes.emplace_back(to_expolygon(exp.contour));
|
lower_without_holes.emplace_back(to_expolygon(exp.contour));
|
||||||
overhangs_unsupported = offset2_ex(diff_ex(last, lower_without_holes, true), -SCALED_RESOLUTION, SCALED_RESOLUTION);
|
overhangs_unsupported = offset2_ex(diff_ex(last, lower_without_holes, true), -SCALED_RESOLUTION, SCALED_RESOLUTION);
|
||||||
if (!overhangs_unsupported.empty()) {
|
if (!overhangs_unsupported.empty()) {
|
||||||
@ -421,7 +421,7 @@ void PerimeterGenerator::process()
|
|||||||
if (!bridgeable.empty()) {
|
if (!bridgeable.empty()) {
|
||||||
//simplify to avoid most of artefacts from printing lines.
|
//simplify to avoid most of artefacts from printing lines.
|
||||||
ExPolygons bridgeable_simplified;
|
ExPolygons bridgeable_simplified;
|
||||||
for (const ExPolygon &poly : bridgeable) {
|
for (const ExPolygon& poly : bridgeable) {
|
||||||
poly.simplify(perimeter_spacing / 2, &bridgeable_simplified);
|
poly.simplify(perimeter_spacing / 2, &bridgeable_simplified);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,16 +447,17 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// In case no perimeters are to be generated, loop_number will equal to -1.
|
// In case no perimeters are to be generated, loop_number will equal to -1.
|
||||||
std::vector<PerimeterGeneratorLoops> contours(loop_number+1); // depth => loops
|
std::vector<PerimeterGeneratorLoops> contours(loop_number + 1); // depth => loops
|
||||||
std::vector<PerimeterGeneratorLoops> holes(loop_number+1); // depth => loops
|
std::vector<PerimeterGeneratorLoops> holes(loop_number + 1); // depth => loops
|
||||||
ThickPolylines thin_walls;
|
ThickPolylines thin_walls;
|
||||||
|
ExPolygons no_last_gapfill;
|
||||||
// we loop one time more than needed in order to find gaps after the last perimeter was applied
|
// we loop one time more than needed in order to find gaps after the last perimeter was applied
|
||||||
for (int i = 0;; ++ i) { // outer loop is 0
|
for (int i = 0;; ++i) { // outer loop is 0
|
||||||
|
|
||||||
// We can add more perimeters if there are uncovered overhangs
|
// We can add more perimeters if there are uncovered overhangs
|
||||||
// improvement for future: find a way to add perimeters only where it's needed.
|
// improvement for future: find a way to add perimeters only where it's needed.
|
||||||
bool has_overhang = false;
|
bool has_overhang = false;
|
||||||
if ( this->config->extra_perimeters_overhangs && !last.empty() && !overhangs_unsupported.empty()) {
|
if (this->config->extra_perimeters_overhangs && !last.empty() && !overhangs_unsupported.empty()) {
|
||||||
overhangs_unsupported = intersection_ex(overhangs_unsupported, last, true);
|
overhangs_unsupported = intersection_ex(overhangs_unsupported, last, true);
|
||||||
if (overhangs_unsupported.size() > 0) {
|
if (overhangs_unsupported.size() > 0) {
|
||||||
//please don't stop adding perimeter yet.
|
//please don't stop adding perimeter yet.
|
||||||
@ -489,9 +490,9 @@ void PerimeterGenerator::process()
|
|||||||
(round_peri ? min_round_spacing : 3));
|
(round_peri ? min_round_spacing : 3));
|
||||||
|
|
||||||
// look for thin walls
|
// look for thin walls
|
||||||
if (this->config->thin_walls) {
|
if (this->config->thin_walls) {
|
||||||
// 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.
|
||||||
std::vector<float> divs = { 2.1f, 1.9f, 2.2f, 1.75f, 1.5f}; //don't go too far, it's not possible to print thin wall after that
|
std::vector<float> divs = { 2.1f, 1.9f, 2.2f, 1.75f, 1.5f }; //don't go too far, it's not possible to print thin wall after that
|
||||||
size_t idx_div = 0;
|
size_t idx_div = 0;
|
||||||
while (next_onion.size() > last.size() && idx_div < divs.size()) {
|
while (next_onion.size() > last.size() && idx_div < divs.size()) {
|
||||||
float div = divs[idx_div];
|
float div = divs[idx_div];
|
||||||
@ -509,7 +510,7 @@ void PerimeterGenerator::process()
|
|||||||
// the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width
|
// the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width
|
||||||
// (actually, something larger than that still may exist due to mitering or other causes)
|
// (actually, something larger than that still may exist due to mitering or other causes)
|
||||||
coord_t min_width = (coord_t)scale_(this->config->thin_walls_min_width.get_abs_value(this->ext_perimeter_flow.nozzle_diameter));
|
coord_t min_width = (coord_t)scale_(this->config->thin_walls_min_width.get_abs_value(this->ext_perimeter_flow.nozzle_diameter));
|
||||||
|
|
||||||
ExPolygons no_thin_zone = offset_ex(next_onion, double(ext_perimeter_width / 2), jtSquare);
|
ExPolygons no_thin_zone = offset_ex(next_onion, double(ext_perimeter_width / 2), jtSquare);
|
||||||
// medial axis requires non-overlapping geometry
|
// medial axis requires non-overlapping geometry
|
||||||
ExPolygons thin_zones = diff_ex(last, no_thin_zone, true);
|
ExPolygons thin_zones = diff_ex(last, no_thin_zone, true);
|
||||||
@ -517,7 +518,7 @@ void PerimeterGenerator::process()
|
|||||||
//a very little bit of overlap can be created here with other thin polygons, but it's more useful than worisome.
|
//a very little bit of overlap can be created here with other thin polygons, but it's more useful than worisome.
|
||||||
ExPolygons half_thins = offset_ex(thin_zones, double(-min_width / 2));
|
ExPolygons half_thins = offset_ex(thin_zones, double(-min_width / 2));
|
||||||
//simplify them
|
//simplify them
|
||||||
for (ExPolygon &half_thin : half_thins) {
|
for (ExPolygon& half_thin : half_thins) {
|
||||||
half_thin.remove_point_too_near((coord_t)SCALED_RESOLUTION);
|
half_thin.remove_point_too_near((coord_t)SCALED_RESOLUTION);
|
||||||
}
|
}
|
||||||
//we push the bits removed and put them into what we will use as our anchor
|
//we push the bits removed and put them into what we will use as our anchor
|
||||||
@ -526,7 +527,7 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
ExPolygons thins;
|
ExPolygons thins;
|
||||||
// compute a bit of overlap to anchor thin walls inside the print.
|
// compute a bit of overlap to anchor thin walls inside the print.
|
||||||
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, double(min_width / 2));
|
ExPolygons thin = offset_ex(half_thin, double(min_width / 2));
|
||||||
assert(thin.size() <= 1);
|
assert(thin.size() <= 1);
|
||||||
@ -535,15 +536,15 @@ void PerimeterGenerator::process()
|
|||||||
ExPolygons anchor = intersection_ex(offset_ex(half_thin, double(min_width / 2) +
|
ExPolygons anchor = intersection_ex(offset_ex(half_thin, double(min_width / 2) +
|
||||||
(float)(thin_walls_overlap), jtSquare), no_thin_zone, true);
|
(float)(thin_walls_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()) {
|
||||||
//be sure it's not too small to extrude reliably
|
//be sure it's not too small to extrude reliably
|
||||||
thin[0].remove_point_too_near((coord_t)SCALED_RESOLUTION);
|
thin[0].remove_point_too_near((coord_t)SCALED_RESOLUTION);
|
||||||
if (thin[0].area() > min_width*(ext_perimeter_width + ext_perimeter_spacing)) {
|
if (thin[0].area() > min_width * (ext_perimeter_width + ext_perimeter_spacing)) {
|
||||||
thins.push_back(thin[0]);
|
thins.push_back(thin[0]);
|
||||||
bound.remove_point_too_near((coord_t)SCALED_RESOLUTION);
|
bound.remove_point_too_near((coord_t)SCALED_RESOLUTION);
|
||||||
// the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop (*1.2 because of circles approx. and enlrgment from 'div')
|
// the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop (*1.2 because of circles approx. and enlrgment from 'div')
|
||||||
Slic3r::MedialAxis ma{ thin[0], (coord_t)((ext_perimeter_width + ext_perimeter_spacing)*1.2),
|
Slic3r::MedialAxis ma{ thin[0], (coord_t)((ext_perimeter_width + ext_perimeter_spacing) * 1.2),
|
||||||
min_width, coord_t(this->layer->height) };
|
min_width, coord_t(this->layer->height) };
|
||||||
ma.use_bounds(bound)
|
ma.use_bounds(bound)
|
||||||
.use_min_real_width((coord_t)scale_(this->ext_perimeter_flow.nozzle_diameter))
|
.use_min_real_width((coord_t)scale_(this->ext_perimeter_flow.nozzle_diameter))
|
||||||
@ -565,7 +566,7 @@ void PerimeterGenerator::process()
|
|||||||
(round_peri ? min_round_spacing : 3)));
|
(round_peri ? min_round_spacing : 3)));
|
||||||
else
|
else
|
||||||
next_onion = union_ex(next_onion, offset2_ex(diff_ex(last, thins, true),
|
next_onion = union_ex(next_onion, offset2_ex(diff_ex(last, thins, true),
|
||||||
-(float)((ext_perimeter_width / 2) + (ext_min_spacing / 4)),
|
-(float)((ext_perimeter_width / 2) + (ext_min_spacing / 4)),
|
||||||
(float)(ext_min_spacing / 4),
|
(float)(ext_min_spacing / 4),
|
||||||
(round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter),
|
(round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter),
|
||||||
(round_peri ? min_round_spacing : 3)));
|
(round_peri ? min_round_spacing : 3)));
|
||||||
@ -607,7 +608,7 @@ void PerimeterGenerator::process()
|
|||||||
new_area += expoly.area();
|
new_area += expoly.area();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<float> divs { 1.8f, 1.6f }; //don't over-extrude, so don't use divider >2
|
std::vector<float> divs{ 1.8f, 1.6f }; //don't over-extrude, so don't use divider >2
|
||||||
size_t idx_div = 0;
|
size_t idx_div = 0;
|
||||||
while ((next_onion.size() > no_thin_onion.size() || (new_area != 0 && last_area > new_area * 100)) && idx_div < divs.size()) {
|
while ((next_onion.size() > no_thin_onion.size() || (new_area != 0 && last_area > new_area * 100)) && idx_div < divs.size()) {
|
||||||
float div = divs[idx_div];
|
float div = divs[idx_div];
|
||||||
@ -616,7 +617,7 @@ void PerimeterGenerator::process()
|
|||||||
last,
|
last,
|
||||||
-(float)(good_spacing + (min_spacing / div) - 1),
|
-(float)(good_spacing + (min_spacing / div) - 1),
|
||||||
+(float)((min_spacing / div) - 1));
|
+(float)((min_spacing / div) - 1));
|
||||||
if (next_onion.size() > next_onion_secondTry.size() * 1.2 && next_onion.size() > next_onion_secondTry.size() + 2) {
|
if (next_onion.size() > next_onion_secondTry.size() * 1.2 && next_onion.size() > next_onion_secondTry.size() + 2) {
|
||||||
// don't get it if it creates too many
|
// don't get it if it creates too many
|
||||||
next_onion = next_onion_secondTry;
|
next_onion = next_onion_secondTry;
|
||||||
} else if (next_onion.size() > next_onion_secondTry.size() || last_area > new_area * 100) {
|
} else if (next_onion.size() > next_onion_secondTry.size() || last_area > new_area * 100) {
|
||||||
@ -636,22 +637,24 @@ void PerimeterGenerator::process()
|
|||||||
} else {
|
} else {
|
||||||
// If "overlapping_perimeters" is enabled, this paths will be entered, which
|
// If "overlapping_perimeters" is enabled, this paths will be entered, which
|
||||||
// leads to overflows, as in prusa3d/Slic3r GH #32
|
// leads to overflows, as in prusa3d/Slic3r GH #32
|
||||||
next_onion = offset_ex(last, double( - good_spacing),
|
next_onion = offset_ex(last, double(-good_spacing),
|
||||||
(round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter),
|
(round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter),
|
||||||
(round_peri ? min_round_spacing : 3));
|
(round_peri ? min_round_spacing : 3));
|
||||||
}
|
}
|
||||||
// look for gaps
|
// look for gaps
|
||||||
if (this->config->gap_fill
|
if (this->config->gap_fill
|
||||||
//check if we are going to have an other perimeter
|
//check if we are going to have an other perimeter
|
||||||
&& (i <= loop_number || has_overhang || next_onion.empty() || (this->config->gap_fill_last.value && i == loop_number+1)))
|
&& (i <= loop_number || has_overhang || next_onion.empty() || (this->config->gap_fill_last.value && i == loop_number + 1))) {
|
||||||
// not using safety offset here would "detect" very narrow gaps
|
// not using safety offset here would "detect" very narrow gaps
|
||||||
// (but still long enough to escape the area threshold) that gap fill
|
// (but still long enough to escape the area threshold) that gap fill
|
||||||
// won't be able to fill but we'd still remove from infill area
|
// won't be able to fill but we'd still remove from infill area
|
||||||
|
no_last_gapfill = offset_ex(next_onion, 0.5f * good_spacing + 10,
|
||||||
|
(round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter),
|
||||||
|
(round_peri ? min_round_spacing : 3));
|
||||||
append(gaps, diff_ex(
|
append(gaps, diff_ex(
|
||||||
offset(last, -0.5f * gap_fill_spacing),
|
offset_ex(last, -0.5f * gap_fill_spacing),
|
||||||
offset(next_onion, 0.5f * good_spacing + 10,
|
no_last_gapfill)); // safety offset
|
||||||
(round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter),
|
}
|
||||||
(round_peri ? min_round_spacing : 3)))); // safety offset
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_onion.empty()) {
|
if (next_onion.empty()) {
|
||||||
@ -671,19 +674,19 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const ExPolygon &expolygon : next_onion) {
|
for (const ExPolygon& expolygon : next_onion) {
|
||||||
//TODO: add width here to allow variable width (if we want to extrude a sightly bigger perimeter, see thin wall)
|
//TODO: add width here to allow variable width (if we want to extrude a sightly bigger perimeter, see thin wall)
|
||||||
contours[i].emplace_back(expolygon.contour, i, true, has_steep_overhang);
|
contours[i].emplace_back(expolygon.contour, i, true, has_steep_overhang);
|
||||||
if (! expolygon.holes.empty()) {
|
if (!expolygon.holes.empty()) {
|
||||||
holes[i].reserve(holes[i].size() + expolygon.holes.size());
|
holes[i].reserve(holes[i].size() + expolygon.holes.size());
|
||||||
for (const Polygon &hole : expolygon.holes)
|
for (const Polygon& hole : expolygon.holes)
|
||||||
holes[i].emplace_back(hole, i, false, has_steep_overhang);
|
holes[i].emplace_back(hole, i, false, has_steep_overhang);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last = std::move(next_onion);
|
last = std::move(next_onion);
|
||||||
|
|
||||||
//store surface for top infill if only_one_perimeter_top
|
//store surface for top infill if only_one_perimeter_top
|
||||||
if(i==0 && (config->only_one_perimeter_top && this->upper_slices != NULL)){
|
if (i == 0 && (config->only_one_perimeter_top && this->upper_slices != NULL)) {
|
||||||
if (this->config->only_one_perimeter_top_other_algo) {
|
if (this->config->only_one_perimeter_top_other_algo) {
|
||||||
//split the polygons with top/not_top
|
//split the polygons with top/not_top
|
||||||
//get the offset from solid surface anchor
|
//get the offset from solid surface anchor
|
||||||
@ -850,14 +853,14 @@ void PerimeterGenerator::process()
|
|||||||
|
|
||||||
// nest loops: holes first
|
// nest loops: holes first
|
||||||
for (int d = 0; d <= loop_number; ++d) {
|
for (int d = 0; d <= loop_number; ++d) {
|
||||||
PerimeterGeneratorLoops &holes_d = holes[d];
|
PerimeterGeneratorLoops& holes_d = holes[d];
|
||||||
// loop through all holes having depth == d
|
// loop through all holes having depth == d
|
||||||
for (int i = 0; i < (int)holes_d.size(); ++i) {
|
for (int i = 0; i < (int)holes_d.size(); ++i) {
|
||||||
const PerimeterGeneratorLoop &loop = holes_d[i];
|
const PerimeterGeneratorLoop& loop = holes_d[i];
|
||||||
// find the hole loop that contains this one, if any
|
// find the hole loop that contains this one, if any
|
||||||
for (int t = d+1; t <= loop_number; ++t) {
|
for (int t = d + 1; t <= loop_number; ++t) {
|
||||||
for (int j = 0; j < (int)holes[t].size(); ++j) {
|
for (int j = 0; j < (int)holes[t].size(); ++j) {
|
||||||
PerimeterGeneratorLoop &candidate_parent = holes[t][j];
|
PerimeterGeneratorLoop& candidate_parent = holes[t][j];
|
||||||
if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
|
if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
|
||||||
candidate_parent.children.push_back(loop);
|
candidate_parent.children.push_back(loop);
|
||||||
holes_d.erase(holes_d.begin() + i);
|
holes_d.erase(holes_d.begin() + i);
|
||||||
@ -869,7 +872,7 @@ void PerimeterGenerator::process()
|
|||||||
// if no hole contains this hole, find the contour loop that contains it
|
// if no hole contains this hole, find the contour loop that contains it
|
||||||
for (int t = loop_number; t >= 0; --t) {
|
for (int t = loop_number; t >= 0; --t) {
|
||||||
for (int j = 0; j < (int)contours[t].size(); ++j) {
|
for (int j = 0; j < (int)contours[t].size(); ++j) {
|
||||||
PerimeterGeneratorLoop &candidate_parent = contours[t][j];
|
PerimeterGeneratorLoop& candidate_parent = contours[t][j];
|
||||||
if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
|
if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
|
||||||
candidate_parent.children.push_back(loop);
|
candidate_parent.children.push_back(loop);
|
||||||
holes_d.erase(holes_d.begin() + i);
|
holes_d.erase(holes_d.begin() + i);
|
||||||
@ -878,19 +881,19 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NEXT_LOOP: ;
|
NEXT_LOOP:;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// nest contour loops
|
// nest contour loops
|
||||||
for (int d = loop_number; d >= 1; --d) {
|
for (int d = loop_number; d >= 1; --d) {
|
||||||
PerimeterGeneratorLoops &contours_d = contours[d];
|
PerimeterGeneratorLoops& contours_d = contours[d];
|
||||||
// loop through all contours having depth == d
|
// loop through all contours having depth == d
|
||||||
for (int i = 0; i < (int)contours_d.size(); ++i) {
|
for (int i = 0; i < (int)contours_d.size(); ++i) {
|
||||||
const PerimeterGeneratorLoop &loop = contours_d[i];
|
const PerimeterGeneratorLoop& loop = contours_d[i];
|
||||||
// find the contour loop that contains it
|
// find the contour loop that contains it
|
||||||
for (int t = d - 1; t >= 0; -- t) {
|
for (int t = d - 1; t >= 0; --t) {
|
||||||
for (size_t j = 0; j < contours[t].size(); ++ j) {
|
for (size_t j = 0; j < contours[t].size(); ++j) {
|
||||||
PerimeterGeneratorLoop &candidate_parent = contours[t][j];
|
PerimeterGeneratorLoop& candidate_parent = contours[t][j];
|
||||||
if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
|
if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
|
||||||
candidate_parent.children.push_back(loop);
|
candidate_parent.children.push_back(loop);
|
||||||
contours_d.erase(contours_d.begin() + i);
|
contours_d.erase(contours_d.begin() + i);
|
||||||
@ -899,7 +902,7 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NEXT_CONTOUR: ;
|
NEXT_CONTOUR:;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// at this point, all loops should be in contours[0] (= contours.front() )
|
// at this point, all loops should be in contours[0] (= contours.front() )
|
||||||
@ -907,7 +910,7 @@ void PerimeterGenerator::process()
|
|||||||
ExtrusionEntityCollection entities;
|
ExtrusionEntityCollection entities;
|
||||||
if (config->perimeter_loop.value) {
|
if (config->perimeter_loop.value) {
|
||||||
//onlyone_perimter = >fusion all perimeterLoops
|
//onlyone_perimter = >fusion all perimeterLoops
|
||||||
for (PerimeterGeneratorLoop &loop : contours.front()) {
|
for (PerimeterGeneratorLoop& loop : contours.front()) {
|
||||||
ExtrusionLoop extr_loop = this->_traverse_and_join_loops(loop, get_all_Childs(loop), loop.polygon.points.front());
|
ExtrusionLoop extr_loop = this->_traverse_and_join_loops(loop, get_all_Childs(loop), loop.polygon.points.front());
|
||||||
//ExtrusionLoop extr_loop = this->_traverse_and_join_loops_old(loop, loop.polygon.points.front(), true);
|
//ExtrusionLoop extr_loop = this->_traverse_and_join_loops_old(loop, loop.polygon.points.front(), true);
|
||||||
extr_loop.paths.back().polyline.points.push_back(extr_loop.paths.front().polyline.points.front());
|
extr_loop.paths.back().polyline.points.push_back(extr_loop.paths.front().polyline.points.front());
|
||||||
@ -917,7 +920,7 @@ void PerimeterGenerator::process()
|
|||||||
// append thin walls
|
// append thin walls
|
||||||
if (!thin_walls.empty()) {
|
if (!thin_walls.empty()) {
|
||||||
ExtrusionEntityCollection tw = thin_variable_width
|
ExtrusionEntityCollection tw = thin_variable_width
|
||||||
(thin_walls, erThinWall, this->ext_perimeter_flow);
|
(thin_walls, erThinWall, this->ext_perimeter_flow);
|
||||||
|
|
||||||
entities.append(tw.entities);
|
entities.append(tw.entities);
|
||||||
thin_walls.clear();
|
thin_walls.clear();
|
||||||
@ -932,7 +935,7 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if brim will be printed, reverse the order of perimeters so that
|
// if brim will be printed, reverse the order of perimeters so that
|
||||||
// we continue inwards after having finished the brim
|
// we continue inwards after having finished the brim
|
||||||
// TODO: add test for perimeter order
|
// TODO: add test for perimeter order
|
||||||
@ -988,11 +991,13 @@ void PerimeterGenerator::process()
|
|||||||
// append perimeters for this slice as a collection
|
// append perimeters for this slice as a collection
|
||||||
if (!entities.empty()) {
|
if (!entities.empty()) {
|
||||||
//move it, to avoid to clone evrything and then delete it
|
//move it, to avoid to clone evrything and then delete it
|
||||||
this->loops->entities.emplace_back( new ExtrusionEntityCollection(std::move(entities)));
|
this->loops->entities.emplace_back(new ExtrusionEntityCollection(std::move(entities)));
|
||||||
}
|
}
|
||||||
} // for each loop of an island
|
} // for each loop of an island
|
||||||
|
|
||||||
// fill gaps
|
// fill gaps
|
||||||
|
ExPolygons gaps_ex;
|
||||||
|
ExPolygons gap_srf;
|
||||||
if (!gaps.empty()) {
|
if (!gaps.empty()) {
|
||||||
// collapse
|
// collapse
|
||||||
double min = 0.2 * perimeter_width * (1 - INSET_OVERLAP_TOLERANCE);
|
double min = 0.2 * perimeter_width * (1 - INSET_OVERLAP_TOLERANCE);
|
||||||
@ -1001,11 +1006,10 @@ void PerimeterGenerator::process()
|
|||||||
double max = 2.2 * perimeter_spacing;
|
double max = 2.2 * perimeter_spacing;
|
||||||
//remove areas that are too big (shouldn't occur...)
|
//remove areas that are too big (shouldn't occur...)
|
||||||
ExPolygons too_big = offset2_ex(gaps, double(-max / 2), double(+max / 2));
|
ExPolygons too_big = offset2_ex(gaps, double(-max / 2), double(+max / 2));
|
||||||
ExPolygons gaps_ex_to_test = too_big.empty()? gaps : diff_ex(gaps,too_big,true);
|
ExPolygons gaps_ex_to_test = too_big.empty() ? gaps : diff_ex(gaps, too_big, true);
|
||||||
ExPolygons gaps_ex;
|
const double minarea = scale_(scale_(this->config->gap_fill_min_area.get_abs_value(unscaled((double)perimeter_width) * unscaled((double)perimeter_width))));
|
||||||
const double minarea = scale_(scale_(this->config->gap_fill_min_area.get_abs_value(unscaled((double)perimeter_width)*unscaled((double)perimeter_width))));
|
|
||||||
// check each gapfill area to see if it's printable.
|
// check each gapfill area to see if it's printable.
|
||||||
for (const ExPolygon &expoly : gaps_ex_to_test) {
|
for (const ExPolygon& expoly : gaps_ex_to_test) {
|
||||||
//remove too small gaps that are too hard to fill.
|
//remove too small gaps that are too hard to fill.
|
||||||
//ie one that are smaller than an extrusion with width of min and a length of max.
|
//ie one that are smaller than an extrusion with width of min and a length of max.
|
||||||
if (expoly.area() > minarea) {
|
if (expoly.area() > minarea) {
|
||||||
@ -1026,13 +1030,13 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//maybe some areas are a just bit too thin, try with just a little more offset to remove them.
|
//maybe some areas are a just bit too thin, try with just a little more offset to remove them.
|
||||||
ExPolygons expoly_after_shrink_test2 = offset_ex(ExPolygons{ expoly }, double(-min *0.8));
|
ExPolygons expoly_after_shrink_test2 = offset_ex(ExPolygons{ expoly }, double(-min * 0.8));
|
||||||
for (int i = 0; i < expoly_after_shrink_test2.size(); i++) {
|
for (int i = 0; i < expoly_after_shrink_test2.size(); i++) {
|
||||||
if (expoly_after_shrink_test2[i].area() < (SCALED_EPSILON * SCALED_EPSILON * 4)) {
|
if (expoly_after_shrink_test2[i].area() < (SCALED_EPSILON * SCALED_EPSILON * 4)) {
|
||||||
expoly_after_shrink_test2.erase(expoly_after_shrink_test2.begin() + i);
|
expoly_after_shrink_test2.erase(expoly_after_shrink_test2.begin() + i);
|
||||||
i--;
|
i--;
|
||||||
|
|
||||||
}else{
|
} else {
|
||||||
ExPolygons wider = offset_ex(ExPolygons{ expoly_after_shrink_test2[i] }, min * 0.5);
|
ExPolygons wider = offset_ex(ExPolygons{ expoly_after_shrink_test2[i] }, min * 0.5);
|
||||||
if (wider.empty() || wider[0].area() < minarea) {
|
if (wider.empty() || wider[0].area() < minarea) {
|
||||||
expoly_after_shrink_test2.erase(expoly_after_shrink_test2.begin() + i);
|
expoly_after_shrink_test2.erase(expoly_after_shrink_test2.begin() + i);
|
||||||
@ -1041,7 +1045,7 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//it's better if there are significantly less extrusions
|
//it's better if there are significantly less extrusions
|
||||||
if (expoly_after_shrink_test.size()/1.42 > expoly_after_shrink_test2.size()) {
|
if (expoly_after_shrink_test.size() / 1.42 > expoly_after_shrink_test2.size()) {
|
||||||
expoly_after_shrink_test2 = offset_ex(expoly_after_shrink_test2, double(min * 0.8));
|
expoly_after_shrink_test2 = offset_ex(expoly_after_shrink_test2, double(min * 0.8));
|
||||||
//insert with move instead of copy
|
//insert with move instead of copy
|
||||||
std::move(expoly_after_shrink_test2.begin(), expoly_after_shrink_test2.end(), std::back_inserter(gaps_ex));
|
std::move(expoly_after_shrink_test2.begin(), expoly_after_shrink_test2.end(), std::back_inserter(gaps_ex));
|
||||||
@ -1057,12 +1061,12 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
// create lines from the area
|
// create lines from the area
|
||||||
ThickPolylines polylines;
|
ThickPolylines polylines;
|
||||||
for (const ExPolygon &ex : gaps_ex) {
|
for (const ExPolygon& ex : gaps_ex) {
|
||||||
MedialAxis{ ex, coord_t(max*1.1), coord_t(min), coord_t(this->layer->height) }.build(polylines);
|
MedialAxis{ ex, coord_t(max * 1.1), coord_t(min), coord_t(this->layer->height) }.build(polylines);
|
||||||
}
|
}
|
||||||
// create extrusion from lines
|
// create extrusion from lines
|
||||||
if (!polylines.empty()) {
|
if (!polylines.empty()) {
|
||||||
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines,
|
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines,
|
||||||
erGapFill, this->solid_infill_flow);
|
erGapFill, this->solid_infill_flow);
|
||||||
this->gap_fill->append(gap_fill.entities);
|
this->gap_fill->append(gap_fill.entities);
|
||||||
/* Make sure we don't infill narrow parts that are already gap-filled
|
/* Make sure we don't infill narrow parts that are already gap-filled
|
||||||
@ -1071,9 +1075,11 @@ void PerimeterGenerator::process()
|
|||||||
are not subtracted from fill surfaces (they might be too short gaps
|
are not subtracted from fill surfaces (they might be too short gaps
|
||||||
that medial axis skips but infill might join with other infill regions
|
that medial axis skips but infill might join with other infill regions
|
||||||
and use zigzag). */
|
and use zigzag). */
|
||||||
//FIXME Vojtech: This grows by a rounded extrusion width, not by line spacing,
|
// get clean surface of gap
|
||||||
// therefore it may cover the area, but no the volume.
|
gap_srf = union_ex(offset(gap_fill.polygons_covered_by_width(float(SCALED_EPSILON) / 10), float(SCALED_EPSILON / 2)));
|
||||||
last = diff_ex(to_polygons(last), gap_fill.polygons_covered_by_width(10.f));
|
// intersection to ignore the bits of gapfill tha may be over infill, as it's epsilon and there may be some voids here anyway.
|
||||||
|
gap_srf = intersection_ex(gap_srf, gaps_ex);
|
||||||
|
// the diff(last, gap) will be done after, as we have to keep the last un-gapped to avoid unneeded gap/infill offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: if a gapfill extrusion is a loop and with width always >= perimeter width then change the type to perimeter and put it at the right place in the loops vector.
|
//TODO: if a gapfill extrusion is a loop and with width always >= perimeter width then change the type to perimeter and put it at the right place in the loops vector.
|
||||||
@ -1082,36 +1088,59 @@ void PerimeterGenerator::process()
|
|||||||
// we offset by half the perimeter spacing (to get to the actual infill boundary)
|
// we offset by half the perimeter spacing (to get to the actual infill boundary)
|
||||||
// and then we offset back and forth by half the infill spacing to only consider the
|
// and then we offset back and forth by half the infill spacing to only consider the
|
||||||
// non-collapsing regions
|
// non-collapsing regions
|
||||||
coord_t inset =
|
coord_t inset =
|
||||||
(loop_number < 0) ? 0 :
|
(loop_number < 0) ? 0 :
|
||||||
(loop_number == 0) ?
|
(loop_number == 0) ?
|
||||||
// one loop
|
// one loop
|
||||||
ext_perimeter_spacing / 2 :
|
ext_perimeter_spacing / 2 :
|
||||||
// two or more loops?
|
// two or more loops?
|
||||||
perimeter_spacing / 2;
|
perimeter_spacing / 2;
|
||||||
// only apply infill overlap if we actually have one perimeter
|
// only apply infill overlap if we actually have one perimeter
|
||||||
if (inset == 0) {
|
if (inset == 0) {
|
||||||
infill_peri_overlap = 0;
|
infill_peri_overlap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//remove gapfill from last
|
||||||
|
ExPolygons last_no_gaps = (gap_srf.empty()) ? last : diff_ex(last, gap_srf);
|
||||||
|
|
||||||
// simplify infill contours according to resolution
|
// simplify infill contours according to resolution
|
||||||
Polygons not_filled_p;
|
Polygons not_filled_p;
|
||||||
for (ExPolygon &ex : last)
|
for (ExPolygon& ex : last_no_gaps)
|
||||||
ex.simplify_p(SCALED_RESOLUTION, ¬_filled_p);
|
ex.simplify_p(SCALED_RESOLUTION, ¬_filled_p);
|
||||||
ExPolygons not_filled_exp = union_ex(not_filled_p);
|
ExPolygons not_filled_exp = union_ex(not_filled_p);
|
||||||
// collapse too narrow infill areas
|
// collapse too narrow infill areas
|
||||||
coord_t min_perimeter_infill_spacing = (coord_t)( solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE) );
|
coord_t min_perimeter_infill_spacing = (coord_t)(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
||||||
// append infill areas to fill_surfaces
|
ExPolygons infill_exp;
|
||||||
//auto it_surf = this->fill_surfaces->surfaces.end();
|
//special branch if gap : don't inset away from gaps!
|
||||||
ExPolygons infill_exp = offset2_ex(not_filled_exp,
|
if (gap_srf.empty())
|
||||||
double(-inset - min_perimeter_infill_spacing / 2 + infill_peri_overlap - infill_gap),
|
infill_exp = offset2_ex(not_filled_exp,
|
||||||
double(min_perimeter_infill_spacing / 2));
|
double(-inset - min_perimeter_infill_spacing / 2 + infill_peri_overlap - infill_gap),
|
||||||
|
double(min_perimeter_infill_spacing / 2));
|
||||||
|
else {
|
||||||
|
//store the infill_exp but not offseted, it will be used as a clip to remove the gapfill portion
|
||||||
|
const ExPolygons infill_exp_no_gap = offset2_ex(not_filled_exp,
|
||||||
|
double(-inset - min_perimeter_infill_spacing / 2 + infill_peri_overlap - infill_gap),
|
||||||
|
double(inset + min_perimeter_infill_spacing / 2 - infill_peri_overlap + infill_gap));
|
||||||
|
//redo the same as not_filled_exp but with last instead of last_no_gaps
|
||||||
|
not_filled_p.clear();
|
||||||
|
for (ExPolygon& ex : last)
|
||||||
|
ex.simplify_p(SCALED_RESOLUTION, ¬_filled_p);
|
||||||
|
not_filled_exp = union_ex(not_filled_p);
|
||||||
|
infill_exp = offset2_ex(not_filled_exp,
|
||||||
|
double(-inset - min_perimeter_infill_spacing / 2 + infill_peri_overlap - infill_gap),
|
||||||
|
double(min_perimeter_infill_spacing / 2));
|
||||||
|
// intersect(growth(last-gap) , last), so you have the (last - small gap) but without voids betweeng gap & last
|
||||||
|
infill_exp = intersection_ex(infill_exp, infill_exp_no_gap);
|
||||||
|
}
|
||||||
|
|
||||||
//if any top_fills, grow them by ext_perimeter_spacing/2 to have the real un-anchored fill
|
//if any top_fills, grow them by ext_perimeter_spacing/2 to have the real un-anchored fill
|
||||||
ExPolygons top_infill_exp = intersection_ex(fill_clip, offset_ex(top_fills, double(ext_perimeter_spacing / 2)));
|
ExPolygons top_infill_exp = intersection_ex(fill_clip, offset_ex(top_fills, double(ext_perimeter_spacing / 2)));
|
||||||
if (!top_fills.empty()) {
|
if (!top_fills.empty()) {
|
||||||
infill_exp = union_ex(infill_exp, offset_ex(top_infill_exp, double(infill_peri_overlap)));
|
infill_exp = union_ex(infill_exp, offset_ex(top_infill_exp, double(infill_peri_overlap)));
|
||||||
}
|
}
|
||||||
|
// append infill areas to fill_surfaces
|
||||||
this->fill_surfaces->append(infill_exp, stPosInternal | stDensSparse);
|
this->fill_surfaces->append(infill_exp, stPosInternal | stDensSparse);
|
||||||
|
|
||||||
if (infill_peri_overlap != 0) {
|
if (infill_peri_overlap != 0) {
|
||||||
ExPolygons polyWithoutOverlap;
|
ExPolygons polyWithoutOverlap;
|
||||||
if (min_perimeter_infill_spacing / 2 > infill_peri_overlap)
|
if (min_perimeter_infill_spacing / 2 > infill_peri_overlap)
|
||||||
@ -1127,18 +1156,19 @@ void PerimeterGenerator::process()
|
|||||||
polyWithoutOverlap = union_ex(polyWithoutOverlap, top_infill_exp);
|
polyWithoutOverlap = union_ex(polyWithoutOverlap, top_infill_exp);
|
||||||
}
|
}
|
||||||
this->fill_no_overlap.insert(this->fill_no_overlap.end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end());
|
this->fill_no_overlap.insert(this->fill_no_overlap.end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end());
|
||||||
/*{
|
/*{
|
||||||
std::stringstream stri;
|
static int isaqsdsdfsdfqzfn = 0;
|
||||||
stri << this->layer->id() << "_2_end_makeperimeter_" << this->layer->id() << ".svg";
|
std::stringstream stri;
|
||||||
SVG svg(stri.str());
|
stri << this->layer->id() << "_2_end_makeperimeter_" << isaqsdsdfsdfqzfn++ << ".svg";
|
||||||
svg.draw(to_polylines(infill_exp), "blue");
|
SVG svg(stri.str());
|
||||||
svg.draw(to_polylines(fill_no_overlap), "cyan");
|
svg.draw(to_polylines(infill_exp), "blue");
|
||||||
svg.draw(to_polylines(not_filled_exp), "green");
|
svg.draw(to_polylines(fill_no_overlap), "cyan");
|
||||||
svg.draw(to_polylines(last), "yellow");
|
svg.draw(to_polylines(not_filled_exp), "green");
|
||||||
svg.draw(to_polylines(offset_ex(fill_clip, ext_perimeter_spacing / 2)), "yellow");
|
svg.draw(to_polylines(last_no_gaps), "yellow");
|
||||||
svg.draw(to_polylines(top_infill_exp), "orange");
|
svg.draw(to_polylines(offset_ex(fill_clip, ext_perimeter_spacing / 2)), "brown");
|
||||||
svg.Close();
|
svg.draw(to_polylines(top_infill_exp), "orange");
|
||||||
}*/
|
svg.Close();
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
} // for each island
|
} // for each island
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user