如何在 3D 中找到四边形的旋转?
我有 4 个向量的坐标定义了一个四边形,另一个向量的坐标是正常的。我正在尝试获得四边形的旋转。我仅使用法线在 X 和 Y 上旋转就得到了很好的结果,但我在获取 Z 时遇到了困难,因为我只使用了 1 个向量。
这是我使用 Processing 和 tokenlibs(Vec3D 和 标题方法):
import toxi.geom.*;
Vec3D[] face = {new Vec3D(1.1920928955078125e-07, 0.0, 1.4142135381698608),new Vec3D(-1.4142134189605713, 0.0, 5.3644180297851562e-07),new Vec3D(-2.384185791015625e-07, 0.0, -1.4142135381698608),new Vec3D(1.4142136573791504, 0.0, 0.0),};
Vec3D n = new Vec3D(0.0, 1.0, 0.0);
print("xy: " + degrees(n.headingXY())+"\t");
print("xz: " + degrees(n.headingXZ())+"\t");
print("yz: " + degrees(n.headingYZ())+"\n");
println("angleBetween x: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("angleBetween y: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("angleBetween z: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("atan2 x: " + degrees(atan2(n.z,n.y)));
println("atan2 y: " + degrees(atan2(n.z,n.x)));
println("atan2 z: " + degrees(atan2(n.y,n.x)));
这是输出:
xy: 90.0 xz: 0.0 yz: 90.0
angleBetween x: 90.0
angleBetween y: 90.0
angleBetween z: 90.0
atan2 x: 0.0
atan2 y: 0.0
atan2 z: 90.0
如何我可以获得四边形 Z 轴的旋转(围绕其中心/法线)吗?
I have coordinates for 4 vectors defining a quad and another one for it's normal. I am trying to get the rotation of the quad. I get good results for rotation on X and Y just using the normal, but I got stuck getting the Z, since I've used just 1 vector.
Here's my basic test using Processing and toxiclibs(Vec3D and heading methods):
import toxi.geom.*;
Vec3D[] face = {new Vec3D(1.1920928955078125e-07, 0.0, 1.4142135381698608),new Vec3D(-1.4142134189605713, 0.0, 5.3644180297851562e-07),new Vec3D(-2.384185791015625e-07, 0.0, -1.4142135381698608),new Vec3D(1.4142136573791504, 0.0, 0.0),};
Vec3D n = new Vec3D(0.0, 1.0, 0.0);
print("xy: " + degrees(n.headingXY())+"\t");
print("xz: " + degrees(n.headingXZ())+"\t");
print("yz: " + degrees(n.headingYZ())+"\n");
println("angleBetween x: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("angleBetween y: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("angleBetween z: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("atan2 x: " + degrees(atan2(n.z,n.y)));
println("atan2 y: " + degrees(atan2(n.z,n.x)));
println("atan2 z: " + degrees(atan2(n.y,n.x)));
And here is the output:
xy: 90.0 xz: 0.0 yz: 90.0
angleBetween x: 90.0
angleBetween y: 90.0
angleBetween z: 90.0
atan2 x: 0.0
atan2 y: 0.0
atan2 z: 90.0
How can I get the rotation(around it's centre/normal) for Z of my quad ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好的。坦率地说,我仍然不太清楚您在寻找什么,但让我尝试澄清问题,然后提出我对您真正想要什么的最佳猜测,看看是否有帮助。
正如评论线程中提到的,旋转是映射一组内容的转换(例如,向量A、B、 C...)到一组不同的内容(A'、B'、C'...)。我们可以用角度(称为 θ)和旋转轴(我们称为 R)来完全定义这种变换。
请注意,R 不是向量,而是一条线。这意味着它有一个位置和一个方向——它锚定在空间中的某个地方——所以你需要两个点或一个点和一个方向向量来定义它。为简单起见,我们可能假设锚点是原点 (0,0,0),因为问题讨论的是主轴 X、Y 和 Z。但是,一般情况下,情况不必如此 - 如果您想确定绕任意线的旋转,您通常需要首先平移所有内容,以便轴通过原点。 (如果您关心的是对象的方向,而不是其位置,那么您可能可以忽略这个问题。)
给定起始位置A,结束位置A' 和轴 R,从概念上来说,确定角度 θ(或一个角度 θ,因为旋转是周期性的,并且有无限多个 θ,将 A 带到 A'),尽管对于一般的 R 来说可能有点繁琐。 最简单的情况下,其中 R 是主轴之一,您可以执行以下操作(对于 R = Z):
在 在这种情况下,从您的代码看来,您似乎已经拥有执行此操作的工具 - 我不熟悉 有毒库,但我会想象
Vec3D
angleBetween
方法应该能够带您大部分到达您想要的答案。然而,这前提是你知道 A、A' 和 R,而且这似乎是你问题的真正症结所在。首先,您只提到一组点,定义了任意四边形。在第二部分中,您将法线视为定义旋转中心。这两者都表明您没有正确指定问题。
正如我多次重复的那样,轮换是从一件事到另一件事。一组四边形顶点可以定义第一个状态或第二个状态,但不能同时定义两者(除非 θ 为 0,在这种情况下问题很简单)。如果你想确定“四边形的旋转”,你还需要说“从较早的位置P”或“到随后的位置Q”,但你还没有这样做。
鉴于所讨论的特定四边形是一个正方形,您可能会认为涉及到一个直观的其他位置,即:边轴对齐。我们确实可以相当容易地确定到达该方向所需的旋转角度,如果我们可以假设四边形是一个矩形:
但是,你指出了指出您可能正在查看任何任意四边形,其中没有“自然”基本位置可供比较。即使在方形的情况下,坦率地说,在没有明确声明的情况下假设基线也不是一个好的做法。
这让我们回到了我最初的问题:你的意思是什么?如果你真的能正确地确定这一点,我怀疑你会发现问题本身相对容易解决。
编辑:根据您下面的评论,您真正想要做的是找到一种旋转,使您的四边形与主要平面之一对齐。这相当于旋转四边形的法线以与垂直于该平面的轴对齐:例如,要使四边形平行于 XY 平面,请将其法线与 Z 轴对齐。
理论上,这可以通过绕某个计算轴进行一次旋转来完成,但实际上,您会将其分解为绕主轴的两次旋转。第一个绕目标轴旋转,直到矢量位于包含该轴和其他轴之一的平面内;然后绕第三个轴旋转以获得最终对齐的法线。口头描述不可避免地很笨拙,所以让我们形式化一下:
假设您有一个平面对象 Q,其顶点为 {v1、v2, v3, ...}(在您的四边形情况下,将有四个,但只要所有点共面,它可以是任何数字),单位为法线 n = (xyz)T。为了便于解释,我们任意假设我们想要将对象与 XY 平面对齐,从而将 n 旋转到 Z 轴 - 对于 XZ/Y,该过程本质上是相同的或 YZ/X。
绕 Z 旋转以使 n 进入 XZ 平面。我们可以这样计算所需的角度:
但是,我们只需要正弦和余弦来构建旋转矩阵,并且我们可以在不知道角度的情况下直接计算它们:(
显然,如果
hypoXY
为 0 这失败,但在这种情况下 n 已经与 Z 对齐。)我们的第一个旋转矩阵 R1 如下所示:
接下来,围绕 Y 旋转以获得 n2 + y2),因此我们需要考虑在计算第二个角度时:
同样,我们实际上并不需要 theta2。因为我们将 n 定义为单位向量,所以接下来的计算很简单:
我们的第二个旋转矩阵 R2 如下所示:
将两者组合在一起得到 R = R2.R1:
如果将此矩阵应用于 n,您应该得到与 Z 轴对齐的法线。 (如果没有,请先检查标志 - 这有点信封背面,我很容易弄错一些方向。我没有时间将其编码并检查现在,但稍后我也会尝试查看您的草图代码。)
一旦成功,请将相同的转换应用于对象中的所有点Q并且它应该平行于(尽管可能偏离)XY 平面。
OK. I am frankly still not really clear on what it is you're looking for, but let me try to clarify the problem and then address my best guess as to what you really want and see if that helps.
As mentioned in the comment thread, a rotation is a transformation that maps one set of stuff (eg, vectors A, B, C...) to a different set of stuff (A', B', C'...). We can fully define this transformation in terms of an angle (call it θ) and an axis of rotation we'll call R.
Note that R is not a vector, it is a line. That means it has a location as well as a direction -- it is anchored somewhere in space -- and so you need either two points or a point and a direction vector to define it. For simplicity we might assume that the anchor point is the origin (0,0,0), since the question talks about the major axes X, Y and Z. In general, however, this need not be the case - if you want to determine rotation about arbitrary lines you will usually need to translate everything first so that the axis passes through the origin. (If all you care about is the orientation of your objects, rather than its position, then you can probably gloss over this issue.)
Given a start position A, end position A' and an axis R, it is conceptually straightforward to determine the angle θ (or an angle θ, since rotation is periodic and there are infinitely many θs that will take A to A'), though it can be a little fiddly for general R. In the simplest case, where R is one of the major axes, you can do something like this (for R = Z):
In any case, it looks from your code as if you have the tools to do this already -- I'm not familiar with toxiclibs, but I would imagine the
Vec3D
angleBetween
method ought to take you most of the way to the answer you want.However, that presupposes that you know A, A' and R, and it seems like this is the real sticking point with your question. In the first place, you mention only a single set of points, defining an arbitrary quad. In the second, you talk about the normal as defining the centre of rotation. Both of these indicate that you haven't properly specified the problem.
As I have repeated tediously several times, a rotation is from one thing to another. A single set of quad vertices may define either the first state or the second, but not both (unless θ is 0, in which case the question is trivial). If you want to determine "the rotation of the quad", you need also to say "from an earlier position P" or "to a subsequent position Q", which you have not done.
Given that the particular quad in question is a square, you might think that there's an intuitive other position involved, to wit: with the sides axis-aligned. And we can indeed rather easily determine the angle of rotation required to get to that orientation, if we can assume that the quad is a rectangle:
But, you made a point of stating that you might be looking at any arbitrary quad, for which there would be no "natural" base position to compare against. And even in the square case it is frankly not good practice to presume a baseline without explicitly declaring it.
Which brings us back to my original question: what do you mean? If you can actually pin that down properly I suspect you will find the problem itself relatively easy to solve.
EDIT: Based on your comments below, what you really want to do is to find a rotation that aligns your quad with one of the major planes. This is equivalent to rotating the quad's normal to align with the axis perpendicular to that plane: eg, to get the quad parallel to the XY plane, align its normal with the Z axis.
This can notionally be done with a single rotation about some calculated axis, but in practice you will decompose it into two rotations about major axes. The first rotates about the target axis until the vector is in the plane containing that axis and one of the others; then rotate around the third axis to get the normal to its final alignment. A verbal description is inevitably clunky, so let's formalise a bit:
Let's say you have a planar object Q, with vertices {v1, v2, v3, ...} (in your quad case there will be four of these, but it could be any number as long as all the points are coplanar), with unit normal n = (x y z)T. For the sake of explanation, let's arbitrarily assume that we want to align the object with the XY plane, and hence to rotate n to the Z axis -- the process would be essentially the same for XZ/Y or YZ/X.
Rotate around Z to get n into the XZ plane. We can calculate the angle required like this:
However, we only need the sine and cosine to build a rotation matrix, and we can calculate these directly without knowing the angle:
(Obviously, if
hypoXY
is 0 this fails, but in that case n is already aligned with Z.)Our first rotation matrix R1 looks like this:
Next, rotate around Y to get n parallel to Z. Note that the previous rotation has moved x to a new position x' = sqrt(x2 + y2), so we need to account for this in calculating our second angle:
Again, we don't actually need theta2. And because we defined n to be a unit vector, our next calculations are easy:
Our second rotation matrix R2 looks like this:
Compose the two together to get R = R2.R1:
If you apply this matrix to n, you should get the normal aligned with the Z axis. (If not, check the signs first -- this is all a bit back of an envelope and I could easily have got some of the directions wrong. I don't have time to code it up and check right now, but will try to give it a go later. I'll also try to look over your sketch code then.)
Once that works, apply the same transformation to all the points in your object Q and it should become parallel to (although likely offset from) the XY plane.
这是 z 轴的旋转矩阵
cos(theta) sin(theta) 0
-sin(theta) cos(theta) 0
0 0 1
结果是旋转向量
Here is the rotation matrix for the z axis
cos(theta) sin(theta) 0
-sin(theta) cos(theta) 0
0 0 1
the result is the rotated vector