Can i switch X Y Z in a quaternion? - matrix

i have a coordinate system where the Y axis is UP. I need to convert it to a coordinate system where Z is UP. I have the rotations stored in quaternions, so my question is : if i have a quaternion X,Y,Z can i switch the Y with the Z and get the result that Z is actually UP?

Just swpping two axes in a quaternions? No this doesn't work because this flips the chirality. However if you flip the chirality and negate the quaternion's real part then you're back in the original chirality. In general form you can write this as
Q'(Q, i'j'k') = εi'j'k' Qw_w + Qi_i + Qj_j + Qk_k
where
is the totally antisymmetric tensor, known as the Levi-Cevita symbol.
This shouldn't be a surprise, as the i², j², k² rules of quaternions are defined also by the same totally antisymmetric tensor.

I'm adapting my answer from this post since the one here was the older and likely more generic one.
It's probably best to consider this in the context of how you convert angle and axis to a quaternion. In Wikipedia you can read that you describe a rotation by an angle θ around an axis with unit direction vector (x,y,z) using
q = cos(θ/2) + sin(θ/2)(xi + yj + zk)
Your post only tells us Y ↦ Z, i.e. the old Y direction is the new Z direction. What about the other directions? You probably want to keep X ↦ X, but that still leaves us with two alternatives.
Either you use Z ↦ Y. In that case you change between left-handed and right-handed coordinate system, and the conversion is essentially a reflection.
Or you use Z ↦ −Y, then it's just a 90° rotation about the X axis. The handedness of the coordinate system remains the same.
Change of chirality
Considering the first case first. What does changing the coordinate system do to your angle and axis? Well, the axis coordinates experience the same coordinate swapping as your points, and the angle changes its sign. So you have
cos(−θ/2) + sin(−θ/2)(xi + zj + yk)
Compared to the above, the real part does not change (since cos(x)=cos(−x)) but the imaginary parts change their sign, in addition to the change in order. Generalizing from this, a quaternion a + bi + cj + dk describing a rotation in the old coordinate system would be turned into a − bi − dj − ck in the new coordinate system. Or into −a + bi + dj + ck which is a different description of the same rotation (since it changes θ by 360° but θ/2 by 180°).
Preserved chirality
Compared to this, the second case of Z ↦ −Y maintains the sign of θ, so you only have to adjust the axis. The new Z coordinate is the old Y coordinate, and the new Y coordinate is the negated old Z coordinate. So a + bi + cj + dk gets converted to a + bi − dj + ck (or its negative). Note that this is just a multiplication of the quaternion by i or −i, depending on which side you multiply it. If you want to write this as a conjugation, you have θ=±45° so you get square roots in the quaternion that expresses the change of coordinate system.

Try :
Quaternion rotation = new Quaternion(X,Z,Y, -W); //i had to swap Z and Y due to

No, you cannot exchange y and z -- it will turn into a Left-Handed Coordinate system, if it was Right-Handed (and vice-versa).
You can, however, do the following substitution:
newX = oldZ
newY = oldX
newZ = oldY
I suspect that what you really want is a simple rotation about the x axis. If that's why you want to switch y and z, then you should instead apply a rotation of -90 degrees about the +x axis (assuming you have a Right-Handed coordinate system).

Related

Why don't translate(${x},${y}) and translate(${-x},${-y}) cancel out?

This is a snippet from https://observablehq.com/#d3/non-contiguous-cartogram , which controls the transformation of the shape of states.
function transform(d, year) {
const [x, y] = path.centroid(d);
return `
translate(${x},${y})
scale(${Math.sqrt(data.get(d.id)[year])})
translate(${-x},${-y})
`;
}
Since x and y are constants, shouldn't translate(${x},${y}) and translate(${-x},${-y}) cancel out?
Further, why does this mechanism secure the centroid in its old position?
It is important to understand that SVG transformations are applied consecutively, i.e. order does matter. You cannot just add up numbers to consolidate a list of various transform definitions. In the words of the spec:
The value of the ‘transform’ attribute is a <transform-list>, which is defined as a list of transform definitions, which are applied in the order provided.
Each transform definition of that list manipulates the coordinate system that is the basis for all following transformations. Although, in your example, the translations are nominally of the same amount in opposing directions they do not cancel out because the scaling that happens in between changes the coordinate system along the way. Thus, the second translation does not cover the same distance as the first one.
To understand why those transformations keep the centroid in place it is helpful to write them down a bit more formally. Given the centroid's coodinates (xc, yc) and the scaling factor k we can write them as:
x ↦ xc + k (x − xc)
y ↦ yc + k (y − yc)
Every original point (x, y) is mapped to the centroid (first terms) and then moved outwards to its original position, yet it is only moved a scaled down portion of the original distance (second terms).
Plugging the centroid itself into these rules shows the second terms cancelling out which keeps the centroid in its original place whereby centering the whole transformation on the centroid:
xc ↦ xc + k (xc − xc) = xc
yc ↦ yc + k (yc − yc) = yc

