C++模擬2D牛頓力學(xué)效果的示例代碼
簡介
如何用計(jì)算機(jī)來模擬真實(shí)世界呢?計(jì)算機(jī)最大的功能是計(jì)算,而物理學(xué)的種種公式就把現(xiàn)實(shí)世界中的物理規(guī)律以數(shù)學(xué)的語言描繪了出來,從而使我們可以通過計(jì)算大致模擬現(xiàn)實(shí)世界的物體運(yùn)動(dòng)。因此不難想到把物理學(xué)定律(這里用的是牛頓力學(xué))用計(jì)算機(jī)語言描述出來,模擬現(xiàn)實(shí)世界。這個(gè)項(xiàng)目就用C++實(shí)現(xiàn)了此功能,為了方便,目前實(shí)現(xiàn)的是二維宇宙。
項(xiàng)目完成后,只要輸入各項(xiàng)參數(shù),我們就可以用它模擬現(xiàn)實(shí)中的運(yùn)動(dòng)了。下面是用該項(xiàng)目模擬某飛船圍繞某恒星運(yùn)動(dòng)的過程(注意,運(yùn)動(dòng)軌跡并不是預(yù)設(shè)的動(dòng)畫,而是通過計(jì)算得出的)。

代碼
完整代碼如下:
namespace NewtonianPhysics
{
using Scalar = long double;//標(biāo)量
const Scalar G = 6.67259e-11l;//萬有引力常數(shù)
namespace _2D
{
class Vector//矢量
{
public:
Scalar x;
Scalar y;
Vector() :x(0.l), y(0.l) {}
Vector(Scalar inX, Scalar inY) :x(inX), y(inY) {}
friend Vector operator+(const Vector& a, const Vector& b)
{
return Vector(a.x + b.x, a.y + b.y);
}
friend Vector operator-(const Vector& a, const Vector& b)
{
return Vector(a.x - b.x, a.y - b.y);
}
friend Vector operator*(const Vector& vec, Scalar n)
{
return Vector(vec.x * n, vec.y * n);
}
friend Vector operator*(Scalar n, const Vector& vec)
{
return Vector(vec.x * n, vec.y * n);
}
Vector& operator*=(Scalar n)
{
x *= n;
y *= n;
return *this;
}
Vector& operator+=(const Vector& right)
{
x += right.x;
y += right.y;
return *this;
}
Vector& operator-=(const Vector& right)
{
x -= right.x;
y -= right.y;
return *this;
}
Scalar LengthSq() const
{
return (x * x + y * y);
}
Scalar Length() const
{
return (std::sqrt(LengthSq()));
}
void Normalize()
{
float length = Length();
x /= length;
y /= length;
}
static Vector Normalize(const Vector& vec)
{
Vector temp = vec;
temp.Normalize();
return temp;
}
};
class MassPoint
{
public:
Scalar m;//質(zhì)量/kg
Vector location;//當(dāng)前位置
Vector v;//速度/(m/s)
Vector f;//受到的合力/(N)
MassPoint(Scalar mass, Vector _location = { 0,0 }, Vector velocity = { 0,0 })
:m(mass), location(_location), v(velocity) {}
void Update(Scalar deltaTime)
{
//由F=ma得出加速度并更新速度
v += f * (1 / m) * deltaTime;
//由速度得出位移并更新坐標(biāo)
location += v * deltaTime;
}
};
}
}標(biāo)量和矢量
首先,我們定義了標(biāo)量和矢量的類型。標(biāo)量就是只有大小的量,如時(shí)間、質(zhì)量等,而矢量是既有大小又有方向的量,如速度、加速度。標(biāo)量用內(nèi)置的long double類型即可。
矢量就是數(shù)學(xué)中的向量,在這里我們用Vector類來表示。根據(jù)數(shù)學(xué)定理,任何一個(gè)矢量都可以用平面直角坐標(biāo)系中的一個(gè)坐標(biāo)來表示。在Vector類里面,我們用兩個(gè)標(biāo)量來表示橫坐標(biāo)和縱坐標(biāo),并且定義了矢量的加法、減法、與實(shí)數(shù)的乘法。Length函數(shù)的作用是求矢量的長度,而LengthSq則是求矢量長度的平方。因?yàn)長ength函數(shù)需要開方,速度比較慢,所以能用LengthSq就盡量用LengthSq。而Normalize函數(shù)的作用則是將矢量變成方向相同、長度為1的單位矢量。
增量時(shí)間
根據(jù)主流物理學(xué)理論,時(shí)間是連續(xù)的,然而,通過計(jì)算機(jī)模擬現(xiàn)實(shí)世界時(shí),我們只能“一幀一幀”地計(jì)算。例如,如果我們每一幀代表0.1s,當(dāng)前物體速度為10m/s,我們只能默認(rèn)在這0.1s內(nèi)物體的速度保持10m/s不變,盡管實(shí)際上速度可能變化了。這有點(diǎn)類似于微分,然而微分可以引入無窮小量,而計(jì)算機(jī)計(jì)算每一幀的時(shí)間不可能是無窮小,所以計(jì)算出來和實(shí)際結(jié)果一定有誤差。并且,每幀代表的時(shí)間越短,誤差越小。
在上面的例子中,0.1s就叫做增量時(shí)間(Δt)。
質(zhì)點(diǎn)
牛頓力學(xué)的核心就是將物體抽象成質(zhì)點(diǎn)(有質(zhì)量無大小的點(diǎn))進(jìn)行研究。這里的MassPoint類就表示質(zhì)點(diǎn)。在MassPoint類的成員變量中,m表示質(zhì)量,v表示當(dāng)前的速度,f表示受到的合力,location是當(dāng)前的坐標(biāo)。
Update函數(shù)根據(jù)物理定律對質(zhì)點(diǎn)的狀態(tài)進(jìn)行更新,它的參數(shù)就是增量時(shí)間。在這個(gè)函數(shù)中,我們先通過牛頓第二定律求出加速度,然后乘以增量時(shí)間得出速度,再乘以時(shí)間便得出了位移。
這樣,我們便實(shí)現(xiàn)了牛頓力學(xué)的基本功能。
實(shí)例
下面是簡介中飛船圍繞恒星運(yùn)動(dòng)的代碼示例(繪圖用了easyx):
using namespace NewtonianPhysics;
void Print(const _2D::MassPoint& p)
{
setfillcolor(YELLOW);
setlinecolor(RED);
setlinestyle(PS_SOLID, 1);
auto x = (p.location.x + 2e7) * 800 / 4e7, y = (2e7 - p.location.y) * 800 / 4e7;
fillcircle(x, y, 5);
}
int main()
{
initgraph(800, 800);
_2D::MassPoint a(5e30l, { 0,0 }), b(1e4, { 1e7,0 }, { 0,5e6 });
while (1)
{
cleardevice();
Print(a);
Print(b);
Sleep(100);
//F=GMm/r2
b.f = _2D::Vector::Normalize(a.location - b.location) * (G * a.m * b.m / (a.location - b.location).LengthSq()); a.Update(0.05);
b.Update(0.1);
}
closegraph();
return 0;
}該代碼中,恒星的質(zhì)量為5×1030kg,且位于(0,0)靜止不動(dòng);飛船的質(zhì)量為1×104kg,初始位于(1×107,0),并且具有向上5×106m/s的初速度。通過萬有引力公式實(shí)時(shí)計(jì)算出恒星對飛船的引力,并調(diào)用Update函數(shù)進(jìn)行更新。這樣便實(shí)現(xiàn)了模擬運(yùn)動(dòng)。當(dāng)然,大家也可以調(diào)節(jié)這些數(shù)據(jù),或者加入更多的元素,實(shí)現(xiàn)更加復(fù)雜的運(yùn)動(dòng)過程(例如三體運(yùn)動(dòng))。
到此這篇關(guān)于C++模擬2D牛頓力學(xué)效果的示例代碼的文章就介紹到這了,更多相關(guān)C++牛頓力學(xué)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c++實(shí)現(xiàn)逐行讀取配置文件寫入內(nèi)存的示例
這篇文章主要介紹了c++實(shí)現(xiàn)逐行讀取配置文件寫入內(nèi)存的示例,需要的朋友可以參考下2014-05-05
關(guān)于單片機(jī)按鍵問題性能提升總結(jié)
今天小編就為大家分享一篇關(guān)于關(guān)于單片機(jī)按鍵問題性能提升總結(jié),小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12
C++標(biāo)準(zhǔn)庫中的Stack(堆棧)和Queue(隊(duì)列)詳解
在C++標(biāo)準(zhǔn)模板庫(STL)中,stack和queue是兩種非常重要的容器適配器,這篇文章主要介紹了C++標(biāo)準(zhǔn)庫中Stack(堆棧)和Queue(隊(duì)列)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-10-10
C++實(shí)操之內(nèi)聯(lián)成員函數(shù)介紹
大家好,本篇文章主要講的是C++實(shí)操之內(nèi)聯(lián)成員函數(shù)介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12
MATLAB全網(wǎng)最全的colormap的使用教程詳解
眾所周知,MATLAB中的colormap只有少得可憐的幾種,有很多應(yīng)用在很特殊的圖形中的colormap幾乎都沒有,而每次寫代碼都要去找顏色的圖屬實(shí)太麻煩。所以本文將包全部集成了進(jìn)來,終于有了這套包含200個(gè)colormap的工具函數(shù),希望對大家有所幫助2023-02-02

