UNPKG

@esengine/nova-ecs-math

Version:

Comprehensive fixed-point mathematics library for deterministic calculations in games and simulations

1,691 lines (1,685 loc) 70.2 kB
import { Component } from '@esengine/nova-ecs'; /** * Fixed-point number implementation for deterministic arithmetic * 用于确定性算术的定点数实现 */ class Fixed { /** * Create a new Fixed-point number * 创建新的定点数 * * @param value - The value to convert to fixed-point */ constructor(value) { if (value instanceof Fixed) { this._value = value._value; } else if (typeof value === 'string') { this._value = Math.round(parseFloat(value) * Fixed.SCALE); } else { this._value = Math.round(value * Fixed.SCALE); } } /** * Create a Fixed number from raw internal value * 从原始内部值创建定点数 */ static fromRaw(rawValue) { const fixed = new Fixed(0); fixed._value = rawValue; return fixed; } /** * Create a cached Fixed number for commonly used values * 为常用值创建缓存的定点数 */ static cached(value) { const rawValue = Math.round(value * Fixed.SCALE); if (Fixed._cache.has(rawValue)) { return Fixed._cache.get(rawValue); } if (Fixed._cache.size >= Fixed.MAX_CACHE_SIZE) { // Clear cache when it gets too large Fixed._cache.clear(); } const fixed = Fixed.fromRaw(rawValue); Fixed._cache.set(rawValue, fixed); return fixed; } /** * Add two fixed-point numbers * 两个定点数相加 */ add(other) { return Fixed.fromRaw(this._value + other._value); } /** * Add in place (modifies this instance for better performance) * 就地相加(修改当前实例以提高性能) */ addInPlace(other) { this._value += other._value; return this; } /** * Subtract two fixed-point numbers * 两个定点数相减 */ subtract(other) { return Fixed.fromRaw(this._value - other._value); } /** * Subtract in place (modifies this instance for better performance) * 就地相减(修改当前实例以提高性能) */ subtractInPlace(other) { this._value -= other._value; return this; } /** * Multiply two fixed-point numbers * 两个定点数相乘 */ multiply(other) { return Fixed.fromRaw(Math.round((this._value * other._value) / Fixed.SCALE)); } /** * Multiply in place (modifies this instance for better performance) * 就地相乘(修改当前实例以提高性能) */ multiplyInPlace(other) { this._value = Math.round((this._value * other._value) / Fixed.SCALE); return this; } /** * Divide two fixed-point numbers * 两个定点数相除 */ divide(other) { if (other._value === 0) { throw new Error('Division by zero'); } return Fixed.fromRaw(Math.round((this._value * Fixed.SCALE) / other._value)); } /** * Divide in place (modifies this instance for better performance) * 就地相除(修改当前实例以提高性能) */ divideInPlace(other) { if (other._value === 0) { throw new Error('Division by zero'); } this._value = Math.round((this._value * Fixed.SCALE) / other._value); return this; } /** * Get the absolute value * 获取绝对值 */ abs() { return Fixed.fromRaw(Math.abs(this._value)); } /** * Negate the value * 取负值 */ negate() { return Fixed.fromRaw(-this._value); } /** * Calculate square root using Newton's method for deterministic results * 使用牛顿迭代法计算平方根,确保确定性结果 */ sqrt() { if (this.lessThan(Fixed.ZERO)) { throw new Error('Square root of negative number'); } if (this.equals(Fixed.ZERO)) { return Fixed.ZERO; } if (this.equals(Fixed.ONE)) { return Fixed.ONE; } // Newton's method: x_{n+1} = (x_n + a/x_n) / 2 // Start with a reasonable initial guess let x = this.greaterThan(Fixed.ONE) ? this.divide(Fixed.TWO) : Fixed.ONE; let prev; // Iterate until convergence (max 20 iterations for safety) for (let i = 0; i < 20; i++) { prev = x; // x = (x + this/x) / 2 x = x.add(this.divide(x)).divide(Fixed.TWO); // Check for convergence (difference less than 1/SCALE) if (x.subtract(prev).abs().rawValue <= 1) { break; } } return x; } /** * Static square root method * 静态平方根方法 */ static sqrt(value) { return value.sqrt(); } /** * Normalize angle to [-π, π] range for trigonometric functions * 将角度标准化到[-π, π]范围用于三角函数 */ static normalizeAngle(angle) { let normalized = new Fixed(angle.toNumber()); // Reduce to [-π, π] range while (normalized.greaterThan(Fixed.PI)) { normalized = normalized.subtract(Fixed.TWO_PI); } while (normalized.lessThanOrEqual(Fixed.PI.negate())) { normalized = normalized.add(Fixed.TWO_PI); } return normalized; } /** * Calculate sine using Taylor series for deterministic results * 使用泰勒级数计算正弦值,确保确定性结果 */ sin() { return Fixed.sin(this); } /** * Static sine function using Taylor series * 使用泰勒级数的静态正弦函数 */ static sin(angle) { // 1. 角度标准化到[-π, π] const normalizedAngle = Fixed.normalizeAngle(angle); // Check lookup table first if (Fixed.SIN_TABLE.has(normalizedAngle.rawValue)) { return Fixed.SIN_TABLE.get(normalizedAngle.rawValue); } // 2. 利用对称性优化 let x = normalizedAngle; let sign = Fixed.ONE; // sin(-x) = -sin(x) if (x.lessThan(Fixed.ZERO)) { x = x.negate(); sign = sign.negate(); } // sin(π - x) = sin(x) for x in [π/2, π] if (x.greaterThan(Fixed.PI_2)) { x = Fixed.PI.subtract(x); } // 3. 泰勒级数展开(使用预计算的阶乘) // sin(x) = x - x³/3! + x⁵/5! - x⁷/7! + x⁹/9! - x¹¹/11! + ... let result = Fixed.ZERO; let term = x; const x_squared = x.multiply(x); let termSign = Fixed.ONE; for (let i = 1; i <= 11; i += 2) { const factorial = Fixed.FACTORIALS[i] || 1; result = result.add(term.multiply(termSign).divide(new Fixed(factorial))); // Next term: multiply by x² term = term.multiply(x_squared); termSign = termSign.negate(); } return result.multiply(sign); } /** * Calculate cosine using the identity cos(x) = sin(x + π/2) * 使用恒等式 cos(x) = sin(x + π/2) 计算余弦值 */ cos() { return Fixed.cos(this); } /** * Static cosine function using cos(x) = sin(x + π/2) * 使用 cos(x) = sin(x + π/2) 的静态余弦函数 */ static cos(angle) { return Fixed.sin(angle.add(Fixed.PI_HALF)); } /** * Calculate tangent * 计算正切值 */ tan() { return Fixed.tan(this); } /** * Static tangent function * 静态正切函数 */ static tan(angle) { const cosValue = Fixed.cos(angle); // Use a small threshold instead of exact zero check for numerical stability if (cosValue.abs().lessThan(new Fixed(0.01))) { throw new Error('Tangent undefined'); } return Fixed.sin(angle).divide(cosValue); } /** * Calculate arcsine using Newton's method * 使用牛顿法计算反正弦值 */ asin() { if (this.abs().greaterThan(Fixed.ONE)) { throw new Error('Arcsine domain error: input must be in [-1, 1]'); } if (this.equals(Fixed.ZERO)) return Fixed.ZERO; if (this.equals(Fixed.ONE)) return Fixed.PI_2; if (this.equals(new Fixed(-1))) return Fixed.PI_2.negate(); // Use Newton's method to solve sin(y) = x for y let y = new Fixed(this.toNumber()); // Initial guess for (let i = 0; i < 10; i++) { const sinY = y.sin(); const cosY = y.cos(); if (cosY.equals(Fixed.ZERO)) break; const delta = sinY.subtract(this).divide(cosY); y = y.subtract(delta); if (delta.abs().rawValue <= 1) break; // Converged } return y; } /** * Calculate arccosine * 计算反余弦值 */ acos() { if (this.abs().greaterThan(Fixed.ONE)) { throw new Error('Arccosine domain error: input must be in [-1, 1]'); } // acos(x) = π/2 - asin(x) return Fixed.PI_2.subtract(this.asin()); } /** * Calculate arctangent using CORDIC algorithm * 使用CORDIC算法计算反正切值 */ atan() { // Use the identity: atan(x) = asin(x/√(1+x²)) const x_squared = this.multiply(this); const denominator = Fixed.ONE.add(x_squared).sqrt(); return this.divide(denominator).asin(); } /** * Calculate atan2 for vector angles * 计算atan2用于向量角度 */ static atan2(y, x) { if (x.equals(Fixed.ZERO) && y.equals(Fixed.ZERO)) { throw new Error('atan2 undefined for (0, 0)'); } if (x.greaterThan(Fixed.ZERO)) { return y.divide(x).atan(); } else if (x.lessThan(Fixed.ZERO)) { if (y.greaterThanOrEqual(Fixed.ZERO)) { return y.divide(x).atan().add(Fixed.PI); } else { return y.divide(x).atan().subtract(Fixed.PI); } } else { // x == 0 if (y.greaterThan(Fixed.ZERO)) { return Fixed.PI_2; } else { return Fixed.PI_2.negate(); } } } /** * Convert to regular number * 转换为普通数字 */ toNumber() { return this._value / Fixed.SCALE; } /** * Convert to string representation * 转换为字符串表示 */ toString() { return this.toNumber().toString(); } /** * Check equality with another Fixed number * 检查与另一个定点数是否相等 */ equals(other) { return this._value === other._value; } /** * Check if this number is less than another * 检查是否小于另一个数 */ lessThan(other) { return this._value < other._value; } /** * Check if this number is less than or equal to another * 检查是否小于或等于另一个数 */ lessThanOrEqual(other) { return this._value <= other._value; } /** * Check if this number is greater than another * 检查是否大于另一个数 */ greaterThan(other) { return this._value > other._value; } /** * Check if this number is greater than or equal to another * 检查是否大于或等于另一个数 */ greaterThanOrEqual(other) { return this._value >= other._value; } /** * Get the raw internal value (for advanced usage) * 获取原始内部值(高级用法) */ get rawValue() { return this._value; } /** * Get the scale factor used for fixed-point arithmetic * 获取用于定点算术的比例因子 */ static get scale() { return Fixed.SCALE; } /** * Floor function - largest integer less than or equal to this value * 向下取整函数 */ floor() { return Fixed.fromRaw(Math.floor(this._value / Fixed.SCALE) * Fixed.SCALE); } /** * Ceiling function - smallest integer greater than or equal to this value * 向上取整函数 */ ceil() { return Fixed.fromRaw(Math.ceil(this._value / Fixed.SCALE) * Fixed.SCALE); } /** * Round to nearest integer * 四舍五入到最近整数 */ round() { return Fixed.fromRaw(Math.round(this._value / Fixed.SCALE) * Fixed.SCALE); } /** * Get fractional part * 获取小数部分 */ frac() { return this.subtract(this.floor()); } /** * Power function using exponentiation by squaring * 使用平方求幂的幂函数 */ pow(exponent) { if (exponent.equals(Fixed.ZERO)) { return Fixed.ONE; } if (exponent.equals(Fixed.ONE)) { return new Fixed(this.toNumber()); } // For integer exponents, use exponentiation by squaring if (exponent.frac().equals(Fixed.ZERO)) { const exp = Math.abs(exponent.toNumber()); let result = Fixed.ONE; let base = new Fixed(this.toNumber()); let n = exp; while (n > 0) { if (n % 2 === 1) { result = result.multiply(base); } base = base.multiply(base); n = Math.floor(n / 2); } return exponent.lessThan(Fixed.ZERO) ? Fixed.ONE.divide(result) : result; } // For fractional exponents, use exp(ln(x) * y) return this.ln().multiply(exponent).exp(); } /** * Natural logarithm using Taylor series * 使用泰勒级数计算自然对数 */ ln() { if (this.lessThanOrEqual(Fixed.ZERO)) { throw new Error('Logarithm domain error: input must be positive'); } if (this.equals(Fixed.ONE)) { return Fixed.ZERO; } // Use ln(x) = 2 * ((x-1)/(x+1) + (x-1)³/(3(x+1)³) + ...) const x = this; const numerator = x.subtract(Fixed.ONE); const denominator = x.add(Fixed.ONE); const ratio = numerator.divide(denominator); const ratio_squared = ratio.multiply(ratio); let result = Fixed.ZERO; let term = ratio; for (let i = 1; i <= 20; i += 2) { result = result.add(term.divide(new Fixed(i))); term = term.multiply(ratio_squared); } return result.multiply(Fixed.TWO); } /** * Exponential function using Taylor series * 使用泰勒级数计算指数函数 */ exp() { // Use Taylor series: e^x = 1 + x + x²/2! + x³/3! + ... let result = Fixed.ONE; let term = Fixed.ONE; for (let i = 1; i <= 20; i++) { term = term.multiply(this).divide(new Fixed(i)); result = result.add(term); } return result; } /** * Minimum of two values * 两个值的最小值 */ static min(a, b) { return a.lessThan(b) ? a : b; } /** * Maximum of two values * 两个值的最大值 */ static max(a, b) { return a.greaterThan(b) ? a : b; } /** * Clamp value between min and max * 将值限制在最小值和最大值之间 */ clamp(min, max) { if (this.lessThan(min)) return min; if (this.greaterThan(max)) return max; return new Fixed(this.toNumber()); } /** * Modulo operation - returns the remainder after division * 模运算 - 返回除法后的余数 */ mod(divisor) { if (divisor.equals(Fixed.ZERO)) { throw new Error('Modulo by zero'); } // Use the formula: a mod b = a - b * floor(a/b) const quotient = this.divide(divisor).floor(); return this.subtract(divisor.multiply(quotient)); } /** * Linear interpolation between two values * 两个值之间的线性插值 */ static lerp(a, b, t) { return a.add(b.subtract(a).multiply(t)); } } Fixed.SCALE = 1000000; // Cache for commonly used values to reduce object creation // 缓存常用值以减少对象创建 Fixed._cache = new Map(); Fixed.MAX_CACHE_SIZE = 1000; // Static constants Fixed.ZERO = new Fixed(0); Fixed.ONE = new Fixed(1); Fixed.PI = new Fixed(3.141592653589793); Fixed.E = new Fixed(2.718281828459045); Fixed.HALF = new Fixed(0.5); Fixed.TWO = new Fixed(2); Fixed.PI_2 = new Fixed(1.5707963267948966); // PI/2 Fixed.PI_HALF = new Fixed(1.5707963267948966); // PI/2 (alias) Fixed.PI_4 = new Fixed(0.7853981633974483); // PI/4 Fixed.PI_QUARTER = new Fixed(0.7853981633974483); // PI/4 (alias) Fixed.TWO_PI = new Fixed(6.283185307179586); // 2*PI Fixed.PI_TWO = new Fixed(6.283185307179586); // 2*PI (alias) Fixed.DEG_TO_RAD = new Fixed(0.017453292519943295); // PI/180 Fixed.RAD_TO_DEG = new Fixed(57.29577951308232); // 180/PI // Precomputed factorial values for Taylor series // 预计算的阶乘值用于泰勒级数 Fixed.FACTORIALS = [ 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600 ]; // Lookup table for common angles (in radians) // 常用角度的查找表(弧度) Fixed.SIN_TABLE = new Map([ [0, Fixed.ZERO], [Fixed.PI_4.rawValue, new Fixed(0.7071067811865476)], // sin(π/4) = √2/2 [Fixed.PI_2.rawValue, Fixed.ONE], // sin(π/2) = 1 [Fixed.PI.rawValue, Fixed.ZERO], // sin(π) = 0 ]); /** * 2D Vector using fixed-point arithmetic for deterministic calculations * 使用定点算术的2D向量,用于确定性计算 */ class FixedVector2 { /** * Create a new 2D fixed-point vector * 创建新的2D定点向量 * * @param x - X component (can be Fixed or number) * @param y - Y component (can be Fixed or number) */ constructor(x = 0, y = 0) { this.x = x instanceof Fixed ? x : new Fixed(x); this.y = y instanceof Fixed ? y : new Fixed(y); } /** * Add two vectors * 两个向量相加 */ add(other) { return new FixedVector2(this.x.add(other.x), this.y.add(other.y)); } /** * Add in place (modifies this instance for better performance) * 就地相加(修改当前实例以提高性能) */ addInPlace(other) { this.x.addInPlace(other.x); this.y.addInPlace(other.y); return this; } /** * Subtract two vectors * 两个向量相减 */ subtract(other) { return new FixedVector2(this.x.subtract(other.x), this.y.subtract(other.y)); } /** * Subtract in place (modifies this instance for better performance) * 就地相减(修改当前实例以提高性能) */ subtractInPlace(other) { this.x.subtractInPlace(other.x); this.y.subtractInPlace(other.y); return this; } /** * Multiply vector by a scalar * 向量乘以标量 */ multiply(scalar) { const scalarFixed = scalar instanceof Fixed ? scalar : new Fixed(scalar); return new FixedVector2(this.x.multiply(scalarFixed), this.y.multiply(scalarFixed)); } /** * Multiply in place (modifies this instance for better performance) * 就地相乘(修改当前实例以提高性能) */ multiplyInPlace(scalar) { const scalarFixed = scalar instanceof Fixed ? scalar : new Fixed(scalar); this.x.multiplyInPlace(scalarFixed); this.y.multiplyInPlace(scalarFixed); return this; } /** * Divide vector by a scalar * 向量除以标量 */ divide(scalar) { const scalarFixed = scalar instanceof Fixed ? scalar : new Fixed(scalar); if (scalarFixed.equals(Fixed.ZERO)) { throw new Error('Division by zero vector'); } return new FixedVector2(this.x.divide(scalarFixed), this.y.divide(scalarFixed)); } /** * Divide in place (modifies this instance for better performance) * 就地相除(修改当前实例以提高性能) */ divideInPlace(scalar) { const scalarFixed = scalar instanceof Fixed ? scalar : new Fixed(scalar); if (scalarFixed.equals(Fixed.ZERO)) { throw new Error('Division by zero vector'); } this.x.divideInPlace(scalarFixed); this.y.divideInPlace(scalarFixed); return this; } /** * Calculate the magnitude (length) of the vector * 计算向量的大小(长度) */ magnitude() { const sqrMagnitude = this.x.multiply(this.x).add(this.y.multiply(this.y)); return sqrMagnitude.sqrt(); } /** * Calculate the squared magnitude (more efficient than magnitude) * 计算平方大小(比magnitude更高效) */ sqrMagnitude() { return this.x.multiply(this.x).add(this.y.multiply(this.y)); } /** * Normalize the vector (make it unit length) * 归一化向量(使其长度为1) */ normalize() { const mag = this.magnitude(); if (mag.equals(Fixed.ZERO)) { return new FixedVector2(Fixed.ZERO, Fixed.ZERO); } return new FixedVector2(this.x.divide(mag), this.y.divide(mag)); } /** * Calculate dot product with another vector * 计算与另一个向量的点积 */ dot(other) { return this.x.multiply(other.x).add(this.y.multiply(other.y)); } /** * Calculate cross product with another vector (returns scalar for 2D) * 计算与另一个向量的叉积(2D返回标量) */ cross(other) { return this.x.multiply(other.y).subtract(this.y.multiply(other.x)); } /** * Calculate distance to another vector * 计算到另一个向量的距离 */ distance(other) { return this.subtract(other).magnitude(); } /** * Calculate squared distance to another vector (more efficient) * 计算到另一个向量的平方距离(更高效) */ sqrDistance(other) { return this.subtract(other).sqrMagnitude(); } /** * Negate the vector * 取向量的负值 */ negate() { return new FixedVector2(this.x.negate(), this.y.negate()); } /** * Get the absolute values of components * 获取分量的绝对值 */ abs() { return new FixedVector2(this.x.abs(), this.y.abs()); } /** * Check equality with another vector * 检查与另一个向量是否相等 */ equals(other) { return this.x.equals(other.x) && this.y.equals(other.y); } /** * Convert to string representation * 转换为字符串表示 */ toString() { return `(${this.x.toString()}, ${this.y.toString()})`; } /** * Convert to array [x, y] * 转换为数组 [x, y] */ toArray() { return [this.x.toNumber(), this.y.toNumber()]; } /** * Create a copy of this vector * 创建此向量的副本 */ clone() { return new FixedVector2(this.x, this.y); } /** * Set this vector's components from another vector (for reusing objects) * 从另一个向量设置此向量的分量(用于重用对象) */ setFrom(other) { this.x = other.x; this.y = other.y; return this; } /** * Set this vector's components from coordinates (for reusing objects) * 从坐标设置此向量的分量(用于重用对象) */ set(x, y) { this.x = x instanceof Fixed ? x : new Fixed(x); this.y = y instanceof Fixed ? y : new Fixed(y); return this; } /** * Reset this vector to zero (for object pooling) * 将此向量重置为零(用于对象池) */ reset() { this.x = Fixed.ZERO; this.y = Fixed.ZERO; return this; } /** * Linear interpolation between two vectors * 两个向量之间的线性插值 */ static lerp(a, b, t) { const tFixed = t instanceof Fixed ? t : new Fixed(t); return new FixedVector2(Fixed.lerp(a.x, b.x, tFixed), Fixed.lerp(a.y, b.y, tFixed)); } /** * Calculate angle between two vectors in radians using deterministic math * 使用确定性数学计算两个向量之间的角度(弧度) */ static angle(a, b) { const dot = a.dot(b); const magnitudes = a.magnitude().multiply(b.magnitude()); if (magnitudes.equals(Fixed.ZERO)) { return Fixed.ZERO; } const cosAngle = dot.divide(magnitudes); // Clamp to [-1, 1] to avoid domain errors const clampedCos = cosAngle.clamp(new Fixed(-1), Fixed.ONE); return clampedCos.acos(); } /** * Get the angle of this vector from the positive X axis * 获取此向量相对于正X轴的角度 */ angle() { return Fixed.atan2(this.y, this.x); } /** * Reflect this vector across a normal vector * 沿法向量反射此向量 * * @param normal - The normal vector to reflect across (should be normalized) * @returns The reflected vector */ reflect(normal) { // Formula: v - 2 * (v · n) * n const dotProduct = this.dot(normal); const reflection = normal.multiply(dotProduct.multiply(new Fixed(2))); return this.subtract(reflection); } /** * Project this vector onto another vector * 将此向量投影到另一个向量上 * * @param onto - The vector to project onto * @returns The projected vector */ project(onto) { // Formula: (v · u) / (u · u) * u const dotProduct = this.dot(onto); const ontoLengthSquared = onto.dot(onto); if (ontoLengthSquared.equals(Fixed.ZERO)) { return FixedVector2.ZERO; } const scalar = dotProduct.divide(ontoLengthSquared); return onto.multiply(scalar); } /** * Get the component of this vector perpendicular to another vector * 获取此向量垂直于另一个向量的分量 * * @param onto - The vector to get the perpendicular component relative to * @returns The perpendicular component */ reject(onto) { // Formula: v - project(v, onto) return this.subtract(this.project(onto)); } /** * Rotate this vector by the given angle in radians * 将此向量按给定角度(弧度)旋转 * * @param angle - Angle in radians * @returns The rotated vector */ rotate(angle) { const a = angle instanceof Fixed ? angle : new Fixed(angle); const cos = a.cos(); const sin = a.sin(); const newX = this.x.multiply(cos).subtract(this.y.multiply(sin)); const newY = this.x.multiply(sin).add(this.y.multiply(cos)); return new FixedVector2(newX, newY); } /** * Get a vector perpendicular to this one (rotated 90 degrees counter-clockwise) * 获取垂直于此向量的向量(逆时针旋转90度) */ perpendicular() { return new FixedVector2(this.y.negate(), this.x); } /** * Get the right perpendicular vector (rotated 90 degrees clockwise) * 获取右垂直向量(顺时针旋转90度) */ perpendicularRight() { return new FixedVector2(this.y, this.x.negate()); } /** * Create a vector from angle and magnitude * 从角度和大小创建向量 */ static fromAngle(angle, magnitude = Fixed.ONE) { return new FixedVector2(angle.cos().multiply(magnitude), angle.sin().multiply(magnitude)); } } // Static constants FixedVector2.ZERO = new FixedVector2(0, 0); FixedVector2.ONE = new FixedVector2(1, 1); FixedVector2.UP = new FixedVector2(0, 1); FixedVector2.DOWN = new FixedVector2(0, -1); FixedVector2.LEFT = new FixedVector2(-1, 0); FixedVector2.RIGHT = new FixedVector2(1, 0); /** * 2x2 Matrix using fixed-point arithmetic for deterministic calculations * 使用定点算术的2x2矩阵,用于确定性计算 * * Matrix layout: * | m00 m01 | * | m10 m11 | */ class FixedMatrix2x2 { /** * Create a new 2x2 fixed-point matrix * 创建新的2x2定点矩阵 * * @param m00 - Element at row 0, column 0 * @param m01 - Element at row 0, column 1 * @param m10 - Element at row 1, column 0 * @param m11 - Element at row 1, column 1 */ constructor(m00 = 1, m01 = 0, m10 = 0, m11 = 1) { this.m00 = m00 instanceof Fixed ? m00 : new Fixed(m00); this.m01 = m01 instanceof Fixed ? m01 : new Fixed(m01); this.m10 = m10 instanceof Fixed ? m10 : new Fixed(m10); this.m11 = m11 instanceof Fixed ? m11 : new Fixed(m11); } /** * Create an identity matrix * 创建单位矩阵 */ static identity() { return new FixedMatrix2x2(1, 0, 0, 1); } /** * Create a zero matrix * 创建零矩阵 */ static zero() { return new FixedMatrix2x2(0, 0, 0, 0); } /** * Create a rotation matrix * 创建旋转矩阵 * * @param angle - Rotation angle in radians */ static rotation(angle) { const cos = angle.cos(); const sin = angle.sin(); return new FixedMatrix2x2(cos, sin.negate(), sin, cos); } /** * Create a scaling matrix * 创建缩放矩阵 * * @param scaleX - Scale factor for X axis * @param scaleY - Scale factor for Y axis (defaults to scaleX for uniform scaling) */ static scaling(scaleX, scaleY) { const sy = scaleY || scaleX; return new FixedMatrix2x2(scaleX, Fixed.ZERO, Fixed.ZERO, sy); } /** * Create a shear matrix * 创建剪切矩阵 * * @param shearX - Shear factor for X axis * @param shearY - Shear factor for Y axis */ static shear(shearX, shearY) { return new FixedMatrix2x2(Fixed.ONE, shearX, shearY, Fixed.ONE); } /** * Create a matrix from an array [m00, m01, m10, m11] * 从数组创建矩阵 [m00, m01, m10, m11] */ static fromArray(array) { if (array.length !== 4) { throw new Error('Array must have exactly 4 elements'); } return new FixedMatrix2x2(array[0], array[1], array[2], array[3]); } /** * Add two matrices * 两个矩阵相加 */ add(other) { return new FixedMatrix2x2(this.m00.add(other.m00), this.m01.add(other.m01), this.m10.add(other.m10), this.m11.add(other.m11)); } /** * Add in place (modifies this instance for better performance) * 就地相加(修改当前实例以提高性能) */ addInPlace(other) { this.m00.addInPlace(other.m00); this.m01.addInPlace(other.m01); this.m10.addInPlace(other.m10); this.m11.addInPlace(other.m11); return this; } /** * Subtract two matrices * 两个矩阵相减 */ subtract(other) { return new FixedMatrix2x2(this.m00.subtract(other.m00), this.m01.subtract(other.m01), this.m10.subtract(other.m10), this.m11.subtract(other.m11)); } /** * Subtract in place (modifies this instance for better performance) * 就地相减(修改当前实例以提高性能) */ subtractInPlace(other) { this.m00.subtractInPlace(other.m00); this.m01.subtractInPlace(other.m01); this.m10.subtractInPlace(other.m10); this.m11.subtractInPlace(other.m11); return this; } /** * Multiply two matrices * 两个矩阵相乘 */ multiply(other) { return new FixedMatrix2x2(this.m00.multiply(other.m00).add(this.m01.multiply(other.m10)), this.m00.multiply(other.m01).add(this.m01.multiply(other.m11)), this.m10.multiply(other.m00).add(this.m11.multiply(other.m10)), this.m10.multiply(other.m01).add(this.m11.multiply(other.m11))); } /** * Multiply matrix by a scalar * 矩阵乘以标量 */ multiplyScalar(scalar) { return new FixedMatrix2x2(this.m00.multiply(scalar), this.m01.multiply(scalar), this.m10.multiply(scalar), this.m11.multiply(scalar)); } /** * Multiply matrix by a scalar in place * 就地矩阵乘以标量 */ multiplyScalarInPlace(scalar) { this.m00.multiplyInPlace(scalar); this.m01.multiplyInPlace(scalar); this.m10.multiplyInPlace(scalar); this.m11.multiplyInPlace(scalar); return this; } /** * Transform a vector by this matrix * 使用此矩阵变换向量 */ transformVector(vector) { return new FixedVector2(this.m00.multiply(vector.x).add(this.m01.multiply(vector.y)), this.m10.multiply(vector.x).add(this.m11.multiply(vector.y))); } /** * Calculate the determinant of this matrix * 计算此矩阵的行列式 */ determinant() { return this.m00.multiply(this.m11).subtract(this.m01.multiply(this.m10)); } /** * Calculate the inverse of this matrix * 计算此矩阵的逆矩阵 */ inverse() { const det = this.determinant(); if (det.equals(Fixed.ZERO)) { throw new Error('Matrix is not invertible (determinant is zero)'); } const invDet = Fixed.ONE.divide(det); return new FixedMatrix2x2(this.m11.multiply(invDet), this.m01.negate().multiply(invDet), this.m10.negate().multiply(invDet), this.m00.multiply(invDet)); } /** * Transpose this matrix * 转置此矩阵 */ transpose() { return new FixedMatrix2x2(this.m00, this.m10, this.m01, this.m11); } /** * Calculate the trace (sum of diagonal elements) of this matrix * 计算此矩阵的迹(对角线元素之和) */ trace() { return this.m00.add(this.m11); } /** * Check if this matrix equals another matrix * 检查此矩阵是否等于另一个矩阵 */ equals(other) { return this.m00.equals(other.m00) && this.m01.equals(other.m01) && this.m10.equals(other.m10) && this.m11.equals(other.m11); } /** * Check if this matrix is the identity matrix * 检查此矩阵是否为单位矩阵 */ isIdentity() { return this.m00.equals(Fixed.ONE) && this.m01.equals(Fixed.ZERO) && this.m10.equals(Fixed.ZERO) && this.m11.equals(Fixed.ONE); } /** * Create a copy of this matrix * 创建此矩阵的副本 */ clone() { return new FixedMatrix2x2(this.m00, this.m01, this.m10, this.m11); } /** * Convert to a regular number array [m00, m01, m10, m11] * 转换为普通数字数组 [m00, m01, m10, m11] */ toArray() { return [ this.m00.toNumber(), this.m01.toNumber(), this.m10.toNumber(), this.m11.toNumber() ]; } /** * Convert to string representation * 转换为字符串表示 */ toString() { return `[${this.m00.toString()}, ${this.m01.toString()}]\n[${this.m10.toString()}, ${this.m11.toString()}]`; } } // Static constants FixedMatrix2x2.IDENTITY = FixedMatrix2x2.identity(); FixedMatrix2x2.ZERO = FixedMatrix2x2.zero(); /** * Rectangle using fixed-point arithmetic for deterministic calculations * 使用定点算术的矩形,用于确定性计算 */ class FixedRect { /** * Create a new fixed-point rectangle * 创建新的定点矩形 * * @param x - X coordinate of the top-left corner * @param y - Y coordinate of the top-left corner * @param width - Width of the rectangle * @param height - Height of the rectangle */ constructor(x = 0, y = 0, width = 0, height = 0) { this.x = x instanceof Fixed ? x : new Fixed(x); this.y = y instanceof Fixed ? y : new Fixed(y); this.width = width instanceof Fixed ? width : new Fixed(width); this.height = height instanceof Fixed ? height : new Fixed(height); } /** * Get the left edge X coordinate * 获取左边缘X坐标 */ get left() { return this.x; } /** * Get the right edge X coordinate * 获取右边缘X坐标 */ get right() { return this.x.add(this.width); } /** * Get the top edge Y coordinate * 获取顶边Y坐标 */ get top() { return this.y; } /** * Get the bottom edge Y coordinate * 获取底边Y坐标 */ get bottom() { return this.y.add(this.height); } /** * Get the center point of the rectangle * 获取矩形的中心点 */ get center() { return new FixedVector2(this.x.add(this.width.divide(new Fixed(2))), this.y.add(this.height.divide(new Fixed(2)))); } /** * Get the top-left corner as a vector * 获取左上角作为向量 */ get topLeft() { return new FixedVector2(this.x, this.y); } /** * Get the top-right corner as a vector * 获取右上角作为向量 */ get topRight() { return new FixedVector2(this.right, this.y); } /** * Get the bottom-left corner as a vector * 获取左下角作为向量 */ get bottomLeft() { return new FixedVector2(this.x, this.bottom); } /** * Get the bottom-right corner as a vector * 获取右下角作为向量 */ get bottomRight() { return new FixedVector2(this.right, this.bottom); } /** * Check if a point is inside this rectangle * 检查点是否在此矩形内 */ contains(point) { return point.x.greaterThanOrEqual(this.x) && point.x.lessThan(this.right) && point.y.greaterThanOrEqual(this.y) && point.y.lessThan(this.bottom); } /** * Check if a point is inside this rectangle (inclusive of edges) * 检查点是否在此矩形内(包含边缘) */ containsInclusive(point) { return point.x.greaterThanOrEqual(this.x) && point.x.lessThanOrEqual(this.right) && point.y.greaterThanOrEqual(this.y) && point.y.lessThanOrEqual(this.bottom); } /** * Check if this rectangle intersects with another rectangle * 检查此矩形是否与另一个矩形相交 */ intersects(other) { return this.left.lessThan(other.right) && this.right.greaterThan(other.left) && this.top.lessThan(other.bottom) && this.bottom.greaterThan(other.top); } /** * Get the intersection rectangle with another rectangle * 获取与另一个矩形的交集矩形 */ intersection(other) { if (!this.intersects(other)) { return null; } const left = Fixed.max(this.left, other.left); const top = Fixed.max(this.top, other.top); const right = Fixed.min(this.right, other.right); const bottom = Fixed.min(this.bottom, other.bottom); return new FixedRect(left, top, right.subtract(left), bottom.subtract(top)); } /** * Get the union rectangle with another rectangle * 获取与另一个矩形的并集矩形 */ union(other) { const left = Fixed.min(this.left, other.left); const top = Fixed.min(this.top, other.top); const right = Fixed.max(this.right, other.right); const bottom = Fixed.max(this.bottom, other.bottom); return new FixedRect(left, top, right.subtract(left), bottom.subtract(top)); } /** * Expand the rectangle by the given amount in all directions * 在所有方向上按给定量扩展矩形 */ expand(amount) { const amt = amount instanceof Fixed ? amount : new Fixed(amount); return new FixedRect(this.x.subtract(amt), this.y.subtract(amt), this.width.add(amt.multiply(new Fixed(2))), this.height.add(amt.multiply(new Fixed(2)))); } /** * Shrink the rectangle by the given amount in all directions * 在所有方向上按给定量收缩矩形 */ shrink(amount) { const amt = amount instanceof Fixed ? amount : new Fixed(amount); return this.expand(amt.negate()); } /** * Move the rectangle by the given offset * 按给定偏移量移动矩形 */ translate(offset) { return new FixedRect(this.x.add(offset.x), this.y.add(offset.y), this.width, this.height); } /** * Create a copy of this rectangle * 创建此矩形的副本 */ clone() { return new FixedRect(this.x, this.y, this.width, this.height); } /** * Check if this rectangle equals another rectangle * 检查此矩形是否等于另一个矩形 */ equals(other) { return this.x.equals(other.x) && this.y.equals(other.y) && this.width.equals(other.width) && this.height.equals(other.height); } /** * Get the area of the rectangle * 获取矩形的面积 */ area() { return this.width.multiply(this.height); } /** * Get the perimeter of the rectangle * 获取矩形的周长 */ perimeter() { return this.width.add(this.height).multiply(new Fixed(2)); } /** * Check if the rectangle is empty (zero or negative area) * 检查矩形是否为空(零或负面积) */ isEmpty() { return this.width.lessThanOrEqual(Fixed.ZERO) || this.height.lessThanOrEqual(Fixed.ZERO); } /** * Convert to string representation * 转换为字符串表示 */ toString() { return `FixedRect(${this.x.toString()}, ${this.y.toString()}, ${this.width.toString()}, ${this.height.toString()})`; } /** * Convert to a regular number array [x, y, width, height] * 转换为普通数字数组 [x, y, width, height] */ toArray() { return [ this.x.toNumber(), this.y.toNumber(), this.width.toNumber(), this.height.toNumber() ]; } /** * Create a rectangle from an array [x, y, width, height] * 从数组创建矩形 [x, y, width, height] */ static fromArray(array) { if (array.length !== 4) { throw new Error('Array must have exactly 4 elements'); } return new FixedRect(array[0], array[1], array[2], array[3]); } /** * Create a rectangle from two corner points * 从两个角点创建矩形 */ static fromCorners(corner1, corner2) { const left = Fixed.min(corner1.x, corner2.x); const top = Fixed.min(corner1.y, corner2.y); const right = Fixed.max(corner1.x, corner2.x); const bottom = Fixed.max(corner1.y, corner2.y); return new FixedRect(left, top, right.subtract(left), bottom.subtract(top)); } /** * Create a rectangle centered at the given point * 创建以给定点为中心的矩形 */ static centered(center, width, height) { const w = width instanceof Fixed ? width : new Fixed(width); const h = height instanceof Fixed ? height : new Fixed(height); const halfW = w.divide(new Fixed(2)); const halfH = h.divide(new Fixed(2)); return new FixedRect(center.x.subtract(halfW), center.y.subtract(halfH), w, h); } } // Static constants FixedRect.ZERO = new FixedRect(0, 0, 0, 0); FixedRect.UNIT = new FixedRect(0, 0, 1, 1); /** * Circle using fixed-point arithmetic for deterministic calculations * 使用定点算术的圆形,用于确定性计算 */ class FixedCircle { constructor(centerOrX, radiusOrY, radius) { if (centerOrX instanceof FixedVector2) { this.center = centerOrX; this.radius = radiusOrY instanceof Fixed ? radiusOrY : new Fixed(radiusOrY); } else { const x = centerOrX instanceof Fixed ? centerOrX : new Fixed(centerOrX); const y = radiusOrY instanceof Fixed ? radiusOrY : new Fixed(radiusOrY); this.center = new FixedVector2(x, y); this.radius = radius instanceof Fixed ? radius : new Fixed(radius); } } /** * Get the X coordinate of the center * 获取中心点的X坐标 */ get x() { return this.center.x; } /** * Set the X coordinate of the center * 设置中心点的X坐标 */ set x(value) { this.center.x = value instanceof Fixed ? value : new Fixed(value); } /** * Get the Y coordinate of the center * 获取中心点的Y坐标 */ get y() { return this.center.y; } /** * Set the Y coordinate of the center * 设置中心点的Y坐标 */ set y(value) { this.center.y = value instanceof Fixed ? value : new Fixed(value); } /** * Get the diameter of the circle * 获取圆的直径 */ get diameter() { return this.radius.multiply(new Fixed(2)); } /** * Set the diameter of the circle (updates radius) * 设置圆的直径(更新半径) */ set diameter(value) { const d = value instanceof Fixed ? value : new Fixed(value); this.radius = d.divide(new Fixed(2)); } /** * Check if a point is inside this circle * 检查点是否在此圆内 */ contains(point) { const distance = this.center.distance(point); return distance.lessThan(this.radius); } /** * Check if a point is inside this circle (inclusive of edge) * 检查点是否在此圆内(包含边缘) */ containsInclusive(point) { const distance = this.center.distance(point); return distance.lessThanOrEqual(this.radius); } /** * Check if this circle intersects with another circle * 检查此圆是否与另一个圆相交 */ intersects(other) { const distance = this.center.distance(other.center); const radiusSum = this.radius.add(other.radius); return distance.lessThan(radiusSum); } /** * Check if this circle intersects with a rectangle * 检查此圆是否与矩形相交 */ intersectsRect(rect) { // Find the closest point on the rectangle to the circle center const closestX = this.center.x.clamp(rect.left, rect.right); const closestY = this.center.y.clamp(rect.top, rect.bottom); const closest = new FixedVector2(closestX, closestY); // Check if the distance to the closest point is less than the radius const distance = this.center.distance(closest); return distance.lessThanOrEqual(this.radius); } /** * Check if this circle completely contains another circle * 检查此圆是否完全包含另一个圆 */ containsCircle(other) { const distance = this.center.distance(other.center); const radiusDiff = this.radius.subtract(other.radius); return distance.lessThanOrEqual(radiusDiff) && radiusDiff.greaterThanOrEqual(Fixed.ZERO); } /** * Check if this circle is completely contained within another circle * 检查此圆是否完全被另一个圆包含 */ isContainedBy(other) { return other.containsCircle(this); } /** * Get the area of the circle * 获取圆的面积 */ area() { // Area = π * r² return Fixed.PI.multiply(this.radius.multiply(this.radius)); } /** * Get the circumference of the circle * 获取圆的周长 */ circumference() { // Circumference = 2 * π * r return new Fixed(2).multiply(Fixed.PI).multiply(this.radius); } /** * Get the bounding rectangle of the circle * 获取圆的边界矩形 */ getBounds() { return new FixedRect(this.center.x.subtract(this.radius), this.center.y.subtract(this.radius), this.diameter, this.diameter); } /** * Move the circle by the given offset * 按给定偏移量移动圆 */ translate(offset) { return new FixedCircle(this.center.add(offset), this.radius); } /** * Scale the circle by the given factor * 按给定因子缩放圆 */ scale(factor) { const f = factor instanceof Fixed ? factor : new Fixed(factor); return new FixedCircle(this.center, this.radius.multiply(f)); } /** * Get the closest point on the circle to the given point * 获取圆上距离给定点最近的点 */ closestPointTo(point) { const direction = point.subtract(this.center).normalize(); return this.center.add(direction.multiply(this.radius)); } /** * Get the distance from the circle edge to the given point * 获取从圆边缘到给定点的距离 */ distanceToPoint(point) { const centerDistance = this.center.distance(point); return centerDistance.subtract(this.radius); } /** * Get a point on the circle at the given angle * 获取圆上给定角度的点 * * @param angle - Angle in radians (0 = right, π/2 = up) */ pointAtAngle(angle) { const a = angle instanceof Fixed ? angle : new Fixed(angle); const x = this.center.x.add(this.radius.multiply(a.cos())); const y = this.center.y.add(this.radius.multiply(a.sin())); return new FixedVector2(x, y); } /** * Get the angle from the center to the given point * 获取从中心到给定点的角度 */ angleToPoint(point) { const direction = point.subtract(this.center); return direction.angle(); } /** * Create a copy of this circle * 创建此圆的副本 */ clone() { return new FixedCircle(this.center.clone(), this.radius); } /** * Check if this circle equals another circle * 检查此圆是否等于另一个圆 */ equals(other) { return this.center.equals(other.center) && this.radius.equals(other.radius); } /** * Convert to string representation * 转换为字符串表示 */ toString() { return `FixedCircle(center: ${this.center.toString()}, radius: ${this.radius.toString()})`; } /** * Convert to a regular number array [x, y, radius] * 转换为普通数字数组 [x, y, radius] */ toArray() { return [this.center.x.toNumber(), this.center.y.toNumber(), this.radius.toNumber()]; } /** * Create a circle from an array [x, y, radius] * 从数组创建圆 [x, y, radius] */ static fromArray(array) { if (array.length !== 3) { throw new Error('Array must have exactly 3 elements'); } return new FixedCircle(array[0], array[1], array[2]); } /** * Create a circle that encompasses the given points * 创建包含给定点的圆 */ static fromPoints(points) { if (points.length === 0) { return new FixedCircle(FixedVector2.ZERO, Fixed.ZERO); } if (points.length === 1) { return new FixedCircle(points[0], Fixed.ZERO); } // Simple implementation: find center as average of points, radius as max distance let centerX = Fixed.ZERO; let centerY = Fixed.ZERO; for (const point of points) { centerX = centerX.add(point.x); centerY = centerY.add(point.y); } const count = new Fixed(points.length); const center = new FixedVector2(centerX.divide(count), centerY.divide(count)); let maxDistance = Fixed.ZERO; for (const point of points) { const distance = center.distance(point); if (distance.greaterThan(maxDistance)) { maxDistance = distance; } } return new FixedCircle(center, maxDistance); } /** * Create a circle from a bounding rectangle (inscribed circle) * 从边界矩形创建圆(内接圆) */ static inscribedInRect(rect) { const center = rect.center; const radius = Fixed.min(rect.width, rect.height).divide(new Fixed(2)); return new FixedCircle(center, radius); } /** * Create a circle from a bounding rectangle (circumscribed circle) * 从边界矩形创建圆(外接圆) */ static circumscribedAroundRect(rect) { const center = rect.center; const radius = rect.width.multiply(rect.width) .add(rect.height.multiply(rect.height)) .sqrt() .divide(new Fixed(2)); return new FixedCircle(center, radius); } } // Static constants FixedCircle.ZERO = new FixedCircle(FixedVector2.ZERO, Fixed.ZERO); FixedCircle.UNIT = new FixedCircle(FixedVector2.ZERO, Fixed.ONE); /** * Utility functions for geometric calculations using fixed-point arithmetic * 使用定点算术进行几何计算的实用函数 */ class GeometryUtils { /** * Calculate the distance between two points * 计算两点之间的距离 */ static distance(point1, point2) { return point1.distance(point2); } /** * Calculate the squared distance between two points (faster than distance) * 计算两点之间的距离平方(比距离计算更快) */ static distanceSquared(point1, point2) { r