《代碼本色:用編程模擬自然系統(tǒng)》習(xí)作——第3章:振蕩

前言

近日拜讀了Daniel Shiffman先生的著作——《代碼本色:用編程模擬自然系統(tǒng)》陕壹,決定做一組習(xí)作拼卵,來對書中提到的隨機行為及牛頓運動學(xué)進行理解,并對一些實例進行拓展學(xué)習(xí)袱讹,從而提升自己相關(guān)方面的知識水平和實踐能力闪湾。

《代碼本色》第3章概述

在第3章中,作者向我們介紹了三角函數(shù)尊搬。三角函數(shù)會給我們帶來很多新工具叁鉴。本章我們會學(xué)習(xí)角、角速度以及角加速度佛寿,期間還會涉及正弦函數(shù)和余弦函數(shù)幌墓,它們可以用來制作平滑的波形曲線。有了這些知識,我們就能計算更復(fù)雜的力克锣,而這些力往往都涉及角度,比如鐘擺的擺動和盒子從斜坡滑下時所受的力腔长。作者通過一些實例深入淺出地講解了這些力袭祟,并對這些力進行了分析和實踐。

在這一章中捞附,我印象比較深的點是對簡諧運動的模擬巾乳,此外,還有對鐘擺鸟召、彈簧的模擬胆绊。下面,我將介紹我根據(jù)本章內(nèi)容而創(chuàng)作的Processing編程習(xí)作欧募。

習(xí)作

成品

可以拉拽綠色點压状,每兩個點之間都有一個彈簧效果的力支撐。此外跟继,在其他地方點擊鼠標還可以添加新的點种冬。

創(chuàng)作過程

本次創(chuàng)作的關(guān)鍵在于——如何實現(xiàn)彈簧的效果。對此舔糖,書上花了很大篇幅進行介紹娱两。
首先介紹下彈簧的彈力。彈簧的彈力可以根據(jù)胡克定律計算得到金吗,胡克定律以英國物理學(xué)家羅伯特·胡克命名十兢,他在1660年發(fā)明了這個公式。胡克最初是用拉丁文描述這個公式的——“Ut tensio,sic vis”, 這句話的意思是“力如伸長(那樣變化)”摇庙。我們可以這么理解它:彈簧的彈力與彈簧的伸長量成正比旱物。

彈簧圖解1

換個說法,就是我們大家都熟悉的公式:F=-kx跟匆。這里的k就是彈性系數(shù)异袄,是一個常數(shù)。而x是當(dāng)前長度與靜止長度的差值玛臂。


彈簧圖解2

接下來烤蜕,我開始編寫Spring類(彈簧類)。
首先定義了這三個變量:

  PVector anchor; // 起始位置
  float len;// 靜止長度 
  float k = 0.05;//彈性系數(shù)

然后迹冤,在update()函數(shù)里計算彈力:

  // 計算彈力
  void update() {
    PVector force = PVector.sub(a.position, b.position);//矢量指向從a點到b點
    float d = force.mag();//計算向量長度
    float stretch = d - len;//形變長度
    force.normalize();
    force.mult(-1 * k * stretch);  //F=-kx
    a.applyForce(force);
    force.mult(-1);//牛頓第三定律
    b.applyForce(force);
  }

代碼中有詳細的注釋讽营,就不一一解釋了。
此外值得一提的是泡徙,在Circle類中添加了這樣一個變量:

  //削減系數(shù)橱鹏,模擬摩擦力
  float damping = 0.9;

這個變量的作用是為了模擬摩擦力和空氣阻力的效果,如果沒有這個變量,或者這個變量為1莉兰,那么這個運動將不會停止挑围,這不符合我們對現(xiàn)實生活中運動的認知。在Circle類的update函數(shù)中糖荒,我們將速度向量乘上這個系數(shù):

  void update() { 
...
    velocity.mult(damping);
...
  }

在主程序中杉辙,我定義了兩個ArrayList,分別用來存儲Circle類變量和Spring類變量:

ArrayList<Circle> circles=new ArrayList<Circle>();
ArrayList<Spring> springs=new ArrayList<Spring>();

