Rounding issue when dealing with Radian Angles and Distance. c++ - c++

Noob Here.
I have a problem where I have to round my outputs to 4 decimal places and I'm getting weird return values.
I'm using this with all variables being double or int since precision is secondary to getting it to work semi-accurately.
//Rounds Input to 4 decimal places
double round(double initial)
{
int newInitial = (initial * 10000);
double round = newInitial / 10000;
return round;
}
This returns values along the lines of 0.781623...-1311 & 2.25194111-3
I have to find 2 things, a Positive radian angle for "vectorC" and Distance saved going from the Origin of a Coordinate plane by following one direct vectorC over the the path created by 2 others, vectorA
+vectorB.
Initially I was getting this problem with my function that finds the radian angle here:
/*Finds Positive Radian Angle of Vector C by using inverse tangent given x and y dimensions. Using Pi at 11 decimals.
*/
double angle(int x2,int y2)
{
double pi = 3.14159265359;
double vAngle = atan(y2 / x2);
if (x2 < 0 && y2 > 0)
{
vAngle = pi + vAngle;
}
if (x2 < 0 && y2 < 0)
{
vAngle = pi + vAngle;
}
if (x2 < 0 && y2 < 0)
{
vAngle = (2 * pi) + vAngle;
}
return vAngle;
}
I was thinking that its because of the decimal length being to long for double but I'm also getting this issue with my Distance function here:
//Uses distance formula to find the Magnitude of a "Vector" from Coordinates (x1,y1) to (x2,y2)
double distance(double x1,double y1,double x2,double y2)
{
double vDistance = sqrt((pow(x2 - x1, 2) + pow(y2 - y1, 2)));
return vDistance;
}
I'm kinda lost. I know the math is correct but my implementation is breaking somewhere. Any Help would be Great.
EDIT: OK so it seems my functions are breaking before the rounding even occurs.
Heres an Example. Lets say we have 3 points. (0,0)(1,1)(1,-3)
Vector A from (0,0)->(1,1) has distance sqrt(2) aprox ~ 1.4142
Vector B from (1,1)->(1,-3) has distance 2
Vector C from (0,0)->(1,-3) has distance sqrt(10) aprox ~ 3.1623
When using distance() to find the values it returns 1.4142143.16228-1, 3.16228 , 2111-3. So there's something wrong with either my distance function or the numbers passed but the numbers passed are whole number doubles. Dont know why the first answer is coming back as a number with 2 decimals
Then with my Angle function the Angle should be x=arctan(-3/1)=5.0341. Instead im getting just -1. I can post the entire program if needed.
EDIT2: So the Error is occuring before my rounding even occurs i'm thinking its cause im using double instead of float maybe?? I have two different functions and both print with a weird ending before i even pass them through my round function. Again using xy(0,0), v1xy(1,1), v2xy(1,-3)
//Uses distance formula to find the Magnitude of a "Vector" from Coordinates (x1,y1) to (x2,y2)
double distance(double x1,double y1,double x2,double y2)
{
double vDistance = sqrt((x2 - x1)*(x2 - x1) + (y2-y1)*(y2-y1));
return vDistance;
}
All three are printed out as:
cout << vectorA <<endl<< vectorB <<endl<< vectorC<<endl;
And the answers come out correctly for the first two but then the third comes out incorrect and with a -3 stuck on. Here:
https://gyazo.com/343ec1eaddb45cc7abd160ab7ac39a5d
Then commenting that out and just checking for Angle:
/*Finds Positive Radian Angle of Vector C by using inverse tangent given x and y dimensions. Using Pi at 11 decimals.
*/
double angle(int x2,int y2)
{
double pi = 3.14159265359;
double vAngle = atan(y2 / x2);
if (x2 < 0 && y2 > 0)
{
vAngle = pi + vAngle;
}
if (x2 < 0 && y2 < 0)
{
vAngle = pi + vAngle;
}
if (x2 < 0 && y2 < 0)
{
vAngle = (2 * pi) + vAngle;
}
return vAngle;
}
gives me a similar result:
https://gyazo.com/db19c0263a45543653e1d9549a4dd50b

Related

Intersection points Point1.Y and Y should be equal. But there is a difference in Point1.Y and Y. WHY? [duplicate]

This question already has answers here:
Comparing doubles
(8 answers)
Closed 2 years ago.
Suppose we have two lines.
L1: y1 = m1.x1 +c1
L2: y2 = m2.x2 +c2
such that m1 != m2
intersection_X = (c2 - c1) / (m1 - m2)
intersection_Y = m1 * intersection_X + c1
Also, if we calculate intersection_Y w.r.t L2 i.e. intersection_Y = m2 * intersection_X +c2
Both the intersection_Y should be equal.
If you run the below code and check point1.Y and Y, you'll find that both are not equal. I think there is something wrong with the precision handling here.
Because of this difference, crash is happening.
Can some one throw light, please?
#include <iostream>
#include<cmath>
#include<limits>
using namespace std;
#define FUZZ_GEN (1e-9) //tolerance for vertical check
#define FEQUAL(a, b, fuzz) (fabs(a - b) <= (fuzz))
struct Point {
double X, Y;
};
class LineSegment { //Line class
public:
LineSegment(double x1, double y1, double x2, double y2);
void IntersectionPoints(LineSegment side);
double X1, Y1, X2, Y2, M, C;
};
LineSegment::LineSegment(double fX1, double fY1, double fX2, double fY2) //Constructor for line
: X1(fX1),
Y1(fY1),
X2(fX2),
Y2(fY2)
{
if (FEQUAL(X1, X2, FUZZ_GEN)) // if vertical, slope is inf.
{
M = C = std::numeric_limits<double>::infinity(); // slope undefined
}
else
{
M = (Y2 - Y1) / (X2 - X1);
C = Y1 - (M * X1);
}
}
void LineSegment::IntersectionPoints (LineSegment side) {
Point point1;
point1.X = (C - side.C) / (side.M - M); //intersection point 1
point1.Y = M * point1.X + C;
double Y = side.M * point1.X + side.C; // ?? Y != point1.Y
}
int main()
{
// data coming from lower level APIs. Can't be changed
LineSegment side = LineSegment(10.267716536547709, //create first line
6.8779527559055005,
10.031496064106765,
6.8779527559055005);
LineSegment line = LineSegment(10.149606299212586, // create second line
9.1220472440944818,
10.149606296983265,
4.2665936725507594);
line.IntersectionPoints(side); //call to calc intersection point
return 0;
}
There is a finite number of double precision floating point numbers.
This means there are infinitely many real numbers between two floating point numbers. There are huge gaps between floating point numbers - filled with numbers you cannot represent!
When you define two lines, their intersection point is very unlikely to lie exactly on a double precision floating point number. It will lie somewhere in the vast void between the numbers.
Imagine you zoom in so deep that you can see the space between floating numbers clearly. You can visualize the intersection like the following image, where grid lines are the floating point numbers:
If the bottom corner here has coordinates x=0 y=0, the x-axis value closest to the intersection is x=2. But if you evaluate the two lines at x=2, for the line C-D you get y=2, and for the line A-B you get y=3. Why? Because the lines don't intersect at (2,2) or (2,3), they intersect at a point that's in the space between.

interior angles of irregular polygon with angles > 180

I'm trying to calculate the values shown in the picture in red i.e. the interior angles.
I've got an array of the points where lines intersect and have tried using the dot-product but it only returns the smallest angles. I need the full range of internal angles (0-359) but can't seem to find much that meets this criteria.
Assuming your angles are in standard counterclockwise format, the following should work:
void angles(double points[][2], double angles[], int npoints){
for(int i = 0; i < npoints; i++){
int last = (i - 1 + npoints) % npoints;
int next = (i + 1) % npoints;
double x1 = points[i][0] - points[last][0];
double y1 = points[i][1] - points[last][1];
double x2 = points[next][0] - points[i][0];
double y2 = points[next][1] - points[i][1];
double theta1 = atan2(y1, x1)*180/3.1415926358979323;
double theta2 = atan2(y2, x2)*180/3.1415926358979323;
angles[i] = (180 + theta1 - theta2 + 360);
while(angles[i]>360)angles[i]-=360;
}
}
Obviously, if you are using some sort of data structure for your points, you will want to replace double points[][2] and references to it with references to your data structure.
You can obtain full angle range (-Pi..Pi) with atan2 function:
atan2(crossproduct, dotproduct)

nFinding Xcrossing point using Data Points

I was going through Algorithm which identify crossing point using data points on x axis. I can understand calculation but could not understand purpose of this calculation. As per my understanding, it determine each time new y point and slope and subtract them.
I want to insert Image also but I do not have 10 reputation point.
Please let me know if I need to provide info.
//This function determine the crossing point when the graph is intersecting x axis.
XPoint findXingPoint(Curve & curve, double rfix, double vcc, int type, int pull_up)
{
//curve class contain x and y data point
// rfix is fixed value which is generally 50
// vcc also fix value
// type contain 0 and 1
//pull up to identify graph
XPoint p = { 0.0, 0.0 };
double r_fix = rfix;
double m = -1 / r_fix;
double c = vcc / r_fix;
if(type)
c=0;
double r, s, X1, X2, Y1, Y2, Y3, Y4;
r = (m * curve[0].first) + c;
// r is a kind of y value which determine from x and y point
s = abs(r);
for (Curve::iterator i = curve.begin(); i != curve.end(); i++) {
curve_point p = (*i);
double xcurve = p.first;
double ycurve = p.second;
double yloadline = m * xcurve + c;
double B = ycurve - yloadline;
if (B >= 0 && r >= B) {
r = B;
X1 = xcurve;
Y1 = yloadline;
Y2 = ycurve;
}
if (B <= 0 && r >= abs(B)) {
s = abs(B);
X2 = xcurve;
Y4 = yloadline;
Y3 = ycurve;
}
}
#could not understand purpose of B calculation
if (s == 0)
X1 = X2;
if (r == 0)
X2 = X1;
if (X1 != X2) {
double m1, m2, c1, c2;
m1 = (Y3 - Y2) / (X2 - X1);
m2 = (Y4 - Y1) / (X2 - X1);
c1 = Y3 - (m1 * X2);
c2 = Y4 - (m2 * X2);
// CASE m1==m2 should be handled.
p.x = (c2 - c1) / (m1 - m2);
p.y = (m2 * p.x) + c2;
} else {
p.x = X1;
p.y = Y1;
}
#not able to also understand calculation
if (verbosityValue >= 1)
loginfo<<"found crossing point # " << p.x << " " << p.y << endl;
return p;
}
Output:
first
found crossing point # 7.84541e-08 -1.96135e-09 with type 0
found crossing point # 0.528564 0.0182859 with type 1
second
found crossing point # 0.654357 -0.0163589 with type 0
found crossing point # 1.25827 4.31937e-05 with type 1
This appears to be a straightforward implementation. For a given point x,y on the curve, find the slope, draw a line through the slope, find where that line would cross the x axis, and then find the new y value at that point. For well-behaved functions, the new y value is a lot closer to 0 than the initial y value. You iterate until the approximation is good enough.
If you look at the graph, you see that the middle part is quite straight. Hence, the slope of the line is a locally good approximation of the curve, and your new y value is a lot closer to zero (At least 10x times, probably 100x, looking at the graph.0. If you start on the the steeper slopes on either side, you'll need one extra step. Your second x point will be on the middle part.

See if a point lies on a line(vector)

I have currently the following line in my program. I have two other whole number variables, x and y.
I wish to see if this new point(x, y) is on this line. I have been looking at the following thread:
Given a start and end point, and a distance, calculate a point along a line
I've come up with the following:
if(x >= x1 && x <= x2 && (y >= y1 && y <= y2 || y <= y1 && y >= y2))
{
float vx = x2 - x1;
float vy = y2 - y1;
float mag = sqrt(vx*vx + vy*vy);
// need to get the unit vector (direction)
float dvx = vx/mag; // this would be the unit vector (direction) x for the line
float dvy = vy/mag; // this would be the unit vector (direction) y for the line
float vcx = x - x1;
float vcy = y - y1;
float magc = sqrt(vcx*vcx + vcy*vcy);
// need to get the unit vector (direction)
float dvcx = vcx/magc; // this would be the unit vector (direction) x for the point
float dvcy = vcy/magc; // this would be the unit vector (direction) y for the point
// I was thinking of comparing the direction of the two vectors, if they are the same then the point must lie on the line?
if(dvcx == dvx && dvcy == dvy)
{
// the point is on the line!
}
}
It doesn't seem to be working, or is this idea whack?
Floating point numbers have a limited precision, so you'll get rounding errors from the calculations, with the result that values that should mathematically be equal will end up slightly different.
You'll need to compare with a small tolerance for error:
if (std::abs(dvcx-dvx) < tolerance && std::abs(dvcy-dvy) < tolerance)
{
// the point is (more or less) on the line!
}
The hard part is choosing that tolerance. If you can't accept any errors, then you'll need to use something other than fixed-precision floating point values - perhaps integers, with the calculations rearranged to avoid division and other inexact operations.
In any case, you can do this more simply, without anything like a square root. You want to find out if the two vectors are parallel; they are if the vector product is zero or, equivalently, if they have equal tangents. So you just need
if (vx * vcy == vy * vcx) // might still need a tolerance for floating-point
{
// the point is on the line!
}
If your inputs are integers, small enough that the multiplication won't overflow, then there's no need for floating-point arithmetic at all.
An efficient way to solve this problem is to use the signed area of a triangle. When the signed area of the triangle created by points {x1,y1}, {x2,y2}, and {x,y} is near-zero, you can consider {x,y} to be on the line. As others have mentioned, picking a good tolerance value is an important part of this if you are using floating point values.
bool isPointOnLine (xy p1, xy p2, xy p3) // returns true if p3 is on line p1, p2
{
xy va = p1 - p2;
xy vb = p3 - p2;
area = va.x * vb.y - va.y * vb.x;
if (abs (area) < tolerance)
return true;
return false;
}
This will let you know if {x,y} lies on the line, but it will not determine if {x,y} is contained by the line segment. To do that, you would also need to check {x,y} against the bounds of the line segment.
First you need to calculate the equation of your line. Then see if this equation holds true for the values of x and y that you have. To calculate the equation of your line, you need to work out where it croses the y-axis and what its gradient is. The equation will be of the form y=mx+c where m is the gradient and c is the 'intercept' (where the line crosses the y-axis).
For float values, don't use == but instead test for small difference:
if (fabs(dvcx-dvx) < delta && fabs(dvcy-dvy) < delta)
Also, you don't really need the unit vector, just the tangent:
float originalTangent = (y2 - y1) / (x2 - x1);
float newTangent = (y - y1) / (x - x1);
if (fabs(newTangent - originalTangent) < delta) { ... }
(delta should be some small number that depends on the accuracy you are expecting.)
Given that (x, y) is actually a point, the job seems a bit simpler than you're making it.
You probably want to start by checking for a perfectly horizontal or vertical line. In those cases, you just check whether x falls between x1 and x2 (or y between y1 and y2 for vertical).
Otherwise you can use linear interpolation on x and see if it gives you the correct value for y (within some possible tolerance for rounding). For this, you'd do something like:
slope = (y2-y1)/(x2-x1);
if (abs(slope * (x - x1) - y) < tolerance)
// (x,y) is on the line
else
// (x,y) isn't on the line

Given two points, find a third point on the line

I have two points A (x1,y1) and B (x2,y2) that are given as an input to the program. I have to find a third point C that lies on the line AB and is at a distance 10 away from the point A.
I can easily get the slope of the line but that doesn't give me the full equation for the line. Even if I get the full equation, I am not sure using this equation, how would I find out a point that is x distance away from A.
Any suggestions on how to approach this?
There are always two points on each line:
get the vector from A to B (subtract the coordinates)
normalize the vector (divide by its length; pythagorean theorem)
multiply the vector by 10 or -10
add the vector to A to get C
Note that if A==B, the line is not defined, and this algorithm causes a division by zero. You may want to add a test for equality at the beginning.
You can use the sine or the cosine (times 10) of the angle of the line to get the horizontal or vertical distance of the point that is a distance of 10 from a given point. A shortcut is to use the horizontal or vertical distance divided by the direct distance between the points to get the sine or cosine.
You can do it using vectors like this:
Let D = the difference between B and A (D = B - A)
Then any point on the line can be described by this formula:
point = A + Dt
where t is a real number.
So just plug in any value for t to get another point. For example if you let t == 1 then the equation above reduces to point = B. If you let t = 0 then it reduces to point = A. So you can see that you can use this to find a point between A and B simply by let t range from 0 to 1. Additionally if you let t > 1, you will find a point past B.
You can see from the image that your given points are x1,y1 and x2,y2. You need to find an intermediate point at a distance 'R' from point x1,y1.
All you need to do is to find θ using
Tan θ = (y2-y1)/(x2-x1)
Then you can get the intermediate point as (R * cos θ),(R * Sin θ)
I have drawn this assuming positive slope.
Going on similar lines you can seek a solution for other special cases lile:
i. Horizontal line
ii. Vertical line
iii. Negative slope
Hope it clarifies.
I have done the calculation in Andengine using a Sprite object. I have two Array List x coordinates and y coordinates. Here i am just calculating using the last two values from these two array list to calculate the third point 800 pixel distant from Your point B. you can modify it using different values other than 800. Hope it will work.The coordinate system here is a little different where (0,0) on the top left corner of the screen. Thanks
private void addExtraCoordinate(CarSprite s) {
int x0, y0, x1, y1;
float x = 0f, y = 0f;
x0 = Math.round(xCoordinates.get(xCoordinates.size() - 2));
x1 = Math.round(xCoordinates.get(xCoordinates.size() - 1));
y0 = Math.round(yCoordinates.get(yCoordinates.size() - 2)) * (-1);
y1 = Math.round(yCoordinates.get(yCoordinates.size() - 1)) * (-1);
if (x1 == x0 && y1 == y0) {
return;
} else if (y1 == y0 && x1 != x0) {
if (x1 > x0) {
x = (float) x1 + 800f;
} else
x = (float) x1 - 800f;
y = Math.round(yCoordinates.get(yCoordinates.size() - 1));
} else if (y1 != y0 && x1 == x0) {
if (y1 > y0) {
y = (float) Math.abs(y1) - 800f;
} else
y = (float) Math.abs(y1) + 800f;
x = Math.round(xCoordinates.get(xCoordinates.size() - 1));
} else {
float m = (float) (yCoordinates.get(yCoordinates.size() - 1) * (-1) - yCoordinates
.get(yCoordinates.size() - 2) * (-1))
/ (float) (xCoordinates.get(xCoordinates.size() - 1) - xCoordinates
.get(xCoordinates.size() - 2));
if (x1 > x0) {
x = (float) ((float) x1 + 800f / (float) Math
.sqrt((double) ((double) 1f + (double) (m * m))));
} else
x = (float) ((float) x1 - 800f / (float) Math
.sqrt((double) ((double) 1f + (double) (m * m))));
if (y0 > y1) {
y = (float) ((float) Math.abs(y1) + 800f / (float) Math
.sqrt((double) (((double) 1f / (double) (m * m)) + (double) 1f)));
} else
y = (float) ((float) Math.abs(y1) - 800f / (float) Math
.sqrt((double) (((double) 1f / (double) (m * m)) + (double) 1f)));
}
xCoordinates.add(x);
yCoordinates.add(y);
}