Offset Clock Hands Angle Calculation

859 Views Asked by At

I have an interesting mathematical problem that I just cant figure out.

I am building a watch face for android wear and need to work out the angle of rotation for the hands based on the time.

Ordinarily this would be simple but here's the kicker: the hands are not central on the clock. Lets say I have a clock face that measures 10,10 My minute hand pivot point resides at 6,6 (bottom left being 0,0) and my hour hand resides at 4,4.

How would I work out the angle at any given minute such that the point always points at the correct minute?

Thanks

2

There are 2 best solutions below

4
On BEST ANSWER

Ok, with the help Nico's answer I've manage to make tweaks and get a working example.

The main changes that needed to be incorporated were changing the order of inputs to the atan calculation as well as making tweaks because of android's insistence to do coordinate systems upside down.

Please see my code below.

        //minutes hand rotation calculation
        int minute = mCalendar.get(Calendar.MINUTE);

        float minutePivotX = mCenterX+minuteOffsetX;
        //because of flipped coord system we take the y remainder of the full width instead
        float minutePivotY = mWidth - mCenterY - minuteOffsetY;

        //calculate target position
        double minuteTargetX = mCenterX + mRadius * Math.cos(ConvertToRadians(minute * 6));
        double minuteTargetY = mCenterY + mRadius * Math.sin(ConvertToRadians(minute * 6));

        //calculate the direction vector from the hand's pivot to the target
        double minuteDirectionX = minuteTargetX - minutePivotX;
        double minuteDirectionY = minuteTargetY - minutePivotY;

        //calculate the angle
        float minutesRotation = (float)Math.atan2(minuteDirectionY,minuteDirectionX );
        minutesRotation = (float)(minutesRotation * 360 / (2 * Math.PI));

        //do this because of flipped coord system
        minutesRotation = minutesRotation-180;

        //if less than 0 add 360 so the rotation is clockwise
        if (minutesRotation < 0)
        {
            minutesRotation = (minutesRotation+360);
        }


        //hours rotation calculations
        float hour = mCalendar.get(Calendar.HOUR);
        float minutePercentOfHour = (minute/60.0f);
        hour = hour+minutePercentOfHour;

        float hourPivotX = mCenterX+hourOffsetX;
        //because of flipped coord system we take the y remainder of the full width instead
        float hourPivotY = mWidth - mCenterY - hourOffsetY;

        //calculate target position
        double hourTargetX = mCenterX + mRadius * Math.cos(ConvertToRadians(hour * 30));
        double hourTargetY = mCenterY + mRadius * Math.sin(ConvertToRadians(hour * 30));

        //calculate the direction vector from the hand's pivot to the target
        double hourDirectionX = hourTargetX - hourPivotX;
        double hourDirectionY = hourTargetY - hourPivotY;

        //calculate the angle
        float hoursRotation = (float)Math.atan2(hourDirectionY,hourDirectionX );
        hoursRotation = (float)(hoursRotation * 360 / (2 * Math.PI));

        //do this because of flipped coord system
        hoursRotation = hoursRotation-180;

        //if less than 0 add 360 so the rotation is clockwise
        if (hoursRotation < 0)
        {
            hoursRotation = (hoursRotation+360);
        }

This also included a small helper function:

public double ConvertToRadians(double angle)
{
    return (Math.PI / 180) * angle;
}

Thanks for your help all

0
On

Just calculate the angle based on the direction vector.

First, calculate the target position. For the minute hand, this could be:

targetX = radius * sin(2 * Pi / 60 * minutes)
targetY = radius * cos(2 * Pi / 60 * minutes)

Then calculate the direction vector from the hand's pivot to the target:

directionX = targetX - pivotX
directionY = targetY - pivotY

And calculate the angle:

angle = atan2(directionX, directionY)