I am using this equation to work out the angles of my x, y and z compared to gravity:
directionalVector = Math.Sqrt(Math.Pow(accelForceX, 2) + Math.Pow(accelForceY, 2) + Math.Pow(accelForceZ, 2));
accelAngleX = (Math.Acos(accelForceX / directionalVector) * (180f / Math.PI)); ;
accelAngleY = (Math.Acos(accelForceY / directionalVector) * (180f / Math.PI));
accelAngleZ = (Math.Acos(accelForceZ / directionalVector) * (180f / Math.PI));
accelForceN is a reading from an accelerometers axis, measured in G's
This way produces a range of result from 0-180degress, no negative numbers.
How can I find the sign of the angles?
I think you are confused about what you are actually calculating here. Make sure you are aware that you are simply calculating the angle by using the definition of cosinus:
cos(accelAngleN*2*Math.Pi/360) = accelForceN/directionalVector
(the multiplication with 2Pi/360 merely transforms an angle into Radian). Now consider that the angular sum in a triangle is 180° and thus in this case a negative angle or an angle larger than 180° as result would not make any sense. This is just another way of looking at the fact that cos is not injective over the whole field of real numbers and thus arccos is defined as function on [-1,1] -> [0,Pi] (or [0°,180°] for that matter).
So what you are currently calculating is the angle of your x/y/z-vectors to your directional vector (rather than to gravity, which would be the z-achsis direction anyways, wouldn't it?) and from this standpoint your output is perfectly valid.
If you need help with transforming your result any further, please provide an example (2 dimensional should be good enough for the sake of simplicity) of what you are expecting.
Related
I have a Vector with 3 components (X,Y,Z) and i want to find a Vector orthogonal to the given one. Since the Vectors orthogonal to any Vector are infinite, i just need one that is randomic.
I've tried using an equation with the Dot Product formula, since the dot product between two orthogonal Vectors is always 0, and I managed to write a bit of code that works only when the given Vector is axis-aligned, but that is probably because the randomized components of the vectors are X and Y. I really can't get my head around this.
I wrote my code on the Unity3D engine in order to be able to easly visualize it:
Vector3 GenerateOrthogonal(Vector3 normal)
{
float x = Random.Range(1f, -1f);
float y = Random.Range(1f, -1f);
float total = normal.x * x + normal.y * y;
float z = -total / -normal.z;
return new Vector3(x, y, z).normalized;
}
There are a few methods for doing this. I'll provide two. The first is a one-liner that uses Quaternions to generate a random vector and then rotate it into place:
Vector3 RandomTangent(Vector3 vector) {
return Quaternion.FromToRotation(Vector3.forward, vector) * (Quaternion.AngleAxis(Random.Range(0f, 360f), Vector3.forward) * Vector3.right);
}
The second is longer, more mathematically rigorous, and less platform dependent:
Vector3 RandomTangent(Vector3 vector) {
var normal = vector.normalized;
var tangent = Vector3.Cross(normal, new Vector3(-normal.z, normal.x, normal.y));
var bitangent = Vector3.Cross(normal, tangent);
var angle = Random.Range(-Mathf.PI, Mathf.PI);
return tangent * Mathf.Sin(angle) + bitangent * Mathf.Cos(angle);
}
Here are some notes on their differences:
Both of these functions generate a random perpendicular vector (or "tangent") with a uniform distribution.
You can measure the accuracy of these functions by getting the angle between the input and the output. While most of the time it will be exactly 90, there will sometimes be very minor deviations, owing mainly to floating point rounding errors.
While neither of these functions generate large errors, the second function generates them far less frequently.
Initial experimentation suggests the performance of these functions is close enough that the faster function may vary depending on platform. The first one was actually faster on my machine for standard Windows builds, which caught me off guard.
If you're prepared to assume that the input to the second function is a normalized vector, you can remove the explicit normalization of the input and get a performance increase. If you do this and then pass it a non-normalized vector, you'll still get a perpendicular vector as a result, but its length and distribution will no longer be reliably uniform.
In the degenerate case of passing a zero vector, the first function will generate random vectors on the XY plane, while the second function will propagate the error and return a zero vector itself.
I'm using GDI+ to implement some simple graphics, I've taken the code from this example http://www.vcskicks.com/3d_gdiplus_drawing.php and can get it to do what I want, but I don't understand how it's doing the conversion from 3D data point to 2D data point:
//Convert 3D Points to 2D
Math3D.Point3D vec;
for (int i = 0; i < point3D.Length; i++)
{
vec = cubePoints[i];
if (vec.Z - camera1.Position.Z >= 0)
{
point3D[i].X = (int)((double)-(vec.X - camera1.Position.X) / (-0.1f) * zoom) + drawOrigin.X;
point3D[i].Y = (int)((double)(vec.Y - camera1.Position.Y) / (-0.1f) * zoom) + drawOrigin.Y;
}
else
{
tmpOrigin.X = (int)((double)(cubeOrigin.X - camera1.Position.X) / (double)(cubeOrigin.Z - camera1.Position.Z) * zoom) + drawOrigin.X;
tmpOrigin.Y = (int)((double)-(cubeOrigin.Y - camera1.Position.Y) / (double)(cubeOrigin.Z - camera1.Position.Z) * zoom) + drawOrigin.Y;
point3D[i].X = (float)((vec.X - camera1.Position.X) / (vec.Z - camera1.Position.Z) * zoom + drawOrigin.X);
point3D[i].Y = (float)(-(vec.Y - camera1.Position.Y) / (vec.Z - camera1.Position.Z) * zoom + drawOrigin.Y);
point3D[i].X = (int)point3D[i].X;
point3D[i].Y = (int)point3D[i].Y;
}
}
I've found a couple of resources which discuss conversion from a 3d data point to a 2d one:
https://amycoders.org/tutorials/3dbasics.html
https://en.wikipedia.org/wiki/Isometric_projection
https://en.wikipedia.org/wiki/3D_projection
However none of these resources seem to detail the maths used in the above example.
I'd be really grateful if someone could point me at the derivation for the maths and/or explain how the above code works.
The article and code is a bit confusing, indeed. Before we start, let's do some modifications to the rest of the code. Through these modifications, you will probably see what's going on more easily. Let's specify a static camera position. Instead of this weird formula:
double cameraZ = -(((anchorPoint.X - cubeOrigin.X) * zoom) / cubeOrigin.X) + anchorPoint.Z;
Let's just do this:
cameraZ = 200;
zoom = 100;
And after that, we keep
camera1.Position = new Math3D.Point3D(cubeOrigin.X, cubeOrigin.Y, cameraZ);
This will position the camera at a depth of 200 such that its x/y coordinates coincide with the cube center. I'll come back to the meaning of zoom.
The camera model uses a perspective projection and a right-handed coordinate system. That means that the camera look in the negative z-direction and things that are far away will appear smaller.
Let's take a closer look at the 3D->2D conversion code step by step:
if (vec.Z - camera1.Position.Z >= 0)
vec is the point that we want to project. A more intuitive way to write that would be:
if (vec.Z >= camera1.Position.Z)
So, this branch applies to all points that are behind the camera (remember that the camera looks into the negative z-direction). What happens in this branch is a bit hacky. It has nothing to do with real projections. What you actually want to do is to cut off those points (as they are not visibile). Luckily, in the example, none of the points lie behind the camera. So, we don't need to care about this. I'll come back to that later.
Let's continue to the else branch.
tmpOrigin = ...
This variable is not used anywhere, so we can ignore it.
point3D[i].X = (float)((vec.X - camera1.Position.X) / (vec.Z - camera1.Position.Z) * zoom + drawOrigin.X);
This is the actual projection (I will only consider the X part. The same goes for the Y part). Let's take a look at the individual parts:
vec.X - camera1.Position.X
This is the vector from the camera position to the point drawn. Everything left of the camera has a negative coordinate, everything right of the camera has a positive coordinate.
vec.Z - camera1.Position.Z
This is the negative depth of the camera. Not sure why the negative depth is used here. This will give you a mirrored image. What you actually wanted to do is (due to the camera looking into the negative z-axis)
camera1.Position.Z - vec.Z
Then,
(vec.X - camera1.Position.X) / (vec.Z - camera1.Position.Z)
is the perspective divide. The difference vector is scaled by its inverse depth (i.e. far objects become smaller).
* zoom
This scales the image from world space (which is very small) to image space (convert world units to pixels). The factor is kind of arbitrary (that's why we just specified 100). More involved camera models use a field of view.
drawOrigin.X
And finally, we align the camera center to the drawOrigin. Remember that points left of the camera had a negative coordinate. With this, these will get a positive coordinate (but still be left of drawOrigin).
point3D[i].X = (int)point3D[i].X;
This is just a cast to int.
For the y-coordinate, there is an additional -. This turns the y-axis around (in the pixel coordinate system of the image, the y-axis points downwards).
Let's go back to the hacky if branch. You see that the formula is exactly the same. Except that the part that had the negative depth of the point before now has (-0.1f). So these points will be considered having a constant depth of 0.1. Pretty dubious and far from actual projections.
And that's basically it. One more note: The article has a section about Gimbal lock. Thing is, the properties of matrix multiplications that are described there have nothing to do with Gimbal lock. So, don't rely on this article too much. It's a nice practical application, but it has quite some flaws.
I'm trying to create a .bvh file via kinect.
It means in need to get rotations of each bone of a skeleton. I need the rotations in Euler angles. I already tried many different approaches, but any of them gave me good result. Could anyone give me some advice what am I doing wrong?
Here is (I think) the main part of my code.
foreach (Skeleton skeleton in newSkeleton)
{
if (skeleton.TrackingState != SkeletonTrackingState.Tracked)
continue;
int j = 0;
foreach (BoneOrientation orientation in skeleton.BoneOrientations)
{
Matrix4 matrix = orientation.HierarchicalRotation.Matrix;
double y = Math.Asin(matrix.M13);
double x = Math.Atan2(-matrix.M23, matrix.M33);
double z = Math.Atan2(-matrix.M12, matrix.M11);
rotationMatrix[j, 0] = x * 180 / Math.PI;
rotationMatrix[j, 1] = y * 180 / Math.PI;
rotationMatrix[j, 2] = z * 180 / Math.PI;
j++;
}
}
My euler angles should be stored in the rotationMatrix array for further use (saving into bvh file). Here comes my problem... the rotations calculated this way doesn't make sense (I mean they have nothing to do with the position of me ahead of kinect) and they seems to be random.
Edit:
I would also need to explain some unclear topics about kinect. I tried to Google it, but didn't succeed.
Does kinect skeleton have something like zero pose? I mean any pose where all bone rotations are zero. (e.g. T-pose and so on)
What kind of standards does kinect use? I mean how does kinect store data into rotation matrices? I would like to know if the matrix is like
[X1, Y1, Z1,
X2, Y2, Z2,
X3, Y3, Z3]
or does it use some other order?
About the marices.. Is it possible to calculate Euler angles from the matrix given by kinect in standard way? I mean some of algorithms mentioned in this paper?
http://www.geometrictools.com/Documentation/EulerAngles.pdf
OK, after some more time spend researching, i think i might be able to answer some of mine questions. If is anyone interested...
i havent found any zero pose, but i created my own using some kind of calibration. I saved rotation matrices for my chosen zero pose (let's call these Mz), made these matrices trandposed (MzT) and I multiplied all the next matrices kinect gave me (let's call these Mr).
It means I calculated matrices for further use this way: M = MzT x Mr.
I used the conversion from link in 3. question for Rxyz order and all worked well, it means the rotation matrices given by kinect probably have the order given in the question. This should be answer to the third question as well.
So I'm coding a synthesizer from scratch in C# using NAudio. I've gotten it play different frequencies, which is cool, but I notice that the higher pitches are significantly louder than the lower pitches. Is that due to this effect:
http://en.wikipedia.org/wiki/Equal-loudness_contour
Or am I doing something wrong when I'm generating the sine wave? How would I implement an Equal-loudness contour curve if it is indeed necessary?
Thanks
My Code:
NAudio expects a buffer filled with floating point values in the range of -1 to +1 to represent the waveform.
Generating the sine wave:
buffer[n + offset] = (float)(Amplitude * Math.Sin(angle));
angle = (angle + angleIncrement) % (2 * Math.PI);
Setting a frequency:
public double Frequency
{
set
{
angleIncrement = 2 * Math.PI * value / sampleRate;
}
get
{
return angleIncrement * sampleRate / 2 / Math.PI;
}
}
Controlling the amplitude of the audio from your synthesizer based on equal-loudness contours is probably not what you want.
In theory, you would need to know the absolute level (SPL) produced by the speakers in order to choose the appropriate contour. In practice, a bigger issue would be when you extend your synthesizer to use complex waveforms instead of merely pure tones, possibly processed by filters etc. The equal-loudness contours are based on pure tones, and when you generate complex signals (i.e. containing many frequencies) you would instead need a loudness model to estimate the loudness of your synthesized sound.
I originally posted a much simpler (and less helpful) question, and have edited this to be more specific.
This animation from wikipedia shows basically what I want to accomplish, however - I'm hoping to have it flipped around, where it starts progressing more towards the destination and "up" (in this image), and then arcs more directly to the end point. However, I only have access to a starting point and ending point, what I am hoping to do is be able to determine the other points by specifying a "height" (or width, whatever you want to call it), to determine how high the arc actually goes.
http://en.wikipedia.org/wiki/File:Bezier_3_big.png (can't post image due to low rep)
I would like to be able to call a function with the start and end points and a height, and have it return all the points along the way of the curve.
Help or direction would be appreciated.
I have wrapped up a blog for calculating Bezier curve Angle and to determine its various points in my blog http://johnexalt.wordpress.com/2011/05/21/bezier-curve-angle-calculation-silverlight/
the code below shows how to calculate the bezier curve points at any given value of t(where t ranges from 0 to 100 % and is represented in 0- 1.
x = ((1 - t) * (1 - t) * p0.X) + (2 * t * (1 - t) * p1.X) + (t * t * p2.X);
//this statement is used to determine the x coordinate of the curve.
y = ((1 - t) * (1 - t) * p0.Y) + (2 * t * (1 - t) * p1.Y) + (t * t * p2.Y);
//this statement is used to determine the y coordinate of the curve.
x = Math.Round(x, 3);
y = Math.Round(y, 3);
angle = Math.Round(Angle(xold, yold, x, y), 3);
There was a previous article given by Carlos Femmer which helps in calculating the angle between 2 points. http://www.carlosfemmer.com/post/2006/02/Calculate-Angle-between-2-points-using-C.aspx.
Without loss of generality, suppose the ending point is on the x axis and the starting point is above and to the left of the ending point.
Imagine the starting point is at the top of a cliff, and the ending point is at the bottom of a cliff. Imagine you throw a ball horizontally from the starting point, such that gravity will pull it down so that it smacks exactly into the ending point.
That curve seems to have the properties you want. It starts shallow and then increases towards the vertical as the ball accelerates.
By changing the angle at which you throw the ball initially you can make the curve more shallow at the beginning. By changing the strength of gravity you can make it more steep at the end.
Does that curve fit your needs? Finding that curve is a pretty basic physics problem.
There seems to be a mechanism in .NET that can help you:
Graphics.DrawCurve
Draws a cardinal spline through a
specified array of Point structures
Also, a quick Google search found these
Writing Name Using Bezier Curves In C#
http://www.codeproject.com/KB/recipes/BezirCurves.aspx
http://www.codeproject.com/KB/cs/SplineInterpolation.aspx
http://www.c-sharpcorner.com/UploadFile/apundit/DrawingCurves11182005012515AM/DrawingCurves.aspx
You basically want a bezier curve with three control points - the start point, the end point and another point somewhere in between.
If the start point 1 is ( x1, y1 ) and the end point 2 is ( x2, y2 ) then the vector from point 1 to point 2 is ( dx = x2-x1, dy = y2-y1 ).
A point along the line by an amount along between zero and one is ( x1 + along * dx, y1 + along * dy ).
The vector ( -dy, dx ) is at right angles to the line, so if you want to go off the line by an amount above then the middle point would be ( x1 + along * dx - above * dy, y1 + along * dy + above * dx).
Vary the values of along and above until you find the sort of skewed curve you want.
Apart for the start-point and the end-point you need to describe the ”angle” or curvature of the arc. A Bezier curve can be good but they are usually implemented with longer sequences of points (as the curvature of the arc is defined by the other points in the line). Have a look at http://en.wikipedia.org/wiki/B%C3%A9zier_curve , at the bottom you can find some information about ”Quadratic curves”. I bet a quick google search will give you some implementation examples.