用.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.Forlock的方式修改合力FdxFdy,可以提高性能(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模拟天体运动的更多相关文章

  1. Unity3D ShaderLab 模拟纹理运动

    Unity3D ShaderLab 模拟纹理运动 这一篇,我们要说到着色器上的uv贴图的滚动效果,这样的场景可以用在河流,瀑布,熔岩等效果.算是创建纹理动画的基础技术之一. 所以 准备一个新的着色器文 ...

  2. OpenGL “太阳、地球和月亮”天体运动动画 例子

    http://oulehui.blog.163.com/blog/static/7961469820119186616743/ OpenGL “太阳.地球和月亮”天体运动动画 例子 2011-10-1 ...

  3. 震惊!OI居然还考天体运动

    看图说话 看这里: 标签: 标签竟然还是模拟,简直活到爆,物理老师狂喜

  4. python+opencv模拟生成运动模糊核

    Mark:https://www.cnblogs.com/wyh1993/p/7118559.html 效果非常的好

  5. 【一统江湖的大前端(8)】matter.js 经典物理

    目录 [一统江湖的大前端(8)]matter.js 经典物理 一.经典力学回顾 二. 仿真的实现原理 2.1 基本动力学模拟 2.2 碰撞模拟 三. 物理引擎matter.js 3.1 <愤怒的 ...

  6. Unity3D ShaderLab 模拟精灵动画

    Unity3D ShaderLab 模拟精灵动画 在上一篇,介绍了通过Shader 模拟纹理运动,那么更深一步讲,我们也可以把帧动画的精灵纹理运动通过shader实现. 虽然大家都是在游戏脚本中做更高 ...

  7. 7款纯CSS3实现的炫酷动画应用

    1.纯CSS3实现人物摇头动画 这次我们要来分享一款超级可爱的纯CSS3人物摇头动画,初始化的时候人物的各个部位是利用CSS3动画效果拼接而成,接下来就是人物听音乐的场景,一边听音乐一边摇着脑袋,十分 ...

  8. 分享12款经典时尚的HTML5应用

    分享伟大,呵呵.今天给大家分享一下收集的12个HTML5小特效. 我整理一下源码,给大家打包一下,我博客园上传文件大小有限,传不了了. 需要的请留下邮箱就行了,觉得好的话,不要忘了点赞哦~ 1.CSS ...

  9. HTML5资源教程

    新款CSS3按钮组合 5组可爱CSS3按钮 Leave a reply 之前我分享过一些时尚的CSS3动画按钮,比如CSS3渲染Checkbox实现3D开关切换按钮.纯CSS3 3D按钮 按钮酷似牛奶 ...

随机推荐

  1. Linux 使用记录

      作为web程序员,该掌握的 linux 命令有哪些,稍微高级点的? - 刘志军的回答 - 知乎  https://www.zhihu.com/question/64063454/answer/21 ...

  2. springboot返回统一接口与统一异常处理

    springboot返回统一接口与统一异常处理 编写人员:yls 编写时间:2019-9-19 0001-springboot返回统一接口与统一异常处理 简介 创建统一的返回格式 Result 封装统 ...

  3. PHP 当Swoole 遇上 ThinkPHP5

    本文假设你已经有了 Linux 操作系统的 PHP 环境,强烈推荐使用 Vagrant 来搭建开发环境 安装 Swoole PECL 拓展可以通过 pecl 命令或者通过源码包编译安装,本文采用 pe ...

  4. 理解Spark SQL(一)—— CLI和ThriftServer

    Spark SQL主要提供了两个工具来访问hive中的数据,即CLI和ThriftServer.前提是需要Spark支持Hive,即编译Spark时需要带上hive和hive-thriftserver ...

  5. 技术人如何利用 github+Jekyll ,搭建一个独立免费的技术博客

    上次有人留言说,技术博客是程序员的标配,但据我所知绝大部分技术同学到现在仍然没有自己的技术博客.原因有很多,有的是懒的写,有的是怕写不好,还有的是一直想憋个大招,幻想做到完美再发出来,结果一直胎死腹中 ...

  6. thinkphp 获取前端传递过来的参数

    thinkphp 获取前端传递过来的参数 use think\facade\Request; // 获取当前请求的name变量 Request::param('name'); // 获取当前请求的所有 ...

  7. nyoj 113-字符串替换 (python replace, try ... except)

    113-字符串替换 内存限制:64MB 时间限制:3000ms 特判: No 通过数:31 提交数:71 难度:2 题目描述: 编写一个程序实现将字符串中的所有"you"替换成&q ...

  8. RALM: 实时 Look-alike 算法在微信看一看中的应用

    嘉宾:刘雨丹 腾讯 高级研究员 整理:Jane Zhang 来源:DataFunTalk 出品:DataFun 注:欢迎关注DataFunTalk同名公众号,收看第一手原创技术文章. 导读:本次分享是 ...

  9. 【NHOI2018】扑克游戏

    [问题描述] 有一种别样“小猫钓鱼”扑克游戏.有 N 张牌,每张牌都有一个花色和点数.游戏的规则:扑克接龙时,若前面有同样花色的牌,你可以将这两张牌连同之间的牌都取走,得到的分值为取走牌点数之和.这里 ...

  10. ubuntu windows mutual remote control

    Win10 remote control Ubuntu18 Part1.ubuntu settings 1.安装所需组件 sudo apt-get update //若没有desktop sharin ...