前言
我们要说点什么:
1.matrix
2.canvas的matrix
3.三类影响bitmap绘制的方式
4.使用camera来完成三维旋转
正文
matrix
一般的坐标变换transform,包含了:平移translate,缩放scale,旋转rotate等
坐标变换改变的是什么:坐标系
坐标系影响了什么:点的坐标值是不会改变的(除非你主动去改变它),但是点是在坐标系上进行绘制的。坐标系的改变,将使得点的绘制发生改变
在Android中,由Matrix这个类来表示坐标变换矩阵,matrix并不是android的概念,他是3d中的概念
且,标准的4*4矩阵,变成了3*3矩阵
Matrix中的post...和pre...有什么样的区别呢?
设Matrix本身的坐标变换为TR1,post...中的东东的坐标变换为TR2,则新的坐标变换TR3=TR2*TR1,它对坐标系的影响是:先执行TR2变换,再执行TR1变换
设Matrix本身的坐标变换为TR1,pre...中的东东的坐标变换为TR2,则新的坐标变换TR3=TR1*TR2,它对坐标系的影响是:先执行TR1变换,再执行TR2变换
即是:
TR1 post TR2:TR1在TR2的后面,在坐标系变换的执行过程中,先执行TR2,再执行TR1
TR1 pre TR2:TR1在TR2的前面,在坐标系变换的执行过程中,先执行TR1,再执行TR2
此外,学生时代,设E是单位矩阵,M*E=E*M=M,还记得吧
进一步的参考:http://blog.csdn.net/kuku20092009/article/details/6740865
canvas的matrix
Canvas.getmatrix返回了一个canvas的matrix的一个拷贝
注意:该matrix并不是一个E矩阵:
view经过measure,确定了mwidth和mheight后,经由父亲group,被layout到某个区域
该区域左上角的坐标,便是canvas的坐标系的原点
则,canvas的matrix是一个translate,相对于屏幕的(0,0)
matrix是如何影响view的绘制的:
view是在canvas中绘制的,一旦改变canvas的坐标系,那么绘制便有所不同
再次强调:
坐标变换,改变的是坐标系,而不是点的坐标
你要绘制的东东都是具有坐标的,无论是点,线,bitmap还是其他,
这些东东的绘制:会参照(0,0)原点,并在x/y轴上进行延伸
当坐标轴经过坐标变换后,变的奇形怪状,那么你的图形才因此变得奇形怪状。或者,你的图形本来就是奇形怪状的,而坐标系是很正统的那种
三类影响bitmap绘制的方式
1.使用matrix,构建一个新的bitmap,在绘制时,使用e矩阵
使用
bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
,来创建一个奇形怪状的bitmap
2.在绘制时,使用一个新的matrix,来绘制原始的bitmap
使用
canvas.drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)
,来将该bitmap绘制的奇形怪状(canvas的坐标系并没有改变)
3.改变canvas的坐标系,来绘制原始的bitmap
canvas.setmatrix(...)
canvas.drawbitmap(...)
方式2 vs 方式3
方式2和方式3,可以达到相同的效果:
设方式2的matrix为m2,方式3中canvas的最终的matrix为m3
则 m3 = m_canvas_original * m2
使用camera来完成三维旋转
matrix中有旋转方法,但是,你会发现,你除了指定旋转角度(或者,旋转点)以外,你并没有指定绕哪个轴旋转
当做了一个实验,你发现结果是:绕z轴旋转
如何才能绕z轴之外的其他轴旋转,你需要构造一个matrix(绕某个轴旋转某个角度):
实际上,绕某个轴某个角度进行旋转的矩阵,都是有固定的格式
我的意思是:比如绕y轴旋转,你会看到一个参数矩阵,这个矩阵有0/1,也有sinx/cosx/..等,你确定sin/cos的值,这个matrix就确定了
但是,查阅matrix这个类,你发现,没有一个构造方法/方法提供了:根据一个float[]来构建一个matrix对象,所以,上述的思路在这里行不通
-----
另外一种方式:有没有现成的矩阵来让我使用
有,使用graphics.camera(而不是hardware.camera)
在这个类中,你将发现,它提供了rotatex/y/z方法
你可以通过camera.getmatrix来获得你想要的旋转矩阵
注意:如果你要想获得绕K轴旋转a角度的矩阵,那么请使用camera.rotateK(-a),注意到a和-a了吗,别奇怪
上述只是拿了旋转来当例子,你可以动手试试translate,scale等
在android中,xyz轴的正方向是什么:x向右,y向下,z向外(拿着手机,屏幕对着你,它拿了z的正方向指向了你)
之下展示了获取 一个以某点为原点,绕k轴旋转的 旋转矩阵 的方法:
/**
* 将原点平移到指定点后,绕axis旋转
*
* @param angle
* 绕axis轴旋转的角度
* @param whichAxis
* 哪一个轴
* @param centerX
* 原点坐标x
* @param centerY
* 原点坐标y
* @param cm
* canvas的原始matrix
* @return
*/
private Matrix getRotateMatrix(float angle, String whichAxis,
float centerX, float centerY, Matrix cm) {
Matrix matrix = null;
Camera c = new Camera();
// 保存当前的camera的状态,如:坐标系等
// 注意:与restore的对应
c.save();
if (whichAxis.toLowerCase().equals("x")) {
c.rotateX(-angle);
} else if (whichAxis.toLowerCase().equals("y")) {
c.rotateY(-angle);
} else if (whichAxis.toLowerCase().equals("z")) {
c.rotateZ(-angle);
}
matrix = new Matrix();
// R
c.getMatrix(matrix);
// 恢复camera到“其在save时刻的状态”
c.restore();
// T1
matrix.preTranslate(-centerX, -centerY);
// T2
matrix.postTranslate(centerX, centerY);
if (whichAxis.toLowerCase().equals("x")) {
// 最后的执行的变换操作是: CTR, T2, R, T1
matrix.postConcat(cm);
} else if (whichAxis.toLowerCase().equals("y")) {
// 最后的执行的变换操作是: T2, R, T1, CTR
matrix.preConcat(cm);
}
return matrix;
}