OVERVIEW:

CenterStage is a Geomview external module that allows you to create
geomview objects easily and interactively.  It can create parametric
surfaces and curves, polyhedra, vectors, and objects that build on other
objects, such as tubes around curves, and offset surfaces and curves. 
Objects can be grouped into compound, hierarchical objects.  You can
control an object's coloration and appearance in a variety of ways, and
there are several different surface and curve domain styles (solid, grid,
bands, lines, dots, checkerboard, etc).  CenterStage also provides a means
of tying sliders, check-boxes, type-in areas and other input devices to
parameters for the objects it creates, and will update them automatically
when these values are changed.  Moreover, StageManager can be used to
control these values, so, for example, you can make a movie of a surface
deforming as its parameters change.

CenterStage is intended as an easy means of producing geometric objects for
use within Geomview.


STARTING CENTERSTAGE:

Once geomview is running, select CenterStage from the modules panel.  This
will load CenterStage.  CenterStage has a fairly long startup sequence, so
it tells you what it is doing via the message bar at the bottom of its
window.  When the menu bar becomes active, CenterStage is ready to go.

To exit from CenterStage, press the QUIT button.


CREATING OBJECTS:

The main purpose of CenterStage is to be able to create objects for
Geomview to display.  To create an object, you first select the NEW item
from the OBJECT menu.  You will be asked to select the type of object to
create and to give the object a name.  The basic object types are SURFACE,
CURVE, and POLYHEDRON, plus some specialized objects like AXES, and ARROWS.
The pop-up menu at the top of the panel lets you select more advanced types
of object; they are grouped by categories.  Once you have selected the type
you want, click the OK button to create it.  The name of your object should
appear in the objects list at the right, and the object's type will be
shown in blue at the far right of the menu bar.

For your convenience, a template for the type of object that you have
selected will be displayed in the type-in area.  The template gives you a
place to start creating your object.  For example, if you have selected a
surface, you will get a template for the domain and the function
definition.  You can edit these to suit your requirements.  The template
usually does not include all possible types of data you can specify for the
object; to obtain a template for one of the optional directives, select the
item from the TEMPLATES submenu in the OBJECT menu.

Once you have defined the object to your liking, press the UPDATE button to
have it computed and displayed in Geomview.  CenterStage is designed for
flexibility, not speed, so this may take a few moments.  It is usually best
to keep your domain sizes small to begin with until you are sure it is the
way you want it to be, then increase the size for the final version of the
object.

For more information about a specific object type, see the documentation
for that object class.

If you make edits to your object, CenterStage will show a small diamond
next to the object type at the right of the menu bar.  This indicates that
you need to update your object.  If this diamond is showing, then the
object being displayed by geomview may not correspond to the data that
appears in the CenterStage window.  Press UPDATE to be sure the object
showing in geomview is up to date.


CENTERSTAGE MENUS:

The FILE menu controls the file you are editing.  Each file can contain any
number of objects (these are listed in the OBJECTS list at the right).  By
default, CenterStage object files have the type ".cs".  The items in the
FILE menu are:

    NEW     Clears the contents of definition area and deletes all the
            objects in the list.  Resets the settings to their
            default.  This is like starting CenterStage from scratch.

    OPEN    Opens an existing CenterStage file (.cs) and loads the
            objects that it contains.

    SAVE    Save the currently defined objects and menu settings to
            the same file they were read from.  You should do this
            periodically to be sure that your edits are saved.

    SAVE AS Saves the objects and menu settings under a new name.  A
            new file is created and it becomes the current files.  The
            original file is not altered.

    REVERT  Rereads the objects and menus settings from the file, thus
            eliminating all edits that occurred since the last save.

    IMPORT  This item lets you load an object (or collection of
            objects) into the current file from some other file.  This
            differs from the OPEN menu in that OPEN forgets about the
            current file and starts using the new file, whereas IMPORT
            incorporates the contents of the new file into the current
            one, making the current file larger.

    EXPORT  This item saves the current object (and only the current
            object, unless the object is a group, in which case all
            the objects contained in the group as well) to a file.
            This differs from the SAVE AS menu in that SAVE AS saves
            ALL the objects to the named file and makes that file the
            current one, whereas EXPORT saves a single object to a
            file but does not change the current file.  Thus EXPORT
            and IMPORT provide a mechanism for copying objects from
            one file to another.

    SAVE OOGL
            This item will cause CenterStage to write an OOGL file
            that contains the data for the current object.  This file
            can be read directly into Geomview without requiring
            CenterStage to recompute it.  Note, however, that
            CenterStage can not read an OOGL file, only a file that
            was created with SAVE, SAVE AS or EXPORT.

    LIBRARY This item brings up a panel that lets you specify
            arbitrary TCL files that should be included when this file
            is loaded.  For example, if you have defined your own
            class of objects, you may want to include the .tcl file
            that defines the object so that your new class will always
            be available when the file is loaded.

    QUIT    Exits CenterStage.

The EDIT menu provides standard editing features, and lists their keyboard
equivalents.  These commands operate on regions of text selected with the
left mouse button, or by holding down the SHIFT key and using the arrow
keys.  The standard X-windows selection mechanism also works for copying
text from one window to another.

The EDIT menu includes a PREFERENCES item.  The first preference controls
whether CenterStage uses the old 'let' statement (that does not understand
mathematics very well) or the new one that allows you to write more
mathematical statements.  This preference is mainly for backward
compatibility with files created by older versions of CenterStage.  The
second preference controls the level of detail used for error messages. 
The ONE LINE choice makes error messages show as single lines in the
message area at the bottom of the screen.  SHORT means that the standard TK
"bgerror" dialog will be used, but that the error info will be shortened to
not include some of the calls that are part of the CenterStage program
itself.  FULL gives the complete stack trace for the error message.

The OBJECT menu lets you create and manipulate objects.  It has the
following items:

    NEW     This item lets you create a new object.  You will be asked
            to select an object type (surface, curve, etc.) and to
            give the object a name.  If the new object requires a link
            to an existing object, you will be requested to make the
            link at this point.  The new object is created at the same
            level of the hierarchy as the currently selected object.

    ADD     Similar to NEW, this menu item creates a new object, but if
            the currently selected object is a group, the new object
            is added to the group.

    RENAME  This item lets you rename the selected object.

    DUPLICATE
            This lets you create a duplicate of the selected object.
            You will be asked for a new name for the duplicate.

    DELETE  This item lets you delete the current object and remove it
            from the objects list.  There is no way to undo this
            operation, so be careful!

    TEMPLATE
            This menu contains items for each type of information that
            you can specify for the given object.  You can get a
            template for the directives that were not included in the
            original template for the object.  For example, if you
            want to add a slider bar, you can select the template for
            Slider to see how to specify one (items in parentheses
            should be replaced by corresponding values).  Some
            templates do not show all possible optional values or
            flags.  See the documentation for the object type you are
            using for more complete details on the directives that can
            be supplied.

    LINK TO Many objects build on other objects in some way; for example,
            the TUBE object requires a CURVE object and builds a tube
            around the curve.  When such an object is created, you must
            supply a link to an object of the appropriate type; however, if
            you want to change the link, you can use this menu item to
            select a new one to link to.  Those objects that do not build
            on some others also can be linked to objects; in this case,
            when the referenced object is updated, it will force the
            current object also to be updated.

    MOVE TO GROUP
            This menu item lets you move the current object into an
            existing group.  You will be asked to select the group
            from a list of the currently available groups.  You can
            move objects from one group to another using this menu
            item.

    REMOVE FROM GROUP
            This menu item makes the currently selected object a
            top-level object (i.e., it is removed from any group it is
            in).

    UPDATE  This menu lets you update the current object in different
            ways.  The DEFINITION option causes the current object to
            process the script area, but not recompute the object at
            this time.  You may want to use this if you have added,
            for example, a ColorFunction and want to be able to select
            it in the COLOR menu without having to update the object
            unnecessarily.  The COLORS item recomputes the object's
            colors (without recomputing its data), and the APPEARANCE
            item updates the object's appearance characteristics
            without recomputing the object's data.  The OBJECT item
            updates the entire object (just like pressing the UPDATE
            button).  These items are most useful when the AUTOMATIC
            checkbox is unchecked.  If AUTOMATIC is checked, then the
            object is updated automatically whenever you select a new
            item in the COLORS and APPEARANCE menu.  If you want to
            make several changes without having to wait for an update
            after each one, you should uncheck the AUTOMATIC checkbox.

    SHOW    This menu controls when Geomview shows the current object.
            Normally, only the selected object will be displayed in
            Geomview.  If you want the current object always to be
            shown, even when it is not selected, chose the ALWAYS
            item.   If you never want Geomview to show this object,
            select NEVER; this is useful for objects that are merely
            needed to define other objects.  For example, if you have a
            curve object that is used as a reference for a tube
            object, you may not want the curve to be displayed, so you
            should select the NEVER item for the curve.

    NORMALIZE
            By default, Geomview scales and centers any object it displays
            so that it will fit into a unit sphere at the origin.  This
            makes sure you can see the entire object, but it also means
            that if you have several objects, their position and size may
            not be correctly represented relative to each other.  You can
            use this menu to help overcome that problem.  NONE means
            Geomview will not normalize the object, so if you have several
            objects with normalization NONE, they will be properly
            positioned.  KEEP means it will normalize the object when it
            first appears, but then will not renormalize it if the object
            changes.  If you have a dynamically changing object, this may
            be the best setting for you.  EACH is the default Geomview
            action: any time the object changes it is re-normalized.  ALL
            means that Geomview will renormalize the object only if it gets
            bigger.  The NORMALIZE/AGAIN item means Geomview should
            normalize the object now, but then KEEP the current normalization. 

            Another way around the normalization problem is to place all
            the objects into a group object, as Geomview only normalizes
            the group as a whole, not the individual objects within the
            group.

    WINDOW  This menu lets you bring the slider, type-in, check-box, pop-up,
            or other input device windows to the front, in case they have fallen
            behind the CenterStage or Geomview windows and can no longer be
            seen, or in case you have closed them to get them out of the way.  
            Only those windows that actually contain active items will be 
            available in this menu.  The WINDOWS submenu of the WINDOWS 
            menu lists any active windows created by the Window directive.


