From 92b394fe4e40e8821184f833b10f8b6fdaaef5e5 Mon Sep 17 00:00:00 2001 From: Hanif Koh Date: Thu, 27 Aug 2026 17:43:02 +0800 Subject: [PATCH] Fix CLI wipe-tower position silently reused across plates when the array is undersized --- src/OrcaSlicer.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 44ca130115..8691848c7a 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -3951,6 +3951,13 @@ int CLI::run(int argc, char **argv) ConfigOptionFloats *wipe_x_option = dynamic_cast(print_config.option("wipe_tower_x")); ConfigOptionFloats *wipe_y_option = dynamic_cast(print_config.option("wipe_tower_y")); + // get_at() clamps an out-of-range index to entry 0 instead of erroring, which + // would silently reuse another plate's wipe tower position here. Warn so a mismatched + // wipe_tower_x/y array (e.g. from a project saved before this plate was added) is visible. + if (static_cast(plate_index) >= wipe_x_option->values.size() || static_cast(plate_index) >= wipe_y_option->values.size()) { + BOOST_LOG_TRIVIAL(warning) << boost::format("plate %1%: wipe_tower_x/y only has %2%/%3% entries, reusing entry 0's position") + %(plate_index+1) %wipe_x_option->values.size() %wipe_y_option->values.size(); + } plate_obj_size_info.wipe_x = wipe_x_option->get_at(plate_index); plate_obj_size_info.wipe_y = wipe_y_option->get_at(plate_index); @@ -5541,6 +5548,26 @@ int CLI::run(int argc, char **argv) } finished_arrange = true; } + // CLI has no m_plater, so PartPlateList::create_plate() never backfills + // wipe_tower_x/y for plates created here during arrange overflow (unlike GUI's + // set_default_wipe_tower_pos_for_plate()). Keep both arrays sized to the actual + // plate count so a later per-plate get_at() never silently reuses another plate's + // wipe tower position via ConfigOptionVector's out-of-range clamp. + { + int final_plate_count = partplate_list.get_plate_count(); + ConfigOptionFloats* wipe_x_opt = m_print_config.option("wipe_tower_x"); + ConfigOptionFloats* wipe_y_opt = m_print_config.option("wipe_tower_y"); + if (wipe_x_opt && !wipe_x_opt->values.empty() && wipe_x_opt->values.size() < static_cast(final_plate_count)) { + BOOST_LOG_TRIVIAL(info) << boost::format("wipe_tower_x had %1% entries for %2% plates, backfilling with entry 0") + % wipe_x_opt->values.size() % final_plate_count; + wipe_x_opt->values.resize(final_plate_count, wipe_x_opt->values.front()); + } + if (wipe_y_opt && !wipe_y_opt->values.empty() && wipe_y_opt->values.size() < static_cast(final_plate_count)) { + BOOST_LOG_TRIVIAL(info) << boost::format("wipe_tower_y had %1% entries for %2% plates, backfilling with entry 0") + % wipe_y_opt->values.size() % final_plate_count; + wipe_y_opt->values.resize(final_plate_count, wipe_y_opt->values.front()); + } + } original_model.clear_objects(); original_model.clear_materials(); }