From 3d734e8ca8cc802e93fa748b0e2e9814e74f84c8 Mon Sep 17 00:00:00 2001 From: march3 Date: Mon, 25 Mar 2024 12:47:13 +0800 Subject: [PATCH] =?UTF-8?q?Python=E8=B6=85=E4=BA=BA-=E5=AE=87=E5=AE=99?= =?UTF-8?q?=E6=A8=A1=E6=8B=9F=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/celestial_data_service.py | 22 ++- .../__init__.py" | 4 + .../\345\244\252\351\230\263\347\263\273.py" | 23 +++ ...51\344\275\223\346\225\260\346\215\256.py" | 97 ++++++++++ ...41\346\213\237\345\234\272\346\231\257.py" | 166 ++++++++++++++++++ ...60\347\220\203\346\234\210\347\220\203.py" | 28 +++ .../\351\200\240\347\211\251\344\270\273.py" | 47 +++++ 7 files changed, 383 insertions(+), 4 deletions(-) create mode 100644 "\345\274\225\345\212\233\344\270\226\347\225\214/__init__.py" create mode 100644 "\345\274\225\345\212\233\344\270\226\347\225\214/\344\270\207\347\211\251/\345\244\252\351\230\263\347\263\273.py" create mode 100644 "\345\274\225\345\212\233\344\270\226\347\225\214/\346\225\260\346\215\256/\345\244\251\344\275\223\346\225\260\346\215\256.py" create mode 100644 "\345\274\225\345\212\233\344\270\226\347\225\214/\346\250\241\346\213\237\345\234\272\346\231\257.py" create mode 100644 "\345\274\225\345\212\233\344\270\226\347\225\214/\346\250\241\346\213\237\345\256\236\351\252\214\345\256\244/\345\244\252\351\230\263\347\263\273/\345\244\252\351\230\263\345\234\260\347\220\203\346\234\210\347\220\203.py" create mode 100644 "\345\274\225\345\212\233\344\270\226\347\225\214/\351\200\240\347\211\251\344\270\273.py" diff --git a/common/celestial_data_service.py b/common/celestial_data_service.py index 276a1b3..a682921 100644 --- a/common/celestial_data_service.py +++ b/common/celestial_data_service.py @@ -54,6 +54,20 @@ def get_body_posvel(body, time=None): if not isinstance(body, str): 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) return posvel @@ -76,7 +90,7 @@ def get_bodies_posvels(planet_names="sun,mercury,venus,earth,moon,mars,jupiter,s return posvels -def recalc_moon_position(moon_posvel, earth_pos): +def recalc_moon_position(moon_posvel, earth_pos, scale=50): """ 重新计算月球的位置(由于月球和地球的距离在整个太阳系尺度下非常近,为了较好的显示效果,需要放大月球和地球的距离,但不要改变月球相对地球的位置) @param moon_posvel: 月球的三维坐标位置和三维矢量速度 @@ -85,7 +99,7 @@ def recalc_moon_position(moon_posvel, earth_pos): """ moon_pos, moon_vel = moon_posvel[0], moon_posvel[1] 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 @@ -109,7 +123,7 @@ def get_celestial_body_data(body_name): 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): """ 根据日期时间 dt 设置太阳系中天体的真实位置 @@ -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] # TODO:注释下行,月球就会在真实的位置 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: # posvel 为空,则使用太阳的坐标 diff --git "a/\345\274\225\345\212\233\344\270\226\347\225\214/__init__.py" "b/\345\274\225\345\212\233\344\270\226\347\225\214/__init__.py" new file mode 100644 index 0000000..2a2709d --- /dev/null +++ "b/\345\274\225\345\212\233\344\270\226\347\225\214/__init__.py" @@ -0,0 +1,4 @@ +from 引力世界.造物主 import 造物主 +from 引力世界.模拟场景 import 模拟场景 + +from 引力世界.万物.太阳系 import * diff --git "a/\345\274\225\345\212\233\344\270\226\347\225\214/\344\270\207\347\211\251/\345\244\252\351\230\263\347\263\273.py" "b/\345\274\225\345\212\233\344\270\226\347\225\214/\344\270\207\347\211\251/\345\244\252\351\230\263\347\263\273.py" new file mode 100644 index 0000000..2011d81 --- /dev/null +++ "b/\345\274\225\345\212\233\344\270\226\347\225\214/\344\270\207\347\211\251/\345\244\252\351\230\263\347\263\273.py" @@ -0,0 +1,23 @@ +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'], 月球) diff --git "a/\345\274\225\345\212\233\344\270\226\347\225\214/\346\225\260\346\215\256/\345\244\251\344\275\223\346\225\260\346\215\256.py" "b/\345\274\225\345\212\233\344\270\226\347\225\214/\346\225\260\346\215\256/\345\244\251\344\275\223\346\225\260\346\215\256.py" new file mode 100644 index 0000000..b2848c6 --- /dev/null +++ "b/\345\274\225\345\212\233\344\270\226\347\225\214/\346\225\260\346\215\256/\345\244\251\344\275\223\346\225\260\346\215\256.py" @@ -0,0 +1,97 @@ +天体信息 = {"太阳": { + "质量": 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) diff --git "a/\345\274\225\345\212\233\344\270\226\347\225\214/\346\250\241\346\213\237\345\234\272\346\231\257.py" "b/\345\274\225\345\212\233\344\270\226\347\225\214/\346\250\241\346\213\237\345\234\272\346\231\257.py" new file mode 100644 index 0000000..e92278d --- /dev/null +++ "b/\345\274\225\345\212\233\344\270\226\347\225\214/\346\250\241\346\213\237\345\234\272\346\231\257.py" @@ -0,0 +1,166 @@ +# -*- 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 diff --git "a/\345\274\225\345\212\233\344\270\226\347\225\214/\346\250\241\346\213\237\345\256\236\351\252\214\345\256\244/\345\244\252\351\230\263\347\263\273/\345\244\252\351\230\263\345\234\260\347\220\203\346\234\210\347\220\203.py" "b/\345\274\225\345\212\233\344\270\226\347\225\214/\346\250\241\346\213\237\345\256\236\351\252\214\345\256\244/\345\244\252\351\230\263\347\263\273/\345\244\252\351\230\263\345\234\260\347\220\203\346\234\210\347\220\203.py" new file mode 100644 index 0000000..6ca5f83 --- /dev/null +++ "b/\345\274\225\345\212\233\344\270\226\347\225\214/\346\250\241\346\213\237\345\256\236\351\252\214\345\256\244/\345\244\252\351\230\263\347\263\273/\345\244\252\351\230\263\345\234\260\347\220\203\346\234\210\347\220\203.py" @@ -0,0 +1,28 @@ +# -*- 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') diff --git "a/\345\274\225\345\212\233\344\270\226\347\225\214/\351\200\240\347\211\251\344\270\273.py" "b/\345\274\225\345\212\233\344\270\226\347\225\214/\351\200\240\347\211\251\344\270\273.py" new file mode 100644 index 0000000..bd0fab7 --- /dev/null +++ "b/\345\274\225\345\212\233\344\270\226\347\225\214/\351\200\240\347\211\251\344\270\273.py" @@ -0,0 +1,47 @@ +# -*- 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()] = 类型 + + -- GitLab