我正在尝试编写一个Java程序来支持离格扩散有限聚合模拟。模拟移动粒子的基本代码已就位,直到所述粒子撞击静态中心粒子。此时,我尝试确保移动粒子恰好接触(相切)静态粒子。然而,由于未知的原因,它有时会失败(8 个粒子中的前 2 个相交,其他 6 个都很好)。
这是代码:
boolean killed, collide;
double xp, yp, dx, dy, theta, xpp, ypp, length;
int xc = 200;
int yc = 200;
int killRadius = 200;
int releaseRadius = 150;
int partRadius = 14;
int partDiam = 2 * partRadius;
drawCircle(xc, yc, killRadius); // kill
drawCircle(xc, yc, releaseRadius); // release
drawCircle(xc, yc, partRadius); // center particle
//while (true) {
killed = false;
collide = false;
theta = Math.random() * Math.PI * 2;
xp = xc + releaseRadius * Math.cos(theta);
yp = yc + releaseRadius * Math.sin(theta);
while (true) {
theta = Math.random() * Math.PI * 2;
length = partDiam;
xpp = xp;
ypp = yp;
xp = xp + length * Math.cos(theta);
yp = yp + length * Math.sin(theta);
//drawCircle((int) xp, (int) yp, partRadius);
// Should it be killed ? (maybe could use a box to fasten
// computations...
// Would switching the test for kill w test for collision
// improve perf ?
dx = xp - xc;
dy = yp - yc;
if ((dx * dx) + (dy * dy) > killRadius * killRadius) {
killed = true;
break;
}
// Does it collide with center? replace by any particle...
dx = xp - xc;
dy = yp - yc;
if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) {
collide = true;
break;
}
}
// Probably something is wrong here...
if (collide) {
// no absolute value because particles move at most by diameter
double depthPenetration = partDiam
- Math.sqrt((dx * dx) + (dy * dy));
dx = xpp - xp;
dy = ypp - yp;
// shorten distance travelled by penetration length to ensure
// that
// particle is tangeant
length = Math.sqrt((dx * dx) + (dy * dy)) - depthPenetration;
xp = xpp + length * Math.cos(theta);
yp = ypp + length * Math.sin(theta);
drawCircle((int) xp, (int) yp, partRadius);
}
//}
当然,在询问之前我检查了很多引用资料,但找不到代码有任何问题...我们将不胜感激。
最佳答案
我对你的代码进行了一些简单的重构,只是为了了解它的作用,发生了什么。
首先让我提一件事:这是意大利面条怪物的复兴,不是吗?你喜欢全局变量吗?长而强大的让我们现在就在这里做这件事?
如果你尽可能晚地引入变量,代码的读者就不需要向上搜索这个变量之前是什么——如果某些东西被覆盖,例如,如果有一个不好的重用。
如果你的变量没有改变:将它们定为最终的。这简化了对它们的推理。 final int KillRadius = 200;
表示获取类型信息以及值,希望在第一次使用之前不久,并且它永远不会改变。仅在源代码中进行配置。可能不是一个太复杂的候选人。与 double dx 相比 - 未初始化,因为它是在循环内初始化的,
static void foo () {
final int xc = 200;
final int yc = 200;
final int killRadius = 200;
final int releaseRadius = 150;
final int partRadius = 14;
drawCircle (xc, yc, killRadius); // kill
drawCircle (xc, yc, releaseRadius); // release
drawCircle (xc, yc, partRadius); // center particle
//while (true) {
boolean killed = false;
boolean collide = false;
double theta = Math.random() * Math.PI * 2;
double xp = xc + releaseRadius * Math.cos (theta);
double yp = yc + releaseRadius * Math.sin (theta);
double dx, dy, xpp, ypp;
while (true) {
theta = Math.random () * Math.PI * 2;
final int partDiam = 2 * partRadius;
final double length = partDiam;
xpp = xp;
ypp = yp;
xp += length * Math.cos (theta);
yp += length * Math.sin (theta);
dx = xp - xc;
dy = yp - yc;
if ((dx * dx) + (dy * dy) > killRadius * killRadius) {
killed = true;
break;
}
// Why again assign dx = xp -xc? Did any of these values change meanwhile?
// I don't think so.
// dx = xp - xc;
// dy = yp - yc;
if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) {
collide = true;
break;
}
}
if (collide) {
// no absolute value because particles move at most by diameter
double depthPenetration = partDiam - Math.sqrt((dx * dx) + (dy * dy));
dx = xpp - xp;
dy = ypp - yp;
// shorten distance travelled by penetration length to ensure
// that
// particle is tangeant
final double length = Math.sqrt((dx * dx) + (dy * dy)) - depthPenetration;
xp = xpp + length * Math.cos (theta);
yp = ypp + length * Math.sin (theta);
drawCircle ((int) xp, (int) yp, partRadius);
}
如果你这样构造你的代码,你不仅会看到像 xc 这样的某个值是 200 并且从未改变 - 在 while 循环的头部,你会看到 theta 没有在循环内声明,因此要么稍后在循环外使用它,要么在循环内按顺序修改它。执行 x += 4;你不能在循环传递中初始化 x 。
在最后,你有两个相似的 block :
dx = xp - xc;
dy = yp - yc;
if ((dx * dx) + (dy * dy) (OP) a OP b) {
c = true;
break;
}
但是 xp、xc 和 dx 同时不会改变 - y 等价物也不会改变。这是一个错误,还是为什么要再次分配它们?
然后,您可以通过这种方式摆脱无尽的 while:由于两个条件都会终止 while,因此将条件放入 while - 测试中,并且仅当第一个 block 未输入时才调用第二个 block (不重复赋值) - 这样做的关键字是 else
:
while (!killed && !collide) {
// ...
dx = xp - xc;
dy = yp - yc;
if ((dx * dx) + (dy * dy) > killRadius * killRadius) {
killed = true;
}
else if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) {
collide = true;
}
}
它对查找错误有什么帮助?没那么多。如果两个圆圈放错了,其余的都很好,那么截图就可以了,而值会导致坏圆圈,而值则可以。
关于java - 圆与圆的碰撞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11022156/