Corresponding rotated object to numeric values

You should reorganize your code completely. Post-multiplying new rotations into a matrix over and over again is a numerically unstable computation. Eventually the bitmap will become distorted. Trying to retrieve the rotation angle from the matrix is too complex and unnecessary.

First note that this is a useful prior article on drawing bitmaps with rotation about a chosen point.

Just maintain a single double dialAngle = 0 that is the current rotation angle of the dial.

You are doing way too much work to retrieve the angle from the touch location. Let (x0,y0) be the location where the touch starts. At that time,

// Record the angle at initial touch for use in dragging.
dialAngleAtTouch = dialAngle;
// Find angle from x-axis made by initial touch coordinate.
// y-coordinate might need to be negated due to y=0 -> screen top. 
// This will be obvious during testing.
a0 = Math.atan2(y0 - yDialCenter, x0 - xDialCenter);

This is the starting angle. When the touch drags to (x,y), use this coordinate to adjust the dial with respect to the initial touch. Then update the matrix and redraw:

// Find new angle to x-axis. Same comment as above on y coord.
a = Math.atan2(y - yDialCenter, x - xDialCenter);
// New dial angle is offset from the one at initial touch.
dialAngle = dialAngleAtTouch + (a - a0); 
// normalize angles to the interval [0..2pi)
while (dialAngle < 0) dialAngle += 2 * Math.PI;
while (dialAngle >= 2 * Math.PI) dialAngle -= 2 * Math.PI;

// Set the matrix for every frame drawn. Matrix API has a call
// for rotation about a point. Use it!
matrix.setRotate((float)dialAngle * (180 / 3.1415926f), xDialCenter, yDialCenter);

// Invalidate the view now so it's redrawn in with the new matrix value.

Note Math.atan2(y, x) does all of what you're doing with quadrants and arcsines.

To get the "tick" of the current angle, you need 2 pi radians to correspond to 100, so it's very simple:

double fractionalTick = dialAngle / (2 * Math.Pi) * 100;

To find the actual nearest tick as an integer, round the fraction and mod by 100. Note you can ignore the matrix!

 int tick = (int)(fractionalTick + 0.5) % 100;

This will always work because dialAngle is in [0..2pi). The mod is needed to map a rounded value of 100 back to 0.


To better understand what the matrix does, it's helpful to understand 2d graphics transform matrices: http://en.wikipedia.org/wiki/Transformation_matrix#Examples_in_2D_graphics . If the only thing that you are doing is rotating (not, say, transforming or scaling) it is relatively easy to extract rotation. But, more practically, you may modify the rotation code, and store a state variable

    private float rotationDegrees = 0;

    /**
     * Rotate the dialer.
     *
     * @param degrees The degrees, the dialer should get rotated.
     */
    private void rotateDialer(float degrees)
            matrix.postRotate(degrees, dialerWidth / 2, dialerHeight / 2);

            this.rotationDegrees += degrees;

            // Make sure we don't go over 360
            this.rotationDegrees = this.rotationDegrees % 360

            dialer.setImageMatrix(matrix);
    }

Keep a variable to store the total rotation in degrees, which you increment in your rotate function. Now, we know 3.6 degrees is a tick. Simple math yields

tickNumber = (int)rotation*100/360
// It could be negative
if (tickNumber < 0)
    tickNumber = 100 - tickNumber

The one last thing you have to check for: If you have a rotation of exactly 360 degrees, or a tick number of 100, you have to treat it as 0 (since there is no tick 100)


This should be a simple multiplication with a "scale" factor that scales down your degree value (0-359) to your 0-99 scale:

float factor = 99f / 359f;
float scaled = rotationDegree * factor;

EDIT: Correcting the getAngle function

For getAngle you could use the atan2 function instead, which transforms cartesian coordinates into an angle.

Just store the first touch coordinate on touch down and on move you can apply the following calculation:

            // PointF a = touch start point
            // PointF b = current touch move point

            // Translate to origin:
            float x = b.x - a.x;
            float y = b.y - a.y;

            float radians = (float) ((Math.atan2(-y, x) + Math.PI + HALF_PI) % TWO_PI);

The radians have a range of two pi. the modulo calculations rotate it so a value of 0 points up. The rotation direction is counter-clockwise.

So you'd need to convert that to degrees and change rotation direction for getting the correct angle.