Смекни!
smekni.com

Основы графического вывода (стр. 12 из 26)

Привязка кисти (brush alignment)

Существует совершенно особый прием при работе с кистями — так называемая привязка кисти. При закраске внутренней области какой–либо фигуры с помощью кисти GDI многократно воспроизводит ее изображение. Однако при этом возникает вопрос: с какого места начинает воспроизводиться изображение кисти? Считается, что GDI по умолчанию повторяет кисть начиная с верхнего левого угла экрана — то есть от точки с координатами устройства (0,0). Это так называемая начальная точка кисти (brush origin).

Рисунок 10. Пояснения к атрибуту начальная точка кисти (brush origin)

Если кисть представлена каким–либо изображением или штриховкой, то все закрашиваемые фрагменты попадают в одну "фазу". В некоторых случаях надо изменять начало отсчета кисти для того, что бы рисунок или штриховка был согласован с закрашиваемой поверхностью. Для этого применяется прием, называемый выравнивание кисти (brush alignment):

POINT pt;

// brush origin устанавливается в координатах устройства,

// а точка по которой мы будем выравнивать обычно определена

// в логических координатах, поэтому требуется преобразование.

pt.x= 0; pt.y= 0; // выбираем логические координаты новой точки

LPtoDP (hDC, &pt, 1); // переводим их в координаты окна

ClientToScreen (hWnd, &pt); // а теперь в координаты экрана

//-если мы применяем систему координат MM_TEXT(по умолчанию),то

// мы можем не использовать функцию LPtoDP;

// - если контекст соответствует иному устройству, чем дисплей,

// то мы не используем функцию ClientToScreen.

// кисть имеет размер 8x8 пикселей, поэтому координаты начальной точки

// лучше задавать в диапазоне 0..7, то есть остаток от деления на 8

pt.x %= 8; pt.y %= 8;

// теперь нам известны координаты устройства нового brush origin

UnrealizeObject (hNewBrush);

SetBrushOrg (hDC, pt.x, pt.y);

// функция UnrealizeObject разрешает назначить для кисти новую начальную

// точку; это назначение произойдет при выборе кисти в контекст устройства,

// причем начальная точка назначается именно контексту, а не кисти.

SelectObject (hDC, hNewBrush);

При выравнивании кисти надо придерживаться нескольких ограничений:

запрещено применять функцию UnrealizeObject ко всем стандартным кистям;

выравнивать можно только кисть, не выбранную в контекст устройства;

Режим заполнения многоугольников

При рисовании многоугольников возникает необходимость в решении достаточно сложной задачи — определении внутренней области многоугольника, которую необходимо закрасить. Задача может существенно осложниться, если учесть возможность рисования нескольких перекрывающихся многоугольников за одну операцию и возможность задания пересекающихся областей одного многоугольника. Типичными примерами являются рисунки пятиконечной звездочки или домика:

Рисунок 11. Примеры многоугольников с перекрывающимися поверхностями.

В такой ситуации поведение GDI будет определяться текущим режимом заполнения многоугольников (polygon filling mode). Вы можете его изменить или узнать с помощью функций

UINT GetPolyFillMode (hDC);

UINT SetPolyFillMode (hDC, nIndex);

допустимы два значения параметра nIndex: ALTERNATE и WINDING. В режиме ALTERNATE GDI закрашивает на каждой строке развертки отрезок между сторонами с нечетным и четным последовательными номерами. Очень упрощенно — область, которая повторно закрашивается сохранит первоначальный вид. В режиме WINDING применяется более сложный алгоритм, который позволяет вычислить и закрасить все внутреннюю область многоугольника. Например, заполнение многоугольника в виде пятиконечной звездочки в различных режимах заполнения многоугольников выглядит так:

Рисунок 12. Заполнение пятиконечной звездочки в различных режимах заполнения многоугольников.

Прямоугольники и регионы

Исторически сложилось так, что прямоугольник является базовой фигурой при работе с графическими устройствами. Значительная часть примитивов GDI требует задания описывающего прямоугольника, окна опять–же имеют форму прямоугольника (не считая возможности использовать эллиптические окна в Windows–95), области окон, нуждающиеся в перерисовке — неверные области — в ранних версиях Windows описывались прямоугольником, растровые изображения — битмапы — имеют форму прямоугольника и так далее. Естественно, что в Windows были включены специальные средства для выполнения математических операций над прямоугольниками и некоторый вспомогательный набор функций, осуществляющий операции закраски, обводки контура, инверсии цвета и прочего в указанной вами прямоугольной области.

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

Функции, ориентированные на работу с прямоугольниками и с регионами достаточно разнородны, относятся к самым разным подсистемам Windows, не только к GDI, смотря по тому, как будет применяться указанный прямоугольник или регион. Большая часть этих функций рассматривается в этом разделе, хотя в других разделах те же самые функции будут рассматриваться дополнительно, с углубленным обсуждением их использования.

Прямоугольники

