The simphy package

Explanation of the simphy package
Jan Tobochnik and Harvey Gould

Test Program Simulation interface ControlFrame ControlMenu
Table Plot WorldGraphics SimFormat

Introduction to the simphy Package

The simphy package is designed to implement some basic tasks that are useful in many simulations of physical systems. Objects can be created from the classes in this package without knowing the details of how the classes are written. However, we also list the classes below for interested users who may wish to modify or extend them. Any class that uses the simphy package must include the statement import simphy.*; at the beginning of the file containing the class. In the following we list the classes and describe what they do and how they can be used. If you are using Metrowerks CodeWarrior then the simphy package jar file must be added to your project.

ControlFrame
This class places any number of Buttons and TextFields on a Frame, and gives the user a simple method for input and output of data through Textfields and the control of the program through Buttons. The user only needs to specify the names for the Buttons, the names for Labels that appear under the TextFields, and optionally, initial strings to appear in the Textfields. An example appears below:
String Blist[] = {"start", "stop", "reset"};
String Llist[] = {"Temperature", "Lattice Size"};
double Tlist[] = {2.2,64};
ControlFrame cf = new ControlFrame(S, Llist, Tlist, Blist);
This example creates three buttons and two TextFields with Labels below them. When a button is pressed or a TextField changed, another object needs to know. To accomplish this communication, the object S must implement the interface Simulation. Why do we use an interface? Why not just write a class with the necessary methods? The answer is that the interface lets ControlFrame have an instantiation of any class as an argument as long as that class implements the Simulation interface. Any class that implements Simulation must include the methods shown in the following example.
public class Example implements Simulation
   {

   public void buttonAction(int k)
   {
      // respond to Buttons numbered from 0 to number of Buttons - 1
   }

   public void textAction(int k, double x)
   {
      // respond to  TextFields numbered from 0 to number of TextFields - 1
   }

   public void menuAction(int k)
   {
      // respond to Menus that perform actions numbered from 0 to number of Menu items - 1
   }

   public void dialogAction(int k, double x)
   {
      // respond to Menus that call up dialog boxes numbered from 0 to number of Menu items - 1
   }

}
This interface is used with ControlMenu also. In method textAction and dialogAction, the double x is the value entered into a TextField by the user.

ControlMenu
This class has the same functionality as ControlFrame. Two Menus are created, one called "Actions" and one called "Parameters" which play the same role as the Buttons and TextFields, respectively. The constructor for ControlMenu works in the same way as the constructor for ControlFrame. Before using the ControlMenu you must first attach the menubar to a frame:

fr.setMenuBar(cm.sBar);  // fr = Frame object , cm = ControlMenu object

Table
This class displays a table of formated numbers separated by tabs in a Frame. The constructor arguments are the TableName and a String array of table headings for the columns. The class contains methods for setting formats for the entries to the table, adding entries to a row (one at a time or up to the first 5 entries at once), and displaying a row. The Table can be copied from the Frame and pasted directly into a spreadsheet or plotting program. Below we show an example.

   "String h[] = {"Column A","Column B","Column C"};
   Table tb = new Table("Example Table",h);
   String pattern[] = {"#.0000", "#.00","#.000"};
   tb.setFormat(pattern,10); // width of each column is 10 characters
   tb.setEntry(0,3.173);     // set zeroth element of row
   tb.setEntry(1,999.9173);  // set first element of row
   tb.setEntry(2,3891.73);   // set second element of row
   tb.displayEntries();  // display first row
   tb.setEntries(3317.3,99.173,817.3);  // set all three elements of row at once
   tb.displayEntries();  // display second row
The result of the above code is to produce a table that looks like the following:
  Column A  Column B  Column C
    3.1730    999.91  3891.730
 3317.3000     99.17   817.300
In some cases you may wish to show the entire table all at once to avoid flicker as each row is shown. To do this use the constructor Table(String TableName, String h[],int FieldSize, boolean visibility) with visibility set equal to false. When all the entries to the table have been displayed, then call showTable() to see the table on the screen. Plot
This class is used to draw simple plots in separate Frames. The constructor arguments set up the title for the plot, labels for the horizontal and vertical axes, the type of plot, the minimum and maximum values for x and y, the symbol size, the symbol type, the horizontal and vertical size of the frame,and the horizontal and vertical location. The data can be encoded in two double arrays that are passed to the method plotPoints or plotCurve. Alternatively, one point can be plotted at a time using the method plotPoint. Below we show one of the constructors and the public methods used in this class.
public Plot(String title, String xLabel, String yLabel, int nAxes,
       double xmin,double xmax, double ymin, double ymax, int symbolSize, String symbolType
       int xsize, int ysize, int xloc, int yloc)