The COLOR menu lets you specify how the object should be colored.  There
are several standard colorations that you can apply, or you can define your
own using the ColorFunction directive.

    BY PARAMETER
            For a parametric surface or curve, this will color the
            object by spreading the colors from the lowest to the
            highest value of one of the parameters:  all the points
            with the same parameter value will be colored the same
            color.

    BY COORDINATE
            Here, all the points on the object that have the same
            value for the coordinate you choose will be colored the
            same color.

    BY FUNCTION
            This lets you choose from among the color functions that
            you have defined (or that are defined automatically by the
            system).  You can create a new coloring function via the
            ColorFunction directive (see the template for
            ColorFunction).  You give the function a name and a means
            of computing the function's value, witch is either an index
            into the color table or an RGB color value (depending on
            whether the result is a single number or a triple of
            numbers).  You can use color functions to produce
            virtually any coloration of the object.

    SOLID   This specifies that the object should be a solid color.
            The menu lets you specify the color to use, or NONE, which
            means no color is applied to the object (Geomview's lights
            also may cause the object to be colored).  If you want a
            solid color that does not appear on the list, you can use
            the OTHER... item to specify RGB values for the color.
            You can also edit the color table to provide additional
            named colors.

    NORMALIZE
            This check-box determines whether CenterStage will scale
            all the color values so that they use the full spread of
            colors.  The color table uses indices from 0 to 1 to
            determine which color to use, so if your color function
            gives values outside this range, or doesn't use the full
            range, the object would be colored strangely.  If
            NORMALIZE is checked, however, CenterStage will scale
            whatever range of color values you specify so that they
            will always be between 0 and 1 (unless there is only one
            value to start with).  This means you don't have to be
            careful about making sure your function always returns a
            number from 0 to 1.  Similarly, for RGB values,
            CenterStage will scale all the coordinates so that the
            range of red, green and blue values used over the entire
            surface is between 0 and 1.  If NORMALIZE is not checked,
            then the exact values you specify will be used, even if
            they are outside of 0 to 1.

    WRAP COLORS
            If checked, this menu item means that the color table will
            have the same color at 0 and 1 (so that the color table
            can be used to color a periodic function more easily).
            Otherwise the two ends of the color table will be
            different colors.

    INHERIT COLORS
            If checked, this means that the object will inherit its
            color table from its parent object (if it is part of a
            group) or from the default color table.

    EDIT COLORS
            This item brings up the color-table editor.  Currently it
            is pretty crude, but it lets you specify named colors and
            their RGB values, plus a count of how many entries in the
            color table should be used to go from this color to the
            next one.  Higher counts mean more gradations are
            possible.  Currently there is no way to edit the default
            color table, but you can copy and paste the complete color
            list from one object to another.


The APPEARANCE menu lets you specify Geomview appearance characteristics,
such as shading and line thickness.

    SHADING This menu lets you choose the way Geomview will shade the
            object.  CONSTANT means no lighting effects will be used,
            and each face will be a single color.  FLAT means each
            face is a single color, but the lighting will be used to
            determine the color.  SMOOTH means that each vertex of a
            face can have its own color and that the color of the rest
            of the face will be determined by linearly interpolating
            the vertex colors (this can make even coarsely
            parameterized surfaces look remarkably smooth).  CSMOOTH
            means the same as SMOOTH but with no lighting effects.

    TRANSPARENCY
            This menu lets you specify how transparent an object
            should be.  Transparency is only available via hardware
            support (on some SGIs).

    FACES   This check-box lets you control whether the object's faces
            are shown.

    EDGES   This check-box lets you control whether the object's edges
            are shown.

    NORMALS This check-box lets you specify whether the object's
            normal vectors are shown (the vectors that are used for
            lighting computations).

    INHERIT This menu lets you specify which appearance
            characteristics are inherited from the object's parent
            object (if it is part of a group).  If a characteristic is
            NOT inherited, then its setting above will override the
            group's appearance characteristic.  If it IS inherited,
            then the group's value will be used.


The DOMAIN menu is available for parametric curves and surfaces.  This menu
lets you specify the style of the domain.  For surfaces, you can specify
that it is a solid patch, a grid, a checkerboard, etc., and for curves, you
can make the domain be a solid line, a dashed line or a dotted line.  See
the documentation for the curve and surface classes for more information.

The VECTOR menu is available for CurveVectors and SurfaceVectors objects. 
It lets you select the type of vectors that will be showing.  You can
select more than one type of vector at a time.  For example, you can choose
the tangent, normal and binormal vectors to get the Frenet frame.  If UNIT
is selected, then all the vectors will be normalized to unit length.  See
the documentation for these object classes for more information.


CONTROLLING OBJECT VISIBILITY:

Since CenterStage lets you define many objects at once, you may not want
them all to be displayed simultaneously.  By default, CenterStage only
displays the object that currently is selected in the OBJECTS list at the
right-hand side of the CenterStage window; as you select different objects,
previous objects will be removed from Geomview.

You can change this behavior via the OBJECT/SHOW menu.  If you select
ALWAYS, the object will always be displayed, even if it is not selected. 
If you choose NEVER, the object will not be displayed, even if you do
select it.  This is useful if the object is merely being used as the basis
for some other object; for example, if you are building a tube around a
curve, you may not want the curve itself to be displayed.

By default, objects in Geomview are centered and scaled so that they fit
within a unit sphere.  If you have several objects created by CenterStage,
this normalization that Geomview performs may cause their relative sizes
and positions to be inaccurate.  For example, if you create a curve and a
tube around the curve and display them both, the tube may not appear to be
properly centered around the curve since Geomview scales the two
differently.

To overcome this problem, you can request that Geomview not normalize the
objects.  This is controlled via the OBJECT/NORMALIZE menu item (do not
confuse this with the COLOR/NORMALIZE menu, which specifies whether the
color values are scaled to between 0 and 1).  If you set OBJECT/NORMALIZE
to NONE, then geomview will display the objects properly; however, you may
need to scale the scene by hand in order to see the complete objects.

Another alternative is to create a GROUP object rather than a collection of
individual objects.  Since Geomview only scales top-level objects (not
individual parts of an object), this will guarantee that the parts of the
group are in proper relation to each other.  Geomview will scale the entire
group so that you can see it, so this gives you the best of both worlds. 
You may wish to specify OBJECT/NORMALIZE as KEEP, so that as you change the
parts of the object, GEOMVIEW will not rescale the group.


CHANGING COLORS:

Objects can be colored in a variety of ways, and these are specified by the
COLOR menu.  For parametric objects, you can color the object by one of its
parameters (all the points with the same parameter will be colored the same
color, and the colors will be spread across the different values of the
parameter).  Any object can be colored by its coordinates.  For example, if
an object has coordinates x, y and z, then coloring by x means that all the
points on the object with the same x-coordinate will be colored the same
color.  Objects can also be colored solid colors or with no color at all
(Geomview will use its default grey color, which may be modified by the
lighting colors).

You can specify an arbitrary coloring function via the ColorFunction
directive.  This requires you to specify a name and a function.  The
function will be evaluated whenever a color is needed, and it should
produce either a single value which will be used as an index into the color
table (usually a number between 0 and 1) or a triple of numbers that
represent RGB values for the color.  For example:

        ColorFunction distance {sqrt(x^2+y^2)}

will define a color function called "distance" that returns the distance of
(x,y) from the origin.  If you select this function in the COLOR/BY
FUNCTION menu, the object will be colored so that concentric cylinders
around the z-axis will have the same color.

If you specify:

        ColorFunction myRGB {(x,y,z)}

then the three coordinates will be used as the values of red, green and
blue for the color at that point.  (This color function is always available
as "RGB=XYZ" in the COLOR/BY FUNCTION menu, and it gives a rather soft
shading to most objects).

The function in a ColorFunction is not a TCL script that is executed, but
rather an expression that is evaluated; however, variable substitution and
command evaluation is performed on the expression before it is computed, so
if you need to do a more complicated calculation for the color function,
you can do so by calling a TCL procedure, as for example:

        ColorFunction TwoColor {ChooseColor(x,y,z)}
        
        proc ChooseColor {x y z} {
          let len = Norm(x,y,z)
          if {$len > 2} {set color 1} else {set color 0}
          return $color
        }

