diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 36e4186f297..f088b6b24bb 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1,3 +1,15 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Tomáš Mészáros @tamasmeszaros, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, David Kocík @kocikdav, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2019 John Drake @foxox +///|/ Copyright (c) 2019 Sijmen Schoon +///|/ Copyright (c) 2017 Eyal Soha @eyal0 +///|/ Copyright (c) Slic3r 2014 - 2015 Alessandro Ranellucci @alranel +///|/ +///|/ ported from lib/Slic3r/Model.pm: +///|/ Copyright (c) Prusa Research 2016 - 2022 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966 +///|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_Model_hpp_ #define slic3r_Model_hpp_ @@ -398,6 +410,10 @@ class ModelObject final : public ObjectBase 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 4656e318a19..5afa63f2084 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1,3 +1,25 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Lukáš Matěna @lukasmatena, Tomáš Mészáros @tamasmeszaros, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Pavel Mikuš @Godrak, Oleksandra Iushchenko @YuSanka, Lukáš Hejl @hejllukas, Filip Sykala @Jony01, Roman Beránek @zavorka, David Kocík @kocikdav +///|/ Copyright (c) BambuStudio 2023 manch1n @manch1n +///|/ Copyright (c) SuperSlicer 2023 Remi Durand @supermerill +///|/ Copyright (c) 2021 Martin Budden +///|/ Copyright (c) 2020 Paul Arden @ardenpm +///|/ Copyright (c) 2019 Thomas Moore +///|/ Copyright (c) 2019 Bryan Smith +///|/ Copyright (c) Slic3r 2013 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2014 Petr Ledvina @ledvinap +///|/ +///|/ ported from lib/Slic3r/Print.pm: +///|/ Copyright (c) Prusa Research 2016 - 2018 Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros +///|/ Copyright (c) Slic3r 2011 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2012 - 2013 Mark Hindess +///|/ Copyright (c) 2013 Devin Grady +///|/ Copyright (c) 2012 - 2013 Mike Sheldrake @mesheldrake +///|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen +///|/ Copyright (c) 2012 Michael Moon +///|/ Copyright (c) 2011 Richard Goodwin +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "Exception.hpp" #include "Print.hpp" #include "BoundingBox.hpp" @@ -1034,6 +1056,53 @@ 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; + }; + + // Checks that the print does not exceed the max print height + for (size_t print_object_idx = 0; print_object_idx < m_objects.size(); ++ print_object_idx) { + const PrintObject &print_object = *m_objects[print_object_idx]; + //FIXME It is quite expensive to generate object layers just to get the print height! + if (auto layers = generate_object_layers(print_object.slicing_parameters(), layer_height_profile(print_object_idx)); + ! layers.empty() && layers.back() > this->config().printable_height + EPSILON) { + return + // Test whether the last slicing plane is below or above the print volume. + { 0.5 * (layers[layers.size() - 2] + layers.back()) > this->config().printable_height + EPSILON ? + format(_u8L("The object %1% exceeds the maximum build volume height."), print_object.model_object()->name) : + format(_u8L("While the object %1% itself fits the build volume, its last layer exceeds the maximum build volume height."), print_object.model_object()->name) + + " " + _u8L("You might want to reduce the size of your model or change current print settings and retry.") }; + } + } + + // Some of the objects has variable layer height applied by painting or by a table. + bool has_custom_layering = std::find_if(m_objects.begin(), m_objects.end(), + [](const PrintObject *object) { return object->model_object()->has_custom_layering(); }) + != m_objects.end(); + + // 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 == smsOrganic || + // Orca: use organic as default + print_object.config().support_style.value == smsDefault) && + 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 {_u8L("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 @@ -1081,19 +1150,8 @@ 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; - } - } 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()); + size_t tallest_object_idx = 0; for (size_t i = 1; i < m_objects.size(); ++ i) { const PrintObject *object = m_objects[i]; const SlicingParameters &slicing_params = object->slicing_parameters(); @@ -1111,8 +1169,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; } } @@ -1198,7 +1257,9 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* // Prusa: Fixing crashes with invalid tip diameter or branch diameter // https://github.com/prusa3d/PrusaSlicer/commit/96b3ae85013ac363cd1c3e98ec6b7938aeacf46d - if (object->config().support_style == smsOrganic) { + if (is_tree(object->config().support_type.value) && (object->config().support_style == smsOrganic || + // Orca: use organic as default + object->config().support_style == smsDefault)) { float extrusion_width = std::min( support_material_flow(object).width(), support_material_interface_flow(object).width()); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index e3b089ca6e5..0d473bdc542 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1,3 +1,12 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Lukáš Hejl @hejllukas, Pavel Mikuš @Godrak, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, David Kocík @kocikdav, Roman Beránek @zavorka +///|/ Copyright (c) 2021 Justin Schuh @jschuh +///|/ Copyright (c) 2021 Ilya @xorza +///|/ Copyright (c) 2016 Joseph Lenox @lordofhyphens +///|/ Copyright (c) Slic3r 2014 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2015 Maksim Derbasov @ntfshard +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "Exception.hpp" #include "Print.hpp" #include "BoundingBox.hpp" @@ -2086,6 +2095,8 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c // use the constructor because the assignement is crashing on ASAN OsX layer_height_profile = std::vector(model_object.layer_height_profile.get()); // layer_height_profile = model_object.layer_height_profile; + // The layer height returned is sampled with high density for the UI layer height painting + // and smoothing tool to work. updated = true; } @@ -2100,6 +2111,7 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c if (layer_height_profile.empty() || layer_height_profile[1] != slicing_parameters.first_object_layer_height) { //layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes); layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); + // The layer height profile is already compressed. updated = true; } @@ -2539,7 +2551,9 @@ void PrintObject::_generate_support_material() support_material.generate(*this); if (this->config().enable_support.value && is_tree(this->config().support_type.value)) { - if (this->config().support_style.value == smsOrganic || this->config().support_style.value == smsDefault) { + if (this->config().support_style.value == smsOrganic || + // Orca: use organic as default + this->config().support_style.value == smsDefault) { fff_tree_support_generate(*this, std::function([this]() { this->throw_if_canceled(); })); } else { TreeSupport tree_support(*this, m_slicing_params); diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index e84d00630ae..acfb17e856b 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, David Kocík @kocikdav, Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include #include "libslic3r.h" @@ -321,7 +325,7 @@ std::vector layer_height_profile_adaptive(const SlicingParameters& slici print_z += height; } - double z_gap = slicing_params.object_print_z_height() - layer_height_profile[layer_height_profile.size() - 2]; + double z_gap = slicing_params.object_print_z_height() - *(layer_height_profile.end() - 2); if (z_gap > 0.0) { layer_height_profile.push_back(slicing_params.object_print_z_height()); @@ -685,6 +689,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 db0be3b863e..464a05ba443 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena, David Kocík @kocikdav, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Vojtěch Král @vojtechkral +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ // Based on implementation by @platsch #ifndef slic3r_Slicing_hpp_ @@ -133,11 +137,11 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters typedef std::pair t_layer_height_range; typedef std::map t_layer_config_ranges; -extern std::vector layer_height_profile_from_ranges( +std::vector layer_height_profile_from_ranges( const SlicingParameters &slicing_params, const t_layer_config_ranges &layer_config_ranges); -extern std::vector layer_height_profile_adaptive( +std::vector layer_height_profile_adaptive( const SlicingParameters& slicing_params, const ModelObject& object, float quality_factor); @@ -150,7 +154,7 @@ struct HeightProfileSmoothingParams HeightProfileSmoothingParams(unsigned int radius, bool keep_min) : radius(radius), keep_min(keep_min) {} }; -extern std::vector smooth_height_profile( +std::vector smooth_height_profile( const std::vector& profile, const SlicingParameters& slicing_params, const HeightProfileSmoothingParams& smoothing_params); @@ -161,7 +165,7 @@ enum LayerHeightEditActionType : unsigned int { LAYER_HEIGHT_EDIT_ACTION_SMOOTH = 3 }; -extern void adjust_layer_height_profile( +void adjust_layer_height_profile( const SlicingParameters &slicing_params, std::vector &layer_height_profile, coordf_t z, @@ -171,14 +175,19 @@ extern void adjust_layer_height_profile( // Produce object layers as pairs of low / high layer boundaries, stored into a linear vector. // The object layers are based at z=0, ignoring the raft layers. -extern std::vector generate_object_layers( +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. -extern int generate_layer_height_texture( +int generate_layer_height_texture( const SlicingParameters &slicing_params, const std::vector &layers, void *data, int rows, int cols, bool level_of_detail_2nd_level); diff --git a/src/libslic3r/Support/SupportCommon.cpp b/src/libslic3r/Support/SupportCommon.cpp index 50e19cca0db..9b2610a4bd6 100644 --- a/src/libslic3r/Support/SupportCommon.cpp +++ b/src/libslic3r/Support/SupportCommon.cpp @@ -1794,7 +1794,9 @@ void generate_support_toolpaths( filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density)); sheath = true; no_sort = true; - } else if (config.support_style == SupportMaterialStyle::smsOrganic) { + } else if (config.support_style == SupportMaterialStyle::smsOrganic || + // Orca: use organic as default + config.support_style == smsDefault) { tree_supports_generate_paths(base_layer.extrusions, base_layer.polygons_to_extrude(), flow, support_params); done = true; } diff --git a/src/libslic3r/Support/SupportMaterial.cpp b/src/libslic3r/Support/SupportMaterial.cpp index 8b1d8bc0dbe..7e1e98c193e 100644 --- a/src/libslic3r/Support/SupportMaterial.cpp +++ b/src/libslic3r/Support/SupportMaterial.cpp @@ -696,6 +696,9 @@ class SupportGridPattern case smsTreeSlim: case smsTreeStrong: case smsTreeHybrid: + + // Orca: use organic as default + case smsDefault: case smsOrganic: // assert(false); [[fallthrough]]; diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index b119824c693..5831a1d61e7 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -3530,8 +3530,10 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume auto t_place = std::chrono::high_resolution_clock::now(); // ### draw these points as circles - - if (print_object.config().support_style.value != smsOrganic) + + if (print_object.config().support_style.value != smsOrganic && + // Orca: use organic as default + print_object.config().support_style.value != smsDefault) draw_areas(*print.get_object(processing.second.front()), volumes, config, overhangs, move_bounds, bottom_contacts, top_contacts, intermediate_layers, layer_storage, throw_on_cancel); else { diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 2f62eadf762..e801e92bec3 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -596,7 +596,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co //toggle_field("support_closing_radius", have_support_material && support_style == smsSnug); bool support_is_tree = config->opt_bool("enable_support") && is_tree(support_type); - bool support_is_normal_tree = support_is_tree && support_style != smsOrganic && support_style != smsDefault; + bool support_is_normal_tree = support_is_tree && support_style != smsOrganic && + // Orca: use organic as default + support_style != smsDefault; bool support_is_organic = support_is_tree && !support_is_normal_tree; // settings shared by normal and organic trees for (auto el : {"tree_support_branch_angle", "tree_support_branch_distance", "tree_support_branch_diameter" }) @@ -613,6 +615,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line("max_bridge_length", support_is_normal_tree); toggle_line("bridge_no_support", !support_is_normal_tree); + // This is only supported for auto normal tree + toggle_line("support_critical_regions_only", is_auto(support_type) && support_is_normal_tree); + for (auto el : { "support_interface_spacing", "support_interface_filament", "support_interface_loop_pattern", "support_bottom_interface_spacing" }) toggle_field(el, have_support_material && have_support_interface);