From ab1ac42dc2c6387aaa88120b2e345f90204a388d Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 12 Jun 2024 00:08:39 +0200 Subject: [PATCH 1/5] fix OCCTWrapper on linux: build it before copying --- BuildLinux.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BuildLinux.sh b/BuildLinux.sh index 45f01e7f4f7..4a97d81e988 100755 --- a/BuildLinux.sh +++ b/BuildLinux.sh @@ -199,12 +199,18 @@ then cmake .. -DCMAKE_PREFIX_PATH="$PWD/../deps/build/destdir/usr/local" -DSLIC3R_STATIC=1 ${BUILD_ARGS} echo "done" + #make avrdude-slic3r + make avrdude-slic3r + # make Slic3r echo "[8/9] Building Slic3r..." make -j$NCORES Slic3r # make .mo make gettext_po_to_mo + + # make OCCTWrapper.so + make OCCTWrapper popd echo "done" From 4f754f251bfdef402b88491cad328af6d52cfb63 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 3 Jul 2024 13:34:53 +0200 Subject: [PATCH 2/5] move size() from ConfigOptionVectorBase to ConfigOption --- src/libslic3r/Config.hpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index f8a2105425d..2723eadc288 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -507,11 +507,13 @@ class ConfigOption { virtual ConfigOption* clone() const = 0; // Set a value from a ConfigOption. The two options should be compatible. virtual void set(const ConfigOption *option) = 0; + // Getters, idx is ignored if it's a scalar value. virtual int32_t get_int(size_t idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_int on a non-int ConfigOption"); } virtual double get_float(size_t idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_float on a non-float ConfigOption"); } virtual bool is_percent(size_t idx = 0) const { return false; } virtual bool get_bool(size_t idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_bool on a non-boolean ConfigOption"); } virtual void set_enum_int(int32_t /* val */) { throw BadOptionTypeException("Calling ConfigOption::set_enum_int on a non-enum ConfigOption"); } + // If scalar, idx is ignore, else: if idx < 0 return the vector; if idx >=0 then return the value at theis index; if idx >= size(), then return the first value or a default one. virtual boost::any get_any(int32_t idx = -1) const { throw BadOptionTypeException("Calling ConfigOption::get_any on a raw ConfigOption"); } virtual void set_any(boost::any, int32_t idx = -1) { throw BadOptionTypeException("Calling ConfigOption::set_any on a raw ConfigOption"); } virtual bool is_enabled(size_t idx = -1) const { return (flags & FCO_ENABLED) != 0; } @@ -528,6 +530,8 @@ class ConfigOption { virtual size_t hash() const throw() = 0; bool is_scalar() const { return (int(this->type()) & int(coVectorType)) == 0; } bool is_vector() const { return ! this->is_scalar(); } + // Size of the vector it contains, or 1 if it's a scalar value. + virtual size_t size() const = 0; // If this option is nullable, then it may have its value or values set to nil. virtual bool nullable() const { return false; } // A scalar is nil, or all values of a vector are nil if idx < 0. @@ -564,6 +568,7 @@ class ConfigOptionSingle : public ConfigOption { operator T() const { return this->value; } boost::any get_any(int32_t idx = -1) const override { return boost::any(value); } void set_any(boost::any anyval, int32_t idx = -1) override { value = boost::any_cast(anyval); } + size_t size() const override { return 1; } void set(const ConfigOption *rhs) override { @@ -626,8 +631,6 @@ class ConfigOptionVectorBase : public ConfigOption { // currently, it's used to try to have a meaningful value for a Field if the default value is Nil (and to avoid cloning the option, clear it, asking for an item) virtual boost::any get_default_value() const = 0; - // Get size of this vector. - virtual size_t size() const = 0; // Is this vector empty? virtual bool empty() const = 0; // Get if the size of this vector is/should be the same as nozzle_diameter @@ -942,6 +945,7 @@ class ConfigOptionVector : public ConfigOptionVectorBase return true; return false; } + // Apply an override option, possibly a nullable one. bool apply_override(const ConfigOption *rhs) override { if (this->nullable()) @@ -3147,9 +3151,11 @@ class DynamicConfig : public virtual ConfigBase // Thus the virtual method get_int() is used to retrieve the enum value. template ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast(this->option(opt_key)->get_int()); } - + bool opt_bool(const t_config_option_key &opt_key) const { return this->option(opt_key)->value != 0; } bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option(opt_key)->get_at(idx) != 0; } + bool& opt_bool(const t_config_option_key &opt_key) { return this->option(opt_key)->value; } + unsigned char& opt_bool(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } // Command line processing bool read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys = nullptr); From 8410660bda7ddb460a57d42bda24e7d3fae79d01 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 3 Jul 2024 13:35:39 +0200 Subject: [PATCH 3/5] move printer config manipulation from Tab to ConfigManipulation also add some checks about min & max layer height. --- src/libslic3r/PrintConfig.cpp | 2 +- src/slic3r/GUI/ConfigManipulation.cpp | 139 ++++++++++++++++++++++++++ src/slic3r/GUI/ConfigManipulation.hpp | 4 + src/slic3r/GUI/Tab.cpp | 134 +------------------------ 4 files changed, 148 insertions(+), 131 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 8d7f0e067df..fab433df5fe 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3749,7 +3749,7 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm or %"); def->ratio_over = "nozzle_diameter"; def->min = 0; - def->max_literal = { 10, false }; + def->max_literal = { 1, true }; def->mode = comSimpleAE | comPrusa; def->is_vector_extruder = true; def->set_default_value(new ConfigOptionFloatsOrPercents{ FloatOrPercent{ 75, true} }); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 2471b601843..4503a947eb0 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -597,6 +597,145 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("max_print_speed", config->opt_float("max_volumetric_speed") != 0); } + +void ConfigManipulation::update_printer_fff_config(DynamicPrintConfig *config, + const bool is_global_config) +{ + const std::vector &nozzle_sizes = config->option("nozzle_diameter")->get_values(); + //for each extruder + for (size_t extruder_idx = 0; extruder_idx < nozzle_sizes.size(); ++extruder_idx) { + double min_lh = config->get_computed_value("min_layer_height", extruder_idx); + double max_lh = config->get_computed_value("max_layer_height", extruder_idx); + if (max_lh > nozzle_sizes[extruder_idx]) { + const wxString msg_text = _( + L("Maximum layer height is not valid, it can't be higher than the nozzle diameter.\n\nThe maximum layer height will be set to 100% of the nozzle diameter.")); + MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Maximum layer height")), wxICON_WARNING | wxOK); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + dialog.ShowModal(); + new_conf.option("max_layer_height")->set_at(FloatOrPercent{100., true}, extruder_idx); + apply(config, &new_conf); + is_msg_dlg_already_exist = false; + } + if (min_lh >= max_lh) { + const wxString msg_text = _( + L("Minimum layer height is not valid, it can't be higher or equal to the maximum layer height.\n\nThe minimum layer height will be set to 0.")); + MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Minimum layer height")), wxICON_WARNING | wxOK); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + dialog.ShowModal(); + new_conf.option("min_layer_height")->set_at(FloatOrPercent{0.0, false}, extruder_idx); + apply(config, &new_conf); + is_msg_dlg_already_exist = false; + } + + bool have_retract_length = config->opt_float("retract_length", extruder_idx) > 0; + bool use_firmware_retraction = config->opt_bool("use_firmware_retraction"); + bool wipe = config->opt_bool("wipe", extruder_idx) && have_retract_length; + if (use_firmware_retraction && wipe) { + DynamicPrintConfig new_conf = *config; + //wxMessageDialog dialog(parent(), + MessageDialog dialog(m_msg_dlg_parent, + _(L("The Wipe option is not available when using the Firmware Retraction mode.\n" + "\nShall I disable it in order to enable Firmware Retraction?")), + _(L("Firmware Retraction")), wxICON_WARNING | wxYES | wxNO); + + if (dialog.ShowModal() == wxID_YES) { + new_conf.opt_bool("wipe", extruder_idx) = false; + } else { + new_conf.opt_bool("use_firmware_retraction") = false; + } + apply(config, &new_conf); + } + } +} +void ConfigManipulation::toggle_printer_fff_options(DynamicPrintConfig *config, DynamicPrintConfig &full_config) +{ + Field* field; + + size_t extruder_count = config->option("nozzle_diameter")->size(); + toggle_field("toolchange_gcode", extruder_count > 1); + toggle_field("single_extruder_multi_material", extruder_count > 1); + + //thumbnails + bool custom_color = config->opt_bool("thumbnails_custom_color"); + toggle_field("thumbnails_color", custom_color); + const ConfigOptionEnum* thumbnails_format = config->option>("thumbnails_format"); + + if (thumbnails_format) { + toggle_field("thumbnails_end_file", thumbnails_format->value != (GCodeThumbnailsFormat::BIQU)); + toggle_field("thumbnails_tag_format", thumbnails_format->value != (GCodeThumbnailsFormat::BIQU)); + } + + //firmware + bool have_remaining_times = config->opt_bool("remaining_times"); + toggle_field("remaining_times_type", have_remaining_times); + + bool have_arc_fitting = config->opt_bool("arc_fitting"); + toggle_field("arc_fitting_tolerance", have_arc_fitting); + + auto flavor = config->option>("gcode_flavor")->value; + bool is_marlin_flavor = flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware; + // Disable silent mode for non-marlin firmwares. + toggle_field("silent_mode", is_marlin_flavor); + + for (size_t i = 0; i < extruder_count; ++i) { + + bool have_retract_length = config->opt_float("retract_length", i) > 0; + + // when using firmware retraction, firmware decides retraction length + bool use_firmware_retraction = config->opt_bool("use_firmware_retraction"); + toggle_field("retract_length", !use_firmware_retraction, i); + + // retraction only if have retraction length or we're using firmware retraction + bool retraction = (have_retract_length || use_firmware_retraction); + + // user can customize other retraction options if retraction is enabled + std::vector vec = { "retract_lift", "retract_layer_change", "retract_before_travel" }; + for (auto el : vec) { + toggle_field(el, retraction, i); + } + + bool has_lift = retraction && config->opt_float("retract_lift", i) > 0; + // retract lift above / below only applies if using retract lift + vec.resize(0); + vec = { "retract_lift_above", "retract_lift_below", "retract_lift_top", "retract_lift_first_layer", "retract_lift_before_travel"}; + for (auto el : vec) { + toggle_field(el, has_lift, i); + } + + // some options only apply when not using firmware retraction + vec.resize(0); + vec = { "retract_speed", "deretract_speed", "retract_before_wipe", "retract_restart_extra", "wipe", "wipe_speed" , "wipe_only_crossing"}; + for (auto el : vec) { + toggle_field(el, retraction && !use_firmware_retraction, i); + } + + bool wipe = config->opt_bool("wipe", i) && have_retract_length; + vec.resize(0); + vec = { "retract_before_wipe", "wipe_only_crossing", "wipe_speed" }; + for (auto el : vec) { + toggle_field(el, wipe, i); + } + + // wipe_only_crossing can only work if avoid_crossing_perimeters + if (!full_config.option("avoid_crossing_perimeters")->get_bool()) { + toggle_field("wipe_only_crossing", false, i); + } + + toggle_field("retract_length_toolchange", extruder_count > 1, i); + + bool toolchange_retraction = config->opt_float("retract_length_toolchange", i) > 0; + toggle_field("retract_restart_extra_toolchange", extruder_count > 1 && toolchange_retraction, i); + } + if (config->opt_bool("single_extruder_multi_material") && extruder_count > 1) { + bool have_advanced_wipe_volume = config->opt_bool("wipe_advanced"); + for (auto el : { "wipe_advanced_nozzle_melted_volume", "wipe_advanced_multiplier", "wipe_advanced_algo" }) { + toggle_field(el, have_advanced_wipe_volume); + } + } +} + void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) { double head_penetration = config->opt_float("support_head_penetration"); diff --git a/src/slic3r/GUI/ConfigManipulation.hpp b/src/slic3r/GUI/ConfigManipulation.hpp index 32ddb52a91a..244de4ffacd 100644 --- a/src/slic3r/GUI/ConfigManipulation.hpp +++ b/src/slic3r/GUI/ConfigManipulation.hpp @@ -58,6 +58,10 @@ class ConfigManipulation void update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config = false); void toggle_print_fff_options(DynamicPrintConfig* config); + // FFF printer + void update_printer_fff_config(DynamicPrintConfig* config, const bool is_global_config = false); + void toggle_printer_fff_options(DynamicPrintConfig* config, DynamicPrintConfig &full_config); + // SLA print void update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config = false); void toggle_print_sla_options(DynamicPrintConfig* config); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ec56dcf2c77..b30b2d2f485 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3606,8 +3606,6 @@ void TabPrinter::toggle_options() if (!m_active_page || m_presets->get_edited_preset().printer_technology() != ptFFF) return; - Field* field; - const DynamicPrintConfig& print_config = m_preset_bundle->fff_prints.get_edited_preset().config; const DynamicPrintConfig& filament_config = m_preset_bundle->filaments.get_edited_preset().config; const DynamicPrintConfig& printer_config = m_preset_bundle->printers.get_edited_preset().config; @@ -3618,37 +3616,8 @@ void TabPrinter::toggle_options() full_print_config.apply(filament_config); full_print_config.apply(printer_config); - bool have_multiple_extruders = m_extruders_count > 1; - field = get_field("toolchange_gcode"); - if (field) field->toggle(have_multiple_extruders); - field = get_field("single_extruder_multi_material"); - if (field) field->toggle(have_multiple_extruders); - - //thumbnails - bool custom_color = m_config->opt_bool("thumbnails_custom_color"); - field = get_field("thumbnails_color"); - if (field) field->toggle(custom_color); - const ConfigOptionEnum* thumbnails_format = m_config->option>("thumbnails_format"); - field = get_field("thumbnails_end_file"); - if (thumbnails_format && field) field->toggle(thumbnails_format->value != (GCodeThumbnailsFormat::BIQU)); - field = get_field("thumbnails_tag_format"); - if (thumbnails_format && field) field->toggle(thumbnails_format->value != (GCodeThumbnailsFormat::BIQU)); - - //firmware - bool have_remaining_times = m_config->opt_bool("remaining_times"); - field = get_field("remaining_times_type"); - if (field) field->toggle(have_remaining_times); - - bool have_arc_fitting = m_config->opt_bool("arc_fitting"); - field = get_field("arc_fitting_tolerance"); - if (field) field->toggle(have_arc_fitting); - - auto flavor = m_config->option>("gcode_flavor")->value; - bool is_marlin_flavor = flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware; - // Disable silent mode for non-marlin firmwares. - field = get_field("silent_mode"); - if (field) field->toggle(is_marlin_flavor); - + m_config_manipulation.toggle_printer_fff_options(m_config, full_print_config); + if (m_last_gcode_flavor != uint8_t(m_config->option>("gcode_flavor")->value)) { m_last_gcode_flavor = uint8_t(m_config->option>("gcode_flavor")->value); m_rebuild_kinematics_page = true; @@ -3659,103 +3628,6 @@ void TabPrinter::toggle_options() m_use_silent_mode = (m_last_gcode_flavor == gcfMarlinLegacy || m_last_gcode_flavor == gcfMarlinFirmware) && m_config->opt_bool("silent_mode"); } - wxString extruder_number; - long val; - if (m_active_page->title().StartsWith("Extruder ", &extruder_number) && extruder_number.ToLong(&val) && - val > 0 && (size_t)val <= m_extruders_count) - { - size_t i = size_t(val) - 1; - bool have_retract_length = m_config->opt_float("retract_length", i) > 0; - - // when using firmware retraction, firmware decides retraction length - bool use_firmware_retraction = m_config->opt_bool("use_firmware_retraction"); - field = get_field("retract_length", i); - if (field) - field->toggle(!use_firmware_retraction); - - // retraction only if have retraction length or we're using firmware retraction - bool retraction = (have_retract_length || use_firmware_retraction); - - // user can customize other retraction options if retraction is enabled - std::vector vec = { "retract_lift", "retract_layer_change", "retract_before_travel" }; - for (auto el : vec) { - field = get_field(el, i); - if (field) - field->toggle(retraction); - } - - bool has_lift = retraction && m_config->opt_float("retract_lift", i) > 0; - // retract lift above / below only applies if using retract lift - vec.resize(0); - vec = { "retract_lift_above", "retract_lift_below", "retract_lift_top", "retract_lift_first_layer", "retract_lift_before_travel"}; - for (auto el : vec) { - field = get_field(el, i); - if (field) - field->toggle(has_lift); - } - - // some options only apply when not using firmware retraction - vec.resize(0); - vec = { "retract_speed", "deretract_speed", "retract_before_wipe", "retract_restart_extra", "wipe", "wipe_speed" , "wipe_only_crossing"}; - for (auto el : vec) { - field = get_field(el, i); - if (field) - field->toggle(retraction && !use_firmware_retraction); - } - - bool wipe = m_config->opt_bool("wipe", i) && have_retract_length; - vec.resize(0); - vec = { "retract_before_wipe", "wipe_only_crossing", "wipe_speed" }; - for (auto el : vec) { - field = get_field(el, i); - if (field) - field->toggle(wipe); - } - - // wipe_only_crossing can only work if avoid_crossing_perimeters - if (!full_print_config.opt_bool("avoid_crossing_perimeters")) { - field = get_field("wipe_only_crossing", i); - if (field) - field->toggle(false); - } - - if (use_firmware_retraction && wipe) { - //wxMessageDialog dialog(parent(), - MessageDialog dialog(parent(), - _(L("The Wipe option is not available when using the Firmware Retraction mode.\n" - "\nShall I disable it in order to enable Firmware Retraction?")), - _(L("Firmware Retraction")), wxICON_WARNING | wxYES | wxNO); - - DynamicPrintConfig new_conf = *m_config; - if (dialog.ShowModal() == wxID_YES) { - auto wipe = static_cast(m_config->option("wipe")->clone()); - for (size_t w = 0; w < wipe->size(); w++) - wipe->get_at(w) = false; - new_conf.set_key_value("wipe", wipe); - } else { - new_conf.set_key_value("use_firmware_retraction", new ConfigOptionBool(false)); - } - load_config(new_conf); - } - - field = get_field("retract_length_toolchange", i); - if (field) - field->toggle(have_multiple_extruders); - - bool toolchange_retraction = m_config->opt_float("retract_length_toolchange", i) > 0; - field = get_field("retract_restart_extra_toolchange", i); - if (field) - field->toggle(have_multiple_extruders && toolchange_retraction); - } - if (m_has_single_extruder_MM_page) { - bool have_advanced_wipe_volume = m_config->opt_bool("wipe_advanced"); - for (auto el : { "wipe_advanced_nozzle_melted_volume", "wipe_advanced_multiplier", "wipe_advanced_algo" }) { - Field *field = get_field(el); - if (field) - field->toggle(have_advanced_wipe_volume); - } - } - if (std::find(m_active_page->descriptions.begin(), m_active_page->descriptions.end(), "machine_limits") != m_active_page->descriptions.end() && m_machine_limits_description_line) { // assert(m_config->option>("gcode_flavor")->value == gcfMarlinLegacy // || m_config->option>("gcode_flavor")->value == gcfMarlinFirmware); @@ -3811,6 +3683,8 @@ void TabPrinter::update() m_presets->get_edited_preset().printer_technology() == ptFFF ? update_fff() : update_sla(); m_update_cnt--; + m_config_manipulation.update_printer_fff_config(m_config, true); + update_description_lines(); Layout(); From d937a822e8142a3c8e88f70d1bb6d963a17709e1 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Wed, 3 Jul 2024 19:15:42 +0800 Subject: [PATCH 4/5] SeamPlacer: fix potential crashing issue When extract_perimeter_polylines() is changed to use polylines instead of polygons, the no-op condition is kept as a 0 sized array, however 1 polyline will lead to 0 polygons available too. Fix this no-op condition to prevent crashing. Fixes: 0b7ea21d4b07 ("seam: rework for polylines instead of polygons") Signed-off-by: Icenowy Zheng --- src/libslic3r/GCode/SeamPlacer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 2b86a36b561..786507a9e94 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -607,7 +607,7 @@ PolylineWithEnds extract_perimeter_polylines(const Layer *layer, const SeamPosit // if Custom Seam modifiers are present, oversamples the polyline if necessary to better fit user intentions void process_perimeter_polylines(const PolylineWithEnd &orig_polyline, float z_coord, const LayerRegion *region, const GlobalModelInfo &global_model_info, PrintObjectSeamData::LayerSeams &result) { - if (orig_polyline.size() == 0) { + if (orig_polyline.size() <= 1) { return; } PolylineWithEnd polyline = orig_polyline; From a40b7ba4d7a9a93bb4eff8cff3417c70516eb408 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 3 Jul 2024 14:11:43 +0200 Subject: [PATCH 5/5] Fix support interface: Don't confuse the first support layer with raft if there's none. supermerill/SuperSlicer/issues#778 --- src/libslic3r/SupportMaterial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 692f13ee7ad..bec29405624 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -4142,7 +4142,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( float raft_angle_1st_layer = 0.f; float raft_angle_base = 0.f; float raft_angle_interface = 0.f; - size_t raft_top_interface_idx = m_slicing_params->interface_raft_layers == 0 ? 0 : (m_slicing_params->base_raft_layers + m_slicing_params->interface_raft_layers - 1); + size_t raft_top_interface_idx = m_slicing_params->interface_raft_layers == 0 ? size_t(-1) : (m_slicing_params->base_raft_layers + m_slicing_params->interface_raft_layers - 1); if (m_slicing_params->base_raft_layers > 1) { // There are all raft layer types (1st layer, base, interface & contact layers) available. raft_angle_1st_layer = m_support_params.interface_angle;