Getting Started Documentation Glish Learn More Programming Contact Us
Version 1.9 Build 1556
News FAQ
Search Home


next up previous contents
Next: The Glish Connection Up: NOTE 231 - All About the AIPS++ Display Previous: Overview

Subsections


Display Library Components

The Display Library is written in C++, and makes extensive use of the basic object-oriented design concepts of encapsulation, inheritance and polymorphism. The Library is built upon the existing AIPS++ classes, and a sound knowledge of the Array, Lattice and Mathematics classes in particular is recommended before approaching the following sections.

PixelCanvasColorTables and Colormaps

Since color plays an important role in visualisation of scientific data, it is important to provide flexible ways to allocate and use colors within the Display Library. To this end, a layered approach to colors has been adopted, wherein one class - the PixelCanvasColorTable (for brevity, the ColorTable) - is primarily concerned with acquiring and managing blocks of color cells from the underlying hardware, and a second class - the Colormap - is mostly concerned with generating sets of colors to be installed in the color cells managed by one or more ColorTable objects. The key to understanding color in the Display Library is to understand the interaction between these two classes, and to more or less ignore the hardware-dependent aspects of the ColorTable class.

The PixelCanvasColorTable class provides dynamic color cell allocation functionality, using primitive routines appropriate to the device in use. For each display device provided by the Display Library, there must be an implementation of the PixelCanvasColorTable class. Upon construction a ColorTable determines the color-specific capabilities of the display device, and where appropriate, acquires control of some number of the device's color cells.2 The number of color cells controlled by the ColorTable should be dynamic (where possible), and under the control of the programmer and thereby the user.

In use, the role of the ColorTable is to dynamically allocate space out of its own set of color cells to one or more registered Colormaps. A Colormap provides a series of colors, on demand, which can be used to fill a series of vacant color cells provided by a ColorTable. Typically, such a set of colors would be used to represent a range of data values, where the minimum data value is mapped to the first color cell, the maximum value to the final color cell, and all other values to cells within the available range.

The interaction between, and division of responsibilities between, ColorTables and Colormaps is important. One or more ColorTables can be constructed for a given display device. For example, a screen display device may provide up to 256 colors, and two ColorTables, each initially acquiring 80 colors, could be created for that screen. The dynamic nature of the ColorTables means that once they have been made, they can be expanded or shrunk, provided enough colors are available. For example, the first ColorTable in this example might then be shrunk to 40 colors, and the second expanded to 120 colors.

In a similar way, one or more Colormaps can be registered with a ColorTable. That is, it is possible to register a greyscale Colormap and a rainbow Colormap on the first of our ColorTables above. Initially, they would each soak up 40 colors (since the ColorTable provides 80 colors), but after the shrink operation described above, they would soak up only 20 colors each. See for a pictorial representation of the hardware color resources, the AIPS++ ColorTable and the AIPS++ Colormap. In order that any images using these Colormaps are still drawn correctly on the screen, a series of callback functions are initiated when ColorTables and Colormaps are resized.

Figure 1: The relationship between hardware color resources, AIPS++ ColorTables and AIPS++ Colormaps.

Finally, it is important to stress that in a single application or tool, multiple Colormaps of the same base type can exist. That is, more than one ``rainbow'' Colormap can be generated, and each can be modified independently. Modification might include altering the brightness or contrast, or ``stretching'' the colors in the map. The same Colormap can be registered on more than one ColorTable, and furthermore may occupy a different number of color cells in each ColorTable! Designing an interface which allows the end-user complete control over this extensive flexibility has proven to be challenging however, and only a subset of the capabilities are provided at present.

The PixelCanvas

The PixelCanvas is the fundamental drawing canvas of the Display Library. It provides an agreed-upon set of routines for drawing graphic primitives, for controlling the ``context'' of the drawing operations, for handling interactive events, and for supplying an advanced caching mechanism (where possible). For each hardware drawing device supported by the Display Library (eg. X-Windows, PostScript) there must be a PixelCanvas class which implements the required routines using low-level, device-specific routines.

