Rotating a dynamic 3D array of positions - c#

So I have a system that holds a cluster of items in positions. The cluster is stored in an array as follows:
int[,,] = int[length, width, height];
Length, width, and height can all be different depending on the cluster. If I wanted to rotate the entire cluster by a set of degrees (ranging 0 to 360):
double rX, double rZ, double rY
How can I determine the new positions of each item and export in a new array?
My busted attempts all start like this:
int iX = Math.Abs(rX / 90), iZ = Math.Abs(rZ / 90), iY = Math.Abs(rY / 90);
if (iY == 1) // 90 or -90 degrees
{
group.Length = (rY / 90) * back.Width;
group.Width = (rY / 90) * back.Length;
}
else if (iY == 2) // 180 degrees
{
group.Length *= -1;
group.Width *= -1;
}
if (iZ == 1) // 90 or -90 degrees
{
group.Length = (rZ / 90) * back.Height;
group.Height = (rZ / 90) * back.Length;
}
else if (iZ == 2) // 180 degrees
{
group.Length *= -1;
group.Height *= -1;
}
if (iX == 1) // 90 or -90 degrees
{
group.Width = (rX / 90) * back.Height;
group.Height = (rX / 90) * back.Width;
}
else if (iX == 2) // 180 degrees
{
group.Width *= -1;
group.Height *= -1;
}
for(int gX = 0; gX < group.Length; gX++)
{
for (int gZ = 0; gZ < group.Width; gZ++)
{
for (int gY = 0; gY < group.Height; gY++)
{
//I lose track here.
}
}
}
From there I don't know where to go. group is the cluster I'm trying to rotate, and back is a copy of group before these operations. The array in this cluster is like this:
Cluster.Items[,,]
And it's sizes are set to the dimensions of the group. The array is based on a X (Length) Z (Width) Y (Height) axis.
I'm guessing the answer has something to do with matrices and flipping certain axis.

You will need a rotation matrix.
A rotation matrix is a matrix which when multiplied with a vector, will result is a rotation of that vector.
there are three types of rotation matrices
Rotation around x-Axis
Rx(a) = [ 1 0 0 0,
0 cos(a) -sin(a) 0,
0 sin(a) cos(a) 0,
0 0 0 1]
around y-Axis
Ry(a) = [ cos(a) 0 sin(a) 0,
0 1 0 0,
-sin(a) 0 cos(a) 0,
0 0 0 1]
ans rotation around z-Axis
Rz(a) = [ cos(a) -sin(a) 0 0,
sin(a) cos(y) 0 0,
0 0 1 0,
0 0 0 0]
More maths about rotation matrices you will find here

I'm still not convinced of your data structure. But let me just answer your question.
First, specify an order of rotations. In the following, I assume the order x, z, y. Then, find the according rotation matrix (e.g. from here). Then, multiply the position vector with the matrix to get the new vector.
If the old vector has coordinates x, y, z, then the new vector's x-coordinate would be (first row of the matrix):
newX = x * cos(rZ) * cos(rY) - y * sin(rZ) + z * cos(rZ) * sin(rY)
So the first entry in the row is multiplied with x, the second with y and so on. Insert the correct angles any you're done.
Since cosine and sine are always -1, 0, or 1 for degrees that are multiples of 90°, the according calculation can be improved to not use the actual sine and cosine functions.

Related

How can I calculate and create positions of triangle shape?

