Search code examples
mathclockanglewatchface

Offset Clock Hands Angle Calculation


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


Solution

  • 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