Warning, /firebird/packages/firebird-core/src/painters/batched-trajectory.painter.spec.ts is written in an unsupported language. File is not indexed.
0001 import { Group } from 'three';
0002 import { BatchedTrajectoryPainter } from './batched-trajectory.painter';
0003 import { PointTrajectoryPiece } from '../model/point-trajectory.piece';
0004 import { entityRefOf } from './event-piece-painter';
0005
0006 describe('BatchedTrajectoryPainter', () => {
0007 let mockParentNode: Group;
0008 let piece: PointTrajectoryPiece;
0009
0010 beforeEach(() => {
0011 mockParentNode = new Group();
0012 vi.spyOn(mockParentNode, 'add');
0013 vi.spyOn(mockParentNode, 'remove');
0014
0015 piece = new PointTrajectoryPiece('TestTrajectories');
0016 piece.pointColumns = ['x', 'y', 'z', 't'];
0017 piece.count = 3;
0018 piece.columns = {
0019 pdg: [11, 22, 2212], // electron (solid), gamma (dashed), proton (solid)
0020 charge: [-1, 0, 1],
0021 };
0022 piece.points = [
0023 [[0, 0, 0, 10], [10, 0, 0, 20]], // 1 segment, t=10
0024 [[0, 10, 0, 15], [10, 10, 0, 25], [20, 10, 0, 35]], // 2 segments, t=15,25
0025 [[0, 20, 0, 40], [10, 20, 0, 50]], // 1 segment, t=40
0026 ];
0027 });
0028
0029 it('builds one solid and one dashed batch covering all segments', () => {
0030 const painter = new BatchedTrajectoryPainter(mockParentNode, piece);
0031 const batches = (painter as any).batches;
0032 expect(batches.length).toBe(2);
0033 const solid = batches.find((b: any) => !b.dashed);
0034 const dashed = batches.find((b: any) => b.dashed);
0035 // electron 1 + proton 1 segments solid; gamma 2 segments dashed
0036 expect(solid.count).toBe(2);
0037 expect(dashed.count).toBe(3 - 1); // gamma has 3 points -> 2 segments
0038 expect(mockParentNode.add).toHaveBeenCalledTimes(2);
0039 });
0040
0041 it('sorts segments by start time and cuts with instanceCount', () => {
0042 const painter = new BatchedTrajectoryPainter(mockParentNode, piece);
0043 const batches = (painter as any).batches;
0044 for (const batch of batches) {
0045 for (let i = 1; i < batch.count; i++) {
0046 expect(batch.startTimes[i]).toBeGreaterThanOrEqual(batch.startTimes[i - 1]);
0047 }
0048 }
0049
0050 const solid = batches.find((b: any) => !b.dashed);
0051 const dashed = batches.find((b: any) => b.dashed);
0052
0053 painter.paint(5); // before everything
0054 expect(solid.geometry.instanceCount).toBe(0);
0055 expect(dashed.geometry.instanceCount).toBe(0);
0056
0057 painter.paint(30); // electron segment (t=10) + gamma segments (t=15, 25)
0058 expect(solid.geometry.instanceCount).toBe(1);
0059 expect(dashed.geometry.instanceCount).toBe(2);
0060
0061 painter.paint(null); // timeless: everything
0062 expect(solid.geometry.instanceCount).toBe(solid.count);
0063 expect(dashed.geometry.instanceCount).toBe(dashed.count);
0064 });
0065
0066 it('resolves a picked segment to its trajectory through entityRefOf', () => {
0067 const painter = new BatchedTrajectoryPainter(mockParentNode, piece);
0068 const dashed = (painter as any).batches.find((b: any) => b.dashed);
0069 // Every dashed segment belongs to the gamma (trajectory id 1)
0070 const ref = entityRefOf(dashed.object, { faceIndex: 0 });
0071 expect(ref).toEqual({ pieceName: 'TestTrajectories', entityIndex: 1 });
0072 });
0073
0074 it('recolors a track for highlight and restores it after', () => {
0075 const painter = new BatchedTrajectoryPainter(mockParentNode, piece);
0076 const solid = (painter as any).batches.find((b: any) => !b.dashed);
0077 const protonSegment = [...solid.trackIds].indexOf(2);
0078 const before = solid.colors.slice(protonSegment * 6, protonSegment * 6 + 3);
0079
0080 painter.highlightEntity(2);
0081 const highlighted = solid.colors.slice(protonSegment * 6, protonSegment * 6 + 3);
0082 expect([...highlighted]).not.toEqual([...before]);
0083
0084 painter.unhighlightEntity(2);
0085 const restored = solid.colors.slice(protonSegment * 6, protonSegment * 6 + 3);
0086 expect([...restored].map(v => v.toFixed(5))).toEqual([...before].map(v => v.toFixed(5)));
0087 });
0088
0089 it('keeps one highlight when another track is highlighted (selection plus hover)', () => {
0090 const painter = new BatchedTrajectoryPainter(mockParentNode, piece);
0091 const solid = (painter as any).batches.find((b: any) => !b.dashed);
0092 const segmentOf = (track: number) => [...solid.trackIds].indexOf(track);
0093 const rgb = (track: number) => [...solid.colors.slice(segmentOf(track) * 6, segmentOf(track) * 6 + 3)]
0094 .map((v: number) => v.toFixed(5));
0095 const electronBefore = rgb(0);
0096
0097 painter.highlightEntity(2); // selected
0098 const protonHighlighted = rgb(2);
0099 painter.highlightEntity(0); // hovered
0100 expect(rgb(2)).toEqual(protonHighlighted);
0101 expect(rgb(0)).toEqual(protonHighlighted);
0102
0103 painter.unhighlightEntity(0); // hover ends, selection stays
0104 expect(rgb(2)).toEqual(protonHighlighted);
0105 expect(rgb(0)).toEqual(electronBefore);
0106 });
0107
0108 it('disposes both batch objects', () => {
0109 const painter = new BatchedTrajectoryPainter(mockParentNode, piece);
0110 painter.dispose();
0111 expect((painter as any).batches.length).toBe(0);
0112 expect(mockParentNode.remove).toHaveBeenCalledTimes(2);
0113 });
0114 });