Sindbad~EG File Manager

Current Path : /usr/home/beeson/public_html/dynamicgeometry/org/dynamicgeometry/diagrammer/
Upload File :
Current File : /usr/home/beeson/public_html/dynamicgeometry/org/dynamicgeometry/diagrammer/SymbolTable.java

/**
 *	General Info:
 *		DynamicGeometry.org
 *		San Jose State University
 *		CS 240, Fall '06
 *		Professor Beeson, Michael
 *
 *	File Info:
 *		SymbolTable.java
 *		Use to handle how to calculate low level script (Primitive) and
 *		48 basic Euclidean scripts
 *
 *	This code is available for public use with no legal restriction
 *
 *	Author  Thang Dao
 *	12-10-2006
 *  12.19.2006  Beeson made isPrimitiveCommand public and static
 *              and added a new constructor that takes an ArrayList
 *  12.21.2006  Beeson modified Execute1, ExecuteScript, ExecutePrimitive to return GeometricObject[]
 *              instead of GeometricObject; provided method copy() and made addObject public.
 *  12.22.2006  Beeson moved isPrimitiveCommand to scripts.java
 *  12.23.2006  Beeson removed package path from call to getScript
 *   1.9.2007   Beeson modified getIntersectLineCircle, IntersectLineCircle1, IntersectLineCircle2
 */

package org.dynamicgeometry.diagrammer;

import org.dynamicgeometry.scripts.*;
import java.util.*;

class IllegalScriptException extends Exception{
   public IllegalScriptException(){}
   public IllegalScriptException(String msg) { super(msg);}
}

public class SymbolTable {

	private Hashtable<String,GeometricObject> symbolTbl;
	private Parser  mParser;
	private final double EPS = 1E-5;

	/**
	 *	Constructor
	 */
	public SymbolTable() {
		mParser   = new Parser();
		symbolTbl = new Hashtable<String,GeometricObject>();
	}

	/**
	 *	Constructor with the GeometricObject[] as parameter to create symbolTable
	 */
	public SymbolTable( GeometricObject[] geoObjs ) {  
		mParser   = new Parser();
		symbolTbl = new Hashtable<String,GeometricObject>();
		for( int i=0; i<geoObjs.length; i++ ) {
			String label = geoObjs[i].getLabel().toString();
			symbolTbl.put( label, geoObjs[i] );
		}
	}

	/**
	*	Constructor with the ArrayList<GeometricObject> as parameter to create symbolTable
	*/
	public SymbolTable( ArrayList<GeometricObject> geoObjs ) {
			mParser   = new Parser();
			symbolTbl = new Hashtable<String,GeometricObject>();
			for( int i=0; i<geoObjs.size(); i++ ) {
				String label = geoObjs.get(i).getLabel().toString();
				symbolTbl.put( label, geoObjs.get(i) );
			}
		}

    /**
    * clone method by Beeson.
    * does not clone the GeometricObjects in the table, just the table itself
    */

     public SymbolTable clone(){
     SymbolTable ans = new SymbolTable();
     ans.mParser = mParser;
     ans.symbolTbl = (Hashtable) symbolTbl.clone();
     return ans;
     }


     /**
     * This method written by Beeson 12.21.06
     * Produce a copy of this symbol table that will have independent data
     * If new objects are added to the original, the copy will not be affected.
     * You can't use Hashtable.clone() to do this since that produces a shallow copy,
     * i.e. the objects themselves are not cloned. Thus if points are dragged (changing
     * their locations) or if their labels are changed in the original, they would be
     * changed in the copy too.
     */
     public SymbolTable copy(){
      System.out.println("checkpoint 8b");
     SymbolTable ans = new SymbolTable();
     System.out.println("checkpoint 9b");
     ans.mParser = mParser;
     for(Enumeration k = symbolTbl.keys(); k.hasMoreElements();)
        { String label = (String) k.nextElement();
          GeometricObject q = symbolTbl.get(label);
          GeometricObject p = q.deepClone();
          ans.symbolTbl.put(label,p);
        }
             System.out.println("checkpoint 10b");
     // now fix up all the arg pointers
     for(Enumeration k = ans.symbolTbl.keys(); k.hasMoreElements();)
        { String label = (String) k.nextElement();
          GeometricObject q = ans.value(label);
          ArrayList<GeometricObject> r = q.getArgs();
          if(r == null) continue;
          ArrayList<GeometricObject> t = new ArrayList<GeometricObject> (r.size());
          for(GeometricObject w: r)
             { GeometricObject z = ans.value(w.getLabel().toString());
               t.add(z);
             }
          q.setArgs(t);
        }
     return ans;
     }


