NewDev
NewDev

Reputation: 257

Measuring between two points

I have created my own ImageView which hopefully will do overlays , zooming , panning and measuring between two points.

So far all but the measuring works The canvas.drawline shows nothing ?

This may be dirty and could probably be cleaned quite a bit. Anyone got an Idea why the canvas.drawline does not work ?

Thanks in Advance

public class myImage extends ImageView implements OnTouchListener {

    private static final short     UNKNOWN     = 0;
    private static final short     IMG_INIT    = 1;
    private static final short     SET_IMAGE   = 2;
    private static final short     DRAGGING    = 3;
    private static final short     MARKING     = 4;
    private static final short     STARTING    = 5;
    private static final short     ZOOM_PAN    = 6;
    private static final short     OVERLAY     = 7;
    private static short     STATE       = UNKNOWN;
    private static PointF  pointA          = null;
    private static PointF  pointB          = null;
    private static PointF  pointC          = null;
    private PointF         busy            = new PointF();
    private Bitmap         tracking        = BitmapFactory.decodeResource(getResources(), R.drawable.target);
    private Drawable[]     layers          = new Drawable[2];
    private Paint          mPaint;          
    private Bitmap         mBitmap;
    private Canvas         busyCanvas;       
    private int            touch_counter   = 0;


    @Override
    protected void onDraw(Canvas  canvas) {
        switch (STATE) {
        /* 0 */ case UNKNOWN:   super.onDraw(canvas);   break;
        /* 1 */ case IMG_INIT:  break;
        /* 2 */ case SET_IMAGE: super.onDraw(canvas);   break;
        /* 3 */ case DRAGGING:  break;
        /* 4 */ case MARKING:  
                    canvas.drawBitmap(mBitmap, matrix, mPaint);


                    if (touch_counter == 0 && pointB != null && CURRENT_STATUS == "DRAW_LINE" ) { 
mPaint.setColor(Color.BLUE);
canvas.drawLine(pointA.x, pointA.y, pointB.x, pointB.y, mPaint);
   This is What does Not Show up OR work
                                        }
                            break;

        /* 5 */ case STARTING:  break;
        /* 6 */ case ZOOM_PAN:  super.onDraw(canvas);   break;
        /* 7 */ case OVERLAY:   super.onDraw(canvas);   break;
        }

        STATE = UNKNOWN;
    }


    public void InitOverlay(String fName) {
        fName = "/sdcard/DCIM/"+fName;
        if ( (fName.endsWith(".jpg") || fName.endsWith(".png")) ) {
            Matrix matrix = new Matrix();
            matrix.postScale(0.35f, 0.35f);
            Bitmap  bitm2 = BitmapFactory.decodeFile( fName );
            layers[0] = new BitmapDrawable( mBitmap );  layers[0].setAlpha(255);
            layers[1] = new BitmapDrawable( Bitmap.createBitmap(bitm2, 0, 0, bitm2.getWidth(), bitm2.getHeight(), matrix, true) );  layers[1].setAlpha( 50);
            LayerDrawable layerDraw = new LayerDrawable(layers);
            super.setImageDrawable(layerDraw);
            super.invalidate();
            STATE = OVERLAY;
        }
    }

    private void OverLay(View view , MotionEvent event) {
        if ( STATE == UNKNOWN && event.getAction() == MotionEvent.ACTION_MOVE) {
            STATE = OVERLAY;
            if ( event.getX() > 1 && event.getX() < 1130 ) {
                layers[1].setAlpha(  (int) (event.getX() / 4.35f) );
            }
        }
    }

