Plotter package
Given a data set, one would like to represent that data with a 3-D object, and
there are obviously a very large number of ways to do this. What we want is to
capture some abstract ideas that will make this task easier. Some things one
would like to do:
- Build the representation in an object-oriented fashion allowing reuse of
components. For example, if you write an alogirthm for setting the colors of
a type of object, you'd like that to work no matter how those objects are
rendered.
- Allow runtime customization of the building algorithm.
- Hide the details of the 3D representation as much as possible from the
application level.
- Store information about how the 3D representation was built so it can
be modified later.
The current implementation is closely tied to the Java3D library, but some
effort has been taken to avoid explicit references whereever possible. The
three essential classes are ObjectGroup, PlotStrategy, and PlotCommand.
An ObjectGroup object wraps the constructed 3D representation. The idea is
to provide three levels of access. The application level can toss around
ObjectGroups without knowing anything about how they are constructed. The
viewer can extract a 3D representation suitable for sending to the
renderer. Finally, specific tools can access and manipulate the internal
structure of the representation to make incremental adjustments to the
3D representation.
A PlotStrategy object defines how to construct a 3D representation of the data.
PlotStrategy itself is an abstract class that defines generic building methods.
These methods are overridden by subclasses to produce custom visualizations.
The components of a PlotStrategy are enumerated below.
The PlotCommand object mediates communication between the data source and the
plotting routine. A PlotCommand contains a DataReader, a predicate, and a
PlotStrategy. PlotCommand provides methods identical to DataReader's data
access methods but without the predicate. A PlotCommand builds an ObjectGroup
by calling its PlotStrategy with a reference to itself; data access commands
are passed on to the DataReader after appending the predicate. In this way
a PlotCommand completely encapsulates a 3D representation of a particular
subset of a particular data set. The ObjectGroup is itself stored in the
PlotCommand for later reference. In future versions, the PlotCommand will
be the key functional object.
PlotStrategy components
Building a 3D representation of data, as described by the PlotStrategy object,
can be broken down into some components that are generically useful. The
following components are currently defined:
- PositionStrategy
- returns the (x,y,z) positions of the objects to be plotted.
- PolygonStrategy
- returns the locations of the vertices of a polygon. These
can be combined with the positions from a PositionStrategy to represent every
object as a complex ploygon.
- ColoringStrategy
- returns a color for each object
- AlphaColoringStrategy
- an alpha color contains 4 numbers: the usual rgb values plus an alpha value.
Alpha values are useful when two objects would overlap on the screen. Instead of
simply showing the closest one, the alpha values can be compared to determine
which object is more "significant" and should be plotted. An AlphaColoringStrategy
takes a set of normal colors (from a ColoringStrategy) and adds an alpha value
for each object.
- AppearanceStrategy
- An Appearance object defines various rendering parameters for a 3D object,
in constrast to vertex-by-vertex parameters. An AppearanceStrategy returns an
appropriate Appearance object. These usually have more to do with the plotting
strategy than with the data set.
A PlotStrategy uses concrete instances of some or all of the above classes to
help it do its work. A PositionStrategy and AppearanceStrategy are
mandatory; the others are optional. Additional components will likely be added
in the future.
A PlotManager object stores PlotStrategy objects keyed by name. This is a
convenient way to store PlotStrategies for later use. A PlotCommand can be
constructed with a PlotManager instead of a PlotStrategy, and the correct
PlotStrategy to be used will be dynamically determined by examining the
supplied predicate.
Exception handling
All kinds of terrible things can happen when trying to assemble a 3D representation.
For example, suppose that a call for positions returns 1000 positions, but a call
for colors returns only 998 colors. What should happen now?
First, we've adopted the standard that everything should be checked whereever
it could matter. This means that an assembler should check everything coming
from its components before assembling. In particular, all plotter classes should
check any incoming data for null values and empty arrays before trying to use
them. In practice the cost for this is low, since checking a large array is much
faster than building it in the first place.
Second, the plotter should not throw fatal errors and crash the system. If something
bad happens, the user should be notified as to what went wrong, and the plotter
should try to go along as best as possible. One way this is handled is via the
PlotterMessageHandler. This is a singleton class that provides methods for
handling messages and exceptions in a uniform way. The default behavior is to
simply write a message to stdout, but this can be easily reconfigured. Classes
in the plotter package should route all their exceptions and complaints to this
class and carry on. For example, in the above case the builder should send a
warning message to PlotterMessageHandler, then set the first 998 colors and leave
the other two missing. This carries all the way to the top application level,
where scenes should be checked for non-zero content before passing them on.
This is not the only way to handle errors, and possibly not the best way, but
we've decided on this as the most reasonable for now.
As you can probably see, there is still room for more design in this package. Its
structure is continually revised by incorporating new abstract ideas. Much of
the current design is chosen to allow these future revisions without forcing a
complete rewrite of the whole package.
Home NVisF Design
This page last updated Jan 2 2001.