wu's antialiasing algorithm - c

function plot(x, y, c) is
plot the pixel at (x, y) with brightness c (where 0 ≤ c ≤ 1)
function ipart(x) is
return integer part of x
function round(x) is
return ipart(x + 0.5)
function fpart(x) is
return fractional part of x
function rfpart(x) is
return 1 - fpart(x)
function drawLine(x1,y1,x2,y2) is
dx = x2 - x1
dy = y2 - y1
if abs(dx) < abs(dy) then
swap x1, y1
swap x2, y2
swap dx, dy
end if
if x2 < x1
swap x1, x2
swap y1, y2
end if
gradient = dy / dx
// handle first endpoint
xend = round(x1)
yend = y1 + gradient * (xend - x1)
xgap = rfpart(x1 + 0.5)
xpxl1 = xend // this will be used in the main loop
ypxl1 = ipart(yend)
plot(xpxl1, ypxl1, rfpart(yend) * xgap)
plot(xpxl1, ypxl1 + 1, fpart(yend) * xgap)
intery = yend + gradient // first y-intersection for the main loop
// handle second endpoint
xend = round (x2)
yend = y2 + gradient * (xend - x2)
xgap = fpart(x2 + 0.5)
xpxl2 = xend // this will be used in the main loop
ypxl2 = ipart (yend)
plot (xpxl2, ypxl2, rfpart (yend) * xgap)
plot (xpxl2, ypxl2 + 1, fpart (yend) * xgap)
// main loop
for x from xpxl1 + 1 to xpxl2 - 1 do
plot (x, ipart (intery), rfpart (intery))
plot (x, ipart (intery) + 1, fpart (intery))
intery = intery + gradient
end function
What does this mean?
function fpart(x) is
return fractional part of x
How do I get the fractional part of x?

Fractional part is the part after the decimal point, for eg. the fractional part of 10.5 is 0.5. Assuming x is a floating-point number, x - floor(x) will get you the fractional part.

You should return the fractional part, which is what comes after the decimal.
4.34 = 0.33 ect...

Related

Finding a point on the right side of a line at a given distance

I want to find the point at distance d on the right side of a line defined by P1(x1,y1) and P2(x2,y2) (the distance is calculated from the middle of the line). I came up with the following code, which works well, but I think I have made unnecessary calculations, and it can be done faster.
#define PI 3.141592653589793238462643383279502884197169399375105820974944592308
double x2, x1, y1, y2, px, py, p1x, p1y, p2x, p2y, d, ax, ay, b, dx, dy;
d = 2.0; // given distance
ax = (x1 + x2) / 2; // middle point
ay = (y1 + y2) / 2; // middle point
b = tan(atan2(y2 - y1, x2 - x1) + PI / 2); // slope of the perpendicular line
dx = (d / sqrt(1 + (b * b)));
dy = b * dx;
p1x = ax + dx;
p1y = ay + dy;
p2x = ax - dx;
p2y = ay - dy;
// cross product
if (((x2 - x1) * (p1y - y1) - (y2 - y1) * (p1x - x1)) > 0)
{
px = p1x;
py = p1y;
}
else
{
px = p2x;
py = p2y;
}
You don't need atan, b value, cross product to check orientation (moreover, b might be zero and cause division error).
Instead calculate normalized (unit length) direction vector and get right normal to it:
d = 2.0; // given distance
ax = (x1 + x2) / 2; // middle point
ay = (y1 + y2) / 2; // middle point
dx = x2 - x1;
dy = y2 - y1;
scale = d / sqrt(dx*dx + dy*dy); //distance/vector length
px = ax + dy * scale; // add normal vector to the right side of p1-p2 direction
py = ay - dx * scale; //note minus sign
For generating a 2D vector perpendicular to another, one result that falls out from a special case of the dot product is that you can swap the two components of the vector and negate one of them.
For example, let's say you have the vector d which points from p1 to p2:
dx = p2x - p1x;
dy = p2y - p1y;
And now you want to generate right which is perpendicular, it is simply:
rightx = dy;
righty = -dx;
Now, let's do a quick visual check for our definition of "on the right", in case we actually want to negate those two values...
o p2 = [2, 3]
/
o p1 = [0, 0]
Above, d is simple: [2, 3]. Intuitively, we would think of (as viewed from above) walking from p1 to p2 and looking to the right, which would mean a vector in the positive X direction and the negative Y direction. So yes, that looks fine.
Note: If your co-ordinate system is screen-based (i.e. positive Y direction is down), then the inverse is true (and you would negate both the terms in the calculation of the right vector). This is due to the handedness of the co-ordinate system being left instead of right.
Now, you can calculate the midpoint mid as either (p1 + p2) / 2 or p1 + d / 2.
midx = (p1x + p2x) / 2;
midy = (p1y + p2y) / 2;
And finally to generate p3 you start from mid and extend down the vector right by an amount height, you need to normalize that vector by dividing by its length and scale by height. Formally, the final point will be mid + right * height / length(right).
This is the only particularly expensive part of the calculation, because it needs a square root.
rdist = height / sqrt(rightx * rightx + righty * righty);
p3x = midx + rightx * rdist;
p3y = midy + righty * rdist;
Congratulations! You now have an isosceles triangle!

