File size: 3,677 Bytes
d5aa24d
a659921
13bdc14
a659921
d5aa24d
a659921
 
 
 
13bdc14
5f41035
 
 
 
 
 
 
 
 
 
 
 
 
 
13bdc14
 
 
 
 
a659921
 
d5aa24d
 
 
 
 
 
13bdc14
 
a659921
d5aa24d
a659921
 
d5aa24d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a659921
d5aa24d
 
 
 
 
a659921
 
d5aa24d
a659921
 
 
5f41035
d5aa24d
 
 
 
 
 
a659921
d5aa24d
a659921
 
d5aa24d
a659921
 
d5aa24d
a659921
 
 
d5aa24d
a659921
 
d5aa24d
 
a659921
d5aa24d
a659921
 
 
d5aa24d
 
 
 
 
 
 
 
 
 
 
 
 
 
a659921
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import EpicycleSystem from './epicycle_system.js';


export default class AnimationController {
    constructor(canvasId, epicycleData) {
        this.canvas = document.getElementById(canvasId);
        this.context = this.canvas.getContext('2d');
        this.width = this.canvas.width;
        this.height = this.canvas.height;



        // Calculate total extent of all circles
        let totalRadius = 0;
        for (let [amplitude] of epicycleData) {
            totalRadius += Math.abs(amplitude);
        }
        
        console.log('Total radius extent:', totalRadius);
        
        // Scale to fit within 60% of canvas size
        const targetSize = Math.min(this.width, this.height) * 1;
        this.scale = totalRadius > 0 ? targetSize / totalRadius : 1;
        
        console.log('Using scale:', this.scale);
    



        this.epicycleSystem = new EpicycleSystem(epicycleData);
        this.isRunning = true;
        
        // NEW: Normalized time system
        this.totalSteps = 500;           // Total number of discrete steps in one period
        this.currentStep = 0;            // Current step [0, totalSteps)
        this.stepsPerFrame = 1;          // How many steps to advance per frame (speed control)
        
        this.xOffset = this.width /2;
        this.yOffset = this.height /2 ;
    }
    
    update() {
        if (this.isRunning) {
            // Discrete stepping approach (like the reference code)
            this.currentStep += this.stepsPerFrame;
            
            // Wrap around when we complete one period
            if (this.currentStep >= this.totalSteps) {
                this.currentStep = this.currentStep % this.totalSteps;
                // Optionally clear path for clean restart
                // this.epicycleSystem.clearPath();
            }
            
            // Calculate normalized time t ∈ [0, 1]
            const t = this.currentStep / this.totalSteps;
            
            // Update system with normalized time
            this.epicycleSystem.updateWithNormalizedTime(t);
            
            /* Alternative: Continuous time approach
            this.time += this.speed;
            if (this.time >= 1.0) {
                this.time = this.time % 1.0;
            }
            this.epicycleSystem.updateWithNormalizedTime(this.time);
            */
        }
    }
    
    render() {
        this.context.fillStyle = '#000';
        this.context.fillRect(0, 0, this.width, this.height);
        this.epicycleSystem.render(this.context, this.xOffset, this.yOffset, this.scale);
        
        // Optional: Display current time for debugging
        this.context.fillStyle = '#fff';
        this.context.font = '14px monospace';
        const t = (this.currentStep / this.totalSteps).toFixed(3);
        this.context.fillText(`t = ${t}`, 10, 20);
    }
    
    loop() {
        this.update();
        this.render();
        requestAnimationFrame(() => this.loop());
    }
    
    pause() {
        this.isRunning = !this.isRunning;
    }
    
    reset() {
        this.epicycleSystem.reset();
        this.currentStep = 0;
        // this.time = 0;  // If using continuous time
    }
    
    clearPath() {
        this.epicycleSystem.clearPath();
    }
    
    // NEW: Jump to specific time
    seekTo(t) {
        // t should be in [0, 1]
        this.currentStep = Math.floor(t * this.totalSteps);
        this.epicycleSystem.clearPath();
        this.epicycleSystem.updateWithNormalizedTime(t);
    }
    
    // NEW: Control speed
    setSpeed(stepsPerFrame) {
        this.stepsPerFrame = stepsPerFrame;
    }
    
    start() {
        this.loop();
    }
}