Preface

This tutorial is the next lesson in a series designed to teach you some of the mathematical skills that you will need (in addition to good programming skills) to become a successful game programmer. The first lesson was titled Math for Java Game Programmers, Getting Started. The previous lesson was titled Math for Java Game Programmers, Getting Started with the Vector Dot Product (seeResources).

In addition to helping you with your math skills, I will also help you learn how to incorporate those skills into object-oriented programming using Java. If you are familiar with other object-oriented programming languages such as C#, you should have no difficulty porting this material from Java to those other programming languages.

Since most computer games make heavy use of either 2D or 3D graphics, you will need skills in the mathematical areas that are required for success in 2D and 3D graphics programming. As a minimum, this includes but is not limited to skills in:

Geometry

Trigonometry

Vectors

Matrices

2D and 3D transforms

Transformations between coordinate systems

Projections

Of course, game programming requires mathematical skills beyond those required for graphics. However, for starters, this series will concentrate on the last five items in the above list.

What you have learned

In the previous lesson, which was the first part of a two-part miniseries on the vector dot product, you learned the fundamentals of the vector dot product in both 2D and 3D. You learned how to update the game-math library to support various aspects of the vector dot product, and you learned how to write 2D and 3D programs that use the vector dot product methods in the game-math library.

What you will learn

In this lesson, you will learn how to apply the vector dot product to three different applications. First, you will learn how to use the dot product to compute nine different angles of interest that a vector makes with various elements in 3D space. Next, you will learn how to use the dot product to find six of the infinite set of vectors that are perpendicular to a given vector as shown in Figure 3, and finally, you will learn how to use the dot product to perform back-face culling to convert the left image in Figure 1 to the right image in Figure 1.

In this series, I will frequently refer you to an excellent interactive tutorial on Vector Math for 3D Computer Graphics by Dr. Bradley P. Kjell (see Resources) for the required technical background. Then I will help you learn how to incorporate the knowledge that you gain from Dr. Kjell's tutorial into Java code with a heavy emphasis on object-oriented programming.

In the process, I will develop and explain a game-math library that you can use to experiment with and to confirm what you learn from the Kjell tutorial. The library started out small and will grow as we progress through more and more material in subsequent lessons.

For this lesson, I recommend that you concurrently study the Kjell tutorial through Chapter 10, Angle between 3D Vectors.

This lesson will build on what you learned about the vector dot product in the previous lesson titled Math for Java Game Programmers, Getting Started with the Vector Dot Product (see Resources). In that lesson, you learned some of the theory behind the dot product. In this lesson, you will learn how to use the dot-product methods of the game-math library to write several applications. I will present and explain the following four programs:

DotProd3D05 - Demonstrates how the dot product can be used to compute nine different angles of interest that a vector makes with various elements in 3D space.

DotProd3D06 - Demonstrates the use of the dot product to find six of the infinite set of vectors that are perpendicular to a given vector. (See Figure 3.)

DotProd3D04 - Draws the same 3D object as the one drawn in DotProd3D03 but without the benefit of back-face culling. (See Figure 1.)

Discussion and sample code

The game-math library has not been modified since the previous lesson. Therefore, there is nothing new to discuss and explain insofar as the library is concerned. For your convenience, a complete listing of the source code for the library is provided in Listing 9 near the end of the lesson.

In order to understand this and the following programs, you need to understand the material in the Kjell tutorial through Chapter 10, Angle between 3D Vectors (see Resources).

Game programming frequently requires the determination of angles of various types. The purpose of this program is to demonstrate how the dot product can be used to compute nine different angles of interest that a vector makes with various elements in 3Dspace.

Figure 2 shows a screen shot of the graphical user interface provided by this program.

Figure 2. Screen shot of the output from the program named DotProd3D05.

Angles relative to the axes

First, the program computes and displays the angle between a user-specified vector (drawn in black in Figure 2) and each of the X, Y, and Z axes. These values are displayed with the labels Angle X, Angle Y, and Angle Z in Figure 2.

Angles relative to the XY, YZ, and ZX planes

Then the program computes and displays the angle between the vector and each of the XY, YZ, and ZX planes. In this case, the program computes the smallest possible angle by projecting the vector onto the plane and then computing the angle between the vector and its projection. These values are displayed with the labels Angle XY, Angle YZ, and Angle ZX.

Angles of projections relatives to the axes

Finally, the program computes and displays the angle between the projection of the vector on each of the three planes and one of the axes that defines each plane. The angle between the projection and the other axis that defines the plane is 90 degrees minus the computed angle. Specifically the values that are computed and displayed are:

Projection onto the XY plane relative to the x-axis, displayed with the label Angle PX.

Projection onto the YZ plane relative to the y-axis, displayed with the label Angle PY.

Projection onto the ZX plane relative to the z-axis, displayed with the label Angle PZ.

The graphical user interface

All angles are reported as positive angles in degrees. As you can see in Figure 2, a GUI is provided that allows the user to enter three double values that define a GM02.Vector3D object. The GUI also provides an OK button as well as nine text fields that are used to display the computed results described above. In addition, the GUI provides a 3D drawing area.

When the user clicks the OK button, the program draws the user-specified vector in black with the tail located at the origin in 3D space. It also draws the projection of that vector in magenta on each of the XY, YZ, AND ZX planes.

Very similar to previously-explained code

Much of the code in this program is very similar to code that I have explained in previous lessons. I won't repeat those explanations here. Most of the new code is contained in the method named actionPerformed, so I will explain the code in that method. A complete listing of this program is provided in Listing 10 near the end of the lesson.

Beginning of the actionPerformed method in the program named DotProd3D05

Listing 1 shows the beginning of the actionPerformed method. This method is called to respond to a click on the OK button shown in Figure 2.

Listing 1. Beginning of the actionPerformed method in the program named DotProd3D05.

Although the actual code in Listing 2 should be familiar to you, the application may be new. The important thing to note is that the projection onto each of the three planes in Listing 2 is accomplished by setting one of the coordinate values to zero for each projection. For example, in order to project the vector onto the XY plane, the value for the z-axis coordinate is set to zero as shown in boldface in Listing 2.

Create and draw vectors

Listing 3 uses the ColMatrix3D objects created in Listing 1 and Listing 2 to create and draw vectors based on those ColMatrix3D objects.

