title: Android - Find original X and Y point from image view after scale zoom
body: <p>I'm building a &quot;find the different&quot; app, and I'm stucked on a problem for a while now..
  My app receives X and Y points from a data source and when the user touches the range of that point he has &quot;found the different&quot;.</p>
  <p>The problem is that I've created a new feature that let the user zoom in and move for a better view of the image... and when he touches the image the x and y are incorrect</p>
  <p>I'm trying to find the original point before the scale and the translation.</p>
  <p>Relevant part of my code:</p>
  <pre><code>private inner class MyGestureListener : GestureDetector.SimpleOnGestureListener() {
  
      override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
          if (e.action == MotionEvent.ACTION_UP &amp;&amp; SystemClock.elapsedRealtime() - GlobalEventHelper.lastClickTime &lt; TOUCH_DEBOUNCE_TIME) {
              return true
          }
          GlobalEventHelper.lastClickTime = SystemClock.elapsedRealtime()
          callback.onImageTap(e, SharedZoomImageValues.zoomScale)
          return true
      }
      
      override fun onDoubleTap(e: MotionEvent?): Boolean {
          resetZoom()
          callback.onImageMovement(id)
          return true
      }
  
      override fun onDown(motionEvent: MotionEvent): Boolean {
          val currentPoint = PointF(motionEvent.x, motionEvent.y)
          SharedZoomImageValues.lastPoint.set(currentPoint)
          SharedZoomImageValues.startPoint.set(SharedZoomImageValues.lastPoint)
          imageMatrix = SharedZoomImageValues.touchMatrix
          callback.onImageMovement(id)
          return false
      }
  
      override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
          if (SharedZoomImageValues.eImageState == EImageState.DRAG || SharedZoomImageValues.eImageState == EImageState.ZOOM) {
              val currentPoint = PointF(e2!!.x, e2.y)
              val dx = currentPoint.x - SharedZoomImageValues.lastPoint.x
              val dy = currentPoint.y - SharedZoomImageValues.lastPoint.y
              val fixTransX = getFixDragTrans(dx, SharedZoomImageValues.viewWidth.toFloat(), SharedZoomImageValues.origWidth * SharedZoomImageValues.zoomScale)
              val fixTransY = getFixDragTrans(dy, SharedZoomImageValues.viewHeight.toFloat(), SharedZoomImageValues.origHeight * SharedZoomImageValues.zoomScale)
              SharedZoomImageValues.touchMatrix.postTranslate(fixTransX, fixTransY)
              fixTranslation()
              SharedZoomImageValues.lastPoint[currentPoint.x] = currentPoint.y
              imageMatrix = SharedZoomImageValues.touchMatrix
              callback.onImageMovement(id)
          }
          return false
      }
  }
  
  private inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
      override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
  
          if (!isZoomEnabled) {
              return true
          }
  
          SharedZoomImageValues.eImageState = EImageState.ZOOM
          return true
      }
  
      override fun onScale(detector: ScaleGestureDetector): Boolean {
  
          if (!isZoomEnabled) {
              return true
          }
  
          SharedZoomImageValues.scaleFocusX = detector.focusX
          SharedZoomImageValues.scaleFocusY = detector.focusY
          SharedZoomImageValues.scaleScaleFactor = detector.scaleFactor
          scaleImage(detector.scaleFactor, detector.focusX, detector.focusY)
          callback.onImageMovement(id)
          return true
      }
  }
  
  private fun scaleImage(deltaScale: Float, focusX: Float, focusY: Float) {
      var saleFactor = deltaScale
      val prevScale = SharedZoomImageValues.zoomScale
      SharedZoomImageValues.zoomScale *= saleFactor
      if (SharedZoomImageValues.zoomScale &gt; SharedZoomImageValues.mMaxScale) {
          SharedZoomImageValues.zoomScale = SharedZoomImageValues.mMaxScale
          saleFactor = SharedZoomImageValues.mMaxScale / prevScale
      } else if (SharedZoomImageValues.zoomScale &lt; SharedZoomImageValues.mMinScale) {
          SharedZoomImageValues.zoomScale = SharedZoomImageValues.mMinScale
          saleFactor = SharedZoomImageValues.mMinScale / prevScale
      }
      if (SharedZoomImageValues.origWidth * SharedZoomImageValues.zoomScale &lt;= SharedZoomImageValues.viewWidth || SharedZoomImageValues.origHeight * SharedZoomImageValues.zoomScale &lt;= SharedZoomImageValues.viewHeight) {
          SharedZoomImageValues.touchMatrix.postScale(saleFactor, saleFactor, SharedZoomImageValues.viewWidth / 2.toFloat(), SharedZoomImageValues.viewHeight / 2.toFloat())
      } else {
          SharedZoomImageValues.touchMatrix.postScale(saleFactor, saleFactor, focusX, focusY)
      }
      fixTranslation()
  }
  
  
  private fun fixTranslation() {
      SharedZoomImageValues.touchMatrix.getValues(SharedZoomImageValues.floatMatrix) //put matrix values into a float array so we can analyze
      val transX = SharedZoomImageValues.floatMatrix[Matrix.MTRANS_X] //get the most recent translation in x direction
      val transY = SharedZoomImageValues.floatMatrix[Matrix.MTRANS_Y] //get the most recent translation in y direction
      val fixTransX = getFixTranslation(transX, SharedZoomImageValues.viewWidth.toFloat(), SharedZoomImageValues.origWidth * SharedZoomImageValues.zoomScale)
      val fixTransY = getFixTranslation(transY, SharedZoomImageValues.viewHeight.toFloat(), SharedZoomImageValues.origHeight * SharedZoomImageValues.zoomScale)
      if (fixTransX != 0f || fixTransY != 0f) {
          SharedZoomImageValues.touchMatrix.postTranslate(fixTransX, fixTransY)
      }
  }
  
  private fun getFixTranslation(trans: Float, viewSize: Float, contentSize: Float): Float {
      val minTrans: Float
      val maxTrans: Float
      if (contentSize &lt;= viewSize) { // case: NOT ZOOMED
          minTrans = 0f
          maxTrans = viewSize - contentSize
      } else { //CASE: ZOOMED
          minTrans = viewSize - contentSize
          maxTrans = 0f
      }
      if (trans &lt; minTrans) { // negative x or y translation (down or to the right)
          return -trans + minTrans
      }
      if (trans &gt; maxTrans) { // positive x or y translation (up or to the left)
          return -trans + maxTrans
      }
      return 0F
  }
  
  private fun getFixDragTrans(delta: Float, viewSize: Float, contentSize: Float): Float {
      return if (contentSize &lt;= viewSize) {
          0F
      } else delta
  }
  </code></pre>
  <p>The tap part:</p>
  <pre><code>private fun onImageClicked(touchX: Float, touchY: Float) {
  
      Log.d(TAG, &quot;onImageClicked: touchX: $touchX,  touchY:$touchY&quot;)
      // the x and y point keep changing while zooming and scrolling
      
  }
  </code></pre>