【4858美高梅】WebGL编制程序指南,js对几何转变的简约包装

By admin in 4858美高梅 on 2019年5月4日

一、前言

转自:

要是是涉及到游戏或动画的编制程序,大家很恐怕会用到几何调换。假诺在大学过线性代数的话,我们就能够知晓,无论是贰d大概三d的几何调换,矩阵都是兑现线性别变化换的2个关键工具。大4线性别变化换都得以用矩阵表示为便于计算的1致情势,并且多少个转移也可以很轻松地通过矩阵的相乘连接在一块儿。本小说首要对如下的退换实行轻易的卷入,并简要演说个中的调换原理:
  壹.平移转变:只改换图形的岗位,不更动大小。
  2.旋转换换:保持图形各部分之间的涉嫌,转换后形状不改变。
  三.比例转换:可转移图形大小和形制。
  4.错切转换:引起图形角度关系的转移,以致招致图形发生畸变。
  伍.对称调换:使图形对称于x轴或y轴或y=x或y=-x的转变。
 
  程序中,我们将概念二个矩阵类Matrix,在那之中的matrix属性保存以2维数组表示的矩阵方式,当大家伊始化矩阵对象时,须要传入该矩阵的现实性数据:
  
 
                var mtx= new matrix({
                    matrix:[
                       [1,0,0],
                       [0,1,0],
                       [0,0,1]
                    ]
                });
 
  由于在改动进度中要求用到矩阵操作的片段通用方法,因而我们得以先在矩阵类中丰盛这个实例方法:
 
            /**
            *矩阵相加
            **/
            add:function(mtx){
                var omtx=this.matrix;
                var newMtx=[];
               
if(!mtx.length||!mtx[0].length||mtx.length!=omtx.length||mtx[0].length!=omtx[0].length){//假设矩阵为空,或行或列不等于,则赶回
                    return;
                }
                for(var i=0,len1=omtx.length;i<len1;i++){
                    var rowMtx=omtx[i];
                    newMtx.push([]);
                    for(var j=0,len2=rowMtx.length;j<len2;j++){
                        newMtx[i][j]=rowMtx[j]+mtx[i][j]【4858美高梅】WebGL编制程序指南,js对几何转变的简约包装。;
                    }
                }
                this.matrix=newMtx;
                return this;
            },
            /**
            *矩阵相乘
            **/
            multiply:function(mtx){
                var omtx=this.matrix;
                var mtx=mtx.matrix;
                var newMtx=[];
                //和数字相乘
                if(cg.core.isNum(mtx)){
                    for(var i=0,len1=omtx.length;i<len1;i++){
                        var rowMtx=omtx[i];
                        newMtx.push([]);
                        for(var j=0,len2=rowMtx.length;j<len2;j++){
                            omtx[i][j]*=mtx;   
                        }
                    }
                    return new matrix({matrix:newMtx});
                }
                //和矩阵相乘
                var sum=0;
                for(var i=0,len1=omtx.length;i<len1;i++){
                    var rowMtx=omtx[i];   
                    newMtx.push([]);
                    for(var m=0,len3=mtx[0].length;m<len3;m++){
                        for(var j=0,len2=rowMtx.length;j<len2;j++){
                            sum+=omtx[i][j]*mtx[j][m];   
                        }
                        newMtx[newMtx.length-1].push(sum);
                        sum=0;
                    }
                }
                this.matrix=newMtx;
                return this;       
            },
 
  每一种操作完结后,再次回到对象自己,那样的链式调用有利于大家对矩阵张开频仍老是的操作,完毕部分列的图纸转变。
 
二D坐标系下的调换:
  贰d坐标系下,大家运用如下的改动矩阵:

      前几日后续第5章的学习内容,开首学习复合调换的知识。

Matrix的数学原理

4858美高梅 1

 

在Android中,尽管您用Matrix实行过图像处理,那么势必驾驭Matrix这一个类。Android中的Matrix是一个三x 3的矩阵,其内容如下:

个中,左上区域(abde)担负图形的缩放、旋转、对称、错切等转移,cf担当平移调换。

二、正文

4858美高梅 2 

  2d平移:

    
 **
Example一: 复合调换
**

Matrix的对图像的管理可分为四类基本转移:

  使点运动一定位移,大家运用的改造矩阵是:

      
在书中,小编为大家封装了壹套用于转移的矩阵对象:Matrix四对象。它包含以下两种艺术:

Translate           平移调换

 4858美高梅 3

  1. Matrix四.setIdentity():
    将Matrix四实例化为单位矩阵
  2. Matrix肆.setTranslate(x,y,z):
    将Matrix四实例设置为平移调换矩阵,在x轴平移距离为x,在y轴平移距离为y,在z轴平移距离为z;

  3. Matrix四.setScale(x,y,z):
    将Matrix四实例设置为缩放转变矩阵,缩放因子分别为x,y,z;

  4. Matrix四.setRotate(angle,x,y,z):
    将Matrix4实例设置为旋转变换矩阵,角度为angle,旋转轴为(x,y,z);
  5. Matrix四.translate(x,y,z):
    将Matrix四实例本身乘以三个平移转换矩阵;
  6. Matrix肆.rototate(angle,x,y,z):
    将Matrix四实例本人乘以一个旋调换换矩阵;
  7. Matrix肆.scale(x,y,z): 将Matrix4实例本人乘以一个缩放转变矩阵;
  8. Matrix4.set(m): 将Matrix4设置为m;
  9. Matrix4.elements:
    类型化数组包括了Matrix四实例的矩阵成分;

    var modelMatrix = new Matrix4();
    modelMatrix.setRotate(ANGLE,0,0,1);
    modelMatrix.translate(Tx,0,0);

    … …

    gl.uniformMatrix4fv(u_ModelMatrix,false,modelMatrix.elements);

Rotate                旋调换换

 

 

Scale                  缩放转变

使x,y点平移Tx,Ty的位移,则使[x,y,1]矩阵与地点的矩阵相乘,具体的卷入如下:

         Example2:
动画

