用.NET模拟天体运动
用.NET模拟天体运动
这将是一篇罕见而偏极客的文章。
我上大学时就见过一些模拟太阳系等天体运动的软件和网站,觉得非常酷炫,比如这个(http://www.astronoo.com/en/articles/positions-of-the-planets.html):
其酷炫之处不仅在于天体运动轨迹能画出美妙的弧线,更重要的是其运动规律完全由万有引力定律产生,不需要对其运动轨迹进行编程。所有天体受其它天体的合力,然后按照其加速度运行。只需一个起始坐标和起始速度,就能坐下来欣赏画面。
我从大学毕业后就一直对这个抱有深厚兴趣,工作第一年时我就用C++
做过一版;后来我负责公司前端工作,又用js
/canvas
又做了一个重制版;由于近期爆发的.NET
“革命”,我近期又用C#
/.NET
再次重制了一版。
需要的数学知识
由于是程序员看数学知识,此处我将使用代码来表示公式。
- 万有引力,该力
F
与两个天体的质量m1
,m2
成正比,如距离r
的平方成反比,用代码表示为:F = m1 * m2 * G / r ^ 2
; - 牛顿第二定律,加速度
a
等于合力F
除以质量m
,用代码表示为:a = F / m
; - 速度
v
与加速度a
以及时间t
的关系,用代码表示为:v = a * t
; - 距离
s
与速度v
以及时间t
的关系,用代码表示为:s = v * t
。
这里面的所有知识都已经在高中物理提过了,但有两点需要注意:
- 所有的力、加速度、速度以及距离都需要分为
x
轴和y
轴两个分量; - 所有的时间
t
实际上是小段时间dt
,程序将循环模拟小段时间累加起来,来模拟天体运动。
核心代码
天体类:
class Star
{
public LinkedList<Vector2> PositionTrack = new LinkedList<SharpDX.Vector2>();
public double Px, Py, Vx, Vy;
public double Mass;
public float Size => (float)Math.Log(Mass) * 2;
public Color Color = Color.Black;
public void Move(double step)
{
Px += Vx * step;
Py += Vy * step;
PositionTrack.AddFirst(new Vector2((float)Px, (float)Py));
if (PositionTrack.Count > 1000)
{
PositionTrack.RemoveLast();
}
}
}
注意,我没指定大小Size
,直接给值为其质量的对数乘2
,另外注意我使用了一个PositionTrack
的链表
来存储其运动轨迹。
万有引力、加速度、速度计算
void Step()
{
foreach (var s1 in Stars)
{
// star velocity
// F = G * m1 * m2 / r^2
// F has a direction:
double Fdx = 0;
double Fdy = 0;
const double Gm1 = 100.0f; // G*s1.m
var ttm = StepDt * StepDt; // t*t/s1.m
foreach (var s2 in Stars)
{
if (s1 == s2) continue;
var rx = s2.Px - s1.Px;
var ry = s2.Py - s1.Py;
var rr = rx * rx + ry * ry;
var r = Math.Sqrt(rr);
var f = Gm1 * s2.Mass / rr;
var fdx = f * rx / r;
var fdy = f * ry / r;
Fdx += fdx;
Fdy += fdy;
}
// Ft = ma -> a = Ft/m
// v = at -> v = Ftt/m
var dvx = Fdx * ttm;
var dvy = Fdy * ttm;
s1.Vx += dvx;
s1.Vy += dvy;
}
foreach (var star in Stars)
{
star.Move(StepDt);
}
}
注意其中有个foreach
循环,它将一一计算每个天体对某天体的力,然后通过累加的方式求出合力,最后依照合力计算加速度和速度。如果使用gmp
等高精度计算库,该循环将存在性能热点,因此可以将这个foreach
改成Parallel.For
加lock
的方式修改合力Fdx
和Fdy
,可以提高性能(C++
的代码就是这样写的)。
绘图代码
public void Draw(DeviceContext ctx)
{
ctx.Clear(Color.DarkGray);
using var solidBrash = new SolidColorBrush(ctx, Color.White);
float allHeight = ctx.Size.Height;
float allWidth = ctx.Size.Width;
float scale = allHeight / 100.0f;
foreach (var star in Stars)
{
using var radialBrush = new RadialGradientBrush(ctx, new RadialGradientBrushProperties
{
Center = Vector2.Zero,
RadiusX = 1.0f,
RadiusY = 1.0f,
}, new SharpDX.Direct2D1.GradientStopCollection(ctx, new[]
{
new GradientStop{ Color = Color.White, Position = 0f},
new GradientStop{ Color = star.Color, Position = 1.0f},
}));
ctx.Transform =
Matrix3x2.Scaling(star.Size) *
Matrix3x2.Translation(((float)star.Px + 50) * scale + (allWidth - allHeight) / 2, ((float)star.Py + 50) * scale);
ctx.FillEllipse(new Ellipse(Vector2.Zero, 1, 1), radialBrush);
ctx.Transform =
Matrix3x2.Translation(allHeight / 2 + (allWidth - allHeight) / 2, allHeight / 2);
foreach (var line in star.PositionTrack.Zip(star.PositionTrack.Skip(1)))
{
ctx.DrawLine(line.First * scale, line.Second * scale, solidBrash, 1.0f);
}
}
ctx.Transform = Matrix3x2.Identity;
}
注意我在绘图代码逻辑中做了一些矩阵变换,我把所有逻辑做成了窗体分辨率无关的,假定屏幕长和宽的较小值为100
,然后左上角坐标为-50, -50
,右下角坐标为50, 50
。
星系模拟
太阳、地球和月亮
这是最容易想到了,地球绕太阳转,月亮绕地球转,创建代码如下:
public static StarSystem CreateSolarEarthMoon()
{
var solar = new Star
{
Px = 0, Py = 0,
Vx = 0.6, Vy = 0,
Mass = 1000,
Color = Color.Red,
};
// Earth
var earth = new Star
{
Px = 0, Py = -41,
Vx = -5, Vy = 0,
Mass = 100,
Color = Color.Blue,
};
// Moon
var moon = new Star
{
Px = 0, Py = -45,
Vx = -10, Vy = 0,
Mass = 10,
};
return new StarSystem(new List<Star> { solar, earth, moon });
}
注意所有数据都没使用真实数字模拟(不然地球绕太阳转一圈需要365
天才能看完
用.NET模拟天体运动的更多相关文章
- Unity3D ShaderLab 模拟纹理运动
Unity3D ShaderLab 模拟纹理运动 这一篇,我们要说到着色器上的uv贴图的滚动效果,这样的场景可以用在河流,瀑布,熔岩等效果.算是创建纹理动画的基础技术之一. 所以 准备一个新的着色器文 ...
- OpenGL “太阳、地球和月亮”天体运动动画 例子
http://oulehui.blog.163.com/blog/static/7961469820119186616743/ OpenGL “太阳.地球和月亮”天体运动动画 例子 2011-10-1 ...
- 震惊!OI居然还考天体运动
看图说话 看这里: 标签: 标签竟然还是模拟,简直活到爆,物理老师狂喜
- python+opencv模拟生成运动模糊核
Mark:https://www.cnblogs.com/wyh1993/p/7118559.html 效果非常的好
- 【一统江湖的大前端(8)】matter.js 经典物理
目录 [一统江湖的大前端(8)]matter.js 经典物理 一.经典力学回顾 二. 仿真的实现原理 2.1 基本动力学模拟 2.2 碰撞模拟 三. 物理引擎matter.js 3.1 <愤怒的 ...
- Unity3D ShaderLab 模拟精灵动画
Unity3D ShaderLab 模拟精灵动画 在上一篇,介绍了通过Shader 模拟纹理运动,那么更深一步讲,我们也可以把帧动画的精灵纹理运动通过shader实现. 虽然大家都是在游戏脚本中做更高 ...
- 7款纯CSS3实现的炫酷动画应用
1.纯CSS3实现人物摇头动画 这次我们要来分享一款超级可爱的纯CSS3人物摇头动画,初始化的时候人物的各个部位是利用CSS3动画效果拼接而成,接下来就是人物听音乐的场景,一边听音乐一边摇着脑袋,十分 ...
- 分享12款经典时尚的HTML5应用
分享伟大,呵呵.今天给大家分享一下收集的12个HTML5小特效. 我整理一下源码,给大家打包一下,我博客园上传文件大小有限,传不了了. 需要的请留下邮箱就行了,觉得好的话,不要忘了点赞哦~ 1.CSS ...
- HTML5资源教程
新款CSS3按钮组合 5组可爱CSS3按钮 Leave a reply 之前我分享过一些时尚的CSS3动画按钮,比如CSS3渲染Checkbox实现3D开关切换按钮.纯CSS3 3D按钮 按钮酷似牛奶 ...
随机推荐
- 微信小程序(mpvue) wx.openSetting 无法调起设置页面
在开发过程有个需要保存图片/视频到设备相册的业务,so easy~ 巴啦啦撸下来了完整功能, wx.saveVideoToPhotosAlbum 会自动调起用户授权,美滋滋~~ btu.... ...
- 一个ip, 两个域名, 两个ssl, 对应多个不同的项目 之 坑
之前配置了好几天, 就想通过tomcat直接配置. 找各种资料, 都说先配置Connector, 在配置Host. 我试了很多次, 都不成功. 原因我也没有找到在哪里. 我的配置参考如下网址: 修改这 ...
- Linux线上与本地的httpd搭建【制作本地yum源】
当前时间 2019-10-24-10:53:12 制作本地yum源 我用的VMware Workstation 系统环境: CentOS 7.5 首先我们先要挂载系统镜像 [root@laopa ~] ...
- [springboot 开发单体web shop] 8. 商品详情&评价展示
上文回顾 上节 我们实现了根据搜索关键词查询商品列表和根据商品分类查询,并且使用到了mybatis-pagehelper插件,讲解了如何使用插件来帮助我们快速实现分页数据查询.本文我们将继续开发商品详 ...
- HTML的标签认识
<!-- html标签 h1~h6 标题标签(只有1~6,依次减小) p 段落标签 span 无意义的行标签 div 无意义的块标签 b 加粗 ...
- 在WebView中加载HTML页面时显示进度对话框的方法
webView.setWebViewClient(new WebViewClient(){ ProgressDialog prDialog; @Overri ...
- Nginx+SpringBoot实现负载均衡
前言 在上一篇中介绍了Nginx的安装,本篇文章主要介绍的是Nginx如何实现负载均衡. 负载均衡介绍 介绍 在介绍Nginx的负载均衡实现之前,先简单的说下负载均衡的分类,主要分为硬件负载均衡和软件 ...
- 2019-11-19:无返回的盲型xxe,使用带外读取数据
文章资料来源于网络,仅供参考,学习使用 复现盲型xxe 实验环境:bwapp,xxe关,注释掉了返回值 准备读取的flag.txt文件为 通过利用服务器外带数据方法步骤 1,攻击机服务器新建两个文件, ...
- java基础总结(1)--深入理解基本数据类型
深入理解java数据类型 java是一种强类型语言,这就意味着必须为每一个声明变量声明一种类型.在java中,一共有8种数据类型,其中4种整型,2种浮点类型,1种字符类型和一种表示真值的boolean ...
- 《浅入浅出》-RocketMQ
你知道的越多,你不知道的越多 点赞再看,养成习惯 本文GitHub https://github.com/JavaFamily 已收录,有一线大厂面试点脑图.个人联系方式和技术交流群,欢迎Star和指 ...