From f7509f2a3f5320290157297f3f2b527bf6dd810c Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 26 Nov 2018 21:13:04 +0100 Subject: [PATCH] Ported PrintObject::slice() to C++ --- lib/Slic3r/Print/Object.pm | 89 ------------------------ xs/src/libslic3r/ExPolygonCollection.hpp | 1 + xs/src/libslic3r/PrintObject.cpp | 83 ++++++++++++++++++++-- xs/xsp/Print.xsp | 1 + 4 files changed, 80 insertions(+), 94 deletions(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index f7c120ca0..4e8aff5a7 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -34,95 +34,6 @@ sub support_layers { return [ map $self->get_support_layer($_), 0..($self->support_layer_count - 1) ]; } -# 1) Decides Z positions of the layers, -# 2) Initializes layers and their regions -# 3) Slices the object meshes -# 4) Slices the modifier meshes and reclassifies the slices of the object meshes by the slices of the modifier meshes -# 5) Applies size compensation (offsets the slices in XY plane) -# 6) Replaces bad slices by the slices reconstructed from the upper/lower layer -# Resulting expolygons of layer regions are marked as Internal. -# -# this should be idempotent -sub slice { - my $self = shift; - - return if $self->step_done(STEP_SLICE); - $self->set_step_started(STEP_SLICE); - $self->print->status_cb->(10, "Processing triangulated mesh"); - - $self->_slice; - - # detect slicing errors - my $warning_thrown = 0; - for my $i (0 .. ($self->layer_count - 1)) { - my $layer = $self->get_layer($i); - next unless $layer->slicing_errors; - if (!$warning_thrown) { - warn "The model has overlapping or self-intersecting facets. I tried to repair it, " - . "however you might want to check the results or repair the input file and retry.\n"; - $warning_thrown = 1; - } - - # try to repair the layer surfaces by merging all contours and all holes from - # neighbor layers - Slic3r::debugf "Attempting to repair layer %d\n", $i; - - foreach my $region_id (0 .. ($layer->region_count - 1)) { - my $layerm = $layer->region($region_id); - - my (@upper_surfaces, @lower_surfaces); - for (my $j = $i+1; $j < $self->layer_count; $j++) { - if (!$self->get_layer($j)->slicing_errors) { - @upper_surfaces = @{$self->get_layer($j)->region($region_id)->slices}; - last; - } - } - for (my $j = $i-1; $j >= 0; $j--) { - if (!$self->get_layer($j)->slicing_errors) { - @lower_surfaces = @{$self->get_layer($j)->region($region_id)->slices}; - last; - } - } - - my $union = union_ex([ - map $_->expolygon->contour, @upper_surfaces, @lower_surfaces, - ]); - my $diff = diff_ex( - [ map @$_, @$union ], - [ map @{$_->expolygon->holes}, @upper_surfaces, @lower_surfaces, ], - ); - - $layerm->slices->clear; - $layerm->slices->append($_) - for map Slic3r::Surface->new - (expolygon => $_, surface_type => S_TYPE_INTERNAL), - @$diff; - } - - # update layer slices after repairing the single regions - $layer->make_slices; - } - - # remove empty layers from bottom - while (@{$self->layers} && !@{$self->get_layer(0)->slices}) { - $self->delete_layer(0); - for (my $i = 0; $i <= $#{$self->layers}; $i++) { - $self->get_layer($i)->set_id( $self->get_layer($i)->id-1 ); - } - } - - # simplify slices if required - if ($self->print->config->resolution) { - $self->_simplify_slices(scale($self->print->config->resolution)); - } - - die "No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n" - if !@{$self->layers}; - - $self->set_typed_slices(0); - $self->set_step_done(STEP_SLICE); -} - sub make_perimeters { my ($self) = @_; diff --git a/xs/src/libslic3r/ExPolygonCollection.hpp b/xs/src/libslic3r/ExPolygonCollection.hpp index 1d911f7e9..4c97f2610 100644 --- a/xs/src/libslic3r/ExPolygonCollection.hpp +++ b/xs/src/libslic3r/ExPolygonCollection.hpp @@ -41,6 +41,7 @@ class ExPolygonCollection /// ExPolygons and check if at least one contains the point. bool contains(const Point &point) const; + bool empty() const { return expolygons.empty(); } size_t size() const { return expolygons.size(); } ExPolygons::iterator begin() { return expolygons.begin(); } ExPolygons::iterator end() { return expolygons.end(); } diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index f401d143d..643b8a839 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -956,6 +956,17 @@ PrintObject::make_perimeters() this->_make_perimeters(); } +/* + 1) Decides Z positions of the layers, + 2) Initializes layers and their regions + 3) Slices the object meshes + 4) Slices the modifier meshes and reclassifies the slices of the object meshes by the slices of the modifier meshes + 5) Applies size compensation (offsets the slices in XY plane) + 6) Replaces bad slices by the slices reconstructed from the upper/lower layer + Resulting expolygons of layer regions are marked as Internal. + + This should be idempotent. +*/ void PrintObject::slice() { @@ -964,8 +975,7 @@ PrintObject::slice() if (_print->status_cb != nullptr) { _print->status_cb(10, "Processing triangulated mesh"); } - - + this->_slice(); // detect slicing errors @@ -975,12 +985,75 @@ PrintObject::slice() << "I tried to repair it, however you might want to check " << "the results or repair the input file and retry.\n"; - if (this->layers.size() == 0) { + bool warning_thrown = false; + for (size_t i = 0; i < this->layer_count(); ++i) { + Layer* layer{ this->get_layer(i) }; + if (!layer->slicing_errors) continue; + if (!warning_thrown) { + Slic3r::Log::warn("PrintObject") << "The model has overlapping or self-intersecting facets. " + << "I tried to repair it, however you might want to check " + << "the results or repair the input file and retry.\n"; + warning_thrown = true; + } + + // try to repair the layer surfaces by merging all contours and all holes from + // neighbor layers + #ifdef SLIC3R_DEBUG + std::cout << "Attempting to repair layer " << i << std::endl; + #endif + + for (size_t region_id = 0; region_id < layer->region_count(); ++region_id) { + LayerRegion* layerm{ layer->get_region(region_id) }; + + ExPolygons slices; + for (size_t j = i+1; j < this->layer_count(); ++j) { + const Layer* upper = this->get_layer(j); + if (!upper->slicing_errors) { + append_to(slices, (ExPolygons)upper->get_region(region_id)->slices); + break; + } + } + for (int j = i-1; j >= 0; --j) { + const Layer* lower = this->get_layer(j); + if (!lower->slicing_errors) { + append_to(slices, (ExPolygons)lower->get_region(region_id)->slices); + break; + } + } + + // TODO: do we actually need to split contours and holes before performing the diff? + Polygons contours, holes; + for (ExPolygon ex : slices) + contours.push_back(ex.contour); + for (ExPolygon ex : slices) + append_to(holes, ex.holes); + + const ExPolygons diff = diff_ex(contours, holes); + + layerm->slices.clear(); + layerm->slices.append(diff, stInternal); + } + + // update layer slices after repairing the single regions + layer->make_slices(); + } + + // remove empty layers from bottom + while (!this->layers.empty() && this->get_layer(0)->slices.empty()) { + this->delete_layer(0); + for (Layer* layer : this->layers) + layer->set_id(layer->id()-1); + } + + // simplify slices if required + if (this->_print->config.resolution() > 0) + this->_simplify_slices(scale_(this->_print->config.resolution())); + + if (this->layers.empty()) { Slic3r::Log::error("PrintObject") << "slice(): " << "No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n"; return; // make this throw an exception instead? } - - + this->typed_slices = false; this->state.set_done(posSlice); } diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index c2ec2d813..1d6f0eba6 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -132,6 +132,7 @@ _constant() void combine_infill(); void discover_horizontal_shells(); void clip_fill_surfaces(); + void slice(); void _slice(); SV* _slice_region(size_t region_id, std::vector z, bool modifier) %code%{