    private void AddPoints(View view , MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:  touch_start(event.getX() , event.getY());   break;
            case MotionEvent.ACTION_MOVE:  touch_busy (event.getX() , event.getY());   break;
            case MotionEvent.ACTION_UP:    touch_end  (event.getX() , event.getY());   break;
        }
    }

    private void touch_start(float x, float y) {
        STATE = STARTING;
        touch_counter++;
        busy.x = ((x - 32.0f + (float)getScrollX()));
        busy.y = ((y - 70.0f + (float)getScrollY()));
    }

    private void touch_busy(float x, float y) {
        busy.x = ((x - 32.0f + (float)getScrollX()));
        busy.y = ((y - 70.0f + (float)getScrollY()));
        STATE = DRAGGING;
    }

    private void touch_end(float x, float y) {
        STATE = MARKING;
        if (touch_counter == 1) {
            pointA   = new PointF();
            pointA.x = ((x - 32.0f));   // + ViewOffset.x));
            pointA.y = ((y - 70.0f));   // + ViewOffset.y));
        } else if (touch_counter == 2) {
            pointB   = new PointF();
            pointB.x = ((x - 32.0f));
            pointB.y = ((y - 70.0f));

            if (CURRENT_STATUS == "DRAW_LINE")   touch_counter = 0;  

Log.i("Image" , "At this Point Calling  Draw   ");      
super.draw(busyCanvas);

        }
    }





    public myImage(Context context , FrameLayout screen) {
        super(context);
        super.setLayerType(LAYER_TYPE_HARDWARE, null);

        mPaint  = new Paint();

        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(0xFF0000FF);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(5);

        STATE = IMG_INIT;
        invalidate();
    }

    public void freeImage() {
        try {
            mBitmap.recycle();
            tracking.recycle();
        } catch (Exception err) {
            ImageExceptionHandler(err);
        }
    }

    @Override
    public void setImageBitmap(Bitmap bmp) {
        try {
            STATE      = SET_IMAGE;
            busyCanvas = new Canvas();
            busyCanvas.setBitmap(bmp);
            mBitmap    = bmp;
            busyCanvas.setBitmap(bmp);

        } catch (Exception err) {
            ImageExceptionHandler(err);
        }
        super.setImageBitmap(bmp);
    }

    private void ImageExceptionHandler(Exception err) {
        Log.e("image" , "==============================================");
        Log.e("image" , "EXCEPTION Handling ");
        Log.e("image" , "==============================================");
        err.printStackTrace();
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if      (CURRENT_STATUS == "PAN & ZOOM"      )  ScrollAndZoom(v , event);   
        else if (CURRENT_STATUS == "OVERLAY"         )  OverLay(v , event);
        else if (CURRENT_STATUS == "DRAW_LINE"       )  AddPoints(v , event);
        else  {
                Log.w("ERROR" , "Should Never Be Here  myImage On Touch"); 
                Log.w("ERROR" , "Should Never Be Here  myImage On Touch"); 
        }
        return true;
    }


    public void init() {
        super.setScaleType( ImageView.ScaleType.MATRIX   );
        mode       = NONE;
        matrix     = new Matrix();
                        matrix.set(getImageMatrix());
        savematrix = new Matrix();
        start      = new PointF();
        mid        = new PointF();
        oldDist    = 1f;
        oldfactor  = 1f;
        factor     = 1f;
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.i("Image" , "Size Changed   ["+w+"] x ["+h+"]      ["+oldw+"] x ["+oldh+"]   ");        
        super.onSizeChanged(w, h, oldw, oldh);
    }

    private static final short  NONE       = 0;
    private static final short  ZOOM       = 1;
    private static final short  DRAG       = 2;
    private Matrix  matrix     = new Matrix();
    private Matrix  savematrix = new Matrix();
    private short   mode       = NONE;
    private PointF  start      = new PointF();
    private PointF  mid        = new PointF();
    private float   oldDist    = 1f;
    private float   oldfactor  = 1f;
    private float   factor     = 1f;

    private void ScrollAndZoom(View view , MotionEvent event) {
        STATE = ZOOM_PAN;
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:               start.set(event.getX() , event.getY());
                                                        savematrix.set(matrix);
                                                        mode = DRAG;
                                                        break;
            //------------------------------------------------
            case MotionEvent.ACTION_POINTER_DOWN:       oldDist = spacing(event);
                                                        midPoint(mid , event);
                                                        mode = ZOOM;
                                                        oldfactor = factor;
                                                        break;
            //------------------------------------------------

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:         start = new PointF();
                                                        mode = NONE;
                                                        matrix.set(getImageMatrix());                                           
                                                        setBackgroundColor(Color.BLACK);
                                                        break;
            //------------------------------------------------
            case MotionEvent.ACTION_MOVE:               matrix.set(savematrix);
                                                        if (mode == DRAG) {
                                                            float dx = event.getX() - start.x;
                                                            float dy = event.getY() - start.y;
                                                            setBackgroundColor(Color.BLACK);
                                                            matrix.postTranslate(dx, dy);
                                                            setImageMatrix(matrix);
                                                        } else if (mode == ZOOM) {
                                                            float newD      = spacing(event);
                                                            float newfactor = newD / oldDist;
                                                            factor = oldfactor * newfactor;
                                                            zoom(newfactor);
                                                        }
                                                        break;
            //------------------------------------------------
        }
    }

    private void zoom (Float scale) {
        setBackgroundColor(Color.BLACK);
        matrix.postScale(scale , scale , mid.x , mid.y);
        setImageMatrix(matrix);
    }

    private float spacing(MotionEvent event) {
        float dx = event.getX(1) - event.getX(0);
        float dy = event.getY(1) - event.getY(0);
        return FloatMath.sqrt(dx*dx + dy*dy);
    }

    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 / 2f , y / 2f);
    }



}

