Skip to content Skip to navigation

OpenStax_CNX

You are here: Home » Content » GAME 2302-0150: Applications of the Vector Dot Product

Navigation

Recently Viewed

This feature requires Javascript to be enabled.
 

GAME 2302-0150: Applications of the Vector Dot Product

Module by: R.G. (Dick) Baldwin. E-mail the author

Summary: Learn how to use the dot product to compute nine different angles of interest that a vector makes with various elements in 3D space. Also learn how to use the dot product to find six of the infinite set of vectors that are perpendicular to a given vector, and how to use the dot product to perform back-face culling of an image.

Preface

This module is one in a collection of modules designed for teaching GAME2302 Mathematical Applications for Game Development at Austin Community College in Austin, TX.

What you have learned

In the previous module, 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 module, you will learn how to apply the vector dot product to three different applications. 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,
  • how to use the dot product to find six somewhat unique vectors of the infinite set of vectors that are perpendicular to a given vector as shown in Image 4 , and
  • how to use the dot product to perform back-face culling to convert the image shown in Image 1 to the image shown in Image 2 .

1
Image 1: A 3D image before back-face culling.
Missing image.

.

2
Image 2: The 3D image after back-face culling.
Missing image.

Viewing tip

I recommend that you open another copy of this module in a separate browser window and use the following links to easily find and view the Images and Listings while you are reading about them.

Images

  • Image 1 . A 3D image before back-face culling.
  • Image 2 . The 3D image after back-face culling.
  • Image 3 . Screen shot of the output from the program named DotProd3D05.
  • Image 4 . Six (magenta) vectors that are perpendicular to a given (black) vector.
  • Image 5 . Screen output when one coordinate has a value of zero.
  • Image 6 . A general formulation of 3D vector perpendicularity.
  • Image 7 . Output from Exercise 1.
  • Image 8 . Output from Exercise 2.

Listings

  • Listing 1 . Beginning of the actionPerformed method in the program named DotProd3D05.
  • Listing 2 . Create ColMatrix3D objects that represent projections.
  • Listing 3 . Create and draw vectors.
  • Listing 4 . Compute and display the nine angles.
  • Listing 5 . Beginning of the actionPerformed method for the program named DotProd3D06.
  • Listing 6 . Remainder of the actionPerformed method.
  • Listing 7 . The method named drawTheCylinder in DotProd3D04.
  • Listing 8 . The method named drawTheCylinder in DotProd3D03.
  • Listing 9 . Source code for the game-math library named GM02.
  • Listing 10 . Source code for the program named DotProd3D05.
  • Listing 11 . Source code for the program named DotProd3D06.
  • Listing 12 . Source code for the program named DotProb3D04.
  • Listing 13 . Source code for the program named DotProb3D03.

Preview

This module will build on what you learned about the vector dot product in the earlier module titled GAME 2302-0145: Getting Started with the Vector Dot Product . In that module, you learned some of the theory behind the dot product. In this module, 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 somewhat unique vectors of the infinite set of vectors that are perpendicular to a given vector. (See Image 4 .)
  • DotProd3D04 - Draws the same 3D object as the one drawn in DotProd3D03 but without the benefit of back-face culling. (See Image 1 .)
  • DotProd3D03 - Demonstrates use of the vector dot product for back-face culling. (See Image 2 .)

I will also provide exercises for you to complete on your own at the end of the module. The exercises will concentrate on the material that you have learned in this module and previous modules.

Discussion and sample code

The game-math library named GM02

The game-math library has not been modified since the previous module. 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 module.

A link to a zip file containing documentation for the library is provided in the earlier module titled GAME 2302-0145: Getting Started with the Vector Dot Product .

The program named DotProd3D05

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 .

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.

Image 3 shows a screen shot of the graphical user interface provided by this program.

3
Image 3: Screen shot of the output from the program named DotProd3D05.
Missing image.

Angles relative to the axes

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

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 Image 3 , 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 modules. 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 module.

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 Image 3 .

4
Listing 1: Beginning of the actionPerformed method in the program named DotProd3D05.
  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);

You have seen code similar to that in Listing 1 many times before. Therefore, this code should not require further explanation beyond the embedded comments.

Create ColMatrix3D objects that represent projections

Listing 2 creates ColMatrix3D objects that represent the projection of the user-specified vector onto each of the three planes.

5
Listing 2: Create ColMatrix3D objects that represent projections.
    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()));

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 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.

6
Listing 3: Create and draw vectors.
    //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 Image 3 .

7
Listing 4: Compute and display the nine angles.
    //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

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.

That concludes the explanation of the program named DotProd3D05 .

The program named DotProd3D06

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 module 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 somewhat unique vectors 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 Image 4 .

8
Image 4: Six (magenta) vectors that are perpendicular to a given (black) vector.
Missing image.

Output on the command-line screen

In addition to the graphic output shown in Image 4 , 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 Image 5 where the value of the z-axis coordinate value was set to zero relative to the value used in Image 4 .

9
Image 5: Screen output when one coordinate has a value of zero.
Missing image.

Special case of two coordinates with a value of zero

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 Image 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 module. Recall that I did some algebraic manipulations in the previous module and produced the equations shown in Image 6 .

10
Image 6: A general formulation of 3D vector perpendicularity.
dot product = x1*x2 + y1*y2 + z1*z2

If the two vectors are perpendicular:

x1*x2 + y1*y2 + z1*z2 = 0.0
x1*x2 =  -(y1*y2 + z1*z2)

x2 = -(y1*y2 + z1*z2)/x1

or

y2 = -(x1*x2 + z1*z2)/y1

or

z2 = -(x1*x2 + y1*y2)/z1

An infinite set of perpendicular vectors

The equations in Image 6 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 Image 4 . The remaining three perpendicular vectors shown in Image 4 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 module is contained in the actionPerformed method. This method is called to respond to a click on the OK button in Image 5 . 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 module.

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.

11
Listing 5: Beginning of the actionPerformed method for the program named DotProd3D06.
  public void actionPerformed(ActionEvent e){
    

Behavior of the actionPerformed method

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

Implement the last equation

Listing 5 implements the last equation from Image 6 , 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 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 expression in Listing 5 matches the last equation in Image 6 .)

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 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 equations shown in Image 6 , creating and drawing four more perpendicular vectors in the process.