private void FormationTriangle()
{
newpositions = new List<Vector3>();
for (int x = 0; x < squadMembers.Count; x++)
{
for (int y = x; y < 2 * (squadMembers.Count - x) - 1; y++)
{
Vector3 position = new Vector3(x, y);
newpositions.Add(position);
}
}
move = true;
formation = Formation.Square;
}
The loops are wrong. It put the squadMembers in one line one above the other.
Not even close to a triangle shape.
I want the squadMembers to stand in a triangle shape.
This is the moving part: But the problem is with the loops calculating the triangle shape positions. Other formations I did are working fine.
private void MoveToNextFormation()
{
if (randomSpeed == false)
{
if (step.Length > 0)
step[0] = moveSpeed * Time.deltaTime;
}
for (int i = 0; i < squadMembers.Count; i++)
{
squadMembers[i].transform.LookAt(newpositions[i]);
if (randomSpeed == true)
{
squadMembers[i].transform.position = Vector3.MoveTowards(
squadMembers[i].transform.position, newpositions[i], step[i]);
}
else
{
squadMembers[i].transform.position = Vector3.MoveTowards(
squadMembers[i].transform.position, newpositions[i], step[0]);
}
if (Vector3.Distance(squadMembers[i].transform.position, newpositions[i]) <
threshold)
{
if (squareFormation == true)
{
Vector3 degrees = new Vector3(0, 0, 0);
Quaternion quaternion = Quaternion.Euler(degrees);
squadMembers[i].transform.rotation = Quaternion.Slerp(
squadMembers[i].transform.rotation, quaternion,
rotateSpeed * Time.deltaTime);
}
else
{
squadMembers[i].transform.rotation = Quaternion.Slerp(
squadMembers[i].transform.rotation, quaternions[i],
rotateSpeed * Time.deltaTime);
}
}
}
}
This answer will produce a triangle arranged like this:
x
x x
x x x
x x x x
x x x x x
Or, if there aren't enough to fill a full triangle:
x
x x
x x x
x x x x
x x x
Since you aren't guaranteed a perfectly triangular number of units, you should overestimate how big your triangle is, keep count of how many units you have placed, and then quit placing them when you reach your limit.
First, find the height of the smallest triangular number greater than your number of units, and that triangular number itself:
int height = Mathf.CeilToInt( (Mathf.Sqrt(8*squadMembers.Count+1f)-1f)/2 )
int slots = (int)(height * (height+1f)/2f)
Then, find the position of the first unit. We need to know how many rows of slots we have and how wide the bottom row of slots is:
float verticalModifier = 0.8f; // 0.8f to decrease vertical space
float horizontalModifier = 1.25f; // 1.25f to increase horizontal space
float width = 0.5f * (height-1f);
Vector3 startPos = new Vector3(width* horizontalModifier, 0f, (float)(height-1f) * verticalModifier);
Then, add until you've added enough
int finalRowCount = height - slots + squadMembers.Count;
for (int rowNum = 0 ; rowNum < height && newpositions.Count < squadMembers.Count; rowNum++) {
for (int i = 0 ; i < rowNum+1 && newpositions.Count < squadMembers.Count ; i++ ) {
float xOffset = 0f;
if (rowNum+1 == height) {
// If we're in the last row, stretch it ...
if (finalRowCount !=1) {
// Unless there's only one item in the last row.
// If that's the case, leave it centered.
xOffset = Mathf.Lerp(
rowNum/2f,
-rowNum/2f,
i/(finalRowCount-1f)
) * horizontalModifier;
}
}
else {
xOffset = (i-rowNum /2f) * horizontalModifier;
}
float yOffset = (float)rowNum * verticalModifier;
Vector3 position = new Vector3(
startPos.x + xOffset, 0f, startPos.y - yOffset);
newpositions.Add(position);
}
}
Let's see what the list of positions contains for a simple value, n = 3
First, loop x from 0 to 2 (3 - 1)
Then for each x, loop from x to 4-x (3*2 - x - 1 - 1)
Remembering that a<b is the same as a<=b-1
That gives us...
0,0
0,1
0,2
0,3
0,4
1,1
1,2
1,3
2,2
Which is a lot of positions. Certainly more than 3 units can occupy! At least it is a triangle:
X\Y 0 1 2 3 4
0 # # # # #
1 # # #
2 #
The main problem is that you're generating way more positions than needed and expecting to fill it somehow.
You need to calculate your width and height based on the area formula for a triangle: A = (b*h)/2 and you may even want b=h, where A = number of units.
So, something like this:
int b = Mathf.CeilToInt(Mathf.Sqrt(squadMembers.Count));
for (int x = 0; x < b; x++)
{
//the divide by 2 is accounted for with this 2*
for (int y = x; y < 2 * (b - x) - 1; y++)
{
Vector3 position = new Vector3(x, y);
newpositions.Add(position);
}
}

Math: Mercator Projection Convert 360 video pixel coordinate to sphere surface coordinate

