Подтвердить что ты не робот

UWP: вычисление преобразования на основе ScrollViewer

У меня есть универсальное приложение для Windows, где я показываю сцену с DirectX. Я хочу использовать Scrollviewer, и поэтому я делаю свою сцену за Scrollviewer и хочу рассчитать трансформацию сцены на основе Scrollviewer. До сих пор он отлично работает, особенно в переводе и прокрутке. Но когда я увеличиваю масштаб, сцена прыгает в двух особых ситуациях:

  • Сцена имела достаточно места и была сосредоточена, и теперь требуется прокрутка.
  • В противоположном направлении.

Более или менее я использую следующий код:

float zoom = scrollViewer.ZoomFactor;

float inverseZoom = 1f / scrollViewer.ZoomFactor;

float scaledContentW = Document.Size.X * scrollViewer.ZoomFactor;
float scaledContentH = Document.Size.Y * scrollViewer.ZoomFactor;

float translateX;
float translateY;

if (scaledContentW < scrollViewer.ViewportWidth)
{
    translateX = ((float)scrollViewer.ViewportWidth * inverseZoom - Document.Size.X) * 0.5f;
}
else
{
    translateX = -inverseZoom * (float)scrollViewer.HorizontalOffset;
}

if (scaledContentH < scrollViewer.ViewportHeight)
{
    translateY = ((float)scrollViewer.ViewportHeight * inverseZoom - Document.Size.Y) * 0.5f;
}
else
{
    translateY = -inverseZoom * (float)scrollViewer.VerticalOffset;
}

float visibleX = inverseZoom * (float)scrollViewer.HorizontalOffset;
float visibleY = inverseZoom * (float)scrollViewer.VerticalOffset; ;

float visibleW = Math.Min(Document.Size.X, inverseZoom * (float)scrollViewer.ViewportWidth);
float visibleH = Math.Min(Document.Size.Y, inverseZoom * (float)scrollViewer.ViewportHeight);

Rect2 visibleRect = new Rect2(visibleX, visibleY, visibleW, visibleH);

transform =
    Matrix3x2.CreateTranslation(
        translateX,
        translateY) *
    Matrix3x2.CreateScale(zoom);

Здесь вы можете привести пример: https://github.com/SebastianStehle/Win2DZoomTest

Чтобы быть уверенным, что мои глаза не сломаны, я увеличивал масштаб и записывал значения трансляции и масштабирования в файл. Вы можете увидеть это здесь:

https://www.dropbox.com/s/9ak6ohg4zb1mnxa/Test.png?dl=0

Значение столбцов следующее:

Столбец 1: Вычисленное значение масштабирования матрицы преобразования (M11) = ScrollViewer.ZoomFactor Столбец 2: Вычисленное смещение x матрицы (см. Выше) Столбец 3: Значение x результата матрицы * vector (500, 500), здесь: Colum1 * 500 + Column2

Вы видите, что значения матрицы выглядят хорошо, но при применении преобразования вы получаете этот небольшой прыжок вправо в течение нескольких миллисекунд. Одна из теорий заключалась в том, что область просмотра может измениться, поскольку полоса прокрутки становится видимой. Но это не так. Я также пробовал фиксированные значения здесь, сделал полосы прокрутки видимыми и даже создал собственный шаблон для scrollviewer без полос прокрутки.

Btw: Это перекрестный пост, я также задал здесь вопрос: https://github.com/Microsoft/Win2D/issues/125

4b9b3361

Ответ 1

Вы видите это поведение, потому что, когда вы увеличиваете масштаб больше размера ScrollViewer, точка центра масштабирования перемещается. Чтобы исправить это, вам просто нужно подписаться на событие ScrollViewer LayoutUpdated и внутри обработчика, вручную сохраните его содержимое в центре.

    private void ScrollViewer_LayoutUpdated(object sender, object e)
    {
        this.ScrollViewer.ChangeView(this.ScrollViewer.ScrollableWidth / 2, this.ScrollViewer.ScrollableHeight / 2, this.ScrollViewer.ZoomFactor, true);
    }

Это должно исправить прыгающее движение по двум выделенным Rectangle из Win2D.


Update

Чтобы доказать свою точку зрения, скачкообразное поведение, скорее всего, связано с необычным изменением значения translate x и/или y, когда размер содержимого превышает размер ScrollViewer. Поэтому я написал код для регистрации этих значений на экране, как показано ниже -

...
this.Test1.Text += ((float)translateX).ToString() + " ";
this.Test2.Text += ((float)translateY).ToString() + " ";

session.Transform =
    Matrix3x2.CreateTranslation(
        (float)translateX,
        (float)translateY) *
    Matrix3x2.CreateScale((float)zoom);

введите описание изображения здесь

Теперь взгляните на цифры на изображении выше. То, что я сделал, я пробовал масштабирование до тех пор, пока не возникла прыгающая сцена. См. Выделенное значение translate y. Это немного больше, чем его предыдущее значение, что противоречит тенденции к снижению.

Итак, чтобы исправить это, вам нужно будет пропустить эти необычные значения, вызванные ScrollViewer.