Introduction to Java. A tutorial from A-SQUARE, Inc. January 2003

© 2000-2003 A-Square, Inc. Cambridge, MA

SourceCode for Exercise 4d, Planes4d

This HTML document has two Java documents which should each be copied into their own files and given the name of the class followed by .java

As always, you get the sourcecode by selecting and copying any text between the two > that separate the source texts from the rest of this HTML document.

Planes4d.java

Plane.java

Planes4d.java

>
/*
 * @Planes4d    1.0  030115
 *
 * © A-Square, Inc.  
 * 175 Richdale Ave, Cambridge MA 02140
 */
 import rrlet.*;
 import rartbase.*;
 import java.awt.*;
 import java.lang.*;


/**
 *    'Planes rotating
 *
 * This Program is one in the Rart®, or Random Art, series of programs
 * that generate ever changing pictures. Simple geometries and random
 * dynamics create visual effects that may be pleasing to the eye.
 * It uses the Plane class for objects, the planes, that fill the screen.
 *
 * In EX4c We show how to write a new universe
 *
 * @version 1.0d  030115
 *
 * @author Jan Aminoff
 */
public final class Planes4d extends Universe { 
  
   // Section 1     Identifying the Universe
   // ------------------------------------------------------------------------
   public String getName() // Name,
       {return("Planes, in Exercise 4b");}   // no more than 20 letters.
   public String getDescription() 
       {return(sd);}       // Description, 
                // no more than 350 letters describing the universe. Will 
               // be displayed in up to five lines of about 70 characters.
                                       
   private String sd=" We shall see how we progressively can add features "+
             "to a new universe to make it more visually interesting. "+
			 "The first version, EX4c, just offers black planes.";
    
    public String getRartist()       // Rartist,
       {return("Jan Aminoff 2003");} // no more than 24 characters.


    // Section 2    What the universe does
   // ------------------------------------------------------------------------
    
    // About colors - constants and defaults
    static Color colors[]=      // Standard Java Colors
        {Color.black,Color.blue,Color.cyan,Color.darkGray,Color.gray,
      Color.green,Color.lightGray,Color.magenta,Color.orange,Color.pink,
      Color.red,Color.white,Color.yellow };
  
   private int bc=0;   // default number of color for background (black )
   private int pc=1;   // default number of color for foreground (blue )
   private Color background = colors[bc];    
   private boolean resetscreen=false; // Signal to recolor background      
    // Other variables
   private int nnmax = 20;  // maximum number of Planes, set in reset
   private int nn=5;        // actual number of Planes, set as number.getCur()
   private Plane planearray[]=new Plane[nnmax];  // Up to 30 Planes.
   private int vv = 5;	//  Current roteation speed in degrees per second
   
   private Debug dB;  // used when debugging, especially as dB.dbg(n, string) 
 
    // The method init() is prescribed by Universe 
   public void init(){
      dB= new Debug();
      dB.setLevel(2);      //  Set level to 1 or 2 for tracing outputs.
      setParams();         //  See Section 3.
      reset();             //  See below.      
   }
      
   private void reset(){
       /** Reset is used in init and also in manageChange when restarting
        *  the universe after change of some parameters.
        */
       // Initialize Planearray
       nn=number.getCur();  // Have to use possibly modified parameters. 
       vv= speed.getCur();  // Max rotation speed in degrees per second
	   int vc = vv*ct.getCur(); // Max rot in degrees per 1000 cycles
       pc=pcolor.getCur();  // Index to colors array.
       dB.dbg( 1 ,"In Planes.reset, xm: "+xm+", ym: "+ym);
	   dB.dbg( 1 ,"In Planes.reset, planecolor is "+colornames[pc]);
       for (int i=0; i < nn; i++) {                 
         planearray[i] = new Plane(xm, ym, vc, pc);
		 planearray[i].setFi(RND(360));
      }
      // Set background
      bc=bcolor.getCur();
      background = colors[bc];
    }   // end reset
      
   
   // This method is prescribed by Universe  
   public Color getBackground(){return background;}       

