diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 618de816f..6660e7200 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -46,66 +46,10 @@ sub 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 ); - } - } - + + my $warning = $self->_fix_slicing_errors; + warn $warning if (defined($warning) && $warning ne ''); + # simplify slices if required if ($self->print->config->resolution) { $self->_simplify_slices(scale($self->print->config->resolution)); diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 233290854..a6df6dd19 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -168,6 +168,7 @@ public: SlicingParameters slicing_parameters() const; void _slice(); + std::string _fix_slicing_errors(); bool has_support_material() const; void detect_surfaces_type(); void process_external_surfaces(); diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index b9c0c2750..20bcdf5ca 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -1133,6 +1133,7 @@ void PrintObject::_slice() end: ; + BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - begin"; tbb::parallel_for( tbb::blocked_range(0, this->layers.size()), [this](const tbb::blocked_range& range) { @@ -1170,6 +1171,7 @@ end: layer->make_slices(); } }); + BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end"; } std::vector PrintObject::_slice_region(size_t region_id, const std::vector &z, bool modifier) @@ -1203,6 +1205,85 @@ std::vector PrintObject::_slice_region(size_t region_id, const std:: return layers; } +std::string PrintObject::_fix_slicing_errors() +{ + // Collect layers with slicing errors. + // These layers will be fixed in parallel. + std::vector buggy_layers; + buggy_layers.reserve(this->layers.size()); + for (size_t idx_layer = 0; idx_layer < this->layers.size(); ++ idx_layer) + if (this->layers[idx_layer]->slicing_errors) + buggy_layers.push_back(idx_layer); + + BOOST_LOG_TRIVIAL(debug) << "Slicing objects - fixing slicing errors in parallel - begin"; + tbb::parallel_for( + tbb::blocked_range(0, buggy_layers.size()), + [this, &buggy_layers](const tbb::blocked_range& range) { + for (size_t buggy_layer_idx = range.begin(); buggy_layer_idx < range.end(); ++ buggy_layer_idx) { + size_t idx_layer = buggy_layers[buggy_layer_idx]; + Layer *layer = this->layers[idx_layer]; + assert(layer->slicing_errors); + // Try to repair the layer surfaces by merging all contours and all holes from neighbor layers. + // BOOST_LOG_TRIVIAL(trace) << "Attempting to repair layer" << idx_layer; + for (size_t region_id = 0; region_id < layer->regions.size(); ++ region_id) { + LayerRegion *layerm = layer->regions[region_id]; + // Find the first valid layer below / above the current layer. + const Surfaces *upper_surfaces = nullptr; + const Surfaces *lower_surfaces = nullptr; + for (size_t j = idx_layer + 1; j < this->layers.size(); ++ j) + if (! this->layers[j]->slicing_errors) { + upper_surfaces = &this->layers[j]->regions[region_id]->slices.surfaces; + break; + } + for (int j = int(idx_layer) - 1; j >= 0; -- j) + if (! this->layers[j]->slicing_errors) { + lower_surfaces = &this->layers[j]->regions[region_id]->slices.surfaces; + break; + } + // Collect outer contours and holes from the valid layers above & below. + Polygons outer; + outer.reserve( + ((upper_surfaces == nullptr) ? 0 : upper_surfaces->size()) + + ((lower_surfaces == nullptr) ? 0 : lower_surfaces->size())); + size_t num_holes = 0; + if (upper_surfaces) + for (const auto &surface : *upper_surfaces) { + outer.push_back(surface.expolygon.contour); + num_holes += surface.expolygon.holes.size(); + } + if (lower_surfaces) + for (const auto &surface : *lower_surfaces) { + outer.push_back(surface.expolygon.contour); + num_holes += surface.expolygon.holes.size(); + } + Polygons holes; + holes.reserve(num_holes); + if (upper_surfaces) + for (const auto &surface : *upper_surfaces) + polygons_append(holes, surface.expolygon.holes); + if (lower_surfaces) + for (const auto &surface : *lower_surfaces) + polygons_append(holes, surface.expolygon.holes); + layerm->slices.set(diff_ex(union_(outer), holes, false), stInternal); + } + // Update layer slices after repairing the single regions. + layer->make_slices(); + } + }); + BOOST_LOG_TRIVIAL(debug) << "Slicing objects - fixing slicing errors in parallel - end"; + + // remove empty layers from bottom + while (! this->layers.empty() && this->layers.front()->slices.expolygons.empty()) { + this->delete_layer(0); + for (size_t i = 0; i < this->layers.size(); ++ i) + this->layers[i]->set_id(this->layers[i]->id() - 1); + } + + return buggy_layers.empty() ? "" : + "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"; +} + void PrintObject::_make_perimeters() { diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index 1931243e1..670e4e999 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -112,6 +112,7 @@ _constant() %code%{ THIS->state.set_started(step); %}; void _slice(); + std::string _fix_slicing_errors(); void detect_surfaces_type(); void process_external_surfaces(); void discover_vertical_shells();