I was trying to map the 360 video pixel coordinate to sphere surface coordinate but I couldn't get right result... It just mapped to the wrong position I already know the points of the XY data for 360 video pixels.
how map 2d grid points (x,y) onto sphere as 3d points (x,y,z)
I checked this link and I copied method from this but what I'm getting is not mapped to the desired position.
How can I get radius from the pixels?
I am not sure if I'm passing right radius for imageRadius but I thought it will be circumference/PI to get radius and the video ratio is 4096x2048. I also tried to pass the number 1 because UV is 0-1 but it was not right...
Is Method wrong?
Maybe the method is wrong. I passed random numbers into the imageRadius but couldn't get the right position... If I make X to negative number the seems like little bit closer to result....?
Current Result
https://youtu.be/t0I7Hlb-tbk
It mapped to up right position with the method that I found online...
Project File
https://drive.google.com/a/swordfish-sf.com/file/d/0B45RYzVs0t0_VVdaaHdmNHRWTk0/view?usp=sharing
If somebody can check the Unity project file that will be great...
Current Code
public class mapScript : MonoBehaviour {
public int input = 4098;
float imageRadius = 4098f / Mathf.PI; //2098? 3072? 4098?
float radius;
public GameObject testSphere;
void Start () {
radius = this.transform.localScale.x;
}
void Update () {
imageRadius = input / Mathf.PI;
int currentFrame = (int)this.GetComponent<VideoPlayer>().frame;
testSphere.transform.position = MercatorProjection(mapVals[currentFrame,0],mapVals[currentFrame,1]);
}
Vector3 MercatorProjection(float xVal, float yVal)
{
float lon = (xVal / imageRadius);
float lat = (2 * Mathf.Atan(Mathf.Exp(yVal / imageRadius)) - Mathf.PI / 2);
float calcX = radius * Mathf.Cos(lat) * Mathf.Cos(lon);
float calcY = radius * Mathf.Cos(lat) * Mathf.Sin(lon);
float calcZ = radius * Mathf.Sin(lat);
Vector3 result = new Vector3(calcX,calcY,calcZ);
Debug.Log(result);
return result;
}
float[,] mapVals = new float[,] {
{1969.21f, 928.625f},
{1969.6f, 928.533f},
{1968.92f, 928.825f},
{1968.68f, 929f},
{1968.47f, 929.067f},
{1968.41f, 929.025f},
{1968.48f, 928.992f},
....
};
}
Thank you.
As a side note, the radius is arbitrary. The pixel coordinates only map to the directional coordinates (polar [θ] and azimuthal [ϕ] angles).
We can do this by mapping each pixel to equal θ and ϕ intervals. The diagram below illustrates a low-resolution setup:
Let us adopt the convention that, for an image of with W, ϕ = 0 corresponds to:
Even W: half way between X = floor((W - 1) / 2) and X = ceil((W - 1) / 2)
Odd W: in the middle of the pixel column at X = floor((W - 1) / 2)
The pixel row at Y maps to the equilatitudinal line at θ = (Y + 0.5) / H * π.
To map all pixels in their entirety, let X start at -0.5 instead of 0, and end at W - 0.5; likewise for Y. Since integer coordinates map to the centers of the pixel regions shown above, this allows the whole area of any particular pixel to be addressed. You may need this later on if you plan on doing multi-sampling filtering for e.g. anti-aliasing.
Code:
Vector3 Mercator(float x, float y, int w, int h)
{
// outside of valid pixel region
if (x < -0.5f || x >= w - 0.5f || y < -0.5f || y >= h - 0.5f)
return new Vector3();
float theta = (y + 0.5f) / h * Math.PI;
float phi = ((x + 0.5f) / w - 0.5f) * 2.0 * Math.PI;
float c_t = Math.Cos(theta);
return new Vector3(c_t * Math.Cos(phi), c_t * Math.Sin(phi), Math.Sin(theta));
}
... and multiply the resulting direction vector by any "radius" you like, since it has (basically) nothing to do with the mapping anyway.

OpenTK / OpenGL - Rotating camera with mouse

