From 988718a091c06f592c200d8dd747e80bd84ccd42 Mon Sep 17 00:00:00 2001 From: sentientstardust Date: Sun, 3 May 2026 14:39:29 +0100 Subject: [PATCH] Prime tower preview fixes --- src/libslic3r/GCode/ToolOrdering.hpp | 9 +++- src/slic3r/GUI/3DScene.cpp | 8 +-- src/slic3r/GUI/GLCanvas3D.cpp | 28 +++++++++-- src/slic3r/GUI/PartPlate.cpp | 73 +++++++++++++++++++++++++++- src/slic3r/GUI/PartPlate.hpp | 1 + 5 files changed, 109 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index c62db49ce0b..534cbc8ab2c 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -239,7 +239,14 @@ public: bool empty() const { return m_layer_tools.empty(); } const std::vector& layer_tools() const { return m_layer_tools; } std::vector& layer_tools() { return m_layer_tools; } - bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().has_wipe_tower; } + bool has_wipe_tower() const { + if (m_layer_tools.empty() || m_first_printing_extruder == (unsigned int)-1) + return false; + for (const LayerTools &layer_tools : m_layer_tools) + if (layer_tools.has_wipe_tower) + return true; + return false; + } int get_most_used_extruder() const { return most_used_extruder; } /* diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index a585543965d..bb07c991728 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1569,14 +1569,16 @@ int GLVolumeCollection::load_wipe_tower_preview( std::vector extruder_colors = GUI::wxGetApp().plater()->get_extruders_colors(); std::vector colors; GUI::PartPlateList& ppl = GUI::wxGetApp().plater()->get_partplate_list(); - std::vector plate_extruders = ppl.get_plate(plate_idx)->get_wipe_tower_extruders(true); + std::vector plate_extruders = ppl.get_plate(plate_idx)->get_extruders(true); TriangleMesh wipe_tower_shell = make_cube(width, depth, height); for (int extruder_id : plate_extruders) { - if (extruder_id <= extruder_colors.size()) + if (extruder_id > 0 && extruder_id <= extruder_colors.size()) colors.push_back(extruder_colors[extruder_id - 1]); - else + else if (!extruder_colors.empty()) colors.push_back(extruder_colors[0]); } + if (colors.empty()) + colors.emplace_back(ColorRGBA::WHITE()); // Orca: make it transparent for(auto& color : colors) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 63acd8a2278..c850591f378 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -123,7 +123,6 @@ float RetinaHelper::get_scale_factor() { return float(m_window->GetContentScaleF #undef Convex #endif - std::string& get_object_limited_text() { static std::string object_limited_text = _u8L("An object is placed in the left/right nozzle-only area or exceeds the printable height of the left nozzle.\n" "Please ensure the filaments used by this object are not arranged to other nozzles."); @@ -2841,10 +2840,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re const Print* print = m_process->fff_print(); const Print* current_print = part_plate->fff_print(); - const std::vector wipe_tower_extruders = part_plate->get_wipe_tower_extruders(true); + const size_t texture_mapping_filaments_count = + part_plate->estimate_wipe_tower_filaments_count(&wxGetApp().preset_bundle->project_config); const size_t wipe_tower_filaments_count = need_wipe_tower ? - std::max(1, wipe_tower_extruders.size()) : - wipe_tower_extruders.size(); + std::max(1, texture_mapping_filaments_count) : + texture_mapping_filaments_count; if (!need_wipe_tower && wipe_tower_filaments_count < 2) continue; if (part_plate->get_objects_on_this_plate().empty()) continue; @@ -2874,8 +2874,28 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re coordf_t plate_bbox_x_min_local_coord = plate_bbox_2d.min(0) - plate_origin(0); coordf_t plate_bbox_x_max_local_coord = plate_bbox_2d.max(0) - plate_origin(0); + coordf_t plate_bbox_y_min_local_coord = plate_bbox_2d.min(1) - plate_origin(1); coordf_t plate_bbox_y_max_local_coord = plate_bbox_2d.max(1) - plate_origin(1); + const float old_x = x; + const float old_y = y; + auto clamp_wipe_tower_axis = [](float value, coordf_t min_value, coordf_t max_value, double size, float margin) { + const float axis_min = float(min_value) + margin; + const float axis_max = float(max_value) - margin - float(size); + return axis_max < axis_min ? axis_min : std::min(std::max(value, axis_min), axis_max); + }; + x = clamp_wipe_tower_axis(x, plate_bbox_x_min_local_coord, plate_bbox_x_max_local_coord, wipe_tower_size(0), margin); + y = clamp_wipe_tower_axis(y, plate_bbox_y_min_local_coord, plate_bbox_y_max_local_coord, wipe_tower_size(1), margin); + + if (std::abs(x - old_x) > EPSILON) { + ConfigOptionFloat x_opt(x); + dynamic_cast(proj_cfg.option("wipe_tower_x"))->set_at(&x_opt, plate_id, 0); + } + if (std::abs(y - old_y) > EPSILON) { + ConfigOptionFloat y_opt(y); + dynamic_cast(proj_cfg.option("wipe_tower_y"))->set_at(&y_opt, plate_id, 0); + } + if (!current_print->is_step_done(psWipeTower) || !current_print->wipe_tower_data().wipe_tower_mesh_data) { // update for wipe tower position { diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 31c62dbd591..bf02f175f63 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -170,6 +170,71 @@ std::vector expand_wipe_tower_extruders(const std::vector &extruders, return expanded; } +size_t estimate_wipe_tower_filaments_count_for_texture_mapping(const std::vector &extruders, const DynamicPrintConfig *config) +{ + if (extruders.empty()) + return 0; + + const std::vector filament_colours = wipe_tower_filament_colours(config); + const size_t num_physical = filament_colours.size(); + if (num_physical == 0) + return 0; + + TextureMappingManager texture_mgr; + const std::string texture_mapping_definitions = config != nullptr && config->has("texture_mapping_definitions") ? + config->opt_string("texture_mapping_definitions") : + (wxGetApp().preset_bundle != nullptr && wxGetApp().preset_bundle->project_config.has("texture_mapping_definitions") ? + wxGetApp().preset_bundle->project_config.opt_string("texture_mapping_definitions") : + std::string()); + texture_mgr.load_entries(texture_mapping_definitions, filament_colours); + + std::vector physical_ids; + size_t texture_slots = 0; + bool texture_changes_physical_component = false; + + for (const int extruder : extruders) { + if (extruder <= 0) + continue; + + const unsigned int filament_id = static_cast(extruder); + if (filament_id <= num_physical) { + physical_ids.emplace_back(filament_id); + continue; + } + + const TextureMappingZone *zone = texture_mgr.zone_from_id(filament_id); + if (zone == nullptr || !zone->enabled || zone->deleted) + continue; + + std::vector component_ids = zone->is_image_texture() ? + TextureMappingManager::effective_texture_component_ids(*zone, num_physical, filament_colours) : + TextureMappingManager::selected_component_ids(*zone, num_physical); + component_ids.erase(std::remove_if(component_ids.begin(), + component_ids.end(), + [num_physical](unsigned int id) { return id == 0 || id > num_physical; }), + component_ids.end()); + std::sort(component_ids.begin(), component_ids.end()); + component_ids.erase(std::unique(component_ids.begin(), component_ids.end()), component_ids.end()); + if (component_ids.empty()) + continue; + + if (component_ids.size() == 1) { + physical_ids.emplace_back(component_ids.front()); + } else { + ++texture_slots; + texture_changes_physical_component = true; + } + } + + std::sort(physical_ids.begin(), physical_ids.end()); + physical_ids.erase(std::unique(physical_ids.begin(), physical_ids.end()), physical_ids.end()); + + size_t count = physical_ids.size() + texture_slots; + if (count < 2 && texture_changes_physical_component) + count = 2; + return count; +} + ColorRGBA PartPlate::SELECT_COLOR = { 0.2666f, 0.2784f, 0.2784f, 1.0f }; //{ 0.4196f, 0.4235f, 0.4235f, 1.0f }; ColorRGBA PartPlate::UNSELECT_COLOR = { 0.82f, 0.82f, 0.82f, 1.0f }; ColorRGBA PartPlate::UNSELECT_DARK_COLOR = { 0.384f, 0.384f, 0.412f, 1.0f }; @@ -1730,6 +1795,11 @@ std::vector PartPlate::get_wipe_tower_extruders(bool conside_custom_gcode) return expand_wipe_tower_extruders(get_extruders(conside_custom_gcode), config); } +size_t PartPlate::estimate_wipe_tower_filaments_count(const DynamicPrintConfig *config) const +{ + return estimate_wipe_tower_filaments_count_for_texture_mapping(get_extruders(true), config); +} + std::vector PartPlate::get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const { std::vector plate_extruders; @@ -2239,8 +2309,7 @@ Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, con // empty plate if (plate_extruder_size == 0) { - std::vector plate_extruders = get_wipe_tower_extruders(true); - plate_extruder_size = plate_extruders.size(); + plate_extruder_size = int(estimate_wipe_tower_filaments_count(&config)); } if (plate_extruder_size == 0) return wipe_tower_size; diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 611060d893f..8c553aa47fb 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -329,6 +329,7 @@ public: Vec3d get_origin() { return m_origin; } //Vec3d calculate_wipe_tower_size(const DynamicPrintConfig &config, const double w, const double wipe_volume, int plate_extruder_size = 0, bool use_global_objects = false) const; + size_t estimate_wipe_tower_filaments_count(const DynamicPrintConfig *config = nullptr) const; Vec3d estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double wipe_volume, int extruder_count = 1, int plate_extruder_size = 0, bool use_global_objects = false, bool enable_wrapping_detection = false) const; arrangement::ArrangePolygon estimate_wipe_tower_polygon(const DynamicPrintConfig & config, int plate_index, Vec3d& wt_pos, Vec3d& wt_size, int extruder_count = 1, int plate_extruder_size = 0, bool use_global_objects = false) const; bool check_objects_empty_and_gcode3mf(std::vector &result) const;