Matrix与graphics.Camera的使用

2024-05-14 00:38
文章标签 使用 matrix camera graphics

本文主要是介绍Matrix与graphics.Camera的使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Matrix的使用

        它可以进行平移,旋转,斜切和缩放,但要注意它的旋转只能在手机屏幕中进行旋转(相当于Camera中绕z轴旋转)

使用步骤

        1,将一个图片转换成Bitmap。

        2,创建一个Canvas

        3,将得到的bitmap画在canvas上,在画的过程中设置matrix。示例:

//图片缩放private Bitmap scaleBitmap(){//将要展示的图片解析成bitmapafter = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);//得到一个新的bitmap,它的大小和要展示的图片一样bitmap = Bitmap.createBitmap(after.getWidth(), after.getHeight(),after.getConfig());// 根据新得到的bitmap创建canvas,那么以后canvas画的东西都会展示在bitmap上。Canvas canvas = new Canvas(bitmap);paint = new Paint();paint.setColor(Color.BLACK);Matrix matrix = new Matrix();/** 可以把float[]看成3*3的数组,在调用drawBitmap()的时候,会有该矩阵乘以after对应的矩阵(一个3*1的矩阵,* 该矩阵分别代表着after的x,y,z轴大小),将所得的结果画在canvas上,这就实现了缩小与放大。如果第一个参数为-1,那么就意味着* bitmap与after的x轴是相反的,相当于镜面效果;如果第五个参数为-1,就意味着bitmap与after的y轴是相反的,* 相当于倒影效果。*/matrix.setValues(new float[] { 0.5f, 0, 0, 0, 1, 0, 0, 0, 1 });//matrix.setScale(0.5f, 1);这句话和setValues的效果是一样的。// 把要展示的图片画在canvas上,此时bitmap上就有了要展示的图片canvas.drawBitmap(after, matrix, paint);return bitmap;}

        上面的代码是用来缩放的。可以为matrix设置两种方法达到缩放的目的。一种是用setValues(),一种是setScale()两者的效果是一样的。具体区别见注释。

常用方法

        setRotate():用来使图片旋转(在屏幕中进行旋转)。

        setTranslate():平移图片。

        setScale():缩放

        setSkew():斜切

        set(Matrix):将参数值复制到matrix中。

        postConcat(Matrix):参数左乘原matrix。如a.postConcat(b),得到的结果就是b*a

        preConcat(Matrix):参数右乘原matrix。如a.preConcat(b),得到的结果就是a*b

        preTranslate(),preRotate(),preScale()与preSkew():与preConcat(Matrix)类似,只不过参数matrix是按方法说明中进行生成的,而不是直接指定的。

        postTranslate(),postRotate(),postScale()与postSkew():与postConcat(Matrix)类似,只不过参数matrix是按方法说明进行生成的,而不是直接指定的。例如将mMatrix进行如下操作:

		mMatrix = new Matrix();mMatrix.setScale(4, 5);mMatrix.preTranslate(2, 4);System.out.println("----------");mMatrix.setScale(4, 5);mMatrix.postTranslate(2, 4);
它的结果为:

        由于在syso前后都调用了setScale(4,5),所以该方法执行后,mMatrix就是主对角线为4,5,1的3*3矩阵。而*Translate()又形成了另一个矩阵。当调用的是preTranslate()时,原矩阵在前(即形成了结果1中等号右边的矩阵相乘),调用postTranslate()时,原矩阵在后(即形成了结果2中等号右边矩阵相乘)。

        isIdentity():是否是单位矩阵。

        invert():返回值代表当前矩阵是否可逆。如果可逆,则将当前矩阵的逆矩阵设置到参数中,否则不进行任何操作。

        mapPoints():将当前矩阵作用到参数点上。如果是一个参数,则变换后的结果存储于参数中;如果是两个参数,则对src进行变换,并将结果存储于dst中,并且src保持不变。多个参数的与两个参数的类似。所有的map操作都是将当前矩阵作用于指定的参数

        mapRect(RectF):将当前matrix的变换作用于指定的矩形,并把作用结果重新写到矩形中。它本质上仍旧是对矩形的四个角进行变换的。如下:

		mMatrix = new Matrix();mRectF = new RectF(10, 10, 100, 100);mMatrix.setScale(1.5f, 2);mMatrix.preTranslate(100, 140);mMatrix.mapRect(mRectF);
        最初rectf左上、右下角坐标分别为(10,10)和(100,100),经过mapRect,坐标变为(165,300)和(300,480)。具体计算过程如下:

方法说明

        每一次matrix调用set*()后,它都会重置。调用不同的set方法时,matrix的值便会不一样。如下:


