书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
目录
3.9 三角函数和力:钟摆
钟摆由枢轴点、摆臂、摆锤组成
1、钟摆模型
- 钟摆模型就是摆锤悬挂在枢轴点上的运动。
- 很显然,现实世界的钟摆是建立在三维空间上的,但我们想简化模型,因此本章的钟摆模型建立在二维空间上——也就是Processing的动画窗口中
2、受力分析
- 重力向量被分解成两个分量,一个分量代表钟摆上物体受到的力。正弦等于对边除以斜边:
我们唯一的疑问就是:如何计算钟摆的角加速度?只要有了角加速度,我们就可以把运动的一般规律运用到钟摆上,最后得到下一时刻钟摆所在的角度。 - 角速度 = 角速度 + 角加速度
- 角度 = 角度 + 角速度
- 钟摆的角加速度 = 重力加速度 * sin(θ)
- 角加速度 = 重力 * sin(θ)
3、钟摆类的实现
钟摆类需要以下几个变量:
- 摆臂长度
- 角度
- 角速度
- 角加速度
- update()函数更新钟摆的角度
- display()函数用于绘制钟摆
4、细节的思考及理想化、简化
- 思考以下问题。
钟摆摆臂的材质是什么?一根金属棒?一根绳子?橡皮筋?
它是如何连接到枢轴点上的?它有多长?它自身的质量是多少?
当前是否有风力的作用?
我们还可以继续问更多的问题,这些问题都会影响模拟过程。 - 但我们的模拟世界是假想出来的,
在这个假想的世界里,钟摆的摆臂是一根理想化的杆子,
它从来不会弯曲,
它的质量集中在一个无限小的点上。 - 尽管不需要考虑上面的所有问题,但我们还是需要添加更多变量用
于计算角加速度。
为了让问题尽可能简单,在钟摆加速度公式的推导过程中,我们假
定钟摆摆臂的长度等于1。
实际上,钟摆摆臂的长度对加速度影响很大:摆臂越长,加速度越小。
为了更精确地模拟钟摆运动,我们将加速度除以摆臂长度(假设以r表
示)。 - 最后,现实世界的钟摆还受摩擦力(枢轴点位置)和空气阻力的作用。
5、示例
示例代码3-10 摆动的钟摆
Pendulum p;
void setup() {
size(640,360);
// Make a new Pendulum with an origin position and armlength
p = new Pendulum(new PVector(width/2,0),175);
}
void draw() {
background(255);
p.go();
}
void mousePressed() {
p.clicked(mouseX,mouseY);
}
void mouseReleased() {
p.stopDragging();
}
Pendulum.pde
class Pendulum {
PVector position; // position of pendulum ball
PVector origin; // position of arm origin
float r; // Length of arm
float angle; // Pendulum arm angle
float aVelocity; // Angle velocity
float aAcceleration; // Angle acceleration
float ballr; // Ball radius
float damping; // Arbitary damping amount
boolean dragging = false;
// This constructor could be improved to allow a greater variety of pendulums
Pendulum(PVector origin_, float r_) {
// Fill all variables
origin = origin_.get();
position = new PVector();
r = r_;
angle = PI/4;
aVelocity = 0.0;
aAcceleration = 0.0;
damping = 0.995; // Arbitrary damping
ballr = 48.0; // Arbitrary ball radius
}
void go() {
update();
drag(); //for user interaction
display();
}
// Function to update position
void update() {
// As long as we aren't dragging the pendulum, let it swing!
if (!dragging) {
float gravity = 0.4; // Arbitrary constant
aAcceleration = (-1 * gravity / r) * sin(angle); // Calculate acceleration (see: http://www.myphysicslab.com/pendulum1.html)
aVelocity += aAcceleration; // Increment velocity
aVelocity *= damping; // Arbitrary damping
angle += aVelocity; // Increment angle
}
}
void display() {
position.set(r*sin(angle), r*cos(angle), 0); // Polar to cartesian conversion
position.add(origin); // Make sure the position is relative to the pendulum's origin
stroke(0);
strokeWeight(2);
// Draw the arm
line(origin.x, origin.y, position.x, position.y);
ellipseMode(CENTER);
fill(175);
if (dragging) fill(0);
// Draw the ball
ellipse(position.x, position.y, ballr, ballr);
}
// The methods below are for mouse interaction
// This checks to see if we clicked on the pendulum ball
void clicked(int mx, int my) {
float d = dist(mx, my, position.x, position.y);
if (d < ballr) {
dragging = true;
}
}
// This tells us we are not longer clicking on the ball
void stopDragging() {
if (dragging) {
aVelocity = 0; // No velocity once you let go
dragging = false;
}
}
void drag() {
// If we are draging the ball, we calculate the angle between the
// pendulum origin and mouse position
// we assign that angle to the pendulum
if (dragging) {
PVector diff = PVector.sub(origin, new PVector(mouseX, mouseY)); // Difference between 2 points
angle = atan2(-1*diff.y, diff.x) - radians(90); // Angle relative to vertical axis
}
}
}
6、运行结果
可以拖曳钟摆到一定角度释放。