diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm index 16c3b944c4..34829a2a2e 100644 --- a/lib/Slic3r/Print/SupportMaterial.pm +++ b/lib/Slic3r/Print/SupportMaterial.pm @@ -681,7 +681,7 @@ sub generate_toolpaths { # interface and contact infill if (@$interface || @$contact_infill) { $fillers{interface}->set_angle($interface_angle); - $fillers{interface}->set_spacing($_interface_flow->spacing); + $fillers{interface}->set_min_spacing($_interface_flow->spacing); # find centerline of the external loop $interface = offset2($interface, +scaled_epsilon, -(scaled_epsilon + $_interface_flow->scaled_width/2)); @@ -734,7 +734,7 @@ sub generate_toolpaths { # We don't use $base_flow->spacing because we need a constant spacing # value that guarantees that all layers are correctly aligned. - $filler->set_spacing($flow->spacing); + $filler->set_min_spacing($flow->spacing); my $density = $support_density; my $base_flow = $_flow; @@ -753,7 +753,7 @@ sub generate_toolpaths { # use the proper spacing for first layer as we don't need to align # its pattern to the other layers - $filler->set_spacing($base_flow->spacing); + $filler->set_min_spacing($base_flow->spacing); } else { # draw a perimeter all around support infill # TODO: use brim ordering algorithm diff --git a/t/fill.t b/t/fill.t index 7cea2726e5..a9e505c16e 100644 --- a/t/fill.t +++ b/t/fill.t @@ -30,7 +30,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } { my $filler = Slic3r::Filler->new_from_type('rectilinear'); $filler->set_angle(-(PI)/2); - $filler->set_spacing(5); + $filler->set_min_spacing(5); $filler->set_dont_adjust(1); $filler->set_endpoints_overlap(0); @@ -44,7 +44,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } }; # square - $filler->set_density($filler->spacing / 50); + $filler->set_density($filler->min_spacing / 50); for my $i (0..3) { # check that it works regardless of the points order my @points = ([0,0], [100,0], [100,100], [0,100]); @@ -64,7 +64,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } # square with hole for my $angle (-(PI/2), -(PI/4), -(PI), PI/2, PI) { for my $spacing (25, 5, 7.5, 8.5) { - $filler->set_density($filler->spacing / $spacing); + $filler->set_density($filler->min_spacing / $spacing); $filler->set_angle($angle); my $paths = $test->(my $e = Slic3r::ExPolygon->new( [ scale_points [0,0], [100,0], [100,100], [0,100] ], @@ -102,7 +102,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } height => 0.4, nozzle_diameter => 0.50, ); - $filler->set_spacing($flow->spacing); + $filler->set_min_spacing($flow->spacing); $filler->set_density(1); foreach my $angle (0, 45) { $surface->expolygon->rotate(Slic3r::Geometry::deg2rad($angle), [0,0]); @@ -128,7 +128,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } height => 0.4, nozzle_diameter => $flow_spacing, ); - $filler->set_spacing($flow->spacing); + $filler->set_min_spacing($flow->spacing); my $paths = $filler->fill_surface( $surface, layer_height => $flow->height, diff --git a/xs/src/libslic3r/Fill/Fill.cpp b/xs/src/libslic3r/Fill/Fill.cpp index 82a392943e..c88a32514a 100644 --- a/xs/src/libslic3r/Fill/Fill.cpp +++ b/xs/src/libslic3r/Fill/Fill.cpp @@ -52,7 +52,10 @@ Fill::fill_surface(const Surface &surface) if (this->density == 0) return Polylines(); // Perform offset. - ExPolygons expp = offset_ex(surface.expolygon, -scale_(this->spacing)/2); + ExPolygons expp = offset_ex(surface.expolygon, -scale_(this->min_spacing)/2); + + // Implementations can change this if they adjust the flow. + this->_spacing = this->min_spacing; // Create the infills for each of the regions. Polylines polylines_out; @@ -85,6 +88,8 @@ Fill::adjust_solid_spacing(const coord_t width, const coord_t distance) assert(factor > 1. - 1e-5); // How much could the extrusion width be increased? By 20%. + // Because of this limit, this method is not idempotent: each run + // will increment distance by 20%. const coordf_t factor_max = 1.2; if (factor > factor_max) distance_new = floor((double)distance * factor_max + 0.5); diff --git a/xs/src/libslic3r/Fill/Fill.hpp b/xs/src/libslic3r/Fill/Fill.hpp index a733a870db..151d61436b 100644 --- a/xs/src/libslic3r/Fill/Fill.hpp +++ b/xs/src/libslic3r/Fill/Fill.hpp @@ -27,7 +27,7 @@ public: coordf_t z; // in unscaled coordinates - coordf_t spacing; + coordf_t min_spacing; // overlap over spacing for extrusion endpoints float endpoints_overlap; @@ -78,11 +78,16 @@ public: // Perform the fill. virtual Polylines fill_surface(const Surface &surface); + coordf_t spacing() const { return this->_spacing; }; + protected: + // the actual one in unscaled coordinates, we fill this while generating paths + coordf_t _spacing; + Fill() : layer_id(size_t(-1)), z(0.f), - spacing(0.f), + min_spacing(0.f), endpoints_overlap(0.3f), angle(0), link_max_length(0), @@ -90,7 +95,8 @@ protected: density(0), dont_connect(false), dont_adjust(false), - complete(false) + complete(false), + _spacing(0.f) {}; typedef std::pair direction_t; diff --git a/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp index 3f523b27c9..4464cc877f 100644 --- a/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp +++ b/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp @@ -156,7 +156,7 @@ Fill3DHoneycomb::_fill_surface_single( { // no rotation is supported for this infill pattern BoundingBox bb = expolygon.contour.bounding_box(); - const coord_t distance = coord_t(scale_(this->spacing) / this->density); + const coord_t distance = coord_t(scale_(this->min_spacing) / this->density); // align bounding box to a multiple of our honeycomb grid module // (a module is 2*$distance since one $distance half-module is diff --git a/xs/src/libslic3r/Fill/FillConcentric.cpp b/xs/src/libslic3r/Fill/FillConcentric.cpp index cb09993b9e..24d8f318a1 100644 --- a/xs/src/libslic3r/Fill/FillConcentric.cpp +++ b/xs/src/libslic3r/Fill/FillConcentric.cpp @@ -15,13 +15,13 @@ FillConcentric::_fill_surface_single( { // no rotation is supported for this infill pattern - const coord_t min_spacing = scale_(this->spacing); + const coord_t min_spacing = scale_(this->min_spacing); coord_t distance = coord_t(min_spacing / this->density); if (this->density > 0.9999f && !this->dont_adjust) { BoundingBox bounding_box = expolygon.contour.bounding_box(); distance = this->adjust_solid_spacing(bounding_box.size().x, distance); - this->spacing = unscale(distance); + this->_spacing = unscale(distance); } Polygons loops = (Polygons)expolygon; diff --git a/xs/src/libslic3r/Fill/FillHoneycomb.cpp b/xs/src/libslic3r/Fill/FillHoneycomb.cpp index df4e62a3d1..02198bcd7d 100644 --- a/xs/src/libslic3r/Fill/FillHoneycomb.cpp +++ b/xs/src/libslic3r/Fill/FillHoneycomb.cpp @@ -14,12 +14,12 @@ FillHoneycomb::_fill_surface_single( Polylines* polylines_out) { // cache hexagons math - CacheID cache_id = std::make_pair(this->density, this->spacing); + CacheID cache_id = std::make_pair(this->density, this->min_spacing); 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); + coord_t min_spacing = scale_(this->min_spacing); m.distance = min_spacing / this->density; m.hex_side = m.distance / (sqrt(3)/2); m.hex_width = m.distance * 2; // $m->{hex_width} == $m->{hex_side} * sqrt(3); diff --git a/xs/src/libslic3r/Fill/FillPlanePath.cpp b/xs/src/libslic3r/Fill/FillPlanePath.cpp index 09b0ea7000..2b78f24e15 100644 --- a/xs/src/libslic3r/Fill/FillPlanePath.cpp +++ b/xs/src/libslic3r/Fill/FillPlanePath.cpp @@ -14,7 +14,7 @@ void FillPlanePath::_fill_surface_single( { expolygon.rotate(-direction.first); - const coord_t distance_between_lines = scale_(this->spacing) / this->density; + const coord_t distance_between_lines = scale_(this->min_spacing) / this->density; // align infill across layers using the object's bounding box (if available) BoundingBox bounding_box = this->bounding_box.defined diff --git a/xs/src/libslic3r/Fill/FillRectilinear.cpp b/xs/src/libslic3r/Fill/FillRectilinear.cpp index 286b1a5506..9af1842958 100644 --- a/xs/src/libslic3r/Fill/FillRectilinear.cpp +++ b/xs/src/libslic3r/Fill/FillRectilinear.cpp @@ -22,7 +22,7 @@ FillRectilinear::_fill_single_direction(ExPolygon expolygon, expolygon.rotate(-direction.first); assert(this->density > 0.0001f && this->density <= 1.f); - const coord_t min_spacing = scale_(this->spacing); + const coord_t min_spacing = scale_(this->min_spacing); coord_t line_spacing = (double) min_spacing / this->density; // We ignore this->bounding_box because it doesn't matter; we're doing align_to_grid below. @@ -36,7 +36,7 @@ FillRectilinear::_fill_single_direction(ExPolygon expolygon, // define flow spacing according to requested density if (this->density > 0.9999f && !this->dont_adjust) { line_spacing = this->adjust_solid_spacing(bounding_box.size().x, line_spacing); - this->spacing = unscale(line_spacing); + this->_spacing = unscale(line_spacing); } else { // extend bounding box so that our pattern will be aligned with other layers // Transform the reference point to the rotated coordinate system. @@ -451,7 +451,7 @@ void FillStars::_fill_surface_single( fill2._fill_single_direction(expolygon, direction2, 0, out); direction2.first += PI/3; - const coord_t x_shift = 0.5 * scale_(fill2.spacing) / fill2.density; + const coord_t x_shift = 0.5 * scale_(fill2.min_spacing) / fill2.density; fill2._fill_single_direction(expolygon, direction2, x_shift, out); } @@ -465,7 +465,7 @@ void FillCubic::_fill_surface_single( fill2.density /= 3.; direction_t direction2 = direction; - const coord_t range = scale_(this->spacing / this->density); + const coord_t range = scale_(this->min_spacing / this->density); const coord_t x_shift = abs(( (coord_t)(scale_(this->z) + range) % (coord_t)(range * 2)) - range); fill2._fill_single_direction(expolygon, direction2, -x_shift, out); diff --git a/xs/src/libslic3r/LayerRegionFill.cpp b/xs/src/libslic3r/LayerRegionFill.cpp index 142e4758f0..6beb82e365 100644 --- a/xs/src/libslic3r/LayerRegionFill.cpp +++ b/xs/src/libslic3r/LayerRegionFill.cpp @@ -211,13 +211,14 @@ LayerRegion::make_fill() -1, // auto width *this->layer()->object() ); - f->spacing = internal_flow.spacing(); + f->min_spacing = internal_flow.spacing(); using_internal_flow = true; } else { - f->spacing = flow.spacing(); + f->min_spacing = flow.spacing(); } + f->endpoints_overlap = this->region()->config.get_abs_value("infill_overlap", - (perimeter_spacing + scale_(f->spacing))/2); + (perimeter_spacing + scale_(f->min_spacing))/2); f->layer_id = this->layer()->id(); f->z = this->layer()->print_z; @@ -225,7 +226,7 @@ LayerRegion::make_fill() // Maximum length of the perimeter segment linking two infill lines. f->link_max_length = (!is_bridge && density > 80) - ? scale_(3 * f->spacing) + ? scale_(3 * f->min_spacing) : 0; // Used by the concentric infill pattern to clip the loops to create extrusion paths. @@ -243,9 +244,9 @@ LayerRegion::make_fill() if (using_internal_flow) { // if we used the internal flow we're not doing a solid infill // so we can safely ignore the slight variation that might have - // been applied to f->spacing + // been applied to f->spacing() } else { - flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, h, is_bridge || f->use_bridge_flow()); + flow = Flow::new_from_spacing(f->spacing(), flow.nozzle_diameter, h, is_bridge || f->use_bridge_flow()); } // Save into layer. diff --git a/xs/xsp/Filler.xsp b/xs/xsp/Filler.xsp index 7a3e995d34..0c5c08b6c7 100644 --- a/xs/xsp/Filler.xsp +++ b/xs/xsp/Filler.xsp @@ -14,10 +14,13 @@ void set_bounding_box(BoundingBox *bbox) %code{% THIS->fill->bounding_box = *bbox; %}; - void set_spacing(coordf_t spacing) - %code{% THIS->fill->spacing = spacing; %}; + void set_min_spacing(coordf_t spacing) + %code{% THIS->fill->min_spacing = spacing; %}; + coordf_t min_spacing() + %code{% RETVAL = THIS->fill->min_spacing; %}; + coordf_t spacing() - %code{% RETVAL = THIS->fill->spacing; %}; + %code{% RETVAL = THIS->fill->spacing(); %}; void set_endpoints_overlap(float overlap) %code{% THIS->fill->endpoints_overlap = overlap; %};