Path draw in opposite direction at canvas when rotate android

2k Views Asked by At

enter image description here Hi i am erasing bitmap that is draw at canvas with touch (fingers) that is working fine the problem i am facing is after rotate bitmap at canvas paths draw in opposition direction mean bitmap erase in opposition direction of my finger touch .

DrawingPane.class

public class DrawingPanel extends ImageView implements OnTouchListener {


private Matrix mMatrix = new Matrix();
private float mScaleFactor = 1f;
private float mRotationDegrees = 0.f;
private float mFocusX = 0.f;
private float mFocusY = 0.f;  
private int mAlpha = 255;
private int mImageHeight, mImageWidth;

private ScaleGestureDetector mScaleDetector;
private RotateGestureDetector mRotateDetector;
private MoveGestureDetector mMoveDetector;
private ShoveGestureDetector mShoveDetector; 
private boolean isMoving=false;
EditPhotoActivity editActivity;


Bitmap overlayDefault;
Bitmap overlay;
Bitmap bmp,bmp2;
Paint pTouch; 
int whichTabSelected=0;

private Path mPath;
Display display ;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Float> xlist = new ArrayList<Float>();
private ArrayList<Float> ylist = new ArrayList<Float>();
@SuppressLint("NewApi")
public DrawingPanel(Context context, int colorPaint,Bitmap bmp) {
    super(context);


    if (Build.VERSION.SDK_INT >= 11) {
        setLayerType(View.LAYER_TYPE_HARDWARE, null);
    }
    display = ((Activity)context).getWindowManager().getDefaultDisplay();

    mFocusX = display.getWidth()/2f;
    mFocusY = display.getHeight()/2f;
    try {

        overlayDefault=bmp;
        overlay=bmp;
        overlay=overlay.copy(Config.ARGB_8888, true);
        overlay.setHasAlpha(true);

    } catch (Exception e) {

        e.printStackTrace();
    }

    mImageHeight    = getHeight();
    mImageWidth     = getWidth();


    // Setup Gesture Detectors
    mScaleDetector  = new ScaleGestureDetector(context, new ScaleListener());
    mRotateDetector = new RotateGestureDetector(context, new RotateListener());
    mMoveDetector   = new MoveGestureDetector(context, new MoveListener());
    mShoveDetector  = new ShoveGestureDetector(context, new ShoveListener());


    pTouch = new Paint(Paint.ANTI_ALIAS_FLAG);         
    pTouch.setXfermode(new PorterDuffXfermode(Mode.CLEAR)); 
    pTouch.setColor(Color.TRANSPARENT);
    //pTouch.setMaskFilter(new BlurMaskFilter(30, Blur.SOLID));
    pTouch.setStyle(Paint.Style.STROKE);
    pTouch.setStrokeJoin(Paint.Join.ROUND);
    pTouch.setStrokeCap(Paint.Cap.ROUND);
    pTouch.setStrokeWidth(50);
    pTouch.setAntiAlias(true);
    setFocusable(true);
    setFocusableInTouchMode(true);
    mPath = new Path();
    paths.add(mPath);
}


@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mImageHeight=getHeight();
    mImageWidth=getWidth();
    bmp  = Bitmap.createScaledBitmap(overlay, w, h, false);
    bmp2  = Bitmap.createScaledBitmap(overlayDefault, w, h, false);
    overlay = bmp.copy(Config.ARGB_8888, true);
    overlayDefault = bmp2.copy(Config.ARGB_8888, true);

}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // TODO Auto-generated method stub
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}

@Override
protected void onDraw(Canvas canvas) {

     //  mCanvas.drawBitmap(overlayDefault,0, 0, null); //exclude this line to show all as you draw

    //  mCanvas.drawCircle(X, Y, 80, pTouch);
    //draw the overlay over the background 

        float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
        float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
        mMatrix.reset();
        mMatrix.postScale(mScaleFactor, mScaleFactor);
        mMatrix.postRotate(mRotationDegrees,  scaledImageCenterX, scaledImageCenterY);

        if(isMoving)
        {
            mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
        }
        else
        {
              mMatrix.postTranslate(0,0);
        }

        canvas.setMatrix(mMatrix);

        canvas.drawBitmap(overlay,0,0, null);

        for (Path p : paths) {
            canvas.drawPath(p, pTouch);
         }
        super.onDraw(canvas);
}