How can i find the length of a line between two points with coordinates (x1, y1) and (x2, y2) in array?

How can i find the length of a line between two points with coordinates (x1, y1) and (x2, y2) in array ? For example i have 2 arrays : arrayX[10] and arrayY[10].
I have to find the results of the following operations in the loop and save them in the result array :
sqrt((arrayX[0]- arrayX[1])^2+(arrayY[0]-arrayY[1]^2))
sqrt((arrayX[1]- arrayX[2])^2+(arrayY[1]-arrayY[2]^2))
.
.
.
In C there is no exponentiation operator. To compute x^2 either use x * x or pow(x, 2) from math.h.
Possible solution
double dist[9];
for (int i = 0; i + 1 < 10; ++i) {
double dx = arrayX[i]- arrayX[i + 1];
double dy = arrayY[i]- arrayY[i + 1];
dist[i] = sqrt(dx *dx + dy * dy);
}

How to draw circles, arcs and vector graphics in SDL?

I'm using SDL2.
The only way I can find to draw a shape is with the line, rect and pixel functions, as explained here.
Apart from using trig or the "equation of a circle", how could I draw a curve? How about general vector graphics?
Is SDL an appropriate starting point or should I look elsewhere?
This is an example of the Midpoint Circle Algorithm as referenced above. It doesn't require a math library and is very fast. (Renders in about 500 microseconds) This is what Windows uses/used to rasterize circles.
void DrawCircle(SDL_Renderer * renderer, int32_t centreX, int32_t centreY, int32_t radius)
{
const int32_t diameter = (radius * 2);
int32_t x = (radius - 1);
int32_t y = 0;
int32_t tx = 1;
int32_t ty = 1;
int32_t error = (tx - diameter);
while (x >= y)
{
// Each of the following renders an octant of the circle
SDL_RenderDrawPoint(renderer, centreX + x, centreY - y);
SDL_RenderDrawPoint(renderer, centreX + x, centreY + y);
SDL_RenderDrawPoint(renderer, centreX - x, centreY - y);
SDL_RenderDrawPoint(renderer, centreX - x, centreY + y);
SDL_RenderDrawPoint(renderer, centreX + y, centreY - x);
SDL_RenderDrawPoint(renderer, centreX + y, centreY + x);
SDL_RenderDrawPoint(renderer, centreX - y, centreY - x);
SDL_RenderDrawPoint(renderer, centreX - y, centreY + x);
if (error <= 0)
{
++y;
error += ty;
ty += 2;
}
if (error > 0)
{
--x;
tx += 2;
error += (tx - diameter);
}
}
}
If you want to write your own circle drawing function, then I'd suggest adapting the midpoint algorithm to SDL2 by drawing pixels.
Curves would be done similarly, but would use more of an ellipses drawing algorithm.
Actual vector graphics start to get much more complicated, and you'd probably have to find something that renders SVG files, which I'm not sure there are many options for SDL2.
However, if you would rather simply have functions that you can work with I'd suggest going straight to SDL2_gfx instead. It has many more functions already implemented for you to work with.
SDL allows for third party libs to draw on a texture. If cairo was desirable, it could be used in a function like this:
cairo_t*cb(cairo_t*cr)
{cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_rectangle(cr, 10, 20, 128, 128);
cairo_stroke(cr);
return cr;
}
then cb can be passed to this function:
cairo_t*cai(SDL_Window*w,SDL_Renderer*r,cairo_t*(*f)(cairo_t*))
{int width, height, pitch;void *pixels;
SDL_GetWindowSize(w, &width, &height);
SDL_Texture*t=SDL_CreateTexture(r,SDL_PIXELFORMAT_ARGB8888,SDL_TEXTUREACCESS_STREAMING,width,height);
SDL_LockTexture(t, NULL, &pixels, &pitch);
cairo_surface_t *cs=cairo_image_surface_create_for_data(pixels,CAIRO_FORMAT_ARGB32,width,height,pitch);
cairo_t*s=cairo_create(cs);
cairo_t*fr=f(s);SDL_UnlockTexture(t);SDL_RenderCopy(r,t,NULL,NULL);SDL_RenderPresent(r);
return fr;
}
If you want to do a circle or ellipse without 3rd party libraries, include math.h and use the function below I wrote. It will draw aliased ellipse or circles very well. Tested on SDL 2.0.2 and works. It draws one quadrant arc, and mirrors the other arcs, reducing calls to cosf and sinf.
//draw one quadrant arc, and mirror the other 4 quadrants
void sdl_ellipse(SDL_Renderer* r, int x0, int y0, int radiusX, int radiusY)
{
float pi = 3.14159265358979323846264338327950288419716939937510;
float pih = pi / 2.0; //half of pi
//drew 28 lines with 4x4 circle with precision of 150 0ms
//drew 132 lines with 25x14 circle with precision of 150 0ms
//drew 152 lines with 100x50 circle with precision of 150 3ms
const int prec = 27; // precision value; value of 1 will draw a diamond, 27 makes pretty smooth circles.
float theta = 0; // angle that will be increased each loop
//starting point
int x = (float)radiusX * cos(theta);//start point
int y = (float)radiusY * sin(theta);//start point
int x1 = x;
int y1 = y;
//repeat until theta >= 90;
float step = pih/(float)prec; // amount to add to theta each time (degrees)
for(theta=step; theta <= pih; theta+=step)//step through only a 90 arc (1 quadrant)
{
//get new point location
x1 = (float)radiusX * cosf(theta) + 0.5; //new point (+.5 is a quick rounding method)
y1 = (float)radiusY * sinf(theta) + 0.5; //new point (+.5 is a quick rounding method)
//draw line from previous point to new point, ONLY if point incremented
if( (x != x1) || (y != y1) )//only draw if coordinate changed
{
SDL_RenderDrawLine(r, x0 + x, y0 - y, x0 + x1, y0 - y1 );//quadrant TR
SDL_RenderDrawLine(r, x0 - x, y0 - y, x0 - x1, y0 - y1 );//quadrant TL
SDL_RenderDrawLine(r, x0 - x, y0 + y, x0 - x1, y0 + y1 );//quadrant BL
SDL_RenderDrawLine(r, x0 + x, y0 + y, x0 + x1, y0 + y1 );//quadrant BR
}
//save previous points
x = x1;//save new previous point
y = y1;//save new previous point
}
//arc did not finish because of rounding, so finish the arc
if(x!=0)
{
x=0;
SDL_RenderDrawLine(r, x0 + x, y0 - y, x0 + x1, y0 - y1 );//quadrant TR
SDL_RenderDrawLine(r, x0 - x, y0 - y, x0 - x1, y0 - y1 );//quadrant TL
SDL_RenderDrawLine(r, x0 - x, y0 + y, x0 - x1, y0 + y1 );//quadrant BL
SDL_RenderDrawLine(r, x0 + x, y0 + y, x0 + x1, y0 + y1 );//quadrant BR
}
}
My answer extends Scotty Stephens answer by making it a bunch more performant by reducing the API calls to a single one.
// rounding helper, simplified version of the function I use
int roundUpToMultipleOfEight( int v )
{
return (v + (8 - 1)) & -8;
}
void DrawCircle( SDL_Renderer * renderer, SDL_Point center, int radius )
{
// 35 / 49 is a slightly biased approximation of 1/sqrt(2)
const int arrSize = roundUpToMultipleOfEight( radius * 8 * 35 / 49 );
SDL_Point points[arrSize];
int drawCount = 0;
const int32_t diameter = (radius * 2);
int32_t x = (radius - 1);
int32_t y = 0;
int32_t tx = 1;
int32_t ty = 1;
int32_t error = (tx - diameter);
while( x >= y )
{
// Each of the following renders an octant of the circle
points[drawCount+0] = { center.x + x, center.y - y };
points[drawCount+1] = { center.x + x, center.y + y };
points[drawCount+2] = { center.x - x, center.y - y };
points[drawCount+3] = { center.x - x, center.y + y };
points[drawCount+4] = { center.x + y, center.y - x };
points[drawCount+5] = { center.x + y, center.y + x };
points[drawCount+6] = { center.x - y, center.y - x };
points[drawCount+7] = { center.x - y, center.y + x };
drawCount += 8;
if( error <= 0 )
{
++y;
error += ty;
ty += 2;
}
if( error > 0 )
{
--x;
tx += 2;
error += (tx - diameter);
}
}
SDL_RenderDrawPoints( renderer, points, drawCount );
}
A circle of radius 141 would have had 800 SDL_RenderDrawPoint calls in Scottys version, this new version does only execute one single SDL_RenderDrawPoints call, making it much more performant.
One could also strip the rendering portion out of this function, to allow the result to be cached and reused like shown below.
std::vector<SDL_Point> PixelizeCircle( SDL_Point center, int radius )
{
std::vector<SDL_Point> points;
// 35 / 49 is a slightly biased approximation of 1/sqrt(2)
const int arrSize = roundUpToMultipleOfEight( radius * 8 * 35 / 49 );
points.reserve( arrSize );
const int32_t diameter = (radius * 2);
int32_t x = (radius - 1);
int32_t y = 0;
int32_t tx = 1;
int32_t ty = 1;
int32_t error = (tx - diameter);
while( x >= y )
{
// Each of the following renders an octant of the circle
points.push_back( { center.x + x, center.y - y } );
points.push_back( { center.x + x, center.y + y } );
points.push_back( { center.x - x, center.y - y } );
points.push_back( { center.x - x, center.y + y } );
points.push_back( { center.x + y, center.y - x } );
points.push_back( { center.x + y, center.y + x } );
points.push_back( { center.x - y, center.y - x } );
points.push_back( { center.x - y, center.y + x } );
if( error <= 0 )
{
++y;
error += ty;
ty += 2;
}
if( error > 0 )
{
--x;
tx += 2;
error += (tx - diameter);
}
}
return points; // RVO FTW
}
int main()
{
std::vector<SDL_Point> circle = PixelizeCircle( SDL_Point{ 84, 72 }, 79 );
//...
while( true )
{
//...
SDL_RenderDrawPoints( renderer, circle.data(), circle.size() );
//...
}
}