Making some progress some steps backwards I have re-written some of it It will now Draw the Line and Zoom the entire image with the line zooming also.

However if I draw a line, then Zoom in Good ! But When I draw again it draws the line a Ultra zooms in, and when you zoom out most of the image is now lost? ? and ideas why?
Thanks in advance

Here is the current code

 public class myImage extends ImageView implements OnTouchListener {
    private static final short   NONE        = 0;
    private static final short   ZOOM        = 1;
    private static final short   DRAG        = 2;
    private static short         mode        = NONE;
    private static PointF  pointA          = null;
    private static PointF  pointB          = null;
    private ImageView      pointer         = null;
    private PointF         busy            = new PointF();
    private PointF         start           = new PointF();
    private PointF         mid             = new PointF();
    private Matrix         matrix          = new Matrix();
    private Matrix         savematrix      = new Matrix();
    private Bitmap         tracking        = BitmapFactory.decodeResource(getResources(), R.drawable.target);
    private Drawable[]     layers          = new Drawable[2];
    private Bitmap         mBitmap;
    private Canvas         mCanvas;         
    private Paint          mPaint;
    private int            touch_counter   = 0;
    private long           touchTime       = -1;
    private float          oldDist         = 1f;
    private float          oldfactor       = 1f;
    private float          factor          = 1f;


public myImage(Context context , FrameLayout screen) {
    super(context);
    super.setLayerType(LAYER_TYPE_HARDWARE, null);

    mPaint  = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(0xFF0000FF);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(2);
    mPaint.setTextSize(20f);

    super.setScaleType( ImageView.ScaleType.MATRIX   );
    mode       = NONE;
    matrix     = new Matrix();
    matrix.set(getImageMatrix());
    savematrix = new Matrix();
    start      = new PointF();
    mid        = new PointF();
    oldDist    = 1f;
    oldfactor  = 1f;
    factor     = 1f;
}

public void freeImage() {
    try {
        mBitmap.recycle();
        tracking.recycle();
    } catch (Exception err) {
        ImageExceptionHandler(err);
    }
}

@Override
public void setImageBitmap(Bitmap bmp) {
    try {
        mBitmap    = bmp;
        mCanvas    = new Canvas(bmp);
        mCanvas.setBitmap(bmp);

    } catch (Exception err) {
        ImageExceptionHandler(err);
    }
    super.setImageBitmap(bmp);
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    if      ( CURRENT_STATUS == "PAN & ZOOM" )    ScrollAndZoom(v , event);   
    else if ( CURRENT_STATUS == "DRAW_LINE"  )    AddPoints(v , event);
    else  {
            Log.w("ERROR" , "Should Never Be Here  myImage On Touch"); 
            Log.w("ERROR" , "Should Never Be Here  myImage On Touch  ["+eedsActivity.CURRENT_STATUS+"]   "); 
            Log.w("ERROR" , "Should Never Be Here  myImage On Touch  ["+eedsActivity.CURRENT_IMAGE +"]   "); 
            Log.w("ERROR" , "Should Never Be Here  myImage On Touch"); 
    }
    return true;
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    Log.i("Image" , "Size Changed   ["+w+"] x ["+h+"]      ["+oldw+"] x ["+oldh+"]   ");        
    super.onSizeChanged(w, h, oldw, oldh);
}

private void myDrawLine(PointF ptA , PointF ptB) {
    mCanvas.drawBitmap(mBitmap , matrix , mPaint);

    mPaint.setColor(Color.BLUE);
    mCanvas.drawLine( ptA.x , ptA.y , ptB.x , ptB.y , mPaint);

    if (ptA.x <= ptB.x )  mCanvas.translate( (ptA.x + 0.0f), (ptA.y + 0.0f) );
    else                  mCanvas.translate( (ptA.x + 0.0f), (ptA.y + 0.0f) );

    line newLine = new line(ptA , ptB , factor);
    switch (newLine.getQuadrant()) {
        case 1:  mCanvas.rotate( (float) newLine.getAngle() );         break;
        case 2:  mCanvas.rotate( (newLine.getAngle() - 180.0f) );      break;
        case 3:  mCanvas.rotate( (newLine.getAngle() + 180.0f) );      break;
        case 4:  mCanvas.rotate( (float) newLine.getAngle() );         break;
    }

    String result = "";
    mPaint.setColor(Color.YELLOW);    
    result  = String.format("%4.3f mm", newLine.getDistance() ); 
    mCanvas.drawText( result, ((newLine.getDistance() * line.PX_TO_MM) / 3.0f), -6.0f, mPaint);

    invalidate();
}


public void recenter() {
    oldDist    = 1f;
    oldfactor  = 1f;
    factor     = 1f;
    setBackgroundColor(Color.BLACK);
    matrix.setScale(1f, 1f);
    matrix.postTranslate(0f , 0f);
    setImageMatrix(matrix);
}

private void AddPoints(View view , MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:  touch_start(event.getX() , event.getY());   break;
        case MotionEvent.ACTION_MOVE:  touch_busy (event.getX() , event.getY());   break;
        case MotionEvent.ACTION_UP:    touch_end  (event.getX() , event.getY());   break;
    }
}

