gi097
gi097

Reputation: 7701

Android: Get correct coordinates with scaled and translated canvas

I am writing an Android (Xamarin) application which is able to zoom and pan an image. A user can also click on a position on the image. I need those coordinates on the image for later use.

The following code is zooming and panning the image:

protected override void OnDraw(Canvas canvas)
{
    base.OnDraw(canvas);

    _maxX = canvas.Width;
    _maxY = canvas.Height;

    canvas.Translate(_posX, _posY);

    if (_scaleDetector.IsInProgress)
        canvas.Scale(_scaleFactor, _scaleFactor, _scaleDetector.FocusX, _scaleDetector.FocusY);
    else
        canvas.Scale(_scaleFactor, _scaleFactor, _lastGestureX, _lastGestureY);
}

So far so good, now I have some MotionEvent in use, which is a LongPressListener. I wrote the following code to translate the coordinates from the MotionEvent to the coordinates on the image:

var actualX = e.GetX() - (_parent._posX / _parent._scaleFactor);
var actualY = e.GetY() - (_parent._posY / _parent._scaleFactor);

e in this case is the frame of the image. The frame holds an image (which is _parent), the user can drag the image. _parent._posX/Y are changed when that happens. The user can also zoom the image, that's the _scaleFactor.

So, when a user taps anywhere in e, I need to translate those coordinates to the image coordinates.

Those two lines of code works, but when the user zooms in, the coordinates are off as you can see in the attached image:

Screen recording

The red dots represent the calculated positions. As you can see, if a user zooms in the coordinates gets more off. What's wrong in this calculation?

Upvotes: 8

Views: 1153

Answers (3)

gi097
gi097

Reputation: 7701

I managed to fix it using a Matrix:

private float[] TranslateCoordinates(float[] coordinates)
{
    var matrix = new Matrix(Matrix);

    matrix.PreScale(_scaleFactor, _scaleFactor);
    matrix.PreTranslate(_posX, _posY);

    matrix.Invert(matrix);
    matrix.MapPoints(coordinates);

    return coordinates;
}

The float[] contains the values of MotionEvent's GetX() and GetY().

Upvotes: 0

Nekeniehl
Nekeniehl

Reputation: 1691

I think your problem is because the Canvas is not getting updated, try using Canvas.UpdateLayout after zooming.

Upvotes: 0

Amol Jindal
Amol Jindal

Reputation: 106

Try to do this :-

  var actualX = (e.GetX() - _parent._posX) / _parent._scaleFactor;

  var actualY = (e.GetY() - _parent._posY) / _parent._scaleFactor;

Upvotes: 3

Related Questions