Skew                  错切转变

            /**
            *2d平移
            **/
            translate2D:function(x,y){
                var changeMtx= new matrix({
                    matrix:[
                       [1,0,0],
                       [0,1,0],
                       [x,y,1]
                    ]
                });
                return this.multiply(changeMtx);
            },
  2d缩放:

 requestAnimationFrame(func):
请求浏览器在现在某时刻回调函数func以达成重绘。大家相应在回调函数最终重复发起该请求。

 

  2d坐标轴下以原点为参考试的地方时,缩放调换使用的调换矩阵如下:

var tick = function() {
    currentAngle = animate(currentAngle);  // Update the rotation angle
    draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix);   // Draw the triangle
    requestAnimationFrame(tick, canvas); // Request that the browser calls tick
};
tick();

从字面上明白,矩阵中的MSCALE用于拍卖缩放转换,MSKEW用于拍卖错切调换,MTRANS用于拍卖平移调换,MPE普拉多SP用于拍卖透视转换。实际中自然不能够完全依据字面上的传道去通晓Matrix。同时,在Android的文书档案中,未见到用Matrix实行透视调换的连带认证,所以本文也不商讨那地点的主题材料。

 4858美高梅 4

 

 

 

由于浏览器试行Tick()的时光是不可控的,大家要求让三角匀速的旋转,那么就要求调节时间:

本着每一种调换,Android提供了pre、set和post二种操作办法。在那之中

使[x,y,1]矩阵与地点的矩阵相乘,则可得出相对于原点缩放后的坐标值。

var g_last = Date.now();
function animate(angle) {
  // Calculate the elapsed time
  var now = Date.now();
  var elapsed = now - g_last;
  g_last = now;
  // Update the current rotation angle (adjusted by the elapsed time)
  var newAngle = angle + ANGLE_STEP * (elapsed / 1000.0);
  return newAngle %= 360;
}

set用于安装Matrix中的值。

  然而洋洋状态下,大家恐怕供给相对于任性点进行缩放而不单单限制于相对于原点的缩放,因而大家那边最佳封装相对于坐标轴上放肆点的缩放方法。相对于任性点的缩放其实也是由相对于原点的缩放转换而来,相对于点(x一,y一)的缩放总结具体步骤如下:

 

pre是先乘,因为矩阵的乘法不满足交流律,由此先乘、后乘必须求严加分裂。先乘相当于矩阵运算中的右乘。

  把坐标原点平移至(x1,y一)–>举行相对于原点的调换–>把坐标原点平移回去

三、结尾

post是后乘,因为矩阵的乘法不满足调换律,由此先乘、后乘必供给严峻区分。后乘约等于矩阵运算中的左乘。

  矩阵总计:

     下一周6继续立异第四章。

 

 4858美高梅 5

除平移转换(Translate)外,旋调换换(Rotate)、缩放转换(Scale)和错切调换(Skew)都得以围绕3个着力点来进展,假设不钦定,在暗中同意情形下是环绕(0,
0)来张开相应的调换的。

 

 

因而对任性点缩放的办法封装如下:

下边大家来看望多样转移的切切实实际情形形。由于具备的图片都以有点构成,因而大家只必要观望3个点有关调换就可以。

            /**
            *2d缩放
            **/               
            scale2D:function(scale,point){//缩放比,参考点
                var
sx=scale[0],sy=scale[1],x=point[0],y=point[1];

 

                var changeMtx= new matrix({
                    matrix:[
                       [sx,0,0],
                       [0,sy,0],
                       [(1-sx)*x,(1-sy)*y,1]
                    ]
                });   
                return this.multiply(changeMtx);               
               
            },
  二d对称转换:

1、 平移调换

  二d对称调换使用的调换矩阵如下:

若果有一个点的坐标是4858美高梅 6 ,将其活动到4858美高梅 7 ,再假定在x轴和y轴方向活动的大小分别为:

 4858美高梅 8

4858美高梅 9

 

一般来说图所示:

分裂的相得益彰调换,通过abde的值的改造来兑现:

4858美高梅 10

    绝对于x轴的调换:b=d=0 a=一 e=-一

十拿九稳通晓:

    相对于y轴的转变:b=d=0 a=-1 e=1

4858美高梅 11

    相对于原点的转移:b=d=0 a=-1 e=-一

假使用矩阵来表示的话,就能够写成:

    相对于y=x的变换:b=d=1 a=e=0

4858美高梅 12 

    现对于y=-x的变换:b=d=-1 a=e=0

 

  由此乘以分裂的转变矩阵,就足以得到差别的转变效果:

2、 旋转换换

            /**
            *贰d对称调换
            **/                   
            symmet2D:function(axis){//对称轴
                var changeMtx;
                axis==”x”&&(changeMtx= new matrix({//相对于x轴对称
                    matrix:[
                       [1,0,0],
                       [0,-1,0],
                       [0,0,1]
                    ]
                }));               
                axis==”y”&&(changeMtx= new matrix({//相对于y轴对称
                    matrix:[
                       [-1,0,0],
                       [0,1,0],
                       [0,0,1]
                    ]
                }));   
                axis==”xy”&&(changeMtx= new matrix({//相对于原点对称
                    matrix:[
                       [-1,0,0],
                       [0,-1,0],
                       [0,0,1]
                    ]
                }));   
                axis==”y=x”&&(changeMtx= new matrix({//相对于y=x对称
                    matrix:[
                       [0,1,0],
                       [1,0,0],
                       [0,0,1]
                    ]
                }));   
                axis==”y=-x”&&(changeMtx= new matrix({//相对于y=-x对称
                    matrix:[
                       [0,-1,0],
                       [-1,0,0],
                       [0,0,1]
                    ]
                }));
                return this.multiply(changeMtx);               
            },
  二d错切转换:

 

  所谓的错切转换,正是图片产生倾斜等的失真,举个例子下图中分别是x方向和y方向下的错切调换:

二.一    围绕坐标原点旋转:

    
  4858美高梅 13
  错切调换下的改造矩阵为:
  4858美高梅 14
  [x,y]转变后的坐标为:[x+by,dx+y,1],能够看出,当b不为0,d为0时,y值不改变,x轴依照b的值作线性增进,由此得以汲取上边的a图。当b为0,d不为0时,x值不改变,y轴依照d的值作线性拉长,由此得以汲取下面的b图。
  错切转变的卷入:
 

