CHAPTER 5  And Now For Something Completely Different
TOC
The Cube ProgramTOC  
I now wish to analyze a single program from 
beginning to end to give the
reader and idea of the Java block structure 
and flow of the program. I have chosen the program
-Cube.java- since it has many of the object features 
which I would like to discuss.  The program begins 
with a list of library paths. 
Each import statement allows the java compiler to search the 
indicated object, method or class for predifined objects, methods or 
classes which the programmer has used in the program.  
For instance, since we wish to create an applet we need 
to put the applet library in our path.  The command
  
 import java.awt.*;
  
allows the programmer to use any of the classes in that library.  On the other hand
the programmer could just import the classes from 
  
java.awt.*;
   which were desired, but the programmer must have a good 
idea of the minmal set of classes in 
  
java.awt.*;
  to do this.
 The program starts with the import statements: 
import java.applet.*; 
import java.awt.*; 
import java.lang.Math; 
import java.lang.Object; 
  Next we have the program/class definition 
statement.  
Our programs extend the
applet class and so that must be mentioned so that 
they can be compiled as applets.  Note that the name of the program
-Cube- must match exactly with the filename, since they both identify a class in Java.
  
public class Cube extends Applet {
 
  Next we have the class definitions for our program.
In this case we have several data structures which we will want to clone.
Unless the program is a simple one, I would encourage the programmer to create the 
cloning overhead when the data structure is created during the programming process.
Note once again that the data structure must implement cloning and so we must 
also import the clone object.   As we have seen before the -super.clone- will 
handle the overhead for  many of the basic data types.  
However more complicated data structures must be specifically cloned 
by the programmer as I have done below for the Rcube class.
 
 
        public class point implements Cloneable{ 
                        public int x; 
                        public int y; 
 
 
                         public Object clone(){ //begin clone 
                            try{ //begin try 
                                return super.clone(); 
                                } //end try 
                          
                            catch(CloneNotSupportedException e){ // begin catch 
                                return null;  //if there is a catch 
                                 } //end catch 
                            } //end cloning structure for point 
              
                         }  //end point def 
 
         public class rpoint implements Cloneable{ 
                         public double x; 
                         public double y; 
                         public double z; 
 
                      public Object clone(){ //begin clone 
                            try{ //begin try 
                                return super.clone(); 
                                } //end try 
                          
                            catch(CloneNotSupportedException e){ // begin catch 
                                return null;  //if there is a catch 
                                 } //end catch 
                            } //end cloning structure for point 
              
                         }  //end rpoint def 
 
 
Now we come to the basic object which we 
wish to draw and rotate: the cube 
in real space.  To implement this I have imagined 
that a center of the cube exists 
at some origin point.  From that point in real space
I find the center of the top face, 
the front face and the side face 
in real space units (i.e. as
real valued vector components).  
 Using these vectors in three space I 
then find the corners of this 
virtual cube in real space and 
project the corners into
a two dimensional space much as 
if I were looking at the sunlit 
shadow of a wire-frame cube.  
The corners are given by finding 
interger approximations to the 
projected corners and labeling these eight corners as
up1, up2, up3, up4, down1, down2, down3, down4.  These labels 
are in fact characteristics of our cube object. 
 
 
   
public class RCube implements Cloneable{ 
                    public rpoint front=new rpoint(); 
                    public rpoint side=new rpoint(); 
                   public rpoint top=new rpoint(); 
                    public point up1=new point(); 
                    public point up2=new point(); 
                    public point up3=new point(); 
                    public point up4=new point(); 
                    public point down1=new point(); 
                    public point down2=new point(); 
                    public point down3=new point(); 
                    public point down4=new point(); 
                    public double esize=30.0; 
                    public rpoint raxis=new rpoint(); 
                        public double theta=0.0; 
 