其中tx,ty为调用setTranslate()时的参数,sx,sy为调用setScale()时的参数,kx,ky为调用setSkew()时的参数。调用setRotate()时生成的矩阵如下:


        当调用pre*(),post*()时,都是Matrix中原有矩阵与新生成的矩阵进行左乘或右乘运算,得到的结果便为matrix中新的矩阵。新的矩阵是按照对应的set*方法形成的。

         setPolyToPoly(float[] src,int,float[] dst,int,int):将矩形src变换成矩形dst时需要的矩阵,src与dst存储的都是矩形的四个顶点的坐标。最后一个参数指的是有几个点参与变换,比如为2,则代表src前两个点经过矩阵变换后变成dst的前两个点,通过该种方法可以得到变换矩阵,因此最后一个点的参数的聚会范围是[0,4]。具体可参看APIDemo->Graphics->PolyToPoly。

        setRectToRect():与setPolyToPoly()类似。最后一个参数代表两个矩形之间的缩放规则,CENTER\START\END分别表示长宽按相同比例缩放,并将放置在中心\左上角\右上角,FILL表示src长宽不按相同比例缩放,直到将dst占满为止。

Camera的使用

        它主要是用来实现三维旋转的,和Matrix不同,它是三维的旋转。以向右为x轴正方向,向上为y轴正方向,向外为z轴正方向。

        rotateX,rotateY,rotateZ三个方法分别是沿x,y,z轴进行旋转。当沿z轴进行旋转时,就相当于matrix中的setRotate()了。

示例:

ImageView iv = (ImageView) findViewById(R.id.iv);Bitmap bm = BitmapFactory.decodeResource(getResources(),R.drawable.kefu_normal);Camera camera = new Camera();camera.save();camera.rotateX(40f);Matrix mMatrix = new Matrix();camera.getMatrix(mMatrix);camera.restore();
//		mMatrix.preTranslate(0,-bm.getHeight()/2);
//		mMatrix.postTranslate(0, bm.getHeight()/2);mMatrix.preTranslate(-bm.getWidth() / 2, 0);mMatrix.postTranslate(bm.getWidth() / 2, 0);Bitmap bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),bm.getHeight(), mMatrix, true);iv.setImageBitmap(bitmap);
说明:

         之所以在camera.restore()方法后调用mMatrix.preTranslate与postTranslate()是为了在旋转的时候移动中心点,并且在旋转之后将图又移回到原来的位置。Camera.rotateXXX()默认的中心点是左上角,可以通过preTranslate与postTranslate两个方法进行移动(左移为正,右移为负;上移为正,下移为负)。

camera.rotate():传入的值为正时,代表从外往屏幕里;否则往外。都是以屏幕为分隔线的,也就是说:-30就是屏幕往外30度。假设:开始时+70,那么再传入-30,一样是旋转到-30度的位置,并不是回到+40处。

        preTranslate与postTranslate两个方法必须放在camera.restore()之后执行,并且camera.getMatrix()要放在restore()之前,rotateXXX()之后,否则不起作用

具体效果图如下:

         save()与restore()方法:save()用来保存当前状态,restore()是用来恢复到save()保存的状态。在save()和restore()之间的操作是不会影响到restore()之后的,但是两者之间的操作会被保留下来。例如:上面代码是在save()与restore()之间进行绕x轴旋转,这个旋转的效果(第二个图片中已经发生了旋转了)被保留了下来,但是不会保留到restore()之后。

         Bitmap.createBitmap()。在本示例中直接是把参数bm复制到bitmap中,在复制的过程中,通过mMatrix进行了变换,从而新得到的bitmap是bm经过变换之后的结果。这和Matrix中的Bitmap.createBitmap()用途是不一样的,后者只是创建一个指定宽、高与Config的空白bitmap,然后通过canvas.drawXXX,把相应的东西再画到它上面。

        在上述代码中可以看到,camera通过调用getMatrix(),为Camera设置了一个Matrix,那么Camera中进行的操作都会在Matrix中体现,因此,可以理解:Camera最终还是依赖于Matrix

示例:win8效果(有bug)

