diff --git a/common/celestial_data_service.py b/common/celestial_data_service.py index a9c850853db422a6744d36558e061e75b3b343e9..870a1d964ef11ef9090f022f87155f12d41d817d 100644 --- a/common/celestial_data_service.py +++ b/common/celestial_data_service.py @@ -7,11 +7,18 @@ # python_version :3.8 # ============================================================================== import math -from common.consts import G -from bodies import Body +from common.consts import G, AU, SECONDS_PER_DAY +from bodies import Body, Sun, Asteroids, Moon, Earth +import numpy as np def calc_solar_acceleration(body_or_pos, big_body): + """ + 计算天体的加速度 + @param body_or_pos: 需要计算的天体 + @param big_body: 大天体(太阳 或者 地球) + @return: + """ if isinstance(body_or_pos, Body): body_pos = body_or_pos.position else: @@ -97,6 +104,108 @@ def get_celestial_body_data(body_name): return position, velocity +def set_solar_system_celestial_position(bodies, dt, recalc_moon_pos): + """ + 根据日期时间 dt 设置太阳系中天体的真实位置 + @param bodies: 太阳系中天体 + @param dt: 时间 + @param recalc_moon_pos: 是否对月球的位置进行重新计算。 + 为了更好的展示效果,需要对月球的位置重新计算(使得地月距离放大,月球相对地球方向不变), + 重新计算位置后,地球和月球可以放大1000倍以上 + @return: + """ + earth_pos = None + sun_pos = None + earth = None + sun = None + moon = None + + for body in bodies: + if isinstance(body, Sun): + sun = body + elif isinstance(body, Earth): + earth = body + elif isinstance(body, Moon): + moon = body + + for body in bodies: + if isinstance(body, Asteroids): # 小行星带是模拟,不是正常的天体 + posvel = None + else: + # 获取天体的三维位置和矢量速度 + posvel = get_body_posvel(body, dt) + + if isinstance(body, Moon): # 如果是月球,为了更好的展示效果,需要对月球的位置重新计算 + moon_real_pos = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU] + # TODO:注释下行,月球就会在真实的位置 + if recalc_moon_pos: + posvel = recalc_moon_position(posvel, earth_pos) + + if posvel is None: + # posvel 为空,则使用太阳的坐标 + position, velocity = [sun_pos.x.value * AU, + sun_pos.z.value * AU, + sun_pos.y.value * AU], [0, 0, 0] + else: + # 坐标单位:千米 速度单位:千米/秒 + position, velocity = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU], \ + [posvel[1].x.value * AU / SECONDS_PER_DAY, + posvel[1].z.value * AU / SECONDS_PER_DAY, + posvel[1].y.value * AU / SECONDS_PER_DAY] + + # 实时调整天体的位置和速度 + body.position = np.array(position) + body.velocity = np.array(velocity) + + if isinstance(body, Asteroids): + pass + elif isinstance(body, Sun): + # 记录太阳的位置 + sun_pos = posvel[0] + elif isinstance(body, Moon): + # 月球受到2个影响比较大的天体引力(地球和太阳),计算引力引起的加速度和 + acc_earth = calc_solar_acceleration(moon_real_pos, earth) + acc_sun = calc_solar_acceleration(moon_real_pos, sun) + body.acceleration = [acc_earth[0] + acc_sun[0], + acc_earth[1] + acc_sun[1], + acc_earth[2] + acc_sun[2]] + # elif isinstance(body, Earth): + # # 月球受到2个影响比较大的天体引力(地球和太阳),计算引力引起的加速度和 + # acc_earth = calc_solar_acceleration(earth, moon) + # acc_sun = calc_solar_acceleration(earth, sun) + # body.acceleration = [acc_earth[0] + acc_sun[0], + # acc_earth[1] + acc_sun[1], + # acc_earth[2] + acc_sun[2]] + else: + # 其他天体受到太阳引力 + body.acceleration = calc_solar_acceleration(body, sun) + + if isinstance(body, Earth): + # 记录地球的位置 + earth_pos = posvel[0] + + +def set_earth_rotation(earth, dt): + """ + 根据指定的时间控制地球的旋转角度(保证地球的自转和北京时间同步) + @param dt: 时间 datetime + @return: + """ + + # timetuple 可以获取当天的小时数、分数钟、秒数 + timetuple = dt.timetuple() + # 当年的第几天 + day_of_year = timetuple.tm_yday + # 根据当年的第几天计算出该日期当天的偏转角度:360度 / 365天 = 当天的偏转角度 + angle_of_day = day_of_year * (360 / 365) + # 计算出精确的小时数 + total_hours = timetuple.tm_hour + timetuple.tm_min / 60 + timetuple.tm_sec / 60 / 60 + # -total_hours: 负号控制地球的旋转方向、1天24小时,360度/24=15 + # total_hours * 15:1天24小时,360度/24小时=1小时15度 + # angle_of_day: 1年第几天的角度 + earth.planet.rotation_y = -total_hours * 15 - angle_of_day + 15 # 精确调整 + + # pip install Astropysics if __name__ == '__main__': diff --git a/sim_scenes/solar_system/earth_moon_reality.py b/sim_scenes/solar_system/earth_moon_reality.py index 291caf5b7aa76ae326204edbbe4abb2c6a394e32..12196f2ce9725136a9ff10db8d2cbc2a4af995fa 100644 --- a/sim_scenes/solar_system/earth_moon_reality.py +++ b/sim_scenes/solar_system/earth_moon_reality.py @@ -11,7 +11,8 @@ import math import numpy as np from bodies import Sun, Mercury, Venus, Earth, Mars, Asteroids, Jupiter, Saturn, Uranus, Neptune, Moon -from common.celestial_data_service import get_body_posvel, recalc_moon_position, calc_solar_acceleration +from common.celestial_data_service import get_body_posvel, recalc_moon_position, calc_solar_acceleration, \ + set_solar_system_celestial_position, set_earth_rotation from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, AU from sim_scenes.func import ursina_run, camera_look_at from simulators.ursina.entities.body_timer import TimeData @@ -53,8 +54,12 @@ class SolarSystemRealitySim: self.moon_size_scale = 5e1 self.sun_size_scale = 1e1 + self.earth_size_scale = 1 + self.moon_size_scale = 1 + self.sun_size_scale = 1 + self.sun = Sun(name="太阳", size_scale=self.sun_size_scale) # 太阳 - self.earth = Earth(name="地球", texture="earth_hd.jpg", + self.earth = Earth(name="地球", # texture="earth_hd.jpg", rotate_angle=3.44, size_scale=self.earth_size_scale) # 地球 self.earth_camera = Earth(name="地球摄像机", texture="transparent.png", @@ -80,26 +85,6 @@ class SolarSystemRealitySim: if self.debug_mode: self.earth.set_light_disable(True) - def set_earth_rotation(self, dt): - """ - 根据指定的时间控制地球的旋转角度(保证地球的自转和北京时间同步) - @param dt: 时间 datetime - @return: - """ - - # timetuple 可以获取当天的小时数、分数钟、秒数 - timetuple = dt.timetuple() - # 当年的第几天 - day_of_year = timetuple.tm_yday - # 根据当年的第几天计算出该日期当天的偏转角度:360度 / 365天 = 当天的偏转角度 - angle_of_day = day_of_year * (360 / 365) - # 计算出精确的小时数 - total_hours = timetuple.tm_hour + timetuple.tm_min / 60 + timetuple.tm_sec / 60 / 60 - # -total_hours: 负号控制地球的旋转方向、1天24小时,360度/24=15 - # total_hours * 15:1天24小时,360度/24小时=1小时15度 - # angle_of_day: 1年第几天的角度 - self.earth.planet.rotation_y = -total_hours * 15 - angle_of_day + 15 # 精确调整 - def show_clock(self, dt): """ 显示时钟 @@ -125,58 +110,7 @@ class SolarSystemRealitySim: @return: """ t = self.start_time + time_data.total_days - - earth_pos = None - sun_pos = None - - for body in self.bodies: - if isinstance(body, Asteroids): # 小行星带是模拟,不是正常的天体 - posvel = None - else: - # 获取天体的三维位置和矢量速度 - posvel = get_body_posvel(body, t) - - if isinstance(body, Moon): # 如果是月球,为了更好的展示效果,需要对月球的位置重新计算 - moon_real_pos = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU] - # TODO:注释下行,月球就会在真实的位置 - if self.recalc_moon_pos: - posvel = recalc_moon_position(posvel, earth_pos) - - if posvel is None: - # posvel 为空,则使用太阳的坐标 - position, velocity = [sun_pos.x.value * AU, - sun_pos.z.value * AU, - sun_pos.y.value * AU], [0, 0, 0] - else: - # 坐标单位:千米 速度单位:千米/秒 - position, velocity = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU], \ - [posvel[1].x.value * AU / SECONDS_PER_DAY, - posvel[1].z.value * AU / SECONDS_PER_DAY, - posvel[1].y.value * AU / SECONDS_PER_DAY] - - # 实时调整天体的位置和速度 - body.position = np.array(position) - body.velocity = np.array(velocity) - - if isinstance(body, Asteroids): - pass - elif isinstance(body, Sun): - # 记录太阳的位置 - sun_pos = posvel[0] - elif isinstance(body, Moon): - # 月球受到2个影响比较大的天体引力(地球和太阳),计算引力引起的加速度和 - acc_earth = calc_solar_acceleration(moon_real_pos, self.earth) - acc_sun = calc_solar_acceleration(moon_real_pos, self.sun) - body.acceleration = [acc_earth[0] + acc_sun[0], - acc_earth[1] + acc_sun[1], - acc_earth[2] + acc_sun[2]] - else: - # 其他天体受到太阳引力 - body.acceleration = calc_solar_acceleration(body, self.sun) - - if isinstance(body, Earth): - # 记录地球的位置 - earth_pos = posvel[0] + set_solar_system_celestial_position(self.bodies, t, self.recalc_moon_pos) def on_ready(self): """ @@ -190,6 +124,8 @@ class SolarSystemRealitySim: # camera.fov = 30 # 调试时,拉近摄像机距离 # camera.fov = 1 camera.parent = self.earth_camera.planet + # camera.update = self.camera_update + # 需要按照时间和日期来控制地球的自转,所以删除控制地球自转的属性 delattr(self.earth.planet, "rotation_speed") delattr(self.earth.planet, "rotspeed") @@ -202,23 +138,36 @@ class SolarSystemRealitySim: # 设置后,可以调整鼠标键盘的控制速度 application.time_scale = 2 + # + # def camera_update(self): + # camera.x = -50 # 100 + # # camera.z = -10 + # camera.y = 20 + # camera.z = -10 + # # 摄像机看向地球 + # camera_look_at(self.earth) - def set_camera_pos(self, time_data: TimeData): - - if time_data.total_days > 120: - self.earth_camera.camera_init_val = +3000000 - elif time_data.total_days > 90: - self.earth_camera.camera_init_val = +1200000 - elif time_data.total_days > 90: - self.earth_camera.camera_init_val += 600000 - elif time_data.total_days > 60: - self.earth_camera.camera_init_val += 100000 - camera.x = -300 # 100 + def set_camera_pos(self, time_data: TimeData): + # if time_data.total_days > 120: + # self.earth_camera.camera_init_val = +3000000 + # elif time_data.total_days > 90: + # self.earth_camera.camera_init_val = +1200000 + # elif time_data.total_days > 90: + # self.earth_camera.camera_init_val += 600000 + # elif time_data.total_days > 60: + # self.earth_camera.camera_init_val += 100000 + + # camera.x = -300 # 100 # camera.z = 200 - camera.y += self.earth_camera.camera_init_val * UrsinaConfig.SCALE_FACTOR + # camera.y += self.earth_camera.camera_init_val * UrsinaConfig.SCALE_FACTOR + + camera.x = -60 # 100 + # camera.z = -10 + camera.y = 50 - UrsinaConfig.trail_factor = 3 * math.sqrt(camera.y / 250) + # UrsinaConfig.trail_factor = 3 * math.sqrt(camera.y / 250) + pass def on_timer_changed(self, time_data: TimeData): """ @@ -230,7 +179,7 @@ class SolarSystemRealitySim: # 设置天体的位置(包含速度和加速度的信息) self.set_bodies_position(time_data) # 保证地球的自转和北京时间同步 - self.set_earth_rotation(dt) + set_earth_rotation(self.earth, dt) # 调整摄像机的位置 self.set_camera_pos(time_data) # 摄像机看向地球 @@ -282,7 +231,7 @@ class SolarSystemRealitySim: # 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹 # position = 左-右+、上+下-、前+后- ursina_run(self.bodies, dt, - position=(0, 500000000, 0), + position=(0, 0, 0), # position=(0, 0.2 * AU, -3 * AU), gravity_works=False, # 关闭万有引力的计算 show_grid=False, diff --git a/sim_scenes/solar_system/solar_system_reality.py b/sim_scenes/solar_system/solar_system_reality.py index 3c01b3287b545cdde9f013b3250a59b9edd7d3f8..411fa966d796c982497a978a27672b54089422fd 100644 --- a/sim_scenes/solar_system/solar_system_reality.py +++ b/sim_scenes/solar_system/solar_system_reality.py @@ -10,7 +10,8 @@ import numpy as np from bodies import Sun, Mercury, Venus, Earth, Mars, Asteroids, Jupiter, Saturn, Uranus, Neptune, Moon -from common.celestial_data_service import get_body_posvel, recalc_moon_position, calc_solar_acceleration +from common.celestial_data_service import get_body_posvel, recalc_moon_position, calc_solar_acceleration, \ + set_solar_system_celestial_position, set_earth_rotation from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, AU from sim_scenes.func import ursina_run from simulators.ursina.entities.body_timer import TimeData @@ -90,26 +91,6 @@ class SolarSystemRealitySim: if self.debug_mode: self.earth.set_light_disable(True) - def set_earth_rotation(self, dt): - """ - 根据指定的时间控制地球的旋转角度(保证地球的自转和北京时间同步) - @param dt: 时间 datetime - @return: - """ - - # timetuple 可以获取当天的小时数、分数钟、秒数 - timetuple = dt.timetuple() - # 当年的第几天 - day_of_year = timetuple.tm_yday - # 根据当年的第几天计算出该日期当天的偏转角度:360度 / 365天 = 当天的偏转角度 - angle_of_day = day_of_year * (360 / 365) - # 计算出精确的小时数 - total_hours = timetuple.tm_hour + timetuple.tm_min / 60 + timetuple.tm_sec / 60 / 60 - # -total_hours: 负号控制地球的旋转方向、1天24小时,360度/24=15 - # total_hours * 15:1天24小时,360度/24小时=1小时15度 - # angle_of_day: 1年第几天的角度 - self.earth.planet.rotation_y = -total_hours * 15 - angle_of_day + 15 # 精确调整 - def show_clock(self, dt): """ 显示时钟 @@ -134,58 +115,7 @@ class SolarSystemRealitySim: @return: """ t = self.start_time + time_data.total_days - - earth_pos = None - sun_pos = None - - for body in self.bodies: - if isinstance(body, Asteroids): # 小行星带是模拟,不是正常的天体 - posvel = None - else: - # 获取天体的三维位置和矢量速度 - posvel = get_body_posvel(body, t) - - if isinstance(body, Moon): # 如果是月球,为了更好的展示效果,需要对月球的位置重新计算 - moon_real_pos = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU] - # TODO:注释下行,月球就会在真实的位置 - if self.recalc_moon_pos: - posvel = recalc_moon_position(posvel, earth_pos) - - if posvel is None: - # posvel 为空,则使用太阳的坐标 - position, velocity = [sun_pos.x.value * AU, - sun_pos.z.value * AU, - sun_pos.y.value * AU], [0, 0, 0] - else: - # 坐标单位:千米 速度单位:千米/秒 - position, velocity = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU], \ - [posvel[1].x.value * AU / SECONDS_PER_DAY, - posvel[1].z.value * AU / SECONDS_PER_DAY, - posvel[1].y.value * AU / SECONDS_PER_DAY] - - # 实时调整天体的位置和速度 - body.position = np.array(position) - body.velocity = np.array(velocity) - - if isinstance(body, Asteroids): - pass - elif isinstance(body, Sun): - # 记录太阳的位置 - sun_pos = posvel[0] - elif isinstance(body, Moon): - # 月球受到2个影响比较大的天体引力(地球和太阳),计算引力引起的加速度和 - acc_earth = calc_solar_acceleration(moon_real_pos, self.earth) - acc_sun = calc_solar_acceleration(moon_real_pos, self.sun) - body.acceleration = [acc_earth[0] + acc_sun[0], - acc_earth[1] + acc_sun[1], - acc_earth[2] + acc_sun[2]] - else: - # 其他天体受到太阳引力 - body.acceleration = calc_solar_acceleration(body, self.sun) - - if isinstance(body, Earth): - # 记录地球的位置 - earth_pos = posvel[0] + set_solar_system_celestial_position(self.bodies, t, self.recalc_moon_pos) def on_ready(self): """ @@ -219,7 +149,7 @@ class SolarSystemRealitySim: # 设置天体的位置(包含速度和加速度的信息) self.set_bodies_position(time_data) # 保证地球的自转和北京时间同步 - self.set_earth_rotation(dt) + set_earth_rotation(self.earth, dt) # 显示时钟 self.show_clock(dt)