diff --git a/common/celestial_data_service.py b/common/celestial_data_service.py index 51a78549bf2069cf29cd7685bd72d1c77b1a1e6a..fc156e9715be7e2d37fec0308cff8e1f5f4b97c6 100644 --- a/common/celestial_data_service.py +++ b/common/celestial_data_service.py @@ -9,7 +9,9 @@ import math import numpy as np - +import pytz +from astropy.coordinates import get_body_barycentric_posvel +from astropy.time import Time from bodies import Body, Sun, Asteroids, Moon, Earth from common.consts import G, AU, SECONDS_PER_DAY @@ -269,13 +271,15 @@ def show_bodies_posvels(dt): earth_pos_vel[1].z.to(u.km / u.second)]) -def gen_real_pos_vel_bodies(body_names, dt): +def gen_real_pos_vel_bodies(body_names='sun,mercury,venus,earth,mars,jupiter,saturn,uranus,neptune', dt=None): 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 # 单位 + if dt is None: + dt = Time.now() # from astropy.coordinates import solar_system_ephemeris as sse print("北京时间:", dt.to_datetime(timezone=pytz.timezone('Asia/Shanghai'))) gen_body_str = " init_pos_vels = {}\n" @@ -358,6 +362,42 @@ def init_bodies_pos_vels(bodies): body.init_velocity = pos_vels['vel'] +def init_bodies_reality_pos_vels(bodies, dt=None): + from astropy.coordinates import solar_system_ephemeris as sse + if dt is None: + dt = Time.now() + # from astropy.coordinates import solar_system_ephemeris as sse + print("北京时间:", dt.to_datetime(timezone=pytz.timezone('Asia/Shanghai'))) + gen_body_str = " init_pos_vels = {}\n" + + # for body_name in str(body_names).split(","): + # earth_pos_vel = get_body_barycentric_posvel(body_name, dt) + # pos, vel = earth_pos_vel[0], earth_pos_vel[1] + # + # # 获取模拟的初始位置和速度 + # init_pos_vels = gen_real_pos_vel_bodies(dt=dt) + + for body in bodies: + body_name = type(body).__name__.lower() + + if body_name not in sse.bodies: + continue + + earth_pos_vel = get_body_barycentric_posvel(body_name, dt) + if earth_pos_vel is None: + continue + pos, vel = earth_pos_vel[0], earth_pos_vel[1] + # pos_vels = init_pos_vels.get(type(body).__name__.lower(), None) + # if pos_vels is None: + # continue + pos, vel = [pos.x.value * AU, pos.z.value * AU, pos.y.value * AU], \ + [vel.x.value * AU / SECONDS_PER_DAY, + vel.z.value * AU / SECONDS_PER_DAY, + vel.y.value * AU / SECONDS_PER_DAY] + + body.init_position = pos + body.init_velocity = vel + if __name__ == '__main__': from astropy.time import Time # 时间 diff --git a/sim_scenes/solar_system/halley_comet_sim_02.py b/sim_scenes/solar_system/halley_comet_sim_02.py new file mode 100644 index 0000000000000000000000000000000000000000..904ce209a3b939a441cd56e3bf89e03bb8275498 --- /dev/null +++ b/sim_scenes/solar_system/halley_comet_sim_02.py @@ -0,0 +1,158 @@ +# -*- coding:utf-8 -*- +# title :哈雷彗星场景模拟 +# description :哈雷彗星场景模拟 +# author :Python超人 +# date :2023-10-25 +# link :https://gitcode.net/pythoncr/ +# python_version :3.9 +# ============================================================================== +import time + +from ursina import camera, application + +from bodies import Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto +from common.celestial_data_service import get_init_pos_vels, init_bodies_reality_pos_vels +from common.consts import SECONDS_PER_YEAR, AU +from common.func import calculate_distance +from objs import HalleComet, Obj +from sim_scenes.func import camera_look_at, two_bodies_colliding, create_text_panel +from sim_scenes.func import ursina_run, create_sphere_sky +from simulators.ursina.ursina_config import UrsinaConfig +from simulators.ursina.ursina_event import UrsinaEvent +from simulators.ursina.ursina_mesh import create_orbit_line + + +class HalleyCometSim: + """ + 哈雷彗星场景模拟 + """ + + def __init__(self): + pass + + def build_solar_system(self): + # region 构建太阳系 + self.sun = Sun(size_scale=0.8e2, show_trail=False) + self.mercury = Mercury(size_scale=5e3, show_trail=False) + self.venus = Venus(size_scale=5e3, show_trail=False) + self.earth = Earth(size_scale=5e3, rotate_angle=0, show_trail=False) + self.mars = Mars(size_scale=5e3, show_trail=False) + self.jupiter = Jupiter(size_scale=2.5e3, show_trail=False) + self.saturn = Saturn(size_scale=2.5e3, show_trail=False) + self.uranus = Uranus(size_scale=6e3, show_trail=False) + self.neptune = Neptune(size_scale=6e3, show_trail=False) + self.pluto = Pluto(size_scale=1e5, show_trail=False) + self.bodies = [ + self.sun, # 太阳 + self.mercury, # 水星 + self.venus, # 金星 + self.earth, # 地球 + self.mars, # 火星 + self.jupiter, # 木星 + self.saturn, # 土星 + self.uranus, # 天王星 + self.neptune, # 海王星 + self.pluto, # 冥王星 + ] + # endregion + + init_bodies_reality_pos_vels(self.bodies) + + def build_halley_comet(self): + """ + 创建哈雷彗星 + @return: + """ + # 哈雷彗星的平均运行速度约为每小时 70,000 英里或每小时 126,000 公里 。(35公里/秒) + # 每76.1年环绕太阳一周的周期彗星 + # 3.335, 0, 10.7 73 + # 3.33, 0, 10.7 73 + # [3.335, 0, 10.699] 71 + # [3.33, 0, 10.655] 68 + # [3.33, 0, 10.66] 69 + self.halley_comet = HalleComet( # size_scale=4e7, + size_scale=1e8, + init_velocity=[3.34, 0, 10.7], # [3.33, 0, 10.6] < ? <[3.34, 0, 10.7] + init_position=[0, 0.5 * AU, -10 * AU]) \ + .set_light_disable(True) + + self.bodies.append(self.halley_comet) + + def build(self): + self.build_solar_system() + self.build_halley_comet() + + def on_ready(self): + """ + 事件绑定后,模拟器运行前会触发 + @return: + """ + # 创建天空 + from ursina import scene + UrsinaConfig.trail_type = "line" + UrsinaConfig.trail_length = 91 + UrsinaConfig.trail_thickness_factor = 3 + # camera.clip_plane_near = 0.1 + camera.clip_plane_far = 1000000 + create_sphere_sky(scale=200000) + application.time_scale = 5 + self.orbit_lines = [] + for body in self.bodies[1:]: + if isinstance(body, HalleComet): + continue + print("create_orbit_line", body) + orbit_line = create_orbit_line(self.sun, body) + orbit_line.body = body + self.orbit_lines.append(orbit_line) + + self.text_panel = create_text_panel() + + def on_timer_changed(self, time_data): + """ + + @param time_data: + @return: + """ + # 哈雷彗星飞行的翻转效果 + if self.halley_comet.planet.enabled: + self.halley_comet.planet.rotation_x += 0.1 + self.halley_comet.planet.rotation_y += 1 + # 摄像机始终看向哈雷彗星 + # camera_look_at(self.halley_comet) + d = calculate_distance(self.halley_comet.position, self.sun.position) + self.text_panel.text = "哈雷彗星距离太阳:%.3f AU" % (d / AU) + + for i, orbit_line in enumerate(self.orbit_lines): + if i < 4: + adj_scale = False + else: + adj_scale = True + # 由于天体运行不是标准的圆形,则需要动态调整轨道的大小,保证轨道线始终在天体的中心位置 + orbit_line.auto_adjust(adj_scale=adj_scale) + + +if __name__ == '__main__': + """ + 哈雷彗星场景模拟 + """ + sim = HalleyCometSim() + sim.build() + # 订阅事件后,上面2个函数功能才会起作用 + # 运行中,每时每刻都会触发 on_timer_changed + UrsinaEvent.on_timer_changed_subscription(sim.on_timer_changed) + # 运行前会触发 on_ready + UrsinaEvent.on_ready_subscription(sim.on_ready) + # 使用 ursina 查看的运行效果 + # 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹 + # position = 左-右+、上+下-、前+后- + ursina_run(sim.bodies, + SECONDS_PER_YEAR, + # position=(0, 2 * AU, -11 * AU), + position=(0, 0.5 * AU, -5 * AU), + cosmic_bg='', + show_trail=True, + # bg_music='sounds/no_glory.mp3', + show_camera_info=False, + show_control_info=False, + show_timer=True, + show_grid=False)