• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import Constants from '../utils/Constants';
17
18/**
19 * 天体类
20 */
21class Body {
22  x: number;
23  y: number;
24  z: number;
25  vx: number;
26  vy: number;
27  vz: number;
28  mass: number;
29
30  constructor(x: number, y: number, z: number, vx: number, vy: number, vz: number, mass: number) {
31    this.x = x;
32    this.y = y;
33    this.z = z;
34    this.vx = vx;
35    this.vy = vy;
36    this.vz = vz;
37    this.mass = mass;
38  }
39}
40
41const jupiter: Body = new Body(Constants.JUPITER_X, Constants.JUPITER_Y, Constants.JUPITER_Z, Constants.JUPITER_VX,
42                               Constants.JUPITER_VY, Constants.JUPITER_VZ, Constants.JUPITER_MASS);
43const saturn: Body = new Body(Constants.SATURN_X, Constants.SATURN_Y, Constants.SATURN_Z, Constants.SATURN_VX,
44                              Constants.SATURN_VY, Constants.SATURN_VZ, Constants.SATURN_MASS);
45const uranus: Body = new Body(Constants.URANUS_X, Constants.URANUS_Y, Constants.URANUS_Z, Constants.URANUS_VX,
46                              Constants.URANUS_VY, Constants.URANUS_VZ, Constants.URANUS_MASS);
47const neptune: Body = new Body(Constants.NEPTUNE_X, Constants.NEPTUNE_Y, Constants.NEPTUNE_Z, Constants.NEPTUNE_VX,
48                               Constants.NEPTUNE_VY, Constants.NEPTUNE_VZ, Constants.NEPTUNE_MASS);
49const sun: Body = new Body(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Constants.SOLAR_MASS);
50
51const bodies: Body[] = Array(sun, jupiter, saturn, uranus, neptune);
52
53/**
54 * 调整太阳的速度,保证该孤立系统动量守恒
55 */
56export function offsetMomentum(): void {
57  // p为momentum的缩写,表示:动量, 等于质量乘以速度 p=mv
58  let px: number = 0;
59  let py: number = 0;
60  let pz: number = 0;
61
62  // 累加计算整个系统中,各个天体在三维各矢量方向的动量
63  for (let i: number = 0; i < bodies.length; i++) {
64    const body: Body = bodies[i];
65    const mass: number = body.mass;
66    px += body.vx * mass;
67    py += body.vy * mass;
68    pz += body.vz * mass;
69  }
70
71  // 太阳预设速度为0,通过动量守恒定律,反推太阳各矢量方向速度
72  const body: Body = bodies[0];
73  body.vx = -px / Constants.SOLAR_MASS;
74  body.vy = -py / Constants.SOLAR_MASS;
75  body.vz = -pz / Constants.SOLAR_MASS;
76}
77
78/**
79 * 更新天体在按指定的时间变化后的位置信息
80 * @param dt - delta time 时间变化
81 */
82export function advance(dt: number): void {
83  const size = bodies.length;
84
85  // 两两配对计算各天体瞬时速度
86  for (let i = 0; i < size; i++) {
87    const iBody = bodies[i];
88    let vxi: number = iBody.vx;
89    let vyi: number = iBody.vy;
90    let vzi: number = iBody.vz;
91    for (let j: number = i + 1; j < size; j++) {
92      const jBody: Body = bodies[j];
93
94      // 天体间距离差
95      const dx: number = iBody.x - jBody.x;
96      const dy: number = iBody.y - jBody.y;
97      const dz: number = iBody.z - jBody.z;
98
99      const d2: number = dx * dx + dy * dy + dz * dz;
100      const mag: number = dt / (d2 * Math.sqrt(d2));
101
102      // 由天体距离计算引力对速度的相互影响
103      const jMass: number = jBody.mass;
104      vxi -= dx * jMass * mag;
105      vyi -= dy * jMass * mag;
106      vzi -= dz * jMass * mag;
107
108      const iMass: number = iBody.mass;
109      jBody.vx += dx * iMass * mag;
110      jBody.vy += dy * iMass * mag;
111      jBody.vz += dz * iMass * mag;
112    }
113    iBody.vx = vxi;
114    iBody.vy = vyi;
115    iBody.vz = vzi;
116  }
117
118  // 更新天体的位置信息
119  for (let i: number = 0; i < size; i++) {
120    const body: Body = bodies[i];
121    body.x += dt * body.vx; // 位置 = 时间 * 速度
122    body.y += dt * body.vy;
123    body.z += dt * body.vz;
124  }
125}
126
127/**
128 * 在程序开始和结束后调用,通过计算机械能,判断机械能守恒与否,以检查程序的运行正确性
129 * @returns 返回系统机械能
130 */
131export function energy(): number {
132  let energy: number = 0.0;
133  const size: number = bodies.length;
134
135  // 计算各天体的机械能总和,机械能公式:机械能=动能+势能
136  for (let i: number = 0; i < size; i++) {
137    const iBody: Body = bodies[i];
138
139    // 对每个天体的动能进行加和,动能公式为:动能=1/2×物体质量×运动速度的平方
140    energy += 0.5 * iBody.mass * (iBody.vx * iBody.vx + iBody.vy * iBody.vy + iBody.vz * iBody.vz);
141
142    // 计算当前遍历到的天体和其他天体间的势能,势能公式为:引力势能=-G*物理A质量*物理B质量/距离
143    for (let j: number = i + 1; j < size; j++) {
144      const jBody: Body = bodies[j];
145      const dx: number = iBody.x - jBody.x;
146      const dy: number = iBody.y - jBody.y;
147      const dz: number = iBody.z - jBody.z;
148
149      const distance: number = Math.sqrt(dx * dx + dy * dy + dz * dz);
150      energy -= (iBody.mass * jBody.mass) / distance;
151    }
152  }
153  return energy;
154}
155