ProjectileMathUtil.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /** 用于弧度转角度 */
  2. const rad2Deg = 180 / Math.PI;
  3. /** 用于角度转弧度 */
  4. const deg2Rad = Math.PI / 180;
  5. /**
  6. * 抛射运动的数学工具
  7. */
  8. export default class ProjectileMathUtil {
  9. /**
  10. * 计算耗时
  11. * @param x 水平位移
  12. * @param angle 初始角度
  13. * @param velocity 初始速度
  14. */
  15. public static calculateTotalTime(x: number, angle: number, velocity: number) {
  16. // 初始角度(弧度制)
  17. const θ = angle * deg2Rad;
  18. // 时间
  19. // t = x / ( v * cos(θ) )
  20. const t = x / (velocity * Math.cos(θ));
  21. return t;
  22. }
  23. /**
  24. * 计算指定时刻的运动角度
  25. * @param angle 初始角度
  26. * @param velocity 初始速度
  27. * @param time 时间
  28. * @param gravity 重力加速度
  29. * @param returnInRadians 是否返回弧度制结果
  30. */
  31. public static calculateAngleAtMoment(angle: number, velocity: number, time: number, gravity: number, returnInRadians: boolean = false) {
  32. // 重力加速度(垂直向下)
  33. const g = gravity;//
  34. // 初始角度(弧度制)
  35. const θ = angle * deg2Rad;
  36. // 水平瞬时速度
  37. // vx = v * cos(θ)
  38. const vx = velocity * Math.cos(θ);
  39. // 垂直瞬时速度
  40. // vy = v * sin(θ) - g * t
  41. const vy = velocity * Math.sin(θ) - g * time;
  42. // 该时刻的运动角度(弧度制)
  43. const θt = Math.atan(vy / vx);
  44. return (returnInRadians ? θt : θt * rad2Deg);
  45. }
  46. /**
  47. * 计算指定时刻的位移距离
  48. * @param angle 初始角度
  49. * @param velocity 初始速度
  50. * @param gravity 重力加速度
  51. * @param time 时间点
  52. */
  53. public static calculateDisplacementAtMoment(angle: number, velocity: number, gravity: number, time: number) {
  54. // 重力加速度(垂直向下)
  55. const g = gravity;
  56. // 初始角度(弧度制)
  57. const θ = angle * deg2Rad;
  58. // 水平位移
  59. // x = v * cos(θ) * t
  60. const x = velocity * Math.cos(θ) * time;
  61. // 垂直位移
  62. // y = v * sin(θ) * t - 0.5 * g * t^2
  63. const y = velocity * Math.sin(θ) * time - 0.5 * g * Math.pow(time, 2);
  64. return { x, y };
  65. }
  66. /**
  67. * 根据初始角度计算初始速度
  68. * @param x 水平距离
  69. * @param y 垂直距离
  70. * @param gravity 重力加速度
  71. * @param angle 初始角度(角度制)
  72. */
  73. public static calculateWithAngle(x: number, y: number, gravity: number, angle: number) {
  74. // 重力加速度(垂直向下)
  75. const g = Math.abs(gravity);
  76. // 初始角度(弧度制)
  77. const θ = angle * deg2Rad;
  78. // 速度公式
  79. // v = sqrt( ( x^2 * g ) / ( 2 * x * sin(θ) * cos(θ) - 2 * y * cos(θ)^2 ) )
  80. // 部分计算结果
  81. const p1 = (2 * x * Math.sin(θ) * Math.cos(θ)) - (2 * y * Math.pow(Math.cos(θ), 2));
  82. // 负数没有平方根
  83. if (p1 < 0) {
  84. return NaN;
  85. }
  86. // 速度
  87. const v = Math.sqrt((g * Math.pow(x, 2)) / p1);
  88. return v;
  89. }
  90. /**
  91. * 根据初始速度计算初始角度
  92. * @param x 水平距离
  93. * @param y 垂直距离
  94. * @param gravity 重力加速度
  95. * @param velocity 初始速度
  96. */
  97. public static calculateWithVelocity(x: number, y: number, velocity: number, gravity: number) {
  98. // 重力加速度(垂直向下)
  99. const g = gravity;
  100. // 初始速度
  101. const v = velocity;
  102. // 角度公式
  103. // θ = atan( ( -v^2 ± sqrt( v^4 - g * ( g * x^2 + 2 * y * v^2 ) ) / ( -g * x ) ) )
  104. // 部分计算结果
  105. const p1 = Math.pow(v, 2);
  106. const p2 = Math.pow(v, 4) - g * (g * Math.pow(x, 2) + 2 * y * p1);
  107. // 负数没有平方根
  108. if (p2 < 0) {
  109. return {
  110. angle1: NaN,
  111. angle2: NaN,
  112. };
  113. }
  114. // 部分计算结果
  115. const p3 = Math.sqrt(p2);
  116. // 角度(两个解)
  117. const θ1 = Math.atan((-p1 + p3) / (-g * x));
  118. const θ2 = Math.atan((-p1 - p3) / (-g * x));
  119. return {
  120. angle1: θ1 * rad2Deg,
  121. angle2: θ2 * rad2Deg,
  122. };
  123. }
  124. /**
  125. * 根据最大高度计算速度和角度
  126. * @param x 水平距离
  127. * @param y 垂直距离
  128. * @param gravity 重力加速度
  129. * @param maxHeight 最大高度
  130. */
  131. public static calculateWithMaxHeight(x: number, y: number, maxHeight: number, gravity: number) {
  132. // 重力加速度(垂直向下)
  133. const g = gravity;
  134. // 最大高度
  135. const h = maxHeight;
  136. // 最大高度不能小于 0,也不能够小于垂直距离
  137. if (h < 0 || (h - y) < 0) {
  138. return {
  139. angle: NaN,
  140. velocity: NaN,
  141. time: NaN,
  142. };
  143. }
  144. // 部分计算结果
  145. const p1 = Math.sqrt(2 * g * h);
  146. const p2 = Math.sqrt(2 * g * (h - y));
  147. // 时间公式
  148. // t = ( -sqrt( 2 * g * h ) ± sqrt( 2 * g * ( h - y ) ) ) / -g
  149. const t1 = (-p1 + p2) / -g;
  150. const t2 = (-p1 - p2) / -g;
  151. // 始终使用较大的解
  152. const t = Math.max(t1, t2);
  153. // 角度公式
  154. // θ = atan( ( sqrt( 2 * g * h ) * t ) / x )
  155. const θ = Math.atan(p1 * t / x);
  156. // 速度公式
  157. // v = sqrt( 2 * g * h ) / sin(θ)
  158. const v = p1 / Math.sin(θ);
  159. return {
  160. angle: θ * rad2Deg,
  161. velocity: v,
  162. time: t,
  163. };
  164. }
  165. }