
		Short Introduction to the Array Visualizer
		==========================================
			(Stefan Haenssgen, 2-jul-92)


INTRODUCTION:

Often you want to be able to know what is "inside" an array, i.e. how
data is arranged, which values occur, if there are specific patterns
in the data and so on.
    It is quite easy to get this information by simply letting the
program print the array in question. Unfortunately, it is much harder
to interpret the resulting mass of numbers accordingly.
    This is where the Array Visualizer is most useful: by a simple
call, we can really "look" at the data, browse around, get an
impression how values are distributed and also examine specific array
elements.


USER INTERFACE:

The basic idea behind the Visualizer is to look into a multidimensional
array by examining 2-dimensional "slices" (e.g. "leafing" through a
3D cube and observing how the "cross sections" change).
    Different values in the array are mapped onto different shades of
gray in the Visualizer to let the user get an expression how data is
distributed. Alternatively, you can set simple criteria (e.g. "the
values is between 10 and 25") and highlight all array elements that
fulfill the condition.
    When visualizing multidimensional arrays the user can choose which
dimensions are "active" (i.e. mapped onto the pixel display). These
two dimensions are highlighted in their "Dim" buttons. By clicking on
another "Dim" Button you can activate the corresponding dimension.
The viewing position in the remaining dimensions can be adjusted using
scrollbars resulting in a display of the array elements "sliced"
through those dimensions.
    The scrollbars of the two active dimensions are updated automagically
as the user moves the mouse through the array. Zooming in at a certain
point is possible by pressing the left mouse button. Acordingly, the right
mouse button zooms out.
    In the case of a 2-dimensional array, the visualization is straight-
forward. A 1-dimensional array gets mapped onto a 2-dimensional array
as it can be displayed much better that way.

Play around with the demo program to get a feeling for the user interface.


AVAILABLE FUNCTIONS:

There are several ways of using the Visualizer from your program:

In the simplest case, you just call the Visualizer describing the kind
of data and the array you want to display and some information about the
array (see "VisualizeValues").
    Another possiblilty is to set a boolean condition like "array value
is less than 5" and highlight all elements that fulfill this condition.
The user may change the condition and the comparison value interactively
and see how the display changes accordingly (see "Visualize").
    Furthermore, you can use ranges of values (e.g. "-10 to infinity")
to highlight elements that match. In general, ranges are more flexible
than simple comparisons (see "VisualizeRange").
    To provide maximum flexibility, it is even possible to supply user
defined functions to access and compare array data. The result is
displayed depending on those functions (see "VisualizeUserFn").
It is even possible to change the supplied user function dynamically
(see "ChangeUserFn"). Naturally, the interface to those routines is a
bit more complicated :-)

Visualization can be synchronous, where the program stops while the
user examines the data using the Visualizer. Or the Visualizer can be
left running in the backgrund with the option to update its data
by sending a message from the main program to the Visualizer. This
message again can be blocking (the program waits for the Visualizer
to confirm that it has got the new data) or non-blocking.
    The Visualizer features a button marked "S" in the lower left
corner which sends a synchronization signal to the calling program.
This makes stepping through sequences of data changes easier. Of course,
this is only useful in the background operation mode.

To better understand the various ways of using the Visualizer better, take
a look at the demonstration program "testv". It displays a 3-dimensional
cone embedded in a box using different Visualizers.


LIST OF FUNCTIONS:

What follows is a list of the functions available to the user,
together with a small description and some examples:

