Android Java Zoom boundaries - java

I am developing an interactive video installation with touch screen control via an android device. I came up with the following code for panning, zooming and a pan limit so far. But I can't figure out how to limit the zooming (min/max) and how to avoid that the image get out of the boundaries (it should be displayed on the complete screen without any offset).
Thank you for your help!
public boolean onTouchEvent(MotionEvent me) {
switch (me.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
startPoint.set(me.getX(), me.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(me);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(midPoint, me);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float transX = me.getX() - startPoint.x;
float transY = me.getY() - startPoint.y;
matrix.set(savedMatrix);
float[] f = new float[9];
matrix.getValues(f);
float viewWidth = 1317.0f + 1317.0f * ((f[Matrix.MSCALE_X] - 1) / 1.1365f );
float viewWidth2 = 772.0f + 772.0f * ((f[Matrix.MSCALE_X] - 1) / 1.998f);
float viewHeight = 1097.0f + 1097.0f * ((f[Matrix.MSCALE_X] - 1) / 1.463f);
float viewHeight2 = 749.0f + 749.0f * ((f[Matrix.MSCALE_X] - 1) / 2.994f);
if (f[Matrix.MTRANS_X] + transX < -viewWidth){
Log.e("", "left bound");
transX = -f[Matrix.MTRANS_X] -viewWidth;
}
if(f[Matrix.MTRANS_X] + transX > -viewWidth2 ){
transX = -f[Matrix.MTRANS_X] -viewWidth2;
}
if (f[Matrix.MTRANS_Y] + transY > viewHeight){
transY = -f[Matrix.MTRANS_Y] + viewHeight;
}
if(f[Matrix.MTRANS_Y] + transY < viewHeight2){
transY = -f[Matrix.MTRANS_Y] + viewHeight2;
}
matrix.postTranslate(transX, transY);
} else if (mode == ZOOM) {
float newDist = spacing(me);
if (newDist > 10f) {
Log.e("MainActivity", "Correction: " + Float.toString(newDist / newDist));
float transX = me.getX() - startPoint.x;
float transY = me.getY() - startPoint.y;
matrix.set(savedMatrix);
float scale = newDist / oldDist;
float[] f = new float[9];
matrix.getValues(f);
matrix.postScale(scale, scale, -startPoint.x+300.f, -startPoint.y+900.0f);
if (f[Matrix.MSCALE_X] >= 270.0f) {
matrix.postScale((270.0f)/(f[Matrix.MSCALE_X]/scale), (270.0f)/(f[Matrix.MSCALE_Y]*scale), 0f ,0f);
mode = DRAG;
savedMatrix.set(matrix);
midPoint(midPoint, me);
} else if (f[Matrix.MSCALE_X] < 0.29f) {
matrix.postScale((0.29f)/(f[Matrix.MSCALE_X]/scale), (0.29f)/(f[Matrix.MSCALE_Y]*scale), 0f ,0f);
mode = DRAG;
savedMatrix.set(matrix);
midPoint(midPoint, me);
}
}
}
break;
}
// Matrix
try {
socket = new DatagramSocket();
// socket.setBroadcast(true);
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String dataString = matrix.toShortString();
Log.e("Activity_Main", dataString);
try {
DatagramPacket packet = new DatagramPacket(dataString.getBytes(), dataString.length(), serverAddr, PORT);
socket.send(packet);
socket.close();
} catch (Exception e) {
}
return true;
}
#SuppressLint("FloatMath")
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}

Related

ImageView onTouch not moving correctly

