canvas - Absolute position click potion of zoomed image in android -
i want calculate un-scaled absolute position of image drawn on canvas based on position clicked user on scaled canvas.
i used following zoom implementation translate/scale bitmap within boundaries?
so far,
public boolean inme(int x, int y, region clickregion) { if(mscalefactor == 0) mscalefactor = 1; float curx = ((x*1.0f)/ mscalefactor) - (mposx * mscalefactor); float cury = ((y*1.0f) / mscalefactor) - (mposy * mscalefactor); x = (int)curx; y = (int)cury; //clickregion grapics.region computed on non-zoomed coordinates if (clickregion.contains(x, y)) return true; else return false; }
this works fine, when there no zooming, when zoomed there significant issues.
edit
this algo used zooming , panning.
public class panzoomview extends view { public static final string tag = panzoomview.class.getname(); private static final int invalid_pointer_id = -1; // ‘active pointer’ 1 moving our object. private int mactivepointerid = invalid_pointer_id; private bitmap bitmap; private float viewheight; private float viewwidth; float canvaswidth, canvasheight; private scalegesturedetector mscaledetector; private float mscalefactor = 1.f; private float minscalefactor; private float mposx; private float mposy; private float mlasttouchx, mlasttouchy; private boolean firstdraw = true; private boolean panenabled = true; private boolean zoomenabled = true; public panzoomview(context context) { super(context); setup(); } public panzoomview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); setup(); } public panzoomview(context context, attributeset attrs) { super(context, attrs); setup(); } private void setup() { mscaledetector = new scalegesturedetector(getcontext(), new scalelistener()); } public void setbitmap(bitmap bmp) { setimagebitmap(bmp); } public void setimagebitmap(bitmap bmp) { bitmap = bmp; resetzoom(); resetpan(); firstdraw = true; invalidate(); } public bitmap getimagebitmap() { return bitmap; } public bitmap getbitmap() { return getimagebitmap(); } public void resetzoom() { mscalefactor = 1.0f; } public void resetpan() { mposx = 0f; mposy = 0f; } public void setimagedrawable(drawable drawable) { setimagebitmap(((bitmapdrawable) drawable).getbitmap()); } public bitmapdrawable getimagedrawable() { bitmapdrawable bd = new bitmapdrawable(getcontext().getresources(), bitmap); return bd; } public bitmapdrawable getdrawable() { return getimagedrawable(); } public void ondraw(canvas canvas) { // log.v(tag, "ondraw()"); if (bitmap == null) { log.w(tag, "nothing draw - bitmap null"); super.ondraw(canvas); return; } if (firstdraw && (bitmap.getheight() > 0) && (bitmap.getwidth() > 0)) { //don't let user zoom out image smaller //than containing frame float minxscalefactor = (float) viewwidth / (float) bitmap.getwidth(); float minyscalefactor = (float) viewheight / (float) bitmap.getheight(); minscalefactor = math.max(minxscalefactor, minyscalefactor); log.d(tag, "minscalefactor: " + minscalefactor); mscalefactor = minscalefactor; //start out "zoomed out" way mposx = mposy = 0; firstdraw = false; } mscalefactor = math.max(mscalefactor, minscalefactor); canvasheight = canvas.getheight(); canvaswidth = canvas.getwidth(); // log.d(tag, "canvas density: " + canvas.getdensity() + " bitmap density: " + bitmap.getdensity()); // log.d(tag, "mscalefactor: " + mscalefactor); //save canvas without translating (panning) or scaling (zooming) //after each change, restore state, instead of compounding //changes upon changes canvas.save(); int maxx, minx, maxy, miny; //regardless of screen density (hdpi, mdpi) or scale factor, //the image consists of bitmap width divided 2 pixels. if image //is 200 pixels wide , scroll right 100 pixels, scrolled image //off screen left. minx = (int) (((viewwidth / mscalefactor) - bitmap.getwidth()) / 2); maxx = 0; //how far can move image vertically without having gap between image , frame? miny = (int) (((viewheight / mscalefactor) - bitmap.getheight()) / 2); maxy = 0; log.d(tag, "minx: " + minx + " maxx: " + maxx + " miny: " + miny + " maxy: " + maxy); //do not go beyond boundaries of image if (mposx > maxx) { mposx = maxx; } if (mposx < minx) { mposx = minx; } if (mposy > maxy) { mposy = maxy; } if (mposy < miny) { mposy = miny; } // log.d(tag, "view width: " + viewwidth + " view height: " // + viewheight); // log.d(tag, "bitmap width: " + bitmap.getwidth() + " height: " + bitmap.getheight()); // log.d(tag, "translating mposx: " + mposx + " mposy: " + mposy); // log.d(tag, "zooming scale factor of " + mscalefactor); canvas.scale(mscalefactor, mscalefactor); // log.d(tag, "panning " + mposx + "," + mposy); canvas.translate(mposx, mposy); super.ondraw(canvas); canvas.drawbitmap(bitmap, mposx, mposy, null); canvas.restore(); //clear translation/scaling } @override public boolean ontouchevent(motionevent ev) { // let scalegesturedetector inspect events. if (zoomenabled) { mscaledetector.ontouchevent(ev); } if (panenabled) { final int action = ev.getaction(); switch (action & motionevent.action_mask) { case motionevent.action_down: { final float x = ev.getx(); final float y = ev.gety(); mlasttouchx = x; mlasttouchy = y; mactivepointerid = ev.getpointerid(0); break; } case motionevent.action_move: { final int pointerindex = ev.findpointerindex(mactivepointerid); final float x = ev.getx(pointerindex); final float y = ev.gety(pointerindex); // move if scalegesturedetector isn't processing gesture. if (!mscaledetector.isinprogress()) { float dx = x - mlasttouchx; float dy = y - mlasttouchy; //adjust zoom factor. otherwise, user's finger moving 10 pixels //at 200% zoom causes image slide 20 pixels instead of //following user's touch dx /= (mscalefactor * 2); dy /= (mscalefactor * 2); mposx += dx; mposy += dy; log.v(tag, "moving " + dx + "," + dy + " mscalefactor: " + mscalefactor); invalidate(); } mlasttouchx = x; mlasttouchy = y; break; } case motionevent.action_up: { mactivepointerid = invalid_pointer_id; break; } case motionevent.action_cancel: { mactivepointerid = invalid_pointer_id; break; } case motionevent.action_pointer_up: { final int pointerindex = (ev.getaction() & motionevent.action_pointer_index_mask) >> motionevent.action_pointer_index_shift; final int pointerid = ev.getpointerid(pointerindex); if (pointerid == mactivepointerid) { // our active pointer going up. choose new // active pointer , adjust accordingly. final int newpointerindex = pointerindex == 0 ? 1 : 0; mlasttouchx = ev.getx(newpointerindex); mlasttouchy = ev.gety(newpointerindex); mactivepointerid = ev.getpointerid(newpointerindex); } break; } } } return true; } private class scalelistener extends scalegesturedetector.simpleonscalegesturelistener { @override public boolean onscale(scalegesturedetector detector) { mscalefactor *= detector.getscalefactor(); // don't let object small or large. mscalefactor = math.max(0.1f, math.min(mscalefactor, 5.0f)); // log.d(tag, "detector scale factor: " + detector.getscalefactor() + " mscalefactor: " + mscalefactor); invalidate(); return true; } } //currently zoomenabled/panenabled can set programmatically, not in xml public boolean ispanenabled() { return panenabled; } public void setpanenabled(boolean panenabled) { this.panenabled = panenabled; } public boolean iszoomenabled() { return zoomenabled; } public void setzoomenabled(boolean zoomenabled) { this.zoomenabled = zoomenabled; } /** * calls getcroppedbitmap(int outputwidth, int outputheight) without * scaling resulting bitmap specific size. * @return */ public bitmap getcroppedbitmap() { return getcroppedbitmap(0, 0); } /** * takes section of bitmap visible in view object * , exports bitmap object, taking account both * translation (panning) , zoom (scaling). * warning: run in separate thread, not on ui thread! * if specify 200x200 image should have outputwidth * of 400 , outputheight of 50, image squished * , stretched dimensions. * @param outputwidth desired width of output bitmap in pixels * @param outputheight desired height of output bitmap in pixels * @return visible portion of image in panzoomimageview */ public bitmap getcroppedbitmap(int outputwidth, int outputheight) { int origx = -1 * (int) mposx * 2; int origy = -1 * (int) mposy * 2; int width = (int) (viewwidth / mscalefactor); int height = (int) (viewheight / mscalefactor); log.e(tag, "origx: " + origx + " origy: " + origy + " width: " + width + " height: " + height + " outputwidth: " + outputwidth + " outputheight: " + outputheight + "getlayoutparams().width: " + getlayoutparams().width + " getlayoutparams().height: " + getlayoutparams().height); bitmap b = bitmap.createbitmap(bitmap, origx, origy, width, height); if (outputwidth > 0 && outputwidth > 0) { //use exact dimensions given--chance won't match aspect ratio b = bitmap.createscaledbitmap(b, outputwidth, outputheight, true); } return b; } @override protected void onsizechanged(int w, int h, int oldw, int oldh) { super.onsizechanged(w, h, oldw, oldh); viewheight = h; viewwidth = w; } }
thanks comment, worked me.
public boolean inme(int x, int y, region clickregion) { float curx = ((x*1.0f)) + (-1*mposx * 2* mscalefactor); float cury = ((y*1.0f)) + (-1*mposy * 2* mscalefactor); x = (int)((curx/ mscalefactor)); y = (int)((cury/ mscalefactor)); if (cluster.clickregion.contains(x, y)) return true; else return false; }
Comments
Post a Comment