почему бы не использовать векторы?
Итак (0,0)
центрированный пироградиуса r
определяется следующим образом:
u = (cos(a0),sin(a0))
v = (cos(a1),sin(a1))
x^2 + y^2 <= r^2 // circle
(x,y) x u -> CCW
(x,y) x v -> CCW
CW / CCW определяется путем вычисления трехмерного перекрестного произведения и изучения результата результатов с координатой z ...
, поэтому обрабатывают все пикселипо кругу вписал квадрат и рендерил все пиксели, соответствующие всем 3 условиям.
Примерно так:
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
}
Однако я не использую BGI, поэтому просто замените Pixels[sy][sx]=c;
на putpixel(sx,sy,c);
и удалите устаревшие проверки диапазона для sx,sy
. Также удалите переменные разрешения xs,ys
и Pixels
.
Здесь предварительный просмотр для (xs2,ys2
- моя середина экрана):
pie(xs2,ys2,ys2-200,10,50,0x00FF0000);
Обратите внимание, что у меня 32-битный цвет RGB вместо ваших индексированных 8-битных, а углы указаны в градусах. Также обратите внимание, что моя ось y направлена вниз, так что угол приращения идет по часовой стрелке, начиная с оси x (указывая вправо)
Однако это работает только для пирогов ниже 180 градусов. Для больших вынеобходимо инвертировать условия перекрестного произведения для рендеринга, когда он не находится внутри незаполненной части пирога, вместо этого что-то вроде этого:
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);
код можно дополнительно оптимизировать, например, x*uy
можно изменить на сложение для цикла, например for(...,xuy=x*uy;...;...,xuy+=uy)
, устраняя медленное умножение из внутренних циклов. То же самое относится ко всем 4 термам в условиях перекрестного произведения.
[edit1] Для большей ясности мы имеем что-то вроде этого:
for (x=-r,xx=x*x,sx=x0+x;x<=+r;x++,xx=x*x,sx++)
{
if (...(x*uy)...) { do something }
}
the (x*uy)
вычисляется на каждой итерации x
. x
увеличивается, поэтому мы можем вычислить значение (x*uy)
из предыдущего значения ((x-1)*uy)+uy
, которое не нуждается в умножении, поскольку ((x-1)*uy)
- это значение из последней итерации. Таким образом, добавление единственной переменной, которая содержит ее, может избавить от повторного умножения:
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 }
}
, поэтому начальное умножение выполняется только один раз, а затем просто его сложение ...
И такрендеринга полностью распараллеливается ...