From 398222a49f3b32beee64324d1c6adef06b25ea44 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 3 Jan 2023 17:28:44 +0100 Subject: [PATCH] =?UTF-8?q?Cherry=20picked=20FillBoundedRectilinear=20Co-a?= =?UTF-8?q?uthored-by:=20Luk=C3=A1=C5=A1=20Hejl=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libslic3r/Fill/FillBase.cpp | 1 + src/libslic3r/Fill/FillBase.hpp | 4 ++ src/libslic3r/Fill/FillConcentric.cpp | 10 +-- src/libslic3r/Fill/FillConcentric.hpp | 5 -- src/libslic3r/Fill/FillRectilinear.cpp | 85 ++++++++++++++++++++++++++ src/libslic3r/Fill/FillRectilinear.hpp | 20 ++++++ src/libslic3r/Polyline.cpp | 13 ++++ src/libslic3r/Polyline.hpp | 5 ++ src/libslic3r/PrintConfig.hpp | 1 + 9 files changed, 131 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index b38c5c9f8..0bf3c4dde 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -49,6 +49,7 @@ Fill* Fill::new_from_type(const InfillPattern type) case ipSupportCubic: return new FillAdaptive::Filler(); case ipSupportBase: return new FillSupportBase(); case ipLightning: return new FillLightning::Filler(); + case ipBoundedRectilinear: return new FillBoundedRectilinear(); default: throw Slic3r::InvalidArgument("unknown type"); } } diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index 5200e1c0d..2a9091d35 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -91,6 +91,10 @@ public: // Octree builds on mesh for usage in the adaptive cubic infill FillAdaptive::Octree* adapt_fill_octree = nullptr; + // PrintConfig and PrintObjectConfig are used by infills that use Arachne (Concentric and FillBoundedRectilinear). + const PrintConfig *print_config = nullptr; + const PrintObjectConfig *print_object_config = nullptr; + public: virtual ~Fill() {} virtual Fill* clone() const = 0; diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp index 7b005ee35..245947cfe 100644 --- a/src/libslic3r/Fill/FillConcentric.cpp +++ b/src/libslic3r/Fill/FillConcentric.cpp @@ -97,14 +97,8 @@ void FillConcentric::_fill_surface_single(const FillParams ¶ms, continue; ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion); - if (extrusion->is_closed && thick_polyline.points.front() == thick_polyline.points.back() && thick_polyline.width.front() == thick_polyline.width.back()) { - thick_polyline.points.pop_back(); - assert(thick_polyline.points.size() * 2 == thick_polyline.width.size()); - int nearest_idx = nearest_point_index(thick_polyline.points, last_pos); - std::rotate(thick_polyline.points.begin(), thick_polyline.points.begin() + nearest_idx, thick_polyline.points.end()); - std::rotate(thick_polyline.width.begin(), thick_polyline.width.begin() + 2 * nearest_idx, thick_polyline.width.end()); - thick_polyline.points.emplace_back(thick_polyline.points.front()); - } + if (extrusion->is_closed) + thick_polyline.start_at_index(nearest_point_index(thick_polyline.points, last_pos)); thick_polylines_out.emplace_back(std::move(thick_polyline)); last_pos = thick_polylines_out.back().last_point(); } diff --git a/src/libslic3r/Fill/FillConcentric.hpp b/src/libslic3r/Fill/FillConcentric.hpp index 405b7238b..c059cc050 100644 --- a/src/libslic3r/Fill/FillConcentric.hpp +++ b/src/libslic3r/Fill/FillConcentric.hpp @@ -26,11 +26,6 @@ protected: ThickPolylines &thick_polylines_out) override; bool no_sort() const override { return true; } - - const PrintConfig *print_config = nullptr; - const PrintObjectConfig *print_object_config = nullptr; - - friend class Layer; }; } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index bb93d824b..c39ec8b1a 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -15,6 +15,7 @@ #include "../Geometry.hpp" #include "../Surface.hpp" #include "../ShortestPath.hpp" +#include "../Arachne/WallToolPaths.hpp" #include "FillRectilinear.hpp" @@ -3043,6 +3044,90 @@ Polylines FillSupportBase::fill_surface(const Surface *surface, const FillParams return polylines_out; } +ThickPolylines FillBoundedRectilinear::fill_surface_arachne(const Surface *surface, const FillParams ¶ms) +{ + // Perform offset. + Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing))); + // Create the infills for each of the regions. + ThickPolylines thick_polylines_out; + for (ExPolygon &ex_poly : expp) + _fill_surface_single(Surface(*surface, std::move(ex_poly)), params, thick_polylines_out); + + return thick_polylines_out; +} + +void FillBoundedRectilinear::_fill_surface_single(const Surface &surface, const FillParams ¶ms, ThickPolylines &thick_polylines_out) +{ + assert(params.use_arachne); + assert(this->print_config != nullptr && this->print_object_config != nullptr && this->print_region_config != nullptr); + + coord_t scaled_spacing = scaled(this->spacing); + Polygons polygons = offset(surface.expolygon, float(scaled_spacing) / 2.f); + Arachne::WallToolPaths wall_tool_paths(polygons, scaled_spacing, scaled_spacing, 1, 0, params.layer_height, *this->print_object_config, *this->print_config); + if (std::vector loop = wall_tool_paths.getToolPaths(); !loop.empty()) { + assert(loop.size() == 1); + + size_t firts_poly_idx = thick_polylines_out.size(); + Point last_pos(0, 0); + for (const Arachne::ExtrusionLine &extrusion : loop.front()) { + if (extrusion.empty()) + continue; + + ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion); + if (thick_polyline.length() == 0.) + //FIXME this should not happen. + continue; + assert(thick_polyline.size() > 1); + assert(thick_polyline.length() > 0.); + //assert(thick_polyline.points.size() == thick_polyline.width.size()); + if (extrusion.is_closed) + thick_polyline.start_at_index(nearest_point_index(thick_polyline.points, last_pos)); + + assert(thick_polyline.size() > 1); + //assert(thick_polyline.points.size() == thick_polyline.width.size()); + thick_polylines_out.emplace_back(std::move(thick_polyline)); + last_pos = thick_polylines_out.back().last_point(); + } + + // clip the paths to prevent the extruder from getting exactly on the first point of the loop + // Keep valid paths only. + size_t j = firts_poly_idx; + for (size_t i = firts_poly_idx; i < thick_polylines_out.size(); ++i) { + assert(thick_polylines_out[i].size() > 1); + assert(thick_polylines_out[i].length() > 0.); + //assert(thick_polylines_out[i].points.size() == thick_polylines_out[i].width.size()); + thick_polylines_out[i].clip_end(this->loop_clipping); + assert(thick_polylines_out[i].size() > 1); + if (thick_polylines_out[i].is_valid()) { + if (j < i) + thick_polylines_out[j] = std::move(thick_polylines_out[i]); + ++j; + } + } + if (j < thick_polylines_out.size()) + thick_polylines_out.erase(thick_polylines_out.begin() + int(j), thick_polylines_out.end()); + } + + // Remaining infill area will be filled with classic Rectilinear infill. + ExPolygons infill_contour = union_ex(wall_tool_paths.getInnerContour()); + if (offset_ex(infill_contour, -float(scaled_spacing / 2.)).empty()) + infill_contour.clear(); // Infill region is too small, so let's filter it out. + + Polygons pp; + for (ExPolygon &ex : infill_contour) + ex.simplify_p(scaled(params.resolution), &pp); + + // Collapse too narrow infill areas and append them to thick_polylines_out. + const auto min_perimeter_infill_spacing = coord_t(scaled_spacing * (1. - INSET_OVERLAP_TOLERANCE)); + const auto infill_overlap = coord_t(scale_(this->print_region_config->get_abs_value("infill_overlap", this->spacing))); + for (ExPolygon &ex_poly : offset2_ex(union_ex(pp), float(-min_perimeter_infill_spacing / 2.), float(infill_overlap + min_perimeter_infill_spacing / 2.))) { + Polylines polylines; + if (Surface new_surface(surface, std::move(ex_poly)); !fill_surface_by_lines(&new_surface, params, 0.f, 0.f, polylines)) + BOOST_LOG_TRIVIAL(error) << "FillBoundedRectilinear::fill_surface() failed to fill a region."; + append(thick_polylines_out, to_thick_polylines(std::move(polylines), scaled(this->spacing))); + } +} + // Lightning infill assumes that the distance between any two sampled points is always // at least equal to the value of spacing. To meet this assumption, we need to use // BoundingBox for whole layers instead of bounding box just around processing ExPolygon. diff --git a/src/libslic3r/Fill/FillRectilinear.hpp b/src/libslic3r/Fill/FillRectilinear.hpp index 0a6c976ad..9f833ea9e 100644 --- a/src/libslic3r/Fill/FillRectilinear.hpp +++ b/src/libslic3r/Fill/FillRectilinear.hpp @@ -7,6 +7,7 @@ namespace Slic3r { +class PrintRegionConfig; class Surface; class FillRectilinear : public Fill @@ -109,6 +110,25 @@ protected: float _layer_angle(size_t idx) const override { return 0.f; } }; +class FillBoundedRectilinear : public FillRectilinear +{ +public: + Fill *clone() const override { return new FillBoundedRectilinear(*this); } + ~FillBoundedRectilinear() override = default; + Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override { return {}; }; + ThickPolylines fill_surface_arachne(const Surface *surface, const FillParams ¶ms) override; + +protected: + void _fill_surface_single(const Surface &surface, const FillParams ¶ms, ThickPolylines &thick_polylines_out); + + bool no_sort() const override { return true; } + + // PrintRegionConfig is used for computing overlap between boundary contour and inner Rectilinear infill. + const PrintRegionConfig *print_region_config = nullptr; + + friend class Layer; +}; + Points sample_grid_pattern(const ExPolygon &expolygon, coord_t spacing, const BoundingBox &global_bounding_box); Points sample_grid_pattern(const ExPolygons &expolygons, coord_t spacing, const BoundingBox &global_bounding_box); Points sample_grid_pattern(const Polygons &polygons, coord_t spacing, const BoundingBox &global_bounding_box); diff --git a/src/libslic3r/Polyline.cpp b/src/libslic3r/Polyline.cpp index e2dcabfe1..d805473b5 100644 --- a/src/libslic3r/Polyline.cpp +++ b/src/libslic3r/Polyline.cpp @@ -292,6 +292,19 @@ void ThickPolyline::clip_end(double distance) assert(this->width.size() == (this->points.size() - 1) * 2); } +void ThickPolyline::start_at_index(int index) +{ + assert(index >= 0 && index < this->points.size()); + assert(this->points.front() == this->points.back() && this->width.front() == this->width.back()); + if (index != 0 && index != (this->points.size() - 1) && this->points.front() == this->points.back() && this->width.front() == this->width.back()) { + this->points.pop_back(); + assert(this->points.size() * 2 == this->width.size()); + std::rotate(this->points.begin(), this->points.begin() + index, this->points.end()); + std::rotate(this->width.begin(), this->width.begin() + 2 * index, this->width.end()); + this->points.emplace_back(this->points.front()); + } +} + double Polyline3::length() const { double l = 0; diff --git a/src/libslic3r/Polyline.hpp b/src/libslic3r/Polyline.hpp index de8f859a5..5615841e2 100644 --- a/src/libslic3r/Polyline.hpp +++ b/src/libslic3r/Polyline.hpp @@ -191,6 +191,11 @@ public: void clip_end(double distance); + // Make this closed ThickPolyline starting in the specified index. + // Be aware that this method can be applicable just for closed ThickPolyline. + // On open ThickPolyline make no effect. + void start_at_index(int index); + std::vector width; std::pair endpoints; }; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 7f8d5df12..edfac5f4f 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -60,6 +60,7 @@ enum InfillPattern : int { ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb, ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipSupportBase, ipLightning, + ipBoundedRectilinear, ipCount, };