How to draw an arc with given starting point in opengl? - c++

I want to draw an arc with opengl. The arc should start from an specific point and ends at a given point. Given are radius, centre of the arc and arc length, start angle and end angle.
I have tried following function:
for (double theta = start_angle1; theta < end_angle1; theta += angle_increment)
{
glVertex2f((arcCenX+ r * sinf(theta)),(arcCenY+ r * cosf(theta)));
}
This functions gives arc properly, but starting point of arc is different.
How to specify a starting point of an arc?
Edit: I also have tried this
for ( angleIndex = 0; angleIndex < arc_len; angleIndex = angleIndex+arcSegmentIndex )
{
glVertex2f((x + ( cosf( start_angle1 + angleIndex ) )* r),
(y + ( sinf( start_angle1 + angleIndex ) )* r));
}
But it also not working.

It should be
glVertex2f((arcCenX+ r * cosf(theta)),(arcCenY+ r * sinf(theta)));
Its bascially the parametric equation of the circle so
x = r cos(0)
y = r sin(0)
where "r" is the radius of the circle. You have your x and y coordinates swapped maybe that's what's causing the problem.
Edit:- to clear it up, the starting point of the arc depends on the first theta value you put in. so if for example the first value that goes into theta is 90 degrees then the arc starts directly above the center of the circle at a distance r.

Related

Understanding GLSL function to draw polygon using distance field

