Draw on custom view with zoom not working properly - android

When drawing on view without zoom it works fine. See the screenshot
But when zooming and then drawing on view It is slightly up or down. See the screenshot
Here is my code for Custom View http://www.paste.org/78026 and for zoom http://www.paste.org/78027 and my xml http://www.paste.org/78028
Please can you tell me where I am wrong

Finally after lot of searching I found how to get relative X,Y when View is zoomed. It may be helpful to someone
// Get the values of the matrix
float[] values = new float[9];
matrix.getValues(values);
// values[2] and values[5] are the x,y coordinates of the top left corner of the drawable image, regardless of the zoom factor.
// values[0] and values[4] are the zoom factors for the image's width and height respectively. If you zoom at the same factor, these should both be the same value.
// event is the touch event for MotionEvent.ACTION_UP
float relativeX = (event.getX() - values[2]) / values[0];
float relativeY = (event.getY() - values[5]) / values[4];

Related

Drawing a circle on a particular pixel of image

I have drawn a circle in a canvas with image in it on click event in one activity. And I have taken the x and y coordinates of that circle. In another activity i want to draw the same circle at the same position but the image size is not same so it is pointing to different position. So, how can achieve this?
The new position of circle (newX, newY) must move at same ratio that image size change.
newX = oldX * (newImageWidth / oldImageWidth)
newY = oldY * (newImageHeight / oldImageHeight)
You may want to change the size of the circle same way.

Any ways of making pinch to zoom smoother

Is there any ways of implementing smooth pinch to zoom without using matrix?
I am building drawing app and I want it to have pinch to zoom.
I get pivot point for scaling with:
centerposX = mScaleDetector.getFocusX();
centerposY = mScaleDetector.getFocusY();
and for scaling then I use:
canvas.scale(scaleFactor, scaleFactor, centerposX, centerposY);
But the problem is that it immediately centers view at the pivot point and them zooms it, rather than using it as a guide for centering.
I've seen that this problem has been solved by using matrix, but I don't want to use them as I need to keep track of offsets, ZoomTranslations which are calculated from centerposX/Y and scaleFactor to put drawings where they belong on screen.
So is there any way to solve this pivot point problem smoothly?
Thanks!
After a week I understood that I need to use matrix and get absolute coordinates on the screen, so I used Gesture detector to set matrix scale
matrix.postScale(mScaleFactor, mScaleFactor, focusX, focusY);
In my onDraw method I used canvas.concat(matrix); so not only Bitmap, but WHOLE canvas get's matrix transformation, and to get real screen coordinates I used a method i found on stack-overflow:
public float[] getAbsolutePosition(float Ax, float Ay) {
matrix.getValues(m);
float x = width - ((m[Matrix.MTRANS_X] - Ax) / m[Matrix.MSCALE_X])
- (width - getTranslationX());
float y = height - ((m[Matrix.MTRANS_Y] - Ay) / m[Matrix.MSCALE_X])
- (height - getTranslationY());
return new float[] { x, y };
}
I call this every time in my onTouchEvent() method, supplying event.getX and event.getY() as arguments.
After that, everything is easy peasy, also because of this beautiful method I've got rid of ~4-5 variables which I had to use to find real touch location.

How to compare MotionEvent coordinates to original image coordinates?

I have an image (ImageView). I have certain areas on the image. When a use taps the screen, I want to detect which area was selected.
I have identified the area boundaries on the original image, but the x and y of MotionEvent are off.
I tried dip-to-pixel conversion (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics)), but they are still off. It certainly has to do with the screen size / density / etc., but how exactly to get the pixel value of the touch event for the original image? (or, vice-versa - how to convert the original image coordinates to something that is comparable with the x and y of the motion event)
I managed to calculate it using the right and bottom coordinates of the ImageView (pic) compared to the real image size (568x1207).
float xCoef = 568f / pic.getRight();
float yCoef = 1207f / pic.getBottom();
float x = event.getX() * xCoef;
float y = event.getY() * yCoef;

