import { describe, expect, test } from 'vitest'; import { parseMocapPacket, resolveMocapPalmCenter } from './useMocapInput'; describe('resolveMocapPalmCenter', () => { test('优先用手腕和四个 MCP 点加权计算掌心派生点', () => { const center = resolveMocapPalmCenter([ { name: 'wrist', x: 0.1, y: 0.2 }, { name: 'index_mcp', x: 0.3, y: 0.4 }, { name: 'middle_mcp', x: 0.5, y: 0.6 }, { name: 'ring_mcp', x: 0.7, y: 0.8 }, { name: 'pinky_mcp', x: 0.9, y: 1 }, { name: 'index_finger_tip', x: 1, y: 1 }, ]); expect(center?.x).toBeCloseTo(0.44); expect(center?.y).toBeCloseTo(0.54); }); test('可用掌心点少于三个时不返回掌心坐标', () => { expect( resolveMocapPalmCenter([ { name: 'wrist', x: 0.1, y: 0.2 }, { name: 'index_mcp', x: 0.3, y: 0.4 }, ]), ).toBeNull(); }); }); describe('parseMocapPacket', () => { test('解析手部数据时优先把 primaryHand 定位到掌心而不是腕部或指尖', () => { const command = parseMocapPacket({ hands: [ { state: 'open_palm', x: 0.01, y: 0.02, landmarks: [ { name: 'wrist', x: 0.1, y: 0.2 }, { name: 'index_mcp', x: 0.3, y: 0.4 }, { name: 'middle_mcp', x: 0.5, y: 0.6 }, { name: 'ring_mcp', x: 0.7, y: 0.8 }, { name: 'pinky_mcp', x: 0.9, y: 1 }, ], }, ], }); expect(command.primaryHand?.x).toBeCloseTo(0.44); expect(command.primaryHand?.y).toBeCloseTo(0.54); expect(command.primaryHand).toEqual( expect.objectContaining({ state: 'open_palm', source: 'palm_center', }), ); }); test('缺少足够掌心关键点时退回 wrist landmark,再退回 hand 直出坐标', () => { const landmarkFallback = parseMocapPacket({ hands: [ { state: 'grab', x: 0.9, y: 0.8, landmarks: [{ name: 'wrist', x: 0.25, y: 0.75 }], }, ], }); expect(landmarkFallback.primaryHand).toEqual( expect.objectContaining({x: 0.25, y: 0.75, source: 'landmark'}), ); const directFallback = parseMocapPacket({ hands: [{ state: 'grab', x: 0.9, y: 0.8 }], }); expect(directFallback.primaryHand).toEqual( expect.objectContaining({x: 0.9, y: 0.8, source: 'direct'}), ); }); test('解析 mocap frame 的身体中心和左右手来源', () => { const command = parseMocapPacket({ schema_version: '1.0', stream: { type: 'mocap.frame' }, general: { body: { center_norm: [0.34, 0.58], }, }, actions: [{ gesture: 'wave-left-hand' }], hands: [ { label: 'Left', state: 'open_palm', landmarks: [ { name: 'wrist', x: 0.21, y: 0.31 }, { name: 'index_mcp', x: 0.25, y: 0.33 }, { name: 'middle_mcp', x: 0.27, y: 0.34 }, { name: 'ring_mcp', x: 0.28, y: 0.35 }, { name: 'pinky_mcp', x: 0.29, y: 0.36 }, ], }, { label: 'Right', state: 'unknown', x: 0.72, y: 0.32, }, ], }); expect(command.bodyCenter).toEqual({x: 0.34, y: 0.58}); expect(command.actions).toEqual( expect.arrayContaining(['wave_left_hand', 'open_palm']), ); expect(command.leftHand).toEqual( expect.objectContaining({side: 'left', source: 'palm_center'}), ); expect(command.rightHand).toEqual( expect.objectContaining({x: 0.72, y: 0.32, side: 'right'}), ); }); });