然后在setup函數(shù)里編寫了如下代碼:

  Circle Circle1 = new Circle(width/2, height/2);
  Circle Circle2 = new Circle(width/2+50, height/2+50);
  circles.add(Circle1);
  circles.add(Circle2);
  Spring Spring = new Spring(circles.get(0), circles.get(1),200);
  springs.add(Spring);

簡單來說就是兩個Circle連接了一個彈簧捶朵,很好懂蜘矢,這就是面向?qū)ο缶幊趟枷氲膬?yōu)點。隨后再進行一些力的應(yīng)用综看,添加了鼠標拖拽事件品腹,就可以跑了,我們看看效果:


兩個球一個彈簧

其實一開始的效果不是那么理想红碑,然后我對一些參數(shù)進行了調(diào)整舞吭,比如彈性系數(shù)k,削減系數(shù)damping 等句喷,最后達成了很“Q彈”的效果镣典。

然后我覺得兩個球一根彈簧過于單調(diào)了,于是做了多個球唾琼,以及每個球都會與除自己之外的所有球連接一根彈簧兄春。這樣一來就會產(chǎn)生一個很神奇的效果,不管怎么拖拽锡溯,最終很可能會回到一個穩(wěn)定的狀態(tài)赶舆,比如五個的情況:

GIF3.gif

看起來就像一個魔法陣一樣,如果用圖論的知識來說祭饭,這是一個完全圖芜茵。
最后,我添加了鼠標點擊增加點的效果倡蝙,這個和之前第0章做的相似:

void mouseClicked()
{
   Circle newCircle = new Circle(mouseX, mouseY);
  for(int i=0;i<circles.size();i++)
  {
    Spring newSpring = new Spring(newCircle,circles.get(i),200);
    springs.add(newSpring);
  }
  circles.add(newCircle);
}

以及添加了漸變軌跡的效果:

  fill(255,255,255,50);
  rect(0,0,width,height);

最終效果如下:


成品

最后附上所有代碼九串。
Circle類:


class Circle { 
  PVector position;
  PVector velocity;
  PVector acceleration;
  float mass = 5;
  
  //削減系數(shù),模擬摩擦力
  float damping = 0.9;
  
  PVector dragOffset;//拉動的距離向量
  boolean dragging = false;  // 鼠標是否按下

  Circle(float x, float y) {
    position = new PVector(x,y);
    velocity = new PVector();
    acceleration = new PVector();
    dragOffset = new PVector();
  } 


  void update() { 
    velocity.add(acceleration);
    velocity.mult(damping);
    position.add(velocity);
    acceleration.mult(0);
  }

  void applyForce(PVector force) {
    PVector f = force.get();//牛頓第二定律F=ma
    f.div(mass);
    acceleration.add(f);
  }


