Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/view-setting-config #208

Merged
merged 17 commits into from
Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added


* Added `viewport` and `camera` in the config
* Added the update method for the `textobject`.


### Changed

* Change the str options in `view_port` into all lower case.
* Change naming `view_mode` to `viewport_mode`, `view_port` to `viewport`.
* Doc building using `sphinx_compas2_theme `.
* Fix the documentation: title lines, comments.
* Fix a bug when camera is looking straight up or down.
Expand Down
Binary file added docs/_images/example_camera_config.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_images/example_camera_config_2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions docs/examples/control/example_camera_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from compas.geometry import Box
from compas.geometry import Frame
from compas_view2.app import App

# If you input incomplete configuration, the rest will be filled by the default values.

config = {
"view": {
"show_grid": True,
"viewmode": "shaded",
"background_color": [1, 1, 1, 1],
"selection_color": [1.0, 1.0, 0.0],
"viewport": "top",
"camera": {
"fov": 45,
"near": 0.1,
"far": 1000,
"position": [-15, -15, 15],
"target": [1,1, 1],
"scale": 1,
},
}
}

viewer_default = App()
viewer_custom = App(config=config)


box = Box(Frame([0, 0, 0], [1, 0, 0], [0, 1, 0]), 1, 1, 1)

viewer_default.add(box)
viewer_custom.add(box)


viewer_default.run()
viewer_custom.run()
33 changes: 33 additions & 0 deletions docs/examples/control/example_camera_config.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
*******************************************************************************
Camera Config
*******************************************************************************

.. autosummary::
:toctree:
:nosignatures:

Default Camera Config
=======================================

By default, the camera is configed 45 dregees perspective:

.. figure:: /_images/example_camera_config.jpg
:figclass: figure
:class: figure-img img-fluid



Custom Camera Config
======================

You can customize the camera configreation by passing the dictionary to the viewer: fov, near, fac, position, target, scale.

.. note::
The `position` is not editable and would be ingored from the config file in `top`, `front`, `right` modes.

.. figure:: /_images/example_camera_config_2.jpg
:figclass: figure
:class: figure-img img-fluid

.. literalinclude:: example_camera_config.py
:language: python
2 changes: 1 addition & 1 deletion docs/tutorials/files/config_default.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"view": {
"show_grid": true,
"view_mode": "shaded",
"viewmode": "shaded",
"background_color": [1, 1, 1, 1],
"selection_color": [1.0, 1.0, 0.0]
},
Expand Down
3 changes: 2 additions & 1 deletion docs/tutorials/tutorial_basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ use the "on" decorator (:meth:`compas_view2.app.App.on`) on a callback function.


Zoom, Pan, Rotate, and Select
===============================
==============================================================================


After launching the viewer, the view can be transformed by zooming, panning, and rotating. Object selection is also possible.

Expand Down
8 changes: 1 addition & 7 deletions docs/tutorials/tutorial_configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ This is a sustainable and sharable way to customize your viewer.
::

>>> from compas_view2.app import App
>>> viewer = App(viewmode="lighted", enable_sceneform=True, enable_propertyform=True, enable_sidebar=True, width=2000, height=1000)
>>> viewer = App(viewmode="lighted", viewport = "top", enable_sceneform=True, enable_propertyform=True, enable_sidebar=True, width=2000, height=1000)

::

Expand All @@ -69,12 +69,6 @@ Configuration Structure
The default configuration file can be downloaded here: :download:`Link <files/config_default.json>`,
or can be printed by the following code:

::

>>> # This prints the default configuration
>>> from compas_view2 import Info
>>> Info().show_config()

It it the template for creating your own settings, keyboard preferences, etc.

