AndroidNote
AndroidNote copied to clipboard
Matrix的前乘和后乘不太明白?
measure.getPosTan(measure.getLength() * currentValue, pos, tan); // 获取当前位置的坐标以及趋势
mMatrix.reset(); // 重置Matrix float degrees = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI); // 计算图片旋转角度
mMatrix.postRotate(degrees, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2); // 旋转图片 mMatrix.postTranslate(pos[0] - mBitmap.getWidth() / 2, pos[1] - mBitmap.getHeight() / 2); // 将图片绘制中心调整到与当前点重合 这是第一种方案, // 获取当前位置的坐标以及趋势的矩阵 measure.getMatrix(measure.getLength() * currentValue, mMatrix, PathMeasure.TANGENT_MATRIX_FLAG | PathMeasure.POSITION_MATRIX_FLAG);
mMatrix.preTranslate(-mBitmap.getWidth() / 2, -mBitmap.getHeight() / 2); // <-- 将图片绘制中心调整到与当前点重合(注意:此处是前乘pre) 这是第二种方案,为什么第一种是用的后乘,第二种用的是前乘,具体看了那个matrix的原理还是不太明白?可以具体讲讲吗?
就是矩阵的乘法而已。对应左乘和右乘。
以translate为例,其他类似,pre是 MT ,post是 TM ,这里的M是源矩阵(对应代码中 mMatrix) ,T是目标矩阵(对应 pre/post translate() 括号中参数对应的矩阵 ),pre操作会受到源矩阵M的影响,post不会受到源矩阵M影响,例如M是一个单位阵先sacle了(0.5,0.5),这时pretranslate(1000,1000)实际效果只有(500,500),而postTranslate(1000,1000)的效果还是(1000,1000)。基于这个理论去理解上面两种方案。 方案一: 整个过程相当于三个操作, 1. 移动矩阵到屏幕中心 2.postRotate(基于图片中心旋转)3.postTranslate去移动圆上某点的坐标再减去图片的宽高距离。 其中操作2 postRotate 实际效果就是基于图片中心点进行旋转,这里作者解释过,围绕某一点旋转对应的矩阵就是 M' = MTR*-T = TR-T 用代码表示出来有两种 // 第一种 mMatrix.preTranslate(mBitmap.getWidth()/2,mBitmap.getHeight()/2); mMatrix.preRotate(degrees); mMatrix.preTranslate(-mBitmap.getWidth()/2,-mBitmap.getHeight()/2); // 第二种 mMatrix.postTranslate(-mBitmap.getWidth()/2,-mBitmap.getHeight()/2); mMatrix.postRotate(degrees); mMatrix.postTranslate(mBitmap.getWidth()/2,mBitmap.getHeight()/2); 由于post操作不受之前矩阵的影响,那么方案一可以这么理解:将matrix经过操作1后再经过操作3 ,这相当于将圆上的点与图片的中心重合,(图片最开始是向右的icon)可以脑补下这个画面,这个icon的中心和圆上的任意一点重合(转一周),然后再经过操作2 将这个图片围绕它的中心进行旋转一定的角度(再转一周)就得到了最终的效果。
方案二: 方案二对应三个操作:1.同样是坐标点移到屏幕中心. 2.通过getMatrix获取当前圆上点对应的matrix变换 3.使用 preTranslate()去移动图片中心和圆上点重合 这个方案是通过measure.getMatrix()方法来获取到的mMatrix,得到的这个mMatrix的含义就是圆上任意一点的切线作为x轴所对应的matrix变换。再做一个与x轴垂直的y轴就得到一个坐标系,想象一下这个坐标系(十字架)围绕圆转一周的情况。 那么最原始的单位阵(坐标原点是屏幕的左上角(0,0))的位置,这个坐标系下去画这个icon刚好是顶在屏幕的左上角,那么想象一下getMatrix()对应相切的各个坐标系下去画这个icon的样子,这时使用preTranslate()的原因是因为此时每个坐标系下的icon去移动和圆上点重合就不再是-icon宽/2、-高/2了,而是这个距离经过当前matrix变换后的情况。 举个栗子,假如圆最上面那个店作为起始点 (此时小飞机的方向是向右 ,对应的角度是 0度) ,在这时的相切坐标系刚好是圆心作为原点所对应的坐标系向上移动半径长度,这时将icon与起始点重合需要移动 -icon宽/2、-高/2。 当顺时针转过45°之后,此时将icon与 45°这个点对应 所要移动的距离是 (0,根号二倍的 -icon高/2 ),也就是将icon向正上方移动 45° 与 0° 要进行重合进行的操作数值也就变化了,这个变化就是隐含在了源矩阵M中 ,(0° 进行重合移动距离所扫过的线是一个 向右下角倾斜45°的线, 在圆经过45°之后 ,这个线也顺时针旋转了45° , 就变成了一条向上的线 )
所以这里使用 preTranslate(-mBitmap.getWidth()/2,-mBitmap.getHeight()/2)方法 ,这个translate的效果就是 (-mBitmap.getWidth()/2,-mBitmap.getHeight()/2) 与之前矩阵mMatrix共同作用的结果。