/***************************/ /* 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; } }