   // The following three variables are important in cycle.
   private int m;      // Index to current waxing or waning egg.
   private int status; // See Plane for the significance of status.
   
   
   // This method is prescribed by Universe. Everything interesting happens
   // in the cycle method which is called periodically by the RartRunner
   public void cycle ( Graphics g){ 
   /** In init, nn Planes have been initiated in planearray. The planes rotate
    * clockvisw and counterclockvise for a total of 360 degrees, when it will
    * be replaced with a new plane.
    */
      // Reset screen always
      g.setColor(background);          
      g.fillRect(0,0,xm,ym);
	  // We go through all planes
	  nn = number.getCur();
      for (int i=0; i<nn; i++){
	  	Plane p1=planearray[i];   // Current Plane.
      	status = p1.drawChange(g);
     	if (status == p1.DONE){   // If plane rotated 360 degrees,
			// put a new Plane in Planearray,
        	planearray[i]= new Plane(xm, ym, vv*ct.getCur(), pc);
 		    dB.dbg( 1 ,"In Planes,cycle, new Plane for index i: "+i);
      	}
	  }         
   }  // end of cycle(g)
   
   
   // Section 3   uParameters as used in the universe
   // ------------------------------------------------------------------------   

   // number of Planes  
   private uParameter number; //Number of Planes - PARAMETER
   private int nnmin=1;       // nnmax and nn are given values before init    
   private String ndescr=  
      "This parameter indicates the maximum number of 'Planes'"+
      "visible at any one time. ";
   // maximum speed of an Plane
   private uParameter speed; // speed of rotation - PARAMETER  
   private int v=2,vmax=5,vmin=1;  
   private String sdescr=
      "The parameter actually determines the maximum rate of rotation"+
      "of all Planes. It is here given in degrees per second.";
   // cycletime
   private uParameter ct;  // Cycletime - PARAMETER
   // Detailes of the ct parameter can be seen in Universe
   // Plane color
   private uParameter pcolor;  // Plane Color - PARAMETER
   private uParameter bcolor;  // Background Color - PARAMETER
   private String cdescr=
      "Plane color and Background colors may be chosen from "+
      "the 13 primary colors offered by Java. ";
   static String colornames[]=
       {" black "," blue "," cyan"," dark grey "," grey ",
       " green "," light grey "," magenta "," orange ",
      " pink "," red "," white "," yellow "};
   
   private void setParams(){
       number= new uParameter 
           (NUMBER,"Number of Planes",nnmin,nn,nnmax,ndescr);
       //The adduParameter() method is defined in Universe.
       adduParameter(number);
       
       speed=new uParameter(PARA4,"Rotation Speed",vmin,v, vmax, sdescr);
       adduParameter(speed);
       
      ct= new uParameter
          (CYCLETIME,"Cycle Time", 20,100,200, CycleTimeDescr);  
          // Since "Cycle Time" is a compulsory parameter, Universe
          // provides the description CycleTimeDescr.
      adduParameter(ct);
      
      // The color parameters pcolor and bcolor have the same description
      // and array, colornames, for selection.  
      pcolor= new uParameter(PARA5,"Plane Color",pc,colornames, cdescr);
      adduParameter(pcolor);
      bcolor= new uParameter(PARA6,"Background Color",bc,colornames, cdescr); 
      adduParameter(bcolor);
    } //end setParams()
   
   // This method is prescribed by universe. Its purpose is to deal with any 
   // changes in parameters by the user. 
   public void manageChange(uParameter uP){
   /** This method is called by the RartRunner when a user has modified any
    * of the parameters. The new information is conveyed in a uParameter.
    * In the case of Planes, we have elected to restart the universe for any
    * changes even if for some parameters it would not be strictly neccesary.
    */
      int idx=uP.getIndex();
      dB.dbg( 2,"In Planes, Change in : "+uP.getName());
      if (uPs[idx]!=null) uPs[idx]=uP; // ensures that uPs, the array of 
                                       // current parameters is up to date         
      switch (idx){
         case VIEWSIZE:
            reset();  // Cange in windowsize, just restart.
            break;
         case NUMBER:   
            number=uP;   // A more sophisticated program could handle
            reset();     // changes in the maximum number of Planes,
            break;       // but this is simpler!
         case PARA4:     // used for speed of rotation
            speed=uP;
            reset();     // simple solution.
            break;
         case PARA5:     // used for for Plane color
             pcolor=uP;
             reset();    // No alternative to restart here.
             dB.dbg(1,"Planecolor is now "+colornames[pc]);
             break;
         case PARA6:     // used for Background color
             bcolor=uP;
             reset();    // No alternative to restart here.
             dB.dbg(1,"Background is now "+colornames[bc]);
             break;
         }  
      }  // end of manageChange()
      
   
   // Sections 4, and 5 in Universe have no corresponding entries in the
   // Planes universe.
      
