Log in
test/helpers.js 63 lines · 2.2 KB · javascript
1
import { NextDraw } from '../src/nextdraw.js';
2
import { EBBSimulator, VirtualClock } from '../src/sim/ebb-sim.js';
3
4
/** A connected-ready NextDraw wired to a simulated machine. */
5
export function makeMachine(simOptions = {}, configure = null) {
6
  const clock = new VirtualClock();
7
  const sim = new EBBSimulator({ clock, ...simOptions });
8
  const messages = [];
9
  const nd = new NextDraw({ transport: sim, clock, log: (m) => messages.push(m) });
10
  nd.interactive();
11
  configure?.(nd);
12
  return { nd, sim, clock, messages };
13
}
14
15
export async function connected(simOptions = {}, configure = null) {
16
  const m = makeMachine(simOptions, configure);
17
  const ok = await m.nd.connect();
18
  if (!ok) throw new Error(`connect failed: ${m.messages.join(' / ')}`);
19
  return m;
20
}
21
22
/** Deterministic PRNG (mulberry32) so failures are reproducible. */
23
export function rng(seed) {
24
  let a = seed >>> 0;
25
  return () => {
26
    a = (a + 0x6d2b79f5) >>> 0;
27
    let t = a;
28
    t = Math.imul(t ^ (t >>> 15), t | 1);
29
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
30
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
31
  };
32
}
33
34
function pointSegmentDistance(p, a, b) {
35
  const dx = b[0] - a[0];
36
  const dy = b[1] - a[1];
37
  const len2 = dx * dx + dy * dy;
38
  let t = len2 > 0 ? ((p[0] - a[0]) * dx + (p[1] - a[1]) * dy) / len2 : 0;
39
  t = Math.max(0, Math.min(1, t));
40
  return Math.hypot(p[0] - (a[0] + t * dx), p[1] - (a[1] + t * dy));
41
}
42
43
export function distanceToPolylines(p, polylines) {
44
  let best = Infinity;
45
  for (const line of polylines) {
46
    if (line.length === 1) best = Math.min(best, Math.hypot(p[0] - line[0][0], p[1] - line[0][1]));
47
    for (let i = 1; i < line.length; i++) best = Math.min(best, pointSegmentDistance(p, line[i - 1], line[i]));
48
  }
49
  return best;
50
}
51
52
/** Two-sided (Hausdorff-style, vertex-sampled) distance between polyline sets. */
53
export function polylineSetDistance(a, b) {
54
  let worst = 0;
55
  for (const line of a) for (const p of line) worst = Math.max(worst, distanceToPolylines(p, b));
56
  for (const line of b) for (const p of line) worst = Math.max(worst, distanceToPolylines(p, a));
57
  return worst;
58
}
59
60
/** Commands sent, with status polling (QG) removed. */
61
export function commands(sim) {
62
  return sim.log.map((l) => l.cmd).filter((c) => c !== 'QG');
63
}