public class MyImageView extends ImageView {private ClickState mCurrtentState;private static final int MAX_ROTATE_ANGLE = 16, MAX_COUNT = 8;// 旋转角度private static final int POSITIVE_NUMBER = 1;private static final int NEGATIVE_NUMBER = -1;private int count = 0;// 记录循环的次数private float scaleRate = (float) Math.sqrt(Math.sqrt(0.95f));// 缩放比例private float bigRate = (float) Math.sqrt(Math.sqrt(1 / 0.95f));// 缩放比例public MyImageView(Context context, AttributeSet attrs) {super(context, attrs);setWillNotDraw(false);}// 翻转用的图片private int mDWidth, mDHeight, mTWidth, mTHeight;private boolean isFirst = true, isFinish = true;@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (isFirst) {int mWidth = getWidth();int mHeight = getHeight();mDWidth = mWidth / 2;mTWidth = mWidth / 3;mDHeight = mHeight / 2;mTHeight = mHeight / 3;isFirst = false;}}@SuppressLint("HandlerLeak")private Handler handler = new Handler() {private int dx, dy;public synchronized void handleMessage(Message msg) {Matrix mMatrix = new Matrix();switch (mCurrtentState) {case ROTATE_BOTTOM:dx = -mDWidth;dy = 0;circleRotate(mMatrix, "rotateX", dx, dy, NEGATIVE_NUMBER,msg.what);break;case ROTATE_LEFT:dy = -mDHeight;dx = -mDWidth * 2;circleRotate(mMatrix, "rotateY", dx, dy, NEGATIVE_NUMBER,msg.what);break;case ROTATE_RIGHT:dy = -mDHeight;dx = 0;circleRotate(mMatrix, "rotateY", dx, dy, POSITIVE_NUMBER,msg.what);break;case ROTATE_TOP:dx = -mDWidth;dy = -mDHeight * 2;circleRotate(mMatrix, "rotateX", dx, dy, POSITIVE_NUMBER,msg.what);break;case SCALE:Matrix m = new Matrix();m.set(getImageMatrix());if (msg.what == 2) {// 如果是抬起的时候m.postScale(bigRate, bigRate, mDWidth, mDHeight);setImageMatrix(m);count--;if (count > 0) {handler.sendEmptyMessage(2);isFinish = false;} else {isFinish = true;}break;}m.postScale(scaleRate, scaleRate, mDWidth, mDHeight);setImageMatrix(m);count++;if (count < MAX_COUNT) {handler.sendEmptyMessage(1);isFinish = false;} else {isFinish = true;}break;}}};/*** 循环着旋转,是为了让旋转有一个动画效果。* * @param angle*            :只有1和-1两种值*/private synchronized void circleRotate(Matrix mMatrix, String methodName,float dx, float dy, int angle, int what) {if (what == 1) {count++;if (count < MAX_COUNT) {rotate(mMatrix, MAX_ROTATE_ANGLE / MAX_COUNT * count * angle,dx, dy, methodName);handler.sendEmptyMessage(what);isFinish = false;} else {isFinish = true;}} else if (what == 2) {count--;if (count > 0) {rotate(mMatrix, MAX_ROTATE_ANGLE / MAX_COUNT * count * angle,dx, dy, methodName);handler.sendEmptyMessage(what);isFinish = false;} else {isFinish = true;}}}// 单次角度旋转private synchronized void rotate(Matrix matrix, int angle, float dx,float dy, String methodName) {matrix.set(getImageMatrix());Camera c = new Camera();c.save();if ("rotateX".equals(methodName)) {c.rotateX(angle);} else {c.rotateY(angle);}c.getMatrix(matrix);c.restore();matrix.preTranslate(dx, dy);matrix.postTranslate(-dx, -dy);setImageMatrix(matrix);}@Overridepublic boolean onTouchEvent(MotionEvent event) {int clickX = (int) event.getX();int clickY = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (!isFinish)break;count = 0;if (clickX > mTWidth && clickX < mTWidth * 2 && clickY > mTHeight&& clickY < mTHeight * 2) {// 应该执行缩放操作mCurrtentState = ClickState.SCALE;} else {int dx = clickX - mDWidth;int dy = clickY - mDHeight;if (Math.abs(dx) > Math.abs(dy)) {if (dx > 0) {// 右边下陷mCurrtentState = ClickState.ROTATE_RIGHT;} else {// 左边下陷mCurrtentState = ClickState.ROTATE_LEFT;}} else {if (dy > 0) {// 下边下陷mCurrtentState = ClickState.ROTATE_BOTTOM;} else {// 上边下陷mCurrtentState = ClickState.ROTATE_TOP;}}}handler.sendEmptyMessage(1);break;case MotionEvent.ACTION_UP:handler.sendEmptyMessage(2);break;}return true;}private enum ClickState {ROTATE_LEFT, ROTATE_RIGHT, ROTATE_TOP, ROTATE_BOTTOM, SCALE}
}


这篇关于Matrix与graphics.Camera的使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/987264

相关文章

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景