一、Android Matrix 矩阵

一、Android矩阵

大学学的线性代数和矩阵基本忘记的差不多了,理解起矩阵Matrix着实有点费劲,记了一次笔记还把左乘右乘记错了。

1.1 使用场景

项目中会使用到矩阵的场景:

  1. 背景图片,指定位置为中心点的缩放,图片平移,图片旋转。
  2. opengles 中GLSurfaceView所承载的内容需要缩放,平移变换。是内容变换不是窗口glViewport 变换

【注意】:这里提到了两种场景就对应了两种坐标体系,2种矩阵

  • 图片场景的矩阵,也就是 android.graphics.Matrix 后文用Android Matrix表示,是 2维坐标,3*3 矩阵。
  • opengles 矩阵 android.opengl.Matrix 后文用opengles 矩阵,后文用opengles Matrix 表示,是 4*4 矩阵。
  • android里也有 44矩阵 android.renderscript.Matrix4f 这个是矩阵和 android.opengl.Matrix 矩阵是能对的上的,都是3维坐标, 44矩阵。后文用 Matrix4f 表示。之所以引入这个是这个类有些方法比opengles Matrix 类的方法使用起来会更简单点。不用该矩阵其实也问题不大

二、 Android Matrix

2.1、元素表达

3*3矩阵,没个元素表达的意思:
一、Android Matrix 矩阵_第1张图片

  • MTRANS_X、MTRANS_Y 同时控制着 Translate (平移)
  • MSCALE_X、MSCALE_Y 同时控制着 Scale (缩放)
  • MSCALE_X、MSKEW_X、MSCALE_Y、MSKEW_Y 同时控制着 Rotate (旋转)
  • MSKEW_X、MSKEW_Y 同时控制着 Skew (倾斜,扭曲)

【注】:项目中没有使用Skew和Rotate不详细讨论

2.2、 set post pre

这里强调这三个函数是因为很容易歧义,但是实际使用中最常用绕不开就是这几个简单操作。Translate ,Scale ,Skew 都有这三个函数,以平移为例:

  1. m.setTranslate 直接设置位移量,m的其它参数变为单位矩阵的初始量。不涉及乘法
  2. m.postTranslate m左乘一个位移矩阵
  3. m.preTranslate m右乘一个位移矩阵

因为存在post 和pre ,就要区分这两个函数的区别,就容易逻辑开叉到底,post和pre哪个是左乘,哪个是右乘。什么场合用post,什么场合用pre。

重学了一遍线性代数里矩阵的一些知识,越学越懵,也读了不少blog,有些说post 是左乘,有些说post是右乘,我的笔记里第一次也是记post为右乘。虽然 也有看post函数的注释,但是理解上还是出现了偏差:
1、官方注释

   /**
     * Postconcats the matrix with the specified translation. M' = T(dx, dy) * M
     */
    public boolean postTranslate(float dx, float dy) {
        nPostTranslate(native_instance, dx, dy);
        return true;
    }

2、识记理解
这里:M’ = T(dx, dy) * M 其中:M是原矩阵,T是位移阵可以理解为目标变换。目标变换在左边就是左乘。目标变换在右边就是右乘。

  • post 是左乘
  • pref 是右乘

3、post VS pref
关于左乘右乘区别说的比较好的有2个观点:
https://www.zhihu.com/question/263660493
空间中的向量用列向量表示。

  1. 左乘是行变换,右乘是列变换。矩阵左乘列向量就是把它在空间当中做变换。
  2. 在固定坐标系里,用左乘。在非固定坐标系用右乘。Android是固定坐标系。

小结:
1、Android的Matrix 的几何变换可以都用post来计算,因为Android是固定坐标系空间变换用post左乘来来做是符合逻辑的。同一组计算变换里一会用post一会用pre逻辑容易乱,需要改变顺序的时候可以拿两个矩阵通过写A.postConcat(B) 或者B.postConcat(A)来修改。

2、android.renderscript.Matrix4f ,android.opengl.Matrix这两个4*4矩阵是能对应的起来的。这两个矩阵类里是不存在post和pref一说,里面的变换都是左乘 post的方式。所以理解起来反而更简单。so,我认为android Matrix都用post来更好理解

三、android Matrix 实际使用

场景一:指定点的放大,缩小。
opengles 的矩阵在这里不详述,因为它的坐标系和坐标比例计算方式都不一样。opengles 坐标依赖顶点坐标和[-1,1]范围计算。后面再写一篇介绍。

1、可以直接用指定点放大缩小函数

m.setScale(scale, scale, cx, cy)

2、使用平移和缩放(android.opengl.Matrix和Matrix4f 都没有上一种方法)
T(cx,cy)*S(s,s)*T(-cx,-cy)*m
因为android的坐标0,0是左上角,如果是opengles 移动的点第一次变换就不是m.postTranslate(-cx, -cy)

// android matrix
//平移原点到目标点
m.postTranslate(-cx, -cy)
m.postScale(scale, scale)
m.postTranslate(cx, cy)

opengl es的矩阵

//opengles matrix
Matrix4f matrix4f = new Matrix4f();
matrix4f.loadTranslate(x, y, 0);
matrix4f.scale(scaleX,scaleX,1);
//满足结合率,所以可以先算变换矩阵
matrix4f.translate(-x,-y,0);
current.multiply(matrix4f);

3、先缩放再平移
这边的1相关是推导出来的公式

m.postScale(scale, scale)
m.postTranslate(-(scale-1)*cx,-(scale-1)*cy)

4、推导的一些公式
指定点放大缩小:位移,中心点,倍数之间最后效果的时候关系
cx,cy:定点x,定点y
dx:平移
s:缩放倍数
dx = -(s-1)*cx = (1-s)*cx
cx = dx/(1-s)
同理
cy = dy/(1-s)

【注】:同样适用于

  • android.renderscript.Matrix4f
  • android.opengl.Matrix

你可能感兴趣的:(android,ui,进阶,android,matrix,android,matrix,opengl,Matrix)