▶ 书中第六章部分程序,包括在加上自己补充的代码,粒子碰撞系统及用到的粒子类

● 粒子系统

 package package01;

 import java.awt.Color;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.MinPQ;
import edu.princeton.cs.algs4.Particle; public class class01
{
private static final double HZ = 0.5; // 每个时间步长内重画的次数
private MinPQ<Event> pq; // 优先队列
private double t = 0.0; // 计时器
private Particle[] particles; // 粒子数据列表 private static class Event implements Comparable<Event> // 碰撞事件类
{
private final double time; // 预计事件发生时间
private final Particle a, b; // 事件中的粒子
private final int countA, countB; // 粒子在加入事件中时的已碰撞的次数 public Event(double inputT, Particle inputA, Particle inputB) // 输入当前时间和两个粒子,计算碰撞事件
{
time = inputT;
a = inputA;
b = inputB;
countA = (a != null) ? a.count() : -1;
countB = (b != null) ? b.count() : -1;
} public int compareTo(Event that) // 比较两个事件哪个先发生
{
return Double.compare(this.time, that.time);
} public boolean isValid() // 判断事件是否有效
{
return (a == null || a.count() == countA) && (b == null || b.count() == countB);// 原代码简化版
//if (a != null && a.count() != countA || b != null && b.count() != countB) // 原代码,只要有粒子当前实际碰撞数与事件中记录的 count 不等,说明事件失效
// return false;
//return true;
}
} public class01(Particle[] inputParticle)
{
particles = inputParticle.clone(); // 输入列表的深拷贝
} private void predict(Particle a, double limit) // 更新优先队列中关于粒子 a 的事件
{
if (a == null)
return;
for (int i = 0; i < particles.length; i++) // 预测 a 与各粒子碰撞的时间,只要时间小于阈值就将其放入优先队列
{
double targetTime = t + a.timeToHit(particles[i]);
if (targetTime <= limit)
pq.insert(new Event(targetTime, a, particles[i]));
}
double targetTimeX = t + a.timeToHitVerticalWall(), targetTimeY = t + a.timeToHitHorizontalWall();
if (targetTimeX <= limit)
pq.insert(new Event(targetTimeX, a, null));
if (targetTimeY <= limit)
pq.insert(new Event(targetTimeY, null, a));
} private void redraw(double limit) // 重画所有粒子位置
{
StdDraw.clear();
for (int i = 0; i < particles.length; i++)
particles[i].draw();
StdDraw.show();
StdDraw.pause(20); // 暂停 20 ms
if (t < limit) // 还没到时限,加入重画事件
pq.insert(new Event(t + 1.0 / HZ, null, null));
} public void simulate(double limit) // 模拟器
{
pq = new MinPQ<Event>();
for (int i = 0; i < particles.length; i++) // 首次计算所有粒子之间的碰撞
predict(particles[i], limit);
for (pq.insert(new Event(0, null, null)); !pq.isEmpty();) // 多加入一个重画所有粒子位置的事件
{
Event e = pq.delMin(); // 取出发生时间最近的时间,判断是否有效
if (!e.isValid())
continue;
Particle a = e.a, b = e.b;
for (int i = 0; i < particles.length; i++) // 更新所有粒子位置
particles[i].move(e.time - t);
t = e.time; // 更新当前时间 if (a != null && b != null) // 粒子 - 粒子碰撞
a.bounceOff(b);
else if (a != null && b == null) // 粒子撞竖直墙壁
a.bounceOffVerticalWall();
else if (a == null && b != null)
b.bounceOffHorizontalWall(); // 粒子撞水平墙壁
else if (a == null && b == null)
redraw(limit); // 仅重画所有粒子位置
predict(a, limit); // 重新预测 a 与 b相关的事件
predict(b, limit);
}
} public static void main(String[] args)
{
StdDraw.setCanvasSize(600, 600); // 窗口大小
StdDraw.enableDoubleBuffering(); // double 缓冲区
Particle[] particles; // 粒子列表 if (args.length == 1) // 输入一个参数,生成相应个数的个粒子
{
int n = Integer.parseInt(args[0]);
particles = new Particle[n];
for (int i = 0; i < n; i++)
particles[i] = new Particle();
}
else // 否则按标准输入流依次输入每个粒子的信息
{
int n = StdIn.readInt();
particles = new Particle[n];
for (int i = 0; i < n; i++)
{
double rx = StdIn.readDouble();
double ry = StdIn.readDouble();
double vx = StdIn.readDouble();
double vy = StdIn.readDouble();
double radius = StdIn.readDouble();
double mass = StdIn.readDouble();
int r = StdIn.readInt();
int g = StdIn.readInt();
int b = StdIn.readInt();
Color color = new Color(r, g, b);
particles[i] = new Particle(rx, ry, vx, vy, radius, mass, color);
}
}
class01 system = new class01(particles); // 模拟和输出
system.simulate(10000); // 模拟事件 10s
}
}

