优化mathHelper代码

This commit is contained in:
yhh
2023-03-13 12:31:59 +08:00
parent 6329200b84
commit 64bd6aa055
4 changed files with 233 additions and 173 deletions
+39 -32
View File
@@ -2526,21 +2526,23 @@ declare module es {
*/ */
static toRadians(degrees: number): number; static toRadians(degrees: number): number;
/** /**
* 返回由给定三角形和两个归一化重心(面积)坐标定义的点的一个轴的笛卡尔坐标 * 计算三角形上给定两个归一化重心坐标所确定点在某个轴的笛卡尔坐标
* @param value1 * @param value1 三角形上某个顶点在该轴上的笛卡尔坐标
* @param value2 * @param value2 三角形上另一个顶点在该轴上的笛卡尔坐标
* @param value3 * @param value3 三角形上第三个顶点在该轴上的笛卡尔坐标
* @param amount1 * @param amount1 第一个重心坐标,即点相对于三角形边2的面积比例
* @param amount2 * @param amount2 第二个重心坐标,即点相对于三角形边1的面积比例
* @returns 计算出的点在该轴上的笛卡尔坐标
*/ */
static barycentric(value1: number, value2: number, value3: number, amount1: number, amount2: number): number; static barycentric(value1: number, value2: number, value3: number, amount1: number, amount2: number): number;
/** /**
* 使用指定位置执行Catmull-Rom插值 * 使用Catmull-Rom插值算法在指定的四个数值之间进行插值,返回给定位置的插值结果
* @param value1 * @param value1 插值范围中的第一个数据点
* @param value2 * @param value2 插值范围中的第二个数据点
* @param value3 * @param value3 插值范围中的第三个数据点
* @param value4 * @param value4 插值范围中的第四个数据点
* @param amount * @param amount 插值位置的值,取值范围为[0, 1],表示该位置在value2和value3之间的相对位置
* @returns 经过Catmull-Rom插值计算后在给定位置的插值结果
*/ */
static catmullRom(value1: number, value2: number, value3: number, value4: number, amount: number): number; static catmullRom(value1: number, value2: number, value3: number, value4: number, amount: number): number;
/** /**
@@ -2578,7 +2580,8 @@ declare module es {
static smoothStep(value1: number, value2: number, amount: number): number; static smoothStep(value1: number, value2: number, amount: number): number;
/** /**
* 将给定角度减小到π到-π之间的值 * 将给定角度减小到π到-π之间的值
* @param angle * @param angle 给定角度值
* @returns 减小后的角度值,保证在[-π, π]的范围内
*/ */
static wrapAngle(angle: number): number; static wrapAngle(angle: number): number;
/** /**
@@ -2620,6 +2623,13 @@ declare module es {
* @returns * @returns
*/ */
static signThreshold(value: number, threshold: number): number; static signThreshold(value: number, threshold: number): number;
/**
* 计算t值在[from, to]区间内的插值比例
* @param from 插值区间的起点
* @param to 插值区间的终点
* @param t 需要计算插值比例的数值
* @returns t值在[from, to]区间内的插值比例,取值范围在[0, 1]之间
*/
static inverseLerp(from: number, to: number, t: number): number; static inverseLerp(from: number, to: number, t: number): number;
/** /**
* 在两个值之间线性插值 * 在两个值之间线性插值
@@ -2802,29 +2812,26 @@ declare module es {
*/ */
static lissajou(xFrequency?: number, yFrequency?: number, xMagnitude?: number, yMagnitude?: number, phase?: number): Vector2; static lissajou(xFrequency?: number, yFrequency?: number, xMagnitude?: number, yMagnitude?: number, phase?: number): Vector2;
/** /**
* lissajou曲线的阻尼形式,其振荡随时间在0和最大幅度之间。 * 生成阻尼的 Lissajous 曲线
* 为获得最佳效果,阻尼应在0到1之间。 * @param xFrequency x 轴上的频率
* 振荡间隔是动画循环的一半完成的时间(以秒为单位)。 * @param yFrequency y 轴上的频率
* @param xFrequency * @param xMagnitude x 轴上的振幅
* @param yFrequency * @param yMagnitude y 轴上的振幅
* @param xMagnitude * @param phase x 轴相位差
* @param yMagnitude * @param damping 阻尼值
* @param phase * @param oscillationInterval 振荡间隔
* @param damping
* @param oscillationInterval
* @returns
*/ */
static lissajouDamped(xFrequency?: number, yFrequency?: number, xMagnitude?: number, yMagnitude?: number, phase?: number, damping?: number, oscillationInterval?: number): Vector2; static lissajouDamped(xFrequency?: number, yFrequency?: number, xMagnitude?: number, yMagnitude?: number, phase?: number, damping?: number, oscillationInterval?: number): Vector2;
/** /**
* 执行Hermite样条插值 * 计算在曲线上特定位置的值。
* @param value1 * @param value1 第一个插值点的值
* @param tangent1 * @param tangent1 第一个插值点的切线或方向向量
* @param value2 * @param value2 第二个插值点的值
* @param tangent2 * @param tangent2 第二个插值点的切线或方向向量
* @param amount * @param amount 在这两个点之间进行插值的位置
* @returns * @returns 在曲线上特定位置的值
*/ */
static hermite(value1: number, tangent1: number, value2: number, tangent2: number, amount: number): any; static hermite(value1: number, tangent1: number, value2: number, tangent2: number, amount: number): number;
/** /**
* 此函数用于确保数不是NaN或无穷大 * 此函数用于确保数不是NaN或无穷大
* @param x * @param x
+82 -62
View File
@@ -6222,31 +6222,41 @@ var es;
return degrees * 0.017453292519943295769236907684886; return degrees * 0.017453292519943295769236907684886;
}; };
/** /**
* 返回由给定三角形和两个归一化重心面积坐标定义的点的一个轴的笛卡尔坐标 * 计算三角形上给定两个归一化重心坐标所确定点在某个轴的笛卡尔坐标
* @param value1 * @param value1 三角形上某个顶点在该轴上的笛卡尔坐标
* @param value2 * @param value2 三角形上另一个顶点在该轴上的笛卡尔坐标
* @param value3 * @param value3 三角形上第三个顶点在该轴上的笛卡尔坐标
* @param amount1 * @param amount1 第一个重心坐标即点相对于三角形边2的面积比例
* @param amount2 * @param amount2 第二个重心坐标即点相对于三角形边1的面积比例
* @returns 计算出的点在该轴上的笛卡尔坐标
*/ */
MathHelper.barycentric = function (value1, value2, value3, amount1, amount2) { MathHelper.barycentric = function (value1, value2, value3, amount1, amount2) {
return value1 + (value2 - value1) * amount1 + (value3 - value1) * amount2; // 计算边2上的点的笛卡尔坐标
var point2 = value2 + (value3 - value2) * amount2;
// 计算从边1起点到点的向量
var vector = (point2 - value1) * (amount1 / (1 - amount1));
// 返回点在该轴上的笛卡尔坐标
return value1 + vector;
}; };
/** /**
* 使用指定位置执行Catmull-Rom插值 * 使用Catmull-Rom插值算法在指定的四个数值之间进行插值返回给定位置的插值结果
* @param value1 * @param value1 插值范围中的第一个数据点
* @param value2 * @param value2 插值范围中的第二个数据点
* @param value3 * @param value3 插值范围中的第三个数据点
* @param value4 * @param value4 插值范围中的第四个数据点
* @param amount * @param amount 插值位置的值取值范围为[0, 1]表示该位置在value2和value3之间的相对位置
* @returns 经过Catmull-Rom插值计算后在给定位置的插值结果
*/ */
MathHelper.catmullRom = function (value1, value2, value3, value4, amount) { MathHelper.catmullRom = function (value1, value2, value3, value4, amount) {
// 使用来自http://www.mvps.org/directx/articles/catmull/的公式 // 计算输入参数amount的平方和立方值
var amountSquared = amount * amount; var amountSquared = amount * amount;
var amountCubed = amountSquared * amount; var amountCubed = amountSquared * amount;
return (0.5 * (2 * value2 + (value3 - value1) * amount + // 使用Catmull-Rom插值算法计算插值结果
(2 * value1 - 5 * value2 + 4 * value3 - value4) * amountSquared + var p0 = (-value1 + 3 * value2 - 3 * value3 + value4) / 2;
(3 * value2 - value1 - 3 * value3 + value4) * amountCubed)); var p1 = 2 * value1 - 5 * value2 + 4 * value3 - value4 / 2;
var p2 = (-value1 + value3) / 2;
var p3 = (value2 - value1 + value3 - value4) / 2;
return p0 * amountCubed + p1 * amountSquared + p2 * amount + p3;
}; };
/** /**
* 将值在leftMin-leftMax范围内映射到一个在rightMin-rightMax范围内的值 * 将值在leftMin-leftMax范围内映射到一个在rightMin-rightMax范围内的值
@@ -6293,17 +6303,19 @@ var es;
}; };
/** /**
* 将给定角度减小到π到-π之间的值 * 将给定角度减小到π到-π之间的值
* @param angle * @param angle 给定角度值
* @returns 减小后的角度值保证在[-π, π]的范围内
*/ */
MathHelper.wrapAngle = function (angle) { MathHelper.wrapAngle = function (angle) {
if ((angle > -Math.PI) && (angle <= Math.PI)) // 将角度值限制在[-2π, 2π]的范围内,这样可以保证取余运算得到的结果始终为正数
return angle; var angleMod = (angle + 2 * Math.PI) % (2 * Math.PI);
angle %= Math.PI * 2; // 如果计算出的余数大于π,则将其减去2π,使得结果在[-π, π]的范围内
if (angle <= -Math.PI) if (angleMod > Math.PI) {
return angle + 2 * Math.PI; return angleMod - 2 * Math.PI;
if (angle > Math.PI) }
return angle - 2 * Math.PI; else {
return angle; return angleMod;
}
}; };
/** /**
* 确定值是否以2为底 * 确定值是否以2为底
@@ -6368,20 +6380,22 @@ var es;
else else
return 0; return 0;
}; };
/**
* 计算t值在[from, to]区间内的插值比例
* @param from 插值区间的起点
* @param to 插值区间的终点
* @param t 需要计算插值比例的数值
* @returns t值在[from, to]区间内的插值比例取值范围在[0, 1]之间
*/
MathHelper.inverseLerp = function (from, to, t) { MathHelper.inverseLerp = function (from, to, t) {
if (from < to) { // 计算插值区间的长度
if (t < from) var length = to - from;
return 0; // 如果插值区间的长度为0,则返回0
else if (t > to) if (length === 0) {
return 1;
}
else {
if (t < to)
return 1;
else if (t > from)
return 0; return 0;
} }
return (t - from) / (to - from); // 计算t在插值区间中的相对位置,并返回插值比例
return (t - from) / length;
}; };
/** /**
* 在两个值之间线性插值 * 在两个值之间线性插值
@@ -6683,17 +6697,14 @@ var es;
return new es.Vector2(x, y); return new es.Vector2(x, y);
}; };
/** /**
* lissajou曲线的阻尼形式其振荡随时间在0和最大幅度之间 * 生成阻尼的 Lissajous 曲线
* 为获得最佳效果阻尼应在0到1之间 * @param xFrequency x 轴上的频率
* 振荡间隔是动画循环的一半完成的时间以秒为单位 * @param yFrequency y 轴上的频率
* @param xFrequency * @param xMagnitude x 轴上的振幅
* @param yFrequency * @param yMagnitude y 轴上的振幅
* @param xMagnitude * @param phase x 轴相位差
* @param yMagnitude * @param damping 阻尼值
* @param phase * @param oscillationInterval 振荡间隔
* @param damping
* @param oscillationInterval
* @returns
*/ */
MathHelper.lissajouDamped = function (xFrequency, yFrequency, xMagnitude, yMagnitude, phase, damping, oscillationInterval) { MathHelper.lissajouDamped = function (xFrequency, yFrequency, xMagnitude, yMagnitude, phase, damping, oscillationInterval) {
if (xFrequency === void 0) { xFrequency = 2; } if (xFrequency === void 0) { xFrequency = 2; }
@@ -6703,31 +6714,40 @@ var es;
if (phase === void 0) { phase = 0.5; } if (phase === void 0) { phase = 0.5; }
if (damping === void 0) { damping = 0; } if (damping === void 0) { damping = 0; }
if (oscillationInterval === void 0) { oscillationInterval = 5; } if (oscillationInterval === void 0) { oscillationInterval = 5; }
// 将时间戳限制在振荡间隔内
var wrappedTime = this.pingPong(es.Time.totalTime, oscillationInterval); var wrappedTime = this.pingPong(es.Time.totalTime, oscillationInterval);
// 计算阻尼值
var damped = Math.pow(Math.E, -damping * wrappedTime); var damped = Math.pow(Math.E, -damping * wrappedTime);
// 计算 x 和 y 方向上的振荡值
var x = damped * Math.sin(es.Time.totalTime * xFrequency + phase) * xMagnitude; var x = damped * Math.sin(es.Time.totalTime * xFrequency + phase) * xMagnitude;
var y = damped * Math.cos(es.Time.totalTime * yFrequency) * yMagnitude; var y = damped * Math.cos(es.Time.totalTime * yFrequency) * yMagnitude;
// 返回二维向量
return new es.Vector2(x, y); return new es.Vector2(x, y);
}; };
/** /**
* 执行Hermite样条插值 * 计算在曲线上特定位置的值
* @param value1 * @param value1 第一个插值点的值
* @param tangent1 * @param tangent1 第一个插值点的切线或方向向量
* @param value2 * @param value2 第二个插值点的值
* @param tangent2 * @param tangent2 第二个插值点的切线或方向向量
* @param amount * @param amount 在这两个点之间进行插值的位置
* @returns * @returns 在曲线上特定位置的值
*/ */
MathHelper.hermite = function (value1, tangent1, value2, tangent2, amount) { MathHelper.hermite = function (value1, tangent1, value2, tangent2, amount) {
var v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result; var s = amount;
var sCubed = s * s * s; var sCubed = s * s * s;
var sSquared = s * s; var sSquared = s * s;
if (amount == 0) // 如果在第一个插值点,直接返回第一个插值点的值
result = value1; if (amount === 0) {
else if (amount == 1) return value1;
result = value2; }
else // 如果在第二个插值点,直接返回第二个插值点的值
result = (2 * v1 - 2 * v2 + t2 + t1) * sCubed + else if (amount === 1) {
return value2;
}
// 否则,根据Hermite插值公式计算特定位置的值
var v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2;
var result = (2 * v1 - 2 * v2 + t2 + t1) * sCubed +
(3 * v2 - 3 * v1 - 2 * t1 - t2) * sSquared + (3 * v2 - 3 * v1 - 2 * t1 - t2) * sSquared +
t1 * s + t1 * s +
v1; v1;
+1 -1
View File
File diff suppressed because one or more lines are too long
+103 -70
View File
@@ -25,32 +25,45 @@ module es {
} }
/** /**
* *
* @param value1 * @param value1
* @param value2 * @param value2
* @param value3 * @param value3
* @param amount1 * @param amount1 2
* @param amount2 * @param amount2 1
* @returns
*/ */
public static barycentric(value1: number, value2: number, value3: number, amount1: number, amount2: number) { public static barycentric(value1: number, value2: number, value3: number, amount1: number, amount2: number) {
return value1 + (value2 - value1) * amount1 + (value3 - value1) * amount2; // 计算边2上的点的笛卡尔坐标
const point2 = value2 + (value3 - value2) * amount2;
// 计算从边1起点到点的向量
const vector = (point2 - value1) * (amount1 / (1 - amount1));
// 返回点在该轴上的笛卡尔坐标
return value1 + vector;
} }
/** /**
* 使Catmull-Rom插值 * 使Catmull-Rom插值算法在指定的四个数值之间进行插值
* @param value1 * @param value1
* @param value2 * @param value2
* @param value3 * @param value3
* @param value4 * @param value4
* @param amount * @param amount [0, 1]value2和value3之间的相对位置
* @returns Catmull-Rom插值计算后在给定位置的插值结果
*/ */
public static catmullRom(value1: number, value2: number, value3: number, value4: number, amount: number) { public static catmullRom(value1: number, value2: number, value3: number, value4: number, amount: number) {
// 使用来自http://www.mvps.org/directx/articles/catmull/的公式 // 计算输入参数amount的平方和立方值
let amountSquared = amount * amount; const amountSquared = amount * amount;
let amountCubed = amountSquared * amount; const amountCubed = amountSquared * amount;
return (0.5 * (2 * value2 + (value3 - value1) * amount +
(2 * value1 - 5 * value2 + 4 * value3 - value4) * amountSquared + // 使用Catmull-Rom插值算法计算插值结果
(3 * value2 - value1 - 3 * value3 + value4) * amountCubed)); const p0 = (-value1 + 3 * value2 - 3 * value3 + value4) / 2;
const p1 = 2 * value1 - 5 * value2 + 4 * value3 - value4 / 2;
const p2 = (-value1 + value3) / 2;
const p3 = (value2 - value1 + value3 - value4) / 2;
return p0 * amountCubed + p1 * amountSquared + p2 * amount + p3;
} }
/** /**
@@ -103,17 +116,19 @@ module es {
/** /**
* π-π * π-π
* @param angle * @param angle
* @returns [-π, π]
*/ */
public static wrapAngle(angle: number) { public static wrapAngle(angle: number) {
if ((angle > -Math.PI) && (angle <= Math.PI)) // 将角度值限制在[-2π, 2π]的范围内,这样可以保证取余运算得到的结果始终为正数
return angle; const angleMod = (angle + 2 * Math.PI) % (2 * Math.PI);
angle %= Math.PI * 2;
if (angle <= -Math.PI) // 如果计算出的余数大于π,则将其减去2π,使得结果在[-π, π]的范围内
return angle + 2 * Math.PI; if (angleMod > Math.PI) {
if (angle > Math.PI) return angleMod - 2 * Math.PI;
return angle - 2 * Math.PI; } else {
return angle; return angleMod;
}
} }
/** /**
@@ -188,20 +203,24 @@ module es {
return 0; return 0;
} }
/**
* t值在[from, to]
* @param from
* @param to
* @param t
* @returns t值在[from, to][0, 1]
*/
public static inverseLerp(from: number, to: number, t: number) { public static inverseLerp(from: number, to: number, t: number) {
if (from < to) { // 计算插值区间的长度
if (t < from) const length = to - from;
return 0;
else if (t > to) // 如果插值区间的长度为0,则返回0
return 1; if (length === 0) {
} else {
if (t < to)
return 1;
else if (t > from)
return 0; return 0;
} }
return (t - from) / (to - from); // 计算t在插值区间中的相对位置,并返回插值比例
return (t - from) / length;
} }
/** /**
@@ -545,50 +564,64 @@ module es {
} }
/** /**
* lissajou曲线的阻尼形式0 * Lissajous 线
* 01 * @param xFrequency x
* * @param yFrequency y
* @param xFrequency * @param xMagnitude x
* @param yFrequency * @param yMagnitude y
* @param xMagnitude * @param phase x
* @param yMagnitude * @param damping
* @param phase * @param oscillationInterval
* @param damping
* @param oscillationInterval
* @returns
*/ */
public static lissajouDamped(xFrequency: number = 2, yFrequency: number = 3, xMagnitude: number = 1, public static lissajouDamped(
yMagnitude: number = 1, phase: number = 0.5, damping: number = 0, xFrequency: number = 2,
oscillationInterval: number = 5) { yFrequency: number = 3,
let wrappedTime = this.pingPong(Time.totalTime, oscillationInterval); xMagnitude: number = 1,
let damped = Math.pow(Math.E, -damping * wrappedTime); yMagnitude: number = 1,
phase: number = 0.5,
damping: number = 0,
oscillationInterval: number = 5
): Vector2 {
// 将时间戳限制在振荡间隔内
const wrappedTime = this.pingPong(Time.totalTime, oscillationInterval);
let x = damped * Math.sin(Time.totalTime * xFrequency + phase) * xMagnitude; // 计算阻尼值
let y = damped * Math.cos(Time.totalTime * yFrequency) * yMagnitude; const damped = Math.pow(Math.E, -damping * wrappedTime);
// 计算 x 和 y 方向上的振荡值
const x = damped * Math.sin(Time.totalTime * xFrequency + phase) * xMagnitude;
const y = damped * Math.cos(Time.totalTime * yFrequency) * yMagnitude;
// 返回二维向量
return new Vector2(x, y); return new Vector2(x, y);
} }
/** /**
* Hermite样条插值 * 线
* @param value1 * @param value1
* @param tangent1 * @param tangent1 线
* @param value2 * @param value2
* @param tangent2 * @param tangent2 线
* @param amount * @param amount
* @returns * @returns 线
*/ */
public static hermite(value1: number, tangent1: number, value2: number, tangent2: number, amount: number) { public static hermite(value1: number, tangent1: number, value2: number, tangent2: number, amount: number) {
let v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result; let s = amount;
let sCubed = s * s * s; let sCubed = s * s * s;
let sSquared = s * s; let sSquared = s * s;
if (amount == 0) // 如果在第一个插值点,直接返回第一个插值点的值
result = value1; if (amount === 0) {
else if (amount == 1) return value1;
result = value2; }
else // 如果在第二个插值点,直接返回第二个插值点的值
result = (2 * v1 - 2 * v2 + t2 + t1) * sCubed + else if (amount === 1) {
return value2;
}
// 否则,根据Hermite插值公式计算特定位置的值
let v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2;
let result = (2 * v1 - 2 * v2 + t2 + t1) * sCubed +
(3 * v2 - 3 * v1 - 2 * t1 - t2) * sSquared + (3 * v2 - 3 * v1 - 2 * t1 - t2) * sSquared +
t1 * s + t1 * s +
v1; v1;