MFC+GDI简化坐标缩放

30 篇文章 4 订阅
7 篇文章 0 订阅

0.背景

0.1问题的由来

视图里画图经常会有负坐标或者很大数值的坐标(地图),在处理的时候需要清楚DC的各种视口的意义,看了几天,头脑越看越混,视口啊,坐标零点啊什么的,一团乱麻,索性按照自己的想法来个简单的解决方案。

0.2几个概念

几个概念在下面几张图里表述
这是调整前的逻辑关系图,有负坐标,有超出客户区的坐标。
调整后
这是调整后的逻辑关系图,经过坐标平移和缩放,在客户区可以完整的显示整个图形。

0.3图形的数据

数据的excel图
这是本例使用的数据在excel里画出来的图形。数据文件在这里可以下载。

0.4默认的结果

默认的结果
这是默认的不处理的结果,只有正值。

1.思路

1.1读取数据

读取所有坐标,存入CArray里去。

    CStdioFile sfile;
    CString s,sx,sy;
    CPoint pt;

    nXmin = 0;
    nYmin = 0;
    nXmax = 0;
    nYmax = 0;
    nXW = 0;
    nYH = 0;

    sfile.Open(_T("testdata.txt"),CFile::modeRead);
    while(sfile.ReadString(s))
    {
        AfxExtractSubString(sx,s,0,'\t');
        AfxExtractSubString(sy,s,1,'\t');
        pt.x = _wtoi(sx);
        pt.y = _wtoi(sy);
        m_PTArray.Add(pt);
        if (pt.x > nXmax)
        {
            nXmax = pt.x;
        }
        if (pt.x< nXmin)
        {
            nXmin = pt.x;
        }
        if (pt.y > nYmax)
        {
            nYmax = pt.y;
        }
        if (pt.y < nYmin)
        {
            nYmin = pt.y;
        }
    }
    nXW = nXmax - nXmin;
    nYH = nYmax - nYmin;

1.2缩放

根据图形的范围和客户区的范围xy的比例确定缩放比例,所有坐标按这个比例缩小。

    CRect rc;
    GetClientRect(&rc);
    if ((double)nXW / (double)rc.Width() > (double)nYH / (double)rc.Height())
    {
        dRatio = (double)rc.Width() / (double)nXW ;
    }
    else
    {
        dRatio = (double)rc.Height() / (double)nYH ;

    }

1.3平移

先把所有负坐标变为正,方法是所有坐标减去最小的负坐标。同时求得图形范围。

    for (int i=0;i<m_PTArray.GetSize();i++)
    {
        m_PTArray.GetAt(i).x += -nXmin; 
        m_PTArray.GetAt(i).x *= dRatio;
        m_PTArray.GetAt(i).y += -nYmin; 
        m_PTArray.GetAt(i).y *= dRatio;

    }

1.4留出空白

所有坐标加上空白的宽度数值就可以。

2.工程设置及其他代码

2.1设置

1.MFC单文档工程
2.视图从ScrollView派生

2.2双缓冲绘图

定义

    CDC* m_pMemoryDC; 
    CBitmap * m_pBitmap; 

视图类构造函数里初始化

    m_pMemoryDC = new CDC();  
    m_pBitmap = new CBitmap();  

视图类析构函数里析构

    delete m_pBitmap;  
    delete m_pMemoryDC; 

响应视图类的OnPaint消息

    CDC* pDC = GetDC();
        CPoint m_ScrolPt = GetScrollPosition();
        CRect rc;
        GetClientRect(&rc);
        m_pMemoryDC->CreateCompatibleDC(pDC); 
        m_pBitmap->CreateCompatibleBitmap(m_pMemoryDC,rc.Width(),rc.Height());
        CBitmap * pOldbmp = m_pMemoryDC->SelectObject(m_pBitmap); 

        m_pMemoryDC->PatBlt(0,0,rc.right, rc.bottom,WHITENESS);//white background


        m_pMemoryDC->MoveTo((m_PTArray.GetAt(0).x - m_ScrolPt.x) * m_dScale,
            (m_PTArray.GetAt(0).y - m_ScrolPt.y) * m_dScale);
        for (int i=1;i<m_PTArray.GetSize();i++)
        {
            m_pMemoryDC->LineTo((m_PTArray.GetAt(i).x - m_ScrolPt.x) * m_dScale,
                (m_PTArray.GetAt(i).y - m_ScrolPt.y) * m_dScale);
        }


        pDC->BitBlt(0, 0, rc.right, rc.bottom, m_pMemoryDC, 0, 0, SRCCOPY);   
        m_pMemoryDC->SelectObject(pOldbmp);   
        m_pBitmap->DeleteObject();  
        m_pMemoryDC->DeleteDC(); 

2.3设置滚动条

    SetScrollSizes(MM_TEXT, CSize(nXW * m_dScale * dRatio,nYH * m_dScale * dRatio));

2.4鼠标中键滚动缩放

定义缩放比尺

double m_dScale ;

初始化为1.0。
响应视图类的

    BOOL CCoordinateView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
    // TODO: Add your message handler code here and/or call default
    m_dScale += 0.05 * zDelta/ 120;
    if(m_dScale <= 0.02)  
    {   
        m_dScale = 0.02;            
    }         
    if(m_dScale >= 4.0)  
    {
        m_dScale = 4.0; 
    }
    SetScrollSizes(MM_TEXT, CSize(nXW * m_dScale * dRatio,nYH * m_dScale * dRatio));
    Invalidate();
    return TRUE;/*CScrollView::OnMouseWheel(nFlags, zDelta, pt)*/;
}

3.结果

结果1
无缩放情况
结果2
缩放的情况

4.继续改进

GDI里画图的坐标只能是int型,但在很多图像里画的都是float型,解决方法就是使用Direct2D。后续结合2者进行程序设计。

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值