Рассмотрение операции над прямоугольниками мы начнем с математических функций. Эти функции рассматривают прямоугольник как некую математическую абстракцию, описываемую структурой типа RECT.

typedef struct tagRECT {

int left;

int top;

int right;

int bottom;

} RECT;

Над этой структурой можно производить некоторые операции, как–то инициализировать нулем, задать ее поля, прибавить ко всем полям определенные величины и так далее. Использование этих функций не всегда целесообразно, так как того же эффекта можно достичь более простыми средствами. Так, функция

void SetRect (lpRect, xLeft, yTop, xRight, yBottom);

позволяет заполнить структуру типа RECT указанными значениями, функция

void SetRectEmpty (lpRect);

обнуляет поля структуры RECT, а функция

void CopyRect (lpRectDst, lpRectSrc);

копирует одну структуру RECT в другую. Рассмотренные функции заменяются на более простые конструкции самым тривиальным образом, причем получаемый код оказывается компактнее и существенно быстрее. Еще две функции осуществляют перемещение прямоугольника по координатной плоскости (OffsetRect) и изменение его размеров (InflateRect):

void OffsetRect (lpRect, nDeltaX, nDeltaY);

void InflateRect (lpRect, nDeltaWidth, nDeltaHeight);

void InsetRect (lpRect, nDeltaWidth, nDelatHeight); 2

Макрос InsetRect соответствует вызову функции:

InflateRect (lpRect, - (nDeltaWidth), - (nDeltaHeight)).

Некоторые функции для работы с прямоугольниками, предоставляемые Windows, все же достаточно удобны, что бы их не заменять собственными:

BOOL IsRectEmpty (lpRect);

проверяет, является ли данный прямоугольник пустым, или нет; Функция

BOOL EqualRect (lpRect, lpRect);

проверяет совпадение прямоугольников (имеют ли они одинаковые размеры и положение); а функция

BOOL PtInRect (lpRect, lpPoint);

проверяет, попадает ли указанная точка в заданный прямоугольник. Еще три функции позволяют выполнить простейшие математические операции над прямоугольниками: вычислить пересечение, объединение и исключение.

BOOL IntersectRect (lpRectDst, lpRectSrc1, lpRectSrc2);

BOOL UnionRect (lpRectDst, lpRectSrc1, lpRectSrc2);

BOOL SubtractRect (lpRectDst, lpRectSrc1, lpRectSrc2);

Рисунок 13. Пересечение, объединение и два варианта исключения прямоугольников.

При использовании функции SubtractRect для вычисления области прямоугольника 1, не входящего в прямоугольник 2 надо быть уверенным, что прямоугольник 2 полностью перекрывает прямоугольник 1 по одной из сторон.

Помимо чисто математических операций над прямоугольниками существуют некоторые функции, предназначенные для рисования прямоугольников. К ним относятся функции для инверсии цвета в прямоугольной области, для закраски прямоугольника указанной кистью и для проведения каемки вокруг прямоугольника.

void InvertRect (hDC, lpRect);

инвертирует цвет указанного прямоугольника, выполняя операцию BITWISE NOT над всеми пикселями прямоугольника. Эта функция удобна для выделения какого-либо прямоугольника, так как повторное выполнение этой операции восстанавливает первоначальный вид прямоугольника.

В некоторых случаях бывает удобно просто закрасить указанной кистью необходимую область. Конечно, это можно сделать с помощью функции Rectangle. Однако этот способ не всегда хорош, так как при рисовании прямоугольника он окружается линией, нарисованной текущим карандашом. Этот карандаш, во–первых всегда представлен чистым цветом, а, во–вторых, прямоугольник не всегда надо ограничивать линией (использование прозрачного карандаша приводит к частой смене карандашей). Для этого Windows содержит две дополнительные функции:

int FillRect (hDC, lpRect, hBrush);

int FrameRect (hDC, lpRect, hBrush);

Функция FillRect закрашивает указанный прямоугольник требуемой кистью, а функция FrameRect проводит вокруг указанного прямоугольника каемку опять же кистью (не карандашом). Ширина проводимой каемки 1 пиксель как по горизонтали, так и по вертикали.

Вместо функции FillRect можно иногда применять функцию PatBlt, которая позволяет закрасить фон текущей кистью. Эта функция поддерживается непосредственно драйверами устройств, так что ее применение дает наиболее быстрый исполняемый код. Подробнее о функции PatBlt см. в разделе «Операции передачи образов»

Частный случай — закраска прямоугольной области не кистью, а конкретным цветом. Очевидный способ — создание однотонной кисти и закраска прямоугольника с помощью функции FillRect или Rectangle — во–первых достаточно громоздок и, во–вторых, не гарантирует закраски именно чистым цветом — кисть может оказаться смешанной из точек разных цветов. Наиболее быстрый способ — использовать функцию ExtTextOut, указав ей пустую строку, ограничивающий прямоугольник и необходимость закраски прямоугольника цветом фона (флаг ETO_OPAQUE).