203 lines
7.5 KiB
TypeScript
203 lines
7.5 KiB
TypeScript
import { describe, expect, test } from 'vitest'
|
|
import * as THREE from 'three'
|
|
|
|
import { buildScenePartRegistry, convertSceneManifestMaterials, remapToPartKeys, resolveObjectPartKey } from '../../components/cad/cadUtils'
|
|
|
|
describe('cadUtils scene manifest conversion', () => {
|
|
test('uses scene manifest part keys as authoritative viewer material map', () => {
|
|
const materials = convertSceneManifestMaterials([
|
|
{
|
|
part_key: 'rwdr_b_f_802044_tr4_h122bk',
|
|
effective_material: 'HARTOMAT_010101_Steel-Bare',
|
|
},
|
|
{
|
|
part_key: 'o_ring_rg_f_802044_tr4_h122bk_1',
|
|
effective_material: 'HARTOMAT_050101_Elastomer-Black',
|
|
},
|
|
{
|
|
part_key: 'ignored',
|
|
effective_material: null,
|
|
},
|
|
])
|
|
|
|
expect(materials).toEqual({
|
|
rwdr_b_f_802044_tr4_h122bk: {
|
|
type: 'library',
|
|
value: 'HARTOMAT_010101_Steel-Bare',
|
|
},
|
|
o_ring_rg_f_802044_tr4_h122bk_1: {
|
|
type: 'library',
|
|
value: 'HARTOMAT_050101_Elastomer-Black',
|
|
},
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('cadUtils legacy fallback remapping', () => {
|
|
test('remaps simple legacy source keys onto part keys when no scene manifest exists', () => {
|
|
const materials = remapToPartKeys(
|
|
{
|
|
'F-802044-0011_AU_TR1_04_1': { type: 'library', value: 'Steel--Stahl' },
|
|
'RWDR_B_F-802044_TR4_H122BK': { type: 'library', value: 'Steel--Stahl' },
|
|
},
|
|
{
|
|
'F-802044-0011_AU_TR1_04': 'f_802044_0011_au_tr1_04',
|
|
'RWDR_B_F-802044_TR4_H122BK': 'rwdr_b_f_802044_tr4_h122bk',
|
|
},
|
|
)
|
|
|
|
expect(materials).toEqual({
|
|
f_802044_0011_au_tr1_04: { type: 'library', value: 'Steel--Stahl' },
|
|
rwdr_b_f_802044_tr4_h122bk: { type: 'library', value: 'Steel--Stahl' },
|
|
})
|
|
})
|
|
|
|
test('remaps serialized instance names using blender-style fuzzy lookup', () => {
|
|
const materials = remapToPartKeys(
|
|
{
|
|
'RWDR_B_F-802044_TR4_H122B-69186': { type: 'library', value: 'Steel--Stahl' },
|
|
'RWDR_K_F-802044_TR4_H122B-68272': { type: 'library', value: 'Steel--Stahl' },
|
|
'RWDR_F_F-802044_TR4_H122B-69391': { type: 'library', value: 'Steel--Stahl' },
|
|
'O_RING_RG_F-802044_TR4_H-120220': { type: 'library', value: 'Eslastomer_black--Elastomer_schwarz' },
|
|
'F-802044-3001_IR_TR2-H_A1-25921_AF0': { type: 'library', value: 'Steel--Stahl' },
|
|
'F-802044-0011_AU_TR1_04_1_AF0_1': { type: 'library', value: 'Steel--Stahl' },
|
|
},
|
|
{
|
|
'RWDR_B_F-802044_TR4_H122BK': 'rwdr_b_f_802044_tr4_h122bk',
|
|
'RWDR_K_F-802044_TR4_H122BK': 'rwdr_k_f_802044_tr4_h122bk',
|
|
'RWDR_F_F-802044_TR4_H122BK': 'rwdr_f_f_802044_tr4_h122bk',
|
|
'O_RING_RG_F-802044_TR4_H122BK': 'o_ring_rg_f_802044_tr4_h122bk',
|
|
'F-802044-3001_IR_TR2-H_A1_04': 'f_802044_3001_ir_tr2_h_a1_04',
|
|
'F-802044-0011_AU_TR1_04_1': 'f_802044_0011_au_tr1_04_1',
|
|
},
|
|
)
|
|
|
|
expect(materials.rwdr_b_f_802044_tr4_h122bk).toEqual({
|
|
type: 'library',
|
|
value: 'Steel--Stahl',
|
|
})
|
|
expect(materials.rwdr_k_f_802044_tr4_h122bk).toEqual({
|
|
type: 'library',
|
|
value: 'Steel--Stahl',
|
|
})
|
|
expect(materials.rwdr_f_f_802044_tr4_h122bk).toEqual({
|
|
type: 'library',
|
|
value: 'Steel--Stahl',
|
|
})
|
|
expect(materials.o_ring_rg_f_802044_tr4_h122bk).toEqual({
|
|
type: 'library',
|
|
value: 'Eslastomer_black--Elastomer_schwarz',
|
|
})
|
|
expect(materials.f_802044_3001_ir_tr2_h_a1_04).toEqual({
|
|
type: 'library',
|
|
value: 'Steel--Stahl',
|
|
})
|
|
expect(materials.f_802044_0011_au_tr1_04_1).toEqual({
|
|
type: 'library',
|
|
value: 'Steel--Stahl',
|
|
})
|
|
})
|
|
|
|
test('keeps ambiguous fuzzy matches unresolved', () => {
|
|
const materials = remapToPartKeys(
|
|
{
|
|
'PART_ALPHA-11111': { type: 'library', value: 'Steel--Stahl' },
|
|
'PART_ALPHA-22222': { type: 'library', value: 'Bronze--Bronze' },
|
|
},
|
|
{
|
|
PART_ALPHA: 'part_alpha',
|
|
},
|
|
)
|
|
|
|
expect(materials.part_alpha).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('cadUtils scene graph part-key registry', () => {
|
|
test('inherits instance part keys from ancestor nodes and keeps logical keys from scene metadata', () => {
|
|
const scene = new THREE.Group()
|
|
|
|
const instanceGroup = new THREE.Group()
|
|
instanceGroup.name = 'KERO_Z-575693-QP-DRH_ISB_1'
|
|
instanceGroup.userData.partKey = 'kero_z_575693_qp_drh_isb_1'
|
|
|
|
const mesh = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshStandardMaterial())
|
|
mesh.name = 'KERO_Z-575693-QP-DRH_ISB_1_1'
|
|
instanceGroup.add(mesh)
|
|
|
|
const logicalOnlyNode = new THREE.Group()
|
|
logicalOnlyNode.name = 'RWDR_SKEL_F-802044_TR4_H122BK'
|
|
logicalOnlyNode.userData.partKey = 'rwdr_skel_f_802044_tr4_h122bk'
|
|
|
|
scene.add(instanceGroup)
|
|
scene.add(logicalOnlyNode)
|
|
|
|
const { meshRegistry, logicalPartKeys } = buildScenePartRegistry(scene, {
|
|
'F-802044_TR4-H122BK_04': 'f_802044_tr4_h122bk_04',
|
|
})
|
|
|
|
expect(meshRegistry).toHaveLength(1)
|
|
expect(meshRegistry[0].partKey).toBe('kero_z_575693_qp_drh_isb_1')
|
|
expect(resolveObjectPartKey(mesh, {})).toBe('kero_z_575693_qp_drh_isb_1')
|
|
expect(logicalPartKeys).toEqual(new Set([
|
|
'kero_z_575693_qp_drh_isb_1',
|
|
'rwdr_skel_f_802044_tr4_h122bk',
|
|
'f_802044_tr4_h122bk_04',
|
|
]))
|
|
})
|
|
|
|
test('prefers sibling semantic instance nodes over mesh-local exporter keys when transforms match', () => {
|
|
const scene = new THREE.Group()
|
|
const assembly = new THREE.Group()
|
|
|
|
const semanticSibling = new THREE.Group()
|
|
semanticSibling.name = 'KERO_Z-575693-QP-DRH_ISB_1_AF21'
|
|
semanticSibling.userData.partKey = 'kero_z_575693_qp_drh_isb_1'
|
|
semanticSibling.position.set(0.08113920585353, 0.236350432177, 0.2109037401181)
|
|
semanticSibling.quaternion.set(0.10417282880530283, -0.01738337059295405, -0.1636740589602252, 0.9808448616315497)
|
|
|
|
const mesh = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshStandardMaterial())
|
|
mesh.name = 'KERO_Z-575693-QP-DRH_ISB_1_1'
|
|
mesh.userData.partKey = 'kero_z_575693_qp_drh_isb_1_1'
|
|
mesh.position.copy(semanticSibling.position)
|
|
mesh.quaternion.copy(semanticSibling.quaternion)
|
|
|
|
assembly.add(semanticSibling)
|
|
assembly.add(mesh)
|
|
scene.add(assembly)
|
|
|
|
const { meshRegistry } = buildScenePartRegistry(scene, {})
|
|
|
|
expect(meshRegistry).toHaveLength(1)
|
|
expect(meshRegistry[0].partKey).toBe('kero_z_575693_qp_drh_isb_1')
|
|
expect(mesh.userData.partKey).toBe('kero_z_575693_qp_drh_isb_1')
|
|
expect(resolveObjectPartKey(mesh, {})).toBe('kero_z_575693_qp_drh_isb_1')
|
|
})
|
|
|
|
test('prefers sibling semantic instance nodes even when transforms do not match', () => {
|
|
const scene = new THREE.Group()
|
|
const assembly = new THREE.Group()
|
|
|
|
const semanticSibling = new THREE.Group()
|
|
semanticSibling.name = 'KERO_Z-575693-QP-DRH_ISB_1_AF21'
|
|
semanticSibling.userData.partKey = 'kero_z_575693_qp_drh_isb_1'
|
|
semanticSibling.position.set(0.08113920585353, 0.236350432177, 0.2109037401181)
|
|
|
|
const mesh = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshStandardMaterial())
|
|
mesh.name = 'KERO_Z-575693-QP-DRH_ISB_1_1'
|
|
mesh.userData.partKey = 'kero_z_575693_qp_drh_isb_1_1'
|
|
mesh.position.set(0.2422435981345, 0.06134441033723, 0.2109037401181)
|
|
|
|
assembly.add(semanticSibling)
|
|
assembly.add(mesh)
|
|
scene.add(assembly)
|
|
|
|
const { meshRegistry } = buildScenePartRegistry(scene, {})
|
|
|
|
expect(meshRegistry).toHaveLength(1)
|
|
expect(meshRegistry[0].partKey).toBe('kero_z_575693_qp_drh_isb_1')
|
|
expect(mesh.userData.partKey).toBe('kero_z_575693_qp_drh_isb_1')
|
|
expect(resolveObjectPartKey(mesh, {})).toBe('kero_z_575693_qp_drh_isb_1')
|
|
})
|
|
})
|