[Contents] [TitleIndex] [WordIndex

Handle Rendering

Short Version

Each handle is associated with a C++ object whose only aim is to display the handle. This object contains a function display which is called each time the handle needed to be drawn. This function uses the handle properties and render the handle on the screen with JOGL.

Detailled version


The two main classes here are the sciPointObj and the DrawableObject. The sciPointObj is the memory representation of a graphic handle and is C code. The DrawableObject is a class whose only aim is to display the sciPointObj to which it is attached. There is many kinds of DrawableObjects, actually as many as there are kinds of graphic handles.

Description of the DrawableObject

The main function of a DrawableObject is the display function which prints the graphic representation of the handle on the screen. This function only results in a call of one of the 3 following functions depending on the context.

This function is called the first time the handle is displayed on the screen or just after a modification on the handle. Typically it will set up some flags, cache data for later use and then display the handle. With OpenGL for example, it will typically create one or several display lists and display them.

With the JOGL driver, there is a special case. Since resizing a GLJPanel destroys the OpenGL context (including display lists), a resize events is forcing a call to draw all the handles within the figure. This behaviour could be improved since except from OpenGL data, other cached data could still be used and don't need to be updated.

This function is called for the display following when a frist draw as already been made. The call to this function should be faster than draw since it used cached data. With OpenGL for example, it will call the display lists.

This function has been added later to increase speed. This function is called instead of show when the handle parent subwindow has been modified. For most of graphic entities it is mapped on a call to show. However, it is requiered for objects which are displayed in pixel coordinates. This is because their relative positions are modified each time the viewpoint is modified.

The choice between draw, show and redraw is automatically set up by the call of the following functions:

This function is called by the handle management part when the handle is modified. When called, it update the DrawableObject by recreating its internal structure and set up a flag so the next display will be a call to draw.

This function is automatically called when the parent subwin of a handle is modified. It does not update the DrawableObject, but the next display will call redraw.

To improve rendering speed we added some fast functions to avoid calling draw when a handle is just translated:

This function is called from the handle management part when the handle is moved by a certain vector [Tx,Ty,Tz]. Although the handle has been modified the next display will call either show or redraw and add an additional translation. This translation is made during the display by a call to the translate method.

This function is called when one or several move has been called. It is done in addition with a show or redraw.

This function is called to restore the state before the call to translate.

This function is automatically called by the draw function to remove any recorded translation. Translation is no longer needed since all the cached data have been updated using new positions.

The two functions initializeDrawing and endDrawing are called at the beginning and the end of the draw and redraw functions. They depend on the kind of object to draw and are driver related.

The function displayChildren calls the display function on all the children of an object.

The function checkVisibility just tells if an object is visible or not.

Description of DrawableClippedObject

This object defines two functions clip and unclip which enable or disable clipping for a handle. The clip bounds are automatically computed by the setClipBox function.

Description of the factory

The factory creates the right DrawableObject for a handle with its create function. User should not call this function directly, the creation of DrawableObject is automatic. The update function is called when some of the handle data have been modified. It updates the internal structure of DrawableObject. Partically, the update function is called the next display after a call to hasChanged.

Description of the bridge

The bridge pattern goal is to separate the driver dependent routines from the graphic algorithms. All the needed functions which draw some shapes on the screen are defined in some interfaces. The top one of these interfaces is the DrawableObjectBridge. It contains all the routines of the DrawableObject class which are driver dependent such as translate or initializeDrawing. Since refinements of DrawableObject also use driver dependent routines, they also have a driver related counterpart such as DrawableClippedObjectBridge. Finally there is olny one DrawableObjectBridge instance for any DrawableObject. The implementation of the bridges is depending on the driver such a OpenGL, VTK, ... In our case it is JOGL. The implementations are basically named DrawableObjectJOGL or DrawableClippedObjectJOGL.

An example DrawableSegs


The class DrawableSegs defines 3 functions drawSegs, showSegs and redrawSegs. These three functions only display the segs handle without caring about clipping, visibility,... The function getBoundingBox is needed by the handle management part to modify the axes bounds while creating the handle.

The class ConcreteDrawableSegs implements the drawSegs, showSegs and redrawSegs methods. The drawSegs scheme is simple, decompose the handle into a set of couple of points, each couple defining an arrow. However the decomposition is not straitghtforward and two cases appear. The segs handle can either be a segs handle or a champ handle. Each one has a different kind of storage for arrow positions. Then different algorithms are used to compute the set of couple of points. Two easily choose beteween each algorithm, the strategy pattern is used. A set of functions that the algorithm must provide is defined in an interface DecomposeSegsStrategy. There are two implementation, one for each kind of handle.

Although the display of the handle is driver related, it is not located in the DrawableSegsJOGL class, it is rather in DrawSegsStrategy. Actually, there are three ways to represent the segs handle, using lines, arrows or marks. To switch between the three a strategy pattern is also used. Depending on the handle properties, one or more DrawSegsStrategies are added for display. The DrawSegsStrategy interface also acts as a bridge, its implementations actually drawing each part of the handle.

We may notice here maybe an error in conception ,the class DrawableSegsJOGL is almost useless and the problem also happens for the other handles whose display relies on strategies.

To create the right classes and add them to the ConcreteDrawableSegs the factory is also used here. The update method of the DrawableSegsFactory is recreating the right classes each time the handle is modified.

All DrawableObjects have a m_pDrawed field which is a pointer on the sciPointObj they draw. In the sciPointObj there is a void * pointer pointing on ... an other pointer. This last pointer is the one actually pointing on the DrawableObject. Why two pointers? Because of polymorphism. It is actually not possible to cast a polymorph class on a void *. That's why we need an intermediate pointer which allows polymorphism. However, the DrawableObject is created automaticallu automatically. If access to a DrawableObject associated to a sciPointObj is needed, the file getHandleDrawer.h gives all the needed accesses.

2022-09-08 09:27