Raycast Players Distance to Grid Intersection

I am programming a raycaster in JavaScript. I am having trouble finding or implementing an algorithm for the raycast. Currently I am trying out the cast in the following style.
Theres an grid with equal block width and height. My player has a position within the grid, a direction as an angle 0 - 360 degrees where hes looking at. In the first step I need to figure out the distace from my Player to the Green dot at the Grid Intersection. I know that the Green Point is at the Intersection therefore i can figure out the length of the red line. Theres an right angle at the intersection. When I ve calculated the distance or x and y position of the green dot I have to do a simular thing in the 2nd step. The distance of the orange line is known, the position of the green dot and the angle is known. Again the right angle is on the intersecting border line.
I am not even sure if its possible this way, but maybe you got any other idea how I should then work it out. Thank you very much.
(Apologies for formatting below; I'm tapping this out on a phone)
From trigonometry, cos(aplha) = (length of red line)/(length of hypotenuse).
Therefore: length of hypotenuse = (length of red line)/cos(alpha).
You'd use sin for a vertical intersection.
A word of caution though: if you think about what would happen when the player is looking directly at a wall, all the lengths should be the same so that it's a constant height on screen, but they'll actually be different because the diagonals are different. You need to multiply by cos of the relative angle between the player's direction and the casting direction (so, if you've a 60 degree field of view then 0 at the centre of the display, off to +30 at one end and down to -30 at the other).
Also don't fall into the common trap of thinking that the angles you cast at should be evenly spaced. Think again of a person looking directly at a wall and use atan to get the proper relative angles.
The parametric equations of the ray read
X = x + t cos α, Y = y + t sin α
with t>0.
Assuming a unit grid (but you can rescale), and the angle in the first quadrant, the first intersections with the grid are
X = ceiling(x) => t = (X - x) / cos α => Y = y + (X - x) . tan α
and
Y = ceiling(y) => t = (Y - y) / sin α => X = x + (Y - y) . cot α
The smallest of the two t will tell you which of the horizontal and vertical is met first.
The next intersections are with X = ceiling(x) + i, and Y = ceiling(y) + j, hence the Y increase in steps tan α and the X in steps cot α.
For the other quadrants, the ceiling's are replaced by floor's.

Can I calculate a transformation matrix given a set of points?