public Bitmap getBitmap(){
    Bitmap b  = Bitmap.createScaledBitmap(overlay,display.getWidth()    ,display.getWidth(), false);
    overlay = b.copy(Config.ARGB_8888, true);
    return overlay;
}
public void setBitmap(Bitmap bmp1){
    overlay = bmp1;

    invalidate();
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 0;

public void touch_start(float x, float y) {

    if(xlist.size()>0 && ylist.size()>0){
        xlist.clear();
        ylist.clear();
    }
    xlist.add(x);
    ylist.add(y);
    mPath.reset();
    mPath.moveTo(x, y);
    mX = x;
    mY = y;
    mPath.transform(mMatrix, mPath);
    invalidate();
}

public void touch_move(float x, float y) {
    float dx = Math.abs(x - mX);
    float dy = Math.abs(y - mY);
    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {

        mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
        mX = x;
        mY = y;
        mPath.transform(mMatrix, mPath);
    }
    xlist.add(x);
    ylist.add(y);
    invalidate();
}

public void touch_up() {
    mPath.lineTo(mX, mY);

    mPath = new Path();
    mPath.transform(mMatrix, mPath);
    paths.add(mPath);
    invalidate();
}


public void OnTouchParent(MotionEvent event){
     mScaleDetector.onTouchEvent(event);
        mRotateDetector.onTouchEvent(event);
        mMoveDetector.onTouchEvent(event);
        mShoveDetector.onTouchEvent(event);
        float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
        float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;

        mMatrix.reset();
        mMatrix.postScale(mScaleFactor, mScaleFactor);
        mMatrix.postRotate(mRotationDegrees,  scaledImageCenterX, scaledImageCenterY);
        mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);

        float x = event.getX();
        float y = event.getY();

        /*switch (event.getAction()) {

        case MotionEvent.ACTION_DOWN:
            if(whichTabSelected==Constant.ERASE)
            {
            touch_start(x, y);
            invalidate();
            }
            break;

        case MotionEvent.ACTION_MOVE:
            if(whichTabSelected==Constant.ERASE)
            {
            touch_move(x, y);
            invalidate();
            }
            break;

        case MotionEvent.ACTION_UP:
            if(whichTabSelected==Constant.ERASE)
            {
            touch_up();
            invalidate();
            }
            break;
        }
        if(whichTabSelected==Constant.ERASE)
        {
        return true;
        }
        else
        {
            return false;
        }*/

        invalidate();

}
@Override
public boolean onTouch(View arg0, MotionEvent event) {


    if(getTabMode()==Constant.PANZOOM)
    {
    mScaleDetector.onTouchEvent(event);
    mRotateDetector.onTouchEvent(event);
    mMoveDetector.onTouchEvent(event);
    mShoveDetector.onTouchEvent(event);

    float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
    float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;



    }

    float x = event.getX();
    float y = event.getY();

    switch (event.getAction()) {

    case MotionEvent.ACTION_DOWN:
        if(getTabMode()==Constant.ERASE)
        {
        touch_start(x, y);
        invalidate();
        }
        break;

    case MotionEvent.ACTION_MOVE:
        if(getTabMode()==Constant.ERASE)
        {
        touch_move(x, y);
        invalidate();
        }
        break;

    case MotionEvent.ACTION_UP:
        if(getTabMode()==Constant.ERASE)
        {
        touch_up();
        invalidate();
        }
        break;
    }


    invalidate();
    return true;
}
public void setBottomTabMode(int mode)
{
    whichTabSelected=mode;
}
public int getTabMode()
{
    return whichTabSelected;
}


private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        mScaleFactor *= detector.getScaleFactor(); // scale change since previous event

        // Don't let the object get too small or too large.

        mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f)); 
        return true;
    }
}

private class RotateListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
    @Override
    public boolean onRotate(RotateGestureDetector detector) {
        mRotationDegrees -= detector.getRotationDegreesDelta();
        return true;
    }
}   

private class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener {
    @Override
    public boolean onMove(MoveGestureDetector detector) {
        PointF d = detector.getFocusDelta();
        mFocusX += d.x;
        mFocusY += d.y;     
        isMoving=true;
        // mFocusX = detector.getFocusX();
        // mFocusY = detector.getFocusY();
        return true;
    }
}       

private class ShoveListener extends ShoveGestureDetector.SimpleOnShoveGestureListener {
    @Override
    public boolean onShove(ShoveGestureDetector detector) {
        mAlpha += detector.getShovePixelsDelta();
        if (mAlpha > 255)
            mAlpha = 255;
        else if (mAlpha < 0)
            mAlpha = 0;

        return true;
    }
}
}
2

There are 2 best solutions below

0
On BEST ANSWER

I fixed my problem. Actually when i rotate canvas the event.getX() and event.getY() were not map to current rotation of matrix so by adding this line in mMatrix.invert(tempMatrix); in OnDraw() and also map current x,y in OnTouch() by adding this in OnTouch() method .

   float[] coords = new float[] { event.getX(), event.getY() };            
   tempMatrix.mapPoints(coords);

        float x =  coords[0];//event.getX();
        float y = coords[1];//event.getY();

its working fine .

1
On

This effect is happening because you are applying the matrix twice to paths.

Once at touch_start/touch_move by doing mPath.transform(mMatrix, mPath);.

And then again at onDraw(Canvas canvas) by canvas.setMatrix(mMatrix); and then canvas.drawPath(p, pTouch);.

To fix, try to remove the mPath.transform(mMatrix, mPath); from touch_start/touch_move.

Also, I do not know if it is a good practice to set the matrix directly to the canvas. Instead of canvas.setMatrix(mMatrix);, I would prefer to do the following:

    canvas.save();
    canvas.concat(mMatrix);
    //write the code....
    canvas.restore();