diff --git a/CHANGELOG.md b/CHANGELOG.md index cc20d868a8..f216fa4104 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Added +* Added `installation` documentation. +* Added documentations: index, api, etc. Mockups style is improved. * Added `DeleteSelected` action class. * Added `DataType` as the data type template for generating the buffer. * Added `NetworkObject` for the scene objects. @@ -45,6 +47,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added `NetworkObject`. ### Changed +* The `Index` page. +* Typing hints improved, now `compas_viewer` only support Python 3.9+. * Introduce decorator @lru_cache() to reduce duplicate calculations. * Refactored the `Selector` and the instance_map structure, the main frame rate is higher and selection action is faster. * Fixed the bug of the `Selector`, drag selection is now more accurate. diff --git a/data/default_config/render.json b/data/default_config/renderer.json similarity index 100% rename from data/default_config/render.json rename to data/default_config/renderer.json diff --git a/docs/_images/PLACEHOLDER b/docs/_images/PLACEHOLDER deleted file mode 100644 index 48f73ebfcf..0000000000 --- a/docs/_images/PLACEHOLDER +++ /dev/null @@ -1 +0,0 @@ -# container for images to be included in the docs diff --git a/docs/_images/PLACEHOLDER.png b/docs/_images/PLACEHOLDER.png new file mode 100644 index 0000000000..c7ace8e1b4 Binary files /dev/null and b/docs/_images/PLACEHOLDER.png differ diff --git a/docs/api.rst b/docs/api.rst deleted file mode 100644 index db4b9a233a..0000000000 --- a/docs/api.rst +++ /dev/null @@ -1,15 +0,0 @@ -******************************************************************************** -API Reference -******************************************************************************** - -.. toctree:: - :maxdepth: 1 - - api/compas_viewer.viewer - api/compas_viewer.layout - api/compas_viewer.components - api/compas_viewer.scene - api/compas_viewer.configurations - api/compas_viewer.controller - api/compas_viewer.actions - api/compas_viewer.utilities diff --git a/docs/api/compas_viewer.components.rst b/docs/api/compas_viewer.components.rst index 460201ab39..d11e0cffa9 100644 --- a/docs/api/compas_viewer.components.rst +++ b/docs/api/compas_viewer.components.rst @@ -5,5 +5,5 @@ compas_viewer.components .. toctree:: :maxdepth: 1 - components/render + components/renderer diff --git a/docs/api/components/render.rst b/docs/api/components/renderer.rst similarity index 50% rename from docs/api/components/render.rst rename to docs/api/components/renderer.rst index 3915052c9b..04f4af5b2c 100644 --- a/docs/api/components/render.rst +++ b/docs/api/components/renderer.rst @@ -1,8 +1,8 @@ ******************************************************************************* -compas_viewer.components.render +compas_viewer.components.renderer ******************************************************************************* -.. currentmodule:: compas_viewer.components.render +.. currentmodule:: compas_viewer.components.renderer Classes ======= @@ -11,14 +11,14 @@ Classes :toctree: ./generated :nosignatures: - Render + Renderer Camera Shader Selector - Render.mouseMoveEvent - Render.mousePressEvent - Render.mouseReleaseEvent - Render.wheelEvent - Render.keyPressEvent - Render.keyReleaseEvent + Renderer.mouseMoveEvent + Renderer.mousePressEvent + Renderer.mouseReleaseEvent + Renderer.wheelEvent + Renderer.keyPressEvent + Renderer.keyReleaseEvent diff --git a/docs/api/index.rst b/docs/api/index.rst new file mode 100644 index 0000000000..490829091e --- /dev/null +++ b/docs/api/index.rst @@ -0,0 +1,67 @@ + +******************************************************************************** +API Reference +******************************************************************************** + +This package provides a viewer for COMPAS. + +Viewer +------ + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + compas_viewer.viewer + + +Scene and Objects +----------------- + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + compas_viewer.scene + + +Controller and Actions +---------------------- + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + compas_viewer.controller + compas_viewer.actions + + +Components and Configurations +----------------------------- + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + compas_viewer.components + compas_viewer.configurations + + +Layout and UI +-------------------- +.. toctree:: + :maxdepth: 1 + :titlesonly: + + compas_viewer.layout + + +Utilities +--------- +.. toctree:: + :maxdepth: 1 + :titlesonly: + + compas_viewer.utilities + + diff --git a/docs/conf.py b/docs/conf.py index f38073e75b..7c0192243d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,7 +2,6 @@ # -*- coding: utf-8 -*- import sphinx_compas2_theme - from sphinx.writers import html from sphinx.writers import html5 @@ -77,10 +76,9 @@ def setup(app): plot_formats = ["png"] # intersphinx options - intersphinx_mapping = { "python": ("https://docs.python.org/", None), - "compas": ("https://compas.dev/compas/latest/", None) + "compas": ("https://compas.dev/compas/latest/", None), } # linkcode @@ -89,7 +87,12 @@ def setup(app): # extlinks -extlinks = {} +extlinks = { + "GL": ("https://pyopengl.sourceforge.net/documentation/manual-3.0/%s.html", "%s"), + "QtCore": ("https://doc.qt.io/qtforpython-6/PySide6/QtCore/Qt.html#PySide6.QtCore.%s", "%s"), + "PySide6": ("https://doc.qt.io/qtforpython-6/%s.html", "%s"), + "compas": ("https://compas.dev/compas//latest/api/%s.html", "%s"), +} # from pytorch @@ -97,8 +100,8 @@ def setup(app): sphinx_compas2_theme.replace(html5.HTML5Translator) # -- Options for HTML output ---------------------------------------------- - -html_theme = "sidebaronly" +html_sidebars = {"index": []} +html_theme = "multisection" html_title = project favicons = [ @@ -109,6 +112,9 @@ def setup(app): ] html_theme_options = { + "external_links": [ + {"name": "COMPAS Framework", "url": "https://compas.dev"}, + ], "icon_links": [ { "name": "GitHub", @@ -138,6 +144,7 @@ def setup(app): "image_dark": "_static/compas_icon_white.png", # relative to parent of conf.py "text": project, }, + "navigation_depth": 2, } html_context = { diff --git a/docs/examples/PLACEHOLDER b/docs/examples/PLACEHOLDER deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/examples.rst b/docs/examples/index.rst similarity index 71% rename from docs/examples.rst rename to docs/examples/index.rst index f65d96ae8d..3a84825364 100644 --- a/docs/examples.rst +++ b/docs/examples/index.rst @@ -1,10 +1,11 @@ + ******************************************************************************** Examples ******************************************************************************** .. toctree:: - :maxdepth: 2 - :titlesonly: - :glob: + :maxdepth: 1 + :titlesonly: + :caption: Basic Examples - examples/basics + basics diff --git a/docs/index.rst b/docs/index.rst index d374a09799..bd6f6c29a9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,33 +1,70 @@ +:html_theme.sidebar_secondary.remove: true + ******************************************************************************** -compas_viewer +COMPAS Viewer ******************************************************************************** - .. rst-class:: lead -Standalone viewer for COMPAS +Standalone viewer for COMPAS 2.0 with features: + -.. .. figure:: /_images/ +* **Fully COMPAS Support**: Full support for all :compas:`compas.geometry` (primitives, shapes, network, mesh, assembly, model, etc.) based on :compas:`compas.scene` structure ... +* **Universal Architecture**: Full support Mac, Windows, and Linux with Python 3.9+. More various platforms are coming soon ... +* **Installation Friendly**: Depend only on COMPAS, OpenGL and PySide6. Installation with pip is fast and easy ... +* **Flexible Customization**: Flexible customize your own UI layout with buttons, render display with colors, action with keyboard preferences ... +* **Data-driven Visualization**: Visualize your assembly data, mesh data, network data, and more with :compas:`compas.datastructures` ... +* **Easy-to-use Interaction**: Action-based interaction with mouse and keyboard, and easy-to-use API for your own interaction ... + +.. figure:: /_images/PLACEHOLDER.png :figclass: figure :class: figure-img img-fluid +Installation +============ + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + installation + -Table of Contents -================= +Tutorials +========= .. toctree:: - :maxdepth: 3 - :titlesonly: + :maxdepth: 2 + :titlesonly: + + tutorials/index + + +Examples +======== + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + examples/index + + +API Reference +============= + +.. toctree:: + :maxdepth: 2 + + api/index - Introduction - installation - tutorials - examples - api - license +History +======= +COMPAS Viewer is the next generation of :mod:`compas_view2` which is beased on the 1.0 version of :mod:`compas`. +Experiencing years' iteraions, this new version of COMPAS Viewer is stabliy designed for wider senarios and use cases. Indices and tables ================== * :ref:`genindex` -* :ref:`modindex` +* :ref:`search` diff --git a/docs/installation.rst b/docs/installation.rst index a2d3ef9c94..02c7c0c9cc 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -1,3 +1,33 @@ ******************************************************************************** Installation ******************************************************************************** +COMPAS Viewer can be easily installed on multiple platforms, using popular package managers such as conda or pip. + +If you don't have COMPAS installed +=================================== +Check out the COMPAS installation instructions at https://compas.dev/compas/latest/userguide/installation.html + +If you have COMPAS installed +============================ +Activate your COMPAS environment and install COMPAS Viewer from `pip`. + +.. code-block:: bash + + pip install compas_viewer + +Verify the installation +======================= +COMPAS Viewer can be simply lunched by the following command in your terminal: + +.. code-block:: bash + + python -m compas_viewer + +Update with pip +=============== +Update COMPAS Viewer to the latest version with pip. + +.. code-block:: bash + + pip install --upgrade compas_viewer + diff --git a/docs/license.rst b/docs/license.rst deleted file mode 100644 index e6a80ce019..0000000000 --- a/docs/license.rst +++ /dev/null @@ -1,5 +0,0 @@ -******************************************************************************** -License -******************************************************************************** - -.. literalinclude:: ../LICENSE diff --git a/docs/tutorials/configurations.rst b/docs/tutorials/configurations.rst new file mode 100644 index 0000000000..bf22680b3b --- /dev/null +++ b/docs/tutorials/configurations.rst @@ -0,0 +1,15 @@ +******************************************************************************** +File Structure +******************************************************************************** + +.. ::`compas_viewer` reads its customized ::`.viewer` file. The file architecture is designed for better data exchange, collaboration, and communication. + +.. Concept +.. =========== + +.. 1. **Folder-based** : ::`.viewer` file is a `.zip` folder (archive) that contains files in various formats. + +.. 2. **Extendability** : ::`.viewer` file could contain any type of files. The core functions of viewer are `.json` based and the invoking functions are dictionary-find based, meaning that only missing parameters will cause the loading failure while redundant parameters will only be ignored. + +.. Quick Look +.. ========== diff --git a/docs/tutorials/file_structure.rst b/docs/tutorials/file_structure.rst deleted file mode 100644 index e21464f49f..0000000000 --- a/docs/tutorials/file_structure.rst +++ /dev/null @@ -1,99 +0,0 @@ -******************************************************************************** -File Structure -******************************************************************************** - -::`compas_viewer` reads its customized ::`.viewer` file. The file architecture is designed for better data exchange, collaboration, and communication. - -Concept -=========== - -1. **Folder-based** : ::`.viewer` file is a `.zip` folder (archive) that contains files in various formats. - -2. **Extendability** : ::`.viewer` file could contain any type of files. The core functions of viewer are `.json` based and the invoking functions are dictionary-find based, meaning that only missing parameters will cause the loading failure while redundant parameters will only be ignored. - -Quick Look -========== - -.. figure:: _images/diagrams/generated/file_structure.svg - :figclass: figure - :class: figure-img img-fluid - - -Structure -========= - -- **FILENAME.viewer**: ::`.viewer` file is a `.zip` based folder that collect rich format of files ... - - - **viewer.json**: The viewer.json contains all the settings about the viewer application it self: with, height, fullscreen, ... - - - **about**: Basic info. | *str* | `"about": "Hello."` - - **title**: The title of the viewer. | *str* | `"title": "COMPAS Viewer"` - - **width**: The width of the viewer. | *int* | `"width": 1280` - - **height**: The height of the viewer. | *int* | `"height ": 720` - - **fullscreen**: Full screen option. | *bool* | `"fullscreen ": false` - - - **scene.json**: The scene.json contains all the settings about the scene: background color, grid, ... - - - **show_grid**: Show grid option. | *bool* | `"show_grid ": true` - - **view_mode**: View mode option. | *str* | `"view_mode ": "shaded"` - - **background_color**: Background color option. | *List* | `"background_color ": [1, 1, 1, 1]` - - **selection_color**: Selection color option. | *List* | `"selection_color ": [1.0, 1.0, 0.0]` - - - **ui.json**: The ui.json contains all the settings about the ui: sidedock, sidebar, statusbar, ... - - - **statusbar**: The statusbar key controls the statusbar behavior. | *Dict* | - - - **texts**: Controls the text in the statusbar. | *str* | `"texts": "Ready"` - - **show_fps**: Controls the fps status in the statusbar. | *bool* | `"show_fps": true` - - - **menubar**: The menubar key controls the menubar behavior. | *Dict* | - - - **enable_menubar**: If the menubar is displayed. false means no further menubar settings will not be applied. | *bool* | `"enable_menubar": true` - - **items**: An *ordered List* of items as *Dictionary* to put in the menubar ... | *List[Dict]* | - - - **text**: The name displayed on the menu item. | *type* | `"text": "View"` - - **items**: An *ordered List* of items to put inside the menu item. | *List[Dict]* | - - - **type**: The type of this group of item: "radio", "action", "separator" ... | *str* | `"type": "radio"` - - **text**: The menu item name displayed inside the menu. | *str* | `"text": "Shaded"` - - **action**: Function name to trigger when the menu item is clicked. | *str* | `"action": "view_shaded"` - - **...**: Other keys depending on the type. - - - **toolbar**: The toolbar key controls the toolbar behavior. | *Dict* | - - - **enable_toolbar**: If the toolbar is displayed. false means no further toolbar settings will not be applied. | *bool* | `"enable_toolbar": true` - - **items**: An *ordered List* of items as *Dictionary* to put in the toolbar ... | *List[Dict]* | - - - **type**: The type of this item: "action", "separator" ... | *str* | `"type": "action"` - - **text**: The toolbar item name displayed on the toolbar. | *str* | `"text": "Capture"` - - **action**: Function name to trigger when the toolbar item is clicked. | *str* | `"action": "view_capture"` - - - **sidebar**: The sidebar key controls the sidebar behavior. | *Dict* | - - - **enable_sidebar**: If the sidebar is displayed. false means no further sidebar settings will not be applied. | *bool* | `"enable_sidebar": true` - - **items**: An *ordered List* of items as *Dictionary* to put in the toolbar ... | *List[Dict]* | - - - **type**: The type of this item: "checkbox", "slider", "button" ... | *str* | `"type": "checkbox"` - - **text**: The sidebar item name displayed on the sidebar. | *str* | `"text": "Slide Point"` - - **...**: Other keys depending on the type. - - - **sidedocks**: ::`compas_viewer` provides sidedocks as the addition to the sidebar. Every single sidedock in this *list* of dideocks follow the basic configuration rule of the sidebar | *list* | - - - **controller.json**: The controller.json contains all the settings about controlling the viewer: mouse, keys, ... - - - **mouse**: The mouse-based control functions. The keys(functions) are fixed but items(bindings) are customizable. | *Dict* | - - - **pan**: The pan function. | *Dict* | `{"mouse": "r", "key": "shift"}` - - **rotate**: The rotate function. | *Dict* | `{"mouse": "r", "key": ""}` - - **box_selection**: The box_selection function. | *Dict* | `{"mouse": "l", "key": ""}` - - **drag_deselection**: The box_selection function. | *Dict* | `{"mouse": "l", "key": "control"}` - - **selection**: The box_selection function. | *Dict* | `{"mouse": "l", "key": ""}` - - **multi_selection**: The box_selection function. | *Dict* | `{"mouse": "l", "key": "shift"}` - - **deselection**: The box_selection function. | *Dict* | `{"mouse": "l", "key": "control"}` - - - **keys**: The key-based control functions. Both keys and items are customizable. Extended actions put in the actions folder | *Dict* | `{"zoom_selected": ["f"],"view_top": ["control", "f1"]}` - - - **actions**: Folder for containing the extended actions. - - **geometries.json**: The geometries.json is *dictionary* data that indicate all the geometry pointers and their relations. - - **geometry_data.json**: The geometry_data.json contains all the geometry information ( items are parsed `compas.geometry`, directory of a geometry file inside this folder, or URL directory). This is the targets of the pointers in the geometries.json - - **flow.json**: The flow function is a `ryven` based visual scripting tool. The documentation and development of flow will be developed later on ... diff --git a/docs/tutorials.rst b/docs/tutorials/index.rst similarity index 70% rename from docs/tutorials.rst rename to docs/tutorials/index.rst index 4c171c5684..ab546e2e7f 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials/index.rst @@ -1,11 +1,11 @@ + ******************************************************************************** Tutorials ******************************************************************************** -.. toctree:: - :maxdepth: 1 - :titlesonly: - - tutorials/file_structure - +.. toctree:: + :maxdepth: 1 + :titlesonly: + :caption: Tutorials + configurations diff --git a/requirements.txt b/requirements.txt index af76855b1a..fc534577f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -compas @ git+https://github.com/compas-dev/compas@main freetype-py pyopengl PySide6 diff --git a/src/compas_viewer/actions/__init__.py b/src/compas_viewer/actions/__init__.py index 7e5e2c400a..ad91b619ce 100644 --- a/src/compas_viewer/actions/__init__.py +++ b/src/compas_viewer/actions/__init__.py @@ -1,8 +1,8 @@ from collections import defaultdict -from typing import Any, Callable, Dict +from typing import Any, Callable -ITEM_ACTIONS: Dict[str, Callable] = defaultdict() +ITEM_ACTIONS: dict[str, Callable] = defaultdict() def register(name: str, action_class: Callable): diff --git a/src/compas_viewer/actions/action.py b/src/compas_viewer/actions/action.py index d5f57cd714..7c4d6182fd 100644 --- a/src/compas_viewer/actions/action.py +++ b/src/compas_viewer/actions/action.py @@ -33,9 +33,9 @@ class Action(QObject): The viewer object. config : :class:`compas_viewer.configurations.controller_config.ActionConfig` The action configuration. - key : :class:`PySide6.QtCore.Qt.Key` + key : :QtCore:`PySide6.QtCore.Qt.Key` The key of the action. - modifier : :class:`PySide6.QtCore.Qt.KeyboardModifier` + modifier : :QtCore:`PySide6.QtCore.Qt.KeyboardModifier` The modifier of the action. References @@ -65,11 +65,11 @@ def pressed_action(self): """ The behavior of the action when the key is pressed. """ - self.viewer.render.update() + self.viewer.renderer.update() @abstractmethod def released_action(self): """ The behavior of the action when the key is released. """ - self.viewer.render.update() + self.viewer.renderer.update() diff --git a/src/compas_viewer/actions/select_all.py b/src/compas_viewer/actions/select_all.py index 62496e7a63..49a7efe1e6 100644 --- a/src/compas_viewer/actions/select_all.py +++ b/src/compas_viewer/actions/select_all.py @@ -7,4 +7,4 @@ class SelectAll(Action): def pressed_action(self): for obj in self.viewer.objects: obj.is_selected = True - self.viewer.render.update() + self.viewer.renderer.update() diff --git a/src/compas_viewer/actions/viewmode.py b/src/compas_viewer/actions/viewmode.py index 5bcecf3d04..ce2d18c6d8 100644 --- a/src/compas_viewer/actions/viewmode.py +++ b/src/compas_viewer/actions/viewmode.py @@ -5,25 +5,25 @@ class ViewTop(Action): """Switch to top.""" def pressed_action(self): - self.viewer.render.viewmode = "top" + self.viewer.renderer.viewmode = "top" class ViewPerspective(Action): """Switch to perspective.""" def pressed_action(self): - self.viewer.render.viewmode = "perspective" + self.viewer.renderer.viewmode = "perspective" class ViewFront(Action): """Switch to front.""" def pressed_action(self): - self.viewer.render.viewmode = "front" + self.viewer.renderer.viewmode = "front" class ViewRight(Action): """Switch to right.""" def pressed_action(self): - self.viewer.render.viewmode = "right" + self.viewer.renderer.viewmode = "right" diff --git a/src/compas_viewer/actions/zoom_selected.py b/src/compas_viewer/actions/zoom_selected.py index be6eb7a2e5..872d5a6bf7 100644 --- a/src/compas_viewer/actions/zoom_selected.py +++ b/src/compas_viewer/actions/zoom_selected.py @@ -26,9 +26,9 @@ def pressed_action(self): center = (max_corner + min_corner) / 2 distance = max(norm(max_corner - min_corner), 1) - self.viewer.render.camera.target = center - vec = (self.viewer.render.camera.target - self.viewer.render.camera.position) / norm( - self.viewer.render.camera.target - self.viewer.render.camera.position + self.viewer.renderer.camera.target = center + vec = (self.viewer.renderer.camera.target - self.viewer.renderer.camera.position) / norm( + self.viewer.renderer.camera.target - self.viewer.renderer.camera.position ) - self.viewer.render.camera.position = self.viewer.render.camera.target - vec * distance * 1.5 - self.viewer.render.update() + self.viewer.renderer.camera.position = self.viewer.renderer.camera.target - vec * distance * 1.5 + self.viewer.renderer.update() diff --git a/src/compas_viewer/components/__init__.py b/src/compas_viewer/components/__init__.py index f3c377aa5c..136372f48e 100644 --- a/src/compas_viewer/components/__init__.py +++ b/src/compas_viewer/components/__init__.py @@ -1 +1 @@ -from .render import Render # noqa: F401 +from .renderer import Renderer # noqa: F401 diff --git a/src/compas_viewer/components/render/__init__.py b/src/compas_viewer/components/renderer/__init__.py similarity index 75% rename from src/compas_viewer/components/render/__init__.py rename to src/compas_viewer/components/renderer/__init__.py index 0bce97d457..f3309443e7 100644 --- a/src/compas_viewer/components/render/__init__.py +++ b/src/compas_viewer/components/renderer/__init__.py @@ -1,4 +1,4 @@ -from .render import Render # noqa: F401 +from .renderer import Renderer # noqa: F401 from .camera import Camera # noqa: F401 from .shaders.shader import Shader # noqa: F401 from .selector import Selector # noqa: F401 diff --git a/src/compas_viewer/components/render/camera.py b/src/compas_viewer/components/renderer/camera.py similarity index 91% rename from src/compas_viewer/components/render/camera.py rename to src/compas_viewer/components/renderer/camera.py index cce5752d16..18c0402d70 100644 --- a/src/compas_viewer/components/render/camera.py +++ b/src/compas_viewer/components/renderer/camera.py @@ -3,9 +3,9 @@ from math import tan from typing import TYPE_CHECKING from typing import Callable -from typing import List + from typing import Optional -from typing import Tuple + from compas.geometry import Rotation from compas.geometry import Transformation @@ -21,7 +21,7 @@ if TYPE_CHECKING: # https://peps.python.org/pep-0484/#runtime-or-type-checking - from .render import Render + from .renderer import Renderer class Position(Vector): @@ -30,14 +30,14 @@ class Position(Vector): Parameters ---------- - vector : Tuple[float, float, float] + vector : tuple[float, float, float] The position of the camera. on_update : Callable A callback function that is called when the position changes. """ - def __init__(self, vector: Tuple[float, float, float], on_update: Optional[Callable] = None): + def __init__(self, vector: tuple[float, float, float], on_update: Optional[Callable] = None): self.on_update = on_update self.pause_update = True super().__init__(*vector) @@ -91,8 +91,8 @@ class Camera: Parameters ---------- - render : :class:`compas_viewer.components.render.Render`, - The parent render of the camera. + renderer : :class:`compas_viewer.components.renderer.Renderer`, + The parent renderer of the camera. Attributes ---------- @@ -109,11 +109,11 @@ class Camera: The location of the "near" clipping plane. far : float The location of the "far" clipping plane. - position : :class:`compas_viewer.components.render.camera.Position` + position : :class:`compas_viewer.components.renderer.camera.Position` The location the camera. - rotation : :class:`compas_viewer.components.render.camera.RotationEuler` + rotation : :class:`compas_viewer.components.renderer.camera.RotationEuler` The euler rotation of camera. - target : :class:`compas_viewer.components.render.camera.Position` + target : :class:`compas_viewer.components.renderer.camera.Position` The viewing target. Default is the origin of the world coordinate system. distance : float @@ -128,9 +128,9 @@ class Camera: The scale factor for camera's near, far and pan_delta. """ - def __init__(self, render: "Render"): - self.render = render - self.config = render.config.camera + def __init__(self, renderer: "Renderer"): + self.renderer = renderer + self.config = renderer.config.camera self._position = Position((0.0, 0.0, 10.0 * self.config.scale), on_update=self._on_position_update) self._rotation = RotationEuler((0, 0, 0), on_update=self._on_rotation_update) self._target = Position((0, 0, 0), on_update=self._on_target_update) @@ -139,7 +139,7 @@ def __init__(self, render: "Render"): self._target.pause_update = False # Camera position only modifiable in perspective view mode. self.reset_position() - if self.render.config.viewmode == "perspective": + if self.renderer.config.viewmode == "perspective": self.position = Position(self.config.position) self.target = Position(self.config.target) @@ -307,13 +307,13 @@ def _on_target_update(self, target: Position): def reset_position(self): """Reset the position of the camera based current view type.""" self.target.set(0, 0, 0, False) - if self.render.viewmode == "perspective": + if self.renderer.viewmode == "perspective": self.rotation.set(pi / 4, 0, -pi / 4, False) - if self.render.viewmode == "top": + if self.renderer.viewmode == "top": self.rotation.set(0, 0, 0, False) - if self.render.viewmode == "front": + if self.renderer.viewmode == "front": self.rotation.set(pi / 2, 0, 0, False) - if self.render.viewmode == "right": + if self.renderer.viewmode == "right": self.rotation.set(pi / 2, 0, pi / 2, False) def rotate(self, dx: float, dy: float): @@ -331,10 +331,10 @@ def rotate(self, dx: float, dy: float): Notes ----- Camera rotations are only available if the current view mode - is a perspective view (``camera.render.config.viewmode == "perspective"``). + is a perspective view (``camera.renderer.config.viewmode == "perspective"``). """ - if self.render.config.viewmode == "perspective": + if self.renderer.config.viewmode == "perspective": self.rotation += [-self.config.rotationdelta * dy, 0, -self.config.rotationdelta * dx] def pan(self, dx: float, dy: float): @@ -364,12 +364,12 @@ def zoom(self, steps: int = 1): ---------- steps : int The number of zoom increments, with each increment the size - of :attr:`compas_viewer.components.render.Camera.config.zoomdelta`. + of :attr:`compas_viewer.components.renderer.Camera.config.zoomdelta`. """ self.distance -= steps * self.config.zoomdelta * self.distance - def projection(self, width: int, height: int) -> List[List[float]]: + def projection(self, width: int, height: int) -> list[list[float]]: """Compute the projection matrix corresponding to the current camera settings. Parameters @@ -381,7 +381,7 @@ def projection(self, width: int, height: int) -> List[List[float]]: Returns ------- - List[List[float]] + list[list[float]] The transformation matrix as a `numpy` array in column-major order. Notes @@ -390,7 +390,7 @@ def projection(self, width: int, height: int) -> List[List[float]]: """ aspect = width / height - if self.render.viewmode == "perspective": + if self.renderer.viewmode == "perspective": P = self.perspective( self.config.fov, aspect, self.config.near * self.config.scale, self.config.far * self.config.scale ) @@ -404,12 +404,12 @@ def projection(self, width: int, height: int) -> List[List[float]]: ) return list(asfortranarray(P, dtype=float32)) - def viewworld(self) -> List[List[float]]: + def viewworld(self) -> list[list[float]]: """Compute the view-world matrix corresponding to the current camera settings. Returns ------- - List[List[float]] + list[list[float]] The transformation matrix in column-major order. Notes diff --git a/src/compas_viewer/components/render/render.py b/src/compas_viewer/components/renderer/renderer.py similarity index 92% rename from src/compas_viewer/components/render/render.py rename to src/compas_viewer/components/renderer/renderer.py index 887c8c2375..4b0b015ed6 100644 --- a/src/compas_viewer/components/render/render.py +++ b/src/compas_viewer/components/renderer/renderer.py @@ -1,8 +1,6 @@ import time from functools import lru_cache from typing import TYPE_CHECKING -from typing import List -from typing import Tuple from compas.geometry import transform_points_numpy from numpy import float32 @@ -16,7 +14,7 @@ from compas_viewer.configurations import RenderConfig from compas_viewer.scene import TagObject -from compas_viewer.scene.sceneobject import ViewerSceneObject +from compas_viewer.scene.meshobject import MeshObject from compas_viewer.scene.vectorobject import VectorObject from .camera import Camera @@ -28,9 +26,9 @@ from compas_viewer import Viewer -class Render(QOpenGLWidget): +class Renderer(QOpenGLWidget): """ - Render class for 3D rendering of COMPAS geometry. + Renderer class for 3D rendering of COMPAS geometry. We constantly use OpenGL version 2.1 and GLSL 120 with a Compatibility Profile at the moment. The width and height are not in its configuration since they are set by the parent layout. @@ -39,7 +37,7 @@ class Render(QOpenGLWidget): viewer : :class:`compas_viewer.viewer.Viewer` The viewer instance. config : :class:`compas_viewer.configurations.RenderConfig` - The render configuration. + The renderer configuration. """ def __init__(self, viewer: "Viewer", config: RenderConfig): @@ -70,11 +68,11 @@ def __init__(self, viewer: "Viewer", config: RenderConfig): @property def rendermode(self): """ - The render mode of the view. + The renderer mode of the view. Returns ------- - The render mode of the view. + The renderer mode of the view. """ return self._rendermode @@ -133,7 +131,12 @@ def opacity(self) -> float: # ========================================================================== def clear(self): - """Clear the view.""" + """Clear the view. + + See Also + -------- + :GL:`glClear` + """ GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) # type: ignore def initializeGL(self): @@ -225,12 +228,12 @@ def paintGL(self, is_instance: bool = False): def mouseMoveEvent(self, event: QMouseEvent): """ Callback for the mouse move event which passes the event to the controller. - Inherited from :class:`PySide6.QtOpenGLWidgets.QOpenGLWidget`. + Inherited from :PySide6:`PySide6/QtOpenGLWidgets/QOpenGLWidget`. Parameters ---------- - event : :class:`PySide6.QtGui.QMouseEvent` + event : :PySide6:`PySide6/QtGui/QMouseEvent` The Qt event. See Also @@ -251,7 +254,7 @@ def mousePressEvent(self, event: QMouseEvent): Parameters ---------- - event : :class:`PySide6.QtGui.QMouseEvent` + event : :PySide6:`PySide6/QtGui/QMouseEvent` The Qt event. See Also @@ -272,7 +275,7 @@ def mouseReleaseEvent(self, event: QMouseEvent): Parameters ---------- - event : :class:`PySide6.QtGui.QMouseEvent` + event : :PySide6:`PySide6/QtGui/QMouseEvent` The Qt event. See Also @@ -293,7 +296,7 @@ def wheelEvent(self, event: QWheelEvent): Parameters ---------- - event : :class:`PySide6.QtGui.QWheelEvent` + event : :PySide6:`PySide6/QtGui/QWheelEvent` The Qt event. See Also @@ -314,7 +317,7 @@ def keyPressEvent(self, event: QKeyEvent): Parameters ---------- - event : :class:`PySide6.QtGui.QKeyEvent` + event : :PySide6:`PySide6/QtGui/QKeyEvent` The Qt event. See Also @@ -333,7 +336,7 @@ def keyReleaseEvent(self, event: QKeyEvent): Parameters ---------- - event : :class:`PySide6.QtGui.QKeyEvent` + event : :PySide6:`PySide6/QtGui/QKeyEvent` The Qt event. See Also @@ -351,7 +354,7 @@ def keyReleaseEvent(self, event: QKeyEvent): # ========================================================================== def init(self): - """Initialize the render.""" + """Initialize the renderer.""" # Init the grid self.grid.init() @@ -412,9 +415,9 @@ def update_projection(self, w=None, h=None): Parameters ---------- w : int, optional - The width of the render, by default None. + The width of the renderer, by default None. h : int, optional - The height of the render, by default None. + The height of the renderer, by default None. """ w = w or self.viewer.config.width h = h or self.viewer.config.height @@ -443,30 +446,30 @@ def update_projection(self, w=None, h=None): def resize(self, w: int, h: int): """ - Resize the render. + Resize the renderer. Parameters ---------- w : int - The width of the render. + The width of the renderer. h : int - The height of the render. + The height of the renderer. """ self.update_projection(w, h) - def sort_objects_from_viewworld(self, objects: List[ViewerSceneObject], viewworld: List[List[float]]): + def sort_objects_from_viewworld(self, objects: list[MeshObject], viewworld: list[list[float]]): """Sort objects by the distances from their bounding box centers to camera location Parameters ---------- - objects : List[:class:`compas_viewer.scene.sceneobject.ViewerSceneObject`] + objects : list[:class:`compas_viewer.scene.meshobject.MeshObject`] The objects to be sorted. - viewworld : List[List[float]] + viewworld : list[list[float]] The viewworld matrix. Returns ------- - List + list A list of sorted objects. """ opaque_objects = [] @@ -487,15 +490,15 @@ def sort_objects_from_viewworld(self, objects: List[ViewerSceneObject], viewworl @lru_cache(maxsize=3) def sort_objects_from_category( - self, objs: Tuple[ViewerSceneObject] - ) -> Tuple[List[TagObject], List[VectorObject], List[ViewerSceneObject]]: + self, objs: tuple[MeshObject] + ) -> tuple[list[TagObject], list[VectorObject], list[MeshObject]]: """Sort objects by their categories Returns ------- - Tuple(List[:class:`compas_viewer.scene.tagobject.TagObject`], - List[:class:`compas_viewer.scene.vectorobject.VectorObject`], - List[:class:`compas_viewer.scene.sceneobject.ViewerSceneObject`]) + tuple(list[:class:`compas_viewer.scene.tagobject.TagObject`], + list[:class:`compas_viewer.scene.vectorobject.VectorObject`], + list[:class:`compas_viewer.scene.sceneobject.MeshObject`]) A tuple of sorted objects. Notes diff --git a/src/compas_viewer/components/render/selector.py b/src/compas_viewer/components/renderer/selector.py similarity index 79% rename from src/compas_viewer/components/render/selector.py rename to src/compas_viewer/components/renderer/selector.py index bdc8bc8c7e..65bf8628fb 100644 --- a/src/compas_viewer/components/render/selector.py +++ b/src/compas_viewer/components/renderer/selector.py @@ -1,5 +1,4 @@ from typing import TYPE_CHECKING -from typing import Tuple from numpy import all from numpy import any @@ -13,7 +12,7 @@ from PySide6.QtCore import Signal if TYPE_CHECKING: - from .render import Render + from .renderer import Renderer class Selector(QObject): @@ -21,13 +20,13 @@ class Selector(QObject): Parameters ---------- - render : :class:`compas_viewer.components.render.Render` - The render instance. + renderer : :class:`compas_viewer.components.renderer.Renderer` + The renderer instance. Attributes ---------- - render : :class:`compas_viewer.components.render.Render` - The render instance. + renderer : :class:`compas_viewer.components.renderer.Renderer` + The renderer instance. enable_selector : bool Enable the selector. selectioncolor : :class:`compas.colors.Color` @@ -54,16 +53,16 @@ class Selector(QObject): def __init__( self, - render: "Render", + renderer: "Renderer", ): - self.enable_selector = render.config.selector.enable_selector + self.enable_selector = renderer.config.selector.enable_selector if not self.enable_selector: return super().__init__() - self.render = render - self.viewer = render.viewer - self.controller = render.viewer.controller - self.selectioncolor = render.config.selector.selectioncolor + self.renderer = renderer + self.viewer = renderer.viewer + self.controller = renderer.viewer.controller + self.selectioncolor = renderer.config.selector.selectioncolor # Drag selection self.on_drag_selection: bool = False @@ -80,7 +79,7 @@ def select_action(self): """Select the object under the mouse cursor.""" # Deselect all objects first - for _, obj in self.render.viewer.instance_colors.items(): + for _, obj in self.renderer.viewer.instance_colors.items(): obj.is_selected = False x = self.controller.mouse.last_pos.x() @@ -88,7 +87,7 @@ def select_action(self): instance_color = self.read_instance_color((x, y, x, y)) unique_color = unique(instance_color, axis=0, return_counts=False) - selected_obj = self.render.viewer.instance_colors.get(tuple(unique_color[0])) # type: ignore + selected_obj = self.renderer.viewer.instance_colors.get(tuple(unique_color[0])) # type: ignore if selected_obj: selected_obj.is_selected = True @@ -100,7 +99,7 @@ def deselect_action(self): instance_color = self.read_instance_color((x, y, x, y)) unique_color = unique(instance_color, axis=0, return_counts=False) - selected_obj = self.render.viewer.instance_colors.get(tuple(unique_color[0])) # type: ignore + selected_obj = self.renderer.viewer.instance_colors.get(tuple(unique_color[0])) # type: ignore if selected_obj: selected_obj.is_selected = False @@ -109,14 +108,14 @@ def multiselect_action(self): See Also -------- - :func:`compas_viewer.components.render.selector.Selector.select_action` + :func:`compas_viewer.components.renderer.selector.Selector.select_action` """ x = self.controller.mouse.last_pos.x() y = self.controller.mouse.last_pos.y() instance_color = self.read_instance_color((x, y, x, y)) unique_color = unique(instance_color, axis=0, return_counts=False) - selected_obj = self.render.viewer.instance_colors.get(tuple(unique_color[0])) # type: ignore + selected_obj = self.renderer.viewer.instance_colors.get(tuple(unique_color[0])) # type: ignore if selected_obj: selected_obj.is_selected = True @@ -124,7 +123,7 @@ def drag_selection_action(self): """Drag select the objects in the rectangle area.""" # Deselect all objects first - for _, obj in self.render.viewer.instance_colors.items(): + for _, obj in self.renderer.viewer.instance_colors.items(): obj.is_selected = False instance_color = self.read_instance_color( @@ -138,7 +137,7 @@ def drag_selection_action(self): if len(unique_colors) == 0: return - for color, obj in self.render.viewer.instance_colors.items(): + for color, obj in self.renderer.viewer.instance_colors.items(): if any(all(color == unique_colors, axis=1)): obj.is_selected = True continue @@ -148,7 +147,7 @@ def drag_deselection_action(self): See Also -------- - :func:`compas_viewer.components.render.selector.Selector.drag_selection_action` + :func:`compas_viewer.components.renderer.selector.Selector.drag_selection_action` """ instance_color = self.read_instance_color( @@ -162,24 +161,24 @@ def drag_deselection_action(self): if len(unique_colors) == 0: return - for color, obj in self.render.viewer.instance_colors.items(): + for color, obj in self.renderer.viewer.instance_colors.items(): if any(all(color == unique_colors, axis=1)): obj.is_selected = False continue - def read_instance_color(self, box: Tuple[int, int, int, int]): + def read_instance_color(self, box: tuple[int, int, int, int]): """ Paint the instance map quickly, and then read the color of the specified area. Parameters ---------- - box : Tuple[int, int, int, int] + box : tuple[int, int, int, int] The box area [x1, y1, x2, y2] to be read. x1=x2 and y1=y2 means a single point. Notes ----- The instance map is used by the selector to identify selected objects. - The mechanism of a :class:`compas_viewer.components.render.selector.Selector` + The mechanism of a :class:`compas_viewer.components.renderer.selector.Selector` is picking the color from instance map and then find the corresponding object. Anti aliasing, which is always force opened in many machines, can cause color picking inaccuracy. @@ -192,8 +191,8 @@ def read_instance_color(self, box: Tuple[int, int, int, int]): See Also -------- - :func:`compas_viewer.components.render.selector.Selector.ANTI_ALIASING_FACTOR` - :attr:`compas_viewer.components.render.rendermode` + :func:`compas_viewer.components.renderer.selector.Selector.ANTI_ALIASING_FACTOR` + :attr:`compas_viewer.components.renderer.rendermode` References ---------- @@ -207,11 +206,11 @@ def read_instance_color(self, box: Tuple[int, int, int, int]): x, y = min(x1, x2), self.viewer.config.height - max(y1, y2) width = max(self.PIXEL_SELECTION_INCREMENTAL, abs(x1 - x2)) height = max(self.PIXEL_SELECTION_INCREMENTAL, abs(y1 - y2)) - r = self.render.devicePixelRatio() + r = self.renderer.devicePixelRatio() # 1. Repaint the canvas with instance color. - self.render.makeCurrent() - self.render.paintGL(is_instance=True) + self.renderer.makeCurrent() + self.renderer.paintGL(is_instance=True) # 2. Read the instance buffer. instance_buffer = GL.glReadPixels(x * r, y * r, width * r, height * r, GL.GL_RGB, GL.GL_UNSIGNED_BYTE) diff --git a/src/compas_viewer/components/render/shaders/__init__.py b/src/compas_viewer/components/renderer/shaders/__init__.py similarity index 100% rename from src/compas_viewer/components/render/shaders/__init__.py rename to src/compas_viewer/components/renderer/shaders/__init__.py diff --git a/src/compas_viewer/components/render/shaders/arrow.frag b/src/compas_viewer/components/renderer/shaders/arrow.frag similarity index 100% rename from src/compas_viewer/components/render/shaders/arrow.frag rename to src/compas_viewer/components/renderer/shaders/arrow.frag diff --git a/src/compas_viewer/components/render/shaders/arrow.vert b/src/compas_viewer/components/renderer/shaders/arrow.vert similarity index 100% rename from src/compas_viewer/components/render/shaders/arrow.vert rename to src/compas_viewer/components/renderer/shaders/arrow.vert diff --git a/src/compas_viewer/components/render/shaders/grid.frag b/src/compas_viewer/components/renderer/shaders/grid.frag similarity index 100% rename from src/compas_viewer/components/render/shaders/grid.frag rename to src/compas_viewer/components/renderer/shaders/grid.frag diff --git a/src/compas_viewer/components/render/shaders/grid.vert b/src/compas_viewer/components/renderer/shaders/grid.vert similarity index 100% rename from src/compas_viewer/components/render/shaders/grid.vert rename to src/compas_viewer/components/renderer/shaders/grid.vert diff --git a/src/compas_viewer/components/render/shaders/instance.frag b/src/compas_viewer/components/renderer/shaders/instance.frag similarity index 100% rename from src/compas_viewer/components/render/shaders/instance.frag rename to src/compas_viewer/components/renderer/shaders/instance.frag diff --git a/src/compas_viewer/components/render/shaders/instance.vert b/src/compas_viewer/components/renderer/shaders/instance.vert similarity index 100% rename from src/compas_viewer/components/render/shaders/instance.vert rename to src/compas_viewer/components/renderer/shaders/instance.vert diff --git a/src/compas_viewer/components/render/shaders/model.frag b/src/compas_viewer/components/renderer/shaders/model.frag similarity index 100% rename from src/compas_viewer/components/render/shaders/model.frag rename to src/compas_viewer/components/renderer/shaders/model.frag diff --git a/src/compas_viewer/components/render/shaders/model.vert b/src/compas_viewer/components/renderer/shaders/model.vert similarity index 100% rename from src/compas_viewer/components/render/shaders/model.vert rename to src/compas_viewer/components/renderer/shaders/model.vert diff --git a/src/compas_viewer/components/render/shaders/shader.py b/src/compas_viewer/components/renderer/shaders/shader.py similarity index 95% rename from src/compas_viewer/components/render/shaders/shader.py rename to src/compas_viewer/components/renderer/shaders/shader.py index be04e13f64..f54fbdf01e 100644 --- a/src/compas_viewer/components/render/shaders/shader.py +++ b/src/compas_viewer/components/renderer/shaders/shader.py @@ -1,7 +1,5 @@ from pathlib import Path from typing import Any -from typing import List -from typing import Tuple from typing import Union from numpy import array @@ -15,14 +13,14 @@ def __init__(self, name: str = "mesh"): self.program = make_shader_program(name) self.locations = {} - def uniform4x4(self, name: str, value: List[List[float]]): + def uniform4x4(self, name: str, value: list[list[float]]): """Store a uniform 4x4 transformation matrix in the shader program at a named location. Parameters ---------- name : str The name of the location in the shader program. - value : List[List[float]] + value : list[list[float]] A 4x4 transformation matrix. """ _value = array(value) @@ -55,14 +53,14 @@ def uniform1f(self, name: str, value: float): location = GL.glGetUniformLocation(self.program, name) GL.glUniform1f(location, value) - def uniform3f(self, name: str, value: Union[Tuple[float, float, float], List[float]]): + def uniform3f(self, name: str, value: Union[tuple[float, float, float], list[float]]): """Store a uniform list of 3 floats in the shader program at a named location. Parameters ---------- name : str The name of the location in the shader program. - value : Union[Tuple[float, float, float], List[float]] + value : Union[tuple[float, float, float], list[float]] An iterable of 3 floats. """ location = GL.glGetUniformLocation(self.program, name) @@ -245,12 +243,12 @@ def draw_arrows(self, elements: Any, n: int, width: float, background: bool = Fa GL.glDrawArrays(GL.GL_LINES, 0, GL.GL_BUFFER_SIZE) GL.glEnable(GL.GL_POINT_SMOOTH) - def draw_2d_box(self, box_coords: Tuple[float, float, float, float], width: int, height: int): + def draw_2d_box(self, box_coords: tuple[float, float, float, float], width: int, height: int): """Draw a 2D box. Mostly used for box selection. Parameters ---------- - box_coords : Tuple[float, float, float, float] + box_coords : tuple[float, float, float, float] The coordinates of the box. The coordinates are in the format of (x1, y1, x2, y2). width : int The width of the viewport. diff --git a/src/compas_viewer/components/render/shaders/tag.frag b/src/compas_viewer/components/renderer/shaders/tag.frag similarity index 100% rename from src/compas_viewer/components/render/shaders/tag.frag rename to src/compas_viewer/components/renderer/shaders/tag.frag diff --git a/src/compas_viewer/components/render/shaders/tag.vert b/src/compas_viewer/components/renderer/shaders/tag.vert similarity index 100% rename from src/compas_viewer/components/render/shaders/tag.vert rename to src/compas_viewer/components/renderer/shaders/tag.vert diff --git a/src/compas_viewer/configurations/config.py b/src/compas_viewer/configurations/config.py index 7d1939a60a..ad5206295e 100644 --- a/src/compas_viewer/configurations/config.py +++ b/src/compas_viewer/configurations/config.py @@ -1,4 +1,3 @@ -from typing import Dict from typing import TypedDict from typing import Union @@ -10,12 +9,12 @@ class Config(Data): The abstract class for different configurations. """ - def __init__(self, config: Union[TypedDict, Dict]): + def __init__(self, config: Union[TypedDict, dict]): super(Config, self).__init__() self.config = config @property - def data(self): # -> Dict[str, Any]: + def data(self): # -> dict[str, Any]: return self.config @classmethod diff --git a/src/compas_viewer/configurations/controller_config.py b/src/compas_viewer/configurations/controller_config.py index 2fc30f106f..0a7decac35 100644 --- a/src/compas_viewer/configurations/controller_config.py +++ b/src/compas_viewer/configurations/controller_config.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Dict + from typing import Optional from typing import TypedDict @@ -40,7 +40,7 @@ class ControllerConfigType(TypedDict): drag_deselection: MouseConfigType multiselect: MouseConfigType deselect: MouseConfigType - actions: Dict[str, ActionConfigType] + actions: dict[str, ActionConfigType] class ActionConfig: @@ -57,9 +57,9 @@ class ActionConfig: ---------- config : :class:`ActionConfigType` A TypedDict with defined keys and types. - key : :class:`PySide6.QtCore.Qt.Key` + key : :QtCore:`PySide6.QtCore.Qt.Key` The Qt key. - modifier : :class:`PySide6.QtCore.Qt.KeyboardModifier` + modifier : :QtCore:`PySide6.QtCore.Qt.KeyboardModifier` The Qt modifier. """ @@ -85,9 +85,9 @@ class MouseConfig: ---------- config : :class:`MouseConfigType` A TypedDict with defined keys and types. - mouse : :class:`PySide6.QtCore.Qt.MouseButton` + mouse : :QtCore:`PySide6.QtCore.Qt.MouseButton` The Qt mouse. - modifier : :class:`PySide6.QtCore.Qt.KeyboardModifier` + modifier : :QtCore:`PySide6.QtCore.Qt.KeyboardModifier` The Qt modifier. """ @@ -102,13 +102,17 @@ def __init__(self, config: MouseConfigType): class ControllerConfig(Config): """ The class representation for the `controller.json` of - the class :class:`compas_viewer.controller.controller.Controller` + the class Controller. The controller.json contains all the settings about controlling the viewer: mouse, keys, ... Parameters ---------- config : :class:`ControllerConfigType` A TypedDict with defined keys and types. + + See Also + -------- + :class:`compas_viewer.components.controller.Controller` """ def __init__(self, config: ControllerConfigType): diff --git a/src/compas_viewer/configurations/render_config.py b/src/compas_viewer/configurations/render_config.py index 82b3aa5164..33960a6c4c 100644 --- a/src/compas_viewer/configurations/render_config.py +++ b/src/compas_viewer/configurations/render_config.py @@ -1,6 +1,5 @@ from pathlib import Path from typing import Literal -from typing import Tuple from typing import TypedDict from compas.colors import Color @@ -16,7 +15,7 @@ class SelectorConfigType(TypedDict): class SelectorConfig(Config): """ - The class representation of a selector class :class:`compas_viewer.components.render.selector.Selector` + The class representation of a selector class Selector. It contains all the settings about the selector: enable_selector, selectioncolor, ... Parameters @@ -24,6 +23,10 @@ class SelectorConfig(Config): config : SelectorConfigType A TypedDict with defined keys and types. + See Also + -------- + :class:`compas_viewer.components.renderer.selector.Selector` + """ def __init__(self, config: SelectorConfigType): @@ -42,8 +45,8 @@ class CameraConfigType(TypedDict): fov: float near: float far: float - position: Tuple[float, float, float] - target: Tuple[float, float, float] + position: tuple[float, float, float] + target: tuple[float, float, float] scale: float zoomdelta: float rotationdelta: float @@ -52,7 +55,7 @@ class CameraConfigType(TypedDict): class CameraConfig(Config): """ - The class representation of a camera class :class:`compas_viewer.components.render.camera.Camera` + The class representation of a camera class Camera. It contains all the settings about the camera: fov, near, far, position, target, ... Parameters @@ -60,6 +63,10 @@ class CameraConfig(Config): config : CameraConfigType A TypedDict with defined keys and types. + See Also + -------- + :class:`compas_viewer.components.renderer.camera.Camera` + """ def __init__(self, config: CameraConfigType): @@ -83,7 +90,7 @@ def from_json(cls, filepath) -> "CameraConfig": class RenderConfigType(TypedDict): show_grid: bool - gridsize: Tuple[float, int, float, int] + gridsize: tuple[float, int, float, int] show_gridz: bool viewmode: Literal["front", "right", "top", "perspective"] rendermode: Literal["wireframe", "shaded", "ghosted", "lighted", "instance"] @@ -95,14 +102,18 @@ class RenderConfigType(TypedDict): class RenderConfig(Config): """ - The class representation for the `render.json` of the class :class:`compas_viewer.components.render.Render` - The render.json contains all the settings about the render: background color, selection color, ... + The class representation for the `renderer.json` of the class Renderer. + The renderer.json contains all the settings about the renderer: background color, selection color, ... Parameters ---------- config : :class:`RenderConfigType` A TypedDict with defined keys and types. + See Also + -------- + :class:`compas_viewer.components.renderer.Renderer` + """ def __init__(self, config: RenderConfigType): @@ -122,7 +133,7 @@ def from_default(cls) -> "RenderConfig": """ Load the default configuration. """ - render_config = RenderConfig.from_json(Path(DATA, "default_config", "render.json")) + render_config = RenderConfig.from_json(Path(DATA, "default_config", "renderer.json")) assert isinstance(render_config, RenderConfig) return render_config diff --git a/src/compas_viewer/configurations/scene_config.py b/src/compas_viewer/configurations/scene_config.py index 8a47c61c99..3420bdf433 100644 --- a/src/compas_viewer/configurations/scene_config.py +++ b/src/compas_viewer/configurations/scene_config.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Tuple + from typing import TypedDict from compas.colors import Color @@ -24,14 +24,14 @@ class SceneConfigType(TypedDict): opacity: float hide_coplanaredges: bool use_vertexcolors: bool - framesize: Tuple[float, int, float, int] + framesize: tuple[float, int, float, int] show_framez: bool vectorsize: float class SceneConfig(Config): """ - The class representation for the `scene.json` of the class :class:`compas_viewer.scene.ViewerSceneObject` + The class representation for the `scene.json` of the class ViewerSceneObject. The scene.json contains all the settings about the general (default) appearance of the scene objects. Parameters @@ -39,6 +39,10 @@ class SceneConfig(Config): config : :class:`SceneConfigType` A TypedDict with defined keys and types. + See Also + -------- + :class:`compas_viewer.scene.ViewerSceneObject` + """ def __init__(self, config: SceneConfigType): diff --git a/src/compas_viewer/configurations/viewer_config.py b/src/compas_viewer/configurations/viewer_config.py index 2aee5b2a53..2eadc93097 100644 --- a/src/compas_viewer/configurations/viewer_config.py +++ b/src/compas_viewer/configurations/viewer_config.py @@ -21,7 +21,7 @@ class ViewerConfigType(TypedDict): class ViewerConfig(Config): """ - The class representation for the `viewer.json` of the class :class:`compas_viewer.viewer.Viewer` + The class representation for the `viewer.json` of the class Viewer. The viewer.json contains all the settings about the viewer application it self: width, height, fullscreen, ... Parameters @@ -29,6 +29,10 @@ class ViewerConfig(Config): config : :class:`ViewerConfigType` A TypedDict with defined keys and types. + See Also + -------- + :class:`compas_viewer.viewer.Viewer` + """ def __init__(self, config: ViewerConfigType): diff --git a/src/compas_viewer/controller/controller.py b/src/compas_viewer/controller/controller.py index a61f0e6f5a..1b77583ce1 100644 --- a/src/compas_viewer/controller/controller.py +++ b/src/compas_viewer/controller/controller.py @@ -1,5 +1,5 @@ from typing import TYPE_CHECKING -from typing import Dict + from PySide6.QtCore import Qt from PySide6.QtGui import QKeyEvent @@ -13,7 +13,7 @@ from .mouse import Mouse if TYPE_CHECKING: - from compas_viewer.components import Render + from compas_viewer.components import Renderer from compas_viewer.viewer import Viewer @@ -43,7 +43,7 @@ def __init__(self, viewer: "Viewer", config: ControllerConfig): self.viewer = viewer self.config = config self.mouse = Mouse() - self.actions: Dict[str, Action] = {} + self.actions: dict[str, Action] = {} for k, v in self.config.actions.items(): self.actions[k] = Action(k, self.viewer, v) @@ -51,16 +51,16 @@ def __init__(self, viewer: "Viewer", config: ControllerConfig): # Actions # ============================================================================== - def mouse_move_action(self, render: "Render", event: QMouseEvent): + def mouse_move_action(self, renderer: "Renderer", event: QMouseEvent): """ - The mouse move action of the render object. + The mouse move action of the renderer object. This function introduces elif for different actions, meaning only one action can be performed at a time. Parameters ---------- - render : :class:`compas_viewer.components.render.Render` - The render object. - event : :class:`PySide6.QtGui.QMouseEvent` + renderer : :class:`compas_viewer.components.renderer.Renderer` + The renderer object. + event : :PySide6:`PySide6/QtGui/QMouseEvent` The Qt event. """ @@ -75,33 +75,33 @@ def mouse_move_action(self, render: "Render", event: QMouseEvent): event.buttons() == self.config.drag_selection.mouse and event.modifiers() == self.config.drag_selection.modifier ): - render.selector.on_drag_selection = True + renderer.selector.on_drag_selection = True # Drag deselection elif ( event.buttons() == self.config.drag_deselection.mouse and event.modifiers() == self.config.drag_deselection.modifier ): - render.selector.on_drag_selection = True + renderer.selector.on_drag_selection = True # Pan elif event.buttons() == self.config.pan.mouse and event.modifiers() == self.config.pan.modifier: - render.camera.pan(dx, dy) + renderer.camera.pan(dx, dy) # Rotate elif event.buttons() == self.config.rotate.mouse and event.modifiers() == self.config.rotate.modifier: - render.camera.rotate(dx, dy) + renderer.camera.rotate(dx, dy) # Record mouse position self.mouse.last_pos = event.pos() - def mouse_press_action(self, render: "Render", event: QMouseEvent): + def mouse_press_action(self, renderer: "Renderer", event: QMouseEvent): """ - The mouse press action of the render object. + The mouse press action of the renderer object. This function introduces elif for different actions, meaning only one action can be performed at a time. Parameters ---------- - render : :class:`compas_viewer.components.render.Render` - The render object. - event : :class:`PySide6.QtGui.QMouseEvent` + renderer : :class:`compas_viewer.components.renderer.Renderer` + The renderer object. + event : :PySide6:`PySide6/QtGui/QMouseEvent` The Qt event. """ self.mouse.last_pos = event.pos() @@ -111,23 +111,23 @@ def mouse_press_action(self, render: "Render", event: QMouseEvent): event.buttons() == self.config.drag_selection.mouse and event.modifiers() == self.config.drag_selection.modifier ): - render.selector.drag_start_pt = event.pos() + renderer.selector.drag_start_pt = event.pos() # Drag deselection elif ( event.buttons() == self.config.drag_deselection.mouse and event.modifiers() == self.config.drag_deselection.modifier ): - render.selector.drag_start_pt = event.pos() + renderer.selector.drag_start_pt = event.pos() # Select: single left click. if event.buttons() == Qt.MouseButton.LeftButton and event.modifiers() == Qt.KeyboardModifier.NoModifier: - render.selector.select.emit() + renderer.selector.select.emit() # Multiselect elif event.buttons() == self.config.multiselect.mouse and event.modifiers() == self.config.multiselect.modifier: - render.selector.multiselect.emit() + renderer.selector.multiselect.emit() # Deselect elif event.buttons() == self.config.deselect.mouse and event.modifiers() == self.config.deselect.modifier: - render.selector.deselect.emit() + renderer.selector.deselect.emit() # Pan elif ( event.buttons() == self.config.pan.mouse @@ -139,59 +139,59 @@ def mouse_press_action(self, render: "Render", event: QMouseEvent): elif event.buttons() == self.config.rotate.mouse and event.modifiers() == self.config.rotate.modifier: QApplication.setOverrideCursor(Qt.CursorShape.SizeAllCursor) - def mouse_release_action(self, render: "Render", event: QMouseEvent): + def mouse_release_action(self, renderer: "Renderer", event: QMouseEvent): """ - The mouse release action of the render object. + The mouse release action of the renderer object. This function introduces elif for different actions, meaning only one action can be performed at a time. Parameters ---------- - render : :class:`compas_viewer.components.render.Render` - The render object. - event : :class:`PySide6.QtGui.QMouseEvent` + renderer : :class:`compas_viewer.components.renderer.Renderer` + The renderer object. + event : :PySide6:`PySide6/QtGui/QMouseEvent` The Qt event. """ # Drag selection - if event.modifiers() == self.config.drag_selection.modifier and render.selector.on_drag_selection: - render.selector.on_drag_selection = False - render.selector.drag_end_pt = event.pos() - render.selector.drag_selection.emit() + if event.modifiers() == self.config.drag_selection.modifier and renderer.selector.on_drag_selection: + renderer.selector.on_drag_selection = False + renderer.selector.drag_end_pt = event.pos() + renderer.selector.drag_selection.emit() # Drag deselection - elif event.modifiers() == self.config.drag_deselection.modifier and render.selector.on_drag_selection: - render.selector.on_drag_selection = False - render.selector.drag_end_pt = event.pos() - render.selector.drag_deselection.emit() + elif event.modifiers() == self.config.drag_deselection.modifier and renderer.selector.on_drag_selection: + renderer.selector.on_drag_selection = False + renderer.selector.drag_end_pt = event.pos() + renderer.selector.drag_deselection.emit() if event.buttons() == Qt.KeyboardModifier.NoModifier or event.buttons() == Qt.MouseButton.NoButton: QApplication.restoreOverrideCursor() - def wheel_action(self, render: "Render", event: QWheelEvent): + def wheel_action(self, renderer: "Renderer", event: QWheelEvent): """ - The wheel action of the render object. + The wheel action of the renderer object. It is used from zooming action only. Parameters ---------- - render : :class:`compas_viewer.components.render.Render` - The render object. - event : :class:`PySide6.QtGui.QWheelEvent` + renderer : :class:`compas_viewer.components.renderer.Renderer` + The renderer object. + event : :PySide6:`PySide6/QtGui/QWheelEvent` The Qt event. """ degrees = event.angleDelta().y() / 8 steps = degrees / 15 - render.camera.zoom(int(steps)) + renderer.camera.zoom(int(steps)) - def key_press_action(self, render: "Render", event: QKeyEvent): + def key_press_action(self, renderer: "Renderer", event: QKeyEvent): """ - The key press action of the render object. + The key press action of the renderer object. This function introduces break for different actions, meaning only one action can be performed at a time. Parameters ---------- - render : :class:`compas_viewer.components.render.Render` - The render object. - event : :class:`PySide6.QtGui.QKeyEvent` + renderer : :class:`compas_viewer.components.renderer.Renderer` + The renderer object. + event : :PySide6:`PySide6/QtGui/QKeyEvent` The Qt event. """ for action in self.actions.values(): @@ -199,16 +199,16 @@ def key_press_action(self, render: "Render", event: QKeyEvent): action.pressed.emit() break - def key_release_action(self, render: "Render", event: QKeyEvent): + def key_release_action(self, renderer: "Renderer", event: QKeyEvent): """ - The key release action of the render object. + The key release action of the renderer object. This function introduces break for different actions, meaning only one action can be performed at a time. Parameters ---------- - render : :class:`compas_viewer.components.render.Render` - The render object. - event : :class:`PySide6.QtGui.QKeyEvent` + renderer : :class:`compas_viewer.components.renderer.Renderer` + The renderer object. + event : :PySide6:`PySide6/QtGui/QKeyEvent` The Qt event. """ for action in self.actions.values(): diff --git a/src/compas_viewer/controller/mouse.py b/src/compas_viewer/controller/mouse.py index 217126f0ee..39c10525d2 100644 --- a/src/compas_viewer/controller/mouse.py +++ b/src/compas_viewer/controller/mouse.py @@ -7,9 +7,9 @@ class Mouse: Attributes ---------- - pos : :class:`PySide6.QtCore.QPoint` + pos : :PySide6:`PySide6/QtCore/QPoint` The current position of the mouse on the screen. - last_pos : :class:`PySide6.QtCore.QPoint` + last_pos : :PySide6:`PySide6/QtCore/QPoint` The last recorded position of the mouse on the screen. """ diff --git a/src/compas_viewer/scene/boxobject.py b/src/compas_viewer/scene/boxobject.py index cd2e0466fb..e6ab65b653 100644 --- a/src/compas_viewer/scene/boxobject.py +++ b/src/compas_viewer/scene/boxobject.py @@ -5,7 +5,12 @@ class BoxObject(MeshObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Box` geometry.""" + """Viewer scene object for displaying COMPAS Box geometry. + + See Also + -------- + :class:`compas.geometry.Box` + """ def __init__(self, box: Box, **kwargs): super(BoxObject, self).__init__(mesh=Mesh.from_shape(box), **kwargs) diff --git a/src/compas_viewer/scene/brepobject.py b/src/compas_viewer/scene/brepobject.py index 988d24d0e1..498bb270c7 100644 --- a/src/compas_viewer/scene/brepobject.py +++ b/src/compas_viewer/scene/brepobject.py @@ -8,7 +8,7 @@ from compas_occ.brep import BRep class BRepObject(MeshObject): - """Viewer scene object for displaying COMPAS :class:`compas_occ.brep.Brep` geometry. + """Viewer scene object for displaying COMPAS BRep geometry. Attributes ---------- @@ -16,6 +16,10 @@ class BRepObject(MeshObject): The compas_occ Brep object. mesh : :class:`compas.datastructures.Mesh` The tesselation mesh representation of the Brep. + + See Also + -------- + :class:`compas_occ.brep.Brep` """ def __init__(self, brep: BRep, **kwargs): diff --git a/src/compas_viewer/scene/capsuleobject.py b/src/compas_viewer/scene/capsuleobject.py index 79269ec648..19c900a463 100644 --- a/src/compas_viewer/scene/capsuleobject.py +++ b/src/compas_viewer/scene/capsuleobject.py @@ -7,9 +7,14 @@ class CapsuleObject(MeshObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Capsule` geometry.""" + """Viewer scene object for displaying COMPAS Capsule geometry. + + See Also + -------- + :class:`compas.geometry.Capsule` + """ def __init__(self, capsule: Capsule, **kwargs): - self.u =kwargs.get("u", int(2 * pi * capsule.radius / self.LINEARDEFLECTION)) + self.u = kwargs.get("u", int(2 * pi * capsule.radius / self.LINEARDEFLECTION)) super(CapsuleObject, self).__init__(mesh=Mesh.from_shape(capsule, u=self.u), **kwargs) diff --git a/src/compas_viewer/scene/circleobject.py b/src/compas_viewer/scene/circleobject.py index ed99143ff0..9a9e71f092 100644 --- a/src/compas_viewer/scene/circleobject.py +++ b/src/compas_viewer/scene/circleobject.py @@ -9,11 +9,16 @@ class CircleObject(ViewerSceneObject, GeometryObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Circle` geometry.""" + """Viewer scene object for displaying COMPAS Circle geometry. + + See Also + -------- + :class:`compas.geometry.Circle` + """ def __init__(self, circle: Circle, **kwargs): self.geometry: Circle - self.u = kwargs.get("u",int(circle.circumference / self.LINEARDEFLECTION)) + self.u = kwargs.get("u", int(circle.circumference / self.LINEARDEFLECTION)) self.u_points = self._calculate_circle_points(circle) super().__init__(geometry=circle, **kwargs) diff --git a/src/compas_viewer/scene/coneobject.py b/src/compas_viewer/scene/coneobject.py index 55726cc48e..cb4d417d7b 100644 --- a/src/compas_viewer/scene/coneobject.py +++ b/src/compas_viewer/scene/coneobject.py @@ -7,7 +7,12 @@ class ConeObject(MeshObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Cone` geometry.""" + """Viewer scene object for displaying COMPAS Cone geometry. + + See Also + -------- + :class:`compas.geometry.Cone` + """ def __init__(self, cone: Cone, **kwargs): self.u = kwargs.get("u", int(2 * pi * cone.radius / self.LINEARDEFLECTION)) diff --git a/src/compas_viewer/scene/cylinderobject.py b/src/compas_viewer/scene/cylinderobject.py index 12ae8af9c4..1822a50684 100644 --- a/src/compas_viewer/scene/cylinderobject.py +++ b/src/compas_viewer/scene/cylinderobject.py @@ -7,9 +7,14 @@ class CylinderObject(MeshObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Cylinder` geometry.""" + """Viewer scene object for displaying COMPAS Cylinder geometry. + + See Also + -------- + :class:`compas.geometry.Cylinder` + """ def __init__(self, cylinder: Cylinder, **kwargs): - self.u =kwargs.get("u", int(2 * pi * cylinder.radius / self.LINEARDEFLECTION)) + self.u = kwargs.get("u", int(2 * pi * cylinder.radius / self.LINEARDEFLECTION)) super(CylinderObject, self).__init__(mesh=Mesh.from_shape(cylinder, u=self.u), **kwargs) diff --git a/src/compas_viewer/scene/ellipseobject.py b/src/compas_viewer/scene/ellipseobject.py index ce09892c51..25645769df 100644 --- a/src/compas_viewer/scene/ellipseobject.py +++ b/src/compas_viewer/scene/ellipseobject.py @@ -13,11 +13,16 @@ class EllipseObject(ViewerSceneObject, GeometryObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Ellipse` geometry.""" + """Viewer scene object for displaying COMPAS Ellipse geometry. + + See Also + -------- + :class:`compas.geometry.Ellipse` + """ def __init__(self, ellipse: Ellipse, **kwargs): self.geometry = ellipse - self.u = kwargs.get("u",int(self._proximate_circumference / self.LINEARDEFLECTION)) + self.u = kwargs.get("u", int(self._proximate_circumference / self.LINEARDEFLECTION)) self.u_points = self._calculate_ellipse_points(ellipse) super().__init__(geometry=ellipse, close=True, **kwargs) diff --git a/src/compas_viewer/scene/frameobject.py b/src/compas_viewer/scene/frameobject.py index 6c4344a2d0..a0bca5e2c4 100644 --- a/src/compas_viewer/scene/frameobject.py +++ b/src/compas_viewer/scene/frameobject.py @@ -1,5 +1,5 @@ from typing import Optional -from typing import Tuple + from compas.colors import Color from compas.geometry import Frame @@ -13,14 +13,14 @@ class FrameObject(ViewerSceneObject, GeometryObject): """ - The scene object of the :class:`compas.geometry.Frame` geometry. + The scene object of the COMPAS Frame geometry. With its modifiable cell size and dimension, the world grid is also created from this class. Parameters ---------- frame : :class:`compas.geometry.Frame` The frame geometry. - framesize : Tuple[float, int, float, int] + framesize : tuple[float, int, float, int] The size of the grid in [dx, nx, dy, ny] format. Notice that the `nx` and `ny` must be even numbers. show_framez : bool @@ -44,12 +44,16 @@ class FrameObject(ViewerSceneObject, GeometryObject): Notes ----- The frame object is always unselectable. + + See Also + -------- + :class:`compas.geometry.Frame` """ def __init__( self, frame: Frame, - framesize: Optional[Tuple[float, int, float, int]] = None, + framesize: Optional[tuple[float, int, float, int]] = None, show_framez: Optional[bool] = None, **kwargs ): diff --git a/src/compas_viewer/scene/lineobject.py b/src/compas_viewer/scene/lineobject.py index 4d87d4c9cf..8fc298b46b 100644 --- a/src/compas_viewer/scene/lineobject.py +++ b/src/compas_viewer/scene/lineobject.py @@ -6,7 +6,12 @@ class LineObject(ViewerSceneObject, GeometryObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Line` geometry.""" + """Viewer scene object for displaying COMPAS Line geometry. + + See Also + -------- + :class:`compas.geometry.Line` + """ def __init__(self, line: Line, **kwargs): super(LineObject, self).__init__(geometry=line, **kwargs) diff --git a/src/compas_viewer/scene/meshobject.py b/src/compas_viewer/scene/meshobject.py index 70befde199..c380fddf7d 100644 --- a/src/compas_viewer/scene/meshobject.py +++ b/src/compas_viewer/scene/meshobject.py @@ -12,7 +12,7 @@ class MeshObject(ViewerSceneObject, BaseMeshObject): - """Viewer scene object for displaying COMPAS :class:`compas.datastructures.Mesh` geometry. + """Viewer scene object for displaying COMPAS Mesh geometry. Parameters ---------- @@ -22,22 +22,26 @@ class MeshObject(ViewerSceneObject, BaseMeshObject): True to hide the coplanar edges. It will override the value in the config file. use_vertexcolors : bool, optional True to use vertex color. It will override the value in the config file. - **kwargs : Dict, optional + **kwargs : dict, optional Additional options for the :class:`compas_viewer.scene.ViewerSceneObject`. Attributes ---------- mesh : :class:`compas.datastructures.Mesh` The mesh data structure. - vertex_xyz : Dict[int, List[float]] + vertex_xyz : dict[int, list[float]] View coordinates of the vertices. Defaults to the real coordinates. - vertexcolor : :class:`compas.colors.ColorDict` + vertexcolor : :class:`compas.colors.Colordict` Vertex colors. use_vertexcolors : bool True to use vertex color. Defaults to False. hide_coplanaredges : bool True to hide the coplanar edges. + + See Also + -------- + :class:`compas.datastructures.Mesh` """ def __init__( diff --git a/src/compas_viewer/scene/networkobject.py b/src/compas_viewer/scene/networkobject.py index f4727bc8e0..e686aea1dd 100644 --- a/src/compas_viewer/scene/networkobject.py +++ b/src/compas_viewer/scene/networkobject.py @@ -6,16 +6,20 @@ class NetworkObject(ViewerSceneObject, BaseNetworkObject): - """Viewer scene object for displaying COMPAS :class:`compas.datastructures.Network` data. + """Viewer scene object for displaying COMPAS Network data. Parameters ---------- network : :class:`compas.datastructures.Network` The network data structure. - **kwargs : Dict, optional + **kwargs : dict, optional Additional options for the :class:`compas_viewer.scene.ViewerSceneObject`. + See Also + -------- + :class:`compas.datastructures.Network` + """ def __init__(self, network: Network, **kwargs): diff --git a/src/compas_viewer/scene/nurbssurfaceobject.py b/src/compas_viewer/scene/nurbssurfaceobject.py index 383981115b..807f5edbe5 100644 --- a/src/compas_viewer/scene/nurbssurfaceobject.py +++ b/src/compas_viewer/scene/nurbssurfaceobject.py @@ -8,14 +8,19 @@ class NurbsSurfaceObject(ViewerSceneObject, GeometryObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.NurbsSurface` geometry.""" + """Viewer scene object for displaying COMPAS NurbsSurface geometry. + + See Also + -------- + :class:`compas.geometry.NurbsSurface` + """ def __init__(self, surface: NurbsSurface, **kwargs): super().__init__(geometry=surface, **kwargs) # LINEARDEFLECTION not implemented in NurbsSurface. - self.u = kwargs.get("u",int(16 + (0 * self.LINEARDEFLECTION))) - self.v = kwargs.get("v",int(16 + (0 * self.LINEARDEFLECTION))) + self.u = kwargs.get("u", int(16 + (0 * self.LINEARDEFLECTION))) + self.v = kwargs.get("v", int(16 + (0 * self.LINEARDEFLECTION))) self._triangles = [list(point) for triangle in surface.to_triangles(nu=self.u, nv=self.v) for point in triangle] diff --git a/src/compas_viewer/scene/planeobject.py b/src/compas_viewer/scene/planeobject.py index b36267fb3a..8332530a25 100644 --- a/src/compas_viewer/scene/planeobject.py +++ b/src/compas_viewer/scene/planeobject.py @@ -9,7 +9,7 @@ class PlaneObject(ViewerSceneObject, GeometryObject): """ - Viewer scene object for displaying COMPAS :class:`compas.geometry.Plane` geometry. + Viewer scene object for displaying COMPAS Plane geometry. Parameters ---------- @@ -18,6 +18,10 @@ class PlaneObject(ViewerSceneObject, GeometryObject): planesize : float The size of the plane. Default is 1. + + See Also + -------- + :class:`compas.geometry.Plane` """ def __init__(self, plane: Plane, planesize: float = 1, **kwargs): diff --git a/src/compas_viewer/scene/pointobject.py b/src/compas_viewer/scene/pointobject.py index 59e42c81ed..27394b8e02 100644 --- a/src/compas_viewer/scene/pointobject.py +++ b/src/compas_viewer/scene/pointobject.py @@ -6,7 +6,12 @@ class PointObject(ViewerSceneObject, GeometryObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Point` geometry.""" + """Viewer scene object for displaying COMPAS Point geometry. + + See Also + -------- + :class:`compas.geometry.Point` + """ def __init__(self, point: Point, **kwargs): super(PointObject, self).__init__(geometry=point, **kwargs) diff --git a/src/compas_viewer/scene/polygonobject.py b/src/compas_viewer/scene/polygonobject.py index 007015f6f7..c5778d99ab 100644 --- a/src/compas_viewer/scene/polygonobject.py +++ b/src/compas_viewer/scene/polygonobject.py @@ -5,7 +5,12 @@ class PolygonObject(MeshObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Polygon` geometry.""" + """Viewer scene object for displaying COMPAS Polygon geometry. + + See Also + -------- + :class:`compas.geometry.Polygon` + """ def __init__(self, polygon: Polygon, **kwargs): super(PolygonObject, self).__init__(mesh=Mesh.from_shape(polygon), **kwargs) diff --git a/src/compas_viewer/scene/polylineobject.py b/src/compas_viewer/scene/polylineobject.py index f0a995e1c8..4e3e1f784a 100644 --- a/src/compas_viewer/scene/polylineobject.py +++ b/src/compas_viewer/scene/polylineobject.py @@ -7,7 +7,12 @@ class PolylineObject(ViewerSceneObject, GeometryObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Polyline` geometry.""" + """Viewer scene object for displaying COMPAS Polyline geometry. + + See Also + -------- + :class:`compas.geometry.Polyline` + """ def __init__(self, polyline: Polyline, **kwargs): super(PolylineObject, self).__init__(geometry=polyline, **kwargs) diff --git a/src/compas_viewer/scene/sceneobject.py b/src/compas_viewer/scene/sceneobject.py index 25843ac5a2..dfc759db91 100644 --- a/src/compas_viewer/scene/sceneobject.py +++ b/src/compas_viewer/scene/sceneobject.py @@ -1,11 +1,10 @@ -from abc import abstractmethod from random import randint from typing import TYPE_CHECKING from typing import Any -from typing import Dict -from typing import List + + from typing import Optional -from typing import Tuple + from typing import Union from compas.colors import Color @@ -26,14 +25,15 @@ if TYPE_CHECKING: from compas_viewer import Viewer - from compas_viewer.components.render.shaders import Shader + from compas_viewer.components.renderer.shaders import Shader # Type template of point/line/face data for generating the buffers. -DataType = Tuple[List[Point], List[Color], List[List[int]]] +DataType = tuple[list[Point], list[Color], list[list[int]]] class ViewerSceneObject(SceneObject): - """Base class for all Viewer scene objects + """ + Base class for all Viewer scene objects which also includes the GL buffer creation and drawing methods. Parameters @@ -52,11 +52,11 @@ class ViewerSceneObject(SceneObject): Whether to show lines/edges of the object. It will override the value in the config file. show_faces : bool, optional Whether to show faces of the object. It will override the value in the config file. - pointscolor : Union[:class:`compas.colors.Color`, Dict[Any, :class:`compas.colors.Color`]], optional + pointscolor : Union[:class:`compas.colors.Color`, dict[Any, :class:`compas.colors.Color`]], optional The color or the dict of colors of the points. It will override the value in the config file. - linescolor : Union[:class:`compas.colors.Color`, Dict[Any, :class:`compas.colors.Color`]], optional + linescolor : Union[:class:`compas.colors.Color`, dict[Any, :class:`compas.colors.Color`]], optional The color or the dict of colors of the lines. It will override the value in the config file. - facescolor : Union[:class:`compas.colors.Color`, Dict[Any, :class:`compas.colors.Color`]], optional + facescolor : Union[:class:`compas.colors.Color`, dict[Any, :class:`compas.colors.Color`]], optional The color or the dict of colors the faces. It will override the value in the config file. lineswidth : float, optional The line width to be drawn on screen. It will override the value in the config file. @@ -68,7 +68,7 @@ class ViewerSceneObject(SceneObject): The configuration of the scene object. Defaults to None. It should be assigned though the :class:`compas_viewer.viewer.Viewer.add` method. Otherwise a exception will be raised. - **kwargs : Dict, optional + **kwargs : dict, optional Additional visualization options for specific objects. Attributes @@ -86,11 +86,11 @@ class ViewerSceneObject(SceneObject): Whether to show lines/edges of the object. show_faces : bool Whether to show faces of the object. - pointscolor : Dict[Any, :class:`compas.colors.Color`] + pointscolor : dict[Any, :class:`compas.colors.Color`] The color of the points. - linescolor : Dict[Any, :class:`compas.colors.Color`] + linescolor : dict[Any, :class:`compas.colors.Color`] The color of the lines. - facescolor : Dict[Any, :class:`compas.colors.Color`] + facescolor : dict[Any, :class:`compas.colors.Color`] The color of the faces. lineswidth : float The line width to be drawn on screen @@ -100,11 +100,15 @@ class ViewerSceneObject(SceneObject): The opacity of the object. background : bool Whether the object is drawn on the background with depth test disabled. - bounding_box : List[float], read-only + bounding_box : list[float], read-only The min and max corners of object bounding box, as a numpy array of shape (2, 3). bounding_box_center : :class:`compas.geometry.Point`, read-only The center of object bounding box, as a point. + See Also + -------- + :class:`compas.scene.SceneObject` + """ LINEARDEFLECTION = 0.2 @@ -118,9 +122,9 @@ def __init__( show_points: Optional[bool] = None, show_lines: Optional[bool] = None, show_faces: Optional[bool] = None, - pointscolor: Optional[Union[Color, Dict[Any, Color]]] = None, - linescolor: Optional[Union[Color, Dict[Any, Color]]] = None, - facescolor: Optional[Union[Color, Dict[Any, Color]]] = None, + pointscolor: Optional[Union[Color, dict[Any, Color]]] = None, + linescolor: Optional[Union[Color, dict[Any, Color]]] = None, + facescolor: Optional[Union[Color, dict[Any, Color]]] = None, lineswidth: Optional[float] = None, pointssize: Optional[float] = None, opacity: Optional[float] = None, @@ -179,8 +183,8 @@ def __init__( # Geometric self.transformation: Optional[Transformation] = None - self._matrix_buffer: Optional[List[List[float]]] = None - self._bounding_box: Optional[List[float]] = None + self._matrix_buffer: Optional[list[list[float]]] = None + self._bounding_box: Optional[list[float]] = None self._bounding_box_center: Optional[Point] = None self._is_collection = False @@ -189,10 +193,10 @@ def __init__( self._lines_data: Optional[DataType] = None self._frontfaces_data: Optional[DataType] = None self._backfaces_data: Optional[DataType] = None - self._points_buffer: Optional[Dict[str, Any]] = None - self._lines_buffer: Optional[Dict[str, Any]] = None - self._frontfaces_buffer: Optional[Dict[str, Any]] = None - self._backfaces_buffer: Optional[Dict[str, Any]] = None + self._points_buffer: Optional[dict[str, Any]] = None + self._lines_buffer: Optional[dict[str, Any]] = None + self._frontfaces_buffer: Optional[dict[str, Any]] = None + self._backfaces_buffer: Optional[dict[str, Any]] = None @property def bounding_box(self): @@ -239,17 +243,17 @@ def _update_matrix(self): # buffer # ========================================================================== - def make_buffer_from_data(self, data: DataType) -> Dict[str, Any]: + def make_buffer_from_data(self, data: DataType) -> dict[str, Any]: """Create buffers from point/line/face data. Parameters ---------- - data : Tuple[List[:class:`compas.geometry.Point`], List[:class:`compas.colors.Color`], List[int]] + data : tuple[list[:class:`compas.geometry.Point`], list[:class:`compas.colors.Color`], list[int]] Contains positions, colors, elements for the buffer. Returns ------- - buffer_dict : Dict[str, Any] + buffer_dict : dict[str, Any] A dict with created buffer indexes. """ positions, colors, elements = data @@ -263,7 +267,7 @@ def make_buffer_from_data(self, data: DataType) -> Dict[str, Any]: def update_buffer_from_data( self, data: DataType, - buffer: Dict[str, Any], + buffer: dict[str, Any], update_positions: bool, update_colors: bool, update_elements: bool, @@ -272,9 +276,9 @@ def update_buffer_from_data( Parameters ---------- - data : Tuple[List[:class:`compas.geometry.Point`], List[:class:`compas.colors.Color`], List[int]] + data : tuple[list[:class:`compas.geometry.Point`], list[:class:`compas.colors.Color`], list[int]] Contains positions, colors, elements for the buffer. - buffer : Dict[str, Any] + buffer : dict[str, Any] The dict with created buffer indexes update_positions : bool Whether to update positions in the buffer dict. @@ -345,9 +349,9 @@ def update(self): """Update the object""" self._update_matrix() self.update_buffers() - self.viewer.render.update() + self.viewer.renderer.update() - def _update_bounding_box(self, positions: Optional[List[Point]] = None): + def _update_bounding_box(self, positions: Optional[list[Point]] = None): """Update the bounding box of the object""" if positions is None: positions = [] @@ -446,7 +450,7 @@ def draw_instance(self, shader, wireframe: bool): if self._lines_buffer is not None and (self.show_lines or wireframe): shader.bind_attribute("position", self._lines_buffer["positions"]) shader.draw_lines( - width=self.lineswidth + self.viewer.render.selector.PIXEL_SELECTION_INCREMENTAL, + width=self.lineswidth + self.viewer.renderer.selector.PIXEL_SELECTION_INCREMENTAL, elements=self._lines_buffer["elements"], n=self._lines_buffer["n"], ) diff --git a/src/compas_viewer/scene/sphereobject.py b/src/compas_viewer/scene/sphereobject.py index a98b360582..56405980bc 100644 --- a/src/compas_viewer/scene/sphereobject.py +++ b/src/compas_viewer/scene/sphereobject.py @@ -7,7 +7,12 @@ class SphereObject(MeshObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Sphere` geometry.""" + """Viewer scene object for displaying COMPAS Sphere geometry. + + See Also + -------- + :class:`compas.geometry.Sphere` + """ def __init__(self, sphere: Sphere, **kwargs): self.u = kwargs.get("u", int(2 * pi * sphere.radius / self.LINEARDEFLECTION)) diff --git a/src/compas_viewer/scene/tagobject.py b/src/compas_viewer/scene/tagobject.py index 3176f7d6e2..c491fc25fb 100644 --- a/src/compas_viewer/scene/tagobject.py +++ b/src/compas_viewer/scene/tagobject.py @@ -1,7 +1,7 @@ from os import PathLike from os import path from typing import Optional -from typing import Tuple + from typing import Union from compas.colors import Color @@ -31,7 +31,7 @@ class Tag(Geometry): ---------- text : str The text of the tag. - position : Union[:class:`compas.geometry.Point`, Tuple[float, float, float]] + position : Union[:class:`compas.geometry.Point`, tuple[float, float, float]] The position of the tag. color : :class:`compas.colors.Color`, optional The color of the tag. @@ -76,7 +76,7 @@ def __eq__(self, other): def __init__( self, text: str, - position: Union[Point, Tuple[float, float, float]], + position: Union[Point, tuple[float, float, float]], color: Color = Color(0.0, 0.0, 0.0), height: float = 50, absolute_height: bool = False, @@ -104,15 +104,19 @@ def transform(self, transformation): class TagObject(ViewerSceneObject, GeometryObject): """ - The scene object of the :class:`compas_viewer.scene.Tag` geometry. + The scene object of the viewer tag geometry. Unlike :class:`compas_viewer.scene.TextObject`, tag object is a sprite always facing the camera. Parameters ---------- tag : :class:`compas_viewer.scene.Tag` The tag geometry. - **kwargs : Dict, optional + **kwargs : dict, optional Additional options for the :class:`compas_viewer.scene.ViewerSceneObject`. + + See Also + -------- + :class:`compas_viewer.scene.Tag` """ def __init__(self, tag: Tag, **kwargs): diff --git a/src/compas_viewer/scene/torusobject.py b/src/compas_viewer/scene/torusobject.py index 6a72d8fb53..1d35c5a5ab 100644 --- a/src/compas_viewer/scene/torusobject.py +++ b/src/compas_viewer/scene/torusobject.py @@ -7,10 +7,15 @@ class TorusObject(MeshObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Torus` geometry.""" + """Viewer scene object for displaying COMPAS Torus geometry. + + See Also + -------- + :class:`compas.geometry.Torus` + """ def __init__(self, torus: Torus, **kwargs): - self.u = kwargs.get("u",int(2 * pi * torus.radius_axis / self.LINEARDEFLECTION)) - self.v = kwargs.get("v",int(2 * pi * torus.radius_pipe / self.LINEARDEFLECTION)) + self.u = kwargs.get("u", int(2 * pi * torus.radius_axis / self.LINEARDEFLECTION)) + self.v = kwargs.get("v", int(2 * pi * torus.radius_pipe / self.LINEARDEFLECTION)) super(TorusObject, self).__init__(mesh=Mesh.from_shape(torus, u=self.u, v=self.v), **kwargs) diff --git a/src/compas_viewer/scene/vectorobject.py b/src/compas_viewer/scene/vectorobject.py index e127475f6d..f3c2b87c34 100644 --- a/src/compas_viewer/scene/vectorobject.py +++ b/src/compas_viewer/scene/vectorobject.py @@ -1,18 +1,18 @@ from typing import Any -from typing import Dict + from compas.geometry import Point from compas.geometry import Vector from compas.scene import GeometryObject -from compas_viewer.components.render.shaders.shader import Shader +from compas_viewer.components.renderer.shaders.shader import Shader from .sceneobject import DataType from .sceneobject import ViewerSceneObject class VectorObject(ViewerSceneObject, GeometryObject): - """Viewer scene object for displaying COMPAS :class:`compas.geometry.Vector` geometry. + """Viewer scene object for displaying COMPAS Vector geometry. Parameters ---------- @@ -21,7 +21,7 @@ class VectorObject(ViewerSceneObject, GeometryObject): anchor : :class:`compas.geometry.Point`, optional The anchor point of the vector. Default is the origin point. - **kwargs : Dict, optional + **kwargs : dict, optional Additional options for the :class:`compas_viewer.scene.ViewerSceneObject`. Notes @@ -31,6 +31,10 @@ class VectorObject(ViewerSceneObject, GeometryObject): that controls the width of the vector, the :attr:`compas_viewer.scene.vectorobject.VectorObject.config.vectorsize` (float 0-1) controls the size of the arrow. + + See Also + -------- + :class:`compas.geometry.Vector` """ # Fixed indices for the arrow faces: @@ -39,7 +43,7 @@ class VectorObject(ViewerSceneObject, GeometryObject): def __init__(self, vector: Vector, anchor: Point = Point(0, 0, 0), **kwargs): self._anchor = anchor super(VectorObject, self).__init__(geometry=vector, **kwargs) - self.arrow_buffer: Dict[str, Any] + self.arrow_buffer: dict[str, Any] def _read_lines_data(self) -> DataType: arrow_end = self._anchor + self.geometry * (1 - self.config.vectorsize) diff --git a/src/compas_viewer/utilities/gl.py b/src/compas_viewer/utilities/gl.py index bb683ca169..ad57e8a8b3 100644 --- a/src/compas_viewer/utilities/gl.py +++ b/src/compas_viewer/utilities/gl.py @@ -38,7 +38,7 @@ def make_vertex_buffer(data, dynamic=False): Parameters ---------- - data : List[float] + data : list[float] A flat list of floats. dynamic : bool, optional If True, the buffer is optimized for dynamic access. @@ -71,7 +71,7 @@ def make_index_buffer(data, dynamic=False): Parameters ---------- - data : List[int] + data : list[int] A flat list of ints. dynamic : bool, optional If True, the buffer is optimized for dynamic access. @@ -104,7 +104,7 @@ def update_vertex_buffer(data, buffer): Parameters ---------- - data : List[float] + data : list[float] A flat list of floats. buffer : int The ID of the buffer. @@ -123,7 +123,7 @@ def update_index_buffer(data, buffer): Parameters ---------- - data : List[int] + data : list[int] A flat list of ints. buffer : int The ID of the buffer. diff --git a/src/compas_viewer/utilities/qt.py b/src/compas_viewer/utilities/qt.py index 4a7dfbc28a..f4e76755f2 100644 --- a/src/compas_viewer/utilities/qt.py +++ b/src/compas_viewer/utilities/qt.py @@ -14,19 +14,20 @@ def key_mapper( Parameters ---------- key : str - The key string which is the same as what it was called in the :class:`PySide6.QtCore.Qt`, + The key string which is the same as what it was called in the :QtCore:`PySide6.QtCore.Qt`, with **lowercases and with prefix&underscores removed**. Check out the reference page to find out the supported keys and the original names. type : Literal[0, 1, 2] The type of the key for mapping. - * 0 for :class:`PySide6.QtCore.Qt.Key`, - * 1 for :class:`PySide6.QtCore.Qt.KeyboardModifier`, - * 2 for :class:`PySide6.QtCore.Qt.MouseButton`. + * 0 for :QtCore:`PySide6.QtCore.Qt.Key`, + * 1 for :QtCore:`PySide6.QtCore.Qt.KeyboardModifier`, + * 2 for :QtCore:`PySide6.QtCore.Qt.MouseButton`. Returns ------- - Literal[:class:`Qt.Key`, :class:`Qt.KeyboardModifier`, :class:`Qt.MouseButton`] + Literal[:QtCore:`PySide6.QtCore.Qt.Key`, :QtCore:`PySide6.QtCore.Qt.KeyboardModifier`, + :QtCore:`PySide6.QtCore.Qt.MouseButton`] The mapped Qt key. Notes @@ -36,9 +37,9 @@ def key_mapper( This function handles: - * :class:`PySide6.QtCore.Qt.Key` - * :class:`PySide6.QtCore.Qt.KeyboardModifier` - * :class:`PySide6.QtCore.Qt.MouseButton` + * :QtCore:`PySide6.QtCore.Qt.Key` + * :QtCore:`PySide6.QtCore.Qt.KeyboardModifier` + * :QtCore:`PySide6.QtCore.Qt.MouseButton` Examples -------- diff --git a/src/compas_viewer/viewer.py b/src/compas_viewer/viewer.py index e0578e460c..7e0df6fcd5 100644 --- a/src/compas_viewer/viewer.py +++ b/src/compas_viewer/viewer.py @@ -4,11 +4,8 @@ from typing import TYPE_CHECKING from typing import Any from typing import Callable -from typing import Dict -from typing import List from typing import Literal from typing import Optional -from typing import Tuple from typing import Union from compas.colors import Color @@ -25,7 +22,7 @@ from compas_viewer import DATA from compas_viewer.actions import Action from compas_viewer.actions import register -from compas_viewer.components import Render +from compas_viewer.components import Renderer from compas_viewer.configurations import ActionConfig from compas_viewer.configurations import ActionConfigType from compas_viewer.configurations import ControllerConfig @@ -133,7 +130,7 @@ def __init__( self.controller_config = ControllerConfig.from_default() else: self.config = ViewerConfig.from_json(Path(configpath, "viewer.json")) - self.render_config = RenderConfig.from_json(Path(configpath, "render.json")) + self.render_config = RenderConfig.from_json(Path(configpath, "renderer.json")) self.scene_config = SceneConfig.from_json(Path(configpath, "scene.json")) self.controller_config = ControllerConfig.from_json(Path(configpath, "controller.json")) @@ -161,10 +158,10 @@ def __init__( self.frame_count: int = 0 # Selection - self.instance_colors: Dict[Tuple[int, int, int], ViewerSceneObject] = {} + self.instance_colors: dict[tuple[int, int, int], ViewerSceneObject] = {} # Primitive - self.objects: List[ViewerSceneObject] + self.objects: list[ViewerSceneObject] self._init() @@ -200,8 +197,8 @@ def _init(self): is_visible=True, config=self.scene_config, ) - self.render = Render(self, self.render_config) - self._window.setCentralWidget(self.render) + self.renderer = Renderer(self, self.render_config) + self._window.setCentralWidget(self.renderer) self._window.setContentsMargins(0, 0, 0, 0) self._app.references.add(self._window) # type: ignore self._window.resize(self.config.width, self.config.height) @@ -399,17 +396,17 @@ def rotate(frame): raise ValueError("Must specify either interval or timeout.") def outer(func: Callable): - def render(): + def renderer(): func(self.frame_count) - self.render.update() + self.renderer.update() self.frame_count += 1 if frames is not None and self.frame_count >= frames: self.timer.stop() if interval: - self.timer = Timer(interval=interval, callback=render) + self.timer = Timer(interval=interval, callback=renderer) if timeout: - self.timer = Timer(interval=timeout, callback=render, singleshot=True) + self.timer = Timer(interval=timeout, callback=renderer, singleshot=True) self.frame_count = 0 @@ -429,9 +426,9 @@ def add( show_points: Optional[bool] = None, show_lines: Optional[bool] = None, show_faces: Optional[bool] = None, - pointscolor: Optional[Union[Color, Dict[Any, List[float]]]] = None, - linescolor: Optional[Union[Color, Dict[Any, List[float]]]] = None, - facescolor: Optional[Union[Color, Dict[Any, List[float]]]] = None, + pointscolor: Optional[Union[Color, dict[Any, list[float]]]] = None, + linescolor: Optional[Union[Color, dict[Any, list[float]]]] = None, + facescolor: Optional[Union[Color, dict[Any, list[float]]]] = None, lineswidth: Optional[float] = None, pointssize: Optional[float] = None, opacity: Optional[float] = None, @@ -467,13 +464,13 @@ def add( show_faces : bool, optional Whether to show faces of the object. It will override the value in the scene config file. - pointscolor : Union[:class:`compas.colors.Color`, Dict[Any, :class:`compas.colors.Color`], optional + pointscolor : Union[:class:`compas.colors.Color`, dict[Any, :class:`compas.colors.Color`], optional The color or the dict of colors of the points. It will override the value in the scene config file. - linescolor : Union[:class:`compas.colors.Color`, Dict[Any, :class:`compas.colors.Color`], optional + linescolor : Union[:class:`compas.colors.Color`, dict[Any, :class:`compas.colors.Color`], optional The color or the dict of colors of the lines. It will override the value in the scene config file. - facescolor : Union[:class:`compas.colors.Color`, Dict[Any, :class:`compas.colors.Color`], optional + facescolor : Union[:class:`compas.colors.Color`, dict[Any, :class:`compas.colors.Color`], optional The color or the dict of colors the faces. It will override the value in the scene config file. lineswidth : float, optional @@ -491,7 +488,7 @@ def add( use_vertexcolors : bool, optional Whether to use vertex color. It will override the value in the scene config file. - **kwargs : Dict, optional + **kwargs : dict, optional The other possible parameters to be passed to the object. Returns @@ -583,7 +580,7 @@ def add_action( name = pressed_action.__name__ if modifier is None: modifier = "no" - config: ActionConfigType = {"key": key, "modifier": modifier} + config = ActionConfigType({"key": key, "modifier": modifier}) class CustomAction(Action): def pressed_action(self):