書名:代碼本色:用編程模擬自然系統(tǒng)
作者:Daniel Shiffman
譯者:周晗彬
ISBN:978-7-115-36947-5
目錄
3.9 三角函數(shù)和力:鐘擺
鐘擺由樞軸點、擺臂、擺錘組成
1、鐘擺模型
- 鐘擺模型就是擺錘懸掛在樞軸點上的運動。
- 很顯然,現(xiàn)實世界的鐘擺是建立在三維空間上的,但我們想簡化模型,因此本章的鐘擺模型建立在二維空間上——也就是Processing的動畫窗口中
2、受力分析
圖3-12
- 重力向量被分解成兩個分量,一個分量代表鐘擺上物體受到的力。正弦等于對邊除以斜邊:
我們唯一的疑問就是:如何計算鐘擺的角加速度?只要有了角加速度,我們就可以把運動的一般規(guī)律運用到鐘擺上,最后得到下一時刻鐘擺所在的角度。 - 角速度 = 角速度 + 角加速度
- 角度 = 角度 + 角速度
- 鐘擺的角加速度 = 重力加速度 * sin(θ)
- 角加速度 = 重力 * sin(θ)
3、鐘擺類的實現(xiàn)
鐘擺類需要以下幾個變量:
- 擺臂長度
- 角度
- 角速度
- 角加速度
- update()函數(shù)更新鐘擺的角度
- display()函數(shù)用于繪制鐘擺
4、細節(jié)的思考及理想化、簡化
- 思考以下問題。
鐘擺擺臂的材質(zhì)是什么?一根金屬棒?一根繩子?橡皮筋?
它是如何連接到樞軸點上的?它有多長?它自身的質(zhì)量是多少?
當前是否有風力的作用?
我們還可以繼續(xù)問更多的問題,這些問題都會影響模擬過程。 - 但我們的模擬世界是假想出來的,
在這個假想的世界里,鐘擺的擺臂是一根理想化的桿子,
它從來不會彎曲,
它的質(zhì)量集中在一個無限小的點上。 - 盡管不需要考慮上面的所有問題,但我們還是需要添加更多變量用
于計算角加速度。
為了讓問題盡可能簡單,在鐘擺加速度公式的推導過程中,我們假
定鐘擺擺臂的長度等于1。
實際上,鐘擺擺臂的長度對加速度影響很大:擺臂越長,加速度越小。
為了更精確地模擬鐘擺運動,我們將加速度除以擺臂長度(假設(shè)以r表
示)。 - 最后,現(xiàn)實世界的鐘擺還受摩擦力(樞軸點位置)和空氣阻力的作用。
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、運行結(jié)果
可以拖曳鐘擺到一定角度釋放。
