In the BGI library's "graphics.h" header there is a function pieslice in that header file,its syntax is:
#include <graphics.h>
void pieslice(int x, int y, int stangle, int endangle, int radius);
[x,y are the center of the circle,stangle and endangle are the starting and end angles respectively]
Can we make a pieslice in C/C++ without using this in-built function of the BGI library.Please help. Tried making it with the help of the lines and mid-point circle generation algorithms.
My code so far:
#include<stdio.h>
#include<graphics.h>
static const double PI =3.141592
int main()
{
int gd=DETECT,gm;
initgraph(&gd,&gm,NULL);
int xc,yc,r,st_angle,ed_angle,k;
printf("Enter the centers of pieslice:\n");
scanf("%d %d",&xc,&yc);
printf("Enter the radius:\n");
scanf("%d",&r);
printf("Enter the starting angle:\n");
scanf("%d",&st_angle);
printf("Enter the end angle:\n");
scanf("%d",&ed_angle);
for(k=st_angle; k<=ed_angle;k++)
{
double radians =(PI /180.0) * k;
int X = xc+ cos(radians) * r;
int Y = yc+ sin(radians) * r;
putpixel(x,y,WHITE);
delay(5000);
}
void wait_for_char()
{
//Wait for a key press
int in = 0;
while (in == 0) {
in = getchar();
}
}
getch();
}
I was able to do the calculation part where i used the parametric equation of circle,but unable to generate the figure using the graphics.h
function. Some help would be nice. Thank you in advance.
While running this program,i am getting this error:
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
a.out: ../../src/xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
a.out: ../../src/xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
Aborted (core dumped)
why not use vectors?
So (0,0)
centered pie of radius r
is determined by:
u = (cos(a0),sin(a0))
v = (cos(a1),sin(a1))
x^2 + y^2 <= r^2 // circle
(x,y) x u -> CW
(x,y) x v -> CCW
the CW/CCW is determined by computing 3D cross product and examining the sign of results z coordinate...
so process all pixels in circle outscribed square and render all pixels that complies all 3 conditions.
Something like this:
void pie(int x0,int y0,int r,int a0,int a1,DWORD c)
{
// variables
int x, y, // circle centered point
xx,yy,rr, // x^2,y^2,r^2
ux,uy, // u
vx,vy, // v
sx,sy; // pixel position
// my Pixel access (remove these 3 lines)
int **Pixels=Main->pyx; // Pixels[y][x]
int xs=Main->xs; // resolution
int ys=Main->ys;
// init variables
rr=r*r;
ux=double(r)*cos(double(a0)*M_PI/180.0);
uy=double(r)*sin(double(a0)*M_PI/180.0);
vx=double(r)*cos(double(a1)*M_PI/180.0);
vy=double(r)*sin(double(a1)*M_PI/180.0);
// render |<-- remove these -->|
for (y=-r,yy=y*y,sy=y0+y;y<=+r;y++,yy=y*y,sy++) if ((sy>=0)&&(sy<ys))
for (x=-r,xx=x*x,sx=x0+x;x<=+r;x++,xx=x*x,sx++) if ((sx>=0)&&(sx<xs))
if (xx+yy<=rr) // inside circle
if ((x*uy)-(y*ux)<=0) // x,y is above a0 in clockwise direction
if ((x*vy)-(y*vx)>=0) // x,y is below a1 in counter clockwise direction
Pixels[sy][sx]=c; // change for putpixel
}
However I do not use BGI so just change the Pixels[sy][sx]=c;
with your putpixel(sx,sy,c);
and remove obsolete range check ifs for sx,sy
. Also remove the resolution xs,ys
and Pixels
variables.
Here preview for (xs2,ys2
is mine middle of screen):
pie(xs2,ys2,ys2-200,10,50,0x00FF0000);
Note that I have 32 bit RGB color instead of your indexed 8 bit ones and angles are in degrees. Also note that mine y axis points down so incrementing angle is going clockwise starting from the x axis (pointing to right)
This however works only for pies below 180 degrees. For bigger ones you need to invert the cross product conditions to render when not inside the not filled pie part instead something like this:
void pie(int x0,int y0,int r,int a0,int a1,DWORD c) // a0 < a1
{
// variables
int x, y, // circle centered point
xx,yy,rr, // x^2,y^2,r^2
ux,uy, // u
vx,vy, // v
sx,sy; // pixel position
// my Pixel access
int **Pixels=Main->pyx; // Pixels[y][x]
int xs=Main->xs; // resolution
int ys=Main->ys;
// init variables
rr=r*r;
ux=double(r)*cos(double(a0)*M_PI/180.0);
uy=double(r)*sin(double(a0)*M_PI/180.0);
vx=double(r)*cos(double(a1)*M_PI/180.0);
vy=double(r)*sin(double(a1)*M_PI/180.0);
// handle big/small pies
x=a1-a0;
if (x<0) x=-x;
// render small pies
if (x<180)
{
for (y=-r,yy=y*y,sy=y0+y;y<=+r;y++,yy=y*y,sy++) if ((sy>=0)&&(sy<ys))
for (x=-r,xx=x*x,sx=x0+x;x<=+r;x++,xx=x*x,sx++) if ((sx>=0)&&(sx<xs))
if (xx+yy<=rr) // inside circle
if (((x*uy)-(y*ux)<=0) // x,y is above a0 in clockwise direction
&&((x*vy)-(y*vx)>=0)) // x,y is below a1 in counter clockwise direction
Pixels[sy][sx]=c;
}
else{
for (y=-r,yy=y*y,sy=y0+y;y<=+r;y++,yy=y*y,sy++) if ((sy>=0)&&(sy<ys))
for (x=-r,xx=x*x,sx=x0+x;x<=+r;x++,xx=x*x,sx++) if ((sx>=0)&&(sx<xs))
if (xx+yy<=rr) // inside circle
if (((x*uy)-(y*ux)<=0) // x,y is above a0 in clockwise direction
||((x*vy)-(y*vx)>=0)) // x,y is below a1 in counter clockwise direction
Pixels[sy][sx]=c;
}
}
pie(xs2,ys2,ys2-200,50,340,0x00FF0000);
The code can be further optimized for example x*uy
can be changed to addition in for cycle like for(...,xuy=x*uy;...;...,xuy+=uy)
eliminating slow multiplication from inner loops. The same goes for all 4 therms in the cross product conditions.
[edit1] To be more clear we have something like this:
for (x=-r,xx=x*x,sx=x0+x;x<=+r;x++,xx=x*x,sx++)
{
if (...(x*uy)...) { do something }
}
the (x*uy)
is computed on each iteration of x
. The x
is incrementing so we can compute the value of (x*uy)
from the previous value ((x-1)*uy)+uy
which does not need multiplication as ((x-1)*uy)
is the value from last iteration. So adding single variable that holds it can get rid of the repeated multiplication:
int xuy; // ******** *******
for (x=-r,xx=x*x,sx=x0+x,xuy=x*uy;x<=+r;x++,xx=x*x,sx++,xuy+=uy)
{
if (...(xuy)...) { do something }
}
so the initial multiplication is done just once and from then its just addition ...
Also this way of rendering is fully parallelisable...