那么现在还差0-180度渐变的原理和代码实现了。这个文章分享完了,渐变就暂时告一段落。
0-180度渐变,如果直接使用大于90度的角度去求值,会有点麻烦。因为tan函数在(-90,90)开区间内是连续的。不过我们对于角度没有方向性,因为我们只需要一条直线即可。所以,既然如此,我们换个思维方式,抓住本质,所以可以将0-180度的渐变内部转为(-90,90)的渐变,这样可以很好利用tan函数。
当然,对于外部调用来说,依然是0-180度哦。而-90到0度的渐变绘制原理如下图所示:
下面是函数的声明:
void GradientLinearRotate(CDC* pDC,CRect rt,COLORREF clr1,COLORREF clr2,int angle);
函数使用示例:
CDC *pDC = GetDC();
CRect rtClient;
GetClientRect(&rtClient);
GradientLinearRotate(pDC,rtClient,RGB(255,100,50),RGB(0,240,100),true);
函数实现代码:
void Ctmp_clrDlg::GradientLinearRotate(CDC* pDC,CRect rt,COLORREF clr1,COLORREF clr2,int angle)
{
//使用内存DC来加速绘制,防止闪烁
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
CBitmap bmp;
bmp.CreateCompatibleBitmap(pDC,rt.Width(),rt.Height());
dcMem.SelectObject(&bmp);
//以左上角为坐标原点,angle为线条的斜度
int width = rt.Width();
int height = rt.Height();
int r1 = GetRValue(clr1);
int r2 = GetRValue(clr2);
int g1 = GetGValue(clr1);
int g2 = GetGValue(clr2);
int b1 = GetBValue(clr1);
int b2 = GetBValue(clr2);
int rSpan = r2 - r1;
int gSpan = g2 - g1;
int bSpan = b2 - b1;
//对0-360角度进行处理,映射到-90度-90度之间
if (angle<0 || angle>180)return;//只支持0-180度
//大于90度转为负数角度处理
if (angle<=90)
{
//不做任何处理
}
else if (angle<=180)angle -= 180;//得到负数角度
int start_x=0,end_x=0,count=0;
if (angle>-90 && angle <0)
{
count = height + width*tan((double)abs(angle)*3.14/180);
for (int i=0;i<count;i++)
{
COLORREF clr = RGB(r1+(i*rSpan)/count,g1+(i*gSpan)/count,b1+(i*bSpan)/count);
CPen pen(PS_SOLID,2,clr);
dcMem.SelectObject(&pen);
dcMem.MoveTo(width,i);
int x = width + i/tan((double)angle*3.14/180);
dcMem.LineTo(x,0);
}
}
else if (angle==0)
{
count = height;
for (int i=0;i<count;i++)
{
COLORREF clr = RGB(r1+(i*rSpan)/count,g1+(i*gSpan)/count,b1+(i*bSpan)/count);
CPen pen(PS_SOLID,2,clr);
dcMem.SelectObject(&pen);
dcMem.MoveTo(0,i);
dcMem.LineTo(width,i);
}
}
else if (angle>0 && angle<=90)
{
count = width + height /tan((double)angle*3.14/180);
if (angle==90)count = width;
for (int i=0;i<count;i++)
{
COLORREF clr = RGB(r1+(i*rSpan)/count,g1+(i*gSpan)/count,b1+(i*bSpan)/count);
CPen pen(PS_SOLID,2,clr);
dcMem.SelectObject(&pen);
int y = (int)i*tan((double)angle*3.14/180);
dcMem.MoveTo(0,y);
dcMem.LineTo(i,0);
}
}
//将内存的数据一次性贴到设备DC中
pDC->BitBlt(rt.left,rt.top,rt.Width(),rt.Height(),&dcMem,0,0,SRCCOPY);
bmp.DeleteObject();
dcMem.DeleteDC();
}