!!!!!!!!!!!!!
!!!!!!!!!!!!!   MODULA-VERSIONEN
!!!!!!!!!!!!!

 *
 *  VIStype *OpenVisualizer(int x, int y)
 *
 *  Initializes the X Window basics to make further visualization possible.
 *  The return value is later needed for visualization and finally for
 *  "CloseVisualizer()"
 *  "x" and "y" specify the coordinates of the upper left corner of the
 *  Visualizer Window when it appears. If "x" or "y" are less than zero,
 *  the Visualizer will be positioned with user interaction (unless the
 *  user's window manager places windows automatically, anyway).
 *
 *
 *  void CloseVisualizer(VIStype *VIS)
 *
 *  Destroys the X Window basics connected with VIS.
 *  Also kill off background process if there is one.
 * 
 * 
 *
 *  void  Visualize(  VIStype *VIS,
 *                    char    *name,
 *                    ulong    namelen,		/* unsigned long */
 *                    void    *adr,
 *                    int     *dims,
 *                    ulong    numdims,
 *                    int      type,
 *                    int      condition,
 *                    void    *comparison,
 *                    Boolean  forkflag,
 *                    Boolean  syncupdateflag)
 *
 *  Creates a visualization of the array with given starting address
 *    "adr" and name "name" of the dimensions [0..dims[i]-1] (whose
 *    number is given in "numdims"). The array is of type "type".
 *    The length of the name string is passed in "namelen" for compati-
 *    bility with Modula calls. It is ignored if it is less than 1.
 *  All array elements fulfilling the comparison defined by "condition"
 *    and "comparison" are displayed in black, the rest in white.
 *  "VIS" is the VIStype* returned by "OpenVisualizer".
 *  If "forkflag" is TRUE, the Visualizer will be put to work in the
 *    background; the displayed data can be updated using a call to
 *    UpdateForkedVisualizer()
 *  If "syncupdateflag" is TRUE, a call to UpdateForkedVisualizer() will block
 *    until the user presses the sync-button of the Visualzier.
 *
 *
 *  Example call:
 *
 *    Visualize(VIS,"a", 1, dims, numdims,
 *              V_INT, V_GREATER, &value, FALSE, FALSE)
 *
 *  will display the visualization of the integer array a and highlight
 *    all elements that are greater than "value", running in the foreground
 *    (i.e. main program being suspended until Visualizer is terminated)
 *  Of course the sync-flag is not set here, because there is no background
 *    process at all.
 *
 *
 *  void  VisualizeRange(  VIStype *VIS,
 *                         char    *name,
 *                         ulong    namelen,		/* unsigned long */
 *                         void    *adr,
 *                         int     *dims,
 *                         ulong    numdims,
 *                         int      type,
 *                         void    *fromvalue,
 *                         void    *tovalue,
 *		           Boolean  forkflag,
 *                         Boolean  syncupdateflag)
 *
 *  Creates a visualization of the array with given starting address
 *    "adr" and name "name" of the dimensions [0..dims[i]-1] (whose
 *    number is given in "numdims"). The array is of type "type".
 *    The length of the name string is passed in "namelen" for compati-
 *    bility with Modula calls. It is ignored if it is less than 1.
 *  All array elements in the range "fromvalue" to "tovalue"
 *    are displayed in black, the rest in white.
 *  "VIS" is the VIStype* returned by "OpenVisualizer".
 *  If "forkflag" is TRUE, the Visualizer will be put to work in the
 *    background; the displayed data can be updated using a call to
 *    UpdateForkedVisualizer()
 *  If "syncupdateflag" is TRUE, a call to UpdateForkedVisualizer() will block
 *    until the user presses the sync-button of the Visualzier.
 *
 *  Example call:
 *
 *    VisualizeRange(VIS,"a", 0, a, dims, numdims, V_INT, &i, &j,
 *                   TRUE, FALSE)
 *
 *  will display the visualization of the integer array a and highlight
 *    all elements in the range [i..j] running in the background (i.e. the
 *    main program continues and is able to update the array using
 *    UpdateForkedVisualizer(VIS) ), not synchronizing the update calls.
 *    Then length of the name (i.e. "a") is computed internally since the
 *    value given (i.e. 0) is less than 1.
 *
 *
 *  void  VisualizeUserFn(  VIStype *VIS,
 *                          char    *name,
 *                          ulong    namelen,		/* unsigned long */
 *                          void    *adr,
 *                          int     *dims,
 *                          ulong    numdims,
 *                          int      type,
 *                          char    *cmptext,
 *                          ulong    cmptextlen,	/* unsigned long */
 *                          Boolean  (*compare)(),
 *                          void    *(*access)(),
 *                          void    *envp,
 *                          ulong    envlen,		/* unsigned long */
 *			    Boolean  forkflag,
 *                          Boolean  syncupdateflag,
 *                          Boolean  syncfunctionflag)
 *
 *  Creates a visualization of the array with given starting address
 *    "adr" and name "name" of the dimensions [0..dims[i]-1] (whose
 *    number is given in "numdims"). The array is of type "type".
 *    The length of the name string is passed in "namelen" for compati-
 *    bility with Modula calls. It is ignored if it is less than 1.
 *    (the same applies to "cmptextlen")
 *  "VIS" is the VIStype* returned by "OpenVisualizer".
 *  "envp" point to some user data that may be used in the compare
 *    function later on. The length of the data is given in "envlen".
 *  The user data is newly allocated and copied so changing it after-
 *    wards has no effect. Use ChangeUserFn() to alter it.
 *  If "forkflag" is TRUE, the Visualizer will be put to work in the
 *    background; the displayed data can be updated using a call to
 *    UpdateForkedVisualizer()
 *  If "syncupdateflag" is TRUE, a call to UpdateForkedVisualizer() will block
 *    until the user presses the sync-button of the Visualzier.
 *  If "syncfunctionflag" is TRUE, a call to ChangeUserFn() will block.
 *
 *  The "cmptext" describes the comparison. It has to contain one
 *    occurence of "%s" which is automagically replaced by the array name
 *    and thea ctual coordinates.
 *  The user defined comparison and array access functions are used as
 *    follows:
 *
 *  Boolean compare(void *a, int cond, void *envp)
 *
 *      Compares the value of the array element (given in "a") to some
 *        other value, possibly given by the environment pointer "envp"
 *        (which is passed at the 1st call to VisualizeUserFn() and may
 *        be changed using ChangeUserFn() ). The comparison condition
 *        (V_EQUAL, V_LESS etc) is passed in "cond".
 *      The user function is free to ignore "cond" as well as "envp"
 *        and perform whatever operation it likes.
 *
 *  void   *access(void *adr, int *x, int *dims, ulong numdims)
 *
 *      Returns a pointer to the array element at adr[x[0],x[1],...]
 *        where the number of dimensions is in numdims and the size of
 *        each dimension is given in dims[].
 *
 *  All array elements fulfilling the comparison defined by the user
 *    supplied functions are displayed in black, the rest in white.
 *
 *  Example call:
 *
 *    VisualizeUserFn(VIS, "a", 0, a, dims, numdims, V_INT,
 *                    "10 <= %s <= 20", 0, my_compare, my_access,
 *                    &data, sizeof(data), TRUE, TRUE, TRUE)
 *
 *  will display the visualization of the integer array a and highlight
 *    all elements that fulfill the comparison function "my_compare"
 *    using the data in "data" and are accessed via "my_access",
 *    running in the background (i.e. the main program continues and is able
 *    to update the array using UpdateForkedVisualizer(VIS))
 *  The Visualizer is synchronized with the foreground process for both
 *    UpdateForkedVisualizer() and ChangeUserFn() calls.
 *  The length of both the name of the array and the string describing
 *    the user function are computed internally since they are both <1.
 *
 *
 *
 *  void  VisualizeValues(  VIStype *VIS,
 *                          char    *name,
 *                          ulong    namelen,		/* unsigned long */
 *                          void    *adr,
 *                          int     *dims,
 *                          ulong    numdims,
 *                          int      type,
 *                          Boolean  forkflag,
 *                          Boolean  syncupdateflag)
 *
 *  Creates a visualization of the array with given starting address
 *    "adr" and name "name" of the dimensions [0..dims[i]-1] (whose
 *    number is given in "numdims"). The array is of type "type".
 *    The length of the name string is passed in "namelen" for compati-
 *    bility with Modula calls. It is ignored if it is less than 1.
 *  The elements of the array are displayed in using grayscale bitmaps,
 *    thus giving a quick overview of the distribution of values in
 *    the array. However, no boolean operators are used.
 *  "VIS" is the VIStype* returned by "OpenVisualizer".
 *  If "forkflag" is TRUE, the Visualizer will be put to work in the
 *    background; the displayed data can be updated using a call to
 *    UpdateForkedVisualizer()
 *  If "syncupdateflag" is TRUE, a call to UpdateForkedVisualizer() will block
 *    until the user presses the sync-button of the Visualzier.
 *
 *
 *  Example call:
 *
 *    VisualizeValues(VIS,"a", 1, a, dims, numdims, V_INT, FALSE, FALSE)
 *
 *  will display the visualization of the integer array a and display
 *    all elements as different shades of gray according to their value.
 *    No background operation (and thus no sync) is initiated.
 *
 *
 *
 *
 * void ChangeUserFn(VIStype *VIS, Boolean (*newfn)(), char* str, ulong strl,
 *                   void *dat, long dlen)
 *
 * Transmit new data for the user function of the Visualizer in the background.
 *   The new function to be called is pointed to by "fn",
 * the string describing the function is "str", "dat" points to the
 * user data to be transmitted and "dlen" is the length of the user data.
 * "str" has to contain one occurence of "%s" which is automatically replaced
 * by the name of the array being visualized. Its length is given in "strl"
 * which is ignored if it is less than one.
 *
 * If "fn" is NULL then no function is given and the old one is used further.
 * If "str" is NULL the string isn't changed and if "dat" is NULL, no
 * data is transmitted.
 *
 * This function requires that the Visualizer uses a User defined Function
 * (i.e. was called using VisualizeUserFn()) and is running in the background. 
 *
 *
 *
 * void UpdateForkedVisualizer(VIStype *VIS)
 *
 * Transmit the new contents of the visualized array to the Visualizer
 * running in the background
 *


LIMITATIONS AND KNOWN BUGS:

- Currently, the Visualizer cannot handle arrays with more than 4 dimensions.
  However, this can easily be raised to an arbitrary (but fixed) number
  of dimensions - I just did not encounter even a 4-dimensional array ;-)

- The resizing behavior of the Visualizer is strange, i.e. when you resize
  it to be small and then make it big again, it will be out of proportions.

- The scrollbars around the array display could behave in a more intuitive
  way. Also, sometimes parts of the display are not redrawn.

- There should be a possibility to use XDefaults.

- And some other things that don't come to my mind right now 8-)


NOTES:

- This program is still under developement. I do appreciate any comments,
  suggestions and (yuck) bug reports. Please mail to haensgen@ira.uka.de

- Feel free to look at the source which is heavily commented.
  There is still much room for improvement. If you make changes to
  the code, *please* let me know and do *not* redistribute a modified
  version yourself.

- Happy Visualizing!


	Stefan Haenssgen
	haensgen@ira.uka.de
