feat: performance optimizations + part-materials validation

- @timed_step decorator with wall-clock + RSS tracking (pipeline_logger)
- Blender timing laps for sharp edges and material assignment
- MeshRegistry pattern: eliminate 13 scene.traverse() calls across viewers
- Lazy material cloning (clone-on-first-write in both viewers)
- _pipeline_session context manager: 7 create_engine() → 2 in render_thumbnail
- KD-tree spatial pre-filter for sharp edge marking (bbox-based pruning)
- Batch material library append: N bpy.ops.wm.append → single bpy.data.libraries.load
- GMSH single-session batching: compound all solids into one tessellation call
- Validate part-materials save endpoints against parsed_objects (prevents bogus keys)
- ROADMAP updated with completion status

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 11:53:14 +01:00
parent ec667dd56a
commit 6c5873d51f
11 changed files with 612 additions and 541 deletions
+24
View File
@@ -172,3 +172,27 @@ export function previewColorForEntry(
}
return '#888888'
}
// ---------------------------------------------------------------------------
// MeshRegistry — O(1) access to meshes by partKey, replaces O(n) traversals
// ---------------------------------------------------------------------------
/** A single entry in the mesh registry, linking a Three.js mesh to its partKey. */
export interface MeshRegistryEntry {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
mesh: any // THREE.Mesh — typed as any to avoid importing THREE
partKey: string
}
/**
* Iterate all materials on a mesh, calling `fn` for each MeshStandardMaterial.
* Handles both single and array materials safely.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function forEachMeshMaterial(mesh: any, fn: (mat: any) => void): void {
if (!mesh?.material) return
const mats = Array.isArray(mesh.material) ? mesh.material : [mesh.material]
for (const m of mats) {
if (m && 'color' in m) fn(m)
}
}