I have this idea in my head and I am trying to figure out how to implement it. One of the parts that I am struggling with is how to take a 3D rigid-body transform and decompose it into dx, dy, dz, theta_X, theta_Y, and theta_Z.
This of course is a very well document algorithm. My problem is that matrix algebra is noncommutative. I would like to reorder the components such that it goes (dx*dy*theta_Z)*(dz*theta_X*theta_Y).
For any of you who wants to know why I want to do this is because I would like to do apply the transform (dx*dy*theta_Z) on a 3D image followed by then another operation followed by the completion of the rigid body transform. Does anyone know how to do this?
If I get it right you want to isolate XY plane transform separately from a 3D transform that is possible only if the theta_Z rotation is applied first (as you want it to be first). If not then you would need to convert your order of Euler angles first for example with this:
Is there a way to calculate 3D rotation on X and Y axis from a 4x4 matrix
If you do not know the translations you can obtain them directly from matrix see:
Understanding 4x4 homogenous transform matrices
now its just a matter of using the translations in corect coordinate system (depends on order of your transformations)
As you did not provide any specific data nor MCVE I can not go in more details as there are quite a few combinations of possible solutions.
If you first decompose your rotation into your desired ordering (theta_Z * theta_X * theta_Y), it is reasonably straightforward to reorder any translation the way you want:
let: t' = theta_Z^-1 * t * theta_Z
then: t * theta_Z = theta_Z * t'
and: t * theta_Z * theta_X * theta_Y
= theta_Z * t' * theta_X * theta_Y
However, for the particular reordering you want, please note that rotation about the Z axis should not affect a pure translation about the Z axis at all! Even though general rigid body transforms don't commute, your dz and theta_Z transforms do:
commutative: dz * theta_Z = theta_Z * dz
and: my_transform = dx * dy * dz * theta_Z * theta_X * theta_Y
= dx * dy * theta_Z * dz * theta_X * theta_Y
Related
This question was migrated from Stack Overflow because it can be answered on Mathematics Stack Exchange.
Migrated 24 days ago.
I have a position vector and a normal vector that describes a plane. The plane is always orthogonal to the position vector. On this plane is a circle with its center at the position vector. How do I generate a random point on that circle with a given radius r? I know that in 2d space, I can do
x = cos(2 * PI * random) * radius
y = sin(2 * PI * random) * radius
but... I don't know how to translate that to a circle on a plane.
I tried to find a way to use the position vector and normal vector to generate points, but I just can't think of a correct way to do so. I might not be familiar enough with planes.
At first we need two base vectors in the circle plane.
The first one is arbitrary vector orthogonal to normal n:
Choose component of normal with the largest magnitude, then component with the second magnitude.
Exchange their values, negate the largest, and make the third component zero (note that dot product of result with normal is zero, so they are othogonal)
For example, if n.y is the largest and n.z is the second, make
v = (0, n.z, -n.y)
Then calculate the second base vector using vector product
u = n x v
Normalize vectors v and u (make unit magnitude).
Now we can generate a random point on circumference using center point c (your position, I think):
rho = 2 * PI * random
f.x = c.x + radius * v.x * cos(rho) + radius * u.x * sin(rho)
f.y = c.y + radius * v.y * cos(rho) + radius * u.y * sin(rho)
f.z = c.z + radius * v.z * cos(rho) + radius * u.z * sin(rho)
could you please help me with this vector math problem?
I have a game actor Camera_Rail that has one spline. Every point on the spline has an Up vector and Right vector, creating a perpendicular plane. Together, the spline and X,Y bounds describe a boxy noodle in space.
I would like a function: ClampPointWithinBounds(Spline, X, Y, ProposedPoint) returns ClampedPoint
This is my plan, but there are some ??? :
Finds the closest SplinePoint to ProposedPoint (done)
Converts ProposedPoint to ProposedPoint2D with SplinePoint at 0,0 (???)
Clamps ProposedPoint2d to X,Y bounds (done)
Convert ClampedPoint2d to ClampedPoint in 3d and return. (???)
Alternatively, I could compute a ClampingVector directly in 3d space, but I don't have a plan for that.
How can I convert from 3d<->2d and back, and is there a better way? I'm using UE4.
Thank you!
"Finds the closest SplinePoint to ProposedPoint (done)."
We will call these Vector3's SP and PP respectively.
A circular/spherical bounds of radius R is easiest:
P = (SP - PP).Normalize() * R; or expanded:
L = Sqrt((SP.X - PP.X) * (SP.X - PP.X) + (SP.Y - PP.Y) * (SP.Y - PP.Y) + (SP.Z - PP.Z) * (SP.Z - PP.Z));
P = ((SP.X - PP.X)/L,(SP.Y - PP.Y)/L,(SP.Z - PP.Z)/L) * R;
For clamped bounds having extents, 1/2 of box size, of (X1,Y1,Z1), use R = X1 * X1 + Y1 * Y1 + Z1 * Z1, the furthest distance possible.
The final clamped result = (Min(Abs(P.X),X1) * Sign(P.X), Min(Abs(P.Y),Y1) * Sign(P.Y), A.Z = Min(Abs(P.Z),Z1) * Sign(P.Z))
For 2D, I would consider using Trig functions:
P = (SP - PP);// ignoring Z
Ang = ATan2(P.Y, P.X);
X = X1 * Cos(Ang);
Y = Y1 * Sin(Ang);
The overhead of the trig functions is not worth extending into 3D. As a single Sqrt() call is usually quicker than the multiple trig calls required in 3D.
I have two vectors and I want to get the angle between those vectors, I am currently doing it with this formula :
acos(dot(v1.unitVector, v2.unitVector))
Here is what I get with it :
I would want the green angle rather than the red angle, but I don't know what formula I should use...
Thank you.
EDIT : So, hen the vectors are still in a certain position (like the first two pairs of vectors, it's ok, but whenever it is in a configuration like in the third pair, it doesn't give me the right angle anymore)
With the dot product you get always an angle that is independent of the order of the vectors and the smaller of the two possibilities.
For what you want, you need the argument function of complex numbers that is realized by the atan2 function. The angle from a=ax+i*ay to b=bx+i*by is the argument of the conjugate of a times b (rotating b backwards by the angle of a, scale not considered), which in coordinates is
(ax-i*ay) * (bx+i*by) = ax*bx+ay*by + i*(ax*by-ay*bx)
so the angle is
atan2( ax*by-ay*bx, ax*bx+ay*by ).
Adding to the accepted answer, the problem with atan2 is that, if you imagine vector a being static and vector b rotating in anti-clockwise direction, you will see the return value ranging from 0 to π, but then it suddenly turns negative and proceeds from -π to 0, which is not exactly good if you're interested in an angle increasing from 0 to 2π.
To tackle that problem, the function below conveniently maps the result from atan2 and returns a value between 0 and 2π as one would expect:
const TAU = Math.PI * 2;
/**
* Gives the angle in radians from vector a to vector b in anticlockwise direction,
* ranging from 0 to 2π.
*
* #param {Vector} a
* #param {Vector} b
* #returns {Number}
*/
static angle(a, b) {
let angle = Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y);
if (angle < 0) {
angle += TAU;
}
return angle;
}
It is written in JavaScript, but it's easily portable to other languages.
Lutz already answered this correctly but let me add that I highly recommend basing modern vector math code on Geometric Algebra which raises the abstraction level dramatically.
Using GA, you can simply multiply the two vectors U and V to get a rotor. The rotor internally looks like A + Bxy where A = U dot V = |U|V|cos(angle) and Bxy = U wedge V = |U||V|sin(angle)xy (this is isomorphic to the complex numbers). Then you can return the rotor's signed CCW angle which is atan2( B, A ).
So with operator overloading, you can just type (u * v).Angle. The final calculations end up the same, but the abstraction level you think and work in is much higher.
Maybe this one is more fit:
atan2( ax*by-ay*bx, ax*bx+ay*by ) % (PI*2)
the calculation which could get the full anti-clockwise radian.
I'm trying to project a vector from said vertex to unknown vertex at the end of
that vector.
The knowns: Length of vector, starting vertex coordinates, angles (yaw,roll,pitch).
Unknowns: Terminating vertex coordinates at end of vector.
In 2D I can accomplish it in this manner:
Target.X = Source.X + (sin(Facing*DEG2RAD)*Distance);
Target.Y = Source.Y - (cos(Facing*DEG2RAD)*Distance);
Matrices seem to be overkill. I have something working feebly for 3D, but it's inaccurate which makes me believe I do not have all of the appropriate elements of the overall formula.
Target.Z = Source.Z - (sin(Pitch*DEG2RAD)*Distance);
Ref: Facing/Pitch are in degrees (multiplied by DEG2RAD which is pi/180).
Any/all help is appreciated. Thanks.
You have to correct the x and y coordinates (project them back onto the x/y plane):
Target.X = Source.X + Distance * cos(Pitch * DEG2RAD) * sin(Facing * DEG2RAD);
Target.Y = Source.Y - Distance * cos(Pitch * DEG2RAD) * cos(Facing * DEG2RAD);
Target.Z = Source.Z - Distance * sin(Pitch * DEG2RAD);
I was in need of a little math help that I can't seem to find the answer to, any links to documentation would be greatly appreciated.
Heres my situation, I have no idea where I am in this maze, but I need to move around and find my way back to the start. I was thinking of implementing a waypoint list of places i've been offset from my start at 0,0. This is a 2D cartesian plane.
I've been given 2 properties, my translation speed from 0-1 and my rotation speed from -1 to 1. -1 is very left and +1 is very right. These are speed and not angles so thats where my problem lies. If I'm given 0 as a translation speed and 0.2 I will continually turn to my right at a slow speed.
How do I figure out the offsets given these 2 variables? I can store it every time I take a 'step'.
I just need to figure out the offsets in x and y terms given the translations and rotation speeds. And the rotation to get to those points.
Any help is appreciated.
Your question is unclear on a couple of points, so I have to make some assumptions:
During each time interval, translation speed and rotational velocity are constant.
You know the values of these variables in every time interval (and you know rotational velocity in usable units, like radians per second, not just "very left").
You know initial heading.
You can maintain enough precision that roundoff error is not a problem.
Given that, there is an exact solution. First the easy part:
delta_angle = omega * delta_t
Where omega is the angular velocity. The distance traveled (maybe along a curve) is
dist = speed * delta_t
and the radius of the curve is
radius = dist / delta_angle
(This gets huge when angular velocity is near zero-- we'll deal with that in a moment.) If angle (at the beginning of the interval) is zero, defined as pointing in the +x direction, then the translation in the interval is easy, and we'll call it deta_x_0 and delta_y_0:
delta_x_0 = radius * sin(delta_angle)
delta_y_0 = radius * (1 - cos(delta_angle))
Since we want to be able to deal with very small delta_angle and very large radius, we'll expand sin and cos, and use this only when angular velocity is close to zero:
dx0 = r * sin(da) = (dist/da) * [ da - da^3/3! + da^5/5! - ...]
= dist * [ 1 - da^2/3! + da^4/5! - ...]
dy0 = r * (1-cos(da)) = (dist/da) * [ da^2/2! - da^4/4! + da^6/6! - ...]
= dist * [ da/2! - da^3/4! + da^5/6! - ...]
But angle generally isn't equal to zero, so we have to rotate these displacements:
dx = cos(angle) * dx0 - sin(angle) * dy0
dy = sin(angle) * dx0 - cos(angle) * dy0
You could do it in two stages. First work out the change of direction to get a new direction vector and then secondly work out the new position using this new direction. Something like
angle = angle + omega * delta_t;
const double d_x = cos( angle );
const double d_y = sin( angle );
x = x + d_x * delta_t * v;
y = y + d_y * delta_t * v;
where you store your current angle out at each step. ( d_x, d_y ) is the current direction vector and omega is the rotation speed that you have. delta_t is obviously your timestep and v is your speed.
This may be too naive to split it up into two distinct stages. I'm not sure I haven't really thought it through too much and haven't tested it but if it works let me know!