Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Python_超人
宇宙模拟器
提交
824056d7
宇宙模拟器
项目概览
Python_超人
/
宇宙模拟器
通知
19
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
宇宙模拟器
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
824056d7
编写于
4月 14, 2023
作者:
三月三net
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Python超人-宇宙模拟器
上级
e3fc23af
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
470 addition
and
18 deletion
+470
-18
objs/__init__.py
objs/__init__.py
+0
-0
objs/obj.py
objs/obj.py
+427
-0
sim_scenes/func.py
sim_scenes/func.py
+4
-4
sim_scenes/funny/dancing_with_jupiter.py
sim_scenes/funny/dancing_with_jupiter.py
+2
-2
sim_scenes/solar_system/speed_of_light.py
sim_scenes/solar_system/speed_of_light.py
+3
-3
sim_scenes/solar_system/speed_of_light_init.py
sim_scenes/solar_system/speed_of_light_init.py
+6
-1
sim_scenes/solar_system/transit_of_venus_mercury.py
sim_scenes/solar_system/transit_of_venus_mercury.py
+27
-8
simulators/ursina_simulator.py
simulators/ursina_simulator.py
+1
-0
textures/transparent.png
textures/transparent.png
+0
-0
未找到文件。
objs/__init__.py
0 → 100644
浏览文件 @
824056d7
objs/obj.py
0 → 100644
浏览文件 @
824056d7
# -*- coding:utf-8 -*-
# title :对象基类
# description :对象基类(所有星体都继承了该类)
# author :Python超人
# date :2023-02-11
# link :https://gitcode.net/pythoncr/
# python_version :3.8
# ==============================================================================
from
abc
import
ABCMeta
,
abstractmethod
import
json
import
numpy
as
np
import
math
from
common.consts
import
AU
import
copy
class
Obj
(
metaclass
=
ABCMeta
):
"""
对象基类
"""
def
__init__
(
self
,
name
,
mass
,
init_position
,
init_velocity
,
density
=
5e3
,
color
=
(
125
/
255
,
125
/
255
,
125
/
255
),
texture
=
None
,
size_scale
=
1.0
,
distance_scale
=
1.0
,
parent
=
None
,
ignore_mass
=
False
,
trail_color
=
None
,
show_name
=
False
):
"""
对象类
@param name: 对象名称
@param mass: 对象质量 (kg)
@param init_position: 初始位置 (km)
@param init_velocity: 初始速度 (km/s)
@param density: 平均密度 (kg/m³)
@param color: 对象颜色(纹理图片优先)
@param texture: 纹理图片
@param size_scale: 尺寸缩放
@param distance_scale: 距离缩放
@param parent: 对象的父对象
@param ignore_mass: 是否忽略质量(如果为True,则不计算引力)
TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在对象物理学中是不严谨)
@param trail_color: 对象拖尾颜色(默认对象颜色)
@param show_name: 是否显示对象名称
"""
self
.
__his_pos
=
[]
self
.
__his_vel
=
[]
self
.
__his_acc
=
[]
self
.
__his_reserved_num
=
200
if
name
is
None
:
name
=
getattr
(
self
.
__class__
,
'__name__'
)
self
.
name
=
name
self
.
__mass
=
mass
# 是否忽略质量(如果为True,则不计算引力)
# TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在对象物理学中是不严谨)
if
self
.
__mass
<=
0
:
# 质量小于等于0就忽略
self
.
ignore_mass
=
True
else
:
self
.
ignore_mass
=
ignore_mass
self
.
__init_position
=
None
self
.
__init_velocity
=
None
self
.
init_position
=
np
.
array
(
init_position
,
dtype
=
'float32'
)
self
.
init_velocity
=
np
.
array
(
init_velocity
,
dtype
=
'float32'
)
self
.
__density
=
density
self
.
color
=
color
self
.
trail_color
=
color
if
trail_color
is
None
else
trail_color
self
.
texture
=
texture
self
.
size_scale
=
size_scale
self
.
distance_scale
=
distance_scale
# 初始化后,加速度为0,只有多个对象的引力才会影响到加速度
# km/s²
self
.
__acceleration
=
np
.
array
([
0
,
0
,
0
],
dtype
=
'float32'
)
self
.
__record_history
()
# 是否显示
self
.
appeared
=
True
self
.
parent
=
parent
self
.
show_name
=
show_name
self
.
resolution
=
None
self
.
light_disable
=
False
self
.
__has_rings
=
False
def
set_ignore_gravity
(
self
,
value
=
True
):
"""
设置忽略质量,True为引力失效
@param value:
@return:
"""
# TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在对象物理学中是不严谨)
if
self
.
__mass
<=
0
:
# 质量小于等于0就忽略
self
.
ignore_mass
=
True
else
:
self
.
ignore_mass
=
value
return
self
def
set_light_disable
(
self
,
value
=
True
):
"""
设置灯光为无效
@param value:
@return:
"""
self
.
light_disable
=
value
return
self
def
set_resolution
(
self
,
value
):
"""
设置对象的分辨率
@param value:
@return:
"""
self
.
resolution
=
value
return
self
@
property
def
init_position
(
self
):
"""
获取对象的初始位置(单位:km)
@return:
"""
return
self
.
__init_position
@
init_position
.
setter
def
init_position
(
self
,
value
):
"""
设置对象的初始位置(单位:km)
@param value:
@return:
"""
self
.
__init_position
=
np
.
array
(
value
,
dtype
=
'float32'
)
self
.
__position
=
copy
.
deepcopy
(
self
.
__init_position
)
@
property
def
init_velocity
(
self
):
"""
获取对象的初始速度 (km/s)
@return:
"""
return
self
.
__init_velocity
@
init_velocity
.
setter
def
init_velocity
(
self
,
value
):
"""
设置对象的初始速度 (km/s)
@param value:
@return:
"""
self
.
__init_velocity
=
np
.
array
(
value
,
dtype
=
'float32'
)
self
.
__velocity
=
copy
.
deepcopy
(
self
.
__init_velocity
)
@
property
def
position
(
self
):
"""
获取对象的位置(单位:km)
@return:
"""
return
self
.
__position
@
position
.
setter
def
position
(
self
,
value
):
"""
设置对象的位置(单位:km)
@param value:
@return:
"""
self
.
__position
=
value
self
.
__record_history
()
@
property
def
acceleration
(
self
):
"""
获取对象的加速度(单位:km/s²)
@return:
"""
return
self
.
__acceleration
@
acceleration
.
setter
def
acceleration
(
self
,
value
):
"""
设置对象的加速度(单位:km/s²)
@param value:
@return:
"""
self
.
__acceleration
=
np
.
array
(
value
,
dtype
=
float
)
self
.
__record_history
()
def
stop
(
self
):
"""
停止运动,将加速度和速度置零
@return:
"""
self
.
init_velocity
=
[
0.0
,
0.0
,
0.0
]
self
.
acceleration
=
[
0.0
,
0.0
,
0.0
]
def
stop_and_ignore_gravity
(
self
):
"""
停止运动,并忽略质量(不受引力影响)
TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在对象物理学中是不严谨)
@return:
"""
self
.
set_ignore_gravity
()
self
.
stop
()
@
property
def
velocity
(
self
):
"""
获取对象的速度(单位:km/s)
@return:
"""
return
self
.
__velocity
@
velocity
.
setter
def
velocity
(
self
,
value
):
"""
设置对象的速度(单位:km/s)
@param value:
@return:
"""
self
.
__velocity
=
value
self
.
__record_history
()
def
__append_history
(
self
,
his_list
,
data
):
"""
追加每个位置时刻的历史数据
@param his_list:
@param data:
@return:
"""
# 如果历史记录为0 或者 新增数据和最后的历史数据不相同,则添加
if
len
(
his_list
)
==
0
or
\
np
.
sum
(
data
==
his_list
[
-
1
])
<
len
(
data
):
his_list
.
append
(
data
.
copy
())
def
__record_history
(
self
):
"""
记录每个位置时刻的历史数据
@return:
"""
# 如果历史记录数超过了保留数量,则截断,只保留 __his_reserved_num 数量的历史
if
len
(
self
.
__his_pos
)
>
self
.
__his_reserved_num
:
self
.
__his_pos
=
self
.
__his_pos
[
len
(
self
.
__his_pos
)
-
self
.
__his_reserved_num
:]
self
.
__his_vel
=
self
.
__his_vel
[
len
(
self
.
__his_vel
)
-
self
.
__his_reserved_num
:]
self
.
__his_acc
=
self
.
__his_acc
[
len
(
self
.
__his_acc
)
-
self
.
__his_reserved_num
:]
# 追加历史记录(位置、速度、加速度)
self
.
__append_history
(
self
.
__his_pos
,
self
.
position
)
self
.
__append_history
(
self
.
__his_vel
,
self
.
velocity
)
self
.
__append_history
(
self
.
__his_acc
,
self
.
acceleration
)
# print(self.name, "his pos->", self.__his_pos)
def
his_position
(
self
):
"""
历史位置
@return:
"""
return
self
.
__his_pos
def
his_velocity
(
self
):
"""
历史瞬时速度
@return:
"""
return
self
.
__his_vel
def
his_acceleration
(
self
):
"""
历史瞬时加速度
@return:
"""
return
self
.
__his_acc
@
property
def
mass
(
self
):
"""
对象质量 (单位:kg)
@return:
"""
return
self
.
__mass
@
property
def
density
(
self
):
"""
平均密度 (单位:kg/m³)
@return:
"""
return
self
.
__density
def
__repr__
(
self
):
return
'<%s(%s)> m=%.3e(kg), d=%.3e(kg/m³), p=[%.3e,%.3e,%.3e](km), v=%s(km/s)'
%
\
(
self
.
name
,
self
.
__class__
.
__name__
,
self
.
mass
,
self
.
density
,
self
.
position
[
0
],
self
.
position
[
1
],
self
.
position
[
2
],
self
.
velocity
)
def
ignore_gravity_with
(
self
,
body
):
"""
是否忽略指定对象的引力
@param body:
@return:
"""
# TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在对象物理学中是不严谨)
if
self
.
ignore_mass
:
return
True
return
False
def
position_au
(
self
):
"""
获取对象的位置(单位:天文单位 A.U.)
@return:
"""
pos
=
self
.
position
pos_au
=
pos
/
AU
return
pos_au
# def change_velocity(self, dv):
# self.velocity += dv
#
# def move(self, dt):
# self.position += self.velocity * dt
def
reset
(
self
):
"""
重新设置初始速度和初始位置
@return:
"""
self
.
position
=
copy
.
deepcopy
(
self
.
init_position
)
self
.
velocity
=
copy
.
deepcopy
(
self
.
init_velocity
)
# def kinetic_energy(self):
# """
# 计算动能(千焦耳)
# 表示动能,单位为焦耳j,m为质量,单位为千克,v为速度,单位为米/秒。
# ek=(1/2).m.v^2
# m(kg) v(m/s) -> j
# m(kg) v(km/s) -> kj
# """
# v = self.velocity
# return 0.5 * self.mass * (v[0] ** 2 + v[1] ** 2 + v[2] ** 2)
@
staticmethod
def
build_objs_from_json
(
json_file
):
"""
JSON文件转为对象对象
@param json_file:
@return:
"""
bodies
=
[]
params
=
{}
from
bodies
import
FixedStar
,
Body
with
open
(
json_file
,
"r"
,
encoding
=
'utf-8'
)
as
read_content
:
json_data
=
json
.
load
(
read_content
)
for
body_data
in
json_data
[
"bodies"
]:
try
:
body_data
=
Obj
.
exp
(
body_data
)
# print(body_data)
except
Exception
as
e
:
err_msg
=
f
"
{
json_file
}
格式错误:"
+
str
(
e
)
raise
Exception
(
err_msg
)
is_fixed_star
=
False
if
"is_fixed_star"
in
body_data
:
if
body_data
[
"is_fixed_star"
]:
is_fixed_star
=
True
if
is_fixed_star
:
body_data
.
pop
(
"is_fixed_star"
)
body
=
FixedStar
(
**
body_data
)
else
:
has_rings
=
False
if
"has_rings"
in
body_data
:
if
body_data
[
"has_rings"
]:
has_rings
=
True
body_data
.
pop
(
"has_rings"
)
if
"rotation_speed"
in
body_data
:
body
=
Body
(
**
body_data
)
if
has_rings
:
body
.
has_rings
=
True
else
:
body_data
.
pop
(
"rotation_speed"
)
body_data
.
pop
(
"is_fixed_star"
)
body
=
Obj
(
**
body_data
)
# [x, y, z]->[-y, z, x]
# body.init_velocity = [-body.init_velocity[1],body.init_velocity[2],body.init_velocity[0]]
# body.init_position = [-body.init_position[1],body.init_position[2],body.init_position[0]]
bodies
.
append
(
body
)
if
"params"
in
json_data
:
params
=
json_data
[
"params"
]
# print(body.position_au())
return
bodies
,
params
@
staticmethod
def
exp
(
body_data
):
"""
进行表达式分析,将表达式改为eval执行后的结果
@param body_data:
@return:
"""
#
for
k
in
body_data
.
keys
():
v
=
body_data
[
k
]
if
isinstance
(
v
,
str
):
if
v
.
startswith
(
"$exp:"
):
exp
=
v
[
5
:]
body_data
[
k
]
=
eval
(
exp
)
elif
isinstance
(
v
,
list
):
for
idx
,
item
in
enumerate
(
v
):
if
isinstance
(
item
,
str
):
if
item
.
startswith
(
"$exp:"
):
exp
=
item
[
5
:]
v
[
idx
]
=
eval
(
exp
)
return
body_data
if
__name__
==
'__main__'
:
# build_bodies_from_json('../data/sun.json')
objs
,
params
=
Obj
.
build_objs_from_json
(
'../data/sun_earth.json'
)
for
obj
in
objs
:
print
(
obj
)
sim_scenes/func.py
浏览文件 @
824056d7
...
...
@@ -190,10 +190,10 @@ def create_solar_system_bodies(ignore_mass=False, init_velocity=None):
sun
=
Sun
(
name
=
"太阳"
,
size_scale
=
0.5e2
)
# 太阳放大 50 倍,距离保持不变
bodies
=
[
sun
,
Mercury
(
name
=
"水星"
,
size_scale
=
1e3
),
# 水星放大 10
00 倍,距离保持不变
Venus
(
name
=
"金星"
,
size_scale
=
1e3
),
# 金星放大 10
00 倍,距离保持不变
Earth
(
name
=
"地球"
,
size_scale
=
1e3
),
# 地球放大 10
00 倍,距离保持不变
Mars
(
name
=
"火星"
,
size_scale
=
1e3
),
# 火星放大 10
00 倍,距离保持不变
Mercury
(
name
=
"水星"
,
size_scale
=
0.3e3
),
# 水星放大 3
00 倍,距离保持不变
Venus
(
name
=
"金星"
,
size_scale
=
0.3e3
),
# 金星放大 3
00 倍,距离保持不变
Earth
(
name
=
"地球"
,
size_scale
=
0.3e3
),
# 地球放大 3
00 倍,距离保持不变
Mars
(
name
=
"火星"
,
size_scale
=
0.3e3
),
# 火星放大 3
00 倍,距离保持不变
# Asteroids(name="小行星群", size_scale=3.2e2,
# parent=sun), # 小行星群模拟(仅 ursina 模拟器支持)
Jupiter
(
name
=
"木星"
,
size_scale
=
0.3e3
),
# 木星放大 300 倍,距离保持不变
...
...
sim_scenes/funny/dancing_with_jupiter.py
浏览文件 @
824056d7
...
...
@@ -21,8 +21,8 @@ if __name__ == '__main__':
"""
# 选择舞者
Dancer
=
Earth
# 舞者为地球
Dancer
=
Venus
# 舞者为金星
Dancer
=
Mars
# 舞者为火星
#
Dancer = Venus # 舞者为金星
#
Dancer = Mars # 舞者为火星
bodies
=
[
Sun
(
size_scale
=
0.8e2
),
# 太阳放大 80 倍
...
...
sim_scenes/solar_system/speed_of_light.py
浏览文件 @
824056d7
...
...
@@ -12,9 +12,9 @@ from sim_scenes.solar_system.speed_of_light_init import SpeedOfLightInit
# TODO: 三种不同的摄像机视角
camera_follow_light
=
None
# 摄像机固定,不会跟随光
#
camera_follow_light = 'ForwardView' # 摄像机跟随光,方向是向前看
#
camera_follow_light = 'SideView' # 摄像机跟随光,方向是从侧面看
#
camera_follow_light = 'SideViewActualSize' # 摄像机跟随光,方向是从侧面看,天体是实际大小
camera_follow_light
=
'ForwardView'
# 摄像机跟随光,方向是向前看
camera_follow_light
=
'SideView'
# 摄像机跟随光,方向是从侧面看
camera_follow_light
=
'SideViewActualSize'
# 摄像机跟随光,方向是从侧面看,天体是实际大小
# 实例化一个初始化对象(订阅事件,记录到达每个行星所需要的时间)
init
=
SpeedOfLightInit
(
camera_follow_light
)
...
...
sim_scenes/solar_system/speed_of_light_init.py
浏览文件 @
824056d7
...
...
@@ -85,7 +85,7 @@ class SpeedOfLightInit:
@return:
"""
self
.
arrived_bodies
.
clear
()
# 重置存放记录光体已到达天体列表
self
.
arrived_info
=
"距离[太阳]:${distance}
\n\n
"
self
.
arrived_info
=
"距离[太阳
中心
]:${distance}
\n\n
"
if
self
.
text_panel
is
not
None
:
self
.
text_panel
.
text
=
self
.
arrived_info
.
replace
(
"${distance}"
,
"0 AU"
)
...
...
@@ -141,6 +141,11 @@ class SpeedOfLightInit:
camera
.
parent
=
self
.
light_body
.
planet
self
.
light_body
.
planet
.
input
=
self
.
light_body_input
camera
.
rotation_y
=
-
15
if
hasattr
(
camera
,
"sky"
):
# 摄像机跟随地球后,需要对深空背景进行调整,否则看到的是黑色背景
camera
.
sky
.
scale
=
800
camera
.
clip_plane_near
=
0.1
camera
.
clip_plane_far
=
1000000
# 取消订阅(防止 光体 的大小进行变化影响摄像机的视角)
UrsinaEvent
.
on_body_size_changed_unsubscription
(
self
.
light_body
.
planet
.
change_body_scale
)
...
...
sim_scenes/solar_system/transit_of_venus_mercury.py
浏览文件 @
824056d7
...
...
@@ -14,30 +14,49 @@ from simulators.ursina.ursina_event import UrsinaEvent
if
__name__
==
'__main__'
:
# 水星、金星凌日
earth
=
Earth
(
name
=
"地球"
)
sun
=
Sun
(
name
=
"太阳"
,
size_scale
=
5e1
)
# 太阳放大
2
0 倍
earth
=
Earth
(
name
=
"地球"
,
rotation_speed
=
0
,
texture
=
"transparent.png"
)
# 地球纹理透明,不会挡住摄像机视线
sun
=
Sun
(
name
=
"太阳"
,
size_scale
=
5e1
)
# 太阳放大
5
0 倍
bodies
=
[
sun
,
earth
,
Mercury
(
name
=
"水星"
,
init_position
=
[
0.384
*
AU
,
0
,
0
],
init_velocity
=
[
0
,
0
,
47.87
],
size_scale
=
5e1
),
# 水星放大
1
0 倍,距离保持不变
size_scale
=
5e1
),
# 水星放大
5
0 倍,距离保持不变
Venus
(
name
=
"金星"
,
init_position
=
[
0.721
*
AU
,
0
,
0
],
init_velocity
=
[
0
,
0
,
35
],
size_scale
=
5e1
)
# 金星放大
1
0 倍,距离保持不变
size_scale
=
5e1
)
# 金星放大
5
0 倍,距离保持不变
]
def
on_ready
():
camera_look_at
(
sun
,
rotation_x
=
None
,
rotation_y
=
None
,
rotation_z
=
0
)
pass
from
ursina
import
camera
# 摄像机跟随地球(模拟在地球上看到的效果)
camera
.
parent
=
earth
.
planet
if
hasattr
(
camera
,
"sky"
):
# 摄像机跟随地球后,需要对深空背景进行调整,否则看到的是黑色背景
camera
.
sky
.
scale
=
800
camera
.
clip_plane_near
=
0.1
camera
.
clip_plane_far
=
1000000
# 让太阳的旋转速度放慢10倍
sun
.
rotation_speed
/=
10
def
on_timer_changed
(
time_data
:
TimeData
):
# 时时刻刻的让地球看向太阳(摄像机跟随地球看向太阳)
earth
.
planet
.
look_at
(
sun
.
planet
)
earth
.
planet
.
rotation_z
=
0
UrsinaEvent
.
on_ready_subscription
(
on_ready
)
UrsinaEvent
.
on_timer_changed_subscription
(
on_timer_changed
)
# 使用 ursina 查看的运行效果
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
ursina_run
(
bodies
,
SECONDS_PER_DAY
*
3
,
position
=
earth
.
init_position
)
ursina_run
(
bodies
,
SECONDS_PER_WEEK
,
position
=
[
0
,
0
,
0
],
# 以地球为中心的位置
show_timer
=
True
)
simulators/ursina_simulator.py
浏览文件 @
824056d7
...
...
@@ -169,6 +169,7 @@ class UrsinaSimulator(Simulator):
# sky = SphereSky(texture=texture, scale=sky_scale)
sky
.
scale
=
sky_scale
camera
.
sky
=
sky
# sky.set_shader_input('texture_scale', Vec2(20, 20))
# 一定要够大,如果小于 Sky(texture=texture).scale = 50000,宇宙背景就会出现黑色方洞
if
camera
.
clip_plane_far
<
sky_scale
*
2
:
...
...
textures/transparent.png
0 → 100644
浏览文件 @
824056d7
2.9 KB
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录