	/**
	 *	Add one Object to the Hashtable
	 */
	public void addObject( String label, GeometricObject gobj ) {
		symbolTbl.put( label, gobj );
	}

	/**
	 *	Remove the associated GeometricObject from the Hashtable
	 */
	private void removeObject( String label ) {
		symbolTbl.remove( label );
	}

	/**
	 *	This method is to look up in the SymbolTable a GeometricObject with an associated label
	 *	@param label	the label to look up
	 *	@return null	if the SymbolTable does not contain the object with associated 'label'
	 *			GeometricObject	if found
	 */
	public GeometricObject value( String name ) {
		return symbolTbl.get( name );
	}

	/**
	 *	Parse the 'line' using the Parser Object
	 *  @param line	the line to be checked
	 *	@return true	if the line is in valid format
	 *			false	if the line is in invalid format
	 */
	public boolean valid( String cmdString ) {
		/* Parse the line - check to see if it returns a 'command' object or null (return false) */
		Command cmd = mParser.parse( cmdString );
		if( cmd == null ) return false;
		String[] args = cmd.getArguments();

		/* Check the arguments of the command object one by one */
		for( int i=0; i<args.length; i++ ) {
			String arg = args[i];
			if( arg == null ) return false;

			int leftParen = arg.indexOf( '(' );

			/* no parenthesis - should be a variable name */
			if( leftParen == -1 ) {
				if( symbolTbl.get( arg ) == null ) return false;
			}
			/* with parenthesis, should be another command. Midpoint(A,MidPoint(B,C)) */
			else return valid( arg );
		}

		return true;
	}

	/**
	 *	Execute primitive commandName with the arguments,
	 *	Store the result to itself with newLabel iff newLabel is valid
	 * 	@param newLabel	the new label to be stored
	 *	@param commandName the command to be execute
	 *	@param args the array of GeometricObject as arguments
	 *	@return GeometricObject[], usually an array of length one
	 *  containing the geometric object that is the result of the execution
	 *			null if the command can't be executed
	 */
	public GeometricObject[] ExecutePrimitive( String newLabel, String commandName, GeometricObject[] args ) {
		GeometricObject geoObj = null;

		/* line( Point A, Point B ) */
		if( commandName.equalsIgnoreCase( "line" ) ) {
			if ( (args[0] instanceof Point) &&
				 (args[1] instanceof Point) )
				geoObj = new Line( (Point) args[0], (Point) args[1] );
		}

		/* segment( Point A, Point B ) */
		else if( commandName.equalsIgnoreCase( "segment" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) )
				geoObj = new Segment( (Point) args[0], (Point) args[1] );
		}