Scaling image of ImageView while maintaining center point in same place

I have set a prescaled Bitmap as ImageView's source. Then I've read Matrix of an ImageView and shift Bitmap of an ImageView via matrix.postTranslate(shiftX, shiftY).
Now I want to zoom in / out and image while maintaining center of ImageView at the same point of Bitmap that was before scale.
If I try to zoom in an image with matrix.postScale(zoom, zoom), point that I want to maintain (blue dot) shifts to other place (purple dot).
I have tried several different ways to shift Bitmap back, but I cant get it to work correctly. I know initial Bitmap size, ImageView size, distances marked by doted line. Tried to calculate needed shift and use matrix.postTranslate(-zoomshiftX, -zoomshiftY) afterwards, but it doesn't shift correctly.
Even found out, that underlying Bitmap's pixel count doesnt change after matrix.postScale() function and tried matrix.postTranslate(-zoomshiftX/zoom, -zoomshiftY/zoom) - but still no luck.
How do I achieve such zoom?
Take a look at my question here regarding creating a zoomable ViewGroup. I've described code snippets from my end solution, and some of it might be helpful.
Extending RelativeLayout, and overriding dispatchDraw() to create a zoomable ViewGroup
Maybe this can be helpful:
If you got two fingers on screen, you can get the event of the two fingers and get the mid point:
PointF mid;
MotionEvent event;
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
mid.set(x / 2, y / 2);
Then you can set the scalation having the mid point in the center of the screen:
matrix.postScale(scale, scale, mid.x, mid.y);

centered zoom in custom view - calculating canvas coordinates

I am working on my first "real" Android application, a graphical workflow editor. The drawing is done in a custom class, that is a subclass of View.At the moment my elements are rectangles, which are drawn on a canvas. To detect actions on elements I compare the coordinates and check for elements on the touch location.
To implement a zoom gesture I tried http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html
With the 4 argument canvas.scale(...) function the centered zooming works well, but I lose the ability to calculate the canvas coordinates using the offset with mPosX and mPosY to detect if the touch after a zoom is on an element.
I tried to change the example in the blogpost above to center the canvas on the zoom gesture with:
canvas.save();
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor, mScalePivotX, mScalePivotY);
//drawing ....
canvas.restore();
I did not find any examples on how this could be done without losing the reference offset to calculate the coordinates. Is there an easy workaround? I tried to calculate the offset with the gesture center and the scaling factor, but failed :/
I have seen that other examples which use an ImageView often use a Matrix to transform the image. Could this be done with a custom View and a Canvas? If yes, how can I get the x and y offset to check the coordinates?
Also, if my ideas are completely wrong, I would be very happy to see some examples on how this is done properly.
Thx! ;)
Perhaps the following code will help you to calculate coordinates with the gesture center and the scaling factor. I use this method in my class representing opengl-sprite.
void zoom(float scale, PointF midPoint) {
if (zoomFactor == MAX_ZOOM_FACTOR && scale > 1) return;
if (zoomFactor == MIN_ZOOM_FACTOR && scale < 1) return;
zoomFactor *= scale;
x = (x - midPoint.x) * scale + midPoint.x;
y = (y - height + midPoint.y) * scale + height - midPoint.y;
if (zoomFactor >= MAX_ZOOM_FACTOR) {
zoomFactor = MAX_ZOOM_FACTOR;
} else if (zoomFactor < MIN_ZOOM_FACTOR) {
zoomFactor = MIN_ZOOM_FACTOR;
x = 0;
y = 0;
}
}
X and Y coordinates are processed in different ways, because of distinction between directions of opengl coordinate system (right and up) and midPoint's coordinate system (right and down). midPoint is taken from MotionEvents coordinates.
All other operations are understandable, i think.
Hope it will help you.

Categories

Resources