• 7308阅读
  • 2回复

[原创]关于窗口和视口的理解 [复制链接]

上一主题 下一主题
离线weilp
 
只看楼主 倒序阅读 楼主  发表于: 2012-12-27
关键词: 窗口视口
    原来学MFC的时候就遇到过这个问题,当时没弄懂,最近在看QT的二维绘图时又碰到同样的问题,查了点资料,做了些实验,感觉自己弄懂了,赶紧记录下来,如果有不对的地方,还请各位帮忙指正。
    首先从官方文档的说明中看到这样的一句话:The viewport represents the physical coordinates specifying an arbitrary rectangle. The "window" describes the same rectangle in logical coordinates. 即视口窗口其实是对物理上同一个矩形区域的不同表示,这块物理区域可能是屏幕上的一部分,也可能是控件的一部分。
    可以这么理解,假设我们有一张A4的纸,以这张纸的左上角为原点,1个单位长度(可以为厘米,毫米或者米)为1个单位坐标形成物理坐标,现在我们想用QPainter在这张纸上作图,如果直接以物理坐标为单位,告诉QPainter在哪个位置上画多长的线多大的矩形,这样的操作有个明显的缺点,不利于代码的重复利用,设想一下如果我们现在不是要在这张纸上作图而是改在屏幕上作图,由于屏幕的物理单位与纸张不同 ,那么我们就需要重新来计算作图的长度。
     因此,QPainter引入了另一个坐标体系,即逻辑坐标,这种坐标是与我们实际绘图的设备无关的,为了方便,本段文章中的视口坐标为默认值,不做任何改变。同样是以在A4纸上作图为例,在逻辑坐标中,你可以任意指定这张A4纸的原点和单位长度,例如,我们利用setWindow(100,100,100,100)重新设定了逻辑坐标的范围,即当前A4纸的左上角为逻辑坐标(100,100),右下角为逻辑坐标(200,200),此时如果用QPainter画线drawLine(QPoint(100,100),QPoint(200,200)),就是在A4纸上画个对角线,同样的代码用来在A3纸上作图,表现的意思就是,A3纸的左上角为逻辑坐标(100,100),右下角为逻辑坐标(200,200),同样的画线代码仍然会生成一条对角线。因此,实际上逻辑坐标可以理解为,绘图的人在实际要绘图的区域人为定义的坐标系,在后续的绘图过程中,提供的坐标数值均以这个坐标系为准,而不关心这些绘图的代码最终会画到哪些实际的设备中。
    现在我们回过头来说说视口坐标,其实我自己的理解是,视口坐标定义了与逻辑坐标相对应的那块矩形区域,即对于一个具体的设备来讲,这个设备上的哪块区域对应了绘图者自定义的逻辑坐标。还是以A4纸为例,假设现在这张A4纸的实际大小为100*100(当然这不是标准A4纸的大小啦,举例嘛,没必要那么较真)默认情况下,视口坐标的范围就是这张纸的左上角到右下角,即如果这时候绘图者用setWindow(100,100,100,100)来设定了逻辑坐标,那么此时的意思就是,这张图的逻辑坐标((100,100)~(200,200))对应的实际的物理区域就是A4的左上角到右下角,如果此时用drawLine(Point(100,100),QPoint(200,200))画线,就会作出一条对角线。现在我们改变下视口的范围,利用setViewport(50,50,50,50),那么此时表示的就是,当前的逻辑坐标范围((100,100)~(200,200))对应的是A4纸中右下角那四分之一大小的区域,因此如果此时还用相同的画线代码drawLine(Point(100,100),QPoint(200,200)),画出来的线就是对角线的一半长。
    现在再来做个稍微复杂的例子,当时我就是卡在这里没弄明白,个人觉得如果能把这些代码的执行效果弄懂,基本上这块内容就差不多了。还是以A4纸为例,仍假设这张A4纸的实际大小为100*100,现在我们执行这样的操作
       setWindow(QPoint(0,0),QPoint(100,100));
       setViewport(QPoint(0,0),QPoint(50,50));
       drawLine(QPoint(0,0),QPoint(200,200));
    此时画出来的线是什么样的呢?毫无疑问还是对角线,那么这条线的长度呢?答案是整个A4纸的对角线。首先我们设定了逻辑坐标范围为(0,0)~(100,100),然后设定了视口坐标,即设定了与当前逻辑坐标实际对应的物理区域大小,这里这块物理区域大小我们设定为A4纸的左上角那四分之一,然后画线,由于我们是从逻辑坐标的(0,0)画到(200,200),根据比例,那么这部分逻辑坐标对应的实际区域就是(0,0)~(100,100),即整个A4纸的大小。从这里也可以看出文档中这句话的意思:Note that the window-viewport conversion is only a linear transformation, i.e. it does not perform clipping. This means that if you paint outside the currently set "window", your painting is still transformed to the viewport using the same linear algebraic approach.即逻辑坐标与视口坐标仅仅是定义了从逻辑坐标到实际物理坐标之间的比例关系,它并不执行裁剪操作,当绘图区域超过定义的逻辑坐标范围时,它仍将按定义的比例关系在相应的物理区域进行绘图。
     基本上物理坐标和逻辑坐标的理解到这就差不多了,但还有两个地方需要注意的,一个是世界坐标(我觉得这个翻译相当地糟糕),另一个是关于setViewport函数中参数数值的单位。第一个问题比较简单,其实就是为了方便绘图过程中的一些仿射变换操作(比如旋转、平移、缩放等),QPainter利用了一个3*3的矩阵,通过这个矩阵,可以将用户画在逻辑坐标中的图很方便的进行这些操作,然后再由逻辑-物理坐标的对应关系,绘到相应的设备上去。关于第二个问题,我查了下文档,大体有个理解,但不是很确定,还请懂的人多多指教。文档中是这么说的: The default unit is one pixel on pixel-based devices and one point (1/72 of an inch) on printers. 即在以像素为单位的设备上,这些数值的单位就是像素,而在打印机上,这些数值的单位就是1/72 inch.也就是说,我们通常通过width()和height()获取得到的控件的长宽,它们的单位就是像素,此时如果我们用setViewport()来设定视口范围,相应的单位也是像素,而如果设备换成打印机,那么这两个单位就变成 1/72 inch。
      综合上面所说的,个人觉得窗口-视口的意义其实就是定义了逻辑坐标到物理坐标之间的比例关系,从而使得QPainter在绘制的过程中,可以不用考虑实际的设备来完成。第一次写这样的文章,如果有说得不好的地方,还请海涵。说得不对的地方,希望大家帮忙指正。
离线dxfans

只看该作者 1楼 发表于: 2012-12-27
不错不错
离线hehuim

只看该作者 2楼 发表于: 2012-12-27
我也一直搞不懂!学习了
快速回复
限100 字节
 
上一个 下一个