//Use the ColMatrix3D objects to create Vector3D
// objects representing the user-specified vector and
// each of the axes.
GM02.Vector3D vecA = new GM02.Vector3D(matrixA);
GM02.Vector3D vecX = new GM02.Vector3D(matrixX);
GM02.Vector3D vecY = new GM02.Vector3D(matrixY);
GM02.Vector3D vecZ = new GM02.Vector3D(matrixZ);
//Create Vector3D objects that represent the
// projection of the user-specified vector on each of
// the planes.
GM02.Vector3D vecXY = new GM02.Vector3D(matrixXY);
GM02.Vector3D vecYZ = new GM02.Vector3D(matrixYZ);
GM02.Vector3D vecZX = new GM02.Vector3D(matrixZX);
//Draw the projection of the user specified vector on
// each of the three planes.
g2D.setColor(Color.MAGENTA);
vecXY.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
vecYZ.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
vecZX.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
//Draw the user-specified vector with its tail at the
// origin.
g2D.setColor(Color.BLACK);
vecA.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));

Once the ColMatrix3D objects have been created to serve each specific purpose, there is nothing new in Listing 3. Therefore, no explanation of the code beyond the embedded comments should be necessary.

Compute and display the nine angles

Listing 4 calls the angle method of the GM02.Vector3D class nine times in succession, using references to the vectors created in Listing 3, to compute and display the nine angle values shown in Figure 2.

Once the required vectors had been created in Listing 3, there is nothing new in the code in Listing 4. Therefore, no explanation of Listing 4 should be required beyond the comments embedded in the code.

The bottom line on the program named DotProd3D05

The bottom line is that because the methods in the game-math library named GM02 were designed to do most of the hard work, writing application programs such as DotProd3D05 using the game-math library is not difficult at all. You simply need to understand how to organize your code to accomplish the things that you need to accomplish.

This program demonstrates how the dot product can be used to find vectors that are perpendicular to a given vector.

An infinite number of possibilities

Recall that you learned in the previous lesson that there are an infinite number of vectors that are perpendicular to a given vector in 3D. This program computes and displays normalized and scaled versions of six of the infinite set of vectors that are perpendicular to a user specified vector.

The graphic output

The screen output from this program is shown in Figure 3.

Figure 3. Six (magenta) vectors that are perpendicular to a given (black) vector.

Output on the command-line screen

In addition to the graphic output shown in Figure 3, the program also displays the values of three of the perpendicular vectors on the command-line screen along with the angle between the perpendicular vector and the user-specified vector. The angle should always be 90 degrees or very close to 90 degrees if the program is working properly. The other three of the six perpendicular vectors are simply negated versions of the three for which the values are displayed.

Special case of one zero coordinate value

If the user specifies one of the coordinate values to be zero (or close to zero), the program only computes and displays four of the possible vectors in order to avoid performing division by a near-zero value. In this case, the orientation of two of the vectors will overlay the orientation of the other two. Because the vectors are normalized to the same length and occupy the same space, you will only see two vectors instead of four. This is illustrated in Figure 4 where the value of the z-axis coordinate value was set to zero relative to the value used in Figure 3.

If the user specifies two of the coordinate values to be zero or close to zero, the program doesn't produce a valid result. Instead, it draws a perpendicular vector where all of the coordinate values are zero resulting in a magenta vector head at the origin. It also displays NaN (Not a Number) for the angle on the command line screen.

The graphical user interface

The GUI shown in Figure 4 is provided to allow the user to enter three double values that define a GM02.Vector3D object. The GUI also provides an OK button in addition to a 3D drawing area.

When the user clicks the OK button, the program draws the user-specified vector in black with the tail located at the origin in 3D space. It draws normalized versions of the perpendicular vectors in magenta with their tails also located at the origin. Each normalized vector is scaled by a factor of 50 before it is drawn to cause it to be long enough to be seen.

A short review

Before getting into the programming details, we need to review some material from the previous lesson. Recall that I did some algebraic manipulations in the previous lesson and produced the equations shown in Figure 5.

The boldface equations in Figure 5 describe an infinite set of vectors that are all perpendicular to a given vector. Given these equations, and given the coordinates (x1, y1, and z1) of a vector for which we need to produce perpendicular vectors, we can assume values for any two of x2, y2, and z2.; We can then determine the value for the other coordinate that will cause the new vector to be perpendicular to the given vector.

That is the procedure that is used by this program to
produce three of the perpendicular vectors shown in Figure 3. The remaining three perpendicular vectors shown in Figure 3 are produced by negating the three vectors that are created using the procedure described above.

Beginning of the actionPerformed method

The only code in this program that is new to this lesson is contained in the actionPerformed method. This method is called to respond to a click on the OK button in Figure 4. Therefore, I will confine my explanation to portions of the actionPerformed method. You can view a complete listing of this program in Listing 11 near the end of the lesson.

The actionPerformed method begins in Listing 5. Note that I deleted some of the code early in the method because it is very similar to code that I have explained before.

Listing 5. Beginning of the actionPerformed method for the program named DotProd3D06.

The actionPerformed method contains three sections of code, each of which implements one of the boldface equations in Figure 5 to compute and draw one of the perpendicular vectors shown in Figure 3. In addition, the code in the actionPerformed method draws the negative of those three vectors to produce the other three perpendicular vectors shown in Figure 3.

Implement the last boldface equation

Listing 5 implements the last boldface equation from Figure 5, provided that the z-axis coordinate value for the given vector is greater than 0.001. As mentioned earlier, if the z-axis coordinate value is not greater than 0.001, the code in Listing 5 is skipped and no effort is made to create and draw that particular vector. This is done to prevent an attempt to divide by a zero or near-zero value.

A new ColMatrix3D object

Listing 5 creates a new ColMatrix3D object with the x and y-axes coordinate values matching the corresponding values for the user specified vector. It executes the expression shown in boldface in Listing 5 to compute the value of the z-axis coordinate that will cause the new vector to be perpendicular to the user-specified vector. (The boldface expression in Listing 5 matches the last boldface equation in Figure 5.)

A new Vector3D object

Then it uses the ColMatrix3D object described above to create, normalize, scale, and draw the first perpendicular vector. Following that, the code negates the perpendicular vector to create another perpendicular vector that points in the opposite direction.

Along the way, some information is displayed on the command-line screen.

The most important code

The most important code in Listing 5, insofar as the objective of the program is concerned, is the boldface expression that computes the z-axis coordinate value that will cause the new vector to be perpendicular to the user-specified vector.

