From 47ff8692d65467cc256847872dc9c596d2e5258c Mon Sep 17 00:00:00 2001 From: march3 Date: Fri, 24 Nov 2023 16:19:11 +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 --- ...1\345\222\214\346\227\266\351\227\264.jpg" | Bin 0 -> 37470 bytes .../halley_comet_sim_02.py | 0 .../halley_comet_sim_03.py | 0 sim_lab/oumuamua_sim.py | 488 ++++++++++++++++++ 4 files changed, 488 insertions(+) create mode 100644 "docs/oumuamua/\350\277\220\350\241\214\350\275\250\350\277\271\345\222\214\346\227\266\351\227\264.jpg" rename {sim_scenes/solar_system => sim_lab}/halley_comet_sim_02.py (100%) rename {sim_scenes/solar_system => sim_lab}/halley_comet_sim_03.py (100%) create mode 100644 sim_lab/oumuamua_sim.py diff --git "a/docs/oumuamua/\350\277\220\350\241\214\350\275\250\350\277\271\345\222\214\346\227\266\351\227\264.jpg" "b/docs/oumuamua/\350\277\220\350\241\214\350\275\250\350\277\271\345\222\214\346\227\266\351\227\264.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..66b41d21280d52b93fc622dd1b89f9fdb4a113bb GIT binary patch literal 37470 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 literal 0 HcmV?d00001 diff --git a/sim_scenes/solar_system/halley_comet_sim_02.py b/sim_lab/halley_comet_sim_02.py similarity index 100% rename from sim_scenes/solar_system/halley_comet_sim_02.py rename to sim_lab/halley_comet_sim_02.py diff --git a/sim_scenes/solar_system/halley_comet_sim_03.py b/sim_lab/halley_comet_sim_03.py similarity index 100% rename from sim_scenes/solar_system/halley_comet_sim_03.py rename to sim_lab/halley_comet_sim_03.py diff --git a/sim_lab/oumuamua_sim.py b/sim_lab/oumuamua_sim.py new file mode 100644 index 0000000..c86314a --- /dev/null +++ b/sim_lab/oumuamua_sim.py @@ -0,0 +1,488 @@ +# -*- coding:utf-8 -*- +# title :哈雷彗星场景半真实模拟 +# description :哈雷彗星运行轨道使用了万有引力,其他天体使用 astropy 包的真实数据 +# author :Python超人 +# date :2023-10-28 +# link :https://gitcode.net/pythoncr/ +# python_version :3.9 +# ============================================================================== +from dataclasses import dataclass +from dataclasses import field +from ursina import camera, application, lerp, Vec3 + +from common.celestial_data_service import init_bodies_reality_pos_vels, conv_to_astropy_time, \ + set_solar_system_celestial_position +from common.consts import SECONDS_PER_YEAR, AU +from common.func import calculate_distance +from bodies import Earth +from sim_scenes.func import create_text_panel, camera_look_at, get_run_speed_factor, \ + camera_move_update, camera_move_to_target_update, camera_move_control +from sim_scenes.func import ursina_run, create_sphere_sky +from simulators.ursina.entities.body_timer import TimeData +from simulators.ursina.entities.entity_utils import get_value_direction_vectors +from simulators.ursina.ui.control_ui import ControlUI +from simulators.ursina.ursina_config import UrsinaConfig +from simulators.ursina.ursina_event import UrsinaEvent +from simulators.ursina.ursina_mesh import create_label + + +@dataclass(order=True) +class OumuamuaParams: + start_time: str = field(default='1983-03-20 00:00:00') + init_velocity: list[float] = field(default_factory=[3.34, 0, 10.718]) + init_position: list[float] = field(default_factory=[0, 0.5 * AU, -10 * AU]) + + +class OumuamuaSim: + """ + 星际访客奥陌陌 + 重要时间点: + + """ + + def __init__(self, _params=None): + # super(OumuamuaParams, self).__init__() + if _params is None: + self.params = OumuamuaParams() + else: + self.params = _params + + if isinstance(_params.start_time, str): + self.start_time = conv_to_astropy_time(_params.start_time) + else: + self.start_time = _params.start_time + + # print("北京时间:", dt.to_datetime(timezone=pytz.timezone('Asia/Shanghai'))) + + def build(self): + """ + 构建太阳系系统以及哈雷彗星 + @return: + """ + self.build_solar_system(ignore_gravity=True, start_time=self.start_time) + self.sun.glows = (2, 1.005, 0.01) + # 创建哈雷彗星创建哈雷彗星 + self.halley_comet = create_halley_comet(self.params.init_velocity, self.params.init_position) + + self.bodies.append(self.halley_comet) + + # from objs import CameraTarget + # + # self.bodies.append(CameraTarget(size_scale=2e8, init_position=[0, 0, 0], color=(255, 0, 0))) + # self.bodies.append(CameraTarget(size_scale=2e8, init_position=[5 * AU, 0, 0], color=(255, 255, 0))) + + # print(CameraTarget.targets) + + def init_settings(self): + """ + 初始化设置 + @return: + """ + from ursina import color + # 创建天空 + create_sphere_sky(scale=50000) + # UrsinaConfig.trail_type = "curve_line" + # UrsinaConfig.trail_length = 300 + UrsinaConfig.trail_type = "line" + # UrsinaConfig.trail_length = 152 # 尾巴数量刚刚好 + UrsinaConfig.trail_length = 130 + UrsinaConfig.trail_thickness_factor = 3 + + # UrsinaConfig.trail_length = 180 + UrsinaConfig.trail_factor = 3 + + # camera.clip_plane_near = 0.1 + camera.clip_plane_far = 51000 + # camera.fov = 60 + + # self.sun.planet.color = color.white + + # application.time_scale = 0.01 + # 摄像机移动 update + # camera_move_update() + # camera_move_to_target_update() + + def create_orbit_lines(self): + """ + 创建太阳系天体的真实轨迹(太阳和哈雷彗星除外) + @return: + """ + self.orbit_lines = [] + for body in self.bodies[1:]: + if isinstance(body, Earth): + alpha = 0.5 + else: + alpha = 0.2 + orbit_line = create_orbit_line(self.sun, body, self.start_time, alpha=alpha) + if orbit_line is not None: + self.orbit_lines.append(orbit_line) + + 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, False) + + def create_year_label(self, trail, year, + halley_comet_pos=None, + pos=None, + label_color=None, + scale=40, + background=False): + """ + 在界面上创建年份的标签 + @param trail: + @param year: + @param halley_comet_pos: + @return: + """ + # 为了不影响 2023年12月9日的显示,附近的 Label 就不显示 + # if year in ["1986", "2061", "2023"]: + # return + + if trail is None: + _pos = halley_comet_pos + else: + _pos = pos + if _pos is None: + _pos = (0, 0, 0) + + if label_color is None: + label_color = (255, 255, 255, 255) + + label = create_label(trail, label=year, pos=_pos, + label_color=label_color, + font="fonts/DroidSansFallback.ttf", + scale=scale, alpha=1.0, background=background + ) + label.set_light_off() + # 只记录年 + if len(str(year)) == 4: + self.last_year = year + + def update_comet_trail_alpha(self, distance_sun): + """ + 根据彗哈雷星和太阳的距离,设置彗星尾巴的透明度来模仿接近太阳有慧尾,离开太阳到一定距离就渐渐消失 + @param distance_sun: 彗哈雷星和太阳的距离 + @return: + """ + # 距离转为天文单位 + d_au = distance_sun / AU + # 渐渐消失的距离范围(开始消失距离, 完全消失距离) + HIDE_DISTANCE = 3, 12 + # 彗星最大的透明度 + MAX_ALPHA = 0.8 + + # 大于完全消失距离 + if d_au >= HIDE_DISTANCE[1]: + alpha = 0 + elif HIDE_DISTANCE[1] > d_au > HIDE_DISTANCE[0]: # 渐渐消失的距离范围内,通过距离值大小确定透明度(慢慢消失的效果) + alpha = MAX_ALPHA - (d_au - HIDE_DISTANCE[0]) / (HIDE_DISTANCE[1] - HIDE_DISTANCE[0]) * MAX_ALPHA + else: + alpha = MAX_ALPHA + # 修改彗星尾巴的透明度 + self.halley_comet.planet.comet_trail.set_alpha(alpha) + # self.halley_comet.planet.comet_sphere.alpha = alpha + + def show_milestone_lable(self, last_trail, dt): + """ + 远日点: 35.1 AU(2023年12月9日) + 近日点: 0.586 AU 上次通过近日点:1986年2月9日 下次通过近日点:2061年7月28日 + @param last_trail: + @param dt: + @return: + """ + milestones = [("1986-02-09", (0, 2, 0)), ("2023-12-09", (0, 0, -3)), ("2061-07-28", (0, 3, 0))] + for milestone, pos in milestones: + prop_name = f"milestone_{milestone}" + if not hasattr(self, prop_name) and dt.strftime("%Y-%m-%d") >= milestone: + setattr(self, prop_name, milestone) + if pos is None: + pos = (0, 2, 0) + self.create_year_label(last_trail, milestone, label_color=(0, 255, 0), + pos=pos, scale=60, + background=True) + # application.paused = True + # UrsinaEvent.on_pause() + # ControlUI.current_ui.on_off_switch.on_value_changed() + + def s_f(self, value=1): + if value == 0: + return 0 + return get_run_speed_factor() * value + + def camera_move(self, dt): + """ + 摄像机移动控制 + @param dt: + @return: + """ + # 摄像机移动控制数据 + camera_move_infos = [ + # 条件:年份 + # 移动的信息: + # 按坐标系方向移动 x:右+左-, y:升+降-, z:前+(接近太阳)后-(远离太阳) + # 以摄像机视角移动 f:前 b:后 l:左 r:右 u:上 d:下 + (1982, {"x": 2, "y": 1}), + # (1983, {"to": {"ct_id": 1, "t": 10}}), + (1986, {"x": 2, "y": -2, "z": -15}), + (1987, {"y": -6, "z": -12}), + (1988, {"y": -3, "z": -12}), + (1989, {"z": -8, "f": -5}), + (1993, {"z": -8, "f": -3}), + (1995, {"z": -8}), + (2000, {"z": -8, "y": -0.2}), + (2013, {}), + (2048, {"f": 3}), + (2062, {"y": -3}), + (2063, {"y": -10, "z": 2}), + (2181, {}), + # (2082, {"exit": True}) + ] + + camera_move_control(camera_move_infos, + cond_cb=lambda ps: ps["next_cond"] > dt.year >= ps["cond"], + value_conv=self.s_f, smooth=10) + + def check_create_year_label(self, last_trail, dt): + """ + 检测并创建年标签 + @param last_trail: + @param dt: + @return: + """ + if last_trail is None: + return + + import copy + year = dt.strftime("%Y") + pos = self.halley_comet.planet.position + # 里程碑标签 + if self.show_milestone_lable(last_trail, dt): + pass + elif not hasattr(self, "last_year"): + # 第一次运行,则创建“年标签” + self.create_year_label(last_trail, year, pos) + self.last_label_pos = copy.deepcopy(self.halley_comet.position) + elif self.last_year != year: + if hasattr(self, "last_label_pos"): + # 防止“年标签”显示非常紧密 + d = calculate_distance(self.halley_comet.position, self.last_label_pos) + if d > 2 * AU: + self.create_year_label(last_trail, year, pos) + self.last_label_pos = copy.deepcopy(self.halley_comet.position) + + def update_halley_comet_info(self, dt): + """ + 更新哈雷彗星的信息 + @param dt: + @return: + """ + # 哈雷彗星面向太阳,这样彗尾就远离太阳的方向 + self.halley_comet.planet.look_at(self.sun.planet) + + # 计算哈雷彗星与太阳、地球的距离 + d_sun = calculate_distance(self.halley_comet.position, self.sun.position) + d_earth = calculate_distance(self.halley_comet.position, self.earth.position) + # 哈雷彗星所有轨迹线(注意不是彗尾) + trail_keys = self.halley_comet.planet.trails.keys() + # 哈雷彗星有轨迹线 + if len(trail_keys) > 0: + # 找的最后的轨迹线 + last_trail = list(trail_keys)[-1] + if hasattr(last_trail, "entity_infos"): + # 如果是轨迹球,则轨迹球会记录当前位置与太阳、地球的距离,并记录了当前的日期 + last_trail.entity_infos["distance_from_sun"] = d_sun + last_trail.entity_infos["distance_from_earth"] = d_earth + last_trail.entity_infos["time"] = dt.strftime("%Y-%m-%d") + + # 检测并再轨迹线上创建年标签 + self.check_create_year_label(last_trail, dt) + + # 更新彗星尾巴的透明度 + self.update_comet_trail_alpha(d_sun) + + # 计算和更新近日点数据 + self.update_comet_peri(d_sun, dt) + # 计算和更新远日点数据 + self.update_comet_aphel(d_sun, dt) + # 更新文字信息面板 + self.update_text_panel(d_sun) + + def update_text_panel(self, d_sun): + """ + 更新文字信息面板 + @param d_sun: + @return: + """ + panel_text = "哈雷彗星:\n\n当前日距:%s AU" % "{:.3f}".format(d_sun / AU).rjust(6, "0") + panel_text += "\n\n最大日距:%s AU" % "{:.3f}".format(self.comet_aphel / AU).rjust(6, "0") + panel_text += "\n\n最小日距:%s AU" % "{:.3f}".format(self.comet_peri / AU).rjust(6, "0") + velocity, _ = get_value_direction_vectors(self.halley_comet.velocity) + panel_text += "\n\n当前速度:%s km/s" % "{:.3f}".format(velocity).rjust(6, "0") + + self.text_panel.text = panel_text + + def update_comet_aphel(self, d_sun, dt): + """ + 计算和更新远日点数据 + @param d_sun: + @param dt: + @return: + """ + # 哈雷彗星离太阳最远的点称为 "aphelion of Halley's Comet"(远日点) + if not hasattr(self, "comet_aphel"): + self.comet_aphel = d_sun + self.comet_aphel_dt = dt.strftime("%Y-%m-%d") + elif d_sun > self.comet_aphel: + self.comet_aphel = d_sun + self.comet_aphel_dt = dt.strftime("%Y-%m-%d") + + def update_comet_peri(self, d_sun, dt): + """ + 计算和更新近日点数据 + @param d_sun: + @param dt: + @return: + """ + # 哈雷彗星离太阳最近的点称为 "perihelion of Halley's Comet"(近日点:comet_peri), + if not hasattr(self, "comet_peri"): + self.comet_peri = d_sun + self.comet_peri_dt = dt.strftime("%Y-%m-%d") + elif d_sun < self.comet_peri: + self.comet_peri = d_sun + self.comet_peri_dt = dt.strftime("%Y-%m-%d") + + def update_ui(self, time_data, dt): + """ + 更新UI,包含天体的位置、时钟、轨道的位置 + @param time_data: + @param dt: + @return: + """ + if dt.year > 2041: + UrsinaConfig.trail_length = 210 + # 更新天体的位置 + self.set_bodies_position(time_data) + # # 更新时钟 + # self.show_clock(dt) + # 更新轨道的位置(TODO:短时间可以忽略) + # for i, orbit_line in enumerate(self.orbit_lines): + # orbit_line.position = self.sun.planet.position + + def on_ready(self): + """ + 事件绑定后,模拟器运行前会触发 + @return: + """ + # 初始化设置 + self.init_settings() + + # self.set_window_size((int(1920 * r), int(1080 * r)), False) + # 最大分辨率的高度-1,保证不全屏 + self.set_window_size((1920, 1079), False) + # self.set_window_size((1920 , 1080 ), False) + # 显示网格以及坐标线 + # self.show_grid_axises() + + # 创建太阳系天体的真实轨迹(太阳和哈雷彗星除外) + self.create_orbit_lines() + # 创建信息显示面板 + # self.text_panel = create_text_panel(font="fonts/sanjixiaozhuanti.ttf", font_scale=1.5) + self.text_panel = create_text_panel(font="fonts/DroidSansFallback.ttf", font_scale=1.3) + + def on_timer_changed(self, time_data): + """ + + @param time_data: + @return: + """ + dt = time_data.get_datetime(self.start_time) + # 摄像机看向哈雷彗星 + camera_look_at(self.halley_comet, rotation_z=0) + # camera.look_at_2d(self.halley_comet.planet.position, axis='y') + + time_total_hours = time_data.total_hours + + # if not hasattr(self, "last_total_hours"): + # self.last_total_hours = time_total_hours + # self.update_halley_comet_info(dt) + # print("time_total_hours", time_total_hours) + # # 摄像机移动每10小时更新一次 + # self.interval_run(fun=self.camera_move, fun_args=[dt], + # total_times=time_total_hours, + # interval=20) + self.camera_move(dt) + + if 2040 > dt.year > 1987: + update_halley_comet_info_interval = 400 + update_clock_interval = 400 + else: + update_halley_comet_info_interval = 33 + update_clock_interval = 60 + + # 更新哈雷彗星信息是每20个小时更新一次(哈雷彗星姿态、哈雷彗星距离信息) + self.interval_run(fun=self.update_halley_comet_info, fun_args=[dt], + total_times=time_total_hours, + interval=update_halley_comet_info_interval) + + # 每50个小时更新一次界面(天体位置) + self.interval_run(fun=self.update_ui, fun_args=[time_data, dt], + total_times=time_total_hours, + interval=60) + + self.interval_run(fun=self.show_clock, fun_args=[dt], + total_times=time_total_hours, + interval=update_clock_interval) + + # # 每隔一段时间运行一次更新(不要太频繁更新,会导致摄像机抖动) + # if time_total_hours - self.last_total_hours > 50: + # self.update_halley_comet_info(dt) + # self.update_ui(time_data, dt) + # # 记录最后更新的总耗时(小时) + # self.last_total_hours = time_total_hours + + +if __name__ == '__main__': + """ + 哈雷彗星场景模拟 + """ + # 远日点: 35.1 AU(2023年12月9日) + # 近日点: 0.586 AU 上次通过近日点:1986年2月9日 下次通过近日点:2061年7月28日 + # 2019年5月6日 34.772 + params = OumuamuaParams( + start_time='1982-09-24 00:00:00', + # init_velocity=[-2.80, 5.10, 8.65], # 1/8 + init_velocity=[-2.774, 5.126, 8.65], # 1/8 + init_position=[0, -5 * AU, -10 * AU] + ) + + sim = OumuamuaSim(params) + 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 * get_run_speed_factor(), + # position=(0, 2 * AU, -11 * AU), + # position=(0, 0.5 * AU, -5 * AU), + # position=(2 * AU, -5 * AU, -20 * AU), + position=(2 * AU, -6 * AU, -20 * AU), + cosmic_bg='', + show_trail=True, + # bg_music='sounds/no_glory.mp3', + show_camera_info=False, + # video_recoder=True, + show_control_info=False, + timer_enabled=True, + show_grid=False + ) -- GitLab