Java Programming Notes # 1700
- Preface
- Preview
- Discussion and sample code
- Points, Lines, and Vectors
- The program named PointLine01
- The program named PointLine02 and the library named GM2D01
- Run the programs
- Summary
- What’s next?
- Resources
- Complete program listings
- Copyright
- About the author
Preface
General
Good math skills are required
In order to be a successful game programmer you must be skilled in technologies other than simply programming. Those technologies include mathematics.
Unfortunately, I find that skills in mathematics are in short supply among programming students at the college where I teach. Further, I suspect that such shortcomings are not peculiar to my college. Those skills are probably in short supply among programming students and experienced programmers on a nationwide basis.
While I don’t claim to have expertise in game programming, I do have quite a lot of strength in mathematics as a result of my engineering background. My purpose in writing this tutorial is to help you to gain mathematical strengths as well.
First in a series
This tutorial is the first in a series designed to teach you some of the mathematical skills that you will need (in addition to good programming skills) to become a successful game programmer. In addition to helping you with your math skills, I will also teach you how to incorporate those skills into object-oriented programming using Java. If you are familiar with other object-oriented programming languages such as C#, you should have no difficulty porting this material from Java to those other programming languages.
Lots of graphics
Since most computer games make heavy use of either 2D or 3D graphics, you will need skills in the mathematical areas that are required for success in 2D and 3D graphics programming. As a minimum, this includes but is not limited to skills in:
- Geometry
- Trigonometry
- Vectors
- Matrices
- 2D and 3D transforms
- Transformations between coordinate systems
- Projections
Of course, game programming requires mathematical skills beyond those required for graphics. However, for starters, this series will concentrate on the last five items in the above list. (I will assume that you either already have, or can gain the required skills in geometry and trigonometry on your own. There are many excellent tutorials available on the web to help you in that quest.)
A different approach
If you are familiar with my previously published tutorials, you will be aware that I usually try to cover the waterfront in my tutorials. Although I often make references to other good material, I rarely depend on material written by others to form an integral part of my presentation. In other words, I usually provide the required technical background to support the programming concepts embodied in my tutorials.
Insofar as vectors and matrices are concerned, I will take a different approach in this series. I will frequently refer you to an excellent interactive tutorial on Vector Math for 3D Computer Graphics by Dr. Bradley P. Kjell (see Resources) for the required technical background. I will then teach you how to incorporate the knowledge that you gain from Kjell’s tutorial into Java code with a heavy emphasis on object-oriented programming.
In the process, I will develop and explain a game-programming math library that you can use to experiment with and to confirm what you learn about vectors and matrices from the Kjell tutorial. The library will start out small and will grow as we progress through more and more material in subsequent lessons.
Navigation issues in the Kjell tutorial
Once you get into the Kjell interactive tutorial, you will find that the technical material is excellent, but the ability to navigate through the tutorial is somewhat limited. In particular, the Kjell tutorial requires you to start at the beginning and to navigate forward or backward one page at a time. (There is a Next button on each page and you can use your browser’s Back button to go back one page.)
I have provided a set of online links that will make it easier for you to navigate the Kjell tutorial. With those links, you will be able to navigate inside the tutorial on the basis of topic headers and you won’t be constrained to navigate from start to finish one page at a time. Among other advantages, this will make it easier for you go back and review topics that you may not have understood completely on your first pass through the material.
Viewing tip
I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.
Figures
- Figure 1. Graphics illustration of four points and two lines.
- Figure 2. Three views in the construction of a 3D human figure.
- Figure 3. Screen output from the program named PointLine02.
- Figure 4. Sample output from updated programming-math library
Listings
- Listing 1. The controlling class named PointLine01.
- Listing 2. Beginning of the class named GUI.
- Listing 3. Beginning of the inner class named MyCanvas.
- Listing 4. Define two points as two locations in space.
- Listing 5. Construct a line segment.
- Listing 6. Construct an object that represents a vertical line segment.
- Listing 7. Draw the two lines on the screen.
- Listing 8. Beginning of the class named PointLine02.
- Listing 9. Beginning of the class named GM2D01.
- Listing 10. Exercising the Point class.
- Listing 11. The static top-level class named Point.
- Listing 12. The static top-level class named Vector.
- Listing 13. The static top-level class named Line.
- Listing 14. Source code for the program named PointLine01.
- Listing 15. Source code for the program named PointLine02.
- Listing 16. Source code for the game-programming math library named GM2D01.
Supplementary material
I recommend that you also study the other lessons in my extensive collection of online Java tutorials. You will find a consolidated index at www.DickBaldwin.com.
Preview
In this lesson, I will introduce you to an excellent interactive tutorial titled Vector Math for 3D Computer Graphics (see Resources) written by Dr. Bradley P. Kjell. Then I will present and explain two sample programs and a sample game-programming math library intended to represent concepts from Dr. Kjell’s tutorial in Java code.
Discussion and sample code
Points, lines, and vectors
To get you started, I recommend that you study CHAPTER 0 — Points and Lines in Kjell’s tutorial (see Resources). I recommend that you also study CHAPTER 1 — Vectors, Points, and Column Matrices down through the topic titled Variables as Elements. You may believe that you already know all there is to know about points and lines. However, I suspect that you will find explanations of some subtle issues that you never thought about before. In addition, Kjell begins the discussion of vectors and establishes the relationship between a vector and a column matrix in this material.
Represent a point with a column matrix
While you are there, make sure you understand what a column matrix means. Make sure you understand that a column matrix can be used to represent a point in a given coordinate frame. Also make sure you understand that the same point will have different representations in different coordinate frames. (You must know which coordinate frame is being used to represent a point with a column matrix.)
The program named PointLine01
Before we go any further, let’s take a look at a simple Java program that illustrates one of the ways that points and lines are represented in Java code.
The Point2D.Double class
This program illustrates one implementation of the concepts of a point and a line segment in Java code. Four points (locations in space) are defined by passing the coordinates of the four points as the x and y parameters to the constructor for the Point2D.Double class. This results in four objects of the Point2D.Double class.
The Line2D.Double class
Two line segments are defined by passing pairs of points as parameters to the constructor for the Line2D.Double class. This results in two objects of the Line2D.Double class. This results in two objects of the Line2D.Double class.
|
The draw method
The draw method belonging to an object of the Graphics2D class is used to draw the two line segments on a Canvas object for which the origin has been translated to the center of the Canvas. The result is as shown in Figure 1. The coordinate values of the points and the selection of point-pairs to specify the ends of the line segments is such that the final rendering is a pair of orthogonal lines that intersect at the origin. (You could think of these lines as the axes in a Cartesian coordinate system.)
Figure 1. Graphics illustration of four points and two lines.
Will discuss in fragments
I will present and explain this program in fragments. A complete listing of the program is provided in Listing 14 near the end of the lesson. The first fragment is shown in Listing 1.
Listing 1. The controlling class named PointLine01.
class PointLine01{ public static void main(String[] args){ GUI guiObj = new GUI(); }//end main }//end controlling class PointLine01 |
Listing 1 shows the controlling class, including the main method for the program named PointLine01. The main method simply instantiates a new object of a class named GUI. It is the GUI object that produces the screen image shown in Figure 1.
The class named GUI
Listing 2 shows the beginning of the class named GUI, including the constructor for the class.
Listing 2. Beginning of the class named GUI.
class GUI extends JFrame{ //Specify the horizontal and vertical size of a JFrame // object. int hSize = 200; int vSize = 200; GUI(){//constructor //Set JFrame size and title setSize(hSize,vSize); setTitle("R.G.Baldwin"); //Create a new drawing canvas and add it to the // center of the JFrame. MyCanvas myCanvas = new MyCanvas(); this.getContentPane().add(myCanvas); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); }//end constructor |
Listing 2 begins by declaring and initializing a pair of instance variables that will be used to specify the size of the JFrame shown in Figure 1.
The constructor for the class named GUI
The constructor begins by using the two instance variables to set the size of the JFrame and setting the title for the JFrame.
Then the constructor instantiates a Canvas object and adds it to theJFrame. Without getting into the details as to why, I will simply tell you that the Canvas object fills the entire client area of the frame, which is the area inside of the four borders.
Finally, the constructor defines the behavior of the X-button in the top right of the JFrame and causes the JFrame to become visible on the screen. Hopefully, everything that I have discussed so far is familiar to you. If not, you may want to spend some time studying my earlier tutorials in this area. As mentioned earlier, you will find links to all of those tutorials at www.DickBaldwin.com.
Beginning of the inner class named MyCanvas
Listing 3 shows the beginning of an inner class named MyCanvas including the beginning of an overridden paint method. (The Canvas class was extended into the MyCanvas class to make it possible to override the paint method.) This overridden paint method will be executed whenever the JFrame containing the Canvas is displayed on the computer screen or whenever the repaint method is called on the canvas.
Listing 3. Beginning of the inner class named MyCanvas.
class MyCanvas extends Canvas{ public void paint(Graphics g){ //Downcast the Graphics object to a Graphics2D // object. The Graphics2D class provides // capabilities that don't exist in the Graphics // class. Graphics2D g2 = (Graphics2D)g; //By default, the origin is at the upper-left corner // of the canvas. This statement translates the // origin to the center of the canvas. g2.translate( this.getWidth()/2.0,this.getHeight()/2.0); |
An object of the Graphics class
The paint method always receives an incoming reference to an object of the class Graphics. As a practical matter, you can think of that object as representing a rectangular area on the screen on which the instructions in the paint method will draw lines, images, etc.
|
The Graphics2D class
The Graphics class was defined early in the life of the Java programming language, and it is of limited capability. Later on, Sun defined the Graphics2D class as a subclass of Graphics. Significant new capabilities, (including the ability to deal with coordinate values as real numbers instead of integers), were included in the Graphics2D class. In order to access those new capabilities, however, it is necessary to downcast the incoming reference to type Graphics2D as shown in Listing 3.
Translate the origin
The last statement in Listing 3 translates the origin from the upper-left corner of the canvas to the center of the canvas. This is equivalent to creating a new coordinate frame as explained by Kjell. The default coordinate frame has the origin at the upper-left corner of the canvas. The new coordinate frame has the origin at the center of the canvas.
Note, however, that even though the origin has been translated, the positive vertical direction is still toward the bottom of the canvas.
Define two points as two locations in space
Listing 4 defines two points in space by instantiating two objects of the class named Point2D.Double, and saving references to those objects in variables of the superclass type Point2D.
Listing 4. Define two points as two locations in space.
Point2D pointA = new Point2D.Double(-this.getWidth()/2.5,0.0); Point2D pointB = new Point2D.Double(this.getWidth()/2.5,0.0); |
The object referred to as pointA represents the location in 2D space at the left end of the horizontal line shown in Figure 1. As explained by Kjell, the values used to represent this location in space are relative to the current coordinate frame in which the origin is at the center of the canvas. Had the origin not been translated to the center of the canvas in Listing 3, a different set of values would have been required to represent that same location in space.
Similarly, the object referred to as pointB represents the location in space at the right end of the horizontal line shown in Figure 1.
Construct a line segment
Listing 5 uses the two points described above to construct an object that represents a line segment connecting the two points by instantiating an object of the class named Line2D.Double. As shown in Figure 1, the values of the points relative to the current coordinate frame causes this line segment to be horizontal when the coordinate frame is displayed with the orientation shown in Figure 1. On the other hand, a different rendering of the coordinate frame may have caused the line segment to be something other than horizontal.
Listing 5. Construct a line segment.
Line2D.Double horizLine = new Line2D.Double(pointA,pointB); |
Not the true line segment
The main point here is that the line segment created in Listing 5 represents a line segment between two points in space but it is not the true line segment. The true line segment has no width, and therefore is not visible to the human eye. The line segment constructed in Listing 5 is simply a representation of the true line segment. When rendered on the screen, that line segment could take on an infinite number of appearances depending on how the space is rendered on the screen. It just happens that in the case of Figure 1, the rendering of that space on the screen causes the line segment to appear to be parallel to the bottom of a rectangular screen.
Construct an object that represents a vertical line segment
Listing 6 uses a similar procedure to construct an object that represents a line segment that is perpendicular to the previous line segment, and which intersects the previous line segment at the origin of the current coordinate frame.
Listing 6. Construct an object that represents a vertical line segment.
Point2D pointC = new Point2D.Double(0.0,-this.getHeight()/2.5); Point2D pointD = new Point2D.Double(0.0,this.getHeight()/2.5); Line2D.Double vertLine = new Line2D.Double(pointC,pointD); |
Draw the two lines on the screen
Finally, Listing 7 calls the draw method of the Graphics2D class twice in succession to draw the two lines on the screen as shown in Figure 1.
Listing 7. Draw the two lines on the screen.
g2.draw(horizLine); g2.draw(vertLine); }//end overridden paint() }//end inner class MyCanvas }//end class GUI |
Listing 7 also signals the end of the overridden paint method, the end of the inner class named MyCanvas, and the end of the top-level class named GUI.
But wait, there’s something wrong here
Kjell describes his points and lines in a very general way that is suitable for use in mathematical operations later on. However, in the above program, I fell into the trap of defining my points and lines using Java classes that are intended primarily for rendering graphics on the screen. That approach is probably not conducive to use in mathematical operations. We need to step back and take another look at what we are doing here.
Points, points, and more points
There will be many occasions when you, as a game programmer, will need to define the coordinate values for a point (or a set of points) that you have no intention of displaying on the screen. Instead, you will use those points for various mathematical operations to produce something else that will be displayed on the screen. For example, Figure 2 shows three views in the construction of the Ice Skater object in the Alice programming language (see Resources).
Figure 2. Three views in the construction of a 3D human figure.
Points as the vertices of triangles
The top image in Figure 2 shows a graphical representation of a set of points used to define the vertices of a set of polygons (probably triangles), which in turn were used in the construction of the Ice Skater object shown in the bottom image of Figure 2. A graphical representation of the polygons is shown in the middle image in Figure 2.
As you can see, neither the points in the top image, nor the lines that comprise the sides of the polygons in the middle image appear in the final rendering of the object in the bottom image. However, both the points and the polygons were required to support the mathematical operations that ultimately resulted in the Ice Skater object. Only the bottom image is typically displayed on the computer screen.
Another look at points and lines
We’ll take another look at points and lines, and will introduce column matrices and vectors in the next sample program.
What is a vector?
According to Kjell, “A vector is a geometrical object that has two properties: length and direction.” He also tells us, “A vector does not have a position.”
In addition, Kjell tells us that we can represent a vector with two real numbers in a 2D system and three real numbers in a 3D system.
Use a column matrix to represent a vector
A column vector provides a good way to store two real numbers in a computer program. Therefore, in addition to representing a point, a column matrix can also be used to represent a vector. However, the column matrix is not the vector. The contents of the column matrix simply represent certain aspects of the vector in a particular frame. Different column matrices can be used to represent the same vector in different frames, in which case, the contents of the matrices will be different.
An absolute location in space
The fact that a column matrix can be used to represent both points and vectors can be confusing. However, as you will see later, this is convenient from a programming viewpoint. The two (or three) real number values contained in the matrix to represent a point specify an absolute location in space relative to the current coordinate frame.
A vector specifies a displacement
A vector does not have a position. Rather, it has only two properties: length and direction. Kjell tells us that the two (or three) real number values contained in the matrix to represent a vector (in 2D or 3D) specify a displacement of a specific distance from an arbitrary point in a specific direction.
In 2D, the two values contained in the matrix represent the displacements along a pair of orthogonal axes (call them x and y for simplicity). As you will see in a future lesson, in the case of 2D, the length of the vector is the length of the hypotenuse of a right triangle formed by the x and y displacement values. The direction of the vector can be determined from the angle formed by the x-displacement and the line segment that represents the hypotenuse of the right triangle. Similar considerations apply in 3D as well but they are somewhat more complicated.
The bottom line is that while a point is an absolute location, a vector is a displacement.
Do we need to draw vectors?
It is very common to draw vectors in various engineering disciplines such as free-body diagrams in theoretical mechanics. My guess is that it is unusual to draw vectors in the final version of computer games, but I may be wrong. Normally what you will need to draw in a computer game is the result of one or more vectors acting on an object, such as the velocity and acceleration vectors that apply to a speeding vehicle going around a curve. In that case, you might draw the results obtained from using the vector for mathematical computations (perhaps the vehicle turns over) but you probably wouldn’t draw the vectors themselves.
The program named PointLine02 and the library named GM2D01
The purpose of this program is to introduce you to a game-math library named GM2D01. (The class name GM2D01 is an abbreviation for GameMath2D01. Later in this series, I will probably develop and present a 3D game-math library named GM3D01.)
This program instantiates objects from the following static top-level classes belonging to the class named GM2D01:
- ColMatrix
- Point
- Vector
- Line
Then the program displays the contents of those objects on the standard output device in two different ways.
A complete listing of the program named PointLine02 is provided in Listing 15 near the end of the lesson and a complete listing of the game-math library named GM2D01 is provided in Listing 16.
Screen output from the program named PointLine02
Figure 3 shows the screen output produced by running this program.
Figure 3. Screen output from the program named PointLine02.
Instantiate and display the contents of a new ColMatrix object 2.5,6.8 2.5 6.8 Bad index Instantiate and display the contents of a new Point object 3.4,9.7 3.4 9.7 Bad index Instantiate and display the contents of a new Vector object -1.9,7.5 -1.9 7.5 Bad index Instantiate and display the contents of a new Line object Tail = 1.1,2.2 Head = 3.3,4.4 1.1,2.2 3.3,4.4 Press any key to continue... |
I will refer back to the material in Figure 3 in subsequent paragraphs.
The game-math library named GM2D01
As mentioned earlier, the name GM2D01 is an abbreviation for GameMath2D01. (I elected to use the abbreviated name to keep the code from being so long.) This is a game-math class, which will be expanded over time as I publish sample programs and additional tutorial lessons in this series.
For educational purposes only
The game-math class is provided solely for educational purposes. No effort was made to optimize the code in any way. Rather, the class was designed and implemented for maximum clarity in order to help you understand the programming details of various mathematical operations commonly used in graphics and game programming.
Each time the library is expanded or modified, it will be given a new name by incrementing the two digits at the end of the class name to make one version distinguishable from the next. No attempt will be made to maintain backward compatibility from one version of the library to the next.
Static top-level methods
The GM2D01 class contains several static top-level classes (See Java 2D Graphics, Nested Top-Level Classes and Interfaces in Resources if you are unfamiliar with static top-level classes.). This organizational approach was chosen primarily for the purpose of gathering the individual classes together under a single naming umbrella while avoiding name conflicts within a single package. For example, as time passes and this library is expanded, my default package may contain class files with the following names, each representing a compiled version of the Point class in a different version of the overall library.
- GM2D01$Point.class
- GM2D02$Point.class
- GM2D03$Point.class
Real numbers represented as type double
All real-number values used in the library are maintained as type double because double is the default representation for real numbers in Java.
Will discuss in fragments
I will explain the code in Listing 15 and Listing 16 in fragments, switching back and forth between the code from the program named PointLine02 and the library class named GM2D01 to show how they work together.
Beginning of the class named PointLine02
Listing 8 shows the beginning of the class named PointLine02 including the beginning of the main method.
Listing 8. Beginning of the class named PointLine02.
class PointLine02{ public static void main(String[] args){ System.out.println( "Instantiate and display the contentsn" + "of a new ColMatrix object"); GM2D01.ColMatrix colMatrix = new GM2D01.ColMatrix(2.5,6.8); System.out.println(colMatrix); try{ System.out.println(colMatrix.getData(0)); System.out.println(colMatrix.getData(1)); //This statement will throw an exception on purpose System.out.println(colMatrix.getData(2)); }catch(Exception e){ System.out.println("Bad index"); }//end catch |
The ColMatrix class
You learned about a column matrix in the Kjell tutorial. The GM2D01 class contains a class named ColMatrix. An object of the ColMatrix class is intended to represent a column matrix as described by Kjell.
The code in Listing 8 instantiates and displays the contents of a new object of the ColMatrix class. (Note the syntax required to instantiate an object of a static top-level class belonging to another class as highlighted in boldface in Listing 8.)
The remaining statements in Listing 8 display the numeric contents of the ColMatrix object using two different approaches.
The overridden toString method
The first approach causes the overridden toString method belonging to the ColMatrix class to be executed. The overridden toString method returns a string that is displayed on the standard output device. That string contains the values of the two real numbers stored in the column matrix.
The getData method
The second approach used to display the data in Listing 8 calls the getData method on the ColMatrix object twice in succession to get the two numeric values stored in the object and to display those two values on the standard output device.
As you will see shortly, the getData method requires an incoming index value of either 0 or 1 to identify the numeric value that is to be returned. Listing 8 purposely calls the getData method with an index value of 2 to demonstrate that this will cause the method to throw an IndexOutOfBoundsException.
Beginning of the class named GM2D01
Listing 9 shows the beginning of the library class named GM2D01, including the entire static top-level class named ColMatrix.
Listing 9. Beginning of the class named GM2D01.
public class GM2D01{ public static class ColMatrix{ double[] data = new double[2]; ColMatrix(double data0,double data1){//constructor data[0] = data0; data[1] = data1; }//end constructor 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(); return data[index]; }//end getData }//end class ColMatrix |
As mentioned earlier, an object of the ColMatrix class represents a 2D column matrix as described by Kjell (see Resources). Furthermore, an object of this class is the fundamental building block for several of the other classes in the library. This class will be expanded in subsequent lessons to provide various matrix arithmetic capabilities.
Constructor for the ColMatrix class
The constructor for the class requires two incoming parameters of type double. (For this example, the code in Listing 8 passes the values 2.5 and 6.8 to the constructor for the class.) The two incoming parameter values are stored in the first two elements of a two-element array of type double where they can be easily accessed later for whatever purpose they may be needed.
Overridden toString method
Listing 9 overrides the toString method to construct and return a reference to a String object containing the two values stored in the array. When the println method is called in Listing 8, the output shown in the third line of text in Figure 3 is produced.
The getData method
Listing 9 defines a method named getData. The purpose of this method is to retrieve and to return the individual values stored in the array. The method requires an incoming parameter value of 0 or 1. This value is used as an index to identify the specific data value that is to be returned. If the method receives any other value, it throws an IndexOutOfBoundsException.
As mentioned earlier, the code in Listing 8 calls this method three times in succession. The first two calls get and display the two data values shown in Figure 3. The third call causes the method to throw an exception producing the first “Bad index” message shown in Figure 3.
The Point class
The GM2D01 class contains a static top-level class named Point. Recall that Kjell tells us that a point is simply a location in space. A point can be represented by a pair of coordinate values in a specific coordinate frame. A convenient way to handle the pair of coordinate values in a program is to store them in a column matrix. An object of the Point class is intended to represent a point in 2D space.
Instantiating a Point object
As you will see shortly, the constructor for the Point class requires a single incoming parameter, which is a reference to an object of the class ColMatrix.
Listing 10, (which is a fragment from the PointLine02 program), instantiates a new ColMatrix object and populates it with the values 3.4 and 9.7. Then it instantiates a new Point object, passing the aforementioned ColMatrix object’s reference as a parameter to the Point constructor.
(Ordinarily I would compress those two statements into a single statement by instantiating an anonymous object of the ColMatrix class in the call to the constructor for the Point class, and I recommend that you do the same. However, I elected to separate the code into two statements in this instance to provide clarity and make it somewhat easier for you to understand.)
Listing 10. Exercising the Point class.
System.out.println(/*blank line*/); System.out.println( "Instantiate and display the contentsn" + "of a new Point object"); colMatrix = new GM2D01.ColMatrix(3.4,9.7); GM2D01.Point point = new GM2D01.Point(colMatrix); System.out.println(point); try{ System.out.println(point.getData(0)); System.out.println(point.getData(1)); //This statement will throw an exception on purpose System.out.println(point.getData(-1)); }catch(Exception e){ System.out.println("Bad index"); }//end catch |
Display the values
Following that, the code in Listing 10 displays the coordinate values that represent the point in the same two ways described earlier for the ColMatrix object. The screen output is shown in Figure 3.
Definition of the static top-level class named Point
The complete definition of the static top-level class named Point is shown in Listing 11.
Listing 11. The static top-level class named Point.
public static class Point{ GM2D01.ColMatrix point; Point(GM2D01.ColMatrix point){ this.point = point; }//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(); return point.getData(index); }//end getData }//end class Point |
Less detail in the discussions
By now, you may be getting a little bored with the detail in which I have been discussing and explaining the code so I will be more brief in my explanations from here on.
The code in Listing 11 is straightforward and shouldn’t require a lot of explanation. Perhaps the most significant thing to note about Listing 11 is that the coordinate values that represent the point are actually stored internally in an object of the type ColMatrix. That approach will prove to be convenient for certain mathematical operations that will be explained in future lessons.
The static top-level class named Vector
The static top-level class named Vector is shown in Listing 12. (Note that this is a different class from the class named java.util.Vector in the standard Java library.) You will find the code that exercises this class and produces the output shown in Figure 3 in the complete listing of the program named PointLine02 in Listing 15. That code is straightforward and shouldn’t require an explanation.
Listing 12. The static top-level class named Vector.
public static class Vector{ GM2D01.ColMatrix vector; Vector(GM2D01.ColMatrix vector){ this.vector = vector; }//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(); return vector.getData(index); }//end getData }//end class Vector |
Storing a vector in a column matrix
Recall that Kjell tells us that both points and vectors can be conveniently stored in a column matrix. As a result, the code in Listing 12, (at this stage in the development of the library), is essentially the same as the code for the Point class in Listing 11. The only differences are a few differences in names.
You may be wondering why I didn’t simply define a single class that can serve both purposes. I probably could have done that. Recall however that this library is being designed for clarity and is not optimized in any way. I believe that such clarity is best served by having consistent names for the kinds of items represented by objects of the classes. Also, it is likely that the definitions of the two classes will be different later when I expand the library to provide additional capabilities.
The static top-level class named Line
Kjell tells us that a line segment is the straight path between two points, and that it has no thickness. The class named GM2D01 contains a class named Line that is intended to represent a line segment as described by Kjell.
Listing 13 is a complete listing of the class named Line. As before, you will find the code that exercises this class and produces the output shown in Figure 3 in the complete listing for the program named PointLine02 in Listing 15. That code is straightforward and shouldn’t require an explanation.
Listing 13. The static top-level class named Line.
table border=”1″ cols=”1″ width=”477″ bgcolor=”#eeeeee” id=”table21″>
//A line is defined by two points. One is called the // tail and the other is called the head. public static class Line{ GM2D01.Point[] line = new GM2D01.Point[2]; Line(GM2D01.Point tail,GM2D01.Point head){ this.line[0] = tail; this.line[1] = head; }//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 GM2D01.Point getTail(){ return line[0]; }//end getTail public GM2D01.Point getHead(){ return line[1]; }//end getTail }//end class Line
Represent a line segment by two points
Since a line segment is the straight path between two points, a line segment is represented by an object that encapsulates two Point objects in this library. One of those points is referred to as the tail and the other is referred to as the head, simply as a means of distinguishing between them.
The constructor for the Line class requires two points as incoming parameters and stores them in a two-element array of type GM2D01.Point. Beyond that, the code in Listing 13 is straightforward and shouldn’t require further explanation.
Run the programs
I encourage you to copy the code from Listing 14, Listing 15, and Listing 16 into your text editor. Compile the code and execute it. Experiment with the code, making changes, and observing the results of your changes. Make sure you understand why your changes produce the results that they do.
Summary
In this lesson, I introduced you to an excellent interactive tutorial titled Vector Math for 3D Computer Graphics (see Resources) written by Dr. Bradley P. Kjell. Then I presented and explained two sample programs and a sample game-programming math library intended to represents concepts from Dr. Kjell’s tutorial in Java code.
What’s next?
While you probably won’t have a frequent need to present points, lines, and vectors in graphical form in computer games that you write, it is often very useful to provide graphical representations of these items during the testing and debugging of the program. In the next lesson in this series, I will update the programming-math library to make it easy to provide graphical representations of points, lines, and vectors. An example of such graphical output is shown in Figure 4. The image on the left consists of graphical objects that represent points and lines. The image on the right consists of graphical objects that represent vectors.
Figure 4. Sample output from updated programming-math library.
Resources
- Index to Baldwin tutorials
- Java 2D Graphics, Nested Top-Level Classes and Interfaces
- Alice 2.0, Educational Software that teaches students computer programming in a 3D environment.
- Vector Math for 3D Computer Graphics, An Interactive Tutorial by Dr. Bradley P. Kjell
Complete program listings
Complete listings of the programs discussed in this lesson are shown in Listing 14, Listing 15, and Listing 16 below.
Listing 14. Source code for the program named PointLine01.
/*PointLine01.java Copyright 2008, R.G.Baldwin This program illustrates the implementation of the concept of a point and a line segment in Java. Four points (locations in space) are defined by using the coordinates of the four points as the x and y parameters to the constructor for the Point2D.Double class. This results in four objects of the Point2D.Double class. Two line segments are defined by using pairs of points as parameters to the Line2D.Double class. This results in two objects of the Line2D.Double class. The draw method belonging to an object of the Graphics2D class is used to draw the two line segments on a Canvas object for which the origin has been translated to the center of the Canvas. The coordinate values of the points and the selection of point-pairs to specify the ends of the line segments is such that the final rendering is a pair of orthogonal lines that intersect at the origin. Tested using JDK 1.6 under WinXP. *********************************************************/ import java.awt.geom.*; import java.awt.*; import javax.swing.*; class PointLine01{ public static void main(String[] args){ GUI guiObj = new GUI(); }//end main }//end controlling class PointLine01 //======================================================// class GUI extends JFrame{ //Specify the horizontal and vertical size of a JFrame // object. int hSize = 200; int vSize = 200; GUI(){//constructor //Set JFrame size and title setSize(hSize,vSize); setTitle("R.G.Baldwin"); //Create a new drawing canvas and add it to the // center of the JFrame. MyCanvas myCanvas = new MyCanvas(); this.getContentPane().add(myCanvas); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); }//end constructor //----------------------------------------------------// //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 in its // contentPane are displayed on the screen. public void paint(Graphics g){ //Downcast the Graphics object to a Graphics2D // object. The Graphics2D class provides // capabilities that don't exist in the Graphics // class. Graphics2D g2 = (Graphics2D)g; //By default, the origin is at the upper-left corner // of the canvas. This statement translates the // origin to the center of the canvas. g2.translate( this.getWidth()/2.0,this.getHeight()/2.0); //Define two points. Point2D pointA = new Point2D.Double(-this.getWidth()/2.5,0.0); Point2D pointB = new Point2D.Double(this.getWidth()/2.5,0.0); //Use the points to construct an object that // represents a line segment that connects the two // points. The values of the points causes this // line segment to be horizontal. Line2D.Double horizLine = new Line2D.Double(pointA,pointB); //Use the same procedure to construct an object that // represents a vertical line segment. Point2D pointC = new Point2D.Double(0.0,-this.getHeight()/2.5); Point2D pointD = new Point2D.Double(0.0,this.getHeight()/2.5); Line2D.Double vertLine = new Line2D.Double(pointC,pointD); //Draw the horizontal and vertical line segments on // the canvas. g2.draw(horizLine); g2.draw(vertLine); }//end overridden paint() }//end inner class MyCanvas }//end class GUI //======================================================// |
Listing 15. Source code for the program named PointLine02.
/*PointLine02.java Copyright 2008, R.G.Baldwin The purpose of this program is to introduce the use of a game-math class library named GM2D01. The class name GM2D01 is an abbreviation for GameMath2D01. The program instantiates objects from the following static top-level classes belonging to the class named GM2D01 and then displays the contents of those objects in two different ways on the standard output device. ColMatrix Point Vector Line Tested using JDK 1.6 under WinXP. *********************************************************/ class PointLine02{ public static void main(String[] args){ System.out.println( "Instantiate and display the contentsn" + "of a new ColMatrix object"); GM2D01.ColMatrix colMatrix = new GM2D01.ColMatrix(2.5,6.8); System.out.println(colMatrix); try{ System.out.println(colMatrix.getData(0)); System.out.println(colMatrix.getData(1)); //This statement will throw an exception on purpose System.out.println(colMatrix.getData(2)); }catch(Exception e){ System.out.println("Bad index"); }//end catch System.out.println(/*blank line*/); System.out.println( "Instantiate and display the contentsn" + "of a new Point object"); colMatrix = new GM2D01.ColMatrix(3.4,9.7); GM2D01.Point point = new GM2D01.Point(colMatrix); System.out.println(point); try{ System.out.println(point.getData(0)); System.out.println(point.getData(1)); //This statement will throw an exception on purpose System.out.println(point.getData(-1)); }catch(Exception e){ System.out.println("Bad index"); }//end catch System.out.println(/*blank line*/); System.out.println( "Instantiate and display the contentsn" + "of a new Vector object"); colMatrix = new GM2D01.ColMatrix(-1.9,7.5); GM2D01.Vector vector = new GM2D01.Vector(colMatrix); System.out.println(vector); try{ System.out.println(vector.getData(0)); System.out.println(vector.getData(1)); //This statement will throw an exception on purpose System.out.println(vector.getData(2)); }catch(Exception e){ System.out.println("Bad index"); }//end catch System.out.println(/*blank line*/); System.out.println( "Instantiate and display the contentsn" + "of a new Line object"); GM2D01.ColMatrix colMatrixTail = new GM2D01.ColMatrix(1.1,2.2); GM2D01.ColMatrix colMatrixHead = new GM2D01.ColMatrix(3.3,4.4); GM2D01.Point pointTail = new GM2D01.Point(colMatrixTail); GM2D01.Point pointHead = new GM2D01.Point(colMatrixHead); GM2D01.Line line = new GM2D01.Line(pointTail,pointHead); System.out.println(line); pointTail = line.getTail(); System.out.println(pointTail); pointHead = line.getHead(); System.out.println(pointHead); }//end main }//end controlling class PointLine02 |
Listing 16. Source code for the game-programming math library named GM2D01.
/*GM2D01.java Copyright 2008, R.G.Baldwin The name GM2D01 is an abbreviation for GameMath2D01. This is a game-math class, which will be expanded over time. The class is provided solely for educational purposes. No effort has been expended to optimize it in any way. Rather, it was designed and implemented for maximum clarity in order to help students understand the programming details of various mathematical operations commonly used in game programming. Each time the class is expanded or modified, it will be given a new name by incrementing the two digits at the end of the name. No attempt will be made to maintain backward compatibility from one version of the class to the next. This class contains a number of static top-level classes. This organizational approach was used primarily for the purpose of gathering such classes under a single naming umbrella while avoiding name conflicts within a single package. For example, as time passes, and this library is expanded, my default package may contain class files with the following names: GM2D01$Point.class GM2D02$Point.class GM2D03$Point.class All real-number values used in this class are maintained as type double. Tested using JDK 1.6 under WinXP. *********************************************************/ public class GM2D01{ //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 ColMatrix{ double[] data = new double[2]; ColMatrix(double data0,double data1){ data[0] = data0; data[1] = data1; }//end constructor 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(); return data[index]; }//end getData }//end class ColMatrix //====================================================// public static class Point{ GM2D01.ColMatrix point; Point(GM2D01.ColMatrix point){ this.point = point; }//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(); return point.getData(index); }//end getData }//end class Point //====================================================// public static class Vector{ GM2D01.ColMatrix vector; Vector(GM2D01.ColMatrix vector){ this.vector = vector; }//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(); return vector.getData(index); }//end getData }//end class Vector //====================================================// //A line is defined by two points. One is called the // tail and the other is called the head. public static class Line{ GM2D01.Point[] line = new GM2D01.Point[2]; Line(GM2D01.Point tail,GM2D01.Point head){ this.line[0] = tail; this.line[1] = head; }//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 GM2D01.Point getTail(){ return line[0]; }//end getTail public GM2D01.Point getHead(){ return line[1]; }//end getTail }//end class Line }//end class GM2D01 //======================================================// |
Copyright
Copyright 2008, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.
About the author
Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.
Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin’s Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.
In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor’s degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.