Remainder of the actionPerformed method

Listing 6 does essentially the same thing two more times to implement the other two boldface equations shown in Figure 5, creating and drawing four more perpendicular vectors in the process.

The purpose of this program is to serve as a counterpoint to the program named Prob3D03, which demonstrates backface culling. (I will explain the program named Prob3D03 shortly.)

This program draws the 3D object shown on the left side of Figure 1, while the program named DotProd3D03 draws the 3D object shown on the right side of Figure 1. The difference between the two is that the object drawn by this program (on the left in Figure 1) does not incorporate backface culling to hide the lines on the back of the object. The object on the right in Figure 1 does incorporate backface culling. The difference is easy to see.

This program draws a 3D circular cylinder by stacking 20circular disks on the x-z plane as shown in Figure 1. The disks are centered on the y-axis and are parallel to the x-z plane. The thickness of each disk is 5 vertical units. As mentioned above, there is no backface culling in this program, so all of the lines that should be hidden show through.

Will discuss in fragments

A complete listing of this program is provided in Listing 12 near the end of the lesson. I will explain portions of the program using code fragments. However, I won't repeat explanations of code that I have already explained in this or in earlier lessons (see Resources).

The method named drawTheCylinder

All of the interesting code in this program is contained in the method named drawTheCylinder, which is shown in Listing 7. (Note that some of the code was deleted from Listing 7 for brevity.) This method is used to set the axes to the center of the off-screen image and to draw a 3D cylinder that is centered on the y-axis.

private void drawTheCylinder(Graphics2D g2D){
//Code deleted for brevity.
//Draw a cylinder by stacking 20 circular disks on
// the x-z plane. The disks are centered on the
// y-axis and are parallel to the x-z plane. The
// thickness of each disk is 5 vertical units.
GM02.Point3D tempPointA;
GM02.Point3D tempPointB;
g2D.setColor(Color.BLACK);
for(int y = 0;y < 105;y += 5){//iterate on disks
//Define the starting point on the circle for this
// disk.
tempPointA = new GM02.Point3D(
new GM02.ColMatrix3D(76,y - osiHeight/4,0));
//Iterate on points on the circle that represents
// this disk.
for(int cnt = 0;cnt < 360;cnt++){//360 points
//Compute the next point on the circle.
tempPointB =
new GM02.Point3D(new GM02.ColMatrix3D(
76*Math.cos(Math.toRadians(cnt*360/360)),
y - osiHeight/4,
76*Math.sin(Math.toRadians(cnt*360/360))));
//Draw the line in 3D. Note that there is no
// backface culling in this program.
new GM02.Line3D(tempPointA,tempPointB).draw(g2D);
//Save the point for use in drawing the next line.
tempPointA = tempPointB;
}//end for loop on points
}//end for loop on disks
}//end drawTheCylinder method

Behavior of the code

Basically, the code in Listing 7 draws 21 circles, one above the other to represent the edges of the 20 circular disks. If you understand the trigonometry involved in drawing a circle, you should find the code in Listing 7 to be straightforward and no explanation beyond the embedded comments should be required. If you don't understand the trigonometry, you will simply have to take my word for it that the expressions in Listing 7 are correct for drawing circles. A study of trigonometry is beyond the scope of this lesson.

The purpose of this program is to demonstrate a practical use of the vector dot product -- backface culling. As before, the program draws a 3D circular cylinder by stacking 20 circular disks on the x-z plane. The disks are centered on the y-axis and are parallel to the x-z plane. The thickness of each disk is 5 vertical units.

Backface culling is incorporated using the dot product between a vector that is parallel to the viewpoint of the viewer and a vector that is perpendicular to the line being drawn to form the outline of a circle. The results are shown in the right image in Figure 1.

Will discuss in fragments

A complete listing of this program is provided in Listing 13 near the end of the lesson. I will explain portions of the program using code fragments. However, I won't repeat explanations of code that I have already explained in this or in earlier lessons (see Resources).

The method named drawTheCylinder

As before, all of the interesting code in this program is contained in the method named drawTheCylinder, which is shown in Listing 8. (Note that some of the code was deleted from Listing 8 for brevity.) This method is used to set the axes to the center of the off-screen image and to draw a 3D cylinder that is centered on the y-axis.

private void drawTheCylinder(Graphics2D g2D){
//Code deleted for brevity.
//Get a vector that is approximately parallel to the
// viewpoint of the viewer. The best values for this
// vector were determined experimentally using this
// program and the earlier program named DotProd3D02.
GM02.Vector3D viewPoint =
new GM02.Vector3D(new GM02.ColMatrix3D(43,5,50));
//Draw a cylinder by stacking 20 circular disks on
// the x-z plane. The disks are centered on the
// y-axis and are parallel to the x-z plane. The
// thickness of each disk is 5 vertical units.
GM02.Point3D tempPointA;
GM02.Point3D tempPointB;
g2D.setColor(Color.BLACK);
for(int y = 0;y < 105;y += 5){//iterate on disks
//Define the starting point on the circle for this
// disk.
tempPointA = new GM02.Point3D(new GM02.ColMatrix3D(
76,y - osiHeight/4,0));
//Iterate on points on the circle that represents
// this disk.
for(int cnt = 0;cnt < 360;cnt++){//360 points
//Compute the next point on the circle.
tempPointB =
new GM02.Point3D(new GM02.ColMatrix3D(
76*Math.cos(Math.toRadians(cnt*360/360)),
y - osiHeight/4,
76*Math.sin(Math.toRadians(cnt*360/360))));
//Do backface culling using the dot product of the
// viewpoint vector and a vector that is almost
// perpendicular to the line being drawn. If the
// dot product is negative, or if the disk being
// drawn is the top disk on the stack, draw the
// line. Otherwise, don't draw the line.
//The perpendicular vector used in the dot
// product is the displacement vector from the
// origin to a point that defines one end of the
// line being drawn. Note that this vector is not
// perfectly perpendicular to the line being
// drawn. Later in the series, we will learn about
// and use the cross product to get perpendicular
// vectors.
if((tempPointB.getDisplacementVector(
new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)))
.dot(viewPoint) < 0.0)
|| (y == 100)){
//Draw the line in 3D.
new GM02.Line3D(
tempPointA,tempPointB).draw(g2D);
}//end if
//Save the point for use in drawing the next line.
tempPointA = tempPointB;
}//end for loop on points
}//end for loop on disks
}//end drawTheCylinder method

