How do I calculate angle from two coordinates? - c#

I'm working on a project with 3D based objects and manipulating them via my program. I currently have a textbox that allows me to put a heading in degrees and a button that will calculate the required values to make my main object change its heading. This is the code for that function:
private void btnSetHeading_Click(object sender, EventArgs e)
{
if (this.textBoxHeading.Text.Length == 0)
return;
float heading = (float)0;
try
{
heading = float.Parse(this.textBoxHeading.Text);
}
catch (FormatException ex)
{
MessageBox.Show(ex.Message);
return;
}
if (heading < (float)0 || heading > (float)360)
{
MessageBox.Show("Invalid heading parameter. Acceptable range: 0 - 360");
return;
}
float tempCosine = (float)Math.Cos(((heading * Math.PI) / (float)360.0));
float tempSine = -((float)Math.Sin(((heading * Math.PI) / (float)360.0)));
try
{
ProgramInterop.CreateInstance.SetHeading(tempCosine, tempSine);
}
catch (Exception ex)
{
MessageBox.Show("Caught: " + ex.Message);
}
}
If I supply 90 as the heading to face, the results are tempCosine=0.7071068 and tempSine=-0.7071068, which then makes my main object face 90 degrees or due east.
The program requires the heading to be given in two seperate values(tempCosine and tempSine) which I'm not familiar with geometry enough to understand why I would multiply by 360 instead of 180 but this is how its required to work.
Now for the next part of my project involves making my main object face another object given both of their (x,y) coordinates. If for example my main object is at (9112.94, 22088.74) and the new object I want to face is at (9127.04, 22088.88), it would require almost exactly 90 degrees heading to make it face the new object.
How can I calculate the tempCosine and tempSine from those two coordinates?

Regarding 180, that's true. I get used to have an extension class like this for working with radians and degrees.
public static class Extension
{
public static double ToRadians(this double degree)
{
return degree * Math.PI / 180;
}
public static double ToDegrees(this double val)
{
return val * 180 / Math.PI;
}
}
Regarding sine and cosine (I'm not sure I understood evetything right) but if I use the code below
float x1 = 9112.94f;
float y1 = 22088.74f;
float x2 = 9127.04f;
float y2 = 22088.88f;
float r = (float) Math.Pow((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1), 0.5);
float cosine = (x2 - x1) /r;
float sine = (y2 - y1) /r;
I'll get the angle 0.5712978 (not equal to 90).
Sorry if I misunderstood the problem.

I was able to work out the answer using Dani's suggestion to use Atan2(y, x). Thanks Dani.
float x1 = 9112.94f;
float y1 = 22088.74f;
float x2 = 9127.04f;
float y2 = 22088.88f;
float angleRadians;
float diffX = x2 - x1;
float diffY = y2 - y1;
float atan2Result = (float)Math.Atan2(diffX, diffY);
angleRadians = atan2Result / 2;
if (angleRadians < 0.0f)
angleRadians += (float)Math.PI;
float tempCosine = (float)Math.Cos(angleRadians);
float tempSine = -((float)Math.Sin(angleRadians));

Related

How to decrease and increase values as a curve

I am trying to do a digging tool for my game, I have x and y coordinates of point A and B, what I want to do is create a curve between these points, nothing graphical I just need loop through the coordinates (float x, float y).
I am not good at explaining so here is a visual example;
The first image is what's happen if I just use a for loop to decrease the y value until middle and then increase it from the middle to end.
//Very specific code for my example
//I wrote it just for this example so I am not sure if it works
float y;
float x;
public void Example(float startX, float endX, float startY, float endY, float depth)
{
y = startY;
x = startX;
float changeAmountOfY = depth / (endX - startX);
for (int i = (int)startX; i < (startX + endX) / 2; i++)
{
x++;
y -= changeAmountOfY;
}
for (int i = (int)(startX + endX) / 2; i < endX; i++)
{
x++;
y += changeAmountOfY;
}
}
public void ChangeCoordinates()
{
Example(100f, 200f, 100f, 100f, 50f);
}
The second image is what I need.
I am developing the game on unity and I am using Vector2 for the coordinates but it is not important.
Pure C# or even C++ is welcome.
It is also fine if someone can just explain the math behind what I am trying to do.
Maybe this can help:
// Calculate radius
int radius = (B.X - A.X) / 2;
// Calculate middle
int middle_x = A.X + radius;
int middle_y = A.Y;
// or
int middle_y = (A.Y + B.Y) / 2;
// Coordinates for a semicircle
// 0 to 180 degree
for (int i = 0; i <= 180; i++)
{
double x_coordinate = middle_x + radius * Math.Cos(i * Math.PI / 180);
// Opened to bottom
double y_coordinate = middle_y + radius * Math.Sin(i * Math.PI / 180);
// or opened to top
double y_coordinate = middle_y - radius * Math.Sin(i * Math.PI / 180);
}
Take a look at unit circle.

Using a weight function to procedurally generate terrain but its not giving me the expected result

I am trying to utilize a weight function from a paper titled "Dijkstra-based Terrain Generation Using Advanced Weight Functions". I have taken a weight function they provide and I have tried to implement it in C#. The output I am getting appears to be working but not completely. My knowledge of maths is not good enough for me to work out a solution.
Here is the weight function from the paper. The paper also defines a method for selecting nodes and calculating the weights but I don't believe this is required if I wish to just use this in isolation:
My current C# code. The data is being output into a Unity Terrain object.
for (int y = 0; y < Resolution; y++)
{
for (int x = 0; x < Resolution; x++)
{
//I tried to inteprite the expression here, this is probably not correct.
float dot = Vector3.Dot(WindDirection.normalized, new Vector3(x, y));
float ri = ReverseInterpolate(dot);
float inter = Interpolate(ri);
terrainheights[y, x] = Weight * inter;
}
}
My methods for Interpolation:
private float Interpolate(float value)
{
float x1 = 0;
float x2 = 1;
float y1 = 0;
float y2 = Weight;
float y = y1 + (value - x1) / (x2 - x1) * (y2 - y1);
return y;
}
private float ReverseInterpolate(float x)
{
float x1 = -1;
float x2 = 1;
float y1 = 0;
float y2 = 1;
float y = y1 + (x - x1)/ (x2 - x1) * (y2 - y1);
return y;
}
Finally is the result I get and the values for Weight and Wind Direction. as you can see, the effect is working slightly but not to the degree that I was hoping:
Any help would be very much appreciated!

Find an index for a given Point coordinate from an array of Points

Given an Point array and an arbitrary x,y coordinate, find the index for _points that is closest to the given coordinate.
PointD[] _points
//create a list of x,y coordinates:
for (int i = 0; i < _numberOfArcSegments + 1; i++)
{
double x1 = _orbitEllipseSemiMaj * Math.Sin(angle) - _focalDistance; //we add the focal distance so the focal point is "center"
double y1 = _orbitEllipseSemiMinor * Math.Cos(angle);
//rotates the points to allow for the LongditudeOfPeriapsis.
double x2 = (x1 * Math.Cos(_orbitAngleRadians)) - (y1 * Math.Sin(_orbitAngleRadians));
double y2 = (x1 * Math.Sin(_orbitAngleRadians)) + (y1 * Math.Cos(_orbitAngleRadians));
angle += _segmentArcSweepRadians;
_points[i] = new PointD() { x = x2, y = y2 };
}
I'm drawing an ellipse which represents an orbit. I'm first creating the point array above, then when I draw it, I (attempt) to find the point closest to where the orbiting body is.
To do this I've been attempting to calculate the angle from the center of the ellipse to the body:
public void Update()
{
//adjust so moons get the right positions (body position - focal point position)
Vector4 pos = _bodyPositionDB.AbsolutePosition - _positionDB.AbsolutePosition;
//adjust for focal point
pos.X += _focalDistance;
//rotate to the LonditudeOfPeriapsis.
double x2 = (pos.X * Math.Cos(-_orbitAngleRadians)) - (pos.Y * Math.Sin(-_orbitAngleRadians));
double y2 = (pos.X * Math.Sin(-_orbitAngleRadians)) + (pos.Y * Math.Cos(-_orbitAngleRadians));
_ellipseStartArcAngleRadians = (float)(Math.Atan2(y2, x2)); //Atan2 returns a value between -180 and 180;
}
then:
double unAdjustedIndex = (_ellipseStartArcAngleRadians / _segmentArcSweepRadians);
while (unAdjustedIndex < 0)
{
unAdjustedIndex += (2 * Math.PI);
}
int index = (int)unAdjustedIndex;
The ellipse draws fine, (the point array is correct and all is good once adjusted for viewscreen and camera offsets and zoom)
But does not start at the correct point (I'm decreasing the alpha in the color so the resulting ellipse fades away the further it gets from the body)
I've spend days trying to figure out what I'm doing wrong here and tried a dozen different things trying to figure out where my math is wrong, but I'm not seeing it.
I assume that _points should be an array of PointD;
This is the shortest way to get the closest point to your array (calcdistance should be a simple function that calculate the euclidean distance):
PointD p = _points.OrderBy(p => CalcDistance(p, gievnPoint)).First();

Circle and line segment collision in C#

I'm trying to implement a method to check if a circle and a line intersect. I took most of this code (fixed based on the answer), and also modified the code a bit to use Point's instead of Vector2f's`.
This is currently what I have:
private bool CircleLineIntersect(int x, int y, int radius, Point linePoint1, Point linePoint2) {
Point p1 = new Point(linePoint1.X,linePoint1.Y);
Point p2 = new Point(linePoint2.X,linePoint2.Y);
p1.X -= x;
p1.Y -= y;
p2.X -= x;
p2.Y -= y;
float dx = p2.X - p1.X;
float dy = p2.Y - p1.Y;
float dr = (float)Math.Sqrt((double)(dx * dx) + (double)(dy * dy));
float D = (p1.X * p2.Y) - (p2.X * p1.Y);
float di = (radius * radius) * (dr * dr) - (D * D);
if (di < 0) return false;
else return true;
}
It looks consistent with this algorithm, so I'm not sure what the problem is.
If anyone could provide guidance it would be much appreciated.
EDIT:
It doesn't seem to be calculating correctly. For example with input x=1272, y=1809, radius=80, linePoint1={X=1272,Y=2332}, linePoint2={X=1272,Y=2544} there shouldn't be an intersection (y+radius is less than both y values of the line segment), but the function is returning true.
Error exists in your test case. Not only does the it intersect, but your line goes through the center of the circle. The line is a vertical line (X =1272). Your circle is centred about (1272, 1809). ERGO it goes through the centre.
Perhaps you have a misunderstanding between the terms line and line-segment, within mathematics.

IsFacing and IsBehind calculations

I'm looking for better way to calculate if one object facing another or one is behind another. So far I've been able to create this but it seems to not working 100% correctly :(
I also think it should be in radians rather then degrees.
public static float GetAngle(float x1, float y1, float x2, float y2)
{
float xDiff = x2 - x1;
float yDiff = y2 - y1;
var angle = RadianToDegree((float)Math.Atan2(yDiff, xDiff));
if (angle < 0)
return 360 + angle;
return angle;
}
public static bool IsFacing(Point obj, float rotationAngle, Point target, float arcDegree = 180)
{
var angleBetweenPoints = GetAngle(obj, target);
return rotationAngle >= angleBetweenPoints - arcDegree / 2 && rotationAngle <= angleBetweenPoints + arcDegree / 2;
}
public static bool IsBehind(Point obj, float rotationAngle, Point target, float arcDegree = 180)
{
var angleBetweenPoints = GetAngle(obj, target);
var backViewAngle = rotationAngle > 180 ? rotationAngle - 180 : 180 - rotationAngle;
return backViewAngle >= angleBetweenPoints - arcDegree / 2 && backViewAngle <= angleBetweenPoints + arcDegree / 2;
}
At first glance it looks like your problem is in the test of rotationAngle vs angleBetweenPoints in the IsFacing() method.
Given:
rotationAngle = 0, angleBetweenPoints = 350, arcDegree = 180
then the test will be:
test = 0 >= (350 - 180 / 2) && 0 <= (350 + 180 / 2)
= 0 >= 260 && 0 <= 440
= false
This will happen fairly often, and is due to the use of the range [0..360] for your angles. While this is useful in some cases, this is not one of those cases. Far more useful here is to get the difference in the heading and target angles in the range [-180..180], then the comparison to arcDegree becomes much simpler.
Try this:
// Adjust a value to fit in the specified range
public static float Clamp(float v, float low, float high)
{
float range = high - low;
float modifier = ((int)((v - low) / range) - (v < low ? 1 : 0)) * range;
v -= modifier;
return v;
}
// Get the angle between a point+heading and another point
// Returns an angle in the range (-180..180) where:
// res < 0 target clockwise from heading
// res == 0 target at heading
// res > 0 target counter-clockwise from heading
static float RelativeAngle(float heading, float x1, float y1, float x2, float y2)
{
// get angle between points in world coordinates
float angle = RadianToDegree((float)Math.Atan2(y2 - y1, x2 - x1));
// adjust to local coordinates and normalize
return Clamp(angle - heading, -180, 180);
}
public static bool IsFacing(Point obj, float rotationAngle, Point target, float arcDegree = 180)
{
var angleBetweenPoints = RelativeAngle(rotationAngle, obj.x, obj.y, target.x, target.y);
return angleBetweenPoints >= -(arcDegree / 2) && angleBetweenPoints <= (arcDegre / 2);
}

Categories

Resources