The braces around the brackets in the ColorFunction are necessary to
prevent the execution of the ChooseColor procedure until the ColorFunction
is used (without them, CenterStage would call ChooseColor at the time it
was trying to define ColorFunction and would use its result as the
definition of TwoColor; you would probably get an error that variable x
does not exist because when CenterStage is processing the directives, it
doesn't).


CREATING HIERARCHICAL OBJECTS:

CenterStage lets you create hierarchical objects using objects of type
GROUP. To create such an object, first select the OBJECT/NEW menu and
select the GROUP type.  Give the group a name, and click OK. The object
should show up in the object list and the type-in area will be blank (there
is no template for groups).  To add an object to the group, select
OBJECT/ADD, choose the type you want, give it a name, and click OK.

The object should appear in the object list just below the group object but
indented.  This means the object is part of the group object.  You can add
more objects to the group by selecting OBJECT/ADD again, or by selecting
OBJECT/NEW when the current object is part of the group you want to add to.

You can add as many objects to a group as you like.  You can also add group
objects to a group, so you can nest groups as deeply as you want.

If you have created a top-level object and then later decide you want to
move it into a group, you can do that using the OBJECT/MOVE TO GROUP
command.  You will be asked to select a group to add the object to; simply
double-click on the group in which you want the object to appear. 
Similarly, you can move an object out of a group by selecting OBJECT/MOVE
TO GROUP and selecting a different group.

You can remove an object from a group by selecting the OBJECT/REMOVE FROM
GROUP menu item.  CenterStage will remove the object from the group and
make it a top-level object.


LINKED OBJECTS:

Some types of objects in CenterStage are defined in terms of other objects. 
For example, the Tube class requires a Curve object about which the tube is
generated.  We call the object defined in terms of another the "referrer"
or the "referring object", and the object it refers to the "linked object"
or the "reference object".  In the example above, the Tube is the referrer
and the Curve is the reference object.

When you create an object that requires a reference, you will be asked to
select the reference object from a list of all possible references (only
the objects of the required type will be shown).  You must pick an object
from this list.

If the reference object is updated, the referrer is updated automatically
so that the two are always synchronized properly.  You can link two objects
together even if the referrer doesn't require a reference.  For example, if
you have a surface and a plane that is a tangent plane to the surface, you
may want to link the tangent plane to the surface so that it will be
updated whenever the surface is changed.  To do so, select the referrer in
the object list and choose the OBJECT/LINK TO menu.  You will be able to
link the object to any object.  Whenever that object is updated, the
current object will be updated automatically.

It is possible to create loops this way, so be careful.  CenterStage tries
to detect these and should be able to process them correctly, but some
situations may cause CenterStage to go into an infinite loop.


INPUT AND OUTPUT DEVICES (WIDGETS):

Frequently, your objects may be defined in terms of a parameter that can be
changed; i.e., you really have a family of objects.  For example, you can
define a cylinder that has its radius as a parameter.  For such objects, is
is often convenient to have a slider, type-in area, checkbox, menu, or
other input device where the value of the parameter can be specified. 
CenterStage lets you create such devices, which we call "widgets".  There
are a number of widget classes:

        Slider       the value is set by dragging a scroll bar
        TypeIn       the value can be typed in
        CheckBox     the value is a toggle switch (0 or 1)
        PopUp        the value is given by selecting a menu item
	Button       the value is 1 if pressed, 0 otherwise
        TypeOut      the value is for display only (it shows the contents
                       of a variable)

There are also two animation widgets that provide for iterative 
computation:

        Evolve       updates the value of a variable by calling a
                       given function to compute the new value
        Animate      attaches to Slider or TypeIn values to move
                       them through a given range of values

Normally, each type of widget appears in a window devoted to that type of
input device (i.e., all the sliders are on one window, while all the
type-ins are in another).  You can create your own custom control panels
using the following directives:

        Window       creates a window in which you can place other widgets
        Frame        creates an organizational sub-window within a window

Each directive has its own syntax, described below, but all of them have 
several options in common.  These are:

        -bg color
        -background color
            These two options are equivalent and allow you to specify the
            background color for the widget being defined.  If unspecified,
            the color will be inherited from the window or frame in which
            the widget appears.  You may specify the color as an x-window
            color name, or as an RGB value in hexadecimal, e.g., "#A05933"

        -fg color
        -foreground color
            These two options are equivalent and allow you to specify the
            foreground color for the widget being defined.  If unspecified,
            the color will be inherited from the window or frame in which
            the widget appears.  You may specify the color as an x-window
            color name, or as an RGB value in hexadecimal, e.g., "#A05933"

        -title string
            This specifies the title used to label the widget in the window
            where it appears.  If unspecified, the default title is the
            name of variable associated with the widget followed by a
            colon.  For example, the default title for "CheckBox a" would
            be "a:".

        -simpletitle
            For widgets appearing in their default windows (i.e., for which
            -in is NOT specified), if the widget belongs to a child of the
            currently selected object (rather than the object itself) or to
            an object linked by the object or its parents or children, then
            the title will include the name of the object in parentheses. 
            This helps you distinguish between two input devices with the
            same name coming from different objects.  For example, if a
            group has a "Slider a" and its child named "Curve" also has a
            "Slider a", then when the group is selected, both sliders will
            appear in the sliders window, but the first will be labelled
            "a:" while the second is labelled "(Curve) a:".  The
            -simpletitle directive suppresses the object name regardless of
            whether the widget comes from the selected object or not.

        -disabled
            This directive causes the widget to be disabled initially.  It
            will not be responsive to user input until it has been enabled. 
            Usually this is done via a call to the widgets "Enable"
            function.  For example,

                        Slider a 0 1 -disabled
                        CheckBox use_a 0 -title "Use a" -command {
                          if {$use_1} {Self Slider a Enable} \
                            else {Self Slider a Disable}
                        }

            will generate a slider that is initially disable together with
            a checkbox that can be used to enable or disable the slider.

	-command script
            This specifies that the specified script should be executed 
            when the value of the widget changes, rather than recomputing
            the object.  This is useful when the value of a widget does not 
            change the geometry of an object, but rather causes some other 
            action to occur.  The script can cause an update to occur 
            either by calling the Update routine directly, or by setting 
            the value of some other widget that does cause an update to 
            occur.  For example,

			Slider t 0 1
			Button set_t -title "Set t to 1/2" \
			   -command {Self Slider t Set .5}

            Here, the button is used to set the slider to a specific 
            value.  In this case, the object will be updated, not because 
            the button was pressed, but because the value of the slider 
            changed and that causes an update.

        -in window
	    This specifies that the widget should appear in the specified
	    window rather than in the default window for the widget's
	    class.  Widgets can be placed in windows belonging to their
	    parent groups; this makes it easy to put all the controls for
	    a hierarchical object into one window.

	-at {x y [w] [h]}
            When the -in option is used, you must specify where in the 
            window the widget should appear.  The -at option does this.  
            You give the column and row (as x and y) and optionally the 
            number of columns and number of rows occupied by the object
            (w and h); these are 1 by default.  Note that you can place 
            objects on top of each other this way, so be careful about 
            where you put them.  See the discussion of the Window and 
            Frame directives below for more information on specifying 
            locations.


THE SLIDER WIDGET CLASS:

The Slider directive has the following form:

        Slider name min max [init] [options]

where "name" is the name of the parameter, "min" is the minimum value for
the slider, "max" is the maximum value, and "init" is the initial value for
the slider.  Once the slider has been created, it is bound to a TCL
variable of the same name, and it can be used just like any other variable
when your object is being computed.  For example, you can define a surface
as follows:

        Domain {{-1 1 10} {-1 1 10}}

        Function {x y} {
          let z = a(x^2-y^2)
        }

        Slider a -1 1

Here, the slider value controls the factor by which the z coordinate is
multiplied in the function definition.  Whenever the slider's value is
changed, the surface will be recomputed using the new value.

The Slider directive has the following options in addition to the standard 
ones:

        -resolution r
            The value of r specifies the units by which the value of
            the slider can change.  For example, -resolution 1 means
            the slider will change by integers only, while
            -resolution .1 means the slider will change by 10ths.

        -ticks r
            If r is not 0, this means that the slider should include
            reference numbers at increments of r.  So -ticks .5 means
            there should be labels every .5 starting from the minimum.

        -digits n
            This specifies how many digits to use for the slider's
            value.  This provides an alternative to the -resolution
            specification.

        -width n
            This specifies the size of the slider bar.  By default it will 
            be 300 pixels.  This may be too wide if you are placing the 
            slider in a custom window, for example.

        -[no]drag
            This option lets you specify whether or not the slider should
            cause updates to occur as the slider is being dragged (-drag)
            or only when the slider is released (-nodrag, the default). 
            Most objects are too complex to update fast enough to use
            -drag, but for some limited cases, this may be useful.

You may have as many sliders as you want for a given object.  Sliders for
group objects are inherited by the objects within the group.  Sliders for
different objects can have the same name, but it is not a good idea to use
the same name in an object and its parent group (if you do, the object's
slider takes precedence).


THE TYPEIN WIDGET CLASS:

Some values are better handled by typing in the value rather than using a
slider.  For this reason, CenterStage provides a TypeIn directive, with the
following form:

        TypeIn name init [options]

where "name" is the name for this type-in (used as a variable just as
with sliders above) and "init" is the initial value for the type-in.
In addition to the standard options are:

        -width n
            This specifies the width of the type-in area, in case you
            need a larger one than the default.

        -lines n
            This specifies the number of lines to use for the type-in.
            The default is to use one, but you can have a multi-line
            type-in by specifying some larger number of lines.  In
            this case, the type-in will have a scroll bar for vertical
            scrolling.

        -[no]evaluate
            The -evaluate option specifies that the text should be
            evaluated as a mathematical expression before assigning it
            to the named TCL variable.  (The -noevaluate option specifies
            that the text should be used literally).  For example, 

                TypeIn r "pi/2" -evaluate

            would cause the variable "r" to get the value 1.57079632679
            rather than the string "pi/2".

	-titlewidth n
            This specifies the width (in characters) of the title area for 
            the widget when a widget appears in a custom window (using -in).
            TypeIns appearing in the default type-in window have their 
            title widths adjusted automatically so that they line up 
            nicely, but for type-ins that you place within your own 
            windows, you may need to adjust this width by hand to get the 
            type-in areas to line up.

Whenever the value of a type-in is changed (and you press RETURN), the
object will be recomputed using the new value.  If you press ENTER, the
value is updated, but the object is not computed (you can then make changes
to other type-ins before recomputing the object).

You may have as many type-ins as you want for a given object.  Type-Ins for
group objects are inherited by the objects within the group.  Type-Ins for
different objects can have the same name, but it is not a good idea to use
the same name in an object and its parent group (if you do, the object's
type-in takes precedence).


THE CHEKBOX WIDGET CLASS:

Sometimes you want the be able to select a boolean value, for example, you
want to be able to select whether a part of a group should be displayed or
not.  For this reason, CenterStage provides you with a CheckBox directive. 
The format for the checkbox is:

        CheckBox name [init] [options]

where "name" is the name of the variable that will contain the value of the
check-box and "init" is the initial value of the check-box (1 or 0).
The only options available for the checkbox are the standard options 
available for all widget directives.

Whenever the value of a check-box is changed, the object will be recomputed
using the new value.

You may have as many check-boxes as you want for a given object. 
Check-Boxes for group objects are inherited by the objects within the
group.  Check-Boxes for different objects can have the same name, but it is
not a good idea to use the same name in an object and its parent group (if
you do, the object's check-box takes precedence).


THE POPUP WIDGET CLASS:

Sometimes you want to be able to select the value of variable from among a
fixed set of choices.  For this reason, CenterStage provides the PopUp
directive.  Its format is:

        PopUp name items [options]

where "name" is the name of the variable that will contain the value of the
pop-up menu selection, "items" is the list of choices for the menu, and
"options" are discussed below.  For example

        PopUp n {Circle Sphere Cylinder}

will create a pop-up menu containing the entries "Circle", "Sphere" and 
"Cylinder" and places the currently selected value into the variable "n".

The options in addition to the standard ones are:

        -init value
            This specifies the menu item to be selected initially (if not
            specified, then the first menu item is selected by default). 
            For example,

                PopUp n {Circle Sphere Cylinder} -init Sphere

            will cause the second menu item to be selected initially.

        -values {list}
            This specifies the values of each menu item.  If this option is
            not specified, the value will be the same as the menu label,
            but this list can be used to override the defaults.

        -width n
            This specifies the width of the pop-up menu, in case you need a
            larger one than the default.

	-titlewidth n
            This specifies the width (in characters) of the title area for 
            the widget when a widget appears in a custom window (using -in).
            PopUps appearing in the default pop-up window have their 
            title widths adjusted automatically so that they line up 
            nicely, but for pop-ups that you place within your own 
            windows, you may need to adjust this width by hand to get the 
            menus to line up.

Whenever the value of a pop-up menu is changed, the object will be
recomputed using the new value.

You may have as many menus as you want for a given object.  Pop-ups for
group objects are inherited by the objects within the group.  Pop-ups for
different objects can have the same name, but it is not a good idea to use
the same name in an object and its parent group (if you do, the object's
pop-up takes precedence).


THE BUTTON WIDGET CLASS:

Sometimes you would like an object to take an action other than recomputing 
its value.  For example, you might want to reset some values or clear some 
state information.  For this reason, CenterStage provide the Button 
directive.  Its format is

	Button name [options]

where "name" is the name of the variable associated with the button, and 
"options" are taken from the standard ones.  There are no additional options 
for buttons, but the most common one is -command, which causes the button 
to be linked to a script that is executed when it is pressed.  Without this 
option, pressing the button will cause the object to be recomputed, and in 
this case, the named variable will have the value 1 (it will have the 
value 0 any other time the object is computed) so you can tell that the 
recompute was caused by the button press.


THE TYPEOUT WIDGET CLASS:

Sometimes it is useful to be able to see the value of a variable that is 
used by an object during its computations.  For this reason, CenterStage 
provides the TypeOut directive, whose format is

	TypeOut name [options]

where "name" is the name of the variable whose value is to be displayed, 
and "options" are from the standard list or the following:

	-format string
	    This specifies an sprintf-style string that indicates how the
	    result should be displayed.  The default is "%s" which means
	    use the value verbatim.  You can use the format, for example,
	    to insert other text as in -format "%s meters", or to adjust the 
	    number of digits displayed, as in "%.3f".

        -width n
            This specifies the width of the type-out area, in case you
            need a larger one than the default.

        -lines n
            This specifies the number of lines to use for the type-out.
            The default is to use one, but you can have a multi-line
            type-out by specifying some larger number of lines.  In
            this case, the type-out will have a scroll bar for vertical
            scrolling.

	-titlewidth n
            This specifies the width (in characters) of the title area for 
            the widget when a widget appears in a custom window (using -in).
            TypeOuts appearing in the default type-out window have their 
            title widths adjusted automatically so that they line up 
            nicely, but for type-outs that you place within your own 
            windows, you may need to adjust this width by hand to get the 
            type-out areas to line up.

A type-out looks exactly the same as a type-in, but the text area will not 
be editable.  It will be selectable, however, so you can copy the contents 
of a type-out and past it somewhere else.


THE EVOLVE WIDGET CLASS:

CenterStage provides two means of producing animation effects within 
objects.  These are the Evolve and Animate directives.  The simpler of the 
two is the Evolve directive, which has the form:

        Evolve name [expression] [back-expression] [options]

where "name" is the name of the variable associated with the evolver, 
"expression" is a formula that is evaluated to move from one step in the 
evolution to the next, "back-expression" is a formula that is evaluated to 
move backward one step in the evolution, and "options" are as described below.

An evolver has six buttons labelled "<<", "<", "||", ">", ">>" and "RESET". 
The RESET button sets the evolver back to its initial state.  The ">"
button causes evolver to move one step forward, while ">>" causes the
evolver to step forward repeatedly until you press the "||" (stop) button. 
The "<" and "<<" buttons are available only if a back-expression is
specified or if the default (forward) expression is used.  These buttons
cause the evolver to step backward once or repeatedly.

The way an evolver steps forward is to evaluate the expression and assign 
the result to the named variable, then recompute the object with the new 
value.  This operation is repeated over and over if ">>" is pressed.

The expression is evaluated as though it were in a "let" statement.  If not 
given explicitly, the expression defaults to adding one to the current 
value of the variable.  You can provide a more complicated expression, or 
you can have the expression call a procedure to produce its value, as 
in the following example:

        proc Next {n} {
          let n = n^2
          return $n
        }

        Evolve n {Next(n)}

You can use a function like this to set other variables or do more
complicated processing at each step of the evolution (the Setup directive
can also be used for this purpose, but note that the Setup script is run
every time anything changes in the object, while the Evolve expression is
executed only when the evolver is running.

The default expression is equivalent to "Evolve n {n+1}".

The evolver steps backward in a similar fashion: the back-expression is
evaluated and its result assigned to the variable, then the object is
recomputed.  This occurs repeatedly if "<<" is pressed.  If no (forward)
expression is given, the default is to reduce the value of the variable by
one.  If a forward expression is given, the step-backward options are only
available if back-expression is given explicitly.

In addition to the standard options, the Evolve directive allows:

        -reset expression
            This specifies an expression whose result is the value to be
            used when the RESET button is pressed.  By default, this is 0.

        -step seconds
            This specifies the minimum length of time between steps of the 
            evolution.  If the object's recomputation takes less than this
            amount of time, the evolver will pause before doing the next
            computation for the remainder of the time.  If an evolver runs
            too fast, you can change the step time to slow it down, or to 
            smooth out the time between steps when some values of the 
            evolver compute faster than others.  The number of seconds 
            can be given as a decimal number.

If ">>" or "<<" is used, the evolver will run forever until you stop it. 
Note that you have to hold down the "||" button until it becomes active, 
and during intensive computation, this may take a moment, so be patient.


THE ANIMATE WIDGET CLASS:

The Animate directive can be used to make a variables (or series of
variables) move from one value to another through a series of intermediate
values.  The process can be made to loop or to loop back and forth between
the two extreme values.  The variables can be associated sliders or
type-ins, or can be simple variables unassigned to other input widgets.

The format for the Animate directive is:

        Animate name steps [variable-list] [options]

where "name" is a variable that counts the steps as they are performed,
"steps" is the total number of steps to use for the animation,
"variable-list" is a list of values to be animated (as described below) and
"options" are selected from the standard one or:

        -[no]loop
            This specifies whether the animation should loop when it
            reaches the end.  If -loop is specified, then the animation
            will repeat over and over again.  If -bounce is specified, the
            animation count will first increment and then decrement before
            repeating if -nobounce is specified (the default), the
            animation counter will be reset to 0 before the loop continues. 
            The default is -noloop

        -[no]bounce
            This option effects how the -loop option performs the loops. 
            If -bounce is specified, the counter will first increment to
            its maximum value and then will decrement back to 0.  With
            -nobounce, when the counter reaches the maximum, it is reset to
            0 and the loop starts over from the beginning.  Note that
            -bounce has no effect if -noloop is specified.  The default is
            -nobounce.

        -step expression
            This specifies the formula to be used when incrementing the
            loop counter.  The default is to increment by one.  Note that
            the loop count always goes from 0 to the number of steps that
            are specified by "steps" above, so your expression should take
            this into account.

        -back expression
            This specifies the formula to be used when decrementing the
            loop counter.  The default is to decrement by one.

        -step seconds
            This specifies the minimum length of time between steps of the 
            animator.  If the object's recomputation takes less than this
            amount of time, the animator will pause before doing the next
            computation for the remainder of the time.  If an animation runs
            too fast, you can change the step time to slow it down, or to 
            smooth out the time between steps when some values of the 
            animator compute faster than others.  The number of seconds 
            can be given as a decimal number.


An animator has a slider, three buttons and two check-boxes.  The buttons
are START, PAUSE, and RESET, and the check-boxes are LOOP and BACK AND
FORTH.  The check-boxes correspond the -loop and -bounce options described
above and are initialized by them, but the user can change their settings
(even when the animation is running).

The START button causes the animation to run, either until the maximum
count is reached (in the case of -noloop) or until the PAUSE button is
pressed.  Note that you have to hold down the PAUSE button until it becomes
active (it will not do so until the object computations are complete), so
be patient.

The RESET button causes the loop to go back to the starting position.

The slider indicates the current position of the animation, and can be 
adjusted by the user (even while the animation is running).  The slider 
can be dragged to a new location to set it, or the arrows can be used to 
move the animation in either direction (this also sets the current 
direction of motion for the animation).  Clicking to the left or right of 
the slider's handle also moves the animation to the left or right one step.

The "variable-list" specifies the values that should be animated and what 
their minimum and maximum values are.  For example:

        Animate n 10 {a 0 1}

will cause the value of a to go between 0 and 1 in 10 steps, while

        Animate n 10 {{Slider b 1 5} {Slider c} {TypeIn f -1 1}}

will animate three values (all at the same time): the first is slider "b",
which will move between the values 1 and 5, the second is slider "c", which
will move from its minimum to its maximum values (whatever they are), and
the third is the type-in "f" which will go from -1 to 1.  All three values
will change before the object is updated, and the animation will perform 10
iterations (plus one initialization).

Note that the Animate directive does not create the sliders and type-ins 
itself; they must already exist before the Animate directive is issued.  
Similarly, any variables that will be animated should also be set already.  
For example:

        set a 0; Slider b 0 1
        Animate n 10 {{a -1 1} {Slider b}}

would be one way to set up an animation.

It is possible to animate sliders, type-ins and variables in objects other
than the one containing the Animate directive.  To do so, put the name of
the object before the Slider, TypeIn or variable name.  For example, if
there is an object called "Curve" contained in a group called "Scene" then
the group can contain the directive

        Animate n 10 {Curve Slider a}

or even

        Animate n 10 {Scene/Curve Slider a}

If an object is linked to another object, you can specify

        Animate n 100 {Object Slider a}

to animate a slider in the reference object without having to know its 
name specifically.


THE WINDOW AND FRAME WIDGET CLASSES:

By default, each kind of widget appears in its own window.  This makes it
fast and easy to set up an object with several input widgets, but the
number of windows can get confusing and awkward if there are many 
different kinds of widgets.  To overcome this, CenterStage allows you to 
create your own custom windows in which to place your widgets via the 
Window directive:

	Window name [options]

where "name" is the name by which this window will be identified (for use 
by other widgets with the -in option), and "options" is a list of options 
taken from the standard set, plus the following:

	-geometry geom
            This specifies the initial geometry for the window, where
            "geom" is a standard x-windows-type geometry specification of
            the form "WxH+X+Y" (W and H give the width and height of the
            window, while X and Y give the location of the top left-hand
            corner of the window).  "WxH" can be used to give just the size
            of the window (the window will be centered), or "+X+Y" can be 
            used to give just the position of the window (it will have its 
            natural size).

	-rows row-list
            This specifies how the rows will respond to resizing of the 
            window.  The row list is a list of integers that give the 
            relative "weights" of the rows.  A zero means the row will not 
            stretch when the window is resized, a 1 means the row will 
            stretch and all the rows with a 1 will get the same amount of 
            extra space, a 2 means it will stretch twice as much as a 1, 
            etc.  For example, -rows {0 1 0 1} means that the first and 
            third rows won't stretch, but the second and fourth will 
            stretch equally to fill up the extra space.

	    It is also possible to specify a width along with the
	    stretchability by using a list of the form {s w} where "s" is
	    the stretch factor, and "w" is the minimum width (in pixels) of the 
	    row.  For example, -rows {{0 10} 1 {0 10} 1 {0 10}} would put 
	    10-pixel spaces between two stretchable columns.  This can be used to 
	    provide extra spacing between rows for better-looking layouts.

            By default, a window's row list is assumed to be all zeros.

	-columns column-list
	    This is analogous to -rows above, but handles the columns instead.

To put widgets into a specific window, use the -in and -at options when you 
define the widgets.  The -in option specifies which window to use, and -at 
the placement within the window.   The -at option gives the column and row 
where the widget will be placed (the first column and row are numbered 0, 
not 1), and optionally the width and height (in columns and rows) of the 
widget.  Objects will expand to fill their entire grid position, so for 
example if a slider appears just above a button, the column will be as 
wide as the slider and the button will expand to be just as wide.  Using 
the width and height specifications in -at can sometimes be used to avoid 
making some objects too wide.  For example, the slider could have been 
placed so that it spanned three columns and the button could be placed in 
the central column; with no other widgets present and with -columns {1 0 1} 
(so that the outer columns get all the extra space), the button would then 
be centered at its natural width below the slider:

	Window controls -columns {1 0 1}
	Slider a 0 1 -in controls -at {0 0 3 1}
	Button b -title "Hit me" -in controls -at {1 1}

Using -columns {1 1 1} would cause the button to be one third as wide as 
the slider rather than its natural width (unless its natural width were 
already wider than that); -columns {0 0 1} would cause the button to be 
left justified below the slider, while -columns {1 1 0} would make it 
right justified and half the width of the slider.

(Actually, "half" and "one third" are not quite accurate here; they are 
really half or one third of the width with the natural width of the button 
subtracted.  To get exactly half or one third, you'd need to specify 
the minimum widths of the unused stretchable columns to be the same as the 
natural width of the button; e.g., -rows {{1 54} {1 54} 0}.)

Subtle placements of this kind can be painful to set up, and it is often 
easier to subdivide one area of a window rather than specify widgets that 
span multiple columns and rows.  For this reason, CenterStage provides the 
Frame directive, which allows you to specify what is essentially a 
subwindow of a window that has its own set of rows and columns within it.
The format is:

	Frame name -in window -at {x y [w] [h]} [options]

where "name" is the name of the frame (for use with -in options for other 
widgets), "window" is the name of the window in which the frame appears, 
"x y [w] [h]" gives the position of the frame in that window, and "options" 
are taken from the standard list plus the following:

	-rows row-list
	-columns column-list
	    These have the same effect as the corresponding options of the
	    Window directive, but they operate within the frame.

	-relief style
            This specifies the outline style for the frame, where "style" 
            is one of the standard TCL/TK styles:  raised, sunken, flat, 
            ridge, groove or solid.  The default is flat, but raised is a 
            useful choice when you want to group a set of related widgets 
            together and make the grouping visually apparent.  Also, 
            several of the standard widgets (Sliders, Buttons, Evolvers and 
            Animators) have raised borders, so raising the borders on a 
            frame can help make the frame balance the other widgets better.

	-bd n
	-borderwidth n
            These two options are equivalent and specify the size of the 
            border to draw.  A border of "-relief raised -bd 2" is 
            equivalent to the borders for the Slider and other raised 
            widgets.  A border of "-flat -bd 10" would put 10 pixels of 
            space around the widgets contained in the frame.

Frames can be used to make specific placement of widgets within a layout 
more accurate (using the -row and -column directives to control the spacing 
within the frames, as discussed for the Window directive above).  For 
example, the Slider/Button example above could be handled as follows:

	Window controls
	Slider a 0 1 -in controls -at {0 0}
	Frame f -in controls -at {0 1}
	Button b -title "Hit me" -in f -at {0 0}

Here, the button will be its natural size (because it is in a frame with no 
other widgets, its column has width the same as the natural width of the 
button, and since it is in an unstrechable column, the button won't 
enlarge) and centered under the slider (the Frame stretches out to the width 
of the slider, but since there is only one column and it has no 
stretchability, this column is centered within the frame).  The -column 
specification for the Frame can be used in conjunction with the -at option 
of the Button to left- or -right justify the button within the frame in a 
fashion similar to that discussed above.

Frames can be used to make different areas of the window have different
background colors without having to specify every widget's color
explicitly (widgets obtain their colors from the containing window or
frame by default).

Finally, Frames can give raised borders to CheckBoxes and other widgets
that don't usually have them.  To do so, simply by making a frame with a
raised border that contains a single widget; e.g.

	Window test
	Frame cb -in test -at {0 0} -relief raised -bd 2
	CheckBox a -title "Hit me" -in cb -at {0 0}

Windows can appear at any level of a hierarchical object, but they are 
commonly specified in the top-most group object.  This is because children 
can put widgets into their parent's windows, but not vice versa.

Only those windows belonging to the selected object and its children (or 
the objects linked by any of these) will be shown; other windows will be 
hidden until their objects are selected.


OTHER DIRECTIVES AVAILABLE FOR ALL OBJECTS:

The objects you define are controlled not only by the menu settings, but 
by commands that you type into the definition window the object.  These 
commands are called "directives".

The following directives can be specified for any object:

    Axes {names}

        This directive specifies the number and names of the
        coordinates for the object being defined.  If not specified,
        objects inherit their axes from their parent object or the
        system default of {x y z}.  You can name the axes anything you
        want, and you can have as many as you need.  For example, to
        specify an object in four dimensions, use

                Axes {x y z w}

        CenterStage will automatically switch to Geomview's ND mode
        for viewing the object, showing the first three axes.

        The names of the axes determine the variables that you need to
        set when defining an object.  For example, to specify a 4D
        surface using the axes listed above, you need to give values
        for x, y, z, and w.  For example:

                Domain {{-1 1 10} {-1 1 10}}

                Function {x y} {
                  let Z = (x,y)
                  let (z,w) = Z^2 + Z
                }

                Axes {x y z w}

        This uses x and y as the parameters for the surface, and
        creates z and w as the result of a complex polynomial.

        The Axes directive also has a second form, which provides a means
        of specifying a projection that will occur before the object is
        displayed in Geomview.  This is done by following the axes by "->"
        and a second list of axes, which are the ones to use in the
        display.  For example:

                Axes {x y z w} -> {x y w}

        would provide computations in 4-space with results shown in 3-space
        via the projection along the z-axis.  Without this, geomview would
        display the 4-dimensional data using its ND-viewing mode. 
        Unfortunately, there are some problems with this mode, in
        particular, on some platforms, no shading is done on the object, so
        all objects appear as though they used SHADING/CONSTANT or
        SHADING/CSMOOTH, which is not as effective visually.  Forcing the
        object into 3D mode with the projection above causes a much more
        pleasing result (the disadvantage is that the object can't be
        manipulated as a 4D object within geomview, and would need to be
        recomputed if you wanted to rotate to view it from another
        direction).  Another problem with geomview's ND mode is that it
        doesn't normalize objects correctly, while the 3D mode does. 
        Finally, the ND-mode projection is always orthographic, while it is
        possible to as CenterStage to do a stereographic projection.

        To obtain a stereographic projection, use the following form:

                Axes {x y z w} -> {x y z} -stereo distance

        where "distance" is a formula (or constant) that specifies the
        height of the projection point for the stereographic projection. 
        The projection is from this distance along the axis that is missing
        from the second set of axes, in this case the "w" axis.  If 
        distance is zero, then the projection will be orthographic.

        If you use the form

                Axes {x y z w} -stereo distance

        then CenterStage will assume the projection is along the last axis
        listed.


    Appearance appearance

        This lets you specify arbitrary Geomview appearance characteristics
        for your object (specifically those that are not available in the
        APPEARANCE menu, such as material and lighting effects).


    ColorFunction name function

        This lets you specify a color function which you can select in the
        COLOR/BY FUNCTION menu.  The name is what will be used in the menu,
        and the function is what computes the color for the different
        points on the surface.  This should be a single equation that
        returns either a single value (which is the index into the color
        table for this point) or a triple of numbers (which is the RGB
        values for the color).  See CHANGING COLORS above for more
        information about color functions.


    Setup script

        This lets you specify a TCL script that should be run just before
        the object is computed.  This lets you set up values or variables
        that are needed by the rest of the object.  For example, you can
        set up needed values for a surface:

            Domain {{-1 1 10} {-1 1 10}}

            Function {u v} {
              let (x,y,z) = (u,v,u v) + V
            }

            Setup {
              let V = (p,q,0)
            }

            Slider p -1 1
            Slider q -1 1


    ShowMe boolean

        This specifies whether the current object should be displayed in
        Geomview (if its OBJECT/SHOW menu allows it).  The main idea for
        this directive is to allow the object to use a check-box or other
        computation to determine whether it should be displayed.  For
        example:

                CheckBox show
                ShowMe show

        will control the visibility of the object through a checkbox; the
        object will not be showing initially (since the check-box is
        unchecked by default) but will be computed and displayed when the
        check-box becomes selected.


    Transform transform-list

        This lets you specify a collection of transformations that are to
        be performed on the final object before it is displayed.  For
        example, you can specify rotations, scalings, translations, etc. 
        Moreover, these can depend on values like the ones from sliders or
        computed values set within the Setup script; for example, you can
        have a rotation that depends on the value of a slider.

        The available transformations can be chosen from among the
        following ones:

            XY(a)       Rotate in the xy-plane by an angle of "a" radians
            XZ(a)       Rotate in the xz-plane by an angle of "a" radians
            XW(a)       Rotate in the xw-plane by an angle of "a" radians
            YZ(a)       Rotate in the yz-plane by an angle of "a" radians
            YW(a)       Rotate in the yw-plane by an angle of "a" radians
            ZW(a)       Rotate in the zw-plane by an angle of "a" radians

            AxisRotate("X","Y",a)
                        Rotate in the plane of the axes given by "X" and
                        "Y" in angle of "a" radians.  Here "X" and "Y" can
                        either be the name of the axis (as specified in the
                        "Axes" directive) or the numeric index of the axis
                        within the list of axes (where the first axis is
                        number 1, etc).  E.g., AxisRotate(0,1,pi)
                        represents a rotation of 180 degrees in the
                        xy-plane.

            Rotate(U,V,a)
                        Rotate in the plane specified by the two vectors
                        U and V by an angle of "a" radians.

            Spin3D(U,a) 
                        Rotate around the vector U an angle of "a" degrees
                        (for objects in 3D only).

            Scale(s)    Scale the object by the given amount, where "s"
                        gives a scaling factor (1.0 means stay the same, 
                        > 1.0 means enlarge and < 1.0 means shrink).  If "s"
                        is a vector, then it specifies a separate scaling
                        factor for each axis.

            Translate(V)    Translate the object by the given vector.

            ReflectX    Reflect the object by negating its x-coordinates.
            ReflectY    Reflect the object by negating its y-coordinates.
            ReflectZ    Reflect the object by negating its z-coordinates.
            ReflectW    Reflect the object by negating its w-coordinates.

            AxisReflect("X")
                        Reflect across the specified axis (either the name
                        of the axis (in quotes) as given in the Axes
                        directive, or the numeric index of the axis, where
                        the first is 1).

            Reflect(V)  Reflect along the direction given by the vector V (so
                        that V becomes -V).

        Note:  all the transforms above can have an optional point specified
        as well, which indicates the center for the operation.  For example, 
        XY(a,p) would rotate in the xy-plane around the point "p" (which is in 
        the dimension of the full ambient space, not just 2 coordinates).


            Roll(n)     Rotate the coordinates of the points right by "n"
                        positions (ones that move off the right are rotated
                        back in on the left).  If "n" is negative, then the
                        rotation is to the left.  For example, if the
                        object includes the vertex (1,2,3), then Roll(1)
                        will transform it to (3,1,2) (as will Roll(-2)),
                        while Roll(2) will transform it to (2,3,1) (as will
                        Roll(-1)).

            Exchange("X","Y")
                        Interchanges the two coordinates specified (either
                        as the names of the axes, in quotes, as given in
                        the Axes directive, or by as numeric indices of the
                        axes).

            Project("X Y Z")
                        Specifies an orthographic projection onto the
                        indicated axes (given either as names or indices). 
                        This does not actually change the dimension of the
                        result, it merely puts zeros into the other
                        coordinates of the points.

            {Stereo d ["X"]}
                        Specifies stereographic projection from a distance
                        "d" along the specified axis (if no axis is given,
                        the right-most axis from the Axes directive is
                        assumed).  As with Project above, this does not
                        actually change the dimension of the result as the
                        coordinate in the position of the projection axis
                        is set to zero.  Note that this transformation must 
                        be enclosed in braces, with no parentheses.  If d 
                        is zero, then the projection will be orthographic.

        The "transform-list" can be a list of these transforms, each
        enclosed in braces.  The object is mapped through all the
        transforms, from right to left (as in function composition) before
        it is displayed.  For example,

                Transform  Scale(2) XY(pi)

        would do a rotation of 180 degrees then a scaling by a factor of 2
        (note that the braces are really only needed if there are spaces
        within one of the transformation specifications.

        There are several additional types of transforms that can be
        specified within a transformation list:

            {Matrix M}  Specifies a transformation matrix that should be
                        used to transform the objects.  Note that the
                        transformations are performed in homogeneous
                        projective coordinates, so the matrix should really
                        be in one dimension higher than the object itself
                        (this makes it possible to specify a translation in
                        matrix form, for example; in fact, all the
                        transforms listed above other that stereographic
                        projection are represented internally as matrix
                        operations).  An extra column and row are added to
                        M if the dimension is too small.

            {Map expr}  Specifies an expression that represents the
                        transformed point, using the axis variables to
                        indicate the values of the coordinates.  For
                        example {Map (y,x,w,z)} would interchange x with y
                        and z with w (if the axes were given with "Axes {x
                        y z w}"), while {Map (x+y,x-y,z)} would perform a
                        more complicated transformation.

            {Apply f [args]}
                        Calls the function "f" with the coordinates of the
                        point to be transformed (followed by any additional
                        arguments specified) and uses its return value for
                        the transformed vertex.  For example,

                                proc Flip {x y z w} {
                                  let P = (y,x,w,z)
                                  return $P
                                }

                                Transform {Apply Flip}

                        would interchange x with y and z with w.

            {vApply f [args]}
                        Calls the function "f" with the point to be
                        transformed as a single list rather than separate
                        coordinates, followed by any additional arguments
                        specified.  For example,

                                proc Cross {v x y z} {
                                  let w = v >< (x,y,z)
                                  return $w
                                }

                                Slider t 0 1
                                Transform {vApply Cross (1,0,t)}

                        would adjust each point in the object by crossing
                        it with the vector (1,0,t), where the value of t is
                        given by a slider.

            {fApply f [args]}
                        For polyhedral objects, this calls the function "f"
                        with each face of the polyhedron (rather than each
                        vertex).  The return value of "f" should also be a
                        face.  For example:

                                proc Shrink {f s} {
                                  let (p0,p1,p2) = f
                                  let p = (p0+p1+p2) / 3
                                  let M = Scale(s,p)
                                  let f = (M p0, M p1, M p2)
                                  return $f
                                }

                                Transform {fApply Shrink .9}

                        will take every face of the polyhedron and shrink
                        it toward the center of each face by 10% (here all
                        the faces are assumed to be triangles; a more
                        sophisticated routine could be used to handle
                        arbitrary faces).

            {lApply f [args]}
                        Calls the function "f" on the complete list of
                        faces or vertices for the object.  One reason to
                        use this transform is if you want to change the
                        number of faces in a polyhedron.

            {Copy [-noidentity] transform-list}
            {Copies [-noidentity] transform-list}
                        This transform produces DUPLICATES of the object,
                        one for each transform in the list.  For example,
                        you can use this method to generate a complete
                        polyhedron using its symmetries and a small number
                        of faces.  E.g.

                                Transform {Copy ReflectZ} \
                                          {Copy ReflectY} \
                                          {Copy ReflectX}

                        would generate an object with three planes of
                        mirror symmetry.  Eight copies of the original
                        object would be produced (if the original were in
                        the first octant, then the copies would be one in
                        each of the eight octants).

                        Note that 

                                Transform {Copies ReflectZ ReflectY ReflectX}

                        is quite different, since it means four objects are
                        produced (three copies and the original) rather
                        than the eight of the previous example.

                        The -noidentity flag prevents the original object
                        from being retained, only the copies are included
                        in the final object.  The two words "Copy" and
                        "Copies" produce exactly the same result, and are
                        included only for readability.

            {Compose transform-list}
                        This transforms the object by the composition (from
                        right to left) of the specified transformations. 
                        It is useful mainly within Copies lists, where one
                        of the copies requires several transformations.

            {if expr transforms [else transforms]}
                        This performs a given set of transforms only when 
                        the condition specified by "expr" is true.  If 
                        false, the second set of transforms are 
                        performed (if any are given).  For example

			    Transform {if {doScale} Scale(.5) Translate(1,0,0)}
			or
			    Transform {if {ortho} {Project("x y")} else {Stereo 1}}

        Transformation lists provide a powerful tool for manipulating
        objects, particularly ones that are easily defined in one
        coordinate system but need to be displayed in another.

In addition to these directives, you can also perform arbitrary TCL
commands within the script of an object.  For example, you can use the
"proc", "set", "let", "global", "if" , etc.  commands to do more
complicated processing while the object is being defined.  Note that
variables and procedures are local to their defining object, but that
children inherit variables and procedures from their parent groups.  This
includes values of sliders, check-boxes, etc.  Thus you can specify a
function in a group's definition that will be available to all its
children.



EXPRESSIONS AND THE "LET" STATEMENT:

CenterStage uses TCL as its underlying language, so when you specify
functions while defining CenterStage objects, you use TCL scripts.  This
gives you powerful programming constructs, like if-then statements,
for-loops, user-defined procedures, and more.  But it also means you are
limited to some of TCL's peculiar syntax.  In particular, TCL does not
evaluate expressions unless you explicitly request it, and its expression
syntax is not very mathematical, especially where variables are concerned.

CenterStage tries hard to remedy this situation in two ways:  first, it 
attempts to evaluate expressions automatically whenever this would be 
appropriate, so you will rarely need to use the TCL "expr" command.  For 
example, if you specify a Vertex directive in a Polyhedron object, you can 
include expressions to compute the coordinates of the points and they will 
be evaluated automatically.

Second, CenterStage provides a replacement for the "expr" command that has 
a more mathematical syntax, and also implements complex numbers and vector 
arithmetic.  Normally in TCL, to set a variable equal to the result of an 
expression you must do something like "set x [expr $y+2*$z]".  This seems 
needlessly complex, so CenterStage provides an easier alternative via the 
"let" command:

    let x = y + 2z

The format for this command is:

    let var = expr
    
where "var" is a variable name and "expr" is an expression.  The equal sign
is required, unlike in the TCL "set" command, where it is absent.  In a
"let" command, the expression is evaluated using the new expression
evaluator and the result is assigned to the variable on the left.

Note that in the expression, dollar signs are not needed in front of
variable names, and multiplication is implied by concatenation.  This
should follow natural mathematical notation much more closely than the
standard TCL "expr" command.

Vectors and matrices are implemented though TCL lists, which can be
specified in the standard TCL form by using braces, as in

    let X = {1+t t^2}

or through a more mathematical notation using parentheses and commas:

    let X = (1+t,t^2)
    
Vectors can be used just like scalar values.  They can be assigned to
variables, added and subtracted, multiplied and divided by scalars, etc. 
There are also some special operations and functions for vectors, such as
vector cross- and dot-products and vector norm (see below).

Vectors of length two are treated as complex numbers and can be multiplied
and divided and raised to a scalar power.  There are also complex functions 
such as sine, cosine, log, exp, etc.  (see below).

CenterStage provides matrix-vector and matrix-matrix multiplication for
square matrices.  A matrix is represented as a vector that is of length
equal to a perfect square.  If such a matrix is multiplied by a vector of
the same length, this is done as matrix-matrix multiplication.  If a vector
of length n*n is multiplied by a vector of length n, then matrix-vector
multiplication is performed.  For example,

    let V = { (cos(t), -sin(t),
               sin(t),  cos(t)) * (x,y)}

will perform matrix-vector multiplication using the rotation matrix on the
left and the 2-vector (x,y) on the right.  Basically, it tries hard to do
the right thing when it sees multiplication.


IMPLIED MULTIPLICATION AND FUNCTION CALLS:

Multiplication and function calls are implied by concatenation.  For
example

    let x = 2y

sets x equal to twice the value of y, while

    let x = sin y

sets x equal to the value of the sine of y.  Function-apply has slightly
higher precedence than implied multiplication, so

    let x = sin y cos z

sets x to sin(x)*cos(z).  This has the drawback that

    let z = sin x y

sets z to (sin x)*y rather than sin(xy).  On the other hand, explicit
multiplication has higher precedence than implied function calls, so

    let z = sin x*y

sets z to sin(x*y).


OPERATORS, PRECEDENCE AND FUNCTIONS:

The operators available are:

    +      addition of scalars, vectors or matrices
    -      subtraction of scalars, vectors or matrices
    *      multiplication of scalars complex numbers, or scalar-vector, 
             scalar-matrix, matrix-vector or matrix-matrix multiplication.  
             * is implied by concatenation, except within braces when a 
             space is used as a separator in a list
    /      division of scalars, complex numbers, or vector by a scalar
    %      remainder after division of integers
    ^      exponentiation of scalars or complex numbers
    ><     vector cross product (for 3-vectors only)
    .      vector dot product
    @      vector element extraction, e.g., (3,2,5)@0 is 3, (3,2,5)@(1,2) 
            is (2,5), etc.
    ::     vector concatenation, e.g., (3,2,5)::(1,2) is (3,2,5,1,2), 
            and (3,2,5)::0 is (3,2,5,0)
    _      array subscripting, e.g., a_0 corresponds to the TCL variable 
            a(0) while a_(x+1) corresponds to a(3) if x is 2.
    <      scalar comparison for less-than
    >      scalar comparison for greater-than
    ==     scalar, vector, matrix, string comparison for exact equality
    ===    scalar, vector, matrix comparison for near equality
    <=     scalar comparison for less-than-or-equal
    >=     scalar comparison for great-than-or-equal
    !=     scalar, vector, matrix, string comparison for not equal
    !==    scalar, vector, matrix comparison for not nearly equal
    =      assignment operator
    &      boolean AND
    |      boolean OR
    ^^     boolean XOR
    !      boolean NOT
    &&     bitwise AND
    ||     bitwise OR
    ~      bitwise NOT
    <<     integer shift left, e.g., 1<<2 is 4, or vector rotate left, e.g.
             (1,2,3) << 1 is (2,3,1)
    >>     integer shift right e.g., 4>>1 is 2, or vector rotate right,
             e.g., (1,2,3) >> 1 is (3,1,2)

The operators grouped by precedence (highest to lowest) are:

     _
     !   ~
     @   ::
     ^
     *   /   %   ><   .
     implied function calls, e.g., sin x
     implied multiplication, e.g., 2 x
     +   -
     <<  >>
     <   >   <=   >=
     ==  !=  ===  !==
     &
     ^^
     |
     &&
     ||
     =

The built-in functions are the following:

     cos, sin, tan     (standard trig functions for real and complex numbers)
     acos, asin, atan  (standard inverse trig functions)
     atan2             (atan2(x,y) returns the signed angle formed by the 
                        positive x-axis and the ray from the origin through 
                        the point (x,y))
     cosh, sinh, tanh  (the hyperbolic trig functions)
     hypot             (hypot(x,y) is sqrt(x^2+y^2))
     exp, ln, log,     (real and complex exponential, and logarithm; both
                        ln and log are the natural log)
     log10             (real logarithm base 10)
     pow               (pow(x,y) is x^y, for compatibility)
     sqrt              (real and complex square root)
     abs               (absolute value of scalars and vector norm)
     ceil, floor       (least-integer and greatest-integer functions)
     round             (nearest integer)
     int               (integer part of)
     double            (convert to real)
     fmod              (fmod(x,y) is the real remainder of x divided by y)
     rand, srand       (random number generators, see TCL manuals)

     Sgn               (Sgn(x) is -1 if x<0, 1 if x>0 and 0 if x==0)
     Norm              (vector norm)
     Unit              (Unit(x) is a unit vector in the direction of X)
     Conj              (complex conjugate)
     Arg, Mod          (complex argument and modulus)
     Re, Im            (real and imaginary parts)
     Max, Min          (largest or smallest element in a list)


You can also provide your own functions that will be called automatically
from within the expression evaluator.  To do so, simply use the TCL "proc"
command to define a function and be sure that it returns a scalar value,
then call it in an expression just as though it were one of TCL's built-in
functions.  For example:

        proc F {x} {
          upvar a a
          let y = x^2 - 2x + a
          return $y
        }

        let z = F(x) + F(x-1)

Here, the procedure F is defined to evaluate a polynomial (that depends on
the value of the variable a, which could be tied to a slider, or to a value
defined in a Setup script).  The last statement then defines z as the value
of this polynomial at x plus the value of the polynomial at x-1.

You can pass more than one argument to a function as follows:

        proc F {x y} {
          let n = (x,y) . (x,y)
          return $n
        }

        let z = F(x,y)

        let X = (x,y)
        let z = F(X)

        let z = F(X + (1,0))

Here, the function expects two arguments and these can either be passed
explicitly (as in the first definition of z) or as a vector (as in the
second case).  The final case performs a vector computation and passes the
result to F.

Note that if a vector-valued quantity is passed to a function, it is broken 
into its components and each one is passed as a separate argument to the 
function.  If you really want the vector passed as a vector, use the 
special parentheses "(:" and ":)"

	proc F {v} {
	  let n = v.v
	  return $n
        }

	let X = (x,y)
	let z = F(:X:)

	let z = F(:x,y:)

Here the vector X is passed as a vector rather than two components, and so 
is the vector (x,y).

You can define a vector-valued function (one that returns a vector result) 
by using the "vproc" command:

        vproc F {x y} {
          let X = (y,x)
          return $X
        }

        let (a,b) = F(X)

Here, the function F switches its two arguments, so if X is (1,2) then the 
result of the final statement will be to assign 2 to a and 1 to b.


SOME ISSUES OF SPACING:

TCL uses spaces to separate items in a list so there is ambiguity about an 
expression like "{1 -t t^2}"; does it mean "(1,-t,t^2)" or "(1-t,t^2)"?  
It turns out to be the former, which seems to make sense.

On the other hand, while the parenthetic form is not ambiguous even if
spaces are inserted, the fact that TCL uses spaces to separate items in a
list makes it difficult to use the parenthetic form in situations where TCL
expects a list (as in Domain directives).  In these cases you may find it
more convenient to use the braced form.

Also, since TCL ends a command at a line break, it is sometimes necessary 
to enclose the entire expression in braces:

    let X = {(1+t^2,
              sin(t)-cos(2t),
              log(t^2+1))}

In general, you do have to be a careful about spaces and line breaks.


EXPRESSIONS OUTSIDE OF THE "LET" COMMAND:

The new expression evaluator in CenterStage only operates within the "let"
command and within object directives, but not within standard TCL commands. 
For example, if you write a script for a Function directive and want to use
an if-then statement, the if expression uses the standard TCL expression
syntax, not the enhanced one defined above.

There are two ways around this problem:  either use a "let" command prior 
to the if-then to obtain the result of the expression using the enhanced 
mathematics, as in

        let result = ((x,y,z) == (1,0,0))
        if {$result} { (do what you need to do) }

or use the "Math" command, which works like the "expr" command, but with 
the new expression evaluator, as in

        if {[Math (x,y,z) == (1,0,0)]} { (do what you need to do) }

This is not necessary in most directives that take numeric arguments, as 
these are processed by the "Math" command automatically.  You should only 
need to use this if you are writing TCL scripts like those used in the 
Function and Setup directives.


DECOMPOSING A VECTOR:

In a "let" command, the variable on the left can actually be a list of 
variables, as in

     let (x,y,z) = (t,t^2,t^3)

Here, the result on the right is a vector, and x is assigned the value of
the first component of the result, y the value of the second component, and
z the value of the third component.  This is especially useful when the
right-hand side is the result of a vector computation, as in

     let (x,y,z) = (t,t^2,t^3) >< (1,2t,3t^2)

When the "let" command is used in this way, both the list on the left and 
the result on the right must have the same number of components.


LISTS WITH ONLY ONE ITEM:

Standard mathematical notation uses parentheses to indicate lists of
coordinates, as in "the origin is at (0,0,0)" as well as grouping within
expressions, as in "(x + 4) / 3".  This notation is ambiguous in the sense
that since "(0,0,0)" and "(0,0)" are lists with 3 and 2 items, "(0)" should
be a list with one item, but we don't want the "(x + 4)" in "(x + 4) / 3"
to be thought of as a list.

CenterStage resolves this ambiguity by assuming that parentheses ALWAYS
mean grouping (lists are constructed by the commas, not the parentheses). 
This means "(0)" is the same as the number 0, and so is "((0))", or any
number of parentheses around a zero.  Moreover, "((3,1))" is just the
vector (3,1) (not the vector of length one containing the vector (3,1) as
its only entry), and if X is the vector (3,1), then "(X)" is just the
vector (3,2) (not the vector of length one containing the vector X).  In
fact, the standard notation does not provide an unambiguous method of
specifying a vector of length one.  CenterStage solves this by using a
special set of parentheses specifically for constructing length-one
vectors.  These are "(:" and ":)", so "(:X:)" is the vector containing the
vector (3,1) as its only element, and so is (:3,1:).

An alternative is to use "list(X)" or "list(3,1)" both of which return the 
list of the vector (3,1).  In TCL notation, this is {{3 1}}.

The need for this notation is rare, but one case where it is important is 
in passing values to user-defined functions (see OPERATORS, PRECEDENCE AND 
FUNCTIONS above).  Another is in constructing lists of vectors when you 
want a list with just one vector in it.


FUTURE ENHANCEMENTS:

There are still quite a few object classes that need to be written.

The color editor needs improvement.
The library mechanism is pretty dismal.
Font handling could be improved.

The script window should have more keybindings and more sophisticated 
editing features (find and replace, smart indenting, etc).

There should be a way to copy and paste entire objects (right now you have 
to export and import them).

Linked objects should be able to inherit colors from their target objects.

There needs to be a mechanism for getting click events from Geomview as a 
means of input to CenterStage objects.  This can be done via Geomview's 
interest and pick commands.  It might also be useful to have a 2D input 
device analogous to the slider (some sort of draggable cross-hair thing).

Everything needs to be optimized for speed.

Error reporting relies too much on TCL's error mechanism, so some errors 
are pretty cryptic when they occur.

Group transformations currently are handled by having the child object 
append the transforms onto its own list.  This means that objects linked to 
the child object will get data that includes the group transform, which is 
not what one would expect.  This mechanism needs to be improved.

When a group object is selected, all its children and their linked objects
are scanned for widgets that need to be included in its windows.  A caching
scheme should be worked out to reduce the overhead involved in selecting an
object.

Currently there are redundant or unneeded commands being sent to Geomview.  
This I/O is time-consuming and should be reduced.

There need to be instructions for users to create their own object classes.


BUG REPORTS AND COMMENTS:

Please send bug reports and comments to <mailto:dpvc@union.edu>.
