6.5 million software developers and still going strong

Java Developer Magazine

Subscribe to Java Developer Magazine: eMailAlertsEmail Alerts newslettersWeekly Newsletters
Get Java Developer Magazine: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn

Java Developer Authors: Douglas Lyon, Stackify Blog, Glenda Sims, APM Blog, Pat Romanski

Related Topics: Java Developer Magazine

Java Developer : Article

Java Feature — Graph3D

Visualizing data using Java3D

In today's work environment analyzing large amounts of varying data types is paramount. Graphing techniques can be an invaluable tool to understanding and interpreting that data. In many cases two-dimensional graphs, such as XY, scatter, pie, and bar charts, are sufficient. But increasingly more complex graphing techniques are needed. In these instances Java3D is an excellent resource with numerous features that allow personalized generation of three-dimensional data displays. Not only will Java3D yield better insight into the data by highlighting important aspects of the data, but it also makes attractive displays to spice up any presentation.

Before going into a detailed description of the Graph3D application and its execution, a basic understanding of Java3D is necessary. Java3D provides a rich set of functionality for viewing, constructing and manipulating geometric objects. Describing all the capabilities of Java3D is beyond the scope of this article, but it includes functionality for light modeling, solid and surface generation, object transformations, texturing and 3D text.

In Java3D, objects and transformations are built using a hierarchical tree structure as illustrated in Figure 1. The following are key classes of the tree.

  • Simple Universe - The top of the tree is the Simple Universe. It creates the default viewing parameters for the 3D display. In most instances, the user doesn't perform operations with the Simple Universe except to make it the root of the hierarchical tree.
  • BranchGroup - A BranchGroup is a tree node that holds logical groupings of objects. They are used to hold other nodes or to start a new tree branch.
  • TransformGroup - A TransformGroup is a tree node that can apply transformation matrices to its children. TransformGroups can contain multiple BranchGroups and other TransformGroups for complex transformations. A class that's added to TransformGroups is the Transform3D class. It's used to hold transformation matrices and is added by using the setTransform() method. Transform3D will transform all the children of the TransformGroup. It also has helper methods to create matrices for rotations, scaling, and translations.
  • Leaf - A Leaf node is where most of the objects are defined, such as lines, text, surfaces, and solids. The Leaf class is an abstract class and as such cannot be instantiated. It also has no children. Instead, the Shape3D class (a subclass of Leaf) is used. Shape3D also include attributes for coloring, polygon fill, transparency, and material type. If the object to be drawn is a sphere, cylinder, box, or cone, Java3D has special classes that do much of the work for you. These special classes are subclasses of Shape3D. You can easily add textures to a Shape3D object. Textures are images that are draped over surfaces or solid models. For example, a sphere can be wrapped with an image of the earth to form a globe. Shape3D instances are added to BranchGroups or a TransformGroup for transformation.
Besides the tree classes, all Java3D programs must use a Canvas3D. It's a member of the java.awt(AWT) package and a Graphical-User-Interface(GUI) component that's usually added to a Frame or a javax.swing.JFame. It's where the 3D rendering is done and has methods that set the eye viewing positions. The Canvas3D coordinate space defaults to a range of -1.0 to 1.0 for each axis. The center of the scene is 0,0,0 with the x-axis horizontal, y-axis vertical, and the positive z-axis coming out of the computer terminal.

Java3D includes three mouse behavior classes (MouseRotate, MouseZoom, MouseTranslate) that are used to rotate, zoom, and translate the display. They automatically compute and apply the transformation matrices to the TransformGroup specified in the constructors for the mouse behaviors. On a two-button mouse, MouseRotate is activated by depressing the left button and dragging the cursor in a horizontal (y-axis rotation) or vertical(x-axis rotation) motion. MouseTranslate is activated by depressing the right mouse button and dragging the cursor left and right. Activating MouseZoom is done by holding down the ALT button while dragging the left mouse up and down. This zooms the display in or out.

