From 4f8a18bbadb52c107fa7c0f37a6fa0edb4385c5c Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Wed, 2 Dec 2015 19:32:57 +0100 Subject: [PATCH] Ported Layer::maker_perimeters() to XS --- lib/Slic3r/Layer.pm | 80 ----------------------------- xs/src/libslic3r/ClipperUtils.cpp | 11 ++++ xs/src/libslic3r/ClipperUtils.hpp | 1 + xs/src/libslic3r/Config.cpp | 16 +++++- xs/src/libslic3r/Config.hpp | 4 +- xs/src/libslic3r/Layer.cpp | 83 +++++++++++++++++++++++++++++++ xs/src/libslic3r/Layer.hpp | 1 + xs/xsp/Layer.xsp | 1 + 8 files changed, 114 insertions(+), 83 deletions(-) diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index 89660aefb..b5e8e42f7 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -2,9 +2,6 @@ package Slic3r::Layer; use strict; use warnings; -use List::Util qw(first); -use Slic3r::Geometry::Clipper qw(union_ex intersection_ex); - # the following two were previously generated by Moo sub print { my $self = shift; @@ -32,83 +29,6 @@ sub regions { return [ map $self->get_region($_), 0..($self->region_count-1) ]; } -sub make_perimeters { - my $self = shift; - Slic3r::debugf "Making perimeters for layer %d\n", $self->id; - - # keep track of regions whose perimeters we have already generated - my %done = (); # region_id => 1 - - for my $region_id (0..$#{$self->regions}) { - next if $done{$region_id}; - my $layerm = $self->get_region($region_id); - my $config = $layerm->region->config; - $done{$region_id} = 1; - - # find compatible regions - my @layerms = ($layerm); - for my $i (($region_id+1)..$#{$self->regions}) { - my $other_layerm = $self->get_region($i); - my $other_config = $other_layerm->region->config; - - if ($config->perimeter_extruder == $other_config->perimeter_extruder - && $config->perimeters == $other_config->perimeters - && $config->perimeter_speed == $other_config->perimeter_speed - && $config->gap_fill_speed == $other_config->gap_fill_speed - && $config->overhangs == $other_config->overhangs - && $config->serialize('perimeter_extrusion_width') eq $other_config->serialize('perimeter_extrusion_width') - && $config->thin_walls == $other_config->thin_walls - && $config->external_perimeters_first == $other_config->external_perimeters_first) { - push @layerms, $other_layerm; - $done{$i} = 1; - } - } - - if (@layerms == 1) { # optimization - $layerm->fill_surfaces->clear; - $layerm->make_perimeters($layerm->slices, $layerm->fill_surfaces); - } else { - # group slices (surfaces) according to number of extra perimeters - my %slices = (); # extra_perimeters => [ surface, surface... ] - foreach my $surface (map @{$_->slices}, @layerms) { - my $extra = $surface->extra_perimeters; - $slices{$extra} ||= []; - push @{$slices{$extra}}, $surface; - } - - # merge the surfaces assigned to each group - my $new_slices = Slic3r::Surface::Collection->new; - foreach my $surfaces (values %slices) { - $new_slices->append(Slic3r::Surface->new( - surface_type => $surfaces->[0]->surface_type, - extra_perimeters => $surfaces->[0]->extra_perimeters, - expolygon => $_, - )) for @{union_ex([ map $_->p, @$surfaces ], 1)}; - } - - # make perimeters - my $fill_surfaces = Slic3r::Surface::Collection->new; - $layerm->make_perimeters($new_slices, $fill_surfaces); - - # assign fill_surfaces to each layer - if ($fill_surfaces->count > 0) { - foreach my $lm (@layerms) { - my $expolygons = intersection_ex( - [ map $_->p, @$fill_surfaces ], - [ map $_->p, @{$lm->slices} ], - ); - $lm->fill_surfaces->clear; - $lm->fill_surfaces->append(Slic3r::Surface->new( - surface_type => $fill_surfaces->[0]->surface_type, - extra_perimeters => $fill_surfaces->[0]->extra_perimeters, - expolygon => $_, - )) for @$expolygons; - } - } - } - } -} - package Slic3r::Layer::Support; our @ISA = qw(Slic3r::Layer); diff --git a/xs/src/libslic3r/ClipperUtils.cpp b/xs/src/libslic3r/ClipperUtils.cpp index f18653702..d9cfd5ff5 100644 --- a/xs/src/libslic3r/ClipperUtils.cpp +++ b/xs/src/libslic3r/ClipperUtils.cpp @@ -569,6 +569,17 @@ union_ex(const Slic3r::Polygons &subject, bool safety_offset) return expp; } +Slic3r::ExPolygons +union_ex(const Slic3r::Surfaces &subject, bool safety_offset) +{ + Polygons pp; + for (Slic3r::Surfaces::const_iterator s = subject.begin(); s != subject.end(); ++s) { + Polygons spp = *s; + pp.insert(pp.end(), spp.begin(), spp.end()); + } + return union_ex(pp, safety_offset); +} + void union_(const Slic3r::Polygons &subject1, const Slic3r::Polygons &subject2, Slic3r::Polygons* retval, bool safety_offset) { Polygons pp = subject1; diff --git a/xs/src/libslic3r/ClipperUtils.hpp b/xs/src/libslic3r/ClipperUtils.hpp index 2b4e8c0b3..e5a3b7da5 100644 --- a/xs/src/libslic3r/ClipperUtils.hpp +++ b/xs/src/libslic3r/ClipperUtils.hpp @@ -121,6 +121,7 @@ void union_(const Slic3r::Polygons &subject, T* retval, bool safety_offset_ = fa Slic3r::Polygons union_(const Slic3r::Polygons &subject, bool safety_offset = false); Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, bool safety_offset = false); +Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject, bool safety_offset = false); void union_(const Slic3r::Polygons &subject1, const Slic3r::Polygons &subject2, Slic3r::Polygons* retval, bool safety_offset = false); diff --git a/xs/src/libslic3r/Config.cpp b/xs/src/libslic3r/Config.cpp index ba77d2aba..366291ff2 100644 --- a/xs/src/libslic3r/Config.cpp +++ b/xs/src/libslic3r/Config.cpp @@ -7,6 +7,18 @@ namespace Slic3r { +bool +operator== (const ConfigOption &a, const ConfigOption &b) +{ + return a.serialize().compare(b.serialize()) == 0; +} + +bool +operator!= (const ConfigOption &a, const ConfigOption &b) +{ + return !(a == b); +} + bool ConfigBase::has(const t_config_option_key &opt_key) { return (this->option(opt_key, false) != NULL); @@ -52,8 +64,8 @@ ConfigBase::diff(ConfigBase &other) { } std::string -ConfigBase::serialize(const t_config_option_key &opt_key) { - ConfigOption* opt = this->option(opt_key); +ConfigBase::serialize(const t_config_option_key &opt_key) const { + const ConfigOption* opt = this->option(opt_key); assert(opt != NULL); return opt->serialize(); } diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp index 49a14e221..2c997817a 100644 --- a/xs/src/libslic3r/Config.hpp +++ b/xs/src/libslic3r/Config.hpp @@ -24,6 +24,8 @@ class ConfigOption { virtual bool deserialize(std::string str) = 0; virtual int getInt() const { return 0; }; virtual void setInt(int val) {}; + friend bool operator== (const ConfigOption &a, const ConfigOption &b); + friend bool operator!= (const ConfigOption &a, const ConfigOption &b); }; class ConfigOptionVectorBase : public ConfigOption { @@ -521,7 +523,7 @@ class ConfigBase void apply(const ConfigBase &other, bool ignore_nonexistent = false); bool equals(ConfigBase &other); t_config_option_keys diff(ConfigBase &other); - std::string serialize(const t_config_option_key &opt_key); + std::string serialize(const t_config_option_key &opt_key) const; bool set_deserialize(const t_config_option_key &opt_key, std::string str); void set_ifndef(t_config_option_key opt_key, SV* value, bool deserialize = false); double get_abs_value(const t_config_option_key &opt_key); diff --git a/xs/src/libslic3r/Layer.cpp b/xs/src/libslic3r/Layer.cpp index 595a5daf4..f3d5b1637 100644 --- a/xs/src/libslic3r/Layer.cpp +++ b/xs/src/libslic3r/Layer.cpp @@ -162,6 +162,89 @@ Layer::any_bottom_region_slice_contains(const T &item) const } template bool Layer::any_bottom_region_slice_contains(const Polyline &item) const; +void +Layer::make_perimeters() +{ + #ifdef SLIC3R_DEBUG + printf("Making perimeters for layer %zu\n", this->id()); + #endif + + // keep track of regions whose perimeters we have already generated + std::set done; + + FOREACH_LAYERREGION(this, layerm) { + size_t region_id = layerm - this->regions.begin(); + if (done.find(region_id) != done.end()) continue; + done.insert(region_id); + const PrintRegionConfig &config = (*layerm)->region()->config; + + // find compatible regions + LayerRegionPtrs layerms; + layerms.push_back(*layerm); + for (LayerRegionPtrs::const_iterator it = layerm + 1; it != this->regions.end(); ++it) { + LayerRegion* other_layerm = *it; + const PrintRegionConfig &other_config = other_layerm->region()->config; + + if (config.perimeter_extruder == other_config.perimeter_extruder + && config.perimeters == other_config.perimeters + && config.perimeter_speed == other_config.perimeter_speed + && config.gap_fill_speed == other_config.gap_fill_speed + && config.overhangs == other_config.overhangs + && config.serialize("perimeter_extrusion_width").compare(other_config.serialize("perimeter_extrusion_width")) == 0 + && config.thin_walls == other_config.thin_walls + && config.external_perimeters_first == other_config.external_perimeters_first) { + layerms.push_back(other_layerm); + done.insert(it - this->regions.begin()); + } + } + + if (layerms.size() == 1) { // optimization + (*layerm)->fill_surfaces.surfaces.clear(); + (*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces); + } else { + // group slices (surfaces) according to number of extra perimeters + std::map slices; // extra_perimeters => [ surface, surface... ] + for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) { + for (Surfaces::iterator s = (*l)->slices.surfaces.begin(); s != (*l)->slices.surfaces.end(); ++s) { + slices[s->extra_perimeters].push_back(*s); + } + } + + // merge the surfaces assigned to each group + SurfaceCollection new_slices; + for (std::map::const_iterator it = slices.begin(); it != slices.end(); ++it) { + ExPolygons expp = union_ex(it->second, true); + for (ExPolygons::iterator ex = expp.begin(); ex != expp.end(); ++ex) { + Surface s = it->second.front(); // clone type and extra_perimeters + s.expolygon = *ex; + new_slices.surfaces.push_back(s); + } + } + + // make perimeters + SurfaceCollection fill_surfaces; + (*layerm)->make_perimeters(new_slices, &fill_surfaces); + + // assign fill_surfaces to each layer + if (!fill_surfaces.surfaces.empty()) { + for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) { + ExPolygons expp = intersection_ex( + fill_surfaces, + (*l)->slices + ); + (*l)->fill_surfaces.surfaces.clear(); + + for (ExPolygons::iterator ex = expp.begin(); ex != expp.end(); ++ex) { + Surface s = fill_surfaces.surfaces.front(); // clone type and extra_perimeters + s.expolygon = *ex; + (*l)->fill_surfaces.surfaces.push_back(s); + } + } + } + } + } +} + #ifdef SLIC3RXS REGISTER_CLASS(Layer, "Layer"); #endif diff --git a/xs/src/libslic3r/Layer.hpp b/xs/src/libslic3r/Layer.hpp index 7cb643c54..a6f6f9a43 100644 --- a/xs/src/libslic3r/Layer.hpp +++ b/xs/src/libslic3r/Layer.hpp @@ -101,6 +101,7 @@ class Layer { void merge_slices(); template bool any_internal_region_slice_contains(const T &item) const; template bool any_bottom_region_slice_contains(const T &item) const; + void make_perimeters(); protected: size_t _id; // sequential number of layer, 0-based diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp index 42338fb16..543b500b1 100644 --- a/xs/xsp/Layer.xsp +++ b/xs/xsp/Layer.xsp @@ -85,6 +85,7 @@ %code%{ RETVAL = THIS->any_internal_region_slice_contains(*polyline); %}; bool any_bottom_region_slice_contains_polyline(Polyline* polyline) %code%{ RETVAL = THIS->any_bottom_region_slice_contains(*polyline); %}; + void make_perimeters(); }; %name{Slic3r::Layer::Support} class SupportLayer {