Rotation Matrix Shrinks Objects?

Is my math wrong? The user is supposed to be able to input an angle in degrees, and it rotate the matrix respectively. Instead, it shrinks the object and flips it... calling
glmxRotate(&modelview, 0.0f, 0.0f, 1.0f, 90.0f);
(with modelview being an identity matrix) yields:
Regular: http://i.imgur.com/eX7Td.png
Rotated: http://i.imgur.com/YnMEn.png
Here's glmxRotate:
glmxvoid glmxRotate(glmxMatrix* matrix, glmxfloat x, glmxfloat y, glmxfloat z,
glmxfloat angle)
{
if(matrix -> mx_size != 4){GLMX_ERROR = GLMX_NOT_4X4; return;}
//convert to rads
angle *= 180.0f / 3.14159;
const glmxfloat len = sqrtf((x * x) + (y * y) + (z * z)),
c = cosf(angle),
c1 = 1.0f - c,
s = sinf(angle);
//normalize vector
x /= len;
y /= len;
z /= len;
glmxfloat rot_mx[] = {x * x * c1 + c,
x * y * c1 + z * s,
x * z * c1 - y * s,
0.0f,
x * y * c1 - z * s,
y * y * c1 + c,
y * z * c1 + x * s,
0.0f,
x * z * c1 + y * s,
y * z * c1 - x * s,
z * z * c1 + c,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,};
_glmxMultiMatrixArray(matrix, rot_mx, 4);
}
Also, if a translation matrix is defined with the translation in the last four column, how would one go about translating an identity matrix, because the outcome would always yield 0s?
Your matrix looks correct to me, though are you aware that your angle to rads multiplication is actually a radians to angle multiplication?
//convert to rads
angle *= 180.0f / 3.14159;
Should be Pi/180.f.
as there is a limited amount of space that the float is stored in the sin and cos are not exactly calculated this means that small errors happen every time the object is rotated this means that over time the object will get smaller.
if you want this to not happen use Quaternions for rotations.
https://www.npmjs.com/package/quaternion

