0
votes

I have a circle drawn on canvas. On top on this circle I draw an angle, which starts from part of the circle equal to current time.

Then onTouchEvent, the angle should be redrawn from start point (current time), to end point, based on a point on the circle.

The problem is with calculation dynamically sweep angle in method onTouchEvent.

I've tried different calculations, taken from different Stackoverflow posts / suggestions, and none did not work according to my expectation. The reaction of the angle, onTouchEvent, was always a bit unpredicted.

My code snippet:

@Override
public void draw(Canvas canvas) {
    super.draw(canvas);

    int radius = getRadius();
    int startAngle = getStartAngle();

    canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, this.bkgPaint);

    this.arcRect = new RectF((getWidth() / 2) - radius, (getHeight() / 2) - radius, (getWidth() / 2) + radius, (getHeight() / 2) + radius);
    canvas.drawArc(this.arcRect, startAngle, sweepAngle, true, arcPaint);
}

@Override
public boolean onTouchEvent(MotionEvent e) {
    if (e.getAction() == MotionEvent.ACTION_MOVE) {
        sweepAngle = (int) ((360.0D + Math.toDegrees(Math.atan2(e.getX() - 360.0D, 360.0D - e.getY()))) % 360.0D);
        invalidate();
    }
    return true;
}

private int getStartAngle() {
    Calendar cal = Calendar.getInstance();
    int minutes = cal.get(Calendar.HOUR_OF_DAY) * 60 + cal.get(Calendar.MINUTE);
    if (minutes > 720) {
        minutes -= 720;
    }
    int angle = minutes / 2;
    return (angle += 270) % 360;
}

private int getRadius() {
    return ((80 * getWidth()) / 100) / 2;
}
1
Calculation of sweep angle in onTouchEvent was a part of code which I didn't understand, what is why I asked in my post about some help in understanding how to properly do it. Sweep angle should be calculated dynamically from start point on circle (current time), till the point on circle which I touched on screen. I think my code is clear enough to someone who understands my problem.damax

1 Answers

2
votes

I've used similar calculations in my color picker. It's open source, you can find sources here.

In your case I would start with calculating end angle, like this:

@Override
public boolean onTouchEvent(MotionEvent e) {
    int action = e.getAction();
    switch (action) {
    case MotionEvent.ACTION_DOWN:
    case MotionEvent.ACTION_MOVE:

        int x = (int) e.getX();
        int y = (int) e.getY();
        int cx = x - getWidth() / 2;
        int cy = y - getHeight() / 2;

        endAngle = (float) (Math.toDegrees(Math.atan2(cy, cx)) + 360f) % 360f;

        invalidate();

        return true;
    }
    return super.onTouchEvent(e);
}

Adding 360 degrees with modulo is required. After this operation you'll have 0 degrees on the right side of the circle, 90 at the bottom, 180 on the left and 270 at the top.

Now your sweep angle will be endAngle - startAngle. And that's it!