Смекни!
smekni.com

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

Режим рисования (Drawing Mode).

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

Направление рисования дуг эллипсов (Arc Direction).

Влияет только на результат рисования дуги эллипса (функции Arc, Pie и Chord). По умолчанию дуги рисуются против хода часовой стрелки, но вы можете изменить это направление. Пользоваться этой возможностью, вообще говоря, не рекомендуется, так как применение этой функции ограничено — в Win32 API в расширенном режиме задания координат (см. SetGraphicsMode, GM_ADVANCED) дуги рисуются всегда против хода часовой стрелки и изменить это направление нельзя.

Собственно для рисования прямых линий необходимо всего две функции:

DWORD MoveTo (hDC, nX, nY); 0

BOOL MoveToEx (hDC, nX, nY, lpPoint);

BOOL LineTo (hDC, nX, nY);

Функция MoveToEx перемещает текущую точку пера в указанное место, не выполняя рисования. Последующий вызов функции LineTo осуществит рисование от текущей точки до указанной конечной отрезка. Нарисованный отрезок линии не включает в себя последнюю точку! Это сделано для удобства рисования ломанных линий из нескольких отрезков — в этом случае любая точка ломанной будет нарисована только один раз. Если вам необходимо нарисовать отрезок обязательно включая последнюю точку — продлите отрезок на один пиксель дальше (не забывайте, что вы задаете логические координаты, а удлинить отрезок надо на одну единицу устройства!). Если это сделать трудно (например отрезок наклонен под каким­–то углом) то можно дополнительно нарисовать крохотный отрезок длиной 1 пиксель в любую сторону.

В случае Windows API часто применялась функция MoveTo, а не MoveToEx; Функция MoveTo возвращала информацию о прежнем положении текущей точки, упакованную в двойное слово. В Win32 API такая упаковка невозможна — каждая координата уже представляет собой двойное слово — поэтому функция MoveTo больше не поддерживается.

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

BOOL Polyline (hDC, lpPoints, nCount);

Эта функция рисует ломаную линию, начальная, конечная и все точки перегиба которой заданы в массиве структур типа POINT (параметр lpPoints), содержащем nCount точек. Линия рисуется, начиная от первой точки и далее, соединяя последовательно отрезками все точки, вплоть до последней. Ломаная линия может быть незамкнутой, GDI не проводит замыкающего отрезка от последней точки к первой.

Еще одна функция GDI предназначена для рисования дуг:

BOOL Arc (hDC, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);

Для задания рисуемой дуги эллипса вы должны задать сначала сам эллипс, дуга которого будет изображаться, а затем задать начальную и конечную точки дуги. Эллипс задается описывающим его прямоугольником (причем нижняя и правая границы не включаются) — параметры xLeft, yTop, xRight и yBottom, а начальная и конечная точки задаются параметрами xStart, yStart и xEnd, yEnd.

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

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

В случае применения Win32 API вы можете использовать еще несколько функций для рисования линий. Так две новых функции предназначены для рисования дуг:

BOOLArcTo (hDC, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd); 1

BOOL AngleArc (hDC, nX, nY, dwRadius, eStartAngle, eSweepAngle); 1

Функция ArcTo аналогична функции Arc, за исключением того, что она сначала рисует отрезок от текущей точки до начальной точки дуги, затем рисует саму дугу и перемещает текущую точку в конечную точку нарисованной дуги. Функция AngleArc рисует дугу окружности, не эллипса. Для нее надо задать центр окружности (параметры nX, nY), радиус (dwRadius), начальный угол (eStartAngle) и угловую величину рисуемой дуги (eSweepAngle), в градусах. GDI не проверяет угловую величину дуги, она может превышать 3600.

Еще пара новых функций предназначена для рисования ломаных линий:

BOOL PolylineTo (hDC, lpPoints, nCount); 1

BOOL PolyPolyline (hDC, lpPoints, lpuCounts, nPolyCount); 1

Функция PolylineTo отличается от Polyline тем, что начинает рисование с отрезка от текущей точки до первой точки, указанной в массиве, а после прорисовки всех отрезков перемещает текущую точку в последнюю точку массива. Функция PolyPolyline может за одну операцию отобразить несколько ломаных линий. Координаты всех точек всех линий задаются массивом структур POINT (параметр lpPoints), число точек в каждой ломаной линии задается массивом целых чисел lpuCounts, а число ломаных, рисуемых этой функцией — параметром nPolyCount.

Кроме того в Win32 API существуют функции для рисования кривых Безье:

BOOL PolyBezier (hDC, lpPoints, cPoints); 1

