From 7deffa0497b160bb140d898dd8106796a4c8f875 Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 11 Jun 2024 14:06:49 +0200 Subject: [PATCH 1/4] fix ExtrusionLoop::split_at() and improved ExtrusionLoop::split_at_vertex() --- src/libslic3r/ExtrusionEntity.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp index 1beae06780c..c669c394746 100644 --- a/src/libslic3r/ExtrusionEntity.cpp +++ b/src/libslic3r/ExtrusionEntity.cpp @@ -159,7 +159,7 @@ bool ExtrusionLoop::split_at_vertex(const Point &point, const double scaled_epsi p2.append(std::move(p1)); path->polyline.swap(p2); // swap points & fitting result } - } else { + } else if (idx > 0 && idx < path->size() - 1) { // new paths list starts with the second half of current path ExtrusionPaths new_paths; PolylineOrArc p1, p2; @@ -236,8 +236,8 @@ void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang, const const Point *p1 = this->paths[path_idx].polyline.get_points().data() + segment_idx; const Point *p2 = p1; ++ p2; - double d2_1 = (point - *p1).cast().squaredNorm(); - double d2_2 = (point - *p2).cast().squaredNorm(); + double d2_1 = (p - *p1).cast().squaredNorm(); + double d2_2 = (p - *p2).cast().squaredNorm(); const double thr2 = scaled_epsilon * scaled_epsilon; if (d2_1 < d2_2) { if (d2_1 < thr2) From eb16ec27cb6baf07c235c86b6a474f3ecc6e9e2a Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 11 Jun 2024 14:08:07 +0200 Subject: [PATCH 2/4] improved concurrency for perimeter & infill (doesn't block the complicated stuff on only one thread) and various little modification (types, debug test) --- src/libslic3r/Fill/Fill.cpp | 24 +++++++++++++++++++----- src/libslic3r/GCode.cpp | 12 ++++++++++++ src/libslic3r/MultiPoint.cpp | 10 +++++----- src/libslic3r/MultiPoint.hpp | 2 +- src/libslic3r/Point.hpp | 10 +++++----- src/libslic3r/PrintObject.cpp | 27 ++++++++++++++++++--------- 6 files changed, 60 insertions(+), 25 deletions(-) diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 6577395f17e..99f5d1ec925 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -716,11 +716,25 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: for(auto &t : temp) real_surface += t.area(); assert(compute_volume.volume < unscaled(unscaled(surface_fill.surface.area())) * surface_fill.params.layer_height + EPSILON); double area = unscaled(unscaled(real_surface)); - assert(compute_volume.volume <= area * surface_fill.params.layer_height * 1.001 || f->debug_verify_flow_mult <= 0.8); - if(compute_volume.volume > 0) //can fail for thin regions - assert(compute_volume.volume >= area * surface_fill.params.layer_height * 0.999 || f->debug_verify_flow_mult >= 1.3 || f->debug_verify_flow_mult == 0 // sawtooth output more filament,as it's 3D (debug_verify_flow_mult==0) - || area < std::max(1.,surface_fill.params.config->solid_infill_below_area.value) || area < std::max(1.,surface_fill.params.config->solid_infill_below_layer_area.value)); - } + if(surface_fill.surface.has_pos_top()) + area *= surface_fill.params.config->fill_top_flow_ratio.value; + if(surface_fill.surface.has_pos_bottom() && f->layer_id == 0) + area *= surface_fill.params.config->first_layer_flow_ratio.value; + if(surface_fill.surface.has_mod_bridge() && f->layer_id == 0) + area *= surface_fill.params.config->first_layer_flow_ratio.value; + //TODO: over-bridge mod + if(surface_fill.params.config->over_bridge_flow_ratio.value == 1){ + assert(compute_volume.volume <= area * surface_fill.params.layer_height * 1.001 || f->debug_verify_flow_mult <= 0.8); + if(compute_volume.volume > 0) //can fail for thin regions + assert( + compute_volume.volume >= area * surface_fill.params.layer_height * 0.999 || + f->debug_verify_flow_mult >= 1.3 || + f->debug_verify_flow_mult == + 0 // sawtooth output more filament,as it's 3D (debug_verify_flow_mult==0) + || area < std::max(1., surface_fill.params.config->solid_infill_below_area.value) || + area < std::max(1., surface_fill.params.config->solid_infill_below_layer_area.value)); + } + } #endif } } diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 213ccee2774..35b072198cb 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -4142,6 +4142,18 @@ void GCode::split_at_seam_pos(ExtrusionLoop& loop, bool was_clockwise) if (loop.paths.empty()) return; +#if _DEBUG + ExtrusionLoop old_loop = loop; + for (const ExtrusionPath &path : loop.paths) + for (int i = 1; i < path.polyline.get_points().size(); ++i) + assert(!path.polyline.get_points()[i - 1].coincides_with_epsilon(path.polyline.get_points()[i])); + for (auto it = std::next(loop.paths.begin()); it != loop.paths.end(); ++it) { + assert(it->polyline.size() >= 2); + assert(std::prev(it)->polyline.back() == it->polyline.front()); + } + assert(loop.first_point() == loop.last_point()); +#endif + // SeamPosition seam_position = m_config.seam_position; // if (loop.loop_role() == elrSkirt) // seam_position = spNearest; diff --git a/src/libslic3r/MultiPoint.cpp b/src/libslic3r/MultiPoint.cpp index 313c96f6497..3dfaa2165d4 100644 --- a/src/libslic3r/MultiPoint.cpp +++ b/src/libslic3r/MultiPoint.cpp @@ -63,16 +63,16 @@ int MultiPoint::find_point(const Point &point) const return -1; // not found } -int MultiPoint::find_point(const Point &point, double scaled_epsilon) const +int MultiPoint::find_point(const Point &point, coordf_t scaled_epsilon) const { if (scaled_epsilon == 0) return this->find_point(point); - auto dist2_min = std::numeric_limits::max(); - auto eps2 = scaled_epsilon * scaled_epsilon; - int idx_min = -1; + coordf_t dist2_min = std::numeric_limits::max(); + coordf_t eps2 = scaled_epsilon * scaled_epsilon; + int idx_min = -1; for (const Point &pt : this->points) { - double d2 = (pt - point).cast().squaredNorm(); + coordf_t d2 = pt.distance_to_square(point); //(pt - point).cast().squaredNorm(); if (d2 < dist2_min) { idx_min = int(&pt - &this->points.front()); dist2_min = d2; diff --git a/src/libslic3r/MultiPoint.hpp b/src/libslic3r/MultiPoint.hpp index c65e9807cba..33edd409738 100644 --- a/src/libslic3r/MultiPoint.hpp +++ b/src/libslic3r/MultiPoint.hpp @@ -50,7 +50,7 @@ class MultiPoint int find_point(const Point &point) const; // Return index of the closest point to point closer than scaled_epsilon. // Return -1 if no such point exists. - int find_point(const Point &point, const double scaled_epsilon) const; + int find_point(const Point &point, const coordf_t scaled_epsilon) const; bool has_boundary_point(const Point &point) const; int closest_point_index(const Point &point) const { int idx = -1; diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 0d5b8eec490..51ef3d5d2ae 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -179,13 +179,13 @@ class Point : public Vec2crd Point projection_onto(const Line &line) const; Point interpolate(const double percent, const Point &p) const; - double distance_to(const Point &point) const { return (point - *this).cast().norm(); } - double distance_to_square(const Point &point) const { - double dx = double(point.x() - this->x()); - double dy = double(point.y() - this->y()); + coordf_t distance_to(const Point &point) const { return (point - *this).cast().norm(); } + coordf_t distance_to_square(const Point &point) const { + coordf_t dx = double(point.x() - this->x()); + coordf_t dy = double(point.y() - this->y()); return dx*dx + dy*dy; } - double distance_to(const Line &line) const; + coordf_t distance_to(const Line &line) const; bool coincides_with(const Point &point) const { return this->x() == point.x() && this->y() == point.y(); } bool coincides_with_epsilon(const Point &point) const { return std::abs(this->x() - point.x()) < SCALED_EPSILON/2 && std::abs(this->y() - point.y()) < SCALED_EPSILON/2; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 8d06e30f780..d981f8c9c98 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -150,16 +150,20 @@ namespace Slic3r { // 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 (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) { - const PrintRegion ®ion = this->printing_region(region_id); + for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) { + const PrintRegion ®ion = this->printing_region(region_id); if (!region.config().extra_perimeters || region.config().perimeters == 0 || region.config().fill_density == 0 || this->layer_count() < 2) continue; - + // use an antomic idx instead of the range, to avoid a thread being very late because it's on the difficult layers. + //TODO: sort the layers by difficulty (difficult first) (number of points, region, surfaces, .. ?) + std::atomic_size_t next_layer_idx(0); BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - start"; tbb::parallel_for( tbb::blocked_range(0, m_layers.size() - 1), - [this, ®ion, region_id](const tbb::blocked_range& range) { - for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { + [this, ®ion, region_id, &next_layer_idx](const tbb::blocked_range& range) { + //TODO: find a better wya to just fire the threads. + //for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { + for (size_t layer_idx = next_layer_idx++; layer_idx < m_layers.size() - 1; layer_idx = next_layer_idx++) { m_print->throw_if_canceled(); LayerRegion &layerm = *m_layers[layer_idx]->get_region(region_id); const LayerRegion &upper_layerm = *m_layers[layer_idx+1]->get_region(region_id); @@ -214,10 +218,12 @@ namespace Slic3r { } BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - start"; + std::atomic_size_t next_layer_idx(0); tbb::parallel_for( tbb::blocked_range(0, m_layers.size()), - [this, &atomic_count, nb_layers_update](const tbb::blocked_range& range) { - for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { + [this, &atomic_count, nb_layers_update, &next_layer_idx](const tbb::blocked_range& range) { + //for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { + for (size_t layer_idx = next_layer_idx++; layer_idx < m_layers.size(); layer_idx = next_layer_idx++) { std::chrono::time_point start_make_perimeter = std::chrono::system_clock::now(); m_print->throw_if_canceled(); m_layers[layer_idx]->make_perimeters(); @@ -456,10 +462,13 @@ namespace Slic3r { const int nb_layers_update = std::max(1, (int)m_layers.size() / 20); BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start"; + std::atomic_size_t next_layer_idx(0); tbb::parallel_for( tbb::blocked_range(0, m_layers.size()), - [this, &adaptive_fill_octree = adaptive_fill_octree, &support_fill_octree = support_fill_octree, &lightning_generator, &atomic_count, nb_layers_update](const tbb::blocked_range& range) { - for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { + [this, &adaptive_fill_octree = adaptive_fill_octree, &support_fill_octree = support_fill_octree, &lightning_generator, &atomic_count, nb_layers_update, &next_layer_idx] + (const tbb::blocked_range& range) { + //for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { + for (size_t layer_idx = next_layer_idx++; layer_idx < m_layers.size(); layer_idx = next_layer_idx++) { std::chrono::time_point start_make_fill = std::chrono::system_clock::now(); m_print->throw_if_canceled(); m_layers[layer_idx]->make_fills(adaptive_fill_octree.get(), support_fill_octree.get(), lightning_generator.get()); From 8d523140d49dd39ce516faeef4d1fa36949e4275 Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 11 Jun 2024 14:51:38 +0200 Subject: [PATCH 3/4] Better status message: for prepare infill, sequential object gcode, seam visibility --- src/libslic3r/GCode.cpp | 22 +++++++++++++++++++--- src/libslic3r/GCode.hpp | 2 ++ src/libslic3r/GCode/SeamPlacer.cpp | 7 ++++++- src/libslic3r/PrintBase.hpp | 5 +++-- src/libslic3r/PrintObject.cpp | 20 +++++++++++++++++--- 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 35b072198cb..c574d053e5f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1905,6 +1905,9 @@ void GCode::_do_export(Print& print_mod, GCodeOutputStream &file, ThumbnailsGene this->m_throw_if_canceled(); // Collect custom seam data from all objects. + print.set_status(0, L("Computing seam visibility areas: object %s / %s"), + {"1", std::to_string(print.objects().size())}, + PrintBase::SlicingStatus::FORCE_SHOW | PrintBase::SlicingStatus::SECONDARY_STATE); m_seam_placer.init(print, this->m_throw_if_canceled); //activate first extruder is multi-extruder and not in start-gcode @@ -3073,6 +3076,22 @@ LayerResult GCode::process_layer( // Nothing to extrude. return result; + if (object_layer) { + if (single_object_instance_idx != size_t(-1)) { + size_t nb_layers = object_layer->object()->layer_count(); + m_object_sequentially_printed.insert(object_layer->object()); + print.set_status(int((layer.id() * 100) / nb_layers), + std::string(L("Generating G-code layer %s / %s for object %s / %s")), + std::vector{std::to_string(layer.id()), std::to_string(nb_layers), m_object_sequentially_printed.size(), print.num_object_instances()}, + PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE); + } else { + print.set_status(int((layer.id() * 100) / layer_count()), + std::string(L("Generating G-code layer %s / %s")), + std::vector{std::to_string(layer.id()), std::to_string(layer_count())}, + PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE); + } + } + // Extract 1st object_layer and support_layer of this set of layers with an equal print_z. coordf_t print_z = layer.print_z; bool first_layer = layer_id == 0; @@ -3764,9 +3783,6 @@ LayerResult GCode::process_layer( BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z << log_memory_info(); - if(object_layer) - print.set_status(int((layer.id() * 100) / layer_count()), std::string(L("Generating G-code layer %s / %s")), std::vector{ std::to_string(layer.id()), std::to_string(layer_count()) }, PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE); - result.gcode = std::move(gcode); result.cooling_buffer_flush = object_layer || raft_layer || last_layer; return result; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 89f70520151..2ff9d345c58 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -436,6 +436,8 @@ class GCode : ExtrusionVisitorConst { std::string m_delayed_layer_change; // Keeps track of the last extrusion role passed to the processor ExtrusionRole m_last_processor_extrusion_role; + // For Progress bar indicator, in sequential mode (complete objects) + std::set m_object_sequentially_printed; // How many times will change_layer() be called? // change_layer() will update the progress bar. uint32_t m_layer_count; diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 5ec022a55e3..98d97418c0e 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -1653,7 +1653,12 @@ void SeamPlacer::init(const Print &print, std::function throw_if_can m_seam_per_object.clear(); this->external_perimeters_first = print.default_region_config().external_perimeters_first; - for (const PrintObject *po : print.objects()) { + for (size_t obj_idx = 0; obj_idx < print.objects().size(); ++ obj_idx) { + const PrintObject *po = print.objects()[obj_idx]; + print.set_status(int((obj_idx * 100) / print.objects().size()), + ("Computing seam visibility areas: object %s / %s"), + {std::to_string(obj_idx + 1), std::to_string(print.objects().size())}, + PrintBase::SlicingStatus::SECONDARY_STATE); throw_if_canceled_func(); SeamPosition configured_seam_preference = po->config().seam_position.value; SeamComparator comparator { configured_seam_preference, *po }; diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 255cb0bf305..532865262c8 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -420,7 +420,8 @@ class PrintBase : public ObjectBase SLICING_ENDED = 1 << 6, GCODE_ENDED = 1 << 7, MAIN_STATE = 1 << 8, - SECONDARY_STATE = 1 << 9 + SECONDARY_STATE = 1 << 9, + FORCE_SHOW = 1 << 10 }; // Bitmap of FlagBits unsigned int flags; @@ -443,7 +444,7 @@ class PrintBase : public ObjectBase } void set_status(int percent, const std::string& message, const std::vector& args, unsigned int flags = SlicingStatus::DEFAULT) const { //check if it need an update. Avoid doing a gui update each ms. - if ((flags & SlicingStatus::SECONDARY_STATE) != 0 && message != m_last_status_message) { + if ((flags & SlicingStatus::FORCE_SHOW) == 0 && (flags & SlicingStatus::SECONDARY_STATE) != 0 && message != m_last_status_message) { std::chrono::time_point current_time = std::chrono::system_clock::now(); if ((static_cast>(current_time - PrintBase::m_last_status_update)).count() > 0.002 && PrintBase::m_last_status_percent != percent) { PrintBase::m_last_status_update = current_time; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index d981f8c9c98..aa2a7be1fdb 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -155,7 +155,6 @@ namespace Slic3r { if (!region.config().extra_perimeters || region.config().perimeters == 0 || region.config().fill_density == 0 || this->layer_count() < 2) continue; // use an antomic idx instead of the range, to avoid a thread being very late because it's on the difficult layers. - //TODO: sort the layers by difficulty (difficult first) (number of points, region, surfaces, .. ?) std::atomic_size_t next_layer_idx(0); BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - start"; tbb::parallel_for( @@ -218,6 +217,8 @@ namespace Slic3r { } BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - start"; + // use an antomic idx instead of the range, to avoid a thread being very late because it's on the difficult layers. + //TODO: sort the layers by difficulty (difficult first) (number of points, region, surfaces, .. ?) (and use parallel_for_each( list.begin(), list.end(), ApplyFoo() );) std::atomic_size_t next_layer_idx(0); tbb::parallel_for( tbb::blocked_range(0, m_layers.size()), @@ -281,6 +282,7 @@ namespace Slic3r { // Then the classifcation of $layerm->slices is transfered onto // the $layerm->fill_surfaces by clipping $layerm->fill_surfaces // by the cummulative area of the previous $layerm->fill_surfaces. + m_print->set_status( 0, L("Detect surfaces types"), {}, PrintBase::SlicingStatus::SECONDARY_STATE); this->detect_surfaces_type(); m_print->throw_if_canceled(); @@ -288,11 +290,17 @@ namespace Slic3r { // Here the stTop / stBottomBridge / stBottom infill is turned to just stInternal if zero top / bottom infill layers are configured. // Also tiny stInternal surfaces are turned to stInternalSolid. BOOST_LOG_TRIVIAL(info) << "Preparing fill surfaces..." << log_memory_info(); - for (auto* layer : m_layers) - for (auto* region : layer->m_regions) { + for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++layer_idx) { + Layer *layer = m_layers[layer_idx]; + m_print->set_status(int(100 * layer_idx / m_layers.size()), + L("Prepare fill surfaces: layer %s / %s"), + {std::to_string(layer_idx), std::to_string(m_layers.size())}, + PrintBase::SlicingStatus::SECONDARY_STATE); + for (auto *region : layer->m_regions) { region->prepare_fill_surfaces(); m_print->throw_if_canceled(); } + } // solid_infill_below_area has just beeing applied at the end of prepare_fill_surfaces() apply_solid_infill_below_layer_area(); @@ -306,10 +314,12 @@ namespace Slic3r { // 3) Clip the internal surfaces by the grown top/bottom surfaces. // 4) Merge surfaces with the same style. This will mostly get rid of the overlaps. //FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties. + m_print->set_status( 20, L("Process external surfaces"), {}, PrintBase::SlicingStatus::SECONDARY_STATE); this->process_external_surfaces(); m_print->throw_if_canceled(); // Add solid fills to ensure the shell vertical thickness. + m_print->set_status( 40, L("Discover shells"), {}, PrintBase::SlicingStatus::SECONDARY_STATE); this->discover_vertical_shells(); m_print->throw_if_canceled(); @@ -335,6 +345,7 @@ namespace Slic3r { m_print->throw_if_canceled(); //as there is some too thin solid surface, please deleted them and merge all of the surfacesthat are contigous. + m_print->set_status( 55, L("Clean surfaces"), {}, PrintBase::SlicingStatus::SECONDARY_STATE); this->clean_surfaces(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING @@ -353,6 +364,7 @@ namespace Slic3r { //FIXME The surfaces are supported by a sparse infill, but the sparse infill is only as large as the area to support. // Likely the sparse infill will not be anchored correctly, so it will not work as intended. // Also one wishes the perimeters to be supported by a full infill. + m_print->set_status( 70, L("Clip surfaces"), {}, PrintBase::SlicingStatus::SECONDARY_STATE); this->clip_fill_surfaces(); m_print->throw_if_canceled(); @@ -388,6 +400,7 @@ namespace Slic3r { m_print->throw_if_canceled(); // combine fill surfaces to honor the "infill every N layers" option + m_print->set_status( 85, L("Combine infill"), {}, PrintBase::SlicingStatus::SECONDARY_STATE); this->combine_infill(); m_print->throw_if_canceled(); @@ -462,6 +475,7 @@ namespace Slic3r { const int nb_layers_update = std::max(1, (int)m_layers.size() / 20); BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start"; + // use an antomic idx instead of the range, to avoid a thread being very late because it's on the difficult layers. std::atomic_size_t next_layer_idx(0); tbb::parallel_for( tbb::blocked_range(0, m_layers.size()), From 7d2f06dc8e8546d643d3024c095e77bf28c69af1 Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 11 Jun 2024 15:03:57 +0200 Subject: [PATCH 4/4] Fix crash when multiple objects are printed, and the first one isn't the tallest. supermerill/SuperSlicer#4309 supermerill/SuperSlicer#4313 --- src/libslic3r/GCode.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c574d053e5f..332eece4fb3 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3058,8 +3058,10 @@ LayerResult GCode::process_layer( const Layer *object_layer = nullptr; const SupportLayer *support_layer = nullptr; const SupportLayer *raft_layer = nullptr; - const size_t layer_id = layers.front().layer()->id(); + /*const*/ size_t layer_id = size_t(-1); for (const LayerToPrint &l : layers) { + if(l.layer()) + layer_id = l.layer()->id(); if (l.object_layer && ! object_layer) object_layer = l.object_layer; if (l.support_layer) { @@ -3070,6 +3072,7 @@ LayerResult GCode::process_layer( } assert(l.layer() == nullptr || layer_id == l.layer()->id()); } + assert(layer_id < layer_count()); const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer; LayerResult result { {}, layer.id(), false, last_layer, false}; if (layer_tools.extruders.empty()) @@ -3082,7 +3085,7 @@ LayerResult GCode::process_layer( m_object_sequentially_printed.insert(object_layer->object()); print.set_status(int((layer.id() * 100) / nb_layers), std::string(L("Generating G-code layer %s / %s for object %s / %s")), - std::vector{std::to_string(layer.id()), std::to_string(nb_layers), m_object_sequentially_printed.size(), print.num_object_instances()}, + std::vector{std::to_string(layer.id()), std::to_string(nb_layers), std::to_string(m_object_sequentially_printed.size()), std::to_string(print.num_object_instances())}, PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE); } else { print.set_status(int((layer.id() * 100) / layer_count()),