import java.awt.*; import java.applet.*; import java.awt.event.*; public class TickTockTabby extends Applet implements Runnable,MouseListener,MouseMotionListener { static final double scale = 24; static final int size = 10; static final double dt = 0.01; static final double ft = 0.1; static final double Young = 1000; static final double Poisson = 0.4; static final double lambda = (Young*Poisson)/((1+Poisson)*(1-2*Poisson)); static final double mu = Young/(2*(1+Poisson)); static final double zeta = 20; static final double nu = 10; static final double gravity = 10; private int width,height; private Image image; private Thread thread; private Particle[] particles = new Particle[size+1]; private Beam[] beams = new Beam[size]; protected int cols,rows; private Particle grabbed; private Polygon rotatedTriangle = new Polygon(new int[3],new int[3],3); public void init() { width = getSize().width; height = getSize().height; setBackground(new Color(0.2f,0.9f,0.7f)); addMouseListener(this); addMouseMotionListener(this); } public void start() { cols = (int)(width/scale); rows = (int)(height/scale); for (int i=0;i<=size;i++) { particles[i] = new Particle(cols/2,(rows-size)/2+i); particles[i].u = i; } for (int i=0;icols) p.u = -Math.abs(p.u); if (p.y<0) p.v = Math.abs(p.v); if (p.y>rows) p.v = -Math.abs(p.v); p.omega += dt*p.alpha; p.x += dt*p.u; p.y += dt*p.v; p.theta += dt*p.omega; while (p.theta>+Math.PI) p.theta -= 2*Math.PI; while (p.theta<-Math.PI) p.theta += 2*Math.PI; p.f = 0; p.g = gravity; p.alpha = 0; } for (int i=0;i+Math.PI) ptheta -= 2*Math.PI; while (ptheta<-Math.PI) ptheta += 2*Math.PI; while (qtheta>+Math.PI) qtheta -= 2*Math.PI; while (qtheta<-Math.PI) qtheta += 2*Math.PI; double nx = dx/r; double ny = dy/r; double Fn = 2*(lambda+2*mu)*(r-b.r)/b.r*b.d +2*(zeta+2*nu)*((b.p.u-b.q.u)*nx+(b.p.v-b.q.v)*ny)/b.r*b.d; double Ft = -mu*(ptheta+qtheta)*b.d -nu*(b.p.omega+b.q.omega)/2 +nu*(-(b.p.u-b.q.u)*ny+(b.p.v-b.q.v)*nx)/b.r; double Mn = (lambda+2*mu)*(ptheta-qtheta)/2*b.d*b.d/b.r +(zeta+2*nu)*(b.p.omega-b.q.omega)/2*b.d*b.d*b.d/b.r; double Mt = Ft*r/4; double f = Fn*nx-Ft*ny; double g = Fn*ny+Ft*nx; b.p.f -= f; b.p.g -= g; b.p.alpha -= Mn-Mt; b.q.f += f; b.q.g += g; b.q.alpha += Mn+Mt; } } public void run() { try { double t = 0; while (!Thread.interrupted()) { for (;t=0;i--) { Particle p = particles[i]; og.setColor(i%2==0?Color.lightGray:Color.darkGray); og.fillOval( (int)(scale*(p.x-0.7)), (int)(scale*(p.y-0.7)), (int)(1.4*scale),(int)(1.4*scale)); } og.setColor(Color.darkGray); Particle p0 = particles[0]; drawRotatedLine(og,-0.25,0.3,0.25,0.3,p0); drawRotatedPoint(og,0.35,-0.2,p0); drawRotatedPoint(og,-0.35,-0.2,p0); fillRotatedTriangle(og,0.6,-0.4,0.1,-0.7,0.5,-1,p0); fillRotatedTriangle(og,-0.6,-0.4,-0.1,-0.7,-0.5,-1,p0); drawRotatedLine(og,0.5,0,0.9,0.1,p0); drawRotatedLine(og,0.5,0.2,0.8,0.4,p0); drawRotatedLine(og,-0.5,0,-0.9,0.1,p0); drawRotatedLine(og,-0.5,0.2,-0.8,0.4,p0); og.dispose(); g.drawImage(image,0,0,this); } private void drawRotatedLine( Graphics g,double s1,double t1,double s2,double t2,Particle p) { double x1 = p.x+s1*Math.cos(p.theta)-t1*Math.sin(p.theta); double y1 = p.y+s1*Math.sin(p.theta)+t1*Math.cos(p.theta); double x2 = p.x+s2*Math.cos(p.theta)-t2*Math.sin(p.theta); double y2 = p.y+s2*Math.sin(p.theta)+t2*Math.cos(p.theta); g.drawLine( (int)(scale*x1),(int)(scale*y1), (int)(scale*x2),(int)(scale*y2)); } private void drawRotatedPoint(Graphics g,double s,double t,Particle p) { double x = p.x+s*Math.cos(p.theta)-t*Math.sin(p.theta); double y = p.y+s*Math.sin(p.theta)+t*Math.cos(p.theta); g.fillOval((int)(scale*x-0.5),(int)(scale*y-0.5),1,1); } private void fillRotatedTriangle( Graphics g, double s1,double t1,double s2,double t2,double s3,double t3,Particle p) { double x1 = p.x+s1*Math.cos(p.theta)-t1*Math.sin(p.theta); double y1 = p.y+s1*Math.sin(p.theta)+t1*Math.cos(p.theta); double x2 = p.x+s2*Math.cos(p.theta)-t2*Math.sin(p.theta); double y2 = p.y+s2*Math.sin(p.theta)+t2*Math.cos(p.theta); double x3 = p.x+s3*Math.cos(p.theta)-t3*Math.sin(p.theta); double y3 = p.y+s3*Math.sin(p.theta)+t3*Math.cos(p.theta); rotatedTriangle.xpoints[0] = (int)(scale*x1); rotatedTriangle.ypoints[0] = (int)(scale*y1); rotatedTriangle.xpoints[1] = (int)(scale*x2); rotatedTriangle.ypoints[1] = (int)(scale*y2); rotatedTriangle.xpoints[2] = (int)(scale*x3); rotatedTriangle.ypoints[2] = (int)(scale*y3); g.fillPolygon(rotatedTriangle); } } class Particle { public double x,y,theta; public double u,v,omega; public double f,g,alpha; public Particle(double x,double y) { this.x = x; this.y = y; } } class Beam { public Particle p,q; public double r,d; public double ptheta,qtheta; public Beam(Particle p,Particle q) { this.p = p; this.q = q; double dx = p.x-q.x; double dy = p.y-q.y; r = Math.sqrt(dx*dx+dy*dy); d = 0.5; double theta = Math.atan2(dx,-dy); ptheta = theta-p.theta; qtheta = theta-q.theta; } }