Register Instance Copies and Moves with Their Plate

An instance added with "+" was never registered with the plate it landed on,
and moving an instance only re-registered instance 0 of its object, so a copy
dragged onto another plate stayed unknown to that plate's registry. The
plate's filament list, its wipe tower preview and the position clamp all read
that registry, so a multi-filament copy moved onto a single-filament plate
drew no tower there and its tower position was never clamped.

Register new copies at creation, notify exactly the instances a move changed
(every instance of the object when one of its parts moved), and drop the
registry entry when a copy is removed again.
This commit is contained in:
Hanif Koh
2026-09-10 12:39:55 +08:00
parent e296d5daac
commit a5d0d33df3
2 changed files with 22 additions and 2 deletions

View File

@@ -5059,7 +5059,21 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
}
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, 0);
// Only what moved: the selected instances, or every instance of an object one of whose
// parts moved. Notifying a plate about an instance that stayed put invalidates its slice
// result, and notifying instance 0 alone left a moved copy unregistered on its new plate.
{
std::set<std::pair<int, int>> notified;
for (unsigned int i : m_selection.get_volume_idxs()) {
const GLVolume* v = m_volumes.volumes[i];
const int object_idx = v->object_idx();
if (object_idx < 0 || object_idx >= static_cast<int>(m_model->objects.size()))
continue;
const std::pair<int, int> key(object_idx, selection_mode == Selection::Volume ? -1 : v->instance_idx());
if (notified.insert(key).second)
m_selection.notify_instance_update(key.first, key.second);
}
}
// Fixes sinking/flying instances (snaps object to buildplate)
for (const std::pair<int, int>& i : done) {

View File

@@ -17653,6 +17653,10 @@ void Plater::increase_instances(size_t num)
model_object->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation(), model_instance->get_mirror());
// p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
}
// Register the copies with the plate they land on before the scene reloads: the plate's
// filament list and wipe tower preview are read from that registry.
for (size_t i = model_object->instances.size() - num; i < model_object->instances.size(); ++i)
p->partplate_list.notify_instance_update(obj_idx, static_cast<int>(i));
#ifdef SUPPORT_AUTO_CENTER
if (p->get_config("autocenter") == "true")
@@ -17683,8 +17687,10 @@ void Plater::decrease_instances(size_t num)
ModelObject* model_object = p->model.objects[obj_idx];
if (model_object->instances.size() > num) {
for (size_t i = 0; i < num; ++ i)
for (size_t i = 0; i < num; ++ i) {
p->partplate_list.notify_instance_removed(obj_idx, static_cast<int>(model_object->instances.size()) - 1);
model_object->delete_last_instance();
}
p->update();
// Delete object from Sidebar list. Do it after update, so that the GLScene selection is updated with the modified model.
sidebar().obj_list()->decrease_object_instances(obj_idx, num);