/***************************/
/* Gas Diffusion V2.0 1997 */
/***************************/
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.util.*;
public class gas extends Applet implements Runnable,
MouseListener, ActionListener, ItemListener
{
// image for double-buffering.
Image backBuffer,newbackBuffer;
// graphics context of double-buffering.
Graphics backBufferG,newbackBufferG;
// overload interface Runnable's run()
Thread animator;
Checkbox checkbox;
Button north, B_Radius, B_Hole, B_Step, B_Iter, Restart, Stop, Resume;
TextField T_Radius, T_Hole, T_Step, T_Iter;
Panel south, east;
Color Background_Color=Color.white,Border_Color=Color.black,
fill_in_color = Color.red;
double radius = 2.0; // radius of molecular ball
double velocity = 100;
// in ms, for each frame of animation
int delay = 100;
int time_step =100; // can be set by T_Step, in ms
int iter = 1000; // max number of iteration
int iter_no = 0;
// geometry of the animation box
int Box_Width=500,Box_Height=500,bx,by;
int Hole_D = 30;
double tmp;
int ball_no = 20; // maximum number of balls
int min_ball=0; // which ball is caught buy mouse
Vector vector;
boolean pause = false, ball_ball_col = false;
Ball ball;
public void init()
{
String arg;
int i;
vector = new Vector();
ball = new Ball();
// get parameters from applet tag fields
arg = getParameter("delay");
if (arg != null) delay = Integer.parseInt(arg);
arg = getParameter("Box_Width");
if (arg != null) Box_Width = Integer.parseInt(arg);
arg = getParameter("Box_Height");
if (arg != null) Box_Height = Integer.parseInt(arg);
arg = getParameter("radius");
if (arg != null) radius = (Double.valueOf(arg)).doubleValue();
addMouseListener(this);
enableEvents(AWTEvent.KEY_EVENT_MASK);
setLayout(new BorderLayout());
// South Buttons and TextFields
Panel south = new Panel();
Panel south1 = new Panel();
Panel south2 = new Panel();
Panel south3 = new Panel();
add ("South", south);
//south.setLayout(new FlowLayout());
south.setLayout(new GridLayout(7,1));
south.add( south1);
south.add( south2);
south.add( south3);
south1.setLayout(new FlowLayout());
south1.add(B_Radius = new Button ("radius"));
B_Radius.addActionListener(this);
B_Radius.setActionCommand("radius");
south1.add(T_Radius = new TextField
(Integer.toString((int)radius,10), 4));
south1.add(B_Hole = new Button ("Hole_D"));
B_Hole.addActionListener(this);
B_Hole.setActionCommand("Hole_D");
south1.add(T_Hole = new TextField
(Integer.toString((int)Hole_D,10), 4));
south1.setLayout(new FlowLayout());
south1.add(B_Step = new Button ("time_step"));
B_Step.addActionListener(this);
B_Step.setActionCommand("time_step");
south1.add(T_Step = new TextField
(Integer.toString((int)time_step,10), 4));
south1.add(B_Iter = new Button ("iter_no"));
B_Iter.addActionListener(this);
B_Iter.setActionCommand("iter_no");
south1.add(T_Iter = new TextField
(Integer.toString((int)iter,10), 4));
south2.setLayout(new FlowLayout());
south2.add(Resume = new Button ("Resume"));
Resume.addActionListener(this);
Resume.setActionCommand("Resume");
south2.add(Restart = new Button ("Restart"));
Restart.addActionListener(this);
Restart.setActionCommand("Restart");
south2.add(Stop = new Button ("Stop"));
Stop.addActionListener(this);
Stop.setActionCommand("Stop");
south2.add(checkbox = new Checkbox ("Ball_Ball_Col",null,false));
checkbox.addItemListener(this);
// Center animation box
bx = getBounds().x + (getSize().width-Box_Width)/2;
by = getBounds().y + 5;
arg = getParameter("Background_Color");
Background_Color = ball.colorFromString (arg,Color.white);
setBackground(Background_Color);
setBackground(Color.white);
arg = getParameter("Border_Color");
Border_Color = ball.colorFromString (arg,Color.black);
Border_Color = Color.black;
// Create double buffer with getSize of the animation box
backBuffer = createImage(Box_Width+1,Box_Height+1);
backBufferG = backBuffer.getGraphics();
repaint();
animator = new Thread(this);
}
/*
** "init(), start(), stop(), destroy()"
** lifecycle method of class Applet.
*/
public void start()
{
// Event myevent = new Event(Restart,1004,"Restart");
if (animator.isAlive())
{
if (!pause)
{
animator.resume();
}
}
else
{
// if animator is not allocated
// (not "new") it's wrong to start.
animator.start();
}
}
public void stop()
{
getAppletContext().showStatus("animator thread stoped");
animator.suspend();
}
public void destroy()
{
// nomenclature of Applet mismatches Thread.
animator.stop();
backBufferG.dispose();
backBuffer.flush();
}
public void drawFilledCircle (Graphics g, int x, int y, int radius)
{
int a,b;
for (a=0,b=1; a= ball_no) return;
ball.x = x - bx;
ball.y = y - by;
if (ball.x<=0 || ball.y<=0 || ball.x>=x_middle || ball.y >=Box_Height)
return;
if (ball.x < xmin) ball.x = xmin;
if (ball.x > x_middle - radius) ball.x = x_middle - radius;
if (ball.y < ymin) ball.y = ymin;
if (ball.y > ymax) ball.y = ymax;
ball.radius = radius;
tmp = Math.random() * Math.PI * 2.;
ball.vx = velocity*Math.cos(tmp);
ball.vy = velocity*Math.sin(tmp);
ball.Fillin_Color = fill_in_color;
vector.addElement(ball);
repaint();
return;
}
public void mouseDragged(MouseEvent evt)
{
}
public void mouseReleased(MouseEvent evt)
{
}
public void mouseClicked(MouseEvent evt){}
public void mouseEntered(MouseEvent evt){}
public void mouseExited(MouseEvent evt){}
public void itemStateChanged(ItemEvent e)
{
String itemparam = e.getItem().toString();
// System.out.println(e.toString());
if (itemparam == "Ball_Ball_Col")
{
// "Checkbox" button pushed:
ball_ball_col = checkbox.getState();
}
return;
}
public void actionPerformed (ActionEvent event)
{
Double R,D;
int i;
String command = event.getActionCommand();
if (command == "radius")
{
// " radius" button pushed:
try
{
R = Double.valueOf(T_Radius.getText());
}
catch (NumberFormatException e)
{
getAppletContext().showStatus("Wrong input");
return;
}
radius = R.doubleValue();
repaint();
return;
}
else if (command == "Hole_D")
{
// "Hole_D" button pushed:
try
{
D = Double.valueOf(T_Hole.getText());
}
catch (NumberFormatException e)
{
getAppletContext().showStatus("Wrong input");
return;
}
Hole_D = (int) D.doubleValue();
repaint();
return;
}
else if (command == "time_step")
{
// "time_stept" button pushed:
try
{
D = Double.valueOf(T_Step.getText());
}
catch (NumberFormatException e)
{
getAppletContext().showStatus("Wrong input");
return;
}
time_step = (int) D.doubleValue();
repaint();
return;
}
else if (command == "iter_no")
{
// "iter_no" button pushed:
try
{
D = Double.valueOf(T_Iter.getText());
}
catch (NumberFormatException e)
{
getAppletContext().showStatus("Wrong input");
return;
}
iter = (int) D.doubleValue();
return;
}
else if (command == "Restart")
{
// if the Restart button pressed, start
pause = false;
vector.removeAllElements();
iter_no = 0;
getAppletContext().showStatus("Game Restarted: press Stop to pause");
animator.resume();
}
else if (command == "Resume")
{
// if the Restart button pressed, start
pause = false;
getAppletContext().showStatus("Game Resumeed: press Stop to pause");
animator.resume();
}
else if (command == "Stop")
{
pause = true;
getAppletContext().showStatus("Game Stopped: press Restart to start");
animator.suspend();
}
}
public void run()
{
while (true)
{
try
{
Thread.sleep (delay);
}
catch (InterruptedException e)
{
}
handle_motion();
iter_no ++;
if (iter_no > iter)
{
pause = true;
getAppletContext().showStatus("Game Stopped: press Restart to start");
animator.suspend();
}
}
}
private void handle_motion()
{
// System equation of motion handler:
// if dis between two ball < 2 radius, collision occur
// if collide with wall within "time_step",
// time of collision and Density at collision:
double dis, alpha, shift, xmin, xmax, ymin, ymax, tc, y_old, x_old,vy_c;
double x_middle, y_up_middle, y_down_middle, y_tc;
double vx_oldi, vy_oldi, vx_oldj, vy_oldj;
int i,j;
Ball ball_tmp = new Ball();
boolean left;
xmin = radius;
ymin = radius;
xmax = Box_Width - radius;
ymax = Box_Height - radius;
x_middle = Box_Width/2;
y_up_middle = (Box_Height - Hole_D)/2;
y_down_middle = (Box_Height + Hole_D)/2;
// discrete integration is exact for constant acceleration
for (i=0; i< vector.size(); i++)
{
ball = (Ball) vector.elementAt(i);
ball.x += time_step*(1E-3)*ball.vx;
ball.y += time_step*(1E-3)*ball.vy;
vector.setElementAt(ball,i);
}
if(ball_ball_col)
{
// see if balls collide
for (i=0; i< vector.size(); i++)
{
ball = (Ball) vector.elementAt(i);
//the two-ball collision
for (j=i+1; j< vector.size(); j++)
{
ball_tmp = (Ball) vector.elementAt(j);
dis = (ball.x-ball_tmp.x)*(ball.x-ball_tmp.x)+
(ball.y-ball_tmp.y)*(ball.y-ball_tmp.y);
if (dis <= (ball.radius+ball_tmp.radius)*
(ball.radius+ball_tmp.radius))
{
dis = Math.sqrt(dis)+0.001;
alpha = (Math.abs(ball.y-ball_tmp.y)<0.1)?
100000000.:(ball.x-ball_tmp.x)/(ball.y-ball_tmp.y);
vx_oldi = ball.vx;
vy_oldi = ball.vy;
vx_oldj = ball_tmp.vx;
vy_oldj = ball_tmp.vy;
ball.vx = (alpha*alpha*vx_oldj-vy_oldi*alpha
+vy_oldj*alpha+vx_oldi)/(alpha*alpha+1);
ball.vy = (-alpha*alpha*vy_oldi+vx_oldi*alpha
-vx_oldj*alpha-vy_oldj)/(alpha*alpha+1);
ball_tmp.vx = (alpha*alpha*vx_oldi+vy_oldi*alpha
-vy_oldj*alpha+vx_oldj)/(alpha*alpha+1);
ball_tmp.vy = (alpha*alpha*vy_oldj+vx_oldi*alpha
-vx_oldj*alpha+vy_oldi)/(alpha*alpha+1);
shift = ball.radius+ball_tmp.radius-dis;
ball.x += (ball.x-ball_tmp.x) / dis * shift / 2.;
ball_tmp.x -= (ball.x-ball_tmp.x) / dis * shift / 2.;
ball.y += (ball.y-ball_tmp.y) / dis * shift / 2.;
ball_tmp.y -= (ball.y-ball_tmp.y) / dis * shift / 2.;
repaint();
// integrate again
ball.x += time_step*(1E-3)*ball.vx;
ball.y += time_step*(1E-3)*ball.vy;
ball_tmp.x += time_step*(1E-3)*ball_tmp.vx;
ball_tmp.y += time_step*(1E-3)* ball_tmp.vy; ;
}
}
}
}
for (i=0; i< vector.size(); i++)
{
ball = (Ball) vector.elementAt(i);
x_old = ball.x - time_step*(1E-3)*ball.vx;
if (ball.x <= xmin)
{
ball.x = 2*xmin - ball.x;
ball.vx = - ball.vx;
}
if (ball.x >= xmax)
{
ball.x = 2*xmax - ball.x;
ball.vx = - ball.vx;
}
if (ball.y <= ymin)
{
ball.y = 2*ymin - ball.y;
ball.vy = - ball.vy;
}
if (ball.y >= ymax)
{
ball.y = 2*ymax - ball.y;
ball.vy = - ball.vy;
}
if ( (ball.y<=y_up_middle) || (ball.y>=y_down_middle))
{
if ((ball.vx > 0) &&
(ball.x >= x_middle - radius) &&
(ball.x <= x_middle + radius))
{
ball.x = 2*(x_middle - radius) - ball.x;
ball.vx = - ball.vx;
}
if ((ball.vx < 0) &&
(ball.x <= x_middle + radius) &&
(ball.x >= x_middle - radius))
{
ball.x = 2* (x_middle + radius) - ball.x;
ball.vx = - ball.vx;
}
}
else
{
if ((ball.y - y_up_middle)*(ball.y - y_up_middle) +
(ball.x - x_middle)*(ball.x - x_middle)
<= radius * radius)
{
ball.x = x_old;
ball.vx = - ball.vx;
}
if ((ball.y - y_down_middle)*(ball.y - y_down_middle) +
(ball.x - x_middle)*(ball.x - x_middle)
<= radius * radius)
{
ball.x = x_old;
ball.vx = - ball.vx;
}
}
vector.setElementAt(ball,i);
}
repaint();
return;
}
public String getAppletInfo()
{
return "Ju Li 1997 ";
}
String[][] parameterInfo = {
{"delay","int", "time inteval of animation in millisecond"},
{"Box_Width","int","width of the animation box"},
{"Box_Height","int","height of the animation box"},
{"radius", "double", "radius of the ball, in screen pixels"},
{"Background_Color", "String",
"RGB format like FF0000, or red,green,blue,white,black,gray"},
{"Border_Color", "String",
"RGB format like FF0000, or red,green,blue,white,black,gray"},
};
public String[][] getParameterInfo() {
return parameterInfo;
}
}