WPF 3D: How to convert a single AxisAngleRotation3D into separate AxisAngleRotation3D? - wpf

I have a 3D viewport that uses the TrackBall of WPF 3D tool to rotate the object by mouse. As a result, I get a single AxisAngleRotation3D with Axis vector like (0.5, 0.2, 0.6) and Angle of e.g. 35. That's fine.
What I would like to do is, as an alternative, to give user the ability to rotate the object by individual axis (i.e. x, y, z). So, if the object is rotated around the axis of (0.5, 0.2, 0.6) by 35 degree, how can I convert this into three rotations around each axis, ie. Xangle for vector (1, 0, 0), Yangle for vector (0, 1, 0), and Zangle for vector (0, 0, 1).
I also need a way to convert them back to a single AxisAngleRotation3D object.
EDIT:
I found some stuff at http://www.gamedev.net/reference/articles/article1095.asp. One thing I learnt is that I can easily get a (combined) quaternion from separete AxisAngleRotation3D. For example,
private AxisAngleRotation3D _axisX = new AxisAngleRotation3D();
private AxisAngleRotation3D _axisY = new AxisAngleRotation3D();
private AxisAngleRotation3D _axisZ = new AxisAngleRotation3D();
...
_axisX.Axis = new Vector3D(1, 0, 0);
_axisY.Axis = new Vector3D(0, 1, 0);
_axisZ.Axis = new Vector3D(0, 0, 1);
...
Quaternion qx = new Quaternion(_axisX.Axis, _axisX.Angle);
Quaternion qy = new Quaternion(_axisY.Axis, _axisY.Angle);
Quaternion qz = new Quaternion(_axisZ.Axis, _axisZ.Angle);
Quaternion q = qx * qy * qz;
This is fine. Now, the problem is how can I do the reverse? So, for a given q, how can I find out qx, qy, qz?

You can convert it to a matrix and then back to three separate rotations representation. You can find formulas for both conversions on the net. You can also optimize it by writing it down and solving the equations on paper resulting in possibly faster formula.
However, I suggest to never represent rotation in three numbers, that's due to singularities resulting from this implementation and numeric instability. Use quaternions instead.

cuanternion to Euler angles

Related

Display sun position with Expo and Three.js

So the idea is quite simple: given the sun's position (azimuth and elevation) I want my app to be able to display a shape using augmented reality when the camera is pointing at the sun.
So there is a few steps:
Convert azimuth and elevation into radians, then into cartesian coordinates to get a simple vector {x, y, z}.
Get the phone's gyroscope data to get its orientation in space as a 3D vector {x, y, z}.
Calculate new coordinates for the sun regarding the phone orientation.
Display a random shape using Three.js at these coordinates.
1 and 2 are quite easy. There are a lot of APIs out there giving the sun's position depending on a location. Then I used a formula to convert the sun's spherical coordinates into cartesian ones:
x = R * cos(ϕ) * sin(θ)
y = R * cos(ϕ) * cos(θ)
z = R * sin(ϕ)
with R, the distance of the point from the origin, θ (the azimuth) and ϕ (the elevation).
I got the device's orientation in space with Expo.io, using their Device Motion API. Documentation here
I'm really struggling with the third step. I don't know how to combine sun and device coordinates in space, and project the whole thing through Three.js perspective camera.
I found this post the other day: Compare device 3D orientation with the sun position but I've found the explanations a bit confusing.
Let's say I want to display a cube with Three:
const geometry = new THREE.BoxGeometry(0.07, 0.07, 0.07);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
cube.position.x = 0;
cube.position.y = 0;
cube.position.z = -1;
The final goal here will be to find the correct {x, y, z} so the cube can be displayed at the sun's location. This vector will be of course updated every time the user moves his phone in space.

How do I transform glOrtho clipping planes?

