Java 两个三维矢量之间的角度
我有一系列要旋转的顶点(粉红色),以便顶点图案的一条边与三角形的边(白色)匹配 为此,我首先创建两个向量来表示边:floretAB和triangelab(绿色)。然后我找到两个顶点的叉积,得到一个轴,我可以围绕它旋转顶点(红色) 然后,我得到两个向量之间的角度,并用它与旋转轴一起创建一个四元数。最后,我围绕四元数旋转所有顶点 轮换前 _ 轮换应该产生什么结果 _ 但是,尽管顶点正确地围绕四元数旋转,但角度并不正确,如下图所示: 这是我用来得到两个向量之间的角度的代码。我不明白我做错了什么:Java 两个三维矢量之间的角度,java,math,vector,geometry,dot-product,Java,Math,Vector,Geometry,Dot Product,我有一系列要旋转的顶点(粉红色),以便顶点图案的一条边与三角形的边(白色)匹配 为此,我首先创建两个向量来表示边:floretAB和triangelab(绿色)。然后我找到两个顶点的叉积,得到一个轴,我可以围绕它旋转顶点(红色) 然后,我得到两个向量之间的角度,并用它与旋转轴一起创建一个四元数。最后,我围绕四元数旋转所有顶点 轮换前 _ 轮换应该产生什么结果 _ 但是,尽管顶点正确地围绕四元数旋转,但角度并不正确,如下图所示: 这是我用来得到两个向量之间的角度的代码。我不明白我做错了什么:
double[] cross = new double[3];
crossProduct(floretAB.mX, floretAB.mY, floretAB.mZ, triangleAB.mX, triangleAB.mY, triangleAB.mZ, cross);
double dot = dotProduct(floretAB.mX, floretAB.mY, floretAB.mZ, triangleAB.mX, triangleAB.mY, triangleAB.mZ);
double crossMag = Math.sqrt(cross[0]*cross[0] + cross[1]*cross[1] + cross[2]*cross[2]);
double angle = Math.atan2(crossMag, dot);
public static double dotProduct(double vector1X,double vector1Y,double vector1Z,double vector2X,double vector2Y,double vector2Z){
return vector1X*vector2X + vector1Y*vector2Y + vector1Z*vector2Z;
}
public static void crossProduct(double vector1X,double vector1Y,double vector1Z,double vector2X,double vector2Y,double vector2Z, double[] outputArray){
outputArray[0] = vector1Y*vector2Z - vector1Z*vector2Y;
outputArray[1] = vector1Z*vector2X - vector1X*vector2Z;
outputArray[2] = vector1X*vector2Y - vector1Y*vector2X;
}
如果您能帮上忙,我将不胜感激,因为这真的让我心烦
谢谢,詹姆斯
编辑:以下是代码的其余部分:
// get floret p1,p2 vector
// get triangle p1,p2 vector
Vector3D floretAB = new Vector3D(florets3D[0], florets3D[7]);
// get triangle p1,p2 vector
Vector3D triangleAB = new Vector3D(triangle[0], triangle[1]);
// get rotation axis (cross) and angle (dot)
/*
double[] cross = new double[3];
crossProduct(floretAB.mX, floretAB.mY, floretAB.mZ, triangleAB.mX, triangleAB.mY, triangleAB.mZ, cross);
double dotMag = floretAB.getMagnitude() * triangleAB.getMagnitude();
double dot = dotProduct(floretAB.mX, floretAB.mY, floretAB.mZ, triangleAB.mX, triangleAB.mY, triangleAB.mZ) / dotMag;
double angle = Math.acos(dot);
*/
double[] cross = new double[3];
crossProduct(floretAB.mX, floretAB.mY, floretAB.mZ, triangleAB.mX, triangleAB.mY, triangleAB.mZ, cross);
double dot = dotProduct(floretAB.mX, floretAB.mY, floretAB.mZ, triangleAB.mX, triangleAB.mY, triangleAB.mZ);
double crossMag = Math.sqrt(cross[0]*cross[0] + cross[1]*cross[1] + cross[2]*cross[2]);
double angle = Math.atan2(crossMag, dot);
// rotate floret so p1,p2 vector matches with triangle p1,p2 vector
double[] newVerts = new double[3];
Quaternion quat = new Quaternion(cross[0], cross[1], cross[2], angle);
for(int i = 0;i<numfloretVerts;i++){
Vertex3D vert = florets3D[i];
quat.RotateVector(vert.getmX(), vert.getmY(), vert.getmZ(), newVerts);
vert.setmX(newVerts[0]);
vert.setmY(newVerts[1]);
vert.setmZ(newVerts[2]);
}
_
我认为问题在于你用错误的方式评估角度。 如果我正确理解了你想要实现的目标,那么你需要两条绿线之间的角度。使用以下定义正确计算两条绿线之间的点积:
(a, b) = a1*b1 + a2*b2 + a3*b3.
但dot产品也可以这样评估:
(a, b) = |a|*|b|*cos(theta)
cos(theta) = (a1*b1 + a2*b2 + a3*b3) / (|a|*|b|)
所以你可以计算cos(θ)-两条绿线之间夹角的余弦-如下所示:
(a, b) = |a|*|b|*cos(theta)
cos(theta) = (a1*b1 + a2*b2 + a3*b3) / (|a|*|b|)
但我会使用另一种方法。首先,我将规范化这两个向量(即,将它们转换为)。您可以通过将每个向量的分量除以向量的长度(sqrt(x1*x1+y1*y1+z1*z1))来完成此操作,然后您将得到以下结果:
(aa, bb) = cos(theta)
其中aa为标准化a,bb为标准化b
我希望这有帮助。我想你的数学太复杂了 给定两个单位向量(你确实说过它们是归一化的),那么叉积的大小等于
sin(θ)
。不需要调用点积或atan2
在创建四元数之前,您可能还需要对叉积向量结果进行归一化-这取决于
新四元数(x,y,z,θ)的实现以及是否需要[x,y,z]
是否标准化。所述答案对于实数是正确的,但在使用浮点数计算时,可能会在某些角度附近失去准确性。对于角度接近零或PI的arcos(),以及接近PI/2和–PI/2的arcsin(),可能会丢失一半的有效数字。假设输入向量为单位长度,则在从零到π的整个范围内(包括零到π的整个范围内)更稳健且仅承受少量均匀舍入误差的方法为:
public double AngleBetween(Vector3D a, Vector3D b)
{
return 2.0d * Math.atan((a-b).Length/(a+b).Length);
}
注意,这给出了两个向量之间的无定向角度。关于这一点以及Kahan的参考资料,请访问:TryMath.atan2(dot,crossMag)代码>没有改变/解决问题:(实际上向量已经归一化。我尝试使用你的方法,但结果完全相同。这表明我的代码在其他地方有问题,但如果我手动将角度设置为Pi或Pi/2(即90或180度),它会正确地旋转amounts@JamesCoote:你的意思是如果你硬编码Pi或Pi/2,并且使用完全相同的代码,它将正确旋转?是的,这就是为什么我推断生成角度的代码一定有问题。我可能错了,所以我将把剩下的代码发布为well@James库特:是的,如果您发布代码的其余部分,它可能会很有用。我现在可以建议的另一件事是检查角度的测量单位。如果您的代码适用于硬编码值,这可能是一个问题。顺便说一句,您是以弧度还是以度进行硬编码?有时可能会出现这样的情况:在一个变量中,您有一个以度为单位的值,但在另一个变量中,您可能有一个以度为单位的值用弧度表示。如果在计算中同时使用它们,而不事先转换为相同的测量单位,则会得到错误的结果。数学很好。我需要在将其放入quaternion@JamesCoote这是一个幸运的猜测:)@user151496代码是c#和“d”告诉编译器常量2.0是双精度值。过度杀戮可能会加强表达式的执行精度。