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