坐标变换和BitBlt

drlsdrls 2013-08-27 04:12:57
用双缓存作图搞得我头都大了,麻烦高手来看一下。

目标:
现在用一个timer在一个static空间上动态绘制一个sin曲线,希望在大约一秒钟内画完一个sin周期图形

思路:
用timer触发Polyline函数依次连接sin数组内的点,然后动态画出sin曲线

问题:
在timer内用双缓存实现绘图,由于sin数组内有正有负,为了直观化,引入坐标变化,把(X=0,Y=rect.bottom/2)设为原点,结果画出来的图如附件所示,感觉内存里的DC坐标并没有变化正确,虽然内存DC中的Y轴方向是朝上了,但是Y轴起始点好像还是在Y=0的位置,想请教高手问题出在哪里,应该如何改善。多谢多谢!

执行结果:



CPoint m_ArySin[1000];//存放sin曲线点坐标的数组,X:0~2PI,Y:-1~+1
void CPage1::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default

switch (nIDEvent)
{
case 1:
CBitmap memBitmap;//内存绘图
CBitmap* pOldBmp = NULL;//内存绘图
CRect rect; //控件区域

//获取空间区域DC
CWnd* pWnd = GetDlgItem(IDC_STATIC1);//控件窗口
pWnd->GetClientRect(&rect);//控件客户区
m_pDC = pWnd->GetDC();//获取控件DC

//坐标转换

m_pDC->SetMapMode(MM_ANISOTROPIC);//设置map模式
m_pDC->SetWindowExt(rect.right, -rect.bottom);//设置窗口尺寸,逻辑单位
m_pDC->SetViewportExt(rect.right, rect.bottom);//设置视口尺寸,物理单位
m_pDC->SetViewportOrg(0, rect.bottom/2);//设置设备坐标原点
//m_pDC->SetWindowOrg(0, rect.bottom/2);//设置逻辑坐标原点

//创建内存绘图设备
m_memDC.CreateCompatibleDC(m_pDC);
memBitmap.CreateCompatibleBitmap(m_pDC,rect.right,rect.bottom);
pOldBmp = m_memDC.SelectObject(&memBitmap);

/*
//坐标转换
m_memDC.SetMapMode(MM_ANISOTROPIC);//设置map模式
m_memDC.SetWindowExt(rect.right, rect.bottom);//设置窗口尺寸,逻辑单位
m_memDC.SetViewportExt(rect.right, -rect.bottom);//设置视口尺寸,物理单位
m_memDC.SetViewportOrg(0, rect.bottom/2);//设置设备坐标原点
//m_memDC.SetWindowOrg(0, rect.bottom/2);//设置逻辑坐标原点
*/

//绘图
CPen Pen;
CPen* pOldPen;
Pen.CreatePen(PS_SOLID, 1, RGB(255,255,0));
pOldPen = m_memDC.SelectObject(&Pen);

//画线
m_memDC.Polyline(m_ArySin, m_nTime1Cnt);

m_memDC.SelectObject(pOldPen);
Pen.DeleteObject();

//内存拷贝到屏幕
m_pDC->BitBlt(0,0,rect.right,rect.bottom,&m_memDC,0,0,SRCCOPY);

//析构
m_memDC.SelectObject(pOldBmp);
m_memDC.DeleteDC();
memBitmap.DeleteObject();

m_nTime1Cnt += 1;
if(m_nTime1Cnt==165)
{
KillTimer(1);
}


break;
}

CDialogEx::OnTimer(nIDEvent);
}
...全文
209 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
drlsdrls 2013-08-28
  • 打赏
  • 举报
回复
谢谢各位回答,做了N次实验,终于找到点规律了,总结如下,如有错误,烦请指正 1,pDC做了坐标变换以后,memDC也要做相应的坐标变换(为了保持一致) 2,BitBlt中不管Src还是Des的X,Y坐标并不像MSDN中说的是逻辑坐标,而是变换后的相对坐标,比如BitBlt函数的第一,第二参数,MSDN中的定义是目标矩形的左上角,但是如果做了坐标变换,比如做了如下坐标变换:

//逻辑坐标系和设备坐标系比例1:1,Y轴方向相反
//设备坐标系原点设为(0, rect.bottom/2),也就是设备坐标系向下平移rect.bottom/2个单位。
m_pDC->SetWindowExt(rect.right, -rect.bottom);//设置窗口尺寸,逻辑单位
m_pDC->SetViewportExt(rect.right, rect.bottom);//设置视口尺寸,物理单位
m_pDC->SetViewportOrg(0, rect.bottom/2);//设置设备坐标原点
那这个时候要把memDC的图拷贝到pDC中是,BitBlt函数就应该这样写: m_pDC->BitBlt(0,-rect.bottom/2,rect.right,rect.bottom,&m_memDC,0,-rect.bottom/2,SRCCOPY); 注意观察红色部分的参数,按照MSDN的解释,第一个红色参数应该是目标DC的左上角的逻辑Y坐标,因为在坐标变换中我并没有改动逻辑坐标的原点,所以我本来以为这里设置为0,但是实际操作下来如果设为0就错了,只有设为-rect.bottom/2才能正确动作,那这个-rect.bottom/2明显是一个负数,看上去其实更像设备坐标系下的坐标,而且是目标DC的左下角的Y坐标,由此可以推断,如果你做了坐标变换,那么BitlBlt的坐标参数应该是设备坐标系下的起始点的参数。换句话说,如果你设备坐标系的Y轴是向上的,那么X,Y就应该是左下角的坐标,而不是左上角的。不知道我说清楚了没有,自己都晕了,唉。。。
zgl7903 2013-08-27
  • 打赏
  • 举报
回复
BitBlt之前恢复坐标映射
drlsdrls 2013-08-27
  • 打赏
  • 举报
回复
引用 2 楼 xiaohuh421 的回复:
数学坐标 到 屏幕坐标的转换 垂直坐标反相, 然后再把原点移动到你要绘图的坐标处.(x1,y1) (x,y) -- (x+x1,-y+y1) 但是, 按这个移动, 会发现坐标系是图是反的, 相当于原来的对于x轴镜像. 想要坐标系不同, 而显示又符合, 那么实际坐标系变换就简单了, 就相当于把第一,四像限的图下移到二,三像限.

//绘制坐标X轴.
		POINT ps = {100,200};
		dc.MoveTo(ps);
		ps.x = 500;
		ps.y = 200;
		dc.LineTo(ps);

		for(double i=0; i<360; i+=1.0f)
		{
			int y = sin(i*3.14159f/180.0f)*100.0f; //把0-1扩展到0-100;
			int x = (int)i;
			dc.SetPixel(x+100, -y+200, RGB(255,0,0));  //原点移动到屏幕 100,200处
		}
谢谢,当然我也可以单纯的先把我的源数据做一个坐标系转换,然后目标DC和内存DC不做任何变换直接画图,这样也没问题,可是我更想知道GDI下的那几个坐标变换函数的用法。。。
xiaohuh421 2013-08-27
  • 打赏
  • 举报
回复
数学坐标 到 屏幕坐标的转换 垂直坐标反相, 然后再把原点移动到你要绘图的坐标处.(x1,y1) (x,y) -- (x+x1,-y+y1) 但是, 按这个移动, 会发现坐标系是图是反的, 相当于原来的对于x轴镜像. 想要坐标系不同, 而显示又符合, 那么实际坐标系变换就简单了, 就相当于把第一,四像限的图下移到二,三像限.

//绘制坐标X轴.
		POINT ps = {100,200};
		dc.MoveTo(ps);
		ps.x = 500;
		ps.y = 200;
		dc.LineTo(ps);

		for(double i=0; i<360; i+=1.0f)
		{
			int y = sin(i*3.14159f/180.0f)*100.0f; //把0-1扩展到0-100;
			int x = (int)i;
			dc.SetPixel(x+100, -y+200, RGB(255,0,0));  //原点移动到屏幕 100,200处
		}
drlsdrls 2013-08-27
  • 打赏
  • 举报
回复
补充: 1,STATIC控件我先用蓝色画刷涂了底色,所以执行效果中下半段是蓝色的 2,从内存DC拷贝到视图DC的命令如下:
m_pDC->BitBlt(0,0,rect.right,rect.bottom,&m_memDC,0,0,SRCCOPY);
第二个参数是目标DC的Y坐标,个人感觉这里应该是0,因为我并没有改变逻辑坐标呵,当然应该从Y=0的位置开始覆盖呵,但是实际效果貌似并非如此,这是为什么呢? 3,为什么内存DC里负数部分没有被画出来?

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