提交 56f5a2b4 编写于 作者: 三月三net's avatar 三月三net

Python超人-宇宙模拟器

上级 6a6612d7
......@@ -194,6 +194,7 @@ class System(object):
# m/s² = kg * m / m**3
# km/s² = kg * m / m**3 / 1e9
# acceleration = G * body2.mass * dx / (d ** 3)
if np.linalg.norm(r) > 0.0:
acceleration += (G * body2.mass * r / np.linalg.norm(r) ** 3) / 1e9
body1.acceleration = acceleration
......
from objs.diamond import Diamond
from objs.football import Football
from objs.satellite import Satellite
......@@ -12,29 +12,32 @@ from objs.obj import Obj
class Diamond(Obj):
"""
钻石
密度:3.51g/cm³
"""
def __init__(self, name="钻石", mass=5.97237e24,
init_position=[0, 0, 0],
init_velocity=[0, 0, 0],
texture="earth1.jpg", size_scale=1.0, distance_scale=1.0,
ignore_mass=False,
texture=None, size_scale=1.0, distance_scale=1.0,
ignore_mass=False, density=3.51e3, color=(7, 0, 162),
trail_color=None, show_name=False,
parent=None):
parent=None, gravity_only_for=[]):
params = {
"name": name,
"mass": mass,
"init_position": init_position,
"init_velocity": init_velocity,
"density": 5507.85,
"color": (7, 0, 162),
"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
"parent": parent,
"gravity_only_for": gravity_only_for,
"model": "diamond"
}
super().__init__(**params)
......
# -*- coding:utf-8 -*-
# title :地球
# description :地球
# author :Python超人
# date :2023-02-11
# link :https://gitcode.net/pythoncr/
# python_version :3.8
# ==============================================================================
from objs.obj import Obj
class Football(Obj):
"""
足球
"""
def __init__(self, name="足球", mass=5.97237e24,
init_position=[0, 0, 0],
init_velocity=[0, 0, 0],
texture="football.jpg", size_scale=1.0, distance_scale=1.0,
ignore_mass=False, density=1e3, color=(7, 0, 162),
trail_color=None, show_name=False,
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,
"gravity_only_for": gravity_only_for,
"model": "sphere"
}
super().__init__(**params)
if __name__ == '__main__':
football = Football()
print(football)
此差异已折叠。
......@@ -12,6 +12,7 @@ import numpy as np
import math
from common.consts import AU
import copy
import os
class Obj(metaclass=ABCMeta):
......@@ -23,7 +24,8 @@ class Obj(metaclass=ABCMeta):
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):
trail_color=None, show_name=False,
gravity_only_for=[], model=None):
"""
对象类
@param name: 对象名称
......@@ -45,6 +47,8 @@ class Obj(metaclass=ABCMeta):
self.__his_vel = []
self.__his_acc = []
self.__his_reserved_num = 200
self.gravity_only_for = gravity_only_for
self.model = self.find_model(model)
if name is None:
name = getattr(self.__class__, '__name__')
......@@ -90,6 +94,21 @@ class Obj(metaclass=ABCMeta):
self.__has_rings = False
def find_model(self, model: str):
if not model.endswith(".obj"):
return model
if os.path.exists(model):
return model
paths = [os.path.join('.', 'objs/models'),
os.path.join('..', 'objs/models'),
os.path.join('..', '..', 'objs/models')]
for path in paths:
p = os.path.join(path, model)
if os.path.exists(p):
return p
return ""
def set_ignore_gravity(self, value=True):
"""
设置忽略质量,True为引力失效
......@@ -198,7 +217,7 @@ class Obj(metaclass=ABCMeta):
停止运动,将加速度和速度置零
@return:
"""
self.init_velocity = [0.0, 0.0, 0.0]
self.velocity = [0.0, 0.0, 0.0]
self.acceleration = [0.0, 0.0, 0.0]
def stop_and_ignore_gravity(self):
......@@ -305,6 +324,10 @@ class Obj(metaclass=ABCMeta):
@param body:
@return:
"""
if len(self.gravity_only_for) > 0:
if body in self.gravity_only_for:
return False
return True
# TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在对象物理学中是不严谨)
if self.ignore_mass:
return True
......
# -*- coding:utf-8 -*-
# title :地球
# description :地球
# author :Python超人
# date :2023-02-11
# link :https://gitcode.net/pythoncr/
# python_version :3.8
# ==============================================================================
from objs.obj import Obj
class Satellite(Obj):
"""
卫星
"""
def __init__(self, name="卫星", mass=5.97237e24,
init_position=[0, 0, 0],
init_velocity=[0, 0, 0],
texture="satelite.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="satelite.obj",
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,
"gravity_only_for": gravity_only_for,
"model": model
}
super().__init__(**params)
if __name__ == '__main__':
satellite = Satellite()
print(satellite)
......@@ -26,7 +26,7 @@ if __name__ == '__main__':
Sun(name="抖音", mass=1.9891e30,
init_position=[0, 0, 0],
init_velocity=[0, 0, 0],
texture="douyin.jpg", size_scale=8e1, distance_scale=1.0),
texture="douyin.jpg", size_scale=6e1, distance_scale=1.0),
# 地球的质量为 5.97237✕10²⁴ kg
# 初始位置 x=1.12天文单位, y=0, z=0
......@@ -35,10 +35,10 @@ if __name__ == '__main__':
# 放大倍数为 5000 倍
# 距离保持不变
Earth(name="超人", mass=5.97237e24,
init_position=[2 * AU, 0, 0],
init_velocity=[0, 29.79, 0],
init_position=[0, 0, AU],
init_velocity=[-29.79, 0, 0],
rotation_speed=1.5,
texture="pythoncr.jpg", size_scale=5e3, distance_scale=1.0),
texture="pythoncr.jpg", size_scale=3e3, distance_scale=1.0),
]
# 使用 mayavi 查看的运行效果
# mayavi_run(bodies, SECONDS_PER_DAY, view_azimuth=135)
......@@ -49,4 +49,4 @@ if __name__ == '__main__':
# 使用 ursina 查看的运行效果
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
ursina_run(bodies, SECONDS_PER_WEEK, position=(0, AU, -5 * AU))
ursina_run(bodies, SECONDS_PER_WEEK * 2, position=(0, AU, -5 * AU))
......@@ -7,8 +7,9 @@
# python_version :3.8
# ==============================================================================
from bodies import Moon, Earth, Body
from objs import Satellite
from common.consts import SECONDS_PER_HOUR, SECONDS_PER_HALF_DAY, SECONDS_PER_DAY, SECONDS_PER_WEEK, SECONDS_PER_MONTH
from sim_scenes.func import mayavi_run, ursina_run
from sim_scenes.func import mayavi_run, ursina_run, camera_look_at
import math
import random
......@@ -36,6 +37,10 @@ import random
import random
import math
from simulators.ursina.entities.body_timer import TimeData
from simulators.ursina.ursina_config import UrsinaConfig
from simulators.ursina.ursina_event import UrsinaEvent
def get_satellite_position_velocity(earth_mass, earth_position, earth_radius, altitude):
# 万有引力常数
......@@ -97,15 +102,37 @@ if __name__ == '__main__':
earth = Earth(init_position=[0, 0, 0], size_scale=1, texture="earth_hd.jpg", init_velocity=[0, 0, 0])
# 北斗卫星高度为2.13-2.15万千米。GPS卫星平均轨道高度2.02万千米。
bodies = [earth]
for i in range(10):
altitude = random.randint(4000, 10000)
position, velocity = get_satellite_position_velocity(earth.mass, earth.init_position, earth.raduis, altitude)
satellite = Body(name=f'卫星{i + 1}', mass=4.4e10, size_scale=1e3, color=(255, 200, 0),
init_position=position,
init_velocity=velocity)
satellite_infos = [
{"position": [0, 0, 10000], "velocity": [-6.3, 0, 0]},
{"position": [0, 0, -12000], "velocity": [5.75, 0, 0]},
{"position": [0, 8000, 0], "velocity": [7.05, 0, 0]},
{"position": [0, -12000, 0], "velocity": [-5.75, 0, 0]},
{"position": [0, 0, 8000], "velocity": [0, 7.05, 0]},
{"position": [0, 0, -10000], "velocity": [0, -6.3, 0]},
]
for i, info in enumerate(satellite_infos):
# altitude = random.randint(4000, 10000)
# position, velocity = get_satellite_position_velocity(earth.mass, earth.init_position, earth.raduis, altitude)
satellite = Satellite(name=f'卫星{i + 1}', mass=4.4e10, size_scale=2e2, color=(255, 200, 0),
init_position=info["position"],
init_velocity=info["velocity"])
bodies.append(satellite)
def on_ready():
camera_look_at(earth, rotation_z=0)
UrsinaConfig.trail_length = 150
UrsinaConfig.trail_type = "line"
pass
UrsinaEvent.on_ready_subscription(on_ready)
# 使用 ursina 查看的运行效果
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
ursina_run(bodies, SECONDS_PER_HOUR/60, position=(0, 0, -80000), show_trail=True, view_closely=0.01)
ursina_run(bodies, SECONDS_PER_HOUR / 2,
position=(30000, 5000, -30000),
show_trail=True,
view_closely=0.001)
......@@ -7,13 +7,14 @@
# python_version :3.8
# ==============================================================================
from bodies import Moon, Earth, Body
from objs import Football
from common.consts import SECONDS_PER_HOUR, SECONDS_PER_MINUTE
from sim_scenes.func import ursina_run, get_vector2d_velocity, camera_look_at, two_bodies_colliding
from simulators.ursina.entities.body_timer import TimeData
from simulators.ursina.ursina_event import UrsinaEvent
def create_ejected_object(velocity, raduis, trail_color, angle=10):
def create_ejected_object(velocity, raduis, trail_color, gravity_only_for, angle=10):
"""
创建一个被抛的物体
@param velocity: 抛出去的速度
......@@ -24,10 +25,10 @@ def create_ejected_object(velocity, raduis, trail_color, angle=10):
"""
# 根据速度、角度获取矢量速度(vx、vy) -> vx² + vy² = velocity²
vx, vy = get_vector2d_velocity(velocity, angle=angle)
moon = Moon(name=f'物体速度:{velocity}', mass=500, size_scale=2e6, trail_color=trail_color,
football = Football(name=f'物体速度:{velocity}', mass=500, size_scale=1e3, trail_color=trail_color,
init_position=[0, raduis, 0],
init_velocity=[vx, vy, 0], gravity_only_for_earth=True) # 仅适用于地球的重力,物体之间重力不要受到影响
return moon
init_velocity=[vx, vy, 0], gravity_only_for=[gravity_only_for]) # 仅适用于地球的重力,物体之间重力不要受到影响
return football
if __name__ == '__main__':
......@@ -39,13 +40,13 @@ if __name__ == '__main__':
raduis = earth.raduis + 300
# TODO: 4个不同的抛出速度 7.5km/s、8.5km/s、10km/s、11.2km/s(第二宇宙速度)
# 粉色:velocity = 7.5,飞不出地球太远,就落地
obj0 = create_ejected_object(velocity=7.5, raduis=raduis, trail_color=(255, 0, 255))
obj0 = create_ejected_object(velocity=7.5, raduis=raduis, trail_color=(255, 0, 255), gravity_only_for=earth)
# 红色:velocity = 8.5,飞不出地球太远,就落地
obj1 = create_ejected_object(velocity=8.5, raduis=raduis, trail_color=(255, 0, 0))
obj1 = create_ejected_object(velocity=8.5, raduis=raduis, trail_color=(255, 0, 0), gravity_only_for=earth)
# 绿色:velocity = 10,能飞出地球很远,但还是无法摆脱地球引力
obj2 = create_ejected_object(velocity=10, raduis=raduis, trail_color=(0, 255, 0))
obj2 = create_ejected_object(velocity=10, raduis=raduis, trail_color=(0, 255, 0), gravity_only_for=earth)
# 蓝色:velocity = 11.2,脱离地球引力直接飞出。速度11.2千米/秒为脱离地球引力的速度叫第二宇宙速度
obj3 = create_ejected_object(velocity=11.2, raduis=raduis, trail_color=(0, 0, 255))
obj3 = create_ejected_object(velocity=11.2, raduis=raduis, trail_color=(0, 0, 255), gravity_only_for=earth)
bodies = [earth, obj0, obj1, obj2, obj3]
......@@ -64,10 +65,12 @@ if __name__ == '__main__':
# 如果抛出物与地球相碰撞了,则静止不动(抛出物停止并忽略引力)
obj.stop_and_ignore_gravity()
def on_reset():
for obj in [obj0, obj1, obj2, obj3]:
obj.ignore_mass = False
# 订阅计时器事件(定时触发)
UrsinaEvent.on_timer_changed_subscription(on_timer_changed)
UrsinaEvent.on_reset_subscription(on_reset)
......
......@@ -55,9 +55,12 @@ class Simulator(metaclass=ABCMeta):
view.acceleration = body.acceleration
view.velocity = body.velocity
# viewer.volume = body.volume
if hasattr(body, "raduis"):
view.raduis = body.raduis
view.his_position = body.his_position()
if hasattr(body, "is_fixed_star"):
view.is_fixed_star = body.is_fixed_star
if hasattr(body, "has_rings"):
view.has_rings = body.has_rings
view.size_scale = body.size_scale
view.distance_scale = body.distance_scale
......
......@@ -33,12 +33,17 @@ class Planet(Entity):
def __init__(self, body_view: BodyView):
self.body_view = body_view
if hasattr(self.body, "rotation_speed"):
self.rotation_speed = self.body.rotation_speed
self.rotMode = 'x' # random.choice(["x", "y", "z"])
self.name = body_view.name
pos = body_view.position * body_view.body.distance_scale * UrsinaConfig.SCALE_FACTOR
scale = body_view.body.diameter * body_view.body.size_scale * UrsinaConfig.SCALE_FACTOR
pos = body_view.position * self.body.distance_scale * UrsinaConfig.SCALE_FACTOR
if hasattr(self.body, "diameter"):
scale = self.body.diameter * self.body.size_scale * UrsinaConfig.SCALE_FACTOR
else:
scale = self.body.size_scale * UrsinaConfig.SCALE_FACTOR
self.init_scale = scale
if hasattr(body_view, "texture"):
texture = load_texture(body_view.texture)
......@@ -51,6 +56,8 @@ class Planet(Entity):
b_color = (b_color[0], b_color[1], b_color[2], 1.0)
self.plant_color = color.rgba(*b_color)
collider = "sphere"
if hasattr(self.body, "torus_stars"):
# 创建一个星环小天体群(主要模拟小行星群,非一个天体)
model = create_torus(0.83, 1.05, 64, 1)
......@@ -60,7 +67,15 @@ class Planet(Entity):
subdivisions = 32
if self.body.resolution is not None:
subdivisions = self.body.resolution
if hasattr(self.body, "model"):
if self.body.model is None:
model = create_sphere(0.5, subdivisions)
elif isinstance(self.body.model, str):
model = self.body.model
else:
model = self.body.model
rotation = (0, 0, 0)
else:
model = create_sphere(0.5, subdivisions)
rotation = (0, 0, 0)
......@@ -73,7 +88,7 @@ class Planet(Entity):
scale=scale,
texture=texture,
color=self.plant_color,
collider="sphere",
collider=collider,
position=pos,
rotation=rotation,
double_sided=True
......@@ -88,16 +103,21 @@ class Planet(Entity):
# 拖尾球体的初始化
trail_init(self)
if hasattr(self.body, "is_fixed_star"):
if self.body.is_fixed_star:
# 如果是恒星,开启恒星的发光的效果、并作为灯光源
create_fixed_star_lights(self)
elif self.body.light_disable:
# 如果是非恒星,并且禁用灯光
self.set_light_off()
elif self.body.light_disable:
# 如果是非恒星,并且禁用灯光
self.set_light_off()
if self.body.show_name:
create_name_text(self)
if hasattr(self.body, "has_rings"):
if self.body.has_rings:
# 创建行星环(目前只有土星环)
create_rings(self)
......@@ -126,6 +146,7 @@ class Planet(Entity):
dt = 0
if hasattr(self.body, "dt"):
dt = self.body.dt
if hasattr(self, "rotation_speed"):
if self.rotation_speed is None or dt == 0:
self.rotspeed = 0
# 旋转速度和大小成反比(未使用真实数据)
......@@ -139,6 +160,7 @@ class Planet(Entity):
# if self.rotation_y < 0:
# self.rotation_y += 360
try:
if hasattr(self, "rotspeed"):
# 天体旋转
self.rotation_y -= self.rotspeed
except Exception as e:
......
......@@ -38,7 +38,10 @@ class BodyView(metaclass=ABCMeta):
self.position = body.position
self.name = body.name
self.mass = body.mass
if hasattr(body, "raduis"):
self.raduis = body.raduis
self.velocity = body.velocity
self.appeared = True
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册