/* nAxes = 1, one bottom horizontal axis, ymin should = 0
   nAxes = 2, one left vertical axis, one bottom horizontal axis, xmin and ymin should = 0
   nAxes = 3, one center vertical axis, one bottom horizontal axis, xmin should = -xmax, ymin should = 0
   nAxes = 4, crossed axes, xmin should = -xmax and ymin should = -ymax
   nAxes = 5, crossed axes, only x > 0, xmin should = 0 and ymin should = -ymax
   nAxes = anything else, no axes drawn.
   symbolType = "fillsquare" or "opensquare" or "opencircle" or "fillcircle"
   symbolSize = 1 for point (default), otherwise gives size in pixels
*/

public void plotPoints(double x[], double y[]);
public void plotPoint(double x, double y);  // Plot one point
public void plotCurve(double x[], double y[]);
public void clear();  // clears frame on buffer
public void clearPoints(); // clears frame and replots axes
public void setColor(String s); 
WorldGraphics
This class creates a Frame and defines many of the methods in the Graphics class in terms of world coordinates where the vertical coordinate increases up the screen. It also uses double coordinates instead of integers, and works with an offscreen Image buffer. The constructor is shown below. The first four arguments define the minimum and maximum coordinates in the horizontal and vertical directions. The argument size defines the horizontal size of the frame in pixels, and the last two arguments define where the upper left hand corner of the frame is on the screen in pixels with yLoc = 0 at the top of the screen.
public WorldGraphics(String title,
       double xmin,double xmax, double ymin, double ymax, int size, int xLoc, int yLoc)

The offscreen buffer can be used to do animation and speed up graphics. To do this call the method setToScreen(false), which will cause all subsequent drawing methods to draw only to the offscreen buffer and not to the screen. Then to draw the buffer to the screen, call drawBuffer(). Animation can be achieved for an image moving from one place to another by clearing the old location of the image using clearRect(x,y,dx,dy), drawing the image at the new location, and then calling drawBuffer().

SimFormat
This abstract class converts a double number to a convenient string representation. The method dformat(double x,int d) converts the number x to a decimal representation with d decimal places. If d is not specified the default value is 3 decimal places. The method eformat(double x,int d) returns a string representation using exponential notation, and aformat(double x,int d, double min, double max) returns decimal notation if min < |x| < max, and exponential notation otherwise. Examples are shown below.
SimFormat.dformat(33.12765,3);         // returns 33.127
SimFormat.eformat(-0.00364);           // returns -3.640 E-3
SimFormat.aformat(-3078.6,2,1.0,10.0); // returns -3.07 E3
SimFormat.aformat(-3078.6);            // returns -3.078 E3  
                                       // default values are min = 0.001, max = 100, d = 3
Test Program

A test program showing how these classes are instantiated and used is shown below. Try running this program and testing the Buttons, TextFields, and menu items. Find the code in the program for the things you see on the screen.

import simphy.*;

   public class Test implements Simulation
   {
      ControlFrame cf;
      ControlMenu cm ;
      WorldGraphics wg;

   public static void main(String args[])
   {
      Test u = new  Test();
   }


   public Test()
   {
      String h[] = {"zero","first","second"};
      Table tb = new Table("test",h);
      String pattern[] = {"#.0000", "#.00","#.000"};
      tb.setFormat(pattern,10);
      tb.setEntry(0,3.173);
      tb.setEntry(1,999.9173);
      tb.setEntry(2,3891.73);
      tb.displayEntries();
      tb.setEntries(3317.3,99.173,817.3);
      tb.displayEntries();
      String lString[] = {"zero", "one", "two","three", "four", "five","six", "seven", "eight"};
      String bString[] = {"A", "B", "C","D", "E", "F","G", "H", "I"};
      double initialP[] = { 1,2,3,4,5,6,7,8,9};
      ControlFrame cf = new  ControlFrame(this,lString,initialP,bString);
      ControlMenu cm = new  ControlMenu(this,lString,initialP,bString);
      WorldGraphics wg = new WorldGraphics("Visualization",0,10,0,10, 500, 200,200);
      wg.setMenuBar(cm.sBar);
   }

   public void buttonAction(int k)
   {
      double x[] = {0,1,2,3,4};
      double y[] = {0,1,2,3,4};
      switch(k)
      {
         case 0: Plot p =  new Plot("y vs x","xxxx","yyyy",1,-5,5,0,5);p.plotPoints(x,y);break;
         case 1: Plot p1 = new Plot("y vs x","xxxx","yyyy",2,-5,5,0,5);p1.plotPoints(x,y);break;
         case 2: Plot p2 = new Plot("y vs x","xxxx","yyyy",3,-5,5,0,5);p2.plotPoints(x,y);break;
         case 3: Plot p3 = new Plot("y vs x","xxxx","yyyy",4,-5,5,0,5);p3.plotPoints(x,y);break;
      }
   }

   public void textAction(int k, double x)
   {
      System.out.println(x);
      cf.setText(0,x);
      cf.setText(1,(int) x);
      cf.setText(2,"hello " + String.valueOf(k));
   }

   public void menuAction(int k)
   {
      switch(k)
      {
         case 0: wg.drawRect(5,5,4,4.0); break;
         case 1: wg.drawString("good job", 7.0,2.0);break;
         case 2: wg.drawLine(0,0,10,10);break;
         case 3: wg.drawRect(200,200,100,100);break;
         case 4: wg.drawCircle(5,5,3);break;
         case 5: wg.clearRect(0,0,10,10);break;
         case 6: wg.setColor("yellow");break;
         case 7: wg.setColor("green");break;
         case 8: wg.setColor("random");break;
      }
      cf.texts[1].setText(String.valueOf(k));  // shows which menu selected in a TextField
   }

   public void dialogAction(int k, double x)
   {
      System.out.println(x);
   }

}