The graphic primitives of the PixelCanvas include points, lines, polygons, ellipses, and images. Multiple interfaces are provided where convenient and possible3, and these can in some instances be implemented with templated member functions in derived classes. All drawing is done in the native units of the device, and in cases where these units are not pixels - for example, pixels are user-defined in PostScript - the constructor for the device-specific PixelCanvas is expected to offer a method for (arbitrarily and artificially) setting the resolution of the device such that PixelCanvas drawing commands retain their meaning across all devices. Again, the PixelCanvas makes use of encapsulation to conceal device differences, and inheritance and polymorphism to enable the same set of drawing commands to be used on any valid PixelCanvas.

The WorldCanvas

The WorldCanvas implements a higher level of drawing capabilities on top of the PixelCanvas class. Multiple WorldCanvas instances can be constructed on a single PixelCanvas, each drawing on a subset of the entire PixelCanvas. The bulk of the infrastructure provided at the level of the WorldCanvas is concerned with coordinate transformations, so that drawing on a WorldCanvas is accomplished by the programmer in full world coordinates, or in a linear coordinate system which mediates between the pixel coordinate system of the PixelCanvas, and the full world coordinate system of the WorldCanvas. Further facilities include higher-level handling of interactive events, and data resampling and rescaling facilities.

Each WorldCanvas is constructed with reference to a specific instance of a PixelCanvas, and occupies some fraction of the PixelCanvas. The position of the WorldCanvas is dynamically adjustable, and an interface can be imagined in which the user freely positions multiple WorldCanvases across a single PixelCanvas, in order to depict several views of one or more datasets in a form suitable for publication, for example. Overlapping WorldCanvases will ultimately need a ``depth specifier'', so that drawing order can be controlled and preserved by the programmer and/or user.

In terms of graphic primitives, the WorldCanvas essentially replicates those present in the PixelCanvas, and applies coordinate conversions to input positions as necessary.

Events

A major part of the ``glue'' which holds together the many components of the Display Library is the event generation and handling system. At the very lowest level, three fundamental event types are defined: refresh events, motion events and position events. Each of these has a corresponding event handler type, for example a motion event handler is expected to process motion events. Throughout the Display Library, classes and instances of classes can register their interest in events, and implement event handlers which do something in response to a particular event, or pass the event on to another interested party, or both. For each event and event handler (EH), there are classes specific to the PixelCanvas (PC) and WorldCanvas (WC).

Refresh Events

The refresh event mechanism is used to synchronise the display of data to the user. For example, when a parameter is changed in a DisplayData, a refresh event should be generated such that all WorldCanvases displaying that DisplayData are redrawn if necessary. Or, if a PixelCanvasColorTable is physically resized, all PixelCanvases using that ColorTable must be cleared and redrawn.

Any class in the Display Library can register its interest in refresh events in one of the following ways:

Having taken one of the options above, the class need simply then register itself, or its helper class, as an event handler with all potential sources of the event of interest. A specific example is the WorldCanvas class, which wishes to know when its underlying PixelCanvas is resized, so that it can resize itself accordingly. To this end, the WorldCanvas class creates a helper class, called ``WCOnPCRefreshEH'', an instance of which can be registered as a handler of PixelCanvas refresh events, and whose only function is to add World Coordinate information to the event and pass it on to its parent WorldCanvas. The function called on the WorldCanvas can then look at the type of the refresh, and if it is a size change, will then act accordingly.

There are many possible reasons for a refresh event to be generated, and indeed such an event can be generated by any class which allows other objects to register themselves as handlers of refresh events. The types of refresh event are listed in DisplayEnums.h, and include:

Motion and Position Events

A motion event is deemed to have occured when the user moves the mouse pointer (cursor) over an exposed PixelCanvas. The motion event is described by the position of the pointer. A position event is deemed to have occured when the user presses or releases a keyboard button or mouse button while the input focus is on a PixelCanvas. PixelCanvas position and motion events are generated by the low-level device interface for some, but not all, PixelCanvases. For example, an interactive X-Windows PixelCanvas should generate these events, but a non-interactive PixelCanvas such as a PostScript PixelCanvas will have no need to pass on events to higher-level objects.

Objects and classes in the Display Library can register their interest in motion and position events in the same way as they can for refresh events.

Tools