如果有2个点4858美高梅 15 ,相对坐标原点顺时针旋转4858美高梅 16后的图景,同时假设P点离坐标原点的偏离为r,如下图:

 /**
            *贰d错切调换
            **/               
            shear2D:function(kx,ky){
                var changeMtx= new matrix({
                    matrix:[
                       [1,kx,0],
                       [ky,1,0],
                       [0,0,1]
                    ]
                });   
                return this.multiply(changeMtx);
            },
  2d旋变换换:

4858美高梅 17

  旋转变换和缩放转变同样,一样有相对于原点调换和对峙于放4点调换那三种景况,由此这里也直接封装相对于放肆点转换的法子。

那么,

  相对于任性点(x1,y一)旋转=把坐标原点平移到(x1,y一)–>相对于原点旋转
–>把原点平移回去

4858美高梅 18

  相对于原点的旋转换换矩阵为:

1旦用矩阵,就足以代表为:

    4858美高梅 19
  由此相对于任意点旋转的调换矩阵为:
  
  4858美高梅 20
  所以封装方法如下:
 

4858美高梅 21

 

 

  /**
            *2d旋转
            **/           
            rotate2D:function(angle,point){
                var x=point[0],y=point[1];
                var cos=Math.cos;
                var sin=Math.sin;
                var changeMtx= new matrix({
                    matrix:[
                       [cos(angle),sin(angle),0],
                       [-sin(angle),cos(angle),0],
                      
[(1-cos(angle))*x+y*sin(angle),(1-cos(angle))*y-x*sin(angle),1]
                    ]
                });   
                return this.multiply(changeMtx);
            },
  

二.二    围绕有些点旋转

  由于3D坐标轴下的调换和贰D坐标轴下的尚未太大差异,所以那边就不作详述,上边包车型地铁欧洲经济共同体源码也隐含了三d坐标轴下几何转换的部分,感兴趣的童鞋也得以看看~

万一是围绕有些点4858美高梅 22顺时针旋转4858美高梅 23,那么能够用矩阵表示为:

 

4858美高梅 24

  其它大家可能会认为dom或canvas的条件下,并不存在真正意义上的z坐标,由此3d坐标轴下的几何转换并未多大要义。其实,就算达成持续真正意义上的3D,不过得以达成伪3D照旧得以的,视觉上,大家能够把成分z轴的坐标值通过xy的坐标值以及成分尺寸的变动来代表,关于那方面包车型客车始末能够参考hongru的rotate3D类别小说。

能够成为:

 

4858美高梅 25

  最后提供全数源码(包蕴3D坐标轴下的几何转变部分):

很显然,

View Code

