2011.10.12(3)——— android Matrix学习02
参考:http://www.iteye.com/topic/713869
http://www.moandroid.com/?p=1771
首先声明一下 上一节是有错误的
这张图是错误的
这两张图才是正确的
解释一下 假设矩阵为[a1,a2,a3][b1,b2,b3][c1,c2,c3]
如图所示 那么
平移为a3 b3
缩放为a1 b2
旋转为a1 a2 b1 b2
这是我大概的理解
下面 针对不同的变化 做一下分析
首先 声明一下 matrix最开始的矩阵是[1,0,0][0,1,0][0,0,1]
下面的都是针对单一变化的分析
1、平移
现设点P0(x0, y0)进行平移后,移到P(x,y),
其中x方向的平移量为△x,y方向的平移量为△y(相当于_matrix.postTranslate(△x, △y);)
那么,点P(x,y)的坐标为:
x = x0 + △x
y = y0 + △y
采用矩阵表达上述如下:
[1,0,△x][0,1,△y][0,0,1] * [x0][y0][1] = [x0+△x][y0+△y][1]
2、缩放
现设点p0(x0 ,y0)进行缩放,其中x放大a倍,y放大b倍,假设p0缩放后的坐标p(x,y)
那么,点P(x,y)的坐标为:
x = x0 * a
y = y0 * b
采用矩阵表达上述如下:
[a,0,0][0,b,0][0,0,1] * [x0][y0][1] = [x0 * a][y0 * b][1]
3、旋转
现设点P0(x0, y0)旋转θ角后的对有点为P(x, y)。通过使用向量,我们得到如下:
x0 = r cosα
y0 = r sinα
x = r cos(α-θ) = x0 cosθ+ y0 sinθ
y = r sia(α-θ) = -x0 sinθ+y0 cosθ
采用矩阵表达上述如下:
[cosX,-sinX,0][sinX,cosX,0][0,0,1] * [x0][y0][1] = x0 cosθ+ y0 sinθ][-x0 sinθ+y0 cosθ][1]
我的测试代码 如下:
package com.lp.matrix;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.drawable.BitmapDrawable;import android.util.Log;import android.view.View;/** * 一个简单的Matrix例子 * * @author lp * [email protected] * http://lipeng88213.iteye.com/ * 2011-10-12 * 上午11:29:19 */public class MatrixView extends View { private final static String TAG = "lp"; private Context _context; private Bitmap _bitmap; private Matrix _matrix = new Matrix(); public MatrixView(Context context) { super(context); this._context = context; //init();// init2(); init3(); } //例子01 private void init(){ //得到图片 _bitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.a)).getBitmap(); //得到30°的sin和cos值 //顺时针是正数,我们这个是逆时针转动30° float sinValue = (float)Math.sin(-Math.PI/6); float cosValue = (float)Math.cos(-Math.PI/6); //给Matrix赋值 按照固定的顺序 // //cosX -sinX translateX //sinX cosX translateY //0 0 scale // //解释 //上面的 sinX 和 cosX ,表示旋转角度的 cos 值和 sin 值,注意,旋转角度是按顺时针方向计算的。 //translateX 和 translateY 表示 x 和 y 的平移量。 //scale 是缩放的比例, 1 是不变, 2 是表示缩放 1/2 后来才知道 这个并不是缩放的 而是控制等比变换的 _matrix.setValues(new float[]{ cosValue,-sinValue,100, sinValue,cosValue,100, 0,0,2 }); } //例子02 private void init2() { _bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.a)).getBitmap(); /* * 首先,将缩放为100*100。这里scale的参数是比例。有一点要注意,如果直接用100/ bmp.getWidth()的话,会得到0, * 因为是整型相除,所以必须其中有一个是float型的,直接用100f就好。 */ _matrix.setScale(100f / _bitmap.getWidth(), 50f / _bitmap.getHeight()); // 平移到(100,100)处 _matrix.postTranslate(100, 100); // 倾斜x和y轴,以(100,100)为中心。 _matrix.postSkew(-0.2f, 0.5f, 100, 100); } //例子03 private void init3() { _bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.a)).getBitmap(); // //cosX -sinX translateX //sinX cosX translateY //0 0 scale // //执行_matrix.postTranslate(250, 250);后的矩阵为 //Matrix{[1.0, 0.0, 100.0][0.0, 1.0, 250.0][0.0, 0.0, 1.0]} //紧接着_matrix.postRotate(30);得到的矩阵 //Matrix{[0.8660254, -0.5, -38.39746][0.5, 0.8660254, 266.50635][0.0, 0.0, 1.0]} //很明显 平移距离x y都变化了// _matrix.postTranslate(100, 250);// _matrix.postRotate(30); //执行_matrix.postRotate(30);后的矩阵为 //Matrix{[0.8660254, -0.5, 0.0][0.5, 0.8660254, 0.0][0.0, 0.0, 1.0]} //紧接着_matrix.postTranslate(250, 250);得到的矩阵 //Matrix{[0.8660254, -0.5, 250.0][0.5, 0.8660254, 250.0][0.0, 0.0, 1.0]} //这个平移的距离没有变化// _matrix.postRotate(30);// _matrix.postScale(100f/_bitmap.getWidth(), 100f/_bitmap.getHeight());// _matrix.postTranslate(250, 250); //这个全部执行完后的矩阵为: //Matrix{[0.5235602, 0.0, 52.35602][0.0, 2.2727273, 227.27272][0.0, 0.0, 1.0]} //可以看出来 原本为cosX的两个位置发生了变化 但是 按照我们的理解 缩放应该改变的为scale位置的数才对啊? //所以 可以证明 我们上面的 //cosX -sinX translateX //sinX cosX translateY //0 0 scale //并不是完全正确的 //// _matrix.postTranslate(100, 100);// _matrix.postScale(100f/_bitmap.getWidth(), 100f/_bitmap.getHeight()); //执行_matrix.postRotate(30);后的矩阵为 //Matrix{[0.8660254, -0.5, 0.0][0.5, 0.8660254, 0.0][0.0, 0.0, 1.0]} // //紧接着_matrix.postScale(2, 3);得到的矩阵 //Matrix{[1.7320508, -1.0, 0.0][1.5, 2.598076, 0.0][0.0, 0.0, 1.0]}// _matrix.postRotate(30);// _matrix.postScale(2, 3); //总结 //1、 //通过上面的 我们可以看出来 我们涉及到平移操作的复合变化时,平移最好放到最后来执行 //否则 就会造成上面的问题 // //前提: //假如 矩阵为[a1,a2,a3][b1,b2,b3][c1,c2,c3] // //2、 //当我们执行平移操作matrix.postTranslate(dx, dy);后 //又执行了旋转、缩放等其他操作的时候 a3和b3就会发生变化 它的运算规则是在这样的 (此矩阵为执行其他操作后的矩阵,以其他值来算a3 b3) //a3 = a1*dx + a2*dy //b3 = b1*dx + b2*dy // //3、 //执行_matrix.postScale(sx,sy)的时候 会改变a1、a2和b1、b2的值 //a1 = a1*sx a2 = a2*sx //b1 = b1*sy b2 = b2*sy } //例子04 垂直镜像 private void init4() { _bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.a)).getBitmap(); //按说 翻转180° 应该就可以翻转过来 //但是 如果不加postTranslate 是不会显示出来的 //因为 垂直翻转 按理说 应该是x = x0 y = -y0 矩阵应该为 //1 0 0 //0 -1 0 //0 0 1 //这样才能保证 这个矩阵 乘以矩阵 //x0 //y0 //1 //的时候 得到的矩阵为 //x0 //-y0 //1 //也就是 //x //y //1 //正好得到 这个矩阵式竖着的 //如果 _matrix.postRotate(180); 则推到出来的矩阵为 //-1 0 0 //0 -1 0 //0 0 1 //而这矩阵 乘以矩阵 //-x0 //y0 //1 //的时候 得到的矩阵为 //-x0 //-y0 //1 //这样 就跑道屏幕的对角线那个象限了 看不到了 //所以 加上_matrix.postTranslate(_bitmap.getWidth(), _bitmap.getHeight()); 让她再平移过来// _matrix.postRotate(180);// _matrix.postTranslate(_bitmap.getWidth(), _bitmap.getHeight()); //Matrix{[1.0, 0.0, 0.0][0.0, -1.0, 0.0][0.0, 0.0, 1.0]} //这个应该可以理解为 先旋转了180° 然后y轴缩放了-1 也就是 变到第二象限了 _matrix.setScale(1.0f, -1.0f); //上面的执行完毕后 和矩阵[x0][y0][1] 相乘后 得到[x0][-y0][1] //映射到屏幕的上方了 也就是x轴的上方了 还是看不到 所以 要给y轴加上图片的高度 让其出现在屏幕里 //这个效果 和上面的一样 //Matrix{[1.0, 0.0, 0.0][0.0, -1.0, 44.0][0.0, 0.0, 1.0]} _matrix.postTranslate(0, _bitmap.getHeight()); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(_bitmap, _matrix, null);// canvas.drawBitmap(_bitmap, 0, 0, null); Log.i(TAG, _matrix.toString()); } }
结论:
例子01:
我们可以通过_matrix.setValues来直接设置矩阵
例子02:
例子03:
1、通过上面的 我们可以看出来 我们涉及到平移操作的复合变化时,平移最好放到最后来执行
否则 就会造成上面的问题
前提:
假如 矩阵为[a1,a2,a3][b1,b2,b3][c1,c2,c3]
2、
当我们执行平移操作matrix.postTranslate(dx, dy);后
又执行了旋转、缩放等其他操作的时候 a3和b3就会发生变化 它的运算规则是在这样的 (此矩阵为执行其他操作后的矩阵,以其他值来算a3 b3)
a3 = a1*dx + a2*dy
b3 = b1*dx + b2*dy
3、
执行_matrix.postScale(sx,sy)的时候 会改变a1、a2、a3和b1、b2、b3的值
a1 = a1*sx a2 = a2*sx a3 = a3*sx
b1 = b1*sy b2 = b2*sy b3 = b3*sy
例子04:
设置垂直镜像
_matrix.setScale(1.0f, -1.0f);
_matrix.postTranslate(0, _bitmap.getHeight());
或者
_matrix.postRotate(180);
_matrix.postTranslate(_bitmap.getWidth(), _bitmap.getHeight());