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

Python超人-宇宙模拟器

上级 e7d1a17f
......@@ -7,11 +7,18 @@
# python_version :3.8
# ==============================================================================
import math
from common.consts import G
from bodies import Body
from common.consts import G, AU, SECONDS_PER_DAY
from bodies import Body, Sun, Asteroids, Moon, Earth
import numpy as np
def calc_solar_acceleration(body_or_pos, big_body):
"""
计算天体的加速度
@param body_or_pos: 需要计算的天体
@param big_body: 大天体(太阳 或者 地球)
@return:
"""
if isinstance(body_or_pos, Body):
body_pos = body_or_pos.position
else:
......@@ -97,6 +104,108 @@ def get_celestial_body_data(body_name):
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
if __name__ == '__main__':
......
......@@ -11,7 +11,8 @@ import math
import numpy as np
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 sim_scenes.func import ursina_run, camera_look_at
from simulators.ursina.entities.body_timer import TimeData
......@@ -53,8 +54,12 @@ class SolarSystemRealitySim:
self.moon_size_scale = 5e1
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.earth = Earth(name="地球", texture="earth_hd.jpg",
self.earth = Earth(name="地球", # texture="earth_hd.jpg",
rotate_angle=3.44,
size_scale=self.earth_size_scale) # 地球
self.earth_camera = Earth(name="地球摄像机", texture="transparent.png",
......@@ -80,26 +85,6 @@ class SolarSystemRealitySim:
if self.debug_mode:
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):
"""
显示时钟
......@@ -125,58 +110,7 @@ class SolarSystemRealitySim:
@return:
"""
t = self.start_time + time_data.total_days
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]
set_solar_system_celestial_position(self.bodies, t, self.recalc_moon_pos)
def on_ready(self):
"""
......@@ -190,6 +124,8 @@ class SolarSystemRealitySim:
# camera.fov = 30 # 调试时,拉近摄像机距离
# camera.fov = 1
camera.parent = self.earth_camera.planet
# camera.update = self.camera_update
# 需要按照时间和日期来控制地球的自转,所以删除控制地球自转的属性
delattr(self.earth.planet, "rotation_speed")
delattr(self.earth.planet, "rotspeed")
......@@ -202,23 +138,36 @@ class SolarSystemRealitySim:
# 设置后,可以调整鼠标键盘的控制速度
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.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):
"""
......@@ -230,7 +179,7 @@ class SolarSystemRealitySim:
# 设置天体的位置(包含速度和加速度的信息)
self.set_bodies_position(time_data)
# 保证地球的自转和北京时间同步
self.set_earth_rotation(dt)
set_earth_rotation(self.earth, dt)
# 调整摄像机的位置
self.set_camera_pos(time_data)
# 摄像机看向地球
......@@ -282,7 +231,7 @@ class SolarSystemRealitySim:
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
ursina_run(self.bodies, dt,
position=(0, 500000000, 0),
position=(0, 0, 0),
# position=(0, 0.2 * AU, -3 * AU),
gravity_works=False, # 关闭万有引力的计算
show_grid=False,
......
......@@ -10,7 +10,8 @@
import numpy as np
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 sim_scenes.func import ursina_run
from simulators.ursina.entities.body_timer import TimeData
......@@ -90,26 +91,6 @@ class SolarSystemRealitySim:
if self.debug_mode:
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):
"""
显示时钟
......@@ -134,58 +115,7 @@ class SolarSystemRealitySim:
@return:
"""
t = self.start_time + time_data.total_days
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]
set_solar_system_celestial_position(self.bodies, t, self.recalc_moon_pos)
def on_ready(self):
"""
......@@ -219,7 +149,7 @@ class SolarSystemRealitySim:
# 设置天体的位置(包含速度和加速度的信息)
self.set_bodies_position(time_data)
# 保证地球的自转和北京时间同步
self.set_earth_rotation(dt)
set_earth_rotation(self.earth, dt)
# 显示时钟
self.show_clock(dt)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册