Files
editor/packages/ifc-converter/tests/cleanup.test.ts
T
Wassim SAMADandGitHub 812b7306e8 Fix editor interaction, loading, and IFC cleanup (#385)
* fix: update site labels after camera swaps

* fix: gate scene display until viewer is ready

* fix: render scene loader on first paint

* fix: keep loader during pending scene graph

* feat: add wasd camera panning

* feat: add x delete mode shortcut

* feat: add floorplan north compass

* fix: move floorplan compass to lower corner

* fix: progressively rebuild heavy scene geometry

* fix: simplify noisy ifc wall output
2026-06-08 15:04:28 -04:00

124 lines
3.4 KiB
TypeScript

import { describe, expect, it } from 'bun:test'
import type { AnyNode } from '@pascal-app/core'
import { simplifyConvertedSceneGraph } from '../src/cleanup'
function level(id = 'level_1', children: string[] = []): AnyNode {
return {
object: 'node',
id,
type: 'level',
name: 'Level',
parentId: null,
visible: true,
level: 0,
children,
} as AnyNode
}
function wall(
id: string,
start: [number, number],
end: [number, number],
children: string[] = [],
): AnyNode {
return {
object: 'node',
id,
type: 'wall',
name: id,
parentId: 'level_1',
visible: true,
start,
end,
thickness: 0.2,
height: 3,
children,
frontSide: 'unknown',
backSide: 'unknown',
} as AnyNode
}
function door(id: string, parentId: string, position: [number, number, number]): AnyNode {
return {
object: 'node',
id,
type: 'door',
name: id,
parentId,
wallId: parentId,
visible: true,
width: 0.9,
height: 2.1,
position,
} as AnyNode
}
function windowNode(id: string, parentId: string, position: [number, number, number]): AnyNode {
return {
object: 'node',
id,
type: 'window',
name: id,
parentId,
wallId: parentId,
visible: true,
width: 1,
height: 1.2,
position,
} as AnyNode
}
describe('simplifyConvertedSceneGraph', () => {
it('merges collinear wall fragments across door-sized gaps', () => {
const nodes: Record<string, AnyNode> = {
level_1: level('level_1', ['wall_a', 'wall_b']),
wall_a: wall('wall_a', [0, 0], [2, 0]),
wall_b: wall('wall_b', [2.9, 0], [5, 0]),
}
const stats = simplifyConvertedSceneGraph(nodes)
expect(stats.removedMergedWalls).toBe(1)
expect(Object.values(nodes).filter((node) => node.type === 'wall')).toHaveLength(1)
const keptWall = Object.values(nodes).find((node) => node.type === 'wall')
expect(keptWall).toMatchObject({ start: [0, 0], end: [5, 0] })
expect((nodes.level_1 as { children: string[] }).children).toEqual([keptWall?.id])
})
it('reprojects openings from removed walls onto the merged wall', () => {
const nodes: Record<string, AnyNode> = {
level_1: level('level_1', ['wall_a', 'wall_b']),
wall_a: wall('wall_a', [0, 0], [2, 0]),
wall_b: wall('wall_b', [2, 0], [4, 0], ['window_1']),
window_1: windowNode('window_1', 'wall_b', [1, 1.4, 0]),
}
simplifyConvertedSceneGraph(nodes)
const keptWall = Object.values(nodes).find((node) => node.type === 'wall')
expect(Object.values(nodes).filter((node) => node.type === 'wall')).toHaveLength(1)
expect(nodes.window_1).toMatchObject({
parentId: keptWall?.id,
wallId: keptWall?.id,
position: [3, 1.4, 0],
})
expect((keptWall as { children: string[] }).children).toEqual(['window_1'])
})
it('removes duplicate openings hosted on the same wall', () => {
const nodes: Record<string, AnyNode> = {
level_1: level('level_1', ['wall_1']),
wall_1: wall('wall_1', [0, 0], [4, 0], ['door_1', 'door_2']),
door_1: door('door_1', 'wall_1', [1.5, 1.05, 0]),
door_2: door('door_2', 'wall_1', [1.51, 1.05, 0]),
}
const stats = simplifyConvertedSceneGraph(nodes)
expect(stats.removedDuplicateOpenings).toBe(1)
expect(nodes.door_1).toBeDefined()
expect(nodes.door_2).toBeUndefined()
expect((nodes.wall_1 as { children: string[] }).children).toEqual(['door_1'])
})
})