The new code and an exercise for the student

The new code in Listing 8 is highlighted in boldface. I will leave it as an exercise for the student to think about the rationale behind deciding which lines to draw and which lines to suppress depending on the algebraic sign of the dot product between the two vectors.

Otherwise, no explanation of the code should be necessary beyond the embedded comments.

Run the programs

I encourage you to copy the code from Listing 9 through Listing 13, compile the code, and execute the programs in conjunction with the game-math library named GM02. Experiment with the code, making changes, and observing the results of your changes. Make certain that you can explain why your changes behave as they do.

In this lesson, you learned how to apply the vector dot product to three different applications. First, you learned how to use the dot product to compute nine different angles of interest that a vector makes with various elements in 3D space. Next, you learned how to use the dot product to find six of the infinite set of vectors that are perpendicular to a given vector as shown in Figure 3. Finally, you learned how to use the dot product to perform back-face culling to convert the left image in Figure 1 to the right image in Figure 1.

/*DotProd3D05.java
Copyright 2008, R.G.Baldwin
Revised 03/06/08
The purpose of this program is to demonstrate how the dot
product can be used to compute nine different angles of
interest that a vector makes with various elements in 3D
space.
First, the program computes and displays the angle between
a user-specified vector and each of the X, Y, and Z axes.
These values are displayed with the labels Angle X,
Angle Y, and Angle Z.
Then the program computes and displays the angle between
the vector and each of the XY, YZ, and ZX planes. In
this case, the program computes the smallest possible
angle by projecting the vector onto the plane and then
computing the angle between the vector and its projection.
These values are displayed with the labels Angle XY,
Angle YZ, and Angle ZX.
Finally, the program computes and displays the angle
between the projection of the vector on each of the three
planes and one of the axes that defines each plane.
Obviously, the angle between the projection and the other
axis that defines the plane is 90 degrees less the
computed angle. Specifically the values that are computed
and displayed are:
Projection onto the XY plane relative to the x-axis,
displayed with the label Angle PX.
Projection onto the YZ plane relative to the y-axis,
displayed with the label Angle PY.
Projection onto the ZX plane relative to the z-axis,
displayed with the label Angle PZ.
All angles are reported as positive angles in degrees.
Study Kjell through Chapter 10, Angle between 3D Vectors.
A GUI is provided that allows the user to enter three
double values that define a GM02.Vector3D object. The GUI
also provides an OK button as well as nine text fields
used to display the computed results described above.
In addition, the GUI provides a 3D drawing area.
When the user clicks the OK button, the program draws the
user-specified vector in black with the tail located at
the origin in 3D space. It also draws the projection of
that vector in magenta on each of the XY, YZ, AND ZX
planes
Tested using JDK 1.6 under WinXP.
*********************************************************/
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class DotProd3D05{
public static void main(String[] args){
GUI guiObj = new GUI();
}//end main
}//end controlling class DotProd3D05
//======================================================//
class GUI extends JFrame implements ActionListener{
//Specify the horizontal and vertical size of a JFrame
// object.
int hSize = 400;
int vSize = 400;
Image osi;//an off-screen image
int osiWidth;//off-screen image width
int osiHeight;//off-screen image height
MyCanvas myCanvas;//a subclass of Canvas
Graphics2D g2D;//off-screen graphics context.
//User input components.
JTextField vecX = new JTextField("50.0");
JTextField vecY = new JTextField("100.0");
JTextField vecZ = new JTextField("0.0");
JTextField angleX = new JTextField("0");
JTextField angleY = new JTextField("0");
JTextField angleZ = new JTextField("0");
JTextField angleXY = new JTextField("0");
JTextField angleYZ = new JTextField("0");
JTextField angleZX = new JTextField("0");
JTextField anglePX = new JTextField("0");
JTextField anglePY = new JTextField("0");
JTextField anglePZ = new JTextField("0");
JButton button = new JButton("OK");
//----------------------------------------------------//
GUI(){//constructor
//Set JFrame size, title, and close operation.
setSize(hSize,vSize);
setTitle("Copyright 2008,R.G.Baldwin");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Instantiate a JPanel that will house the user input
// components and set its layout manager.
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new GridLayout(0,6));
//Add the user input components and appropriate labels
// to the control panel.
controlPanel.add(new JLabel(" Vec X "));
controlPanel.add(vecX);
controlPanel.add(new JLabel(" Vec Y "));
controlPanel.add(vecY);
controlPanel.add(new JLabel(" Vec Z "));
controlPanel.add(vecZ);
controlPanel.add(new JLabel(" Angle X "));
controlPanel.add(angleX);
controlPanel.add(new JLabel(" Angle Y "));
controlPanel.add(angleY);
controlPanel.add(new JLabel(" Angle Z "));
controlPanel.add(angleZ);
controlPanel.add(new JLabel(" Angle XY "));
controlPanel.add(angleXY);
controlPanel.add(new JLabel(" Angle YZ "));
controlPanel.add(angleYZ);
controlPanel.add(new JLabel(" Angle ZX "));
controlPanel.add(angleZX);
controlPanel.add(new JLabel(" Angle PX "));
controlPanel.add(anglePX);
controlPanel.add(new JLabel(" Angle PY "));
controlPanel.add(anglePY);
controlPanel.add(new JLabel(" Angle PZ "));
controlPanel.add(anglePZ);
controlPanel.add(button);
//Add the control panel to the SOUTH position in the
// JFrame.
this.getContentPane().add(
BorderLayout.SOUTH,controlPanel);
//Create a new drawing canvas and add it to the
// CENTER of the JFrame above the control panel.
myCanvas = new MyCanvas();
this.getContentPane().add(
BorderLayout.CENTER,myCanvas);
//This object must be visible before you can get an
// off-screen image. It must also be visible before
// you can compute the size of the canvas.
setVisible(true);
//Make the size of the off-screen image match the
// size of the canvas.
osiWidth = myCanvas.getWidth();
osiHeight = myCanvas.getHeight();
//Create an off-screen image and get a graphics
// context on it.
osi = createImage(osiWidth,osiHeight);
g2D = (Graphics2D)(osi.getGraphics());
//Translate the origin to the center.
GM02.translate(g2D,0.5*osiWidth,-0.5*osiHeight);
//Register this object as an action listener on the
// button.
button.addActionListener(this);
//Cause the overridden paint method belonging to
// myCanvas to be executed.
myCanvas.repaint();
}//end constructor
//----------------------------------------------------//
//This method is used to draw orthogonal 3D axes on the
// off-screen image that intersect at the origin.
private void setCoordinateFrame(Graphics2D g2D){
//Erase the screen
g2D.setColor(Color.WHITE);
GM02.fillRect(g2D,-osiWidth/2,osiHeight/2,
osiWidth,osiHeight);
//Draw x-axis in RED
g2D.setColor(Color.RED);
GM02.Point3D pointA = new GM02.Point3D(
new GM02.ColMatrix3D(-osiWidth/2,0,0));
GM02.Point3D pointB = new GM02.Point3D(
new GM02.ColMatrix3D(osiWidth/2,0,0));
new GM02.Line3D(pointA,pointB).draw(g2D);
//Draw y-axis in GREEN
g2D.setColor(Color.GREEN);
pointA = new GM02.Point3D(
new GM02.ColMatrix3D(0,-osiHeight/2,0));
pointB = new GM02.Point3D(
new GM02.ColMatrix3D(0,osiHeight/2,0));
new GM02.Line3D(pointA,pointB).draw(g2D);
//Draw z-axis in BLUE. Make its length the same as the
// length of the x-axis.
g2D.setColor(Color.BLUE);
pointA = new GM02.Point3D(
new GM02.ColMatrix3D(0,0,-osiWidth/2));
pointB = new GM02.Point3D(
new GM02.ColMatrix3D(0,0,osiWidth/2));
new GM02.Line3D(pointA,pointB).draw(g2D);
}//end setCoordinateFrame method
//----------------------------------------------------//
//This method is called to respond to a click on the
// button.
public void actionPerformed(ActionEvent e){
//Erase the off-screen image and draw the axes.
setCoordinateFrame(g2D);
//Create one ColMatrix3D object based on the user
// input values.
GM02.ColMatrix3D matrixA = new GM02.ColMatrix3D(
Double.parseDouble(vecX.getText()),
Double.parseDouble(vecY.getText()),
Double.parseDouble(vecZ.getText()));
//Create ColMatrix3D objects that represent each of
// the three axes.
GM02.ColMatrix3D matrixX =
new GM02.ColMatrix3D(1,0,0);
GM02.ColMatrix3D matrixY =
new GM02.ColMatrix3D(0,1,0);
GM02.ColMatrix3D matrixZ =
new GM02.ColMatrix3D(0,0,1);
//Create ColMatrix3D objects that represent the
// projection of the user-specified vector onto each
// of the three planes.
GM02.ColMatrix3D matrixXY = new GM02.ColMatrix3D(
Double.parseDouble(vecX.getText()),
Double.parseDouble(vecY.getText()),
0);
GM02.ColMatrix3D matrixYZ = new GM02.ColMatrix3D(
0,
Double.parseDouble(vecY.getText()),
Double.parseDouble(vecZ.getText()));
GM02.ColMatrix3D matrixZX = new GM02.ColMatrix3D(
Double.parseDouble(vecX.getText()),
0,
Double.parseDouble(vecZ.getText()));
//Use the ColMatrix3D objects to create Vector3D
// objects representing the user-specified vector and
// each of the axes.
GM02.Vector3D vecA = new GM02.Vector3D(matrixA);
GM02.Vector3D vecX = new GM02.Vector3D(matrixX);
GM02.Vector3D vecY = new GM02.Vector3D(matrixY);
GM02.Vector3D vecZ = new GM02.Vector3D(matrixZ);
//Create Vector3D objects that represent the
// projection of the user-specified vector on each of
// the planes.
GM02.Vector3D vecXY = new GM02.Vector3D(matrixXY);
GM02.Vector3D vecYZ = new GM02.Vector3D(matrixYZ);
GM02.Vector3D vecZX = new GM02.Vector3D(matrixZX);
//Draw the projection of the user specified vector on
// each of the three planes.
g2D.setColor(Color.MAGENTA);
vecXY.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
vecYZ.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
vecZX.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
//Draw the user-specified vector with its tail at the
// origin.
g2D.setColor(Color.BLACK);
vecA.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
//Compute and display the angle relative to the
// x-axis.
double angle = vecA.angle(vecX);
angleX.setText("" + prepareForDisplay(angle));
//Compute and display the angle relative to the
// y-axis.
angle = vecA.angle(vecY);
angleY.setText("" + prepareForDisplay(angle));
//Compute and display the angle relative to the
// z-axis.
angle = vecA.angle(vecZ);
angleZ.setText("" + prepareForDisplay(angle));
//Compute and display the angle relative to the
// XY plane
angle = vecA.angle(vecXY);
angleXY.setText("" + prepareForDisplay(angle));
//Compute and display the angle relative to the
// YZ plane
angle = vecA.angle(vecYZ);
angleYZ.setText("" + prepareForDisplay(angle));
//Compute and display the angle relative to the
// ZX plane
angle = vecA.angle(vecZX);
angleZX.setText("" + prepareForDisplay(angle));
//Compute and display the angle of the projection onto
// the XY plane relative to the x-axis
angle = vecXY.angle(vecX);
anglePX.setText("" + prepareForDisplay(angle));
//Compute and display the angle of the projection onto
// the YZ plane relative to the y-axis
angle = vecYZ.angle(vecY);
anglePY.setText("" + prepareForDisplay(angle));
//Compute and display the angle of the projection onto
// the ZX plane relative to the z-axis
angle = vecZX.angle(vecZ);
anglePZ.setText("" + prepareForDisplay(angle));
myCanvas.repaint();//Copy off-screen image to canvas.
}//end actionPerformed
//----------------------------------------------------//
//The code in this method prepares a double value for
// display in a text field by eliminating exponential
// format for very small values and setting the number
// of decimal digits to four.
private double prepareForDisplay(double data){
//Eliminate exponential notation in the display.
if(Math.abs(data) < 0.001){
data = 0.0;
}//end if
//Convert to four decimal digits.
return ((int)(10000*data))/10000.0;
}//end prepareForDisplay
//====================================================//
//This is an inner class of the GUI class.
class MyCanvas extends Canvas{
//Override the paint() method. This method will be
// called when the JFrame and the Canvas appear on the
// screen or when the repaint method is called on the
// Canvas object.
//The purpose of this method is to display the
// off-screen image on the screen.
public void paint(Graphics g){
g.drawImage(osi,0,0,this);
}//end overridden paint()
}//end inner class MyCanvas
}//end class GUI
//======================================================//

