当前位置:C++技术网 > 精选软件 > GDI渐变:8 斜向渐变(0-180度)实现原理分析和代码实现

GDI渐变:8 斜向渐变(0-180度)实现原理分析和代码实现

更新时间:2016-11-09 22:59:49浏览次数:1+次

    在文章《GDI斜向渐变(0-90度)实现原理分析》中我已经图解了0-90度的渐变原理。在文章《GDI斜向渐变(0-90度)代码实现分析》中分享了实现代码。
    那么现在还差0-180度渐变的原理和代码实现了。这个文章分享完了,渐变就暂时告一段落。
    0-180度渐变,如果直接使用大于90度的角度去求值,会有点麻烦。因为tan函数在(-90,90)开区间内是连续的。不过我们对于角度没有方向性,因为我们只需要一条直线即可。所以,既然如此,我们换个思维方式,抓住本质,所以可以将0-180度的渐变内部转为(-90,90)的渐变,这样可以很好利用tan函数。
    当然,对于外部调用来说,依然是0-180度哦。而-90到0度的渐变绘制原理如下图所示:
GDI斜向渐变(0-180度)实现原理分析和代码实现
    根据坐标轴对称的规律,我们可以知道,-90到0度之间实现渐变的效果,和0-90度的效果是相似的。因为要方便计算,所以不能再使用X轴递增了。而需要使用Y轴渐变。
    下面是函数的声明:
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();
}