● 粒子类

package package01;

import java.awt.Color;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdRandom; public class class01
{
private static final double INFINITY = Double.POSITIVE_INFINITY; private double rx, ry;
private double vx, vy;
private int count; // 粒子已经碰撞的次数
private final double radius;
private final double mass;
private final Color color; public class01(double inputRx, double inputRy, double inputVx, double inputVy, double inputRadius, double inputMass, Color inputColor)
{
rx = inputRx;
ry = inputRy;
vx = inputVx;
vy = inputVy;
radius = inputRadius;
mass = inputMass;
color = inputColor;
} public class01()
{
rx = StdRandom.uniform(0.0, 1.0);
ry = StdRandom.uniform(0.0, 1.0);
vx = StdRandom.uniform(-0.005, 0.005);
vy = StdRandom.uniform(-0.005, 0.005);
radius = 0.02;
mass = 0.5;
color = Color.BLACK;
} public void move(double dt)
{
rx += vx * dt;
ry += vy * dt;
} public void draw() // 绘制粒子
{
StdDraw.setPenColor(color);
StdDraw.filledCircle(rx, ry, radius);
} public int count()
{
return count;
} public double timeToHit(class01 that)
{
if (this == that)
return INFINITY;
double dx = that.rx - rx, dy = that.ry - ry, dvx = that.vx - vx, dvy = that.vy - vy;
double dvdr = dx * dvx + dy * dvy;
if (dvdr > 0) // Δx 与 Δv 同号,不会撞
return INFINITY;
double dvdv = dvx * dvx + dvy * dvy;
if (dvdv == 0) // 速度完全相等,不会撞
return INFINITY;
double drdr = dx * dx + dy * dy;
double dist = radius + that.radius;
double d = (dvdr*dvdr) - dvdv * (drdr - dist * dist);
return (d > 0) ? -(dvdr + Math.sqrt(d)) / dvdv : INFINITY;
} public double timeToHitVerticalWall()
{
return (vx > 0) ? (1.0 - rx - radius) / vx : ((vx < 0) ? (radius - rx) / vx : INFINITY);
} public double timeToHitHorizontalWall()
{
return (vy > 0) ? (1.0 - ry - radius) / vy : ((vy < 0) ? (radius - ry) / vy : INFINITY);
} public void bounceOff(class01 that)
{
double dx = that.rx - rx, dy = that.ry - ry;
double dvx = that.vx - vx, dvy = that.vy - vy;
double dvdr = dx * dvx + dy * dvy;
double dist = radius + that.radius;
double magnitude = 2 * mass * that.mass * dvdr / ((mass + that.mass) * dist);
double fx = magnitude * dx / dist, fy = magnitude * dy / dist;
vx += fx / mass;
vy += fy / mass;
that.vx -= fx / that.mass;
that.vy -= fy / that.mass;
count++;
that.count++;
} public void bounceOffVerticalWall()
{
vx = -vx;
count++;
} public void bounceOffHorizontalWall()
{
vy = -vy;
count++;
} public double kineticEnergy()
{
return 0.5 * mass * (vx*vx + vy * vy);
}
}

