001package algs61; // section 6.1
002import stdlib.*;
003import java.awt.Color;
004/* ***********************************************************************
005 *  Compilation:  javac Particle.java
006 *
007 *  A particle moving in the unit box with a given position, velocity,
008 *  radius, and mass.
009 *
010 *************************************************************************/
011
012public class Particle {
013        private static final double INFINITY = Double.POSITIVE_INFINITY;
014
015        private double rx, ry;    // position
016        private double vx, vy;    // velocity
017        private final double radius;    // radius
018        private final double mass;      // mass
019        private final Color color;      // color
020        private int count;        // number of collisions so far
021
022
023        // create a new particle with given parameters
024        public Particle(double rx, double ry, double vx, double vy, double radius, double mass, Color color) {
025                this.vx = vx;
026                this.vy = vy;
027                this.rx = rx;
028                this.ry = ry;
029                this.radius = radius;
030                this.mass   = mass;
031                this.color  = color;
032        }
033
034        // create a random particle in the unit box (overlaps not checked)
035        public Particle() {
036                rx     = Math.random();
037                ry     = Math.random();
038                vx     = 0.01 * (Math.random() - 0.5);
039                vy     = 0.01 * (Math.random() - 0.5);
040                radius = 0.01;
041                mass   = 0.5;
042                //color  = Color.BLACK;
043                color  = new Color (StdRandom.uniform(200), StdRandom.uniform(200), StdRandom.uniform(200));
044        }
045
046        // updates position
047        public void move(double dt) {
048                rx += vx * dt;
049                ry += vy * dt;
050        }
051
052        // draw the particle
053        public void draw() {
054                StdDraw.setPenColor(color);
055                StdDraw.filledCircle(rx, ry, radius);
056        }
057
058        // return the number of collisions involving this particle
059        public int count() { return count; }
060
061
062        // how long into future until collision between this particle a and b?
063        public double timeToHit(Particle b) {
064                Particle a = this;
065                if (a == b) return INFINITY;
066                double dx  = b.rx - a.rx;
067                double dy  = b.ry - a.ry;
068                double dvx = b.vx - a.vx;
069                double dvy = b.vy - a.vy;
070                double dvdr = dx*dvx + dy*dvy;
071                if (dvdr > 0) return INFINITY;
072                double dvdv = dvx*dvx + dvy*dvy;
073                double drdr = dx*dx + dy*dy;
074                double sigma = a.radius + b.radius;
075                double d = (dvdr*dvdr) - dvdv * (drdr - sigma*sigma);
076                // if (drdr < sigma*sigma) StdOut.println("overlapping particles");
077                if (d < 0) return INFINITY;
078                return -(dvdr + Math.sqrt(d)) / dvdv;
079        }
080
081        // how long into future until this particle collides with a vertical wall?
082        public double timeToHitVerticalWall() {
083                if      (vx > 0) return (1.0 - rx - radius) / vx;
084                else if (vx < 0) return (radius - rx) / vx;
085                else             return INFINITY;
086        }
087
088        // how long into future until this particle collides with a horizontal wall?
089        public double timeToHitHorizontalWall() {
090                if      (vy > 0) return (1.0 - ry - radius) / vy;
091                else if (vy < 0) return (radius - ry) / vy;
092                else             return INFINITY;
093        }
094
095        // update velocities upon collision between this particle and that particle
096        public void bounceOff(Particle that) {
097                double dx  = that.rx - this.rx;
098                double dy  = that.ry - this.ry;
099                double dvx = that.vx - this.vx;
100                double dvy = that.vy - this.vy;
101                double dvdr = dx*dvx + dy*dvy;             // dv dot dr
102                double dist = this.radius + that.radius;   // distance between particle centers at collison
103
104                // normal force F, and in x and y directions
105                double F = 2 * this.mass * that.mass * dvdr / ((this.mass + that.mass) * dist);
106                double fx = F * dx / dist;
107                double fy = F * dy / dist;
108
109                // update velocities according to normal force
110                this.vx += fx / this.mass;
111                this.vy += fy / this.mass;
112                that.vx -= fx / that.mass;
113                that.vy -= fy / that.mass;
114
115                // update collision counts
116                this.count++;
117                that.count++;
118        }
119
120        // update velocity of this particle upon collision with a vertical wall
121        public void bounceOffVerticalWall() {
122                vx = -vx;
123                count++;
124        }
125
126        // update velocity of this particle upon collision with a horizontal wall
127        public void bounceOffHorizontalWall() {
128                vy = -vy;
129                count++;
130        }
131
132        // return kinetic energy associated with this particle
133        public double kineticEnergy() { return 0.5 * mass * (vx*vx + vy*vy); }
134}