                          public Object clone(){ //begin clone 
                            try{ //begin try 
                                RCube cu=(RCube)super.clone(); 
                                cu.front=(rpoint)front.clone(); 
                                cu.top=(rpoint)top.clone(); 
                                cu.side=(rpoint)side.clone(); 
                                cu.raxis=(rpoint)raxis.clone(); 
                                cu.up1=(point)up1.clone(); 
                                cu.up2=(point)up2.clone(); 
                                cu.up3=(point)up3.clone(); 
                                cu.up4=(point)up4.clone(); 
                                cu.down1=(point)down1.clone(); 
                                cu.down2=(point)down2.clone(); 
                                cu.down3=(point)down3.clone(); 
                                cu.down4=(point)down4.clone();                
                                return cu; 
                                } //end try 
                        catch(CloneNotSupportedException e){ 
                               return null; 
                              }//end catch 
 
                            } //end cloning structure for body 
   
                        } // end Cube  def 
  Next we define the basic variables 
which will be needed to carry out the project.
  
       private int i; 
       private int last_x=0; 
       private int last_y=0; 
 
       private Color current_color=Color.black; 
       private Button clear_button; 
       private Button draw_button; 
       private Choice ang_choices; 
 
       public RCube er=new RCube(); 
       public RCube cu=new RCube(); 
       public RCube c=new RCube(); 
 
       private double xmult=0.5; 
       private double mult=0.01; 
       private double phi=0.0; 
       private double psi=0.0; 
       private int delX; 
       private int delY; 
 