In the C++ Display Library, the term Tool has a meaning quite different to the standard meaning in AIPS++. A tool in the library is a single entity which can react to - and generate - refresh, motion and position events. A specific example is the zooming tool. This tool listens for position and motion events which indicate the user wishes to zoom in on a part of a WorldCanvas. By reacting in a particular way, this tool allows the user to stretch out a rubberband rectangle, adjust its size, and then double-click inside the rectangle. Upon detecting a double-click, the zoom tool sets some new parameters on the WorldCanvas, and then sends a refresh event to the WorldCanvas. In response, the WorldCanvas notices that the coordinates have changed, and redraws itself accordingly. Other tools already implemented include the region tools and Colormap fiddling tools.

DisplayDatas

The DisplayDatas are a very high-level set of classes in the Display Library, and ultimately will be the place where most programming is done in the Display Library. These objects encapsulate data and a drawing method, such that they simply draw their data on demand into a supplied WorldCanvas. The WorldCanvasHolder class (see below) manages a set of DisplayDatas and a single WorldCanvas, and coordinates the refresh cycle of the WorldCanvas so that each DisplayData is drawn in turn.

An example DisplayData is the LatticeAsRaster class. It is constructed with reference to an ImageInterface or an Array, which is registered as the source of the data to be displayed. The LatticeAsRaster class can then be called to draw a depiction of the data on any WorldCanvas, and that depiction happens to simply be a false color pixel map of some subset of the data. The LatticeAsRaster object offers various parameters for the user to tune, including such things as what Colormap to use and how to resample data pixels to screen pixels. These parameters are independent of the display device (ie. the PixelCanvas) and so the DisplayData can be simultaneously displayed on more than one device.

The critical function in a DisplayData implementation is the draw method. This method is called to get the DisplayData to draw itself on the supplied WorldCanvas. A quite sophisticated caching mechanism is now available such that if this WorldCanvas has previously been drawn on by this DisplayData, each in the same state as they were last time, then a cached drawing can be rapidly drawn to the WorldCanvas. To use this caching mechanism, the programmer need simply derive from the special class CachingDisplayData. More on this below.

The WorldCanvasHolder

The WorldCanvasHolder has been touched upon already. Its main task is to manage a single WorldCanvas, and some number of DisplayDatas who are ``registered'' to draw on that WorldCanvas. Consequently, the main activity of the WorldCanvasHolder is to register an interest in refresh events occuring on its ``contained'' WorldCanvas, and upon the occurence of said events to arrange each DisplayData to draw itself in turn. The bulk of the user interface of the WorldCanvasHolder is related to implementing various event handlers for the WorldCanvas, to managing the collection of registered DisplayDatas, and to arranging a set of ``restrictions'' which are used to assist the DisplayDatas in determining what of their data to draw, and how.

The MultiWCHolder and PanelDisplay

Over the period of development of the first Display Library application -- the Viewer (see below) -- it became clear that significant demand existed for the type of display where multiple slices from a multi-dimensional dataset are shown in individual panels forming a grid across the visible surface. This type of display, a PanelDisplay, is common in multi-frequency radio astronomy packages, and is required in AIPS++. One of the most recent additions to the Display Library then, has been the MultiWCHolder and PanelDisplay classes. The first of these is essentially a class which is capable of managing a number of WorldCanvasHolders, and which provides functions to register and unregister DisplayDatas across all the managed WorldCanvasHolders: it is a holder of WorldCanvasHolders.

The PanelDisplay class wraps all this up in a convenient class which creates a set of WorldCanvases and WorldCanvasHolders on a given PixelCanvas according to specifications given in the constructor, creates a MultiWCHolder to manage these WorldCanvasHolders, and which provides convenience functions for registering and unregistering DisplayDatas across the PanelDisplay.

A new Animation tool will need to be written for the MultiWCHolder to provide smart animation whereby the individual slices of data ``march'' across the screen from panel to panel. Further tricky issues have arisen in the development of the multi-panel facilities, and relate mostly to event handling in the case of overlapping, or nearly overlapping, WorldCanvases on a single PixelCanvas. The developer in the future will need to decide whether events should be consumed by the first WorldCanvas asked to process the event, or whether they should instead be processed by all WorldCanvases. The latter solution could create havoc for even simple operations, such as zooming, and needs extremely careful thought. However, this is the current mode of operation...


next up previous contents
Next: The Glish Connection Up: NOTE 231 - All About the AIPS++ Display Previous: Overview   Contents
Please send questions or comments about AIPS++ to aips2-request@nrao.edu.
Copyright © 1995-2000 Associated Universities Inc., Washington, D.C.

Return to AIPS++ Home Page
2006-10-15