diff --git a/lib/Slic3r/GCode/Layer.pm b/lib/Slic3r/GCode/Layer.pm index 9bac7901c..5f3531d6d 100644 --- a/lib/Slic3r/GCode/Layer.pm +++ b/lib/Slic3r/GCode/Layer.pm @@ -135,7 +135,7 @@ sub process_layer { } # tweak region ordering to save toolchanges - my @region_ids = 0 .. ($self->print->regions_count-1); + my @region_ids = 0 .. ($self->print->region_count-1); if ($self->gcodegen->multiple_extruders) { my $last_extruder = $self->gcodegen->extruder; my $best_region_id = first { $self->print->regions->[$_]->config->perimeter_extruder-1 eq $last_extruder } @region_ids; diff --git a/lib/Slic3r/GUI/Plater/2DToolpaths.pm b/lib/Slic3r/GUI/Plater/2DToolpaths.pm index 93b61f56e..8e48a7290 100644 --- a/lib/Slic3r/GUI/Plater/2DToolpaths.pm +++ b/lib/Slic3r/GUI/Plater/2DToolpaths.pm @@ -135,7 +135,7 @@ sub set_z { my $interlaced = (defined first { $_->config->support_material } @{$print->objects}) || (defined first { $_->config->infill_every_layers > 1 } @{$print->regions}); - my $max_layer_height = $print->max_layer_height; + my $max_layer_height = $print->max_allowed_layer_height; my @layers = (); foreach my $object (@{$print->objects}) { diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index f6fc9f342..694f7050d 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -39,24 +39,6 @@ sub regions { return [ map $self->get_region($_), 0..($self->region_count-1) ]; } -# merge all regions' slices to get islands -sub make_slices { - my $self = shift; - - my $slices; - if (@{$self->regions} == 1) { - $slices = [ map $_->expolygon->clone, @{$self->regions->[0]->slices} ]; - } else { - $slices = union_ex([ map $_->p, map @{$_->slices}, @{$self->regions} ]); - } - - # sort slices - $slices = [ @$slices[@{chained_path([ map $_->contour->first_point, @$slices ])}] ]; - - $self->slices->clear; - $self->slices->append(@$slices); -} - sub merge_slices { my ($self) = @_; $_->merge_slices for @{$self->regions}; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 755823661..71e591734 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -148,13 +148,6 @@ sub apply_config { return $invalidated; } -sub has_support_material { - my $self = shift; - return (first { $_->config->support_material } @{$self->objects}) - || (first { $_->config->raft_layers > 0 } @{$self->objects}) - || (first { $_->config->support_material_enforce_layers > 0 } @{$self->objects}); -} - # caller is responsible for supplying models whose objects don't collide # and have explicit instance positions sub add_model_object { @@ -311,43 +304,6 @@ sub validate { } } -# 0-based indices of used extruders -sub extruders { - my ($self) = @_; - - # initialize all extruder(s) we need - my @used_extruders = (); - foreach my $region (@{$self->regions}) { - push @used_extruders, - map $region->config->get("${_}_extruder")-1, - qw(perimeter infill); - } - foreach my $object (@{$self->objects}) { - push @used_extruders, - map $object->config->get("${_}_extruder")-1, - qw(support_material support_material_interface); - } - - my %h = map { $_ => 1 } @used_extruders; - return [ sort keys %h ]; -} - -sub init_extruders { - my $self = shift; - - return if $self->step_done(STEP_INIT_EXTRUDERS); - $self->set_step_started(STEP_INIT_EXTRUDERS); - - # enforce tall skirt if using ooze_prevention - # FIXME: this is not idempotent (i.e. switching ooze_prevention off will not revert skirt settings) - if ($self->config->ooze_prevention && @{$self->extruders} > 1) { - $self->config->set('skirt_height', -1); - $self->config->set('skirts', 1) if $self->config->skirts == 0; - } - - $self->set_step_done(STEP_INIT_EXTRUDERS); -} - # this value is not supposed to be compared with $layer->id # since they have different semantics sub total_layer_count { @@ -355,16 +311,6 @@ sub total_layer_count { return max(map $_->total_layer_count, @{$self->objects}); } -sub regions_count { - my $self = shift; - return scalar @{$self->regions}; -} - -sub max_layer_height { - my ($self) = @_; - return max(@{$self->config->nozzle_diameter}); -} - # the bounding box of objects placed in copies position # (without taking skirt/brim/support material into account) sub bounding_box { @@ -410,16 +356,6 @@ sub size { return $self->bounding_box->size; } -sub _simplify_slices { - my $self = shift; - my ($distance) = @_; - - foreach my $layer (map @{$_->layers}, @{$self->objects}) { - $layer->slices->simplify($distance); - $_->slices->simplify($distance) for @{$layer->regions}; - } -} - sub process { my ($self) = @_; diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 182e21998..a1aaff307 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -173,7 +173,7 @@ sub slice { } # make sure all layers contain layer region objects for all regions - my $regions_count = $self->print->regions_count; + my $regions_count = $self->print->region_count; foreach my $layer (@{ $self->layers }) { $layer->region($_) for 0 .. ($regions_count-1); } @@ -427,7 +427,7 @@ sub make_perimeters { # but we don't generate any extra perimeter if fill density is zero, as they would be floating # inside the object - infill_only_where_needed should be the method of choice for printing # hollow objects - for my $region_id (0 .. ($self->print->regions_count-1)) { + for my $region_id (0 .. ($self->print->region_count-1)) { my $region = $self->print->regions->[$region_id]; my $region_perimeters = $region->config->perimeters; @@ -555,7 +555,7 @@ sub infill { threads => $self->print->config->threads, items => sub { my @items = (); # [layer_id, region_id] - for my $region_id (0 .. ($self->print->regions_count-1)) { + for my $region_id (0 .. ($self->print->region_count-1)) { push @items, map [$_, $region_id], 0..($self->layer_count - 1); } @items; @@ -627,7 +627,7 @@ sub detect_surfaces_type { my $self = shift; Slic3r::debugf "Detecting solid surfaces...\n"; - for my $region_id (0 .. ($self->print->regions_count-1)) { + for my $region_id (0 .. ($self->print->region_count-1)) { for my $i (0 .. ($self->layer_count - 1)) { my $layerm = $self->get_layer($i)->regions->[$region_id]; @@ -885,7 +885,7 @@ sub bridge_over_infill { sub process_external_surfaces { my ($self) = @_; - for my $region_id (0 .. ($self->print->regions_count-1)) { + for my $region_id (0 .. ($self->print->region_count-1)) { $self->get_layer(0)->regions->[$region_id]->process_external_surfaces(undef); for my $i (1 .. ($self->layer_count - 1)) { $self->get_layer($i)->regions->[$region_id]->process_external_surfaces($self->get_layer($i-1)); @@ -898,7 +898,7 @@ sub discover_horizontal_shells { Slic3r::debugf "==> DISCOVERING HORIZONTAL SHELLS\n"; - for my $region_id (0 .. ($self->print->regions_count-1)) { + for my $region_id (0 .. ($self->print->region_count-1)) { for (my $i = 0; $i < $self->layer_count; $i++) { my $layerm = $self->get_layer($i)->regions->[$region_id]; @@ -1048,7 +1048,7 @@ sub combine_infill { my @layer_heights = map $_->height, @{$self->layers}; - for my $region_id (0 .. ($self->print->regions_count-1)) { + for my $region_id (0 .. ($self->print->region_count-1)) { my $region = $self->print->regions->[$region_id]; my $every = $region->config->infill_every_layers; diff --git a/xs/src/Layer.cpp b/xs/src/Layer.cpp index 69f9fb13a..3df747250 100644 --- a/xs/src/Layer.cpp +++ b/xs/src/Layer.cpp @@ -1,4 +1,7 @@ #include "Layer.hpp" +#include "ClipperUtils.hpp" +#include "Geometry.hpp" +#include "Print.hpp" namespace Slic3r { @@ -108,6 +111,42 @@ Layer::delete_region(int idx) delete item; } +// merge all regions' slices to get islands +void +Layer::make_slices() +{ + ExPolygons slices; + if (this->regions.size() == 1) { + // optimization: if we only have one region, take its slices + slices = this->regions.front()->slices; + } else { + Polygons slices_p; + FOREACH_LAYERREGION(this, layerm) { + Polygons region_slices_p = (*layerm)->slices; + slices_p.insert(slices_p.end(), region_slices_p.begin(), region_slices_p.end()); + } + union_(slices_p, slices); + } + + this->slices.expolygons.clear(); + this->slices.expolygons.reserve(slices.size()); + + // prepare ordering points + Points ordering_points; + ordering_points.reserve(slices.size()); + for (ExPolygons::const_iterator ex = slices.begin(); ex != slices.end(); ++ex) + ordering_points.push_back(ex->contour.first_point()); + + // sort slices + std::vector<Points::size_type> order; + Slic3r::Geometry::chained_path(ordering_points, order); + + // populate slices vector + for (std::vector<Points::size_type>::const_iterator it = order.begin(); it != order.end(); ++it) { + this->slices.expolygons.push_back(slices[*it]); + } +} + #ifdef SLIC3RXS REGISTER_CLASS(Layer, "Layer"); diff --git a/xs/src/Layer.hpp b/xs/src/Layer.hpp index ca876be99..bfbaddc3c 100644 --- a/xs/src/Layer.hpp +++ b/xs/src/Layer.hpp @@ -84,6 +84,8 @@ class Layer { size_t region_count(); LayerRegion* get_region(int idx); LayerRegion* add_region(PrintRegion* print_region); + + void make_slices(); protected: int _id; // sequential number of layer, 0-based diff --git a/xs/src/Print.cpp b/xs/src/Print.cpp index 7137e804b..a4b69be4c 100644 --- a/xs/src/Print.cpp +++ b/xs/src/Print.cpp @@ -1,5 +1,6 @@ #include "Print.hpp" #include "BoundingBox.hpp" +#include <algorithm> namespace Slic3r { @@ -511,7 +512,7 @@ Print::invalidate_step(PrintStep step) if (step == psSkirt) { this->invalidate_step(psBrim); } else if (step == psInitExtruders) { - for (PrintObjectPtrs::iterator object = this->objects.begin(); object != this->objects.end(); ++object) { + FOREACH_OBJECT(this, object) { (*object)->invalidate_step(posPerimeters); (*object)->invalidate_step(posSupportMaterial); } @@ -533,6 +534,77 @@ Print::invalidate_all_steps() return invalidated; } +// returns 0-based indices of used extruders +std::set<size_t> +Print::extruders() const +{ + std::set<size_t> extruders; + + FOREACH_REGION(this, region) { + extruders.insert((*region)->config.perimeter_extruder - 1); + extruders.insert((*region)->config.infill_extruder - 1); + } + FOREACH_OBJECT(this, object) { + extruders.insert((*object)->config.support_material_extruder - 1); + extruders.insert((*object)->config.support_material_interface_extruder - 1); + } + + return extruders; +} + +void +Print::_simplify_slices(double distance) +{ + FOREACH_OBJECT(this, object) { + FOREACH_LAYER(*object, layer) { + (*layer)->slices.simplify(distance); + FOREACH_LAYERREGION(*layer, layerm) { + (*layerm)->slices.simplify(distance); + } + } + } +} + +double +Print::max_allowed_layer_height() const +{ + std::vector<double> nozzle_diameter; + + std::set<size_t> extruders = this->extruders(); + for (std::set<size_t>::const_iterator e = extruders.begin(); e != extruders.end(); ++e) { + nozzle_diameter.push_back(this->config.nozzle_diameter.get_at(*e)); + } + + return *std::max_element(nozzle_diameter.begin(), nozzle_diameter.end()); +} + +void +Print::init_extruders() +{ + if (this->state.is_done(psInitExtruders)) return; + this->state.set_done(psInitExtruders); + + // enforce tall skirt if using ooze_prevention + // FIXME: this is not idempotent (i.e. switching ooze_prevention off will not revert skirt settings) + if (this->config.ooze_prevention && this->extruders().size() > 1) { + this->config.skirt_height.value = -1; + if (this->config.skirts == 0) this->config.skirts.value = 1; + } + + this->state.set_done(psInitExtruders); +} + +bool +Print::has_support_material() const +{ + FOREACH_OBJECT(this, object) { + PrintObjectConfig &config = (*object)->config; + if (config.support_material || config.raft_layers > 0 || config.support_material_enforce_layers > 0) + return true; + } + return false; +} + #ifdef SLIC3RXS REGISTER_CLASS(Print, "Print"); diff --git a/xs/src/Print.hpp b/xs/src/Print.hpp index 9bd0d8212..aa94ded66 100644 --- a/xs/src/Print.hpp +++ b/xs/src/Print.hpp @@ -160,12 +160,25 @@ class Print bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); bool invalidate_step(PrintStep step); bool invalidate_all_steps(); - + + void init_extruders(); + + std::set<size_t> extruders() const; + void _simplify_slices(double distance); + double max_allowed_layer_height() const; + bool has_support_material() const; + private: void clear_regions(); void delete_region(size_t idx); }; +#define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator) +#define FOREACH_REGION(print, region) FOREACH_BASE(PrintRegionPtrs, (print)->regions, region) +#define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->objects, object) +#define FOREACH_LAYER(object, layer) FOREACH_BASE(LayerPtrs, (object)->layers, layer) +#define FOREACH_LAYERREGION(layer, layerm) FOREACH_BASE(LayerRegionPtrs, (layer)->regions, layerm) + } #endif diff --git a/xs/src/SurfaceCollection.cpp b/xs/src/SurfaceCollection.cpp index 77c2e6d0a..1590e7a21 100644 --- a/xs/src/SurfaceCollection.cpp +++ b/xs/src/SurfaceCollection.cpp @@ -3,6 +3,26 @@ namespace Slic3r { +SurfaceCollection::operator Polygons() const +{ + Polygons polygons; + for (Surfaces::const_iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) { + Polygons surface_p = surface->expolygon; + polygons.insert(polygons.end(), surface_p.begin(), surface_p.end()); + } + return polygons; +} + +SurfaceCollection::operator ExPolygons() const +{ + ExPolygons expp; + expp.reserve(this->surfaces.size()); + for (Surfaces::const_iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) { + expp.push_back(surface->expolygon); + } + return expp; +} + void SurfaceCollection::simplify(double tolerance) { diff --git a/xs/src/SurfaceCollection.hpp b/xs/src/SurfaceCollection.hpp index cb8088c47..fe3fae8c6 100644 --- a/xs/src/SurfaceCollection.hpp +++ b/xs/src/SurfaceCollection.hpp @@ -10,6 +10,9 @@ class SurfaceCollection { public: Surfaces surfaces; + + operator Polygons() const; + operator ExPolygons() const; void simplify(double tolerance); void group(std::vector<SurfacesPtr> *retval); }; diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp index 6c5243aed..7d297216f 100644 --- a/xs/xsp/Layer.xsp +++ b/xs/xsp/Layer.xsp @@ -60,6 +60,8 @@ int ptr() %code%{ RETVAL = (int)(intptr_t)THIS; %}; + + void make_slices(); }; %name{Slic3r::Layer::Support} class SupportLayer { diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index c104eaf30..548123f75 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -153,6 +153,20 @@ _constant() %code%{ THIS->state.set_done(step); %}; void set_step_started(PrintStep step) %code%{ THIS->state.set_started(step); %}; + + std::vector<int> extruders() + %code%{ + std::set<size_t> extruders = THIS->extruders(); + RETVAL.reserve(extruders.size()); + for (std::set<size_t>::const_iterator e = extruders.begin(); e != extruders.end(); ++e) { + RETVAL.push_back(*e); + } + %}; + void _simplify_slices(double distance); + double max_allowed_layer_height() const; + bool has_support_material() const; + + void init_extruders(); %{ double