Правильный способ использования матрицы для масштабирования изображения вокруг фокальной точки

Позвольте мне начать с того, что я прочитал довольно много вопросов о масштабировании и пересчете координат здесь. Но я не могу применить их к моей ситуации.

У меня есть собственный класс ImageView, который может масштабировать и прокручивать. Проблема, с которой я столкнулся, связана с выполнением следующих действий в следующем порядке:

  1. Увеличение точки и использование этой точки в качестве фокуса (это работает)
  2. Прокрутка в увеличенном масштабе
  3. Попытка увеличить или уменьшить масштаб в другой точке (не работает)

Вот пример пользовательского представления. Есть два круга: красный и зеленый. красный — там, где фокус должен быть, а зеленый — там, где фокус близок к тому месту, где он фактически находится. введите здесь описание изображения

Проблема возникает, когда я пытаюсь увеличить область, обведенную оранжевым. На картинке ниже я попытался увеличить область, обведенную оранжевым кружком (не очень сильно, просто чтобы показать, где рассчитывается фокус). Как вы можете видеть ниже, красный кружок правильно вычисляет новую фокусную точку, но по какой-то причине зеленый кружок находится там, где он увеличивает/уменьшает масштаб.

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

Я использую следующий код для сопоставления увеличенных координат с фактическими координатами изображения.

public boolean onScale(ScaleGestureDetector detector) {
        //update the current scale
    scaleFactor *= detector.getScaleFactor();
    scaleFactor = Math.max(ZOOM_LEVEL_4, Math.min(scaleFactor, ZOOM_LEVEL_0));

    //applying the scaleFactor to the focal point as determined in onScaleBegin
    transformMatrix.setScale(scaleFactor, scaleFactor, 
                  newFocalPoints[0], newFocalPoints[1]);

    //apply the matrix to the child
    child.transform(transformMatrix, newFocalPoints[0],  newFocalPoints[1],
                oldFocalPoints[0], oldFocalPoints[1]);
    return true;
}

@Override
public boolean onScaleBegin(ScaleGestureDetector detector){
    //when a new scaling process begins, get the current imageMatrix and 
    //map the points to account for the current zoom level

    //the initial points. based on screen location and current scroll pos
    float startX = detector.getFocusX() + getScrollX();
    float startY = detector.getFocusY() + getScrollY();
    oldFocalPoints = new float[]{startX, startY};

    //map oldFocalPoints to coordinates of the imageView based on current zoom
    Matrix inverseTransformMatrix = new Matrix();

    if(transformMatrix.invert(inverseTransformMatrix))
        inverseTransformMatrix.mapPoints(newFocalPoints, oldFocalPoints);

    return true;
}

Зеленая точка на изображениях выше установлена ​​на {oldCoordinates[0], oldCoordinates[1]} в целях отладки, и хотя она не совсем фокусная точка, она чертовски близка. Таким образом, кажется, что, хотя я правильно вычисляю новую фокусную точку (красный кружок), кажется, что она не применяется правильно. Кто-нибудь может заметить что-то не так? Заранее спасибо!


person kburbach    schedule 26.08.2013    source источник


Ответы (1)


После долгих мучений я нашел решение. Вот код:

@Override
public boolean onScale(ScaleGestureDetector detector) {

    scaleFactor *= detector.getScaleFactor();
    scaleFactor = Math.max(ZOOM_4, Math.min(scaleFactor, ZOOM_LEVEL_0));

    float xDiff = initialFocalPoints[0] - currentFocalPoints[0];
    float yDiff = initialFocalPoints[1] - currentFocalPoints[1];

    transformMatrix.setScale(scaleFactor, scaleFactor, 
                                 currentFocalPoints[0], currentFocalPoints[1]);
    transformMatrix.postTranslate(xDiff, yDiff);    
    child.setImageMatrix(transformMatrix);

    return true;
}

@Override
public boolean onScaleBegin(ScaleGestureDetector detector){

    float startX = detector.getFocusX() + getScrollX();
    float startY = detector.getFocusY() + getScrollY();

    initialFocalPoints = new float[]{startX, startY};

    if(transformMatrix.invert(inverseTransformMatrix))
    inverseTransformMatrix.mapPoints(currentFocalPoints, initialFocalPoints);
    return true;
}

Строки, которые имели значение, были следующими:

float xDiff = initialFocalPoints[0] - currentFocalPoints[0];
float yDiff = initialFocalPoints[1] - currentFocalPoints[1];
transformMatrix.postTranslate(xDiff, yDiff);

Ответ был таким же простым, как определение разницы между двумя точками и перевод изображения каждый раз, когда изображение масштабируется.

person kburbach    schedule 03.09.2013
comment
текущие фокусные точки рассчитываются внутри шкалы или где-то еще? - person ShrimpCrackers; 20.02.2017