title: Rotation image with its canvas objects in Android
body: <p>I'm using Eclipse to write android app. as navigation system.
  And I'm using  "TouchImageView" class to showing the map and the map points on its canvas.</p>
  
  <pre><code>import java.util.ArrayList;
  import java.util.List;
  import android.annotation.SuppressLint;
  import android.content.Context;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.Matrix;
  import android.graphics.Paint;
  import android.graphics.Point;
  import android.graphics.PointF;
  import android.graphics.drawable.Drawable;
  import android.util.AttributeSet;
  import android.util.Log;
  import android.view.MotionEvent;
  import android.view.ScaleGestureDetector;
  import android.view.View;
  import android.widget.ImageView;
  
  public class TouchImageView extends ImageView {
  
  Matrix 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 = 50f;
  float[] m;
  
  List&lt;Point&gt; AllPoints;
  
  
  int viewWidth, viewHeight;
  static final int CLICK = 3;
  float saveScale = 1f;
  protected float origWidth, origHeight;
  int oldMeasuredWidth, oldMeasuredHeight;
  float upx = 0, upy = 0;
  public boolean ShowDrawingsOnMap;
  ScaleGestureDetector mScaleDetector;
  
  Context context;
  
  public int OriginalImageWidth=424;
  public int OriginalImageHeight=592;
  float CurrentDegree=0;
  
  public TouchImageView(Context context) {
      super(context);
      sharedConstructing(context);
  }
  
  
  public TouchImageView(Context context, AttributeSet attrs) {
      super(context, attrs);
      sharedConstructing(context);
  }
  
  
  
  
  private Point GetRealPos(float x, float y)
  { 
      int centerX=ImageCenter.x+xTrans;
      int centerY=ImageCenter.y+yTrans;
      double theta = CurrentDegree * Math.PI;
      theta = theta / 180;
      theta = -theta;
      double newx = (x - centerX) * Math.cos(theta) + (y - centerY) * Math.sin(theta) + centerX;
      double newy = -(x - centerX) * Math.sin(theta) + (y - centerY) * Math.cos(theta) + centerY;
      return new Point((int)newx, (int)newy);
  }
  
  boolean IfFirstInitialized=true;
  @SuppressLint("DrawAllocation")
  @Override
  protected void onDraw(Canvas canvas) {   
      super.onDraw(canvas);
  
  
  
      // Define Paint     
      Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
      paint.setColor(Color.RED);
  
  
      int xOrigin=AllPoints.get(0).x;
      int yOrigin=AllPoints.get(0).y; 
      int x = (int) (((xOrigin*(origWidth/424)*saveScale)+upx));
      int y = (int) (((yOrigin*(origHeight/592)*saveScale)+upy));
  
      if(ImageCenter==null)
      {
          canvas.drawCircle(x, y, 5, paint);
      }
      else
      {
          Point point = GetRealPos(x, y);
          canvas.drawCircle(point.x, point.y, 5, paint);
      }
  
  }
  
  
  
  boolean IfRotate=false;
  Point ImageCenter=null;
  @SuppressLint("NewApi")
  public void rotate(float degree) {      
      IfRotate=true;
      CurrentDegree +=degree;     
  
      //If ImageCenter at first time initialized
      if(ImageCenter==null)
      {
          int XmidImage=(int) (origWidth/2+upx);
          int YmidImage=(int) (origHeight/2+upy);
          ImageCenter=new Point(XmidImage, YmidImage);
      }   
      matrix.postRotate(degree, ImageCenter.x+xTrans, ImageCenter.y+yTrans);      
  
      setImageMatrix(matrix);
      invalidate();
  
  }
  
  
  
  private void sharedConstructing(Context context) {
      /*********************************/
      AllPoints=new ArrayList&lt;Point&gt;();
      AllPoints.add(new Point(250, 200));
      /********************************/
  
      super.setClickable(true);
      this.context = context;
      ShowDrawingsOnMap=true;
      mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
  
      matrix = new Matrix();
      m = new float[9];
      setImageMatrix(matrix);
      setScaleType(ScaleType.MATRIX);
  
      setOnTouchListener(new OnTouchListener() {
          @Override
          public boolean onTouch(View v, MotionEvent event) {
              mScaleDetector.onTouchEvent(event);
              PointF curr = new PointF(event.getX(), event.getY());
  
  
              switch (event.getAction()) {
                  case MotionEvent.ACTION_DOWN:                       
                      last.set(curr);
                      start.set(last);
                      mode = DRAG;   
                      break;
  
                  case MotionEvent.ACTION_POINTER_DOWN:
                      break;
  
                  case MotionEvent.ACTION_MOVE:
                      if (mode == DRAG) {
                          float deltaX = curr.x - last.x; 
                          float deltaY = curr.y - last.y; 
  
                          xTrans +=(int)deltaX;
                          yTrans +=(int)deltaY;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 &lt; CLICK &amp;&amp; yDiff &lt; CLICK)
                          performClick();                        
                      break;
  
                  case MotionEvent.ACTION_POINTER_UP:
                      mode = NONE; 
                      break;
              }
  
              setImageMatrix(matrix);   
              UpdateLines();
              invalidate();                 
              return true; // indicate event was handled
          }
  
      });         
  }
  
  
  
  int xTrans=0;
  int yTrans=0;
  public void UpdateLines()
  {       
      matrix.getValues(m);
      upx=m[2];
      upy=m[5];
  }
  
  
  
  
  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 = detector.getScaleFactor();
          float origScale = saveScale;
          saveScale *= mScaleFactor;
          if (saveScale &gt; maxScale) {
              saveScale = maxScale;
              mScaleFactor = maxScale / origScale;
          } else if (saveScale &lt; minScale) {
              saveScale = minScale;
              mScaleFactor = minScale / origScale;
          }
  
          if (origWidth * saveScale &lt;= viewWidth || origHeight * saveScale &lt;= viewHeight)
              matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2+xTrans, viewHeight / 2+yTrans);
          else
              matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
          return true;
      }
  }
  
  
  void fixTrans() {
      matrix.getValues(m);
      float transX = m[Matrix.MTRANS_X];
      float transY = m[Matrix.MTRANS_Y]; 
  
      float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
      float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale);
  
      if (fixTransX != 0 || fixTransY != 0) 
          matrix.postTranslate(fixTransX, fixTransY);
  }
  
  float getFixTrans(float trans, float viewSize, float contentSize) {
      float minTrans, maxTrans;
  
      if (contentSize &lt;= viewSize) {
          minTrans = 0;
          maxTrans = viewSize - contentSize;
      } else {
          minTrans = viewSize - contentSize;
          maxTrans = 0;
      }
  
      if (trans &lt; minTrans)
          return -trans + minTrans;
      if (trans &gt; maxTrans)
          return -trans + maxTrans;
      return 0;
  }
  
  float getFixDragTrans(float delta, float viewSize, float contentSize) {
      if (contentSize &lt;= viewSize) {
          return 0;
      }
      return delta;
  }
  
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      viewWidth = MeasureSpec.getSize(widthMeasureSpec);
      viewHeight = MeasureSpec.getSize(heightMeasureSpec);
  
      //
      // Rescales image on rotation
      //
      if (oldMeasuredHeight == viewWidth &amp;&amp; oldMeasuredHeight == viewHeight
              || viewWidth == 0 || viewHeight == 0)
          return;
      oldMeasuredHeight = viewHeight;
      oldMeasuredWidth = viewWidth;
  
      if (saveScale == 1) {
          //Fit to screen.
          float scale;
  
          Drawable drawable = getDrawable();
          if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0)
              return;
          int bmWidth = drawable.getIntrinsicWidth();
          int bmHeight = drawable.getIntrinsicHeight();
  
          Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);
  
          float scaleX = (float) viewWidth / (float) bmWidth;
          float scaleY = (float) viewHeight / (float) bmHeight;
          scale = Math.min(scaleX, scaleY);
          matrix.setScale(scale, scale); 
  
          // Center the image            
          float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
          float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
          redundantYSpace /= (float) 2;
          redundantXSpace /= (float) 2;
  
          matrix.postTranslate(redundantXSpace, redundantYSpace);
  
          origWidth = viewWidth - 2 * redundantXSpace;
          origHeight = viewHeight - 2 * redundantYSpace;
          setImageMatrix(matrix);
          }
          fixTrans();
          UpdateLines();
      }
  
  }
  </code></pre>
  
  <p>Now at first running time the point is drawing correctly, and if I rotate the map also it drawing correctly, but if I touching the image after rotation, the point doesn't show correct.</p>
  
  <p>In the main activity I'm using this code:</p>
  
  <pre><code>public class MainActivity extends Activity
  {
  
  RelativeLayout myLayout;
  TouchImageView img;
  
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
  
      myLayout=(RelativeLayout)findViewById(R.id.MapLayout); 
      myLayout.removeAllViews();       
      img = new TouchImageView(getApplicationContext());
      img.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
      img.setImageResource(R.drawable.map);
      myLayout.addView(img);
  
  }
  
     public void RotateLeftClick(View view)
     {
        img.rotate(-90);
     }
  }
  </code></pre>