Today, Phil, Allen and I worked together on the project in the uni library. It was a great day that we have done many fixes and made the save and load knot to and from a xml file properly. We also made the undo redo working better. The project is now waiting for finalizing. We beleive that we could finish it by Thursday 26th of May.
Big thanks to Phil, Allen and Tim.
Jun
diary jun
Sunday, May 22, 2011
A string geometry calculation problem has been solved
Hi all,
The suddenly disappeared rope when creating it was found due to a very interesting floating point number calculation issue in computers: the 'NaN', not a number value.
C# defines a valid value called float.NaN for float data type. Under some circumstances, a math calcualtion would get a NaN result,
e.g.,
The additions ∞ + (−∞), (−∞) + ∞ and equivalent subtractions
The square root of a negative number.
In our project, the calcualtion for the rotation angle, rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, previousAxis)), sometimes returns a NaN as well, this is the root of the problem.
This bug has been fixed by doing---
if (rotationAngle != rotationAngle)
rotationMatrix = Matrix.Identity;
else
rotationMatrix = Matrix.CreateFromAxisAngle(rotationAxis, rotationAngle);
A new StringGeometry.cs file with the fix will be sent out soon.
Kindest regards,
Jun
The suddenly disappeared rope when creating it was found due to a very interesting floating point number calculation issue in computers: the 'NaN', not a number value.
C# defines a valid value called float.NaN for float data type. Under some circumstances, a math calcualtion would get a NaN result,
e.g.,
The additions ∞ + (−∞), (−∞) + ∞ and equivalent subtractions
The square root of a negative number.
In our project, the calcualtion for the rotation angle, rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, previousAxis)), sometimes returns a NaN as well, this is the root of the problem.
This bug has been fixed by doing---
if (rotationAngle != rotationAngle)
rotationMatrix = Matrix.Identity;
else
rotationMatrix = Matrix.CreateFromAxisAngle(rotationAxis, rotationAngle);
A new StringGeometry.cs file with the fix will be sent out soon.
Kindest regards,
Jun
Rotation problem sorted out
Hi Casey,
The rotation problem has been finally solved. Thank you so much for all your help.
Inspired by you, I changed the algorithm for creating the rope a little bit. Instead of always rotating and translating from the base circle to those positions on the central line, now we only do it for the starting circle, but for the rest of circles, each one is based on its previous circle on the central line: rotating and translating from its previous circle. By doing so, we actually avoid the need to handle the complaxity of a lot of different cases. E.g., whenever the rope goes upwards first then goes downwards, or goes forwards first then goes backwards, it has to be ended up with doing:
rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, Vector3.Up));
rotationAngle += MathHelper.Pi;
This is because the Math.Acos returns an angle always smaller than a Pi. But the rope has some cases needing the rotation bigger than Pi, otherwise a crossover (over-rotated ones) would happen, and it's very hard to cover and handle all the cases.
The new algorithm can help avoid this complexity, because the angle between previous cirle base axis and the current circle base axis will never be bigger than a Pi. Hence the problem is solved by doing this:
//get the current circle's base axis
rotationAxis = Vector3.Normalize(calVectors[i + 1] - calVectors[i]);
rotationAxis = Vector3.Normalize(calVectors[i + 1] - calVectors[i]);
//angle between circle's base axis and previous circle's base axis
rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, previousAxis));
rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, previousAxis));
//find a vector perpendicular to both the circle's base axis and the circle's base axis
rotationAxis = Vector3.Cross(rotationAxis, previousAxis);
rotationAxis.Normalize();
rotationAxis = Vector3.Cross(rotationAxis, previousAxis);
rotationAxis.Normalize();
//save current circle's base axis for next run
previousAxis = Vector3.Normalize(calVectors[i + 1] - calVectors[i]);
previousAxis = Vector3.Normalize(calVectors[i + 1] - calVectors[i]);
//construct the rotation matrix from the rotation axis and rotation angle
rotationMatrix = Matrix.CreateFromAxisAngle(rotationAxis, rotationAngle);
magicMatrix = Matrix.CreateTranslation(-calVectors[i - 1]) * rotationMatrix * Matrix.CreateTranslation(calVectors[i]);
rotationMatrix = Matrix.CreateFromAxisAngle(rotationAxis, rotationAngle);
magicMatrix = Matrix.CreateTranslation(-calVectors[i - 1]) * rotationMatrix * Matrix.CreateTranslation(calVectors[i]);
newCircle = new Vector3[baseCircle.segPointNo];
//transform from the previous to current one
Vector3.Transform(vectorCircleList[i - 1].vecotrCircle, ref magicMatrix, newCircle);
vectorCircleList.Add(newCircle);
With this new algorithm, we finally got this very nice rope:
Attempting to solve the rotation problem
Hi Casey,
Sorry for my late reply, as I was doing a lot testing on the code, trying to figure the problem out these two days. I found the over-rotation problem is not caused by this code:
else if (rotationAxis == -Vector3.Up)
{
rotationAxis = Vector3.Backward;
rotationAngle = MathHelper.Pi;
}
{
rotationAxis = Vector3.Backward;
rotationAngle = MathHelper.Pi;
}
Now I only use the following code for all cases:
rotationAxis = Vector3.Normalize(calVectors[i + 1] - calVectors[i]);
rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, Vector3.Up));
rotationAxis = Vector3.Cross(rotationAxis, Vector3.Up);
rotationAxis.Normalize();
rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, Vector3.Up));
rotationAxis = Vector3.Cross(rotationAxis, Vector3.Up);
rotationAxis.Normalize();
The problem seems to occur only when the rope goes from up to down. I'm currently looking into the secret of these two lines of code. Maybe I need to add more code to cover all cases:
rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, Vector3.Up));
rotationAxis = Vector3.Cross(rotationAxis, Vector3.Up);
rotationAxis = Vector3.Cross(rotationAxis, Vector3.Up);
Attempting to solve the rotation problem
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/base/pgrs-sm.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
Philip Davies
Jun, that is amazing. Fantastic work! Phil
5/4/2011
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![Offline](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![]() | ![]() | ![]() |
Hi Casey,
Thank you so much! You've been a great help. The code example by you is exactly what we want and it helped resolve the legacy rotation problem in our Knot_A_Problem project from last semester.
Now we can have nicer knot strings: the flat one has gone, and the string can be rotated to any direction in 3D world smoothly. Only, it seems to have been rotated too much in some areas. I'm thinking of the reasons of it. If you know what's wrong there, could you please let me know? The over-rotated ones are shown on the screenshots below:
The code used for it is as following:
rotationAxis = Vector3.Normalize(calVectors[i + 1] - calVectors[i]);
if (rotationAxis == Vector3.Up)
{
rotationAngle = 0f;
}
else if (rotationAxis == -Vector3.Up)
{
rotationAxis = Vector3.Backward;
rotationAngle = MathHelper.Pi;
}
else
{
//angle between circle's base axis and up vector
rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, Vector3.Up));
{
rotationAngle = 0f;
}
else if (rotationAxis == -Vector3.Up)
{
rotationAxis = Vector3.Backward;
rotationAngle = MathHelper.Pi;
}
else
{
//angle between circle's base axis and up vector
rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, Vector3.Up));
//find a vector perpendicular to both the circle's base axis and the up vector, this will be your rotation axis
rotationAxis = Vector3.Cross(rotationAxis, Vector3.Up);
rotationAxis.Normalize();
}
rotationAxis = Vector3.Cross(rotationAxis, Vector3.Up);
rotationAxis.Normalize();
}
//construct the rotation matrix from the rotation axis and rotation angle
Matrix rotationMatrix = Matrix.CreateFromAxisAngle(rotationAxis, rotationAngle);
Matrix rotationMatrix = Matrix.CreateFromAxisAngle(rotationAxis, rotationAngle);
Matrix magicMatrix = rotationMatrix * Matrix.CreateTranslation(calVectors[i]);
Vector3[] newCircle = new Vector3[baseCircle.segPointNo];
Vector3.Transform(baseCircle.vecotrCircle, ref magicMatrix, newCircle);
Vector3.Transform(baseCircle.vecotrCircle, ref magicMatrix, newCircle);
Do you think it's the Gimbal lock issue or do we need to make more check on the 'rotationAngle = -(float)Math.Acos(Vector3.Dot(rotationAxis, Vector3.Up));' ?
Kind regards,
Jun
From: Casey Chow [caseyc@uow.edu.au]
Sent: Thursday, April 28, 2011 6:22 AM
To: Jun Ye
Cc: Luke McAven; philip_m_davies@hotmail.com; timothy overton [timothy_overton@hotmail.com]; Xun He; jernej.cesar@gmail.com
Subject: RE: Rotation Issue - CSCI321 - From Jun
Sent: Thursday, April 28, 2011 6:22 AM
To: Jun Ye
Cc: Luke McAven; philip_m_davies@hotmail.com; timothy overton [timothy_overton@hotmail.com]; Xun He; jernej.cesar@gmail.com
Subject: RE: Rotation Issue - CSCI321 - From Jun
Hi Jun,
Following my previous email, depending on what you are trying to do, I don't think Euler angles is what you need. If I understand correctly, for your purposes what you can do is to construct the rotation matrix from an axis and an angle. I've hacked up some XNA code (attached) that shows you how to do this, you should be able to figure it out from there.
Regards,
Casey
In response to the message from Jun Ye, 4/23/2011
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/base/pgrs-sm.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
Casey Chow
Hi Jun, Following my previous email, depending on what you are trying to do, I don't think Euler angles is what you need. If I understand correctly, for your purposes what you can do is to construct the rotation matrix from an axis and an angle. I've hacked
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
4/28/2011
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![Offline](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
Thursday, April 28, 2011 6:22 AM
![]() | ![]() | ![]() |
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
Hi Jun,
Following my previous email, depending on what you are trying to do, I don't think Euler angles is what you need. If I understand correctly, for your purposes what you can do is to construct the rotation matrix from an axis and an angle. I've hacked up some XNA code (attached) that shows you how to do this, you should be able to figure it out from there.
Regards,
Casey
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/base/pgrs-sm.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
Casey Chow
Hi Jun, Apologies for the late reply. I think you've got the wrong idea about Euler angles, matrices and quaternions. Whether or not you use Euler angles or quaternions, you still perform transformations using matrices (in XNA Matrix.CreateFromQuaternion(quaternion);
4/27/2011
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![Offline](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![Offline](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![Offline](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![Offline](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![Offline](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
![Offline](https://r3.res.outlook.com/owa/14.1.225.52/themes/resources/clear1x1.gif)
Wednesday, April 27, 2011 7:45 PM
![]() | ![]() | ![]() |
Hi Jun,
Apologies for the late reply.
I think you've got the wrong idea about Euler angles, matrices and quaternions. Whether or not you use Euler angles or quaternions, you still perform transformations using matrices (in XNA Matrix.CreateFromQuaternion(quaternion); )
However, if I understand you correctly, what you're asking instead (from "The problem is how we could calculate the Euler angle... ") is how to calculate the Euler angles from Vector.Up to the rotated vector?
If so, you can do this by calculating the projection of the rotated vector onto the xz, yz, and xy planes, then finding the individual angles between the projected vectors and the x, y, and z reference vectors respectively.
Regards,
Casey
Attempting to solve the rotation problem
Hi Casey,
I'm still working on resolving the rotation problem, but haven't been able to get a correct yaw, pitch and roll.
If I understood Matrix and Quaternion correctly, they can both be used to do rotations. In the case of rotation, Matrix could possibly have the Gimbal lock issue, but Quaternion is partiqularly designed to avoid this problem and Quaternion has better performance on intensive rotation calculation.
As illustrated below, suppose I have two normalized Vector3 representing two directions, how can I get the correct values of yaw, pitch and roll from the difference between this two directions:
I'm still working on resolving the rotation problem, but haven't been able to get a correct yaw, pitch and roll.
If I understood Matrix and Quaternion correctly, they can both be used to do rotations. In the case of rotation, Matrix could possibly have the Gimbal lock issue, but Quaternion is partiqularly designed to avoid this problem and Quaternion has better performance on intensive rotation calculation.
As illustrated below, suppose I have two normalized Vector3 representing two directions, how can I get the correct values of yaw, pitch and roll from the difference between this two directions:
Cheers,
Jun
Attempting to solve the rotation problem
For now, I'd like to jsut post couples of my emails as my diaries:
Hi Casey,
How are you? This is Jun once doing CSCI336 and 356 under you. Haven't seen you around Wollongong campus for a long time, I'm wondering that you are probably in Singapore at the moment.
I'm currently doing CSCI321 project and this is my last semester in my bachelor degree. A group of us are doing a software project called Knot under Luke. The software is to allow users to create and learn how to tie some knots, like this:
We are currently facing a difficulty and although tried many methods many times, we cannot solve it properly. Could you do us a favor and help?
The problem is as bellow:
We use a set of base points (a cycle in the 0 position of the world) as the reference. We calculate a central line (a cubic curve calcuated using a set of control points). Then for each point we pick up on the central line, we try to use Matrix.CreateTranslation and Matrix.CreateRotation to copy, move and rotate the base cycle to get the surface points we want on the cube. The following code is what we are using. It seems only the translation is working:
Matrix magicMatrix = Matrix.CreateTranslation(calVectors[i]); // calVectors[i] is a point on the central line
Vector3[] newCycle = new Vector3[cyclePointNumber]; // cyclePointNumber is the number of points we take from the base cycle
Vector3.Transform(baseCircle, ref magicMatrix, newCycle); // baseCircle is Vector3[]
Vector3[] newCycle = new Vector3[cyclePointNumber]; // cyclePointNumber is the number of points we take from the base cycle
Vector3.Transform(baseCircle, ref magicMatrix, newCycle); // baseCircle is Vector3[]
By doing so, we get some unwanted cube geometries --- when the geometry goes horixontally, it becomes flat, as shown on the image bellow:
To solve this problem, we tried something like:
Vector3 currentCircleDirection = calVectors[i+1] - calVectors[i];
currentCircleDirection.Normalize(); // get the current direction of the current point on the central line
currentCircleDirection.Normalize(); // get the current direction of the current point on the central line
Matrix magicMatrix = Matrix.CreateTranslation(calVectors[i]); // move to new position
After translation, how can I use the currentCircleDirection to rotate the circle properly? Using Matrix.CreateRotationX, or Y, or Z? Or do something like magicMatrix.Forward = currentCircleDirection?
We tried many formulars and tests, but all failed. How can I use the currentCircleDirection to not only make the magicMatrix have the right info of the new position, but also have the right direction (rotation)?
Thanks very much for your time Casey!
Warm regards,
Jun
Subscribe to:
Posts (Atom)