1.   

    /**
    *
    *矩阵 www.2cto.com
    *
    **/
    cnGame.register(“cnGame”, function(cg) {
        var matrix=function(options){
            if (!(this instanceof arguments.callee)) {
                return new arguments.callee(options);
            }
            this.init(options);
        };
        matrix.prototype={
            /**
            *初始化
            **/           
            init:function(options){
                this.matrix=[];
                this.setOptions(options);
            },
            /**
            *设置参数
            **/
            setOptions: function(options) {
                cg.core.extend(this, options);
            },
            /**
            *矩阵相加
            **/
            add:function(mtx){
                var omtx=this.matrix;
                var newMtx=[];
               
if(!mtx.length||!mtx[0].length||mtx.length!=omtx.length||mtx[0].length!=omtx[0].length){//假设矩阵为空,或行或列不等于,则赶回
                    return;
                }
                for(var i=0,len1=omtx.length;i<len1;i++){
                    var rowMtx=omtx[i];
                    newMtx.push([]);
                    for(var j=0,len2=rowMtx.length;j<len2;j++){
                        newMtx[i][j]=rowMtx[j]+mtx[i][j];
                    }
                }
                this.matrix=newMtx;
                return this;
            },
            /**
            *矩阵相乘
            **/
            multiply:function(mtx){
                var omtx=this.matrix;
                var mtx=mtx.matrix;
                var newMtx=[];
                //和数字相乘
                if(cg.core.isNum(mtx)){
                    for(var i=0,len1=omtx.length;i<len1;i++){
                        var rowMtx=omtx[i];
                        newMtx.push([]);
                        for(var j=0,len2=rowMtx.length;j<len2;j++){
                            omtx[i][j]*=mtx;   
                        }
                    }
                    return new matrix({matrix:newMtx});
                }
                //和矩阵相乘
                var sum=0;
                for(var i=0,len1=omtx.length;i<len1;i++){
                    var rowMtx=omtx[i];   
                    newMtx.push([]);
                    for(var m=0,len3=mtx[0].length;m<len3;m++){
                        for(var j=0,len2=rowMtx.length;j<len2;j++){
                            sum+=omtx[i][j]*mtx[j][m];   
                        }
                        newMtx[newMtx.length-1].push(sum);
                        sum=0;
                    }
                }
                this.matrix=newMtx;
                return this;       
            },
            /**
            *2d平移
            **/
            translate2D:function(x,y){
                var changeMtx= new matrix({
                    matrix:[
                       [1,0,0],
                       [0,1,0],
                       [x,y,1]
                    ]
                });
                return this.multiply(changeMtx);
            },
            /**
            *2d缩放
            **/               
            scale2D:function(scale,point){//缩放比,参考点
                var
sx=scale[0],sy=scale[1],x=point[0],y=point[1];

  4858美高梅 26是将坐标原点移动到点4858美高梅 27后,4858美高梅 28 的新坐标。

                var changeMtx= new matrix({
                    matrix:[
                       [sx,0,0],
                       [0,sy,0],
                       [(1-sx)*x,(1-sy)*y,1]
                    ]
                });   
                return this.multiply(changeMtx);               
               
            },
            /**
            *2d对称调换
            **/                   
            symmet2D:function(axis){//对称轴
                var changeMtx;
                axis==”x”&&(changeMtx= new matrix({//相对于x轴对称
                    matrix:[
                       [1,0,0],
                       [0,-1,0],
                       [0,0,1]
                    ]
                }));               
                axis==”y”&&(changeMtx= new matrix({//相对于y轴对称
                    matrix:[
                       [-1,0,0],
                       [0,1,0],
                       [0,0,1]
                    ]
                }));   
                axis==”xy”&&(changeMtx= new matrix({//相对于原点对称
                    matrix:[
                       [-1,0,0],
                       [0,-1,0],
                       [0,0,1]
                    ]
                }));   
                axis==”y=x”&&(changeMtx= new matrix({//相对于y=x对称
                    matrix:[
                       [0,1,0],
                       [1,0,0],
                       [0,0,1]
                    ]
                }));   
                axis==”y=-x”&&(changeMtx= new matrix({//相对于y=-x对称
                    matrix:[
                       [0,-1,0],
                       [-1,0,0],
                       [0,0,1]
                    ]
                }));
                return this.multiply(changeMtx);               
            },
            /**
            *2d错切转换
            **/               
            shear2D:function(kx,ky){
                var changeMtx= new matrix({
                    matrix:[
                       [4858美高梅 ,1,kx,0],
                       [ky,1,0],
                       [0,0,1]
                    ]
                });   
                return this.multiply(changeMtx);
            },
            /**
            *2d旋转
            **/           
            rotate2D:function(angle,point){
                var x=point[0],y=point[1];
                var cos=Math.cos;
                var sin=Math.sin;
                var changeMtx= new matrix({
                    matrix:[
                       [cos(angle),sin(angle),0],
                       [-sin(angle),cos(angle),0],
                      
[(1-cos(angle))*x+y*sin(angle),(1-cos(angle))*y-x*sin(angle),1]
                    ]
                });   
                return this.multiply(changeMtx);
            },
            /**
            *3d平移
            **/
            translate3D:function(x,y,z){
                var changeMtx= new matrix({
                    matrix:[
                       [1,0,0,0],
                       [0,1,0,0],
                       [0,0,1,0],
                       [x,y,z,1]
                    ]
                });
                return this.multiply(changeMtx);
            },
            /**
            *3d缩放
            **/               
            scale3D:function(scale,point){//缩放比数组,参考试的场地数组
                var
sx=scale[0],sy=scale[1],sz=scale[2],x=point[0],y=point[1],z=point[2];           
                var changeMtx= new matrix({
                    matrix:[
                       [sx,0,0,0],
                       [0,sy,0,0],
                       [0,0,sz,0],
                       [(1-sx)*x,(1-sy)*y,(1-sz)*z,1]
                    ]
                });   
                return this.multiply(changeMtx);               
               
            },           
            /**
            *3d旋转
            **/           
            rotate3D:function(angle,axis){
                var cos=Math.cos;
                var sin=Math.sin;
                var changeMtx;

2.     

                axis==”x”&&(changeMtx=new matrix({
                                matrix:[
                                   [1,0,0,0],
                                   [0,cos(angle),sin(angle),0],
                                   [0,-sin(angle),cos(angle),0],
                                   [0,0,0,1]
                                ]
                            }));   

4858美高梅 29

                axis==”y”&&(changeMtx=new matrix({
                                matrix:[
                                   [cos(angle),0,-sin(angle),0],
                                   [0,1,0,0],
                                   [sin(angle),0,cos(angle),0],
                                   [0,0,0,1]
                                ]
                            }));                       
                axis==”z”&&(changeMtx=new matrix({
                                matrix:[
                                   [cos(angle),sin(angle),0,0],
                                   [-sin(angle),cos(angle),0,0],
                                   [0,0,1,0],
                                   [0,0,0,1]
                                ]
                            }));                                   
                return this.multiply(changeMtx);
            },           
        };
        this.Matrix=matrix;
    });
   
 

是将上一步调换后的4858美高梅 30,围绕新的坐标原点顺时针旋转4858美高梅 31 。

 参考资料:计算机图形学

3.     

 

4858美高梅 32

摘自 Cson’s Room

经过上一步旋调换换后,再将坐标原点移回到原来的坐标原点。

 

故此,围绕某一点开始展览旋调换换,可以分为三个步骤,即首先将坐标原点移至该点,然后围绕新的坐标原点实行旋转换换,再然后将坐标原点移回到原来的坐标原点。

 

3、 缩放转换

辩驳上来说,三个点是不设有怎么样缩放转换的,但考虑到持有图像都是由点组成,因而,借使图像在x轴和y轴方向分别放大k1k2倍的话,那么图像中的全部点的x坐标和y坐标均会独家放大k1k2倍,即

4858美高梅 33

用矩阵表示正是:

4858美高梅 34

缩放转变相比好理解,就不多说了。

 

肆、 错切变换

错切调换(skew)在数学上又称为Shear
mapping(可译为“剪切转变”)也许Transvection(缩并),它是一种相比特殊的线性别变化换。错切转换的功力就是让全部点的x坐标(或者y坐标)保持不改变,而相应的y坐标(或者x坐标)则按百分比爆发位移,且活动的轻重缓急和该点到x轴(或y轴)的垂直距离成正比。错切调换,属于等面积变换,即贰个造型在错切转换的光景,其面积是非常的。

比方下图,各点的y坐标保持不变,但其x坐标则按百分比发生了活动。那种境况将水平错切。

4858美高梅 35

下图各点的x坐标保持不变,但其y坐标则按比例发生了移动。那种情形叫垂直错切。

4858美高梅 36 

万13个点4858美高梅 37通过错切转变后收获4858美高梅 38,对于水平错切来讲,应该有如下事关:

4858美高梅 39

用矩阵表示正是:

4858美高梅 40

增加到叁 x 叁的矩阵正是底下那样的款式:

4858美高梅 41 

同理,对于垂直错切,能够有:

4858美高梅 42

在数学上严苛的错切转变便是上面那样的。在Android中除了有上边谈起的情状外,还足以而且进行水平、垂直错切,那么方式上正是:

4858美高梅 43

 

伍、 对称转变

除此之外上面讲到的4中基本转移外,事实上,大家仍是能够运用Matrix,实行对称转变。所谓对称转换,正是经过变化后的图像和原图像是关于某些对称轴是对称的。例如,某点4858美高梅 44 经过对称调换后收获4858美高梅 45

