From 1aed7dfe5b57ba944c5e43448cd24c3dae48f5e6 Mon Sep 17 00:00:00 2001 From: Max Paperno Date: Sun, 8 Mar 2026 22:32:28 -0400 Subject: [PATCH 1/2] FIX: Divide by zero exception in `InterlockingGenerator` when invalid configuration parameters are used. (fixes https://github.com/bambulab/BambuStudio/issues/9910 ) (cherry picked from commit cdd60ab71f8a3895fcb1345b2ccc2f2f472bf968) --- src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp index a3e6cd21b0..84a3d62136 100644 --- a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp +++ b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp @@ -26,7 +26,8 @@ namespace Slic3r { void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_object) { const auto& config = print_object->config(); - if (!config.interlocking_beam) { + // Check if interlocking is enabled, and avoid errors like division by zero due to invalid configuration. + if (!config.interlocking_beam || config.interlocking_beam_layer_count < 1 || config.interlocking_depth < 1 || config.interlocking_beam_width < EPSILON ) { return; } From 485917461a3c6c6930c5bc938c1861281a53932b Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 13 Mar 2026 23:33:19 +0800 Subject: [PATCH 2/2] Allow cancellation during beam interlocking generation --- .../Feature/Interlocking/InterlockingGenerator.cpp | 12 +++++++++--- .../Feature/Interlocking/InterlockingGenerator.hpp | 8 ++++++-- src/libslic3r/PrintObjectSlice.cpp | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp index 84a3d62136..726ee2ffd8 100644 --- a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp +++ b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp @@ -23,7 +23,7 @@ template<> struct hash namespace Slic3r { -void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_object) +void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_object, const std::function& throw_on_cancel) { const auto& config = print_object->config(); // Check if interlocking is enabled, and avoid errors like division by zero due to invalid configuration. @@ -56,8 +56,10 @@ void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_o continue; } + throw_on_cancel(); + InterlockingGenerator gen(*print_object, region_a_index, region_b_index, beam_width, boundary_avoidance, rotation, cell_size, beam_layer_count, - interface_dilation, air_dilation, air_filtering); + interface_dilation, air_dilation, air_filtering, throw_on_cancel); gen.generateInterlockingStructure(); } } @@ -109,12 +111,14 @@ void InterlockingGenerator::handleThinAreas(const std::unordered_set } } for (auto& near_interlock : near_interlock_per_layer) { + throw_on_cancel(); near_interlock = offset(union_(closing(near_interlock, rounding_errors)), detect); polygons_rotate(near_interlock, rotation); } // Only alter layers when they are present in both meshes, zip should take care if that. for (size_t layer_nr = 0; layer_nr < print_object.layer_count(); layer_nr++){ + throw_on_cancel(); auto layer = print_object.get_layer(layer_nr); ExPolygons polys_a = to_expolygons(layer->get_region(region_a_index)->slices.surfaces); ExPolygons polys_b = to_expolygons(layer->get_region(region_b_index)->slices.surfaces); @@ -200,7 +204,8 @@ void InterlockingGenerator::addBoundaryCells(const std::vector& lay const DilationKernel& kernel, std::unordered_set& cells) const { - auto voxel_emplacer = [&cells](GridPoint3 p) { + auto voxel_emplacer = [this, &cells](GridPoint3 p) { + this->throw_on_cancel(); if (p.z() < 0) { return true; } @@ -314,6 +319,7 @@ void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_s for (size_t region_idx = 0; region_idx < 2; region_idx++) { const size_t region = (region_idx == 0) ? region_a_index : region_b_index; for (size_t layer_nr = 0; layer_nr < max_layer_count; layer_nr++) { + throw_on_cancel(); ExPolygons layer_outlines = layer_regions[layer_nr]; expolygons_rotate(layer_outlines, unapply_rotation); diff --git a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp index 6f331fb8ef..e6b79f9bc8 100644 --- a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp +++ b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp @@ -45,7 +45,7 @@ public: /*! * Generate an interlocking structure between each two adjacent meshes. */ - static void generate_interlocking_structure(PrintObject* print_object); + static void generate_interlocking_structure(PrintObject* print_object, const std::function& throw_on_cancel); private: /*! @@ -75,7 +75,8 @@ private: const coord_t beam_layer_count, const DilationKernel& interface_dilation, const DilationKernel& air_dilation, - const bool air_filtering) + const bool air_filtering, + const std::function& throw_on_cancel) : print_object(print_object) , region_a_index(region_a_index) , region_b_index(region_b_index) @@ -88,6 +89,7 @@ private: , interface_dilation(interface_dilation) , air_dilation(air_dilation) , air_filtering(air_filtering) + , throw_on_cancel(throw_on_cancel) {} /*! Given two polygons, return the parts that border on air, and grow 'perpendicular' up to 'detect' distance. @@ -165,6 +167,8 @@ private: // Whether to fully remove all of the interlocking cells which would be visible on the outside. If no air filtering then those cells // will be cut off midway in a beam. const bool air_filtering; + + const std::function& throw_on_cancel; }; } // namespace Slic3r diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 532307414d..2d67ac0939 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -1212,7 +1212,7 @@ void PrintObject::slice_volumes() apply_fuzzy_skin_segmentation(*this, [print]() { print->throw_if_canceled(); }); } - InterlockingGenerator::generate_interlocking_structure(this); + InterlockingGenerator::generate_interlocking_structure(this, [print]() { print->throw_if_canceled(); }); m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin";