geoptics.guis.qt package

Package contents

Qt backend.

Interface with IPython

And at the ipython3 prompt, %gui qt5 has to be issued, otherwise the command line is stuck until the window is closed.

So, starting from a shell:

ipython3

And from the ipython command line:

%load_ext autoreload
%autoreload 2      # for debugging purposes, reload modules if changed
%gui qt5            # mandatory, before %run, otherwise blocked
%run t_geo         # runs the t_geo.py script

sip API

In python3, sip.setapi('QVariant', 2) is default, so that any Qt method that returns a QVariant will return a python type instead.

This means that no new_pos = value.ToPoint() are needed anymore. Just use new_pos = value directly.

Do not use QString, this is deprecated. we use sip.setapi('QString', 2)

cf. http://stackoverflow.com/a/22184911/3565696

Beware that with sip.setapi('QVariant', 2), there is a caveat when using QSettings. in a nutshell, we must use the type= keyword argument for value()

cf. Support for QSettings

Architecture

_images/UML_Polycurve.svg

elements/gui relationships

When working with a guis.qt.scene.Scene, either on the command line or from the gui, only the gui class qt.regions.Polycurve instance exist. There is no pure elements.regions.Polycurve instance at all.

The gui class qt.regions.Polycurve inherits from elements.regions.Polycurve. Methods that could lead to round trips are overloaded, and just call a method of qt.regions._GPolycurve with the same name, prefixed with g_. At this point, everything looks like a direct modification to the Qt part only.

All qt.regions._GPolycurve methods act on the Qt items, eventually triggering a call to the corresponding elements.regions.Polycurve method, never to qt.regions.Polycurve methods.

Here is an example of such a call: elements.regions.Polycurve.translate(self.e, …). In this call, self is the _GPolycurve, self.e is a property yielding the corresponding qt.regions.Polycurve instance.

Advantages of such a layout are

  • Imperative style programming. Commands are excuted immediately, and only once.

  • There are no round trips (element => gui => element => …)

  • It is possible to exploit fully the QGraphicsView framework for items selection and movement. It is is actually what settled this choice in the beginning.

    Changing to a model-observer pattern or model-view-controller would involve a rewrite of the items displacement. For instance the gui would take only the mouse movements, and transmit them to the controller.

Some disadvantages of the current layout are

  • need for Scene.class_map (explained later). But maybe this could fit well with plugins.

  • foreseen issues for multithreaded operations. But the display is currently quite fast, with room for optimisations; multithreads are perhaps not worth the trouble.

Whether advantages dominate is not clear at the moment, but here it is. Forks are welcome.

Submodules

geoptics.guis.qt.counterpart module

Graphical counterpart to elements.

See also

The purpose is described in the Architecture section.

class geoptics.guis.qt.counterpart.GOverload(*names)[source]

Bases: object

Decorator factory.

Used to make the interface class cls (which inherits from element) call _G<cls> methods instead.

Parameters:

*names – names (str) of methods to be overloaded

Returns:

decorator, which effectively replaces each call to <cls>.<name>(self, ...) with _G<cls>.g_<name>(self.g, ...)

Note

_G<cls> must be in the same module as <cls>

Example

# in guis.qt.regions
class _GPolycurve(...):
        ...
        def g_translate(...):
                ...


@GOverload("start", "add_line", "add_arc", "close", "translate")
class Polycurve(elements.regions.Polycurve):
        ...


# in ipython, create a region with qt gui interface
r = guis.gt.sources.Polycurve(...)

# the following will call
# guis.gt.sources._GPolycurve.g_translate(r.g, ...)
# instead of the normaly inherited
# elements.regions.Polycurve.translate(self, ...)
r.translate(...)
__call__(cls)[source]

Overload the cls methods with wrappers to graphical methods.

geoptics.guis.qt.counterpart._g_overload(cls, names)[source]

Add overloading methods.

Parameters:
  • cls (class) – the class to add methods to

  • names (list of str) – names of the methods of element that should be overloaded with wrappers to g_<name> methods

Returns:

The modified class

geoptics.guis.qt.counterpart.g_counterpart(original_class)[source]

Enhance a graphical class to be a counterpart to an element.

Add element to the __init__ keyword arguments. Add the .e property to access the element.

Note

This function is intended to be used as a decorator. Decorators should be commutative. Hence element is a keyword - not positional - argument.

geoptics.guis.qt.handles module