I'm trying to deduct the 2D-transformation parameters from the result.
Given is a large number of samples in an unknown X-Y-coordinate system as well as their respective counterparts in WGS84 (longitude, latitude). Since the area is small, we can assume the target system to be flat, too.
Sadly I don't know which order of scale, rotate, translate was used, and I'm not even sure if there were 1 or 2 translations.
I tried to create a lengthy equation system, but that ended up too complex for me to handle. Basic geometry also failed me, as the order of transformations is unknown and I would have to check every possible combination order.
Is there a systematic approach to this problem?
Figuring out the scaling factor is easy, just choose any two points and find the distance between them in your X-Y space and your WGS84 space and the ratio of them is your scaling factor.
The rotations and translations is a little trickier, but not nearly as difficult when you learn that the result of applying any number of rotations or translations (in 2 dimensions only!) can be reduced to a single rotation about some unknown point by some unknown angle.
Suddenly you have N points to determine 3 unknowns, the axis of rotation (x and y coordinate) and the angle of rotation.
Calculating the rotation looks like this:
Pr = R*(Pxy - Paxis_xy) + Paxis_xy
Pr is your rotated point in X-Y space which then needs to be converted to WGS84 space (if the axes of your coordinate systems are different).
R is the familiar rotation matrix depending on your rotation angle.
Pxy is your unrotated point in X-Y space.
Paxis_xy is the axis of rotation in X-Y space.
To actually find the 3 unknowns, you need to un-scale your WGS84 points (or equivalently scale your X-Y points) by the scaling factor you found and shift your points so that the two coordinate systems have the same origin.
First, finding the angle of rotation: take two corresponding pairs of points P1, P1' and P2, P2' and write out
P1' = R(P1-A) + A
P2' = R(P2-A) + A
where I swapped A = Paxis_xy for brevity. Subtracting the two equations gives:
P2'-P1' = R(P2-P1)
B = R * C
Bx = cos(a) * Cx - sin(a) * Cy
By = cos(a) * Cx + sin(a) * Cy
By + Bx = 2 * cos(a) * Cx
(By + Bx) / (2 * Cx) = cos(a)
...
(By - Bx) / (2 * Cy) = sin(a)
a = atan2(sin(a), cos(a)) <-- to get the right quadrant
And you have your angle, you can also do a quick check that cos(a) * cos(a) + sin(a) * sin(a) == 1 to make sure either you got all the calculations correct or that your system really is an orientation-preserving isometry (consists only of translations and rotations).
Now that we know a we know R and so to find A we do:
P1` = R(P1-A) + A
P1' - R*P1 = (I-R)A
A = (inverse(I-R)) * (P1' - R*P1)
where the inversion of a 2x2 matrix is easy.
EDIT: There is an error in the above, or more specifically one case that needs to be treated separately.
There is one combination of translations and rotations that does not reduce to a single rotation and that is a single translation. You can think of it in terms of fixed points (how many points are unchanged after the operation).
A translation has no fixed points (all points are changed) and a rotation has 1 fixed point (the axis doesn't change). It turns out that two rotations leave 1 fixed point and a translation and a rotation leaves 1 fixed point, which (with a little proof that says the number of fixed points tells you the operation performed) is the reason that arbitrary combinations of these result in a single rotation.
What this means for you is that if your angle comes out as 0 then using the method above will give you A = 0 as well, which is likely incorrect. In this case you have to do A = P1' - P1.
If I understood the question correctly, you have n points (X1,Y1),...,(Xn,Yn), the corresponding points, say, (x1,y1),...,(xn,yn) in another coordinate system, and the former are supposedly obtained from the latter by rotation, scaling and translation.
Note that this data does not determine the fixed point of rotation / scaling, or the order in which the operations "should" be applied. On the other hand, if you know these beforehand or choose them arbitrarily, you will find a rotation, translation and scaling factor that transform the data as supposed to.
For example, you can pick an any point, say, p0 = [X1, Y1]T (column vector) as the fixed point of rotation & scaling and subtract its coordinates from those of two other points to get p2 = [X2-X1, Y2-Y1]T, and p3 = [X3-X1, Y3-Y1]T. Also take the column vectors q2 = [x2-x1, y2-y1]T, q3 = [x3-x1, y3-y1]T. Now [p2 p3] = A*[q2 q3], where A is an unknwon 2x2 matrix representing the roto-scaling. You can solve it (unless you were unlucky and chose degenerate points) as A = [p2 p3] * [q2 q3]-1 where -1 denotes matrix inverse (of the 2x2 matrix [q2 q3]). Now, if the transformation between the coordinate systems really is a roto-scaling-translation, all the points should satisfy Pk = A * (Qk-q0) + p0, where Pk = [Xk, Yk]T, Qk = [xk, yk]T, q0=[x1, y1]T, and k=1,..,n.
If you want, you can quite easily determine the scaling and rotation parameter from the components of A or combine b = -A * q0 + p0 to get Pk = A*Qk + b.
The above method does not react well to noise or choosing degenerate points. If necessary, this can be fixed by applying, e.g., Principal Component Analysis, which is also just a few lines of code if MATLAB or some other linear algebra tools are available.

In a triangulated isometric grid, what triangle is a given point in?

I have a triangulated isometric grid, like this:
(source: mathforum.org)
In my code, triangles are grouped by columns.
As I hover the mouse, I want to calculate what triangle the mouse coordinates are in. Is there a simple algorithm to do that?
What you want to do is turn this into a grid as much as possible because grids are far easier to work with.
The first thing you do is work out what column it's in. You say you store that so it should be easier by doing a simple integer division on the x coordinate by the column width offset by the box start. Easy.
After that you want to work out what triangle it's in (obviously). How you partially turn this into a grid is you pretend that you have a stack of right angle triangles instead of a stack of isometric triangles.
The triangles have a length along the y axis (the side of the column). Divide that number in two and work out how many steps down you are. Based on the number of steps down and if the column is even or odd will tell you if you're looking at:
+--------+
|-_ |
| -_ |
| -_ |
| -_|
+--------+
or the reverse. At this point you only need to determine which side of the line it's on to determine which right triangle it's in, which also tells you which isometric triangle it's in.
You have a couple of options for this.
You could use something like Bresenham's line algorithm to rasterize the hypotenuse and when you hit the column you're in work out if you're above or below that line;
Because you only have two possible grids here (one being the reverse of the other so it's really only one). You could store a array of row values, saying that for column 3, the hypotenuse is at offset 2, whereas for 6 it's at 4 and so on.
You could even use (1) to generate (2) as a fast lookup.
The only other thing to consider is what happens if the mouse cursor is on an edge?
This is similar to what cletus said, but a different way to look at it I suppose.
I am assuming the triangle side is 1.
Suppose you have the grid as below:
y'
/
/__/__/__/__/__/__/
/__/__/__/__/__/__/
/__/__/__/__/__/__/____ x'
(0,0)
If you consider the grid in a co-ordinate system in which the x & y axes are at an angle of 60 degrees, a point whose co-ordinate in the angled system (x',y') will correspond to the coordinate in the orthogonal system (with same origin an general direction of axes) to (x,y).
In your problem, you are given (x,y), we need to find (x',y') and then figure out the triangle.
If i is the unit vector along x and j the orthogonal along y, then we have that
x'* i + y'( i/2 + sqrt(3) * j /2) = xi + yj.
(Basically the unit vector along the 'angled' y axis is i/2 + sqrt(3)/2 * j. The unit vector along the x axis is the same as the normal x-axis, i.e. i).
Thus
x' + y'/2 = x
y' * sqrt(3)/2 = y
Solving gives:
y' = 2*y/sqrt(3)
x' = x - y/sqrt(3)
Assume for now that x' and y' are positive.
Now if c = [x'], the integer part of x'
and r = [y'], the integer part of y'
then in the (angular) grid, the point lies in the cth column and the rth row. (Counting right and up and start counting at 0).
Thus we have narrowed down your point to a parallelogram
____
/\ * /
/___\/
(c,r)
Now in order to find out which triangle it is in you can consider the fractional parts of x' and y'.
{x} = x' - [x'] = x' - c.
{y} = y' - [y'] = y' - r.
Now,
if {x} + {y} > 1, then the point lies in the triangle marked with *.
if {x} + {y} < 1, then the point lies in the other triangle.
if {x} + {y} = 1, then the point lies on the line common to the two triangles.
Hope that helps too.

Finding the spin of a sphere given X, Y, and Z vectors relative to sphere

I'm using Electro in Lua for some 3D simulations, and I'm running in to something of a mathematical/algorithmic/physics snag.
I'm trying to figure out how I would find the "spin" of a sphere of a sphere that is spinning on some axis. By "spin" I mean a vector along the axis that the sphere is spinning on with a magnitude relative to the speed at which it is spinning. The reason I need this information is to be able to slow down the spin of the sphere by applying reverse torque to the sphere until it stops spinning.
The only information I have access to is the X, Y, and Z unit vectors relative to the sphere. That is, each frame, I can call three different functions, each of which returns a unit vector pointing in the direction of the sphere model's local X, Y and Z axes, respectively. I can keep track of how each of these change by essentially keeping the "previous" value of each vector and comparing it to the "new" value each frame. The question, then, is how would I use this information to determine the sphere's spin? I'm stumped.
Any help would be great. Thanks!
My first answer was wrong. This is my edited answer.
Your unit vectors X,Y,Z can be put together to form a 3x3 matrix:
A = [[x1 y1 z1],
[x2 y2 z2],
[x3 y3 z3]]
Since X,Y,Z change with time, A also changes with time.
A is a rotation matrix!
After all, if you let i=(1,0,0) be the unit vector along the x-axis, then
A i = X so A rotates i into X. Similarly, it rotates the y-axis into Y and the
z-axis into Z.
A is called the direction cosine matrix (DCM).
So using the DCM to Euler axis formula
Compute
theta = arccos((A_11 + A_22 + A_33 - 1)/2)
theta is the Euler angle of rotation.
The magnitude of the angular velocity, |w|, equals
w = d(theta)/dt ~= (theta(t+dt)-theta(t)) / dt
The axis of rotation is given by e = (e1,e2,e3) where
e1 = (A_32 - A_23)/(2 sin(theta))
e2 = (A_13 - A_31)/(2 sin(theta))
e3 = (A_21 - A_12)/(2 sin(theta))
I applaud ~unutbu's, answer, but I think there's a simpler approach that will suffice for this problem.
Take the X unit vector at three successive frames, and compare them to get two deltas:
deltaX1 = X2 - X1
deltaX2 = X3 - X2
(These are vector equations. X1 is a vector, the X vector at time 1, not a number.)
Now take the cross-product of the deltas and you'll get a vector in the direction of the rotation vector.
Now for the magnitude. The angle between the two deltas is the angle swept out in one time interval, so use the dot product:
dx1 = deltaX1/|deltaX1|
dx2 = deltax2/|deltaX2|
costheta = dx1.dx2
theta = acos(costheta)
w = theta/dt
For the sake of precision you should choose the unit vector (X, Y or Z) that changes the most.

Resources