   // Section 6   Methods related to security. 
   // -----------------------------------------------------------------------
   
   // The following constructor invokes the Universe constructor which is 
   // programmed to throw an exception in order to avoid multiple 
   // instantiations by mistake or bad intent.
   
   public Planes4d( ) throws InstantiationException
   { }

}  // end of Planes class
>

Top


Plane.java


>
/*
 * @Plane    1.0d  030115
 *
 * © A-Square, Inc.  
 * 175 Richdale Ave, Cambridge MA 02140
 */
import java.awt.*;
import java.lang.*;
import rartbase.*;
//import java.lang.math;		// for sin, cos and pi

public class Plane{
/** --------------------------------------------------------------------------
 * The Plane is a rectangle which rotates around a vertical axis at some speed.
 * The effect of rotation is achieved through the modification of the color
 * which changes as the angle of the light, which is thought to come from an
 * infinitely distant source behind the right the observer, at 45 degrees to 
 * the plane of the screen.
 *
 * @version 1.0d  030115
 * Used in Exercise 4d in the Introduction to Java tutorial.
 *
 * @author Jan Aminoff  
 */
   private int x;        // x pos of center of oval
   private int y;        // y pos of center of oval 
   private static int xys = 40;   // minimum space between center and edge of window
   private int dir;   // dir = 1 for positive rotation, -1 for negative	
   private float dv;  // Speed degrees/cycle set as dir*(1.0+RND(speed))/1000;
   private float ffi; // Floating point repr of fi
   private int fi;		// Angle from plane of screen in degrees.
   private int rr;    // half max size of plane
   private int hh;	  // half height of plane
   private int nc = 0;
   
   public int status;  
   public static final int INITIALIZED=1;         
   public static final int ROTATING1=2;
   public static final int ROTATING2=3; 
   public static final int DONE=4; 
   
   private static int RND(int x){
       return(Universe.RND(x));
   }

   // About colors - constants and defaults
    static Color colors[]=      // Standard Java Colors
        {Color.black,Color.blue,Color.cyan,Color.darkGray,Color.gray,
      Color.green,Color.lightGray,Color.magenta,Color.orange,Color.pink,
      Color.red,Color.white,Color.yellow };
   
	  private int colorindex;
   
