向量数学库
基本信息
| 属性 | 值 |
|---|---|
| 包 | com.github.lunatrius.core.util.vector |
| 类数 | 9(2/3/4 维 × i 整数 / f 浮点 / d 双精度) |
| 总行数 | 1367 |
| 内存占用 | 0 —— 全部成员为 public static 方法或常量,无实例字段 |
这是本 mod 最大的 API 面(9/28 个 Java 文件)。EntityHelper 是本 mod 内唯一使用它的类,返回 Vector3f 与 Vector3i。
类继承关系
| 类 | 继承 | 坐标字段 |
|---|---|---|
Vector2d |
无(基类) | public double x, public double y |
Vector2f |
无(基类) | public float x, public float y |
Vector2i |
无(基类) | public int x, public int y |
Vector3d |
extends Vector2d |
继承 x y,新增 public double z |
Vector3f |
extends Vector2f |
继承 x y,新增 public float z |
Vector3i |
extends Vector2i |
继承 x y,新增 public int z |
Vector4d |
extends Vector3d |
继承 x y z,新增 public double w |
Vector4f |
extends Vector3f |
继承 x y z,新增 public float w |
Vector4i |
extends Vector3i |
继承 x y z,新增 public int w |
[!IMPORTANT] 三个
Vector3*继承对应的Vector2*,三个Vector4*继承对应的Vector3*——形成 3 条并行的继承链。坐标字段是public可直接读写,与getX/setX访问器并存。
构造函数
每个类 4 个重载,模式完全一致(以 Vector3f 为例):
| 签名 | 行为 |
|---|---|
public Vector3f() |
各分量取 0 |
public Vector3f(Vector3f vec) |
复制构造 |
public Vector3f(float num) |
所有分量取同一值 num |
public Vector3f(float x, float y, float z) |
分量分别赋值 |
通用方法
以下方法在每一族(2 维 / 3 维 / 4 维)内的签名完全一致,只是分量数与类型不同。
访问器
| 签名 | 说明 |
|---|---|
getX() / getY() |
读 x / y(所有类都有) |
getZ() / getW() |
读 z / w(仅 Vector3* / Vector4* 有) |
setX(...) / setY(...) |
写 x / y(所有类都有) |
setZ(...) / setW() |
写 z / w(仅 Vector3* / Vector4* 有) |
set(VectorXX vec) |
用另一向量覆盖全部分量,返回 this |
set(分量 1, 分量 2, …) |
逐分量覆盖,返回 this |
[!NOTE]
setX/setY/setZ/setW与getX等都是final;set两个重载不是final(子类要重载set时依赖这一点)。
长度与距离
| 签名 | 返回类型(以 2 维 d 为例) |
|---|---|
length() |
double = Math.sqrt(lengthSquared()),标 final |
lengthSquared() |
double = x*x + y*y(3/4 维加上 z、w) |
lengthTo(VectorXX vec) |
double = Math.sqrt(lengthSquaredTo(vec)),标 final |
lengthSquaredTo(VectorXX vec) |
double = pow2(差x) + pow2(差y) + … |
protected final X pow2(X num) |
return num * num;(内部辅助) |
[!IMPORTANT] 返回类型随分量类型变化,浮点与整数不一致:
| 类 | length() |
lengthSquared() |
lengthTo() |
lengthSquaredTo() |
dot() |
|---|---|---|---|---|---|
Vector2d / Vector3d / Vector4d |
double |
double |
double |
double |
double |
Vector2f / Vector3f / Vector4f |
double |
float |
double |
float |
float |
Vector2i / Vector3i / Vector4i |
double |
int |
double |
int |
double |
即 length() 与 lengthTo() 在 9 个类中全部返回 double(内部用 Math.sqrt),而平方长度与点积跟随分量类型。
运算
| 签名 | 行为 |
|---|---|
public final VectorXX normalize() |
double len = length(); if (len != 0.0) return scale(1.0 / len); return this; |
public VectorXX negate() |
各分量取负,返回 this |
public <T> dot(VectorXX vec) |
各分量相乘求和 |
public VectorXX scale(double scale) |
各分量 *= scale(参数恒为 double,即使 Vector2i 的分量是 int) |
public VectorXX add(VectorXX vec) |
逐分量相加,返回 this |
public VectorXX add(分量…) |
逐分量加上独立参数,返回 this |
public VectorXX sub(VectorXX vec) |
逐分量相减,返回 this |
public VectorXX sub(分量…) |
逐分量减去独立参数,返回 this |
[!WARNING] 除
length()/lengthTo()/lengthSquaredTo()/pow2外,几乎所有运算方法都原地修改this并返回它(链式写法),不做不可变语义。dot()与lengthSquared()是纯查询。误以为它们返回新对象会直接破坏原向量。
[!NOTE]
normalize()对Vector*i同样可用:它调用scale(1.0 / len),而scale的参数是double,所以整数向量的分量会被隐式回落到int截断(如Vector2i(3, 4).normalize()→(int)(0.6)/(int)(0.8)→(0, 0))。同理dot()在Vector*i上返回double,但内部按int相乘后相加再隐式转回double。
克隆与相等
| 签名 | 行为 |
|---|---|
public VectorXX clone() |
标注 @Override,返回 new VectorXX(this) |
public boolean equals(Object obj) |
标注 @Override,obj instanceof VectorXX && equals((VectorXX) obj) |
public boolean equals(VectorXX vec) |
浮点:转调 equals(vec, EPSILON);整数:逐分量 == |
public boolean equals(VectorXX vec, double epsilon) / (…, float epsilon) |
仅浮点类有:Math.abs(this.x - vec.x) < epsilon && … |
public String toString() |
标注 @Override,String.format("[%s, %s]", …),逗号分隔(3/4 维继续追加) |
[!IMPORTANT] 浮点类
equals(Object)不使用 epsilon 之外的精度,判定规则是严格小于:
Vector2d.equals(vec)→equals(vec, DOUBLE_EPSILON)Vector2f.equals(vec)→equals(vec, FLOAT_EPSILON)Vector2i.equals(vec)→ 无重载,直接this.x == vec.x && this.y == vec.y
精度常量
| 类 | 常量 | 源码值 | 实际数值 |
|---|---|---|---|
Vector2d |
DOUBLE_EPSILON |
10e-6f |
≈ 1.0 × 10⁻⁵ |
Vector2f |
FLOAT_EPSILON |
10e-6f |
≈ 1.0 × 10⁻⁵ |
[!WARNING] 常量名暗示
1 × 10⁻⁶,但字面量写的是10e-6f(10 × 10⁻⁶ = 10⁻⁵),且Vector2d.DOUBLE_EPSILON声明为double却用浮点字面量f初始化。实际容差是0.00001而不是0.000001,比命名意图宽 10 倍。这两个常量分别定义在Vector2d/Vector2f上,被 3 维、4 维的同族子类继承复用。
类型转换
每个类提供 4 个转换方法,分为「无参新建」与「写入传入向量」两两成对:
| 签名模式 | 行为 |
|---|---|
public VectorYY toVectorYY() |
new VectorYY(转换后的各分量) — 分配新对象 |
public VectorYY toVectorYY(VectorYY vec) |
vec.set(转换后的各分量) — 写入调用方提供的对象,返回该对象 |
转换矩阵
| 源类 | 可转目标(无参 / 带参各一) |
|---|---|
Vector2d |
Vector2i、Vector2f |
Vector2f |
Vector2i、Vector2d |
Vector2i |
Vector2f、Vector2d |
Vector3d |
Vector3i、Vector3f |
Vector3f |
Vector3i、Vector3d |
Vector3i |
Vector3f、Vector3d |
Vector4d |
Vector4i、Vector4f |
Vector4f |
Vector4i、Vector4d |
Vector4i |
Vector4f、Vector4d |
[!IMPORTANT] 只能向同维数转换,且必须转成另一种分量类型(不转回自身类型)。 因此:
- 没有降维转换:4 个
Vector4*类全部没有toVector3x()方法,无法从 4 维降到 3 维- 3 个
Vector3*也没有toVector2x()- 跨族只能靠字段继承间接访问(
Vector3f是Vector2f的子类,其x/y可直接读)Vector4d自身类型无法再转成Vector4d(无意义),要复制请用clone()
转换取整规则
| 转换 | 取整方式 | 示例 |
|---|---|---|
d → i |
(int) Math.floor(...) |
Vector2d(1.7, -0.5).toVector2i() → Vector2i(1, -1) |
d → f |
(float) Math.floor(...) |
Vector2d(1.7, -0.5).toVector2f() → 1.7f 变 1.0f、-0.5f 变 -1.0f |
f → i |
(int) Math.floor(...) |
Vector2f(1.7f, -0.5f).toVector2i() → Vector2i(1, -1) |
f → d |
直接隐式提升 | Vector2f(1.7f, …).toVector2d() → 1.7000000476837158 |
i → f / i → d |
直接隐式提升 | Vector2i(3, -4).toVector2f() → 3.0f |
[!WARNING] 向浮点类型转换时也会
Math.floor,即Vector2d(1.7, 2.3).toVector2f()得到的是1.0f而不是1.7f。这会丢失小数部分,与「向浮点类型转换应保留精度」的直觉相反。另外f → d因 IEEE 754 单精度无法精确表示某些小数,往返转换可能出现1.7000000476837158这类尾数。
完整方法清单(以 Vector4d 为例)
| 分类 | 方法 |
|---|---|
| 字段 | public double x, y, z, w |
| 常量 | 继承 Vector2d.DOUBLE_EPSILON |
| 构造函数 | Vector4d() / Vector4d(Vector4d) / Vector4d(double num) / Vector4d(double x, double y, double z, double w) |
| 访问器 | getX getY getZ getW setX setY setZ setW set(Vector4d) set(double×4) |
| 长度 | length() lengthSquared() lengthTo(Vector4d) lengthSquaredTo(Vector4d) protected pow2(double) |
| 运算 | normalize() negate() dot(Vector4d) scale(double) add(Vector4d) add(double×4) sub(Vector4d) sub(double×4) |
| 转换 | toVector4i() toVector4i(Vector4i) toVector4f() toVector4f(Vector4f) |
| 对象契约 | clone() equals(Object) equals(Vector4d) equals(Vector4d, double) toString() |
[!NOTE]
Vector3*/Vector4*不重复声明length()、normalize()、getX/setX/pow2等——它们直接从父类继承并使用this.x/this.y,父类的运算方法则被子类按分量数重载覆盖(add、sub、dot、negate、scale、lengthSquared等)。
使用示例
// 新建 + 链式运算(注意全部原地修改)
Vector3f dir = new Vector3f(3.0f, 0.0f, 4.0f); // 长度 5
dir.normalize(); // → (0.6, 0.0, 0.8)
// 复用向量,零分配
Vector3i block = new Vector3i();
block.set(entity.posX, entity.posY, entity.posZ); // 由调用方完成 floor
// 整数向量求方向
Vector3i step = new Vector3i(1, 0, 0);
step.normalize(); // → (0, 0, 0)(1.0 截断为 0)
相关条目
- 实体辅助 - 本库唯一的本 mod 内部使用方