Introduction to Java. A tutorial from IEEE in cooperation with A-SQUARE, Inc. May 2001
© 2000-2001 A-Square, Inc. Reston Virginia

Source Code for the helper class rPoint60.java

This code is used in Exercise 5d to support Flakes, while Exercise 5e.uses a version with integer arithmetic but the same functionality.

>

/*
 * @rPoint60	 2.0	001210
 *
 * © A-Square, Inc. 1996-2000
 * 1648 Waters Edge Lane, Reston Virginia, 20190, USA
 */

import java.awt.*;
import java.lang.Math;

/**
 * rPoint60 stands for relative origin. An rPoint60 serves as the center of a
 * flake in the Flakes universe but serves also as the origin of any branch.
 *
 * The rPoint60 class encapsulates the geometry of flakes, that is, branches 
 * of 60 or 30 degrees. The branches are 1, 3 or 5 pixels wide. Each 
 * rPoint60 is associated with a direction 0, 1, 2, . . . 11 corresponding to 
 * 0, 30, 60, . . . 330 degrees.
 *
 * @Author Jan Aminoff 1996-2000.
 *
 * Version 2.0 is exactly the same functionally as Version 1.0 released with
 * RDK 1.0 beta. This version is cleaned up for documentation purposes. It is
 * part of the Introduction to Java Tutorial, Exercise 5d.
 *
 */

final class rPoint60 {

	// Static variables having to do with geometry
	private static double d30=Math.PI/6.0;
	private static double d60=Math.PI/3.0;
	private static double d90=Math.PI/2.0;
	private static double d120=d60*2;
	private static double d150=d30*5;
	private static double d180=Math.PI;
	private static double sin30=.5;
	private static double cos30=Math.sqrt(3)/2.0;
	private static double sin[]={0,sin30,cos30,1,cos30,sin30,
							0,-sin30,-cos30,-1,-cos30,-sin30};
	private static double cos[]={1,cos30,sin30,0,-sin30,-cos30,
							-1,-cos30,-sin30,0,sin30,cos30};
	private static double dir2rad[]={0, d30, d60, d90, d120, d150, 
								d180, d30, d60, d90, d120, d150, 0};

	// Static variables used for color and for blueshading
	private static int satValue[]={0,10,20,35,55,75,90};
	private static Color Blues[]= new Color[7];

	// Instance variables  
	
	// Coordinates relative to Origin at x0,y0
	public int x,y;												  
	 // Direction of a line is indicated as 0, 1, 2 , . . 11 corresponding to 
	// 0, 30, 60, . . 330 or in 30 degree increments counting counterclockvise.
	public int dir;		
	// Origin
	private Point P0;
	// Origin of reference coordinate system in absolute coordinates			
	private int x0,y0;	
	// Signal Origin has been set
	private boolean originSet=false;
	
	/**
	 * Constructor 1, Sets the origin, must be first constructor called
	 * 
	 * @Param Point P The point of origin in absolute coordinates
	 */
	public rPoint60(Point P){
		if (!originSet){
			for(int i=0; i<7;i++)
				// Construct shades of blue for shadowing
					Blues[i]=Color.getHSBColor((float)240/360,
					(float)satValue[i]/100, (float)100/100);
			P0=P;
			x0=P.x;
			y0=P.y;
			dir=1;
			originSet=true;
		}else{
			System.out.println
					  ("Attempt to set Origin in rPoint60 more than once");
		}	 
	}	 // end rPoint60 constructor 1
	/**
	 * Constructor 2, Creates a new rPoint60 given its direction 
	 * and coordinates relative to the origin Po.
	 *
	 * @param Dir		  direction from origin to 
	 *						  this point
	 * @param X,Y		  coordinates relative to Po
	 * @param Point Po  the origin 
	 */
	public rPoint60(int Dir, int X, int Y, Point Po){
		this(Po);
		if (originSet){
			x=X;
			y=Y;
			dir=Dir;
		 }else{
			System.out.println
					  ("Attempt to invoke rPoint60 without having set origin");
		}		
	}	 // end rPoint60 constructor 2
	
	/**
	 * Constructor 3 Creates a new rPoint60 at a point PA
	 * given its direction relative to the origin Po.
	 *
	 * @param Dir		  direction from origin to 
	 *						  this point
	 * @param Point PA  point relative to Po
	 * @param Point Po  the origin 
	 */	
	public rPoint60(int Dir, Point PA, Point Po){
		this(Po);
		if (originSet){
			x=PA.x-x0;
			y=PA.y-y0;
			dir=Dir;
		}else{
			System.out.println
					  ("Attempt to invoke rPoint60 without having set origin");
		}	
	}	 // end rPoint60 constructor 3
	
