提交 6eb5abae 编写于 作者: 三月三net's avatar 三月三net

太阳系三体模拟器

上级 77d1b8e6
......@@ -22,7 +22,8 @@ class Body(metaclass=ABCMeta):
def __init__(self, name, mass, init_position, init_velocity,
density=5e3, color=(125 / 255, 125 / 255, 125 / 255),
texture=None, size_scale=1.0, distance_scale=1.0,
rotation_speed=None, parent=None):
rotation_speed=None, parent=None, ignore_mass=False,
is_fixed_star=False):
"""
天体类
:param name: 天体名称
......@@ -35,13 +36,16 @@ class Body(metaclass=ABCMeta):
:param size_scale: 尺寸缩放
:param distance_scale: 距离缩放
:param rotation_speed: 自旋速度(度/小时)
:param parent: 天体的父对象
:param ignore_mass: 是否忽略质量(如果为True,则不计算引力)
:param is_fixed_star: 是否为恒星
"""
self.__his_pos = []
self.__his_vel = []
self.__his_acc = []
self.__his_reserved_num = 200
# 是否忽略质量(如果为True,则不计算引力)
self.ignore_mass = False
self.ignore_mass = ignore_mass
if name is None:
name = getattr(self.__class__, '__name__')
......@@ -75,6 +79,7 @@ class Body(metaclass=ABCMeta):
# 是否显示
self.appeared = True
self.parent = parent
self.__is_fixed_star = is_fixed_star
@property
def init_position(self):
......@@ -126,7 +131,11 @@ class Body(metaclass=ABCMeta):
是否为恒星(太阳为 True)
:return:
"""
return False
return self.__is_fixed_star
@is_fixed_star.setter
def is_fixed_star(self, value):
self.__is_fixed_star = value
@property
def position(self):
......@@ -340,20 +349,24 @@ class Body(metaclass=ABCMeta):
:return:
"""
bodies = []
with open(json_file, "r") as read_content:
params = {}
with open(json_file, "r", encoding='utf-8') as read_content:
json_data = json.load(read_content)
for body_data in json_data["bodies"]:
# print(body_data)
body = Body(**body_data)
bodies.append(body)
if "params" in json_data:
params = json_data["params"]
# print(body.position_au())
return bodies
return bodies, params
if __name__ == '__main__':
# build_bodies_from_json('../data/sun.json')
bodies = Body.build_bodies_from_json('../data/sun_earth.json')
bodies, params = Body.build_bodies_from_json('../data/sun_earth.json')
# 太阳半径 / 地球半径
print("太阳半径 / 地球半径 =", bodies[0].raduis / bodies[1].raduis)
print("params:", params)
for body in bodies:
print(body)
......@@ -21,6 +21,7 @@ class Sun(Body):
def __init__(self, name="Sun", mass=1.9891e30,
init_position=[0, 0, 0],
init_velocity=[0, 0, 0],
color=(170, 98, 25),
texture="sun2.jpg", size_scale=1.0, distance_scale=1.0,
rotation_speed=0.6130):
params = {
......@@ -29,7 +30,7 @@ class Sun(Body):
"init_position": init_position,
"init_velocity": init_velocity,
"density": 1.408e3,
"color": (170, 98, 25),
"color": color,
"texture": texture,
"size_scale": size_scale,
"distance_scale": distance_scale,
......
......@@ -66,6 +66,36 @@ class System(object):
# body.position += 0.5 * body.acceleration * (dt ** 2)
body.position += body.velocity * dt
def save_to_json(self, json_file_name, params=None):
"""
:param json_file_name:
:param params:
:return:
"""
import json
import os
# json_file = os.path.join("../data", json_file_name)
filed_names = ["name", "mass", "init_position", "init_velocity",
"density", "color", "texture",
"size_scale", "distance_scale", # "parent"
"rotation_speed", "ignore_mass", "is_fixed_star"]
bodies = []
for b in self.bodies:
body = {}
for filed_name in filed_names:
filed_value = getattr(b, filed_name)
if type(filed_value) is np.ndarray:
filed_value = filed_value.tolist()
body[filed_name] = filed_value
bodies.append(body)
data = {"bodies": bodies}
if params is not None:
data["params"] = params
json_str = json.dumps(data, indent=2, ensure_ascii=False, separators=(',', ': '))
with open(json_file_name, "w", encoding='utf-8') as f:
f.write(json_str)
def calc_bodies_acceleration(self):
"""
计算加速度
......@@ -124,17 +154,42 @@ class System(object):
if __name__ == '__main__':
body_sys = System([
Sun(), # 太阳
Mercury(), # 水星
Venus(), # 金星
Earth(), # 地球
Mars(), # 火星
Jupiter(), # 木星
Saturn(), # 土星
Uranus(), # 天王星
Neptune(), # 海王星
Pluto() # 冥王星(从太阳系的行星中排除)
])
print(body_sys)
# body_sys = System([
# Sun(), # 太阳
# Mercury(), # 水星
# Venus(), # 金星
# Earth(), # 地球
# Mars(), # 火星
# Jupiter(), # 木星
# Saturn(), # 土星
# Uranus(), # 天王星
# Neptune(), # 海王星
# Pluto() # 冥王星(从太阳系的行星中排除)
# ])
import math
mass = 2e30
r = 2 * AU
# p = 14.9
p = 14.89
bodies = [
Sun(name="太阳A红色", mass=mass,
init_position=[0, r * math.sqrt(3), 0], # 位置
init_velocity=[-p, 0, 0], # 速度(km/s)
size_scale=5e1, texture="sun2.jpg", color=(255, 0, 0)), # 太阳放大 100 倍
Sun(name="太阳B绿色", mass=mass,
init_position=[-r, 0, 0],
init_velocity=[1 / 2 * p, -math.sqrt(3) / 2 * p, 0],
size_scale=5e1, texture="sun2.jpg", color=(0, 255, 0)), # 太阳放大 100 倍
Sun(name="太阳C蓝色", mass=mass,
init_position=[r, 0, 0],
init_velocity=[1 / 2 * p, math.sqrt(3) / 2 * p, 0],
size_scale=5e1, texture="sun2.jpg", color=(0, 0, 255)), # 太阳放大 100 倍
Earth(name="地球",
# init_position=[0, -AU * -2, 5 * AU],
init_position=[0, math.sqrt(3) * r / 6, 5 * AU],
init_velocity=[0, 0, -10],
size_scale=4e3, distance_scale=1), # 地球放大 4000 倍,距离保持不变
]
body_sys = System(bodies)
print(body_sys.save_to_json("../data/tri_bodies_sim_perfect_01.json"))
{
"bodies": [
{
"name": "太阳",
"mass": 1.9891e+30,
"init_position": [
0.0,
0.0,
0.0
],
"init_velocity": [
0.0,
0.0,
0.0
],
"density": 1408.0,
"color": [
170,
98,
25
],
"texture": "sun2.jpg",
"size_scale": 20.0,
"distance_scale": 1.0,
"rotation_speed": 0.613,
"ignore_mass": false,
"is_fixed_star": true
},
{
"name": "地球",
"mass": 5.97237e+24,
"init_position": [
0.0,
-448793600.0,
0.0
],
"init_velocity": [
0.0,
38.0,
-1.0
],
"density": 5507.85,
"color": [
1,
89,
162
],
"texture": "earth1.jpg",
"size_scale": 1000.0,
"distance_scale": 1.0,
"rotation_speed": 15,
"ignore_mass": false,
"is_fixed_star": false
}
],
"params": {
"dt": 2592000,
"position": [
0,
149597870.7,
-448793612.09999996
]
}
}
\ No newline at end of file
{
"bodies": [
{
{
"name": "太阳",
"mass": 1.9891e30,
"mass": 1.9891e+30,
"init_position": [
0,
0,
0
0.0,
0.0,
0.0
],
"init_velocity": [
0,
0,
0
0.0,
0.0,
0.0
],
"density": 1.408e3,
"color": [170, 98, 25],
"texture": "",
"size_scale": 1.0,
"distance_scale": 1.0
"density": 1408.0,
"color": [
170,
98,
25
],
"texture": "sun2.jpg",
"size_scale": 50.0,
"distance_scale": 1.0,
"rotation_speed": 0.613,
"ignore_mass": false,
"is_fixed_star": true
}
]
],
"params": {
"dt": 604800,
"position": [
0,
149597870.7,
-448793612.09999996
]
}
}
\ No newline at end of file
......@@ -2,49 +2,63 @@
"bodies": [
{
"name": "太阳",
"mass": 1.9891e30,
"mass": 1.9891e+30,
"init_position": [
0,
0,
0
0.0,
0.0,
0.0
],
"init_velocity": [
0,
0,
0
0.0,
0.0,
0.0
],
"density": 1.408e3,
"density": 1408.0,
"color": [
125,
125,
125
170,
98,
25
],
"texture": "",
"size_scale": 1.0,
"distance_scale": 1.0
"texture": "sun2.jpg",
"size_scale": 50.0,
"distance_scale": 1.0,
"rotation_speed": 0.613,
"ignore_mass": false,
"is_fixed_star": true
},
{
"name": "地球",
"mass": 5.97237e24,
"mass": 5.97237e+24,
"init_position": [
149597870.700,
0,
0
167549616.0,
0.0,
0.0
],
"init_velocity": [
29.79,
0,
0
0.0,
29.790000915527344,
0.0
],
"density": 5507.85,
"color": [
125,
125,
125
1,
89,
162
],
"texture": "",
"size_scale": 1.0,
"distance_scale": 1.0
"texture": "earth1.jpg",
"size_scale": 2000.0,
"distance_scale": 1,
"rotation_speed": 15,
"ignore_mass": false,
"is_fixed_star": false
}
]
],
"params": {
"dt": 604800,
"position": [
0,
149597870.7,
-448793612.09999996
]
}
}
\ No newline at end of file
{
"bodies": [
{
"name": "太阳",
"mass": 1.9891e+30,
"init_position": [
149597872.0,
0.0,
0.0
],
"init_velocity": [
0.0,
0.0,
0.0
],
"density": 1408.0,
"color": [
170,
98,
25
],
"texture": "sun2.jpg",
"size_scale": 20.0,
"distance_scale": 1.0,
"rotation_speed": 0.613,
"ignore_mass": true,
"is_fixed_star": true
},
{
"name": "地球",
"mass": 5.97237e+24,
"init_position": [
0.0,
0.0,
0.0
],
"init_velocity": [
0.0,
0.0,
0.0
],
"density": 5507.85,
"color": [
1,
89,
162
],
"texture": "earth1.jpg",
"size_scale": 10.0,
"distance_scale": 1.0,
"rotation_speed": 15,
"ignore_mass": false,
"is_fixed_star": false
},
{
"name": "月球",
"mass": 7.342e+22,
"init_position": [
384400.0,
0.0,
0.0
],
"init_velocity": [
0.0,
1.0230000019073486,
0.0
],
"density": 3344.0,
"color": [
162,
162,
162
],
"texture": "moon.jpg",
"size_scale": 20.0,
"distance_scale": 1.0,
"rotation_speed": 0.5487,
"ignore_mass": false,
"is_fixed_star": false
}
],
"params": {
"dt": 86400,
"position": [
0,
0,
0
]
}
}
\ No newline at end of file
{
"bodies": [
{
"name": "红轨太阳A",
"mass": 2e+30,
"init_position": [
0.0,
518222240.0,
0.0
],
"init_velocity": [
-14.890000343322754,
0.0,
0.0
],
"density": 1408.0,
"color": [
255,
0,
0
],
"texture": "sun2.jpg",
"size_scale": 50.0,
"distance_scale": 1.0
},
{
"name": "绿轨太阳B",
"mass": 2e+30,
"init_position": [
-299195744.0,
0.0,
0.0
],
"init_velocity": [
7.445000171661377,
-12.895118713378906,
0.0
],
"density": 1408.0,
"color": [
0,
255,
0
],
"texture": "sun2.jpg",
"size_scale": 50.0,
"distance_scale": 1.0
},
{
"name": "蓝轨太阳C",
"mass": 2e+30,
"init_position": [
299195744.0,
0.0,
0.0
],
"init_velocity": [
7.445000171661377,
12.895118713378906,
0.0
],
"density": 1408.0,
"color": [
0,
0,
255
],
"texture": "sun2.jpg",
"size_scale": 50.0,
"distance_scale": 1.0
},
{
"name": "流浪地球",
"mass": 5.97237e+24,
"init_position": [
0.0,
86370368.0,
747989376.0
],
"init_velocity": [
0.0,
0.0,
-10.0
],
"density": 5507.85,
"color": [
1,
89,
162
],
"texture": "earth1.jpg",
"size_scale": 4000.0,
"distance_scale": 1
}
],
"params": {
"dt": 31536000,
"position": [
0,
149597870.7,
-1495978707.0
]
}
}
\ No newline at end of file
......@@ -59,7 +59,8 @@ def ursina_run(bodies,
# view_azimuth=0,
light=True,
cosmic_bg=None,
show_grid=True):
show_grid=True,
save_as_json=None):
"""
:param bodies: 天体
......@@ -76,9 +77,17 @@ def ursina_run(bodies,
from ursina import application, Sequence, camera, held_keys, time, clamp, Entity, Text, color
from ursina.prefabs.first_person_controller import FirstPersonController
body_sys = System(bodies)
if save_as_json is not None:
try:
body_sys.save_to_json(save_as_json, {"dt": dt, "position": position})
print(f"{save_as_json} 文件生成成功!")
except Exception as e:
print(f"{save_as_json} 文件生成失败!" + str(e))
return
simulator = UrsinaSimulator(body_sys)
view_azimuth = 0 # 暂时未用
player = UrsinaPlayer(position, view_azimuth, simulator.ursina_views)
# # player = FirstPersonController(model='cube', y=-1e20, color=color.orange, origin_y=-5000, speed=8)
# # player.on_disable()
# # player.position = position
......
......@@ -32,4 +32,4 @@ if __name__ == '__main__':
# 使用 ursina 查看的运行效果
# position = 左-右+、上+下-、前+后-
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
ursina_run(bodies, SECONDS_PER_MONTH, position=(0, AU, -3 * AU))
ursina_run(bodies, SECONDS_PER_MONTH, position=(0, AU, -3 * AU), save_as_json='../data/gravity_slingshot.json')
......@@ -43,7 +43,7 @@ if __name__ == '__main__':
# position = 左-右+、上+下-、前+后-
# position=(0, 0, 0) 的位置是站在地球视角,可以观看月相变化的过程
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
ursina_run(bodies, SECONDS_PER_DAY, position=(0, 0, 0))
ursina_run(bodies, SECONDS_PER_DAY, position=(0, 0, 0), save_as_json="../data/sun_earth_moon.json")
# 使用 mayavi 查看的运行效果
# mayavi_run(bodies, SECONDS_PER_HALF_DAY / 2, view_azimuth=-45)
# -*- coding:utf-8 -*-
# title :ursina模拟器(支持天体json文件的读取)
# description :ursina模拟器(支持天体json文件的读取)
# author :Python超人
# date :2023-02-11
# link :https://gitcode.net/pythoncr/
# python_version :3.8
# ==============================================================================
from bodies import Body
from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, SECONDS_PER_YEAR, SECONDS_PER_MONTH, AU
from scenes.func import mayavi_run, ursina_run, mpl_run
if __name__ == '__main__':
# TODO: 太阳演示
bodies, params = Body.build_bodies_from_json('../data/sun.json')
# TODO: 太阳和地球演示
bodies, params = Body.build_bodies_from_json('../data/sun_earth.json')
# TODO: 在地球上看月相演示变化过程演示
bodies, params = Body.build_bodies_from_json('../data/sun_earth_moon.json')
# TODO: 完美数据的三体模型的演示01
# bodies, params = Body.build_bodies_from_json('../data/tri_bodies_sim_perfect_01.json')
# TODO: 引力弹弓的演示
bodies, params = Body.build_bodies_from_json('../data/gravity_slingshot.json')
dt = params["dt"] if "dt" in params else SECONDS_PER_YEAR
position = params["position"] if "position" in params else (0, 0, 0)
# 使用 ursina 查看的运行效果
# position = 左-右+、上+下-、前+后-
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
json_file = None # 指定 json_file 保存路径,则会将模拟环境天体数据保存到该json文件中
ursina_run(bodies, dt, position=position, save_as_json=json_file)
......@@ -180,7 +180,7 @@ class ControlHandler(EventHandler):
print(key)
elif key == 'y': # 寻找天体
if hasattr(self, "bodies_button_list"):
if self.ui.bodies_button_list.enabled:
if self.bodies_button_list.enabled:
self.bodies_button_list_close()
return
self.on_searching_bodies_click()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册