import java.applet.*;
import java.awt.*;
public class Tripolar extends Applet implements Runnable
{
Thread kicker_ = null;
boolean timeToDie_;
private int speed_;
Image offScrImage_;
Graphics offScrGC_;
int screenWidth_, screenHeight_;
double centerX_, centerY_;
double scale_;
boolean down_ = false;
Point mousePt_;
double probeX_ = 1e10, probeY_ = 1e10;
double damping_ = 0.97;
double gravity_ = 0.005;
double magnetism_ = 0.1;
double height_ = 0.1;
double mass_ = 1.0;
double dtSim_ = 0.01;
double [] magnetX_, magnetY_;
public void run() {
while (kicker_ != null) {
updateAnimation();
repaint();
try {
if (!timeToDie_) {
Thread.sleep(speed_);
} else {
if (kicker_ != null) {
kicker_.stop();
kicker_ = null;
break;
}
}
} catch (InterruptedException e) {
break;
}
}
}
public void start() {
requestFocus();
if (kicker_ == null) {
kicker_ = new Thread(this);
kicker_.start();
}
}
public void stop() {
timeToDie_ = true;
}
public void init()
{
speed_ = 33;
screenWidth_ = size().width;
screenHeight_ = size().height;
centerX_ = (double) screenWidth_ / 2.0;
centerY_ = (double) screenHeight_ / 2.0;
scale_ = Math.min(centerX_, centerY_);
offScrImage_ = createImage(screenWidth_, screenHeight_);
offScrGC_ = offScrImage_.getGraphics();
setBackground(Color.white);
setForeground(Color.black);
mousePt_ = new Point();
magnetX_ = new double [3];
magnetY_ = new double [3];
setMagnets(0.5);
timeToDie_ = false;
}
void setMagnets(double r) {
magnetX_[0] = r * Math.cos(Math.PI/2);
magnetY_[0] = r * Math.sin(Math.PI/2);
magnetX_[1] = r * Math.cos(Math.PI/2 + (2*Math.PI) / 3);
magnetY_[1] = r * Math.sin(Math.PI/2 + (2*Math.PI) / 3);
magnetX_[2] = r * Math.cos(Math.PI/2 - (2*Math.PI) / 3);
magnetY_[2] = r * Math.sin(Math.PI/2 - (2*Math.PI) / 3);
}
void updatePaths(double x, double y, Graphics g) {
double vX=0, vY=0; // velocity
double fX,fY;
double r, over_rsq, over_rcube;
double dx, dy;
double filtVel = 1;
double lastX, lastY;
int iter = 0;
g.setColor(Color.black);
while (filtVel > 0.1 && iter < 10000) {
iter++;
fX=0;
fY=0; // zero forces
/v2/img/enterproject.gif
r = x*x + y*y;
if (r < 0.00001)
r= 0.00001;
over_rsq = 1.0 / r;
fX -= (x * gravity_) * over_rsq;
fY -= (y * gravity_) * over_rsq;
for (int m = 0; m < 3; m++) {
dx = magnetX_[m] - x;
dy = magnetY_[m] - y;
r = Math.sqrt(dx*dx + dy*dy + height_*height_);
if (r < 0.00001)
r = 0.00001;
over_rcube = 1.0 / (r*r*r);
fX += magnetism_ * dx * over_rcube;
fY += magnetism_ * dy * over_rcube;
}
fX -= vX*damping_;
fY -= vY*damping_;
vX += dtSim_ * fX / mass_;
vY += dtSim_ * fY / mass_;
filtVel = 0.99 * filtVel + 0.1 * Math.max(Math.abs(vX), Math.abs(vY));
lastX = x;
lastY = y;
x += vX;
y += vY;
drawNormalizedLine(lastX, lastY, x, y, g);
}
}
void drawNormalizedLine(double x1, double y1, double x2, double y2, Graphics g) {
g.drawLine((int) Math.round(x1 * scale_ + centerX_),
(int) Math.round(y1 * scale_ + centerY_),
(int) Math.round(x2 * scale_ + centerX_),
(int) Math.round(y2 * scale_ + centerY_));
}
public void update(Graphics g) {
paint(g);
}
void updateAnimation() {
if (!down_) return;
if (probeX_ == 1e10) {
probeX_ = mousePt_.x;
probeY_ = mousePt_.y;
}
double dx = mousePt_.x - probeX_;
double dy = mousePt_.y - probeY_;
double distSq = dx*dx + dy*dy;
if (distSq > 1) {
probeX_ += dx/2;
probeY_ += dy/2;
} else {
probeX_ += dx * 0.01;
probeY_ += dy * 0.01;
}
}
public void paint(Graphics g)
{
offScrGC_ = offScrImage_.getGraphics();
offScrGC_.setColor(Color.white);
offScrGC_.fillRect(0, 0, screenWidth_, screenHeight_);
if (probeX_ != 1e10) {
updatePaths((probeX_ - centerX_) / scale_,
(probeY_ - centerY_) / scale_, offScrGC_);
}
g.drawImage(offScrImage_, 0, 0, this);
}
public boolean mouseDown(Event evt, int x, int y) {
down_ = true;
mousePt_.setLocation(x, y);
return true;
}
public boolean mouseUp(Event evt, int x, int y) {
down_ = false;
return true;
}
public boolean mouseDrag(Event evt, int x, int y) {
if (down_) {
mousePt_.setLocation(x, y);
}
return true;
}
public boolean mouseEnter(Event evt, int x, int y) {
requestFocus();
return true;
}
}
Code with comments