开发者

How can I find the rotation of a quad in 3D?

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 开发者_JAVA百科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 ?


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):

theta0 = atan2(A.x, A.y);
theta1 = atan2(A_prime.x, A_prime.y);
theta = theta1 - theta0;

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:

// A and B are adjacent corners of the square
// B - A is the direction of the edge joining them
// theta is the angle between that side and the X axis
// (rotating by -theta around Z should align the square)
theta = atan2(B.x - A.x, B.y - A.y);

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:

theta1 = -atan2(x,y);

However, we only need the sine and cosine to build a rotation matrix, and we can calculate these directly without knowing the angle:

hypoXY = sqrt(x*x + y*y);
c1 = x/hypoXY;
s1 = y/hypoXY;

(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:

[  c1  s1  0 ]
[ -s1  c1  0 ]
[  0   0   1 ]

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:

theta2 = -atan2(z, sqrt(x*x + y*y));

Again, we don't actually need theta2. And because we defined n to be a unit vector, our next calculations are easy:

c2 = z;
s2 = hypoXY;

Our second rotation matrix R2 looks like this:

[ c2  0  -s2 ]
[ 0   1   0  ]
[ s2  0   c2 ]

Compose the two together to get R = R2.R1:

[  c2c1   c2s1  -s2  ]
[ -s1     c1     0   ]
[  s2c1   s2s1  c2   ]

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.


Here is the rotation matrix for the z axis

cos(theta) sin(theta) 0

-sin(theta) cos(theta) 0

0 0 1

  • your vector

the result is the rotated vector

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