Handles to control elements in the guis.qt backend.

Currently handles are always naturally related to another Qt item. This item should be the handle parent. Allowing handles without any parent (parent=None) is not implemented yet.

Note

PointHandle derive from a Qt class, and are living in the Qt realm only.

They are not aware of the underlying elements. Hence the Qt self.scene() should be used, instead of self.scene – mind the ().

This simplifies the calls, when PointHandle are created with given parent=. The Qt scene() is inherited from parent, hence no need to add the scene= keyword.

This is not the case for LineHandle that are python objects

class geoptics.guis.qt.handles.LineHandle(line, parent=None, zvalue=1000, **kwargs)[source]

Bases: object

Handle to control a “line”.

That is, control a point and a vector from that point.

Parameters:
  • line (Line) –

  • parent (QGraphicsItem) – the parent for all items composing this handle

property h_p0

Handle for the starting point of the line.

property h_u

Handle for the end of the u vector.

property line_item

Line item, joining the point and the end of the u vector.

p0_moved(x, y)[source]

React to change of the point position.

Parameters:
  • x (float) –

  • y (float) – new position of the point.

reset_move()[source]

Store the initial position, for move restrictions.

setVisible(visible: bool)[source]

Set visibility.

setZValue(zvalue)[source]

Set the z_value.

The zvalue can be that of the item to be controlled. The Qt items composing the LineHandle will be set to z_values 1 or 2 above, to ensure their visibility.

signal_moved

signal emitted when either end of the LineHandle has been moved.

slot args: (Line)

u_moved(dx, dy)[source]

React to change of the vector end position.

Parameters:
  • dx (float) –

  • dy (float) – displacements of the vector end, in view coordinates.

update_line()[source]

Update the line item.

class geoptics.guis.qt.handles.PointHandle(*args: Any, **kwargs: Any)[source]

Bases: QGraphicsEllipseItem

Handle to control a “point”.

Parameters:

relative (bool) –

  • False (default): positions are absolute and in scene coordinates

  • True: positions are relative to the parent, and in view coordinates

Note

Beware that a call to setPos() will emit signal_moved. Hence, call setPos() first, and only then connect to signal_moved.

ignore_move_restrictions

ignore move restrictions ? Initially True so that the first move, to the initial position, is free The user is responsible for setting it back to False, to honor the scene setting

itemChange(change, value)[source]

Overload QGraphicsEllipseItem.

reset_move()[source]

Store the initial position, for move restrictions.

setPos(*args)[source]

Overload QGraphicsEllipseItem.

signal_moved

Signal to be emitted when the PointHandle is moved.

slot args: (dx, dy), where dx and dy are displacements along x and y, in scene coordinates.

signal_selected_change

Signal emitted when an ItemSelectedChange occurs.

slot args: (boolean)

geoptics.guis.qt.main module

geoptics.guis.qt.rays module

Rays for the guis.qt backend.

class geoptics.guis.qt.rays.Ray(line0=None, s0=100, source=None, n=None, tag=None, zvalue=100, **kwargs)[source]

Bases: Ray

Ray of light.

This is the Ray that should be instanciated, in the guis.qt backend.

Note

Regular users should not use Ray directly, but instead use one of the sources in qt.sources.

__del__()[source]

Cleanup upon deletion.

add_part(*args, g_func=<function _GRay.g_add_part>, **kwargs)

Same as geoptics.elements.rays.Ray.add_part

Overloaded to call _GRay.g_add_part(self.g, ...)

change_s(*args, g_func=<function _GRay.g_change_s>, **kwargs)

Same as geoptics.elements.rays.Ray.change_s

Overloaded to call _GRay.g_change_s(self.g, ...)

draw(*args, g_func=<function _GRay.g_draw>, **kwargs)

Same as geoptics.elements.rays.Ray.draw

Overloaded to call _GRay.g_draw(self.g, ...)

property g

Return the corresponding graphical item.

class geoptics.guis.qt.rays._GRay(**kwargs)[source]

Bases: QGraphicsPathItem

The graphical class corresponding to Ray.

property e

The corresponding element.

g_add_part(u, s, n=None)[source]
g_change_s(part_number, new_s)[source]
g_draw()[source]
hoverEnterEvent(event)[source]

Overload QGraphicsPathItem method.

hoverLeaveEvent(event)[source]

Overload QGraphicsPathItem method.

isSelected()[source]

Overload QGraphicsPathItem method.

itemChange(change, value)[source]

Overload QGraphicsPathItem method.

paint(painter, option, widget=None)[source]

Overload QGraphicsPathItem method.

setSelected(selected)[source]

Overload QGraphicsPathItem method.

shape()[source]

Overload QGraphicsPathItem method.

geoptics.guis.qt.regions module

Regions for the guis.qt backend.

class geoptics.guis.qt.regions.Polycurve(n=None, scene=None, tag=None, zvalue=0, **kwargs)[source]

Bases: Polycurve

Define a region inside curves (for instance line segments).

Parameters:

scene (Scene) – to belong to.

add_arc(*args, g_func=<function _GPolycurve.g_add_arc>, **kwargs)

Same as geoptics.elements.regions.Polycurve.add_arc

Overloaded to call _GPolycurve.g_add_arc(self.g, ...)

add_line(*args, g_func=<function _GPolycurve.g_add_line>, **kwargs)

Same as geoptics.elements.regions.Polycurve.add_line

Overloaded to call _GPolycurve.g_add_line(self.g, ...)

close(*args, g_func=<function _GPolycurve.g_close>, **kwargs)

Same as geoptics.elements.regions.Polycurve.close

Overloaded to call _GPolycurve.g_close(self.g, ...)

start(*args, g_func=<function _GPolycurve.g_start>, **kwargs)

Same as geoptics.elements.regions.Polycurve.start

Overloaded to call _GPolycurve.g_start(self.g, ...)

translate(*args, g_func=<function _GPolycurve.g_translate>, **kwargs)

Same as geoptics.elements.regions.Polycurve.translate

Overloaded to call _GPolycurve.g_translate(self.g, ...)

class geoptics.guis.qt.regions._GPolycurve(**kwargs)[source]

Bases: QGraphicsPathItem

Graphical class corresponding to Polycurve.

Note

_G* objects are living in the Qt realm only.

They are not aware of the underlying elements. Hence the Qt self.scene() should be used, instead of self.scene() – mind the ().

Note

when about to change the pos() of this item, e.g. before a setPos() of a translate(), first issue a reset_move()

property e

The corresponding element.

g_add_arc(M_next, tangent)[source]
g_add_line(M_next)[source]
g_close()[source]
g_start(M_start)[source]
g_translate(v=None, dx=0, dy=0)[source]
hoverEnterEvent(event)[source]

Overload QGraphicsPathItem.

hoverLeaveEvent(event)[source]

Overload QGraphicsPathItem.

itemChange(change, value)[source]

Overload QGraphicsPathItem.

reset_move()[source]

Reset the move machinery.

Should be called at the beginning of a new move. Store the initial position. This is important to be able to constraint moves along a particular direction (move restrictions on).

setSelected(selected)[source]

Overload QGraphicsItem.

geoptics.guis.qt.scene module

Scene to be used with the Qt gui.

class geoptics.guis.qt.scene.Scene(**kwargs)[source]

Bases: Scene

The Scene that should be instanciated by user, in the guis.qt backend.

add(other, tag=None)[source]

Add an element to the scene.

Parameters:

other (dict or element) – the element to be added, either as a config dictionnary, or directly as an object such as guis.qt.sources.Beam or guis.qt.regions.Polycurve

class_map

correspondance between names in config data, and classes

remove(element)[source]

Remove the element from scene.

class geoptics.guis.qt.scene._GScene(**kwargs)[source]

Bases: QGraphicsScene

The graphical class corresponding to Scene.

Parameters:

element (Scene) – The corresponding element

See also

More informations on the relationships between Scene and _GScene can be found in the Architecture section.

property active_view

Get current active view.

addItem(item)[source]

Overload QGraphicsScene method.

property e

The corresponding element.

keyPressEvent(event)[source]

Handle key pressed events.

  • Delete: remove selected items

  • ESC: deselect all

mouseMoveEvent(event)[source]

Overload QGraphicsScene method.

mousePressEvent(event)[source]

Overload QGraphicsScene method.

mouseReleaseEvent(event)[source]

Overload QGraphicsScene method.

move_restrictions_on

Whether objects moves should be restricted.

move restrictions

Some displacements can be restricted to certain directions. If move_restrictions_on is True, then the displacements are constrained to be along the x or y direction. The actual direction (x or y) should be the closest to the mouse displacement. For instance, if the mouse movement is mainly horizontal, then a PointHandle would move along x only.