Class and interface Listings

Simulation
package simphy;

public interface Simulation
{  // used with ControlFrame or ControlMenu
   public void buttonAction(int k);
   public void textAction(int k, double x);
   public void menuAction(int k);
   public void dialogAction(int k, double x);
}

ControlFrame

package simphy;

   import java.awt.*;
   import java.awt.event.*;

   public class ControlFrame extends Frame
   {
      public TextField texts[];
      Label labels[];
      Button buttons[];
      Simulation S;
      String lString[], bString[];
      double x[];

      public ControlFrame(Simulation S, String lString[], String bString[])
      {
         this.S = S;
         this.lString = lString;
         this.bString = bString;
         int nT = lString.length;
         x = new double[nT];
         for(int i = 0; i < nT;i++)
            x[i] = 0.0;
         setUpFrame();
      }

      public ControlFrame(Simulation S, String lString[], double x[], String bString[])
      {
         this.S = S;
         this.lString = lString;
         this.bString = bString;
         this.x = x;
         setUpFrame();
      }

      public void setUpFrame()
      {
         int ix = 20, iy = 20,bxT = 100,by = 20, ysep = 80, lsep = 20;
         int fSize = 0, bx;
         int nT = lString.length;      // number of textfields
         int nB = bString.length;      // number of buttons
         for (int i = 0; i < nB; i++)
            fSize += 20 + max(bString[i].length()*10,bxT);
         for (int i = 0; i < nT; i++)
            fSize += 20 + max(lString[i].length()*10,bxT);
         if(fSize < 500)
            setSize(fSize, ysep);
         else
         {
            setSize(500, (2 + fSize/500)*ysep);
            fSize = 500;
         }
         setTitle("Controls");
         this.S = S;
         setLayout(null);
         texts = new TextField[nT];    // new array of textfields
         labels = new Label[nT];       // new array of labels
         buttons = new Button[nB];     // new array of buttons

         for(int i = 0; i < nB;i++)
         {
            bx = max(bString[i].length()*10,bxT);   // button size
            if(ix + bx + 20 > fSize)
            {
               ix = 20;
               iy += ysep;
            }
            buttons[i] = new Button(bString[i]);     // new button
            buttons[i].addActionListener(new B(i));  // add listener
            buttons[i].setSize(bx,by);
            buttons[i].setLocation(ix,iy);
            add(buttons[i]);                          // add button
            ix += bx + 20;
         }
         for(int i = 0; i < nT;i++)
         {
            bx = max(lString[i].length()*10,bxT); // label size
            if(ix + bx + 20 > fSize)
               {
                  ix = 20;
                  iy += ysep;
               }
               labels[i]= new Label(lString[i]);  // new label for textfield
               labels[i].setSize(bx,by);
               labels[i].setLocation(ix,iy+lsep);
               add(labels[i]);    // add label
               if( (int) x[i] == x[i])
                  texts[i]= new TextField(String.valueOf( (int) x[i]));  // new textfield
               else
                   texts[i]= new TextField(String.valueOf(x[i]));  // new textfield
               texts[i].addActionListener( new T(i));  // add listener
               texts[i].setSize(bxT,by);
               texts[i].setLocation(ix,iy);
               add(texts[i]);                     // add textfield
               ix +=  bx + 20;
            }
            setVisible(true);
         }

         private int max(int a, int b)
         {
            if ( a > b)
               return a;
            else
               return b;
         }

         public void setText(int k, String s)
         {
            texts[k].setText(s);
         }

         public void setText(int k, int x)
         {
            texts[k].setText(String.valueOf(x));
         }

         public void setText(int k, double x)
         {
            texts[k].setText(String.valueOf(x));
         }

     //  Inner classes

         class B implements ActionListener
         {
            int k;    // kth button

            public B(int k)
            {
               this.k = k;
            }

            public void actionPerformed(ActionEvent e)
            {
               S.buttonAction(k);
            }
         }

         class T implements ActionListener
         {
            int k;   // kth TextField

            public T(int k)
            {
               this.k = k;
            }

            public void actionPerformed(ActionEvent e)
            {
               Double R = new Double(texts[k].getText().trim());
               S.textAction(k,R.doubleValue());
            }
         }

      }

