欢迎拍砖
#include <atlimage.h>
using namespace Gdiplus;
class CRadarDrawClass
{
public:
//绘制的单元
typedef struct _tagRadarItem_t
{
WCHAR szName[64]; //名称
float fValue; //数值
WCHAR szDescp[128]; //描述
}RADARITEM, *LPRADARITEM;
//GDI+
protected:
ULONG_PTR gdiplusToken;
Bitmap *m_pBakImage; //背景图片
Color m_BackColor; //背景色
Color m_LayerLineColor; //坐标层颜色
Color m_EvLayerFColor; //偶数层填充色
Color m_OdLayerFColor; //奇数层填充色
Color m_NameStrColor; //字体颜色
Color m_DataLineColor; //数据线颜色
Color m_DataFillColor; //数据填充颜色
public:
CRadarDrawClass()
{
//初始化GDI+
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
m_pBakImage = NULL; //背景图片
//Color(a,r,g,b)
//背景色
SetColor(m_BackColor, 255, 100, 100, 100);
//坐标层颜色
SetColor(m_LayerLineColor, 100, 200, 200, 233);
//偶数层填充色
SetColor(m_EvLayerFColor, 120, 100, 200, 100);
//奇数层填充色
SetColor(m_OdLayerFColor, 120, 100, 100, 200);
//字体颜色
SetColor(m_NameStrColor, 200, 255, 255, 0);
//数据线颜色
SetColor(m_DataLineColor, 200, 255, 100, 200);
//数据填充颜色
SetColor(m_DataFillColor, 100, 200, 100, 100);
}
virtual ~CRadarDrawClass()
{
if(m_pBakImage)
{
delete m_pBakImage;
m_pBakImage = NULL;
}
//关闭GDI+
GdiplusShutdown(gdiplusToken);
}
public:
virtual void SetColor(Color &cr, BYTE a, BYTE r, BYTE g, BYTE b)
{
cr.SetValue(cr.MakeARGB(a, r, g, b));
}
BOOL SetBackImage(LPCWSTR szFile)
{
if(m_pBakImage != NULL)
{
delete m_pBakImage;
m_pBakImage = NULL;
}
m_pBakImage = Bitmap::FromFile(szFile, TRUE);
return m_pBakImage != NULL;
}
public:
void DrawRadarGraphics(HDC hDstDC, RECT rcRect,
RADARITEM *pRadItem, int iMaxRadItem, float fMaxValue)
{
INT cx = rcRect.right - rcRect.left;
INT cy = rcRect.bottom - rcRect.top;
//双缓冲绘制
HDC hdc = CreateCompatibleDC(hDstDC);
int nSaveDC = SaveDC(hdc);
HBITMAP hMemBmp = CreateCompatibleBitmap(hDstDC, cx, cy);
SelectObject(hdc, hMemBmp);
//绘制
DrawRadarGraphicsEx(hdc, RectF(0, 0, (REAL)cx, (REAL)cy),
pRadItem, iMaxRadItem, fMaxValue);
//贴图
BitBlt(hDstDC, rcRect.left, rcRect.top, cx, cy,
hdc, 0, 0, SRCCOPY);
//结束清理
RestoreDC(hdc, nSaveDC);
DeleteObject(hMemBmp);
DeleteDC(hdc);
}
protected:
void DrawRadarGraphicsEx(HDC hdc, RectF rect,
RADARITEM *pRadItem, int iMaxRadItem, float fMaxValue)
{
Graphics gs(hdc);
gs.SetSmoothingMode(SmoothingModeDefault);
if(m_pBakImage != NULL) //背景图片
{
gs.DrawImage(m_pBakImage, rect);
}
else //填充背景色
{
Brush *br = new SolidBrush(m_BackColor);
gs.FillRectangle(br, rect);
delete br;
}
//字体
LOGFONTW lfont;
memset( &lfont, 0, sizeof(lfont) );
lfont.lfHeight = -MulDiv(14, GetDeviceCaps(hdc, LOGPIXELSY), 72);
lfont.lfWeight = FW_NORMAL;
lfont.lfCharSet = DEFAULT_CHARSET;
wcscpy_s( lfont.lfFaceName, (L"宋体") );
Gdiplus::Font gfont(hdc, &lfont);
FontFamily fontfamily;
gfont.GetFamily(&fontfamily);
const int iMaxCorners = max(1, iMaxRadItem); //顶点数
const int iMaxLayers = (int)max(1, ceil(fMaxValue)); //分层数
double f2PI = 2.0 * (4.0 * atan(1.0)); //2π
double fSAng = f2PI / 4.0; //起始90度
double fDAng = f2PI / iMaxCorners; //角度间隔
//中心点
REAL cntX = rect.X + rect.Width/2;
REAL cntY = rect.Y + rect.Height/2;
//最大圆半径
double fMaxRad = min(rect.Width, rect.Height)/2.0 * 0.8;
//层步距
double fLayDis = fMaxRad / iMaxLayers ;
//绘制坐标
{
//线画笔
Pen gPen(m_LayerLineColor);
double fRad = fMaxRad;
for(int iLay=0; iLay<iMaxLayers; iLay++)
{
//填充模式
{
double fAng = fSAng;
int iPrvX=0, iPrvY=0;
GraphicsPath *gPath = new GraphicsPath();
for(int iCon=0; iCon<=iMaxCorners; iCon++)
{
int x = (int)(cntX + fRad * cos(fAng));
int y = (int)(cntY - fRad * sin(fAng));
if(iCon > 0)
{
gPath->AddLine(iPrvX, iPrvY, x, y);
}
iPrvX = x;
iPrvY = y;
fAng += fDAng;
}
gPath->CloseFigure();
Color crFill((iLay%2)? m_OdLayerFColor:m_EvLayerFColor);
Brush *br = new SolidBrush(crFill);
gs.FillPath(br, gPath);
delete br;
delete gPath;
}
//画线模式
{
double fAng = fSAng;
int iPrvX, iPrvY;
for(int iCon=0; iCon<=iMaxCorners; iCon++)
{
int x = (int)(cntX + fRad * cos(fAng));
int y = (int)(cntY - fRad * sin(fAng));
RectF rc((REAL)(x-1), (REAL)(y-1), (REAL)2, (REAL)2);
gs.DrawRectangle(&gPen, rc);
if(iCon > 0)
{
gs.DrawLine(&gPen, (REAL)iPrvX, (REAL)iPrvY, (REAL)x, (REAL)y);
}
iPrvX = x;
iPrvY = y;
fAng += fDAng;
}
}
fRad -= fLayDis;
}
//中心点
{
Brush *br = new SolidBrush(m_LayerLineColor);
RectF rc((REAL)(cntX-2), (REAL)(cntY-2), (REAL)4, (REAL)4);
gs.FillEllipse(br, rc);
delete br;
}
}
//绘制名称
if(pRadItem != NULL)
{
Brush *brs = new SolidBrush(m_NameStrColor);
double fRad = fMaxRad + 20;
double fAng = fSAng;
for(int iCon=0; iCon<iMaxCorners; iCon++)
{
//要绘制的字体
WCHAR wString[128];
swprintf_s(wString, L"%s\r\n(%.1f)",
pRadItem[iCon].szName, pRadItem[iCon].fValue);
//字体中心
int x = (int)(cntX + fRad * cos(fAng));
int y = (int)(cntY - fRad * sin(fAng));
//字体区域大小
RectF rcTxt(0,0,0,0);
gs.MeasureString(wString, wcslen(wString), &gfont, PointF(0,0), &rcTxt);
//字体起始位置
PointF pt(x - rcTxt.Width/2, y - rcTxt.Height/2);
//绘制字体
gs.DrawString(wString, wcslen(wString), &gfont, pt, brs);
fAng += fDAng;
}
delete brs;
}
//绘制数据
if(pRadItem != NULL && iMaxCorners > 0)
{
//填充模式
{
GraphicsPath *gPath = new GraphicsPath();
int iPrvX = 0, iPrvY = 0;
double fAng = fSAng;
for(int iCon=0; iCon<=iMaxCorners; iCon++)
{
double fRad = pRadItem[iCon%iMaxCorners].fValue * fMaxRad / iMaxLayers;
//数据坐标中心
int x = (int)(cntX + fRad * cos(fAng));
int y = (int)(cntY - fRad * sin(fAng));
if(iCon > 0)
{
gPath->AddLine(iPrvX, iPrvY, x, y);
}
iPrvX = x;
iPrvY = y;
fAng += fDAng;
}
gPath->CloseFigure();
Brush *brs = new SolidBrush(m_DataFillColor);
gs.FillPath(brs, gPath);
delete brs;
delete gPath;
}
//画线模式
{
Pen gPen(m_DataLineColor, 2.0f);
int iPrvX = 0, iPrvY = 0;
double fAng = fSAng;
for(int iCon=0; iCon<=iMaxCorners; iCon++)
{
double fRad = pRadItem[iCon%iMaxCorners].fValue * fMaxRad / iMaxLayers;
//数据坐标中心
int x = (int)(cntX + fRad * cos(fAng));
int y = (int)(cntY - fRad * sin(fAng));
if(iCon > 0)
{
gs.DrawLine(&gPen, iPrvX, iPrvY, x, y);
}
iPrvX = x;
iPrvY = y;
fAng += fDAng;
}
}
}
}
};
//调用示例
void CSDI1View::OnDraw(CDC* pDC)
{
CSDI1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rcRect;
GetClientRect(&rcRect);
HDC hdc = pDC->m_hDC;
CRadarDrawClass::RADARITEM Item[]=
{
{ L"Con1", 2 },
{ L"Con2", 3 },
{ L"Con3", 6 },
{ L"Con4", 0.5 },
{ L"Con5", 4 },
};
CRadarDrawClass m_radDraw;
m_radDraw.SetBackImage(L"C:\\temp\\8.jpg");
m_radDraw.DrawRadarGraphics(hdc, rcRect, Item, _countof(Item), 10);
}