Как Canvas определяет границы клипа?

я делал некоторые работы с Android в Canvas, специально пытаясь определить, как его getClipBounds результаты определяются. Я понимаю!--5--> внутренне поддерживает преобразование Matrix, которая обновляется, как я называю translate, scale, etc. но попытка воспроизвести это 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(). Translate и Scale вызываются из обработчиков событий жестов, которые работают правильно.

часть это меня смущает viewportMatrix. Не имеет значения, знаю я или нет.--37-->

viewportMatrix.set(canvas.getMatrix());

или

viewportMatrix.preConcat(canvas.getMatrix());

или даже одноразовый звонок в

viewportMatrix.set(canvas.getMatrix());

в начале следуют бок о бок Translate/Scale вызовы двух матриц. Я даже пытался полностью игнорировать Canvasв своем Matrix и рерайтинг GetViewport as

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

    translationMatrix.mapRect(viewport, originalViewport);

    return viewport;
}

я никогда не могу сравниться getClipBounds(), и расхождения достаточно серьезно:

С viewportMatrix.set(canvas.getMatrix):

clipBounds: Rect(-97, -97 - 602, 452) (699, 549)
видовое окно: RectF(97.04178, 97.06036, 797.04175, 647.06036) (700.0, 550.0)

С viewportMatrix.preConcat(canvas.getMatrix):

clipBounds: Rect(-97, -96 - 602, 453) (699, 549)
видовое окно: RectF(2708.9663, 2722.2754, 3408.9663, 3272.2754) (700.0, 550.0)

С translationMatrix.mapRect:

clipBounds: Rect(-96, -96 - 603, 453) (699, 549)
видовое окно: RectF(96.73213, 96.85794, 796.7321, 646.8579) (700.0, 550.0)

С одним выстрелом вызова viewportMatrix.preConcat(canvas.getMatrix()) затем бок-о-бок Translate/Scale вызовы:

clipBounds: Rect(-96, -97 - 603, 452) (699, 549)
видовое окно: RectF(96.57738, 97.78168, 796.5774, 647.7817) (700.0, 550.0)

С a один выстрел вызов viewportMatrix.set(canvas.getMatrix()) затем бок-о-бок Translate/Scale вызовы:

clipBounds: Rect(-96, -96 - 603, 453) (699, 549)
видовое окно: RectF(96.40051, 96.88153, 796.4005, 646.88153) (700.0, 550.0)

я даже не могу проверить the Canvas источник, как все Matrix код исчезает в частные собственные вызовы, код которых не отображается.

почему GetViewport вызовы так грубо, и что происходит за кулисами с getClipBounds?

1 ответов


Я прочитал до конца этот ответ на GameDev SE, который использует инверсию матрицы для обмена между экраном и мировыми системами координат:

чтобы перейти от экрана к мировому пространству просто использовать Vector2.Преобразиться. Это обычно используется для получения местоположения мыши в мире для выбора объекта.

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.

эта матрица учебник объясняет, что я заметил по результатам transform звонки, но не применялись к моей матрице:

в компьютерной программе камера вообще не движется, и на самом деле мир просто движется в противоположном направление и ориентация о том, как вы хотели бы камеру двигаться в реальности.

чтобы понять это правильно, мы должны думать в терминах двух разных вещей:

  1. Матрица Преобразования Камеры: преобразование, которое помещает камеру в правильное положение и ориентацию в мировом пространстве (это преобразование, которое вы бы применили к 3D-модели камеры, если бы вы хотели представить ее в сцене).
  2. Матрица Просмотра: это матрица преобразования вершин мира-пространстве-пространстве. эта матрица является обратной матрице преобразования камеры, описанной выше.