Matrix.postScale(sx,sy,px,py)如何工作?

Inj*_*ury 8 android 2d matrix

首先阅读Taig的问题

泰格说:

调用Matrix.postScale时(sx,sy,px,py); 矩阵得到缩放并且也被翻译(取决于给定的点x,y).这预示着这种方法可用于放大图像,因为我可以轻松地聚​​焦一个特定的点.android doc描述了这样的方法:

Postconcats the matrix with the specified scale. M' = S(sx, sy, px, py) * M
Run Code Online (Sandbox Code Playgroud)

乍一看这看起来很荒谬,因为M应该是3x3-Matrix.挖掘我发现android使用4x4-Matrix进行计算(同时只在其API上提供3x3).由于此代码是用C语言编写的,因此我很难理解实际发生的情况.

我在Wolfram看到了视觉变换

我的问题和Taig一样

我真正想知道的是:如何将这种缩放(有重点)应用于我可以在Java代码中访问的3x3 Matrix?

谁能给我一个例子和2d-scaling公式,其中包含一个10岁孩子能理解的4个参数(sx,sy,px,py)?

kri*_*son 19

仔细查看Matrix方法.你会看到getValue()setValue().文档说他们使用float具有9个值的数组.也有一串常数:MSCALE_X,MSCALE_Y,MTRANS_X,MTRANS_Y等等.这些常数是索引到float[9]阵列.

由于我们只在2维工作,因此矩阵实际上是2x2矩阵.但由于该矩阵支持仿射变换,因此矩阵扩展为3x3矩阵.3x3 = 9,对应于float[9]数组.那就是你的3x3矩阵.

实际的内容Matrix是用C++编写的,并通过JNI访问,因为操作必须快速,快速,快速.它们甚至使用特殊的非标准浮点数格式("16.16"),该格式针对计算速度进行了优化.

我不知道你在哪里获得有关4x4阵列的信息.这是C++ JNI的代码片段:

SkScalar         fMat[9];
mutable uint32_t fTypeMask;

void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) {
    fMat[kMScaleX] = sx;
    fMat[kMSkewX]  = 0;
    fMat[kMTransX] = tx;

    fMat[kMSkewY]  = 0;
    fMat[kMScaleY] = sy;
    fMat[kMTransY] = ty;

    fMat[kMPersp0] = 0;
    fMat[kMPersp1] = 0;
    fMat[kMPersp2] = 1;

    unsigned mask = 0;
    if (sx != 1 || sy != 1) {
        mask |= kScale_Mask;
    }
    if (tx || ty) {
        mask |= kTranslate_Mask;
    }
    this->setTypeMask(mask | kRectStaysRect_Mask);
}
Run Code Online (Sandbox Code Playgroud)

它是仿射变换的3x3矩阵.

当您调用时matrix.postScale(),您正在修改scaleX,scaleY,transX和transY.(pre..()post...()方法保留矩阵中开始的任何变换.)Matrix应用这样的新变换:

X' = X * scaleX + transX
Y' = Y * scaleY + transY

这是整个矩阵乘法的简化版本.如果我有一个带点(2,2)的数字并且我将其缩放2倍,那么新点将是(4,4).要沿X轴或Y轴移动,我只需添加一个常量.

因为Matrix.postScale()实际上是一个焦点,所以该方法在内部调整transX和transY,就好像你正在翻译,缩放,然后翻译一样.这使得缩放看起来好像扩展/收缩以点px,py为中心.

transX = (1 - scaleX) * px
transY = (1 - scaleY) * py

因此,对于焦点,我通过将px和py直接添加到原始x,y值来将图形移动到(px,py).然后我做缩放.但是为了撤消翻译,我必须考虑到我的原始焦点点现在已经缩放,因此我不得不减去px和py,而是减去scaleX*px和scaleY*py.

歪斜剪切就像缩放,但具有相反的轴:

X' = Y * skewX
Y' = X * skewY

由于您在不进行变形的情况下进行缩放和平移,因此skewX和skewY设置为零.因此它们仍然用于矩阵乘法,它们只是不影响最终结果.

通过添加一点trig来完成旋转:

theta = angle of rotation
scaleX = cos(theta)
skewX = -sin(theta)
skewY = sin(theta)
scaleY = cos(theta)

然后是android.graphics.Camera(相对于android.hardware.Camera)可以采用2D平面并在3D空间中旋转/平移它.这就是MPERSP_0,MPERSP_1,和MPERSP_2发挥作用.我不是在做那些方程式; 我是程序员,不是数学家.

但我不需要成为一名数学家.我甚至不需要知道Matrix它的计算方法.我一直在研究支持捏合/缩放的ImageView子类.所以我用a ScaleGestureDetector来告诉我用户何时缩放.它有方法getScaleFactor(),getFocusX()getFocusY().我将这些值插入matrix.postScale(),并且我ImageView将比例类型设置为MATRIX,我ImageView.setImageMatrix()用我的缩放矩阵调用.Voilà,图像完全按照用户期望的方式缩放,基于他们的手势.

因此,我不理解所有关于如何Matrix在引擎盖下工作的焦虑.不过,我希望我在这里写的东西可以为你提供你想要的答案.