import type { ToolcraftModelBounds, ToolcraftModelDocumentV1, ToolcraftModelNode, ToolcraftModelPrimitive, } from "../canonical/model-document"; const IDENTITY_MATRIX = [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ] as const; export function boundsForPositions(positions: Float32Array): ToolcraftModelBounds { const min: [number, number, number] = [ positions[0]!, positions[1]!, positions[2]!, ]; const max: [number, number, number] = [...min]; for (let offset = 3; offset < positions.length; offset += 3) { for (let axis = 0; axis < 3; axis += 1) { min[axis] = Math.min(min[axis], positions[offset + axis]!); max[axis] = Math.max(max[axis], positions[offset + axis]!); } } return { max, min }; } export function createTopologyPrimitive( overrides: Partial = {}, ): ToolcraftModelPrimitive { const positions = overrides.positions ?? new Float32Array([ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, ]); return { bounds: overrides.bounds ?? boundsForPositions(positions), id: overrides.id ?? "primitive-1", indices: overrides.indices ?? new Uint32Array([ 0, 2, 1, 0, 1, 3, 0, 3, 2, 1, 2, 3, ]), normals: Object.prototype.hasOwnProperty.call(overrides, "normals") ? overrides.normals : new Float32Array(positions.length).fill(1), positions, }; } export function createTopologyDocument( primitives: readonly ToolcraftModelPrimitive[] = [createTopologyPrimitive()], nodeOverrides: Partial = {}, ): ToolcraftModelDocumentV1 { const primitiveIds = primitives.map((primitive) => primitive.id); const node: ToolcraftModelNode = { children: [], id: "node-1", localMatrix: [...IDENTITY_MATRIX], name: "Root", primitiveIds, ...nodeOverrides, }; const min: [number, number, number] = [...primitives[0]!.bounds.min]; const max: [number, number, number] = [...primitives[0]!.bounds.max]; for (const primitive of primitives.slice(1)) { for (let axis = 0; axis < 3; axis += 1) { min[axis] = Math.min(min[axis], primitive.bounds.min[axis]); max[axis] = Math.max(max[axis], primitive.bounds.max[axis]); } } return { bounds: { max, min }, nodes: [node], primitives, provenance: { adapterVersion: "topology-test@1", canonicalSchemaVersion: 1, operations: [], sourceFormat: "glb", }, rootNodeIds: [node.id], version: 1, }; } export function createOpenPlanePrimitive( overrides: Partial = {}, ): ToolcraftModelPrimitive { const positions = overrides.positions ?? new Float32Array([ 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, ]); return createTopologyPrimitive({ bounds: boundsForPositions(positions), indices: new Uint32Array([0, 1, 2, 0, 2, 3]), normals: new Float32Array([ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ]), positions, ...overrides, }); } export function createRepairablePrimitive(): ToolcraftModelPrimitive { const positions = new Float32Array([ 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 2, 0, 0, 3, 0, 0, 5, 5, 5, ]); return createTopologyPrimitive({ bounds: boundsForPositions(positions), indices: new Uint32Array([ 0, 1, 2, 0, 2, 3, 0, 0, 1, 0, 4, 5, 2, 0, 1, ]), normals: undefined, positions, }); } export function createDisconnectedClosedPrimitive(): ToolcraftModelPrimitive { const positions = new Float32Array([ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 4, 0, 0, 3, 1, 0, 3, 0, 1, ]); const tetra = [0, 2, 1, 0, 1, 3, 0, 3, 2, 1, 2, 3]; return createTopologyPrimitive({ bounds: boundsForPositions(positions), indices: new Uint32Array([...tetra, ...tetra.map((index) => index + 4)]), normals: new Float32Array(positions.length).fill(1), positions, }); } export function createClosedSolidWithDuplicatePrimitive(): ToolcraftModelPrimitive { const primitive = createTopologyPrimitive(); return createTopologyPrimitive({ indices: new Uint32Array([ ...primitive.indices, primitive.indices[0]!, primitive.indices[1]!, primitive.indices[2]!, ]), }); }