Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Bumped `compas-pb` to 1.2.0 (within the existing `>=1,<2` constraint), matching the version the bundled frontend's `compas-pb-ts` was upgraded to.
- Fixed `Workspace.remove_object()` never clearing an object's `Inbox`-side registrations (`geometry_registry`, `metadata_registry`, `object_actions_registry`, the guid-keyed `buttons` callback map, and a removed `Brep`'s `brep_viewmesh_registry` entry) - only the `Outbox`'s persisted material/visibility slots were forgotten, so any workflow that repeatedly removes and re-adds objects under the same guid (e.g. a viewer that rebuilds part of its own scene, or an object action whose geometry gets refreshed to pick up a new default value) leaked a growing set of stale entries, unbounded, for the life of the process.

### Removed

Expand Down
19 changes: 19 additions & 0 deletions src/compas_threejs/viewer/inbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,25 @@ def register_geometry(self, obj_id, geometry, metadata=None, actions=None):
def register_button(self, guid, action):
self.buttons[guid] = action

def forget_geometry(self, obj_id: str) -> None:
"""
Drops every registry entry register_geometry created for `obj_id` - called by
Workspace.remove_object, whose own cleanup only forgets the *outbox*'s persisted
material/visibility state (see there) and never touched these inbox-side registries.
Without this, a removed object's geometry/metadata/action-callback registrations stay
forever, and re-adding the same guid later (a Brep re-registered after
to_viewmesh()) would otherwise still work, but at the cost of a permanently growing
`buttons`/`object_actions_registry` for any workflow that repeatedly removes and
re-adds objects (e.g. a live-editable object action, or a viewer that clears and
rebuilds part of its own scene).
"""
self.geometry_registry.pop(obj_id, None)
self.metadata_registry.pop(obj_id, None)
actions = self.object_actions_registry.pop(obj_id, None)
if actions:
for action in actions:
self.buttons.pop(str(action.guid), None)

def register_action(self, name, callable_function):
"""Manually registers a callable against a fixed action name.

Expand Down
9 changes: 8 additions & 1 deletion src/compas_threejs/viewer/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,10 @@ def update_geometry(self, geometry):
def remove_object(self, geometry):
"""Removes a geometry object from this workspace."""
# If the geometry is a Brep, remove its viewmesh from the registry
brep_id = None
if isinstance(geometry, Brep):
viewmesh = self.app.inbox.brep_viewmesh_registry.get((self.workspace_id, geometry.guid))
brep_id = geometry.guid
viewmesh = self.app.inbox.brep_viewmesh_registry.get((self.workspace_id, brep_id))
if viewmesh:
geometry = viewmesh

Expand All @@ -372,6 +374,11 @@ def remove_object(self, geometry):
# for whichever it never had.
self.app.outbox.forget(("material", obj_id), workspace_id=self.workspace_id)
self.app.outbox.forget(("visibility", obj_id), workspace_id=self.workspace_id)
# Drops the inbox-side registrations too (geometry/metadata/action-callbacks) - see
# Inbox.forget_geometry for why that matters on its own, not just as an outbox mirror.
self.app.inbox.forget_geometry(str(obj_id))
if brep_id is not None:
self.app.inbox.brep_viewmesh_registry.pop((self.workspace_id, brep_id), None)

def hide_geometry(self, geometry):
"""Hides a geometry object in this workspace without removing it.
Expand Down