Canvas如何确定其剪辑边界?

时间:2016-04-17 23:03:48

标签: java android android-canvas

我一直在使用Android的Canvas做一些工作,特别是试图确定其getClipBounds结果的确定方式。我了解Canvas在内部保留了一个转换Matrix,该转换会在我调用translatescale等时更新,但尝试复制Matrix的结果已经困惑我。

@Override
public void onDraw(Canvas canvas) {
    Rect clipBounds;
    RectF viewport;

    canvas.save();
    canvas.concat(translationMatrix);
    //viewportMatrix.preConcat(canvas.getMatrix());
    viewportMatrix.set(canvas.getMatrix());

    clipBounds = canvas.getClipBounds();
    viewport = GetViewport();

    Log.d("clipBounds", clipBounds.toString() + " (" + clipBounds.width() + ", " + clipBounds.height() + ")");
    Log.d("viewport", viewport.toString() + " (" + viewport.width() + ", " + viewport.height() + ")");

    //drawing is done here

    canvas.restore();
}

//viewport code modeled after http://stackoverflow.com/a/17142856/2245528
private RectF GetViewport() {
    RectF viewport = new RectF();

    viewportMatrix.mapRect(viewport, originalViewport);

    return viewport;
}

private void Translate(float x, float y) {
    translationMatrix.postTranslate(x, y);

    invalidate();
}

private void Scale(float scaleFactor, PointF focusPoint) {
    if (focusPoint == null) {
        translationMatrix.postScale(scaleFactor, scaleFactor);
    }
    //keep the focus point in focus if possible
    else {
        translationMatrix.postScale(scaleFactor, scaleFactor, focusPoint.x, focusPoint.y);
    }

    invalidate();
}

private final Matrix translationMatrix = new Matrix();
private final RectF originalViewport = new RectF();
private final Matrix viewportMatrix = new Matrix();

originalViewport设置为0, 0, canvas.getWidth(), canvas.getHeight()。 <{1}}和Translate是从手势事件处理程序调用的,它们正常工作。

令我困惑的部分是Scale。我是否

似乎并不重要
viewportMatrix

viewportMatrix.set(canvas.getMatrix());

甚至一次性致电

viewportMatrix.preConcat(canvas.getMatrix());

在开头,然后是对两个矩阵的并排viewportMatrix.set(canvas.getMatrix()); / Translate调用。我甚至试图完全忽略Scale的内置Canvas并重写Matrix

GetViewport

我似乎永远不会匹配//viewport code modeled after http://stackoverflow.com/a/17142856/2245528 private RectF GetViewport() { RectF viewport = new RectF(); translationMatrix.mapRect(viewport, originalViewport); return viewport; } ,而且差异非常严重:

getClipBounds()

  

clipBounds:Rect(-97,-97 - 602,452)(699,549)
  视口:RectF(97.04178,97.06036,797.04175,647.06036)(700.0,550.0)

viewportMatrix.set(canvas.getMatrix)

  

clipBounds:Rect(-97,-96 - 602,453)(699,549)
  viewport:RectF(2708.9663,2722.2754,3408.9663,3272.2754)(700.0,550.0)

viewportMatrix.preConcat(canvas.getMatrix)

  

clipBounds:Rect(-96,-96 - 603,453)(699,549)
  viewport:RectF(96.73213,96.85794,796.7321,646.8579)(700.0,550.0)

translationMatrix.mapRect进行一次性通话,然后是并排的viewportMatrix.preConcat(canvas.getMatrix()) / Translate来电:

  

clipBounds:Rect(-96,-97 - 603,452)(699,549)
  视口:RectF(96.57738,97.78168,796.5774,647.7817)(700.0,550.0)

Scale进行一次性通话,然后是并排的viewportMatrix.set(canvas.getMatrix()) / Translate来电:

  

clipBounds:Rect(-96,-96 - 603,453)(699,549)
  viewport:RectF(96.40051,96.88153,796.4005,646.88153)(700.0,550.0)

我甚至无法检查the Canvas source,因为所有Scale代码都会消失为未显示代码的私有本机调用。

为什么我的Matrix电话如此严重,以及GetViewport在幕后发生了什么?

1 个答案:

答案 0 :(得分:1)

我通读this answer on GameDev SE,它使用矩阵反转在屏幕和世界坐标系之间交换:

  

要从屏幕转到世界空间,只需使用Vector2.Transform即可。这通常用于获取鼠标在世界中的位置以进行对象拾取。

Vector2.Transform(mouseLocation, Matrix.Invert(Camera.TransformMatrix));
     

从世界到屏幕空间只需做相反的事情。

Vector2.Transform(mouseLocation, Camera.TransformMatrix);

受这种方法的启发,我尝试反转变换矩阵,如下所示:

private RectF GetViewport() {
    RectF viewport = new RectF();
    Matrix viewportMatrix = new Matrix();

    translationMatrix.invert(viewportMatrix);

    viewportMatrix.mapRect(viewport, originalViewport);

    return viewport;
}

此视口正确匹配getClipBounds返回的结果。

This matrix tutorial解释了我在transform次调用的结果中注意到的内容,但没有应用于我的矩阵:

  

在计算机程序中,相机根本不会移动,实际上,世界正朝着相反的方向和方向移动,希望相机在现实中移动。< / p>      

为了正确理解这一点,我们必须考虑两个不同的事情:

     
      
  1. 相机转换矩阵:将相机置于世界空间中的正确位置和方向的转换(如果您愿意,可以应用于相机的3D模型的转换在场景中代表它。)
  2.   
  3. 视图矩阵:此矩阵将顶点从世界空间转换为视图空间。 此矩阵是上述相机变换矩阵的反转。
  4.