12
Listing 6: Remainder of the actionPerformed method.
    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
  //----------------------------------------------------//

Listing 6 also causes the off-screen image to be displayed on the canvas.

That concludes the explanation of the program named DotProd3D06 .

The program named DotProd3D04

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 in Image 1 , while the program named DotProd3D03 draws the 3D object shown in Image 2 . The difference between the two is that the object drawn by this program ( Image 1 ) does not incorporate backface culling to hide the lines on the back of the object. The object in Image 2 does incorporate backface culling. The difference is easy to see.

This program draws a 3D circular cylinder by stacking 20 circular disks on the x-z plane as shown in Image 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 module. 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 modules.

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.

13
Listing 7: The method named drawTheCylinder in DotProd3D04.
  private void drawTheCylinder(Graphics2D g2D){

    

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 module.

The program named DotProd3D03

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 Image 2 .

Will discuss in fragments

A complete listing of this program is provided in Listing 13 near the end of the module. 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 modules.

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.

14
Listing 8: The method named drawTheCylinder in DotProd3D03.
  private void drawTheCylinder(Graphics2D g2D){

The new code and an exercise for the student

The new code in Listing 8 is highlighted by a long explanatory comment near the middle of Listing 8 . I will leave it as an exercise for the student to think about the rationale that was used to decide 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.

Homework assignment

The homework assignment for this module was to study the Kjell tutorial through Chapter 10, Angle between 3D Vectors.

The homework assignment for the next module is to study the Kjell tutorial through Chapter 11, Projections.

In addition to studying the Kjell material, you should read at least the next two modules in this collection and bring your questions about that material to the next classroom session.

Finally, you should have begun studying the physics material at the beginning of the semester and you should continue studying one physics module per week thereafter. You should also feel free to bring your questions about that material to the classroom for discussion.

Run the program

I encourage you to copy the code from Listing 9 through Listing 13 . Compile the code and execute it in conjunction with the game-math library named GM02 in Listing 9 . 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.

Summary

In this module, you learned how to apply the vector dot product to three different applications. 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,
  • 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 Image 4 , and
  • you learned how to use the dot product to perform back-face culling to convert the image in Image 1 to the image in Image 2 .

What's next?

In the next module, you will learn about first-person computer games in general, and how to use the game-math library to write a first-person game in a 3D world using the game math library.

Miscellaneous

This section contains a variety of miscellaneous information.

Note:

Housekeeping material
  • Module name: GAME 2302-0150: Applications of the Vector Dot Product
  • File: Game0150.htm
  • Published: 10/23/12
  • Revised: 12/31/12

Note:

Disclaimers:

Financial : Although the Connexions site makes it possible for you to download a PDF file for this module at no charge, and also makes it possible for you to purchase a pre-printed version of the PDF file, you should be aware that some of the HTML elements in this module may not translate well into PDF.

I also want you to know that, I receive no financial compensation from the Connexions website even if you purchase the PDF version of the module.

In the past, unknown individuals have copied my modules from cnx.org, converted them to Kindle books, and placed them for sale on Amazon.com showing me as the author. I neither receive compensation for those sales nor do I know who does receive compensation. If you purchase such a book, please be aware that it is a copy of a module that is freely available on cnx.org and that it was made and published without my prior knowledge.

Affiliation : I am a professor of Computer Information Technology at Austin Community College in Austin, TX.

Complete program listing

Complete listings of the programs discussed in this module are shown in Listing 9 through Listing 13 below.

15
Listing 9: Source code for the game-math library named GM02.
/*GM02.java 
Copyright 2008, R.G.Baldwin
Revised 02/08/08

This is an update to the game-math library named GM01.

The main purpose of this update was to add vector dot
product and related capabilities to the library.

Please see the comments at the beginning of the library
class named GM01 for a general description of the library.

The following methods are new instance methods of the 
indicated static top-level classes belonging to the class
named GM02.

GM02.ColMatrix2D.dot - compute dot product of two
 ColMatrix2D objects.
GM02.Vector2D.dot - compute dot product of two
 Vector2D objects.
GM02.Vector2D.angle - compute angle between two Vector2D
 objects.

GM02.ColMatrix3D.dot - compute dot product of two
 ColMatrix3D objects
GM02.Vector3D.dot - compute dot product of two
 Vector3D objects.
GM02.Vector3D.angle - compute angle between two Vector3D
 objects.

Tested using JDK 1.6 under WinXP.
*********************************************************/
import java.awt.geom.*;
import java.awt.*;

public class GM02{
  //----------------------------------------------------//
  
  //This method converts a ColMatrix3D object to a
  // ColMatrix2D object. The purpose is to accept
  // x, y, and z coordinate values and transform those
  // values into a pair of coordinate values suitable for
  // display in two dimensions.
  //See http://local.wasp.uwa.edu.au/~pbourke/geometry/
  // classification/ for technical background on the
  // transform from 3D to 2D.
  //The transform equations are:
  // x2d = x3d + z3d * cos(theta)/tan(alpha)
  // y2d = y3d + z3d * sin(theta)/tan(alpha);
  //Let theta = 30 degrees and alpha = 45 degrees
  //Then:cos(theta) = 0.866
  //     sin(theta) = 0.5
  //     tan(alpha) = 1;
  //Note that the signs in the above equations depend
  // on the assumed directions of the angles as well as
  // the assumed positive directions of the axes. The
  // signs used in this method assume the following:
  //   Positive x is to the right.
  //   Positive y is up the screen.
  //   Positive z is protruding out the front of the
  //     screen.
  //   The viewing position is above the x axis and to the
  //     right of the z-y plane.
  public static GM02.ColMatrix2D convert3Dto2D(
                                   GM02.ColMatrix3D data){
    return new GM02.ColMatrix2D(
                  data.getData(0) - 0.866*data.getData(2),
                  data.getData(1) - 0.50*data.getData(2));
  }//end convert3Dto2D 
  //----------------------------------------------------//
  
  //This method wraps around the translate method of the
  // Graphics2D class. The purpose is to cause the
  // positive direction for the y-axis to be up the screen
  // instead of down the screen. When you use this method,
  // you should program as though the positive direction
  // for the y-axis is up.
  public static void translate(Graphics2D g2D,
                               double xOffset,
                               double yOffset){
    //Flip the sign on the y-coordinate to change the
    // direction of the positive y-axis to go up the
    // screen.
    g2D.translate(xOffset,-yOffset);
  }//end translate
  //----------------------------------------------------//
  
  //This method wraps around the drawLine method of the
  // Graphics class. The purpose is to cause the positive
  // direction for the y-axis to be up the screen instead
  // of down the screen. When you use this method, you
  // should program as though the positive direction for
  // the y-axis is up.
  public static void drawLine(Graphics2D g2D,
                              double x1,
                              double y1,
                              double x2,
                              double y2){
    //Flip the sign on the y-coordinate value.
    g2D.drawLine((int)x1,-(int)y1,(int)x2,-(int)y2);
  }//end drawLine
  //----------------------------------------------------//
  
  //This method wraps around the fillOval method of the
  // Graphics class. The purpose is to cause the positive
  // direction for the y-axis to be up the screen instead
  // of down the screen. When you use this method, you
  // should program as though the positive direction for
  // the y-axis is up.
  public static void fillOval(Graphics2D g2D,
                              double x,
                              double y,
                              double width,
                              double height){
    //Flip the sign on the y-coordinate value.
    g2D.fillOval((int)x,-(int)y,(int)width,(int)height);
  }//end fillOval
  //----------------------------------------------------//

  //This method wraps around the drawOval method of the
  // Graphics class. The purpose is to cause the positive
  // direction for the y-axis to be up the screen instead
  // of down the screen. When you use this method, you
  // should program as though the positive direction for
  // the y-axis is up.
  public static void drawOval(Graphics2D g2D,
                              double x,
                              double y,
                              double width,
                              double height){
    //Flip the sign on the y-coordinate value.
    g2D.drawOval((int)x,-(int)y,(int)width,(int)height);
  }//end drawOval
  //----------------------------------------------------//
  
  //This method wraps around the fillRect method of the
  // Graphics class. The purpose is to cause the positive
  // direction for the y-axis to be up the screen instead
  // of down the screen. When you use this method, you
  // should program as though the positive direction for
  // the y-axis is up.
  public static void fillRect(Graphics2D g2D,
                              double x,
                              double y,
                              double width,
                              double height){
    //Flip the sign on the y-coordinate value.
    g2D.fillRect((int)x,-(int)y,(int)width,(int)height);
  }//end fillRect
  //----------------------------------------------------//
  
  

  //An object of this class represents a 2D column matrix.
  // An object of this class is the fundamental building
  // block for several of the other classes in the
  // library.
  public static class ColMatrix2D{
    double[] data = new double[2];
    
    public ColMatrix2D(double data0,double data1){
      data[0] = data0;
      data[1] = data1;
    }//end constructor
    //--------------------------------------------------//
    
    //Overridden toString method.
    public String toString(){
      return data[0] + "," + data[1];
    }//end overridden toString method
    //--------------------------------------------------//
    
    public double getData(int index){
      if((index < 0) || (index > 1)){ 
        throw new IndexOutOfBoundsException();
      }else{
        return data[index];
      }//end else
    }//end getData method
    //--------------------------------------------------//
    
    public void setData(int index,double data){
      if((index < 0) || (index > 1)){ 
        throw new IndexOutOfBoundsException();
      }else{
        this.data[index] = data;
      }//end else
    }//end setData method
    //--------------------------------------------------//
    
    //This method overrides the equals method inherited
    // from the class named Object. It compares the values
    // stored in two matrices and returns true if the
    // values are equal or almost equal and returns false
    // otherwise. 
    public boolean equals(Object obj){
      if(obj instanceof GM02.ColMatrix2D &&
         Math.abs(((GM02.ColMatrix2D)obj).getData(0) - 
                                 getData(0)) <= 0.00001 &&
         Math.abs(((GM02.ColMatrix2D)obj).getData(1) - 
                                  getData(1)) <= 0.00001){
        return true;
      }else{
        return false;
      }//end else
     
    }//end overridden equals method
    //--------------------------------------------------//

    //Adds one ColMatrix2D object to another ColMatrix2D
    // object, returning a ColMatrix2D object.
    public GM02.ColMatrix2D add(GM02.ColMatrix2D matrix){
      return new GM02.ColMatrix2D(
                            getData(0)+matrix.getData(0),
                            getData(1)+matrix.getData(1));
    }//end add
    //--------------------------------------------------//
    
    //Subtracts one ColMatrix2D object from another
    // ColMatrix2D object, returning a ColMatrix2D object.
    // The object that is received as an incoming
    // parameter  is subtracted from the object on which
    // the method is called.
    public GM02.ColMatrix2D subtract(
                                 GM02.ColMatrix2D matrix){
      return new GM02.ColMatrix2D(
                            getData(0)-matrix.getData(0),
                            getData(1)-matrix.getData(1));
    }//end subtract
    //--------------------------------------------------//
    
    //Computes the dot product of two ColMatrix2D
    // objects and returns the result as type double.
    public double dot(GM02.ColMatrix2D matrix){
      return getData(0) * matrix.getData(0) 
           + getData(1) * matrix.getData(1);
    }//end dot
    //--------------------------------------------------//
  }//end class ColMatrix2D
  //====================================================//


  //An object of this class represents a 3D column matrix.
  // An object of this class is the fundamental building
  // block for several of the other classes in the
  // library.
  public static class ColMatrix3D{
    double[] data = new double[3];
    
    public ColMatrix3D(
                  double data0,double data1,double data2){
      data[0] = data0;
      data[1] = data1;
      data[2] = data2;
    }//end constructor
    //--------------------------------------------------//
    
    public String toString(){
      return data[0] + "," + data[1] + "," + data[2];
    }//end overridden toString method
    //--------------------------------------------------//
    
    public double getData(int index){
      if((index < 0) || (index > 2)){ 
        throw new IndexOutOfBoundsException();
      }else{
        return data[index];
      }//end else
    }//end getData method
    //--------------------------------------------------//
    
    public void setData(int index,double data){
      if((index < 0) || (index > 2)){ 
        throw new IndexOutOfBoundsException();
      }else{
        this.data[index] = data;
      }//end else
    }//end setData method
    //--------------------------------------------------//
    
    //This method overrides the equals method inherited
    // from the class named Object. It compares the values
    // stored in two matrices and returns true if the
    // values are equal or almost equal and returns false
    // otherwise. 
    public boolean equals(Object obj){
      if(obj instanceof GM02.ColMatrix3D &&
         Math.abs(((GM02.ColMatrix3D)obj).getData(0) - 
                                 getData(0)) <= 0.00001 &&
         Math.abs(((GM02.ColMatrix3D)obj).getData(1) - 
                                 getData(1)) <= 0.00001 &&
         Math.abs(((GM02.ColMatrix3D)obj).getData(2) - 
                                  getData(2)) <= 0.00001){
        return true;
      }else{
        return false;
      }//end else
     
    }//end overridden equals method
    //--------------------------------------------------//

    //Adds one ColMatrix3D object to another ColMatrix3D
    // object, returning a ColMatrix3D object.
    public GM02.ColMatrix3D add(GM02.ColMatrix3D matrix){
      return new GM02.ColMatrix3D(
                            getData(0)+matrix.getData(0),
                            getData(1)+matrix.getData(1),
                            getData(2)+matrix.getData(2));
    }//end add
    //--------------------------------------------------//
    
    //Subtracts one ColMatrix3D object from another
    // ColMatrix3D object, returning a ColMatrix3D object.
    // The object that is received as an incoming
    // parameter is subtracted from the object on which
    // the method is called.
    public GM02.ColMatrix3D subtract(
                                 GM02.ColMatrix3D matrix){
      return new GM02.ColMatrix3D(
                            getData(0)-matrix.getData(0),
                            getData(1)-matrix.getData(1),
                            getData(2)-matrix.getData(2));
    }//end subtract
    //--------------------------------------------------//
    
    //Computes the dot product of two ColMatrix3D
    // objects and returns the result as type double.
    public double dot(GM02.ColMatrix3D matrix){
      return getData(0) * matrix.getData(0) 
           + getData(1) * matrix.getData(1)
           + getData(2) * matrix.getData(2);
    }//end dot
    //--------------------------------------------------//
  }//end class ColMatrix3D
  //====================================================//
  //====================================================//


  public static class Point2D{
    GM02.ColMatrix2D point;
    
    public Point2D(GM02.ColMatrix2D point){//constructor
      //Create and save a clone of the ColMatrix2D object
      // used to define the point to prevent the point
      // from being corrupted by a later change in the
      // values stored in the original ColMatrix2D object
      // through use of its set method.
      this.point = new ColMatrix2D(
                       point.getData(0),point.getData(1));
    }//end constructor
    //--------------------------------------------------//

    public String toString(){
      return point.getData(0) + "," + point.getData(1);
    }//end toString
    //--------------------------------------------------//
    
    public double getData(int index){
      if((index < 0) || (index > 1)){ 
        throw new IndexOutOfBoundsException();
      }else{
        return point.getData(index);
      }//end else
    }//end getData
    //--------------------------------------------------//
    
    public void setData(int index,double data){
      if((index < 0) || (index > 1)){ 
        throw new IndexOutOfBoundsException();
      }else{
        point.setData(index,data);
      }//end else
    }//end setData
    //--------------------------------------------------//

    //This method draws a small circle around the location
    // of the point on the specified graphics context.
    public void draw(Graphics2D g2D){
      drawOval(g2D,getData(0)-3,
                   getData(1)+3,6,6);
    }//end draw

    //--------------------------------------------------//
    
    //Returns a reference to the ColMatrix2D object that
    // defines this Point2D object.
    public GM02.ColMatrix2D getColMatrix(){
      return point;
    }//end getColMatrix
    //--------------------------------------------------//

    //This method overrides the equals method inherited
    // from the class named Object. It compares the values
    // stored in the ColMatrix2D objects that define two
    // Point2D objects and returns true if they are equal
    // and false otherwise. 
    public boolean equals(Object obj){
      if(point.equals(((GM02.Point2D)obj).
                                         getColMatrix())){
        return true;
      }else{
        return false;
      }//end else
     
    }//end overridden equals method
    //--------------------------------------------------//

    //Gets a displacement vector from one Point2D object
    // to a second Point2D object. The vector points from
    // the object on which the method is called to the
    // object passed as a parameter to the method. Kjell
    // describes this as the distance you would have to
    // walk along the x and then the y axes to get from
    // the first point to the second point.
    public GM02.Vector2D getDisplacementVector(
                                      GM02.Point2D point){
      return new GM02.Vector2D(new GM02.ColMatrix2D(
                            point.getData(0)-getData(0),
                            point.getData(1)-getData(1)));
    }//end getDisplacementVector
    //--------------------------------------------------//
    
    //Adds a Vector2D to a Point2D producing a
    // new Point2D.
    public GM02.Point2D addVectorToPoint(
                                      GM02.Vector2D vec){
      return new GM02.Point2D(new GM02.ColMatrix2D(
                          getData(0) + vec.getData(0),
                          getData(1) + vec.getData(1)));
    }//end addVectorToPoint
    //--------------------------------------------------//
    
    //Returns a new Point2D object that is a clone of
    // the object on which the method is called.
    public Point2D clone(){
      return new Point2D(
                  new ColMatrix2D(getData(0),getData(1)));
    }//end clone
    //--------------------------------------------------//
    
    //The purpose of this method is to rotate a point
    // around a specified anchor point in the x-y plane.
    //The rotation angle is passed in as a double value
    // in degrees with the positive angle of rotation
    // being counter-clockwise.
    //This method does not modify the contents of the
    // Point2D object on which the method is called.
    // Rather, it uses the contents of that object to
    // instantiate, rotate, and return a new Point2D
    // object.
    //For simplicity, this method translates the
    // anchorPoint to the origin, rotates around the
    // origin, and then translates back to the
    // anchorPoint.
    /*
    See http://www.ia.hiof.no/~borres/cgraph/math/threed/
    p-threed.html for a definition of the equations
    required to do the rotation.

    x2 = x1*cos - y1*sin
    y2 = x1*sin + y1*cos
    */ 
    public GM02.Point2D rotate(GM02.Point2D anchorPoint,
                               double angle){
      GM02.Point2D newPoint = this.clone();
      
      double tempX ;
      double tempY;
 
      //Translate anchorPoint to the origin
      GM02.Vector2D tempVec = 
            new GM02.Vector2D(anchorPoint.getColMatrix());
      newPoint = 
              newPoint.addVectorToPoint(tempVec.negate());
      
      //Rotate around the origin.
      tempX = newPoint.getData(0);
      tempY = newPoint.getData(1);
      newPoint.setData(//new x coordinate
                      0,
                      tempX*Math.cos(angle*Math.PI/180) -
                      tempY*Math.sin(angle*Math.PI/180));

      newPoint.setData(//new y coordinate
                      1,
                      tempX*Math.sin(angle*Math.PI/180) +
                      tempY*Math.cos(angle*Math.PI/180));

      //Translate back to anchorPoint
      newPoint = newPoint.addVectorToPoint(tempVec);
      
      return newPoint;

    }//end rotate
    //--------------------------------------------------//
    
    //Multiplies this point by a scaling matrix received
    // as an incoming parameter and returns the scaled
    // point.
    public GM02.Point2D scale(GM02.ColMatrix2D scale){
      return new GM02.Point2D(new ColMatrix2D(
                          getData(0) * scale.getData(0),
                          getData(1) * scale.getData(1)));
    }//end scale
    //--------------------------------------------------//
  }//end class Point2D
  //====================================================//


  public static class Point3D{
    GM02.ColMatrix3D point;
    
    public Point3D(GM02.ColMatrix3D point){//constructor
      //Create and save a clone of the ColMatrix3D object
      // used to define the point to prevent the point
      // from being corrupted by a later change in the
      // values stored in the original ColMatrix3D object
      // through use of its set method.
      this.point = 
         new ColMatrix3D(point.getData(0),
                         point.getData(1),
                         point.getData(2));
    }//end constructor
    //--------------------------------------------------//

    public String toString(){
      return point.getData(0) + "," + point.getData(1) 
                                 + "," + point.getData(2);
    }//end toString
    //--------------------------------------------------//
    
    public double getData(int index){
      if((index < 0) || (index > 2)){ 
        throw new IndexOutOfBoundsException();
      }else{
        return point.getData(index);
      }//end else
    }//end getData
    //--------------------------------------------------//
    
    public void setData(int index,double data){
      if((index < 0) || (index > 2)){ 
        throw new IndexOutOfBoundsException();
      }else{
        point.setData(index,data);
      }//end else
    }//end setData
    //--------------------------------------------------//

    //This method draws a small circle around the location
    // of the point on the specified graphics context.
    public void draw(Graphics2D g2D){
      
      //Get 2D projection coordinate values.
      ColMatrix2D temp = convert3Dto2D(point);
      drawOval(g2D,temp.getData(0)-3,
                   temp.getData(1)+3,
                   6,
                   6);
    }//end draw
    //--------------------------------------------------//
    
    //Returns a reference to the ColMatrix3D object that
    // defines this Point3D object.
    public GM02.ColMatrix3D getColMatrix(){
      return point;
    }//end getColMatrix
    //--------------------------------------------------//

    //This method overrides the equals method inherited
    // from the class named Object. It compares the values
    // stored in the ColMatrix3D objects that define two
    // Point3D objects and returns true if they are equal
    // and false otherwise. 
    public boolean equals(Object obj){
      if(point.equals(((GM02.Point3D)obj).
                                         getColMatrix())){
        return true;
      }else{
        return false;
      }//end else
     
    }//end overridden equals method
    //--------------------------------------------------//

    //Gets a displacement vector from one Point3D object
    // to a second Point3D object. The vector points from
    // the object on which the method is called to the
    // object passed as a parameter to the method. Kjell
    // describes this as the distance you would have to
    // walk along the x and then the y axes to get from
    // the first point to the second point.
    public GM02.Vector3D getDisplacementVector(
                                      GM02.Point3D point){
      return new GM02.Vector3D(new GM02.ColMatrix3D(
                            point.getData(0)-getData(0),
                            point.getData(1)-getData(1),
                            point.getData(2)-getData(2)));
    }//end getDisplacementVector
    //--------------------------------------------------//
    
    //Adds a Vector3D to a Point3D producing a
    // new Point3D.
    public GM02.Point3D addVectorToPoint(
                                      GM02.Vector3D vec){
      return new GM02.Point3D(new GM02.ColMatrix3D(
                          getData(0) + vec.getData(0),
                          getData(1) + vec.getData(1),
                          getData(2) + vec.getData(2)));
    }//end addVectorToPoint
    //--------------------------------------------------//
    
    //Returns a new Point3D object that is a clone of
    // the object on which the method is called.
    public Point3D clone(){
      return new Point3D(new ColMatrix3D(getData(0),
                                         getData(1),
                                         getData(2)));
    }//end clone
    //--------------------------------------------------//
    
    //The purpose of this method is to rotate a point
    // around a specified anchor point in the following
    // order:
    // Rotate around z - rotation in x-y plane.
    // Rotate around x - rotation in y-z plane.
    // Rotate around y - rotation in x-z plane.
    //The rotation angles are passed in as double values
    // in degrees (based on the right-hand rule) in the
    // order given above, packaged in an object of the
    // class GM02.ColMatrix3D. (Note that in this case,
    // the ColMatrix3D object is simply a convenient
    // container and it has no significance from a matrix
    // viewpoint.)
    //The right-hand rule states that if you point the
    // thumb of your right hand in the positive direction
    // of an axis, the direction of positive rotation
    // around that axis is given by the direction that
    // your fingers will be pointing.
    //This method does not modify the contents of the
    // Point3D object on which the method is called.
    // Rather, it uses the contents of that object to
    // instantiate, rotate, and return a new Point3D
    // object.
    //For simplicity, this method translates the
    // anchorPoint to the origin, rotates around the
    // origin, and then translates back to the
    // anchorPoint.
    /*
    See http://www.ia.hiof.no/~borres/cgraph/math/threed/
    p-threed.html for a definition of the equations
    required to do the rotation.
    z-axis 
    x2 = x1*cos - y1*sin
    y2 = x1*sin + y1*cos
    
    x-axis
    y2 = y1*cos(v) - z1*sin(v)
    z2 = y1*sin(v) + z1* cos(v) 
    
    y-axis
    x2 = x1*cos(v) + z1*sin(v)
    z2 = -x1*sin(v) + z1*cos(v)
    */ 
    public GM02.Point3D rotate(GM02.Point3D anchorPoint,
                               GM02.ColMatrix3D angles){
      GM02.Point3D newPoint = this.clone();
      
      double tempX ;
      double tempY;
      double tempZ;
 
      //Translate anchorPoint to the origin
      GM02.Vector3D tempVec = 
            new GM02.Vector3D(anchorPoint.getColMatrix());
      newPoint = 
              newPoint.addVectorToPoint(tempVec.negate());

      double zAngle = angles.getData(0);
      double xAngle = angles.getData(1);
      double yAngle = angles.getData(2);
      
      //Rotate around z-axis
      tempX = newPoint.getData(0);
      tempY = newPoint.getData(1);
      newPoint.setData(//new x coordinate
                      0,
                      tempX*Math.cos(zAngle*Math.PI/180) -
                      tempY*Math.sin(zAngle*Math.PI/180));

      newPoint.setData(//new y coordinate
                      1,
                      tempX*Math.sin(zAngle*Math.PI/180) +
                      tempY*Math.cos(zAngle*Math.PI/180));
      
      //Rotate around x-axis
      tempY = newPoint.getData(1);
      tempZ = newPoint.getData(2);
      newPoint.setData(//new y coordinate
                      1,
                      tempY*Math.cos(xAngle*Math.PI/180) -
                      tempZ*Math.sin(xAngle*Math.PI/180));

      newPoint.setData(//new z coordinate
                      2,
                      tempY*Math.sin(xAngle*Math.PI/180) +
                      tempZ*Math.cos(xAngle*Math.PI/180));
      
      //Rotate around y-axis
      tempX = newPoint.getData(0);
      tempZ = newPoint.getData(2);
      newPoint.setData(//new x coordinate
                      0,
                      tempX*Math.cos(yAngle*Math.PI/180) +
                      tempZ*Math.sin(yAngle*Math.PI/180));

      newPoint.setData(//new z coordinate
                     2,
                     -tempX*Math.sin(yAngle*Math.PI/180) +
                     tempZ*Math.cos(yAngle*Math.PI/180));
      
      //Translate back to anchorPoint
      newPoint = newPoint.addVectorToPoint(tempVec);
      
      return newPoint;

    }//end rotate
    //--------------------------------------------------//
    
    //Multiplies this point by a scaling matrix received
    // as an incoming parameter and returns the scaled
    // point.
    public GM02.Point3D scale(GM02.ColMatrix3D scale){
      return new GM02.Point3D(new ColMatrix3D(
                          getData(0) * scale.getData(0),
                          getData(1) * scale.getData(1),
                          getData(2) * scale.getData(2)));
    }//end scale
    //--------------------------------------------------//
  }//end class Point3D
  //====================================================//
  //====================================================//

  
  public static class Vector2D{
    GM02.ColMatrix2D vector;
    
    public Vector2D(GM02.ColMatrix2D vector){//constructor
      //Create and save a clone of the ColMatrix2D object
      // used to define the vector to prevent the vector
      // from being corrupted by a later change in the
      // values stored in the original ColVector2D object.
      this.vector = new ColMatrix2D(
                     vector.getData(0),vector.getData(1));
    }//end constructor
    //--------------------------------------------------//

    public String toString(){
      return vector.getData(0) + "," + vector.getData(1);
    }//end toString
    //--------------------------------------------------//
    
    public double getData(int index){
      if((index < 0) || (index > 1)){
        throw new IndexOutOfBoundsException();
      }else{
        return vector.getData(index);
      }//end else
    }//end getData
    //--------------------------------------------------//
    
    public void setData(int index,double data){
      if((index < 0) || (index > 1)){ 
        throw new IndexOutOfBoundsException();
      }else{
        vector.setData(index,data);
      }//end else
    }//end setData
    //--------------------------------------------------//
    
    //This method draws a vector on the specified graphics
    // context, with the tail of the vector located at a
    // specified point, and with a small filled circle at
    // the head.
    public void draw(Graphics2D g2D,GM02.Point2D tail){

      drawLine(g2D,
               tail.getData(0),
               tail.getData(1),
               tail.getData(0)+vector.getData(0),
               tail.getData(1)+vector.getData(1));

      fillOval(g2D,
               tail.getData(0)+vector.getData(0)-3,
               tail.getData(1)+vector.getData(1)+3,
               6,
               6);
    }//end draw
    //--------------------------------------------------//
    
    //Returns a reference to the ColMatrix2D object that
    // defines this Vector2D object.
    public GM02.ColMatrix2D getColMatrix(){
      return vector;
    }//end getColMatrix
    //--------------------------------------------------//

    //This method overrides the equals method inherited
    // from the class named Object. It compares the values
    // stored in the ColMatrix2D objects that define two
    // Vector2D objects and returns true if they are equal
    // and false otherwise. 
    public boolean equals(Object obj){
      if(vector.equals((
                     (GM02.Vector2D)obj).getColMatrix())){
        return true;
      }else{
        return false;
      }//end else
     
    }//end overridden equals method
    //--------------------------------------------------//
    
    //Adds this vector to a vector received as an incoming
    // parameter and returns the sum as a vector.
    public GM02.Vector2D add(GM02.Vector2D vec){
      return new GM02.Vector2D(new ColMatrix2D(
                       vec.getData(0)+vector.getData(0),
                       vec.getData(1)+vector.getData(1)));
    }//end add
    //--------------------------------------------------//
    
    //Returns the length of a Vector2D object.
    public double getLength(){
      return Math.sqrt(
           getData(0)*getData(0) + getData(1)*getData(1));
    }//end getLength
    //--------------------------------------------------//
    
    //Multiplies this vector by a scale factor received as
    // an incoming parameter and returns the scaled
    // vector.
    public GM02.Vector2D scale(Double factor){
      return new GM02.Vector2D(new ColMatrix2D(
                                    getData(0) * factor,
                                    getData(1) * factor));
    }//end scale
    //--------------------------------------------------//
    
    //Changes the sign on each of the vector components
    // and returns the negated vector.
    public GM02.Vector2D negate(){
      return new GM02.Vector2D(new ColMatrix2D(
                                            -getData(0),
                                            -getData(1)));
    }//end negate
    //--------------------------------------------------//
    
    //Returns a new vector that points in the same
    // direction but has a length of one unit.
    public GM02.Vector2D normalize(){
      double length = getLength();
      return new GM02.Vector2D(new ColMatrix2D(
                                      getData(0)/length,
                                      getData(1)/length));
    }//end normalize
    //--------------------------------------------------//
    
    //Computes the dot product of two Vector2D
    // objects and returns the result as type double.
    public double dot(GM02.Vector2D vec){
      GM02.ColMatrix2D matrixA = getColMatrix();
      GM02.ColMatrix2D matrixB = vec.getColMatrix();
      return matrixA.dot(matrixB);
    }//end dot
    //--------------------------------------------------//
    
    //Computes and returns the angle between two Vector2D
    // objects. The angle is returned in degrees as type
    // double.
    public double angle(GM02.Vector2D vec){
      GM02.Vector2D normA = normalize();
      GM02.Vector2D normB = vec.normalize();
      double normDotProd = normA.dot(normB);
      return Math.toDegrees(Math.acos(normDotProd));
    }//end angle
    //--------------------------------------------------//
  }//end class Vector2D
  //====================================================//


  public static class Vector3D{
    GM02.ColMatrix3D vector;
    
    public Vector3D(GM02.ColMatrix3D vector){//constructor
      //Create and save a clone of the ColMatrix3D object
      // used to define the vector to prevent the vector
      // from being corrupted by a later change in the
      // values stored in the original ColMatris3D object.
      this.vector = new ColMatrix3D(vector.getData(0),
                                    vector.getData(1),
                                    vector.getData(2));
    }//end constructor
    //--------------------------------------------------//

    public String toString(){
      return vector.getData(0) + "," + vector.getData(1) 
                                + "," + vector.getData(2);
    }//end toString
    //--------------------------------------------------//
    
    public double getData(int index){
      if((index < 0) || (index > 2)){
        throw new IndexOutOfBoundsException();
      }else{
        return vector.getData(index);
      }//end else
    }//end getData
    //--------------------------------------------------//
    
    public void setData(int index,double data){
      if((index < 0) || (index > 2)){ 
        throw new IndexOutOfBoundsException();
      }else{
        vector.setData(index,data);
      }//end else
    }//end setData
    //--------------------------------------------------//
    
    //This method draws a vector on the specified graphics
    // context, with the tail of the vector located at a
    // specified point, and with a small circle at the
    // head.
    public void draw(Graphics2D g2D,GM02.Point3D tail){
      
      //Get a 2D projection of the tail
      GM02.ColMatrix2D tail2D = convert3Dto2D(tail.point);
      
      //Get the 3D location of the head
      GM02.ColMatrix3D head = 
                      tail.point.add(this.getColMatrix());
      
      //Get a 2D projection of the head
      GM02.ColMatrix2D head2D = convert3Dto2D(head);
      drawLine(g2D,tail2D.getData(0),
                   tail2D.getData(1),
                   head2D.getData(0),
                   head2D.getData(1));      

      //Draw a small filled circle to identify the head.
      fillOval(g2D,head2D.getData(0)-3,
                   head2D.getData(1)+3,
                   6,
                   6);

    }//end draw
    //--------------------------------------------------//
    
    //Returns a reference to the ColMatrix3D object that
    // defines this Vector3D object.
    public GM02.ColMatrix3D getColMatrix(){
      return vector;
    }//end getColMatrix
    //--------------------------------------------------//

    //This method overrides the equals method inherited
    // from the class named Object. It compares the values
    // stored in the ColMatrix3D objects that define two
    // Vector3D objects and returns true if they are equal
    // and false otherwise. 
    public boolean equals(Object obj){
      if(vector.equals((
                     (GM02.Vector3D)obj).getColMatrix())){
        return true;
      }else{
        return false;
      }//end else
     
    }//end overridden equals method
    //--------------------------------------------------//
    
    //Adds this vector to a vector received as an incoming
    // parameter and returns the sum as a vector.
    public GM02.Vector3D add(GM02.Vector3D vec){
      return new GM02.Vector3D(new ColMatrix3D(
                       vec.getData(0)+vector.getData(0),
                       vec.getData(1)+vector.getData(1),
                       vec.getData(2)+vector.getData(2)));
    }//end add
    //--------------------------------------------------//
    
    //Returns the length of a Vector3D object.
    public double getLength(){
      return Math.sqrt(getData(0)*getData(0) + 
                       getData(1)*getData(1) + 
                       getData(2)*getData(2));
    }//end getLength
    //--------------------------------------------------//
    
    //Multiplies this vector by a scale factor received as
    // an incoming parameter and returns the scaled
    // vector.
    public GM02.Vector3D scale(Double factor){
      return new GM02.Vector3D(new ColMatrix3D(
                                    getData(0) * factor,
                                    getData(1) * factor,
                                    getData(2) * factor));
    }//end scale
    //--------------------------------------------------//
    
    //Changes the sign on each of the vector components
    // and returns the negated vector.
    public GM02.Vector3D negate(){
      return new GM02.Vector3D(new ColMatrix3D(
                                            -getData(0),
                                            -getData(1),
                                            -getData(2)));
    }//end negate
    //--------------------------------------------------//
    
    //Returns a new vector that points in the same
    // direction but has a length of one unit.
    public GM02.Vector3D normalize(){
      double length = getLength();
      return new GM02.Vector3D(new ColMatrix3D(
                                      getData(0)/length,
                                      getData(1)/length,
                                      getData(2)/length));
    }//end normalize
    //--------------------------------------------------//
    
    //Computes the dot product of two Vector3D
    // objects and returns the result as type double.
    public double dot(GM02.Vector3D vec){
      GM02.ColMatrix3D matrixA = getColMatrix();
      GM02.ColMatrix3D matrixB = vec.getColMatrix();
      return matrixA.dot(matrixB);
    }//end dot
    //--------------------------------------------------//
    
    //Computes and returns the angle between two Vector3D
    // objects. The angle is returned in degrees as type
    // double.
    public double angle(GM02.Vector3D vec){
      GM02.Vector3D normA = normalize();
      GM02.Vector3D normB = vec.normalize();
      double normDotProd = normA.dot(normB);
      return Math.toDegrees(Math.acos(normDotProd));
    }//end angle
    //--------------------------------------------------//
  }//end class Vector3D
  //====================================================//
  //====================================================//

  
  //A line is defined by two points. One is called the
  // tail and the other is called the head. Note that this
  // class has the same name as one of the classes in
  // the Graphics2D class. Therefore, if the class from
  // the Graphics2D class is used in some future upgrade
  // to this program, it will have to be fully qualified.
  public static class Line2D{
    GM02.Point2D[] line = new GM02.Point2D[2];
    
    public Line2D(GM02.Point2D tail,GM02.Point2D head){
      //Create and save clones of the points used to
      // define the line to prevent the line from being 
      // corrupted by a later change in the coordinate
      // values of the points.
      this.line[0] = new Point2D(new GM02.ColMatrix2D(
                        tail.getData(0),tail.getData(1)));
      this.line[1] = new Point2D(new GM02.ColMatrix2D(
                        head.getData(0),head.getData(1)));
    }//end constructor
    //--------------------------------------------------//

    public String toString(){
      return "Tail = " + line[0].getData(0) + "," 
             + line[0].getData(1) + "\nHead = " 
             + line[1].getData(0) + "," 
             + line[1].getData(1);
    }//end toString
    //--------------------------------------------------//

    public GM02.Point2D getTail(){
      return line[0];
    }//end getTail
    //--------------------------------------------------//
    
    public GM02.Point2D getHead(){
      return line[1];
    }//end getHead
    //--------------------------------------------------//
    
    public void setTail(GM02.Point2D newPoint){
      //Create and save a clone of the new point to
      // prevent the line from being corrupted by a
      // later change in the coordinate values of the
      // point.
      this.line[0] = new Point2D(new GM02.ColMatrix2D(
                newPoint.getData(0),newPoint.getData(1)));
    }//end setTail
    //--------------------------------------------------//
    
    public void setHead(GM02.Point2D newPoint){
      //Create and save a clone of the new point to
      // prevent the line from being corrupted by a
      // later change in the coordinate values of the
      // point.
      this.line[1] = new Point2D(new GM02.ColMatrix2D(
                newPoint.getData(0),newPoint.getData(1)));
    }//end setHead
    //--------------------------------------------------//
    
    public void draw(Graphics2D g2D){
      drawLine(g2D,getTail().getData(0),
                   getTail().getData(1),
                   getHead().getData(0),
                   getHead().getData(1));
    }//end draw
    //--------------------------------------------------//
  }//end class Line2D
  //====================================================//


  //A line is defined by two points. One is called the
  // tail and the other is called the head.
  public static class Line3D{
    GM02.Point3D[] line = new GM02.Point3D[2];
    
    public Line3D(GM02.Point3D tail,GM02.Point3D head){
      //Create and save clones of the points used to
      // define the line to prevent the line from being 
      // corrupted by a later change in the coordinate
      // values of the points.
      this.line[0] = new Point3D(new GM02.ColMatrix3D(
                                        tail.getData(0),
                                        tail.getData(1),
                                        tail.getData(2)));
      this.line[1] = new Point3D(new GM02.ColMatrix3D(
                                        head.getData(0),
                                        head.getData(1),
                                        head.getData(2)));
    }//end constructor
    //--------------------------------------------------//

    public String toString(){
      return "Tail = " + line[0].getData(0) + "," 
                       + line[0].getData(1)  + "," 
                       + line[0].getData(2) 
                       + "\nHead = " 
                       + line[1].getData(0) + "," 
                       + line[1].getData(1) + ","      
                       + line[1].getData(2);
    }//end toString
    //--------------------------------------------------//

    public GM02.Point3D getTail(){
      return line[0];
    }//end getTail
    //--------------------------------------------------//
    
    public GM02.Point3D getHead(){
      return line[1];
    }//end getHead
    //--------------------------------------------------//

    public void setTail(GM02.Point3D newPoint){
      //Create and save a clone of the new point to
      // prevent the line from being corrupted by a
      // later change in the coordinate values of the
      // point.
      this.line[0] = new Point3D(new GM02.ColMatrix3D(
                                    newPoint.getData(0),
                                    newPoint.getData(1),
                                    newPoint.getData(2)));
    }//end setTail
    //--------------------------------------------------//
    
    public void setHead(GM02.Point3D newPoint){
      //Create and save a clone of the new point to
      // prevent the line from being corrupted by a
      // later change in the coordinate values of the
      // point.
      this.line[1] = new Point3D(new GM02.ColMatrix3D(
                                    newPoint.getData(0),
                                    newPoint.getData(1),
                                    newPoint.getData(2)));
    }//end setHead
    //--------------------------------------------------//

    public void draw(Graphics2D g2D){
      
      //Get 2D projection coordinates.
      GM02.ColMatrix2D tail = 
                           convert3Dto2D(getTail().point);
      GM02.ColMatrix2D head = 
                           convert3Dto2D(getHead().point);

      drawLine(g2D,tail.getData(0),
                   tail.getData(1),
                   head.getData(0),
                   head.getData(1));
    }//end draw
    //--------------------------------------------------//
  }//end class Line3D
  //====================================================//

}//end class GM02

.

16
Listing 10: Source code for the program named DotProd3D05.
/*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

.

17
Listing 11: Source code for the program named DotProd3D06.
/*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 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

.

18
Listing 12: Source code for the program named DotProb3D04.
/*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

.

19
Listing 13: Source code for the program named DotProb3D03.
/*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

Exercises

Exercise 1

Using Java and the game-math library named GM02 , or using a different programming environment of your choice, write a program that creates the drawing of half of a 3D sphere protruding upward from the x-z plane as shown in Image 7 . The north and south poles of the sphere lie on the y-axis, but only the northern hemisphere is visible.

Cause your name to appear in the screen output in some manner.

20
Image 7: Output from Exercise 1.
Missing image.

Exercise 2

Beginning with a program similar to the one that you wrote in Exercise 1 , create a drawing of a 3D sphere as shown in Image 8 . The north and south poles of the sphere lie on the y-axis.

21
Image 8: Output from Exercise 2.
Missing image.

-end-

Content actions

Download module as:

PDF | EPUB (?)

What is an EPUB file?

EPUB is an electronic book format that can be read on a variety of mobile devices.

Downloading to a reading device

For detailed instructions on how to download this content's EPUB to your specific device, click the "(?)" link.

| More downloads ...

Add module to:

My Favorites (?)

'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own (?)

Definition of a lens

Lenses

A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks