From f2b938ebc694052a95aa9b4684a5c61c81e5534b Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 19 Dec 2023 14:42:36 +0800 Subject: [PATCH] FIX: prevent slicing with adaptive layer height and organic support Variable layer height is not supported with Organic supports. This is picked from Prusa. Thanks. jira: STUDIO-5614, STUDIO-5615 Change-Id: Iea462ecf8dd56e2a5a25cbe071519c29a2a763d3 (cherry picked from commit 708c5f0f7a00a30f9fe414b3dabe007ebdc48ca6) --- src/libslic3r/Model.hpp | 4 ++++ src/libslic3r/Print.cpp | 46 ++++++++++++++++++++++++++++----------- src/libslic3r/Slicing.cpp | 34 +++++++++++++++++++++++++++++ src/libslic3r/Slicing.hpp | 4 ++++ 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 8c7585e14..a6449ad6d 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -410,6 +410,10 @@ public: bool is_seam_painted() const; // Checks if any of object volume is painted using the multi-material painting gizmo. bool is_mm_painted() const; + // This object may have a varying layer height by painting or by a table. + // Even if true is returned, the layer height profile may be "flat" with no difference to default layering. + bool has_custom_layering() const + { return ! this->layer_config_ranges.empty() || ! this->layer_height_profile.empty(); } ModelInstance* add_instance(); ModelInstance* add_instance(const ModelInstance &instance); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 049635da2..11f8f675c 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1032,6 +1032,32 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* return {L("The spiral vase mode does not work when an object contains more than one materials."), nullptr, "spiral_mode"}; } + // Cache of layer height profiles for checking: + // 1) Whether all layers are synchronized if printing with wipe tower and / or unsynchronized supports. + // 2) Whether layer height is constant for Organic supports. + // 3) Whether build volume Z is not violated. + std::vector> layer_height_profiles; + auto layer_height_profile = [this, &layer_height_profiles](const size_t print_object_idx) -> const std::vector& { + const PrintObject &print_object = *m_objects[print_object_idx]; + if (layer_height_profiles.empty()) + layer_height_profiles.assign(m_objects.size(), std::vector()); + std::vector &profile = layer_height_profiles[print_object_idx]; + if (profile.empty()) + PrintObject::update_layer_height_profile(*print_object.model_object(), print_object.slicing_parameters(), profile); + return profile; + }; + + + // Custom layering is not allowed for tree supports as of now. + for (size_t print_object_idx = 0; print_object_idx < m_objects.size(); ++ print_object_idx) + if (const PrintObject &print_object = *m_objects[print_object_idx]; + print_object.has_support_material() && is_tree(print_object.config().support_type.value) && print_object.config().support_style.value == smsTreeOrganic && + print_object.model_object()->has_custom_layering()) { + if (const std::vector &layers = layer_height_profile(print_object_idx); ! layers.empty()) + if (! check_object_layers_fixed(print_object.slicing_parameters(), layers)) + return { L("Variable layer height is not supported with Organic supports.") }; + } + if (this->has_wipe_tower() && ! m_objects.empty()) { // Make sure all extruders use same diameter filament and have the same nozzle diameter // EPSILON comparison is used for nozzles and 10 % tolerance is used for filaments @@ -1079,19 +1105,12 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* #endif if (m_objects.size() > 1) { - bool has_custom_layering = false; - std::vector> layer_height_profiles; - for (const PrintObject *object : m_objects) { - has_custom_layering = ! object->model_object()->layer_config_ranges.empty() || ! object->model_object()->layer_height_profile.empty(); - if (has_custom_layering) { - layer_height_profiles.assign(m_objects.size(), std::vector()); - break; - } - } + // Some of the objects has variable layer height applied by painting or by a table. + bool has_custom_layering = std::any_of(m_objects.begin(), m_objects.end(), + [](const PrintObject* object) { return object->model_object()->has_custom_layering(); }); + const SlicingParameters &slicing_params0 = m_objects.front()->slicing_parameters(); size_t tallest_object_idx = 0; - if (has_custom_layering) - PrintObject::update_layer_height_profile(*m_objects.front()->model_object(), slicing_params0, layer_height_profiles.front()); for (size_t i = 1; i < m_objects.size(); ++ i) { const PrintObject *object = m_objects[i]; const SlicingParameters &slicing_params = object->slicing_parameters(); @@ -1109,8 +1128,9 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* if (!equal_layering(slicing_params, slicing_params0)) return { L("The prime tower requires that all objects are sliced with the same layer heights."), object }; if (has_custom_layering) { - PrintObject::update_layer_height_profile(*object->model_object(), slicing_params, layer_height_profiles[i]); - if (*(layer_height_profiles[i].end()-2) > *(layer_height_profiles[tallest_object_idx].end()-2)) + auto &lh = layer_height_profile(i); + auto &lh_tallest = layer_height_profile(tallest_object_idx); + if (*(lh.end()-2) > *(lh_tallest.end()-2)) tallest_object_idx = i; } } diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 2c0185d26..b7e159316 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -685,6 +685,40 @@ std::vector generate_object_layers( return out; } +// Check whether the layer height profile describes a fixed layer height profile. +bool check_object_layers_fixed( + const SlicingParameters &slicing_params, + const std::vector &layer_height_profile) +{ + assert(layer_height_profile.size() >= 4); + assert(layer_height_profile.size() % 2 == 0); + assert(layer_height_profile[0] == 0); + + if (layer_height_profile.size() != 4 && layer_height_profile.size() != 8) + return false; + + bool fixed_step1 = is_approx(layer_height_profile[1], layer_height_profile[3]); + bool fixed_step2 = layer_height_profile.size() == 4 || + (layer_height_profile[2] == layer_height_profile[4] && is_approx(layer_height_profile[5], layer_height_profile[7])); + + if (! fixed_step1 || ! fixed_step2) + return false; + + if (layer_height_profile[2] < 0.5 * slicing_params.first_object_layer_height + EPSILON || + ! is_approx(layer_height_profile[3], slicing_params.first_object_layer_height)) + return false; + + double z_max = layer_height_profile[layer_height_profile.size() - 2]; + double z_2nd = slicing_params.first_object_layer_height + 0.5 * slicing_params.layer_height; + if (z_2nd > z_max) + return true; + if (z_2nd < *(layer_height_profile.end() - 4) + EPSILON || + ! is_approx(layer_height_profile.back(), slicing_params.layer_height)) + return false; + + return true; +} + int generate_layer_height_texture( const SlicingParameters &slicing_params, const std::vector &layers, diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index db0be3b86..00ea608e6 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -175,6 +175,10 @@ extern std::vector generate_object_layers( const SlicingParameters &slicing_params, const std::vector &layer_height_profile); +// Check whether the layer height profile describes a fixed layer height profile. +bool check_object_layers_fixed( + const SlicingParameters &slicing_params, + const std::vector &layer_height_profile); // Produce a 1D texture packed into a 2D texture describing in the RGBA format // the planned object layers. // Returns number of cells used by the texture of the 0th LOD level.