三角函數(shù)和力:鐘擺

書名:代碼本色:用編程模擬自然系統(tǒng)
作者:Daniel Shiffman
譯者:周晗彬
ISBN:978-7-115-36947-5
目錄

3.9 三角函數(shù)和力:鐘擺

鐘擺由樞軸點、擺臂、擺錘組成

1、鐘擺模型

  • 鐘擺模型就是擺錘懸掛在樞軸點上的運動。
  • 很顯然,現(xiàn)實世界的鐘擺是建立在三維空間上的,但我們想簡化模型,因此本章的鐘擺模型建立在二維空間上——也就是Processing的動畫窗口中

2、受力分析

圖3-12
  • 重力向量被分解成兩個分量,一個分量代表鐘擺上物體受到的力。正弦等于對邊除以斜邊:
    F_p=F_g*sin\theta
    我們唯一的疑問就是:如何計算鐘擺的角加速度?只要有了角加速度,我們就可以把運動的一般規(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é)果

可以拖曳鐘擺到一定角度釋放。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容