How do I correctly translate pixel coordinates to canvas coordinates in Android?
Asked Answered
H

6

9

I am capturing a MotionEvent for a long click in an Android SurfaceView using a GestureListener. I then need to translate the coordinates of the MotionEvent to canvas coordinates, from which I can generate custom map coordinates (not Google Maps).

From what I have read, I take that given MotionEvent e, e.getX() and e.getY() get pixel coordinates. How can I convert these coordinates to the SurfaceView's canvas coordinates?

Here is my GestureListener for listening for long clicks:

/**
* Overrides touch gestures not handled by the default touch listener
*/
private class GestureListener extends GestureDetector.SimpleOnGestureListener {

  @Override
  public void onLongPress(MotionEvent e) {
     Point p = new Point();
     p.x =  (int) e.getX();
     p.y = (int) e.getY();
     //TODO translate p to canvas coordinates
  }
}

Thanks in advance!

Edit: Does this have to do with screen size/resolution/depth and the canvas' Rect object?

Handball answered 28/7, 2011 at 0:23 Comment(5)
Did you tried translate (float dx, float dy)?Emblazonment
I looked into it. Unfortunately, I'm not drawing to the canvas. I need the actual coordinates. Once I get the canvas coordinates I plan to translate my canvas coordinates to the application's map coordinates which will be used for navigation.Handball
Really no one else? Does this have to do with screen size/resolution/depth and the canvas' Rect object? Hasn't anyone done this translation before?Handball
solved? I also face the same problemIve
https://mcmap.net/q/658716/-mismatch-of-event-coordinates-and-view-coordinates-in-androidElodiaelodie
K
1

If i understand correctly you have a canvas View inside surfaceview. If so try VIEW.getLeft() | getTop() that returns the left | top position of the view relative to it's parent.

float x= e.getX() - canvasView.getLeft();
float y= e.getY() - canvasView.getTop();
Kanishakanji answered 30/7, 2011 at 23:58 Comment(2)
Thanks for the idea. I tried it out and it still doesn't work.Handball
What to do when the canvas is scaled?Valentine
G
8

You might try using the MotionEvent.getRawX()/getRawY() methods instead of the getX()/getY().

// get the surfaceView's location on screen
int[] loc = new int[2];
surfaceView.getLocationOnScreen(loc);
// calculate delta
int left = e.getRawX()-loc[0];
int top = e.getRawY()-loc[1];
Gardener answered 4/8, 2011 at 9:44 Comment(0)
L
5

Well, you have the screen px from the display in x,y, and you can call the canvas px via:

Canvas c = new Canvas();
int cx = c.getWidth();
int cy = c.getHeight();
...
Display display = getWindowManager().getDefaultDisplay(); 
int sx = display.getWidth();
int sy = display.getHeight();

Then, you can do the math to map the screen touch view , with the given px in both the view and the screen.

canvasCoordX = p.x*((float)cx/(float)sx);
canvasCoordY = p.y*((float)cy/(float)sy);

See http://developer.android.com/reference/android/view/WindowManager.html for more info on the screen manager. I think it needs to be initialized inside an activity to work.

Latrice answered 1/8, 2011 at 17:42 Comment(3)
thanks for the idea. I tried it out, but it still does not work correctly.Handball
There's no error. It does provide some translation, however it is not the correct translation. It is finding canvas coordinates way to the top of the screen no matter where I press.Handball
I'd recommend some debugging then - it could be that the display px didn't get initialized correctly and are both 0,0. Print out the variables, and if everything still looks good, abandon this method. :)Latrice
G
4

I recently came upon this problem while doing something very similiar and after some trial and error and lots of googling I ended up adapting this answer (https://mcmap.net/q/593919/-how-to-convert-coordinates-of-the-image-view-to-the-coordinates-of-the-bitmap) :

(e is a MotionEvent, so the best place to use this code would be in onTouch or onLongPress)

mClickCoords = new float[2];

//e is the motionevent that contains the screen touch we
//want to translate into a canvas coordinate
mClickCoords[0] = e.getX();
mClickCoords[1] = e.getY();

Matrix matrix = new Matrix();
matrix.set(getMatrix());

//this is where you apply any translations/scaling/rotation etc.
//Typically you want to apply the same adjustments that you apply
//in your onDraw().

matrix.preTranslate(mVirtualX, mVirtualY);
matrix.preScale(mScaleFactor, mScaleFactor, mPivotX, mPivotY);

// invert the matrix, creating the mapping from screen 
//coordinates to canvas coordinates
matrix.invert(matrix); 

//apply the mapping
matrix.mapPoints(mClickCoords);

//mClickCoords[0] is the canvas x coordinate and
//mClickCoords[1] is the y coordinate.

There are some obvious optimizations that can be applied here but I think it is more clear this way.

Gride answered 24/5, 2013 at 21:7 Comment(0)
K
1

If i understand correctly you have a canvas View inside surfaceview. If so try VIEW.getLeft() | getTop() that returns the left | top position of the view relative to it's parent.

float x= e.getX() - canvasView.getLeft();
float y= e.getY() - canvasView.getTop();
Kanishakanji answered 30/7, 2011 at 23:58 Comment(2)
Thanks for the idea. I tried it out and it still doesn't work.Handball
What to do when the canvas is scaled?Valentine
S
0

if you are using scrolling, then the actual y on the canvas is

float y = event.getY() + arg0.getScrollY();
Sero answered 1/3, 2014 at 11:19 Comment(0)
F
0

What I do in these situations is just:

  1. put a listener on whatever View/ViewGroup whose coordinates you wanna get by click
  2. Make it store them locally
  3. Whoever wants to access them should just request them via helper method.

And translation is done...

Freiburg answered 11/4, 2018 at 18:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.