I'm having a problem moving an image from a place, where I touch it with a finger on a screen. It means when I touch it, let say in a center of a button and want to move it, it gets me to teh left a top corner of a button and from that point, I can move it around, up, left, right and so on...I want to have a possibility to move a button from wherever user put a finger on a button
Code:
public class Joystick extends RelativeLayout implements View.OnTouchListener {
private Context context;
private ImageView backgroundImageView;
private ImageView buttonImageView;
float xx = 0;
float yy = 0;
private static final String TRANSLATIONX = "setTranslationX";
public Joystick(Context context) {
super(context);
this.context = context;
initSlider();
if(buttonImageView != null) {
buttonImageView.setOnTouchListener(this);
}
this.setClipChildren(false);
}
public ImageView setView ( String imageName) {
ImageView image = new ImageView(context);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
image.setLayoutParams(layoutParams);
// load image
try {
// get input stream
InputStream ims = getContext().getAssets().open(imageName);
// load image as Drawable
Drawable d = Drawable.createFromStream(ims, null);
// set image to ImageView
image.setImageDrawable(d);
} catch (IOException ex) {
}
return image;
}
public void initSlider() {
backgroundImageView = setView("background.png");
buttonImageView = setView("jostick.png");
addView(backgroundImageView);
addView(buttonImageView);
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
float x = motionEvent.getRawX();
float y = motionEvent.getRawY();
float cx = buttonImageView.getWidth() / 2.f;
float cy = buttonImageView.getHeight() / 2.f;
float w = backgroundImageView.getWidth();
float h = backgroundImageView.getHeight();
double r = cx / 2.;
double dx = x - cx;
double dy = y - cy;
double hypot = Math.hypot(dx, dy);
double cos = dx / hypot; // cos
double sin = dy / hypot; // sin
double rcos = r * cos;
double rsin = r * sin;
double rdx = Math.abs(dx) < Math.abs(rcos) ? dx : rcos; // if,else
double rdy = Math.abs(dy) < Math.abs(rsin) ? dy : rsin;
Log.d("VALUES", "RAW X:" + motionEvent.getRawX() + ", X:" + motionEvent.getX() + ", CX:" + cx + ", CY:" + cy + ", dx:" + dx + ", dy:" + dy + ", Hypo:" + hypot + ", cos:" + cos + ", sin" + sin);
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
view.setX(xx);
view.setY(yy);
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
float transX = (float) (cx + rdx - w / 2.);
float transY = (float) (cy + rdy - h / 2.);
buttonImageView.setTranslationX(transX);
buttonImageView.setTranslationY(transY);
Log.d(TRANSLATIONX,"X:" + transX + ", Y:" + transY);
break;
}
return true;
}
}
Somewhere is a small bug. I hope for any help. Thanks
If anyone is interested or looking for some answer how to make a Joystick Button moving inside box, I have found a solution:
private Point calculate (float x, float y) {
float cx = buttonImageView.getWidth() / 2.f;
float cy = buttonImageView.getHeight() / 2.f;
double r = cx / 2.; // vrednost radius
double dx = x;
double dy = y;
double hypot = Math.hypot(dx, dy); // izracun hipotenuze
double cos = dx / hypot; // cos
double sin = dy / hypot; // sin
double rcos = r * cos;
double rsin = r * sin;
double rdx = Math.abs(dx) < Math.abs(rcos) ? dx : rcos; // if,else
double rdy = Math.abs(dy) < Math.abs(rsin) ? dy : rsin;
return new Point((int)rdx, (int)rdy);
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
final float x = motionEvent.getRawX(); // x točko
final float y = motionEvent.getRawY(); // y točka
//Log.d("VALUES", "RAW X:" + motionEvent.getRawX() + ", RAW Y:" + motionEvent.getRawY() + ", X:" + motionEvent.getX() + ", CX:" + cx + ", CY:" + cy + ", dx:" + dx + ", dy:" + dy + ", Hypo:" + hypot + ", cos:" + cos + ", sin" + sin);
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
xDelta = view.getX() - x;
yDelta = view.getY() - y;
break;
case MotionEvent.ACTION_UP:
doBounceAnimation(buttonImageView);
doVibration();
view.setX(xx);
view.setY(yy);
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
final float transX = (float) x;
final float transY = (float) y;
thread = new Thread() {
#Override
public void run() {
Point newPoint = calculate(transX+ xDelta,transY + yDelta);
buttonImageView.setX(newPoint.x);
buttonImageView.setY(newPoint.y);
}
};
thread.start();
Log.d(TRANSLATIONX,"X:" + transX + ", Y:" + transY);
break;
}
return true;
}
Enjoy coding!

How to Draw on android ImageView after scaling it?