	/**
	 * Draws a shadowed line of length r and width w from a point p 
	 * in the direction dir.
	 * 
	 * @param rPoint60 p		origin of the line
	 * @param dir				direction (as an integer 0, 1, 2, . . 11.)
	 * @param r					length of the line
	 * @param Graphics g		graphics context
	 * @param w					width of the line
	 *
	 * @return	rPoint60		a new rPoint60 at the end of the line		
	 *
	 */
	public static rPoint60 extendBranch60
			  (rPoint60 p,int dir, int r, Graphics g, int w){
		int x1=p.x+p.x0;
		int y1=p.y+p.y0;
		int di=(dir<0)?dir+12:dir;
		int xr=p.x+(int)(r*cos[di]);
		int yr=p.y+(int)(r*sin[di]);
		int x2=xr+p.x0;
		int y2=yr+p.y0;
		drawShadowedLine60(x1,y1,x2,y2,di,g,w);
		rPoint60 P= new rPoint60(di,xr,yr,p.P0);
		return P;
	}	 // end extendBranch60

	/**
	 * draws a line between two rPoint60 points P1 and P2 five times, each time 
	 * rotated 60 degrees relative to the origin.
	 * 
	 * @param rPoint60 P1	one endpoint of the line
	 * @param rPoint60 P2	the other endpoint od the line
	 * @param Graphics g		the graphics context
	 * @param w					the width of the line
	 */ 
	public static void rotateLine60(rPoint60 P1, rPoint60 P2,  Graphics g, int w){
		rPoint60 pa,pb;
		//rotates the line from P1 to P2 around origo 5 times in 60 degree increments
		for (int i=1;i<6;i++){
			pa= rotate60(P1,2*i);
			pb= rotate60(P2,2*i);
			drawLine60(pa,pb,g,w);
		}
	}	 // end rotateLine60		
	
	 /**
	  * Draws a line between two rPoints
	  *
	  * @param rPoint60 P1	 origin of line
	  * @param rPoint60 P2	 termination of line
	  * @param Graphics g	 the graphics context
	  * @param w				 width of the line (1, 3 or 5 pixels)
	  */
	private static void drawLine60
			  (rPoint60 P1, rPoint60 P2,	Graphics g, int w){
		//Prepares for invocation of drawShadowedLine
		int x1=P1.x+P1.x0;
		int y1=P1.y+P1.y0;
		int x2=P2.x+P2.x0;
		int y2=P2.y+P2.y0;
		int dir=0;
		// Find the direction of the line
		float delta=(float).05;
		float r=(float)Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
		if (r<.5) return;
		float co=(x2-x1)/r;
		float si=(y2-y1)/r;
		for (int i=0; i<12; i++){
			if ((Math.abs(co-cos[i])<delta)&&(Math.abs(si-sin[i])<delta)){
				dir=i;
				//System.out.println("cos: "+co+" sin: "+ si+" dir: "+i);
				break;
			}
		}
		drawShadowedLine60(x1,y1,x2,y2,dir,g, w);
	}	 // end drawLine60
		
