Getting direction vectors from 3d position and/or rotation - math

I have a camera, in which, I've obtained its 3d position and its 3d rotation (in degrees). The coordinate system is as follows:
The order is XYZ and is intrinsic.
pitch
roll
yaw
(aka right/front/top vector)
With this information, how can I calculate the Up and Front vectors?

Yaw rotation is about OY (vertical) axis and has matrix MY (for CCW positive)
Cos(Yaw) -Sin(Yaw) 0
Sin(Yaw) Cos(Yaw) 0
0 0 1
Pitch rotation is about OZ axis and has matrix MP
Cos(Pitch) 0 Sin(Pitch)
0 1 0
-Sin(Pitch) 0 Cos(Yaw)
Roll rotation is about OX axis and has matrix MR
1 0 0
0 Cos(Roll) -Sin(Roll)
0 Sin(Roll) Cos(Roll)
Now one has to multiply matrices MP, MR, MY in right order and get matrix M.
To find forward direction vector - multiply M and vector [1, 0, 0]. To get top direction vector - multiply M and vector [0, 1, 0]. To get side direction vector - multiply M and vector [1, 0, 0].
I cannot check right matrix multiplication order and the last result now. If you have any symbolic math software like Maple, Matlab - try it.
Result should look like this for forward
X = Cos(Pitch) * Cos(Yaw)
Y = Sin(Pitch)
Z = Cos(Pitch) * Sin(Yaw)
and up (perhaps wrong)
X = -Cos(Yaw) * Sin(Roll) - Sin(Yaw) * Sin(Pitch) * Cos(Roll)
Y = Sin(Yaw) * Sin(Roll) - Cos(Yaw) * Sin(Pitch) * Cos(Roll)
Z = Cos(Pitch) * Cos(Roll)

Related

Map angles to a 0-1 range

Let's say you have two angles, and you label them 0 and 1. Then you have another angle x. You also know if you'll be going Clockwise or Counter Clockwise to get from angle 0 to angle 1. How do you calculate a number that can describe that third angle?
Examples:
Angle at 0
Angle at 1
Rotation Direction
Target Angle
Mapped number (x)
0°
90°
CCW
60°
2/3
90°
0°
CW
60°
1/3
0°
180°
CW
90°
1.5
0°
180°
CCW
90°
0.5
Problems I'm having:
When x can't be supported within 0 and 1 (I am fine with it just telling me it couldn't do it, but having the number would be cooler).
When switching from Counter-Clock-Wise (CCW) to CW.
Check the next approach:
def ratio(x, a, b, dircw = False):
if dircw:
if x > a:
x -= 360
if b > a:
b -= 360
else:
if b < a:
b += 360
if x < a:
x += 360
return (x-a)/(b-a)
print(ratio(60, 0, 90))
print(ratio(60, 0, 90, True))
print(ratio(60, 90, 0, True))
print(ratio(90, 0, 180, True))
print(ratio(90, 0, 180))
0.6666666666666666
1.1111111111111112
0.3333333333333333
1.5
0.5
We consider solution of linear equation (solve inverse of linear interpolation)
x = a*(1-t) + b*t
for unknown t.
We have to make normalization to provide b after a in cyclic manner in both directions - so b+- correction.
To get only positive results, we normalize also x.

Quaternion to matrix rotation only one axis

I have a quaternion that contains the rotation of the three axes (x, y, z) at the same time.
I want to convert this quaternion to a rotation matrix but only the rotation on the Y axis of the quaternion or of any of the other axes, without all three at the same time.
A possible route:
Transform unit vectors X=(1,0,0) and Z=(0,0,1) by the quaternion
Call these rotated vectors (x0,x1,x2) and (z0,z1,z2)
If the rotation would have been purely around Y, we would have:
(x0,x1,x2) = (cos(theta), 0, sin(theta))
(z0,z1,z2) = (-sin(theta), 0, cos(theta))
not used is (y0,y1,y2) = (0, 1, 0)
so, calculate
c = (x0+z2) / 2
and s = (x2-z0) / 2
then normalize to get c2 + s2 equal to 1
norm = sqrt(c * c + s * s)
if norm != 0:
c = c / norm
s = s / norm
(if the norm would be zero, there is not much we can do)
the angle would be atan2(c, s)
the rotation matrix would be [[c,0,-s],[0,1,0],[s,0,c]]

Wrong graph when trying to rotate coordinates