I have an ImageView and i want to zoom/drag on by two fingers and draw on it using one finger , but after scaling ImageView , bitmap coordinates and ImageView coordinates doesn't match , to solve this i provided onTouch like this :
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
final int NONE = 0;
final int DRAW = 1;
final int PINCH = 2;
float x,y;
switch (event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
drawStartX = event.getX();
drawStartY = event.getY();
imageMode = DRAW;
break;
case MotionEvent.ACTION_POINTER_DOWN:
//drag
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
x = event.getX(0) - event.getX(1);
y = event.getY(0) - event.getY(1);
oldDistance = (float) Math.sqrt(x * x + y * y);
if (oldDistance > 5f) {
savedMatrix.set(matrix);
x = event.getX(0) + event.getX(1);
y = event.getY(0) + event.getY(1);
mid.set(x / 2, y / 2);
imageMode = PINCH;
}
break;
case MotionEvent.ACTION_UP:
imageMode = NONE;
break;
case MotionEvent.ACTION_POINTER_UP:
imageMode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (imageMode == DRAW) {
float drawEndX = event.getX();
float drawEndY = event.getY();
drawTest(drawStartX/bitmapScale - xTranslate, drawStartY/bitmapScale- yTranslate,drawEndX/bitmapScale - xTranslate,drawEndY/bitmapScale - yTranslate,0);
} else if (imageMode == PINCH) {
x = event.getX(0) - event.getX(1);
y = event.getY(0) - event.getY(1);
float newDistance = (float) Math.sqrt(x * x + y * y);
matrix.set(savedMatrix);
if(newDistance > 5f) {
//drag
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
matrix.postTranslate(dx, dy);
//zoom
float scale = (newDistance / oldDistance);
matrix.postScale(scale, scale);
}
//get matrix
float[] mat = new float[9];
matrix.getValues(mat);
bitmapScale = mat[0];
xTranslate = mat[2];
yTranslate = mat[5];
}
break;
}
view.setImageMatrix(matrix);
return true;
}
drawTest is just a void that draws a line.
pic
in before scale picture i drag my finger on imageview and line drawn in exact position , but after scaling i dragged on same position but result is not right
but it's not working properly. how can i fix it ?

pinch to zoom in min3D

I am trying to add pinch to zoom in my 3D view, and it doesn't work. Rotating is working, but not zooming.
I have also tried with ACTION_POINTER1_UP/DOWN, but that was a fail
Here's my code :
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getPointerCount() > 1)
{
int x1 = (int) event.getX(0);
int y1 = (int) event.getY(0);
int x2 = (int) event.getX(1);
int y2 = (int) event.getY(1);
d = Math.sqrt((x1-x2)^2+(y1-y2)^2);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
rotating = true;
break;
case MotionEvent.ACTION_UP:
rotating = true;
prevSwipeY = swipeY = 0; // for the Y axis
prevSwipeX = swipeX = 0; // for the X axis
break;
case MotionEvent.ACTION_MOVE:
float directionY = (prevSwipeY - event.getX()) * -1;
float directionX = (prevSwipeX - event.getY()) * -1;
swipeY = (int) (directionY * ROTATION_SPEED);
swipeX = (int) (directionX * ROTATION_SPEED);
if(event.getPointerCount() > 1)
{
int x1 = (int) event.getX(0);
int y1 = (int) event.getY(0);
int x2 = (int) event.getX(1);
int y2 = (int) event.getY(1);
d2 = Math.sqrt((x1-x2)^2+(y1-y2)^2);
r = d2/d;
}
break;
}
// Camera pivot point is different
prevSwipeY = (int) event.getX();
prevSwipeX = (int) event.getY();
return super.onTouchEvent(event);
}
#Override
public void updateScene() {
if (faceObject3D != null) { // If an object is loaded
if (swipeY != 0) // and we did swiped in the correct direction
faceObject3D.rotation().y += swipeY;
swipeY = 0; // Reset the pointer
if (swipeX != 0) // and we did swiped in the correct direction
faceObject3D.rotation().x += swipeX;
swipeX = 0; // Reset the pointer
if(r != 0) {faceObject3D.scale().x = faceObject3D.scale().y = faceObject3D.scale().z = (float) (r*2.0f);};
}
}
Do yo know what is missing ?

android jumps around?

