Since you already have the information about the rotation, that is good. All you need to do now is apply rotation matrix to the original center point of your circle (as original, I am referring to the point that is already translated and it's rotation angle is 0°... you have that information in your code). As you can see from the webpage I provided you, the equation to get current x and y values would be:
x_new = x_original * Math.cos(mAngle) - y_original * Math.sin(mAngle);
y_new = x_original * Math.sin(mAngle) + y_original * Math.cos(mAngle);
Note: sin
and cos
functions take an angular parameter that is in RADians. As I can see you were doing some converting on your own, you can use Math.toDegrees(double radians) and Math.toRadians(double degrees)
You can use the same principle for the other three points if you need them.
EDIT: Explaining what is wrong with your code and pasting a simple solution
Download the source HERE
There are two things wrong with your code.
- Canvas rotates object in the clockwise direction, which is the opposite of how math defines rotation. (If you see this and know the guy that made it this way, give him a slap to the face in my name). To fix this, you have to use a negative angle of rotation.
- You are rotating your point arround the center of the view, yet you are using touch values in Android's coordinate system. The two are offset like this image shows (I know, I'm terrible with images. Sorry)

Meaning that if you convert a point from the coordinate system 0 to 1 you would use equations
x1 = x0 - view_size / 2
y1 = -y0 + view_size / 2
Here is the promised code. First create a custom view named RotationSquare
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class RotationSquare extends View {
private int squareBorderColor = 0xFF000000; // black
private int innerCircleColor = 0xFFFF0000; // red
private int outerCircleColor = 0xFF000000; // black
private Paint squarePaint, innerCirclePaint, outerCirclePaint;
private RectF squareRect;
private int measuredDimenson;
private float rotation = 0;
// Circle parameters that should be remembered
private float innerRadius, outerRadius, centerX, centerY;
boolean touchedInsideCircle;
public RotationSquare(Context context) {
super(context);
init(context, null, 0);
}
public RotationSquare(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public RotationSquare(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attributeSet, int defStyle) {
squareRect = new RectF();
squarePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
squarePaint.setColor(squareBorderColor);
squarePaint.setStyle(Paint.Style.STROKE);
innerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
innerCirclePaint.setColor(innerCircleColor);
innerCirclePaint.setStyle(Paint.Style.FILL);
outerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
outerCirclePaint.setColor(outerCircleColor);
outerCirclePaint.setStyle(Paint.Style.FILL);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
int measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
// Make a square
measuredDimenson = Math.min(measuredHeight, measuredWidth);
squareRect.set(0.25f * measuredDimenson, 0.25f * measuredDimenson, 0.85f * measuredDimenson, 0.85f * measuredDimenson);
squarePaint.setStrokeWidth(0.025f * measuredDimenson);
centerX = squareRect.right;
centerY = squareRect.top;
innerRadius = 0.07f * measuredDimenson;
outerRadius = 0.08f * measuredDimenson;
setMeasuredDimension((int) (measuredDimenson * 1f), (int) (measuredDimenson * 1f));
}
@Override
protected void onDraw(Canvas canvas) {
if (measuredDimenson <= 0) {
return;
}
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.rotate(rotation, measuredDimenson / 2, measuredDimenson / 2);
canvas.drawCircle(centerX, centerY, outerRadius, outerCirclePaint);
canvas.drawCircle(centerX, centerY, innerRadius, innerCirclePaint);
canvas.drawRect(squareRect, squarePaint);
canvas.restore();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX(0);
float y = event.getY(0);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchedInsideCircle = isTouchInsideCircle(x, y);
return true;
case MotionEvent.ACTION_MOVE:
return true;
case MotionEvent.ACTION_UP:
if (touchedInsideCircle && isTouchInsideCircle(x, y)) {
Toast.makeText(getContext(), "Clicked the circle", Toast.LENGTH_SHORT).show();
}
return true;
default:
return super.onTouchEvent(event);
}
}
public void setRotation(int rotation) {
this.rotation = rotation;
invalidate();
}
private boolean isTouchInsideCircle(float x, float y) {
double angleRad = Math.toRadians(rotation);
// Convert to the centered coordinate system
double centerXConverted = centerX - measuredDimenson / 2;
double centerYConverted = -centerY + measuredDimenson / 2;
// Use the negative angle
double currentCenterX = centerXConverted * Math.cos(-angleRad) - centerYConverted * Math.sin(-angleRad);
double currentCenterY = centerXConverted * Math.sin(-angleRad) + centerYConverted * Math.cos(-angleRad);
// Convert to the centered coordinate system
x = x - measuredDimenson / 2;
y = -y + measuredDimenson / 2;
double squareRadius = outerRadius * outerRadius;
double squaredXDistance = (x - currentCenterX) * (x - currentCenterX);
double squaredYDistance = (y - currentCenterY) * (y - currentCenterY);
return (squaredXDistance + squaredYDistance) < squareRadius;
}
}
Make activity layout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<some.package.that.you.must.change.RotationSquare
android:id="@+id/rotatingSquare"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true"/>
<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:max="360"/>
<TextView
android:id="@+id/tvRotation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/seekBar"
android:gravity="center_horizontal"
android:text="Rotation: 0°"
android:textSize="15sp"/>
</RelativeLayout>
And the Activity
public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener {
private SeekBar seekBar;
private RotationSquare rotationSquare;
private TextView tvRotation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rotationSquare = (RotationSquare) findViewById(R.id.rotatingSquare);
seekBar = (SeekBar) findViewById(R.id.seekBar);
seekBar.setOnSeekBarChangeListener(this);
tvRotation = (TextView) findViewById(R.id.tvRotation);
}
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
rotationSquare.setRotation(i);
tvRotation.setText("Rotation: " + i + "°");
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
Here is the final result.

Hope I didn't scare you off with the math and these equations :/