I've created an OpenGL application where I define a viewing volume with glOrtho(). Then I use gluLookAt() to transform all the points.
The problem is - as soon as I do this all the points fall out of the clipping plane because it is "left behind". And I end up with a black screen.
How do I change the viewing volume so that it is still tight to my objects once they have been transformed by gluLookAt()?
Here's some code to help better illustrate my problem:
Vector3d eyePos = new Vector3d(0.25, 0.25, 0.6);
Vector3d point = new Vector3d(0, 0, 0.001);
Vector3d up = new Vector3d(0, 1,0);
Matrix4d mat = Matrix4d.LookAt(eyePos, point, up);
GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0, 1, 0, 1, 0, 1);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
GL.LoadMatrix(ref mat);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Enable(EnableCap.DepthTest);
GL.DepthMask(true);
GL.ClearDepth(1.0);
GL.Color3(Color.Yellow);
GL.Begin(PrimitiveType.Triangles);
GL.Vertex3(0.2, 0.3, 0.01);
GL.Vertex3(0, 0.600, 0.01);
GL.Vertex3(0.600, 0.600, 0.01);
GL.Color3(Color.Blue);
GL.Vertex3(0, 0.6, 0.01);
GL.Vertex3(0.2, 0.3, 0.01);
GL.Vertex3(0.7, 0.5, 0.03);
GL.Color3(Color.Red);
GL.Vertex3(0.100, 0.000, 0.01);
GL.Vertex3(0, 0.0, 0.01);
GL.Vertex3(0.600, 0.600, 0.03);
GL.End();
glControl1.SwapBuffers();
I suppose a more succinct revision of my question is how do I transform two points by the lookat matrix?("mat" in my code)
Okay, I got your problem.
You set the camera position to (0.25, 0.25, 0.6) and with the point to look at your view direction is (-0.25, -0.25, -0.599) (has to be normalised). As I mentioned in my comment below your question, you are drawing a cube in the upper right corner of your view direction.
So the two points (0.25, 0.25, 0.6) (the camera position) and the point defined by the camera position and your view direction, your up vector and your right vector (Have a look at this) define the cube of the things which are shown on the screen (the two points define a diagonal within the cube). Unfortunatly, all of your points are not within this cube.
May it be, that you mixed up the camera position with the point you wanna look at? The change of the two values should solve your problem. The rest of your code seems to be correct. The only thing you have to do is to check whether your points are within the clip space of your projections. Another solution to check where your points are, would be to use, e.g. the keyboard input, to move your camera dynamically.

What exactly is the output quaternion of slerp?