《算法》第六章部分程序 part 1的更多相关文章

  1. 《算法》第六章部分程序 part 7

    ▶ 书中第六章部分程序,加上自己补充的代码,包括全局最小切分 Stoer-Wagner 算法,最小权值二分图匹配 ● 全局最小切分 Stoer-Wagner 算法 package package01; ...

  2. 《算法》第六章部分程序 part 6

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,包括二分图最大匹配(最小顶点覆盖)的交替路径算法和 HopcroftKarp 算法 ● 二分图最大匹配(最小顶点覆盖)的交替路径算法 package ...

  3. 《算法》第六章部分程序 part 5

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,网络最大流 Ford - Fulkerson 算法,以及用到的流量边类和剩余流量网络类 ● 网络最大流 Ford - Fulkerson 算法 pac ...

  4. 《算法》第六章部分程序 part 8

    ▶ 书中第六章部分程序,加上自己补充的代码,包括单纯形法求解线性规划问题 ● 单纯形法求解线性规划问题 // 表上作业法,I 为单位阵,y 为对偶变量,z 为目标函数值 // n m 1 // ┌── ...

  5. 《算法》第六章部分程序 part 4

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,利用后缀树查找最长重复子串.查找最大重复子串并输出其上下文(Key word in context,KWIC).求两字符串的最长公共子串 ● 利用后缀 ...

  6. 《算法》第六章部分程序 part 3

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,后缀树的两种实现 ● 后缀树实现一 package package01; import java.util.Arrays; import edu.pr ...

  7. 《算法》第六章部分程序 part 2

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,B-树 ● B-树 package package01; import edu.princeton.cs.algs4.StdOut; public c ...

  8. 《算法》第一章部分程序 part 1

    ▶ 书中第一章部分程序,加上自己补充的代码,包括若干种二分搜索,寻找图上连通分量数的两种算法 ● 代码,二分搜索 package package01; import java.util.Arrays; ...

  9. 《算法》第二章部分程序 part 5

    ▶ 书中第二章部分程序,加上自己补充的代码,包括利用优先队列进行多路归并和堆排序 ● 利用优先队列进行多路归并 package package01; import edu.princeton.cs.a ...

随机推荐

  1. PPT资源

    PPT模板下载:www.1ppt.com/moban/ 行业PPT模板:www.1ppt.com/hangye/ 节日PPT模板:www.1ppt.com/jieri/ PPT素材下载:www.1pp ...

  2. input输入框type=number时的一个缺陷

    本来是在vue里发现获取不到 input[ type="number"]的值,就是输入两个小数点的数值,比如1.1.1,以为是vue的错误,然而不是,vue只做了数字处理 不明白为 ...

  3. android 退出程序解决内存释放so的问题

    做Android程序的时候发现一个问题,由于用到了so库,当应用程序退出了,但是手机变得很卡,点击"设置"查看应用程序,界面显示着可以点击"强制关闭". 由于这 ...

  4. TweenMax 参考

    http://bbs.9ria.com/thread-214959-1-1.html TweenMax 可能是很多人都用的,包括我 但 是最近发现大量的运用就总会产生这样或那样的"怪事&qu ...

  5. vc++获取网页源码之使用import+接口方式

    1.使用IWinHttpRequest获取网页源码 首先要创建基于对话框的mfc应用程序 2.import+接口方式 首先导入winhttp.dll,使用IWinHttpRequest接口 #impo ...

  6. 【ZZ】详解哈希表的查找

    详解哈希表的查找 https://mp.weixin.qq.com/s/j2j9gS62L-mmOH4p89OTKQ 详解哈希表的查找 2018-03-01 算法与数据结构 来自:静默虚空 http: ...

  7. 廖雪峰Java3异常处理-1错误处理-4自定义异常

    JDK已有的异常: RuntimeException * NullPointerException * IndexOutOfBoundsException * SecurityException * ...

  8. OpenVZ管理

    查找内存超过5%,CPU超过10% CPU=${:-} MEM=${:-} for CTID in `vzlist|sed '1d'|awk '{print $1}'` { echo "== ...

  9. sqlite之多线程总结

    12.android 多线程数据库读写分析与优化 11.多线程操作Sqlite? ==== 11.android 多线程数据库读写分析与优化 最新需要给软件做数据库读写方面的优化,之前无论读写,都是用 ...

  10. servlet简单的小例子

    去我云盘下载: https://pan.baidu.com/s/1E2yoZ2Nmk2FE2XjuPOCvjA 访问方式:http://localhost:8080/testServlet/index ...