Линия сглаживания Bresenham работает не так, как ожидалось

Я пытаюсь реализовать рисование линий Bresenham с помощью сглаживания, используя эту статью:
http://members.chello.at/~easyfilter/bresenham.html

А вот и функция:

void ColoringScene::drawLineAA(int x0, int y0, int x1, int y1, int r, int g, int b, int a)
{
float dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
float dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
float err = dx-dy, e2, x2;                       /* error value e_xy */
float ed = dx+dy == 0 ? 1 : sqrt((float)dx*dx+(float)dy*dy);

for (;;){                                         /* pixel loop */
setPixel(x0, y0, r, g, b, a*abs(err-dx+dy)/ed);
e2 = err; x2 = x0;
if (2*e2 >= -dx) {                                    /* x step */
if (x0 == x1) break;
if (e2+dy < ed) setPixel(x0, y0 + sy, r, g, b, a*(e2+dy)/ed);
err -= dy; x0 += sx;
}
if (2*e2 <= dy) {                                     /* y step */
if (y0 == y1) break;
if (dx-e2 < ed) setPixel(x2 + sx, y0, r, g, b, a*(dx-e2)/ed);
err += dx; y0 += sy;
}
}
}

Не знаю, меняет ли это что-нибудь, но я изменил все int на float. Просто чтобы убедиться, что деление работает на поплавках. В любом случае по целым числам результат один и тот же.

Теперь пример вызова:

drawLineAA(10, 10, 50, 400, 255, 0, 0, 255);
drawLineAA(100, 10, 500, 40, 255, 0, 0, 255);

Результаты в этом:
введите описание изображения здесь

Если я изменю y0 + sy на y0 — sy следующим образом:

if (e2+dy < ed) setPixel(x0, y0 - sy, r, g, b, a*(e2+dy)/ed);

Выход становится таким:

введите описание изображения здесь

Если я изменю x2 + sx на x2 — sx следующим образом:

if (dx-e2 < ed) setPixel(x2 - sx, y0, r, g, b, a*(dx-e2)/ed);

Вывод теперь:

введите описание изображения здесь

Таким образом, последняя конфигурация является отрицательной, что дает:

введите описание изображения здесь

Почти хорошо, но появляются некоторые дыры. Так что все равно не так. Я не могу понять, почему он не рисует правильно. Когда я пробовал обычные bresenham без сглаживания, и это работает без проблем.

Также важно отметить, что в моем случае я использую текстуру cocos2d-x, поэтому y переворачивается. Вот почему у меня есть этот метод:

void ColoringScene::setPixel(int x, int y, int r, int g, int b, int a){
if(x < 0 || x >= img->getWidth() || y < 0 || y >= img->getHeight()) return;
int index = (x + (img->getHeight() - y - 1) * img->getWidth()) * 4;
data[index] = r;
data[index + 1] = g;
data[index + 2] = b;
data[index + 3] = a;
}

Может быть, проблема в этом. Как я могу это исправить?
С уважением

2

Решение

Этот алгоритм кажется просто неверным.

  • x0==x1 или же y0==y1 это фатальная ошибка
  • dx==dy это фатальная ошибка
  • настройка ed=1 когда dx+dy=0 совершенно произвольно.
  • 2*e2==dy а также 2*e2==-dx приводит к рисованию трех пикселей за шаг.

Рекомендации: рассматривайте dx = dy, dx = -dy, dx = 0, dy = 0 как особые случаи, делайте отдельные случаи для каждого октанта, не используйте числа с плавающей запятой, если они вам не нужны.

1

Другие решения


По вопросам рекламы [email protected]