From 812cbade4d6cd8f157f39d78daafbaa13e030540 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 16 Nov 2020 12:51:51 +0100 Subject: [PATCH] Fills: 1) New algorithm for connecting along the perimeters is now applied to Honeycomb, Hilbert and similar planar filling curves. 2) The old expensive path chaining is not applied if the new algorithm to connect along the perimeter lines is called afterwards. --- src/libslic3r/Fill/Fill3DHoneycomb.cpp | 12 ++- src/libslic3r/Fill/FillAdaptive.cpp | 4 +- src/libslic3r/Fill/FillGyroid.cpp | 3 +- src/libslic3r/Fill/FillHoneycomb.cpp | 78 +++++-------------- src/libslic3r/Fill/FillPlanePath.cpp | 101 ++++++++++--------------- src/libslic3r/SupportMaterial.cpp | 2 - xs/xsp/Filler.xsp | 2 - 7 files changed, 69 insertions(+), 133 deletions(-) diff --git a/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/src/libslic3r/Fill/Fill3DHoneycomb.cpp index 8aac6e49c8..144a275059 100644 --- a/src/libslic3r/Fill/Fill3DHoneycomb.cpp +++ b/src/libslic3r/Fill/Fill3DHoneycomb.cpp @@ -162,15 +162,13 @@ void Fill3DHoneycomb::_fill_surface_single( pl.translate(bb.min); // clip pattern to boundaries, chain the clipped polylines - Polylines polylines_chained = chain_polylines(intersection_pl(polylines, to_polygons(expolygon))); + polylines = intersection_pl(polylines, to_polygons(expolygon)); // connect lines if needed - if (! polylines_chained.empty()) { - if (params.dont_connect) - append(polylines_out, std::move(polylines_chained)); - else - this->connect_infill(std::move(polylines_chained), expolygon, polylines_out, this->spacing, params); - } + if (params.dont_connect || polylines.size() <= 1) + append(polylines_out, chain_polylines(std::move(polylines))); + else + this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params); } } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 188deca7c1..a1d592bc3a 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -1333,9 +1333,9 @@ void Filler::_fill_surface_single( #endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */ if (params.dont_connect || all_polylines_with_hooks.size() <= 1) - append(polylines_out, std::move(all_polylines_with_hooks)); + append(polylines_out, chain_polylines(std::move(all_polylines_with_hooks))); else - connect_infill(chain_polylines(std::move(all_polylines_with_hooks)), expolygon, polylines_out, this->spacing, params); + connect_infill(std::move(all_polylines_with_hooks), expolygon, polylines_out, this->spacing, params); #ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT { diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index 964b87cefc..b0cd507bc0 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -190,11 +190,10 @@ void FillGyroid::_fill_surface_single( polylines.end()); if (! polylines.empty()) { - polylines = chain_polylines(polylines); // connect lines size_t polylines_out_first_idx = polylines_out.size(); if (params.dont_connect) - append(polylines_out, std::move(polylines)); + append(polylines_out, chain_polylines(polylines)); else this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params); diff --git a/src/libslic3r/Fill/FillHoneycomb.cpp b/src/libslic3r/Fill/FillHoneycomb.cpp index 948af182bb..aa0157fb9a 100644 --- a/src/libslic3r/Fill/FillHoneycomb.cpp +++ b/src/libslic3r/Fill/FillHoneycomb.cpp @@ -18,21 +18,21 @@ void FillHoneycomb::_fill_surface_single( Cache::iterator it_m = this->cache.find(cache_id); if (it_m == this->cache.end()) { it_m = this->cache.insert(it_m, std::pair(cache_id, CacheData())); - CacheData &m = it_m->second; - coord_t min_spacing = scale_(this->spacing); - m.distance = min_spacing / params.density; - m.hex_side = m.distance / (sqrt(3)/2); - m.hex_width = m.distance * 2; // $m->{hex_width} == $m->{hex_side} * sqrt(3); - coord_t hex_height = m.hex_side * 2; - m.pattern_height = hex_height + m.hex_side; - m.y_short = m.distance * sqrt(3)/3; - m.x_offset = min_spacing / 2; - m.y_offset = m.x_offset * sqrt(3)/3; - m.hex_center = Point(m.hex_width/2, m.hex_side); + CacheData &m = it_m->second; + coord_t min_spacing = coord_t(scale_(this->spacing)); + m.distance = coord_t(min_spacing / params.density); + m.hex_side = coord_t(m.distance / (sqrt(3)/2)); + m.hex_width = m.distance * 2; // $m->{hex_width} == $m->{hex_side} * sqrt(3); + coord_t hex_height = m.hex_side * 2; + m.pattern_height = hex_height + m.hex_side; + m.y_short = coord_t(m.distance * sqrt(3)/3); + m.x_offset = min_spacing / 2; + m.y_offset = coord_t(m.x_offset * sqrt(3)/3); + m.hex_center = Point(m.hex_width/2, m.hex_side); } CacheData &m = it_m->second; - Polygons polygons; + Polylines all_polylines; { // adjust actual bounding box to the nearest multiple of our hex pattern // and align it so that it matches across layers @@ -52,7 +52,7 @@ void FillHoneycomb::_fill_surface_single( coord_t x = bounding_box.min(0); while (x <= bounding_box.max(0)) { - Polygon p; + Polyline p; coord_t ax[2] = { x + m.x_offset, x + m.distance - m.x_offset }; for (size_t i = 0; i < 2; ++ i) { std::reverse(p.points.begin(), p.points.end()); // turn first half upside down @@ -69,55 +69,15 @@ void FillHoneycomb::_fill_surface_single( x += m.distance; } p.rotate(-direction.first, m.hex_center); - polygons.push_back(p); + all_polylines.push_back(p); } } - if (params.complete || true) { - // we were requested to complete each loop; - // in this case we don't try to make more continuous paths - Polygons polygons_trimmed = intersection((Polygons)expolygon, polygons); - for (Polygons::iterator it = polygons_trimmed.begin(); it != polygons_trimmed.end(); ++ it) - polylines_out.push_back(it->split_at_first_point()); - } else { - // consider polygons as polylines without re-appending the initial point: - // this cuts the last segment on purpose, so that the jump to the next - // path is more straight - Polylines paths; - { - Polylines p; - for (Polygon &poly : polygons) - p.emplace_back(poly.points); - paths = intersection_pl(p, to_polygons(expolygon)); - } - - // connect paths - if (! paths.empty()) { // prevent calling leftmost_point() on empty collections - Polylines chained = chain_polylines(std::move(paths)); - assert(paths.empty()); - paths.clear(); - for (Polyline &path : chained) { - if (! paths.empty()) { - // distance between first point of this path and last point of last path - double distance = (path.first_point() - paths.back().last_point()).cast().norm(); - if (distance <= m.hex_width) { - paths.back().points.insert(paths.back().points.end(), path.points.begin(), path.points.end()); - continue; - } - } - // Don't connect the paths. - paths.push_back(std::move(path)); - } - } - - // clip paths again to prevent connection segments from crossing the expolygon boundaries - paths = intersection_pl(paths, to_polygons(offset_ex(expolygon, SCALED_EPSILON))); - // Move the polylines to the output, avoid a deep copy. - size_t j = polylines_out.size(); - polylines_out.resize(j + paths.size(), Polyline()); - for (size_t i = 0; i < paths.size(); ++ i) - std::swap(polylines_out[j ++], paths[i]); - } + all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon)); + if (params.dont_connect || all_polylines.size() <= 1) + append(polylines_out, chain_polylines(std::move(all_polylines))); + else + connect_infill(std::move(all_polylines), expolygon, polylines_out, this->spacing, params); } } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillPlanePath.cpp b/src/libslic3r/Fill/FillPlanePath.cpp index 7a322ce991..002fcadc0d 100644 --- a/src/libslic3r/Fill/FillPlanePath.cpp +++ b/src/libslic3r/Fill/FillPlanePath.cpp @@ -1,4 +1,5 @@ #include "../ClipperUtils.hpp" +#include "../ShortestPath.hpp" #include "../Surface.hpp" #include "FillPlanePath.hpp" @@ -23,14 +24,14 @@ void FillPlanePath::_fill_surface_single( Point shift = this->_centered() ? bounding_box.center() : bounding_box.min; - expolygon.translate(-shift(0), -shift(1)); - bounding_box.translate(-shift(0), -shift(1)); + expolygon.translate(-shift.x(), -shift.y()); + bounding_box.translate(-shift.x(), -shift.y()); Pointfs pts = _generate( - coord_t(ceil(coordf_t(bounding_box.min(0)) / distance_between_lines)), - coord_t(ceil(coordf_t(bounding_box.min(1)) / distance_between_lines)), - coord_t(ceil(coordf_t(bounding_box.max(0)) / distance_between_lines)), - coord_t(ceil(coordf_t(bounding_box.max(1)) / distance_between_lines))); + coord_t(ceil(coordf_t(bounding_box.min.x()) / distance_between_lines)), + coord_t(ceil(coordf_t(bounding_box.min.y()) / distance_between_lines)), + coord_t(ceil(coordf_t(bounding_box.max.x()) / distance_between_lines)), + coord_t(ceil(coordf_t(bounding_box.max.y()) / distance_between_lines))); Polylines polylines; if (pts.size() >= 2) { @@ -38,39 +39,24 @@ void FillPlanePath::_fill_surface_single( polylines.push_back(Polyline()); Polyline &polyline = polylines.back(); polyline.points.reserve(pts.size()); - for (Pointfs::iterator it = pts.begin(); it != pts.end(); ++ it) + for (const Vec2d &pt : pts) polyline.points.push_back(Point( - coord_t(floor((*it)(0) * distance_between_lines + 0.5)), - coord_t(floor((*it)(1) * distance_between_lines + 0.5)))); + coord_t(floor(pt.x() * distance_between_lines + 0.5)), + coord_t(floor(pt.y() * distance_between_lines + 0.5)))); // intersection(polylines_src, offset((Polygons)expolygon, scale_(0.02)), &polylines); - polylines = intersection_pl(polylines, to_polygons(expolygon)); - -/* - if (1) { - require "Slic3r/SVG.pm"; - print "Writing fill.svg\n"; - Slic3r::SVG::output("fill.svg", - no_arrows => 1, - polygons => \@$expolygon, - green_polygons => [ $bounding_box->polygon ], - polylines => [ $polyline ], - red_polylines => \@paths, - ); - } -*/ - + polylines = intersection_pl(std::move(polylines), to_polygons(expolygon)); + Polylines chained; + if (params.dont_connect || params.density > 0.5 || polylines.size() <= 1) + chained = chain_polylines(std::move(polylines)); + else + connect_infill(std::move(polylines), expolygon, chained, this->spacing, params); // paths must be repositioned and rotated back - for (Polylines::iterator it = polylines.begin(); it != polylines.end(); ++ it) { - it->translate(shift(0), shift(1)); - it->rotate(direction.first); + for (Polyline &pl : chained) { + pl.translate(shift.x(), shift.y()); + pl.rotate(direction.first); } + append(polylines_out, std::move(chained)); } - - // Move the polylines to the output, avoid a deep copy. - size_t j = polylines_out.size(); - polylines_out.resize(j + polylines.size(), Polyline()); - for (size_t i = 0; i < polylines.size(); ++ i) - std::swap(polylines_out[j ++], polylines[i]); } // Follow an Archimedean spiral, in polar coordinates: r=a+b\theta @@ -85,13 +71,13 @@ Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t m coordf_t r = 1; Pointfs out; //FIXME Vojtech: If used as a solid infill, there is a gap left at the center. - out.push_back(Vec2d(0, 0)); - out.push_back(Vec2d(1, 0)); + out.emplace_back(0, 0); + out.emplace_back(1, 0); while (r < rmax) { // Discretization angle to achieve a discretization error lower than RESOLUTION. theta += 2. * acos(1. - RESOLUTION / r); r = a + b * theta; - out.push_back(Vec2d(r * cos(theta), r * sin(theta))); + out.emplace_back(r * cos(theta), r * sin(theta)); } return out; } @@ -128,15 +114,12 @@ static inline Point hilbert_n_to_xy(const size_t n) ++ ndigits; } } - int state = (ndigits & 1) ? 4 : 0; -// int dirstate = (ndigits & 1) ? 0 : 4; + int state = (ndigits & 1) ? 4 : 0; coord_t x = 0; coord_t y = 0; for (int i = (int)ndigits - 1; i >= 0; -- i) { int digit = (n >> (i * 2)) & 3; state += digit; -// if (digit != 3) -// dirstate = state; // lowest non-3 digit x |= digit_to_x[state] << i; y |= digit_to_y[state] << i; state = next_state[state]; @@ -162,7 +145,7 @@ Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, line.reserve(sz2); for (size_t i = 0; i < sz2; ++ i) { Point p = hilbert_n_to_xy(i); - line.push_back(Vec2d(p(0) + min_x, p(1) + min_y)); + line.emplace_back(p.x() + min_x, p.y() + min_y); } return line; } @@ -175,27 +158,27 @@ Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_ coordf_t r = 0; coordf_t r_inc = sqrt(2.); Pointfs out; - out.push_back(Vec2d(0, 0)); + out.emplace_back(0., 0.); while (r < rmax) { r += r_inc; coordf_t rx = r / sqrt(2.); coordf_t r2 = r + rx; - out.push_back(Vec2d( r, 0.)); - out.push_back(Vec2d( r2, rx)); - out.push_back(Vec2d( rx, rx)); - out.push_back(Vec2d( rx, r2)); - out.push_back(Vec2d(0., r)); - out.push_back(Vec2d(-rx, r2)); - out.push_back(Vec2d(-rx, rx)); - out.push_back(Vec2d(-r2, rx)); - out.push_back(Vec2d(-r, 0.)); - out.push_back(Vec2d(-r2, -rx)); - out.push_back(Vec2d(-rx, -rx)); - out.push_back(Vec2d(-rx, -r2)); - out.push_back(Vec2d(0., -r)); - out.push_back(Vec2d( rx, -r2)); - out.push_back(Vec2d( rx, -rx)); - out.push_back(Vec2d( r2+r_inc, -rx)); + out.emplace_back( r, 0.); + out.emplace_back( r2, rx); + out.emplace_back( rx, rx); + out.emplace_back( rx, r2); + out.emplace_back( 0., r); + out.emplace_back(-rx, r2); + out.emplace_back(-rx, rx); + out.emplace_back(-r2, rx); + out.emplace_back(- r, 0.); + out.emplace_back(-r2, -rx); + out.emplace_back(-rx, -rx); + out.emplace_back(-rx, -r2); + out.emplace_back( 0., -r); + out.emplace_back( rx, -r2); + out.emplace_back( rx, -rx); + out.emplace_back( r2+r_inc, -rx); } return out; } diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 1669f60d21..a27b857349 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -2324,7 +2324,6 @@ static inline void fill_expolygons_generate_paths( { FillParams fill_params; fill_params.density = density; - fill_params.complete = true; fill_params.dont_adjust = true; for (const ExPolygon &expoly : expolygons) { Surface surface(stInternal, expoly); @@ -2351,7 +2350,6 @@ static inline void fill_expolygons_generate_paths( { FillParams fill_params; fill_params.density = density; - fill_params.complete = true; fill_params.dont_adjust = true; for (ExPolygon &expoly : expolygons) { Surface surface(stInternal, std::move(expoly)); diff --git a/xs/xsp/Filler.xsp b/xs/xsp/Filler.xsp index caeb2af9aa..2ea2b34d5a 100644 --- a/xs/xsp/Filler.xsp +++ b/xs/xsp/Filler.xsp @@ -36,8 +36,6 @@ %code{% THIS->params.density = density; %}; void set_dont_adjust(bool dont_adjust) %code{% THIS->params.dont_adjust = dont_adjust; %}; - void set_complete(bool complete) - %code{% THIS->params.complete = complete; %}; PolylineCollection* _fill_surface(Surface *surface) %code{%