Could someone help me understand the following function that draws a polygon of N sides (i.e. 3 being a triangle and 4 being a square):
float theta = atan(pos.x, pos.y);
float rotate_angle = 2 * PI / N;
float d = cos(floor(0.5 + theta / rotate_angle) * rotate_angle - theta) * length(pos);
What I understand from this illustration is that:
we're interested in finding the angle indicated by the red curve (call it alpha)
cos(alpha) * length will project the green line onto the blue line
by comparing the size of said projection with that of the blue line (radius of circle), we know whether a test point is inside or outside of the polygon we're trying to draw
Question
Why does alpha equal floor(0.5 + theta / rotate_angle) * rotate_angle - theta? Where does 0.5 come from? What's the significance of theta / rotate_angle?
What I have read:
[1] https://codepen.io/nik-lever/full/ZPKmmx
[2] https://thndl.com/square-shaped-shaders.html
[3] https://thebookofshaders.com/07
Simply, floor(0.5 + x) = round(x). However, because round(x) may not be available in some environments (e.g. in GLES2), floor(0.5 + x) is to be used instead.
Then, since n = round(theta / rotate_angle) gives edge section index which contains pos (e.g. n =-1, 0 or 1 for a triangle) , n * rotate_angle is the angle of edge center point(=blue line) which is nearest to the theta.
Therefore, alpha = n * rotate_angle - theta is certainly relative angle from pos to the nearest center, where -rotate_angle/2 < alpha <= rotate_angle/2.
Checking pos's projection length to the center point direction, it's possible to tell inside or outside. To detect discrete direction of polygon edges('s orthogonal vectors) seamlessly, round() function is used.

Trying to use a rotation matrix, and failing

I have been trying to use a rotation matrix to rotate an image. Below is the code I've been using. I have been trying to do so for days now, and everytime it seems there is something wrong, but I can't see what I am doing wrong. For example, my image is getting slanted, instead of rotating...
The code below is divided in two parts: the actual rotation, and moving the picture upwards to make it appear in the correct spot (it needs to have all its point above 0 to be saved properly). It takes as input an array of pixels (containing position information (x, y), and colour information (r, g, b)), an image (used solely to get its pixel count, aka the array size, and the width), and a value in radians for the rotation.
The part responsible for the rotation itself is the one above the line, while the part below the line is responsible for calculating the lowest point in the image, and moving all pixels up or to the right so the all fit (I need still to implement a function to change the image size when an image is rotated by 45 degrees, or similar).
void Rotate( Pixel *p_pixelsToRotate, prg::Image* img, float rad )
{
int imgLength = img->getPixelCount();
int width = img->getWidth();
int x { 0 }, y { 0 };
for( int i = 0; i < imgLength; i++ )
{
x = p_pixelsToRotate[i].x;
y = p_pixelsToRotate[i].y;
p_pixelsToRotate[i].x = round( cos( rad ) * x - sin( rad ) * y );
p_pixelsToRotate[i].y = round( sin( rad ) * x + sin( rad ) * y );
}
===========================================================================
Pixel* P1 = &p_pixelsToRotate[ width - 1 ]; // Definitions of these are in the supporting docs
Pixel* P3 = &p_pixelsToRotate[ imgLength - 1 ];
int xDiff = 0;
int yDiff = 0;
if( P1->x < 0 || P3->x < 0 )
{
(( P1->x < P3->x )) ? ( xDiff = abs( P1->x )) : ( xDiff = abs( P3->x ));
}
if( P1->y < 0 || P3->y < 0 )
{
(( P1->y < P3->y )) ? ( yDiff = abs( P1->y )) : ( yDiff = abs( P3->y ));
}
for( int i = 0; i < imgLength; i++ )
{
p_pixelsToRotate[i].x += xDiff;
p_pixelsToRotate[i].y += yDiff;
}
}
I would prefer fixing this myself, but have been unable to do so for more than a week now. I don't see why the function is not rotating the position information for the array of input pixel. If someone could have a look, and maybe spot why my logic isn't working, I would be immensely grateful. Thank you.
Seems you just made a mistake in the rotation matrix itself:
p_pixelsToRotate[i].y = round( sin( rad ) * x + sin( rad ) * y );
^^^---------------change to cos
For one thing, this is a mistake:
p_pixelsToRotate[i].x = round( cos( rad ) * x - sin( rad ) * y );
p_pixelsToRotate[i].y = round( sin( rad ) * x + >>>sin<<<( rad ) * y );
The >>>sin<<< should be cos. This would explain getting a shear rather than a rotation.
Other comments: Storing pixel coordinates in bitmap data is an extremely expensive way to solve the problem of bitmap rotation. The better way is inverse transform sampling. With a source image X and wishing to rotate it with transform R to get Y, you are currently thinking
Y = R X
where X and Y have the pixel coordinates explicitly stored. To use inverse sampling, think instead of the same equation multiplied on both sides by the inverse of R.
R^(-1) Y = X
where the coordinates are implicit. That is, to produce Y[j][i], transform (j,i) with the inverse R^(-1) to get a coordinate (x,y) in the X image. Use this to sample the nearest pixel X[round(x)][round(y)] in X and assign that as Y[j][i].
(Actually, rather than simple rounding, a more sophisticated algorithm will take a weighted average of the X pixels around (x,y) to get a smoother result. How to choose the weights is a big additional topic.)
After you have this working, you can go a step farther. Instead of doing a full matrix-vector multiplication for each pixel, some algebra will show that the previous sampling coordinate can be updated to get an adjacent one (next to the right or left, up or down) with just a couple of additions. This speeds things up considerably.
The inverse of a rotation is trivial to compute! Just negate the rotation angle.
A last note is that your use of ternary operators o ? o : o to select assignments is truly terrible style. Instead of this:
(( P1->x < P3->x )) ? ( xDiff = abs( P1->x )) : ( xDiff = abs( P3->x ));
say
xDiff = ( P1->x < P3->x ) ? abs( P1->x ) : abs( P3->x );

OpenGL - Creating a circle, change radius?

I must be the worst person on the planet when it comes to math because i can't figure out how to change this circle radius:
from math import *
posx, posy = 0,0
sides = 32
glBegin(GL_POLYGON)
for i in range(100):
cosine=cos(i*2*pi/sides)+posx
sine=sin(i*2*pi/sides)+posy
glVertex2f(cosine,sine)
I'm not entirely sure how or why this becomes a circle because the *2 confuses me a bit.
Note that this is done in Pyglet under Python2.6 calling OpenGL libraries.
Followed Example 4-1: http://fly.cc.fer.hr/~unreal/theredbook/chapter04.html
Clarification: This works, i'm interested in why and how to modify the radius.
This should do the trick :)
from math import *
posx, posy = 0,0
sides = 32
radius = 1
glBegin(GL_POLYGON)
for i in range(100):
cosine= radius * cos(i*2*pi/sides) + posx
sine = radius * sin(i*2*pi/sides) + posy
glVertex2f(cosine,sine)
But I would pick another names for variables. cosine and sine is not exactly what these variables are.
And as far as I see, you son't need a loop from 1 to 100 (or from 0 to 99, I'm not too good at Python), you just need a loop from 1 to sides.
Explanation:
When you calculate
x = cos (angle)
y = sin(angle)
you get a point on a circle with radius = 1, and centre in the point (0; 0) (because sin^2(angle) + cos^2(angle) = 1).
If you want to change a radius to R, you simply multiply cos and sin by R.
x = R * cos (angle)
y = R * sin(angle)
If you want to transfer the circle to another location (for example, you want the circle to have it's centre at (X_centre, Y_centre), you add X_centre and Y_xentre to x and y accordingly:
x = R * cos (angle) + X_centre
y = R * sin(angle) + Y_centre
When you need to loop through N points (in your case N = sides) on your circle, you should change the angle on each iteration. All those angles should be equal and their sum should be 2 * pi. So each angle should be equal to 2 * pi/ N. And to get i-th angle you multiply this value by i: i * 2 * pi / N.
math : P=pr^2=p*r*r= p*r*2 programming i*2*pi/sides
together : i = p i*2, *2=r^2 this should help you

efficient line from hough transform coordinates

i'm working with a hough transform (polar coordinates). i'd like to compute a vector representation of a line from a coordinate from the hough transform.
my current implementation loops through all the pixel coordinates in the image from (0,0) to (M, N) where M and N are the size of the image. as the loop traverses the space, this value is computed:
// angle and rho are the polar coordinates from hough space.
tmp = (int) ( (i * cos( angle ) ) + ( j * sin(angle) ) );
where tmp - rho == 0, is part of the line, so i track that position. when the loop reaches the end of the image (i,j) == (M,N), the loop is done again from the opposite direction (M, N) to (0,0).
the first (tmp-rho == 0) going left to right and the second (tmp-rho == 0) going right to left are the coordinates of the line. i then subtract those pixel coordinates to get a vector of the line in the hough space.
this is terribly inefficient (slow) and i'm 100% sure there's a better way to compute this but, i can't seem to figure it out. any help would be greatly appreciated!
You can solve your equation for i=0, i=M, j=0, j=N instead of looping
rho = i * cos(angle) + j * sin(angle)
i = 0 --> j1 = rho / sin(angle)
i = M --> j2 = (rho - M*cos(angle)) / sin(angle)
j = 0 --> i1 = rho / cos(angle)
j = N --> i2 = (rho - N*sin(angle)) / cos(angle)

Algorithm to generate radial gradient

I have this algorithm here:
pc = # the point you are coloring now
p0 = # start point
p1 = # end point
v = p1 - p0
d = Length(v)
v = Normalize(v) # or Scale(v, 1/d)
v0 = pc - p0
t = Dot(v0, v)
t = Clamp(t/d, 0, 1)
color = (start_color * t) + (end_color * (1 - t))
to generate point to point linear gradients. It works very well for me. I was wondering if there was a similar algorithm to generate radial gradients. By similar, I mean one that solves for color at point P rather than solve for P at a certain color (where P is the coordinate you are painting).
Thanks
//loop through vector
//x and y px position
int x = i%w;
int y = i/w;
float d = distance(center,int2(x,y));
//if within the grad circle
if(d < radius)
{
//somehow set v[i] alpha to this:
float a = d/r;
}
Linerise over atan2(dy,dx) where dx is x-center, and dy is y-center.
cx # center x
cy # center y
r1 # ring is defined by two radius
r2 # r1 < r2
c1 # start color
c2 # stop color
ang # start angle
px # currect point x,y
py
if( px^2 + py^2 <= r2^2 AND px^2 + py^2 >= r1^2 ) # lies in ring?
t= atan2(py-cy,px-cx)+ang
t= t+ pi # atan2 is from -pi to pi
if (t > 2* pi) # it might over 2pi becuse of +ang
t=t-2*pi
t=t/(2*pi) # normalise t from 0 to 1
color = (c1 * t) + (c2 * (1 - t))
Problem whit this algorhitm is that ang is actualy wrong and should be rotated by pi and normalized between 0 and 2pi.
Based on the comment, what you want can still be viewed as a linear gradient -- i.e. you have a line from the center to the outside of the circle, and you have a linear gradient along that line. As such, the calculation is virtually identical to what you already had.
Edit: Okay, apparently I misunderstood what you want. To figure a gradient running around a radius, you still basically linearize it -- figure out the circumference at that radius (2*Pi*R), and then do a linear interpolation along a line of that length.