Supported Keys
Expand Down
5 changes: 5 additions & 0 deletions src/compas_view2/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ class App:
viewmode : {'shaded', 'ghosted', 'wireframe', 'lighted'}, optional
The display mode of the OpenGL view. It will override the value in the config file.
In `ghosted` mode, all objects have a default opacity of 0.7.
viewport : {'front', 'right', 'top', 'perspective'}, optional
The viewport of the OpenGL view. It will override the value in the config file.
show_grid : bool, optional
Show the XY plane. It will override the value in the config file.
config : dict | filepath, optional
Expand Down Expand Up @@ -135,6 +137,7 @@ def __init__(
width: int = None,
height: int = None,
viewmode: Literal["wireframe", "shaded", "ghosted", "lighted"] = None,
viewport: Literal["front", "right", "top", "perspective"] = None,
show_grid: bool = None,
enable_sidebar=None,
enable_sidedock1: bool = None,
Expand Down Expand Up @@ -177,6 +180,8 @@ def __init__(

if viewmode is not None:
config["view"]["viewmode"] = viewmode
if viewport is not None:
config["view"]["viewport"] = viewport
if show_grid is not None:
config["view"]["show_grid"] = show_grid

Expand Down
13 changes: 11 additions & 2 deletions src/compas_view2/app/config_default.json
Copy link
Collaborator Author

@ZacZhangzhuo ZacZhangzhuo Dec 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I think we should use a custom setting here in the default config. It should be something minimal and simple.

the default value is already custom.

Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,18 @@
},
"view": {
"show_grid": true,
"view_mode": "shaded",
"viewmode": "shaded",
"viewport": "perspective",
"background_color": [1, 1, 1, 1],
"selection_color": [1.0, 1.0, 0.0]
"selection_color": [1.0, 1.0, 0.0],
"camera": {
"fov": 45,
"near": 0.1,
"far": 1000,
"position":[-1.5, -1.5, 1.5],
"target": [0, 0, 0],
"scale": 1
}
},
"statusbar": {
"texts": "Ready",
Expand Down
8 changes: 4 additions & 4 deletions src/compas_view2/app/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ def view_front(self):
None

"""
self.app.view.current = self.app.view.FRONT
self.app.view.current = self.app.view.VIEWPORTS["front"]
self.app.view.camera.reset_position()
self.app.view.update_projection()
self.app.view.update()
Expand All @@ -444,7 +444,7 @@ def view_right(self):
None

"""
self.app.view.current = self.app.view.RIGHT
self.app.view.current = self.app.view.VIEWPORTS["right"]
self.app.view.camera.reset_position()
self.app.view.update_projection()
self.app.view.update()
Expand All @@ -457,7 +457,7 @@ def view_top(self):
None

"""
self.app.view.current = self.app.view.TOP
self.app.view.current = self.app.view.VIEWPORTS["top"]
self.app.view.camera.reset_position()
self.app.view.update_projection()
self.app.view.update()
Expand All @@ -470,7 +470,7 @@ def view_perspective(self):
None

"""
self.app.view.current = self.app.view.PERSPECTIVE
self.app.view.current = self.app.view.VIEWPORTS["perspective"]
self.app.view.camera.reset_position()
self.app.view.update_projection()
self.app.view.update()
Expand Down
35 changes: 19 additions & 16 deletions src/compas_view2/scene/camera.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
from compas.geometry import Translation
from compas.geometry import Rotation
from compas.geometry import Vector
from numpy.linalg import norm
from numpy.linalg import det
from math import atan2
from numpy import pi
from typing import List

from numpy import array
from numpy import asfortranarray
from numpy import dot
from numpy import float32
from numpy import pi
from numpy.linalg import det
from numpy.linalg import norm

from compas.geometry import Rotation
from compas.geometry import Translation
from compas.geometry import Vector
from compas_view2.objects import Object
from typing import List

from .matrices import perspective, ortho
from .matrices import ortho
from .matrices import perspective


class Position(Vector):
Expand Down Expand Up @@ -134,7 +137,7 @@ def __init__(self, view, fov=45, near=0.1, far=1000, position=None, target=None,
self.reset_position()
if target:
self.target = target
if position:
if position and view._current == 4:
self.position = position

@property
Expand Down Expand Up @@ -235,13 +238,13 @@ def _on_target_update(self, target):
def reset_position(self):
"""Reset the position of the camera based current view type."""
self.target.set(0, 0, 0)
if self.view.current == self.view.PERSPECTIVE:
if self.view.current == self.view.VIEWPORTS["perspective"]:
self.rotation.set(pi / 4, 0, -pi / 4)
if self.view.current == self.view.TOP:
if self.view.current == self.view.VIEWPORTS["top"]:
self.rotation.set(0, 0, 0)
if self.view.current == self.view.FRONT:
if self.view.current == self.view.VIEWPORTS["front"]:
self.rotation.set(pi / 2, 0, 0)
if self.view.current == self.view.RIGHT:
if self.view.current == self.view.VIEWPORTS["right"]:
self.rotation.set(pi / 2, 0, pi / 2)

def rotate(self, dx, dy):
Expand All @@ -260,10 +263,10 @@ def rotate(self, dx, dy):

Notes
-----
Camera rotations are only available if the current view is a perspective view (``camera.view.current == camera.view.PERSPECTIVE``).
Camera rotations are only available if the current view is a perspective view (``camera.view.current == camera.view.VIEWPORTS["perspective"]``).

"""
if self.view.current == self.view.PERSPECTIVE:
if self.view.current == self.view.VIEWPORTS["perspective"]:
self.rotation += [-self.rotation_delta * dy, 0, -self.rotation_delta * dx]

def pan(self, dx, dy):
Expand Down Expand Up @@ -323,7 +326,7 @@ def projection(self, width, height):

"""
aspect = width / height
if self.view.current == self.view.PERSPECTIVE:
if self.view.current == self.view.VIEWPORTS["perspective"]:
P = perspective(self.fov, aspect, self.near * self.scale, self.far * self.scale)
else:
left = -self.distance
Expand Down
15 changes: 6 additions & 9 deletions src/compas_view2/views/view.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import time
from OpenGL import GL

from OpenGL import GL
from qtpy import QtCore
from qtpy import QtWidgets

from compas_view2.scene import Camera
from compas_view2.objects import GridObject
from compas_view2.scene import Camera


class View(QtWidgets.QOpenGLWidget):
Expand All @@ -19,23 +19,20 @@ class View(QtWidgets.QOpenGLWidget):
The view configuration.
"""

FRONT = 1
RIGHT = 2
TOP = 3
PERSPECTIVE = 4
VIEWPORTS = {"front": 1, "right": 2, "top": 3, "perspective": 4}

def __init__(self, app, view_config):
super().__init__()
self.setFocusPolicy(QtCore.Qt.StrongFocus)
self._opacity = 1.0
self._current = View.PERSPECTIVE
self._current = self.VIEWPORTS[view_config["viewport"]]
self.shader_model = None
self.app = app
self.color = view_config["background_color"]
self.mode = view_config["view_mode"]
self.mode = view_config["viewmode"]
self.selection_color = view_config["selection_color"]
self.show_grid = view_config["show_grid"]
self.camera = Camera(self)
self.camera = Camera(self, **view_config["camera"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also to my point earlier, view_config could be interpreted as "viewing the config" (action + subject). it is clearer what is meant when viewconfig is used, in my opinion...

self.grid = GridObject(1, 10, 10)
self.objects = {}
self.keys = {"shift": False, "control": False, "f": False}
Expand Down
11 changes: 5 additions & 6 deletions src/compas_view2/views/view120.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
from OpenGL import GL

# from PIL import Image

import os

import numpy as np
from OpenGL import GL

from compas.geometry import transform_points_numpy

from compas_view2.objects import BufferObject
from compas_view2.objects import TextObject
from compas_view2.objects import VectorObject
from compas_view2.shaders import Shader

from .view import View

# from PIL import Image


class View120(View):
"""View widget for OpenGL version 2.1 and GLSL 120 with a Compatibility Profile."""
Expand Down Expand Up @@ -120,7 +119,7 @@ def sort_objects_from_viewworld(self, viewworld):

def paint(self):
viewworld = self.camera.viewworld()
if self.current != self.PERSPECTIVE:
if self.current != self.VIEWPORTS["perspective"]:
self.update_projection()

# Draw instance maps
Expand Down
Loading