万一对称轴是x轴,难么,

4858美高梅 46

用矩阵表示正是:

4858美高梅 47

若果对称轴是y轴,那么,

4858美高梅 48

用矩阵表示就是:

4858美高梅 49

倘诺对称轴是y = x,如图:

4858美高梅 50

那么,

4858美高梅 51

很轻巧能够解得:

4858美高梅 52

用矩阵表示正是:

4858美高梅 53

同等的道理,倘使对称轴是y = -x,那么用矩阵表示便是:

4858美高梅 54 

卓殊地,要是对称轴是y = kx,如下图:

4858美高梅 55

那么,

4858美高梅 56

很轻巧可解得:

4858美高梅 57

用矩阵表示正是:

4858美高梅 58

k = 0时,即y =
0
,也便是对称轴为x轴的事态;当k趋于无穷大时,即x =
0
,也正是对称轴为y轴的地方;当k =1时,即y = x,也正是对称轴为y =
x
的情况;当k = –1时,即y = -x,也正是对称轴为y =
-x
的处境。轻松验证,那和我们前面聊起的四中具体境况是相适合的。

 

只要对称轴是y = kx +
b
那般的景况,只需求在地点的基础上增添一次平移转变就可以,即先将坐标原点移动到(0,
b
),然后做地点的有关y =
kx
的对称转换,再然后将坐标原点移回到原来的坐标原点就可以。用矩阵表示大致是这么的:

4858美高梅 59

内需尤其注意:在骨子里编制程序中,大家领会显示屏的y坐标的正向和数学中y坐标的正向刚好是倒转的,所以在数学上y
= x
和显示屏上的y =
-x
才是的确的同3个事物,反之亦然。也正是说,固然要使图片在显示屏上看起来像依据数学意义上y
= x
对称,那么需采取那种转移:

4858美高梅 60

要使图片在显示器上看起来像依据数学意义上y =
-x
对称,那么需使用那种转移:
4858美高梅 61 

有关对称轴为y = kx y = kx + b的图景,一样必要思虑那方面包车型客车标题。

第一有个别 代码验证

在率先部分中讲到的各样图像转换的认证代码如下,壹共列出了拾种景况。借使要申明个中的某一种情况,只需将相应的代码反注释就能够。试验中用到的图片:

4858美高梅 62

其尺寸为16贰 x 25一。

4858美高梅 63