private void touch_start(float x, float y) {
    touch_counter++;
    busy.x = (x - 32.0f);
    busy.y = (y - 70.0f);
    LayoutParams  lp = new LayoutParams(32 , 32);
    pointer = new ImageView(super.getContext());
    pointer.setBackgroundDrawable(getResources().getDrawable(R.drawable.target2));
    lp.leftMargin = (int) x;
    lp.topMargin  = (int) y;
    ((ViewGroup) super.getParent()).addView(pointer , lp);
}

private void touch_busy(float x, float y) {
    busy.x = (x - 32.0f);
    busy.y = (y - 70.0f);
    if (pointer != null) {
        pointer.setLeft( (int)busy.x );         pointer.setRight ( (int)(busy.x+32) );
        pointer.setTop ( (int)busy.y );         pointer.setBottom( (int)(busy.y+32) );
    }
}

private void touch_end(float x, float y) {
    ((ViewGroup) super.getParent()).removeView(pointer);
    if (touch_counter == 1) {
        pointA   = new PointF();
        pointA.x = ((x - 32.0f));
        pointA.y = ((y - 70.0f));

    } else if (touch_counter == 2) {
        pointB   = new PointF();
        pointB.x = ((x - 32.0f));
        pointB.y = ((y - 70.0f));
    }

    if (touch_counter == 2) {
        myDrawLine(pointA , pointB);

        pointA     = null;    pointB     = null;
        pointC     = null;    touch_counter = 0;

    }
}


