diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 23799e8bed..3b0bfea252 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -255,134 +255,6 @@ EOF print "Done.\n" unless $params{quiet}; } -sub make_skirt { - my $self = shift; - - # prerequisites - $_->make_perimeters for @{$self->objects}; - $_->infill for @{$self->objects}; - $_->generate_support_material for @{$self->objects}; - - return if $self->step_done(STEP_SKIRT); - $self->set_step_started(STEP_SKIRT); - - # since this method must be idempotent, we clear skirt paths *before* - # checking whether we need to generate them - $self->skirt->clear; - - if (!$self->has_skirt) { - $self->set_step_done(STEP_SKIRT); - return; - } - $self->status_cb->(88, "Generating skirt"); - - # First off we need to decide how tall the skirt must be. - # The skirt_height option from config is expressed in layers, but our - # object might have different layer heights, so we need to find the print_z - # of the highest layer involved. - # Note that unless has_infinite_skirt() == true - # the actual skirt might not reach this $skirt_height_z value since the print - # order of objects on each layer is not guaranteed and will not generally - # include the thickest object first. It is just guaranteed that a skirt is - # prepended to the first 'n' layers (with 'n' = skirt_height). - # $skirt_height_z in this case is the highest possible skirt height for safety. - my $skirt_height_z = -1; - foreach my $object (@{$self->objects}) { - my $skirt_height = $self->has_infinite_skirt - ? $object->layer_count - : min($self->config->skirt_height, $object->layer_count); - my $highest_layer = $object->get_layer($skirt_height - 1); - $skirt_height_z = max($skirt_height_z, $highest_layer->print_z); - } - - # collect points from all layers contained in skirt height - my @points = (); - foreach my $object (@{$self->objects}) { - my @object_points = (); - - # get object layers up to $skirt_height_z - foreach my $layer (@{$object->layers}) { - last if $layer->print_z > $skirt_height_z; - push @object_points, map @$_, map @$_, @{$layer->slices}; - } - - # get support layers up to $skirt_height_z - foreach my $layer (@{$object->support_layers}) { - last if $layer->print_z > $skirt_height_z; - push @object_points, map @{$_->polyline}, @{$layer->support_fills} if $layer->support_fills; - push @object_points, map @{$_->polyline}, @{$layer->support_interface_fills} if $layer->support_interface_fills; - } - - # repeat points for each object copy - foreach my $copy (@{$object->_shifted_copies}) { - my @copy_points = map $_->clone, @object_points; - $_->translate(@$copy) for @copy_points; - push @points, @copy_points; - } - } - return if @points < 3; # at least three points required for a convex hull - - # find out convex hull - my $convex_hull = convex_hull(\@points); - - my @extruded_length = (); # for each extruder - - # skirt may be printed on several layers, having distinct layer heights, - # but loops must be aligned so can't vary width/spacing - # TODO: use each extruder's own flow - my $first_layer_height = $self->skirt_first_layer_height; - my $flow = $self->skirt_flow; - my $spacing = $flow->spacing; - my $mm3_per_mm = $flow->mm3_per_mm; - - my @extruders_e_per_mm = (); - my $extruder_idx = 0; - - my $skirts = $self->config->skirts; - $skirts ||= 1 if $self->has_infinite_skirt; - - # draw outlines from outside to inside - # loop while we have less skirts than required or any extruder hasn't reached the min length if any - my $distance = scale max($self->config->skirt_distance, $self->config->brim_width); - for (my $i = $skirts; $i > 0; $i--) { - $distance += scale $spacing; - my $loop = offset([$convex_hull], $distance, 1, JT_ROUND, scale(0.1))->[0]; - my $eloop = Slic3r::ExtrusionLoop->new_from_paths( - Slic3r::ExtrusionPath->new( - polyline => Slic3r::Polygon->new(@$loop)->split_at_first_point, - role => EXTR_ROLE_SKIRT, - mm3_per_mm => $mm3_per_mm, # this will be overridden at G-code export time - width => $flow->width, - height => $first_layer_height, # this will be overridden at G-code export time - ), - ); - $eloop->role(EXTRL_ROLE_SKIRT); - $self->skirt->append($eloop); - - if ($self->config->min_skirt_length > 0) { - $extruded_length[$extruder_idx] ||= 0; - if (!$extruders_e_per_mm[$extruder_idx]) { - my $config = Slic3r::Config::GCode->new; - $config->apply_static($self->config); - my $extruder = Slic3r::Extruder->new($extruder_idx, $config); - $extruders_e_per_mm[$extruder_idx] = $extruder->e_per_mm($mm3_per_mm); - } - $extruded_length[$extruder_idx] += unscale $loop->length * $extruders_e_per_mm[$extruder_idx]; - $i++ if defined first { ($extruded_length[$_] // 0) < $self->config->min_skirt_length } 0 .. $#{$self->extruders}; - if ($extruded_length[$extruder_idx] >= $self->config->min_skirt_length) { - if ($extruder_idx < $#{$self->extruders}) { - $extruder_idx++; - next; - } - } - } - } - - $self->skirt->reverse; - - $self->set_step_done(STEP_SKIRT); -} - sub make_brim { my $self = shift; diff --git a/xs/src/libslic3r/ExPolygonCollection.hpp b/xs/src/libslic3r/ExPolygonCollection.hpp index 4c97f2610b..e2638a2653 100644 --- a/xs/src/libslic3r/ExPolygonCollection.hpp +++ b/xs/src/libslic3r/ExPolygonCollection.hpp @@ -45,6 +45,8 @@ class ExPolygonCollection size_t size() const { return expolygons.size(); } ExPolygons::iterator begin() { return expolygons.begin(); } ExPolygons::iterator end() { return expolygons.end(); } + const ExPolygons::const_iterator begin() const { return expolygons.cbegin(); } + const ExPolygons::const_iterator end() const { return expolygons.cend(); } ExPolygons::const_iterator cbegin() const { return expolygons.cbegin();} ExPolygons::const_iterator cend() const { return expolygons.cend();} ExPolygon& at(size_t i) { return expolygons.at(i); } diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.hpp b/xs/src/libslic3r/ExtrusionEntityCollection.hpp index 819a1bc2c4..eaad7d97bb 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.hpp @@ -74,6 +74,8 @@ class ExtrusionEntityCollection : public ExtrusionEntity ExtrusionEntitiesPtr::iterator begin() { return entities.begin(); } ExtrusionEntitiesPtr::iterator end() { return entities.end(); } + ExtrusionEntitiesPtr::const_iterator begin() const { return entities.cbegin(); } + ExtrusionEntitiesPtr::const_iterator end() const { return entities.cend(); } ExtrusionEntitiesPtr::const_iterator cbegin() const { return entities.cbegin(); } ExtrusionEntitiesPtr::const_iterator cend() const { return entities.cend(); } diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 728b5dacbe..487a5b4187 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -140,16 +140,16 @@ Print::make_brim() void Print::make_skirt() { + if (this->state.is_done(psSkirt)) return; + this->state.set_started(psSkirt); + // prereqs - for(auto& obj: this->objects) { + for (auto* obj: this->objects) { obj->make_perimeters(); obj->infill(); obj->generate_support_material(); } - if (this->state.is_done(psSkirt)) return; - this->state.set_started(psSkirt); - // since this method must be idempotent, we clear skirt paths *before* // checking whether we need to generate them this->skirt.clear(); @@ -173,10 +173,11 @@ Print::make_skirt() // prepended to the first 'n' layers (with 'n' = skirt_height). // $skirt_height_z in this case is the highest possible skirt height for safety. double skirt_height_z {-1.0}; - for (const auto& object : this->objects) { + for (const auto* object : this->objects) { const size_t skirt_height { - this->has_infinite_skirt() ? object->layer_count() : - std::min(size_t(this->config.skirt_height()), object->layer_count()) + this->has_infinite_skirt() + ? object->layer_count() + : std::min(size_t(this->config.skirt_height()), object->layer_count()) }; const Layer* highest_layer { object->get_layer(skirt_height - 1) }; skirt_height_z = std::max(skirt_height_z, highest_layer->print_z); @@ -184,116 +185,83 @@ Print::make_skirt() // collect points from all layers contained in skirt height Points points; - for(auto* object : this->objects) { + for (auto* object : this->objects) { Points object_points; // get object layers up to skirt_height_z - for(auto* layer : object->layers) { - if(layer->print_z > skirt_height_z)break; - for(ExPolygon poly : layer->slices){ - for(Point point : static_cast(poly)){ - object_points.push_back(point); - } - } + for (const auto* layer : object->layers) { + if (layer->print_z > skirt_height_z) break; + for (const ExPolygon ex : layer->slices) + append_to(object_points, static_cast(ex)); } - // get support layers up to $skirt_height_z - for(auto* layer : object->support_layers) { - if(layer->print_z > skirt_height_z)break; - for(auto* ee : layer->support_fills){ - for(Point point : ee->as_polyline().points){ - object_points.push_back(point); - } - } - for(auto* ee : layer->support_interface_fills){ - for(Point point : ee->as_polyline().points){ - object_points.push_back(point); - } - } + // get support layers up to skirt_height_z + for (const auto* layer : object->support_layers) { + if (layer->print_z > skirt_height_z) break; + for (auto* ee : layer->support_fills) + append_to(object_points, ee->as_polyline().points); + for (auto* ee : layer->support_interface_fills) + append_to(object_points, ee->as_polyline().points); } // repeat points for each object copy - for(auto copy : object->_shifted_copies) { - for(Point point : object_points){ - point.translate(copy); - points.push_back(point); + for (const auto& copy : object->_shifted_copies) { + for (Point p : object_points) { + p.translate(copy); + points.push_back(p); } } } if (points.size() < 3) return; // at least three points required for a convex hull // find out convex hull - auto convex = Geometry::convex_hull(points); + const Polygon convex = Geometry::convex_hull(points); // skirt may be printed on several layers, having distinct layer heights, // but loops must be aligned so can't vary width/spacing // TODO: use each extruder's own flow - auto first_layer_height = this->skirt_first_layer_height(); - auto flow = this->skirt_flow(); - auto spacing = flow.spacing(); - auto mm3_per_mm = flow.mm3_per_mm(); - - - auto skirts = this->config.skirts; - if(this->has_infinite_skirt() && skirts == 0){ - skirts = 1; - } - - //my @extruded_length = (); # for each extruder - //extruders_e_per_mm = (); - //size_t extruder_idx = 0; - - // new to the cpp implementation - float e_per_mm {0.0}, extruded_length = 0; - size_t extruders_warm = 0; - if (this->config.min_skirt_length.getFloat() > 0) { - //my $config = Config::GCode(); - //$config->apply_static($self->config); - auto extruder = Extruder(0, &this->config); - e_per_mm = extruder.e_per_mm(mm3_per_mm); - } + const auto first_layer_height = this->skirt_first_layer_height(); + const auto flow = this->skirt_flow(); + const auto spacing = flow.scaled_spacing(); + const auto mm3_per_mm = flow.mm3_per_mm(); + + int skirts = this->config.skirts(); + if (skirts == 0 && this->has_infinite_skirt()) + skirts = 1; + + const std::set extruders{ this->extruders() }; + auto extruder_it { extruders.begin() }; + std::vector e_per_mm{0}, extruded_length{0}; + if (this->config.min_skirt_length() > 0) + for (auto i : extruders) + e_per_mm[i] = Extruder(i, &this->config).e_per_mm(mm3_per_mm); // draw outlines from outside to inside // loop while we have less skirts than required or any extruder hasn't reached the min length if any - float distance = scale_(std::max(this->config.skirt_distance.getFloat(), this->config.brim_width.getFloat())); + float distance = scale_(std::max(this->config.skirt_distance(), this->config.brim_width())); for (int i = skirts; i > 0; i--) { - distance += scale_(spacing); - auto loop = offset(Polygons{convex}, distance, 1, jtRound, scale_(0.1)).at(0); - auto epath = ExtrusionPath(erSkirt, - mm3_per_mm, // this will be overridden at G-code export time - flow.width, - first_layer_height // this will be overridden at G-code export time + distance += spacing; + const Polygon loop = offset(Polygons{convex}, distance, 1, jtRound, scale_(0.1)).at(0); + auto epath = ExtrusionPath( + erSkirt, + mm3_per_mm, // this will be overridden at G-code export time + flow.width, + first_layer_height // this will be overridden at G-code export time ); epath.polyline = loop.split_at_first_point(); - auto eloop = ExtrusionLoop(epath,elrSkirt); + auto eloop = ExtrusionLoop(epath, elrSkirt); this->skirt.append(eloop); - if (this->config.min_skirt_length.getFloat() > 0) { - // Alternative simpler method - extruded_length += unscale(loop.length()) * e_per_mm; - if(extruded_length >= this->config.min_skirt_length.getFloat()){ - extruders_warm++; - extruded_length = 0; - } - if (extruders_warm < this->extruders().size()){ - i++; - } - - /*$extruded_length[$extruder_idx] ||= 0; - if (!$extruders_e_per_mm[$extruder_idx]) { - my $config = Slic3r::Config::GCode->new; - $config->apply_static($self->config); - my $extruder = Slic3r::Extruder->new($extruder_idx, $config); - $extruders_e_per_mm[$extruder_idx] = $extruder->e_per_mm($mm3_per_mm); - } - $extruded_length[$extruder_idx] += unscale $loop->length * $extruders_e_per_mm[$extruder_idx]; - $i++ if defined first { ($extruded_length[$_] // 0) < $self->config->min_skirt_length } 0 .. $#{$self->extruders}; - if ($extruded_length[$extruder_idx] >= $self->config->min_skirt_length) { - if ($extruder_idx < $#{$self->extruders}) { - $extruder_idx++; - next; + if (this->config.min_skirt_length() > 0) { + extruded_length[*extruder_it] += unscale(loop.length()) * e_per_mm[*extruder_it]; + for (auto j : extruders) { + if (extruded_length[j] < this->config.min_skirt_length()) { + ++i; + break; } - }*/ + } + if (extruded_length[*extruder_it] >= this->config.min_skirt_length() && extruder_it != extruders.end()) + ++extruder_it; } } diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index cb1cb7d1f9..0bf82d06da 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -287,6 +287,7 @@ _constant() double skirt_first_layer_height(); Clone brim_flow(); Clone skirt_flow(); + void make_skirt(); void _make_brim(); %{