From 5badf4d0ef5d2ac4d956c5a709361f719b91a8ca Mon Sep 17 00:00:00 2001 From: march3 Date: Sun, 9 Apr 2023 14:09: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 --- bodies/asteroid.py | 4 +- bodies/asteroids.py | 4 +- bodies/body.py | 33 +++++++++++++--- bodies/dysen_sphere.py | 5 ++- bodies/moon.py | 8 +++- common/system.py | 2 +- sim_scenes/fiction/fixed_stars_1.py | 4 +- sim_scenes/fiction/fixed_stars_2.py | 2 + sim_scenes/func.py | 28 +++++++++++++- sim_scenes/funny/text_bodies.py | 3 ++ sim_scenes/funny/the_eye_of_god.py | 3 ++ sim_scenes/science/parabolic_curve.py | 40 ++++++++++++++++---- sim_scenes/solar_system/earth_clouds.py | 2 +- sim_scenes/solar_system/hd_earth_at_night.py | 2 + sim_scenes/solar_system/speed_of_light.py | 1 + simulators/ursina/entities/body_timer.py | 9 +++++ simulators/ursina/entities/planet.py | 2 +- 17 files changed, 126 insertions(+), 26 deletions(-) diff --git a/bodies/asteroid.py b/bodies/asteroid.py index ea2638e..0324fa8 100644 --- a/bodies/asteroid.py +++ b/bodies/asteroid.py @@ -47,9 +47,9 @@ class Asteroid(Body): def show_trail(self): return False - def ignore_gravity(self, body): + def ignore_gravity_with(self, body): """ - 是否忽略引力 + 是否忽略指定天体的引力 @param body: @return: """ diff --git a/bodies/asteroids.py b/bodies/asteroids.py index f1b38df..7310842 100644 --- a/bodies/asteroids.py +++ b/bodies/asteroids.py @@ -50,9 +50,9 @@ class Asteroids(Body): # 环状星群 self.torus_stars = True - def ignore_gravity(self, body): + def ignore_gravity_with(self, body): """ - 是否忽略引力 + 是否忽略指定天体的引力 @param body: @return: """ diff --git a/bodies/body.py b/bodies/body.py index 2f8fa63..3376aeb 100644 --- a/bodies/body.py +++ b/bodies/body.py @@ -38,6 +38,7 @@ class Body(metaclass=ABCMeta): @param rotation_speed: 自旋速度(度/小时) @param parent: 天体的父对象 @param ignore_mass: 是否忽略质量(如果为True,则不计算引力) + TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) @param is_fixed_star: 是否为恒星 @param trail_color: 天体拖尾颜色(默认天体颜色) @param show_name: 是否显示天体名称 @@ -53,10 +54,11 @@ class Body(metaclass=ABCMeta): self.name = name self.__mass = mass + # 是否忽略质量(如果为True,则不计算引力) + # TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) if self.__mass <= 0: # 质量小于等于0就忽略 self.ignore_mass = True else: - # 是否忽略质量(如果为True,则不计算引力) self.ignore_mass = ignore_mass self.__init_position = None @@ -97,12 +99,13 @@ class Body(metaclass=ABCMeta): self.__has_rings = False - def set_ignore_mass(self, value=True): + def set_ignore_gravity(self, value=True): """ 设置忽略质量,True为引力失效 @param value: @return: """ + # TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) if self.__mass <= 0: # 质量小于等于0就忽略 self.ignore_mass = True else: @@ -220,9 +223,26 @@ class Body(metaclass=ABCMeta): @param value: @return: """ - self.__acceleration = value + 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): """ @@ -359,12 +379,15 @@ class Body(metaclass=ABCMeta): (self.name, self.__class__.__name__, self.mass, self.raduis, self.diameter, self.volume, self.density, self.position[0], self.position[1], self.position[2], self.velocity) - def ignore_gravity(self, body): + def ignore_gravity_with(self, body): """ - 是否忽略引力 + 是否忽略指定天体的引力 @param body: @return: """ + # TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) + if self.ignore_mass: + return True return False diff --git a/bodies/dysen_sphere.py b/bodies/dysen_sphere.py index ec17cc4..00cb167 100644 --- a/bodies/dysen_sphere.py +++ b/bodies/dysen_sphere.py @@ -39,13 +39,14 @@ class DysenSphere(Body): "parent": parent } super().__init__(**params) + # TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) self.ignore_mass = True # 灯光禁用 self.light_disable = True - def ignore_gravity(self, body): + def ignore_gravity_with(self, body): """ - 是否忽略引力 + 是否忽略指定天体的引力 @param body: @return: """ diff --git a/bodies/moon.py b/bodies/moon.py index 18bb5f0..a16011f 100644 --- a/bodies/moon.py +++ b/bodies/moon.py @@ -39,6 +39,7 @@ class Moon(Body): @param distance_scale: 距离缩放 @param rotation_speed: 自旋速度(度/小时) @param ignore_mass: 是否忽略质量(如果为True,则不计算引力) + TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) @param trail_color:月球拖尾颜色(默认天体颜色) @param show_name: 是否显示月球名称 @param gravity_only_for_earth: 如果为True,则仅适用于地球的重力,与其他天体之间的重力不会受到影响 @@ -61,12 +62,15 @@ class Moon(Body): super().__init__(**params) self.gravity_only_for_earth = gravity_only_for_earth - def ignore_gravity(self, body): + def ignore_gravity_with(self, body): """ - 是否忽略引力 + 是否忽略指定天体的引力 @param body: @return: """ + if self.ignore_mass: + return True + if self.gravity_only_for_earth: # 月球只对地球有引力,忽略其他的引力 if isinstance(body, Earth): diff --git a/common/system.py b/common/system.py index 44c88a4..f6a7f0d 100644 --- a/common/system.py +++ b/common/system.py @@ -186,7 +186,7 @@ class System(object): if body1 is body2: continue - elif body1.ignore_gravity(body2) or body2.ignore_gravity(body1): + elif body1.ignore_gravity_with(body2) or body2.ignore_gravity_with(body1): continue r = body2.position - body1.position diff --git a/sim_scenes/fiction/fixed_stars_1.py b/sim_scenes/fiction/fixed_stars_1.py index 55ab459..d551bde 100644 --- a/sim_scenes/fiction/fixed_stars_1.py +++ b/sim_scenes/fiction/fixed_stars_1.py @@ -14,11 +14,13 @@ from bodies.body import Body, AU if __name__ == '__main__': """ - 恒星演示 + 恒星演示 """ # 构建恒星天体对象 D = 5e5 # 基本距离单位:km(随意赋值) SIZE_SCALE = 0.5 # 所有天体尺寸缩放保持一致 + # TODO: ignore_mass=True + # 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) bodies = [ Earth(size_scale=SIZE_SCALE, ignore_mass=True), Sun(size_scale=SIZE_SCALE, ignore_mass=True), # 太阳 diff --git a/sim_scenes/fiction/fixed_stars_2.py b/sim_scenes/fiction/fixed_stars_2.py index 51e221c..15f71a2 100644 --- a/sim_scenes/fiction/fixed_stars_2.py +++ b/sim_scenes/fiction/fixed_stars_2.py @@ -19,6 +19,8 @@ if __name__ == '__main__': # 构建恒星天体对象 D = 5e5 # 基本距离单位:km(随意赋值) SIZE_SCALE = 0.5 # 所有天体尺寸缩放保持一致 + # TODO: ignore_mass=True + # 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) bodies = [ Earth(size_scale=SIZE_SCALE, ignore_mass=True), Sun(size_scale=SIZE_SCALE, ignore_mass=True), # 太阳 diff --git a/sim_scenes/func.py b/sim_scenes/func.py index da4f5f9..b0dbd23 100644 --- a/sim_scenes/func.py +++ b/sim_scenes/func.py @@ -8,11 +8,14 @@ # ============================================================================== import matplotlib.pyplot as plt from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, SECONDS_PER_HALF_DAY +from common.func import calculate_distance from common.system import System +from bodies import Body from simulators.ursina.ursina_config import UrsinaConfig from simulators.ursina.ursina_event import UrsinaEvent from common.consts import LIGHT_SPEED import math +import numpy as np def mayavi_run(bodies, dt=SECONDS_PER_WEEK, @@ -202,7 +205,7 @@ def create_solar_system_bodies(ignore_mass=False, init_velocity=None): # 遍历所有天体, for idx, body in enumerate(bodies): - body.set_ignore_mass(ignore_mass) # 忽略质量(引力无效) + body.set_ignore_gravity(ignore_mass) # 忽略质量(引力无效) if init_velocity is not None: body.init_velocity = init_velocity return bodies @@ -262,6 +265,29 @@ def get_vector2d_velocity(velocity, angle=15): return vx, vy +def two_bodies_colliding(body1: Body, body2: Body): + """ + 判断两个天体是否相撞 + @param body1: + @param body2: + @return: + """ + if hasattr(body1, "planet") and hasattr(body2, "planet"): + # 使用 Ursina 的算法 + if hasattr(body1.planet, "intersects"): + return body1.planet.intersects(body2.planet).hit + + # 自行实现的算法,两物体的距离小于两物体半径的和,就视为碰撞了 + d = calculate_distance(np.array(body1.position) * body1.distance_scale, + np.array(body2.position) * body2.distance_scale) + + if d <= body1.raduis * body1.size_scale + body2.raduis * body2.size_scale: + return True + return False + + # raise Exception("two_bodies_colliding 不支持类型[body1 body2]") + + if __name__ == '__main__': from bodies import Sun, Earth diff --git a/sim_scenes/funny/text_bodies.py b/sim_scenes/funny/text_bodies.py index aeacc91..6374323 100644 --- a/sim_scenes/funny/text_bodies.py +++ b/sim_scenes/funny/text_bodies.py @@ -27,7 +27,10 @@ def show_text_bodies(): pixel_image="./images/china.png", texture="color_body.png", params={"camera_pos": camera_pos}) + # 放一个恒星作为背景 + # TODO: ignore_mass=True + # 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) bg = FixedStar(name="背景恒星", texture="fixed_star.png", mass=2e32, color=(0xff, 0xf8, 0xd4), init_position=[-450 * D, 100 * D, 6000 * D], # [ 左-右+, 上+下-, 远+近- ] diff --git a/sim_scenes/funny/the_eye_of_god.py b/sim_scenes/funny/the_eye_of_god.py index 0f58e05..6162350 100644 --- a/sim_scenes/funny/the_eye_of_god.py +++ b/sim_scenes/funny/the_eye_of_god.py @@ -24,7 +24,10 @@ def show_eye_of_god(): bodies = gen_bodies_from_image(pixel_image="./images/eye.png", texture="color_body.jpg", params={"camera_pos": camera_pos}) + # 放一个恒星作为背景 + # TODO: ignore_mass=True + # 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) bg = FixedStar(name="背景恒星", texture="fixed_star.png", mass=2e32, color=(0xff, 0xf8, 0xd4), init_position=[-400 * D, 100 * D, 6000 * D], # [ 左-右+, 上+下-, 远+近- ] diff --git a/sim_scenes/science/parabolic_curve.py b/sim_scenes/science/parabolic_curve.py index d0da316..6fbe248 100644 --- a/sim_scenes/science/parabolic_curve.py +++ b/sim_scenes/science/parabolic_curve.py @@ -8,7 +8,9 @@ # ============================================================================== from bodies import Moon, Earth, Body from common.consts import SECONDS_PER_HOUR, SECONDS_PER_MINUTE -from sim_scenes.func import ursina_run, get_vector2d_velocity +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): @@ -33,16 +35,38 @@ if __name__ == '__main__': 抛物线模拟 """ # 地球在中心位置 - e = Earth(init_position=[0, 0, 0], size_scale=1, texture="earth_hd.jpg", init_velocity=[0, 0, 0]) - raduis = e.raduis + 300 - # 红色:velocity = 8 # 物体飞不出地球太远,就落地 - obj1 = create_ejected_object(velocity=8, raduis=raduis, trail_color=(255, 0, 0)) - # 绿色:velocity = 10 # 物体能飞出地球很远,但还是无法摆脱地球引力 + earth = Earth(init_position=[0, 0, 0], size_scale=1, texture="earth_hd.jpg", init_velocity=[0, 0, 0]) + 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)) + # 红色:velocity = 8.5,飞不出地球太远,就落地 + obj1 = create_ejected_object(velocity=8.5, raduis=raduis, trail_color=(255, 0, 0)) + # 绿色:velocity = 10,能飞出地球很远,但还是无法摆脱地球引力 obj2 = create_ejected_object(velocity=10, raduis=raduis, trail_color=(0, 255, 0)) - # 蓝色:velocity = 11.2 # 脱离地球引力直接飞出。速度11.2千米/秒为脱离地球引力的速度叫第二宇宙速度 + # 蓝色:velocity = 11.2,脱离地球引力直接飞出。速度11.2千米/秒为脱离地球引力的速度叫第二宇宙速度 obj3 = create_ejected_object(velocity=11.2, raduis=raduis, trail_color=(0, 0, 255)) - bodies = [e, obj1, obj2, obj3] + bodies = [earth, obj0, obj1, obj2, obj3] + + + def on_timer_changed(time_data: TimeData): + """ + 定时触发,在10分钟后,进行碰撞判断,如果抛出物与地球相碰撞了,则抛出物体静止不动 + @param time_data: + @return: + """ + if time_data.total_minutes > 10: + # 抛出物体10分钟后,再进行碰撞判断 + for obj in [obj0, obj1, obj2, obj3]: + # 循环判断每个抛出物与地球是否相碰撞 + if two_bodies_colliding(obj, earth): + # 如果抛出物与地球相碰撞了,则静止不动(抛出物停止并忽略引力) + obj.stop_and_ignore_gravity() + + + # 订阅计时器事件(定时触发) + UrsinaEvent.on_timer_changed_subscription(on_timer_changed) # 使用 ursina 查看的运行效果 # 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹 diff --git a/sim_scenes/solar_system/earth_clouds.py b/sim_scenes/solar_system/earth_clouds.py index adcbf47..ff09eab 100644 --- a/sim_scenes/solar_system/earth_clouds.py +++ b/sim_scenes/solar_system/earth_clouds.py @@ -17,7 +17,7 @@ if __name__ == '__main__': """ earth = Earth(texture="earth_hd.jpg", init_position=[0, 0, 0], init_velocity=[0, 0, 0], - size_scale=1).set_ignore_mass() + size_scale=1).set_ignore_gravity() # 创建带有云层的地球 earth_with_clouds = Earth(texture="earth_hd.jpg", diff --git a/sim_scenes/solar_system/hd_earth_at_night.py b/sim_scenes/solar_system/hd_earth_at_night.py index d53aed0..4f4575a 100644 --- a/sim_scenes/solar_system/hd_earth_at_night.py +++ b/sim_scenes/solar_system/hd_earth_at_night.py @@ -19,6 +19,8 @@ if __name__ == '__main__': """ resolution = 50 # resolution = 500 + # TODO: ignore_mass=True + # 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) bodies = [ Earth(texture="earth_at_night_hd.jpg", init_position=[0, 0, 0], init_velocity=[0, 0, 0], diff --git a/sim_scenes/solar_system/speed_of_light.py b/sim_scenes/solar_system/speed_of_light.py index f10a087..a3eb74e 100644 --- a/sim_scenes/solar_system/speed_of_light.py +++ b/sim_scenes/solar_system/speed_of_light.py @@ -18,6 +18,7 @@ camera_follow_light = 'SideView' # 摄像机跟随光,方向是侧面看 # 实例化一个初始化对象(订阅事件,记录到达每个行星所需要的时间) init = SpeedOfLightInit(camera_follow_light) +# TODO: 注意:这里的算法是基于牛顿的万有引力(质量为0不受引力的影响在天体物理学中是不严谨) # 创建太阳系天体(忽略质量,引力无效,初速度全部为0) bodies = create_solar_system_bodies(ignore_mass=True, init_velocity=[0, 0, 0]) diff --git a/simulators/ursina/entities/body_timer.py b/simulators/ursina/entities/body_timer.py index 03a6df1..18e0ac5 100644 --- a/simulators/ursina/entities/body_timer.py +++ b/simulators/ursina/entities/body_timer.py @@ -41,6 +41,15 @@ class TimeData: else: self.time_text = f'{self.hours:02d}:{self.minutes:02d}:{self.seconds:02d}' + @property + def total_minutes(self): + return self.total_seconds / 60 + + @property + def total_hours(self): + return self.total_seconds / 3600 + + class BodyTimer(Singleton): """ diff --git a/simulators/ursina/entities/planet.py b/simulators/ursina/entities/planet.py index 35fe941..d971d59 100644 --- a/simulators/ursina/entities/planet.py +++ b/simulators/ursina/entities/planet.py @@ -73,7 +73,7 @@ class Planet(Entity): scale=scale, texture=texture, color=self.plant_color, - # collider="sphere", + collider="sphere", position=pos, rotation=rotation, double_sided=True -- GitLab