mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 21:41:59 +08:00
Improve performance of bridge over infill algorithm for very noisy/textured top surfaces
improve bridging direction unification when briding areas start overlapping
This commit is contained in:
parent
47aacbdc5e
commit
3a08097cd2
@ -1651,7 +1651,8 @@ 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
|
// By expanding the lower layer solids, we avoid making bridges from the tiny internal overhangs that are (very likely) supported by previous layer solids
|
||||||
// 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
|
// 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
|
||||||
lower_layer_solids = expand(lower_layer_solids, 3 * spacing);
|
lower_layer_solids = shrink(lower_layer_solids, 1 * spacing); // first remove thin regions that will not support anything
|
||||||
|
lower_layer_solids = expand(lower_layer_solids, (1 + 3) * spacing); // then expand back (opening), and further for parts supported by internal solids
|
||||||
// By shrinking the unsupported area, we avoid making bridges from narrow ensuring region along perimeters.
|
// By shrinking the unsupported area, we avoid making bridges from narrow ensuring region along perimeters.
|
||||||
unsupported_area = shrink(unsupported_area, 3 * spacing);
|
unsupported_area = shrink(unsupported_area, 3 * spacing);
|
||||||
unsupported_area = diff(unsupported_area, lower_layer_solids);
|
unsupported_area = diff(unsupported_area, lower_layer_solids);
|
||||||
@ -1825,23 +1826,28 @@ void PrintObject::bridge_over_infill()
|
|||||||
|
|
||||||
std::map<double, int> counted_directions;
|
std::map<double, int> counted_directions;
|
||||||
for (const Polygon &p : bridged_area) {
|
for (const Polygon &p : bridged_area) {
|
||||||
|
double acc_distance = 0;
|
||||||
for (int point_idx = 0; point_idx < int(p.points.size()) - 1; ++point_idx) {
|
for (int point_idx = 0; point_idx < int(p.points.size()) - 1; ++point_idx) {
|
||||||
Vec2d start = p.points[point_idx].cast<double>();
|
Vec2d start = p.points[point_idx].cast<double>();
|
||||||
Vec2d next = p.points[point_idx + 1].cast<double>();
|
Vec2d next = p.points[point_idx + 1].cast<double>();
|
||||||
Vec2d v = next - start; // vector from next to current
|
Vec2d v = next - start; // vector from next to current
|
||||||
double dist_to_next = v.norm();
|
double dist_to_next = v.norm();
|
||||||
v.normalize();
|
acc_distance += dist_to_next;
|
||||||
int lines_count = int(std::ceil(dist_to_next / scaled(3.0)));
|
if (acc_distance > scaled(2.0)) {
|
||||||
float step_size = dist_to_next / lines_count;
|
acc_distance = 0.0;
|
||||||
for (int i = 0; i < lines_count; ++i) {
|
v.normalize();
|
||||||
Point a = (start + v * (i * step_size)).cast<coord_t>();
|
int lines_count = int(std::ceil(dist_to_next / scaled(2.0)));
|
||||||
auto [distance, index, p] = lines_tree.distance_from_lines_extra<false>(a);
|
float step_size = dist_to_next / lines_count;
|
||||||
double angle = lines_tree.get_line(index).orientation();
|
for (int i = 0; i < lines_count; ++i) {
|
||||||
if (angle > PI) {
|
Point a = (start + v * (i * step_size)).cast<coord_t>();
|
||||||
angle -= PI;
|
auto [distance, index, p] = lines_tree.distance_from_lines_extra<false>(a);
|
||||||
|
double angle = lines_tree.get_line(index).orientation();
|
||||||
|
if (angle > PI) {
|
||||||
|
angle -= PI;
|
||||||
|
}
|
||||||
|
angle += PI * 0.5;
|
||||||
|
counted_directions[angle]++;
|
||||||
}
|
}
|
||||||
angle += PI * 0.5;
|
|
||||||
counted_directions[angle]++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2083,27 +2089,43 @@ void PrintObject::bridge_over_infill()
|
|||||||
};
|
};
|
||||||
return a.min.x() < b.min.x();
|
return a.min.x() < b.min.x();
|
||||||
});
|
});
|
||||||
|
if (surfaces_by_layer[lidx].size() > 2) {
|
||||||
|
Vec2d origin = get_extents(surfaces_by_layer[lidx].front().new_polys).max.cast<double>();
|
||||||
|
std::stable_sort(surfaces_by_layer[lidx].begin() + 1, surfaces_by_layer[lidx].end(),
|
||||||
|
[origin](const CandidateSurface &left, const CandidateSurface &right) {
|
||||||
|
auto a = get_extents(left.new_polys);
|
||||||
|
auto b = get_extents(right.new_polys);
|
||||||
|
|
||||||
|
return (origin - a.min.cast<double>()).squaredNorm() <
|
||||||
|
(origin - b.min.cast<double>()).squaredNorm();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Gather deep infill areas, where thick bridges fit
|
// Gather deep infill areas, where thick bridges fit
|
||||||
coordf_t spacing = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).scaled_spacing();
|
coordf_t spacing = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).scaled_spacing();
|
||||||
coordf_t target_flow_height = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).height() * target_flow_height_factor;
|
coordf_t target_flow_height = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).height() * target_flow_height_factor;
|
||||||
Polygons deep_infill_area = gather_areas_w_depth(po, lidx, target_flow_height);
|
Polygons deep_infill_area = gather_areas_w_depth(po, lidx, target_flow_height);
|
||||||
|
|
||||||
// Now also remove area that has been already filled on lower layers by bridging expansion - For this
|
{
|
||||||
// reason we did the clustering of layers per thread.
|
// Now also remove area that has been already filled on lower layers by bridging expansion - For this
|
||||||
double bottom_z = layer->print_z - target_flow_height - EPSILON;
|
// reason we did the clustering of layers per thread.
|
||||||
if (job_idx > 0) {
|
Polygons filled_polyons_on_lower_layers;
|
||||||
for (int lower_job_idx = job_idx - 1; lower_job_idx >= 0; lower_job_idx--) {
|
double bottom_z = layer->print_z - target_flow_height - EPSILON;
|
||||||
size_t lower_layer_idx = clustered_layers_for_threads[cluster_idx][lower_job_idx];
|
if (job_idx > 0) {
|
||||||
const Layer *lower_layer = po->get_layer(lower_layer_idx);
|
for (int lower_job_idx = job_idx - 1; lower_job_idx >= 0; lower_job_idx--) {
|
||||||
if (lower_layer->print_z >= bottom_z) {
|
size_t lower_layer_idx = clustered_layers_for_threads[cluster_idx][lower_job_idx];
|
||||||
for (const auto &c : surfaces_by_layer[lower_layer_idx]) {
|
const Layer *lower_layer = po->get_layer(lower_layer_idx);
|
||||||
deep_infill_area = diff(deep_infill_area, c.new_polys);
|
if (lower_layer->print_z >= bottom_z) {
|
||||||
|
for (const auto &c : surfaces_by_layer[lower_layer_idx]) {
|
||||||
|
filled_polyons_on_lower_layers.insert(filled_polyons_on_lower_layers.end(), c.new_polys.begin(),
|
||||||
|
c.new_polys.end());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deep_infill_area = diff(deep_infill_area, filled_polyons_on_lower_layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
deep_infill_area = expand(deep_infill_area, spacing * 1.5);
|
deep_infill_area = expand(deep_infill_area, spacing * 1.5);
|
||||||
@ -2123,9 +2145,8 @@ void PrintObject::bridge_over_infill()
|
|||||||
Polylines anchors = intersection_pl(infill_lines[lidx - 1], shrink(expansion_area, spacing));
|
Polylines anchors = intersection_pl(infill_lines[lidx - 1], shrink(expansion_area, spacing));
|
||||||
|
|
||||||
#ifdef DEBUG_BRIDGE_OVER_INFILL
|
#ifdef DEBUG_BRIDGE_OVER_INFILL
|
||||||
debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" +
|
debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_total_area",
|
||||||
"_total_area",
|
to_lines(total_fill_area), to_lines(expansion_area), to_lines(deep_infill_area), to_lines(anchors));
|
||||||
to_lines(total_fill_area), to_lines(expansion_area), to_lines(deep_infill_area), to_lines(anchors));
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -2186,6 +2207,7 @@ void PrintObject::bridge_over_infill()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bridging_area = opening(bridging_area, flow.scaled_spacing());
|
bridging_area = opening(bridging_area, flow.scaled_spacing());
|
||||||
|
bridging_area = closing(bridging_area, flow.scaled_spacing());
|
||||||
bridging_area = intersection(bridging_area, limiting_area);
|
bridging_area = intersection(bridging_area, limiting_area);
|
||||||
bridging_area = intersection(bridging_area, total_fill_area);
|
bridging_area = intersection(bridging_area, total_fill_area);
|
||||||
expansion_area = diff(expansion_area, bridging_area);
|
expansion_area = diff(expansion_area, bridging_area);
|
||||||
@ -2220,35 +2242,33 @@ void PrintObject::bridge_over_infill()
|
|||||||
for (LayerRegion *region : layer->regions()) {
|
for (LayerRegion *region : layer->regions()) {
|
||||||
Surfaces new_surfaces;
|
Surfaces new_surfaces;
|
||||||
|
|
||||||
|
SurfacesPtr internal_infills = region->m_fill_surfaces.filter_by_type(stInternal);
|
||||||
|
ExPolygons new_internal_infills = diff_ex(internal_infills, cut_from_infill);
|
||||||
|
for (const ExPolygon &ep : new_internal_infills) {
|
||||||
|
new_surfaces.emplace_back(*internal_infills.front(), ep);
|
||||||
|
}
|
||||||
|
|
||||||
|
SurfacesPtr internal_solids = region->m_fill_surfaces.filter_by_type(stInternalSolid);
|
||||||
for (const CandidateSurface &cs : surfaces_by_layer.at(lidx)) {
|
for (const CandidateSurface &cs : surfaces_by_layer.at(lidx)) {
|
||||||
for (Surface &surface : region->m_fill_surfaces.surfaces) {
|
for (const Surface *surface : internal_solids) {
|
||||||
if (cs.original_surface == &surface) {
|
if (cs.original_surface == surface) {
|
||||||
Surface tmp(surface, {});
|
Surface tmp{*surface, {}};
|
||||||
for (const ExPolygon &expoly : diff_ex(surface.expolygon, cs.new_polys)) {
|
|
||||||
if (expoly.area() > region->flow(frSolidInfill).scaled_width() * scale_(4.0)) {
|
|
||||||
new_surfaces.emplace_back(tmp, expoly);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp.surface_type = stInternalBridge;
|
tmp.surface_type = stInternalBridge;
|
||||||
tmp.bridge_angle = cs.bridge_angle;
|
tmp.bridge_angle = cs.bridge_angle;
|
||||||
for (const ExPolygon &expoly : union_ex(cs.new_polys)) {
|
for (const ExPolygon &ep : union_ex(cs.new_polys)) {
|
||||||
new_surfaces.emplace_back(tmp, expoly);
|
new_surfaces.emplace_back(tmp, ep);
|
||||||
}
|
}
|
||||||
surface.clear();
|
break;
|
||||||
} else if (surface.surface_type == stInternal) {
|
|
||||||
Surface tmp(surface, {});
|
|
||||||
for (const ExPolygon &expoly : diff_ex(surface.expolygon, cut_from_infill)) {
|
|
||||||
new_surfaces.emplace_back(tmp, expoly);
|
|
||||||
}
|
|
||||||
surface.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
region->m_fill_surfaces.surfaces.insert(region->m_fill_surfaces.surfaces.end(), new_surfaces.begin(), new_surfaces.end());
|
ExPolygons new_internal_solids = diff_ex(internal_solids, cut_from_infill);
|
||||||
region->m_fill_surfaces.surfaces.erase(std::remove_if(region->m_fill_surfaces.surfaces.begin(),
|
for (const ExPolygon &ep : new_internal_solids) {
|
||||||
region->m_fill_surfaces.surfaces.end(),
|
new_surfaces.emplace_back(*internal_solids.front(), ep);
|
||||||
[](const Surface &s) { return s.empty(); }),
|
}
|
||||||
region->m_fill_surfaces.surfaces.end());
|
|
||||||
|
region->m_fill_surfaces.remove_types({stInternalSolid, stInternal});
|
||||||
|
region->m_fill_surfaces.append(new_surfaces);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user