安卓Matrix基础知识解析

 

 

1、什么是Matrix?

官方的释义:The Matrix class holds a 3x3 matrix for transforming coordinates

翻译一下:矩阵类包含一个用于变换坐标的3x3矩阵

2、如何搞懂Matrix?

我们只关心旋转、位移和缩放,只有透视和错切暂时不理会,有兴趣的自行研究。

 

我们先测试一下,看看Matrix里面到底存的是什么:

Matrix mMatrix=new Matrix();
//打印矩阵中的数据
Log.i("Matrix",mMatrix.toShortString());

结果:
[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]

放到上面的图里,看一下:

 

然后我们验证一下:

Matrix mMatrix=new Matrix();
        //放到两倍
        mMatrix.postScale(2,2);
        Log.i("Matrix",mMatrix.toShortString());
结果:
[2.0, 0.0, 0.0][0.0, 2.0, 0.0][0.0, 0.0, 1.0]
Matrix mMatrix=new Matrix();
        //放到两倍
        mMatrix.postScale(2,2);
        //平移X-150,Y-200
        mMatrix.postTranslate(150,200);
        Log.i("Matrix",mMatrix.toShortString());
结果:
[2.0, 0.0, 150.0][0.0, 2.0, 200.0][0.0, 0.0, 1.0]
//旋转30度
mMatrix.postRotate(30);
        Log.i("Matrix",mMatrix.toShortString());
        double sin = Math.sin(30);
        Log.i("Matrix",sin+"");
结果:
[0.8660254, -0.5, 0.0][0.5, 0.8660254, 0.0][0.0, 0.0, 1.0]
-0.9880316240928618

关于角度的测试,直接引用http://www.gcssloop.com/customview/Matrix_Basic  gcssloop大神的解释,本人几何功底有限,不甚明了,会用就行。

3、一个例子,搞懂post和pre

例:

实现X方向平移100像素,Y方向平移100像素,放大2倍。默认情况下,Matrix的操作坐标为左上角为0,0起始点。

代码一:

代码一:先平移,在缩放,结果平移了200,200像素,不是想要的结果。
@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //要实现的效果,平移X-100,Y-100,放大2倍
        //进行平移
        mScaleMatrix.postTranslate(100, 100);
        //进行缩放
        mScaleMatrix.postScale(2, 2);
        //设置这个矩阵
        setImageMatrix(mScaleMatrix);
    }

 

代码二:

代码二:想缩放,在平移,平移100,100,放大2倍,是想要的结果 
@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //要实现的效果,平移X-100,Y-100,放大2倍
        //进行缩放
        mScaleMatrix.postScale(2, 2);
        //进行平移
        mScaleMatrix.postTranslate(100, 100);
        //设置这个矩阵
        setImageMatrix(mScaleMatrix);
    }

分析:

为什么只是改变一下平移和缩放的顺序,结果就不一样了呢?这要了解Matrix的乘操作,还要知道post的时候到底是如何操作的。我们想打印一下,看看Matrix里面到底是什么,平移和缩放操作后Matrix到底发生了什么变化。

代码二:想缩放,在平移,平移100,100,放大2倍,是想要的结果 
@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //要实现的效果,平移X-100,Y-100,放大2倍
        //进行缩放
        mScaleMatrix.postScale(2, 2);
        //进行平移
        mScaleMatrix.postTranslate(100, 100);
        //设置这个矩阵
        setImageMatrix(mScaleMatrix);
    }

I/MatrixView: 初始状态:  [1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
I/MatrixView: 缩放后状态:[2.0, 0.0, 0.0][0.0, 2.0, 0.0][0.0, 0.0, 1.0]
I/MatrixView: 平移后状态:[2.0, 0.0, 100.0][0.0, 2.0, 100.0][0.0, 0.0, 1.0]

根据上面的解释,我们可以发现,Matrix中的数据是正确的,可以实现平移100,100,放到2倍的效果。
代码一:先平移,在缩放,结果平移了200,200像素,不是想要的结果。
@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //要实现的效果,平移X-100,Y-100,放大2倍
        //进行平移
        mScaleMatrix.postTranslate(100, 100);
        //进行缩放
        mScaleMatrix.postScale(2, 2);
        //设置这个矩阵
        setImageMatrix(mScaleMatrix);
    }
    