其尺寸为16贰 x 251。

  1 <pre name="code" class="java">package com.pat.testtransformmatrix;  
  2   
  3 import android.app.Activity;  
  4 import android.content.Context;  
  5 import android.graphics.Bitmap;  
  6 import android.graphics.BitmapFactory;  
  7 import android.graphics.Canvas;  
  8 import android.graphics.Matrix;  
  9 import android.os.Bundle;  
 10 import android.util.Log;  
 11 import android.view.MotionEvent;  
 12 import android.view.View;  
 13 import android.view.Window;  
 14 import android.view.WindowManager;  
 15 import android.view.View.OnTouchListener;  
 16 import android.widget.ImageView;  
 17   
 18 public class TestTransformMatrixActivity extends Activity  
 19 implements  
 20 OnTouchListener  
 21 {  
 22     private TransformMatrixView view;  
 23     @Override  
 24     public void onCreate(Bundle savedInstanceState)  
 25     {  
 26         super.onCreate(savedInstanceState);  
 27         requestWindowFeature(Window.FEATURE_NO_TITLE);  
 28         this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);  
 29   
 30         view = new TransformMatrixView(this);  
 31         view.setScaleType(ImageView.ScaleType.MATRIX);  
 32         view.setOnTouchListener(this);  
 33           
 34         setContentView(view);  
 35     }  
 36       
 37     class TransformMatrixView extends ImageView  
 38     {  
 39         private Bitmap bitmap;  
 40         private Matrix matrix;  
 41         public TransformMatrixView(Context context)  
 42         {  
 43             super(context);  
 44             bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sophie);  
 45             matrix = new Matrix();  
 46         }  
 47   
 48         @Override  
 49         protected void onDraw(Canvas canvas)  
 50         {  
 51             // 画出原图像  
 52             canvas.drawBitmap(bitmap, 0, 0, null);  
 53             // 画出变换后的图像  
 54             canvas.drawBitmap(bitmap, matrix, null);  
 55             super.onDraw(canvas);  
 56         }  
 57   
 58         @Override  
 59         public void setImageMatrix(Matrix matrix)  
 60         {  
 61             this.matrix.set(matrix);  
 62             super.setImageMatrix(matrix);  
 63         }  
 64           
 65         public Bitmap getImageBitmap()  
 66         {  
 67             return bitmap;  
 68         }  
 69     }  
 70   
 71     public boolean onTouch(View v, MotionEvent e)  
 72     {  
 73         if(e.getAction() == MotionEvent.ACTION_UP)  
 74         {  
 75             Matrix matrix = new Matrix();  
 76             // 输出图像的宽度和高度(162 x 251)  
 77             Log.e("TestTransformMatrixActivity", "image size: width x height = " +  view.getImageBitmap().getWidth() + " x " + view.getImageBitmap().getHeight());  
 78             // 1. 平移  
 79             matrix.postTranslate(view.getImageBitmap().getWidth(), view.getImageBitmap().getHeight());  
 80             // 在x方向平移view.getImageBitmap().getWidth(),在y轴方向view.getImageBitmap().getHeight()  
 81             view.setImageMatrix(matrix);  
 82               
 83             // 下面的代码是为了查看matrix中的元素  
 84             float[] matrixValues = new float[9];  
 85             matrix.getValues(matrixValues);  
 86             for(int i = 0; i < 3; ++i)  
 87             {  
 88                 String temp = new String();  
 89                 for(int j = 0; j < 3; ++j)  
 90                 {  
 91                     temp += matrixValues[3 * i + j ] + "\t";  
 92                 }  
 93                 Log.e("TestTransformMatrixActivity", temp);  
 94             }  
 95               
 96   
 97 //          // 2. 旋转(围绕图像的中心点)  
 98 //          matrix.setRotate(45f, view.getImageBitmap().getWidth() / 2f, view.getImageBitmap().getHeight() / 2f);  
 99 //            
100 //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠  
101 //          matrix.postTranslate(view.getImageBitmap().getWidth() * 1.5f, 0f);  
102 //          view.setImageMatrix(matrix);  
103 //  
104 //          // 下面的代码是为了查看matrix中的元素  
105 //          float[] matrixValues = new float[9];  
106 //          matrix.getValues(matrixValues);  
107 //          for(int i = 0; i < 3; ++i)  
108 //          {  
109 //              String temp = new String();  
110 //              for(int j = 0; j < 3; ++j)  
111 //              {  
112 //                  temp += matrixValues[3 * i + j ] + "\t";  
113 //              }  
114 //              Log.e("TestTransformMatrixActivity", temp);  
115 //          }  
116               
117               
118 //          // 3. 旋转(围绕坐标原点) + 平移(效果同2)  
119 //          matrix.setRotate(45f);  
120 //          matrix.preTranslate(-1f * view.getImageBitmap().getWidth() / 2f, -1f * view.getImageBitmap().getHeight() / 2f);  
121 //          matrix.postTranslate((float)view.getImageBitmap().getWidth() / 2f, (float)view.getImageBitmap().getHeight() / 2f);  
122 //            
123 //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠  
124 //          matrix.postTranslate((float)view.getImageBitmap().getWidth() * 1.5f, 0f);  
125 //          view.setImageMatrix(matrix);  
126 //            
127 //          // 下面的代码是为了查看matrix中的元素  
128 //          float[] matrixValues = new float[9];  
129 //          matrix.getValues(matrixValues);  
130 //          for(int i = 0; i < 3; ++i)  
131 //          {  
132 //              String temp = new String();  
133 //              for(int j = 0; j < 3; ++j)  
134 //              {  
135 //                  temp += matrixValues[3 * i + j ] + "\t";  
136 //              }  
137 //              Log.e("TestTransformMatrixActivity", temp);  
138 //          }             
139               
140 //          // 4. 缩放  
141 //          matrix.setScale(2f, 2f);  
142 //          // 下面的代码是为了查看matrix中的元素  
143 //          float[] matrixValues = new float[9];  
144 //          matrix.getValues(matrixValues);  
145 //          for(int i = 0; i < 3; ++i)  
146 //          {  
147 //              String temp = new String();  
148 //              for(int j = 0; j < 3; ++j)  
149 //              {  
150 //                  temp += matrixValues[3 * i + j ] + "\t";  
151 //              }  
152 //              Log.e("TestTransformMatrixActivity", temp);  
153 //          }  
154 //            
155 //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠  
156 //          matrix.postTranslate(view.getImageBitmap().getWidth(), view.getImageBitmap().getHeight());  
157 //          view.setImageMatrix(matrix);  
158 //            
159 //          // 下面的代码是为了查看matrix中的元素  
160 //          matrixValues = new float[9];  
161 //          matrix.getValues(matrixValues);  
162 //          for(int i = 0; i < 3; ++i)  
163 //          {  
164 //              String temp = new String();  
165 //              for(int j = 0; j < 3; ++j)  
166 //              {  
167 //                  temp += matrixValues[3 * i + j ] + "\t";  
168 //              }  
169 //              Log.e("TestTransformMatrixActivity", temp);  
170 //          }  
171   
172               
173 //          // 5. 错切 - 水平  
174 //          matrix.setSkew(0.5f, 0f);  
175 //          // 下面的代码是为了查看matrix中的元素  
176 //          float[] matrixValues = new float[9];  
177 //          matrix.getValues(matrixValues);  
178 //          for(int i = 0; i < 3; ++i)  
179 //          {  
180 //              String temp = new String();  
181 //              for(int j = 0; j < 3; ++j)  
182 //              {  
183 //                  temp += matrixValues[3 * i + j ] + "\t";  
184 //              }  
185 //              Log.e("TestTransformMatrixActivity", temp);  
186 //          }  
187 //            
188 //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠           
189 //          matrix.postTranslate(view.getImageBitmap().getWidth(), 0f);  
190 //          view.setImageMatrix(matrix);  
191 //            
192 //          // 下面的代码是为了查看matrix中的元素  
193 //          matrixValues = new float[9];  
194 //          matrix.getValues(matrixValues);  
195 //          for(int i = 0; i < 3; ++i)  
196 //          {  
197 //              String temp = new String();  
198 //              for(int j = 0; j < 3; ++j)  
199 //              {  
200 //                  temp += matrixValues[3 * i + j ] + "\t";  
201 //              }  
202 //              Log.e("TestTransformMatrixActivity", temp);  
203 //          }  
204               
205 //          // 6. 错切 - 垂直  
206 //          matrix.setSkew(0f, 0.5f);  
207 //          // 下面的代码是为了查看matrix中的元素  
208 //          float[] matrixValues = new float[9];  
209 //          matrix.getValues(matrixValues);  
210 //          for(int i = 0; i < 3; ++i)  
211 //          {  
212 //              String temp = new String();  
213 //              for(int j = 0; j < 3; ++j)  
214 //              {  
215 //                  temp += matrixValues[3 * i + j ] + "\t";  
216 //              }  
217 //              Log.e("TestTransformMatrixActivity", temp);  
218 //          }  
219 //            
220 //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠               
221 //          matrix.postTranslate(0f, view.getImageBitmap().getHeight());  
222 //          view.setImageMatrix(matrix);  
223 //            
224 //          // 下面的代码是为了查看matrix中的元素  
225 //          matrixValues = new float[9];  
226 //          matrix.getValues(matrixValues);  
227 //          for(int i = 0; i < 3; ++i)  
228 //          {  
229 //              String temp = new String();  
230 //              for(int j = 0; j < 3; ++j)  
231 //              {  
232 //                  temp += matrixValues[3 * i + j ] + "\t";  
233 //              }  
234 //              Log.e("TestTransformMatrixActivity", temp);  
235 //          }             
236               
237 //          7. 错切 - 水平 + 垂直  
238 //          matrix.setSkew(0.5f, 0.5f);  
239 //          // 下面的代码是为了查看matrix中的元素  
240 //          float[] matrixValues = new float[9];  
241 //          matrix.getValues(matrixValues);  
242 //          for(int i = 0; i < 3; ++i)  
243 //          {  
244 //              String temp = new String();  
245 //              for(int j = 0; j < 3; ++j)  
246 //              {  
247 //                  temp += matrixValues[3 * i + j ] + "\t";  
248 //              }  
249 //              Log.e("TestTransformMatrixActivity", temp);  
250 //          }  
251 //            
252 //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠               
253 //          matrix.postTranslate(0f, view.getImageBitmap().getHeight());  
254 //          view.setImageMatrix(matrix);  
255 //            
256 //          // 下面的代码是为了查看matrix中的元素  
257 //          matrixValues = new float[9];  
258 //          matrix.getValues(matrixValues);  
259 //          for(int i = 0; i < 3; ++i)  
260 //          {  
261 //              String temp = new String();  
262 //              for(int j = 0; j < 3; ++j)  
263 //              {  
264 //                  temp += matrixValues[3 * i + j ] + "\t";  
265 //              }  
266 //              Log.e("TestTransformMatrixActivity", temp);  
267 //          }  
268               
269 //          // 8. 对称 (水平对称)  
270 //          float matrix_values[] = {1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f};  
271 //          matrix.setValues(matrix_values);  
272 //          // 下面的代码是为了查看matrix中的元素  
273 //          float[] matrixValues = new float[9];  
274 //          matrix.getValues(matrixValues);  
275 //          for(int i = 0; i < 3; ++i)  
276 //          {  
277 //              String temp = new String();  
278 //              for(int j = 0; j < 3; ++j)  
279 //              {  
280 //                  temp += matrixValues[3 * i + j ] + "\t";  
281 //              }  
282 //              Log.e("TestTransformMatrixActivity", temp);  
283 //          }  
284 //            
285 //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠   
286 //          matrix.postTranslate(0f, view.getImageBitmap().getHeight() * 2f);  
287 //          view.setImageMatrix(matrix);  
288 //            
289 //          // 下面的代码是为了查看matrix中的元素  
290 //          matrixValues = new float[9];  
291 //          matrix.getValues(matrixValues);  
292 //          for(int i = 0; i < 3; ++i)  
293 //          {  
294 //              String temp = new String();  
295 //              for(int j = 0; j < 3; ++j)  
296 //              {  
297 //                  temp += matrixValues[3 * i + j ] + "\t";  
298 //              }  
299 //              Log.e("TestTransformMatrixActivity", temp);  
300 //          }             
301               
302 //          // 9. 对称 - 垂直  
303 //          float matrix_values[] = {-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f};  
304 //          matrix.setValues(matrix_values);  
305 //          // 下面的代码是为了查看matrix中的元素  
306 //          float[] matrixValues = new float[9];  
307 //          matrix.getValues(matrixValues);  
308 //          for(int i = 0; i < 3; ++i)  
309 //          {  
310 //              String temp = new String();  
311 //              for(int j = 0; j < 3; ++j)  
312 //              {  
313 //                  temp += matrixValues[3 * i + j ] + "\t";  
314 //              }  
315 //              Log.e("TestTransformMatrixActivity", temp);  
316 //          }     
317 //            
318 //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠   
319 //          matrix.postTranslate(view.getImageBitmap().getWidth() * 2f, 0f);  
320 //          view.setImageMatrix(matrix);  
321 //            
322 //          // 下面的代码是为了查看matrix中的元素  
323 //          matrixValues = new float[9];  
324 //          matrix.getValues(matrixValues);  
325 //          for(int i = 0; i < 3; ++i)  
326 //          {  
327 //              String temp = new String();  
328 //              for(int j = 0; j < 3; ++j)  
329 //              {  
330 //                  temp += matrixValues[3 * i + j ] + "\t";  
331 //              }  
332 //              Log.e("TestTransformMatrixActivity", temp);  
333 //          }  
334   
335               
336 //          // 10. 对称(对称轴为直线y = x)  
337 //          float matrix_values[] = {0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f};  
338 //          matrix.setValues(matrix_values);  
339 //          // 下面的代码是为了查看matrix中的元素  
340 //          float[] matrixValues = new float[9];  
341 //          matrix.getValues(matrixValues);  
342 //          for(int i = 0; i < 3; ++i)  
343 //          {  
344 //              String temp = new String();  
345 //              for(int j = 0; j < 3; ++j)  
346 //              {  
347 //                  temp += matrixValues[3 * i + j ] + "\t";  
348 //              }  
349 //              Log.e("TestTransformMatrixActivity", temp);  
350 //          }  
351 //            
352 //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠               
353 //          matrix.postTranslate(view.getImageBitmap().getHeight() + view.getImageBitmap().getWidth(),   
354 //                  view.getImageBitmap().getHeight() + view.getImageBitmap().getWidth());  
355 //          view.setImageMatrix(matrix);  
356 //            
357 //          // 下面的代码是为了查看matrix中的元素  
358 //          matrixValues = new float[9];  
359 //          matrix.getValues(matrixValues);  
360 //          for(int i = 0; i < 3; ++i)  
361 //          {  
362 //              String temp = new String();  
363 //              for(int j = 0; j < 3; ++j)  
364 //              {  
365 //                  temp += matrixValues[3 * i + j ] + "\t";  
366 //              }  
367 //              Log.e("TestTransformMatrixActivity", temp);  
368 //          }  
369               
370             view.invalidate();  
371         }  
372         return true;  
373     }  
374 }  