	/**
	 * Draws a line between two points with coordinates x1, y1 and x2, y2, 
	 * in the direction dir and width w shadowed in shades of blue.
	 * Used by drawLine60 and extendBranch60
	 * @param x1, y1			coordinates of starting point
	 * @param x2, y2			coordinates of end point
	 * @param dir				direction of line
	 * @param Graphics g		graphics context
	 * @param w					width (1, 3 or 5) of line
	 */
	private static void drawShadowedLine60
			  (int x1,int y1,int x2,int y2, int dir, Graphics g,int w){
		int dx,dy;
		g.setColor(Blues[1]);
		g.drawLine(x1,y1,x2,y2);
		if (w>1){
			switch ((dir<6)?dir:dir-6){		
				case 0:		//		0 degrees
					dy=(w<5)?1:2;
					g.setColor(Blues[1]);
					g.drawLine(x1,y1-dy,x2,y2-dy);
					g.setColor(Blues[3]);
					g.drawLine(x1,y1+dy,x2,y2+dy);
					if (w<5) break;
					g.setColor(Blues[1]);
					g.drawLine(x1,y1-1,x2,y2-1);
					g.drawLine(x1,y1+1,x2,y2+1);
					break;
				case 1:		//30 degrees
					dy=(w<5)?1:2;
					g.setColor(Blues[0]);
					g.drawLine(x1-1,y1-dy,x2-1,y2-dy);
					g.setColor(Blues[4]);
					g.drawLine(x1+1,y1+dy,x2+1,y2+dy);
					if (w<5) break;
					g.setColor(Blues[1]);
					g.drawLine(x1,y1-1,x2,y2-1);
					g.drawLine(x1,y1+1,x2,y2+1);
					break;			
				case 2:	//60 degrees
					dx=(w<5)?1:2;
					g.setColor(Blues[6]);
					g.drawLine(x1-dx,y1-1,x2-dx,y2+1);
					g.setColor(Blues[0]);
					g.drawLine(x1+dx,y1+1,x2+dx,y2+1);
					if (w<5) break;
					g.setColor(Blues[1]);
					g.drawLine(x1-1,y1,x2-1,y2);
					g.drawLine(x1+1,y1,x2+1,y2);
					break;															
				case 3:		//90 degrees
					dx=(w<5)?1:2;
					g.setColor(Blues[4]);
					g.drawLine(x1-dx,y1,x2-dx,y2);
					g.setColor(Blues[0]);
					g.drawLine(x1+dx,y1,x2+dx,y2);
					if (w<5) break;
					g.setColor(Blues[1]);
					g.drawLine(x1-1,y1,x2-1,y2);
					g.drawLine(x1+1,y1,x2+1,y2);
					break;		
				case 4:		//	 120 degrees
					dx=(w<5)?1:2;
					g.setColor(Blues[3]);
					g.drawLine(x1-dx,y1-1,x2-dx,y2-1);
					g.setColor(Blues[0]);
					g.drawLine(x1+dx,y1+1,x2+dx,y2+1);
					if (w<5) break;
					g.setColor(Blues[1]);
					g.drawLine(x1-1,y1,x2-1,y2);
					g.drawLine(x1+1,y1,x2+1,y2);
					break;				
				case 5:	//	 150 degrees
					dy=(w<5)?1:2;
					g.setColor(Blues[1]);
					g.drawLine(x1-1,y1-dy,x2-1,y2-dy);
					g.setColor(Blues[1]);
					g.drawLine(x1+1,y1+dy,x2+1,y2+dy);
					if (w<5) break;
					g.setColor(Blues[1]);
					g.drawLine(x1,y1+1,x2,y2+1);
					g.drawLine(x1,y1-1,x2,y2-1);
					break;	
			} // end switch
		}	
	}	 // end drawShadowedLine60	 
	
	/**
	 * Reflects the point P1 in a line through the origin at P0 in direction 
	 * dir and returns the virtual point of reflexion.
	 *
	 * @param rPoint60 P1	the point to be reflected
	 * @param dir				the direction ( 0, 1, 2 ... 11) of the line in 
	 *								which P1 is reflected
	 * @return rPoint60		the virtual reflection of P1
	 */
	private static rPoint60 reflect60(rPoint60 P1, int dir){
		//
		int di=(2*P1.dir-dir+12)%12;
		int twodir=(2*dir)%12;
		int xr=(int)(cos[twodir]*P1.x+sin[twodir]*P1.y);
		int yr=(int)(sin[twodir]*P1.x-cos[twodir]*P1.y);
		rPoint60 P2= new rPoint60(di,xr,yr,P1.P0);		
		return P2;
	}
	
	/**
	 * rotates the point P1 an angle dir*pi/12 radians, that is dir*30 
	 * degrees, and returns a new rPoint60 as rotated
	 *
	 * @param rPoint60 P1	the rPoint60 to be rotated
	 * @param dir				the multiple of 30 degree angles P1 will be rotated
	 * 
	 * @return rPoint60		a new rPoint60 rotated dir*30 degrees relative to P1
	 */
	private static rPoint60 rotate60(rPoint60 P1, int dir){ 
		//
		int di=(P1.dir+dir)%12;
		int xr=(int)(cos[dir]*P1.x-sin[dir]*P1.y);
		int yr=(int)(sin[dir]*P1.x+cos[dir]*P1.y);
		rPoint60 P2= new rPoint60(di, xr,yr,P1.P0);
		return P2;
	}	// end rotate60

		
}	 // end of class rPoint60

>