File size: 2,990 Bytes
8d4485f
 
 
 
 
 
 
16b67eb
 
 
8d4485f
16b67eb
8d4485f
 
 
 
 
 
74f4fb6
8d4485f
 
 
 
 
 
 
 
 
 
 
 
 
 
16b67eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8d4485f
 
 
 
74f4fb6
8d4485f
 
 
 
 
 
 
 
 
 
74f4fb6
8d4485f
 
 
 
 
 
74f4fb6
 
8d4485f
 
 
 
 
 
 
 
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
import { describe, expect, it } from 'vitest';
import * as THREE from 'three';
import { IT_CORE_GROUP_ID } from '../src/ui/itCoreCorpus.js';
import {
  boundingBoxFromLabels,
  centroidForGroup,
  galaxyCameraTarget,
  GALAXY_DEFAULT_SCALE,
  GALAXY_MIN_SCALE,
  GALAXY_SPACING_TO_SCALE,
  layoutGalaxyPoints,
  resolveGalaxyWorldScale,
} from '../src/visualizer/galaxyLayout.js';

describe('galaxyLayout', () => {
  it('maps one world point per token from positions', () => {
    const items = [
      { id: 'a', text: 'server', groupId: IT_CORE_GROUP_ID, cosine_vs_first: 1 },
      { id: 'b', text: 'car', groupId: 'vehicles', cosine_vs_first: 0.2 },
    ];
    const positions = [
      [1, 0, 0],
      [0, 1, 0],
    ];
    const { pointsData, labels, scale } = layoutGalaxyPoints(items, positions, { scale: 10 });
    expect(scale).toBe(10);
    expect(pointsData).toHaveLength(2);
    expect(labels).toHaveLength(2);
    expect(labels[0].origin3D).toEqual(new THREE.Vector3(10, 0, 0));
    expect(labels[1].origin3D).toEqual(new THREE.Vector3(0, 10, 0));
    expect(pointsData[0].meta.token).toBe('server');
  });

  it('default layout scale matches GALAXY_DEFAULT_SCALE', () => {
    const { scale } = layoutGalaxyPoints(
      [{ id: 'a', text: 'x', cosine_vs_first: 0 }],
      [[1, 0, 0]],
    );
    expect(scale).toBe(GALAXY_DEFAULT_SCALE);
    expect(GALAXY_DEFAULT_SCALE).toBeGreaterThan(48);
  });

  it('resolveGalaxyWorldScale maps spacing and floors tiny values', () => {
    expect(resolveGalaxyWorldScale(null)).toBe(GALAXY_DEFAULT_SCALE);
    expect(resolveGalaxyWorldScale({ threadSpacing: 0.4 })).toBeCloseTo(
      0.4 * GALAXY_SPACING_TO_SCALE,
    );
    expect(resolveGalaxyWorldScale({ threadSpacing: 0.01 })).toBe(GALAXY_MIN_SCALE);
  });

  it('centroidForGroup averages member origins', () => {
    const labels = [
      { groupId: IT_CORE_GROUP_ID, origin3D: new THREE.Vector3(0, 0, 0) },
      { groupId: IT_CORE_GROUP_ID, origin3D: new THREE.Vector3(2, 4, 6) },
      { groupId: 'vehicles', origin3D: new THREE.Vector3(100, 0, 0) },
    ];
    const c = centroidForGroup(labels, IT_CORE_GROUP_ID);
    expect(c.x).toBeCloseTo(1);
    expect(c.y).toBeCloseTo(2);
    expect(c.z).toBeCloseTo(3);
  });

  it('galaxyCameraTarget prefers IT core, else all bbox center', () => {
    const withCore = [
      { groupId: IT_CORE_GROUP_ID, origin3D: new THREE.Vector3(1, 2, 3) },
      { groupId: 'vehicles', origin3D: new THREE.Vector3(50, 0, 0) },
    ];
    const t1 = galaxyCameraTarget(withCore);
    expect(t1.source).toBe(IT_CORE_GROUP_ID);
    expect(t1.lookAt).toEqual(new THREE.Vector3(1, 2, 3));

    const noCore = [
      { groupId: 'vehicles', origin3D: new THREE.Vector3(0, 0, 0) },
      { groupId: 'women', origin3D: new THREE.Vector3(10, 0, 0) },
    ];
    const t2 = galaxyCameraTarget(noCore);
    expect(t2.source).toBe('all');
    expect(t2.lookAt.x).toBeCloseTo(5);

    expect(boundingBoxFromLabels([]).isEmpty()).toBe(true);
  });
});