zoom jumps around when I remove my finger and put it again ! anybody knows the problem ?
boolean surfaceTouchEvent(MotionEvent event) {
pointNum=event.getPointerCount();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
// User is pressing down another finger.
float x11 = event.getX(0) - event.getX(1);
float y22 = event.getY(0) - event.getY(1);
z4 = sqrt(x11*x11+y22*y22);
break;
case MotionEvent.ACTION_POINTER_UP:
// User is released one of the fingers.
break;
case MotionEvent.ACTION_MOVE:
if (pointNum >= 2 ) {
x1=event.getX(0);
x2=event.getX(1);
y1=event.getY(0);
y2=event.getY(1);
float x = event.getX(0) - event.getX(1);
float y= event.getY(0) - event.getY(1);
float z3 = sqrt(x*x+y*y);
if (pointNum >= 2 ) {
if ( z3 < z4 ) {
zoom = z3/z4;
}
else {
zoom = z3/z4;
}
zoom = constrain(zoom, 0, 100);
}
press1=event.getSize(0);
press2=event.getSize(1);
}
break;
}
return super.surfaceTouchEvent(event);
}

How to disable resizing image in a imagaivew after scaling it?

I'm writing a application that there are a upper-imageview and a scollview under the imageview.
The imageview is used by a class provided by my friend, it supports pinch zoom, but after i zood in the image then i touch the scollview below, the image will resize to fit the imageview's size.
It's a big trouble for me to build my app because i want to scroll the information after zooming.
Then i try to change the scrollview to be a imageview as well, i find that there is not resizimg between two views.
I wonder if it is possible to disable the resizing function for the imageview to implement my idea.
The class below is used for the imageview.
Thank you for solutions.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
public class TouchImageView extends ImageView {
Matrix matrix = new Matrix();
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 3f;
float[] m;
float redundantXSpace, redundantYSpace;
float width, height;
static final int CLICK = 3;
float saveScale = 1f;
float right, bottom, origWidth, origHeight, bmWidth, bmHeight;
int windowId;
ScaleGestureDetector mScaleDetector;
Context context;
public TouchImageView(Context context,int id) {
super(context);
super.setClickable(true);
this.context = context;
this.windowId=id;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
setBackgroundColor(Color.BLACK);
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
EasyPageActivity.resetView();
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float scaleWidth = Math.round(origWidth * saveScale);
float scaleHeight = Math.round(origHeight * saveScale);
if (scaleWidth < width) {
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
} else if (scaleHeight < height) {
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
} else {
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
matrix.postTranslate(deltaX, deltaY);
last.set(curr.x, curr.y);
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
if(windowId==1){
EasyPageActivity.defineId(1);
}
if(windowId==2){
EasyPageActivity.defineId(2);
}
if(windowId==3){
EasyPageActivity.defineId(3);
}
if(windowId==4){
EasyPageActivity.defineId(4);
}
if(windowId==5){
EasyPageActivity.defineId(5);
}
if(windowId==6){
EasyPageActivity.defineId(6);
}
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}
});
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
bmWidth = bm.getWidth();
bmHeight = bm.getHeight();
}
public void setMaxZoom(float x)
{
maxScale = x;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
#Override
public boolean onScale(ScaleGestureDetector detector) {
float mScaleFactor = (float)Math.min(Math.max(.301f, detector.getScaleFactor()), 4);
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
if (origWidth * saveScale <= width || origHeight * saveScale <= height) {
matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
if (mScaleFactor < 1) {
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (Math.round(origWidth * saveScale) < width) {
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
} else {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
}
}
}
} else {
matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
}
return true;
}
}
#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
//Fit to screen.
float scale;
float scaleX = (float)width / (float)bmWidth;
float scaleY = (float)height / (float)bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
saveScale = 1f;
// Center the image
redundantYSpace = (float)height - (scale * (float)bmHeight) ;
redundantXSpace = (float)width - (scale * (float)bmWidth);
redundantYSpace /= (float)2;
redundantXSpace /= (float)2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = width - 2 * redundantXSpace;
origHeight = height - 2 * redundantYSpace;
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
setImageMatrix(matrix);
}
}
Did you find any solution?
If not, then you must understand that your image re-sizes itself to fit the screen in the onMeasure method. So, to detect the problem you must debug and see why onMeasure is called after you change the focus to the ScrollView. Try to put some logs and see the flow of actions.

Categories

Resources