背景
问题由来
在参考1这篇文章里写了GDI下坐标缩放的情况,这里记录下再Direct2D绘图引擎下的缩放操作。
环境配置
参考文章2
几个概念
参考上一篇文章的说明配图
实现功能
1.所有图形初始缩放在默认视图框架内
2.(0,0)位置位于视图左下角
3.可以从屏幕坐标反推出原始数据坐标
4.使用Direct2D技术,在保持抗锯齿效果的同时,绘图效率和GDI差不多
思路及代码
流程图
计算等效初始坐标
1.遍历原始坐标获得XMAX,YMAX,XMIN,YMIN.
2.获得视窗访问WIDTH,HEIGHT.
3.计算初始缩放比率SCALE,计算方法为:
if(YMAX−YMINHEIGHT>XMAX−XMINWIDTH),SCALE=HEIGHTYMAX−YMIN
if(YMAX−YMINHEIGHT<XMAX−XMINWIDTH),SCALE=WIDTHXMAX−XMIN
同时得到绘图范围
RANGEX=(XMAX−XMIN)∗SCALE
RANGEY=(YMAX−YMIN)∗SCALE
4.计算等效初始坐标,计算方法为:
xnew=(xold−XMIN)∗SCALE
ynew=(yold−YMIN)∗−SCALE+RANGEY
其中乘以负的缩放系数并加上绘图范围的Y值是为了将坐标调整为y正向向上,左下角为(0,0)
5.反推原始数据
为了从屏幕坐标反推得到原始数据,必须传入视图滚动条位置信息ScrollPT及视图缩放系数Zoom(注意不是初始缩放系数SCALE)
计算方法为:
xold=xscreen+ScrollPT.xZoom∗SCALE+XMIN
yold=yscreen+ScrollPT.yZoom−RANGEY−SCALE+YMIN
代码
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教程(外篇)环境配置