Java 从PVector获取XYZ旋转

Java 从PVector获取XYZ旋转,java,3d,angle,Java,3d,Angle,我有一个标准化的PVector,表示从原点开始的方向: PVector dir = new PVector(-0.1, 0.8, 0.3); 我想得到该方向上的X、Y和Z角,所以我可以使用rotateX()等矩阵变换 在2D中,我会使用atan2()获取角度,但我不知道如何对3D点进行此操作 我找到轴的角度的方法是使用点积。我的向量都叫做重力向量,主要是因为我在引力n体模拟中使用它。我的向量实现有一些方法,比如.magnity(),可以轻松返回向量的大小,这是您需要的 基本上是将向量X、Y和Z

我有一个标准化的
PVector
,表示从原点开始的方向:

PVector dir = new PVector(-0.1, 0.8, 0.3);
我想得到该方向上的X、Y和Z角,所以我可以使用
rotateX()
等矩阵变换


在2D中,我会使用
atan2()
获取角度,但我不知道如何对3D点进行此操作

我找到轴的角度的方法是使用点积。我的向量都叫做重力向量,主要是因为我在引力n体模拟中使用它。我的向量实现有一些方法,比如
.magnity()
,可以轻松返回向量的大小,这是您需要的

基本上是将向量X、Y和Z值相乘,然后将所有这些乘积相加。对于三维,可以这样明确地写:

public double dotProduct(GravVector vector) {
    return this.x * vector.x + this.y * vector.y + this.z * vector.z;
}
现在,点积有一个很好的特性,它等于两个向量的大小乘以这两个向量之间夹角的余弦。当改变方向时,会变成这样:

这意味着要找到角度,只需对右侧的值进行反余弦运算即可

我的代码在下面执行此操作,生成带有
angleX
angleY
angleZ
double
s。请注意,结果以弧度为单位。如果你想用度数来表示,你需要用弧度乘以
180/Math.PI

GravVector vector = new GravVector(1, 1, 0);

// magnitude * 1 because the magnitude of the temporary vector is 1.
double angleX = Math.acos(vector.dotProduct(new GravVector(1, 0, 0)) / (vector.magnitude() * 1));
double angleY = Math.acos(vector.dotProduct(new GravVector(0, 1, 0)) / (vector.magnitude() * 1));
double angleZ = Math.acos(vector.dotProduct(new GravVector(0, 0, 1)) / (vector.magnitude() * 1));

// in radians
System.out.println(String.format("x: %.2f, y: %.2f, z: %.2f",
        angleX, angleY, angleZ));

// in degrees
System.out.println(String.format("x: %.2f, y: %.2f, z: %.2f",
        angleX * 180 / Math.PI,
        angleY * 180 / Math.PI, 
        angleZ * 180 / Math.PI));
输出到控制台的输出为,第一行以弧度为单位,第二行以度为单位:

x: 0.79, y: 0.79, z: 1.57
x: 45.00, y: 45.00, z: 90.00
您可以很容易地将其推广到任意两个向量之间的角度(不管它们是否为单位大小),如下所示:


< > >编辑> 。考虑到任何一个轴,点积总是等同于相关组件。因此,对于X轴,它将只是X分量

这意味着您可以简化计算并使用如下方法:

public static double xAngle(GravVector vector) {
    return Math.acos(vector.x / (vector.magnitude()));
}

public static double yAngle(GravVector vector) {
    return Math.acos(vector.y / (vector.magnitude()));
}

public static double zAngle(GravVector vector) {
    return Math.acos(vector.z / (vector.magnitude()));
}
对于分量为[1,1,0]的示例向量,如果调用并打印这些方法中每种方法的值,将产生以下结果,这些结果与上述值一致:

x, rad: 0.7853981633974484
y, rad: 0.7853981633974484
z, rad: 1.5707963267948966

我找到轴的角度的方法是使用点积。我的向量都叫做重力向量,主要是因为我在引力n体模拟中使用它。我的向量实现有一些方法,比如
.magnity()
,可以轻松返回向量的大小,这是您需要的

