-
Привет! Может кто сталкивался с алгоритмом Wu? Есть 2 функции, но обе работают некорректно. Ссылка на результат работы функций: http://postimg.org/image/5bn15901l/Функция 2. В ней пикселы перекрываются. procedure CircleAA2(ABitmap: TScreenBitmap; dX, dY: integer; radius: integer; AColor: TColorRef; dAlpha, dOpacity: byte);
var
fAlpha, pAlpha: byte;
cX, cY: integer;
rX, rY: integer;
rX2, rY2: integer;
x, y: double;
Q: integer;
error: single;
procedure Set4Pixels(cX, cY, deltaX, deltaY: integer; iAlpha, iOpacity: byte);
begin
SetPixelInRect(ABitmap, cX + deltaX, cY + deltaY, AColor, iAlpha, iOpacity);
SetPixelInRect(ABitmap, cX - deltaX, cY + deltaY, AColor, iAlpha, iOpacity);
SetPixelInRect(ABitmap, cX + deltaX, cY - deltaY, AColor, iAlpha, iOpacity);
SetPixelInRect(ABitmap, cX - deltaX, cY - deltaY, AColor, iAlpha, iOpacity);
end;
begin
cX := dX;
cY := dY;
rX := radius;
rY := radius;
rX2 := rX * rX;
rY2 := rY * rY;
Q := round(rX2 / sqrt(rX2 + rY2));
x := 0;
while (x <= Q) do
begin
y := rY * Sqrt(1 - x * x / rX2);
error := y - floor(y);
fAlpha := Round(error * dAlpha);
pAlpha := dAlpha - fAlpha;
Set4Pixels(cX, cY, floor(x), floor(y), pAlpha, dOpacity);
Set4Pixels(cX, cY, floor(x), floor(y) + 1, fAlpha, dOpacity);
x := x + 1;
end;
Q := round(rY2 / sqrt(rX2 + rY2));
y := 0;
while (y <= Q) do
begin
x := rX * Sqrt(1 - y * y / rY2);
error := x - floor(x);
fAlpha := Round(error * dAlpha);
pAlpha := dAlpha - fAlpha;
Set4Pixels(cX, cY, floor(x), floor(y), pAlpha, dOpacity);
Set4Pixels(cX, cY, floor(x) + 1, floor(y), fAlpha, dOpacity);
y := y + 1;
end;
end;
-
Функция 1 - еще не доделана, но суть та же - перекрывающиеся пикселы. Они или заползают друг на друга или не дорисовываются. procedure CircleAA(ABitmap: TScreenBitmap; dX, dY: integer; radius: integer; AColor: TColorRef; dAlpha, dOpacity: byte);
var
iX, iY: double;
fX, fY: double;
x, y: integer;
fAlpha, pAlpha: byte;
dRadius: double;
xyEQ: boolean;
const
PI: double = 3.1415926535897932384626433832795;
begin
iX := 0;
iY := 0;
x := 0;
y := 0;
xyEQ := False;
SetPixelInRect(ABitmap, dX, dY - radius, AColor, dAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + radius, dY, AColor, dAlpha, dOpacity);
SetPixelInRect(ABitmap, dX, dY + radius, AColor, dAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - radius, dY, AColor, dAlpha, dOpacity);
dRadius := radius * 0.99990604980155050801971795294044;
while (x <= y) do
begin
iY := Sqrt(radius * radius - x * x);
y := Floor(Int(iY)); fY := (iY - y); fAlpha := Floor(fY * dAlpha); pAlpha := dAlpha - fAlpha;
if (x > 0) and (x < y) then
begin
SetPixelInRect(ABitmap, dX + x, dY - y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + x, dY - y - 1, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + x, dY + y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + x, dY + y + 1, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x, dY + y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x, dY + y + 1, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x, dY - y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x, dY - y - 1, AColor, fAlpha, dOpacity);
end;
if (x = y) then
begin
InfoMessage(Form3.Handle, 'iY: ' + IntToStr(y)+ ' ' + 'fY: ' + FloatToStrF(fY, ffNumber, 18, 2));
xyEQ := True;
SetPixelInRect(ABitmap, dX + x, dY - y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + x, dY - y - 1, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + x, dY + y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + x, dY + y + 1, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x, dY + y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x, dY + y + 1, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x, dY - y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x, dY - y - 1, AColor, fAlpha, dOpacity);
end;
x := x + 1;
end;
x := 0;
y := 0;
while (y <= x) do
begin
iX := Sqrt(radius * radius - y * y);
x := Floor(Int(iX)); fX := (iX - x); fAlpha := Floor(fX * dAlpha); pAlpha := dAlpha - fAlpha;
if (y > 0) and (y < x) then
begin
SetPixelInRect(ABitmap, dX + x, dY - y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + x + 1, dY - y, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + x, dY + y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + x + 1, dY + y, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x, dY + y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x - 1, dY + y, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x, dY - y, AColor, pAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - x - 1, dY - y, AColor, fAlpha, dOpacity);
end;
y := y + 1;
end;
end;
-
В некоторых случаях x=y вообще отсутствует. Хочется понять, в чем проблема. Не хватает точности сопроцессора?
-
Рисуешь ты 4 сегмента. Рисовать надо по кругу. Последний пиксель сегмента не рисуешь. Начальный(нуливой) пиксель рисуешь у каждого сегмента. Так у тебя не будет дублирования и пропусков.
Тоже самое с квадратом.
-
Тут другая тема. Все рисуется правильно при альфа = 1. При 0.5 видно перекрывающиеся пикселы. Вот этого я и хочу избежать. Чтобы при любом диаметре и альфе был идеальный "пушистый" круг :) Даже при дробном диаметре.
Потому что при радиусах 49 - 56 все рисуется идеально, как и должно быть. До 49 и после 56 почему то точность пропадает. Потом идеальный промежуток 189-196. Потом опять разрывы.
Насколько я понимаю, тут 1 пиксел расползается то ли по окружности, то ли еще куда, т.к. при заданном радиусе, скажем 42, получается диаметр 85. 1 пиксел появляется из округлений до целого.
-
Видимо X дробный надо делать, а не целочисленный.
-
> Тут другая тема. Все рисуется правильно при альфа = 1. При > 0.5 видно перекрывающиеся пикселы.
Ну так я о чём вам толкую. У вас пискели смежных сегментов перекрываются.
Где может быть такое перекрьыие только в начале и в конце. Подставим
x := 0; // X=0 while (x <= Q) do begin y := rY * Sqrt(1 - x * x / rX2); // y=rY error := y - floor(y); // error=0 fAlpha := Round(error * dAlpha);// fAlpha=0 pAlpha := dAlpha - fAlpha; // pAlpha=dAlpha=пусть 0.5 Set4Pixels(cX, cY, floor(x), floor(y), pAlpha, dOpacity); Set4Pixels(cX, cY, floor(x), floor(y) + 1, fAlpha, dOpacity); x := x + 1; end;
Откуда deltaX=0, deltaY=rY procedure Set4Pixels(cX, cY, deltaX, deltaY: integer; iAlpha, iOpacity: byte); begin SetPixelInRect(ABitmap, cX + deltaX, cY + deltaY, AColor, iAlpha, iOpacity); // cX + deltaX=cX, cY + deltaY=cY+rY SetPixelInRect(ABitmap, cX - deltaX, cY + deltaY, AColor, iAlpha, iOpacity); // cX + deltaX=cX, cY + deltaY=cY+rY SetPixelInRect(ABitmap, cX + deltaX, cY - deltaY, AColor, iAlpha, iOpacity); SetPixelInRect(ABitmap, cX - deltaX, cY - deltaY, AColor, iAlpha, iOpacity); end;
Вот вам сразуже на первом шаге у вас перекрытие. Что-бы такого не было рисуйте все сегменты в одном направлении к примеру по часовой стрелки. Только последний пиксель в сегменте не рисуете.
var fAlpha, pAlpha: byte; cX, cY: integer; rX, rY: integer; rX2, rY2: integer; x, y: double; Q: integer; error: single;
procedure Set2Pixels1(cX, cY, deltaX, deltaY: integer; iAlpha, iOpacity: byte); begin SetPixelInRect(ABitmap, cX + deltaX, cY + deltaY, AColor, iAlpha, iOpacity); //Перемещаем SetPixelInRect(ABitmap, cX - deltaX, cY + deltaY, AColor, iAlpha, iOpacity); SetPixelInRect(ABitmap, cX + deltaX, cY - deltaY, AColor, iAlpha, iOpacity); //Перемещаем SetPixelInRect(ABitmap, cX - deltaX, cY - deltaY, AColor, iAlpha, iOpacity); end;
procedure Set2Pixels2(cX, cY, deltaX, deltaY: integer; iAlpha, iOpacity: byte); begin SetPixelInRect(ABitmap, cX - deltaX, cY + deltaY, AColor, iAlpha, iOpacity); SetPixelInRect(ABitmap, cX - deltaX, cY - deltaY, AColor, iAlpha, iOpacity); end;
begin cX := dX; cY := dY; rX := radius; rY := radius; rX2 := rX * rX; rY2 := rY * rY;
// upper and lower halves Q := round(rX2 / sqrt(rX2 + rY2));
x := 0; while (x < Q) do // Не дорисовываем последний пиксель begin y := rY * Sqrt(1 - x * x / rX2); error := y - floor(y); fAlpha := Round(error * dAlpha); pAlpha := dAlpha - fAlpha; Set2Pixels1(cX, cY, floor(x), floor(y), pAlpha, dOpacity); Set2Pixels1(cX, cY, floor(x), floor(y) + 1, fAlpha, dOpacity); x := x + 1; end;
// right and left halves Q := round(rY2 / sqrt(rX2 + rY2));
y := 0; while (y < Q) do // Не дорисовываем последний пиксель begin x := rX * Sqrt(1 - y * y / rY2); error := x - floor(x); fAlpha := Round(error * dAlpha); pAlpha := dAlpha - fAlpha; Set2Pixels1(cX, cY, floor(x), floor(y), pAlpha, dOpacity); Set2Pixels1(cX, cY, floor(x) + 1, floor(y), fAlpha, dOpacity); y := y + 1; end;
// Рисуем оставшиеся сегменты // У вас они часть рисовались, по часовой другая против. // Так что разворачиваем оставшиеся. Что-бы все рисовались в одну сторону. cX := dX; cY := dY; rX := radius; rY := radius; rX2 := rX * rX; rY2 := rY * rY;
// upper and lower halves Q := round(rX2 / sqrt(rX2 + rY2));
x := rX; while (x >= 0) do // Не дорисовываем последний пиксель begin y := rY * Sqrt(1 - x * x / rX2); error := y - floor(y); fAlpha := Round(error * dAlpha); pAlpha := dAlpha - fAlpha; Set2Pixels2(cX, cY, floor(x), floor(y), pAlpha, dOpacity); Set2Pixels2(cX, cY, floor(x), floor(y) + 1, fAlpha, dOpacity); x := x - 1; end; // right and left halves Q := round(rY2 / sqrt(rX2 + rY2));
y := rY; while (y >= 0) do // Не дорисовываем последний пиксель begin x := rX * Sqrt(1 - y * y / rY2); error := x - floor(x); fAlpha := Round(error * dAlpha); pAlpha := dAlpha - fAlpha; Set2Pixels2(cX, cY, floor(x), floor(y), pAlpha, dOpacity); Set2Pixels2(cX, cY, floor(x) + 1, floor(y), fAlpha, dOpacity); y := y - 1; end;
end;
Код не проверял но должен работаь
-
>Pavia © (12.03.16 20:52) [6] Да не. Не о том речь. Центральный пиксел то не делится. Отсюда и расхождение. На рисунке видно, что пикселы не доливаются до конца. В вашем варианте получилось то же что и у меня. Я тоже дошел до этого момента и завис. Тут X дробный нужен иначе никак. Если взять Линию Ву, то там и X и Y дробные. Поэтому она получается ровненькая. Тут так же надо.
-
-
Зная это тут надо или x,y на единицу смещать для каждого квадранта или дробный X, Y делать с шагом меньше единицы.
-
-
NoUser © (12.03.16 21:58) [10]
Спасибо, но косинус выкинут за ненадобностью. Заменил на Round — пока лидер среди округления :) Разрывы стали совсем маленькими ;)))
-
Странно, но Cos(45) выдает полную чушь. Сто-то около 0.52, а Sin(45) около 0.85. sqrt(2)/2 - правильно - 0.707....
-
> Странно, но Cos(45) выдает полную чушь. Сто-то около 0.52, > а Sin(45) около 0.85.sqrt(2)/2 - правильно - 0.707....
Если хочется работать. Ляг поспи и всё пройдёт. :-) Обычно в Cos и Sin принимают на вход значения в радианах. Cos(45 рад.)=0.52 Cos(45°/180°*(Pi рад))=0.707
-
-
>Вопрос: как привести функцию обратно в линейную величину? Т.е. действие обратное косинусу? Все, разобрался. sqrt(2).
-
-
>Учим наизусть! Для чего? Кроме того я уже нашел, то что мне надо. Спасибо!
-
Научился компенсировать альфу при превышении функции: http://hostingkartinok.com/show-image.php?id=edb39c0d876b66ae5604d27c028ea278Не пойму что делать если x=y? В цикле по X и в цикле по Y эти пикселы (x=y) встречаются дважды. Если ослабить альфу ровно в 2 раза, то получаются провалы (разрывы). Пока не понял что делать. Видимо надо как то от максимума функции считать. Максимум у меня считается так: cosX2 := sqrt(2);
cosX := cosX2/2;
maxX := cosX * radius; В общем вопрос остается открытым: как компенсировать альфу при x=y? Разницы функции в данной точке идет в плюс, т.е. разрыв.
-
Вот весь код процедуры: procedure CircleAA(ABitmap: TScreenBitmap; dX, dY: integer; radius: integer; AColor: TColorRef; dAlpha, dOpacity: byte);
var
iX, iY: double;
fX, fY: double;
x, y: integer;
fAlpha, pAlpha: byte;
iR: double;
xInc, yInc: double;
fxInc, fyInc: double;
maxX, maxY: double;
difX, difY: double;
cosX, cosY: double;
cosX2: double;
aP: double;
procedure Set8XPixels(sX, sY, deltaX, deltaY: integer; sColor: TColorRef; pixelAlpha, fracAlpha, sOpacity: byte);
begin
SetPixelInRect(ABitmap, sX + deltaX, sY - deltaY, sColor, pixelAlpha, sOpacity);
SetPixelInRect(ABitmap, sX + deltaX, sY - deltaY - 1, sColor, fracAlpha, sOpacity);
SetPixelInRect(ABitmap, sX + deltaX, sY + deltaY, sColor, pixelAlpha, sOpacity);
SetPixelInRect(ABitmap, sX + deltaX, sY + deltaY + 1, sColor, fracAlpha, sOpacity);
SetPixelInRect(ABitmap, sX - deltaX, sY + deltaY, sColor, pixelAlpha, sOpacity);
SetPixelInRect(ABitmap, sX - deltaX, sY + deltaY + 1, sColor, fracAlpha, sOpacity);
SetPixelInRect(ABitmap, sX - deltaX, sY - deltaY, sColor, pixelAlpha, sOpacity);
SetPixelInRect(ABitmap, sX - deltaX, sY - deltaY - 1, sColor, fracAlpha, sOpacity);
end;
procedure Set8YPixels(sX, sY, deltaX, deltaY: integer; sColor: TColorRef; pixelAlpha, fracAlpha, sOpacity: byte);
begin
SetPixelInRect(ABitmap, sX + deltaX, sY - deltaY, sColor, pixelAlpha, dOpacity);
SetPixelInRect(ABitmap, sX + deltaX + 1, sY - deltaY, sColor, fracAlpha, dOpacity);
SetPixelInRect(ABitmap, sX + deltaX, sY + deltaY, sColor, pixelAlpha, dOpacity);
SetPixelInRect(ABitmap, sX + deltaX + 1, sY + deltaY, sColor, fracAlpha, dOpacity);
SetPixelInRect(ABitmap, sX - deltaX, sY + deltaY, sColor, pixelAlpha, dOpacity);
SetPixelInRect(ABitmap, sX - deltaX - 1, sY + deltaY, sColor, fracAlpha, dOpacity);
SetPixelInRect(ABitmap, sX - deltaX, sY - deltaY, sColor, pixelAlpha, dOpacity);
SetPixelInRect(ABitmap, sX - deltaX - 1, sY - deltaY, sColor, fracAlpha, dOpacity);
end;
procedure CorrectAlpha(funcDifference: double; var pixelAlpha, fracAlpha: byte);
var
dA: byte;
begin
if (funcDifference < 0) then
begin
dA := Round((-funcDifference) * cosX2 * 100 * aP);
if dA < pixelAlpha then
pixelAlpha := pixelAlpha - dA else
pixelAlpha := 0;
if dA < fracAlpha then
fracAlpha := fracAlpha - dA else
fracAlpha := 0;
end
else
if (funcDifference > 0) then
begin
dA := Round((funcDifference) * cosX2 * 100 * aP);
if (dA + pixelAlpha) < dAlpha then
pixelAlpha := pixelAlpha + dA else
pixelAlpha := dAlpha;
if (dA + fracAlpha) < dAlpha then
fracAlpha := fracAlpha + dA else
fracAlpha := dAlpha;
end;
end;
begin
fAlpha := Round(dAlpha * 0.5);
SetPixelInRect(ABitmap, dX, dY - radius, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX, dY - radius + 1, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + radius, dY, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX + radius - 1, dY, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX, dY + radius, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX, dY + radius - 1, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - radius, dY, AColor, fAlpha, dOpacity);
SetPixelInRect(ABitmap, dX - radius + 1, dY, AColor, fAlpha, dOpacity);
aP := dAlpha / 100;
iR := radius - 0.5;
cosX2 := sqrt(2);
cosX := cosX2/2;
cosY := cosX;
maxX := cosX * iR;
maxY := maxX;
xInc := iR / radius;
yInc := xInc;
fxInc := xInc * cosX;
fyInc := yInc * cosY;
iX := 0;
iY := 0;
x := 0;
y := 0;
repeat
iY := Sqrt(iR * iR - iX * iX);
y := Round(Int(iY)); fY := (iY - y); fAlpha := Round(fY * dAlpha); pAlpha := dAlpha - fAlpha;
if (iX > maxX) then
begin
if (x = y) then
begin
end
else
begin
difX := (maxX - iX);
CorrectAlpha(difX, pAlpha, fAlpha);
end;
end;
if (x > 0) then
begin
Set8XPixels(dX, dY, x, y, AColor, pAlpha, fAlpha, dOpacity);
end;
iX := iX + xInc;
x := Round(iX);
until (x > y);
iX := 0;
iY := 0;
x := 0;
y := 0;
repeat
iX := Sqrt(iR * iR - iY * iY);
x := Round(Int(iX)); fX := (iX - x); fAlpha := Round(fX * dAlpha); pAlpha := dAlpha - fAlpha;
if (iY > maxY) then
begin
if (x = y) then
begin
end
else
begin
difY := (maxY - iY);
CorrectAlpha(difY, pAlpha, fAlpha);
end;
end;
if (y > 0) then
begin
Set8YPixels(dX, dY, x, y, AColor, pAlpha, fAlpha, dOpacity);
end;
iY := iY + yInc;
y := Round(iY);
until (y > x);
end;
|