Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Рисование полупрозрачных полигонов (Win32 API) / 2 сообщений из 2, страница 1 из 1
02.11.2010, 16:47
    #36934361
kaktambaev
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Рисование полупрозрачных полигонов (Win32 API)
Добрый день!
Мне требуется нарисовать средствами Win32API лепестковую диаграмму (radar в англоязычных источниках). Серии этой диаграммы отображаются в виде полигонов (polygons) с непрозрачной заливкой. В отдельных случаях возникает ситуация, когда одна серия полностью затмевает другую. Одним из решений этой проблемы видится рисование полупрозрачных полигонов, чтобы серии, лежащие внизу и затмеваемые находящимися выше, были видны пользователю.
Уважаемые коллеги, посоветуйте, как правильно отобразить такие полигоны или как-то иначе решить описанную проблему.

С уважением, Канат Кактамбаев
...
Рейтинг: 0 / 0
05.11.2010, 02:48
    #36938622
Пётр Седов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Рисование полупрозрачных полигонов (Win32 API)
2 kaktambaev:

Если очень хочется рисовать полу-прозрачные многоугольники с помощью GDI, то можно так:
(обработки ошибок нет, чтобы понятнее)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
#include <assert.h>
#include <limits.h> // для INT_MIN, INT_MAX

void PaintTranslucentPolygon(HDC hDC, const POINT pVerts[], int NumVerts, COLORREF FillColor, int Opacity)
{
  const unsigned int TransparentColor = 0xFF00FF; // magenta (ядовито-розовый цвет)

  assert(NumVerts >=  3 );
  assert(FillColor != RGB( 255 ,  0 ,  255 )); // не magenta
  assert(( 0  <= Opacity) && (Opacity <=  255 ));

  // считаем границы многоугольника
  int MinX = INT_MAX;
  int MaxX = INT_MIN;
  int MinY = INT_MAX;
  int MaxY = INT_MIN;
  for (int i =  0 ; i < NumVerts; i++)
  {
    int x = pVerts[i].x;
    if (x < MinX) MinX = x;
    if (x > MaxX) MaxX = x;
    int y = pVerts[i].y;
    if (y < MinY) MinY = y;
    if (y > MaxY) MaxY = y;
  }
  // слегка раздвигаем границы (чтобы избежать нежелательного отсечения)
  MinX--;
  MaxX++;
  MinY--;
  MaxY++;

  // создаём временный буфер для вне-экранного рисования
  int BufWidth = MaxX - MinX +  1 ;
  int BufHeight = MaxY - MinY +  1 ;
  BITMAPINFO bi;
  bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  bi.bmiHeader.biWidth = BufWidth;
  bi.bmiHeader.biHeight = BufHeight;
  bi.bmiHeader.biPlanes =  1 ;
  bi.bmiHeader.biBitCount =  32 ;
  bi.bmiHeader.biCompression = BI_RGB;
  bi.bmiHeader.biSizeImage =  0 ;
  bi.bmiHeader.biXPelsPerMeter =  0 ;
  bi.bmiHeader.biYPelsPerMeter =  0 ;
  bi.bmiHeader.biClrUsed =  0 ;
  bi.bmiHeader.biClrImportant =  0 ;
  void* pBufPixels;
  HBITMAP hBuf = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &pBufPixels, NULL,  0 );

  // заполняем буфер прозрачным цветом
  int NumPixels = BufHeight * BufWidth;
  unsigned int* pPix = static_cast<unsigned int*>(pBufPixels);
  for (int i =  0 ; i < NumPixels; i++)
  {
    *pPix++ = TransparentColor;
  }

  // рисуем многоугольник в буфер
  HDC hBufDC = CreateCompatibleDC(NULL);
  SelectObject(hBufDC, hBuf);
  SelectObject(hBufDC, GetStockObject(DC_BRUSH));
  SetDCBrushColor(hBufDC, FillColor);
  SelectObject(hBufDC, GetStockObject(NULL_PEN)); // контур не рисовать
  SetWindowOrgEx(hBufDC, MinX, MinY, NULL);
  Polygon(hBufDC, pVerts, NumVerts);
  SetWindowOrgEx(hBufDC,  0 ,  0 , NULL);

  // приводим содержимое буфера к формату с premultiplied alpha
  pPix = static_cast<unsigned int*>(pBufPixels);
  for (int i =  0 ; i < NumPixels; i++)
  {
    unsigned int c = *pPix;
    if (c == TransparentColor)
    {
      *pPix =  0 ;
    }
    else
    {
      c |= 0xFF000000; // сделать alpha = 255
      *pPix = c;
    }
    pPix++;
  }

  // рисуем содержимое буфера в указанный DC, со смешиванием (blending) цветов
  BLENDFUNCTION bf;
  bf.BlendOp = AC_SRC_OVER;
  bf.BlendFlags =  0 ;
  bf.SourceConstantAlpha = Opacity;
  bf.AlphaFormat = AC_SRC_ALPHA;
  AlphaBlend(hDC, MinX, MinY, BufWidth, BufHeight, hBufDC,  0 ,  0 , BufWidth, BufHeight, bf);

  // освобождаем временные GDI-объекты
  DeleteDC(hBufDC);
  DeleteObject(hBuf);
}
Пример использования:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
case WM_PAINT:
{
  PAINTSTRUCT PaintStruct;
  HDC hDC = BeginPaint(hwnd, &PaintStruct);

  // рисуем шашечки
  int CellSize =  8 ;
  int MinRow = PaintStruct.rcPaint.top / CellSize;
  int MaxRow = PaintStruct.rcPaint.bottom / CellSize;
  int MinCol = PaintStruct.rcPaint.left / CellSize;
  int MaxCol = PaintStruct.rcPaint.right / CellSize;
  HBRUSH hGrayBrush = static_cast<HBRUSH>(GetStockObject(LTGRAY_BRUSH));
  HBRUSH hWhiteBrush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
  for (int Row = MinRow; Row <= MaxRow; Row++)
  {
    for (int Col = MinCol; Col <= MaxCol; Col++)
    {
      RECT Cell;
      Cell.left = Col * CellSize;
      Cell.right = (Col +  1 ) * CellSize;
      Cell.top = Row * CellSize;
      Cell.bottom = (Row +  1 ) * CellSize;
      FillRect(hDC, &Cell, (Row & 0x1) == (Col & 0x1) ? hGrayBrush : hWhiteBrush);
    }
  }

  // рисуем прямоугольники
  for (int Rect =  1 ; Rect <=  10 ; Rect++)
  {
    double CenterX = Rect *  30 ;
    double CenterY =  50 ;
    double Width =  20 ;
    double Height =  80 ;
    double Rot =  20 ; // угол в градусах

    double hw =  0 . 5  * Width;
    double hh =  0 . 5  * Height;
    const double Pi =  3 . 1415926535897932384626433832795 ;
    double cr = cos((Pi /  180 ) * Rot);
    double sr = sin((Pi /  180 ) * Rot);
    POINT Verts[ 4 ];
    Verts[ 0 ].x = (int)(CenterX + cr * hw - sr * hh);
    Verts[ 0 ].y = (int)(CenterY + sr * hw + cr * hh);
    Verts[ 1 ].x = (int)(CenterX - cr * hw - sr * hh);
    Verts[ 1 ].y = (int)(CenterY - sr * hw + cr * hh);
    Verts[ 2 ].x = (int)(CenterX - cr * hw + sr * hh);
    Verts[ 2 ].y = (int)(CenterY - sr * hw - cr * hh);
    Verts[ 3 ].x = (int)(CenterX + cr * hw + sr * hh);
    Verts[ 3 ].y = (int)(CenterY + sr * hw - cr * hh);
    int Opacity = Rect *  255  /  10 ;
    PaintTranslucentPolygon(hDC, Verts,  4 , RGB( 0 ,  255 ,  0 ), Opacity);
  }

  EndPaint(hwnd, &PaintStruct);
  break;
}
Результат -- см. приложенный screenshot (снял в Windows 2000).

Но, GDI -- очень старый API, родом из 80-ых. Так что если хочется много рисовать с градиентами, anti-aliasing-ом и альфа-смешиванием, то я бы взял что-нибудь поновее: Cairo ( пример использования ) или GDI+ (не использовал).
...
Рейтинг: 0 / 0
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Рисование полупрозрачных полигонов (Win32 API) / 2 сообщений из 2, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]