| 1 | import { describe, expect, it } from 'vitest'; |
| 2 | import { flickOf, type Sample } from './flick'; |
| 3 | |
| 4 | /** A stroke of `n` points, each turned `turn` radians further round than the |
| 5 | * last, `step` px apart, one every `ms`. `turn` of 0 is a straight flick. */ |
| 6 | function stroke(n: number, step: number, turn: number, ms: number): Sample[] { |
| 7 | const out: Sample[] = [{ x: 0, y: 0, t: 0 }]; |
| 8 | let a = 0; |
| 9 | for (let i = 1; i < n; i++) { |
| 10 | const p = out[i - 1]; |
| 11 | out.push({ x: p.x + Math.cos(a) * step, y: p.y + Math.sin(a) * step, t: i * ms }); |
| 12 | a += turn; |
| 13 | } |
| 14 | return out; |
| 15 | } |
| 16 | |
| 17 | describe('reading a flick', () => { |
| 18 | it('reads the speed off the stroke, not off its last pair of points', () => { |
| 19 | // 20px every 10ms is 2000px/s, whatever the sampling happened to be. |
| 20 | const v = flickOf(stroke(6, 20, 0, 10)); |
| 21 | expect(Math.hypot(v.vx, v.vy)).toBeCloseTo(2000, 0); |
| 22 | }); |
| 23 | |
| 24 | it('puts no turn on a straight flick, however fast it was made', () => { |
| 25 | expect(flickOf(stroke(6, 20, 0, 10)).spin).toBe(0); |
| 26 | expect(flickOf(stroke(6, 60, 0, 10)).spin).toBe(0); |
| 27 | }); |
| 28 | |
| 29 | it('puts a turn on one that curves, and the way it curved', () => { |
| 30 | const right = flickOf(stroke(6, 20, 0.25, 10)).spin; |
| 31 | const left = flickOf(stroke(6, 20, -0.25, 10)).spin; |
| 32 | expect(right).toBeGreaterThan(0.5); |
| 33 | expect(left).toBeCloseTo(-right, 6); |
| 34 | }); |
| 35 | |
| 36 | it('reads the same curve made faster as more turn, which is what a rate means', () => { |
| 37 | // The same shape, drawn in half the time. The old measure was the area |
| 38 | // between the two halves of the stroke and had no time in it at all, so a |
| 39 | // lazy curl and a hooked flick came out the same. |
| 40 | const slow = flickOf(stroke(6, 20, 0.25, 20)).spin; |
| 41 | const fast = flickOf(stroke(6, 20, 0.25, 10)).spin; |
| 42 | expect(fast).toBeCloseTo(slow * 2, 4); |
| 43 | }); |
| 44 | |
| 45 | it('gives up rather than guessing when there is nothing to read', () => { |
| 46 | expect(flickOf([])).toEqual({ vx: 0, vy: 0, spin: 0 }); |
| 47 | expect(flickOf([{ x: 0, y: 0, t: 0 }])).toEqual({ vx: 0, vy: 0, spin: 0 }); |
| 48 | // A press that never moved is not a curve, whatever the jitter says. |
| 49 | expect(flickOf(stroke(6, 1, 0.6, 10)).spin).toBe(0); |
| 50 | }); |
| 51 | }); |