From 348c654c26d8eb8a7db283b85ec1787694aa5540 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 18 Sep 2020 13:35:17 +0200 Subject: [PATCH] Adaptive infill: Fixing compilation on Linux, WIP: Better chainining of infill lines. --- src/libslic3r/Fill/FillAdaptive.cpp | 80 ++++++++++++++++++++++------- src/libslic3r/Fill/FillBase.cpp | 18 ++++--- 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index b016242f4..54ac6c262 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -434,6 +434,64 @@ static void generate_infill_lines_recursive( } } +#if 0 +// Collect the line segments. +static Polylines chain_lines(const std::vector &lines, const double point_distance_epsilon) +{ + // Create line end point lookup. + struct LineEnd { + LineEnd(Line *line, bool start) : line(line), start(start) {} + Line *line; + // Is it the start or end point? + bool start; + const Point& point() const { return start ? line->a : line->b; } + const Point& other_point() const { return start ? line->b : line->a; } + LineEnd other_end() const { return LineEnd(line, ! start); } + bool operator==(const LineEnd &rhs) const { return this->line == rhs.line && this->start == rhs.start; } + }; + struct LineEndAccessor { + const Point* operator()(const LineEnd &pt) const { return &pt.point(); } + }; + typedef ClosestPointInRadiusLookup ClosestPointLookupType; + ClosestPointLookupType closest_end_point_lookup(point_distance_epsilon); + for (const Line &line : lines) { + closest_end_point_lookup.insert(LineEnd(&line, true)); + closest_end_point_lookup.insert(LineEnd(&line, false)); + } + + // Chain the lines. + std::vector line_consumed(lines.size(), false); + static const double point_distance_epsilon2 = point_distance_epsilon * point_distance_epsilon; + Polylines out; + for (const Line &seed : lines) + if (! line_consumed[&seed - lines.data()]) { + line_consumed[&seed - lines.data()] = true; + closest_end_point_lookup.erase(LineEnd(&seed, false)); + closest_end_point_lookup.erase(LineEnd(&seed, true)); + Polyline pl { seed.a, seed.b }; + for (size_t round = 0; round < 2; ++ round) { + for (;;) { + auto [line_end, dist2] = closest_end_point_lookup.find(pl.last_point()); + if (line_end == nullptr || dist2 >= point_distance_epsilon2) + // Cannot extent in this direction. + break; + // Average the last point. + pl.points.back() = 0.5 * (pl.points.back() + line_end->point()); + // and extend with the new line segment. + pl.points.emplace_back(line_end->other_point()); + closest_end_point_lookup.erase(line_end); + closest_end_point_lookup.erase(line_end->other_end()); + line_consumed[line_end->line - lines.data()] = true; + } + // reverse and try the oter direction. + pl.reverse(); + } + out.emplace_back(std::move(pl)); + } + return out; +} +#endif + #ifndef NDEBUG // #define ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT #endif @@ -517,6 +575,7 @@ void Filler::_fill_surface_single( lines.emplace_back(line); } // Convert lines to polylines. + //FIXME chain the lines all_polylines.reserve(lines.size()); std::transform(lines.begin(), lines.end(), std::back_inserter(all_polylines), [](const Line& l) { return Polyline{ l.a, l.b }; }); } @@ -533,23 +592,8 @@ void Filler::_fill_surface_single( if (params.dont_connect) append(polylines_out, std::move(all_polylines)); - else { - Polylines boundary_polylines; - Polylines non_boundary_polylines; - for (const Polyline &polyline : all_polylines) - // connect_infill required all polylines to touch the boundary. - if (polyline.lines().size() == 1 && expolygon.has_boundary_point(polyline.lines().front().a) && expolygon.has_boundary_point(polyline.lines().front().b)) - boundary_polylines.push_back(polyline); - else - non_boundary_polylines.push_back(polyline); - - if (!boundary_polylines.empty()) { - boundary_polylines = chain_polylines(boundary_polylines); - connect_infill(std::move(boundary_polylines), expolygon, polylines_out, this->spacing, params); - } - - append(polylines_out, std::move(non_boundary_polylines)); - } + else + connect_infill(chain_polylines(std::move(all_polylines)), expolygon, polylines_out, this->spacing, params); #ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT { @@ -618,7 +662,7 @@ OctreePtr build_octree(const indexed_triangle_set &triangle_mesh, coordf_t line_ auto octree = OctreePtr(new Octree(cube_center, cubes_properties)); if (cubes_properties.size() > 1) { - auto up_vector = support_overhangs_only ? transform_to_octree() * Vec3d(0., 0., 1.) : Vec3d(); + auto up_vector = support_overhangs_only ? Vec3d(transform_to_octree() * Vec3d(0., 0., 1.)) : Vec3d(); for (auto &tri : triangle_mesh.indices) { auto a = triangle_mesh.vertices[tri[0]].cast(); auto b = triangle_mesh.vertices[tri[1]].cast(); diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 43b5d464a..fc5f548a3 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -847,8 +847,9 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_ boundary.assign(boundary_src.holes.size() + 1, Points()); boundary_data.assign(boundary_src.holes.size() + 1, std::vector()); // Mapping the infill_ordered end point to a (contour, point) of boundary. - std::vector> map_infill_end_point_to_boundary; - map_infill_end_point_to_boundary.assign(infill_ordered.size() * 2, std::pair(std::numeric_limits::max(), std::numeric_limits::max())); + std::vector> map_infill_end_point_to_boundary; + static constexpr auto boundary_idx_unconnected = std::numeric_limits::max(); + map_infill_end_point_to_boundary.assign(infill_ordered.size() * 2, std::pair(boundary_idx_unconnected, boundary_idx_unconnected)); { // Project the infill_ordered end points onto boundary_src. std::vector> intersection_points; @@ -898,13 +899,14 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_ contour_data.front().param = contour_data.back().param + (contour_dst.back().cast() - contour_dst.front().cast()).norm(); } -#ifndef NDEBUG assert(boundary.size() == boundary_src.num_contours()); - assert(std::all_of(map_infill_end_point_to_boundary.begin(), map_infill_end_point_to_boundary.end(), +#if 0 + // Adaptive Cubic Infill produces infill lines, which not always end at the outer boundary. + assert(std::all_of(map_infill_end_point_to_boundary.begin(), map_infill_end_point_to_boundary.end(), [&boundary](const std::pair &contour_point) { return contour_point.first < boundary.size() && contour_point.second < boundary[contour_point.first].size(); })); -#endif /* NDEBUG */ +#endif } // Mark the points and segments of split boundary as consumed if they are very close to some of the infill line. @@ -935,9 +937,9 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_ const Polyline &pl2 = infill_ordered[idx_chain]; const std::pair *cp1 = &map_infill_end_point_to_boundary[(idx_chain - 1) * 2 + 1]; const std::pair *cp2 = &map_infill_end_point_to_boundary[idx_chain * 2]; - const std::vector &contour_data = boundary_data[cp1->first]; - if (cp1->first == cp2->first) { + if (cp1->first != boundary_idx_unconnected && cp1->first == cp2->first) { // End points on the same contour. Try to connect them. + const std::vector &contour_data = boundary_data[cp1->first]; float param_lo = (cp1->second == 0) ? 0.f : contour_data[cp1->second].param; float param_hi = (cp2->second == 0) ? 0.f : contour_data[cp2->second].param; float param_end = contour_data.front().param; @@ -964,7 +966,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_ const std::pair *cp1prev = cp1 - 1; const std::pair *cp2 = &map_infill_end_point_to_boundary[(connection_cost.idx_first + 1) * 2]; const std::pair *cp2next = cp2 + 1; - assert(cp1->first == cp2->first); + assert(cp1->first == cp2->first && cp1->first != boundary_idx_unconnected); std::vector &contour_data = boundary_data[cp1->first]; if (connection_cost.reversed) std::swap(cp1, cp2);