Specificities for each handle
This handle is different from the other since it is mostly build using the GUI API (Swing) and not only JOGL. It corresponds to the graphic tab and the canvas used for rendering. Consequently, many of its properties are not stored in the sciPointObj but rather in the Java World. Here is the representation of the figure:
Interface with the Handle Management part
The function forceDisplay force an update of the whole figure. It should be called from the Scilab thread. The function drawSingleObjs is similar but only display a subset of the hierarchy. Both functions will actually call the display functions of the GLJPanel.
Interface with the Java Part
It is done in the FigureScilabCall.cpp file, from the OpenGL thread. Normally, for a standard redraw, only the display function is called. However, if the size changed the redrawSubwins is called and if a total reinitialization of the canvas has been done, the familyHasChangedFunction are also called.
There is actually only the draw function which is used in display. It is pretty simple, since it just draw the background of the canvas and draw the requested children (depending wether the drawSingleObjs or forceDisplay functions where called.
Theses functions are only a bridge between Scilab and the Java tab or canvas properties.
We've got here the function to call the rubber box on the screen and the one used to track the mouse movements for the rotations.
The openRenderingCanvas and closeRenderingCanvas are the functions which actually create the Java components of the figure. The openRenderingCanvas is not in the constructor of the class but rater in the factory since it needed that all the object composing the bridge are set. The showWindow function make the window visible and raise it on the foreground.
This is the more complex handle of Scilab, it contains two tricky parts, the camera and the ticksDrawing.
The camera class is used place a subwindow on the canvas (using margins and axes bounds), set the scaling (using isoview, cube scaling) and set up the view point (using rotation angles). It is also used to perform 3D to pixel coordinates changes. There is two kinds of Cameras, one for the normal mode and one for the isoview mode.
The set up of the camera relies on the call of OpenGL commands (such as glTranslate, glOrtho,...). When the camera is set up, the OpenGL projection matrix is copied into the CameraJOGL instance. Afterwards, all the coordinates changes rely on the projection matrix. For example the pixel coordinate p1 of a 3D point p0 is p1 = P.p0 where P is the projection matrix. We also need the inverse change, and that's why the inverse of the projection matrix is also stored. Similarly, to provide compatibility with previous versions, there is also to possibilty to project on the default 2D plane. That's why there are 2 other matrices one for each change.
The use of OpenGL simplifies the set up of the camera. However, it implies that the set up must be performed on the OpenGL thread. Consequently, a redraw or at least a synchronization with the OpenGL thread might be needed before a coordinates change. The problems occurs in drawlater mode since the subwin is never displayed. In this case when a coordinate change is requested, there is a special display function which only update the camera and does not modify the canvas.
I think this behavior might be improved by computing directly the matrices from the Scilab thread and send them when needed to the Camera using glLoadMatrix as in showCamera. The transformations performed by the OpenGL functions can be found on their man pages so it should not be hard to compute the matrix from outside OpenGL (but tedious :().
There is an other tricky part in the Camera which can be found on any OpenGL application is the setting of front and clipping planes. It's mandatory to have them both otherwise depth test could not work. To get usable values, I first set up the camera using some default values for the planes. When all is set up, I compute the depth range used by the axes box. It then give an idea of what can be the actual needed depth range.
Ticks drawing is also a tricky part, however it is common to every axes. It can draw the ticks for one of the X, Y or Z axis but also an other axis created with a Axis handle. The ticks algorithm can be decomposed as follow:
- Getting the axis position and ticks direction.
First we search the axis segment on which the ticks will be drawn against. This is done using an AxisPositioner object.
- Getting ticks
The position of ticks on the Axis segment are computed. This is done using a ComputeTicksStrategy object.
- Getting subticks
Once the ticks have been computed, the positions of all the subticks along the Axis segment are computed. This is done using a ComputeSubTicksStrategy object.
- Draw ticks.
In some modes the ticks and subticks previously computed are directly drawn on the screen with JOGL. However in some other modes, the number of ticks might be reduced in order to prevent labels from overlapping. In both cases the ticks and subticks are sent to JOGL for rendering. In the second case, a check is performed before to find whether the can be render or if then number of ticks should be reduced. If the test fails (drawTicks returning a negative value), then a new set of ticks and subticks is computed until the test pass. As you may notice the drawticks function returns a double. This is a distance used to set the position of the axis label handle (X, Y or Z). The nice thing here is that there is only one kind of drawer since the decomposition is in the previous steps.
- Draw grid
Since grid lines are drawn in front of ticks and then very dependent on ticks drawing, grid drawing is included in within the function. The AxisPositioner class is used to get the position of each grid lines and the GridDrawer one draw them.
Unfortunately, OpenGL is only able to perform affine transformations (transaltions, scale, rotations,...) and logarithmic scale is not such a transformation. Consequentely, it must be emulated. Actually, the transformation is pretty straightforward. Before sending 3D points for display (in Java), only the log10 function must be applied to the coordinates.
However, to make the transformations as easy as possible and avoid to multiply conditional such as if (logOnXaxis) then ... else ... end, if (logOnYAxis) ... a function was created inside theDrawableObject class to hide the complexity. This is the pointScale function, which automaticaly transform its input data into data which can be used for display (with logarithmic scale applied as needed). The inverse function inversePointScale is also sometime needed.
The array versions of the above functions are faster than the ones working only on a point and should be used if possible.
Although the pointScale and inversePointScale functions are located in the DrawableObject they are just gateway for the ones redefined inside the DrawableSubwin class. These are the actual functions which perform the conversion.
Unlike other objects, texts objects are not only displayed, it is also needed to get their bounding boxes. Consequently they contain functions which retrieve the bounding box and that can be accessed from the HandleManagement part. Since draw and redraw functions also needs the bounding box, it is updated during each display circle. While the text objects is not modified, the values are up to date and can be use directly. This avoid extra computation each time the bounding box is needed. However, specially in drawlater mode, it is needed to update the bounding from the Scilab thread. Fortunately, with JOGL, it is not mandatory to be on the OpneGL thread in order to retrieve the bounding box.
Text also have 3 display modes depending on the handle property text_box_mode. The "off" one is the standard mode the text being display just above its position. With the "centered" mode, the text is displayed in the middle of a the rectangle defined by the text_box property. With the "filled" mode, the most tricky one, the text is also displayed in the center of a rectangle but its font size is modify in order to fill the rectangle.