基本上是将向量X、Y和Z值相乘,然后将所有这些乘积相加。对于三维,可以这样明确地写:

public double dotProduct(GravVector vector) {
    return this.x * vector.x + this.y * vector.y + this.z * vector.z;
}
现在,点积有一个很好的特性,它等于两个向量的大小乘以这两个向量之间夹角的余弦。当改变方向时,会变成这样:

这意味着要找到角度,只需对右侧的值进行反余弦运算即可

我的代码在下面执行此操作,生成带有
angleX
angleY
angleZ
double
s。请注意,结果以弧度为单位。如果你想用度数来表示,你需要用弧度乘以
180/Math.PI

GravVector vector = new GravVector(1, 1, 0);

// magnitude * 1 because the magnitude of the temporary vector is 1.
double angleX = Math.acos(vector.dotProduct(new GravVector(1, 0, 0)) / (vector.magnitude() * 1));
double angleY = Math.acos(vector.dotProduct(new GravVector(0, 1, 0)) / (vector.magnitude() * 1));
double angleZ = Math.acos(vector.dotProduct(new GravVector(0, 0, 1)) / (vector.magnitude() * 1));

// in radians
System.out.println(String.format("x: %.2f, y: %.2f, z: %.2f",
        angleX, angleY, angleZ));

// in degrees
System.out.println(String.format("x: %.2f, y: %.2f, z: %.2f",
        angleX * 180 / Math.PI,
        angleY * 180 / Math.PI, 
        angleZ * 180 / Math.PI));
输出到控制台的输出为,第一行以弧度为单位,第二行以度为单位:

x: 0.79, y: 0.79, z: 1.57
x: 45.00, y: 45.00, z: 90.00
您可以很容易地将其推广到任意两个向量之间的角度(不管它们是否为单位大小),如下所示:


< > >编辑> 。考虑到任何一个轴,点积总是等同于相关组件。因此,对于X轴,它将只是X分量

这意味着您可以简化计算并使用如下方法:

public static double xAngle(GravVector vector) {
    return Math.acos(vector.x / (vector.magnitude()));
}

public static double yAngle(GravVector vector) {
    return Math.acos(vector.y / (vector.magnitude()));
}

public static double zAngle(GravVector vector) {
    return Math.acos(vector.z / (vector.magnitude()));
}
对于分量为[1,1,0]的示例向量,如果调用并打印这些方法中每种方法的值,将产生以下结果,这些结果与上述值一致:

x, rad: 0.7853981633974484
y, rad: 0.7853981633974484
z, rad: 1.5707963267948966

不是100%确定我是否理解你所说的x,y,z角的意思,但我认为你的意思是,在“z角”的情况下,用你的话来说,旋转一个向量所需要的角度,原点是(0,0,0),终点是z是0,它沿着x或y轴(这是你的选择),将其绕Z轴旋转,以使生成的向量是原始向量在X,Y平面上的投影,顺便说一句,该投影仅为(X,Y,0)

围绕Z的角度将是y/x或(x/y)的反正切


对X轴和Y轴执行相同的操作,就得到了这三个旋转角度。你只需要其中的两个和一个初始向量,但我不知道这是否与问题有关。

我不100%确定我是否理解你所说的x,y,z角的意思,但我想你的意思是,在“z角”的情况下,用你的话来说,用原点(0,0,0)旋转向量所需要的角度最后,Z是0,它沿着X或Y轴(这是你的选择),绕Z轴旋转,得到的向量是原始向量在X,Y平面上的投影,顺便说一句,投影就是(X,Y,0)

围绕Z的角度将是y/x或(x/y)的反正切


对X轴和Y轴执行相同的操作,就得到了这三个旋转角度。你只需要其中的两个和一个初始向量,但我不知道这是否与问题有关。

我要补充一点,关于欧拉角和相关的东西有很多问题,但不确定这是否适用于获得XYZ角度?在向量和坐标之间使用点积axes@ifly6–你能发布一些代码作为答案吗?我的向量数学是。。。太糟糕了,我现在正在写这篇文章,我要补充一点,关于欧拉角和一些相关的问题,b