Light sources are used to realistically model solid objects. Java3D light source options include PointLight, SpotLight, Directional, AmbientLight, or any combination. They can be added as children to a BranchGroup. If this is done, the whole BranchGroup will be rendered with these light sources. For the Graph3D application, a separate BranchGroup was made to hold the light sources. The BranchGroup was then added as a child to the BranchGroup known as "objRoot." This was done so that the light sources could be easily detached from the Java3D hierarchical tree to make a wire frame display of the 3D graph. The definition of the light sources and how they are used is a complex subject and additional references should be consulted.

For a more complete description of the tree and on getting started with Java3D, an excellent Java3D tutorial can be found at java.sun.com/developer/onlineTraining/java3D/.

Graph3D Description
The Graph3D application is a program that plots three-dimensional data from a text file as illustrated in Figure 2. It is comprised of eight classes: Graph3D, FileIn, GraphData, BoundaryBox, Axis, Labels, Graph, and Grid. Included with the source code for Graph3D are JApplet1.java and Standalone.java. JApplet1 enables Graph3D to run from a web browser and Standalone enables it to run as a standalone application.

The following is a description of the sequence of events when the Graph3D application is executed. Both JApplet1 and Standalone pass an instance of a GraphData object into the constructor of Graph3D.java. GraphData reads in the data from a file using FileIn.java. Inside of Graph3D.java the SimpleUniverse is created and the top-level BranchGroup, called objRoot, is created with a call to the method createSceneGraph(). This method creates a BranchGroup with a TransformGroup as a child. Inside of the createSceneGraph() method a TransformGroup, called objTrans, is created and contains a Transform3D object that will handle the transformation matrix that applies to the whole scene. Three mouse behaviors (MouseRotate, MouseZoom, MouseTranslate) are added to objTrans. These behaviors allow for the automatic computation and application of the transformation matrix to objTrans. For the mouse behaviors to take effect, objTrans must set the appropriate capabilities. Use ALLOW_TRANSFORM_READ and ALLOW_TRANSFORM_WRITE in the setCapability() method of TransformGroup to allow the transformation matrix to be read and written. Unfortunately, the default behavior of Java3D doesn't to let the matrix be read and written. In Java3D, many capabilities that a user would expect to have as a default must be explicitly set using setCapability() methods.

Next, the graph labels, axes, grid, and surface are generated via the classes Labels, Axis, Grid, and Graph. These are all subclasses of the Shaped3D class and are added to objTrans. All children of objTrans will be transformed using the mouse to transform the display. And finally a BranchGroup is added to objRoot called lightRoot that will handle the lights to be applied to the scene. The lights are made via a call to the makeLight() method in Graph3D.java. AmbientLight and two PointLight sources are used to shade the scene.

The following describe the vital functions:

  • Graph.java does the 3D surface construction of the data to be plotted. The data is stored in the GraphData object as a two-dimensional array and are converted into a Point3f array so that they can be used by the QuadArray class. Any solid modeling that requires shading must be defined in a QuadArray or a TriangleArray. These two classes let surfaces be created using a grid of rectangles and triangles. Both the QuadArray and the TriangleArray also need an array of surface normals passed into their constructors. All shading algorithms require the surface normals of each individual quad or triangle so that they can apply the appropriate color. Other attributes of the data, such as transparency, material, and polygon fill are also set in the Graph class.
  • Grid.java takes the QuadArray formed in the Graph class as an input to its constructor. Grid takes the QuadArray and draws it as lines instead of filled polygons as in the Graph class. The grid attributes are also set in this class. In Grid.java, you'll notice a call method setPolygonOffset(). Polygon offset is a necessary capability that must be used to display the line grid on top of the filled surface. Since the grid data points have the same vertices as the filled polygon surface, both can't be displayed at the same location or seen unless the surface is translucent. Basically it "nudges" the line grid to a slightly different coordinate so the vertices of the grid can be seen.
  • Axis.java creates the 3D axis lines. All the vertices of each axis are put into a LineArray that's used for the geometry of this Shape3D class. Note that our example data has only positive y-axis values. If your data have negative values this class will have to be augmented.
  • Labels.java constructs the labels needed for the three axes. This class isn't a subclass of the Shape3D class. It makes a separate Shape3D object for each of the labels and for the graph title. Notice that the labels are added as children to a separate TransformGroup. This is necessary so that the labels can be scaled properly. The z-axis labels also need to be children of another TransformGroup so that they can be rotated along the direction of the z-axis. Each label is made with the Text3D class.
  • BoundaryBox.java encloses the 3D graph with the three-sided translucent box. It's a BranchGroup that contains three BranchGroups each with a TransformGroup as a child. Each TransformGroup contains a Shape3D object that is a side of the translucent box. This configuration is necessary because each side of the box must be translated to the correct box side location.