private void ScrollAndZoom(View view , MotionEvent event) {
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:               if ((System.currentTimeMillis() - touchTime)  < 400) {
                                                    // Double Click
                                                        touchTime = -1;
                                                        setBackgroundColor(Color.BLACK);
                                                        matrix.setScale(1f, 1f);
                                                        matrix.postTranslate(0f , 0f);
                                                        setImageMatrix(matrix);
                                                    } else {
                                                    // Single Click
                                                        touchTime = System.currentTimeMillis();
                                                        start.set(event.getX() , event.getY());
                                                        savematrix.set(matrix);
                                                        mode = DRAG;
                                                    }
                                                    break;
        //------------------------------------------------
        case MotionEvent.ACTION_POINTER_DOWN:       touchTime = -1;
                                                    oldDist = distance(event);
                                                    midPoint(mid , event);
                                                    mode = ZOOM;
                                                    oldfactor = factor;
                                                    break;
        //------------------------------------------------
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_POINTER_UP:         start = new PointF();
                                                    mode = NONE;
                                                    matrix.set(getImageMatrix());
                                                    setBackgroundColor(Color.BLACK);
                                                    break;
        //------------------------------------------------
        case MotionEvent.ACTION_MOVE:               matrix.set(savematrix);
                                                    if (mode == DRAG) {
                                                        float dx = event.getX() - start.x;
                                                        float dy = event.getY() - start.y;
                                                        setBackgroundColor(Color.BLACK);
                                                        matrix.postTranslate(dx, dy);
                                                        setImageMatrix(matrix);
                                                    } else if (mode == ZOOM) {
                                                        float newD      = distance(event);
                                                        float newfactor = newD / oldDist;
                                                        factor = oldfactor * newfactor;
                                                        setBackgroundColor(Color.BLACK);
                                                        matrix.postScale(newfactor , newfactor , mid.x , mid.y);
                                                        setImageMatrix(matrix);
                                                    }
                                                    break;
        //------------------------------------------------
    }
}

private float distance(MotionEvent event) {
    float dx = event.getX(1) - event.getX(0);
    float dy = event.getY(1) - event.getY(0);
    return FloatMath.sqrt(dx*dx + dy*dy);
}

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 / 2f , y / 2f);
}




private void ImageExceptionHandler(Exception err) {
    Log.e("image" , "==============================================");
    Log.e("image" , "EXCEPTION Handling ");
    Log.e("image" , "==============================================");
    err.printStackTrace();
}
}

Upvotes: 0

Views: 670

Answers (2)

E.Z. Hart
E.Z. Hart

Reputation: 5757

Your line is only drawn when STATE is 'MARKING'; at the end of onDraw you're setting your state back to UNKNOWN which calls the base class's onDraw but doesn't draw your line. If you want your line to stick around in other states, you'll have to redraw it every time onDraw gets called.

Upvotes: 0

Geobits
Geobits

Reputation: 22342

It looks to me like pointB is always null, because you only ever get one ACTION_DOWN per gesture. When the first finger goes down, you get the action, and it triggers touch_start(), setting touch_counter to 1. When the second finger goes down, it doesn't, because you get an ACTION_POINTER_DOWN instead, which isn't checked for.

That's assuming you want a two-finger gesture. If it's meant to be a 'touch here and then touch there' instead, then you shouldn't set touch_counter to zero with each touch_end().

Upvotes: 1

Related Questions