I'm trying to implement SLERP (described by Ken Shoemake in "Animating Rotation with Quaternion Curves)
I've read up on the topic on wikipedia (topic: quaternions, 1 and 2) and other sites and also searched stackoverflow about this problem. It seems like I understand the theory behind it, but oversee one small detail. I will use w for the scalar value of the quaternion
So initially I have two 3D vectors. Each vector has a representation in two coordinate systems (C and C'). My goal is to find a third representation of these vectors in the system "halfway" the initial two.
So what I do is I find the rotation matrix, which transform the vectors from C to C', which seems to work out quite fine.
My next step is to transform this matrix into a quaternion, which also works.
Now my issue is with the formula of slerp, which is:
slerp(q1, q2; u) = ((sin(1-u) * t)/ (sin t)) * q1 + (sin(ut)/sin t) * q2
(sorry can't upload images yet for a better representation: see source 1)
so I guess here u = 0.5, q1 is the vector I would like to rotate (with w=0) and q2 equals the quaternion I calculated previously. Theta is calculated from the dotproduct of the normalized vector and the (already) normalized quaternion.
So what I expect is that I get back a vector, rotated either from C to the third coordinate system or from C' to the third coordinate system.
My issue now is, that I don't see, how I will get a vector and not a quaternion. Meaning, how is it possible, that I will get a quaternion with (w=0), as by simply multiplying q2 with this factor won't set w to 0. Or is it something else I will get from this function?
What am I overseeing here?
Thanks for your help!
Seems like I figured it out. For someone with the same understanding problem:
slerp simply interpolates between two orientations, meaning between two actual rotations. So in my case, q1 is the quaternion corresponding to the identity matrix (so [1, 0, 0, 0]). q2 is the rotation. theta is still 0.5.
With the quaternion I get from this, I have to calculate the rotation with q^-1 v q. Where v is my vector I want to rotate. This can be calculated using the Hamilton product.

WPF: Getting new coordinates after a Rotation

With reference to this programming game I am currently building.
alt text http://img12.imageshack.us/img12/2089/shapetransformationf.jpg
To translate a Canvas in WPF, I am using two Forms: TranslateTransform (to move it), and RotateTransform (to rotate it) [children of the same TransformationGroup]
I can easily get the top left x,y coordinates of a canvas when its not rotated (or rotated at 90deg, since it will be the same), but the problem I am facing is getting the top left (and the other 3 points) coordinates.
This is because when a RotateTransform is applied, the TranslateTransform's X and Y properties are not changed (and thus still indicate that the top-left of the square is like the dotted-square (from the image)
The Canvas is being rotated from its center, so that is its origin.
So how can I get the "new" x and y coordinates of the 4 points after a rotation?
[UPDATE]
alt text http://img25.imageshack.us/img25/8676/shaperotationaltransfor.jpg
I have found a way to find the top-left coordinates after a rotation (as you can see from the new image) by adding the OffsetX and OffsetY from the rotation to the starting X and Y coordinates.
But I'm now having trouble figuring out the rest of the coordinates (the other 3).
With this rotated shape, how can I figure out the x and y coordinates of the remaining 3 corners?
[EDIT]
The points in the 2nd image ARE NOT ACCURATE AND EXACT POINTS. I made the points up with estimates in my head.
[UPDATE] Solution:
First of all, I would like to thank Jason S for that lengthy and Very informative post in which he describes the mathematics behind the whole process; I certainly learned a lot by reading your post and trying out the values.
But I have now found a code snippet (thanks to EugeneZ's mention of TransformBounds) that does exactly what I want:
public Rect GetBounds(FrameworkElement of, FrameworkElement from)
{
// Might throw an exception if of and from are not in the same visual tree
GeneralTransform transform = of.TransformToVisual(from);
return transform.TransformBounds(new Rect(0, 0, of.ActualWidth, of.ActualHeight));
}
Reference: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/86350f19-6457-470e-bde9-66e8970f7059/
If I understand your question right:
given:
shape has corner (x1,y1), center (xc,yc)
rotated shape has corner (x1',y1') after being rotated about center
desired:
how to map any point of the shape (x,y) -> (x',y') by that same rotation
Here's the relevant equations:
(x'-xc) = Kc*(x-xc) - Ks*(y-yc)
(y'-yc) = Ks*(x-xc) + Kc*(y-yc)
where Kc=cos(theta) and Ks=sin(theta) and theta is the angle of counterclockwise rotation. (to verify: if theta=0 this leaves the coordinates unchanged, otherwise if xc=yc=0, it maps (1,0) to (cos(theta),sin(theta)) and (0,1) to (-sin(theta), cos(theta)) . Caveat: this is for coordinate systems where (x,y)=(1,1) is in the upper right quadrant. For yours where it's in the lower right quadrant, theta would be the angle of clockwise rotation rather than counterclockwise rotation.)
If you know the coordinates of your rectangle aligned with the x-y axes, xc would just be the average of the two x-coordinates and yc would just be the average of the two y-coordinates. (in your situation, it's xc=75,yc=85.)
If you know theta, you now have enough information to calculate the new coordinates.
If you don't know theta, you can solve for Kc, Ks. Here's the relevant calculations for your example:
(62-75) = Kc*(50-75) - Ks*(50-85)
(40-85) = Ks*(50-75) + Kc*(50-85)
-13 = -25*Kc + 35*Ks = -25*Kc + 35*Ks
-45 = -25*Ks - 35*Kc = -35*Kc - 25*Ks
which is a system of linear equations that can be solved (exercise for the reader: in MATLAB it's:
[-25 35;-35 -25]\[-13;-45]
to yield, in this case, Kc=1.027, Ks=0.3622 which does NOT make sense (K2 = Kc2 + Ks2 is supposed to equal 1 for a pure rotation; in this case it's K = 1.089) so it's not a pure rotation about the rectangle center, which is what your drawing indicates. Nor does it seem to be a pure rotation about the origin. To check, compare distances from the center of rotation before and after the rotation using the Pythagorean theorem, d2 = deltax2 + deltay2. (for rotation about xc=75,yc=85, distance before is 43.01, distance after is 46.84, the ratio is K=1.089; for rotation about the origin, distance before is 70.71, distance after is 73.78, ratio is 1.043. I could believe ratios of 1.01 or less would arise from coordinate rounding to integers, but this is clearly larger than a roundoff error)
So there's some missing information here. How did you get the numbers (62,40)?
That's the basic gist of the math behind rotations, however.
edit: aha, I didn't realize they were estimates. (pretty close to being realistic, though!)
I use this method:
Point newPoint = rotateTransform.Transform(new Point(oldX, oldY));
where rotateTransform is the instance on which I work and set Angle...etc.
Look at GeneralTransform.TransformBounds() method.
I'm not sure, but is this what you're looking for - rotation of a point in Cartesian coordinate system:
link
You can use Transform.Transform() method on your Point with the same transformations to get a new point to which these transformations were applied.

Applying in-place transformations to 3D Model in WPF

I have a simple 3D cube that I can rotate using the following code:
void mui3D_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
RotateTransform3D rotation = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0), mui.Model.Bounds.Location);
DoubleAnimation rotateAnim = new DoubleAnimation(0, 130d TimeSpan.FromMilliseconds(3000));
rotateAnim.Completed += new EventHandler(rotateAnim_Completed);
mui.Transform = rotation;
rotation.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, rotateAnim);
}
Each time it executes, this code rotates the cube using an animation around the Y axis from an angle of 0 to 130 degrees.
However I would like to apply the rotation "cumulatively" so that the any previous rotation is taken into account and the cube commences each rotation from the angle it finished the previous rotation.
For example: the animation constructor, instead of requiring a "from" and "to" value for the angle, simply rotates the cube an an additional 130 degrees based on whatever the current rotation angle is.
I could easily use a member variable that contains the current angle, pass it to the animation and then update it when the animation has completed. But I'm wondering if there is a standard approach using WPF to achieve this.
I'm sure there's a method for retrieving the current Euler rotation angle in degrees from the object's transformation matrix. You could then use that as the "from" value and animate to the "to" value.
Failing that, simply create a variable somewhere in your application that remembers the number of degrees the cube as been rotated. Each time the function is run just add the number of degrees you'd like it to rotate and then store the result back in your variable.
some pseudo-code:
angle = 0
function onClick:
new_angle = angle + 30
Animate(angle, new_angle)
angle = new_angle

Resources