上面给出上述代码中,各样调换的具体结果及其相应的有关转变矩阵

1.     平移

4858美高梅 64

输出的结果:

4858美高梅 65

请对照第二有的中的“壹、平移变换”所讲的动静,侦察上述矩阵的不利。

 

二.     旋转(围绕图像的大旨点)

4858美高梅 66

出口的结果:

4858美高梅 67

它实质上是

matrix.setRotate(45f,view.getImageBitmap().getWidth() / 2f,
view.getImageBitmap().getHeight() / 2f);

matrix.postTranslate(view.getImageBitmap().getWidth()* 1.5f, 0f);

那两条语句综合功效的结果。依照第二局部中“贰、旋调换换”里面关于围绕某点旋转的公式,

matrix.setRotate(45f,view.getImageBitmap().getWidth() / 2f,
view.getImageBitmap().getHeight() / 2f);

所发出的调换矩阵正是:

4858美高梅 68

而matrix.postTranslate(view.getImageBitmap().getWidth()* 一.5f,
0f);的意趣就是在上述矩阵的右侧再乘以上面包车型客车矩阵:

4858美高梅 69

有关post是左乘那或多或少,大家在前方的争论部分已经聊起过,前边大家还会特地研讨这一个主题材料。

 

为此它事实上就是:

4858美高梅 70

出来总结上的精度引用误差,大家得以看来我们计算出来的结果,和程序直接出口的结果是如出1辙的。

 

三.     旋转(围绕坐标原点旋转,在加上三回活动,效果同二)

4858美高梅 71

依靠第一某在那之中“贰、旋转换换”里面关于围绕某点旋转的分解,简单知道:

matrix.setRotate(45f,view.getImageBitmap().getWidth() / 2f,
view.getImageBitmap().getHeight() / 2f);

等价于

matrix.setRotate(45f);

matrix.preTranslate(-1f* view.getImageBitmap().getWidth() / 2f, -1f
*view.getImageBitmap().getHeight() / 2f);

matrix.postTranslate((float)view.getImageBitmap().getWidth()/ 2f,
(float)view.getImageBitmap().getHeight() / 2f);

 

其间matrix.setRotate(4伍f)对应的矩阵是:

4858美高梅 72

matrix.preTranslate(-1f* view.getImageBitmap().getWidth() / 2f, -1f *
view.getImageBitmap().getHeight()/ 二f)对应的矩阵是:

4858美高梅 73

由于是preTranslate,是先乘,相当于右乘,即它应有出现在matrix.setRotate(45f)所对应矩阵的动手。

 

matrix.postTranslate((float)view.getImageBitmap().getWidth()/ 2f,
(float)view.getImageBitmap().getHeight() / 二f)对应的矩阵是:

4858美高梅 74

本次是因为是postTranslate,是后乘,也正是左乘,即它应当出现在matrix.setRotate(四5f)所对应矩阵的右侧。

 

所以综合起来,

matrix.setRotate(45f);

matrix.preTranslate(-1f* view.getImageBitmap().getWidth() / 2f, -1f
*view.getImageBitmap().getHeight() / 2f);

matrix.postTranslate((float)view.getImageBitmap().getWidth()/ 2f,
(float)view.getImageBitmap().getHeight() / 2f);

相应的矩阵就是:

4858美高梅 75

那和下边这么些矩阵(围绕图像中央顺时针旋转45度)其实是如出一辙的:

4858美高梅 76

之所以,此处转变后的图像和第22中学改动后的图像时一致的。

 

四.     缩放调换

4858美高梅 77

先后所出口的四个矩阵分别是:

4858美高梅 78

其间第三个矩阵,其实是下边多少个矩阵相乘的结果:

4858美高梅 79 

世家能够相比第二片段中的“叁、缩放调换”和“一、平移转换”说法,自行验证结果。

 

5.     错切调换(水平错切)

4858美高梅 80

代码所出口的多个矩阵分别是:

4858美高梅 81

中间,第2个矩阵其实是上面多个矩阵相乘的结果:

 4858美高梅 82

大家能够对照第3有的中的“4、错切调换”和“一、平移转换”的连带说法,自行验证结果。

 

陆.     错切调换(垂直错切)

4858美高梅 83

代码所出口的多少个矩阵分别是:

4858美高梅 84

在那之中,第一个矩阵其实是底下八个矩阵相乘的结果:

4858美高梅 85

世家可以对照第贰部分中的“四、错切转变”和“1、平移转换”的相干说法,自行验证结果。

 

七.     错切转换(水平+垂直错切)

4858美高梅 86

代码所出口的七个矩阵分别是:

4858美高梅 87

个中,后者是上面三个矩阵相乘的结果:

4858美高梅 88

我们可以比较第2局地中的“四、错切转变”和“1、平移转换”的连锁说法,自行验证结果。

 

捌.     对称转变(水平对称)

4858美高梅 89

代码所出口的五个各矩阵分别是:

4858美高梅 90

个中,后者是上边三个矩阵相乘的结果:

4858美高梅 91 

大家能够对照第3某当中的“5、对称调换”和“一、平移转换”的有关说法,自行验证结果。

 

九.     对称转换(垂直对称)

4858美高梅 92

代码所出口的多个矩阵分别是:

4858美高梅 93

内部,后者是上边多个矩阵相乘的结果:

4858美高梅 94 

世家能够相比第一片段中的“伍、对称调换”和“一、平移调换”的相关说法,自行验证结果。

 

十.   对称转变(对称轴为直线y = x)

4858美高梅 95

代码所出口的五个矩阵分别是:

4858美高梅 96

里面,后者是上边三个矩阵相乘的结果:

4858美高梅 97 

世家能够对照第3有的中的“五、对称转换”和“壹、平移转变”的连带说法,自行验证结果。

 

1壹.   关于先乘和后乘的难点

由于矩阵的乘法运算不满意交流律,大家在头里已经多次谈起首乘、后乘的主题素材,即先乘就是矩阵运算中右乘,后乘便是矩阵运算中的左乘。其实先乘、后乘的定义是针对调换操作的日子先后来讲的,左乘、右乘是本着矩阵运算的左右岗位来讲的。以第2局地“2、旋调换换”中围绕某点旋转的事态为例:

4858美高梅 98 

越走近原图像中像素的矩阵,越先乘,越远隔原图像中像素的矩阵,越后乘。事实上,图像管理时,矩阵的演算是从左边往左边方向拓展演算的。那就造成了越在右侧的矩阵(右乘),越先运算(先乘),反之亦然。

 

当然,在实际中,要是首先钦命了一个matrix,比方大家先setRotate(4858美高梅 99),即钦命了地方转变矩阵中,中间的老大矩阵,那么继续的矩阵到底是pre依旧post运算,都以周旋那几个个中矩阵来说的。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有