   static int primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,   //11
                41, 43, 43,47, 53, 59, 61, 67, 71, 73,      //10
                  47, 83, 83};                        //3
   private Debug dB;  // used when debugging, especially as dB.dbg(n, string) 
   // constructor
   /**
    * Constructor for a Plane, rotating around its middle vertical axis
	* @param xmax		Width of present screen in pixels
	* @param ymax		Height of screen in pixels
	* @param speed		Speed of rotation in degrees per 1000 cycles
	* @param c			Basic color of plane, index to color array
	*/
   public Plane(int xmax, int ymax, int speed, int c) {
      // We may need Debug to develop this universe
      dB= new Debug();
	  int debuglevel=2;	    //  Set level to 1 or 2 for tracing outputs.
      dB.setLevel(debuglevel);      
     // Center of plane is more than xys away from edge
      x = xys+RND(xmax-xys);
      y = xys+RND(ymax-xys);
      status = INITIALIZED;
	  colorindex = c;
      // Note that dx and dy are selected independently from the primes array. 
      // Causes great variation in the configurations.
      hh = (primes[2+RND(13)]*ymax)/200;   // max size 40% of window height
      rr = (primes[3+RND(21)]*xmax)/200;   // max size 80% of window width
      fi = 90;  //Angle to plane of screen, Starts perpedicular	  
	  dir = 2*RND(2)-1;		// 1 or -1, that is clockwise or counterclocwise
	  dv = (float)(dir*((2.0+RND(speed))/100)); // Increment angle per cycle
	  //dB.dbg(1, "Plane.Plane dv "+dv);
	  // dB.dbg(1,"Debug activated at level "+debuglevel);
   }  // End of Plane constructor
   
   public void setFi( int phi){				     // new for version d
   		fi = (phi < 0)? - phi%360:phi%360 ;
	}
   
   public int drawChange(Graphics g){
   /** The drawChange method provides the functionality of the planes class.
    * It redraws the plane after a rotation of  nc*dv degrees .
    * It returns its status which relates to the number of complete rotations
    * passing the plane perpendicular to the screen.
    */
       int newstatus=status;
       switch(status){
           case INITIALIZED:
               newstatus = ROTATING1;
      		   ffi = fi;
           case ROTATING1:
		   case ROTATING2:
               drawPlane(g);
			   ffi += dv;
			   // dB.dbg(1,"Plane.drawChange x "+x+", ffi "+ffi);
               fi= (int)(ffi) ;
			   // Make sure fi in interval 0 - 360
			   int fi1= (ffi < 0.0)? 360:(ffi>360.0)? 0:fi;
			   if (fi != fi1){
			   		fi = fi1;
					ffi = fi;
					newstatus = ROTATING2;
				}	
               if ((status == ROTATING2) && (((dv>0)&& (ffi>90))||((dv<0)&&(ffi<90))))
			   			newstatus = DONE;
               break;
       }
       status = newstatus;
       return (status);
   }   // end DrawChange
           
	private void drawPlane( Graphics g){
	/*
 	 * Draws the plane
	 * Width is rr*COS(fi), Height is constant hh
	 * First determine the color
	 * Our strategy must be to consider the thirteen colors separately, and for
	 * each color consider how the tree components move. See shadedColor.
	 *
	 * In Plane4d, we only consider light as coming from straight behind the 
	 * observer. When fi goes from 90 to 0 or 180, the color of the plane 
	 * goes from 80% to white. We call the angle psi. Here psi = 90-fi and the
	 * sat can be calculated as 20.0+80.0*cos(abs(psi))
	 */
		int idx = colorindex;
		int psi = (fi>180)?90- fi+180: 90-fi; 
		double alpha = Math.abs(psi)*Math.PI / 180;
		// ecial case for white, idx = 11
		int sat = (int)(((idx == 11)? 100.0:50.0)*Math.sin(alpha));
		g.setColor(shadedColor(idx, sat));
		alpha =  ffi * Math.PI / 180.0 ;
		int r = Math.abs( (int) (rr*Math.cos(alpha)));
		// dB.dbg(1, "Plane.drawPlane Width="+2*r+" Height="+hh+ " fi="+fi);
		g.fillRect(x-r, y-hh, 2*r, 2*hh);		                          
   }	// end drawPlane

  /**
   * Produces a color that is linearly changed from original basic Java
   * color to white.
   * @ idx 		index to one of 13 Java colors
   * @ sat      measure of saturation (?) percent from 0 to 100
   */
   private Color shadedColor( int idx, int sat){	   // New for 4d
   			int dig, dig1;		//Digits of Color
			Color c1;			// Resulting color	
   		switch(idx){
 	    	case 0:		// Black Shades of Grey treated the dame
			case 3:		// Dark Grey
			case 4:	    // Light gray
			case 6:		// Grey
				dig=(int)(sat*255.0/100);
				c1= new Color(dig,dig,dig);
				break;
			case 1:		// Blue
				dig = (int)(sat*255.0/100);
				c1= new Color(dig,dig,255);
				break;
			case 2:		// Cyan
				dig = (int)(127.0+sat*128.0/100);
				c1 = new Color(dig,255,255);
				break;
			case 5:		// Green
				dig = (int)(127.0+sat*128.0/100);
				c1 = new Color(dig,255,dig);
				break;
			case 7:		// Magenta
				dig = (int)(127.0+sat*128.0/100);
				c1 = new Color(255,dig,255);
				break;
			case 8:		// Orange
				dig = (int)(127.0+sat*128.0/100);
				dig1 = (int)(sat*255.0/100);
				c1 = new Color(255,dig,dig1);
				break;
			case 9:		// Pink
				dig = (int)(163.0+sat*93.0/100);
				c1 = new Color(255,dig,dig);
				break;
			case 10:	// Red
				dig = (int)(sat*255.0/100);
				c1 = new Color(255,dig,dig);
				break;
			case 11:	// White - Shades from light grey to whitw
				dig = (int)(163.0+sat*93.0/100);
				c1 = new Color(dig,dig,dig);
				break;
			case 12:	// Yellow
				dig = (int)(sat*255.0/100);
				c1 = new Color(255,255,dig);
				break;
			default:
				dB.dbg(0,"Color " +idx + " not yet supported.");
				c1 = null;
				break;
		}
		return c1;
	}	// end shadedColor
				
}  // end class Plane
>

Top