Алгоритм сглаживания

или дробное координатное пространство

Конечно, дробное пространство – виртуальное, координаты точек в любом случае остаются целочисленными.

Цвет одной точки влияет на четыре, квадрат размером 2х2. Яркость каждой из этих точек зависит от расстояния до точки, которую нужно вывести.

Итак, яркость каждой точки этого «квадрата» можно рассчитать следующими формулами, где Dx - дробная часть x, Dy - дробная часть y.

(0;0) = (1-Dx)*(1-Dy)

(1;0) = Dx*(Dx+Dy-2*Dx*Dy)/(Dx+Dy)

(0;1) = Dy*(Dx+Dy-2*Dx*Dy)/(Dx+Dy)

(1;1) = Dx*Dy

Точка с координатами (0;0) – точка, координаты которой можно получить отбрасыванием дробной части.

Эти формулы дают соотношение, необходимое для просчета конечного цвета точки. Зная степень яркости точки «А», можно получить конченый цвет:

Cl = Cl×A + Cl1×A

(Cl – старый цвет точки, Cl1 – цвет выводимой точки)

Причем умножать на степень яркости нужно не просто готовый цвет, а отдельно каждую компоненту (RGB). Для этого можно воспользоваться такой функцией:

function MulByte(a:dword; b:real):dword;

begin

Result:=Round((a and $FF)*b) + Round(((a shr 8) and $FF)*b) shl 8 +

+ Round(((a shr 16) and $FF)*b) shl 16 + Round(((a shr 24) and $FF)*b) shl 24;

end;

Функция вычисляет дробную часть:

function Drob(a:real):real;

begin

Result:=a-trunc(a);

end;

Функция вычисляет побайтовую сумму чисел

function AddByte(a, b:dword):dword;

var t:dword;

begin

asm

movd mm0, [a]

movd mm1, [b]

paddusb mm0, mm1 // Сложение с насыщением, чтобы значение не выходило за пределы

НЕ нашли? Не то? Что вы ищете?

movd [c], mm0

emms

end;

Result:=t;

end;

А общая процедура будет такой:

procedure PutPixel(x, y:real; cl:dword; Canvas:TCanvas);

{Процедура реализует дробную координатную плоскость}

var a, Dx, Dy, T00, T01, T10, T11:real;

Xt, Yt:integer;

begin

Dx:=Drob(x);

Dy:=Drob(y);

Xt:=trunc(x);

Yt:=trunc(y);

if Dx+Dy=0 then a:=0 else a:=(Dx+Dy-2*Dx*Dy)/(Dx+Dy);

T00:=(1-Dx)*(1-Dy);

T10:=Dx*a;

T01:=Dy*a;

T11:=Dx*Dy;

Canvas. Pixels[Xt, Yt]:=AddByte(MulByte(Canvas. Pixels[Xt , Yt], 1-T00),

MulByte(cl, T00));

Canvas. Pixels[Xt+1 , Yt]:=AddByte(MulByte(Canvas. Pixels[Xt+1 , Yt], 1-T10),

MulByte(cl, T10));

Canvas. Pixels[Xt, Yt+1]:=AddByte(MulByte(Canvas. Pixels[Xt , Yt+1], 1-T01),

MulByte(cl, T01));

Canvas. Pixels[Xt+1,Yt+1]:=AddByte(MulByte(Canvas. Pixels[Xt+1,Yt+1], 1-T11),

MulByte(cl, T11));

end;

Я бы не советовал использовать этот алгоритм для всех случаев, поскольку работает он не очень быстро. При построении линий, окружностей или конкретных фигур лучше использовать частные более быстрые случаи этого алгоритма (иногда одна координата является целой). Однако этот алгоритм пригодится, например, для построения графиков математических функций и других целей.

P. S.: В этой статье не акцентировалось внимание на оптимизации кода, если вы можете сделать быстрее – делайте, но статья не об этом.

Я не занимался тщательным поиском по этому вопросу, когда возникла потребность, мне было легче самостоятельно придумать способ сглаживания линий. Так что не говорите, что идея была украдена, если вдруг это уже придумано.