body.py 8.0 KB
Newer Older
M
march3 已提交
1 2 3 4 5 6 7 8
# -*- coding:utf-8 -*-
# title           :
# description     :
# author          :Python超人
# date            :2023-01-22
# notes           :
# python_version  :3.8
# ==============================================================================
M
march3 已提交
9
from abc import ABCMeta, abstractmethod
M
march3 已提交
10 11 12
import json
import numpy as np
import math
M
march3 已提交
13
from common.consts import AU
M
march3 已提交
14 15


M
march3 已提交
16
class Body(metaclass=ABCMeta):
M
march3 已提交
17 18 19
    """
    天体信息基类
    """
M
march3 已提交
20

M
march3 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
    def __init__(self, name, mass, init_position, init_velocity,
                 density=5e3, color=(125 / 255, 125 / 255, 125 / 255),
                 texture=None, size_scale=1.0, distance_scale=1.0):
        """
        天体类
        :param name: 天体名称
        :param mass: 天体质量 (kg)
        :param init_position: 初始位置 (km)
        :param init_velocity: 初始速度 (km/s)
        :param density: 平均密度 (kg/m³)
        :param color: 天体颜色(纹理图片优先)
        :param texture: 纹理图片
        :param size_scale: 尺寸缩放
        :param distance_scale: 距离缩放
        """
M
march3 已提交
36 37 38
        self.__his_pos = []
        self.__his_vel = []
        self.__his_acc = []
M
march3 已提交
39
        self.__his_reserved_num = 100
M
march3 已提交
40

M
march3 已提交
41 42 43
        if name is None:
            name = getattr(self.__class__, '__name__')

M
march3 已提交
44 45 46 47 48 49
        self.name = name
        self.__mass = mass

        self.init_position = np.array(init_position, dtype='float32')
        self.init_velocity = np.array(init_velocity, dtype='float32')

M
march3 已提交
50 51
        self.__position = self.init_position
        self.__velocity = self.init_velocity
M
march3 已提交
52 53 54 55 56 57 58 59 60 61

        self.__density = density

        self.color = color
        self.texture = texture

        self.size_scale = size_scale
        self.distance_scale = distance_scale

        # 初始化后,加速度为0,只有多个天体的引力才会影响到加速度
M
march3 已提交
62
        # km/s²
M
march3 已提交
63 64
        self.__acceleration = np.array([0, 0, 0], dtype='float32')
        self.__record_history()
M
march3 已提交
65

M
march3 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
    @property
    def has_rings(self):
        """
        是否为带光环的天体(土星为 True)
        :return:
        """
        return False

    @property
    def is_fixed_star(self):
        """
        是否为恒星(太阳为 True)
        :return:
        """
        return False

M
march3 已提交
82 83
    @property
    def position(self):
M
march3 已提交
84 85 86 87
        """
        获取天体的位置(单位:km)
        :return:
        """
M
march3 已提交
88 89 90 91
        return self.__position

    @position.setter
    def position(self, value):
M
march3 已提交
92 93 94 95 96
        """
        设置天体的位置(单位:km)
        :param value:
        :return:
        """
M
march3 已提交
97 98 99 100 101
        self.__position = value
        self.__record_history()

    @property
    def acceleration(self):
M
march3 已提交
102 103 104 105
        """
        获取天体的加速度(单位:km/s²)
        :return:
        """
M
march3 已提交
106 107 108 109
        return self.__acceleration

    @acceleration.setter
    def acceleration(self, value):
M
march3 已提交
110 111 112 113 114
        """
        设置天体的加速度(单位:km/s²)
        :param value:
        :return:
        """
M
march3 已提交
115 116 117 118 119
        self.__acceleration = value
        self.__record_history()

    @property
    def velocity(self):
M
march3 已提交
120 121 122 123
        """
        获取天体的速度(单位:km/s)
        :return:
        """
M
march3 已提交
124 125 126 127
        return self.__velocity

    @velocity.setter
    def velocity(self, value):
M
march3 已提交
128 129 130 131 132
        """
        设置天体的速度(单位:km/s)
        :param value:
        :return:
        """
M
march3 已提交
133 134 135 136
        self.__velocity = value
        self.__record_history()

    def __append_history(self, his_list, data):
M
march3 已提交
137
        """
M
march3 已提交
138
        追加每个位置时刻的历史数据
M
march3 已提交
139 140 141 142 143 144 145 146 147
        :param his_list:
        :param data:
        :return:
        """
        # 如果历史记录为0 或者 新增数据和最后的历史数据不相同,则添加
        if len(his_list) == 0 or \
                np.sum(data == his_list[-1]) < len(data):
            his_list.append(data.copy())

M
march3 已提交
148
    def __record_history(self):
M
march3 已提交
149
        """
M
march3 已提交
150
        记录每个位置时刻的历史数据
M
march3 已提交
151 152 153 154
        :return:
        """
        # 如果历史记录数超过了保留数量,则截断,只保留 __his_reserved_num 数量的历史
        if len(self.__his_pos) > self.__his_reserved_num:
M
march3 已提交
155 156 157
            self.__his_pos = self.__his_pos[len(self.__his_pos) - self.__his_reserved_num:]
            self.__his_vel = self.__his_vel[len(self.__his_vel) - self.__his_reserved_num:]
            self.__his_acc = self.__his_acc[len(self.__his_acc) - self.__his_reserved_num:]
M
march3 已提交
158 159

        # 追加历史记录(位置、速度、加速度)
M
march3 已提交
160 161 162 163
        self.__append_history(self.__his_pos, self.position)
        self.__append_history(self.__his_vel, self.velocity)
        self.__append_history(self.__his_acc, self.acceleration)
        # print(self.name, "his pos->", self.__his_pos)
M
march3 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

    def his_position(self):
        """
        历史位置
        :return:
        """
        return self.__his_pos

    def his_velocity(self):
        """
        历史瞬时速度
        :return:
        """
        return self.__his_vel

    def his_acceleration(self):
        """
        历史瞬时加速度
        :return:
        """
        return self.__his_acc

    @property
    def mass(self):
        """
M
march3 已提交
189
        天体质量 (单位:kg)
M
march3 已提交
190 191 192 193 194 195 196
        :return:
        """
        return self.__mass

    @property
    def density(self):
        """
M
march3 已提交
197
        平均密度 (单位:kg/m³)
M
march3 已提交
198 199 200 201 202 203 204
        :return:
        """
        return self.__density

    @property
    def volume(self):
        """
M
march3 已提交
205
        天体的体积(单位:km³)
M
march3 已提交
206 207 208
        """
        # v = m/ρ
        # 体积(m³) = 质量(kg) / 密度(kg/m³)
M
march3 已提交
209 210
        # 体积(km³) = 体积(m³)  / 1e9
        v = self.mass / self.density / 1e9
M
march3 已提交
211 212 213 214 215
        return v

    @property
    def raduis(self):
        """
M
march3 已提交
216
        天体的半径(单位:km)
M
march3 已提交
217 218 219 220 221 222 223 224
        :return:
        """
        # V = ⁴⁄₃πr³  -> r = pow((3V)/(4π),1/3)
        return pow(3 * self.volume / (4 * math.pi), 1 / 3)

    @property
    def diameter(self):
        """
M
march3 已提交
225
        天体的直径(单位:km)
M
march3 已提交
226 227 228 229 230 231 232 233 234
        :return:
        """
        return self.raduis * 2

    def __repr__(self):
        return '<%s> m=%.3e(kg), r=%.3e(km), p=[%.3e,%.3e,%.3e](km), v=%s(km/s)' % \
               (self.name, self.mass, self.raduis,
                self.position[0], self.position[1], self.position[2], self.velocity)

M
march3 已提交
235 236 237 238 239 240 241 242 243
    def ignore_gravity(self, body):
        """
        是否忽略引力
        :param body:
        :return:
        """

        return False

M
march3 已提交
244
    def position_au(self):
M
march3 已提交
245 246 247 248
        """
        获取天体的位置(单位:天文单位 A.U.)
        :return:
        """
M
march3 已提交
249 250 251 252
        pos = self.position
        pos_au = pos / AU
        return pos_au

M
march3 已提交
253 254 255 256 257
    # def change_velocity(self, dv):
    #     self.velocity += dv
    #
    # def move(self, dt):
    #     self.position += self.velocity * dt
M
march3 已提交
258 259

    def reset(self):
M
march3 已提交
260 261 262 263
        """
        重新设置初始速度和初始位置
        :return:
        """
M
march3 已提交
264 265 266
        self.position = self.init_position
        self.velocity = self.init_velocity

M
march3 已提交
267 268 269 270 271 272 273 274 275 276
    # def kinetic_energy(self):
    #     """
    #     计算动能(千焦耳)
    #     表示动能,单位为焦耳j,m为质量,单位为千克,v为速度,单位为米/秒。
    #     ek=(1/2).m.v^2
    #     m(kg) v(m/s) -> j
    #     m(kg) v(km/s) -> kj
    #     """
    #     v = self.velocity
    #     return 0.5 * self.mass * (v[0] ** 2 + v[1] ** 2 + v[2] ** 2)
M
march3 已提交
277 278 279

    @staticmethod
    def build_bodies_from_json(json_file):
M
march3 已提交
280 281 282 283 284
        """
        JSON文件转为天体对象
        :param json_file:
        :return:
        """
M
march3 已提交
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
        bodies = []
        with open(json_file, "r") as read_content:
            json_data = json.load(read_content)
            for body_data in json_data["bodies"]:
                # print(body_data)
                body = Body(**body_data)
                bodies.append(body)
                # print(body.position_au())
        return bodies


if __name__ == '__main__':
    # build_bodies_from_json('../data/sun.json')
    bodies = Body.build_bodies_from_json('../data/sun_earth.json')
    # 太阳半径 / 地球半径
M
march3 已提交
300
    print("太阳半径 / 地球半径 =", bodies[0].raduis / bodies[1].raduis)
M
march3 已提交
301
    for body in bodies:
M
march3 已提交
302
        print(body)