背景
问题由来
在参考1这篇文章里写了GDI下坐标缩放的情况,这里记录下再Direct2D绘图引擎下的缩放操作。
环境配置
参考文章2
几个概念
参考上一篇文章的说明配图
实现功能
1.所有图形初始缩放在默认视图框架内 2.(0,0)位置位于视图左下角 3.可以从屏幕坐标反推出原始数据坐标 4.使用Direct2D技术,在保持抗锯齿效果的同时,绘图效率和GDI差不多
思路及代码
流程图
Created with Raphaël 2.1.0
计算等效初始坐标
1.遍历原始坐标获得XMAX,YMAX,XMIN,YMIN. 2.获得视窗访问WIDTH,HEIGHT. 3.计算初始缩放比率SCALE,计算方法为:
i f ( Y M A X − Y M I N H E I G H T > X M A X − X M I N W I D T H ) , S C A L E = H E I G H T Y M A X − Y M I N
i f ( Y M A X − Y M I N H E I G H T < X M A X − X M I N W I D T H ) , S C A L E = W I D T H X M A X − X M I N
同时得到绘图范围
R A N G E X = ( X M A X − X M I N ) ∗ S C A L E
R A N G E Y = ( Y M A X − Y M I N ) ∗ S C A L E
4.计算等效初始坐标,计算方法为:
x n e w = ( x o l d − X M I N ) ∗ S C A L E
y n e w = ( y o l d − Y M I N ) ∗ − S C A L E + R A N G E Y
其中乘以负的缩放系数并加上绘图范围的Y值是为了将坐标调整为y正向向上,左下角为(0,0) 5.反推原始数据 为了从屏幕坐标反推得到原始数据,必须传入视图滚动条位置信息ScrollPT及视图缩放系数Zoom(注意不是初始缩放系数SCALE) 计算方法为:
x o l d = x s c r e e n + S c r o l l P T . x Z o o m ∗ S C A L E + X M I N
y o l d = y s c r e e n + S c r o l l P T . y Z o o m − R A N G E Y − S C A L E + Y M I N
代码
typedef std ::vector vPT; typedef D2D1_POINT_2F DPoint;typedef std ::vector vDPT; typedef D2D1::Matrix3x2F Matrix;typedef struct _InitOffset { int nXOffset; int nYOffset; double dInitScale; CSize range; _InitOffset() { nXOffset = 0 ; nYOffset = 0 ; dInitScale = 1.0 ; range.cx = 1 ; range.cy = 1 ; } }InitOffset;typedef struct _ZoomOffset { CPoint ScrolPT; double dZoom; _ZoomOffset() { ScrolPT = CPoint(0 ,0 ); dZoom = 1.0 ; } }ZoomOffset;typedef struct _ScreenPara { InitOffset initoffset; ZoomOffset zoomoffset;inline CPoint GetOriginPTFromScreenPT(CPoint ScreenPT) { CPoint PT; PT.x = (ScreenPT.x + zoomoffset.ScrolPT.x) / (zoomoffset.dZoom * initoffset.dInitScale) + initoffset.nXOffset ; PT.y = ((ScreenPT.y + zoomoffset.ScrolPT.y) / zoomoffset.dZoom - initoffset.range.cy) / -initoffset.dInitScale + initoffset.nYOffset; return (PT); }inline CSize GetZoomRange(void ) { return (CSize(initoffset.range.cx * zoomoffset.dZoom, initoffset.range.cy * zoomoffset.dZoom)); } }ScreenPara;extern ScreenPara g_ScreenPara;
//.cpp //鼠标滚轮缩放 BOOL CScaleD2DView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { // TODO: Add your message handler code here and /or call default double m_dScale = g_ScreenPara.zoomoffset .dZoom m_dScale += 0.1 * zDelta/ 120 if(m_dScale <= 0.2 ) { m_dScale = 0.2 } if(m_dScale >= 2.0 ) { m_dScale = 2.0 } g_ScreenPara.zoomoffset .dZoom = m_dScale SetScrollSizes(MM_TEXT, g_ScreenPara.GetZoomRange ()) Invalidate() return CScrollView::OnMouseWheel(nFlags, zDelta, pt) }
结果
参考
1.MFC+GDI简化坐标平移缩放 2.Direct2D+MFC学习笔记 3.Direct2D教程(外篇)环境配置