提交 92b65ae6 编写于 作者: 三月三net's avatar 三月三net

Python超人-宇宙模拟器

上级 e7d1a17f
...@@ -7,11 +7,18 @@ ...@@ -7,11 +7,18 @@
# python_version :3.8 # python_version :3.8
# ============================================================================== # ==============================================================================
import math import math
from common.consts import G from common.consts import G, AU, SECONDS_PER_DAY
from bodies import Body from bodies import Body, Sun, Asteroids, Moon, Earth
import numpy as np
def calc_solar_acceleration(body_or_pos, big_body): def calc_solar_acceleration(body_or_pos, big_body):
"""
计算天体的加速度
@param body_or_pos: 需要计算的天体
@param big_body: 大天体(太阳 或者 地球)
@return:
"""
if isinstance(body_or_pos, Body): if isinstance(body_or_pos, Body):
body_pos = body_or_pos.position body_pos = body_or_pos.position
else: else:
...@@ -97,6 +104,108 @@ def get_celestial_body_data(body_name): ...@@ -97,6 +104,108 @@ def get_celestial_body_data(body_name):
return position, velocity return position, velocity
def set_solar_system_celestial_position(bodies, dt, recalc_moon_pos):
"""
根据日期时间 dt 设置太阳系中天体的真实位置
@param bodies: 太阳系中天体
@param dt: 时间
@param recalc_moon_pos: 是否对月球的位置进行重新计算。
为了更好的展示效果,需要对月球的位置重新计算(使得地月距离放大,月球相对地球方向不变),
重新计算位置后,地球和月球可以放大1000倍以上
@return:
"""
earth_pos = None
sun_pos = None
earth = None
sun = None
moon = None
for body in bodies:
if isinstance(body, Sun):
sun = body
elif isinstance(body, Earth):
earth = body
elif isinstance(body, Moon):
moon = body
for body in bodies:
if isinstance(body, Asteroids): # 小行星带是模拟,不是正常的天体
posvel = None
else:
# 获取天体的三维位置和矢量速度
posvel = get_body_posvel(body, dt)
if isinstance(body, Moon): # 如果是月球,为了更好的展示效果,需要对月球的位置重新计算
moon_real_pos = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU]
# TODO:注释下行,月球就会在真实的位置
if recalc_moon_pos:
posvel = recalc_moon_position(posvel, earth_pos)
if posvel is None:
# posvel 为空,则使用太阳的坐标
position, velocity = [sun_pos.x.value * AU,
sun_pos.z.value * AU,
sun_pos.y.value * AU], [0, 0, 0]
else:
# 坐标单位:千米 速度单位:千米/秒
position, velocity = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU], \
[posvel[1].x.value * AU / SECONDS_PER_DAY,
posvel[1].z.value * AU / SECONDS_PER_DAY,
posvel[1].y.value * AU / SECONDS_PER_DAY]
# 实时调整天体的位置和速度
body.position = np.array(position)
body.velocity = np.array(velocity)
if isinstance(body, Asteroids):
pass
elif isinstance(body, Sun):
# 记录太阳的位置
sun_pos = posvel[0]
elif isinstance(body, Moon):
# 月球受到2个影响比较大的天体引力(地球和太阳),计算引力引起的加速度和
acc_earth = calc_solar_acceleration(moon_real_pos, earth)
acc_sun = calc_solar_acceleration(moon_real_pos, sun)
body.acceleration = [acc_earth[0] + acc_sun[0],
acc_earth[1] + acc_sun[1],
acc_earth[2] + acc_sun[2]]
# elif isinstance(body, Earth):
# # 月球受到2个影响比较大的天体引力(地球和太阳),计算引力引起的加速度和
# acc_earth = calc_solar_acceleration(earth, moon)
# acc_sun = calc_solar_acceleration(earth, sun)
# body.acceleration = [acc_earth[0] + acc_sun[0],
# acc_earth[1] + acc_sun[1],
# acc_earth[2] + acc_sun[2]]
else:
# 其他天体受到太阳引力
body.acceleration = calc_solar_acceleration(body, sun)
if isinstance(body, Earth):
# 记录地球的位置
earth_pos = posvel[0]
def set_earth_rotation(earth, dt):
"""
根据指定的时间控制地球的旋转角度(保证地球的自转和北京时间同步)
@param dt: 时间 datetime
@return:
"""
# timetuple 可以获取当天的小时数、分数钟、秒数
timetuple = dt.timetuple()
# 当年的第几天
day_of_year = timetuple.tm_yday
# 根据当年的第几天计算出该日期当天的偏转角度:360度 / 365天 = 当天的偏转角度
angle_of_day = day_of_year * (360 / 365)
# 计算出精确的小时数
total_hours = timetuple.tm_hour + timetuple.tm_min / 60 + timetuple.tm_sec / 60 / 60
# -total_hours: 负号控制地球的旋转方向、1天24小时,360度/24=15
# total_hours * 15:1天24小时,360度/24小时=1小时15度
# angle_of_day: 1年第几天的角度
earth.planet.rotation_y = -total_hours * 15 - angle_of_day + 15 # 精确调整
# pip install Astropysics # pip install Astropysics
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -11,7 +11,8 @@ import math ...@@ -11,7 +11,8 @@ import math
import numpy as np import numpy as np
from bodies import Sun, Mercury, Venus, Earth, Mars, Asteroids, Jupiter, Saturn, Uranus, Neptune, Moon from bodies import Sun, Mercury, Venus, Earth, Mars, Asteroids, Jupiter, Saturn, Uranus, Neptune, Moon
from common.celestial_data_service import get_body_posvel, recalc_moon_position, calc_solar_acceleration from common.celestial_data_service import get_body_posvel, recalc_moon_position, calc_solar_acceleration, \
set_solar_system_celestial_position, set_earth_rotation
from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, AU from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, AU
from sim_scenes.func import ursina_run, camera_look_at from sim_scenes.func import ursina_run, camera_look_at
from simulators.ursina.entities.body_timer import TimeData from simulators.ursina.entities.body_timer import TimeData
...@@ -53,8 +54,12 @@ class SolarSystemRealitySim: ...@@ -53,8 +54,12 @@ class SolarSystemRealitySim:
self.moon_size_scale = 5e1 self.moon_size_scale = 5e1
self.sun_size_scale = 1e1 self.sun_size_scale = 1e1
self.earth_size_scale = 1
self.moon_size_scale = 1
self.sun_size_scale = 1
self.sun = Sun(name="太阳", size_scale=self.sun_size_scale) # 太阳 self.sun = Sun(name="太阳", size_scale=self.sun_size_scale) # 太阳
self.earth = Earth(name="地球", texture="earth_hd.jpg", self.earth = Earth(name="地球", # texture="earth_hd.jpg",
rotate_angle=3.44, rotate_angle=3.44,
size_scale=self.earth_size_scale) # 地球 size_scale=self.earth_size_scale) # 地球
self.earth_camera = Earth(name="地球摄像机", texture="transparent.png", self.earth_camera = Earth(name="地球摄像机", texture="transparent.png",
...@@ -80,26 +85,6 @@ class SolarSystemRealitySim: ...@@ -80,26 +85,6 @@ class SolarSystemRealitySim:
if self.debug_mode: if self.debug_mode:
self.earth.set_light_disable(True) self.earth.set_light_disable(True)
def set_earth_rotation(self, dt):
"""
根据指定的时间控制地球的旋转角度(保证地球的自转和北京时间同步)
@param dt: 时间 datetime
@return:
"""
# timetuple 可以获取当天的小时数、分数钟、秒数
timetuple = dt.timetuple()
# 当年的第几天
day_of_year = timetuple.tm_yday
# 根据当年的第几天计算出该日期当天的偏转角度:360度 / 365天 = 当天的偏转角度
angle_of_day = day_of_year * (360 / 365)
# 计算出精确的小时数
total_hours = timetuple.tm_hour + timetuple.tm_min / 60 + timetuple.tm_sec / 60 / 60
# -total_hours: 负号控制地球的旋转方向、1天24小时,360度/24=15
# total_hours * 15:1天24小时,360度/24小时=1小时15度
# angle_of_day: 1年第几天的角度
self.earth.planet.rotation_y = -total_hours * 15 - angle_of_day + 15 # 精确调整
def show_clock(self, dt): def show_clock(self, dt):
""" """
显示时钟 显示时钟
...@@ -125,58 +110,7 @@ class SolarSystemRealitySim: ...@@ -125,58 +110,7 @@ class SolarSystemRealitySim:
@return: @return:
""" """
t = self.start_time + time_data.total_days t = self.start_time + time_data.total_days
set_solar_system_celestial_position(self.bodies, t, self.recalc_moon_pos)
earth_pos = None
sun_pos = None
for body in self.bodies:
if isinstance(body, Asteroids): # 小行星带是模拟,不是正常的天体
posvel = None
else:
# 获取天体的三维位置和矢量速度
posvel = get_body_posvel(body, t)
if isinstance(body, Moon): # 如果是月球,为了更好的展示效果,需要对月球的位置重新计算
moon_real_pos = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU]
# TODO:注释下行,月球就会在真实的位置
if self.recalc_moon_pos:
posvel = recalc_moon_position(posvel, earth_pos)
if posvel is None:
# posvel 为空,则使用太阳的坐标
position, velocity = [sun_pos.x.value * AU,
sun_pos.z.value * AU,
sun_pos.y.value * AU], [0, 0, 0]
else:
# 坐标单位:千米 速度单位:千米/秒
position, velocity = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU], \
[posvel[1].x.value * AU / SECONDS_PER_DAY,
posvel[1].z.value * AU / SECONDS_PER_DAY,
posvel[1].y.value * AU / SECONDS_PER_DAY]
# 实时调整天体的位置和速度
body.position = np.array(position)
body.velocity = np.array(velocity)
if isinstance(body, Asteroids):
pass
elif isinstance(body, Sun):
# 记录太阳的位置
sun_pos = posvel[0]
elif isinstance(body, Moon):
# 月球受到2个影响比较大的天体引力(地球和太阳),计算引力引起的加速度和
acc_earth = calc_solar_acceleration(moon_real_pos, self.earth)
acc_sun = calc_solar_acceleration(moon_real_pos, self.sun)
body.acceleration = [acc_earth[0] + acc_sun[0],
acc_earth[1] + acc_sun[1],
acc_earth[2] + acc_sun[2]]
else:
# 其他天体受到太阳引力
body.acceleration = calc_solar_acceleration(body, self.sun)
if isinstance(body, Earth):
# 记录地球的位置
earth_pos = posvel[0]
def on_ready(self): def on_ready(self):
""" """
...@@ -190,6 +124,8 @@ class SolarSystemRealitySim: ...@@ -190,6 +124,8 @@ class SolarSystemRealitySim:
# camera.fov = 30 # 调试时,拉近摄像机距离 # camera.fov = 30 # 调试时,拉近摄像机距离
# camera.fov = 1 # camera.fov = 1
camera.parent = self.earth_camera.planet camera.parent = self.earth_camera.planet
# camera.update = self.camera_update
# 需要按照时间和日期来控制地球的自转,所以删除控制地球自转的属性 # 需要按照时间和日期来控制地球的自转,所以删除控制地球自转的属性
delattr(self.earth.planet, "rotation_speed") delattr(self.earth.planet, "rotation_speed")
delattr(self.earth.planet, "rotspeed") delattr(self.earth.planet, "rotspeed")
...@@ -202,23 +138,36 @@ class SolarSystemRealitySim: ...@@ -202,23 +138,36 @@ class SolarSystemRealitySim:
# 设置后,可以调整鼠标键盘的控制速度 # 设置后,可以调整鼠标键盘的控制速度
application.time_scale = 2 application.time_scale = 2
#
# def camera_update(self):
# camera.x = -50 # 100
# # camera.z = -10
# camera.y = 20
# camera.z = -10
# # 摄像机看向地球
# camera_look_at(self.earth)
def set_camera_pos(self, time_data: TimeData):
if time_data.total_days > 120:
self.earth_camera.camera_init_val = +3000000
elif time_data.total_days > 90:
self.earth_camera.camera_init_val = +1200000
elif time_data.total_days > 90:
self.earth_camera.camera_init_val += 600000
elif time_data.total_days > 60:
self.earth_camera.camera_init_val += 100000
camera.x = -300 # 100 def set_camera_pos(self, time_data: TimeData):
# if time_data.total_days > 120:
# self.earth_camera.camera_init_val = +3000000
# elif time_data.total_days > 90:
# self.earth_camera.camera_init_val = +1200000
# elif time_data.total_days > 90:
# self.earth_camera.camera_init_val += 600000
# elif time_data.total_days > 60:
# self.earth_camera.camera_init_val += 100000
# camera.x = -300 # 100
# camera.z = 200 # camera.z = 200
camera.y += self.earth_camera.camera_init_val * UrsinaConfig.SCALE_FACTOR # camera.y += self.earth_camera.camera_init_val * UrsinaConfig.SCALE_FACTOR
camera.x = -60 # 100
# camera.z = -10
camera.y = 50
UrsinaConfig.trail_factor = 3 * math.sqrt(camera.y / 250) # UrsinaConfig.trail_factor = 3 * math.sqrt(camera.y / 250)
pass
def on_timer_changed(self, time_data: TimeData): def on_timer_changed(self, time_data: TimeData):
""" """
...@@ -230,7 +179,7 @@ class SolarSystemRealitySim: ...@@ -230,7 +179,7 @@ class SolarSystemRealitySim:
# 设置天体的位置(包含速度和加速度的信息) # 设置天体的位置(包含速度和加速度的信息)
self.set_bodies_position(time_data) self.set_bodies_position(time_data)
# 保证地球的自转和北京时间同步 # 保证地球的自转和北京时间同步
self.set_earth_rotation(dt) set_earth_rotation(self.earth, dt)
# 调整摄像机的位置 # 调整摄像机的位置
self.set_camera_pos(time_data) self.set_camera_pos(time_data)
# 摄像机看向地球 # 摄像机看向地球
...@@ -282,7 +231,7 @@ class SolarSystemRealitySim: ...@@ -282,7 +231,7 @@ class SolarSystemRealitySim:
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹 # 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后- # position = 左-右+、上+下-、前+后-
ursina_run(self.bodies, dt, ursina_run(self.bodies, dt,
position=(0, 500000000, 0), position=(0, 0, 0),
# position=(0, 0.2 * AU, -3 * AU), # position=(0, 0.2 * AU, -3 * AU),
gravity_works=False, # 关闭万有引力的计算 gravity_works=False, # 关闭万有引力的计算
show_grid=False, show_grid=False,
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
import numpy as np import numpy as np
from bodies import Sun, Mercury, Venus, Earth, Mars, Asteroids, Jupiter, Saturn, Uranus, Neptune, Moon from bodies import Sun, Mercury, Venus, Earth, Mars, Asteroids, Jupiter, Saturn, Uranus, Neptune, Moon
from common.celestial_data_service import get_body_posvel, recalc_moon_position, calc_solar_acceleration from common.celestial_data_service import get_body_posvel, recalc_moon_position, calc_solar_acceleration, \
set_solar_system_celestial_position, set_earth_rotation
from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, AU from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, AU
from sim_scenes.func import ursina_run from sim_scenes.func import ursina_run
from simulators.ursina.entities.body_timer import TimeData from simulators.ursina.entities.body_timer import TimeData
...@@ -90,26 +91,6 @@ class SolarSystemRealitySim: ...@@ -90,26 +91,6 @@ class SolarSystemRealitySim:
if self.debug_mode: if self.debug_mode:
self.earth.set_light_disable(True) self.earth.set_light_disable(True)
def set_earth_rotation(self, dt):
"""
根据指定的时间控制地球的旋转角度(保证地球的自转和北京时间同步)
@param dt: 时间 datetime
@return:
"""
# timetuple 可以获取当天的小时数、分数钟、秒数
timetuple = dt.timetuple()
# 当年的第几天
day_of_year = timetuple.tm_yday
# 根据当年的第几天计算出该日期当天的偏转角度:360度 / 365天 = 当天的偏转角度
angle_of_day = day_of_year * (360 / 365)
# 计算出精确的小时数
total_hours = timetuple.tm_hour + timetuple.tm_min / 60 + timetuple.tm_sec / 60 / 60
# -total_hours: 负号控制地球的旋转方向、1天24小时,360度/24=15
# total_hours * 15:1天24小时,360度/24小时=1小时15度
# angle_of_day: 1年第几天的角度
self.earth.planet.rotation_y = -total_hours * 15 - angle_of_day + 15 # 精确调整
def show_clock(self, dt): def show_clock(self, dt):
""" """
显示时钟 显示时钟
...@@ -134,58 +115,7 @@ class SolarSystemRealitySim: ...@@ -134,58 +115,7 @@ class SolarSystemRealitySim:
@return: @return:
""" """
t = self.start_time + time_data.total_days t = self.start_time + time_data.total_days
set_solar_system_celestial_position(self.bodies, t, self.recalc_moon_pos)
earth_pos = None
sun_pos = None
for body in self.bodies:
if isinstance(body, Asteroids): # 小行星带是模拟,不是正常的天体
posvel = None
else:
# 获取天体的三维位置和矢量速度
posvel = get_body_posvel(body, t)
if isinstance(body, Moon): # 如果是月球,为了更好的展示效果,需要对月球的位置重新计算
moon_real_pos = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU]
# TODO:注释下行,月球就会在真实的位置
if self.recalc_moon_pos:
posvel = recalc_moon_position(posvel, earth_pos)
if posvel is None:
# posvel 为空,则使用太阳的坐标
position, velocity = [sun_pos.x.value * AU,
sun_pos.z.value * AU,
sun_pos.y.value * AU], [0, 0, 0]
else:
# 坐标单位:千米 速度单位:千米/秒
position, velocity = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU], \
[posvel[1].x.value * AU / SECONDS_PER_DAY,
posvel[1].z.value * AU / SECONDS_PER_DAY,
posvel[1].y.value * AU / SECONDS_PER_DAY]
# 实时调整天体的位置和速度
body.position = np.array(position)
body.velocity = np.array(velocity)
if isinstance(body, Asteroids):
pass
elif isinstance(body, Sun):
# 记录太阳的位置
sun_pos = posvel[0]
elif isinstance(body, Moon):
# 月球受到2个影响比较大的天体引力(地球和太阳),计算引力引起的加速度和
acc_earth = calc_solar_acceleration(moon_real_pos, self.earth)
acc_sun = calc_solar_acceleration(moon_real_pos, self.sun)
body.acceleration = [acc_earth[0] + acc_sun[0],
acc_earth[1] + acc_sun[1],
acc_earth[2] + acc_sun[2]]
else:
# 其他天体受到太阳引力
body.acceleration = calc_solar_acceleration(body, self.sun)
if isinstance(body, Earth):
# 记录地球的位置
earth_pos = posvel[0]
def on_ready(self): def on_ready(self):
""" """
...@@ -219,7 +149,7 @@ class SolarSystemRealitySim: ...@@ -219,7 +149,7 @@ class SolarSystemRealitySim:
# 设置天体的位置(包含速度和加速度的信息) # 设置天体的位置(包含速度和加速度的信息)
self.set_bodies_position(time_data) self.set_bodies_position(time_data)
# 保证地球的自转和北京时间同步 # 保证地球的自转和北京时间同步
self.set_earth_rotation(dt) set_earth_rotation(self.earth, dt)
# 显示时钟 # 显示时钟
self.show_clock(dt) self.show_clock(dt)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册