Физическая система координат

Выбор режима отображения

Напомним, что режим отображения - это атрибут контекста отображения, влияющий на используемую функциями GDI систему координат. Для обеспечения независимости приложений от аппаратного обеспечения приложения Windows работают с логическими координатами, которые отображаются в физические. Приложения Windows (в отличие от программ MS-DOS) могут не знать номер используемого видеорежима и соответствующее ему разрешение по вертикали и горизонтали в пикселах, определяя размеры элементов формируемого изображения в миллиметрах или дюймах. Хотя в качестве единицы измерения можно использовать и пиксел, если выбрать соответствующий режим отображения.

Из уроков геометрии в школе и институте вы знаете, что существуют различные системы координат, каждая из которых удобна в том или ином случае. Мы не будем описывать все возможные системы координат, ограничившись доступными в Windows версии 3.1 (в операционной системе Windows NT набор систем координат немного расширен).

Изучение режимов отображения Windows версии 3.1 мы начнем с определения основных понятий и терминов, имеющих отношение к системам координат и преобразованию логических координат в физические.

Основные определения

Прежде всего необходимо определить понятия "физические координаты " и "логические координаты ".

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

Логические координаты передаются функциям GDI, выполняющим рисование фигур или вывод текста. Используемые единицы измерения зависят от режима отображения.

При отображении GDI преобразует логические координаты в физические. Способ преобразования зависит от режима отображения и других атрибутов контекста отображения, таких как расположение начала системы координат для окна, расположение начала системы физических координат, масштаб осей для окна и масштаб осей физических координат.

Режимы отображения

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

Режим MM_TEXT

Режим отображения MM_TEXT устанавливается в контексте отображения по умолчанию. Для этого режима формулы преобразования координат упрощаются:



xViewport = (xWindow - xWinOrg) + xViewOrgyViewport = (yWindow - yWinOrg) + yViewOrg

Соответствующая система координат представлена на рис. 2.3 (начало системы координат расположено точно в левом верхнем углу внутренней области окна, рисунок иллюстрирует только направление координатных осей).

Физическая система координат - student2.ru

Рис. 2.3. Система координат в режиме отображения MM_TEXT

Так как в формуле преобразования не присутствуют переменные xViewExt, yViewExt, xWinExt и yWinExt, в данном режиме преобразования невозможно изменить масштаб осей координат. Поэтому логическая единица длины в режиме отображения MM_TEXT равна физической, т. е. одному пикселу.

Тем не менее, приложение может изменить смещение физической или логической системы координат, изменив, соответственно, значение пар переменных (xViewOrg, yViewOrg) и (xWinOrg,yWinOrg). Для установки смещения можно использовать функции SetViewportOrg и SetWindowOrg.

Функция SetViewportOrg устанавливает смещение физической системы координат:

DWORD WINAPI SetViewportOrg( HDC hdc, // контекст отображения int nXOrigin, // новое значение для xViewOrg int nYOrigin); // новое значение для yViewOrg

Для контекста отображения hdc эта функция устанавливает новое расположение начала физической системы координат. Младшее и старшее слово возвращаемого значения содержат, соответственно, предыдущие x- и y-координаты начала физической системы координат.

С помощью функции SetWindowOrg вы можете установить начало логической системы координат:

DWORD WINAPI SetWindowOrg( HDC hdc, // контекст отображения int nXOrigin, // новое значение для xWinOrg int nYOrigin); // новое значение для yWinOrg

По своему смыслу параметры nXOrigin и nYOrigin являются логическими x- и y-координатами верхнего угла окна, используемого для отображения (так как в формуле они используются со знаком минус).

Как правило, приложения изменяют либо начало физических координат, вызывая функцию SetViewportOrg, либо начало логических координат, вызывая функцию SetWindowOrg, хотя, в принципе, вы можете изменить и то, и другое (если не боитесь запутаться в координатных "сетях").

В программном интерфейсе Windows версии 3.1 есть новые варианты описанных выше двух функций, которые называются SetViewportOrgEx и SetWindowOrgEx . Они отличаются более удобным способом передачи старых координат начала соответствующей системы координат:

BOOL WINAPI SetViewportOrgEx( HDC hdc, // контекст отображения int nXOrigin, // новое значение для xWinOrg int nYOrigin, // новое значение для yWinOrg POINT FAR* lppt); // указатель на структуру POINT BOOL WINAPI SetWindowOrgEx( HDC hdc, // контекст отображения int nXOrigin, // новое значение для xWinOrg int nYOrigin, // новое значение для yWinOrg POINT FAR* lppt); // указатель на структуру POINT

В структуру, адрес которой передается через параметр lppt, записываются старые координаты начала системы координат. Обе функции возвращают TRUE в случае успеха и FALSE при возникновении ошибки.

В любой момент времени вы можете определить расположение начала физических или логических координат, если воспользуетесь функциями GetViewportOrg и GetWindowOrg (или их более новыми аналогами - GetViewportOrgEx и GetWindowOrgEx).

Функция GetViewportOrg возвращает x- и y-координаты начала физической системы координат для контекста отображения hdc:

DWORD WINAPI GetViewportOrg(HDC hdc);

Младшее и старшее слово возвращаемого значения содержат, соответственно, предыдущие x- и y-координаты начала физической системы координат.

Функция GetWindowOrg возвращает x- и y-координаты начала логической системы координат:

DWORD WINAPI GetWindowOrg(HDC hdc);

Новые функции, появившиеся в Windows версии 3.1, с именами GetViewportOrgEx и GetWindowExtEx записывают координаты начала координат в структуру, адрес которой передается через параметры lppt и lpSize:

BOOL WINAPI GetViewportOrgEx(HDC hdc, POINT FAR* lppt);BOOL WINAPI GetWindowExtEx(HDC hdc, SIZE FAR* lpSize);

Структура SIZE определена для Windows версии 3.1 и описана в файле windows.h следующим образом:

typedef struct tagSIZE{ int cx; int cy;} SIZE;

Определены также разнообразные указатели на структуру SIZE:

typedef SIZE* PSIZE;typedef SIZE NEAR* NPSIZE;typedef SIZE FAR* LPSIZE;

Рисование точки

Функция рисования точки SetPixel устанавливает цвет точки с заданными координатами:

COLORREF WINAPI SetPixel( HDC hdc, // контекст отображения int nXPos, // x-координата точки int nYPos, // y-координата точки COLORREF clrref); // цвет точки

Установка первых трех параметров этой функции не должна вызывать у вас никаких затруднений. Параметр hdc определяет контекст отображения, для которого необходимо изменить цвет точки. Параметры nXPos и nYPos определяют координаты точки в системе координат, которая зависит от установленного для контекста hdc режима отображения.

Последний параметр clrref определяет новый цвет точки. О том, как "раскрасить" окно приложения, вы узнаете из третьей главы нашей книги. Тем не менее мы опишем самый простой способ для функции SetPixel.

В файле windows.h есть описание макрокоманды RGB , позволяющей сконструировать цвет в формате COLORREF из отдельных компонент красного (r), зеленого (g) и голубого (b) цвета:

#define RGB(r,g,b) \ ((COLORREF)(((BYTE)(r)|((WORD)(g)<<8)) | \ (((DWORD)(BYTE)(b))<<16)))

Вы можете использовать эту макрокоманду совместно с функцией SetPixel для установки, например, красного цвета точки, расположенной в начале системы координат (0,0), следующим образом:

SetPixel(hdc, 0, 0, RGB(0xff, 0, 0));

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

Функция SetPixel возвращает цвет, который фактически был использован для рисования точки. Как мы только что заметили, возвращенное значение может отличаться от заданного параметром clrref. В случае ошибки оно будет равно -1.

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

COLORREF WINAPI GetPixel(HDC hdc, int nXPos, int nYPos);

С помощью следующих трех макрокоманд, определенных в файле windows.h, вы можете определить отдельные цветовые компоненты для значения, возвращаемого функциями SetPixel и GetPixel:

#define GetRValue (rgb) ((BYTE)(rgb))#define GetGValue (rgb) ((BYTE)(((WORD)(rgb)) >> 8))#define GetBValue (rgb) ((BYTE)((rgb)>>16))

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

Рисование линий

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

Текущая позиция пера

Для рисования прямых линий (и только для этого) в контексте отображения хранятся координаты текущей позиции пера . Для изменения текущей позиции пера в Windows версии 3.1 есть две функции с именами MoveTo и MoveToEx . Для совместимости с 32-разрядными версиями Windows, такими, как Windows NT, в новых приложениях следует использовать функцию MoveToEx:

BOOL WINAPI MoveToEx( HDC hdc, // идентификатор контекста отображения int x, // x-координата int y, // y-координата POINT FAR* lppt); // указатель на структуру POINT

Для контекста отображения hdc эта функция устанавливает текущую позицию пера, равную (x,y). В структуру типа POINT, на которую указывает параметр lppt, после возврата из функции будут записаны старые координаты пера.

Функция MoveToEx возвращает TRUE при нормальном завершении или FALSE при ошибке.

Чтобы узнать текущую позицию пера, приложение может использовать функцию GetCurrentPositionEx :

BOOL WINAPI GetCurrentPositionEx(HDC hdc, POINT FAR* lppt);

После вызова этой функции текущая позиция пера будет записана в структуру типа POINT, на которую указывает параметр lppt. Функция GetCurrentPositionEx возвращает TRUE при нормальном завершении или FALSE при ошибке.

Рисование прямой линии

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

BOOL WINAPI LineTo(HDC hdc, int xEnd, int yEnd);

Эта функция рисует линию из текущей позиции пера, установленной ранее функцией MoveTo или MoveToEx, в точку с координатами (xEnd,yEnd). После того как линия будет нарисована, текущая позиция пера станет равной (xEnd,yEnd).

Функция LineTo возвращает TRUE при нормальном завершении или FALSE при ошибке.

Таким образом, для того чтобы нарисовать прямую линию, приложение должно сначала с помощью функции MoveToEx установить текущую позицию пера в точку, которая будет началом линии, а затем вызвать функцию LineTo, передав ей через параметры xEnd и yEnd координаты конца линии.

Особенностью функции LineTo является то, что она немного не дорисовывает линию - эта функция рисует всю линию, не включая ее конец, т. е. точку (xEnd,yEnd). Это иллюстрируется на рис. 2.11.

Физическая система координат - student2.ru

Рис. 2.11. Рисование прямой линии

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

BOOL DrawLine(HDC hdc, int x1, int y1, int x2, int y1){ POINT pt; MoveToEx(hdc, x1, y1, &pt); return LineTo(hdc, x2, y2);}

Преимущества использования отдельных функций для установки текущей позиции и для рисования линии из текущей позиции в заданную точку с последующим изменением текущей позиции проявляются при рисовании ломаных линий. В этом случае вы можете только один раз установить текущую позицию пера на начало ломаной линии и в дальнейшем вызывать только функцию LineTo, передавая ей координаты точек излома линии. Однако для рисования ломаных линий (если известны координаты всех точек излома) больше подходит функция Polyline, которую мы рассмотрим в следующем разделе.

Рисование ломаной линии

Функции Polyline , предназначенной для рисования ломаных линий, следует передать идентификатор контекста отображения hdc, указатель lppt на массив структур POINT, в котором должны находится координаты начала ломаной линии, координаты точек излома и координаты конца ломаной линии, а также размер этого массива cPoints:

BOOL WINAPI Polyline( HDC hdc, // идентификатор контекста отображения const POINT FAR* lppt,// указатель на массив структур POINT int cPoints); // размер массива

Функция Polyline возвращает TRUE при нормальном завершении или FALSE при ошибке. Она не использует текущую позицию пера и не изменяет ее.

Если ломаная линия не замкнута, ее последняя точка не рисуется (рис. 2.12).

Физическая система координат - student2.ru

Рис. 2.12. Рисование ломаной линии

Рисование дуги эллипса

К сожалению, возможности рисования кривых линий при помощи функций GDI ограничены - единственная функция Arc позволяет нарисовать дугу эллипса или окружности:

BOOL WINAPI Arc( HDC hdc, // идентификатор контекста отображения int nxLeft, int nyTop, // верхий левый угол int nxRight, int nyBottom, // правый нижний угол int nxStart, int nyStart, // начало дуги int nxEnd, int nyEnd); // конец дуги

Первый параметр этой функции определяет контекст отображения, в котором будет нарисована дуга. Для объяснения назначения остальных параметров обратимся к рис. 2.13.

Физическая система координат - student2.ru

Рис. 2.13. Рисование дуги эллипса

Параметры (nxLeft,nyTop) и (nxRight,nyBottom) задают координаты, соответственно, верхнего левого и правого нижнего углов воображаемого прямоугольника, в который вписан эллипс.

Начало дуги эллипса определяется пересечением эллипса с воображаемой прямой линией, проведенной из центра эллипса (xC,yC) в точку (xStart,yStart).

Конец дуги определяется аналогично - как пересечение эллипса с воображаемой прямой линии, проведенной из центра эллипса в точку (xEnd,yEnd).

Дуга рисуется в направлении против часовой стрелки.

Координаты центра эллипса (если это потребуется) можно вычислить следующим образом:

xC = (nxLeft + nxRight) / 2;yC = (nyTop + nyBottom) / 2;

Выбор пера

Для рисования линий приложения Windows могут выбрать одно из трех встроенных перьев, либо создать собственное перо.

Для выбора встроенного пера лучше всего воспользоваться макрокомандами GetStockPen и SelectPen , определенными в файле windowsx.h:

#define GetStockPen(i) ((HPEN)GetStockObject(i))#define SelectPen(hdc, hpen) \ ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen)))

Макрокоманда GetStockPen возвращает идентификатор встроенного пера, заданного параметром i. Вы можете выбрать для этого параметра одно из следующих значений:

Значение Описание
BLACK_PEN Перо, рисующее черную линию толщиной в один пиксел (для любого режима отображения). Это перо выбрано в контекст отображения по умолчанию
WHITE_PEN Перо белого цвета. Толщина пера также равна одному пикселу и не зависит от режима отображения
NULL_PEN Невидимое перо толщиной в один пиксел. Используется для рисования замкнутых закрашенных фигур (таких, как прямоугольник или эллипс) в тех случаях, когда контур фигуры должен быть невидимым

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

Макрокоманда SelectPen возвращает идентификатор пера, который был выбран в контекст отображения раньше. Вы можете сохранить этот идентификатор и использовать его для восстановления старого пера.

Однако при помощи встроенных перьев вы не можете нарисовать цветные, широкие, штриховые и штрих-пунктирные линии.

Если вас не устраивают встроенные перья, вы можете легко создать собственные. Для этого нужно воспользоваться функциями CreatePen или CreatePenIndirect.

Функция CreatePen позволяет определить стиль, ширину и цвет пера:

HPEN WINAPI CreatePen( int fnPenStyle, // стиль пера int nWidth, // ширина пера COLORREF clrref); // цвет пера

Параметр fnPenStyle определяет стиль линии и может принимать одно из следующих значений, определенных в файле windows.h:

Стиль линии Внешний вид Описание
PS_SOLID Физическая система координат - student2.ru Сплошная
PS_DASH Физическая система координат - student2.ru Штриховая
PS_DOT Физическая система координат - student2.ru Пунктирная
PS_DASHDOT Физическая система координат - student2.ru Штрих-пунктирная, одна точка на одну линию
PS_DASHDOTDOT Физическая система координат - student2.ru Штрих-пунктирная, две точки на одну линию
PS_NULL   Невидимая
PS_INSIDEFRAME Физическая система координат - student2.ru Линия, предназначенная для обводки замкнутых фигур

Параметр nWidth определяет ширину пера. Используемая при этом единица длины зависит от режима отображения, поэтому вы можете задавать ширину пера не только в пикселах, но и в долях миллиметра или дюйма. Учтите, что для линий PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT можно использовать только единичную или нулевую ширину, в обоих случаях ширина линии будет равна одному пикселу. Поэтому вы не можете создать перо для рисования, например, пунктирной линии шириной 5 миллиметров.

Параметр clrref задает цвет пера.

На первый взгляд линии PS_SOLID и PS_INSIDEFRAME похожи, однако между ними имеются различия, особенно заметные для широких линий. Широкая линия, имеющая стиль PS_SOLID, располагается по обе стороны оси, заданной координатами линии. Линии, имеющие стиль PS_INSIDEFRAME, располагаются внутри контура, определяющего размеры замкнутой фигуры (рис. 2.14).

Физическая система координат - student2.ru

Рис. 2.14. Использование стилей PS_SOLID и PS_INSIDEFRAME

Еще одно отличие связано с использованием смешанных цветов (dithered color). Когда Windows не может в точности подобрать цвет, указанный для толстой линии стиля PS_INSIDEFRAME, он раскрашивает эту линию с использованием смешанного цвета, полученного из других цветов. В этом случае изображение линии формируется из отдельных точек разных цветов. Техника смешанных цветов может применяться и при закрашивании замкнутых фигур, о чем мы еще будем говорить.

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

Небольшое замечание относительно концов толстых линий. Концы толстых линий закруглены (рис. 2.15).

Физическая система координат - student2.ru

Рис. 2.15. Закругленные концы толстой линии

Для изображения толстой линии с прямыми концами следует задать прямоугольную область ограничения (см. ниже раздел, посвященный области ограничения). Можно также нарисовать толстую линию как закрашенный прямоугольник с использованием тонкого пера.

Другая возможность создать перо - вызвать функцию CreatePenIndirect :

HPEN WINAPI CreatePenIndirect(LOGPEN FAR* lplgpn);

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

Структура LOGPEN и различные указатели на нее определены в файле windows.h:

typedef struct tagLOGPEN{ UINT lopnStyle; // стиль пера POINT lopnWidth; // ширина пера COLORREF lopnColor; // цвет пера} LOGPEN;typedef LOGPEN* PLOGPEN;typedef LOGPEN NEAR* NPLOGPEN;typedef LOGPEN FAR* LPLOGPEN;

Заметим, что ширина пера в данном случае находится в поле x структуры POINT. Поле y не используется.

Если вы создали перо, его можно выбрать в контекст отображения при помощи макрокоманды SelectPen. После этого можно рисовать линии обычным образом, вызывая функции MoveToEx и LineTo.

Созданные вашим приложением перья принадлежат GDI, соответствующие структуры данных располагаются в его сегменте данных. Поэтому если перо больше не нужно, его нужно удалить для освобождения памяти.

Прежде чем удалять созданное вами перо, следует выбрать в контекст отображения одно из встроенных перьев (например то, которое использовалось раньше). После этого для удаления вашего пера нужно вызвать макрокоманду DeleletePen , определенную в файле windowsx.h:

#define DeletePen(hpen) DeleteObject((HGDIOBJ)(HPEN)(hpen))

В качестве параметра этой макрокоманде необходимо передать идентификатор удаляемого пера.

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

Выбор режима фона

Режим фона влияет на заполнение промежутков между штрихами и точками в штрих-пунктирных, штриховых и пунктирных линиях.

Напомним, что по умолчанию в контексте отображения установлен непрозрачный режим фона OPAQUE . В этом режиме промежутки закрашиваются цветом фона, определенным как атрибут контекста отображения. Приложение может установить прозрачный режим фона TRANSPARENT , в этом случае промежутки в линиях не будут закрашиваться (рис. 2.16).

Физическая система координат - student2.ru

Рис. 2.16. Режимы фона OPAQUE и TRANSPARENT

Для установки режима фона предназначена функция SetBkMode :

int WINAPI SetBkMode(HDC hdc, int fnBkMode);

Эта функция устанавливает новый режим фона fnBkMode для контекста отображения hdc, возвращая в случае успеха код старого режима фона.

Для параметра fnBkMode вы можете использовать значения OPAQUE или TRANSPARENT, определенные в файле windows.h.

Приложение может определить текущий режим фона, вызвав функцию GetBkMode :

int WINAPI GetBkMode(HDC hdc);

С помощью функций SetBkColor и GetBkColor вы можете, соответственно, установить и определить текущий цвет фона, который используется для закраски промежутков между штрихами и точками линий:

COLORREF WINAPI SetBkColor(HDC hdc, COLORREF clrref);COLORREF WINAPI GetBkColor(HDC hdc);

Выбор режима рисования

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

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

Для выбора режима рисования предназначена функция SetROP2 :

int WINAPI SetROP2(HDC hdc, int fnDrawMode);

Параметр hdc предназначен для указания контекста отображения, в котором необходимо установить новый режим рисования, определяемый параметром fnDrawMode.

Функция SetROP2 возвращает код предыдущего режима рисования.

Процесс рисования на экране монитора заключается в выполнении логической операции над цветами точек экрана и цветами изображения. Ниже в таблице мы привели возможные значения для параметра fnDrawMode. Для каждого режима рисования в этой таблице есть формула, с использованием которой вычисляется результат, и краткое описание режима рисования. В формулах цвет пера обозначается буквой P, цвет подложки - D.

Режим рисования Формула Цвет пиксела
R2_COPYPEN P Соответствует (равен) цвету пера
R2_BLACK Черный
R2_WHITE Белый
R2_NOP D Не меняется, т. е. перо ничего не рисует
R2_NOT ~D Получается инвертированием цвета подложки, т. е. цвета пиксела до рисования
R2_NOTCOPYPEN ~P Получается инвертированием цвета пера
R2_MASKPEN P&D Комбинация компонент цветов, имеющихся как в цвете подложки, так и в цвете пера
R2_NOTMASKPEN ~(P&D) Инверсия предыдущего значения
R2_MERGEPEN P|D Комбинация компонент цветов подложки и пера
R2_NOTMERGEPEN ~(P|D) Инверсия предыдущего значения
R2_XORPEN P^D При определении цвета пиксела выполняется операция "ИСКЛЮЧАЮЩЕЕ ИЛИ" между компонентами цвета подложки и пера
R2_NOTXORPEN ~(P^D) Инверсия предыдущего значения
R2_MASKNOTPEN ~P & D Комбинация цвета подложки и инверсии цвета пера
R2_MASKPENNOT P & ~D Комбинация двух цветов: инверсии цвета подложки и цвета пера
R2_MERGENOTPEN ~P | D Комбинация компонент цветов подложки и инверсии цвета пера
R2_MERGEPENNOT P | ~D Комбинация инверсии цвета подложки и цвета пера

Если изображение и перо черно-белые, результат выполнения описанных выше операций (которые, кстати, называются растровыми операциями ) можно легко предсказать.

В режиме R2_COPYPEN, который установлен в контексте отображения по умолчанию, цвет нарисованной линии будет такой же, как и цвет пера. Для режимов R2_BLACK и R2_WHITE цвет линии будет, соответственно, черный и белый. В режиме R2_NOP вы не увидите нарисованную линию, так как цвет вдоль нее вообще не изменится. Более интересен режим R2_NOT, при использовании которого на черном фоне будет нарисована белая линия, а на белом фоне - черная.

Для цветных изображений перечисленные выше формулы применяются по отдельности к каждой компоненте цвета (всего в Windows используется три компоненты цвета - красная, зеленая и голубая), поэтому для некоторых режимов рисования цвет линии предсказать достаточно трудно. Использование цветовых палитр, которые мы рассмотрим в третьей главе нашей книги, дополнительно усложняет эту задачу.

С помощью функции GetROP2 приложение может определить режим рисования, установленный для контекста отображения hdc:

int WINAPI GetROP2(HDC hdc);

Рисование замкнутых фигур

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

Для закрашивания внутренней области замкнутых фигур используется кисть, задаваемая как атрибут контекста отображения. Внешний контур фигуры обводится пером, которое также выбирается в контекст отображения. Учитываются и остальные атрибуты, установку которых мы рассмотрели для функций рисования линий, такие, как режим отображения, режим фона, код растровой операции.

Мы начнем изучение функций GDI, предназначенных для рисования замкнутых фигур, с функций рисования прямоугольников.

Рисование прямоугольника

Простейшая функция, с помощью которой можно нарисовать прямоугольник, называется Rectangle :

BOOL WINAPI Rectangle( HDC hdc, // идентификатор контекста отображения int nxTL, // координата x верхнего левого угла int nyTL, // координата y верхнего левого угла int nxBR, // координата x правого нижнего угла int nyBR); // координата y правого нижнего угла

Функция Rectangle рисует прямоугольник для контекста отображения hdc, возвращая значение TRUE в случае успеха или FALSE при ошибке.

Назначение остальных параметров иллюстрируется рис. 2.17.

Физическая система координат - student2.ru

Рис. 2.17. Рисование прямоугольника

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

В зависимости от стиля пера граница фигуры может находится полностью внутри прямоугольника, заданного координатами (nxTL, nyTL), (nxBR,nyBR) или выходить за его пределы (см. рис. 2.14). Если выбрать стиль пера PS_NULL, граница фигуры станет невидимой.

В зависимости от кисти, выбранной в контекст отображения, внутренность прямоугольника может быть закрашенной в тот или иной цвет, заштрихована одним из нескольких способов (как показано на рис. 2.16) или закрашена с помощью любого битового изображения размером 8х8 пикселов.

С помощью функции RoundRect можно нарисовать прямоугольник со скругленными углами (рис. 2.18).

Физическая система координат - student2.ru

Рис. 2.18. Прямоугольник со скругленными углами

По сравнению с функцией Rectangle функция RoundRect имеет два дополнительных параметра nxEllipse и nyEllipse, определяющих форму и радиус закругления:

BOOL WINAPI RoundRect( HDC hdc, // идентификатор контекста отображения int nxTL, // координата x верхнего левого угла int nyTL, // координата y верхнего левого угла int nxBR, // координата x правого нижнего угла int nyBR, // координата y правого нижнего угла int nxEllipse, // ширина эллипса int nyEllipse); // высота эллипса

Есть и другие функции, которые можно использовать для рисования прямоугольников.

Функция FillRect закрашивает прямоугольную область окна заданной кистью:

int WINAPI FillRect( HDC hdc, // идентификатор контекста отображения const RECT FAR* lprc, // указатель на структуру RECT HBRUSH hbrush); // идентификатор кисти для закрашивания

Параметр lprc должен указывать на структуру типа RECT, в которую следует записать координаты закрашиваемой прямоугольной области. Правая и нижняя граница указанной области не закрашивается.

Независимо от того, какая кисть выбрана в контекст отображения, функция FillRect будет использовать для закраски кисть, указанную параметром hbrush.

Учтите, что правильная работа функции FillRect гарантируется только в том случае, когда значение поля bottom структуры RECT больше значения поля top, а значение поля right больше значения поля left.

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

int WINAPI FrameRect( HDC hdc, // идентификатор контекста отображения const RECT FAR* lprc, // указатель на структуру RECT HBRUSH hbrush); // идентификатор кисти для закрашивания

Параметры этой функции аналогичны параметрам функции FillRect.

Ширина пера, используемого для рисования рамки, всегда равна одной логической единице. Структура RECT должна быть подготовлена таким же образом, что и для функции FillRect, т. е. значение поля bottom структуры RECT должно быть больше значения поля top, а значение поля right - больше значения поля left.

Значение, возвращаемое функциями FillRect и FrameRect не используется, приложения должны его игнорировать.

Используя функцию InvertRect , вы можете инвертировать содержимое прямоугольной области, заданной параметром lprc:

void WINAPI InvertRect(HDC hdc, const RECT FAR* lprc);

Есть еще одна интересная функция, предназначенная для рисования прямоугольников. Она имеет имя DrawFocusRect :

void WINAPI DrawFocusRect(HDC hdc, const RECT FAR* lprc);

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

Функция DrawFocusRect имеет три интересные особенности.

Во-первых, для рисования используется растровая операция "ИСКЛЮЧАЮЩЕЕ ИЛИ". Это приводит к тому, что для удаления нарисованной таким образом рамки ее достаточно нарисовать еще раз на том же месте.

Вторая особенность заключается в том, что для использования этой функции не нужно выбирать перо, рисующее пунктирную линию. Функция DrawFocusRect рисует пунктирную линию с нестандартным, очень близким расположением точек.

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

Первые две особенности позволяют использовать ее для рисования рамки выделения произвольных участков изображения на экране монитора (при помощи мыши).

В заключение отметим, что в программном интерфейсе Windows нет функции для рисования квадрата и круга. Эти фигуры являются частными случаями, соответственно, прямоугольника и эллипса, поэтому для рисования, например, квадрата, вы должны использовать одну из только что описанных функций. Для сохранения пропорций проще всего использовать одну из метрических систем координат.

Рисование эллипса

Для рисования эллипса вы можете использовать функцию Ellipse :

BOOL WINAPI Ellipse( HDC hdc, // идентификатор контекста отображения int nxTL, // координата x верхнего левого угла int nyTL, // координата y верхнего левого угла int nxBR, // координата x правого нижнего угла int nyBR); // координата y правого нижнего угла

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

Физическая система координат - student2.ru

Рис. 2.19. Рисование эллипса

Рисование сегмента эллипса

Сегмент эллипса (рис. 2.20) можно нарисовать при помощи функции Chord :

BOOL WINAPI Chord( HDC hdc, // идентификатор контекста отображения int nxLeft, int nyTop, // верхий левый угол int nxRight, int nyBottom, // правый нижний угол int nxStart, int nyStart, // начало дуги int nxEnd, int nyEnd); // конец дуги

Параметры этой функции аналогичны параметрам рассмотренной нами ранее функции Arc.

Физическая система координат - student2.ru

Рис. 2.20. Рисование сегмента эллипса

Рисование сектора эллипса

Для рисования сектора эллипса (рис. 2.21) следует использовать функцию Pie , аналогичную по своим параметрам функциям Arc и Chord:

BOOL WINAPI Pie( HDC hdc, // идентификатор контекста отображения int nxLeft, int nyTop, // верхний левый угол int nxRight, int nyBottom, // правый нижний угол int nxStart, int nyStart, // начало дуги int nxEnd, int nyEnd); // конец дуги

Физическая система координат - student2.ru

Рис. 2.21. Рисование сектора эллипса

Рисование многоугольников

Рисование многоугольников (рис. 2.22) выполняется функцией Polygon , аналогичной по своим параметрам функции Polyline, с помощью которой рисуются ломаные линии:

BOOL WINAPI Polygon( HDC hdc, // идентификатор контекста отображения const POINT FAR* lppt,// указатель на массив структур POINT int cPoints); // размер массива

Через параметр hdc передается идентификатор контекста отображения.

Параметр lppt указывает на массив структур POINT, в котором должны находится координаты вершин многоугольника. Параметр cPoints определяет размер этого массива.

Функция Polygon возвращает TRUE при нормальном завершении или FALSE при ошибке. Она не использует текущую позицию пера и не изменяет ее.

Физическая система координат - student2.ru

Рис. 2.22. Рисование многоугольника

В массиве структур POINT, определяющих вершины многоугольника, каждая вершина должна быть указана один раз. Функция Polygon автоматически замыкает ломаную линию, образующую многоугольник.

С помощью функции PolyPolygon можно нарисовать одновременно несколько многоугольников:

BOOL WINAPI PolyPolygon( HDC hdc, // идентификатор контекста отображения const POINT FAR*lppt, // указатель на массив структур POINT int FAR* lpnPolyCounts, // адрес массива количества точек // в многоугольниках int cPolygons); // количество многоугольников

Первый параметр hdc, как обычно, задает контекст отображения.

Параметр cPolygons определяет количество многоугольников, которые нужно нарисовать.

Параметр lppt должен содержать указатель на массив структур типа POINT, содержащий координаты вершин всех многоугольников.

И, наконец, через параметр lpnPolyCounts передается указатель на массив целых чисел. Каждое число в этом массиве определяет количество точек в соответствующем многоугольнике.

В отличие от функции Polygon, функция PolyPolygon не замыкает автоматически ломаную линию, образующую многоугольник.

В контексте отображения имеется атрибут, влияющий на способ закрашивания для самопересекающихся многоугольников. По умолчанию выбран режим ALTERNATE , в котором эти области не закрашиваются (закрашиваются только те области, которые расположены между нечетными и четными сторонами многоугольника).

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

Немного позже вы сможете изучить этот алгоритм с помощью приложения

Наши рекомендации