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

Python超人-宇宙模拟器

上级 3a39a517
此差异已折叠。
此差异已折叠。
# -*- coding:utf-8 -*-
# title :石头
# description :石头
# author :Python超人
# date :2023-11-10
# link :https://gitcode.net/pythoncr/
# python_version :3.9
# ==============================================================================
from objs.obj import Obj
class Stone(Obj):
"""
石头
"""
def __init__(self, name="石头", mass=5.97237e24,
init_position=[0, 0, 0],
init_velocity=[0, 0, 0],
texture="stone1.png", size_scale=1.0, distance_scale=1.0,
ignore_mass=False, density=1e3, color=(7, 0, 162),
trail_color=None, show_name=False,
model="stone1.obj", rotation=(0, 0, 0),
parent=None, gravity_only_for=[]):
params = {
"name": name,
"mass": mass,
"init_position": init_position,
"init_velocity": init_velocity,
"density": density,
"color": color,
"texture": texture,
"size_scale": size_scale,
"distance_scale": distance_scale,
"ignore_mass": ignore_mass,
"trail_color": trail_color,
"show_name": show_name,
"parent": parent,
"rotation": rotation,
"gravity_only_for": gravity_only_for,
"model": model
}
super().__init__(**params)
# 对岩石进行缩放,保证 create_rock 保证创建的岩石大小差异不会过大
ROCK_SIZE_SCALE_FACTOR = {
6: 0.5,
7: 1e-2
}
def create_stone(no: int = None, **kwargs):
if no is not None:
kwargs["model"] = f"stone{no}.obj"
kwargs["texture"] = f"stone{no}.jpg"
if "size_scale" in kwargs:
kwargs["size_scale"] = kwargs["size_scale"] * ROCK_SIZE_SCALE_FACTOR.get(no, 1.0)
else:
kwargs["size_scale"] = ROCK_SIZE_SCALE_FACTOR.get(no, 1.0)
stone = Stone(**kwargs)
# print(rock)
return stone
if __name__ == '__main__':
# stone = Stone()
# print(stone)
# stone.show_demo(size_scale=1000000)
stone = create_stone(no=2)
stone.show_demo(size_scale=1000000)
# -*- coding:utf-8 -*-
# title :哈雷彗星场景半真实模拟
# description :哈雷彗星运行轨道使用了万有引力,其他天体使用 astropy 包的真实数据
# author :Python超人
# date :2023-10-28
# link :https://gitcode.net/pythoncr/
# python_version :3.9
# ==============================================================================
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 objs import HalleComet, CameraTarget
from sim_scenes.func import create_text_panel, camera_look_at
from sim_scenes.func import ursina_run, create_sphere_sky
from sim_scenes.solar_system.halley_comet_lib import HalleyCometSimBase, HalleyCometParams, \
create_halley_comet, create_orbit_line
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
RUN_SPEED = 1 / 8
class HalleyCometSim(HalleyCometSimBase):
"""
哈雷彗星场景模拟
"""
def __init__(self, _params=None):
super(HalleyCometSim, self).__init__()
if _params is None:
self.params = HalleyCometParams()
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.halley_comet = create_halley_comet(self.params.init_velocity, self.params.init_position)
self.bodies.append(self.halley_comet)
# # 创建一个摄像机跟踪目标
# self.camera_target = CameraTarget(size_scale=1e9)
# self.bodies.append(self.camera_target)
def init_settings(self):
"""
初始化设置
@return:
"""
# 创建天空
create_sphere_sky(scale=200000)
# UrsinaConfig.trail_type = "curve_line"
# UrsinaConfig.trail_length = 300
UrsinaConfig.trail_type = "line"
# UrsinaConfig.trail_length = 152 # 尾巴数量刚刚好
UrsinaConfig.trail_length = 135
UrsinaConfig.trail_thickness_factor = 3
# UrsinaConfig.trail_length = 180
UrsinaConfig.trail_factor = 3
# camera.clip_plane_near = 0.1
camera.clip_plane_far = 1000000
application.time_scale = 5
camera.forward_factor = 0
def camera_update():
camera_look_at(self.halley_comet, rotation_z=0)
if camera.forward_factor != 0:
camera.position += camera.forward * camera.forward_factor
camera.update = camera_update
def on_ready(self):
"""
事件绑定后,模拟器运行前会触发
@return:
"""
# 初始化设置
self.init_settings()
# 显示网格以及坐标线
# self.show_grid_axises()
# 创建太阳系天体的真实轨迹(太阳和哈雷彗星除外)
self.create_orbit_lines()
# 创建信息显示面板
self.text_panel = create_text_panel()
def create_orbit_lines(self):
"""
创建太阳系天体的真实轨迹(太阳和哈雷彗星除外)
@return:
"""
self.orbit_lines = []
for body in self.bodies[1:]:
orbit_line = create_orbit_line(self.sun, body, self.start_time)
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, scale=40, background=False):
"""
在界面上创建年份的标签
@param trail:
@param year:
@param halley_comet_pos:
@return:
"""
# 为了不影响 2023年12月9日的显示,附近的 Label 就不显示
if year in ["1986", "2061", "2023", "2024", "2025"]:
return
if trail is None:
_pos = halley_comet_pos
else:
_pos = pos
if _pos is None:
_pos = (0, 0, 0)
label = create_label(trail, label=year, pos=_pos, color=(255, 255, 255), scale=scale, alpha=1.0,
background=background)
label.set_light_off()
def set_comet_trail_alpha(self, distance_sun):
"""
根据彗哈雷星和太阳的距离,设置彗星尾巴的透明度来模仿接近太阳有慧尾,离开太阳到一定距离就渐渐消失
@param distance_sun: 彗哈雷星和太阳的距离
@return:
"""
# 距离转为天文单位
d_au = distance_sun / AU
# 渐渐消失的距离范围(开始消失距离, 完全消失距离)
HIDE_DISTANCE = 1, 15
# 彗星最大的透明度
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
# 修改彗星尾巴的透明度
c = self.halley_comet.planet.children[0]
c.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, -2, 0)), ("2061-07-28", (0, 2, 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, pos=pos, scale=60, background=True)
# application.paused = True
# UrsinaEvent.on_pause()
def look_at_halley_comet(self, dt):
forward_infos = [
(1983, 0.1 * RUN_SPEED * 12),
(1986, -8 * RUN_SPEED * 12),
(1987, -3 * RUN_SPEED * 12),
(1988, 0),
(2049, 1 * RUN_SPEED * 12),
(2061, 0),
(2062, -5 * RUN_SPEED * 12),
(2066, 0),
(2100, 0),
(2124, 0)
]
for idx, (year, factor) in enumerate(forward_infos[:-1]):
next_year = forward_infos[idx + 1][0]
if next_year > dt.year >= year:
if factor < 0 and camera.position[0] < -3000:
# 最远
continue
camera.forward_factor = factor
# if dt.year > 1986:
# self.camera_target.planet.look_at(self.halley_comet.planet)
# self.camera_target.planet.position = \
# lerp(self.camera_target.planet.position, self.halley_comet.planet.position, 1)
# print(self.camera_target.planet.position, self.halley_comet.planet.position)
# camera_look_at(self.halley_comet, rotation_z=0)
# if 2000 > dt.year >= 1986:
# camera.forward_factor = -0.3 * RUN_SPEED * 12
# elif 2008 > dt.year >= 2000:
# camera.forward_factor = 0
# elif 2064 > dt.year >= 2008:
# camera.forward_factor = 0.3 * RUN_SPEED * 12
# def camera_update():
# camera_look_at(self.halley_comet, rotation_z=0)
# camera.position += camera.forward * -0.3
#
# camera.forward = Vec3(0, 0, 0)
# camera.update = camera_update
# if dt.year > 1986:
# # camera.position += Vec3(0, 0, -1)
# camera.position += camera.forward * -5
def on_timer_changed(self, time_data):
"""
@param time_data:
@return:
"""
dt = time_data.get_datetime(str(self.start_time))
year = dt.strftime("%Y")
# camera_look_at(self.halley_comet)
self.look_at_halley_comet(dt)
if hasattr(self, "halley_comet"):
if self.halley_comet.planet.enabled:
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()
last_trail = list(trail_keys)[-1] # self.halley_comet.planet.trails[list(trail_keys)[-1]]
if hasattr(last_trail, "entity_infos"):
# print(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")
# print(last_trail.entity_infos)
pos = self.halley_comet.planet.position
import copy
if self.show_milestone_lable(last_trail, dt):
pass
elif not hasattr(self, "last_year"):
self.create_year_label(last_trail, year, pos)
elif self.last_year != year:
if not hasattr(self, "last_label_pos"):
self.create_year_label(last_trail, year, pos)
self.last_label_pos = copy.deepcopy(self.halley_comet.position)
else:
# 防止标签非常紧密
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)
self.last_year = year
# 哈雷彗星离太阳最近的点称为 "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")
# 哈雷彗星离太阳最远的点称为 "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")
self.set_comet_trail_alpha(d_sun)
panel_text = "哈雷彗星:\n距离太阳:%.3f AU" % (d_sun / AU)
# panel_text += "\n离日最远:%.3f AU(%s)" % (self.comet_aphel / AU, self.comet_aphel_dt)
panel_text += "\n离日最远:%.3f AU" % (self.comet_aphel / AU)
# panel_text += "\n离日最近:%.3f AU(%s)" % (self.comet_peri / AU, self.comet_peri_dt)
panel_text += "\n离日最近:%.3f AU" % (self.comet_peri / AU)
# panel_text += "\n距离地球:%.3f AU" % (d_earth / AU)
velocity, _ = get_value_direction_vectors(self.halley_comet.velocity)
panel_text += "\n当前速度:%.3f km/s" % velocity
self.text_panel.text = panel_text
self.set_bodies_position(time_data)
self.show_clock(dt)
for i, orbit_line in enumerate(self.orbit_lines):
orbit_line.position = self.sun.planet.position
def on_body_trail_clicked(self, e):
if e["key"] == "right mouse up":
trail = e["sender"]
d_sun = trail.entity_infos["distance_from_sun"]
d_earth = trail.entity_infos["distance_from_earth"]
t = trail.entity_infos["time"]
# print("key:", e["key"])
msg = "哈雷彗星:\n距离太阳:%.3f AU" % (d_sun / AU)
msg += "\n距离地球:%.3f AU" % (d_earth / AU)
msg += "\n当前日期:[%s]" % t
ControlUI.current_ui.show_message(msg, close_time=3)
if __name__ == '__main__':
"""
哈雷彗星场景模拟
"""
# 远日点: 35.1 AU(2023年12月9日)
# 近日点: 0.586 AU 上次通过近日点:1986年2月9日 下次通过近日点:2061年7月28日
# 2019年5月6日 34.772
params = HalleyCometParams(
start_time='1982-09-24 00:00:00',
# init_velocity=[-2.835, 4.72, 8.847],
# init_velocity=[-2.826, 4.695, 8.86],
# init_velocity=[-2.836, 4.705, 8.85],
# 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 = HalleyCometSim(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)
# 天体拖尾点击事件
UrsinaEvent.on_body_trail_clicked_subscription(sim.on_body_trail_clicked)
# 使用 ursina 查看的运行效果
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
ursina_run(sim.bodies,
SECONDS_PER_YEAR * RUN_SPEED,
# position=(0, 2 * AU, -11 * AU),
# position=(0, 0.5 * AU, -5 * AU),
position=(2 * AU, -5 * AU, -20 * AU),
cosmic_bg='',
show_trail=True,
# bg_music='sounds/no_glory.mp3',
show_camera_info=False,
# save_as_video=True,
show_control_info=False,
timer_enabled=True,
show_grid=False
)
......@@ -13,7 +13,6 @@ from common.celestial_data_service import init_bodies_reality_pos_vels, conv_to_
set_solar_system_celestial_position
from common.consts import SECONDS_PER_YEAR, AU
from common.func import calculate_distance
from objs import HalleComet, CameraTarget
from sim_scenes.func import create_text_panel, camera_look_at
from sim_scenes.func import ursina_run, create_sphere_sky
from sim_scenes.solar_system.halley_comet_lib import HalleyCometSimBase, HalleyCometParams, \
......@@ -56,9 +55,6 @@ class HalleyCometSim(HalleyCometSimBase):
# 创建哈雷彗星创建哈雷彗星
self.halley_comet = create_halley_comet(self.params.init_velocity, self.params.init_position)
self.bodies.append(self.halley_comet)
# # 创建一个摄像机跟踪目标
# self.camera_target = CameraTarget(size_scale=1e9)
# self.bodies.append(self.camera_target)
def init_settings(self):
"""
......@@ -195,7 +191,7 @@ class HalleyCometSim(HalleyCometSimBase):
forward_infos = [
(1983, 0.1 * RUN_SPEED * 12),
(1986, -8 * RUN_SPEED * 12),
(1987, -3 * RUN_SPEED * 12),
(1987, -2 * RUN_SPEED * 12),
(1988, 0),
(2049, 1 * RUN_SPEED * 12),
(2061, 0),
......@@ -212,28 +208,6 @@ class HalleyCometSim(HalleyCometSimBase):
# 最远
continue
camera.forward_factor = factor
# if dt.year > 1986:
# self.camera_target.planet.look_at(self.halley_comet.planet)
# self.camera_target.planet.position = \
# lerp(self.camera_target.planet.position, self.halley_comet.planet.position, 1)
# print(self.camera_target.planet.position, self.halley_comet.planet.position)
# camera_look_at(self.halley_comet, rotation_z=0)
# if 2000 > dt.year >= 1986:
# camera.forward_factor = -0.3 * RUN_SPEED * 12
# elif 2008 > dt.year >= 2000:
# camera.forward_factor = 0
# elif 2064 > dt.year >= 2008:
# camera.forward_factor = 0.3 * RUN_SPEED * 12
# def camera_update():
# camera_look_at(self.halley_comet, rotation_z=0)
# camera.position += camera.forward * -0.3
#
# camera.forward = Vec3(0, 0, 0)
# camera.update = camera_update
# if dt.year > 1986:
# # camera.position += Vec3(0, 0, -1)
# camera.position += camera.forward * -5
def on_timer_changed(self, time_data):
"""
......@@ -254,32 +228,33 @@ class HalleyCometSim(HalleyCometSimBase):
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()
last_trail = list(trail_keys)[-1] # self.halley_comet.planet.trails[list(trail_keys)[-1]]
if hasattr(last_trail, "entity_infos"):
# print(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")
# print(last_trail.entity_infos)
pos = self.halley_comet.planet.position
import copy
if self.show_milestone_lable(last_trail, dt):
pass
elif not hasattr(self, "last_year"):
self.create_year_label(last_trail, year, pos)
elif self.last_year != year:
if not hasattr(self, "last_label_pos"):
if len(trail_keys) > 0:
last_trail = list(trail_keys)[-1] # self.halley_comet.planet.trails[list(trail_keys)[-1]]
if hasattr(last_trail, "entity_infos"):
# print(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")
# print(last_trail.entity_infos)
pos = self.halley_comet.planet.position
import copy
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)
else:
# 防止标签非常紧密
d = calculate_distance(self.halley_comet.position, self.last_label_pos)
if d > 2 * AU:
elif self.last_year != year:
if not hasattr(self, "last_label_pos"):
self.create_year_label(last_trail, year, pos)
self.last_label_pos = copy.deepcopy(self.halley_comet.position)
else:
# 防止标签非常紧密
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)
self.last_year = year
# 哈雷彗星离太阳最近的点称为 "perihelion of Halley's Comet"(近日点:comet_peri),
......@@ -301,14 +276,14 @@ class HalleyCometSim(HalleyCometSimBase):
self.set_comet_trail_alpha(d_sun)
panel_text = "哈雷彗星:\n距离太阳:%.3f AU" % (d_sun / AU)
panel_text = "哈雷彗星:\n\n距离太阳:%.3f AU" % (d_sun / AU)
# panel_text += "\n离日最远:%.3f AU(%s)" % (self.comet_aphel / AU, self.comet_aphel_dt)
panel_text += "\n离日最远:%.3f AU" % (self.comet_aphel / AU)
panel_text += "\n\n离日最远:%.3f AU" % (self.comet_aphel / AU)
# panel_text += "\n离日最近:%.3f AU(%s)" % (self.comet_peri / AU, self.comet_peri_dt)
panel_text += "\n离日最近:%.3f AU" % (self.comet_peri / AU)
panel_text += "\n\n离日最近:%.3f AU" % (self.comet_peri / AU)
# panel_text += "\n距离地球:%.3f AU" % (d_earth / AU)
velocity, _ = get_value_direction_vectors(self.halley_comet.velocity)
panel_text += "\n当前速度:%.3f km/s" % velocity
panel_text += "\n\n当前速度:%.3f km/s" % velocity
self.text_panel.text = panel_text
......
......@@ -96,6 +96,8 @@ class VideoRecorder(Entity):
def convert_to_mp4(self):
print("视频保存中")
for frame in self.frames:
self.video.write(frame)
self.video.release()
cv2.destroyAllWindows()
# crop('video.mp4')
......@@ -160,7 +162,7 @@ class VideoRecorder(Entity):
# img_bgr = cv2.cvtColor(img, cv2.COLOR_RGBA2BGR)
# if imageNum < self.fps * args.total_time:
# show_image(frame)
self.video.write(normal_image)
self.frames.append(normal_image)
# store screenshot in memory
# def renderToPNM(self):
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册