I/MatrixView: 初始状态:[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
I/MatrixView: 平移后状态:[1.0, 0.0, 100.0][0.0, 1.0, 100.0][0.0, 0.0, 1.0]
I/MatrixView: 缩放后状态:[2.0, 0.0, 200.0][0.0, 2.0, 200.0][0.0, 0.0, 1.0]
我们发现,这里平移成了200,200.

为什么我们只是更改了一下平移和缩放的执行顺序,结果就不同了呢?这个问题困扰了很多初次接触Matrix的攻城狮,这里做一下解释,希望可以帮助更多人理解好Matrix的操作。

首先,我们看一下源码,以平移为例。

/**
     * Preconcats the matrix with the specified translation.
     * M' = M * T(dx, dy)
     */
    public boolean preTranslate(float dx, float dy) {
        return native_preTranslate(native_instance, dx, dy);
    }


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

pre是拿当前的矩阵乘以T,而post是拿T来乘以当前的矩阵,(矩阵的乘法是不满足交换率的,所以这两种乘法的结果是不一样的)

在图形学中,矩阵M右乘A,表示的是 A * M,而矩阵 M 左乘 A,则表示的是 M * A,可以形象地理解为右乘就是从右边乘进来,左乘就是从左边乘进来。

一比较,我们可以看出,pre其实执行的就是右乘的操作,而post执行的就是左乘的操作。

这是因为,在图像处理中,越靠近右边的矩阵越先执行,所以pre(也就是先的意思)所设置的矩阵T(Scale,Rotation也是一样的)就会先于其一开始设置的Scale执行,而post(后的意思)的因为是左乘,所以它会放在最左边,那么就会最后执行。
 

那么平移和缩放操作顺序执行时,顺序的先后,导致Matrix的乘操作不同,进而结果也不同。

代码三:

代码三:
 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //要实现的效果,平移X-100,Y-100,放大2倍
        Log.i(TAG,"初始状态:"+mScaleMatrix.toShortString());
        //进行平移
        mScaleMatrix.preTranslate(100, 100);
        Log.i(TAG,"平移后状态:"+mScaleMatrix.toShortString());
        //进行缩放
        mScaleMatrix.preScale(2, 2);
        Log.i(TAG,"缩放后状态:"+mScaleMatrix.toShortString());
        //设置这个矩阵
        setImageMatrix(mScaleMatrix);
    }

代码三,大家应该可以自己理解了。

 

关键类的完整代码:

package hongzhen.com.matrixdemo;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;

@SuppressLint("AppCompatCustomView")
public class MatrixView extends ImageView {

    private String TAG="MatrixView";
    private Matrix mScaleMatrix;
    private Paint paint;

    enum Mode {
        NONE, DOWN, MOVE
    }

    private Mode mode; //当前mode

    public MatrixView(Context context) {
        this(context, null);
    }

    public MatrixView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MatrixView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setScaleType(ScaleType.MATRIX);
        mScaleMatrix = new Matrix();
        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(2);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //要实现的效果,平移X-100,Y-100,放大2倍
        Log.i(TAG,"初始状态:"+mScaleMatrix.toShortString());
        //进行平移
        mScaleMatrix.preTranslate(100, 100);
        Log.i(TAG,"平移后状态:"+mScaleMatrix.toShortString());
        //进行缩放
        mScaleMatrix.preScale(2, 2);
        Log.i(TAG,"缩放后状态:"+mScaleMatrix.toShortString());
        //设置这个矩阵
        setImageMatrix(mScaleMatrix);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制100像素的标线,用于观察图片的平移
        canvas.drawLine(100, 0, 100, getHeight(), paint);
        canvas.drawLine(0, 100, getWidth(), 100, paint);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <hongzhen.com.matrixdemo.MatrixView
        android:src="@mipmap/ic_launcher"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值