diff --git a/objs/__init__.py b/objs/__init__.py index 1b6d0ca49e77996ed5e70aa1a392ba5f36e0aed9..d757203f2866467b9a87e619a89cb2321604e337 100644 --- a/objs/__init__.py +++ b/objs/__init__.py @@ -1,3 +1,4 @@ +from objs.obj import Obj from objs.diamond import Diamond from objs.football import Football from objs.satellite import Satellite, Satellite2 diff --git a/objs/obj.py b/objs/obj.py index 5a05dcf6dace2a60522ce35711b93a3fc680b116..46795b123d76bec87e80e1e98a4647d6a6c41f2e 100644 --- a/objs/obj.py +++ b/objs/obj.py @@ -14,6 +14,8 @@ from common.consts import AU import copy import os +from simulators.ursina.entities.entity_utils import get_value_direction_vectors + class Obj(metaclass=ABCMeta): """ @@ -197,6 +199,36 @@ class Obj(metaclass=ABCMeta): self.__position = value self.__record_history() + def acceleration_value(self): + """ + 获取加速度的值(km/s²) + @return: + """ + direction_vectors = get_value_direction_vectors(self.acceleration) + return direction_vectors[0] # km/s² + + def velocity_value(self): + """ + 获取速度的值(km/s) + @return: + """ + direction_vectors = get_value_direction_vectors(self.velocity) + return direction_vectors[0] # km/s + + def acceleration_value_direction(self): + """ + 获取加速度的值(km/s²)和方向 + @return: 值[0],方向[1] + """ + return get_value_direction_vectors(self.acceleration) + + def velocity_value_direction(self): + """ + 获取速度的值(km/s)和方向 + @return: 值[0],方向[1] + """ + return get_value_direction_vectors(self.velocity) + @property def acceleration(self): """ diff --git a/sim_lab/research_calc.py b/sim_lab/research_calc.py index b515917de4add3f3bb12887b8e081292f2bdd76d..449df3ea482e7455492cffb00c9228b30ba70286 100644 --- a/sim_lab/research_calc.py +++ b/sim_lab/research_calc.py @@ -7,11 +7,31 @@ # python_version :3.8 # ============================================================================== from bodies import Body, Sun, Earth, Moon +from objs import Obj from objs import Satellite, Satellite2 from common.consts import SECONDS_PER_HOUR, SECONDS_PER_DAY, SECONDS_PER_WEEK, SECONDS_PER_MONTH from sim_scenes.func import calc_run from bodies.body import AU -from simulators.calc_simulator import CalcSimulator, CalcContext + + +def get_lagrangian_points(m1, m2, r): + """ + https://baike.baidu.com/item/%E6%8B%89%E6%A0%BC%E6%9C%97%E6%97%A5%E7%82%B9/731078 + + @param m1: 大质量 + @param m2: 小质量 + @param r: 半径 + @return: + """ + a = m2 / (m1 + m2) + l1 = (0, 0, r * (1 - pow(a / 3, 1 / 3))) + l2 = (0, 0, r * (1 + pow(a / 3, 1 / 3))) + l3 = (0, 0, -r * (1 + (5 * a) / 12)) + l4 = (pow(3, 1 / 2) / 2 * r, 0, (r / 2) * ((m1 - m2) / (m1 + m2))) + l5 = (-pow(3, 1 / 2) / 2 * r, 0, (r / 2) * ((m1 - m2) / (m1 + m2))) + + return l1, l2, l3, l4, l5 + bodies = [ Earth(init_position=[0, 0, 0], texture="earth_hd.jpg", @@ -19,17 +39,98 @@ bodies = [ Moon(init_position=[0, 0, 363104], # 距地距离约: 363104 至 405696 km init_velocity=[-1.054152222, 0, 0], size_scale=1e1) # 月球放大 10 倍,距离保持不变 ] +earth = bodies[0] +moon = bodies[1] +points = get_lagrangian_points(earth.mass, moon.mass, 363104) +L1_point = points[0] +point_z = L1_point[2] + 3301.0505 # 越大,离月球越近 +init_velocity = [-0.890211, 0, 0] +satellite = Satellite(name=f'卫星', mass=1.4e10, size_scale=1e3, color=(255, 200, 0), + init_position=[L1_point[0], L1_point[1], point_z], + init_velocity=init_velocity, gravity_only_for=[earth, moon]) +bodies.append(satellite) + + +def calc_simulator(): + from simulators.calc_simulator import CalcSimulator, CalcContext + def evolve_next(context: CalcContext): + return context.evolve_count < 500 + + def after_evolve(dt, context: CalcContext): + target: Body = context.bodies[1] + # target: Obj = context.bodies[2] + + context.init_param("acc_values", []).params["acc_values"].append(target.acceleration_value()) + context.init_param("vel_values", []).params["vel_values"].append(target.velocity_value()) + + print(satellite.acceleration_value(), satellite.velocity_value()) + + def on_finished(context: CalcContext): + import matplotlib.pyplot as plt + # 解决中文显示问题 + plt.rcParams['font.sans-serif'] = ['SimHei'] + plt.rcParams['axes.unicode_minus'] = False + acc_values = context.params["acc_values"] + vel_values = context.params["vel_values"] + max_value = max(acc_values) + min_value = min(acc_values) + fig = plt.figure(figsize=(10, 6)) + ax1 = fig.add_subplot(111) + ax1.plot(acc_values, 'blue', label='加速度') + ax1.set_ylabel('加速度', fontdict={'weight': 'normal', 'size': 15, 'color': 'blue'}) + # ax1.set_title("加速度/速度", fontdict={'weight': 'normal', 'size': 15}) + plt.title("%s max:%.4f mix:%.4f diff:%.4f" % ( + moon.init_velocity[0], max_value * 1e6, min_value * 1e6, (max_value - min_value) * 1e6)) + l1 = ax1.legend(loc='lower left', labels=['加速度']) + + ax2 = ax1.twinx() # this is the important function + ax2.plot(vel_values, 'red', label='速度') + ax2.set_ylabel('速度', fontdict={'weight': 'normal', 'size': 15, 'color': 'red'}) + ax2.set_xlabel('Same') + + l2 = ax2.legend(loc='upper right', labels=['速度']) + plt.show() + + CalcSimulator.on_after_evolve_subscription(after_evolve) + CalcSimulator.on_finished_subscription(on_finished) + + calc_run(bodies, SECONDS_PER_HOUR, evolve_next=evolve_next) + +def ursina_simulator(): + from sim_scenes.func import ursina_run, camera_look_at + from simulators.ursina.entities.body_timer import TimeData + from simulators.ursina.entities.entity_utils import create_directional_light + from simulators.ursina.ursina_event import UrsinaEvent + from simulators.ursina.ursina_mesh import create_line + def on_ready(): + # 运行前触发 + # 运行开始前,将摄像机指向地球 -def evolve_next(context: CalcContext): - return context.evolve_count < 200 + # 摄像机看向地球 + camera_look_at(moon) + def on_timer_changed(time_data: TimeData): + from ursina import destroy + if hasattr(earth, "line"): + destroy(earth.line) + earth.line = create_line(from_pos=earth.planet.position, to_pos=moon.planet.main_entity.position) -def after_evolve(dt, context: CalcContext): - moon: Body = context.bodies[1] - print(moon.acceleration_value(), moon.velocity_value()) + # 订阅事件后,上面的函数功能才会起作用 + # 运行前会触发 on_ready + UrsinaEvent.on_ready_subscription(on_ready) + # 运行中,每时每刻都会触发 on_timer_changed + UrsinaEvent.on_timer_changed_subscription(on_timer_changed) + # 使用 ursina 查看的运行效果 + # 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹 + # position = 左-右+、上+下-、前+后- + ursina_run(bodies, SECONDS_PER_HOUR * 10, + position=(-300000, 1500000, -100), + show_timer=True, + show_trail=True) -CalcSimulator.on_after_evolve_subscription(after_evolve) -calc_run(bodies, SECONDS_PER_HOUR, evolve_next=evolve_next) +if __name__ == '__main__': + calc_simulator() + # ursina_simulator() diff --git a/simulators/calc_simulator.py b/simulators/calc_simulator.py index 4ba3cea887ec993d49fbedccdb3c20cf7bf51e0c..fae55452a8dc0deb3854d00b08ed6ef23fa8cadc 100644 --- a/simulators/calc_simulator.py +++ b/simulators/calc_simulator.py @@ -38,6 +38,17 @@ class CalcContext(Singleton): # 存放参数字典数据,通过 get_param 获取 self._params = {} + def init_param(self, key, value): + """ + 只会初始化一次(除非删除掉) + @param key: + @param value: + @return: + """ + if key not in self._params: + self.put_param(key, value) + return self + @property def bodies(self) -> []: return self.simulator.bodies_sys.bodies @@ -52,6 +63,7 @@ class CalcContext(Singleton): def put_param(self, key, data): self._params[key] = data + return self def get_param(self, key): """