Compute bridging direction. Now what is left is to stretch the bridge lines across infill and cut them to ideal length
This commit is contained in:
parent
696b316e2b
commit
fd81d7a460
2 changed files with 134 additions and 37 deletions
|
@ -126,12 +126,6 @@ inline std::tuple<Vec2d, double> detect_bridging_direction(const Polygons &to_co
|
|||
};
|
||||
|
||||
|
||||
inline Vec2d detect_internal_bridge_direction() {
|
||||
//TODO AABB tree, get nearest point on the infill polylines (or perimeters) and do not take duplicates
|
||||
// this could yield some density map where the more scattered points are more interesting
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
#include "AABBTreeLines.hpp"
|
||||
#include "BridgeDetector.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "Exception.hpp"
|
||||
#include "KDTreeIndirect.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "Polyline.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
|
@ -1530,7 +1535,6 @@ void PrintObject::bridge_over_infill()
|
|||
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, this->layers().size()), [po = this](tbb::blocked_range<size_t> r) {
|
||||
for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
|
||||
|
||||
const Layer *layer = po->get_layer(lidx);
|
||||
|
||||
// gather also sparse infill surfaces on this layer, to which we can expand the bridges for anchoring
|
||||
|
@ -1539,6 +1543,7 @@ void PrintObject::bridge_over_infill()
|
|||
std::unordered_map<const LayerSlice *, SurfacesPtr> bridging_surface_candidates;
|
||||
std::unordered_map<const LayerSlice *, SurfacesPtr> expansion_space;
|
||||
std::unordered_map<const LayerSlice *, float> max_bridge_flow_height;
|
||||
std::unordered_map<const LayerSlice *, float> max_bridge_flow_width;
|
||||
for (const LayerSlice &slice : layer->lslices_ex) {
|
||||
std::unordered_set<size_t> regions_to_check;
|
||||
for (const LayerIsland &island : slice.islands) {
|
||||
|
@ -1552,8 +1557,10 @@ void PrintObject::bridge_over_infill()
|
|||
const LayerRegion *region = layer->get_region(region_idx);
|
||||
auto region_internal_solids = region->fill_surfaces().filter_by_type(stInternalSolid);
|
||||
if (!region_internal_solids.empty()) {
|
||||
max_bridge_flow_height[&slice] = std::max(max_bridge_flow_height[&slice],
|
||||
region->bridging_flow(frSolidInfill).height());
|
||||
max_bridge_flow_height[&slice] = std::max(max_bridge_flow_height[&slice],
|
||||
region->bridging_flow(frSolidInfill).height());
|
||||
max_bridge_flow_width[&slice] = std::max(max_bridge_flow_width[&slice],
|
||||
region->bridging_flow(frSolidInfill).width());
|
||||
}
|
||||
bridging_surface_candidates[&slice].insert(bridging_surface_candidates[&slice].end(), region_internal_solids.begin(),
|
||||
region_internal_solids.end());
|
||||
|
@ -1562,33 +1569,15 @@ void PrintObject::bridge_over_infill()
|
|||
}
|
||||
}
|
||||
|
||||
for (const std::pair<const LayerSlice *, SurfacesPtr> &candidates : bridging_surface_candidates) {
|
||||
if (candidates.second.empty()) {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Gather lower layers sparse infill areas, to depth defined by used bridge flow
|
||||
Polygons lower_layers_sparse_infill;
|
||||
double bottom_z = layer->print_z - max_bridge_flow_height[candidates.first] - EPSILON;
|
||||
LayerSlice::Links current_links = candidates.first->overlaps_below;
|
||||
for (auto i = int(lidx) - 1; i >= 0; --i) {
|
||||
// Stop iterating if layer is lower than bottom_z.
|
||||
if (po->get_layer(i)->print_z < bottom_z)
|
||||
break;
|
||||
for (const auto &link : current_links) {
|
||||
const LayerSlice& slice_below = po->get_layer(i)->lslices_ex[link.slice_idx];
|
||||
for (const LayerRegion *region : po->get_layer(i)->regions()) {
|
||||
for (const Surface *surface : region->fill_surfaces().filter_by_type(stInternal)) {
|
||||
Polygons p = to_polygons(surface->expolygon);
|
||||
lower_layers_sparse_infill.insert(lower_layers_sparse_infill.end(), p.begin(), p.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lower_layers_sparse_infill = union_(lower_layers_sparse_infill);
|
||||
// if there are none briding candidates, exit now, before making infill for the previous layer
|
||||
if (std::all_of(bridging_surface_candidates.begin(), bridging_surface_candidates.end(),
|
||||
[](const std::pair<const LayerSlice *, SurfacesPtr> &candidates) { return candidates.second.empty(); })) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now, temporarily fill the previous layer and extract the extrusions.
|
||||
// TODO - the make_fills function does a lot of work, some of it is not needed (e.g. sorting the paths)
|
||||
// It would be nice to have a function that only creates the fill polylines, ideally without modifying the global state
|
||||
po->get_layer(lidx)->lower_layer->make_fills(nullptr, nullptr, nullptr);
|
||||
Polylines lower_layer_polylines;
|
||||
for (const LayerRegion *region : layer->lower_layer->m_regions) {
|
||||
|
@ -1598,15 +1587,128 @@ void PrintObject::bridge_over_infill()
|
|||
lower_layer_polylines.insert(lower_layer_polylines.end(), region_polylines.begin(), region_polylines.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::pair<const LayerSlice *, SurfacesPtr> candidates : bridging_surface_candidates) {
|
||||
if (candidates.second.empty()) {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Gather lower layers sparse infill areas, to depth defined by used bridge flow
|
||||
Polygons lower_layers_sparse_infill;
|
||||
double bottom_z = layer->print_z - max_bridge_flow_height[candidates.first] - EPSILON;
|
||||
LayerSlice::Links current_links = candidates.first->overlaps_below;
|
||||
LayerSlice::Links next_links{};
|
||||
for (auto i = int(lidx) - 1; i >= 0; --i) {
|
||||
// Stop iterating if layer is lower than bottom_z.
|
||||
if (po->get_layer(i)->print_z < bottom_z)
|
||||
break;
|
||||
for (const auto &link : current_links) {
|
||||
const LayerSlice &slice_below = po->get_layer(i)->lslices_ex[link.slice_idx];
|
||||
next_links.insert(next_links.end(), slice_below.overlaps_below.begin(), slice_below.overlaps_below.end());
|
||||
std::unordered_set<size_t> regions_under_to_check;
|
||||
for (const LayerIsland &island : slice_below.islands) {
|
||||
regions_under_to_check.insert(island.perimeters.region());
|
||||
if (!island.fill_expolygons_composite()) {
|
||||
regions_under_to_check.insert(island.fill_region_id);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t region_idx : regions_under_to_check) {
|
||||
const LayerRegion *region = layer->get_region(region_idx);
|
||||
for (const Surface *surface : region->fill_surfaces().filter_by_type(stInternal)) {
|
||||
Polygons p = to_polygons(surface->expolygon);
|
||||
lower_layers_sparse_infill.insert(lower_layers_sparse_infill.end(), p.begin(), p.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
current_links = next_links;
|
||||
}
|
||||
if (lower_layers_sparse_infill.empty()) {
|
||||
continue;
|
||||
}
|
||||
lower_layers_sparse_infill = union_(lower_layers_sparse_infill);
|
||||
|
||||
Polygons expand_area;
|
||||
for (const Surface *sparse_infill : expansion_space[candidates.first]) {
|
||||
assert(sparse_infill->surface_type == stInternal);
|
||||
Polygons a = to_polygons(sparse_infill->expolygon);
|
||||
expand_area.insert(expand_area.end(), a.begin(), a.end());
|
||||
}
|
||||
|
||||
// Lower layers sparse infill sections gathered
|
||||
// now we can intersected them with bridging surface candidates to get actual areas that need and can accumulate
|
||||
// bridging. These areas we then expand (within the surrounding sparse infill only!)
|
||||
// to touch the infill polylines on previous layer.
|
||||
for (const Surface *candidate : candidates.second) {
|
||||
assert(candidate->surface_type == stInternalSolid);
|
||||
Polygons bridged_area = to_polygons(candidate->expolygon);
|
||||
bridged_area =
|
||||
intersection(bridged_area,
|
||||
lower_layers_sparse_infill); // cut off parts which are not over sparse infill - material overflow
|
||||
|
||||
if (bridged_area.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Polygons max_area = expand_area;
|
||||
max_area.insert(max_area.end(), bridged_area.begin(), bridged_area.end());
|
||||
closing(max_area, max_bridge_flow_width[candidates.first]);
|
||||
|
||||
Polylines anchors = intersection_pl(lower_layer_polylines, max_area);
|
||||
anchors = diff_pl(anchors, shrink(bridged_area, scale_(max_bridge_flow_width[candidates.first])));
|
||||
|
||||
AABBTreeLines::LinesDistancer<Line> anchors_and_walls;
|
||||
{
|
||||
Lines tmp = to_lines(anchors);
|
||||
Lines tmp2 = to_lines(max_area);
|
||||
tmp.insert(tmp.end(), tmp.begin(), tmp.end());
|
||||
anchors_and_walls = AABBTreeLines::LinesDistancer<Line>{tmp};
|
||||
}
|
||||
|
||||
double bridging_dir = 0;
|
||||
{
|
||||
std::vector<std::pair<double,double>> directions_with_distances;
|
||||
for (const Polygon &p : bridged_area) {
|
||||
for (int point_idx = 0; point_idx < int(p.points.size()) - 1; ++point_idx) {
|
||||
Vec2d start = p.points[point_idx].cast<double>();
|
||||
Vec2d next = p.points[point_idx + 1].cast<double>();
|
||||
Vec2d v = next - start; // vector from next to current
|
||||
double dist_to_next = v.norm();
|
||||
v.normalize();
|
||||
int lines_count = int(std::ceil(dist_to_next / scaled(3.0)));
|
||||
float step_size = dist_to_next / lines_count;
|
||||
for (int i = 0; i < lines_count; ++i) {
|
||||
Point a(start + v * (i * step_size));
|
||||
auto [distance, index, p] = anchors_and_walls.distance_from_lines_extra<false>(a);
|
||||
const Line& l = anchors_and_walls.get_line(index);
|
||||
directions_with_distances.emplace_back(l.direction(), unscaled(distance));
|
||||
}
|
||||
}
|
||||
}
|
||||
double max_dist = directions_with_distances[0].second;
|
||||
for (const auto& dir :directions_with_distances) {
|
||||
max_dist = std::max(max_dist, dir.second);
|
||||
}
|
||||
double acc = 0;
|
||||
for (const auto& dir : directions_with_distances) {
|
||||
bridging_dir += dir.first * (max_dist - dir.second);
|
||||
acc += (max_dist - dir.second);
|
||||
}
|
||||
bridging_dir /= acc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // surface iteration end
|
||||
} // island iteration end
|
||||
} // layer iteration end
|
||||
});
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Bridge over infill - End" << log_memory_info();
|
||||
|
||||
} // void PrintObject::bridge_over_infill()
|
||||
|
||||
|
||||
|
||||
|
||||
void a(){
|
||||
std::vector<int> sparse_infill_regions;
|
||||
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id)
|
||||
if (const PrintRegion ®ion = this->printing_region(region_id); region.config().fill_density.value < 100)
|
||||
|
@ -1731,6 +1833,7 @@ void PrintObject::bridge_over_infill()
|
|||
m_print->throw_if_canceled();
|
||||
}
|
||||
});
|
||||
|
||||
} // void PrintObject::bridge_over_infill()
|
||||
|
||||
static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)
|
||||
|
|
Loading…
Add table
Reference in a new issue