书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
目录
2.8 空气和流体阻力
5、Mover对象如何与流体对象交互?
我们想达到这样的效果:
- 运动者穿过流体对象时会受到阻力的作用。
用Processing实现起来是这样的(假设我们用索引i遍历整个Mover对象数组):
if (movers[i].isInside(liquid)) {
movers[i].drag(liquid); 如果Mover对象位于流体内部,流体阻力将作用在物体上
}
从这段代码可以看出,我们需要在Mover类中加入两个额外的函数:
- isInside()函数
用于判断Mover对象是否在流体对象内部, - drag()函数
计算并将流体阻力作用在Mover对象上。
6、isInside()函数的实现
- isInside()函数的实现很简单,我们只需要加一个条件判断语句,判断Mover对象的位置是否在流体的矩形区域内部。
boolean isInside(Liquid l) {
if (location.x>l.x && location.x<l.x+l.w && location.y>l.y && location.y<l.y+l.h) {
return true;
}
else {
return false;
}
}
7、drag()函数
drag()函数就稍显复杂,但前面我们已经实现过类似的逻辑,它只是流体阻力公式的实现:阻力的大小等于阻力系数乘以Mover对象速度的平方,方向与Mover对象的速度方向相反。
// 流体阻力公式的实现
void drag(Liquid l) {
float speed = velocity.mag();
float dragMagnitude = l.c * speed * speed; // 力的大小
PVector drag = velocity.get();
drag.mult(-1);
drag.normalize(); // 力的方向:与速度相反
drag.mult(dragMagnitude); // 最终确定力:大小和方向
applyForce(drag); // 应用力
}
8、示例代码2-5
示例代码2-5 流体阻力
Mover[] movers = new Mover[9];
// Liquid
Liquid liquid;
void setup() {
size(640, 360);
reset();
// Create liquid object
liquid = new Liquid(0, height/2, width, height/2, 0.1);
}
void draw() {
background(255);
// Draw water
liquid.display();
for (int i = 0; i < movers.length; i++) {
// Is the Mover in the liquid?
if (liquid.contains(movers[i])) {
// Calculate drag force
PVector dragForce = liquid.drag(movers[i]);
// Apply drag force to Mover
movers[i].applyForce(dragForce);
}
// Gravity is scaled by mass here!
PVector gravity = new PVector(0, 0.1*movers[i].mass);
// Apply gravity
movers[i].applyForce(gravity);
// Update and display
movers[i].update();
movers[i].display();
movers[i].checkEdges();
}
fill(0);
text("click mouse to reset", 10, 30);
}
void mousePressed() {
reset();
}
// Restart all the Mover objects randomly
void reset() {
for (int i = 0; i < movers.length; i++) {
movers[i] = new Mover(random(0.5, 3), 40+i*70, 0);
}
}
Liquid.pde
class Liquid {
// Liquid is a rectangle
float x, y, w, h;
// Coefficient of drag
float c;
Liquid(float x_, float y_, float w_, float h_, float c_) {
x = x_;
y = y_;
w = w_;
h = h_;
c = c_;
}
// Is the Mover in the Liquid?
boolean contains(Mover m) {
PVector l = m.position;
return l.x > x && l.x < x + w && l.y > y && l.y < y + h;
}
// Calculate drag force
PVector drag(Mover m) {
// Magnitude is coefficient * speed squared
float speed = m.velocity.mag();
float dragMagnitude = c * speed * speed;
// Direction is inverse of velocity
PVector dragForce = m.velocity.get();
dragForce.mult(-1);
// Scale according to magnitude
// dragForce.setMag(dragMagnitude);
dragForce.normalize();
dragForce.mult(dragMagnitude);
return dragForce;
}
void display() {
noStroke();
fill(50);
rect(x, y, w, h);
}
}
Mover.pde(略)
运行结果
- 运行这段代码,你会发现它模拟的是物体掉入水中的效果。物体穿过窗口底部的灰色区域(代表流体)时,会减速。你还会发现物体越小,速度减小地越快。
- 回想牛顿第二运动定律, ,加速度等于力除以质量。在同一个力的作用下,物体的质量越大,加速度就越小。
- 在本例中,阻力产生的反向加速度有减速的效果。因此物体的质量越小,减速越快。