As mentioned above, Java3D makes use of a Canvas3D object to do its final display rendering. For inexperienced Java GUI programmers, Canvas3D has features that can be problematic. Graph3D uses javax.swing (Swing) components because of their ability to programmatically change their appearance, but the GUI display can behave strange when mixing classes from AWT and Swing. For example, the AWT GUI component (Canvas3D) will always be drawn on top of Swing GUI components. This undesired effect is most noticeable when dragging a JFrame or a JInternalFrame (Swing windows) in front of the window containing the Canvas3D. To mitigate this problem you can either rewrite Graph3D using only AWT components (a fairly simple task) or arrange your GUI display so that Swing components will never interfere with the Canvas3D. This feature has been reported to Sun Microsystems but fixes have yet to be released.

Input Data
The file plot3D.dat (included with the source code) shows an example of the data format. The top part of the file describes the graph labels and data bounds. The data is formatted so that each coordinate is a corner of a square. The squares form a grid that has the same number of rows as columns. Of course, the format of the data file can be changed by simply changing the readFile() method in FileIn.java to reflect the change. The data are read into a two-dimensional array that will be used by the Graph class in constructing the surface. Notice that the coordinates range between -1.0 and 1.0. Your data will need to be converted to fit this range if they fall outside of these values.

Additional Capabilities
At the bottom of the Graph3D window are two additional capabilities that can be applied to the graph: perspective and wire frame plotting. To change the display from a perspective projection to a parallel projection, click on the "Perspective" checkbox. The following two lines of code are executed when the checkbox is unselected:

View view = canvas.getView();

The wire frame plot (see Figure 3) can only be accomplished with a trick - which is to set the four different color components of the Material class in Graph.java to be the same as the background color of the Canvas3D. The following four lines of code are executed in Graph.java when the "Fill On" checkbox is unselected:

material.setAmbientColor( backgroundColor );
material.setEmissiveColor( backgroundColor );
material.setSpecularColor( backgroundColor );
material.setDiffuseColor( backgroundColor );

The BranchGroup containing the lights (lightRoot) must also be detached from the hierarchy tree with lightRoot.detach(). Before this call is made, the following capability must be set in the makeLight() method in Graph3D:


More Stories By Valor Dodd

Valor Dodd is a Java-certified senior software engineer at Lockheed Martin in Denver, Colorado. He has more than 20 years of software experience developing computer graphics and GUI applications for the telephone and defense industries.

Comments (6) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.

Most Recent Comments
Jerry Schultz 06/11/06 04:50:17 AM EDT

Same comment. I am beginning work on similar classes. Was excited to read that it was done and the article stated that this is how you complile the source code and then no source code. An email with the source code link would be great!

Bob Byrnes 06/01/06 06:02:43 PM EDT

At the risk of being repetitious, I too would like to find the source code for Graph3D.

Anders Lindstrom 05/26/06 08:36:58 PM EDT

The section "Running Graph3D" implies that the source code is available but I cannot find it.

Chaouki MAIZA 05/26/06 10:00:36 AM EDT

Hi there,

Sorry for repeating the question but, is the Graph3D source available for download???

Chris Pratt 05/24/06 05:51:48 PM EDT

I was a little disappointed with the article. I thought it was going to show me how to do cool things with Java3D, not just talk about what the author had done for himself! Especially since it doesn't appear that the code discussed in the article is available. I usually expect more from JDJ.

Jeff Dinkins 05/24/06 01:25:28 PM EDT

Hi - where might one download the Graph3D application you're mentioning?