Почему бы не использовать:
(x-x0)^2 + (y-y0)^2 <= r^2
так просто:
int x0=?,y0=?,r=?; // your planet position and size
int x,y,xx,rr,col;
for (rr=r*r,x=-r;x<=r;x++)
for (xx=x*x,y=-r;y<=r;y++)
if (xx+(y*y)<=rr)
{
col = whateverFunctionIMake(x, y);
setPixel(x0+x, y0+y, col);
}
все на целых числах, без плавающих или медленных операций, без пробелов ... Не забудьте использовать randseed для функция раскраски ...
[Edit1] еще кое-что
Теперь, если вам нужна скорость, вам нужен прямой пиксельный доступ (на большинстве платформ Pixels, SetPixel, PutPixels et c являются slooow, потому что они выполняют много таких вещей, как проверка диапазона, преобразование цветов и т. д. c ...) В случае, если вы получили прямой пиксельный доступ или визуализировали в свой собственный массив / изображение все, что вам нужно, чтобы добавить отсечение с помощью экран (поэтому вам не нужно проверять, находится ли пиксель внутри экрана на каждом пикселе), чтобы избежать нарушений доступа, если ваш круг перекрывает экран.
Как уже упоминалось в комментариях, вы можете избавиться от x*x
и y*y
внутри l oop с использованием предыдущего значения (поскольку оба x,y
только увеличиваются). Для получения дополнительной информации об этом см .:
математика выглядит так:
(x+1)^2 = (x+1)*(x+1) = x^2 + 2x + 1
поэтому вместо xx = x*x
мы просто делаем xx+=x+x+1
для еще не увеличенного x
или xx+=x+x-1
, если x
уже увеличено.
Когда все сложено, я получил это:
void circle(int x,int y,int r,DWORD c)
{
// my Pixel access
int **Pixels=Main->pyx; // Pixels[y][x]
int xs=Main->xs; // resolution
int ys=Main->ys;
// circle
int sx,sy,sx0,sx1,sy0,sy1; // [screen]
int cx,cy,cx0, cy0 ; // [circle]
int rr=r*r,cxx,cyy,cxx0,cyy0; // [circle^2]
// BBOX + screen clip
sx0=x-r; if (sx0>=xs) return; if (sx0< 0) sx0=0;
sy0=y-r; if (sy0>=ys) return; if (sy0< 0) sy0=0;
sx1=x+r; if (sx1< 0) return; if (sx1>=xs) sx1=xs-1;
sy1=y+r; if (sy1< 0) return; if (sy1>=ys) sy1=ys-1;
cx0=sx0-x; cxx0=cx0*cx0;
cy0=sy0-y; cyy0=cy0*cy0;
// render
for (cxx=cxx0,cx=cx0,sx=sx0;sx<=sx1;sx++,cxx+=cx,cx++,cxx+=cx)
for (cyy=cyy0,cy=cy0,sy=sy0;sy<=sy1;sy++,cyy+=cy,cy++,cyy+=cy)
if (cxx+cyy<=rr)
Pixels[sy][sx]=c;
}
При этом отображается круг с радиусом 512 px
в ~35ms
, поэтому 23.5 Mpx/s
заполняется при настройке шахты (64-битное однопоточное VCL / GDI 32-битное приложение AMD A8-5500 Win7, закодированное BDS2006 C ++). Просто измените прямой доступ к пикселям на стиль / API, который вы используете ...
[Edit2]
, чтобы измерить скорость на x86 / x64, вы можете использовать RDTSC
asm Здесь приведен некоторый древний код C ++, который я использовал в возрасте go (в 32-битной среде без встроенных 64-битных компонентов):
double _rdtsc()
{
LARGE_INTEGER x; // unsigned 64bit integer variable from windows.h I think
DWORD l,h; // standard unsigned 32 bit variables
asm {
rdtsc
mov l,eax
mov h,edx
}
x.LowPart=l;
x.HighPart=h;
return double(x.QuadPart);
}
Возвращает часы, прошедшие с момента включения вашего ЦП. Помните, что вы должны учитывать переполнение, поскольку на быстрых машинах 32-битный счетчик переполняется за секунды. Также каждое ядро имеет отдельный счетчик, так что установите сродство к одному процессору. На часах с переменной частотой перед измерением нагрейте процессор с помощью некоторых вычислений, а для преобразования во время просто поделите его на тактовую частоту процессора. Чтобы получить его, просто сделайте следующее:
t0=_rdtsc()
sleep(250);
t1=_rdtsc();
fcpu = (t1-t0)*4;
и измерение:
t0=_rdtsc()
mesured stuff
t1=_rdtsc();
time = (t1-t0)/fcpu
, если t1<t0
переполнено, и вам нужно добавить постоянную для результата или измерения снова. Также измеряемый процесс должен занимать меньше, чем период переполнения. Для повышения точности игнорируйте детализацию ОС. для получения дополнительной информации см .: