From 0a7c48f5fd7a8db15c7c117eda60e0faf845d172 Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Tue, 2 May 2023 16:49:46 +0200 Subject: [PATCH] Little refactoring, make the fill modifiable --- src/libslic3r/Fill/FillBase.hpp | 2 +- src/libslic3r/Fill/FillEnsuring.cpp | 368 ++++++++++++++-------------- src/libslic3r/Fill/FillEnsuring.hpp | 9 +- 3 files changed, 197 insertions(+), 182 deletions(-) diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index cf37667587..4130cc3313 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -147,9 +147,9 @@ protected: virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; } - virtual std::pair _infill_direction(const Surface *surface) const; public: + virtual std::pair _infill_direction(const Surface *surface) const; static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams ¶ms); static void connect_infill(Polylines &&infill_ordered, const Polygons &boundary, const BoundingBox& bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms); static void connect_infill(Polylines &&infill_ordered, const std::vector &boundary, const BoundingBox &bbox, Polylines &polylines_out, double spacing, const FillParams ¶ms); diff --git a/src/libslic3r/Fill/FillEnsuring.cpp b/src/libslic3r/Fill/FillEnsuring.cpp index 474a889262..2a24e2360e 100644 --- a/src/libslic3r/Fill/FillEnsuring.cpp +++ b/src/libslic3r/Fill/FillEnsuring.cpp @@ -25,10 +25,9 @@ namespace Slic3r { -ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const FillParams ¶ms) +ThickPolylines make_fill_polylines(const Fill *fill, const Surface *surface, const FillParams ¶ms, bool stop_vibrations, bool fill_gaps) { - assert(params.use_arachne); - assert(this->print_config != nullptr && this->print_object_config != nullptr && this->print_region_config != nullptr); + assert(fill->print_config != nullptr && fill->print_object_config != nullptr && fill->print_region_config != nullptr); auto rotate_thick_polylines = [](ThickPolylines &tpolylines, double cos_angle, double sin_angle) { for (ThickPolyline &tp : tpolylines) { @@ -46,14 +45,13 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const (bhigh >= alow && bhigh <= ahigh); }; - const coord_t scaled_spacing = scaled(this->spacing); + const coord_t scaled_spacing = scaled(fill->spacing); double distance_limit_reconnection = double(scaled_spacing); double squared_distance_limit_reconnection = distance_limit_reconnection * distance_limit_reconnection; Polygons filled_area = to_polygons(surface->expolygon); - std::pair rotate_vector = this->_infill_direction(surface); + std::pair rotate_vector = fill->_infill_direction(surface); double aligning_angle = -rotate_vector.first + PI; polygons_rotate(filled_area, aligning_angle); - Polygons internal_area = shrink(filled_area, 0.5 * scaled_spacing - scale_(this->overlap)); BoundingBox bb = get_extents(filled_area); const size_t n_vlines = (bb.max.x() - bb.min.x() + scaled_spacing - 1) / scaled_spacing; @@ -65,11 +63,18 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const vertical_lines[i].a = Point{x, y_min}; vertical_lines[i].b = Point{x, y_max}; } + vertical_lines.push_back(vertical_lines.back()); vertical_lines.back().a = Point{coord_t(bb.min.x() + n_vlines * double(scaled_spacing) + scaled_spacing * 0.5), y_min}; vertical_lines.back().b = Point{vertical_lines.back().a.x(), y_max}; - auto area_walls = AABBTreeLines::LinesDistancer{ - to_lines(intersection(filled_area, opening(filled_area, 2 * scaled_spacing, 3 * scaled_spacing)))}; + AABBTreeLines::LinesDistancer area_walls; + if (stop_vibrations) { + area_walls = AABBTreeLines::LinesDistancer{ + to_lines(intersection(filled_area, opening(filled_area, 2 * scaled_spacing, 3 * scaled_spacing)))}; + } else { + area_walls = AABBTreeLines::LinesDistancer{to_lines(filled_area)}; + } + std::vector> polygon_sections(n_vlines); for (size_t i = 0; i < n_vlines; i++) { @@ -86,75 +91,77 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const } } - struct Node - { - int section_idx; - int line_idx; - int skips_taken = 0; - bool neighbours_explored = false; - std::vector> neighbours{}; - }; + if (stop_vibrations) { + struct Node + { + int section_idx; + int line_idx; + int skips_taken = 0; + bool neighbours_explored = false; + std::vector> neighbours{}; + }; - coord_t length_filter = scale_(4); - size_t skips_allowed = 2; - size_t min_removal_conut = 5; - for (int section_idx = 0; section_idx < polygon_sections.size(); section_idx++) { - for (int line_idx = 0; line_idx < polygon_sections[section_idx].size(); line_idx++) { - if (const Line &line = polygon_sections[section_idx][line_idx]; line.a != line.b && line.length() < length_filter) { - std::set> to_remove{{section_idx, line_idx}}; - std::vector to_visit{{section_idx, line_idx}}; + coord_t length_filter = scale_(4); + size_t skips_allowed = 2; + size_t min_removal_conut = 5; + for (int section_idx = 0; section_idx < polygon_sections.size(); section_idx++) { + for (int line_idx = 0; line_idx < polygon_sections[section_idx].size(); line_idx++) { + if (const Line &line = polygon_sections[section_idx][line_idx]; line.a != line.b && line.length() < length_filter) { + std::set> to_remove{{section_idx, line_idx}}; + std::vector to_visit{{section_idx, line_idx}}; - bool initial_touches_long_lines = false; - if (section_idx > 0) { - for (int prev_line_idx = 0; prev_line_idx < polygon_sections[section_idx - 1].size(); prev_line_idx++) { - if (const Line &nl = polygon_sections[section_idx - 1][prev_line_idx]; - nl.a != nl.b && segments_overlap(line.a.y(), line.b.y(), nl.a.y(), nl.b.y())) { - initial_touches_long_lines = true; - } - } - } - - while (!to_visit.empty()) { - Node curr = to_visit.back(); - const Line &curr_l = polygon_sections[curr.section_idx][curr.line_idx]; - if (curr.neighbours_explored) { - bool is_valid_for_removal = (curr_l.length() < length_filter) && - ((int(to_remove.size()) - curr.skips_taken > min_removal_conut) || - (curr.neighbours.empty() && !initial_touches_long_lines)); - if (!is_valid_for_removal) { - for (const auto &n : curr.neighbours) { - if (to_remove.find(n) != to_remove.end()) { - is_valid_for_removal = true; - break; - } + bool initial_touches_long_lines = false; + if (section_idx > 0) { + for (int prev_line_idx = 0; prev_line_idx < polygon_sections[section_idx - 1].size(); prev_line_idx++) { + if (const Line &nl = polygon_sections[section_idx - 1][prev_line_idx]; + nl.a != nl.b && segments_overlap(line.a.y(), line.b.y(), nl.a.y(), nl.b.y())) { + initial_touches_long_lines = true; } } - if (!is_valid_for_removal) { - to_remove.erase({curr.section_idx, curr.line_idx}); - } - to_visit.pop_back(); - } else { - to_visit.back().neighbours_explored = true; - int curr_index = to_visit.size() - 1; - bool can_use_skip = curr_l.length() <= length_filter && curr.skips_taken < skips_allowed; - if (curr.section_idx + 1 < polygon_sections.size()) { - for (int lidx = 0; lidx < polygon_sections[curr.section_idx + 1].size(); lidx++) { - if (const Line &nl = polygon_sections[curr.section_idx + 1][lidx]; - nl.a != nl.b && segments_overlap(curr_l.a.y(), curr_l.b.y(), nl.a.y(), nl.b.y()) && - (nl.length() < length_filter || can_use_skip)) { - to_visit[curr_index].neighbours.push_back({curr.section_idx + 1, lidx}); - to_remove.insert({curr.section_idx + 1, lidx}); - Node next_node{curr.section_idx + 1, lidx, curr.skips_taken + (nl.length() >= length_filter)}; - to_visit.push_back(next_node); + } + + while (!to_visit.empty()) { + Node curr = to_visit.back(); + const Line &curr_l = polygon_sections[curr.section_idx][curr.line_idx]; + if (curr.neighbours_explored) { + bool is_valid_for_removal = (curr_l.length() < length_filter) && + ((int(to_remove.size()) - curr.skips_taken > min_removal_conut) || + (curr.neighbours.empty() && !initial_touches_long_lines)); + if (!is_valid_for_removal) { + for (const auto &n : curr.neighbours) { + if (to_remove.find(n) != to_remove.end()) { + is_valid_for_removal = true; + break; + } + } + } + if (!is_valid_for_removal) { + to_remove.erase({curr.section_idx, curr.line_idx}); + } + to_visit.pop_back(); + } else { + to_visit.back().neighbours_explored = true; + int curr_index = to_visit.size() - 1; + bool can_use_skip = curr_l.length() <= length_filter && curr.skips_taken < skips_allowed; + if (curr.section_idx + 1 < polygon_sections.size()) { + for (int lidx = 0; lidx < polygon_sections[curr.section_idx + 1].size(); lidx++) { + if (const Line &nl = polygon_sections[curr.section_idx + 1][lidx]; + nl.a != nl.b && segments_overlap(curr_l.a.y(), curr_l.b.y(), nl.a.y(), nl.b.y()) && + (nl.length() < length_filter || can_use_skip)) { + to_visit[curr_index].neighbours.push_back({curr.section_idx + 1, lidx}); + to_remove.insert({curr.section_idx + 1, lidx}); + Node next_node{curr.section_idx + 1, lidx, curr.skips_taken + (nl.length() >= length_filter)}; + to_visit.push_back(next_node); + } } } } } - } - for (const auto &pair : to_remove) { - Line &l = polygon_sections[pair.first][pair.second]; - l.a = l.b; + for (const auto &pair : to_remove) { + Line &l = polygon_sections[pair.first][pair.second]; + l.a = l.b; + } } } } @@ -182,9 +189,9 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const std::unordered_set used_segments; for (TracedPoly &traced_poly : current_traced_polys) { auto candidates_begin = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.lows.back(), - [](const Point &low, const Line &seg) { return seg.b.y() > low.y(); }); - auto candidates_end = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.highs.back(), - [](const Point &high, const Line &seg) { return seg.a.y() > high.y(); }); + [](const Point &low, const Line &seg) { return seg.b.y() > low.y(); }); + auto candidates_end = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.highs.back(), + [](const Point &high, const Line &seg) { return seg.a.y() > high.y(); }); bool segment_added = false; for (auto candidate = candidates_begin; candidate != candidates_end && !segment_added; candidate++) { @@ -247,8 +254,8 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const reconstructed_area = closing(reconstructed_area, float(SCALED_EPSILON), float(SCALED_EPSILON)); ExPolygons gaps_for_additional_filling = diff_ex(filled_area, reconstructed_area); - if (this->overlap != 0) { - gaps_for_additional_filling = offset_ex(gaps_for_additional_filling, scaled(this->overlap)); + if (fill->overlap != 0) { + gaps_for_additional_filling = offset_ex(gaps_for_additional_filling, scaled(fill->overlap)); } // BoundingBox bbox = get_extents(filled_area); @@ -274,129 +281,132 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const } } - for (ExPolygon &ex_poly : gaps_for_additional_filling) { - BoundingBox ex_bb = ex_poly.contour.bounding_box(); - coord_t loops_count = (std::max(ex_bb.size().x(), ex_bb.size().y()) + scaled_spacing - 1) / scaled_spacing; - Polygons polygons = to_polygons(ex_poly); - Arachne::WallToolPaths wall_tool_paths(polygons, scaled_spacing, scaled_spacing, loops_count, 0, params.layer_height, - *this->print_object_config, *this->print_config); - if (std::vector loops = wall_tool_paths.getToolPaths(); !loops.empty()) { - std::vector all_extrusions; - for (Arachne::VariableWidthLines &loop : loops) { - if (loop.empty()) - continue; - for (const Arachne::ExtrusionLine &wall : loop) - all_extrusions.emplace_back(&wall); - } + if (fill_gaps) { + for (ExPolygon &ex_poly : gaps_for_additional_filling) { + BoundingBox ex_bb = ex_poly.contour.bounding_box(); + coord_t loops_count = (std::max(ex_bb.size().x(), ex_bb.size().y()) + scaled_spacing - 1) / scaled_spacing; + Polygons polygons = to_polygons(ex_poly); + Arachne::WallToolPaths wall_tool_paths(polygons, scaled_spacing, scaled_spacing, loops_count, 0, params.layer_height, + *fill->print_object_config, *fill->print_config); + if (std::vector loops = wall_tool_paths.getToolPaths(); !loops.empty()) { + std::vector all_extrusions; + for (Arachne::VariableWidthLines &loop : loops) { + if (loop.empty()) + continue; + for (const Arachne::ExtrusionLine &wall : loop) + all_extrusions.emplace_back(&wall); + } - for (const Arachne::ExtrusionLine *extrusion : all_extrusions) { - if (extrusion->junctions.size() < 2) { - continue; + for (const Arachne::ExtrusionLine *extrusion : all_extrusions) { + if (extrusion->junctions.size() < 2) { + continue; + } + ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion); + if (extrusion->is_closed) { + thick_polyline.start_at_index(nearest_point_index(thick_polyline.points, ex_bb.min)); + thick_polyline.clip_end(scaled_spacing * 0.5); + } + if (thick_polyline.is_valid() && thick_polyline.length() > 0 && thick_polyline.points.size() > 1) { + thick_polylines.push_back(thick_polyline); + } } - ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion); - if (extrusion->is_closed) { - thick_polyline.start_at_index(nearest_point_index(thick_polyline.points, ex_bb.min)); - thick_polyline.clip_end(scaled_spacing * 0.5); - } - thick_polylines.push_back(thick_polyline); } } - } - // connect tiny gap fills to close colinear line - struct EndPoint - { - Vec2d position; - size_t polyline_idx; - size_t other_end_point_idx; - bool is_first; - bool used = false; - }; - std::vector connection_endpoints; - connection_endpoints.reserve(thick_polylines.size() * 2); - for (size_t pl_idx = 0; pl_idx < thick_polylines.size(); pl_idx++) { - size_t current_idx = connection_endpoints.size(); - connection_endpoints.push_back({thick_polylines[pl_idx].first_point().cast(), pl_idx, current_idx + 1, true}); - connection_endpoints.push_back({thick_polylines[pl_idx].last_point().cast(), pl_idx, current_idx, false}); - } + std::sort(thick_polylines.begin(), thick_polylines.end(), [](const ThickPolyline &left, const ThickPolyline &right) { + BoundingBox lbb(left.points); + BoundingBox rbb(right.points); + if (lbb.min.x() == rbb.min.x()) + return lbb.min.y() < rbb.min.y(); + else + return lbb.min.x() < rbb.min.x(); + }); - auto coord_fn = [&connection_endpoints](size_t idx, size_t dim) { return connection_endpoints[idx].position[dim]; }; - KDTreeIndirect<2, double, decltype(coord_fn)> endpoints_tree{coord_fn, connection_endpoints.size()}; - for (size_t ep_idx = 0; ep_idx < connection_endpoints.size(); ep_idx++) { - EndPoint &ep1 = connection_endpoints[ep_idx]; - if (!ep1.used) { - std::vector close_endpoints = find_nearby_points(endpoints_tree, ep1.position, double(scaled_spacing)); - for (size_t close_endpoint_idx : close_endpoints) { - EndPoint &ep2 = connection_endpoints[close_endpoint_idx]; - if (ep2.used || ep2.polyline_idx == ep1.polyline_idx) { - continue; + // connect tiny gap fills to close colinear line + struct EndPoint + { + Vec2d position; + size_t polyline_idx; + size_t other_end_point_idx; + bool is_first; + bool used = false; + }; + std::vector connection_endpoints; + connection_endpoints.reserve(thick_polylines.size() * 2); + for (size_t pl_idx = 0; pl_idx < thick_polylines.size(); pl_idx++) { + size_t current_idx = connection_endpoints.size(); + connection_endpoints.push_back({thick_polylines[pl_idx].first_point().cast(), pl_idx, current_idx + 1, true}); + connection_endpoints.push_back({thick_polylines[pl_idx].last_point().cast(), pl_idx, current_idx, false}); + } + + auto coord_fn = [&connection_endpoints](size_t idx, size_t dim) { return connection_endpoints[idx].position[dim]; }; + KDTreeIndirect<2, double, decltype(coord_fn)> endpoints_tree{coord_fn, connection_endpoints.size()}; + for (size_t ep_idx = 0; ep_idx < connection_endpoints.size(); ep_idx++) { + EndPoint &ep1 = connection_endpoints[ep_idx]; + if (!ep1.used) { + std::vector close_endpoints = find_nearby_points(endpoints_tree, ep1.position, double(scaled_spacing)); + for (size_t close_endpoint_idx : close_endpoints) { + EndPoint &ep2 = connection_endpoints[close_endpoint_idx]; + if (ep2.used || ep2.polyline_idx == ep1.polyline_idx) { + continue; + } + + ThickPolyline &tp1 = thick_polylines[ep1.polyline_idx]; + ThickPolyline &tp2 = thick_polylines[ep2.polyline_idx]; + + Vec2d v1 = ep1.is_first ? (tp1.points[0] - tp1.points[1]).cast() : + (tp1.points.back() - tp1.points[tp1.points.size() - 1]).cast(); + Vec2d v2 = ep2.is_first ? (tp2.points[1] - tp2.points[0]).cast() : + (tp2.points[tp2.points.size() - 1] - tp2.points.back()).cast(); + + if (std::abs(Slic3r::angle(v1, v2)) > PI / 6.0) { + continue; + } + + // connect ep and ep2; + if (ep1.is_first) { + tp1.reverse(); + ep1.is_first = false; + connection_endpoints[ep1.other_end_point_idx].is_first = true; + } + + size_t new_start_idx = ep1.other_end_point_idx; + + if (!ep2.is_first) { + tp2.reverse(); + ep2.is_first = true; + connection_endpoints[ep2.other_end_point_idx].is_first = false; + } + + size_t new_end_idx = ep2.other_end_point_idx; + + tp1.points.insert(tp1.points.end(), tp2.points.begin(), tp2.points.end()); + tp1.width.push_back(tp1.width.back()); + tp1.width.push_back(tp2.width.front()); + tp1.width.insert(tp1.width.end(), tp2.width.begin(), tp2.width.end()); + ep1.used = true; + ep2.used = true; + + connection_endpoints[new_start_idx].polyline_idx = ep1.polyline_idx; + connection_endpoints[new_end_idx].polyline_idx = ep1.polyline_idx; + connection_endpoints[new_start_idx].other_end_point_idx = new_end_idx; + connection_endpoints[new_end_idx].other_end_point_idx = new_start_idx; + tp2.clear(); + break; } - - ThickPolyline &tp1 = thick_polylines[ep1.polyline_idx]; - ThickPolyline &tp2 = thick_polylines[ep2.polyline_idx]; - - Vec2d v1 = ep1.is_first ? (tp1.points[0] - tp1.points[1]).cast() : - (tp1.points.back() - tp1.points[tp1.points.size() - 1]).cast(); - Vec2d v2 = ep2.is_first ? (tp2.points[1] - tp2.points[0]).cast() : - (tp2.points[tp2.points.size() - 1] - tp2.points.back()).cast(); - - if (std::abs(Slic3r::angle(v1, v2)) > PI / 6.0) { - continue; - } - - // connect ep and ep2; - if (ep1.is_first) { - tp1.reverse(); - ep1.is_first = false; - connection_endpoints[ep1.other_end_point_idx].is_first = true; - } - - size_t new_start_idx = ep1.other_end_point_idx; - - if (!ep2.is_first) { - tp2.reverse(); - ep2.is_first = true; - connection_endpoints[ep2.other_end_point_idx].is_first = false; - } - - size_t new_end_idx = ep2.other_end_point_idx; - - tp1.points.insert(tp1.points.end(), tp2.points.begin(), tp2.points.end()); - tp1.width.push_back(tp1.width.back()); - tp1.width.push_back(tp2.width.front()); - tp1.width.insert(tp1.width.end(), tp2.width.begin(), tp2.width.end()); - ep1.used = true; - ep2.used = true; - - connection_endpoints[new_start_idx].polyline_idx = ep1.polyline_idx; - connection_endpoints[new_end_idx].polyline_idx = ep1.polyline_idx; - connection_endpoints[new_start_idx].other_end_point_idx = new_end_idx; - connection_endpoints[new_end_idx].other_end_point_idx = new_start_idx; - tp2.clear(); - break; } } - } - thick_polylines.erase(std::remove_if(thick_polylines.begin(), thick_polylines.end(), + thick_polylines.erase(std::remove_if(thick_polylines.begin(), thick_polylines.end(), [scaled_spacing](const ThickPolyline &tp) { return tp.length() < scaled_spacing && std::all_of(tp.width.begin(), tp.width.end(), [scaled_spacing](double w) { return w < scaled_spacing; }); }), thick_polylines.end()); + } - std::sort(thick_polylines.begin(), thick_polylines.end(), [](const ThickPolyline &left, const ThickPolyline &right) { - BoundingBox lbb(left.points); - BoundingBox rbb(right.points); - if (lbb.min.x() == rbb.min.x()) - return lbb.max.y() < rbb.max.y(); - else - return lbb.max.x() < rbb.max.x(); - }); - - Algorithm::sort_paths(thick_polylines.begin(), thick_polylines.end(), bb.min, double(scaled_spacing) * 1.2, [](const ThickPolyline - &tp) { + Algorithm::sort_paths(thick_polylines.begin(), thick_polylines.end(), bb.min, double(scaled_spacing) * 1.2, [](const ThickPolyline &tp) { Lines ls; Point prev = tp.first_point(); for (size_t i = 1; i < tp.points.size(); i++) { diff --git a/src/libslic3r/Fill/FillEnsuring.hpp b/src/libslic3r/Fill/FillEnsuring.hpp index faa0801535..8f36dde2df 100644 --- a/src/libslic3r/Fill/FillEnsuring.hpp +++ b/src/libslic3r/Fill/FillEnsuring.hpp @@ -6,13 +6,18 @@ namespace Slic3r { -class FillEnsuring : public FillRectilinear +ThickPolylines make_fill_polylines(const Fill *fill, const Surface *surface, const FillParams ¶ms, bool stop_vibrations, bool fill_gaps); + +class FillEnsuring : public Fill { public: Fill *clone() const override { return new FillEnsuring(*this); } ~FillEnsuring() override = default; Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override { return {}; }; - ThickPolylines fill_surface_arachne(const Surface *surface, const FillParams ¶ms) override; + ThickPolylines fill_surface_arachne(const Surface *surface, const FillParams ¶ms) override + { + return make_fill_polylines(this, surface, params, true, true); + }; protected: void fill_surface_single_arachne(const Surface &surface, const FillParams ¶ms, ThickPolylines &thick_polylines_out);