Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Алгоритм Брезенхэма пропускает некоторые пикселы, Пропуск пикселов при рисовании окружност 
V
    Опции темы
MAXIQ
Дата 4.2.2012, 06:07 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 92
Регистрация: 30.12.2006

Репутация: нет
Всего: нет



Здравствуйте, помогите разобраться с рисованием, а точнее с обращением к пикселам окружности (В примере дла простоты пользуемся 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));
           }
       }

PM MAIL   Вверх
borisbn
Дата 4.2.2012, 15:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 6
Всего: 135



Вот алгоритм из Вики
Код

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 );
        }
    }
}



--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
MAXIQ
Дата 4.2.2012, 23:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 92
Регистрация: 30.12.2006

Репутация: нет
Всего: нет



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

Код

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);

    }
}


Не фонтан конечно, за то закрывает весь круг без дырок. Как видно, слабое место у алгоритма - выбор диагональной точки и если добавить дополнительную прорисовку пиксела внутрь окружности (у--), то результат получается более-менее терпимый. Большое спасибо за помощь, тема закрыта
PM MAIL   Вверх
xvr
Дата 6.2.2012, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



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

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


PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.1012 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.