Skip to content

Graphics

ilabs-kdc edited this page Feb 28, 2022 · 5 revisions

When using QtGL, which is the default, the python files in ui/qtgl are used. Every python file processes a different part of the graphics interface. For example, gltraffic.py is used to draw the traffic related graphics on the screen and glnavdata.py is used to draw all navigation related graphics (like waypoints, airports, ... etc.). The python files that are used to draw things on the radar screen (the ones that start with gl) all have the same structure, which is explained below. These python files use functionalities from glhelpers.py.

To draw things, the graphics card uses vertices. These are basically just points (vertex) with (screen) coordinates. You can tell the graphics card what is should do with these vertices, which is called the primitive type (e.g. lines, triangles, ... etc.).

To eventually draw things on the screen, OpenGL is used. If you want to learn more about this, you can checkout this website.

Radar screen graphics

Every file that is used to draw things on the radar screen, contains a class (e.g. Traffic(glh.RenderObject, layer=100)). There are basically two important variable types:

  • Buffers: A buffer contains data, which the graphics card need to draw things on the screen (e.g. latitude, longitude, ... etc.).
  • Vertex Array Objects (VAOs): The VAO basically combines all the data that is needed to draw a certain object. So the buffers are used, together with other variables, inside the VAO. One important special type is the Text object, which is used to draw text on the radar screen (e.g. labels).

There are basically four "phases", which are explained below:

  • Initialize: Here the variables are initialized. This looks something like this:
def __init__(self, parent=None):
    super().__init__(parent)
    ...
    # Initialize buffers
    self.buffer_name = glh.GLBuffer()
    ...
    # Initialize VAOs
    self.object_name = glh.VertexArrayObject(PRIMITIVE_TYPE)
    ...
    # Initialize text objects
    self.text_name = glh.Text(text_size, (width, height))
    ...
  • Create: Here the buffers and VAOs are created. This looks something like this:
def create(self):
    ...
    # Create buffers
    self.buffer_name.create(buffer_size, drawing_type)
    ...
    # Create VAOs
    self.object_name.create(vertex=..., color=..., other_attributes)
    # Optionally you can also set some attributes using:
    self.object_name.set_attribs(attribute_1=..., attribute_2=..., other_attributes)
    ...
    # Initialize text objects
    self.text_name.create(text_buffer, other_attributes)
    ...
  • Draw: Here the objects are actually drawn. This looks something like this:
def draw(self):
    ...
    self.object_name.draw()
    ...
    # When an object is instanced, the graphics card uses the same vertices multiple times:
    self.instanced_object.draw(n_instances=...)
  • Update: Here the buffers are updated with new data. How to get the data from the simulation part is explained in the Update section below. In the code, updating buffers would look something like this:
def some_update_function(self):
    ...
    self.buffer_name.update(data)
    ...

glhelpers

The glhelpers.py file contains classes to process the buffers and VAOs. These classes are imported in the other files:

from bluesky.ui.qtgl import glhelpers as glh

Update

To get the data from the simulation part, you can connect a function to the "network" when the class is initialized. This function is often called self.actdata_changed(). In this way this function is called every time when there is new data.

bs.net.actnodedata_changed.connect(self.actdata_changed)

The standard input arguments are:

  • nodeid: The id of the node sending the data.
  • nodedata: The data
  • changed_elems: A list containing the elements that have new data, for example ACDATA or ATCMODE.