ControlMenu

package simphy;
   import java.awt.*;
   import java.awt.event.*;

   public class ControlMenu
   {
      public MenuBar sBar;          // declare menubar
      Menu bMenu,tMenu;             // declare two menus
      MenuItem bItems[];            // declare array of menu items
      MenuItem tItems[];            // declare array of menu items
      Simulation S;
      String lString[], bString[];
      public double x[];

      public ControlMenu(Simulation S, String lString[], String bString[])
      {
         this.S = S;
         this.lString = lString;
         this.bString = bString;
         int nT = lString.length;
         x = new double[nT];
         for(int i = 0; i < nT;i++)
            x[i] = 0.0;
         setUpMenu();
      }

      public ControlMenu(Simulation S, String lString[], double x[], String bString[])
      {
         this.S = S;
         this.lString = lString;
         this.bString = bString;
         this.x = x;
         setUpMenu();
      }

      public void setUpMenu()
      {
         sBar = new MenuBar();                    // assign menubar
         bMenu = new Menu("Actions");             // assign menu
         tMenu = new Menu("Parameters");          // assign menu
         sBar.add(bMenu);                   // add menu to menubar
         sBar.add(tMenu);               // add menu to menubar
         int nB = bString.length;
         bItems = new MenuItem[nB];    // assign array of menu items
         int nT = lString.length;
         tItems = new MenuItem[nT];    // assign array of menu items

         for(int i = 0; i < nT;i++)
         {
            tItems[i] = new MenuItem(lString[i]);  // assign menu item to array element
            tItems[i].addActionListener( new T(i));
            tMenu.add(tItems[i]); }        // add menu item to menu
            for(int i = 0; i < nB;i++)
            {
               bItems[i] = new MenuItem(bString[i]);  // assign menu item to array element
               bItems[i].addActionListener( new B(i));
               bMenu.add(bItems[i]); // add menu item to menu
            }                
         }

         class B implements ActionListener
         {
            int k;

            public B(int k)
            {
               this.k = k;
            }

            public void actionPerformed(ActionEvent e)
            {
               S.menuAction(k);
            }
         }

         class T implements ActionListener
         {
            int k;

            public T(int k)
            {
               this.k = k;
            }

            public void actionPerformed(ActionEvent e)
            {
               InputDialog d = new InputDialog(S,k,lString[k],x);
            }
         }
      }

      package simphy;
      import java.awt.*;
      import java.awt.event.*;

      class InputDialog extends Frame // Used with ControlMenu
      {    

         TextField newValueText;
         double x[];

         public InputDialog(Simulation S,int k, String lString, double x[])
         {
            this.x = x;
            setTitle("Dialog Box");
            setSize(250,250);
            setLocation(50,50);
            setLayout(null);
            Label label = new Label("Enter new  " + lString);
            label.setSize(150,20);
            label.setLocation(50,20);
            add(label);
            Button b1 = new Button("Okay");
            b1.addActionListener( new OkayClass(k,S));
            Button b2 = new Button("Cancel");
            b2.addActionListener( new CancelClass());
            b1.setLocation(30,80);
            b2.setLocation(150,80);
            b1.setSize(70,20);
            b2.setSize(70,20);
            add(b1);
            add(b2);
            newValueText = new TextField(String.valueOf(x[k]));
            newValueText.setSize(80,20);
            newValueText.setLocation(50,50);
            add(newValueText);
            setVisible(true);
         }

         class OkayClass implements ActionListener
         {

            int k;
            Simulation S;

            public OkayClass(int k, Simulation S)
            {
               this.k = k;
               this.S = S;
            }

            public void actionPerformed(ActionEvent e)
            {
               String s = newValueText.getText();
               Double R = new Double(s.trim());
               S.dialogAction(k,R.doubleValue());
               x[k] = R.doubleValue();
               setVisible(false);
               dispose();
            }
         }

         class CancelClass implements ActionListener
         {

            public void actionPerformed(ActionEvent e)
            {
               setVisible(false);
               dispose();
            }
         }
      }

Table

