场景视图中二维空间变换矩阵的计算

本文详细探讨了场景视图中如何通过二维空间变换矩阵实现控件的平移、缩放和旋转。通过实例解析了变换矩阵的组成及操作背后的数学原理,包括拖拽缩放、旋转和手势操作的算法。并提供了基于Qt的实现代码供读者实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        所谓场景视图,就是一个包含控件的容器。在场景视图中,可以通过鼠标或者触摸屏任意平移、缩放、旋转里面的控件。

        要实现这个效果,最关键的部分就是计算控件的二维空间变换矩阵。

        常见的二维空间变换矩阵是 3x3 的矩阵,通过这个矩阵可以实现平移、缩放、旋转的功能。

         也有 4x4 的变换矩阵,可以增加实现斜变效果,不过不在本文讲解范围内。

        本文侧重与思路分析,不做具体的公式推导。文后附有实现代码,可以用来快速体验实际效果。

二维变换分量

        为了更容易理解,我们将平移、缩放、旋转分开,这样就有三个变换矩阵,他们的乘积还是原来的矩阵。

        A = S * R * T

         S(Scale)表示缩放矩阵,只有 m11,m22 有值,其他都是 0(除 m33 永远是1)。m 11 表示 x 轴方向缩放系数,m22 表示 y 轴方向缩放系数。

        R(Rotate)表示旋转矩阵,只有左上角 2x2 的子矩阵有值,其他都是 0(除 m33 永远是1)。(Rz 表示围绕 z 轴旋转)

        

        T(Translate)表示平移矩阵,只有 m31,m32有值,其他都是 0(除 m11,m22,m33 永远是1)。m31 表示 x 轴方向的偏移量,m32 表示 y 轴方向的偏移量。

         需要注意的是,S、R、T 三者的顺序不能调整。缩放、旋转是有中心的,如果放在平移之后,效果就变成中心点偏移后的缩放、旋转了,从直观上很难理解。至于缩放为什么要放在旋转前面,是因为缩放有方向性(沿 x、y 轴),一旦旋转之后,再缩放,就偏离了初始的轴定义。

二维变换操作

        接下来考虑常见的二维变换操作,如何影响变换矩阵。我们在三个矩阵的基础上作调整,最终反映到矩阵乘积 A 上。

  • 平移

         平移操作改变控件的位置,控件整体平移。

        如上图,我们在已有变换的基础上增加了一个平移量。对应的修改 T 矩阵就可以了:T = T * T' 。

  • 拖拽缩放

        拖拽缩放是指拖动边框的一个顶点或者一个边,达到缩放控件的效果。如下图的 8 个白点是拖拽点。

           此时除了缩放,其实还附加有平移操作。分析一下算法的输入是:

  • 拖拽方向:4 个顶点,4个边,共有 8 个可能的方向
  • 拖拽量:沿着拖拽方向的调整量,比如拖拽某个顶点的位移量,相对于控件的坐标轴

         先计算缩放增量,拿新的宽高分别除以原来的宽高,得到一个缩放增量 S',那么:S = S * S'

        然后计算平移量,是否就是控件前后两个中心点的差值 t 呢?不然,因为中心点平移是相对于控件的坐标轴的,实际平移是在旋转(坐标轴也旋转了)之后,所以平移量应该是通过 t = t * R 调整后的值。

  • 拖拽旋转

        拖拽旋转的操作是,拖拽控件上方的旋转句柄(见上图蓝色原点),围绕控件中心点旋转。

            是不是只有旋转呢?不是的,除了旋转,还附加有平移操作,原因还是因为坐标轴旋转了。拖拽旋转并不会引起平移,但是在旋转之前控件是有平移的,相对于旋转了的坐标轴,这个平移是有变化的。

         先计算旋转增量,以中心点和旋转拖拽点的前后点,三点的夹角,就是旋转角度 \Theta。代入到中,可以得到旋转增量 R',那么:R = R * R'

        然后计算平移量,用 t 表示旋转之前偏移量的,那么新增平移量为 t' = t * R'。 

  • 滚轮操作

  • 手势操作

        手势操作是指用双指按住控件上的两个点,然后移动两个手指,实现对控件同时平移、缩放、旋转的操作。手势操作能够极大的提升操作体验,但也是实现最为复杂的。        

         如上图,手指1从起点1向下移动,同时,手指2从起点2向右上移动。我们来分析一下这个过程中,三个变换矩阵分别有什么变化。

        首先要明确两个定理:“旋转不变性”和“缩放同向性”。

        旋转不变性是指在旋转过程中,刚体上任意两点的连线,其旋转的角度是一样的;同时也说明,以任意一点为中心点,旋转的角度是一样的

        缩放同向性是指在手势操作中,任意方向的缩放倍数是一样的,也即任意两点的连接线段,其长度变化的比例是一样的。

        基于此,我们容易得出下面的结论:

  • 手势操作中,缩放增量是双指距离的变化系数,即:操作后双指的距离 / 操作前双指的距离
  • 手势操作中,旋转增量是双指连线转过的角度,即上图中的夹角

        所以比较容易的就计算出 S' 和 R',剩下的就是平移量了 T'。先给出平移增量公式:

t' = t * S' * R' + d1 - s1 * S' * R' - t

        其中:

  • t:操作前的平移量
  • S‘:本次操作的缩放增量
  • R':本次操作的旋转增量
  • s1:手指1的起点(也可以用手指2)
  • d1:手指1的终点

         怎么理解这个公式呢?

        首先,操作前的平移量,经过新的缩放、旋转增量后,会加入到最终的平移量上。

        然后 d1 - s1 * S' * R' 是表面上的新的平移量。

        最后,但是因为计算的是平移增量,所以要减去操作前的平移量。

算法实现

        以上算法,是电子白板中的一部分。

        基于 Qt 的实现版本,可以从这里获取。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fighting Horse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值