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 10 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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added


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


### Changed

* 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,
"view_mode": "shaded",
"background_color": [1, 1, 1, 1],
"selection_color": [1.0, 1.0, 0.0],
"view_port": "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
4 changes: 2 additions & 2 deletions docs/examples/control/example_custom_keys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Custom Keys
:nosignatures:

Default Keys
===========
=============

By default, the keys are like:

Expand All @@ -18,7 +18,7 @@ By default, the keys are like:


Custom Keys
===========
=============

You can customize the keys by modifying the ``keys`` parameter of the configuration.

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/tutorial_basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ use the "on" decorator (:meth:`compas_view2.app.App.on`) on a callback function.


Zoom, Pan, Rotate, and Select
=================
===========================
ZacZhangzhuo marked this conversation as resolved.
Show resolved Hide resolved
tomvanmele marked this conversation as resolved.
Show resolved Hide resolved

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

Expand Down
6 changes: 3 additions & 3 deletions docs/tutorials/tutorial_configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Thinking of the ``options`` in :mod:`Rhino` , the ``preferences..`` in :mod:`Ble


Customize Your Viewer
===================
=====================

There are two ways to customize your viewer:

Expand Down Expand Up @@ -65,7 +65,7 @@ This is a quick way to customize your viewer. It is suitable for task-specific c


Configuration Structure
====================
========================================
The default configuration file can be downloaded here: :download:`Link <files/config_default.json>`,
or can be printed by the following code:

Expand All @@ -78,7 +78,7 @@ or can be printed by the following code:
It it the template for creating your own settings, keyboard preferences, etc.

Supported Keys
===============
===================
In the `controller -> keys`, you can add you preferred keys. Currently, :mod:`compas_view2` supports below keys:

.. figure:: /_images/keyboard.png
Expand Down
6 changes: 3 additions & 3 deletions docs/tutorials/tutorial_software_concepts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@ to help you better the design concepts behind it.


Software Architecture
===========
======================

.. figure:: /_images/software_concept.png
:figclass: figure
:class: figure-img img-fluid


UI Components
===========
===============
.. figure:: /_images/UI.PNG
:figclass: figure
:class: figure-img img-fluid

Configuration Structure
===========
===========================
.. figure:: /_images/config_structure.png
:figclass: figure
:class: figure-img img-fluid
2 changes: 1 addition & 1 deletion requirements-dev.txt
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

pin the sphinx version, related to compas-dev/compas_invocations@067a873

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ m2r2
nbsphinx
pydocstyle
pytest
sphinx == 7.1.2
sphinx >=3.4, <=7.1.2
sphinx_compas_theme >=0.15.18
ZacZhangzhuo marked this conversation as resolved.
Show resolved Hide resolved
twine
wheel
Expand Down
11 changes: 10 additions & 1 deletion 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 @@ -14,8 +14,17 @@
"view": {
"show_grid": true,
"view_mode": "shaded",
"view_port": "PERSPECTIVE",
Copy link
Member

Choose a reason for hiding this comment

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

personally, i would not add an underscore in keys like these. you could consider "viewmode" and "viewport" as one word. "show_grid" is different in that sense...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes. I didn't find the naming conversions for the configuration / .jason file so I named it this way. All the items in this file, including some long words, like enable_propertyform, flow_view_size, zoom_selected, view_perspective, background_color, and selection_color, then need to be changed. Shall we decide fixing them all?

We could create a separate PR/Issue for this

"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.VIEW_PORTS["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.VIEW_PORTS["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.VIEW_PORTS["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.VIEW_PORTS["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.VIEW_PORTS["PERSPECTIVE"]:
self.rotation.set(pi / 4, 0, -pi / 4)
if self.view.current == self.view.TOP:
if self.view.current == self.view.VIEW_PORTS["TOP"]:
self.rotation.set(0, 0, 0)
if self.view.current == self.view.FRONT:
if self.view.current == self.view.VIEW_PORTS["FRONT"]:
self.rotation.set(pi / 2, 0, 0)
if self.view.current == self.view.RIGHT:
if self.view.current == self.view.VIEW_PORTS["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.VIEW_PORTS["PERSPECTIVE"]``).

"""
if self.view.current == self.view.PERSPECTIVE:
if self.view.current == self.view.VIEW_PORTS["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.VIEW_PORTS["PERSPECTIVE"]:
P = perspective(self.fov, aspect, self.near * self.scale, self.far * self.scale)
else:
left = -self.distance
Expand Down
13 changes: 5 additions & 8 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
VIEW_PORTS = {"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.VIEW_PORTS[view_config["view_port"]]
self.shader_model = None
self.app = app
self.color = view_config["background_color"]
self.mode = view_config["view_mode"]
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.VIEW_PORTS["PERSPECTIVE"]:
self.update_projection()

# Draw instance maps
Expand Down
Loading