body.py 6.3 KB
Newer Older
M
march3 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
# -*- coding:utf-8 -*-
# title           :
# description     :
# author          :Python超人
# date            :2023-01-22
# notes           :
# python_version  :3.8
# ==============================================================================
import json
import numpy as np
import math

"""
天文单位
"""
AU: float = 149597870.700


class Body:
    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 已提交
35 36 37 38 39
        self.__his_pos = []
        self.__his_vel = []
        self.__his_acc = []
        self.__his_reserved_num = 20

M
march3 已提交
40 41 42 43 44 45
        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 已提交
46 47
        self.__position = self.init_position
        self.__velocity = self.init_velocity
M
march3 已提交
48 49 50 51 52 53 54 55 56 57

        self.__density = density

        self.color = color
        self.texture = texture

        self.size_scale = size_scale
        self.distance_scale = distance_scale

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


M
march3 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

    @property
    def position(self):
        return self.__position

    @position.setter
    def position(self, value):
        self.__position = value
        self.__record_history()

    @property
    def acceleration(self):
        return self.__acceleration

    @acceleration.setter
    def acceleration(self, value):
        self.__acceleration = value
        self.__record_history()

    @property
    def velocity(self):
        return self.__velocity

    @velocity.setter
    def velocity(self, value):
        self.__velocity = value
        self.__record_history()

    def __append_history(self, his_list, data):
M
march3 已提交
92 93 94 95 96 97 98 99 100 101 102
        """

        :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 已提交
103
    def __record_history(self):
M
march3 已提交
104 105 106 107 108 109
        """
        记录历史
        :return:
        """
        # 如果历史记录数超过了保留数量,则截断,只保留 __his_reserved_num 数量的历史
        if len(self.__his_pos) > self.__his_reserved_num:
M
march3 已提交
110 111 112
            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 已提交
113 114

        # 追加历史记录(位置、速度、加速度)
M
march3 已提交
115 116 117 118
        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 已提交
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 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 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234

    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):
        """
        天体质量 (kg)
        :return:
        """
        return self.__mass

    @property
    def density(self):
        """
        平均密度 (kg/m³)
        :return:
        """
        return self.__density

    @property
    def volume(self):
        """
        天体的体积
        """
        # v = m/ρ
        # 体积(m³) = 质量(kg) / 密度(kg/m³)
        v = self.mass / self.density
        return v

    @property
    def raduis(self):
        """
        天体的半径
        :return:
        """
        # V = ⁴⁄₃πr³  -> r = pow((3V)/(4π),1/3)
        return pow(3 * self.volume / (4 * math.pi), 1 / 3)

    @property
    def diameter(self):
        """
        天体的直径
        :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)

    def position_au(self):
        pos = self.position
        pos_au = pos / AU
        return pos_au

    def change_velocity(self, dv):
        self.velocity += dv

    def move(self, dt):
        self.position += self.velocity * dt

    def reset(self):
        self.position = self.init_position
        self.velocity = self.init_velocity

    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)

    @staticmethod
    def build_bodies_from_json(json_file):
        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')
    # 太阳半径 / 地球半径
    print(bodies[0].raduis / bodies[1].raduis)
    for body in bodies:
        print(body.kinetic_energy())