Background
I currently have an object that I am displaying that will always be at the origin. I have a function which increments my x and y angles and then calculates the new x,y,z coordinate for the camera:
Public Sub update_rotation()
If cam.manual_lookat = True Then
If camangley >= 360 Then
camangley = camangley - 360
End If
If camanglex >= 360 Then
camanglex = camanglex - 360
End If
If camangley < 0 Then
camangley = 360 + camangley
End If
If camanglex < 0 Then
camanglex = 360 + camanglex
End If
If camangley > 90 And camangley <= 270 Then
cam.invert_y = True
Else
cam.invert_y = False
End If
camx = distance * -Sin(camanglex * (PI / 180)) * Cos((camangley) * (PI / 180))
camy = distance * -Sin((camangley) * (PI / 180))
camz = distance * Cos((camanglex) * (PI / 180)) * Cos((camangley) * (PI / 180))
cam.Position.X = camx
cam.Position.Y = camy
cam.Position.Z = camz
cam.lookat.X = 0
cam.lookat.Y = 0
cam.lookat.Z = 0
' Label2.Text = camanglex & "," & camangley
End If
End Sub
I have this set up to use keyboard events.. the X button adds to the camanglex variable, the Y button adds to the camangley variable, and the Z button adds to the distance variable.
Everything works well doing it this way, using the keyboard.
Problem
I am trying to now use the mouse to handle the rotation instead of the keyboard. I believe this is simply a math question but how do I go about calculating either the new camanglex and camangley variables or directly calculating the new camx,camy,camz ones to establish my cameras new location?
I have a mouse function which will capture the mouse coordinates but am having trouble with the calculation part.
If you want to orbit around object you could trace the path your mouse goes on fake sphere (which is called trackball sometimes). There is a working example of orbit controls.
And here is a pseudocode sketch for something similiar:
mouseDownEventFunction(event) {
computeDragPoint (event.mouseX, event.mouseY, &oldDragPoint);
isMouseDown = true;
}
mouseUpEventFunction(event) {
isMouseDown = false;
}
mouseMoveEventFunction(event) {
if (isMouseDown) {
computeDragPoint (event.mouseX, event.mouseY, &newDragPoint);
rotateCamera (oldDragPoint, newDragPoint);
oldDragPoint = newDragPoint;
}
}
Here we find a point on trackball:
/* we want to ray trace a point on face side of fake sphere.
dragPoint* is our result*/
computeDragPoint(int x, int y, Vector3* dragPoint) {
/* normalize x and y to [-1, 1] so they match flat circle position on screen.
And assign this to dragPoint->x and dragPoint->y.
This part depends on what you want to achieve and input units of x, y.
Keep in mind aspect ratio */
dragPoint->x = (2*x/screenWidth - 0.5) * (screenHeight/screenWidth);
dragPoint->y = 2*y/screenHeight - 0.5;
dragPoint->x /= sqrt(dragPoint->x*dragPoint->x + dragPoint->y*dragPoint->y);
dragPoint->y /= sqrt(dragPoint->x*dragPoint->x + dragPoint->y*dragPoint->y);
/* Then having two values in [-1,1] compute corresponding z */
float tmp = dragPoint->x*dragPoint->x + dragPoint->y*dragPoint->y;
if (tmp > 1) {
dragPoint.x /= sqrt(tmp);
dragPoint.y /= sqrt(tmp);
}
dragPoint->z = -sqrt (1 - dragPoint->x^2 - dragPoint->y^2) || 0;
}
And rotation math can be done with quaternions (or just matrices from Euler angles if you don't want to use quats):
rotateCamera(oldDragPoint, newDragPoint) {
Quaternion quat = new Quaternion (Config.AngleX, Config.AngleY, Config.AngleZ);
quat.normalize();
Quaternion deltaQuat = new Quaternion();
deltaQuat = deltaQuat.setFromUnitVectors(oldDragPoint, newDragPoint);
quat = quat.multiply(deltaQuat);
quat.normalize();
Vector3 resultAngles = Vector3();
resultAngles.setFromQuaternion(quat);
setCameraPositionFromAngles(resultAngles);
}
And in setCameraPositionFromAngles(resultAngles) set your final X, Y, Z coordinates by applying three basic rotations to your initial camera position. So your main parameters are resultAngles. You renew angles and then set position.
Maybe this working example will explain better.

GDI+ curve "overflowing"

I'm currently using GDI+ to draw a line graph, and using Graphics.DrawCurve to smooth out the line. The problem is that the curve doesn't always match the points I feed it, and that makes the curve grow out of the graph frame in some points, as seen below(red is Graphics.DrawLines, green is Graphics.DrawCurve).
How would I go about solving this?
The simplest solution is to set a tension:
The green curve is drawn with the default tension, the blue one set a tension of 0.1f:
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawLines(Pens.Red, points.ToArray());
e.Graphics.DrawCurve(Pens.Green, points.ToArray());
e.Graphics.DrawCurve(Pens.Blue, points.ToArray(), 0.1f);
}
You will need to test what is the best compromise, 0.2f is still ok, 0.3f is already overdrawing quite a bit..
For a really good solution you will need to use DrawBeziers. This will let you draw curves that can go through the points without any overdrawing and with full control of the radius of the curves; but to to so you will need to 'find', i.e. calculate good control points, which is anything but trivial..:
This result is by no means perfect but already complicated enough.. I have displayed the curve points and their respective control points in the same color. For each point there is an incoming and an outgoing control point. For a smooth curve they need to have the same tangents/gradients in their curve points.
I use a few helper functions to calculate a few things about the segments:
A list of gradients
A list of signs of the gradients
A list of segment lengths
Lists of horizontal and of vertical gaps between points
The main function calculates the array of bezier points, that is the curve points and between each pair the previous left and the next right control points.
In the Paint event it is used like this:
List<PointF> bezz = getBezz(points);
using (Pen pen = new Pen(Color.Black, 2f))
e.Graphics.DrawBeziers(pen, bezz.ToArray());
Here are the functions I used:
List<float> getGradients(List<PointF> p)
{
List<float> grads = new List<float>();
for (int i = 0; i < p.Count - 1; i++)
{
float dx = p[i + 1].X - p[i].X;
float dy = p[i + 1].Y - p[i].Y;
if (dx == 0) grads.Add(dy == 0 ? 0 : dy > 0 ?
float.PositiveInfinity : float.NegativeInfinity);
else grads.Add(dy / dx);
}
return grads;
}
List<float> getLengths(List<PointF> p)
{
List<float> lengs = new List<float>();
for (int i = 0; i < p.Count - 1; i++)
{
float dx = p[i + 1].X - p[i].X;
float dy = p[i + 1].Y - p[i].Y;
lengs.Add((float)Math.Sqrt(dy * dy + dx * dx));
}
return lengs;
}
List<float> getGaps(List<PointF> p, bool horizontal)
{
List<float> gaps = new List<float>();
for (int i = 0; i < p.Count - 1; i++)
{
float dx = p[i + 1].X - p[i].X;
float dy = p[i + 1].Y - p[i].Y;
gaps.Add(horizontal ? dx : dy);
}
return gaps;
}
List<int> getSigns(List<float> g)
{
return g.Select(x => x > 0 ? 1 : x == 0 ? 0 : -1).ToList();
}
And finally the main function; here I make a distinction: Extreme points ( minima & maxima) should have their control points on the same height as the points themselves. This will prevent vertical overflowing. They are easy to find: The signs of their gradients will always altenate.
Other points need to have the same gradient for incoming and outcoming control points. I use the average between the segments' gradients. (Maybe a weighed average would be better..) And I weigh their distance according to the segment lengths..
List<PointF> getBezz(List<PointF> points)
{
List<PointF> bezz = new List<PointF>();
int pMax = points.Count;
List<float> hGaps = getGaps(points, true);
List<float> vGaps = getGaps(points, false);
List<float> grads = getGradients(points);
List<float> lengs = getLengths(points);
List<int> signs = getSigns(grads);
PointF[] bezzA = new PointF[pMax * 3 - 2];
// curve points
for (int i = 0; i < pMax; i++) bezzA[i * 3] = points[i];
// left control points
for (int i = 1; i < pMax; i++)
{
float x = points[i].X - hGaps[i - 1] / 2f;
float y = points[i].Y;
if (i < pMax - 1 && signs[i - 1] == signs[i])
{
float m = (grads[i-1] + grads[i]) / 2f;
y = points[i].Y - hGaps[i-1] / 2f * m * vGaps[i-1] / lengs[i-1];
}
bezzA[i * 3 - 1] = new PointF(x, y);
}
// right control points
for (int i = 0; i < pMax - 1; i++)
{
float x = points[i].X + hGaps[i] / 2f;
float y = points[i].Y;
if (i > 0 && signs[i-1] == signs[i])
{
float m = (grads[i-1] + grads[i]) / 2f;
y = points[i].Y + hGaps[i] / 2f * m * vGaps[i] / lengs[i];
}
bezzA[i * 3 + 1] = new PointF(x, y);
}
return bezzA.ToList();
}
Note that I didn't code for the case of points with the same x-coordinate. So this is ok for 'functional graphs' but not for, say figures, like e.g. stars..
Maybe you just want to look at the "overshooting the bounds" problem as not a problem with the overshoot, but with the bounds. In which case, you can determine the actual bounds of a curve using the System.Drawing.Drawing2D.GraphicsPath object:
GraphicsPath gp = new GraphicsPath();
gp.AddCurve(listOfPoints);
RectangleF bounds = gp.GetBounds();
You can draw that GraphicsPath directly:
graphics.DrawPath(Pens.Black, gp);
As far as solving the bounds problem, the line necessarily overshoots the vertex on some axis. It's easier to see this fact when the lines are aligned to the bounds.
Given these points:
In order for them to be curved, they must exceed their bounds in some way:
If you never want to exceed their vertical bounds, you could simply ensure that the bezier handles have the same Y value as the vertex, but they will overshoot on the X:
Or vice-versa:
You could deliberately undershoot just enough to avoid the way curves can overshoot. This can be done by swapping the bezier handles, which would maybe be at the line-centers, with the vertices:

How to calculate the angles XYZ from a Matrix4x4

I am trying to ascertain the X,Y,Z angles held within a Matrix by decomposing the matrix. I am using .net 4.5 c#.
I created a test to check the following:
If I create an Matrix4x4 with identity values only
Rotate the matrix by 45 degrees
Decompose the matrix and evaluate the quaternion returned (gives the x,y,z angles)
Check that the X value out matches the 45 degrees put in
I get the following results:
X:0.5 Y:0 Z:0
I was expecting:
X:0.45 Y:0 Z:0
Test Code
Quaternion quatDecomposed;
Vector3D translation;
Matrix4x4 rot = Matrix4x4.RotationAroundX(45);
rot.DecomposeNoScaling(out quatDecomposed, out translation);
I have created my own Matrix4x4, Vector3D and Angle3D structures shown in the examples below.
My Matrix4x4 rotate around x method is as follows:
public static Matrix4x4 RotationAroundX(double degrees)
{
// [1, 0, 0, 0]
// [0, cos,-sin,0]
// [0, sin,cos, 0]
// [0, 0, 0, 1]
// convert degrees to radians.
double radians = DoubleExtensions.DegreesToRadians(degrees);
// return matrix.
var matrixTransformed = Matrix4x4.Identity;
matrixTransformed.M22 = (float)Math.Cos(radians);
matrixTransformed.M23 = (float)-(Math.Sin(radians));
matrixTransformed.M32 = (float)Math.Sin(radians);
matrixTransformed.M33 = (float)Math.Cos(radians);
//return matrix;
return matrixTransformed;
}
My decompose no scaling method is as follows:
public void DecomposeNoScaling(out Quaternion rotation, out Vector3D translation)
{
translation.X = this[1, 4];
translation.Y = this[2, 4];
translation.Z = this[3, 4];
rotation = new Quaternion(new Matrix3x3(this));
}
What I am looking to get out is the angles contained within the Matrix4x4, I do this as follows:
Angle3D angles = new Angle3D(quatDecomposed.X, quatDecomposed.Y, quatDecomposed.Z);
Can anyone spot what I'm doing wrong? What I am REALLY trying to work out is the Euler angles from the matrix4x4 in ZYX order.
Thanks in advance!
Shouldn't be the last row of the matrix be "1" ?
[1 0 0 0]
[0 cos -sin 0]
[0 sin cos 0]
[0 0 0 1]
(last row last column should be 1)
Just in case anyone else needs to know, this is how I get the Euler angles directly from the Matrix:
public static Angle3D GetAngles(Matrix4x4 source)
{
double thetaX, thetaY, thetaZ = 0.0;
thetaX = Math.Asin(source.M32);
if (thetaX < (Math.PI / 2))
{
if (thetaX > (-Math.PI / 2))
{
thetaZ = Math.Atan2(-source.M12, source.M22);
thetaY = Math.Atan2(-source.M31, source.M33);
}
else
{
thetaZ = -Math.Atan2(-source.M13, source.M11);
thetaY = 0;
}
}
else
{
thetaZ = Math.Atan2(source.M13, source.M11);
thetaY = 0;
}
// Create return object.
Angle3D angles = new Angle3D(thetaX, thetaY, thetaZ);
// Convert to degrees.;
angles.Format = AngleFormat.Degrees;
// Return angles.
return angles;
}

Categories