package simphy;
     import java.awt.*;
     import java.text.*;


     public class Table extends Frame {

        protected double entry[];
        int n;
        public TextArea t;
        DecimalFormat number[];
        int FieldSize = 10; 

        
        public Table(String TableName, String h[],int FieldSize, boolean visibility) {   
           this.FieldSize = FieldSize;
           n = h.length;
           entry = new double[n];
           number = new DecimalFormat[n];
           setTitle(TableName);
           setSize(90*n,500);
           t = new TextArea();
           add(t);
           t.setEditable(true);
           setVisible(visibility);  // set visibility to false and use showTable to show all at once
           setHeadings(h);
           String pattern[] = new String[n];
           for(int i = 0; i < n ; i++) 
              pattern[i] = "#.000";
           setFormat(pattern,FieldSize);
        }

        public Table(String TableName, String h[]) {   // sets up Table with default formats
           this(TableName,h,10,true);
        }
 
        public Table(String TableName, String h[], int FieldSize) {   
           this(TableName,h,FieldSize,true);
        }

        public void showTable() {
           setVisible(true);
        }
        
        public void setHeadings(String h[]) {
           int len;
           setFont(new Font("Monospaced",Font.BOLD,10));
           for(int i = 0; i < n ; i++) {
              len = h[i].length();
              if(len < FieldSize) 
                 for(int j = 0; j < FieldSize-len;j++) h[i] = " " + h[i];
              t.append(h[i] + "\t");
           }
           t.append("\n" + "\n");
        }
        
        public void println(String S) {
           t.append(S + "\n");
        }
        
        public void setFormat(String pattern[],int FieldSize) {
           this.FieldSize = FieldSize;
           for(int i = 0; i < n ; i++)
             number[i] = new DecimalFormat(pattern[i]);
        }
        
         public void displayEntries() {
           int len,Eloc;
           String s;
           setFont(new Font("Monospaced",Font.PLAIN,10));
           for(int i = 0; i < n ; i++) {
              if(Math.abs(entry[i]) < 1.0E7) {
                s = number[i].format(entry[i]);
                len = s.length();
               }
               else{
                s = String.valueOf(entry[i]);
                len = s.length();
                Eloc = len;
                for(int j = 0; j < len;j++) 
                   if ( s.substring(j,j+1).equalsIgnoreCase("E"))Eloc = j;
                s = s.substring(0,4) + s.substring(Eloc,len);
                len = s.length();
               }
              if(len < FieldSize) 
                 for(int j = 0; j < FieldSize-len;j++) s = " " + s;
              t.append(s + "\t");
           }
           t.append("\n");
        }
       
         public void setEntry(int i, double x) {
            entry[i] = x;
         }

         public void setEntries(double x0, double x1) {
            entry[0] = x0;
            entry[1] = x1;
         }

         public void setEntries(double x0, double x1, double x2) {
            setEntries(x0,x1);
            entry[2] = x2;
         }

         public void setEntries(double x0, double x1, double x2, double x3) {
            setEntries(x0,x1,x2);
            entry[3] = x3;
         }

         public void setEntries(double x0, double x1, double x2, double x3, double x4) {
            setEntries(x0,x1,x2,x3);
            entry[4] = x4;
         }

     }

Plot

