diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e2e6cc39..f248685df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added `list` to accepted types for `Scene.add`. * Added `list[float]` to accepted types for `Camera.position` and `Camera.target`. +* Added `unit` to `Viewer` and `Config`. * Added `bounding_box` and `_update_bounding_box` to `BufferObject`. ### Changed diff --git a/scripts/unit.py b/scripts/unit.py new file mode 100644 index 000000000..b262a933f --- /dev/null +++ b/scripts/unit.py @@ -0,0 +1,20 @@ +from compas.colors import Color +from compas.geometry import Box +from compas.geometry import Frame +from compas_viewer.viewer import Viewer +from compas_viewer.config import Config + +config = Config() +config.unit = "mm" +viewer = Viewer(config) + +for i in range(10): + for j in range(10): + viewer.scene.add( + Box(500, 500, 500, Frame([i * 1000, j * 1000, 0], [1, 0, 0], [0, 1, 0])), + show_lines=True, + surfacecolor=Color(i / 10, j / 10, 0.0), + name=f"Box_{i}_{j}", + ) + +viewer.show() diff --git a/src/compas_viewer/config.py b/src/compas_viewer/config.py index fcf5c06ca..3c4da0fc2 100644 --- a/src/compas_viewer/config.py +++ b/src/compas_viewer/config.py @@ -369,6 +369,7 @@ class UIConfig(ConfigBase): @dataclass class Config(ConfigBase): vectorsize: float = 0.1 + unit: Literal["m", "cm", "mm"] = "m" ui: UIConfig = field(default_factory=UIConfig) window: WindowConfig = field(default_factory=WindowConfig) renderer: RendererConfig = field(default_factory=RendererConfig) diff --git a/src/compas_viewer/viewer.py b/src/compas_viewer/viewer.py index 04e763550..0c60588ef 100644 --- a/src/compas_viewer/viewer.py +++ b/src/compas_viewer/viewer.py @@ -20,12 +20,15 @@ class Viewer(Singleton): def __init__(self, config: Optional[Config] = None, **kwargs): + + self.running = False self.app = QApplication(sys.argv) self.app.setApplicationName("COMPAS Viewer") self.app.setApplicationDisplayName("COMPAS Viewer") self.app.setWindowIcon(QIcon(os.path.join(HERE, "assets", "icons", "compas_icon_white.png"))) self._scene = None + self._unit = "m" self.config = config or Config() self.timer = QTimer() @@ -36,8 +39,7 @@ def __init__(self, config: Optional[Config] = None, **kwargs): # renderer should be part of UI self.renderer = Renderer(self) self.ui = UI(self) - - self.running = False + self.unit = self.config.unit @property def scene(self) -> ViewerScene: @@ -52,6 +54,31 @@ def scene(self, scene: Scene): for obj in self._scene.objects: obj.init() + @property + def unit(self) -> str: + return self._unit + + @unit.setter + def unit(self, unit: str): + if self.running: + raise NotImplementedError("Changing the unit after the viewer is running is not yet supported.") + if unit != self._unit: + previous_scale = self.config.camera.scale + if unit == "m": + self.config.renderer.gridsize = (10.0, 10, 10.0, 10) + self.renderer.camera.scale = 1.0 + elif unit == "cm": + self.config.renderer.gridsize = (1000.0, 10, 1000.0, 10) + self.renderer.camera.scale = 100.0 + elif unit == "mm": + self.config.renderer.gridsize = (10000.0, 10, 10000.0, 10) + self.renderer.camera.scale = 1000.0 + else: + raise ValueError(f"Invalid unit: {unit}. Valid units are 'm', 'cm', 'mm'.") + self.renderer.camera.distance *= self.renderer.camera.scale / previous_scale + + self._unit = unit + def show(self): self.running = True self.ui.init()