提交 3d734e8c 编写于 作者: 三月三net's avatar 三月三net

Python超人-宇宙模拟器

上级 fa9e1779
...@@ -54,6 +54,20 @@ def get_body_posvel(body, time=None): ...@@ -54,6 +54,20 @@ def get_body_posvel(body, time=None):
if not isinstance(body, str): if not isinstance(body, str):
body = body.__class__.__name__ body = body.__class__.__name__
body_dict = {'地球': 'earth',
'太阳': 'sun',
'月球': 'moon',
'水星': 'mercury',
'金星': 'venus',
'地月': 'earth-moon-barycenter',
'火星': 'mars',
'木星': 'jupiter',
'土星': 'saturn',
'天王星': 'uranus',
'海王星': 'neptune'}
body = body_dict.get(body, body)
posvel = get_body_barycentric_posvel(body, time) posvel = get_body_barycentric_posvel(body, time)
return posvel return posvel
...@@ -76,7 +90,7 @@ def get_bodies_posvels(planet_names="sun,mercury,venus,earth,moon,mars,jupiter,s ...@@ -76,7 +90,7 @@ def get_bodies_posvels(planet_names="sun,mercury,venus,earth,moon,mars,jupiter,s
return posvels return posvels
def recalc_moon_position(moon_posvel, earth_pos): def recalc_moon_position(moon_posvel, earth_pos, scale=50):
""" """
重新计算月球的位置(由于月球和地球的距离在整个太阳系尺度下非常近,为了较好的显示效果,需要放大月球和地球的距离,但不要改变月球相对地球的位置) 重新计算月球的位置(由于月球和地球的距离在整个太阳系尺度下非常近,为了较好的显示效果,需要放大月球和地球的距离,但不要改变月球相对地球的位置)
@param moon_posvel: 月球的三维坐标位置和三维矢量速度 @param moon_posvel: 月球的三维坐标位置和三维矢量速度
...@@ -85,7 +99,7 @@ def recalc_moon_position(moon_posvel, earth_pos): ...@@ -85,7 +99,7 @@ def recalc_moon_position(moon_posvel, earth_pos):
""" """
moon_pos, moon_vel = moon_posvel[0], moon_posvel[1] moon_pos, moon_vel = moon_posvel[0], moon_posvel[1]
moon_pos_to_earth = moon_pos - earth_pos moon_pos_to_earth = moon_pos - earth_pos
moon_pos_to_earth = moon_pos_to_earth * 50 moon_pos_to_earth = moon_pos_to_earth * scale
return moon_pos_to_earth + earth_pos, moon_vel return moon_pos_to_earth + earth_pos, moon_vel
...@@ -109,7 +123,7 @@ def get_celestial_body_data(body_name): ...@@ -109,7 +123,7 @@ def get_celestial_body_data(body_name):
return position, velocity return position, velocity
def set_solar_system_celestial_position(bodies, dt, recalc_moon_pos, def set_solar_system_celestial_position(bodies, dt, recalc_moon_pos, recalc_moon_pos_scale=50,
set_velocity=True, set_acceleration=True): set_velocity=True, set_acceleration=True):
""" """
根据日期时间 dt 设置太阳系中天体的真实位置 根据日期时间 dt 设置太阳系中天体的真实位置
...@@ -152,7 +166,7 @@ def set_solar_system_celestial_position(bodies, dt, recalc_moon_pos, ...@@ -152,7 +166,7 @@ def set_solar_system_celestial_position(bodies, dt, recalc_moon_pos,
moon_real_pos = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU] moon_real_pos = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU]
# TODO:注释下行,月球就会在真实的位置 # TODO:注释下行,月球就会在真实的位置
if recalc_moon_pos: if recalc_moon_pos:
posvel = recalc_moon_position(posvel, earth_pos) posvel = recalc_moon_position(posvel, earth_pos,scale= recalc_moon_pos_scale)
if posvel is None: if posvel is None:
# posvel 为空,则使用太阳的坐标 # posvel 为空,则使用太阳的坐标
......
from 引力世界.造物主 import 造物主
from 引力世界.模拟场景 import 模拟场景
from 引力世界.万物.太阳系 import *
from bodies import Sun, Earth, Moon
from 引力世界 import 造物主
class 太阳(Sun):
def __init__(self, 初始位置=[0, 0, 0], 初始速度=[0, 0, 0], 缩放大小=1):
super(太阳, self).__init__(init_velocity=初始速度, init_position=初始位置, size_scale=缩放大小)
class 地球(Earth):
def __init__(self, 初始位置=[0, 0, 0], 初始速度=[0, 0, 0], 缩放大小=1):
super(地球, self).__init__(init_velocity=初始速度, init_position=初始位置, size_scale=缩放大小)
class 月球(Moon):
def __init__(self, 初始位置=[0, 0, 0], 初始速度=[0, 0, 0], 缩放大小=1):
super(月球, self).__init__(init_velocity=初始速度, init_position=初始位置, size_scale=缩放大小)
造物主.登记(['太阳', 'sun'], 太阳)
造物主.登记(['地球', 'earth'], 地球)
造物主.登记(['月球', 'moon'], 月球)
天体信息 = {"太阳": {
"质量": 1.9891e30, "平均密度": 1.408e3
}, "地球": {
"质量": 5.97237e24, "平均密度": 5507.85, "转轴倾角": 23.44
}, "月球": {
"质量": 7.342e22, "平均密度": 3.344e3
}}
def get_body_pos_vel(body_name: str, dt=None):
"""
根据日期时间获取地球的
@param dt:
@return:
"""
import pytz
# 安装 astropy 包
# pip install -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com astropy
# 获取天体的坐标pos和速度vel
from astropy.coordinates import get_body_barycentric_posvel
import astropy.units as u # 单位
body_dict = {'地球': 'earth',
'太阳': 'sun',
'月球': 'moon',
'水星': 'mercury',
'金星': 'venus',
'地月': 'earth-moon-barycenter',
'火星': 'mars',
'木星': 'jupiter',
'土星': 'saturn',
'天王星': 'uranus',
'海王星': 'neptune'}
body_name = body_dict.get(body_name, body_name)
# from astropy.coordinates import solar_system_ephemeris
# print("天体名:", solar_system_ephemeris.bodies)
# ('earth', 'sun', 'moon', 'mercury', 'venus', 'earth-moon-barycenter',
# 'mars', 'jupiter', 'saturn', 'uranus', 'neptune')
if dt is None:
from astropy.time import Time
from datetime import datetime
# dt = Time(datetime.strptime('2149-02-01 12:00:00+0800', '%Y-%m-%d %H:%M:%S%z'),
# format='datetime')
dt = Time.now()
print('----------------------------------------')
print("北京时间:", dt.to_datetime(timezone=pytz.timezone('Asia/Shanghai')))
# 获取地球的坐标和速度
pos, vel = get_body_barycentric_posvel(body_name.lower(), dt)
pos = [pos.x.to(u.km).value,
pos.y.to(u.km).value,
pos.z.to(u.km).value]
# print("地球坐标(公里):", pos)
# pos = [pos.x.to(u.au).value,
# pos.y.to(u.au).value,
# pos.z.to(u.au).value]
# print("地球坐标(天文单位):", pos)
vel = [vel.x.to(u.km / u.second).value,
vel.y.to(u.km / u.second).value,
vel.z.to(u.km / u.second).value]
# print("地球速度(公里/秒):", vel)
print('----------------------------------------')
# pos = [pos[0].value,pos[1].value,pos[2].value]
return pos, vel
from astropy.coordinates import solar_system_ephemeris
print(solar_system_ephemeris.bodies)
print(get_body_pos_vel('earth'))
#
# from astropy.coordinates import SkyCoord, get_sun
# from astropy import units as u
# from astropy.time import Time
#
# # 指定时间,这里以2023年10月1日为例
# obs_time = Time('2023-10-01')
#
# # 创建冥王星的坐标对象,使用名称'Pluto'或者天体ID 134340
# pluto_coord = SkyCoord(body='Pluto', frame='icrs', obstime=obs_time)
#
# # 计算并输出冥王星在该时间的赤道坐标(赤经和赤纬)
# print(pluto_coord.ra, pluto_coord.dec)
#
# # 如果需要获取相对于太阳的坐标,可以使用get_sun函数获取太阳的位置
# sun_coord = get_sun(obs_time)
#
# # 计算冥王星相对于太阳的坐标
# pluto_relative_coord = pluto_coord.separation(sun_coord)
#
# # 输出冥王星相对于太阳的角距离
# print(pluto_relative_coord.arcsec)
# -*- coding:utf-8 -*-
# title :模拟场景
# description :模拟场景
# author :Python超人
# date :2024-03-20
# link :https://gitcode.net/pythoncr/
# python_version :3.9
# ==============================================================================
from ursina import Ursina, camera, EditorCamera, Sky, Entity, load_model, color
from common.celestial_data_service import set_solar_system_celestial_position, conv_to_astropy_time
from common.consts import SECONDS_PER_DAY, AU
from bodies.body import Body
from sim_scenes.func import create_sphere_sky, ursina_run
from sim_scenes.universe_sim_scenes import UniverseSimScenes
from simulators.ursina.entities.body_timer import TimeData
from simulators.ursina.ui.control_ui import ControlUI
from simulators.ursina.ursina_config import UrsinaConfig
from simulators.ursina.ursina_event import UrsinaEvent
from 引力世界.数据.天体数据 import get_body_pos_vel
class 模拟场景(UniverseSimScenes):
def __init__(self):
# self.app = Ursina()
#
# self.sky = create_sphere_sky(scale=80000)
self.造物()
#
# EditorCamera()
def 获取天体列表(self):
for p in vars(self):
f = getattr(self, p)
if isinstance(f, Body):
yield f
def 获取坐标和速度(self, 天体名称):
pos, vel = get_body_pos_vel(天体名称)
return pos, vel
def 造物(self):
pass
def 摄像机看向(self, 物体):
camera.look_at(物体)
camera.rotation_z = 0
def on_ready(self):
from ursina import application
# application.time_scale = 0.0001
# 运行前触发
self.sky = create_sphere_sky(texture="bg_pan2.jpg", scale=500000, rotation_x=20, rotation_y=160, rotation_z=20)
# UrsinaConfig.trail_type = "line"
# UrsinaConfig.trail_length = 91
# UrsinaConfig.trail_type = "line"
UrsinaConfig.trail_length = 420
# UrsinaConfig.trail_length = 1000
UrsinaConfig.trail_factor = 3
UrsinaConfig.trail_thickness_factor = 3
camera.clip_plane_near = 0.1
camera.clip_plane_far = 51000000
# camera.position=[1000,1000,-1000]
# from sim_scenes.func import create_sphere_sky
# create_sphere_sky(scale=500000)
#
# # 为了较好的立体效果,可以增加太阳光线,光线指向木星(target=jupiter)
# create_directional_light(position=(10.5e3, -1e3, -175e3), light_num=1, target=moon, look_at_target_always=True)
def 运行(self, 全屏=False):
# 使用 ursina 查看的运行效果
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
bodies = list(self.获取天体列表())
UrsinaEvent.on_ready_subscription(self.on_ready)
# UrsinaEvent.on_timer_changed_subscription(on_timer_changed)
ursina_run(bodies, SECONDS_PER_DAY, position=(0, 0, -2*AU),
cosmic_bg="",
view_closely=0.001)
# self.app.run()
class 太阳系模拟场景(模拟场景):
def __init__(self):
self.造物()
def set_bodies_position(self, time_data: TimeData):
"""
设置天体的位置(包含速度和加速度的信息)
@param time_data:
@return:
"""
t = self.start_time + time_data.total_days
set_solar_system_celestial_position(self.bodies, t, True, self.地月距离放大倍数)
def show_clock(self, time_data):
"""
显示时钟
@param dt: 时间 datetime
@return:
"""
# if self.clock_position_center:
# position, origin = (0, .25), (0, 0),
# else:
from ursina import window
dt = time_data.get_datetime(self.start_time)
aspect_ratio = window.aspect_ratio
position, origin = (0.5 * aspect_ratio - 0.15, -0.45), (-0.05, 0.1),
ControlUI.current_ui.show_message(dt.strftime('%Y-%m-%d'),
position=position,
origin=origin,
# font="verdana.ttf",
font="fonts/Digital-7Mono.TTF",
font_scale=2,
font_color=(0, 255, 0),
close_time=-1)
def on_timer_changed(self, time_data: TimeData):
"""
@param time_data:
@return:
"""
dt = time_data.get_datetime(str(self.start_time))
year = dt.strftime("%Y")
self.set_bodies_position(time_data)
self.show_clock(time_data)
def 运行(self, 运行时间=None, 全屏=False):
# 使用 ursina 查看的运行效果
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
self.地月距离放大倍数 = 50
if isinstance(运行时间, str):
self.start_time = conv_to_astropy_time(运行时间)
else:
self.start_time = 运行时间
if self.start_time is None:
from astropy.time import Time
self.start_time = Time.now()
self.bodies = list(self.获取天体列表())
UrsinaEvent.on_ready_subscription(self.on_ready)
UrsinaEvent.on_timer_changed_subscription(self.on_timer_changed)
ursina_run(self.bodies, SECONDS_PER_DAY, position=(0, 0, -2 * AU),
cosmic_bg="",
gravity_works=False,
timer_enabled=True,
show_grid=False,
show_camera_info=False,
view_closely=0.001)
\ No newline at end of file
# -*- coding:utf-8 -*-
# title :太阳地球月球模拟
# description :太阳地球月球模拟
# date :2024-03-20
# python_version :3.9
# ==============================================================================
from 引力世界 import 造物主
from 引力世界.模拟场景 import 太阳系模拟场景
class 太阳地球月球模拟(太阳系模拟场景):
def 造物(self):
太阳坐标, 太阳速度 = self.获取坐标和速度('太阳')
地球坐标, 地球速度 = self.获取坐标和速度('地球')
月球坐标, 月球速度 = self.获取坐标和速度('月球')
self.太阳 = 造物主.造物(名称='太阳', 初始位置=太阳坐标, 初始速度=太阳速度, 缩放大小=1e1)
self.地球 = 造物主.造物(名称='地球', 初始位置=地球坐标, 初始速度=地球速度, 缩放大小=5.5e2)
self.月球 = 造物主.造物(名称='月球', 初始位置=月球坐标, 初始速度=月球速度, 缩放大小=5e2)
# print(self.太阳)
场景 = 太阳地球月球模拟()
# 场景.摄像机看向(场景.地球)
场景.运行(运行时间='1982-09-24 00:00:00')
# -*- coding:utf-8 -*-
# title :造物主
# description :造物主
# author :Python超人
# date :2024-03-20
# link :https://gitcode.net/pythoncr/
# python_version :3.9
# ==============================================================================
"""
要在PyCharm中关闭“Non-ASCII characters in an identifier”警告,您可以按照以下步骤操作:
1. 打开PyCharm,并转到"File" -> "Settings"。
2. 在设置窗口中,选择"Editor" -> "Inspections"。
3. 在右侧的搜索框中输入"Non-ASCII characters in an identifier"。
4. 在搜索结果中找到这个警告 Non-ASCII,并取消勾选相应的复选框以禁用该警告。
5. 点击"Apply"和"OK"保存更改并关闭设置窗口。
"""
import inspect
class 造物主:
registered_objs = {}
@staticmethod
def 造物(名称: str, **kwargs):
o = 造物主.取物(名称, **kwargs)
# current_method = inspect.currentframe().f_code.co_name
return o
@staticmethod
def 取物(名称, **kwargs):
cls = 造物主.registered_objs.get(名称, None)
if cls is None:
return None
return cls(**kwargs)
@staticmethod
def 登记(名称, 类型):
if isinstance(名称, list):
for in 名称:
造物主.registered_objs[str().lower()] = 类型
造物主.registered_objs[str(名称).lower()] = 类型
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册