clock_util.js

/**
 * CLOCK UTILITIES: Manages the movement and position of clock hands.
 * @module clock_util
 */

import * as config from './config.js';

/**
 * Helper class to construct an array where the lowest-valued indices are spaced the farthest from one another. Used to
 * set the phases of the clocks such that the highest probability clocks have the most disparate phases.
 *
 * For example, `SpacedArray(5).arr = [0, 4, 2, 5, 1, 3]`. Note that adjacent numbers (such as 0 and 1, 1 and 2, ...) are pretty far from each other.
 *
 * The values 0, 4, 2, ... are the starting locations of each clock’s hour hands when there are 6 active clocks on the screen.
 *
 * @param {number} nels - The number of elements in the array. Equal to the number of unique hour hand phases (determined by rotation period and framerate).
 * @property {Array<number>} arr - The 'spaced' array of length `nels`. For example, if we call `SpacedArray(nels=5)`, then `arr` will equal `[0, 4, 2, 5, 1, 3]`
 */
export class SpacedArray{
    constructor(nels){
        this.rev_arr = [];
        var insert_pt = 0;
        var level = 0;
        for (var index = 0; index < nels; index++) {
            this.rev_arr.splice(insert_pt, 0, index + 1);
            insert_pt += 2;
            if (insert_pt > 2 * (2 ** level - 1)) {
                insert_pt = 0;
                level += 1;
            }
        }
        this.rev_arr.splice(0, 0, 0);

        this.arr = [];
        for (index=0; index < nels + 1; index++) {
            this.arr.push(0);
        }
        for (index=0; index < nels + 1; index++) {
            this.arr[this.rev_arr[index]] = index;
        }
    }
}

/**
 * Helper class to define the unique phase locations available for the clock hands.
 * @param {number} num_divs_time - The number of unique hour hand phases (determined by rotation period and framerate).
 * @property {Array<number>} hour_locs - An array of length `num_divs_time` that defines the angles for each unique hour hand phase.
 */
export class HourLocs{

    constructor(num_divs_time){
        this.num_divs_time = num_divs_time;

        this.hour_locs = [];
        this.hl_base = [];
        for (var index=0; index < num_divs_time; index++){
            var base = -Math.PI / 2.0 + (2.0 * Math.PI * index) / num_divs_time;
            var theta = -config.theta0 + base;
            this.hour_locs.push([theta]);
            this.hl_base.push(base);
        }

    }
}

/**
 * This class is instantiated as the “backend” of the clocks defined in Widgets. This class is not for a single clock, but all
 * clocks on the screen. It orchestrates the phases assigned to each clock and the process of updating their hands on each animation frame.
 * @param {Keyboard} parent - The instance of the `Keyboard` class.
 * @param {BroderClocks} bc - The instance of the `BroderClocks` class.
 * @param {ClockInference} clock_inf - The instance of the `ClockInference` class.
 * @property {number} num_divs_time - The number of unique hour hand phases (determined by rotation period and framerate).
 * @property {SpacedArray} spaced - The instance of the `SpacedArray` class.
 * @property {HourLocs} hl - The instance of the `HourLocs` class.
 * @property {Array<number>} cur_hours - An array specifying the hour hand locations for each clock. This value corresponds to an index in the `SpacedArray'.
 * @property {Array<number>} clock_angles - An array specifying the angle of the clock hand corresponding to each entry in `cur_hours`.
 */
export class ClockUtil{

    constructor(parent, bc, clock_inf) {
        this.parent = parent;
        this.bc = bc;
        this.clock_inf = clock_inf;

        this.cur_hours = [];
        this.clock_angles = [];
        for (var i in this.parent.clock_centers){
            this.cur_hours.push(0.0);
            this.clock_angles.push(0.0);
        }

        this.time_rotate = this.parent.time_rotate;
        this.num_divs_time = Math.ceil(this.parent.time_rotate / config.ideal_wait_s);
        this.spaced = new SpacedArray(this.num_divs_time);
        this.hl = new HourLocs(this.num_divs_time);

        this.adt = [0, 0];
    }

    /**
     * Updates cur hours by one for all clocks: increment the index among [0,80] by 1 for where the clock hand exists.
     * @param {Array<number>} update_clocks_list - Array containing the indices of all active clocks to increment.
     */
    update_curhours(update_clocks_list){
        var count = 0;
        for (var sind_index in update_clocks_list) {
            var sind = update_clocks_list[sind_index];
            this.cur_hours[sind] = this.spaced.arr[count % this.num_divs_time];
            count ++;
        }
    }

    /**
     * Recalculates the clock hours and spacedArray given the new rotation period.
     * @param {number} new_period - The time in seconds of the new clock rotation period.
     */
    change_period(new_period) {
        this.clock_inf.time_rotate = new_period;
        this.clock_inf.update_dens(new_period);
        this.time_rotate = new_period;

        this.num_divs_time = Math.ceil(this.time_rotate / config.ideal_wait_s);

        this.wait_s = this.time_rotate / this.num_divs_time;

        this.hl = new HourLocs(this.num_divs_time);

        this.spaced = new SpacedArray(this.num_divs_time);

        this.init_round(this.clock_inf.clocks_on);
    }
    init_round(clock_index_list){
        this.update_curhours(clock_index_list);
    }
    /**
     * Updates the cur hours by 1, and update both the screen and the parameters of the clocks.
     * @param {Array<number>} clock_index_list - Array containing the indices of all active clocks to increment.
     */
    increment(clock_index_list){
        this.bc.latest_time = Date.now()/1000;
        var clock;
        var clock_ind;
        for (clock_ind in clock_index_list){
            clock = clock_index_list[clock_ind];
            this.cur_hours[clock] = (this.cur_hours[clock] + 1) % this.num_divs_time;
            this.clock_angles[clock] = this.hl.hour_locs[this.cur_hours[clock]];
        }

        var clocks = this.bc.parent.clockgrid.clocks;
        for (clock_ind in clock_index_list){
            var clock_index = clock_index_list[clock_ind];
            clock = clocks[clock_index];
            var angle = this.hl.hour_locs[this.cur_hours[clock_index]];
            clock.angle = angle[0];
            clock.draw_hand();
        }

    }
}