From 997a27b8d286b89aa1c153ca256cf10dce06968d Mon Sep 17 00:00:00 2001 From: march3 Date: Tue, 9 Apr 2024 10:40:28 +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 --- common/china_24_jieqi.py | 157 ++++++++++++ sim_scenes/featured/earth_12jieqi_live.py | 295 ++++++++++++++++++++++ sim_scenes/science/earth_season_func.py | 27 +- 3 files changed, 478 insertions(+), 1 deletion(-) create mode 100644 common/china_24_jieqi.py create mode 100644 sim_scenes/featured/earth_12jieqi_live.py diff --git a/common/china_24_jieqi.py b/common/china_24_jieqi.py new file mode 100644 index 0000000..8f501c5 --- /dev/null +++ b/common/china_24_jieqi.py @@ -0,0 +1,157 @@ +import sys +import json +import gc +import os + +default_encoding = 'utf-8' +if sys.getdefaultencoding() != default_encoding: + reload(sys) + + +class JieQi: + # 计算节气的C常量组 + C_list_21 = [3.87, 18.73, 5.63, 20.646, 4.81, 20.1, 5.52, 21.04, 5.678, 21.37, 7.108, 22.83, 7.5, 23.13, 7.646, + 23.042, 8.318, 23.438, 7.438, 22.36, 7.18, 21.94, 5.4055, 20.12] + + C_list_20 = [4.6295, 19.4599, 6.3826, 21.4155, 5.59, 20.888, 6.318, 21.86, 6.5, 22.2, 7.928, 23.65, 8.35, 23.95, + 8.44, 23.822, 9.098, 24.218, 8.218, 23.08, 7.9, 22.6, 6.11, 20.84] + + # 节气名称组 + name_Array = ["立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", + "霜降", "立冬", "小雪", "大雪", "冬至", "小寒", "大寒"] + + def __init__(self, name_arr=None): + self.c_list = [] + if name_arr is not None: + self.name_arr = name_arr + else: + self.name_arr = JieQi.name_Array + + ## 特殊年份特殊节气进行纠正 + def rectify_year(self, year, jieqiid, day): + ## 特殊年份 + rectify_year = [2026, 2084, 1911, 2008, 1902, 1928, 1925, 2016, 1922, 2002, 1927, 1942, 2089, 2089, 1978, 1954, + 1918, 2021, 1982, 2082, 2019, 2021] + ## 特殊节气 + rectify_jieqi = [1, 3, 6, 7, 8, 9, 10, 10, 11, 12, 14, 15, 17, 18, 19, 20, 21, 21, 22, 22, 23] + ## 偏移量 + rectify_offset = [-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1] + pop2 = -1 + if year in rectify_year: + if year == 2089: + pop1 = rectify_year.index(year) ## 找到位置 + pop2 = pop1 + 1 + else: + pop1 = rectify_year.index(year) ## 找到位置 + + if rectify_jieqi[pop1] == jieqiid: + day = day + int(rectify_offset[pop1]) + if rectify_jieqi[pop2] == jieqiid: + day = day + int(rectify_offset[pop2]) + return day + + # 计算节气日期,并创建文件 + def get_year_jieqi(self, year): + year_pre = year // 100 + if year_pre == 19: + C_arr = self.C_list_20 + elif year_pre == 20: + C_arr = self.C_list_21 + + year_num = year % 100 + list_arr = [] + for i in range(0, 24): + C = C_arr[i] + ## 注意:凡闰年3月1日前闰年数要减一,即:L=[(Y-1)/4],因为小寒、大寒、立春、雨水这两个节气都小于3月1日,所以 y = y-1 + if i == 0 or i == 1 or i == 22 or i == 23: + if self.comrun(year): + days = (year_num * 0.2422 + C) // 1 - ((year_num - 1) // 4) + else: + days = (year_num * 0.2422 + C) // 1 - (year_num // 4) + else: + days = (year_num * 0.2422 + C) // 1 - (year_num // 4) + + ## 特殊年份节气进行纠正 + days = self.rectify_year(year, i, days) + + days = int(days) + days = '%02d' % days + y = int(year_num // 1) + m = i // 2 + 2 + if m == 13: + m = 1 + m = '%02d' % m + y = '%02d' % y + strs = "{3}{0}-{1}-{2} 00:00:00".format(str(y), str(m), str(days), str(year_pre)) + item = dict(name=self.name_Array[i], jieqiid=str(i + 1), time=strs) + # print (item) + list_arr.append(item) + return list_arr + # list_str = json.dumps(list_arr,ensure_ascii=False) ## 中文不进行编码 + # file_name = "./json/{0}.json".format(str(year)) + # with open(file_name, "w",encoding="utf-8") as f: ## 打开时用 utf-8 编码 + # json.dump(list_str, f,ensure_ascii=False) + # print("{0}已载入文件完成...".format(str(year))) + + # 读取年份为 name 年的节气数据 + def read_json_file(self, name): + json_file = open('./json/' + name + '.json', 'r', encoding="utf-8") + json_str = json_file.read() + dic = json.loads(json_str) + print(dic) + + # 读取测试 + # read_json_file('2029') + + # 读取所有年份的节气数据 + def check_all_file(self): + for index in range(1900, 2100): + c_file_name = './json/{0}.json'.format(str(index)) + if os.path.isfile(c_file_name): + json_file = open(c_file_name, 'r', encoding="utf-8") + json_str = json_file.read() + dic = json.loads(json_str) + print(str(index) + dic) + + ## 算是否是闰年 + def comrun(self, year): + i = 0 + if (year % 4) != 0: + i = 0 + elif ((year % 100) == 0) & ((year % 400) != 0): + i = 0 + else: + i = 1 + return i + + def get_years_jieqi(self, y1, y2): + # "春分-2023": '2023-03-21 00:00:00', + jieqis = {} + for y in range(y1, y2 + 1): + d = self.get_year_jieqi(y) + d = [(i["name"], i["time"]) for i in d] + for di in d: + if di[0] in self.name_arr: + jieqis[f"{di[0]}-{y}"] = di[1] + return jieqis + + +if __name__ == '__main__': + names = ["立春", "雨水", "惊蛰", "春分", + "清明", "谷雨", "立夏", "小满", + "芒种", "夏至", "小暑", "大暑", + "立秋", "处暑", "白露", "秋分", + "寒露", "霜降", "立冬", "小雪", + "大雪", "冬至", "小寒", "大寒"] + names = ["立春", "春分", + "立夏", "夏至", + "立秋", "秋分", + "立冬", "冬至"] + jieqi = JieQi(names) + d = jieqi.get_years_jieqi(2024, 2024) + print(d) + # jieqi.read_json_file('2006') + # jieqi.check_all_file() + # + # for i in range(1900,2100): + # jieqi.creat_year_jieqi(i) diff --git a/sim_scenes/featured/earth_12jieqi_live.py b/sim_scenes/featured/earth_12jieqi_live.py new file mode 100644 index 0000000..c47af91 --- /dev/null +++ b/sim_scenes/featured/earth_12jieqi_live.py @@ -0,0 +1,295 @@ +# -*- coding:utf-8 -*- +# title :地球季节模拟(四季和24节气) +# description :地球季节模拟(四季和24节气) +# author :Python超人 +# date :2023-02-11 +# link :https://gitcode.net/pythoncr/ +# python_version :3.8 +# ============================================================================== +from ursina import camera, window, Text, color, Vec3, destroy + +from bodies import * +from common.celestial_data_service import set_solar_system_celestial_position, conv_to_astropy_time, get_body_posvel +from common.consts import * +from sim_scenes.featured.earth_seasons_base import EarthSeasonsSimBase +from sim_scenes.func import ursina_run, camera_look_at, create_sphere_sky +from sim_scenes.science.earth_season_func import create_important_pos_earths, get_solar_terms_angles, create_earth, \ + create_important_pos_earths_2 +from sim_scenes.universe_sim_scenes import UniverseSimScenes +from simulators.ursina.entities.body_timer import TimeData, BodyTimer +from simulators.ursina.ui.control_ui import ControlUI +from simulators.ursina.ursina_config import UrsinaConfig +from simulators.ursina.ursina_event import UrsinaEvent +from simulators.ursina_simulator import UrsinaSimulator +import numpy as np +import math + + +class EarthSeasonsSimLive(EarthSeasonsSimBase): + def __init__(self): + super(EarthSeasonsSimLive, self).__init__(sun_transparent=False, + exit_at_total_days=3700, + delay_run=False, + earth_cn_size_factor=1.01, + earth_clouds_size_factor=1.015) + self.start_time = '2023-12-20 00:00:00' + # self.start_time = '2024-04-08 00:00:00' + self.sun.size_scale = 5e1 + self.earth.size_scale = 2e3 + self.earth_clouds.size_scale = self.earth.size_scale + self.earth_cn.size_scale = self.earth.size_scale + + self.moon = Moon(name="月球", size_scale=2e3, + rotation_speed=0.645 + ) # 月球 + self.mercury = Mercury(size_scale=2e3) + self.venus = Venus(name="金星", size_scale=2e3) + self.mars = Mars(size_scale=2e3) + self.jupiter = Jupiter(size_scale=0.6e3) + self.saturn = Saturn(size_scale=0.6e3) + self.uranus = Uranus(size_scale=2e3) + self.neptune = Neptune(size_scale=2e3) + + self.bodies += [self.moon, self.mercury, self.venus, self.mars, + self.jupiter, self.saturn, self.uranus, self.neptune, + self.earth_5, self.earth_6, self.earth_7, self.earth_8] + + self.last_year = None + + for body in self.bodies: + if isinstance(body, Earth): + body.show_name = True + body.rotate_angle -= 22 + body.rotation_speed *= 2.5 + body.set_resolution(50) + + self.season_earths = [self.earth_1, self.earth_2, self.earth_3, self.earth_4, + self.earth_5, self.earth_6, self.earth_7, self.earth_8] + self.planets = [] + + names = ["立春", "春分", + "立夏", "夏至", + "立秋", "秋分", + "立冬", "冬至"] + from common.china_24_jieqi import JieQi + jieqi = JieQi(names) + self.jieqis = jieqi.get_years_jieqi(2023, 2025) + + font = "fonts/DroidSansFallback.ttf" + + # font = "fonts/新青年体.ttf" + from common.func import find_file + self.font = find_file(f"{font}", UrsinaConfig.CN_FONT) + + for body in self.bodies: + if body not in self.season_earths: + self.planets.append(body) + else: + # body.texture = "transparent.png" + body.size_scale = self.earth.size_scale / 1.1 + body.show_trail = False + + def create_important_pos_earths(self): + self.earth_1, self.earth_2, self.earth_3, self.earth_4 = create_important_pos_earths(texture="earth-huge.jpg", + size_scale=4.9e3, + position_offset=1.0) + self.earth_5, self.earth_6, self.earth_7, self.earth_8 = create_important_pos_earths_2(texture="earth-huge.jpg", + size_scale=4.9e3, + position_offset=1.0) + return self.earth_1, self.earth_2, self.earth_3, self.earth_4 + + def earth_text_display(self, term_name): + for e in [self.earth_1, self.earth_2, self.earth_3, self.earth_4, + self.earth_5, self.earth_6, self.earth_7, self.earth_8]: + # if hasattr(e, "name_text"): + # if term_name == e.name: + # e.name_text.enabled = False + # else: + e.name_text.enabled = True + + def get_center_pos(self, dt): + posvel = get_body_posvel(self.earth, dt) + position = [posvel[0].x.value * AU, posvel[0].z.value * AU, posvel[0].y.value * AU] + center_pos = np.array(position) + return center_pos + + def on_ready(self): + super(EarthSeasonsSimLive, self).on_ready() + + for e in self.season_earths: + if hasattr(e, "planet"): + # e.planet.rotation_y += 15 # 夏至 + e.planet.alpha = 0.2 + # 将 4 个节气位置的地球进行旋转,让中国面对太阳 + # if hasattr(self.earth_1, "planet"): + # self.earth_1.planet.rotation_y += 115 # 春分 + # self.earth_1.planet.alpha = 0.2 + # if hasattr(self.earth_2, "planet"): + # self.earth_2.planet.rotation_y += 15 # 夏至 + # self.earth_2.planet.alpha = 0.2 + # if hasattr(self.earth_3, "planet"): + # self.earth_3.planet.rotation_y -= 80 # 秋分 + # self.earth_3.planet.alpha = 0.2 + # if hasattr(self.earth_4, "planet"): + # self.earth_4.planet.rotation_y -= 145 # 冬至 + # self.earth_4.planet.alpha = 0.2 + + UrsinaConfig.trail_type = "line" + # UrsinaConfig.trail_length = 91 + UrsinaConfig.trail_type = "curve_line" + UrsinaConfig.trail_length = 50 + # UrsinaConfig.trail_length = 1000 + UrsinaConfig.trail_thickness_factor = 2 + + for body in self.planets: + body.planet.trail_scale = 3 + body.planet.name_text.scale = 5 + destroy(body.planet.name_text.background) + body.planet.name_text.color = color.white + body.planet.name_text.font = self.font + body.planet.name_text.position = Vec3(0, 0.6, 0) + # body.planet.name_text.position = Vec3(0, pow(body.planet.main_entity.scale_y, 1 / 12) / 2, 0) + # body.planet.name_text + def camera_distance_update(name_text): + o_scale = name_text.scale_x + def update2(): + print(name_text.parent.body) + + return update2 + # body.planet.name_text.update = camera_distance_update(body.planet.name_text) + + self.moon.planet.trail_scale = 1 + # camera.orthographic = True + camera.clip_plane_near = 1 + # camera.clip_plane_far = sky.scale_x * 1.5 + + destroy(self.earth_clouds.planet) + destroy(self.earth_cn.planet) + # self.earth_cn.size_scale = self.earth.size_scale + + for e in self.season_earths: + # camera_look_at(self.sun, rotation_z=0) + # e.planet.scale = 0.1 + # e.planet.alpha = 0.2 + if not hasattr(e, "name_text"): + continue + e.name_text.scale = Vec3(10, 10, 10) + e.name_text.font = self.font + destroy(e.name_text.background) + + # self.earth_2.planet.alpha = 0.2 + # self.earth_3.planet.alpha = 0.2 + # self.earth_4.planet.alpha = 0.2 + + self.earth.planet.name_text.enabled = False + # , self.earth_clouds, self.earth_cn + + self.earth_1.planet.rotation_y = 115 # 春分 + self.earth_2.planet.rotation_y = 15 # 夏至 + self.earth_3.planet.rotation_y = -80 # 秋分 + self.earth_4.planet.rotation_y = -145 # 冬至 + + self.moon.planet.rotation_y = 180 + + self.show_title() + # camera.fov = 140 + + window.borderless = True + window.exit_button = False + # window.fullscreen = True + # window.position = (1920, 0) + # # 设置窗口的宽度和高度 + # window.size = (2340, 1079) + + def on_timer_changed(self, time_data: TimeData): + super(EarthSeasonsSimLive, self).on_timer_changed(time_data) + camera.rotation_z = -8 + dt = time_data.get_datetime(self.start_time) + self.set_bodies_position(time_data) + self.show_clock(dt) + self.camera_around() + + def camera_around(self): + + ec = UrsinaSimulator.EditorCamera + ec.rotation_y -= 0.01 * UrsinaConfig.run_speed_factor # 每帧绕y轴旋转1度 + # print(self.earth.planet.world_position) + # print(self.earth.planet.position) + + def set_bodies_position(self, time_data: TimeData): + """ + 设置天体的位置(包含速度和加速度的信息) + @param time_data: + @return: + """ + dt = conv_to_astropy_time(self.start_time) + + t = dt + time_data.total_days + center_pos = self.get_center_pos(t) + set_solar_system_celestial_position(self.planets, t, True, recalc_moon_pos_scale=60, center_pos=center_pos) + + year = int(t.jyear) + if self.last_year != year: + for body in self.season_earths: + jieqir = self.jieqis.get(f"{body.name}-{year}", None) + if jieqir is not None: + jieqir = conv_to_astropy_time(jieqir) + set_solar_system_celestial_position([body], jieqir, False, center_pos=None) + body.abs_position = body.position + self.last_year = year + + for body in self.season_earths: + body.position = body.abs_position + self.sun.position + + def exit_handle(self): + UrsinaEvent.on_reset() + return True + + def show_title(self): + aspect_ratio = window.aspect_ratio + position, origin = (-0.5 * aspect_ratio - 0.1, 0.48), (-0.05, 0.1) + position2, origin2 = (-0.5 * aspect_ratio - 0.1, 0.40), (-0.05, 0.1) + # text1 = Text(text="太阳视角:观察日食月食", color=color.white, scale=2.5, position=position, # (-0.98, 0.48), + # font=font) + ext1 = Text(text="太阳视角:2024年重要天象", color=color.white, scale=2.5, position=position, # (-0.98, 0.48), + font=self.font) + text2 = Text(text="(地球自转放慢10倍)", color=color.white, scale=1.5, position=position2, # (-0.98, 0.48), + font=self.font) + # 2024年重要天象 + + def show_clock(self, dt): + """ + 显示时钟 + @param dt: 时间 datetime + @return: + """ + # if self.clock_position_center: + # position, origin = (0, .25), (0, 0), + # else: + from ursina import window + aspect_ratio = window.aspect_ratio + position, origin = (0., 0.45), (0., 0.), + ControlUI.current_ui.show_message(dt.strftime('%Y-%m-%d'), + position=position, + origin=origin, + # font="verdana.ttf", + font="fonts/Digital-7Mono.TTF", + font_scale=2, + font_color=(0, 255, 0), + close_time=-1) + + +if __name__ == '__main__': + """ + 摄像机以太阳的视角看地球(四季和24节气) + """ + sim = EarthSeasonsSimLive() + sim.run( + # dt=SECONDS_PER_DAY * 10, + dt=SECONDS_PER_DAY * 3, + # dt=SECONDS_PER_HOUR, + init_position=[0, 0, -3 * AU], + show_exit_button=False, + show_camera_info=False, + gravity_works=False, + show_control_info=False) diff --git a/sim_scenes/science/earth_season_func.py b/sim_scenes/science/earth_season_func.py index 3074655..56cfb7b 100644 --- a/sim_scenes/science/earth_season_func.py +++ b/sim_scenes/science/earth_season_func.py @@ -41,7 +41,32 @@ def create_important_pos_earths(texture="earth_transparent.png", size_scale=5e3, texture=texture, size_scale=size_scale) earth_3 = create_trans_earth(name="秋分", text_color=(255, 255, 0), position=[position_offset * AU, 0, 0], texture=texture, size_scale=size_scale) - earth_4 = create_trans_earth(name="冬至", text_color=(0, 255, 255), position=[0, 0, position_offset * AU], + earth_4 = create_trans_earth(name="冬至", text_color=(255, 255, 255), position=[0, 0, position_offset * AU], + texture=texture, size_scale=size_scale) + + earth_1.set_light_disable(True) + earth_2.set_light_disable(True) + earth_3.set_light_disable(True) + earth_4.set_light_disable(True) + + return earth_1, earth_2, earth_3, earth_4 + + +def create_important_pos_earths_2(texture="earth_transparent.png", size_scale=5e3, position_offset=1.05): + """ + 创建24节气中4个重要位置的透明地球 + @param texture: 透明地球的纹理图片 + @param size_scale: + @param position_offset: + @return: + """ + earth_1 = create_trans_earth(name="立春", text_color=(0, 255, 0), position=[-position_offset * AU, 0, 0], + texture=texture, size_scale=size_scale) + earth_2 = create_trans_earth(name="立夏", text_color=(255, 0, 0), position=[0, 0, -position_offset * AU], + texture=texture, size_scale=size_scale) + earth_3 = create_trans_earth(name="立秋", text_color=(255, 255, 0), position=[position_offset * AU, 0, 0], + texture=texture, size_scale=size_scale) + earth_4 = create_trans_earth(name="立冬", text_color=(255, 255, 255), position=[0, 0, position_offset * AU], texture=texture, size_scale=size_scale) earth_1.set_light_disable(True) -- GitLab