From c06a02f22168d07ab48153f3dac77e93000a64c5 Mon Sep 17 00:00:00 2001 From: Brent Yi Date: Wed, 11 Oct 2023 07:25:29 +0800 Subject: [PATCH 1/3] SceneNodeHandle cleanup --- pyproject.toml | 2 +- src/viser/_scene_handles.py | 66 +++++++++++++------------------------ 2 files changed, 24 insertions(+), 44 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 59b97af80..4e115d20a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "viser" -version = "0.1.5" +version = "0.1.6" description = "3D visualization + Python" readme = "README.md" license = { text="MIT" } diff --git a/src/viser/_scene_handles.py b/src/viser/_scene_handles.py index 43bc2b886..71d07b39b 100644 --- a/src/viser/_scene_handles.py +++ b/src/viser/_scene_handles.py @@ -29,7 +29,6 @@ TSceneNodeHandle = TypeVar("TSceneNodeHandle", bound="SceneNodeHandle") -TSupportsVisibility = TypeVar("TSupportsVisibility", bound="_SupportsVisibility") @dataclasses.dataclass @@ -60,12 +59,14 @@ def _make( name: str, wxyz: Tuple[float, float, float, float] | onp.ndarray, position: Tuple[float, float, float] | onp.ndarray, + visible: bool, ) -> TSceneNodeHandle: out = cls(_SceneNodeHandleState(name, api)) api._handle_from_node_name[name] = out out.wxyz = wxyz out.position = position + out.visible = visible return out @property @@ -102,6 +103,18 @@ def position(self, position: Tuple[float, float, float] | onp.ndarray) -> None: _messages.SetPositionMessage(self._impl.name, position_cast) ) + @property + def visible(self) -> bool: + """Whether the scene node is visible or not. Synchronized to clients automatically when assigned.""" + return self._impl.visible + + @visible.setter + def visible(self, visible: bool) -> None: + self._impl.api._queue( + _messages.SetSceneNodeVisibilityMessage(self._impl.name, visible) + ) + self._impl.visible = visible + def remove(self) -> None: """Remove the node from the scene.""" self._impl.api._queue(_messages.RemoveSceneNodeMessage(self._impl.name)) @@ -114,7 +127,7 @@ class ClickEvent(Generic[TSceneNodeHandle]): @dataclasses.dataclass -class _SupportsClick(SceneNodeHandle): +class _ClickableSceneNodeHandle(SceneNodeHandle): def on_click( self: TSceneNodeHandle, func: Callable[[ClickEvent[TSceneNodeHandle]], None] ) -> Callable[[ClickEvent[TSceneNodeHandle]], None]: @@ -134,71 +147,38 @@ def on_click( @dataclasses.dataclass -class _SupportsVisibility(SceneNodeHandle): - @classmethod - def _make( - cls: Type[TSupportsVisibility], - api: MessageApi, - name: str, - wxyz: Tuple[float, float, float, float] | onp.ndarray, - position: Tuple[float, float, float] | onp.ndarray, - visible: bool = True, - ) -> TSupportsVisibility: - out = cls(_SceneNodeHandleState(name, api)) - api._handle_from_node_name[name] = out - - out.wxyz = wxyz - out.position = position - out.visible = visible - - return out - - @property - def visible(self) -> bool: - """Whether the scene node is visible or not. Synchronized to clients automatically when assigned.""" - return self._impl.visible - - @visible.setter - def visible(self, visible: bool) -> None: - self._impl.api._queue( - _messages.SetSceneNodeVisibilityMessage(self._impl.name, visible) - ) - self._impl.visible = visible - - -@dataclasses.dataclass -class CameraFrustumHandle(_SupportsClick, _SupportsVisibility): +class CameraFrustumHandle(_ClickableSceneNodeHandle): """Handle for camera frustums.""" @dataclasses.dataclass -class PointCloudHandle(_SupportsVisibility): +class PointCloudHandle(SceneNodeHandle): """Handle for point clouds. Does not support click events.""" @dataclasses.dataclass -class FrameHandle(_SupportsClick, _SupportsVisibility): +class FrameHandle(_ClickableSceneNodeHandle): """Handle for coordinate frames.""" @dataclasses.dataclass -class MeshHandle(_SupportsClick, _SupportsVisibility): +class MeshHandle(_ClickableSceneNodeHandle): """Handle for mesh objects.""" @dataclasses.dataclass -class GlbHandle(_SupportsClick, _SupportsVisibility): +class GlbHandle(_ClickableSceneNodeHandle): """Handle for GLB objects.""" @dataclasses.dataclass -class ImageHandle(_SupportsClick, _SupportsVisibility): +class ImageHandle(_ClickableSceneNodeHandle): """Handle for 2D images, rendered in 3D.""" @dataclasses.dataclass class LabelHandle(SceneNodeHandle): - """Handle for 2D label objects. Does not support click events or visibility toggling.""" + """Handle for 2D label objects. Does not support click events.""" @dataclasses.dataclass @@ -209,7 +189,7 @@ class _TransformControlsState: @dataclasses.dataclass -class TransformControlsHandle(_SupportsClick, _SupportsVisibility): +class TransformControlsHandle(_ClickableSceneNodeHandle): """Handle for interacting with transform control gizmos.""" _impl_aux: _TransformControlsState From 203f912fa915f6bd0fb50c52d40453b9152410bc Mon Sep 17 00:00:00 2001 From: Brent Yi Date: Wed, 11 Oct 2023 07:27:36 +0800 Subject: [PATCH 2/3] Make `visible=` argument consistent --- src/viser/_message_api.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/viser/_message_api.py b/src/viser/_message_api.py index 1dcc9d4dc..53d12b005 100644 --- a/src/viser/_message_api.py +++ b/src/viser/_message_api.py @@ -37,7 +37,6 @@ PointCloudHandle, SceneNodeHandle, TransformControlsHandle, - _SupportsVisibility, _TransformControlsState, ) @@ -353,10 +352,11 @@ def add_label( text: str, wxyz: Tuple[float, float, float, float] | onp.ndarray = (1.0, 0.0, 0.0, 0.0), position: Tuple[float, float, float] | onp.ndarray = (0.0, 0.0, 0.0), + visible: bool = True, ) -> LabelHandle: """Add a 2D label to the scene.""" self._queue(_messages.LabelMessage(name, text)) - return LabelHandle._make(self, name, wxyz, position) + return LabelHandle._make(self, name, wxyz, position, visible=visible) def add_point_cloud( self, @@ -633,6 +633,7 @@ def add_3d_gui_container( name: str, wxyz: Tuple[float, float, float, float] | onp.ndarray = (1.0, 0.0, 0.0, 0.0), position: Tuple[float, float, float] | onp.ndarray = (0.0, 0.0, 0.0), + visible: bool = True, ) -> Gui3dContainerHandle: """Add a 3D gui container to the scene. The returned container handle can be used as a context to place GUI elements into the 3D scene.""" @@ -658,5 +659,5 @@ def add_3d_gui_container( container_id=container_id, ) ) - node_handle = SceneNodeHandle._make(self, name, wxyz, position) + node_handle = SceneNodeHandle._make(self, name, wxyz, position, visible=visible) return Gui3dContainerHandle(node_handle._impl, gui_api, container_id) From 029a8acc15b95f54f7009a60e0da8dfb8b0d80b0 Mon Sep 17 00:00:00 2001 From: Brent Yi Date: Wed, 11 Oct 2023 07:58:30 +0800 Subject: [PATCH 3/3] Fix transform controls --- src/viser/_message_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/viser/_message_api.py b/src/viser/_message_api.py index 53d12b005..43324084e 100644 --- a/src/viser/_message_api.py +++ b/src/viser/_message_api.py @@ -562,7 +562,7 @@ def sync_cb(client_id: ClientId, state: TransformControlsHandle) -> None: message_position.excluded_self_client = client_id self._queue(message_position) - node_handle = _SupportsVisibility._make(self, name, wxyz, position, visible) + node_handle = SceneNodeHandle._make(self, name, wxyz, position, visible) state_aux = _TransformControlsState( last_updated=time.time(), update_cb=[],