import java.awt.*; import java.applet.*; import java.awt.event.*; import java.util.*; public class ACupOfTea extends Applet implements MouseListener,MouseMotionListener,Runnable { int width,height; Cup[] cup=new Cup[5]; Vector drops=new Vector(); Image offscreen; Thread daemon; Point mouse=new Point(); double dt=0.01; double ft=0.1; double spring=200; public void init() { width=getSize().width; height=getSize().height; setBackground(Color.white); addMouseListener(this); addMouseMotionListener(this); offscreen=createImage(width,height); for (int i=0;i0 && dyMath.PI) dtheta-=2*Math.PI; domega=2*(dtheta/ft-omega)/ft; } else domega=-omega/ft; u+=dt*du; v+=dt*dv; omega+=dt*domega; if (volume>0) { du+=Math.tan(domega)*volume/width/2; dv+=g; double a=-cos()*du-sin()*dv; double b=-sin()*du+cos()*dv; flow+=dt*(a+b*(Math.max(left,0)-Math.max(right,0))/bottom)/3 -Math.min(dt*registance*Math.abs(flow),1)*flow; } } public void move(double dt) { x+=dt*u; y+=dt*v; theta+=dt*omega; double wave=bottom>0? flow*(Math.max(left,0)+Math.max(right,0))/bottom:flow; if (right>0 && left<0) { bottom-=dt*flow; right+=dt*wave; left=2*volume/width-right; } else if (right<0 && left>0) { bottom+=dt*flow; left-=dt*wave; right=2*volume/width-left; } else { left-=dt*wave; right+=dt*wave; bottom=width; } } public void correct() { while (theta<-Math.PI) theta+=2*Math.PI; while (theta>Math.PI) theta-=2*Math.PI; if (right>0 && left<0) { bottom+=volume/right-bottom/2; right+=(bottom>0?volume/bottom:0)-right/2; left=2*volume/width-right; } else if (right<0 && left>0) { bottom+=volume/left-bottom/2; left+=(bottom>0?volume/bottom:0)-left/2; right=2*volume/width-left; } else { double correction=volume/width-(left+right)/2; left+=correction; right+=correction; } if (Double.isNaN(left)) left=0; if (Double.isNaN(right)) right=0; if (Double.isNaN(bottom)) bottom=width; if (Double.isNaN(flow)) flow=0; } public Droplet drop() { double volume; double x,y; double u,v; double wave=flow*(Math.max(left,0)+Math.max(right,0))/bottom; if (right>height) { volume=(right-height)*bottom; x=width/2; y=right; u=Math.sqrt((right-height)*g); v=wave; } else if (left>height) { volume=(left-height)*bottom; x=-width/2; y=left; u=-Math.sqrt((left-height)*g); v=-wave; } else return null; if (volume>this.volume) { volume=this.volume; this.volume=0; } else if (volumemax_droplet) volume=max_droplet; this.volume-=volume; } return new Droplet(volume, this.x+cos()*x-sin()*y,this.y-sin()*x-cos()*y, this.u+cos()*u-sin()*v,this.v-sin()*u-cos()*v); } public boolean receive(Droplet drop,double dt,double ft) { double x=cos()*(drop.x-this.x)-sin()*(drop.y-this.y); double y=-sin()*(drop.x-this.x)-cos()*(drop.y-this.y); double u=cos()*drop.u-sin()*drop.v; double v=-sin()*drop.u-cos()*drop.v; double x2=x+ft*u; double y2=y+ft*v; double a=(right-left)/width; double b=(right+left)/2; if ( (x>-width/2 && x0 && (y2-width/2 && x2<-width/2 && y>0 && ywidth/2 && y>0 && y-width/2 && x0) { double bounce=1+Math.random(); drop.u+=bounce*sin()*v; drop.v+=bounce*cos()*v; } if ((x<-width/2 && x2>-width/2 && y>0 && ywidth/2 && x20 && y0) { g.setColor(Color.blue); if (left>=0 && right>=0) drawLine(g,-width/2,left,width/2,right); else if (left<0) drawLine(g,width/2,right,-bottom+width/2,0); else drawLine(g,-width/2,left,bottom-width/2,0); } } private void drawLine(Graphics g, double x0,double y0,double x1,double y1) { x0=Math.max(-width/2,Math.min(x0,width/2)); y0=Math.max(0,Math.min(y0,height)); x1=Math.max(-width/2,Math.min(x1,width/2)); y1=Math.max(0,Math.min(y1,height)); g.drawLine( (int)(x+cos()*x0-sin()*y0), (int)(y-sin()*x0-cos()*y0), (int)(x+cos()*x1-sin()*y1), (int)(y-sin()*x1-cos()*y1)); } public static class Droplet { private double volume; private double x,y; private double u,v; private int r; private double t; public Droplet(double volume, double x,double y,double u,double v) { this.volume=volume; this.x=x; this.y=y; this.u=u; this.v=v; this.t=timeout; r=(int)Math.sqrt(volume/Math.PI); } public boolean consists( double x,double y,double width,double height) { return t>0 && this.x>x && this.y>y && this.x