Алгоритмизации
Скачать 1.15 Mb.
|
ПримеризображенияграфикафункцииsinПрограмма содержит массив из 1000 структур POINT. В цикле от 0 до 999 член x структуры растет от 0 до cxClient. В каждом цикле член структуры определяет значение синуса и масштабируется до размеров клиентской области окна. Вся кривая целиком отображается с использованием одного вызова функции Polyline (рис. П 6.3). Текст программы может быть следующим: #include Приложение6 #define NUM 1000 #define TWOPI (2 * 3.14159) LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static char szAppName[] = "Sin" ; HWND hwnd ; MSG msg ; WNDCLASSEX wndclass ; wndclass.cbSize = sizeof (wndclass) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground=(HBRUSH) GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; hwnd = CreateWindow (szAppName, "Second Example", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { static int cxClient, cyClient ; HDC hdc ; int i ; Приложение6 PAINTSTRUCT ps ; POINT pt [NUM] ; switch (iMsg) { case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; MoveToEx (hdc, 0, cyClient / 2, NULL) ; LineTo (hdc, cxClient, cyClient / 2) ; for (i = 0 ; i < NUM ; i++) { pt[i].x = i * cxClient / NUM ; pt[i].y = (int) (cyClient / 2 * (1 - sin (TWOPI * i / NUM))) ; } Polyline (hdc, pt, NUM) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } Результат работы программы: Рис. П 6.3 РисованиезамкнутыхфигурРассмотрим функции для рисования замкнутых фигур: Rectangle– прямоугольник; Ellipse– эллипс; RoundRect– прямоугольник со скругленными углами; Chord– дуга кривой эллипса, Приложение6 концы которой соединены хордой; Pie– кусок, вырезанный из эллипса; Polygon– многоугольник; PolyPolygon– множество многоугольников. Контур фигуры рисуется текущим пером, а фигура закрашивается текущей кистью. По умолчанию это стандартная кисть WHITE_BRUSH. Простейшей является функция рисования прямоугольника: Rectangle(hdc, x1, y1, x2, y2); (x1, y1) – координаты левого верхнего угла, (x2, y2) – правого нижнего угла. Для рисования эллипса используется x1 функция, имеющая те же параметры: y1 Ellipse(hdc, x1, y1, x2, y2); Фигура, отображаемая функцией Ellipse(вместе с ограничивающим прямоугольником). y2 Функция для рисования прямоугольника со скругленными углами: RoundRect(hdc, x1, y1, x2, y2, xEllipse, yEllipse); имеет два дополнительных параметра: для рисования скругленных углов используется маленький эллипс, x1 шириной xEllipse, высотой yEllipse. y1 Фигура, отображаемая этой функцией, приведена на рисунке. Скругленные углы были нарисованы с использованием размеров эллипса, вычисленных по формулам xEllipse = (x2–x1)/4; yEllipse = (y2–y1)/4; y2 Это простое приближение, но результаты yEllipse x2 xEllipse скорее всего будут выглядеть не совсем правильно, потому что округлость углов более заметна при больших размерах прямоугольника. Функции Chord(сегмент эллипса) и Pie(сектор эллипса) имеют одинаковые параметры: Chord(hdc, x1, y1, x2, y2, xStart, yStart, xEnd, yEnd); Pie(hdc, x1, y1, x2, y2, xStart, yStart, xEnd, yEnd); При рисовании используется воображаемая линия для соединения точки (xStart, yStart– начало дуги) с центром эллипса. В точке, где эта линия пересекается с ограничивающим прямоугольником, начинается рисование дуги эллипса в направлении против часовой стрелки; аналогично используется воображаемая линия для соединения точки (xEnd, yEnd – конец дуги) с центром эллипса. В точке, где эта линия пересекается с ограничивающим прямоугольником, завершается рисование дуги. В функции Chordсоединяются конечные точки дуги, а в функции Pie соединяются начальная и конечная точки дуги с центром эллипса. Фигуры, отображаемые функциями Chordи Pie, приведены на рис. П 6.3. аxStart,yStart xStart,yStart б Приложение6 xEnd,yEnd Рис. П 6.3. Фигуры, нарисованные с использованием: а– функции Chord; б– функции Pie ФункцияPolygonирежимзакрашиваниямногоугольникаФункция рисования многоугольника: Polygon(hdc, pt, iCount); pt– это массив структур типа POINT, iCount– число точек; если последняя точка в массиве не совпадает с первой, то добавляется линия, их соединяющая. Внутренняя область фигуры закрашивается текущей кистью. По умолчанию режим закрашивания равен ALTERNATE(попеременный), т.е. закрашиваются только те фрагменты внутренней области многоугольника, которые получаются путем соединения линий с нечетными номерами (1, 3, 5...), другие фрагменты внутренней области не закрашиваются. Режим закрашивания устанавливается функцией: SetPolyFillMode(hdc, iMode); iMode– режим закрашивания, WINDING(сквозной) – закрашиваются все внутренние области. Для иллюстрации приведем пример: звезда, находящаяся слева, нарисована в режиме ALTERNATE, а звезда, находящаяся справа – в режиме WINDING. ПримеротображениялинийЕсли в предыдущей программе (Second Example) заменить case WM_PAINT... и убрать лишние переменные, получим программу (Third Example), в которой рисуются прямоугольник, эллипс, прямоугольник со скругленными углами и два отрезка. Программа показывает, что функции, Приложение6 определяющие области, закрашивают их, поэтому отрезки не видны там, где нарисован эллипс. Результат работы программы приведен на рис. П 6.4. . . . case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; Rectangle (hdc, cxClient /8, cyClient /8, 7*cxClient /8, 7*cyClient /8) ; MoveToEx (hdc, 0, 0, NULL) ; LineTo (hdc, cxClient, cyClient) ; MoveToEx (hdc, 0, cyClient, NULL) ; LineTo (hdc, cxClient, 0) ; Ellipse (hdc, cxClient /8, cyClient /8, 7*cxClient /8, 7*cyClient /8) ; RoundRect (hdc, cxClient /4, cyClient /4, 3*cxClient /4, 3*cyClient /4, cxClient /4, cyClient /4) ; EndPaint (hwnd, &ps) ; return 0 ; . . . Рис. П 6.4. Результат программы ThirdExample УправлениеобластямивыводаиотсечениемСтандартно графический вывод отсекается по границам окна, с которым связан контекст, кроме того, из области вывода удаляются части, перекрытые другими окнами. Таким образом, границы области вывода могут иметь достаточно сложную форму. В средеWindows используются функции, работающие с прямоугольными областями, использующими структуры типа RECT (прямоугольник) и произвольными областями – регионами (regions). РаботаспрямоугольникамиПростейшим средством, задающим границу области вывода, является прямоугольник. Функции отображения прямоугольных областей используют указатель на структуру rectтипа RECT(прямоугольник), имеющую поля: left, top, right, bottom, заданные в логических единицах. Приложение6 Функция FillRect(hdc, &rect, hBrush); закрашивает прямоугольник (не включая правую и нижнюю координаты) заданной кистью. Функция FrameRect(hdc, &rect, hBrush); использует кисть для рисования прямоугольной рамки, но не закрашивает внутреннюю область. ФункцияInvertRect(hdc, &rect); инвертирует все пиксели в прямоугольнике, устанавливая единичные биты в ноль, а нулевые– в единицу, т.е. переводит белую область в черную, черную – в белую (зеленую в фиолетовую). Windowsсодержит функции, позволяющие легко манипулировать со структурами типа RECT: установка всех полей структуры RECTв заданные значения: SetRect(&rect, xLeft, yTop, xRight, yBottom); перемещение на заданное число координат вдоль осей xи y: OffsetRect(&rect, x, y); увеличение или уменьшение размеров прямоугольника: InflateRect(&rect, x, y); установка полей структуры прямоугольника в ноль: SetRectEmpty(&rect); копирование одного прямоугольника в другой: CopyRect(&DestRect, &SrcRect); пересечение двух прямоугольников: IntersectRect(&DestRect, &SrcRect1, &SrcRect2); объединение двух прямоугольников: UnionRect(&DestRect, &SrcRect1, &SrcRect2); определение, является ли прямоугольник пустым: bEmpty = IsRectEmpty (&rect); определение, содержится ли точка внутри прямоугольника: bInRect = PtInRect (&rect, point); СозданиеирисованиерегионовУнифицированным средством, задающим границу области вывода, являетсярегион, который может иметь прямоугольную, многоугольную, эллиптическую формы или их сочетание. Регион является объектом, идентифицируемым его описателем HRGN. Произвольный регион создается универсальной функцией: ExtCreateRegion(const XFORM *lpXform, DWORD nDataSize, const RGNDATA lpRgnData); структура XFORM описывает преобразование региона в экранные координаты, при его равенстве NULLкоординаты считаются идентичными; регион описывается структурой RGNDATA, содержащей поля: RGNDATAHEADER rdh– структура данных заголовка; char Buffer[1] – буфер структур RECT, образующих регион. В свою очередь, структураRGNDATAHEADERсодержит поля: DWORD dwSize – размер заголовка в байтах; Приложение6 DWORD iType – тип региона (RGN_RECTANGLES); DWORD nCount– количество прямоугольников в буфере; DWORD nRgnSize– требуемый размер буфера (может быть нулевым); RECT rcBound – вмещающий прямоугольник для региона. Простейший тип региона– прямоугольник может быть создан с помощью функций hRgn = CreateRectRgn(xLeft, yTop, xRight, yBottom); hRgn = CreateRectRgnIndirect (&rect); Для создания эллиптических регионов: hRgn = CreateEllipticRgn(xLeft, yTop, xRight, yBottom); hRgn = CreateEllipticRgnIndirect (&rect); Функция CreateRoundRectRgnстроит прямоугольный регион со скругленными углами. Создание многоугольного региона (похоже на функцию Polygon): hRgn = CreatePolygonRgn (&point, iCount, iPolyFillMode); параметр point– массив структур типаPOINT, iCount– число точек, iPolyFillMode– ALTERNATE(WINDING). Регион из множества многоугольников – CreatePolyPolygonRgn. Два региона могут быть объединены в один функцией: iRgnType = CombineRgn (hDestRgn, hSrcRgn1, hSrcRgn2, iCombine); которая комбинирует два исходных региона (hSrcRgn1и hSrcRgn2) и строит третий, на который ссылается hDestRgn. Все три описателя регионов еще до вызова функции должны быть действительными, однако дополнительный регион, описываемый ранее hDestRgn, уничтожается. Параметр iCombine задает правило объединения регионов: RGN_AND – область пересечения двух исходных регионов; RGN_OR – объединение двух исходных регионов; RGN_XOR – объединение двух исходных регионов за исключением области пересечения; RGN_DIFF – часть регионаhSrcRgn1, не входящая в регион hSrcRg2; RGN_COPY– регион hSrcRgn1. Значение iRgnType, возвращаемое функцией, означает: NULLREGION– регион пуст; SIMPLEREGION– регион представляет собой простой прямо- угольник, эллипс или многоугольник; COMPLEXREGION– комбинация прямоугольников, эллипсов или многоугольников; ERROR– произошла ошибка. Полученный описатель региона можно использовать в функциях FillRgn(hdc,hRgn,hBrush); FrameRgn(hdc,hRgn,hBrush,xFrame,yFrame); InvertRgn(hdc, hRgn); PaintRgn(hdc, hRgn); аналогичных функциям FillRect(закрашивание прямоугольной области), FrameRect(закрашивание границы прямоугольной области) и InvertRect Приложение6 (инвертирование пикселей в прямоугольнике); параметры xFrameи yFrame – ширина и высота рамки, которая будет нарисована вокруг региона. Функция PaintRgnзакрашивает внутреннюю область региона текущей выбранной в контекст устройства кистью. Во всех функциях предполагается, что регион определен в логических координатах. Для удаления региона используется функция удаления объектов GDI: DeleteObject(hRgn); Функция GetRgnDataпозволяет получить доступ к данным региона по его описателю. Вмещающий прямоугольник для региона может быть получен функцией GetRgnBox. Функции PtInRegionи RectInRegionпроверяют соответственно точку и прямоугольник на вхождение их в регион. Регион может быть обведен или закрашен с использованием текущих инструментов данного контекста. ПрямоугольникиирегионыотсеченияПрямоугольники и регионы могут принимать участие в отсечении. Функция InvalidateRectделает недействительным прямоугольную область дисплея и генерирует сообщение WM_PAINT. Ее можно использовать, например, для обновления рабочей области: InvalidateRect(hwnd, NULL, TRUE); Получить координаты недействительного прямоугольника можно с помощью функции GetUpdateRect, а сделать действительным прямоугольник в рабочей области – ValidateRect. Получая сообщение WM_PAINT, координаты недействительного прямоугольника доступны из полей структурыPAINTSTRUCT, заполняемой при вызове функции BeginPaint. Этот недействительный прямоугольник также определяет регион отсечения, за пределами которого нельзя рисовать. Для создания региона отсечения (выбрав регион в контекст устройства) используются функции SelectObject(hdc, hRgn); SelectClipRgn(hdc, hRgn); регион отсечения задается в координатах устройства. Среда Windows содержит несколько функций для манипуляции с регионом отсечения, таких как ExcludeClipRect– исключение прямоуголь- ника из региона отсечения; IntersectClipRect – создание нового региона отсечения, который представляет собой пересечение предыдущего региона отсечения и прямоугольника; OffsetClipRgn – перемещение региона отсечения в другую часть рабочей области. РастроваяграфикаВсе рассмотренные выше функции базировались на вычерчивании графических примитивов определенными инструментами по заданным Приложение6 командам, т.е. по векторному принципу. Растровая графика предусматривает доступ к изображению на уровне образующих его точек. Для большинства устройств отображения первичен растровый принцип формирования изображения. Некоторые контексты поддерживают не все функции растровой графики. Информацию о совместимости может предоставить функция GetDeviceCaps(). Простейшим и наиболее универсальным способом получения произвольных изображений является доступ к отдельным его точкам. Функции COLORREF SetPixel(hdc, nX, nY, crColor); BOOL SetPixelV (hdc, nX, nY, crColor); COLORREF GetPixel (hdc, nX, nY); выполняют соответственно изменение состояния (цвета) одной логической точки и получение текущего состояния. Функция SetPixelV() приводит значение цвета к ближайшему представимому в данном контексте цвету; возвращаемое значение – состояние точки на момент вызова функции (COLORREF), либо признак успешности выполнения (BOOL). Параметры nX, nY– логические координаты точки (int); crColor– новое значение цвета точки (COLORREF). Более сложные и эффективные функции манипулируют не отдельными точками, а массивами точек – фрагментами изображений и битовыми образами. Битовыйобраз(bitmap) – двухмерный массив числовых значений, характеризующий состояние точек некоторой области, обычно прямоугольной. В простейшем случае битовый образ описывается структурой BITMAP, содержащей поля: LONG bmType– тип образа, должен быть равен 0; LONG bmWidth, LONG bmHeight– положительные значения ширины и высоты прямоугольной области в пикселах; LONG bmWidthBytes– размер в байтах образа одной строки изображения, в среде Windows должен быть кратен 2, т.к. система предполагает, что массив состоит из слов; WORD bmPlanes– количество цветовых планов (плоскостей), т.е. компонент, задающих цвет; WORD bmBitsPixel– количество бит для кодирования цвета точки; LPVOID bmBits– указатель на двухмерный массив данных, каждая строка которого соответствует одной строке изображения. Используются монохромный и цветной типы образов. В случае монохромного – одноцветовой план и один бит на точку, единичное значение этого бита задает для точки цвет переднего плана (foreground), нулевое – заднего (backgroung). Приложение6 Битовые образы – объекты, идентифицирующиеся их описателями – HBITMAP. Различают совместимые и контекстно-независимые объекты BITMAP. Функции HBITMAP CreateBitmap( int nWidth, int nHeight, UINT cPlanes, UINT cBitsPerPel, const void* lpvBits ); HBITMAP CreateBitmapIndirect(const BITMAP* lpBitmap); создают объект BITMAPс указанными характеристиками, возвращаемое значение – описатель объекта или NULL в случае ошибки; параметры: nWidth, nHeight– размеры образа в точках изображения; cPlanes– количество цветовых планов; cBitsPerPel– «глубина» цвета; lpvBits– массив данных образа; lpBitmap– структура BITMAP, содержащая перечисленные параметры. Функция HBITMAP CreateCompatibleBitmap(hdc, int nWidth, int nHeight); создает объект BITMAP совместимого типа для заданного контекста с заданными размерами; в зависимости от контекста он может быть создан цветным или монохромным (если в контексте заданы данные раздела DIB – контекстно-независимым); возвращаемое значение – описатель объекта или NULL; nWidth и nHeight – размеры образа. Для доступа к содержимому битового образа предусмотрены функции SetDlBits() и GetDlBits(), которые работают построчно, однако имеется возможность воздействовать на него всеми доступными инструментами. Для этого объект BITMAP связывается с некоторым контекстом с помощью универсальной функции SelectObject(), после чего все изменения в контексте будут отображаться и в битовом образе. Функции: BOOL BitBlt(HDC hDstDC, int nDstX, int nDstY, int nDstWidth, int nDstHeight,HDC hSrcDC, int nSrcX, int nSrcY, DWORD dwRop); BOOL StretchBlt (HDC hDstDC, int nDstX, int nDstY, int nDstWidth, int nDstHeight, HDC hSrcDC, int nSrcX, int nSrcY, int nSrcWidth, int nSrcHeight, DWORD dwRop); BOOL MaskBlt(HDC hDstDC, int nDstX, int nDstY, int nDstWidth, int nDstHeight, HDC hSrcDC, int nSrcX, int nSrcY, HBITMAP hbmMask, int nMaskX, int nMaskY, DWORD dwRop); BOOL PlgBlt (HDC hDstDC, const POINT* lpDstVertices, HDC hSrcDC, int nSrcX, int nSrcY, HBITMAP hbmMask, int nMaskX, int nMaskY, DWORD dwRop); выполняют перенос прямоугольного фрагмента изображения из контекста- источника в контекст-приемник (с трансформацией и дополнительными операциями). Функция StretchBlt может изменять масштаб изображения фрагмента; MaskBlt позволяет маскировать часть изображения; PlgBlt осуществляет перенос в непрямоугольную область приемника с Приложение6 соответствующим искажением; возвращаемое значение – признак успешности выполнения; параметры: hSrcDC, hDstDC– контексты источника и приемника данных; nSrcX, nSrcY, nDstX, nDstY– координаты фрагмента в обоих контекстах; nSrcWidth, nSrcHeight, nDstWidth, nDstHeight– размеры фрагментов; hbmMask– битовый образ маски, монохромного типа, нулевые точки маски указывают на применение к данной точке изображения операции «заднего плана», единичные – «переднего плана»; nMaskX, nMaskY– точка привязки в образе маски; lpDstVertices– массив структур, задающих вершины параллелограмма, образующего фрагмент-приемник; dwRop – дополнительная операция, применяемая к фрагменту при переносе: SRCCOPY– простое копирование, SRCAND– комбинация цветов источника и приемника по «И», SRCPAINT – комбинация по «ИЛИ», SRCIN- VERT– комбинация по «исключающему ИЛИ», SRCERASE– комбинация по «И» цвета источника и инверсии цвета приемника, NOTSRCCOPY, NOT- SRCERASE– соответствует одноименным, но результирующий цвет инвертируется, DSTINVERT– инверсия фрагмента-приемника, BLACKNESS, WHITENESS – заполнение фрагмента-получателя цветом соответственно 0 и 1 физической палитры и другие. Для MaskBlt параметр включает операции для переднего и заднего фонов, формируется с помощью макроса MAKEROP4. Для успешного применения этих функций требуется, чтобы оба контекста относились к одному устройству или идентичным устройствам. При использовании функций следует учитывать, что в логических координатных системах, связанных с обоими контекстами, отсчитываются только координаты опорных точек и размеры границ фрагмента, содержимое же его всегда ориентировано одинаково. Эффекты, возникающие при деформации битового образа, дополните- льно управляются функцией SetStretchBltMode, текущая настойка – GetStretchBltMode. |