/*DotProd3D06.java
Copyright 2008, R.G.Baldwin
Revised 03/09/08
This program demonstrates how the dot product can be used
to find vectors that are perpendicular to a given vector.
The program computes and displays normalized and scaled
versions of six of the infinite set of vectors that are
perpendicular to a user specified vector.
If the user specifies one of the coordinates to be zero
or close to zero, the program only computes and displays
four of the possible vectors in order to avoid performing
division by a near-zero value. For a value of zero, the
orientation of two of the vectors will overlay the
orientation of the other two. Because they are the same
length, and occupy the same space, you will only see two
vectors.
If the user specifies two of the coordinates to be zero
or close to zero, the program doesn't produce a valid
result. Instead, it displays the coordinates for a
perpendicular vector where all of the coordinates are
zero and displays NaN for the angle.
Study Kjell through Chapter 10, Angle between 3D Vectors.
A GUI is provided that allows the user to enter three
double values that define a GM02.Vector3D object. The GUI
also provides an OK button.
In addition, the GUI provides a 3D drawing area.
When the user clicks the OK button, the program draws the
user-specified vector in black with the tail located at
the origin in 3D space. It also draws normalized versions
of the perpendicular vectors in magenta with their tails
located at the origin. Each normalized vector is scaled
by a factor of 50 before it is drawn.
The program also displays the values of three of the
perpendicular vectors on the command-line screen along
with the angle between the perpendicular vector and the
user-specified vector. The angle should be 90 degrees or
at least very very close to 90 degrees. The other three
perpendicular vectors are simply negated versions of the
three for which the values are displayed.
Tested using JDK 1.6 under WinXP.
*********************************************************/
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class DotProd3D06{
public static void main(String[] args){
GUI guiObj = new GUI();
}//end main
}//end controlling class DotProd3D06
//======================================================//
class GUI extends JFrame implements ActionListener{
//Specify the horizontal and vertical size of a JFrame
// object.
int hSize = 400;
int vSize = 400;
Image osi;//an off-screen image
int osiWidth;//off-screen image width
int osiHeight;//off-screen image height
MyCanvas myCanvas;//a subclass of Canvas
Graphics2D g2D;//off-screen graphics context.
//User input components.
JTextField vecX = new JTextField("50.0");
JTextField vecY = new JTextField("50.0");
JTextField vecZ = new JTextField("50.0");
JButton button = new JButton("OK");
//----------------------------------------------------//
GUI(){//constructor
//Set JFrame size, title, and close operation.
setSize(hSize,vSize);
setTitle("Copyright 2008,R.G.Baldwin");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Instantiate a JPanel that will house the user input
// components and set its layout manager.
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new GridLayout(0,6));
//Add the user input components and appropriate labels
// to the control panel.
controlPanel.add(new JLabel(" Vec X "));
controlPanel.add(vecX);
controlPanel.add(new JLabel(" Vec Y "));
controlPanel.add(vecY);
controlPanel.add(new JLabel(" Vec Z "));
controlPanel.add(vecZ);
controlPanel.add(button);
//Add the control panel to the SOUTH position in the
// JFrame.
this.getContentPane().add(
BorderLayout.SOUTH,controlPanel);
//Create a new drawing canvas and add it to the
// CENTER of the JFrame above the control panel.
myCanvas = new MyCanvas();
this.getContentPane().add(
BorderLayout.CENTER,myCanvas);
//This object must be visible before you can get an
// off-screen image. It must also be visible before
// you can compute the size of the canvas.
setVisible(true);
//Make the size of the off-screen image match the
// size of the canvas.
osiWidth = myCanvas.getWidth();
osiHeight = myCanvas.getHeight();
//Create an off-screen image and get a graphics
// context on it.
osi = createImage(osiWidth,osiHeight);
g2D = (Graphics2D)(osi.getGraphics());
//Translate the origin to the center.
GM02.translate(g2D,0.5*osiWidth,-0.5*osiHeight);
//Register this object as an action listener on the
// button.
button.addActionListener(this);
//Cause the overridden paint method belonging to
// myCanvas to be executed.
myCanvas.repaint();
}//end constructor
//----------------------------------------------------//
//This method is used to draw orthogonal 3D axes on the
// off-screen image that intersect at the origin.
private void setCoordinateFrame(Graphics2D g2D){
//Erase the screen
g2D.setColor(Color.WHITE);
GM02.fillRect(g2D,-osiWidth/2,osiHeight/2,
osiWidth,osiHeight);
//Draw x-axis in RED
g2D.setColor(Color.RED);
GM02.Point3D pointA = new GM02.Point3D(
new GM02.ColMatrix3D(-osiWidth/2,0,0));
GM02.Point3D pointB = new GM02.Point3D(
new GM02.ColMatrix3D(osiWidth/2,0,0));
new GM02.Line3D(pointA,pointB).draw(g2D);
//Draw y-axis in GREEN
g2D.setColor(Color.GREEN);
pointA = new GM02.Point3D(
new GM02.ColMatrix3D(0,-osiHeight/2,0));
pointB = new GM02.Point3D(
new GM02.ColMatrix3D(0,osiHeight/2,0));
new GM02.Line3D(pointA,pointB).draw(g2D);
//Draw z-axis in BLUE. Make its length the same as the
// length of the x-axis.
g2D.setColor(Color.BLUE);
pointA = new GM02.Point3D(
new GM02.ColMatrix3D(0,0,-osiWidth/2));
pointB = new GM02.Point3D(
new GM02.ColMatrix3D(0,0,osiWidth/2));
new GM02.Line3D(pointA,pointB).draw(g2D);
}//end setCoordinateFrame method
//----------------------------------------------------//
//This method is called to respond to a click on the
// button.
public void actionPerformed(ActionEvent e){
//Erase the off-screen image and draw the axes.
setCoordinateFrame(g2D);
//Get and save the user specified coordinate values.
double xCoor = Double.parseDouble(vecX.getText());
double yCoor = Double.parseDouble(vecY.getText());
double zCoor = Double.parseDouble(vecZ.getText());
//Create a ColMatrix3D object based on the user input
// values.
GM02.ColMatrix3D matrixA =
new GM02.ColMatrix3D(xCoor,yCoor,zCoor);
//Use the ColMatrix3D object to create a Vector3D
// object representing the user-specified vector.
GM02.Vector3D vecA = new GM02.Vector3D(matrixA);
//Draw the user-specified vector with its tail at the
// origin.
g2D.setColor(Color.BLACK);
vecA.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
//Create and draw the perpendicular vectors. However,
// if a coordinate value is near zero, don't attempt
// to create and draw the perpendicular vector that
// would require division by the near-zero value.
GM02.Vector3D tempVec;
GM02.ColMatrix3D tempMatrix;
g2D.setColor(Color.MAGENTA);
if(Math.abs(zCoor) > 0.001){
tempMatrix = new GM02.ColMatrix3D(
xCoor,yCoor,-(xCoor*xCoor + yCoor*yCoor)/zCoor);
tempVec = new GM02.Vector3D(tempMatrix);
System.out.println(tempVec);
//Normalize and scale the perpendicular vector.
tempVec = tempVec.normalize().scale(50.0);
tempVec.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
tempVec.negate().draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
System.out.println(vecA.angle(tempVec));
}//end if
if(Math.abs(yCoor) > 0.001){
tempMatrix = new GM02.ColMatrix3D(
xCoor,-(xCoor*xCoor + zCoor*zCoor)/yCoor,zCoor);
tempVec = new GM02.Vector3D(tempMatrix);
System.out.println(tempVec);
//Normalize and scale the perpendicular vector.
tempVec = tempVec.normalize().scale(50.0);
tempVec.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
tempVec.negate().draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
System.out.println(vecA.angle(tempVec));
}//end if
if(Math.abs(xCoor) > 0.001){
tempMatrix = new GM02.ColMatrix3D(
-(yCoor*yCoor + zCoor*zCoor)/xCoor, yCoor,zCoor);
tempVec = new GM02.Vector3D(tempMatrix);
System.out.println(tempVec);
//Normalize and scale the perpendicular vector.
tempVec = tempVec.normalize().scale(50.0);
tempVec.draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
tempVec.negate().draw(g2D,new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)));
System.out.println(vecA.angle(tempVec));
}//end if
myCanvas.repaint();//Copy off-screen image to canvas.
System.out.println();//blank line
}//end actionPerformed
//----------------------------------------------------//
//====================================================//
//This is an inner class of the GUI class.
class MyCanvas extends Canvas{
//Override the paint() method. This method will be
// called when the JFrame and the Canvas appear on the
// screen or when the repaint method is called on the
// Canvas object.
//The purpose of this method is to display the
// off-screen image on the screen.
public void paint(Graphics g){
g.drawImage(osi,0,0,this);
}//end overridden paint()
}//end inner class MyCanvas
}//end class GUI
//======================================================//

