Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Алгоритм Брезенхэма пропускает некоторые пикселы


Автор: MAXIQ 4.2.2012, 06:07
Здравствуйте, помогите разобраться с рисованием, а точнее с обращением к пикселам окружности (В примере дла простоты пользуемся SetPixel()). Дело в том, что нужно заполнить круг, но сделать это нужно пошагово, уменьшая радиус добраться до центра. Алгоритм  Брезенхэма пропускает некоторые пикселы и результат слегка напоминает дуршлаг. Может я его недопонял и код кривой написал, а может сам алгоритм не так уж и хорош. Сталкивался ли кто с подобной проблемой, может идеи какие есть?

Код

       int R=35;
        int x0=rRect.left+35+190;
        int y0=rRect.top+35+50;
        for (int iRadius=R;iRadius>0;iRadius--)//Перемещение по радиусам
        {
                //Координаты центра окружности
                int x=0;
                int y=iRadius;
                int Di=2*(1-iRadius);
            while (y>0)
                {
                //Выделение случая 1или2;,4или54;3
               if (Di<0)//Случай 1 или 2 Диагональная точка находится внутри окружности
                {
                int d=2*Di+2*y-1;
                if (d<=0)//Горизонтальная точка
                        {
                        x++;
                        Di=Di+2*x+1;
                        }
                else    //Диагоняльная точка
                        {
                        x++;
                        y--;
                        Di=Di+2*x-2*y+2;
                        }
                }
               if (Di>0)//Случай 4 или 5 Диагональная точка находится вне окружности
                {
                int d=2*Di+2*x-1;
                if (d<=0)//Диагоняльная точка
                        {
                        x++;
                        y--;
                        Di=Di+2*x-2*y+2;
                        }
                else    //Вертикальная точка
                        {
                        y--;
                        Di=Di-2*y+1;
                        }
                }
               if (Di==0)//Случай 3 Диагональная точка находится на окружности
                {
                x++;
                y--;
                Di=Di+2*x-2*y+2;
                }
                SetPixel(hCompatibleButtonDC,x0+x,y0+y,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0+y,y0+x,RGB(244,199,42));

                SetPixel(hCompatibleButtonDC,x0+y,y0-x,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0+x,y0-y,RGB(244,199,42));

                SetPixel(hCompatibleButtonDC,x0-x,y0-y,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0-y,y0-x,RGB(244,199,42));

                SetPixel(hCompatibleButtonDC,x0-y,y0+x,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0-x,y0+y,RGB(244,199,42));
           }
       }

Автор: borisbn 4.2.2012, 15:51
Вот http://ru.wikipedia.org/wiki/Алгоритм_Брезенхэма#.D0.A0.D0.B8.D1.81.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_.D0.BE.D0.BA.D1.80.D1.83.D0.B6.D0.BD.D0.BE.D1.81.D1.82.D0.B5.D0.B9
Код

void drawCircle(int x0, int y0, int radius) {
        int x = 0;
        int y = radius;
        int delta = 2 - 2 * radius;
        int error = 0;
        while(y >= 0) {
                setPixel(x0 + x, y0 + y);
                setPixel(x0 + x, y0 - y);
                setPixel(x0 - x, y0 + y);
                setPixel(x0 - x, y0 - y);
                error = 2 * (delta + y) - 1;
                if(delta < 0 && error <= 0) {
                        ++x;
                        delta += 2 * x + 1;
                        continue;
                }
                error = 2 * (delta - x) - 1;
                if(delta > 0 && error > 0) {
                        --y;
                        delta += 1 - 2 * y;
                        continue;
                }
                ++x;
                delta += 2 * (x - y);
                --y;
        }
}

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

x0 = ...; // x центра окружности
y0 = ...; // y центра окружности
r = ...; // радиус окружности
for ( int y = y0 - r; y < y0 + r; y++ ) {
    for ( int x = x0 - r; x < x0 + r; x++ ) {
        if ( sqrt( ( x - x0 ) * ( x - x0 ) + ( y - y0 ) * ( y - y0 ) ) <= r ) {
            setPixel( x, y );
        }
    }
}

Автор: MAXIQ 4.2.2012, 23:15
С алгоритмом из Вики столкнулся сразу же, он то же дырявый. Но его можно доработать:

Код

int R=35;
        int x0=rRect.left+35+190;
        int y0=rRect.top+35+50;
        for (int iRadius=R;iRadius>0;iRadius--)//Перемещение по радиусам
        {
                int x=0;
                int y=iRadius;
                int Di=2*(1-iRadius);
                int d=0;
            while (y>=0)
            {
                SetPixel(hCompatibleButtonDC,x0+x,y0+y,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0+y,y0+x,RGB(244,199,42));

                SetPixel(hCompatibleButtonDC,x0+y,y0-x,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0+x,y0-y,RGB(244,199,42));

                SetPixel(hCompatibleButtonDC,x0-x,y0-y,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0-y,y0-x,RGB(244,199,42));

                SetPixel(hCompatibleButtonDC,x0-y,y0+x,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0-x,y0+y,RGB(244,199,42));
                //error = 2 * (delta + y) - 1;
                d=2*Di+2*y-1;//error
               if (Di<0&&d<=0)
                    {
                    x++;
                    Di=Di+2*x+1;//delta += 2 * x + 1;
                    continue;
                    }
                d=2*Di-2*x-1;//error = 2 * (delta - x) - 1;
                if (Di>0&&d>0)
                    {
                     y--;
                     Di=Di-2*y+1;//delta += 1 - 2 * y;
                     continue;
                    }
                 y--;//Диагональная точка
                SetPixel(hCompatibleButtonDC,x0+x,y0+y,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0+y,y0+x,RGB(244,199,42));

                SetPixel(hCompatibleButtonDC,x0+y,y0-x,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0+x,y0-y,RGB(244,199,42));

                SetPixel(hCompatibleButtonDC,x0-x,y0-y,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0-y,y0-x,RGB(244,199,42));

                SetPixel(hCompatibleButtonDC,x0-y,y0+x,RGB(244,199,42));
                SetPixel(hCompatibleButtonDC,x0-x,y0+y,RGB(244,199,42));

                 x++;
                 Di=Di+2*x-2*y;// delta += 2 * (x - y);

    }
}


Не фонтан конечно, за то закрывает весь круг без дырок. Как видно, слабое место у алгоритма - выбор диагональной точки и если добавить дополнительную прорисовку пиксела внутрь окружности (у--), то результат получается более-менее терпимый. Большое спасибо за помощь, тема закрыта

Автор: xvr 6.2.2012, 14:24
Цитата(MAXIQ @  4.2.2012,  06:07 Найти цитируемый пост)
Алгоритм  Брезенхэма пропускает некоторые пикселы и результат слегка напоминает дуршлаг. 

Это нормально. Рисуйте по точкам пол-окружности (по вертикали). Вторая половина будет зеркальным отражением первой половины. Вместе с окружностью рисуйте прямые от текущей точки на одной половине до текущей точки на другой


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)