  Since we are running an applet 
and not a traditional program we must 
tell the browser how to initialize 
the applets dwelling place.  Since in particular 
we are interested in graphics applications, we set  
the background color and add buttons to the tableau.  
These buttons will allow the user to work or interact within the 
applet dwelling place.
  
 
//init applet 
       public void init(){ 
 
//set backgd color 
        this.setBackground(Color.white); 
 
//create a button 
        clear_button=new Button("Clear"); 
        clear_button.setForeground(Color.black); 
        clear_button.setBackground(Color.lightGray); 
        this.add(clear_button); 
 
//create a button 
        draw_button=new Button("Draw Cube"); 
        draw_button.setForeground(Color.black); 
        draw_button.setBackground(Color.lightGray); 
        this.add(draw_button); 
 
       } 
//end init applet 
    This portion of the program 
will interrupt  the usual or super-class  
function of the
mouseDown (i.e. click on mouse) event 
and it will store the pixel 
position of the mouseDown event for use in the program.  
If the mouse is held in the down position the 
the super-class
will continue to monitor and periodically feed new
pixel information to the program. In addtion as 
the mouse is dragged across the screen  
the super-class will give the 
position of the mouse under the dragging 
process periodically.   
Consequently, we may use the last_x  and 
last_y from mouseDown 
and the new values x and y from
mouseDrag to obtain an approximation for the 
change in the mouse postion from time to time.  
Then considering the change in mouse position under drag
we can obtain a change in x which we rescale to rotate 
the cube in the xz-plane.
  
 
//called when mouse click 
        public boolean mouseDown(Event e, int x, int y){ 
                  last_x=x; last_y=y; 
                   return true; 
           } 
  
//called when mouse moves 
        public boolean mouseDrag(Event e, int x, int y){ 
                  Graphics g=this.getGraphics(); 
                  er=(RCube)c.clone(); 
 
// figure phi and psi 
  
           delX=x - last_x; 
           delY=y - last_y; 
 
           phi=phi+ mult*delX; 
           psi=0.0; 
         
c.front.x=Math.cos(psi)*Math.cos(phi); 
c.front.z=Math.sin(psi)*Math.cos(phi); 
c.front.y= Math.sin(phi); 
 
c.side.x= -Math.cos(psi)*Math.sin(phi); 
c.side.z= -Math.sin(psi)*Math.sin(phi); 
c.side.y= Math.cos(phi); 
 
c.top.x =c.front.y*c.side.z - c.front.z*c.side.y; 
c.top.y = c.front.z*c.side.x - c.front.x*c.side.z; 
c.top.z = c.front.x*c.side.y - c.front.y*c.side.x; 
 
//figure vertices 
 
c.down1.y=(int)(80 + c.esize*(xmult*(c.front.x - c.top.x - c.side.x)  
                                 +  c.top.z - c.front.z + c.side.z)); 
c.down1.x=(int)(60 + c.esize*(xmult*(-c.front.x + c.top.x + c.side.x)  
                                 +  c.front.y + c.top.y - c.side.y)); 
c.down2.y=(int)(80 + c.esize*(xmult*(c.front.x - c.top.x + c.side.x)  
                                 +  c.top.z - c.front.z + c.side.z)); 
c.down2.x=(int)(60 + c.esize*(xmult*(-c.front.x + c.top.x - c.side.x)  
                                 +  c.front.y + c.top.y + c.side.y)); 
c.down4.y=(int)(80 + c.esize*(xmult*(-c.front.x - c.top.x + c.side.x)  
                                 +  c.top.z + c.front.z + c.side.z)); 
c.down4.x=(int)(60 + c.esize*(xmult*(c.front.x + c.top.x - c.side.x)  
                                 -  c.front.y + c.top.y + c.side.y)); 
c.down3.y=(int)(80 + c.esize*(xmult*(-c.front.x - c.top.x - c.side.x)  
                                 +  c.top.z + c.front.z + c.side.z)); 
c.down3.x=(int)(60 + c.esize*(xmult*(c.front.x + c.top.x + c.side.x)  
                                 -  c.front.y - c.top.y - c.side.y)); 
 
c.up1.y=(int)(80 + c.esize*(xmult*(c.front.x + c.top.x - c.side.x)  
                                 -  c.top.z - c.front.z - c.side.z)); 
c.up1.x=(int)(60 + c.esize*(xmult*(-c.front.x - c.top.x + c.side.x)  
                                 +  c.front.y - c.top.y - c.side.y)); 
c.up2.y=(int)(80 + c.esize*(xmult*(c.front.x + c.top.x + c.side.x)  
                                 -  c.top.z - c.front.z - c.side.z)); 
c.up2.x=(int)(60 + c.esize*(xmult*(-c.front.x - c.top.x - c.side.x)  
                                 +  c.front.y + c.top.y + c.side.y)); 
c.up4.y=(int)(80 + c.esize*(xmult*(-c.front.x + c.top.x + c.side.x)  
                                 -  c.top.z + c.front.z - c.side.z)); 
c.up4.x=(int)(60 + c.esize*(xmult*(c.front.x - c.top.x - c.side.x)  
                                 -  c.front.y + c.top.y + c.side.y)); 
c.up3.y=(int)(80 + c.esize*(xmult*(-c.front.x + c.top.x - c.side.x)  
                                 -  c.top.z + c.front.z - c.side.z)); 
c.up3.x=(int)(60 + c.esize*(xmult*(c.front.x - c.top.x + c.side.x)  
                                 -  c.front.y - c.top.y - c.side.y)); 
// begin erase last cube  
 
             g.setColor(Color.white); 
 
               g.drawLine(er.up3.x,er.up3.y,er.up4.x,er.up4.y);//up3 to up4 
               g.drawLine(er.up3.x,er.up3.y,er.up1.x,er.up1.y);//up3 to up1 
               g.drawLine(er.up4.x,er.up4.y,er.up2.x,er.up2.y);//up4 to up2 
               g.drawLine(er.up1.x,er.up1.y,er.up2.x,er.up2.y);//up1 to up2 
               g.drawLine(er.up3.x,er.up3.y,er.down3.x,er.down3.y);//up3 to down3 
               g.drawLine(er.up4.x,er.up4.y,er.down4.x,er.down4.y);//up4 to down4 
               g.drawLine(er.up1.x,er.up1.y,er.down1.x,er.down1.y);//up1 to down1 
               g.drawLine(er.up2.x,er.up2.y,er.down2.x,er.down2.y);//up2 to down2 
               g.drawLine(er.down3.x,er.down3.y,er.down1.x,er.down1.y);//down3 to down1 
               g.drawLine(er.down2.x,er.down2.y,er.down4.x,er.down4.y);//down4 to down2 
               g.drawLine(er.down4.x,er.down4.y,er.down3.x,er.down3.y);//down3 to down4 
               g.drawLine(er.down1.x,er.down1.y,er.down2.x,er.down2.y);//down1 to down2 
 
// bein draw next cube 
         
               g.setColor(Color.black); 
 
               g.drawLine(c.up1.x,c.up1.y,c.up2.x,c.up2.y);//up1 to up2 
               g.drawLine(c.up3.x,c.up3.y,c.up1.x,c.up1.y);//up3 to up1 
               g.drawLine(c.up4.x,c.up4.y,c.up2.x,c.up2.y);//up4 to up2 
               g.drawLine(c.up3.x,c.up3.y,c.up4.x,c.up4.y);//up3 to up4 
               g.setColor(Color.red); 
               g.drawLine(c.up3.x,c.up3.y,c.down3.x,c.down3.y);//up3 to down3 
               g.drawLine(c.up4.x,c.up4.y,c.down4.x,c.down4.y);//up4 to down4 
               g.drawLine(c.up1.x,c.up1.y,c.down1.x,c.down1.y);//up1 to down1 
               g.drawLine(c.up2.x,c.up2.y,c.down2.x,c.down2.y);//up2 to down2 
               g.drawLine(c.down4.x,c.down4.y,c.down3.x,c.down3.y);//down3 to down4 
               g.drawLine(c.down1.x,c.down1.y,c.down2.x,c.down2.y);//down1 to down2 
               g.drawLine(c.down3.x,c.down3.y,c.down1.x,c.down1.y);//down3 to down1 
               g.drawLine(c.down2.x,c.down2.y,c.down4.x,c.down4.y);//down4 to down2 
 
              last_x=x; 
              last_y=y; 
              return true; 
          } 
  We need the data for at 
least two cubes at a time.  The old cube and a new one.
We therefore need to be able to 
clone the Rcube structure.  We use white to erase or draw over the old 
cube and then we draw the  new cube.  All mouse driven 
animation can be handle in this way. 
Next we would like to 
override some of the mouse functions.  
We may add buttons 
in the init portion of the applet,  
but the buttons will be of no use 
unless we can control the class characteristics of
the mouse.  These method-classes appear in the 
 
 
java.awt.Component
   class.
  
//user clicks button or chooses a color 
         public boolean action(Event event, Object arg){ 
                 if(event.target==clear_button){ 
                       Graphics g=this.getGraphics(); 
                       Rectangle r=this.bounds(); 
                       g.setColor(this.getBackground()); 
                       g.fillRect(r.x,r.y,r.width,r.height); 
                   return true; 
                  } 
                  //end clear 
   
              // in case of click 
             else if(event.target==draw_button){ 
 
// draw 
c.front.x=1.0; 
c.front.y=0.0; 
c.front.z=0.0; 
c.side.x=0.0; 
c.side.y=1.0; 
c.side.z=0.0; 
c.top.x=0.0; 
c.top.y=0.0; 
c.top.z=1.0; 
phi=0.0; 
psi=0.0; 
 
c.down1.y=(int)(80 + c.esize*(xmult*(c.front.x - c.top.x - c.side.x)  
                                 +  c.top.z - c.front.z + c.side.z)); 
c.down1.x=(int)(60 + c.esize*(xmult*(-c.front.x + c.top.x + c.side.x)  
                                 +  c.front.y + c.top.y - c.side.y)); 
c.down2.y=(int)(80 + c.esize*(xmult*(c.front.x - c.top.x + c.side.x)  
                                 +  c.top.z - c.front.z + c.side.z)); 
c.down2.x=(int)(60 + c.esize*(xmult*(-c.front.x + c.top.x - c.side.x)  
                                 +  c.front.y + c.top.y + c.side.y)); 
c.down4.y=(int)(80 + c.esize*(xmult*(-c.front.x - c.top.x + c.side.x)  
                                 +  c.top.z + c.front.z + c.side.z)); 
c.down4.x=(int)(60 + c.esize*(xmult*(c.front.x + c.top.x - c.side.x)  
                                 -  c.front.y + c.top.y + c.side.y)); 
c.down3.y=(int)(80 + c.esize*(xmult*(-c.front.x - c.top.x - c.side.x)  
                                 +  c.top.z + c.front.z + c.side.z)); 
c.down3.x=(int)(60 + c.esize*(xmult*(c.front.x + c.top.x + c.side.x)  
                                 -  c.front.y - c.top.y - c.side.y)); 
 
c.up1.y=(int)(80 + c.esize*(xmult*(c.front.x + c.top.x - c.side.x)  
                                 -  c.top.z - c.front.z - c.side.z)); 
c.up1.x=(int)(60 + c.esize*(xmult*(-c.front.x - c.top.x + c.side.x)  
                                 +  c.front.y - c.top.y - c.side.y)); 
c.up2.y=(int)(80 + c.esize*(xmult*(c.front.x + c.top.x + c.side.x)  
                                 -  c.top.z - c.front.z - c.side.z)); 
c.up2.x=(int)(60 + c.esize*(xmult*(-c.front.x - c.top.x - c.side.x)  
                                 +  c.front.y + c.top.y + c.side.y)); 
c.up4.y=(int)(80 + c.esize*(xmult*(-c.front.x + c.top.x + c.side.x)  
                                 -  c.top.z + c.front.z - c.side.z)); 
c.up4.x=(int)(60 + c.esize*(xmult*(c.front.x - c.top.x - c.side.x)  
                                 -  c.front.y + c.top.y + c.side.y)); 
c.up3.y=(int)(80 + c.esize*(xmult*(-c.front.x + c.top.x - c.side.x)  
                                 -  c.top.z + c.front.z - c.side.z)); 
c.up3.x=(int)(60 + c.esize*(xmult*(c.front.x - c.top.x + c.side.x)  
                                 -  c.front.y - c.top.y - c.side.y)); 
 
                   Graphics g=this.getGraphics(); 
                   g.setColor(Color.black); 
              
   g.drawLine(c.up3.x,c.up3.y,c.up4.x,c.up4.y);//up3 to up4 
   g.drawLine(c.up3.x,c.up3.y,c.down3.x,c.down3.y);//up3 to down3 
   g.drawLine(c.down4.x,c.down4.y,c.down3.x,c.down3.y);//down3 to down4 
   g.drawLine(c.up4.x,c.up4.y,c.down4.x,c.down4.y);//up4 to down4 
   g.drawLine(c.up1.x,c.up1.y,c.up2.x,c.up2.y);//up1 to up2 
   g.drawLine(c.up1.x,c.up1.y,c.down1.x,c.down1.y);//up1 to down1 
   g.drawLine(c.up2.x,c.up2.y,c.down2.x,c.down2.y);//up2 to down2 
   g.drawLine(c.down1.x,c.down1.y,c.down2.x,c.down2.y);//down1 to down2 
   g.drawLine(c.up3.x,c.up3.y,c.up1.x,c.up1.y);//up3 to up1 
   g.drawLine(c.up4.x,c.up4.y,c.up2.x,c.up2.y);//up4 to up2 
   g.drawLine(c.down3.x,c.down3.y,c.down1.x,c.down1.y);//down3 to down1 
   g.drawLine(c.down2.x,c.down2.y,c.down4.x,c.down4.y);//down4 to down2 
                 
                   return true; 
              } //end draw button event 
               // other wise let superclass handle it 
              else return super.action(event, arg); 
         } 
     // end action method 
} 
//end Applet
 
  References TOC
 
 |