  void display() { 
    stroke(0);
    strokeWeight(2);
    fill(#98FFCC);
    if (dragging) {
      fill(#FF9898);
    }
    ellipse(position.x,position.y,mass*5,mass*5);
  } 


  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類:


class Spring { 
  PVector anchor; // 起始位置
  float len;// 靜止長度 
  float k = 0.05;//彈性系數(shù)
  
  Circle a;
  Circle b;

  Spring(Circle a_, Circle b_, int l) {
    a = a_;
    b = b_;
    len = l;
  } 

  // 計算彈力
  void update() {
    PVector force = PVector.sub(a.position, b.position);//矢量指向從a點到b點
    float d = force.mag();//計算向量長度
    float stretch = d - len;//形變長度
    force.normalize();
    force.mult(-1 * k * stretch);  //F=-kx
    a.applyForce(force);
    force.mult(-1);//牛頓第三定律
    b.applyForce(force);
  }


  void display() {
    strokeWeight(2);
    stroke(0);
    line(a.position.x, a.position.y, b.position.x, b.position.y);
  }
}

主程序類:

//Circle[] circle = new Circle[5];
//Spring[] springs = new Spring[20];
ArrayList<Circle> circles=new ArrayList<Circle>();
ArrayList<Spring> springs=new ArrayList<Spring>();

void setup() {
  size(600, 600);

  for (int i = 0; i < 5; i++) {
    Circle newCircle = new Circle(width/2+i*100-200, height/2+i*100-200);
    circles.add(newCircle);
  }
  for (int i = 0; i < circles.size(); i++) {
     for (int j = 0; j< circles.size(); j++) {
        if(i!=j) {
          Spring newSpring = new Spring(circles.get(i), circles.get(j),200);
          springs.add(newSpring);
       }  
   }
  }
  //Circle Circle1 = new Circle(width/2, height/2);
  //Circle Circle2 = new Circle(width/2+50, height/2+50);
  //circles.add(Circle1);
  //circles.add(Circle2);
  //Spring Spring = new Spring(circles.get(0), circles.get(1),200);
  //springs.add(Spring);
}

void draw() {
  fill(255,255,255,50);
  rect(0,0,width,height);
  for (Spring s : springs) {
    s.update();
    s.display();
  }


  for (Circle b : circles) {
    b.update();
    b.display();
    b.drag(mouseX, mouseY);
  }
  
 
}
void mouseClicked()
{
   Circle newCircle = new Circle(mouseX, mouseY);
  for(int i=0;i<circles.size();i++)
  {
    Spring newSpring = new Spring(newCircle,circles.get(i),200);
    springs.add(newSpring);
  }
  circles.add(newCircle);
}


void mousePressed() {
  for (Circle b : circles) {
    b.clicked(mouseX, mouseY);
  }
}

void mouseReleased() {
  for (Circle b : circles) {
    b.stopDragging();
  }
}

總結(jié)

本文介紹了《代碼本色:用編程模擬自然系統(tǒng)》第3章的主要內(nèi)容寺鸥,并在示例的基礎(chǔ)上進行了拓展性的創(chuàng)作猪钮,創(chuàng)作了彈簧的模型并進行了拓展。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胆建,一起剝皮案震驚了整個濱河市烤低,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌笆载,老刑警劉巖扑馁,帶你破解...
    沈念sama閱讀 223,207評論 6 521
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涯呻,死亡現(xiàn)場離奇詭異,居然都是意外死亡腻要,警方通過查閱死者的電腦和手機复罐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,455評論 3 400
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雄家,“玉大人市栗,你說我怎么就攤上這事】榷蹋” “怎么了?”我有些...
    開封第一講書人閱讀 170,031評論 0 366
  • 文/不壞的土叔 我叫張陵蛛淋,是天一觀的道長咙好。 經(jīng)常有香客問我,道長褐荷,這世上最難降的妖魔是什么勾效? 我笑而不...
    開封第一講書人閱讀 60,334評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮叛甫,結(jié)果婚禮上层宫,老公的妹妹穿的比我還像新娘。我一直安慰自己其监,他們只是感情好萌腿,可當(dāng)我...
    茶點故事閱讀 69,322評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著抖苦,像睡著了一般毁菱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锌历,一...
    開封第一講書人閱讀 52,895評論 1 314
  • 那天贮庞,我揣著相機與錄音,去河邊找鬼究西。 笑死窗慎,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卤材。 我是一名探鬼主播遮斥,決...
    沈念sama閱讀 41,300評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼商膊!你這毒婦竟也來了伏伐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,264評論 0 277
  • 序言:老撾萬榮一對情侶失蹤晕拆,失蹤者是張志新(化名)和其女友劉穎藐翎,沒想到半個月后材蹬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,784評論 1 321
  • 正文 獨居荒郊野嶺守林人離奇死亡吝镣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,870評論 3 343
  • 正文 我和宋清朗相戀三年堤器,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片末贾。...
    茶點故事閱讀 40,989評論 1 354
  • 序言:一個原本活蹦亂跳的男人離奇死亡闸溃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拱撵,到底是詐尸還是另有隱情辉川,我是刑警寧澤,帶...
    沈念sama閱讀 36,649評論 5 351
  • 正文 年R本政府宣布拴测,位于F島的核電站乓旗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏集索。R本人自食惡果不足惜屿愚,卻給世界環(huán)境...
    茶點故事閱讀 42,331評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望务荆。 院中可真熱鬧妆距,春花似錦、人聲如沸函匕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,814評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盅惜。三九已至吸耿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間酷窥,已是汗流浹背咽安。 一陣腳步聲響...
    開封第一講書人閱讀 33,940評論 1 275
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蓬推,地道東北人妆棒。 一個月前我還...
    沈念sama閱讀 49,452評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像沸伏,于是被迫代替她去往敵國和親糕珊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,995評論 2 361