/*DotProd3D04.java
Copyright 2008, R.G.Baldwin
Revised 03/07/08
The purpose of this program is serve as a counterpoint to
the program named Prob3D03, which demonstrates backface
culling.
This program draws the same 3D object as the one drawn in
DotProd3D03 but without the benefit of backface culling.
Study Kjell through Chapter 10, Angle between 3D Vectors.
The program draws a 3D circular cylinder by stacking 20
circular disks on the x-z plane. The disks are centered on
the y-axis and are parallel to the x-z plane. The
thickness of each disk is 5 vertical units.
There is no backface culling in this program, so all of
the lines that should be hidden show through.
Tested using JDK 1.6 under WinXP.
*********************************************************/
import java.awt.*;
import javax.swing.*;
class DotProd3D04{
public static void main(String[] args){
GUI guiObj = new GUI();
}//end main
}//end controlling class DotProd3D04
//======================================================//
class GUI extends JFrame{
//Specify the horizontal and vertical size of a JFrame
// object.
int hSize = 230;
int vSize = 250;
Image osi;//an off-screen image
int osiWidth;//off-screen image width
int osiHeight;//off-screen image height
MyCanvas myCanvas;//a subclass of Canvas
Graphics2D g2D;//off-screen graphics context.
//----------------------------------------------------//
GUI(){//constructor
//Set JFrame size, title, and close operation.
setSize(hSize,vSize);
setTitle("Copyright 2008,R.G.Baldwin");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create a new drawing canvas and add it to the
// CENTER of the JFrame above the control panel.
myCanvas = new MyCanvas();
this.getContentPane().add(
BorderLayout.CENTER,myCanvas);
//This object must be visible before you can get an
// off-screen image. It must also be visible before
// you can compute the size of the canvas.
setVisible(true);
//Make the size of the off-screen image match the
// size of the canvas.
osiWidth = myCanvas.getWidth();
osiHeight = myCanvas.getHeight();
//Create an off-screen image and get a graphics
// context on it.
osi = createImage(osiWidth,osiHeight);
g2D = (Graphics2D)(osi.getGraphics());
//Call a method that sets the axes and draws the
// cylinder.
drawTheCylinder(g2D);
//Cause the overridden paint method belonging to
// myCanvas to be executed.
myCanvas.repaint();
}//end constructor
//----------------------------------------------------//
//This method is used to set the axes to the center of
// the off-screen image and to draw a 3D cylinder that
// is centered on the y-axis.
private void drawTheCylinder(Graphics2D g2D){
//Translate the origin to the center of the off-screen
// image.
GM02.translate(g2D,0.5*osiWidth,-0.5*osiHeight);
//Erase the screen
g2D.setColor(Color.WHITE);
GM02.fillRect(g2D,-osiWidth/2,osiHeight/2,
osiWidth,osiHeight);
//Draw a cylinder by stacking 20 circular disks on
// the x-z plane. The disks are centered on the
// y-axis and are parallel to the x-z plane. The
// thickness of each disk is 5 vertical units.
GM02.Point3D tempPointA;
GM02.Point3D tempPointB;
g2D.setColor(Color.BLACK);
for(int y = 0;y < 105;y += 5){//iterate on disks
//Define the starting point on the circle for this
// disk.
tempPointA = new GM02.Point3D(
new GM02.ColMatrix3D(76,y - osiHeight/4,0));
//Iterate on points on the circle that represents
// this disk.
for(int cnt = 0;cnt < 360;cnt++){//360 points
//Compute the next point on the circle.
tempPointB =
new GM02.Point3D(new GM02.ColMatrix3D(
76*Math.cos(Math.toRadians(cnt*360/360)),
y - osiHeight/4,
76*Math.sin(Math.toRadians(cnt*360/360))));
//Draw the line in 3D. Note that there is no
// backface culling in this program.
new GM02.Line3D(tempPointA,tempPointB).draw(g2D);
//Save the point for use in drawing the next line.
tempPointA = tempPointB;
}//end for loop on points
}//end for loop on disks
}//end drawTheCylinder method
//====================================================//
//This is an inner class of the GUI class.
class MyCanvas extends Canvas{
//Override the paint() method. This method will be
// called when the JFrame and the Canvas appear on the
// screen or when the repaint method is called on the
// Canvas object.
//The purpose of this method is to display the
// off-screen image on the screen.
public void paint(Graphics g){
g.drawImage(osi,0,0,this);
}//end overridden paint()
}//end inner class MyCanvas
}//end class GUI
//======================================================//