This requires to store the initial position, at the beginning of the displacement. This is done by reset_move() slots.

remove(item)[source]

Remove item from both Qt and elements scene.

remove_selected_items()[source]

Remove selected items from scene.

signal_element_moved
signal_mouse_position_changed
signal_remove_selected_items
signal_reset_move
signal_set_all_selected

geoptics.guis.qt.signal module

Signal for non-QObjects.

class geoptics.guis.qt.signal.Signal[source]

Bases: object

Only QObject can send signals.

We need this trick for GraphicsItems taken from http://stackoverflow.com/questions/21101500/custom-pyqtsignal-implementation

see also http://abstractfactory.io/blog/dynamic-signals-in-pyqt/

a priori the only problem is that it can’t be used across threads

Note

Contrary to pyqtSignal, a new Signal instance must be created for each object instance, otherwise signals would be mixed up between instances.

Hence the correct place is in the __init__ function:

def __init__(self):
        self.signal_name = Signal()
connect(func)[source]

Connect a function (a “slot”) to this signal.

disconnect(func)[source]

Remove a slot from this signal.

emit(*args, **kwargs)[source]

Emit signal.

This calls all connected slots with the emit arguments.

geoptics.guis.qt.sources module

Sources of light rays for the guis.qt backend.

class geoptics.guis.qt.sources.Beam(line_start=None, s_start=None, line_end=None, s_end=None, N_inter=0, scene=None, tag=None, zvalue=100, **kwargs)[source]

Bases: Beam

Beam source.

This is the Beam that should be instanciated by user, in the guis.qt backend.

class geoptics.guis.qt.sources.SingleRay(line0=None, s0=None, scene=None, tag=None, zvalue=100, **kwargs)[source]

Bases: SingleRay

Single ray source.

This is the SingleRay that should be instanciated by user, in the guis.qt backend.

class geoptics.guis.qt.sources._GBeam(element=None, zvalue=100, **kwargs)[source]

Bases: _GSource

The graphical class corresponding to Beam.

Parameters:

(class (element) – .Beam): the corresponding element.

change_line_end(line)[source]
change_line_start(line)[source]
isSelected()[source]

Overload QGraphicsItem.

reset_move()[source]
setSelected(selected)[source]

Overload QGraphicsItem.

class geoptics.guis.qt.sources._GSingleRay(element=None, zvalue=100, **kwargs)[source]

Bases: _GSource

The graphical class corresponding to SingleRay.

Parameters:

element (SingleRay) – the corresponding element.

change_line_0(line)[source]
isSelected()[source]

Overload QGraphicsItem.

reset_move()[source]
setSelected(selected)[source]

Overload QGraphicsItem.

class geoptics.guis.qt.sources._GSource(zvalue=100, **kwargs)[source]

Bases: QGraphicsItem

The corresponding graphical class to sources.

Parameters:

element (Source) – a source element belonging to guis.qt.sources, such as guis.qt.sources.Beam.

boundingRect()[source]

Overload QGraphicsItem method.

property e

The corresponding element.

itemChange(change, value)[source]

Overload QGraphicsItem method.

shape()[source]

Overload QGraphicsItem method.

geoptics.guis.qt.view module

View displaying the scene.

class geoptics.guis.qt.view.GraphicsView(**kwargs)[source]

Bases: QGraphicsView

Scene holder.

enterEvent(event)[source]

Overload QGraphicsView method.

map_vector_from_scene(u_scene_x, u_scene_y)[source]

Map a vector given in scene coords to view coords.

map_vector_to_scene(u_view_x, u_view_y)[source]

Map a vector given in view coords to scene coords.

mouseMoveEvent(event)[source]

Overload QGraphicsView method.

mousePressEvent(event)[source]

Overload QGraphicsView method.

mouseReleaseEvent(event)[source]

Overload QGraphicsView method.

scale_view(scale_factor)[source]

Zoom in or out.

wheelEvent(event)[source]

Ctrl+mouse wheel zoom, otherwise pan.

class geoptics.guis.qt.view.GraphicsViewFrame(view=None, **kwargs)[source]

Bases: QFrame

Frame containing the view and related widgets.

position_indicator

PositionIndicator

property view

GraphicsView.

class geoptics.guis.qt.view.PositionIndicator(**kwargs)[source]

Bases: QLabel

Displays an x,y position.

on_changed_position(x, y)[source]

Update the display to the given x, y position.