Fix int overflow, reduces amount of bridging substantially, improve code description,

extend bridge anchors when anchoring to solid surfaces on lower layers
This commit is contained in:
PavelMikus 2023-03-17 17:13:57 +01:00
parent 16024b12c5
commit 79adb72a25

View File

@ -1618,7 +1618,8 @@ void PrintObject::bridge_over_infill()
if (layer->lower_layer == nullptr) { if (layer->lower_layer == nullptr) {
continue; continue;
} }
auto spacing = layer->regions().front()->flow(frSolidInfill).scaled_spacing(); double spacing = layer->regions().front()->flow(frSolidInfill).scaled_spacing();
// unsupported area will serve as a filter for polygons worth bridging.
Polygons unsupported_area; Polygons unsupported_area;
Polygons lower_layer_solids; Polygons lower_layer_solids;
bool contains_only_lightning = true; bool contains_only_lightning = true;
@ -1627,6 +1628,7 @@ void PrintObject::bridge_over_infill()
contains_only_lightning = false; contains_only_lightning = false;
} }
Polygons fill_polys = to_polygons(region->fill_expolygons()); Polygons fill_polys = to_polygons(region->fill_expolygons());
// initially consider the whole layer unsupported, but also gather solid layers to later cut off supported parts
unsupported_area.insert(unsupported_area.end(), fill_polys.begin(), fill_polys.end()); unsupported_area.insert(unsupported_area.end(), fill_polys.begin(), fill_polys.end());
for (const Surface &surface : region->fill_surfaces()) { for (const Surface &surface : region->fill_surfaces()) {
if (surface.surface_type != stInternal || region->region().config().fill_density.value == 100) { if (surface.surface_type != stInternal || region->region().config().fill_density.value == 100) {
@ -1636,25 +1638,30 @@ void PrintObject::bridge_over_infill()
} }
} }
unsupported_area = closing(unsupported_area, SCALED_EPSILON); unsupported_area = closing(unsupported_area, SCALED_EPSILON);
// By expanding the lower layer solids, we avoid making bridges from the tiny internal overhangs that are (very likely) supported by previous layer solids
lower_layer_solids = expand(lower_layer_solids, 4 * spacing); // NOTE that we cannot filter out polygons worth bridging by their area, because sometimes there is a very small internal island that will grow into large hole
unsupported_area = shrink(unsupported_area, 4 * spacing); lower_layer_solids = expand(lower_layer_solids, 3 * spacing);
// By shrinking the unsupported area, we avoid making bridges from narrow ensuring region along perimeters.
unsupported_area = shrink(unsupported_area, 3 * spacing);
unsupported_area = diff(unsupported_area, lower_layer_solids); unsupported_area = diff(unsupported_area, lower_layer_solids);
for (const LayerRegion *region : layer->regions()) { for (const LayerRegion *region : layer->regions()) {
SurfacesPtr region_internal_solids = region->fill_surfaces().filter_by_type(stInternalSolid); SurfacesPtr region_internal_solids = region->fill_surfaces().filter_by_type(stInternalSolid);
for (const Surface *s : region_internal_solids) { for (const Surface *s : region_internal_solids) {
Polygons unsupported = intersection(to_polygons(s->expolygon), unsupported_area); Polygons unsupported = intersection(to_polygons(s->expolygon), unsupported_area);
// The following flag marks those surfaces, which overlap with unuspported area, but at least part of them is supported.
// These regions can be filtered by area, because they for sure are touching solids on lower layers, and it does not make sense to bridge their tiny overhangs
bool partially_supported = area(unsupported) < area(to_polygons(s->expolygon)) - EPSILON; bool partially_supported = area(unsupported) < area(to_polygons(s->expolygon)) - EPSILON;
if (!unsupported.empty() && (!partially_supported || area(unsupported) > 5 * 5 * spacing * spacing)) { if (!unsupported.empty() && (!partially_supported || area(unsupported) > 3 * 3 * spacing * spacing)) {
Polygons worth_bridging = intersection(to_polygons(s->expolygon), expand(unsupported, 5 * spacing)); Polygons worth_bridging = intersection(to_polygons(s->expolygon), expand(unsupported, 4 * spacing));
// after we extracted the part worth briding, we go over the leftovers and merge the tiny ones back, to not brake the surface too much
for (const Polygon& p : diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))) { for (const Polygon& p : diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))) {
auto area = p.area(); double area = p.area();
if (area < spacing * scale_(12.0) && area > spacing * spacing) { if (area < spacing * scale_(12.0) && area > spacing * spacing) {
worth_bridging.push_back(p); worth_bridging.push_back(p);
} }
} }
worth_bridging = intersection(closing(worth_bridging, 2 * spacing), s->expolygon); worth_bridging = intersection(closing(worth_bridging, SCALED_EPSILON), s->expolygon);
candidate_surfaces.push_back(CandidateSurface(s, lidx, worth_bridging, region, 0, contains_only_lightning)); candidate_surfaces.push_back(CandidateSurface(s, lidx, worth_bridging, region, 0, contains_only_lightning));
#ifdef DEBUG_BRIDGE_OVER_INFILL #ifdef DEBUG_BRIDGE_OVER_INFILL
@ -1663,7 +1670,7 @@ void PrintObject::bridge_over_infill()
to_lines(unsupported_area)); to_lines(unsupported_area));
#endif #endif
#ifdef DEBUG_BRIDGE_OVER_INFILL #ifdef DEBUG_BRIDGE_OVER_INFILL
debug_draw(std::to_string(lidx) + "_candidate_processing_" + std::to_string(area(s->expolygon)), debug_draw(std::to_string(lidx) + "_candidate_processing_" + std::to_string(area(unsupported)),
to_lines(unsupported), to_lines(intersection(to_polygons(s->expolygon), expand(unsupported, 5 * spacing))), to_lines(unsupported), to_lines(intersection(to_polygons(s->expolygon), expand(unsupported, 5 * spacing))),
to_lines(diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))), to_lines(diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))),
to_lines(unsupported_area)); to_lines(unsupported_area));
@ -1728,15 +1735,15 @@ void PrintObject::bridge_over_infill()
layer_area_covered_by_candidates[pair.first] = {}; layer_area_covered_by_candidates[pair.first] = {};
} }
// prepare inflated filter for each candidate on each layer. layers will be put into single thread cluster if they are close to each other (z-axis-wise)
// and if the inflated AABB polygons overlap somewhere
tbb::parallel_for(tbb::blocked_range<size_t>(0, layers_with_candidates.size()), [&layers_with_candidates, &surfaces_by_layer, tbb::parallel_for(tbb::blocked_range<size_t>(0, layers_with_candidates.size()), [&layers_with_candidates, &surfaces_by_layer,
&layer_area_covered_by_candidates]( &layer_area_covered_by_candidates](
tbb::blocked_range<size_t> r) { tbb::blocked_range<size_t> r) {
for (size_t job_idx = r.begin(); job_idx < r.end(); job_idx++) { for (size_t job_idx = r.begin(); job_idx < r.end(); job_idx++) {
size_t lidx = layers_with_candidates[job_idx]; size_t lidx = layers_with_candidates[job_idx];
for (const auto &candidate : surfaces_by_layer.at(lidx)) { for (const auto &candidate : surfaces_by_layer.at(lidx)) {
Polygon candiate_inflated_aabb = get_extents(candidate.new_polys) Polygon candiate_inflated_aabb = get_extents(candidate.new_polys).inflated(scale_(7)).polygon();
.inflated(candidate.region->flow(frSolidInfill, true).scaled_spacing() * 5)
.polygon();
layer_area_covered_by_candidates.at(lidx) = union_(layer_area_covered_by_candidates.at(lidx), layer_area_covered_by_candidates.at(lidx) = union_(layer_area_covered_by_candidates.at(lidx),
Polygons{candiate_inflated_aabb}); Polygons{candiate_inflated_aabb});
} }
@ -2088,13 +2095,13 @@ void PrintObject::bridge_over_infill()
} }
} }
deep_infill_area = expand(deep_infill_area, spacing); deep_infill_area = expand(deep_infill_area, spacing * 1.5);
// Now gather expansion polygons - internal infill on current layer, from which we can cut off anchors // Now gather expansion polygons - internal infill on current layer, from which we can cut off anchors
Polygons expansion_area; Polygons expansion_area;
Polygons total_fill_area; Polygons total_fill_area;
for (const LayerRegion *region : layer->regions()) { for (const LayerRegion *region : layer->regions()) {
Polygons internal_polys = to_polygons(region->fill_surfaces().filter_by_type(stInternal)); Polygons internal_polys = to_polygons(region->fill_surfaces().filter_by_types({stInternal, stInternalSolid}));
expansion_area.insert(expansion_area.end(), internal_polys.begin(), internal_polys.end()); expansion_area.insert(expansion_area.end(), internal_polys.begin(), internal_polys.end());
Polygons fill_polys = to_polygons(region->fill_expolygons()); Polygons fill_polys = to_polygons(region->fill_expolygons());
total_fill_area.insert(total_fill_area.end(), fill_polys.begin(), fill_polys.end()); total_fill_area.insert(total_fill_area.end(), fill_polys.begin(), fill_polys.end());