C# -Trigonometric code explaination (Physics) - c#

This piece of code has been taken from a game built with XNA framework. I'd like some explanation of how it works in terms of trig and physics.
ball.velocity = new
Vector2((float)Math.Cos(cannon.rotation),
(float)Math.Sin(cannon.rotation));
ball.rotation is the rotation of a sprite in what i should think, radians.
Why is it that they can use the angle in radians only to find the x position then the same thing to find the y position of a direction of where the hypotenuse is pointing.
Reason why I asked this. I would like to get a feel of how this frameworks does calculations for trig. I am trying to get a sprite to turn in the direction of where the mouse is, that is: x and y is known, i just need the angle.
So there are 2 questions here. explaining that code above and pointing a sprite in the direction of a known point.
Update:
I found out that the point a which the object is at is not (0,0) because xna uses inverse coordinate system. So now the variables I have are these:
point of object.
point of mouse.

Every angle corresponds to a point on the unit circle (the unit circle is the unique circle centered at the origin with radius one; that is, the unit circle is the set of points satisfying x^2 + y^2 = 1). The correspondence is the following: given an angle theta, theta corresponds to the point (cos theta, sin theta). Why does (cos theta, sin theta) live on the unit circle? Because of everyone's favorite identity
cos^2 theta + sin^2 theta = 1.
That is with x = cos theta and y = sin theta, the point (x, y) satisfies x^2 + y^2 = 1 so that (x, y) is on the unit circle.
To reverse this, given a point on the unit circle you can find the angle by using the inverse tangent (perhaps known to you as arctan or atan and sometimes tan-1). Precisely, given (x, y) on the unit circle you can find the angle corresponding to (x, y) by computing theta = arctan(y / x).
Of course, there are some messy details here. The function arctan can't tell the difference between the inputs (x, y) and (-x, -y) because y / x and (-y / -x) have the same sign. Further, arctan can't handle inputs where x = 0. So we typically handle these by defining the function atan2 that will handle these messy details for us
atan2(y, x) = arctan(y / x) if x > 0
= pi + arctan(y / x) if y >= 0, x < 0
= -pi + arctan(y / x) if y < 0, x < 0
= pi / 2 if y > 0, x = 0
= -pi / 2 if y < 0, x = 0
= NaN if y = 0, x = 0
In C#, Math.Atan is the function arctan that I have referred to above, and Math.Atan2 is the function atan2 that I have referred to above.

|
y.-----* P
| /|
| / |
| r/ |
| / a |
|/)___.__
O x
we have:
a = angle in radians
O: origin
P: known point
r: distince between O & P
to calculate x, y:
x = r*cos(a)
y = r*sin(a)
(in your example : r = 1, a = cannon.rotation)
Now, if you have x, y and you want a:
if x!= 0 a = atan(y/x)
otherwise a = sign(y)*Pi/2
for more informations (& prettier graphs): Wikipedia: Polar coordinate system

You can see cos and sin returning the point on a circle.
In that respect see the middle of the canon as the center of the circle. Then given an angle (the angle of the canon) you can get the position on the circle it points to with sin and cos.
If you think of the cannon being centered on the 0,0 position, then this value is also the direction the bullet should travel to.
answer2: if you know x and y and you need to know the angle..you need the atan function which returns the angle formed from the sloping side of the triangle where one point is 0,0, the other point is the x,y point and one point is a point which is at the 90 degree angle

Sadly, this is a good question where SO isn't the best format to answer in.
Instead of explaining in text, I think it would be helpful to learn about parametric equations. You can start by searching "circle parametric equation" in Google.
The way that this concept clicked for me was to experiment with different pieces of code until I understood the relation between sin, cos, circles, and angles. Seeing pictures and images help a lot as well. Before then I would read descriptions but could never firmly grasp the explanations.

What you're asking is difficult to explain if you're not familiar with trig.
The line of code in question calculates a unit vector for the direction of the ball, that I presume will be fired from the cannon. The Cos and Sin part of things extract the X and Y components, respectively, of the cannon's angle. So, where the cannon points, that's the direction the ball shoots.
It's a little misleading because the result is most likely only a direction, not an actual velocity. I would assume there's a line below that one that multiplies that vector by a constant, to give the ball its final movement speed.

Related

Reverse of Atan2 with det and dot product of two vectors as input

I have a piece of code that returns the angle between two vectors in the range of [0,360]. For this I used this question: Direct way of computing clockwise angle between 2 vectors. Now I need to create a function that takes a vector and an angle as input and returns a vector, that has the specified angle with the inputvector. The length of this vector doesn't matter. For this, I need to know how to reverse the effect of Atan2. The rest is pretty simple math.
internal virtual double AngleWith(Vector2 direction, Vector2 location)
{
Vector2 normDir = Vector2.Normalize(direction);
Vector2 normLoc = Vector2.Normalize(location);
double dot = (normDir.X * normLoc.X) + (normDir.Y * normLoc.Y);
double det = (normDir.X * normLoc.Y) - (normDir.Y * normLoc.X);
return Math.Atan2(-det, -dot) * (180 / Math.PI) + 180;
}
Any help is appreciated.
I don't know what you need this for, but arguably there is merit in transforming your vectors from the x,y-coordinate system to the polar coordinate system, in which points in a plane are given by their distance from the origin and the angle to a reference vector (for instance the x-axis in the explanation below), or
To convert from (x, y) to (r, t) with r being the distance between (x,y) and (0,0) and t being the angle in radians between the x-axis and the line connecting (0, 0) and (x, y), you use this:
(r, t) = (sqrt(x^x+y^y), atan(y/x))
The result can be stored in Vector2, just like with x and y. You just have to remember that the values inside don't signify x and y.
If you want the difference in angle, you can just subtract t2 and t1 of your polar coordinates (in radians, still need to convert to degrees).
If you need to add a certain angle in degrees, just add or subtract it to the t value of your polar coordinate.
To convert back to x and y, use
(x, y) = (r cos(t), r sin(t))
The typical way to do this is with a rotation matrix.
RotatedX = x * sin ϴ - y * sin ϴ
RotatedY = x * sin ϴ + y * cos ϴ
Or use System.Numerics.Matrix3x2.CreateRotation(angle) and use it to transform your vector. Note that 'Clockwise' may depend on what coordinate conventions are used. So you might need to adjust the formula depending on your convention.

Check if a 3D Point lies on a given 3D line(between two 3D Points)

I have two 3D Points viz. (x1,y1,z1) and (x2,y2,z2) and a 3D Point (x,y,z).
I would like to know if (x,y,z) lies on the line connecting (x1,y1,z1) and (x2,y2,z2).
I tried the following algorithm:
if ((((x - x1) / x2-x1) == ((y - y1) / y2-y1)) && (((x - x1) / x2 - x1)
== ((z - z1) / z2- z1)) --> then,the 3D Line intersects (x,y,z)
But,what if my x1 = x2 (or) y1 = y2 (or) z1=z2? Then I would be getting an error saying "Division by zero" is not possible.
I would be glad,if someone can propose some alternative method.
Thanks in Advance.
I would use point-line distance measurement, and return true if the distance is less than some error threshold close to zero.
To elaborate, we are using a line made of two points, p1 and p2. We want to know if p3 is on the line. First we find d using the point-to-line distance formula.
d = ((p0 - p1).cross(p0 - p2)).length() / (p2 - p1).length()
That is, assuming you can use +, -, cross, length operations. You might prefer to find d squared for performance reasons.
d2 = ((p0 - p1).cross(p0 - p2)).lengthSquared() / (p2 - p1).lengthSquared()
Now, if d or d2 are exactly zero, then you must be on the line. But this is floating point arithmetic so I would allow a little bit of leeway depending on your application. So in essence, d < 1e6 or something should do the trick.
simple dot product can do this easily ... so let consider we got line defined by two points p0,p1. Any point p on that line will have the same or negative slope to any of the endpoints so
|dot(p1-p0,p-p0)|/(|p1-p0|*|p-p0|) = 1.0
to make it more robust with floating point compare like this:
|dot(p1-p0,p-p0)|/(|p1-p0|*|p-p0|) >= 1.0-1e-10;
Where 1e-10 is small enough epsilon ... rewriten to code:
dx=x1-x0;
dy=y1-y0;
dz=z1-z0;
ex=x-x0;
ey=y-y0;
ez=z-z0;
q =dx*ex;
q+=dy*ey;
q+=dz*zy;
q*=q;
q/=(dx*dx+dy*dy+dz*dz);
q/=(ex*ex+ey*ey+ez*ez);
if (q>=1.0-1e-10) point p(x,y) is on the line
else p(x,y) is not on line
As you can see no need for the sqrt we can compare the power instead ...
However you should handle edge case when p==p0 then either use p1 or return true right away.
In case you want points only inside the line segment (not outside the edge points) then you need a slight change in code
0.0 <= dot(p1-p0,p-p0)/|p-p0| <= 1.0
So:
dx=x1-x0;
dy=y1-y0;
dz=z1-z0;
ex=x-x0;
ey=y-y0;
ez=z-z0;
q =dx*ex;
q+=dy*ey;
q+=dz*zy;
if (q<0.0) p(x,y) is not on line
q*=q;
q/=(ex*ex+ey*ey+ez*ez);
if (q<=1.0) point p(x,y) is on the line
else p(x,y) is not on line
btw the result of the dot product gives you ratio of one vector projected to another perpendicularly or cos of the angle between them (if they are normalized) so for parallel vectors the result is 100% of length or 1.0. If you tweak the 1e-10 value using goniometry and p-p0 you can convert this to detect points up to some perpendicular distance to line (which might get handy for thick lines and or mouse selecting).
To solve the above-mentioned problem you need to check the area of the triangle considering them as 3 points in the 3-d space. To find the area go through this link. If area = 0 then given points are collinear.
if you are not concerned about performance issue you can use the parametric equation of a segment in the space.
P(t) = P0 + t(P1 - P0)
where P0 and P1 are 3d point and t is a parameter ranging from 0 to 1.
this lead to 3 equations
x(t) = x0 + t(x1 - x0)
y(t) = y0 + t(y1 - y0)
z(t) = z0 + t(z1 - z0)
so to check if your (x,y,z) point lies in the line, you could get an initial value for t, for example t = (x - x0)/(x1-x0) then check if that satisfies the other two equations
t = (x - x0)/(x1-x0)
if ( (y0 + t(y1-y0) == y) and (z0 + t(z1-z0) == z) ) then
---> we are in the line
Like #Jay pointed out, this is floating point math you have to deal with some tolerance with values. For example to test y could be y0 + t(y1-y0) - y < 0.001
As you yourself point out, doing this in a robust way is not trivial. Therefore, I suggest you don't reinvent the wheel and use a geometric library. I have good experience with using Wild Magic from geometrictools.com.
In your case, the predicate to use would be gte::DCPQuery to get the distance between a point and the line, and then test if it's close enough to zero for your purpose of "on the line."
An example of use could look like this:
using namespace gte;
Line3<double> line({x1, y1, z1}, {x2 - x1, y2 - y1, z2 - z1});
Vector3<double> point{x, y, z};
DCPPoint3Line3 query;
auto result = query(point, line);
bool pointIsOnLine = (result.distance < some_epsilon);
(Code note touched by compiler, intended to show the approach, not to be "semicolon-perfect").

I have a list of points and would like to determine if they form a circle

I'm using C#, I have a list of Vector points and would like to try and approximate how close they look like a circle.
Any ideas how to implement this or if someone else has?
Based on the "gestures" tag I guess you not only want to know how close are these points to the smallest-circle (search for "Smallest-circle problem"), but you have to be concerned also about their order and spread:
I would start with the distance from the smallest-circle. If they are too far, you're done, it's not a circle.
If they are close enough to your configured threshold, compute the angle between the vector defined by the circle center, first point and each other point (picture bellow)
Check that each angle is greater than the previous.
Check that difference between any two angles next to each other is not over some configured threshold.
Check that the last point is close enough to the first one.
You will probably think of some other checks eventually, so make it simple to extend.
Another possibility:
Find the centroid
(http://en.wikipedia.org/wiki/Centroid#Of_a_finite_set_of_points) of
the points
Determine the distance (radius) of each point from the location of
the centroid
Calculate the distribution and determine if the points
are within acceptable tolerances (e.g. standard deviation < ±0.05 × mean radius or something like that)
Without knowing more about the source of the points, it's hard to suggest the best solution.
These might be of use: http://link.springer.com/article/10.1007%2FBF02276879#page-1 and http://www.dtcenter.org/met/users/docs/write_ups/circle_fit.pdf. Those methods will give you the best fitting circle through the points, but you are still going to need to determine whether your data points are close enough for your purposes.
UPDATE: based on the 'gesture' tag, somebody has already implemented it: http://depts.washington.edu/aimgroup/proj/dollar/
1) Pick any three points from that list, find the center of their appropriate circle
We can do this, using triangle circumcircle construction method, you find the medians of all three sides (two are sufficient) and their intersection is the center of the circle. Something like this:
public PointF findCenter(PointF a, PointF b, PointF c)
{
float k1 = (a.Y - b.Y) / (a.X - b.X) //Two-point slope equation
float k2 = (a.Y - c.Y) / (a.X - c.X) //Same for the (A,C) pair
PointF midAB = new PointF((a.X + b.X) / 2, (a.Y + b.Y) / 2) //Midpoint formula
PointF midAC = new PointF((a.X + c.X) / 2, (a.Y + c.Y) / 2) //Same for the (A,C) pair
k1 = -1*k1; //If two lines are perpendicular, then the product of their slopes is -1.
k2 = -1*k2; //Same for the other slope
float n1 = midAB.Y - k1*midAB.X; //Determining the n element
float n2 = midAC.Y - k2*midAC.Y; //Same for (A,C) pair
//Solve y1=y2 for y1=k1*x1 + n1 and y2=k2*x2 + n2
float x = (n2-n1) / (k1-k2);
float y = k1*x + n1;
return new PointF(x,y);
}
2) Check if the other points are equivalently distanced from this center, if yes, you have a circle, if no, you don't.
P.S. I haven't tested the code, so be prepared to debug. Ask if you need anything else
Take any three points from your point set.
If the points are co-linear then, your point set doesn't all lie on a circle.
Find the circumcircle of the triangle. The diameter is given by: d = (a*b*c)/2*area. The center of the circle is the point of intersection of the perpendicular bisectors of the three sides.
Now for every remaining point in the point set, if the distance from the center is not equal to the radius then the points are not on a circle. You can speed up the calculations by comparing the square of the radius against the square of the distance between the given point and the center.

Find the point on a circle with given center point, radius, and degree

It's been 10 years since I did any math like this... I am programming a game in 2D and moving a player around. As I move the player around I am trying to calculate the point on a circle 200 pixels away from the player position given a positive OR negative angle(degree) between -360 to 360. The screen is 1280x720 with 0,0 being the center point of the screen. The player moves around this entire Cartesian coordinate system. The point I am trying trying to find can be off screen.
I tried the formulas on article Find the point with radius and angle but I don't believe I am understanding what "Angle" is because I am getting weird results when I pass Angle as -360 to 360 into a Cos(angle) or Sin(angle).
So for example I have...
1280x720 on a Cartesian plane
Center Point (the position of player):
let x = a number between minimum -640 to maximum 640
let y = a number between minimum -360 to maximum 360
Radius of Circle around the player: let r always = 200
Angle: let a = a number given between -360 to 360 (allow negative to point downward or positive to point upward so -10 and 350 would give same answer)
What is the formula to return X on the circle?
What is the formula to return Y on the circle?
The simple equations from your link give the X and Y coordinates of the point on the circle relative to the center of the circle.
X = r * cosine(angle)
Y = r * sine(angle)
This tells you how far the point is offset from the center of the circle. Since you have the coordinates of the center (Cx, Cy), simply add the calculated offset.
The coordinates of the point on the circle are:
X = Cx + (r * cosine(angle))
Y = Cy + (r * sine(angle))
You should post the code you are using. That would help identify the problem exactly.
However, since you mentioned measuring your angle in terms of -360 to 360, you are probably using the incorrect units for your math library. Most implementations of trigonometry functions use radians for their input. And if you use degrees instead...your answers will be weirdly wrong.
x_oncircle = x_origin + 200 * cos (degrees * pi / 180)
y_oncircle = y_origin + 200 * sin (degrees * pi / 180)
Note that you might also run into circumstance where the quadrant is not what you'd expect. This can fixed by carefully selecting where angle zero is, or by manually checking the quadrant you expect and applying your own signs to the result values.
I highly suggest using matrices for this type of manipulations. It is the most generic approach, see example below:
// The center point of rotation
var centerPoint = new Point(0, 0);
// Factory method creating the matrix
var matrix = new RotateTransform(angleInDegrees, centerPoint.X, centerPoint.Y).Value;
// The point to rotate
var point = new Point(100, 0);
// Applying the transform that results in a rotated point
Point rotated = Point.Multiply(point, matrix);
Side note, the convention is to measure the angle counter clockwise starting form (positive) X-axis
I am getting weird results when I pass Angle as -360 to 360 into a Cos(angle) or Sin(angle).
I think the reason your attempt did not work is that you were passing angles in degrees. The sin and cos trigonometric functions expect angles expressed in radians, so the numbers should be from 0 to 2*M_PI. For d degrees you pass M_PI*d/180.0. M_PI is a constant defined in math.h header.
I also needed this to form the movement of the hands of a clock in code. I tried several formulas but they didn't work, so this is what I came up with:
motion - clockwise
points - every 6 degrees (because 360 degrees divided by 60 minuites is 6 degrees)
hand length - 65 pixels
center - x=75,y=75
So the formula would be
x=Cx+(r*cos(d/(180/PI))
y=Cy+(r*sin(d/(180/PI))
where x and y are the points on the circumference of a circle, Cx and Cy are the x,y coordinates of the center, r is the radius, and d is the amount of degrees.
Here is the c# implementation. The method will return the circular points which takes radius, center and angle interval as parameter. Angle is passed as Radian.
public static List<PointF> getCircularPoints(double radius, PointF center, double angleInterval)
{
List<PointF> points = new List<PointF>();
for (double interval = angleInterval; interval < 2 * Math.PI; interval += angleInterval)
{
double X = center.X + (radius * Math.Cos(interval));
double Y = center.Y + (radius * Math.Sin(interval));
points.Add(new PointF((float)X, (float)Y));
}
return points;
}
and the calling example:
List<PointF> LEPoints = getCircularPoints(10.0f, new PointF(100.0f, 100.0f), Math.PI / 6.0f);
The answer should be exactly opposite.
X = Xc + rSin(angle)
Y = Yc + rCos(angle)
where Xc and Yc are circle's center coordinates and r is the radius.
Recommend:
public static Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
{
return Quaternion.Euler(angles) * (point - pivot) + pivot;
}
You can use this:
Equation of circle
where
(x-k)2+(y-v)2=R2
where k and v is constant and R is radius

How to update x, y coordinates on an rotating rectangle edge

Ok so I have searched and searched for a solution to my problem, but non seem to fix it.
I need to make a game with a rotating "cannon", my cannon is a simple rectangle placed in the middle of my panel that I can rotate with my keyboard. It rotates around one edge. I want to shoot out of the edge on the other side. I have found the starting point of where to shoot my bullets by using:
x = a + dia * (float)Math.Cos(angle);
y = b + dia * (float)Math.Sin(angle)
where "a, b" is the center coordinate I rotate it around and "dia" is the diagonal of the rectangle and "angle" is the angle of the one half of my rectangle.
public float rotate = 0.0f;
g.TranslateTransform(a , b);
g.RotateTransform(rotate);
I have a own class for my bullets that I put in a List.
So far so good. But when I rotate my cannon, the bullets don't come out from the tip anymore..they just start appearing far off where I want them to. it's because of this code:
x = (float)((x * Math.Cos(rotate)) - (y * Math.Sin(rotate)));
y = (float)((x * Math.Sin(rotate)) + (y * Math.Cos(rotate)));
that's supposed to update the x, y coordinates of the tip of the cannon.
If I delete it, it just fires from the same spot(no shit).
Can someone please explain to me what code I need to write to update the X, Y so they come out of my rectangle edge? It's driving me crazy..
Edit:
Found my answer staring at the screen in the early mornings. I had no need for any "find new x, y coordinates". I simply made a updater that updated the original angle with the float number it needed to move a little bit each time i rotated it.
hah! so simple, yet so hard to see.
First of all,
x = (float)((x * Math.Cos(rotate)) - (y * Math.Sin(rotate)));
y = (float)((x * Math.Sin(rotate)) + (y * Math.Cos(rotate)));
needs to be something like:
float oldx = x;
float oldy = y;
x = (float)((oldx * Math.Cos(rotate)) - (oldy * Math.Sin(rotate)));
y = (float)((oldx * Math.Sin(rotate)) + (oldy * Math.Cos(rotate)));
your new values need to be based purely off the old values..
If there's any other problem after fixing this, it may be related to how the rectangle is translated on the plane.
Edit: If this were a code review, I'd say the solution I just gave isn't quite the best solution either (it just doesn't suffer from the bug you introduced by using the new value of x to calculate the new value of y). See, Math.Cos and Math.Sin are generally expensive operations compared to multiplication and addition. If you had a bunch of points that need transformed the same way, best to calculate Math.Sin(rotate) and Math.Cos(rotate) once and use those values for every point. This might be a good place to use the Flyweight pattern and define a class where an instance would hold all your points for a given object/context so that operations can be done in aggregate.

Categories