书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
目录
3.10 弹力
1、胡克定律
弹簧的弹力可以根据胡克定律计算得到,胡克定律以英国物理学家罗伯特·胡克命名,他在1660年发明了这个公式。
- 弹簧的弹力与弹簧的伸长量成正比。
- 也就是说,弹簧被拉伸的越长,它的弹力(Fspring)也越大;被拉伸的越短,弹力越小
- k是一个常量,它会影响弹力的大小。它的弹性如何?是紧绷的还是松垮的?
- x代表弹簧的形变,也就是当前长度和静止长度的差。静止长度被定义为弹簧在平衡状态下的长度。
请记住,弹力是一个向量,除了大小,我们还应该计算它的方向。
2、弹力的方向
- 如果弹簧被拉伸,当前长度大于静止长度,它就会产生一个指向枢轴点的拉力;
- 如果弹簧被压缩,当前长度小于静止长度,它就会产生一个相反的推力。
- 在公式中,我们用-1表示相反的方向,因此只需将前面计算距离的过程中得到的向量单位化。
在下面的代码中,我们用force变量表示弹力向量。
float k = 0.1; 按照胡克定律计算得到的弹力
PVector force = PVector.sub(bob,anchor);
float currentLength = dir.mag();
float x = restLength - currentLength;
force.normalize(); 弹力的方向(单位向量)
force.mult(-1 k x); 把方向和大小放在一起!
3、钟摆类
如图3-18所示,钟摆类(bob)主要用于管理钟摆的运动;
4、弹簧类
弹簧类用于管理弹簧的枢轴点位置、静止长度和计算作用在钟摆上的弹力。
- 为什么弹簧类的实现方式和Attractor类的实现方式不同?
因为刚开始学习力的建模时,我们喜欢在主draw()函数中实现力的作用,这样做会让程序的意图更清晰,让读者更容易理解力的累加效应。 - 上面的目的达成后,我还是希望采用更简单的做法:
在对象内部封装这部分逻辑。
5、示例
示例代码3-11 弹簧连接
Bob bob;
Spring spring;
void setup() {
size(640,360);
// Create objects at starting position
// Note third argument in Spring constructor is "rest length"
spring = new Spring(width/2,10,100);
bob = new Bob(width/2,100);
}
void draw() {
background(255);
// Apply a gravity force to the bob
PVector gravity = new PVector(0,2);
bob.applyForce(gravity);
// Connect the bob to the spring (this calculates the force)
spring.connect(bob);
// Constrain spring distance between min and max
spring.constrainLength(bob,30,200);
// Update bob
bob.update();
// If it's being dragged
bob.drag(mouseX,mouseY);
// Draw everything
spring.displayLine(bob); // Draw a line between spring and bob
bob.display();
spring.display();
fill(0);
text("click on bob to drag",10,height-5);
}
// For mouse interaction with bob
void mousePressed() {
bob.clicked(mouseX,mouseY);
}
void mouseReleased() {
bob.stopDragging();
}
mover.pde
// Bob class, just like our regular Mover (position, velocity, acceleration, mass)
class Bob {
PVector position;
PVector velocity;
PVector acceleration;
float mass = 24;
// Arbitrary damping to simulate friction / drag
float damping = 0.98;
// For mouse interaction
PVector dragOffset;
boolean dragging = false;
// Constructor
Bob(float x, float y) {
position = new PVector(x,y);
velocity = new PVector();
acceleration = new PVector();
dragOffset = new PVector();
}
// Standard Euler integration
void update() {
velocity.add(acceleration);
velocity.mult(damping);
position.add(velocity);
acceleration.mult(0);
}
// Newton's law: F = M * A
void applyForce(PVector force) {
PVector f = force.get();
f.div(mass);
acceleration.add(f);
}
// Draw the bob
void display() {
stroke(0);
strokeWeight(2);
fill(0,175,0);
if (dragging) {
fill(50);
}
ellipse(position.x,position.y,mass*2,mass*2);
}
// The methods below are for mouse interaction
// This checks to see if we clicked on the mover
void clicked(int mx, int my) {
float d = dist(mx,my,position.x,position.y);
if (d < mass) {
dragging = true;
dragOffset.x = position.x-mx;
dragOffset.y = position.y-my;
}
}
void stopDragging() {
dragging = false;
}
void drag(int mx, int my) {
if (dragging) {
position.x = mx + dragOffset.x;
position.y = my + dragOffset.y;
}
}
}
Spring.pde
class Spring {
PVector anchor; //弹簧的枢轴点位置
float len; //静止长度和相关常量
float k = 0.3;
// Constructor 在构造函数中初始化枢轴点和静止长度
Spring(float x, float y, int l) {
anchor = new PVector(x, y);
len = l;
}
// 计算弹力,实现胡克定律
void connect(Bob b) {
// 获取由枢轴点指向摆锤的向量
PVector force = PVector.sub(b.position, anchor);
// What is distance
float d = force.mag();
// 计算距离和静止长度的差值
float stretch = d - len;
// Calculate force according to Hooke's Law
// F = k * stretch
force.normalize(); //合并大小和方向
force.mult(-1 * k * stretch);
b.applyForce(force); //调用applyForce()函数
}
// Constrain the distance between bob and anchor between min and max
void constrainLength(Bob b, float minlen, float maxlen) {
PVector dir = PVector.sub(b.position, anchor);
float d = dir.mag();
// Is it too short?
if (d < minlen) {
dir.normalize();
dir.mult(minlen);
// Reset position and stop from moving (not realistic physics)
b.position = PVector.add(anchor, dir);
b.velocity.mult(0);
// Is it too long?
}
else if (d > maxlen) {
dir.normalize();
dir.mult(maxlen);
// Reset position and stop from moving (not realistic physics)
b.position = PVector.add(anchor, dir);
b.velocity.mult(0);
}
}
void display() {
stroke(0);
fill(0,175,0);
strokeWeight(2);
rectMode(CENTER);
rect(anchor.x, anchor.y, 10, 10);
}
void displayLine(Bob b) {
strokeWeight(2);
stroke(0);
line(b.position.x, b.position.y, anchor.x, anchor.y);
}
}