BOOL PolyBezierTo (hDC, lpPoints, cPoints); 1

Функция PolyBezier рисует линию состоящую из сегментов кривых Безье. Для задания каждого сегмента требуется указать четыре точки: начальную, две направляющие и конечная. Так как рисуется линия из нескольких сегментов, то конечная точка одного сегмента является в свою очередь начальной точкой другого сегмента. Таким образом кривая будет определяться набором из Npt = 1 + Nsegments*3; здесь Npt — число точек для задания кривой, Nsegments — число сегментов в кривой.

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

Функция PolyBezierTo отличается тем, что текущая точка используется в качестве начальной точки первого сегмента. В этом случае в массиве должно содержаться на одну точку меньше — только по две направляющих и одной конечной для каждого сегмента кривой. И, кроме того, после рисования кривой текущая точка будет перемещена в конечную точку последнего нарисованного сегмента.

Последняя рассматриваемая функция предназначена для рисования целого набора из прямых отрезков и кривых Безье за одну операцию:

BOOL PolyDraw (hDC, lpPoints, lpbyTypes, cCount); 1

Массивы структур POINT (lpPoints) и байтов (lpbyTypes) имеют одинаковое количество элементов; каждый элемент массива lpbyTypes определяет тип рисуемой линии из текущей точки до точки, задаваемой соответствующим элементом массива lpPoints. Допустимы следующие значения для типов линий:

PT_MOVETO линия не рисуется, текущая точка перемещается в указанную позицию
PT_LINETO рисуется отрезок от текущей точки, до указанной; текущая точка перемещается в конечную точку отрезка.
PT_BEZIERTO рисуется кривая Безье; для задания кривой надо определить подряд три точки типа PT_LINETO: первые две точки — направляющие, последняя — конечная; текущая точка будет начальная точка кривой, а после рисования текущая точка переместится в конец нарисованного сегмента.
PT_CLOSEFIGURE этот флаг может быть объединен со значениями PT_LINETO или PT_BEZIERTO; при его указании фигура будет замкнута проведением отрезка от последней точки нарисованного сегмента до первой точки фигуры (точки типа PT_MOVETO или точки, заданной функцией MoveTo перед вызовом PolyDraw.

Перо

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

GDI предоставляет возможность использовать одно из трех стандартных перьев или создавать собственные перья, имеющие нужные свойства. Функция GetStockObject позволяет получить стандартное перо; они отличаются только цветом, проводимая ими линия всегда сплошная, шириной 1 единицу устройства (пиксель). Вместо функции GetStockObject можно использовать макрос GetStockPen из windowsx.h. Как и все стандартные объекты GDI эти перья нельзя уничтожать.

HANDLE GetStockObject (nIndex);

HPEN GetStockPen (nIndex); 2

BLACK_PEN — черное перо
WHITE_PEN — белое перо
NULL_PEN — прозрачное перо

Куда больше возможностей предоставляют функции, создающие перья. Две из них — CreatePen и CreatePenIndirect отличаются только способом передачи параметров. Функция CreatePen получает все характеристики создаваемого пера в виде отдельных параметров, а функция CreatePenIndirect использует структуру LOGPEN, описывающую создаваемое перо. Функционально обе функции тождественны. Эта же структура используется функцией GetObject для получения информации о пере.

HPEN CreatePen (nPenStyle, nWidth, crColor);

HPEN CreatePenIndirect (lpLogPen);

typedef struct tagLOGPEN {

WORD lopnStyle; // стильпера

POINT lopnWidth; // шириналинии

COLORREF lopnColor; // цветпера

} LOGPEN;

Стиль пера может быть:

PS_SOLID
сплошная тонкая или толстая линия
PS_DASH
штриховая тонкая линия
PS_DOT
пунктирная тонкая линия
PS_DASHDOT
штрих–пунктирная тонкая линия
PS_DASHDOTDOT
штрих–точка–точка тонкая линия
PS_NULL (прозрачный)
PS_INSIDEFRAME
сплошная тонкая или толстая линия

Ширина пера задается в логических единицах, причем в случае функции CreatePenIndirect для задания толщины используется структура типа POINT, в которой используется только поле x, а поле y — нет. Ширина пера задается в логических единицах. Так как логическая единица в общем случае может не совпадать с физической, то для создания тонких перьев (ширина которых равна 1 пикселю или одной строке растра) надо указать требуемую ширину равной 0 — тогда будет создано перо шириной 1 пиксель. Все прерывистые линии (PS_DOT, PS_DASH, PS_DASHDOT, PS_DASHDOTDOT), шириной больше физической 1 воспроизводятся как PS_SOLID.