Consider the following toy data:
clear
input double x1 float y1
0 0
.0013440860215053765 .02503477
.0013440860215053765 .05006954
.005376344086021506 .0751043
.009408602150537635 .10013908
.01747311827956989 .12482615
.03225806451612903 .1498609
.056451612903225805 .1748957
.07661290322580645 .19993046
.09946236559139784 .22496523
.15725806451612903 .25
.2110215053763441 .2750348
.32661290322580644 .3000695
.3803763440860215 .3251043
.4986559139784946 .3497914
.603494623655914 .3748261
.706989247311828 .3998609
.7661290322580645 .4248957
.8064516129032258 .4499305
.885752688172043 .4749652
.9099462365591398 .5
1 .5250348
.9811827956989247 .5500696
.8870967741935484 .5751043
.7661290322580645 .5997913
.6599462365591398 .6248261
.5873655913978495 .6498609
.5282258064516129 .6748957
.40053763440860213 .6999304
.3279569892473118 .7249652
.2163978494623656 .75
.15053763440860216 .7750348
.09408602150537634 .8000696
.06586021505376344 .8247566
.04973118279569892 .8497913
.024193548387096774 .8748261
.025537634408602152 .8998609
.006720430107526882 .9248957
.002688172043010753 .9499304
.004032258064516129 .9749652
0 1
end
twoway scatter y1 x1
When I try to rotate the entire graph by say 20 degrees counter-clockwise:
local theta = 0.349066
generate x2 = (x1 * cos(`theta') ) - (y1 * sin(`theta') )
generate y2 = (x1 * sin(`theta') ) - (y1 * cos(`theta') )
The coordinates transform as follows:
clear
input float(x2 y2)
0 0
-.007299372 -.023065284
-.01586177 -.04659027
-.020635087 -.06873614
-.025408404 -.09088202
-.026273714 -.11132205
-.02094281 -.12979028
-.006770712 -.14504059
.0036123034 -.16167
.016521374 -.17738
.06226916 -.1811377
.10422786 -.1862745
.20428585 -.1702649
.24624455 -.1754017
.3489475 -.1581459
.4389013 -.14581393
.527592 -.13394167
.57460284 -.13723963
.6039312 -.1469735
.6698875 -.1433759
.6840596 -.1586262
.76012 -.151351
.7338752 -.18131188
.6369009 -.23701614
.51478493 -.3015878
.4064434 -.3614295
.3296775 -.4097785
.26554185 -.45353055
.13699183 -.52072746
.06022594 -.5690765
-.05316776 -.630757
-.12361852 -.6768075
-.1852281 -.7196401
-.22019514 -.7524921
-.24391386 -.7815335
-.2764738 -.8137929
-.28377315 -.8368582
-.3100179 -.8668191
-.3223694 -.8917232
-.3296688 -.9147884
-.3420203 -.9396926
end
twoway scatter y2 x2
What am I missing?
Note that I have also tried to center the values first around a specific point.
In addition, I would also like the solution to account for different axes scales and graph aspect ratio.
For example:
clear
input float y double x
-2013 .001
-1941 .0010053763440860215
-1869 .0010053763440860215
-1797 .0010215053763440861
-1725 .0010376344086021505
-1654 .0010698924731182796
-1582 .0011290322580645162
-1510 .0012258064516129032
-1438 .0013064516129032257
-1366 .0013978494623655914
-1294 .0016290322580645162
-1222 .0018440860215053765
-1150 .0023064516129032257
-1078 .0025215053763440864
-1007 .0029946236559139786
-935 .003413978494623656
-863 .003827956989247312
-791 .004064516129032258
-719 .004225806451612904
-647 .004543010752688172
-575 .004639784946236559
-503 .005
-431 .0049247311827956995
-359 .004548387096774194
-288 .004064516129032258
-216 .0036397849462365592
-144 .003349462365591398
-72 .0031129032258064514
0 .0026021505376344085
72 .002311827956989247
144 .0018655913978494624
216 .0016021505376344087
288 .0013763440860215053
359 .0012634408602150537
431 .0011989247311827958
503 .0010967741935483872
575 .0011021505376344087
647 .0010268817204301076
719 .001010752688172043
791 .0010161290322580644
863 .001
end
twoway scatter y x
The y-xis of this graph is 4 inches while the x-axis is 5.5 inches (aspect ratio of 1.375).
I have consulted a number of posts including the following:
Programmatically rotate shapes using coordinates
How to rotate coordinate system?
I hope what I am trying to do is clear but I will be happy to clarify further.
The formulas for rotation are the following:
generate x2 = (x1 * cos(`theta') ) - (y1 * sin(`theta') )
generate y2 = (x1 * sin(`theta') ) + (y1 * cos(`theta') )
These perform rotation about point (0,0).
To make rotation about specific center point (cx, cy), one can apply the next approach:
generate x2 = cx + ((x1 - cx) * cos(`theta') ) - ((y1 - cy) * sin(`theta') )
generate y2 = cy + ((x1 - cx) * sin(`theta') ) + ((y1 - cy) * cos(`theta') )
The above formulas represent affine transformation matrix. To account for axes scale you have to multiply result matrix by scaling matrix - it is very simple, just multiply x or y by coefficient according to axis/axis ratio.
But seems you want to rotate already stretched visual representation. Say your plot is stretched along OX in 5 times. In this case at first multiply internal data x-coordinates by 5, make rotation (note - scale rotation center too), then divide by 5.
For your first example the x-axis is ~1.5 times longer. So we can multiply x-column by 1.5, rotate by 20 degrees, and divide by 1.5. If axes preserve their length, we should see the same plot rotated by 20 degrees. However, data ranges have changed, and plot is resized! Angle is not 20 degrees exactly. This effect will be more evident on the second example with huge axes scale difference.
If ranges remain the same after rotation, I expect that described approach should give correct angles. It might be checked with simple pixel plotting, but I'm afraid this simulation won't reproduce behavior of your plotting system. With automatic axes ranges, exact angles are not possible.

Matrix.rotateM android API result in wrong rotating Matrix

I´m doing my own collada parser. When animating joints I have a list of ordered transformations to apply. When all them are applied, I get a matrix, the joint node matrix. I think is this way how it works.
The way this system works as far as I know is, in the first transformation, applying it to the identity matrix, and successively applying to the result matrix the next transformation until the last one.
Applying a translate transformation to a matrix looks to works ok, but when rotating it something strange is happening:
For example: the two first transformations are a translation and a rotation arround the z axis. This looks like this:
<translate> -0.6289 63.7555 0.008499979 </translate>
<rotate>0 0 1 -5.00881</rotate>
Using the Matrix.translateM and Matrix.rotateM android api functions I get this matrix:
storedMatrix =
0.9961813 0.0873089 0. - 0.6289
- 0.0873089 0.9961813 0. 63.7555
0. 0. 1. 0.0085000
0. 0. 0. 1.
Using SciLAB (it´s a free software to replace Matlab) I programmed a script to calculate a translate and a rotate matrix. This is the code I put into the script:
function [storedMatrix] = rotateStoredMat(x_axis,y_axis,z_axis,angle_amount)
// t is angle amount, x is x_axis, and...
// ESTA ES LA FÓRMULA (NO SACADA DE WIKIPEDIA PERO ALLI ESTA IGUAL) PARA MATRICES ORGANIZADAS POR COLUMNAS
// FROM WIKIPEDIA:
// x*x * (cos(t) - 1) + cos(t) x*y * (cos(t) - 1) + (z*sin(t)) x*z * (cos(t) - 1) - (y*sin(t))
// x*y * (cos(t) - 1) - z*sin(t) y*y * (cos(t) - 1) + cos(t) y*z * (cos(t) - 1) + (x*sin(t))
// x*z * (cos(t) - 1) + y*sin(t) y*z * (cos(t) - 1) - (x*sin(t)) z*z * (cos(t) - 1) + cos(t)
global storedMatrix;
xx = x_axis * x_axis;
xy = x_axis * y_axis;
xz = x_axis * z_axis;
yy = y_axis * y_axis;
yz = y_axis * z_axis;
zz = z_axis * z_axis;
cost = cos(angle_amount);
sint = sin(angle_amount);
mat = [
xx*(cost -1)+cost xy*(cost -1)+(z_axis*sint) xz*(cost -1)-(y_axis*sint) 0;
xy*(cost -1)-z_axis*sint yy*(cost -1)+cost yz*(cost -1)+(x_axis*sint) 0;
xz*(cost -1)+y_axis*sint yz*(cost -1)-(x_axis*sint) zz*(cost -1)+cost 0;
0 0 0 1;
];
storedMatrix = mat * storedMatrix;
endfunction
function [storedMatrix] = translateStoredMat(x,y,z)
global storedMatrix;
mat = [
1 0 0 x;
0 1 0 y;
0 0 1 z;
0 0 0 1;
];
storedMatrix = mat * storedMatrix;
endfunction
function [storedMatrix] = loadIdentity()
global storedMatrix;
mat = [
1 0 0 0;
0 1 0 0;
0 0 1 0;
0 0 0 1;
];
storedMatrix = mat;
endfunction
Using this "helper" script this is the matrix i get:
ans =
0.2920992 0.9563880 0. 60.791296
- 0.9563880 0.2920992 0. 19.224402
0. 0. - 0.4158016 - 0.0035343
0. 0. 0. 1.
So, is my scilab script wrong? Am I applying the rotateM function in the wrong way ?
All I can say is that the bones and the joints are drawn in wrong positions, so I supouse I´m not calculating the them fine and that my scilab is giving me the right matrix to use.
Can you help me? Do you need some information more to evaluate this and give an answer? Please feel free to ask.
There are a few reasons for the difference:
rotateM() takes an angle in degrees, while the script you wrote treats it as an angle in radians.
Your rotation matrix calculation does not match the formula I see on Wikipedia (http://en.wikipedia.org/wiki/Rotation_matrix). All the terms look somewhat different. For example, you use (cost - 1) everywhere the Wikipedia page has (1 - cost).
Your rotation matrix looks transposed compared to what rotateM() produces.
When you use the Matrix functions, you're multiplying the two matrices in the reverse order compared to what you do with your script.

Calculation of a perspective transformation matrix

Given a point in 3D space, how can I calculate a matrix in homogeneous coordinates which will project that point into the plane z == d, where the origin is the centre of projection.
OK, let's try to sort this out, expanding on Emmanuel's answer.
Assuming that your view vector is directly along the Z axis, all dimensions must be scaled by the ratio of the view plane distance d to the original z coordinate. That ratio is trivially d / z, giving:
x' = x * (d / z)
y' = y * (d / z)
z' = z * (d / z) ( = d)
In homogenous coordinates, it's usual to start with P = [x, y, z, w] where w == 1 and the transformation is done thus:
P' = M * P
The result will have w != 1, and to get the real 3D coordinates we normalise the homogenous vector by dividing the whole thing by its w component.
So, all we need is a matrix that given [x, y, z, 1] gives us [x * d, y * d, z * d, z], i.e.
| x' | = | d 0 0 0 | * | x |
| y' | = | 0 d 0 0 | * | y |
| z' | = | 0 0 d 0 | * | z |
| w' | = | 0 0 1 0 | * | 1 |
which once normalised (by dividing by w' == z) gives you:
[ x * d / z, y * d / z, d, 1 ]
per the first set of equations above
I guess the projection you mean, as Beta says, consists in the intersection between:
the line formed by the origin O(0, 0, 0) and the point P(a, b, c) to be transformed
and the plane z=d
If I'm right, then let's have a look at the equation of this line, given by the vectorial product OP ^ OM = 0 (let's remind that the equation of a line between 2 given points A and B is given by AB ^ AM = 0, with M(x, y, z); this is a vectorial product, so all are vectors: 0 represents the null vector, AB is the vector AB, etc):
bz - cy = 0
cx - az = 0
cz - bx = 0
With z = d, we then have only 2 linearily independent equations:
bd = cy
cx = ad
So this projection converts a point P(a, b, c) into a point P'(ad/c, bd/c, d). For homogeneous coordinates that gives:
P'(ad/c, bd/c, d) = P'(ad/c, bd/c, cd/c)
= P'(ad/c: bd/c: cd/c: 1)
= P'(a: b: c: d/c)
EDIT : the matrix I 1st found was:
1, 0, 0, 0
0, 1, 0, 0
A = 0, 0, 1, 0
0, 0, 0, d/c
but it uses c which is the a coordinate of the point P !! This is nonsense, I couldn't find an expression of A that does not use these coordinates. I may not be familiar enough with homogeneous coordinates.
the homogeneous transformation matrix is (Euler roll-pitch-yaw):
|r1 r2 r3 dx|
|r4 r5 r6 dy|
|r7 r8 r9 dz|
|px py pz sf|
r1-9 are the elements of the combined rotation matrix: Rx*Ry*Rz (work it out)
dx dy and dz are displacement vector (d) elements
px py and pz are the perspective vector (p) elements
sf is the scaling factor
from here on, if you use the inverse of this, you get your projection as a perspective in any arbitrary plane by feeding rotations of your target plane, as well as it's position of origin wrt the reference one in (keep perspective vector at 0 0 0 and sf=1 for pure kinematics), you get T->T* = T1. Get T1^-1 (for kinematics, this is simply R' (transposed,), horizontal concatenated by -R'*d, then vertical concatenated simply by 0 0 0 1).
can have multiple planes e.g. a,b,c as a chain, in which case T1 = Ta*Tb*Tc*...
then, v(new) = (T1^-1)*v(old), job done.

Resources