package simphy;
     import java.awt.*;

     public class Plot extends Frame{
      double scalex,scaley,xmin,ymin,xmax,ymax;
      int nAxes;
      String xLabel,yLabel;
      int mg = 30;
      int width,height;
      int symbolSize;
      String symbolType;
      Image buffer;
      Graphics b;
      

       public Plot(String title, String xLabel, String yLabel, int nAxes, 
              double xmin,double xmax, double ymin, double ymax, int symbolSize, 
              String symbolType, int xsize, int ysize, int xloc, int yloc) {
              this.nAxes = nAxes;
              this.xLabel = xLabel;
              this.yLabel = yLabel;
              this.xmin = xmin;
              this.ymin = ymin;
              this.xmax = xmax;
              this.ymax = ymax;
              this.symbolSize = symbolSize;
              setTitle(title);
              setSize(xsize,ysize);
              width = getSize().width;
              height = getSize().height;
              setLocation(xloc,yloc);
              setVisible(true);
              setScale();
              buffer = createImage(getSize().width,getSize().height);
              b = buffer.getGraphics();
              setAxes();
      }
      
       public Plot(String title, String xLabel, String yLabel, int nAxes, 
                   double xmin,double xmax, double ymin, double ymax, 
                   int symbolSize, String symbolType) {
              this(title, xLabel, yLabel,nAxes, xmin, xmax,  ymin,  ymax, symbolSize, 
                   symbolType, 400, 400,150,150);
   }


       public Plot(String title, String xLabel, String yLabel, int nAxes, 
                   double xmin,double xmax, double ymin, double ymax) {
              this(title,xLabel,yLabel,nAxes,xmin,xmax,ymin,ymax,1,"dot",400,400,150,150);
       }
       
       public Plot(String title,double xmin,double xmax, double ymin, double ymax,
                   int xsize, int ysize) {
              this(title,"","",0,xmin,xmax,ymin,ymax,1,"dot",xsize,ysize,150,150);
       }

       public Plot(String title,double xmin,double xmax, double ymin, double ymax,
                   int xsize, int ysize, int xloc, int yloc) {
              this(title,"","",0,xmin,xmax,ymin,ymax,1,"dot",xsize,ysize,xloc,yloc);
       }

       public Plot(int nAxes, 
                   double xmin,double xmax, double ymin, double ymax) {
              this("Plot","x","y",nAxes,xmin,xmax,ymin,ymax,1,"dot",400,400,150,150);
       }

       
          
       private void setScale() { 
              if(xmax > xmin) 
                 scalex = (getSize().width-2*mg)/(xmax-xmin);
              else {
                 System.out.println("Error  xmax not greater than xmin");
                 return;
              }
              if(ymax > ymin) 
                 scaley = (getSize().height-2*mg)/(ymax-ymin);
              else {
                 System.out.println("Error  ymax not greater than ymin");
                 return;
              }
        }
        
        
        public void setAxes() {
               int mg = 30; 
               int ix,iy;  
               if(width != getSize().width || height != getSize().height) {
                    width = getSize().width;
                    height = getSize().height;
                    setScale();
               }
               b.clearRect(0,0,getSize().width,getSize().height);
               switch (nAxes) {   // draw axes and axis labels
                case 1: b.drawLine(mg,size().height-mg,size().width-mg,size().height-mg);
                        b.drawString(xLabel,getSize().width/2,getSize().height-10);
                        break;
                case 2: b.drawLine(mg,getSize().height-mg,mg,mg);
                        b.drawLine(mg,getSize().height-mg,getSize().width-mg,size().height-mg);
                        b.drawString(xLabel,getSize().width-2*mg,getSize().height-10);
                        b.drawString(yLabel,10,20);
                        break;
                case 3: b.drawLine(mg,size().height-mg,size().width-mg,size().height-mg);
                        b.drawLine(size().width/2,size().height-mg,size().width/2,mg);
                        b.drawString(xLabel,getSize().width-2*mg,getSize().height-10);
                        b.drawString(yLabel,getSize().width/2,20);
                        break;
                case 4: b.drawLine(mg,getSize().height/2,getSize().width-mg,getSize().height/2);
                        b.drawLine(getSize().width/2,size().height-mg,getSize().width/2,mg);
                        b.drawString(xLabel,getSize().width-2*mg,getSize().height/2+20);
                        b.drawString(yLabel,getSize().width/2,20);
                        break;
                case 5: b.drawLine(mg,getSize().height/2,getSize().width-mg,getSize().height/2);
                        b.drawLine(mg,mg,mg,getSize().height-mg);
                        b.drawString(xLabel,getSize().width-2*mg,getSize().height/2+20);
                        b.drawString(yLabel,mg,20);
                        break;
              }
              Graphics g = getGraphics();
              g.drawImage(buffer,0,0,this);   // draw image onto screen 
         }
         
         
         public void clearPoints() {
            b.clearRect(0,0,getSize().width,getSize().height);
            setAxes();
         }
         
         public void clear() {
            b.clearRect(0,0,getSize().width,getSize().height);
         }
         
         public void plotPoints(double x[],double y[]) {
              int ix,iy;  
              for(int i = 0; i < x.length; i++) {     // plot points
                  ix = (int)((x[i]-xmin)*scalex) +mg;
                  iy = getSize().height - (int)((y[i]-ymin)*scaley) - mg;
                  if(symbolSize > 1) {
                    if(symbolType == "fillsquare")
                       b.fillRect(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
                    else if(symbolType == "opensquare")
                       b.drawRect(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
                    else if(symbolType == "opencircle")
                       b.drawOval(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
                    else 
                       b.fillOval(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
                  }
                  else
                    b.drawLine(ix,iy,ix,iy);
               }
              Graphics g = getGraphics();
              g.drawImage(buffer,0,0,this);   // draw image onto screen 
        }

         public void plotPoint(double x,double y) {
               int ix,iy;  
               // plot point
                  ix = (int)((x-xmin)*scalex) +mg;
                  iy = getSize().height - (int)((y-ymin)*scaley) - mg;
                  if(symbolSize > 1) {
                    if(symbolType == "fillsquare")
                       b.fillRect(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
                    else if(symbolType == "opensquare")
                       b.drawRect(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
                    else if(symbolType == "opencircle")
                       b.drawOval(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
                    else 
                       b.fillOval(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
                  }
                  else
                    b.drawLine(ix,iy,ix,iy);
               Graphics g = getGraphics();
               g.drawImage(buffer,0,0,this);   // draw image onto screen 
        }

         public void plotCurve(double x[],double y[]) {
              int ix1,iy1,ix2,iy2;  
              ix1 = (int)((x[0]-xmin)*scalex) +mg;
              iy1 = size().height - (int)((y[0]-ymin)*scaley) - mg;
              for(int i = 1; i < x.length; i++) {     // plot points
                  ix2 = (int)((x[i]-xmin)*scalex) +mg;
                  iy2 = size().height - (int)((y[i]-ymin)*scaley) - mg;
                  b.drawLine(ix1,iy1,ix2,iy2);
                  ix1 = ix2;
                  iy1 = iy2;
               }
              Graphics g = getGraphics();
              g.drawImage(buffer,0,0,this);   // draw image onto screen 
        }
        
        public void setColor(String s) {
           Color c = Color.black; 
            if(s == "red") c = Color.red;
             else if(s == "blue") c = Color.blue;
             else if(s == "black") c = Color.black;
             else if(s == "green") c = Color.green;
             else if(s == "yellow") c = Color.yellow;
             else if(s == "white") c = Color.white;
             else if(s == "magenta") c = Color.magenta;
             else if(s == "cyan") c = Color.cyan;
             else if(s == "orange") c = Color.orange;
             else if(s == "pink") c = Color.pink;
             else if(s == "random") c = new Color((int) (Math.random()*255),
                  (int) (Math.random()*255), (int) (Math.random()*255));
             b.setColor(c);
      }
      
      
       public void paint(Graphics g) {
         if(getSize().width != width || getSize().height != height) {
            width = getSize().width;
            height = getSize().height;
            setScale();
            buffer = createImage(getSize().width,getSize().height);
            b = buffer.getGraphics();
         }
            g.drawImage(buffer,0,0,this);   // draw image onto screen 
        }


      }

WorldGraphics

package simphy;

     /* Creates Frame for drawing on using world coordinates. y increases as you move up, 
        x increases as you move right. Unless otherwise specified methods use world
        coordinates. */
        
     import java.awt.*;
     
     public class WorldGraphics extends Frame {
      double scalex,scaley,xmin,ymin,xmax,ymax;
      int width,height;
      Image buffer;
      Graphics b;
      Color c = Color.black; 
      boolean toScreen = true; // draw to screen as well as buffer
      
       public WorldGraphics(String title, 
              double xmin,double xmax, double ymin, double ymax, int size, int xLoc, int yLoc) {
              this.xmin = xmin;
              this.ymin = ymin;
              this.xmax = xmax;
              this.ymax = ymax;
              double f = (ymax-ymin)/(xmax-xmin);
              setTitle(title);
              setSize(size,(int)(size*f));
              width = getSize().width;
              height = getSize().height;
              setScale();
              setLocation(xLoc,yLoc);
              setVisible(true);
              buffer = createImage(getSize().width,getSize().height);
              b = buffer.getGraphics();
      }
         public WorldGraphics(String title, 
              double xmin,double xmax, double ymin, double ymax) {
              // old version
              this.xmin = xmin;
              this.ymin = ymin;
              this.xmax = xmax;
              this.ymax = ymax;
              double f = (ymax-ymin)/(xmax-xmin);
              setTitle(title);
              setSize(360,(int)(360*f));
              width = getSize().width;
              height = getSize().height;
              setScale();
              setLocation(200,100);
              setVisible(true);
              buffer = createImage(getSize().width,getSize().height);
              b = buffer.getGraphics();
      }
           
          
       public void setScale() { 
              if(xmax > xmin) {
                 scalex = (getSize().width)/(xmax-xmin);
              }
              else {
                 System.out.println("Error xmax not greater than xmin");
                 return;
              }
              if(ymax > ymin) {
                 scaley = (getSize().height)/(ymax-ymin);
              }
              else {
                 System.out.println("Error  ymax not greater than ymin");
                 return;
              }
        }
        
        private int scrX(double x) {
              return (int)((x-xmin)*scalex);
        }

        private int scrY(double y) {
              return getSize().height - (int)((y-ymin)*scaley);
        }

        private int scrDX(double dx) {
              return (int)(dx*scalex);
        }

        private int scrDY(double dy) {
              return (int)(dy*scaley);
        }
        
        public void setToScreen(boolean toScreen) {
           this.toScreen = toScreen;
        }
        
        public void drawLine(double x1, double y1, double x2, double y2) {
              b.drawLine(scrX(x1),scrY(y1),scrX(x2),scrY(y2));
              if (toScreen) repaint();
         }
      
        public void drawPoint(double x1, double y1) {
              b.drawLine(scrX(x1),scrY(y1),scrX(x1),scrY(y1));
              if (toScreen) repaint();
         }

        public void fillRect(double x, double y, double dx, double dy) {
              b.fillRect(scrX(x),scrY(y)-scrDY(dy),scrDX(dx),scrDY(dy));
              if (toScreen) repaint();
        }   
        
        public void drawRect(double x, double y, double dx, double dy) {
              b.drawRect(scrX(x),scrY(y)-scrDY(dy),scrDX(dx),scrDY(dy));
              if (toScreen) repaint();
        }   
        
        public void drawRect(int x, int y, int dx, int dy) {  // uses screen coordinates
              b.drawRect(x,y,dx,dy);
              if (toScreen) repaint();
        }   
        
        public void fillRect(int x, int y, int dx, int dy) {  // uses screen coordinates
              b.fillRect(x,y,dx,dy);
              if (toScreen) repaint();
        }   

        public void fillOval(double x, double y, double dx, double dy) {
              b.fillOval(scrX(x),scrY(y)-scrDY(dy),scrDX(dx),scrDY(dy));
              if (toScreen) repaint();
        }   

        public void drawOval(double x, double y, double dx, double dy) {
              b.drawOval(scrX(x),scrY(y)-scrDY(dy),scrDX(dx),scrDY(dy));
              if (toScreen) repaint();
        }   
        
        public void drawCircle(double x, double y, double r) {
              b.drawOval(scrX(x)-scrDX(r),scrY(y)-scrDY(r),scrDX(2*r),scrDY(2*r));
              if (toScreen) repaint();
        }   
      
        public void fillCircle(double x, double y, double r) {
              b.fillOval(scrX(x)-scrDX(r),scrY(y)-scrDY(r),scrDX(2*r),scrDY(2*r));
              if (toScreen) repaint();
        }   

       public void clearRect(double x, double y, double dx, double dy) {
              b.clearRect(scrX(x),scrY(y)-scrDY(dy),scrDX(dx),scrDY(dy));
              if (toScreen) repaint();
       }
       
       public void clearBuffer() {
              b.clearRect(scrX(xmin),scrY(ymin)-scrDY(ymax-ymin),scrDX(xmax-xmin),scrDY(ymax-ymin));
       }
       
       public void clearLine(double x1, double y1, double x2, double y2) {  // erase line
            Color cSave = c;
            b.setColor(getBackground());
            drawLine(x1,y1,x2,y2);
            b.setColor(cSave);
       }
       
       public void drawString(String s, double x, double y) {
              b.drawString(s, scrX(x),scrY(y));
              if (toScreen) repaint();
       }
      
       public void drawString(String s, int x, int y) {  //uses screen coordinates
              b.drawString(s,x,y);
              if (toScreen) repaint();
       }
      
      public void setColor(int red, int green, int blue) {
              c = new Color(red,green,blue);
              b.setColor(c);
      }
      
      public void setColor(String s) {
             if(s == "red") c = Color.red;
             else if(s == "blue") c = Color.blue;
             else if(s == "black") c = Color.black;
             else if(s == "green") c = Color.green;
             else if(s == "yellow") c = Color.yellow;
             else if(s == "white") c = Color.white;
             else if(s == "magenta") c = Color.magenta;
             else if(s == "cyan") c = Color.cyan;
             else if(s == "orange") c = Color.orange;
             else if(s == "pink") c = Color.pink;
             else if(s == "random") c = new Color((int) (Math.random()*255),
                  (int) (Math.random()*255), (int) (Math.random()*255));
             b.setColor(c);
      }

      
      public void drawBuffer() {
            Graphics g = getGraphics();
            g.drawImage(buffer,0,0,this);   // draw image onto screen, useful for animation 
      }

      public void paint(Graphics g) {
         if(getSize().width != width || getSize().height != height) {
            width = getSize().width;
            height = getSize().height;
            setScale();
            buffer = createImage(getSize().width,getSize().height);
            b = buffer.getGraphics();
         }
            g.drawImage(buffer,0,0,this);   // draw image onto screen 
      }
  }

SimFormat

package simphy;

import java.text.DecimalFormat;

public abstract class SimFormat {


 public static String dformat(double x, int d) {
        DecimalFormat df = new DecimalFormat();
        df.setMinimumIntegerDigits(1);
        df.setMaximumFractionDigits(d);
        df.setMinimumFractionDigits(d);
        df.setGroupingUsed(false);
        return df.format(x);
 }


 public static String dformat(double x) {
        return dformat(x,3);
 }

 public static String eformat(double x, int d) {
        if(x == 0)
          return "0";
        if(x < 0) {
          double y = Math.log(-x)/Math.log(10);
          int p = (int) y;
          double dec = Math.pow(10,y-p);
          if(dec <= 1) 
            return "-" + dformat(10*dec,d) + " E" + String.valueOf(p-1);
          else 
             return "-" + dformat(dec,d) + " E" + String.valueOf(p);
        }
        else {
          double y = Math.log(x)/Math.log(10);
          int p = (int) y;
          double dec = Math.pow(10,y-p);
          if(dec <= 1) 
             return dformat(10*dec,d) + " E" + String.valueOf(p-1);
          else 
             return dformat(dec,d) + " E" + String.valueOf(p);
       } 
 }
    
 public static String eformat(double x) {
       return eformat(x,3);
 }
    
    
 public static String aformat(double x, int d, double min, double max) {
       if(Math.abs(x) > max || Math.abs(x) < min) 
          return eformat(x,d);
       else 
          return dformat(x,d);
 }
    
 public static String aformat(double x, double min, double max) {
       return aformat(x,3,min,max);
 }
    
 public static String aformat(double x) {
       return aformat(x,3,0.001,100);
 }
}

Updated 20 May 2000.