diff --git a/pylabrobot/visualizer3D/server.py b/pylabrobot/visualizer3D/server.py index f4a23eca6c2..b4e5a5442be 100644 --- a/pylabrobot/visualizer3D/server.py +++ b/pylabrobot/visualizer3D/server.py @@ -368,9 +368,13 @@ def _live_loop(self) -> Optional[asyncio.AbstractEventLoop]: # -- state channel ----------------------------------------------------------- def _placed_as_kept(self, name: str, location: Dict[str, Any]) -> bool: - """Whether `location` is where the kept scene already places `name`: published, but no move.""" + """Whether `location` is where the kept scene already places `name`: published, but no move. + + A resource moved since the scene was built is placed elsewhere by the clients, so its return + to the kept place is a move too. + """ index = self._index_of.get(name) - if self._scene is None or index is None: + if self._scene is None or index is None or name in self._moved: return False return _xyz(location) == self._scene.transforms[6 * index : 6 * index + 3] diff --git a/pylabrobot/visualizer3D/server_tests.py b/pylabrobot/visualizer3D/server_tests.py index 4b5e25bbad2..591ec20e278 100644 --- a/pylabrobot/visualizer3D/server_tests.py +++ b/pylabrobot/visualizer3D/server_tests.py @@ -264,6 +264,21 @@ async def test_a_moved_resource_publishes_its_new_position(self): finally: await ws.close() + async def test_a_resource_moved_back_to_where_the_scene_placed_it_publishes_that(self): + """A return to the scene's place is news to a client that was told of the move away.""" + ws, _, _ = await self.connect() + try: + kept = self.plate.location + assert kept is not None + self.plate.location = Coordinate(400, 300, 0) + self.assertEqual((await self.next_state(ws))["locations"]["plate"]["x"], 400) + self.plate.location = kept + update = await self.next_state(ws) + self.assertIsNotNone(update) + self.assertEqual(update["locations"]["plate"]["x"], kept.x) + finally: + await ws.close() + async def test_a_resource_moved_under_another_parent_is_moved_not_rebuilt(self): """The same names are the same instances: a change of parent is a move, a parent index and six floats, applied to the scene the client has. Its new location travels in the move and in no