弹丸数学错误
Projectile Mathematics error
所以,基本上我是在尝试创建两种计算方法来执行以下操作:
1) 根据发射位置、速度和发射角度获取弹丸发射器的命中位置。
2) 根据速度和所需命中位置获取射击角度。
我目前有以下代码。
'use strict';
import Mortar from '../mortar/Mortar.js';
const GRAVITY = 9.8;
const MAX_RANGE = 1250;
const MIN_RANGE = 50;
/**
* A class for the mortar calculator.
*/
class Calc {
/**
* Get Hit Location Data from Dial Data.
* @param {*} dialData The current dialed in data
* @param {*} mortarData The current Mortar Data
* @return {*} Hit Location Data
*/
static getHitLocData(dialData, mortarData = Mortar.getDefaultData()) {
const {mrads, bearing} = dialData;
const {velocity, x, y, elevation} = mortarData;
const rads = Calc.getRadFromMils(mrads);
const b = Calc.getRadFromDegree(bearing);
const vx = (velocity * Math.cos(rads));
const vy = (velocity * Math.sin(rads));
const time = (2 * (vy / GRAVITY));
const range = ((2 * vx) * (vy / GRAVITY));
const yMax = (Math.pow(vy, 2) / (2 * GRAVITY));
let canHit = true;
// We need a modification for the difference in elevation
// If the range wont hit
if ((range < MIN_RANGE) || (range > MAX_RANGE)) {
canHit = false;
}
const hitX = (x + (range * Math.cos(b)));
const hitY = (y + (range * Math.sin(b)));
return {
bearing,
'mrads': `${Math.round(mrads)}mrads`,
'map': {
'x': Math.round(hitX),
'y': Math.round(hitY),
'heightDiff': '0m',
'distance': `${range.toFixed(2)}m`,
'flight': `${time.toFixed(2)}sec`
},
'grid': 'A1-1-1-000',
'misc': {
'velocityX': `${vx.toFixed(1)}m/s`,
'velocityY': `${vy.toFixed(1)}m/s`,
'maxHeight': `${yMax.toFixed(2)}m`
},
canHit
};
}
/**
* Get Dial Data Data from Hit Location Data.
* @param {*} hitLocData The current requested hit location
* @param {*} mortarData The current Mortar Data
* @return {*} Dial Data
*/
static getDialData(hitLocData, mortarData = Mortar.getDefaultData()) {
const {hitX, hitY, hitHeight} = hitLocData;
const {x, y, mortHeight, velocity} = mortarData;
const range = Math.sqrt(Math.pow((hitX - x), 2) + Math.pow((hitY - y), 2));
const bearing = (Math.atan2((hitY - y), (hitX - x)) * (180 / Math.PI));
const heightDiff = (hitHeight - mortHeight);
let rads = 0;
if (heightDiff) {
// Height difference has not been math proven as 0,0 doesnt even work
const v4 = Math.pow(velocity, 4);
const gx = (GRAVITY * range);
const gx2 = (GRAVITY * Math.pow(range, 2));
const yv2 = (heightDiff * (Math.pow(velocity, 2)));
const m1 = (GRAVITY * (gx2 - (2 * yv2)));
rads = Math.atan((v4 - m1) / gx);
} else {
const gx = (GRAVITY * range);
rads = Math.atan(Math.pow(velocity, 2) / gx);
}
const mrads = (rads * 1000);
const vy = (velocity * Math.sin(rads));
const time = (2 * (vy / GRAVITY));
let canHit = true;
// If the range wont hit
if ((range < MIN_RANGE) || (range > MAX_RANGE)) {
canHit = false;
}
return {
bearing,
'mrads': (`${Math.round(mrads)}mrad`),
'heightDiff': (`${heightDiff}m`),
'flight': (`${time.toFixed(2)}sec`),
'distance': (`${range.toFixed(2)}m`),
'spread': 0,
canHit
};
}
/**
* Get the number of radians from Milradians.
*
* @param {Number} mrads The number of mrads
* @return {Number} The new number of rads
*/
static getRadFromMils(mrads) {
return (mrads / 1000);
}
/**
* Get the number of radians from degrees.
*
* @param {Number} deg The current degree bearing
* @return {Number} The new number of rads
*/
static getRadFromDegree(deg) {
return (deg * (Math.PI / 180));
}
}
export default Calc;
前者,获取命中位置是我知道的方法。如果我给它一个给定的方位角和 mrad 发射角,我可以找到我击中的位置与迫击炮位置的关系。
然而,尽管传递了与第一个函数相同的输出,但后者并不匹配。请参阅下面的输入和输出数据示例
输入:
var dialData = getDialData({
'hitX': 1250,
'hitY': 0,
'hitHeight': 0
}, {
'x': 0,
'y': 0,
'mortHeight': 0,
'velocity': 110.75
});
var hitData = getHitLocData({
'mrads': 800,
'bearing': 0,
}, {
'x': 0,
'y': 0,
'elevation': 0,
'velocity': 110.75
});
输出:
{"bearing":0,"mrads":"786mrad","heightDiff":"0m","flight":"15.99sec","distance":"1250.00m","spread":0,"canHit":true}
{"bearing":0,"mrads":"800mrads","map":{"x":1251,"y":0,"heightDiff":"0m","distance":"1251.05m","flight":"16.21sec"},"grid":"A1-1-1-000","misc":{"velocityX":"77.2m/s","velocityY":"79.4m/s","maxHeight":"322.03m"},"canHit":false}
我一辈子都弄不明白为什么会这样。两者应该计算出相同的距离、mrads 和飞行。
我知道问题出在哪里了。问题是使用以下等式:
Equation image
我的实现完全不正确。而不是计算 ± 的两边,我只是计算其中之一。您可以在检查 heightDiff 的 if 语句中看到这一点。
正确的解决方法是:
// Below are the two calculaitons we need to work out
const dx = range;
const v = velocity;
const g = GRAVITY;
const hd = heightDiff;
const v4 = (Math.pow(velocity, 4));
const gx2 = (GRAVITY * Math.pow(range, 2));
const yv2 = (heightDiff * Math.pow(velocity, 2));
const gx = (GRAVITY * range);
const p1 = Math.sqrt(v4 - (GRAVITY * (gx2 + (2 * yv2))));
const a1 = Math.atan((Math.pow(velocity, 2) + p1) / gx);
rads = a1;
const mrads = (rads * 1000);
所以,基本上我是在尝试创建两种计算方法来执行以下操作:
1) 根据发射位置、速度和发射角度获取弹丸发射器的命中位置。
2) 根据速度和所需命中位置获取射击角度。
我目前有以下代码。
'use strict';
import Mortar from '../mortar/Mortar.js';
const GRAVITY = 9.8;
const MAX_RANGE = 1250;
const MIN_RANGE = 50;
/**
* A class for the mortar calculator.
*/
class Calc {
/**
* Get Hit Location Data from Dial Data.
* @param {*} dialData The current dialed in data
* @param {*} mortarData The current Mortar Data
* @return {*} Hit Location Data
*/
static getHitLocData(dialData, mortarData = Mortar.getDefaultData()) {
const {mrads, bearing} = dialData;
const {velocity, x, y, elevation} = mortarData;
const rads = Calc.getRadFromMils(mrads);
const b = Calc.getRadFromDegree(bearing);
const vx = (velocity * Math.cos(rads));
const vy = (velocity * Math.sin(rads));
const time = (2 * (vy / GRAVITY));
const range = ((2 * vx) * (vy / GRAVITY));
const yMax = (Math.pow(vy, 2) / (2 * GRAVITY));
let canHit = true;
// We need a modification for the difference in elevation
// If the range wont hit
if ((range < MIN_RANGE) || (range > MAX_RANGE)) {
canHit = false;
}
const hitX = (x + (range * Math.cos(b)));
const hitY = (y + (range * Math.sin(b)));
return {
bearing,
'mrads': `${Math.round(mrads)}mrads`,
'map': {
'x': Math.round(hitX),
'y': Math.round(hitY),
'heightDiff': '0m',
'distance': `${range.toFixed(2)}m`,
'flight': `${time.toFixed(2)}sec`
},
'grid': 'A1-1-1-000',
'misc': {
'velocityX': `${vx.toFixed(1)}m/s`,
'velocityY': `${vy.toFixed(1)}m/s`,
'maxHeight': `${yMax.toFixed(2)}m`
},
canHit
};
}
/**
* Get Dial Data Data from Hit Location Data.
* @param {*} hitLocData The current requested hit location
* @param {*} mortarData The current Mortar Data
* @return {*} Dial Data
*/
static getDialData(hitLocData, mortarData = Mortar.getDefaultData()) {
const {hitX, hitY, hitHeight} = hitLocData;
const {x, y, mortHeight, velocity} = mortarData;
const range = Math.sqrt(Math.pow((hitX - x), 2) + Math.pow((hitY - y), 2));
const bearing = (Math.atan2((hitY - y), (hitX - x)) * (180 / Math.PI));
const heightDiff = (hitHeight - mortHeight);
let rads = 0;
if (heightDiff) {
// Height difference has not been math proven as 0,0 doesnt even work
const v4 = Math.pow(velocity, 4);
const gx = (GRAVITY * range);
const gx2 = (GRAVITY * Math.pow(range, 2));
const yv2 = (heightDiff * (Math.pow(velocity, 2)));
const m1 = (GRAVITY * (gx2 - (2 * yv2)));
rads = Math.atan((v4 - m1) / gx);
} else {
const gx = (GRAVITY * range);
rads = Math.atan(Math.pow(velocity, 2) / gx);
}
const mrads = (rads * 1000);
const vy = (velocity * Math.sin(rads));
const time = (2 * (vy / GRAVITY));
let canHit = true;
// If the range wont hit
if ((range < MIN_RANGE) || (range > MAX_RANGE)) {
canHit = false;
}
return {
bearing,
'mrads': (`${Math.round(mrads)}mrad`),
'heightDiff': (`${heightDiff}m`),
'flight': (`${time.toFixed(2)}sec`),
'distance': (`${range.toFixed(2)}m`),
'spread': 0,
canHit
};
}
/**
* Get the number of radians from Milradians.
*
* @param {Number} mrads The number of mrads
* @return {Number} The new number of rads
*/
static getRadFromMils(mrads) {
return (mrads / 1000);
}
/**
* Get the number of radians from degrees.
*
* @param {Number} deg The current degree bearing
* @return {Number} The new number of rads
*/
static getRadFromDegree(deg) {
return (deg * (Math.PI / 180));
}
}
export default Calc;
前者,获取命中位置是我知道的方法。如果我给它一个给定的方位角和 mrad 发射角,我可以找到我击中的位置与迫击炮位置的关系。
然而,尽管传递了与第一个函数相同的输出,但后者并不匹配。请参阅下面的输入和输出数据示例
输入:
var dialData = getDialData({
'hitX': 1250,
'hitY': 0,
'hitHeight': 0
}, {
'x': 0,
'y': 0,
'mortHeight': 0,
'velocity': 110.75
});
var hitData = getHitLocData({
'mrads': 800,
'bearing': 0,
}, {
'x': 0,
'y': 0,
'elevation': 0,
'velocity': 110.75
});
输出:
{"bearing":0,"mrads":"786mrad","heightDiff":"0m","flight":"15.99sec","distance":"1250.00m","spread":0,"canHit":true}
{"bearing":0,"mrads":"800mrads","map":{"x":1251,"y":0,"heightDiff":"0m","distance":"1251.05m","flight":"16.21sec"},"grid":"A1-1-1-000","misc":{"velocityX":"77.2m/s","velocityY":"79.4m/s","maxHeight":"322.03m"},"canHit":false}
我一辈子都弄不明白为什么会这样。两者应该计算出相同的距离、mrads 和飞行。
我知道问题出在哪里了。问题是使用以下等式: Equation image 我的实现完全不正确。而不是计算 ± 的两边,我只是计算其中之一。您可以在检查 heightDiff 的 if 语句中看到这一点。
正确的解决方法是:
// Below are the two calculaitons we need to work out
const dx = range;
const v = velocity;
const g = GRAVITY;
const hd = heightDiff;
const v4 = (Math.pow(velocity, 4));
const gx2 = (GRAVITY * Math.pow(range, 2));
const yv2 = (heightDiff * Math.pow(velocity, 2));
const gx = (GRAVITY * range);
const p1 = Math.sqrt(v4 - (GRAVITY * (gx2 + (2 * yv2))));
const a1 = Math.atan((Math.pow(velocity, 2) + p1) / gx);
rads = a1;
const mrads = (rads * 1000);