I've run into an interesting piece of legacy code that I'm having trouble understanding.
We perform two rotations using euler matrices and then multiply by the original vector to determine the new position of a point (x,y). No problem.
However, the next line of code takes the dot product of the rotation matrix 2nd row with the vector to determine which side of the plane the point is on. For clarity, the rotation matrix is the product of a rotation around the x axis then around the y axis, a “combo” matrix.
I'm aware of how to do this using the dot product of a plane and a vector, but I can find no references about why using the 2nd row of a euler matrix works -- and it does work!
Thank you
Consider a basic rotation:
[p0] [R00 R01 R02] [q0]
[p1] = [R10 R11 R12] [q1]
[p2] [R20 R21 R22] [q2]
The "y" component of p (p1) is just the dot product between the 2nd row of R with q. If positive, it's on one side of the x-z plane, and if negative, it's on the other. If it's zero, it sitting right on top of the plane. (Recall that the x-z plane contain all of the points where y is 0.)
Related
I am not sure if a question like this was asked before but i searched and didn't found what i am looking for.
I know how to determine if a point is to the left or right of a 2D line. but suppose we have a vector in 3D. of course a 3D vector passes through infinite planes, but suppose we chose one plane of them in which we are interested, and we have a specific point on this plane which we want to know if it lies to the left or right or on our vector (with respect to the chosen plane). how to do this ?
You should explicitly define orientation of that plane - for example, define main (forward) normal N - like OZ axis is normal for OXY plane.
If you have A,B,C triangle and claim that it is oriented counterclockwise, you can calculate forward plane normal as N = AB x BC
For points A, B, D in given plane calculate mixed product (vector product of AB and AD, then scalar product of result and N)
mp = (AB x AD) . dot. N
Sign of this value is positive, if vectors AB, AD, N form right-handed triplet and D lies left to AB direction
An intuitive solution is to define a coordinate system for the plane as follows. Let's normalize the 3d vector in your question and call the resulting unit vector v, and let x be a point on your plane, whose unit normal we will denote as n. You can now chose a coordinate system centered at x, that is made by the three 3*1 unit vectors v, n and b=v.crossProduct(n).
The idea is that if you express a point in this coordinate system, then if its b coordinate is negative, you can says that it is, say, on the left. So, if its b coordinate is positive, it will be on the right.
Obviously, if you have a point q expressed in this coordinates system, you can write its expression q_w in world coordinates using
q_w=R*q+x
where the rotation matrix R is the matrix whose columns are the unit axes of the plane coordinate system:
R=[v n b]
So, if you have a point Q in world coordinates, using the inverse of the relation above, you compute transpose(R)*(Q-x), and look at whether the b coordinate is positive or negative.
I'm doing something where I have a plane in a coord sys A with a set of points already on it. I also have a normal vector in space N. How can I rotate the points on coord sys A so that the underlying plane will have the same normal direction as N?
Wondering if any one has a good idea on how to do this. Thanks
If you have, or can easily compute, the normal vector to the plane that your points are currently in, I think the easiest way to do this will be to rotate around the axis common to the two planes. Here's how I'd go about it:
Let M be the vector normal to your current plane, and N be the vector normal to the plane you want to rotate into. If M == N you can stop now and leave the original points unchanged.
Calculate the rotation angle as
costheta = dot(M,N)/(norm(M)*norm(N))
Calculate the rotation axis as
axis = unitcross(M, N)
where unitcross is a function that performs the cross product and normalizes it to a unit vector, i.e. unitcross(a, b) = cross(a, b) / norm(cross(a, b)). As user1318499 pointed out in a comment, this step can cause an error if M == N, unless your implementation of unitcross returns (0,0,0) when a == b.
Compute the rotation matrix from the axis and angle as
c = costheta
s = sqrt(1-c*c)
C = 1-c
rmat = matrix([ x*x*C+c x*y*C-z*s x*z*C+y*s ],
[ y*x*C+z*s y*y*C+c y*z*C-x*s ]
[ z*x*C-y*s z*y*C+x*s z*z*C+c ])
where x, y, and z are the components of axis. This formula is described on Wikipedia.
For each point, compute its corresponding point on the new plane as
newpoint = dot(rmat, point)
where the function dot performs matrix multiplication.
This is not unique, of course; as mentioned in peterk's answer, there are an infinite number of possible rotations you could make that would transform the plane normal to M into the plane normal to N. This corresponds to the fact that, after you take the steps described above, you can then rotate the plane around N, and your points will be in different places while staying in the same plane. (In other words, each rotation you can make that satisfies your conditions corresponds to doing the procedure described above followed by another rotation around N.) But if you don't care where in the plane your points wind up, I think this rotation around the common axis is the simplest way to just get the points into the plane you want them in.
If you don't have M, but you do have the coordinates of the points in your starting plane relative to an origin in that plane, you can compute the starting normal vector from two points' positions x1 and x2 as
M = cross(x1, x2)
(you can also use unitcross here but it doesn't make any difference). If you have the points' coordinates relative to an origin that is not in the plane, you can still do it, but you'll need three points' positions:
M = cross(x3-x1, x3-x2)
A single vector (your normal - N) will not be enough. You will need another two vectors for the other two dimensions. (Imagine that your 3D space could still rotate/spin around the normal vector, and you need another 2 vectors to nail it down). Once you have the normal and another one on the plane, the 3rd one should be easy to find (left- or right-handed depending on your system).
Make sure all three are normalized (length of 1) and put them in a matrix; use that matrix to transform any point in your 3D space (use matrix multiplication). This should give you the new coordinates.
I'm thinking make a unit vector [0,0,1] and use the dot-product along two planes to find the angle of difference, and shift all your points by those angles. This is assuming you want the z-axis to align with the normal vector, else just use [1,0,0] or [0,1,0] for x and y respectively.
If I have two vector coordinates representing positions on the surface of the earth where the center of the earth is (0,0,0) and the Up vector is (0,0,1);
What is the best way to calculate a 3d plane that is running along the two vectors (the direction v2 - v1) but back by a set number of meters (just imagine a virtual clip plane that is behind the two vectors and running parallel to them).
well, you do the cross product of v1 and v2 to get the normal of your plane (don't forget to normalize if you want to), then the 4th element of your plane would just be 0 (because it crosses 0,0,0).
and then you want to project the plane in a certain direction based on the UP vector, not the plane's normal?
in that case I think you would just get the dot product of the normal and the up vector, then multiply the inverse of the dot (1/dot) by the number of units you want to project along the up vector and set that as your 4th element?
to clarify, that creates a plane where the two vectors, and the center of the earth are points on the plane, the plane can then be projected up or down by a certain amount in the UP direction.
Planes are usually described by a normal vector N, and as all points x,y,z fitting the equation Ax + By + Cz + D = 0. (A,B,C) is the normal vector. It doesn't even need to be normalized (unit length) if you choose D. Sounds like you want a plane to which v1 and v2 are parallel (and v2-v1 too). For that, make N perpendicular to v1 and v2 by setting it to the cross product of v2 x v1. Then pick a point in (x,y,z) coordinates that you know the plane should pass through. Plug N and (x,y,z) into the equation and compute D.
1- Find the Normal vector N = V1 X V2
2-Select a point that you want your plane tuch P0 ==>R0
3- All the other points(P==>R) in the plane follow N(R-R0)=0
See the link
I'm using CML to manage the 3D math in an OpenGL-based interface project I'm making for work. I need to know the width of the viewing frustum at a given distance from the eye point, which is kept as a part of a 4x4 matrix that represents the camera. My goal is to position gui objects along the apparent edge of the viewport, but at some distance into the screen from the near clipping plane.
CML has a function to extract the planes of the frustum, giving them back in Ax + By + Cz + D = 0 form. This frustum is perpendicular to the camera, which isn't necessarily aligned with the z axis of the perspective projection.
I'd like to extract x and z coordinates so as to pin graphical elements to the sides of the screen at different distances from the camera. What is the best way to go about doing it?
Thanks!
This seems to be a duplicate of Finding side length of a cross-section of a pyramid frustum/truncated pyramid, if you already have a cross-section of known width a known distance from the apex. If you don't have that and you want to derive the answer yourself you can follow these steps.
Take two adjacent planes and find
their line of intersection L1. You
can use the steps here. Really
what you need is the direction
vector of the line.
Take two more planes, one the same
as in the previous step, and find
their line of intersection L2.
Note that all planes of the form Ax + By + Cz + D = 0 go through the origin, so you know that L1 and L2
intersect.
Draw yourself a picture of the
direction vectors for L1 and L2,
tails at the origin. These form an
angle; call it theta. Find theta
using the formula for the angle
between two vectors, e.g. here.
Draw a bisector of that angle. Draw
a perpendicular to the bisector at
the distance d you want from the
origin (this creates an isosceles
triangle, bisected into two
congruent right triangles). The
length of the perpendicular is your
desired frustum width w. Note that w is
twice the length of one of the bases
of the right triangles.
Let r be the length of the
hypotenuses of the right triangles.
Then rcos(theta/2)=d and
rsin(theta/2)=w/2, so
tan(theta/2)=(w/2)/d which implies
w=2d*tan(theta/2). Since you know d
and theta, you are done.
Note that we have found the length of one side of a cross-section of a frustrum. This will work with any perpendicular cross-section of any frustum. This can be extended to adapt it to a non-perpendicular cross-section.
I want to calculate the angle between two vectors a and b. Lets assume these are at the origin. This can be done with
theta = arccos(a . b / |a| * |b|)
However arccos gives you the angle in [0, pi], i.e. it will never give you an angle greater than 180 degrees, which is what I want. So how do you find out when the vectors have gone past the 180 degree mark? In 2D I would simply let the sign of the y-component on one of the vectors determine what quadrant the vector is in. But what is the easiest way to do it in 3D?
EDIT: I wanted to keep the question general but here we go. I'm programming this in c and the code I use to get the angle is theta = acos(dot(a, b)/mag(a)*mag(b)) so how would you programmatically determine the orientation?
This works in 2D because you have a plane defined in which you define the rotation.
If you want to do this in 3D, there is no such implicit 2D plane. You could transform your 3D coordinates to a 2D plane going through all three points, and do your calculation inside this plane.
But, there are of course two possible orientations for the plane, and that will affect which angles will be > 180 or smaller.
I came up with the following solution that takes advantage of the direction change of the cross product of the two vectors:
Make a vector n = a X b and normalize it. This vector is normal to the plane spanned by a and b.
Whenever a new angle is calculated compare it with the old normal. In the comparison, treat the old and the current normals as points and compute the distance between them. If this distance is 2 the normal (i.e. the cross product a X b has flipped).
You might want to have a threshold for the distance as the distance after a flip might be shorter than 2, depending on how the vectors a and b are oriented and how often you update the angle.
One solution that you could use:
What you effectively need to do is create a plane that one of the vectors is coplanar to.
Getting the cross product of both vectors will create a plane, then is you get the normal of this plane, you can get the angle between this and the vector you need to get the signed angle for, and you can use the angle to determine the sign.
If the angle is greater than 90 degrees, then it is below the created plane; less than 90 degrees, and it is above.
Depending on cost of calculations, the dot product can be used at this stage instead of the angle.
Just make sure that you always calculate the normals by the same order of vectors.
This is useable more easily if you're using the XYZ axes, and that's what you're comparing against, since you already have the vectors needed for the plane.
There are possbly more efficient solutions, but this is one I came up with.
Edit: clarification of created vectors
a X b = p. This is perpendicular to both a and b.
Then, do either:
a X p or b X p to create another vector that is the normal to the plane created by the 2 vectors. Choice of vector depends on which you're trying to find the angle for.
Strictly speaking, two 3D vectors always have two angles between them - one below or equal to 180, the other over or equal to 180. Arccos gives you one of them, you can get the other by subtracting from 360. Think of it that way: imagine two lines intersect. You have 4 angles there - 2 of one value, 2 of another. What's the angle between the lines? No single answer. Same here. Without some kind of extra criteria, you can not, in theory, tell which of the two angle values should be taken into account.
EDIT: So what you really need is an arbitrary example of fixing an orientation. Here's one: we look from the positive Z direction. If the plane between the two vectors contains the Z axis, we look from the positive Y direction. If the plane is YZ, we look from the positive X direction. I'll think how to express this in coordinate form, then edit again.