Point on a straight line specific distance away in C

How do I find the point on the straight line that is specific distance away from a given point. I am writing this code in C but I do not get the right answer..Could you anyone guide me on what I am doing wrong.
I get the x1,y1,x2,y2 values and the distance left fine. Using these I can find the slope m and the y-intercept also fine.
Now, I need to find the point on the straight line connecting these two points that is 10 units away from the point x1,y1. I seem to be going wrong here. here's the code that I wrote.
int x1 = node[n].currentCoordinates.xCoordinate;
int y1 = node[n].currentCoordinates.yCoordinate;
int x2 = node[n].destinationLocationCoordinates.xCoordinate;
int y2 = node[n].destinationLocationCoordinates.yCoordinate;
int distanceleft = (y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1);
distanceleft = sqrt(distanceleft);
printf("Distance left to cover is %d\n",distanceleft);
int m = (y2 - y1)/(x2 - x1); // slope.
int b = y1 - m * x1; //y-intercept
//find point on the line that is 10 units away from
//current coordinates on equation y = mx + b.
if(x2 > x1)
{
printf("x2 is greater than x1\n");
int tempx = 0;
int tempy = 0;
for(tempx = x1; tempx <= x2; tempx++)
{
tempy = y1 + (y2 - y1) * (tempx - x1)/(x2 - x1);
printf("tempx = %d, tempy = %d\n",tempx,tempy);
int distanceofthispoint = (tempy - y1) * (tempy - y1) + (tempx - x1) * (tempx - x1);
distanceofthispoint = sqrt((int)distanceofthispoint);
if(distanceofthispoint >= 10)
{
//found new points.
node[n].currentCoordinates.xCoordinate = tempx;
node[n].currentCoordinates.yCoordinate = tempy;
node[n].TimeAtCurrentCoordinate = clock;
printf("Found the point at the matching distance\n");
break;
}
}
}
else
{
printf("x2 is lesser than x1\n");
int tempx = 0;
int tempy = 0;
for(tempx = x1; tempx >= x2; tempx--)
{
tempy = y1 + (y2 - y1) * (tempx - x1)/(x2 - x1);
printf("tempx = %d, tempy = %d\n",tempx,tempy);
int distanceofthispoint = (tempy - y1) * (tempy - y1) + (tempx - x1) * (tempx - x1);
distanceofthispoint = sqrt((int)distanceofthispoint);
if(distanceofthispoint >= 10)
{
//found new points.
node[n].currentCoordinates.xCoordinate = tempx;
node[n].currentCoordinates.yCoordinate = tempy;
node[n].TimeAtCurrentCoordinate = clock;
printf("Found the point at the matching distance\n");
break;
}
}
}
printf("at time %f, (%d,%d) are the coordinates of node %d\n",clock,node[n].currentCoordinates.xCoordinate,node[n].currentCoordinates.yCoordinate,n);
Here is how it is in math, I don't have time to write something in C.
You have a point (x1,y1) and another one (x2,y2), when linked it gives you a segment.
Thus you have a directional vector v=(xv, yv) where xv=x2-x1 and yv=y2-y1.
Now, you need to divide this vector by its norm, you get a new vector: vector = v / sqrt(xv2 + yv2).
Now, you just have to add to your origin point the vector multiplied by the distance at which you want your point:
Position = (x origin, y origin) + distance × vector
I hope this helps!
Or simpler,
Find the angle from the slope
θ = arctan(y2-y1/x2-x1)
You might want to modify the quadrant of θ based on the numerator and denominator of the slope. Then you can find any point on the line at distance d from (x1, y1)
x_new = x1 + d×cos(θ)
y_new = y1 + d×sin(θ)
In this case, you have d=10

Resources