Files
Genarrative/src/services/useMocapInput.test.ts
T

145 lines
4.3 KiB
TypeScript

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],
},
limb_nodes: [
{ name: 'left_shoulder', x: 0.28, y: 0.42 },
{ name: 'left_elbow', x: 0.24, y: 0.5 },
{ name: 'left_wrist', x: 0.2, y: 0.57 },
{ name: 'right_shoulder', x: 0.72, y: 0.42 },
{ name: 'right_elbow', x: 0.76, y: 0.5 },
{ name: 'right_wrist', x: 0.8, y: 0.57 },
],
},
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.bodyJoints).toEqual({
leftShoulder: {x: 0.28, y: 0.42},
leftElbow: {x: 0.24, y: 0.5},
leftWrist: {x: 0.2, y: 0.57},
rightShoulder: {x: 0.72, y: 0.42},
rightElbow: {x: 0.76, y: 0.5},
rightWrist: {x: 0.8, y: 0.57},
});
expect(command.actions).toEqual(
expect.arrayContaining(['wave_left_hand', 'open_palm']),
);
expect(command.leftHand).toEqual(
expect.objectContaining({
side: 'left',
source: 'palm_center',
wrist: {x: 0.21, y: 0.31},
}),
);
expect(command.rightHand).toEqual(
expect.objectContaining({x: 0.72, y: 0.32, side: 'right'}),
);
});
});