		/* circle( Point Center, Point P ) */
		else if( commandName.equalsIgnoreCase( "circle" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) ) {
				geoObj = new Circle( (Point) args[0], (Point) args[1] );
			}
		}

		/* ray( Point A, Point B ) - endpoint is A passthrough B */
		else if( commandName.equalsIgnoreCase( "ray" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) )
				geoObj = new Ray( (Point) args[0], (Point) args[1] );
		}

		/* arc( Point C, Point E, Point A, Point B ) - arc from A to B clockwise on Circle (center C, endpoint E) */
		else if( commandName.equalsIgnoreCase( "arc" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) &&
				(args[2] instanceof Point) &&
				(args[3] instanceof Point) )
				geoObj = new Arc( (Point) args[0], (Point) args[1], (Point) args[2], (Point) args[3] );
		}

		/* triangle(Point, Point , Point  )  */
		else if( commandName.equalsIgnoreCase( "triangle" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) &&
				(args[2] instanceof Point) ) {
				geoObj = new Triangle( (Point) args[0], (Point) args[1], (Point) args[2] );
			}
		}

		/* quadrilateral( Point, Point, Point, Point */
		else if( commandName.equalsIgnoreCase( "quadrilateral" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) &&
				(args[2] instanceof Point) &&
				(args[3] instanceof Point) )
				geoObj = new Quadrilateral( (Point) args[0], (Point) args[1], (Point) args[2], (Point) args[3] );
		}

		/* vertex(k,p) - vertext kth of the p polygon */
		else if( commandName.equalsIgnoreCase( "vertex" )) {
			if( args[1] instanceof ClosedPolygon ) {
				ArrayList<GeometricObject> cpArgs = ((ClosedPolygon) args[1]).getPoints();
				//if( k <= cpArgs.size() );
					//geoObj = cpArgs.get( k-1 );
			}
		}

		/* intersectLines(Point A, Point B, Point C, Point D) - point of intersection of two non-parallel lines AB and CD */
		else if( commandName.equalsIgnoreCase( "intersectLines" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) &&
				(args[2] instanceof Point) &&
				(args[3] instanceof Point) ) {
				Point p1 = (Point) args[0];
				Point p2 = (Point) args[1];
				Point p3 = (Point) args[2];
				Point p4 = (Point) args[3];

				// coordination should be in DOUBLE >.>
				double denominator = (p4.getY()-p3.getY())*(p2.getX()-p1.getX()) - (p4.getX()-p3.getX())*(p2.getY()-p1.getY());
				double numerator   = (p4.getX()-p3.getX())*(p1.getY()-p3.getY()) - (p4.getY()-p3.getY())*(p1.getX()-p3.getX());

				// if = 0: two lines are parallel
				if( denominator != 0 ) {
					double x = p1.getX() + (numerator/denominator)*(p2.getX()-p1.getX());
					double y = p1.getY() + (numerator/denominator)*(p2.getY()-p1.getY());

					geoObj = new Point( x, y );
				}
			}
		}

		/* intersectLineCircle1( Point A, Point B, Point C, Point D) -
				point of intersection of line AB with circle(C,D) that is encountered first moving in the direction AB */

		else if( commandName.equalsIgnoreCase( "intersectLineCircle1" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) &&
				(args[2] instanceof Point) &&
				(args[3] instanceof Point) ) {

				Point A = (Point) args[0];
				Point[] intersects = getIntersectLineCircle( A, (Point) args[1], (Point) args[2], (Point) args[3]);

				if( intersects != null ) {
				    geoObj = intersects[0];
				}
			}
		}

		/* intersectLineCircle2( Point A, Point B, Point C, Point D) -
				point of intersection of line AB with circle(C,D) that is farther to the A end of line AB. if they meet */
		else if( commandName.equalsIgnoreCase( "intersectLineCircle2" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) &&
				(args[2] instanceof Point) &&
				(args[3] instanceof Point) ) {

				Point A = (Point) args[0];
				Point[] intersects = getIntersectLineCircle( A, (Point) args[1], (Point) args[2], (Point) args[3]);

				if( intersects != null ) {
				    geoObj = intersects[1];
				}
			}
		}


		/* intersectCircleCircle1(A,B,C,D) - point of intersection Q of circle(A,B) with circle(C,D)
				such that ABQ is a left turn */
		else if( commandName.equalsIgnoreCase( "intersectCircleCircle1" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) &&
				(args[2] instanceof Point) &&
				(args[3] instanceof Point) ) {
				geoObj = getIntersectCircleCircle( (Point) args[0], (Point) args[1], (Point) args[2],
												   (Point) args[3], "left" );
  			}
		}

		/* intersectCircleCircle2(A,B,C,D) - point of intersection Q of circle(A,B) with circle(C,D)
				such that ABQ is a right turn */
		else if( commandName.equalsIgnoreCase( "intersectCircleCircle2" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) &&
				(args[2] instanceof Point) &&
				(args[3] instanceof Point) ) {
				geoObj = getIntersectCircleCircle( (Point) args[0], (Point) args[1], (Point) args[2],
												   (Point) args[3], "right" );
			}
		}

		/* intersectCircle1(C1,C2) - point of intersection of two circles such that
			the angle from center of C1 to center of C2 to this point is a left turn. */
		else if( commandName.equalsIgnoreCase( "intersectCircles1" ) ) {
			if( (args[0] instanceof Circle) &&
				(args[1] instanceof Circle) ) {
				geoObj = getIntersectCircle( (Circle) args[0], (Circle) args[1], "left" );
			}
		}

		/* intersectCircle2(C1,C2) - point of intersection of two circles such that
			the angle from center of C1 to center of C2 to this point is a left turn. */
		else if( commandName.equalsIgnoreCase( "intersectCircles2" ) ) {
			if( (args[0] instanceof Circle) &&
				(args[1] instanceof Circle) ) {
				geoObj = getIntersectCircle( (Circle) args[0], (Circle) args[1], "right" );
			}
		}

		/* extend(A,B,C,D) - constructs point E on ray AB
			(so B is between A and E) such that BE = CD */
		else if( commandName.equalsIgnoreCase( "extend" ) ) {
			if( (args[0] instanceof Point) &&
				(args[1] instanceof Point) &&
				(args[2] instanceof Point) &&
				(args[3] instanceof Point) ) {

				Point A   = (Point) args[0];
				Point B   = (Point) args[1];
				double CD = distanceBetween2Points( (Point) args[2], (Point) args[3] );
				Point E   = new Point( B.getX() + CD, B.getY() );

				Point[] intersects = getIntersectLineCircle( A, B, B, E );
				double distAP1     = distanceBetween2Points( A, intersects[0] );
				double distAP2     = distanceBetween2Points( A, intersects[1] );

				if( distAP1 > distAP2 ) geoObj = intersects[0];
				else geoObj = intersects[1];
			}
		}

		/* if the returned object is not null, set its label/construction/args field */
		if( geoObj != null ) {
			if( isLegalLabelFormat( newLabel )) {

				Label lbl = new Label();
				lbl.setLabel( newLabel );
				geoObj.setLabel( lbl );
				symbolTbl.put( newLabel, geoObj ); // moved down 3 lines by Beeson
			}
			geoObj.setConstruction( commandName );

			if( geoObj instanceof Point ) {
				ArrayList<GeometricObject> geoObjArgs = geoObj.getArgs();
				geoObjArgs.clear();
				for( int i = 0; i < args.length; i++ )
					geoObj.addArg( args[i] );
			}
		}
        GeometricObject[] ans = new GeometricObject[1];
        ans[0] = geoObj;
		return ans;
	}



 	/**
 	 *	To Execute the 48 Scripts using the given Argument array
 	 *	@param label	label for the script
 	 *	@param cmd		the command to be executed
	 *	@param args		the arrays of arguments for the scripts
	 *	@return GeometricObject[] the results of the execution, often just a one-element array.
	 *			null if the command is invalid
	 */
	public GeometricObject[] Execute1( String label, String cmd, GeometricObject[] args )
	throws IllegalScriptException
	{
		/* check to see if cmd is a primitive one */
		if( Scripts.isPrimitiveCommand( cmd ))
		    return ExecutePrimitive( label, cmd, args );

		/* Retrieve the associate param names & types of the given script (command) */
		String[] scriptParamName = null;
		String[] scriptParamType = null;
		String[] scriptReturnTypes = null;
		try {
			scriptParamName = Scripts.getParameterNames(cmd );
			scriptParamType = Scripts.getParameterTypes(cmd );
			scriptReturnTypes = Scripts.getReturnTypes(cmd);
		}
		catch( Exception e ) {
			e.printStackTrace();
			return null;
		}

		/* Test for consistency between parameters in Scripts and the args */
		if( args.length != scriptParamName.length ) return null;
		if( scriptParamName.length != scriptParamType.length ) return null;
		for( int i=0; i<args.length; i++ )
			if( !(args[i].getClass().toString().equalsIgnoreCase( "class org.dynamicgeometry.diagrammer."+scriptParamType[i] ))) return null;
        System.out.println("Upon entering Execute1 with " + cmd + " we have ");for( int i=0; i < args.length;  i++ ) System.out.println("args["+ i + "] is " + args[i].getLabel());
		/* Relabel the args' labels to match with Scripts' label */
		GeometricObject[] tmpArgs = new GeometricObject[args.length];
		ArrayList<GeometricObject> arrlist = new ArrayList<GeometricObject>();

		for( int i=0; i<args.length; i++ ) {
			tmpArgs[i] = (GeometricObject) (args[i].deepClone());
			Label lbl = new Label();
			System.out.println("Relabeling " + tmpArgs[i].getLabel().toString() + " as " + scriptParamName[i]);
			lbl.setLabel( scriptParamName[i] );
			tmpArgs[i].setLabel( lbl );
			arrlist.add( tmpArgs[i] );
		}

		/* Execute the command */
		GeometricObject[] ans = ExecuteScript( cmd, arrlist );
		if(ans==null || ans.length == 0)
		   { System.out.println("ExecuteScript failed on " + cmd);
		     return null;
		   }
        GeometricObject geoObj = ans[0];
        /* If there are more returned objects, what about them?
           At present they are labelled with whatever variable the called script used.  That could conflict with variables back
           in the symbol table that called this.  That's OK, as it says in the spec, but the calling function must rename them.
              However,  their ARGUMENTS are still members of tmpArgs.  These arguments must either be among the original
           arguments or must be the first returned object.
        */
        String oldReturnLabel = geoObj.getLabel().toString();
        if(isLegalLabelFormat( label )) {
				Label lbl = new Label();
				lbl.setLabel( label );
				geoObj.setLabel( lbl );
			 }
		 geoObj.setConstruction( cmd );
		 ArrayList<GeometricObject> mArgs = geoObj.getArgs();
		 mArgs.clear();
		 System.out.println("Setting the args of " + geoObj.getLabel());
		 for( int i=0; i < args.length;  i++ )
			 { geoObj.addArg( args[i] );
			   System.out.println("args["+ i + "] is " + args[i].getLabel());
			 }
        int n = ans.length;
        System.out.println(cmd + " returned " + n + " objects ");
        /* If the remaining returned objects are not null, set their arguments field correctly too */
        for(int i=1;i<n;i++)
           {  // fix up the args of ans[i].   These args must be among the args and geoObj.
              ArrayList<GeometricObject> newArgs = new ArrayList<GeometricObject>();
              for(GeometricObject o: ans[i].getArgs())
                 { String currentLabel = o.getLabel().toString();
                   if(currentLabel.equals(oldReturnLabel))
                         newArgs.add(geoObj);
                    else
                       { int j;
                         for(j = 0; j < args.length;j++)
                            { if(currentLabel.equals(scriptParamName[j]))
                                 { newArgs.add(args[j]);  // add the corresponding argument in the calling environment
                                   break;
                                 }
                            }
                         if(j == args.length)
                            {  String errmsg = "Oops!  Script " + cmd + " violates the rules for multiple returns at argument " + j +", because " + currentLabel + " is not equal to";
                               for(j=0;j<args.length;j++)
                                  errmsg += " " + scriptParamName[j];
                               throw new IllegalScriptException(errmsg );
                            }
                       }
                 }
              if(newArgs.size() != ans[i].getArgs().size())
                 { throw new IllegalScriptException("Oops!  Script " + cmd + " violates the rules for multiple returns.  Multiple returns can only depend on the parameters and the first return.");
                 }
              ans[i].setArgs(newArgs);
           }
		return ans;
	}

	/**
	 *	Carrying out the execution of 1 in 48 scripts - recursively
	 */
	private GeometricObject[]  ExecuteScript( String cmdName, ArrayList<GeometricObject> args ) {
		ArrayList<GeometricObject> argsClone = new ArrayList<GeometricObject>();
		GeometricObject[] geoObjs = null;
		String[] scriptList;
		Command  curCmd;
		int      totalScripts;

		/* Get the list of scripts based on the command name */
		try {
			scriptList   = Scripts.getScript(cmdName );
			totalScripts = scriptList.length;
		}
 		catch( Exception e ) {
 			e.printStackTrace();
 			return null;
 		}

 		for( int i=0; i<args.size(); i++ ) {
 			addToArgsClone( argsClone, args.get(i) );
		}

		/* Execute each script */
		for( int i=0; i<totalScripts-1; i++ ) {
			int size = args.size();

			/* parse the current script */
			curCmd = mParser.parse( scriptList[i].substring( 0,scriptList[i].length()-1 ) );
			if( curCmd == null ) return null;

			/* retrieve information about current command */
			String curCmdLabel        = curCmd.getLabel();
			String curCmdName         = curCmd.getCommandName();
			String curCmdArgs[]       = curCmd.getArguments();
			int curArgsSize           = curCmdArgs.length;
			GeometricObject cmdArgs[] = new GeometricObject[curArgsSize];
			GeometricObject geoObj;

			/* check to see if current command is a primitive one
				if yes, build an array of GeometricObject as parameters */
			if( Scripts.isPrimitiveCommand( curCmdName ) ) {
				for( int j=0; j<curArgsSize; j++ ) {
					for( int k=size-1; k>=0; k-- ) {
						if( args.get(k).getLabel().toString().equals( curCmdArgs[j] ) ) {
							cmdArgs[j] = (GeometricObject) (argsClone.get(k).deepClone());
							break;
						}
					}
				}

				geoObjs = ExecutePrimitive( curCmdLabel, curCmdName, cmdArgs );
				if( geoObjs == null ) return null;
			}

			/* it is 1 of 48 Euclidean scripts
				rebuild the ArrayList of arguments for the current script
				with appropriate label name of this particular script */
			else {
				ArrayList<GeometricObject> cmdArgsAL = new ArrayList<GeometricObject>();
				String[] scriptParamName = null;

				try {
					scriptParamName = Scripts.getParameterNames( "org.dynamicgeometry.scripts." + curCmdName );
				}
				catch( Exception e ) {
					e.printStackTrace();
					return null;
				}

				for( int j=0; j<curArgsSize; j++ ) {
					for( int k=size-1; k>=0; k-- ) {
						if( args.get(k).getLabel().toString().equals( curCmdArgs[j] ) ) {
							Label lbl = new Label();
							lbl.setLabel( scriptParamName[j] );
							argsClone.get(k).setLabel( lbl );

							cmdArgsAL.add( (GeometricObject)(argsClone.get(k).deepClone()) );
							cmdArgs[j] = (GeometricObject)(argsClone.get(k).deepClone());
							break;
						}
					}
				}

				geoObjs = ExecuteScript( curCmdName, cmdArgsAL );
				if( geoObjs == null ) return null;
				int n = geoObjs.length;
				geoObj = geoObjs[0];  // the main return value
				 /* set construction and arguments for the particular GeometricObject */
				geoObj.setConstruction( curCmdName );
				ArrayList<GeometricObject> mArgs = geoObj.getArgs();
				mArgs.clear();
				for( int j=0; j < cmdArgs.length; j++ )
				   geoObj.addArg( cmdArgs[j] );
				for( int j=1;j<n;j++)
				   { geoObjs[j].setConstruction(null); // meaning it comes automatically with other constructed objects
				     geoObjs[j].setArgs(null);
				   }
			}

			/* Set the correct label to the new GeometricObjects */
			geoObj = geoObjs[0];  // the main return object
  		    Label mLabel = new Label();
	        mLabel.setLabel( curCmdLabel );
  			geoObj.setLabel( mLabel );
		    args.add( geoObj );
		    addToArgsClone( argsClone, geoObj );
			/* Now if there are any extra return objects, they must be among the parameters or equal to the main returned object,
			   Their args are still pointing to copies of these objects but will be fixed when we return to Execute1. */
		}

		/* Check to see which object is actually returned - rather than the last line */
		String returnStmt = scriptList[totalScripts-1].substring( 0,scriptList[totalScripts-1].length()-1 );  // ignore ending semicolon
		System.out.println("Return statement is " + returnStmt);
		String[] stoken   = returnStmt.split( " +" );
		if(!stoken[0].equals("return"))
		    return geoObjs;
		int i,j,count=0;
		for(i=1; i< stoken.length;i++)
		   { if( stoken[i].equals("and")) continue;
		     ++count;
		   }
		GeometricObject[] ans = new GeometricObject[count];
		count = 0;
		for(i=1;i < stoken.length;i++)
		   { if( stoken[i].equals("and")) continue;
		     for( int jj=args.size()-1; jj>=1; jj-- )
		       { if( args.get(jj).getLabel().toString().equalsIgnoreCase( stoken[i] ))
			        { ans[count] =  args.get(jj);
  			          ++count;
  			          break;
  			        }
			   }
		   }
		return ans;
	}

	/**
	 *	Add one GeometricObject into the Arguments Clone
	 */
	private void addToArgsClone( ArrayList<GeometricObject> mClone, GeometricObject mGO ) {
		Object o = mGO.deepClone();

		if( o instanceof Line )	              mClone.add( (Line)o );
		else if( o instanceof Point )         mClone.add( (Point)o );
		else if( o instanceof Circle )        mClone.add( (Circle)o );
		else if( o instanceof Segment )       mClone.add( (Segment)o );
		else if( o instanceof Ray )           mClone.add( (Ray)o );
		else if( o instanceof Arc )           mClone.add( (Arc)o );
		else if( o instanceof Triangle )      mClone.add( (Triangle)o );
		else if( o instanceof Quadrilateral ) mClone.add( (Quadrilateral)o );
	}

	/**
	 *	To retrieve the appropriate intersection points between line AB and circle CD (center, end point)
	 *  Returns both intersections.  The two intersections occur on the line AB in the same order as A and B do.
	 */
	private Point[] getIntersectLineCircle( Point A, Point B, Point center, Point end ) {
		double radius       = distanceBetween2Points( center, end );
		double Ax           = A.getX();
		double Ay           = A.getY();
		double Bx           = B.getX();
		double By           = B.getY();
		double xTransform   = center.getX();
		double yTransform   = center.getY();

		Ax -= xTransform; Ay -= yTransform;
		Bx -= xTransform; By -= yTransform;

		double dx           = Bx - Ax;
		double dy           = By - Ay;
		double D            = Ax*By - Ay*Bx;
		double distABsquare = dx*dx + dy*dy;
		double distAB       = Math.sqrt( distABsquare );
		double discriminant = (radius*radius) * (distABsquare) - D*D;
		double x1,x2,y1,y2;
		Point p1,p2;

		x1=x2=y1=y2=0;

		// < 0 : no intersection
		if( discriminant >= 0 ) {
			if( Math.abs( discriminant ) > 0 ) { // 2 intersections
				x1 = (D*dy + sign( dy )*dx*Math.sqrt( discriminant )) / (distABsquare);
				y1 = (-D*dx + Math.abs(dy)*Math.sqrt( discriminant )) / (distABsquare);

				x2 = (D*dy - sign( dy )*dx*Math.sqrt( discriminant )) / (distABsquare);
				y2 = (-D*dx - Math.abs(dy)*Math.sqrt( discriminant )) / (distABsquare);
			}
			else {	// tangent line
				x1 = (D*dy + sign( dy )*dx*Math.sqrt( discriminant )) / (distABsquare);
				y1 = (-D*dx + Math.abs( dy )*Math.sqrt(discriminant)) / (distABsquare);

				x2 = x1;
				y2 = y1;
			}

			x1 += xTransform; y1 += yTransform;
			x2 += xTransform; y2 += yTransform;
		    p1 = new Point( x1, y1,true );
			p2 = new Point( x2, y2,true );
			if (Ay > By + 0.0001 * radius)
     			return new Point[]{p1,p2};
     	    else if( Ay < By - 0.0001 * radius)
     	        return new Point[]{p2,p1};
     	    else if( Ax < Bx)
     	        return (x1 < x2) ? new Point[]{p1,p2} : new Point[]{p2,p1};
     	    else
     	        return (x1 < x2) ? new Point[]{p2,p1} : new Point[]{p1,p2};

		}

		return null;
	}

	/**
	 *	Used for intersectCircleCircle1 and intersectCircleCircle2 calls
	 *	To retrieve the appropriate intersected point between 2 Circle (A,B) and (C,D)
	 *	The result will be Q such as (ABQ) makes the correct turn - (right or left)
	 */
	private GeometricObject getIntersectCircleCircle( Point A, Point B, Point C, Point D, String turn ) {
		double rAB = distanceBetween2Points( A, B );
		double rCD = distanceBetween2Points( C, D );

		GeometricObject[] intersects = calculateIntersectionBetween2Circles( A, rAB, C, rCD );
		if( intersects == null ) return null;	// no solution

		if( turn.equalsIgnoreCase( "left" )) return (Point)( intersects[0] );
		else if( turn.equalsIgnoreCase( "right" )) return (Point)( intersects[1] );

		return null;
	}

	/**
	 *	Used for intersectCircle1 and intersectCircle2 calls
	 *	To retrieve the appropriate intersected point between 2 Circle C1 and C2
	 *	The result will be Q such as the angel from the center of C1 to the center of C2
	 *  to Q makes the correct turn - (right or left)
	 */
	private GeometricObject getIntersectCircle( Circle C1, Circle C2, String angle ) {
		Point center1 = C1.getCenter();
		Point end1    = C1.getEnd();
		Point center2 = C2.getCenter();
		Point end2    = C2.getEnd();

		double r1 = Math.sqrt(	Math.pow( center1.getX() - end1.getX(), 2 ) +
								Math.pow( center1.getY() - end1.getY(), 2 ));
		double r2 = Math.sqrt(	Math.pow( center2.getX() - end2.getX(), 2 ) +
								Math.pow( center2.getY() - end2.getY(), 2 ));

		GeometricObject[] intersects = calculateIntersectionBetween2Circles( center1, r1, center2, r2 );
		if( intersects == null ) return null;	// no solution

		Point p1    = (Point) intersects[0];
		Point p2    = (Point) intersects[1];
		Point left  = null;
		Point right = null;

		double c1x = center1.getX();
		double c1y = center1.getY();
		double c2x = center2.getX();
		double c2y = center2.getY();
		double p1x = p1.getX();
		double p1y = p1.getY();
		double p2x = p2.getX();
		double p2y = p2.getY();

		if( c1x < c2x ) {					// big case 1
			if( p1y > p2y ) left = p1;
			else left = p2;
		}
		else if( c1x == c2x ) {				// big case 2
			if( c1y < c2y ) {					// case 2.1
				if( p1x < p2x ) left = p1;
				else left = p2;
			}
			else {								// case 2.2
				if( p1x > p2x ) left = p1;
				else left = p2;
			}
		}
		else {								// big case 3
			if( p1y < p2y ) left = p1;
			else left = p2;
		}

		right = (left==p1)?p2:p1;

		if( angle.equalsIgnoreCase( "left" )) return left;
		else if( angle.equalsIgnoreCase( "right" )) return right;

		return null;
	}

	/**
	 *	Calculate 2 intersections coordinate of 2 circles using their center and radius
	 */
	private GeometricObject[] calculateIntersectionBetween2Circles( Point o1, double r1, Point o2, double r2 ) {
		double d   = distanceBetween2Points( o1, o2 );
		double o1x = o1.getX();
		double o1y = o1.getY();
		double o2x = o2.getX();
		double o2y = o2.getY();

		if( d > r1 + r2 || d < Math.abs( r1 - r2 ) ) return null;	// no solution

		double a   = ( r1*r1 - r2*r2 + d*d) / ( 2*d );
		double h   = Math.sqrt( r1*r1 - a*a );
		double x2  = o1x + a*( o2x - o1x ) / d;
		double y2  = o1y + a*( o2y - o1y ) / d;

		double p1x = x2 + h*( o2y - o1y ) / d;
		double p1y = y2 - h*( o2x - o1x ) / d;
		double p2x = x2 - h*( o2y - o1y ) / d;
		double p2y = y2 + h*( o2x - o1x ) / d;

		GeometricObject[] res = new GeometricObject[2];
		res[0] = new Point( p1x, p1y );
		res[1] = new Point( p2x, p2y );

		return res;
	}

	/**
	 *	To calculate the distance between 2 given points
	 */
	private double distanceBetween2Points( Point A, Point B ) {
		double dx = A.getX() - B.getX();
		double dy = A.getY() - B.getY();

		return( Math.sqrt( dx*dx + dy*dy ) );
	}

	/**
	 *	Get the sign of a number x
	 */
	private int sign( double x ) {
		return (x > 0? 1: -1);
	}

	/**
	 *	3 Points A ,X, Y are on the same line
	 *	Check to see if A is the middle point
	 */
	private boolean isMiddlePoint( Point A, Point X, Point Y ) {
		double dAX = distanceBetween2Points( A, X );
		double dAY = distanceBetween2Points( A, Y );
		double dXY = distanceBetween2Points( X, Y );

		if( (dXY > dAX) && (dXY > dAY) ) return true;

		return false;
	}

	/**
	 *	Check to see if label is "" or contains only spaces and tabs
	 */
	private boolean isLegalLabelFormat( String label ) {
		if( label == null ) return false;
		if( label.length() == 0 ) return false;

		for( int i=0; i<label.length(); i++ )
			if( label.charAt( i ) != ' ' && label.charAt( i ) != '\t' ) return true;
		return false;
	}

	/**
	 *	Check to see if cmdString is a variable name or a commandName
	 *	command name format:	begin with 2 letters ...
	 *	variable name:			begin with 1 letter, followed by multiple numbers
	 */
	private boolean isVariableName( String cmdString ) {
		if( cmdString.length() == 1 ) return true;
		if( !Character.isDigit( cmdString.charAt( cmdString.length()-1 )) ) return false;
		if( Character.isDigit( cmdString.charAt( 1 )) ) return true;

		return false;
	}


	/**
	 *	Used for debug: short cut to print statement
	 */
	private void print( Object o) {
		System.out.print( o );
	}

	/**
	 *	Used for debug: short cut to println statement
	 */
	private void println( Object o ) {
		System.out.println( o );
	}
}

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists