I have the following c++ functions (implementing Bresenham's line algorithm), seen in the book
Computer Graphics From Pixels to Programmable Graphics Hardware By
Alexey Boreskov, Evgeniy Shikin
One of the function uses floats, and due to their inefficiency the book has presented another function which uses integer arithmetic only.
I'm having trouble understading why are the two equivalent, and why are we using left shift << here, doesn't a<<1 simply multiply a by 2?
Note: We assume the points A:(xa,ya) and B:(xb,yb) have integer values.
Float Version
void drawLine(int xa, int ya, int xb, int yb, int color) {
float k = (float)(yb-ya)/(float)(xb-xa);
float d = 2*k - 1
int y = ya;
putPixel(xa, ya, color); // paint the pixel (xa,ya) in color "color"
for (int x = xa+1; x<=xb; x++) {
if (d > 0) {
d += 2*k + 2;
y++;
} else {
d += 2*k;
}
putPixel(x, y, color);
}
}
Integer Version
void drawLine(int xa, int ya, int xb, int yb, int color) {
int dx = xb - xa;
int dy = yb -ya;
int d = (dy<<1) - dx;
int d1 = dy <<1;
int d2 = (dy - dx) << 1;
int y = ya;
putPixel(xa, ya, color); // paint the pixel (xa,ya) in color "color"
for (int x = xa+1; x<=xb; x++) {
if (d > 0) {
d += d2;
y++;
} else {
d += d1;
}
putPixel(x, y, color);
}
}
The floating-point code does four things with d:
Initialize d to 2dy/dx−1, where dy and dx are yb−ya and xb−xa, respectively.
Evaluate whether d is greater than 0.
Add 2dy/dx+2 to d.
Add 2dy/dx to d.
In floating-point, the division by dx may produce a non-integer. To avoid this, we transform the operations by multiplying everything by dx, yielding:
Initialize d to 2dy−dx.
Evaluate whether d is greater than 0dx (equal to 0).
Add 2dy+2dx to d.
Add 2dy to d.
We can readily see that these four equivalent operations are implemented in the integer code except for 3. The integer code appears to add 2dy−2dx to d. The integer code matches code shown in the Wikipedia page for Bresenham’s line algorithm. I suspect the + in the floating-point version is an error in the book.
Related
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.
I'm trying to find a root with simple fixed-point method by C++, but the point is that Xr is a root of f(x) and a inflection point as well. In addition, A equation is a little bit more complex than the normal Fixed-Point method.
The equation is added constant c for check how quickly converge to the root xr.
I was going to find a root and then check if the root is a inflection point or not, but it is not working and I can't find the problem in my code.
I need your help.
The real Problem is
Consider the root finding problem f(x)=0 with root xr, with f'(x)=0.
Convert it to the simple fixed-point problem.
x=x+c*f(x)=g(x)
with c a nonzero constant. How should c be chosen to ensure rapid convergence of
x(n+1)=x(n)+c*f(x(n)) ( x(n+1) means the value of the n+1th of X )
to c (provided that x0 is chosen sufficiently close to xr?). Apply your way of choosing c to the root-finding problem x*x*x-5=0. Start your program with x0=1.0 and run with several values of c and discuss about the observed trend in your results (in other words, the effect of c value on convergence behavior)
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
double gx(double x, double c)
{
return(x + c*(x*x*x - 5));
}
double gxpr(double x, double c)
{
return(x + c*(3 * x*x));
}
void Simple_Fixed_Point(double x, double c)
{
int i = 1;
long double x2=0.0;
long double x3=0.0;
long double ea=0.0;
long double ea2 = 0.0;
long double es = pow(10, -6);
printf("Simple Fixed Point Method\n");
Lbl:
x2 = gx(x,c);
printf("iteration=%d Root=%.5f Approximate error=%.15f\n", i++,
x2, ea);
if (ea=fabs((x2 - x)/x2*100) <es)
{
goto Lbm;
}
else
{
x = x2;
goto Lbl;
}
Lbm:
x3 = gxpr(x2, c);
if (ea2 = fabs((x3 - x2) / x3 * 100) < es)
{
goto End;
}
else
{
x2 = x3;
goto Lbm;
}
End:
getch();
}
int main(void)
{
Simple_Fixed_Point(1.0, 1.0);
return(0);
}
Hope this helps you:
//f(x+dx) = f(x) + (dfdx) * dx;
eps = 1.0;
dx = 1e-7; //something small
x = x0;
while (eps > mineps) {
f1 = f(x);
f2 = f(x + dx);
f3 = f(x + dx + dx);
d2fdx2 = (f3 - f2 - f2 + f1) / dx / dx;
dfdx = (f2 - f1) / dx;
x -= (relax1 * f1 / dfdx + relax2 * dfdx / d2fdx2); //relax - something less 1
eps = max(abs(dfdx), abs(f1));
}
Here is an image: http://i.imgur.com/MRvz24u.gif
So I can tell what the problem is, that my epsilon (or whatever that symbol is) used for spherical coordinates are repeating. So the way I calculate the points is:
double theta = acos(p.getY()/p.magnitude());
theta = theta/3.1415926;
double epsilon = atan(p.getZ()/p.getX());
epsilon = epsilon + 3.1415926/2;
epsilon = epsilon /3.1415926;
I'm pretty sure the rest isn't the problem but I will put it here just in case
int w = texture ->columns();
int h = texture ->rows();
double x = w * epsilon ; x = (int) x;
double y = h * theta; y = (int) y;
int row = y;
int column = x;
Magick::PixelPacket *pixels = texture->getPixels(0, 0, w, h);
Magick::Color color = pixels[w * row + column];
double range = pow(2, texture -> modulusDepth());
double r = color.redQuantum()/range ;
double g = color.greenQuantum()/range ;
double b = color.blueQuantum()/range ;
return Color(r, g, b, 0);
I am not sure why I would be getting repeating values because my range should originally be -pi/2 < epsilon < pi/2 and I just shift it then scale it.
Use atan2 instead of atan. atan accepts x/y while atan2 accepts x,y .
This allows atan2 handle the case where x and y are both negative differently from the case where they're positive. atan has no way of knowing.
I am trying to implement the Trilateration process in 2D. The wikipedia article relating to this: Tilateration
I have found a nice question here at this site, where the algorithm is well explained:artifical intelligence
After all, I tried to implement the algorithm in c++. Unfortunately I faced some problems...
Let's see my implementation. It is only a function: The first inputs are three vector, each representing a 2D point with X,Y coordinates. The other (r1,r2,r3) input variables stand for the distance/radius of each point.
#include <iostream>
#include <fstream>
#include <sstream>
#include <math.h>
#include <vector>
using namespace std;
std::vector<double> trilateration(double point1[], double point2[], double point3[], double r1, double r2, double r3) {
std::vector<double> resultPose;
//unit vector in a direction from point1 to point 2
double p2p1Distance = pow(pow(point2[0]-point1[0],2) + pow(point2[1]-point1[1],2),0.5);
double exx = (point2[0]-point1[0])/p2p1Distance;
double exy = (point2[1]-point1[1])/p2p1Distance;
//signed magnitude of the x component
double ix = exx*(point3[0]-point1[0]);
double iy = exy*(point3[1]-point1[1]);
//the unit vector in the y direction.
double eyx = (point3[0]-point1[0]-ix*exx)/pow(pow(point3[0]-point1[0]-ix*exx,2) + pow(point3[1]-point1[1]-iy*exy,2),0.5);
double eyy = (point3[1]-point1[1]-iy*exy)/pow(pow(point3[0]-point1[0]-ix*exx,2) + pow(point3[1]-point1[1]-iy*exy,2),0.5);
//the signed magnitude of the y component
double jx = eyx*(point3[0]-point1[0]);
double jy = eyy*(point3[1]-point1[1]);
//coordinates
double x = (pow(r1,2) - pow(r2,2) + pow(p2p1Distance,2))/ (2 * p2p1Distance);
double y = (pow(r1,2) - pow(r3,2) + pow(iy,2) + pow(jy,2))/2*jy - ix*x/jx;
//result coordinates
double finalX = point1[0]+ x*exx + y*eyx;
double finalY = point1[1]+ x*exy + y*eyy;
resultPose.push_back(finalX);
resultPose.push_back(finalY);
return resultPose;
}
As I mentioned I followed this article. I am of the opinion that the problem lies at the part where the y coordinate is calculated. I am also not sure about last part, where I calculate finalX, finalY...
My main function is the following:
int main(int argc, char* argv[]){
std::vector<double> finalPose;
double p1[] = {4.0,4.0};
double p2[] = {9.0,7.0};
double p3[] = {9.0,1.0};
double r1,r2,r3;
r1 = 4;
r2 = 3;
r3 = 3.25;
finalPose = trilateration(p1,p2,p3,r1,r2,r3);
cout<<"X::: "<<finalPose[0]<<endl;
cout<<"Y::: "<<finalPose[1]<<endl;
//x = 8, y = 4.1
}
The result should be around X~8 and Y~4.1, but I got X = 13.5542 and Y=-5.09038
So my problem is and question is: I have problem with dividing the calculations for x and y. I think I could solve the algorithm till x, after that I have problems with calculating y.
The calculation is the following for y: y = (r12 - r32 + i2 + j2) / 2j - ix / j
I do not know which i and j I should use here since I have two i (ix,iy) and two j(jx,jy). As you can see I used iy and jy but at the end of the line I used ix due to multiplication with x.
Thanks in advance!
I used a couple of auxiliary variables but it works just fine...
#include <iostream>
#include <fstream>
#include <sstream>
#include <math.h>
#include <vector>
using namespace std;
struct point
{
float x,y;
};
float norm (point p) // get the norm of a vector
{
return pow(pow(p.x,2)+pow(p.y,2),.5);
}
point trilateration(point point1, point point2, point point3, double r1, double r2, double r3) {
point resultPose;
//unit vector in a direction from point1 to point 2
double p2p1Distance = pow(pow(point2.x-point1.x,2) + pow(point2.y- point1.y,2),0.5);
point ex = {(point2.x-point1.x)/p2p1Distance, (point2.y-point1.y)/p2p1Distance};
point aux = {point3.x-point1.x,point3.y-point1.y};
//signed magnitude of the x component
double i = ex.x * aux.x + ex.y * aux.y;
//the unit vector in the y direction.
point aux2 = { point3.x-point1.x-i*ex.x, point3.y-point1.y-i*ex.y};
point ey = { aux2.x / norm (aux2), aux2.y / norm (aux2) };
//the signed magnitude of the y component
double j = ey.x * aux.x + ey.y * aux.y;
//coordinates
double x = (pow(r1,2) - pow(r2,2) + pow(p2p1Distance,2))/ (2 * p2p1Distance);
double y = (pow(r1,2) - pow(r3,2) + pow(i,2) + pow(j,2))/(2*j) - i*x/j;
//result coordinates
double finalX = point1.x+ x*ex.x + y*ey.x;
double finalY = point1.y+ x*ex.y + y*ey.y;
resultPose.x = finalX;
resultPose.y = finalY;
return resultPose;
}
int main(int argc, char* argv[]){
point finalPose;
point p1 = {4.0,4.0};
point p2 = {9.0,7.0};
point p3 = {9.0,1.0};
double r1,r2,r3;
r1 = 4;
r2 = 3;
r3 = 3.25;
finalPose = trilateration(p1,p2,p3,r1,r2,r3);
cout<<"X::: "<<finalPose.x<<endl;
cout<<"Y::: "<<finalPose.y<<endl;
}
$ the output is:
X::: 8.02188
Y::: 4.13021
It's a little unclear, and perhaps incorrect, in the linked SO answer that the values of i and j are scalar values and computed a bit differently than the other vector quantities. More explicitly you should have:
i = ex · (P3 - P1) = exx (P3x - P1x) + exy (P3y - P1y) = ix + iy
j = ey · (P3 - P1) = eyx (P3x - P1x) + eyy (P3y - P1y) = jx + jy
Note that · is the dot product of two vectors here. Thus, in your code there should be no ix, iy, jx or jy.
Also, in your calculation of y you should change the denominator of /2*j to:
/ (2*j)
otherwise you are multiplying by j instead of dividing. Making these changes gives me the result of [7.05, 5.74] which is closer to your expected values.
i was wondering why in this program, "pi_estimated" wouldn't print out as a number with decimal places although the variable was declared as a "double". However, it prints out an integer.
double get_pi(double required_accuracy)
{
double pi_estimation=0.0;
int x,y;
double p=0.0,q=0.0,r=0.0;
int D=0;
for(int N=1;N<=1e2;N++)
{
x = rand()%100;
p = (x/50.0 - 1.0)/100.0;
y = rand()%100;
q = (y/50.0 - 1.0)/100.0;
r = p*p + q*q;
if((sqrt(r))<1.0)
{
D++;
pi_estimation = 4.0*(double (D/N));
}
if(double (4/(N+1)) < (required_accuracy*pi_estimation/100.0))
{
cout<<pi_estimation<<endl;
return (pi_estimation);
}
}
}
int main()
{
double pi_approx=0.0, a, actual_accuracy=0.0;
for(a=0.1;a>=1e-14;a/=10)
{
pi_approx = get_pi(a);
actual_accuracy = (fabs((pi_approx - M_PI)/(M_PI)))*100.0;
cout<<actual_accuracy<<endl;
}
}
This line is the culprit:
pi_estimation = 4.0*(double (D/N));
Since D and N are both ints, D/N is an int. Casting the int to a double cannot magically make decimals appear out of nowhere.
Here's the line, fixed:
pi_estimation = 4.0 * (((double) D) / N));
You could also multiply first, so you don't need so many parens:
pi_estimation = 4.0 * D / N;
D is being multiplied by 4.0, so it becomes a double because double * int = double. Then it's divided by N. Since (x * y) / z === x * (y / z) (associative property), the expressions are equivalent.
The problem is here:
pi_estimation = 4.0*(double (D/N));
D and N are both integers, so D/N is an integer that you are casting to a double and then multiplying by 4.0.
You want to do this:
pi_estimation = 4.0 * (static_cast<double>(D) / N));
Since D and N are both integral types, D/N is performed in integer arithmetic; the cast to double happens too late as precision is lost prior to the cast.
One fix is to write 4.0 * D / N. This will ensure that everything is calculated in floating point. (Since * and / have the same precedence, you don't need to write (double).)