/*DotProd3D03.java
Copyright 2008, R.G.Baldwin
Revised 03/07/08
The purpose of this program is to demonstrate a practical
use of the vector dot product - backface culling.
Study Kjell through Chapter 10, Angle between 3D Vectors.
The program draws a 3D circular cylinder by stacking 20
circular disks on the x-z plane. The disks are centered on
the y-axis and are parallel to the x-z plane. The
thickness of each disk is 5 vertical units.
Backface culling is done using the dot product between a
vector that is parallel to the viewpoint of the viewer and
a vector that is perpendicular to the line being drawn to
form the outline of a disk. The backface culling
process is good but not perfect. There is some leakage
around the back on the right and left sides of the
cylinder and some short lines segments are visible that
should not be visible.
Tested using JDK 1.6 under WinXP.
*********************************************************/
import java.awt.*;
import javax.swing.*;
class DotProd3D03{
public static void main(String[] args){
GUI guiObj = new GUI();
}//end main
}//end controlling class DotProd3D03
//======================================================//
class GUI extends JFrame{
//Specify the horizontal and vertical size of a JFrame
// object.
int hSize = 230;
int vSize = 250;
Image osi;//an off-screen image
int osiWidth;//off-screen image width
int osiHeight;//off-screen image height
MyCanvas myCanvas;//a subclass of Canvas
Graphics2D g2D;//off-screen graphics context.
//----------------------------------------------------//
GUI(){//constructor
//Set JFrame size, title, and close operation.
setSize(hSize,vSize);
setTitle("Copyright 2008,R.G.Baldwin");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create a new drawing canvas and add it to the
// CENTER of the JFrame above the control panel.
myCanvas = new MyCanvas();
this.getContentPane().add(
BorderLayout.CENTER,myCanvas);
//This object must be visible before you can get an
// off-screen image. It must also be visible before
// you can compute the size of the canvas.
setVisible(true);
//Make the size of the off-screen image match the
// size of the canvas.
osiWidth = myCanvas.getWidth();
osiHeight = myCanvas.getHeight();
//Create an off-screen image and get a graphics
// context on it.
osi = createImage(osiWidth,osiHeight);
g2D = (Graphics2D)(osi.getGraphics());
//Call a method that sets the axes and draws the
// cylinder.
drawTheCylinder(g2D);
//Cause the overridden paint method belonging to
// myCanvas to be executed.
myCanvas.repaint();
}//end constructor
//----------------------------------------------------//
//This method is used to set the axes to the center of
// the off-screen image and to draw a 3D cylinder that
// is centered on the y-axis.
private void drawTheCylinder(Graphics2D g2D){
//Translate the origin to the center of the off-screen
// image.
GM02.translate(g2D,0.5*osiWidth,-0.5*osiHeight);
//Erase the screen
g2D.setColor(Color.WHITE);
GM02.fillRect(g2D,-osiWidth/2,osiHeight/2,
osiWidth,osiHeight);
//Get a vector that is approximately parallel to the
// viewpoint of the viewer. The best values for this
// vector were determined experimentally using this
// program and the earlier program named DotProd3D02.
GM02.Vector3D viewPoint =
new GM02.Vector3D(new GM02.ColMatrix3D(43,5,50));
//Draw a cylinder by stacking 20 circular disks on
// the x-z plane. The disks are centered on the
// y-axis and are parallel to the x-z plane. The
// thickness of each disk is 5 vertical units.
GM02.Point3D tempPointA;
GM02.Point3D tempPointB;
g2D.setColor(Color.BLACK);
for(int y = 0;y < 105;y += 5){//iterate on disks
//Define the starting point on the circle for this
// disk.
tempPointA = new GM02.Point3D(new GM02.ColMatrix3D(
76,y - osiHeight/4,0));
//Iterate on points on the circle that represents
// this disk.
for(int cnt = 0;cnt < 360;cnt++){//360 points
//Compute the next point on the circle.
tempPointB =
new GM02.Point3D(new GM02.ColMatrix3D(
76*Math.cos(Math.toRadians(cnt*360/360)),
y - osiHeight/4,
76*Math.sin(Math.toRadians(cnt*360/360))));
//Do backface culling using the dot product of the
// viewpoint vector and a vector that is almost
// perpendicular to the line being drawn. If the
// dot product is negative, or if the disk being
// drawn is the top disk on the stack, draw the
// line. Otherwise, don't draw the line.
//The perpendicular vector used in the dot
// product is the displacement vector from the
// origin to a point that defines one end of the
// line being drawn. Note that this vector is not
// perfectly perpendicular to the line being
// drawn. Later in the series, we will learn about
// and use the cross product to get perpendicular
// vectors.
if((tempPointB.getDisplacementVector(
new GM02.Point3D(
new GM02.ColMatrix3D(0,0,0)))
.dot(viewPoint) < 0.0)
|| (y == 100)){
//Draw the line in 3D.
new GM02.Line3D(
tempPointA,tempPointB).draw(g2D);
}//end if
//Save the point for use in drawing the next line.
tempPointA = tempPointB;
}//end for loop on points
}//end for loop on disks
}//end drawTheCylinder method
//====================================================//
//This is an inner class of the GUI class.
class MyCanvas extends Canvas{
//Override the paint() method. This method will be
// called when the JFrame and the Canvas appear on the
// screen or when the repaint method is called on the
// Canvas object.
//The purpose of this method is to display the
// off-screen image on the screen.
public void paint(Graphics g){
g.drawImage(osi,0,0,this);
}//end overridden paint()
}//end inner class MyCanvas
}//end class GUI
//======================================================//

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.