import { inspectSldprt } from "../../native-sldprt/index.mjs"; import { recognizeMeshFeatures } from "../../mesh-features/index.mjs"; import type { MeshFeatureReport } from "../../mesh-features/index.mjs"; import { analyzeStep, analyzeStepNormalized, CadAnalysisError } from "../../cad-features/index.mjs"; import type { StepOptions } from "../../cad-features/index.mjs"; import { inspectStepObrounds } from "../../cad-obround/index.mjs"; import { validateStepInput } from "./step-preflight.mjs"; import { OcctKernel } from "occt-wasm"; import wasmUrl from "occt-wasm/dist/occt-wasm.wasm?url"; import { recognizeMeshDepthFeatures } from "../../mesh-depth-features/index.mjs"; import { depthMeshes,type DepthAnalysis,type NormalizedAnalysis } from "./types"; function addDepth(analysis:DepthAnalysis):DepthAnalysis{ try{ const depth=recognizeMeshDepthFeatures(depthMeshes(analysis),{source:analysis.report.source,geometry_basis:analysis.mode==="native_cache"?"saved_native_display":"step_tessellation"}); if(analysis.mode==="step_brep"&&analysis.report.features.length===0){ const withheld=depth.features.length; return{...analysis,depth_features:{...depth,features:[],unassigned_surface_ids:depth.surfaces.map(surface=>surface.id),limitations:[...depth.limitations,`No exact B-rep feature candidates were recognized. ${withheld} tessellation-only candidate(s) are withheld from executable depth intents; approximate mesh evidence is not promoted to Generate.`]}}; } return{...analysis,depth_features:depth}; } catch(error){return{...analysis,depth_error:`Depth recognition was not completed: ${error instanceof Error?error.message:"unsupported geometry"}. No replacement features were substituted.`};} } self.onmessage=async(event:MessageEvent<{filename:string;bytes:ArrayBuffer;kernelBytes?:ArrayBuffer;kernelName?:string;stepEncoding?:StepOptions["encoding"]}>)=>{ try{ const {filename,bytes}=event.data; if(!(bytes instanceof ArrayBuffer)||bytes.byteLength===0||bytes.byteLength>20*1024*1024)throw new Error("Model must be between 1 byte and 20 MiB."); if(/\.sldprt$/i.test(filename)){ const report=await inspectSldprt(new Uint8Array(bytes),{filename}); let cache_features:MeshFeatureReport; try{cache_features=recognizeMeshFeatures(report.meshes);}catch(error){cache_features={schema_version:"mesh-features-1.0",features:[],surfaces:[],unclassified_mesh_ids:report.meshes.map(m=>m.id),limitations:[`Display geometry decoded, but feature fitting was not completed: ${error instanceof Error?error.message:"unsupported mesh"}`],machine_release:{eligible:false,reasons:["Feature fitting unavailable."]}};} self.postMessage({ok:true,result:addDepth({mode:"native_cache",report,cache_features})}); }else if(/\.(?:step|stp)$/i.test(filename)){ const digest=await crypto.subtle.digest("SHA-256",bytes),sha256=Array.from(new Uint8Array(digest)).map(n=>n.toString(16).padStart(2,"0")).join(""); const replacement=event.data.kernelBytes; if(replacement&&(!(replacement instanceof ArrayBuffer)||replacement.byteLength>32*1024*1024||replacement.byteLength<8))throw new Error("Replacement kernel must be a compatible WASM binary, at most 32 MiB."); const options=event.data.stepEncoding?{encoding:event.data.stepEncoding}:undefined,source={filename,sha256,byte_length:bytes.byteLength}; let normalized=false; try{validateStepInput(new Uint8Array(bytes),source,options);} catch(error){ if(!(error instanceof CadAnalysisError)||error.code!=="UNSUPPORTED_UNITS")throw error; if(replacement)throw new Error("Normalized STEP unit inspection requires the bundled kernel. Restore the bundled kernel and reopen the original file; replacement-library unit behavior has not been verified."); normalized=true; } const kernel=await OcctKernel.init({wasm:replacement??wasmUrl}); try{ const kernel_source=replacement?{kind:"user_replacement",filename:event.data.kernelName,sha256:Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256",replacement))).map(n=>n.toString(16).padStart(2,"0")).join("")}: {kind:"bundled",package:"occt-wasm@3.4.0"}; if(normalized){ const report=analyzeStepNormalized(kernel,new Uint8Array(bytes),source,options); const result:NormalizedAnalysis={mode:"step_brep",report,kernel_source:{kind:"bundled",package:"occt-wasm@3.4.0"}, exact_openings_not_run:"Normalized-unit inspection retains analytical surfaces and feature candidates. Paired-opening inspection is currently qualified only on the strict millimetre reader.", depth_error:"Inspection only: source units were resolved and geometry normalized to mm. A normalized-unit machining strategy and its independent final-NC checks are not yet qualified, so no executable depth intents were created."}; self.postMessage({ok:true,result}); }else if(replacement){ const report=analyzeStep(kernel,new Uint8Array(bytes),source,options); self.postMessage({ok:true,result:addDepth({mode:"step_brep",report,kernel_source,exact_openings_not_run:"Exact opening inspection was not run with the replacement kernel. Restore the bundled kernel and reopen the model to use its bounded inspection."})}); }else{ const inspection=await inspectStepObrounds(kernel,new Uint8Array(bytes),source,options); if(!inspection.cad_report)throw new Error("STEP solid inspection did not complete. Check the source, units and model validity; no replacement geometry was used."); const {cad_report:report,...exact_openings}=inspection; self.postMessage({ok:true,result:addDepth({mode:"step_brep",report,kernel_source,exact_openings})}); } }finally{kernel[Symbol.dispose]();} }else throw new Error("Choose a STEP/STP solid or a supported SLDPRT file. Images and PDFs are supplementary evidence, not 3D geometry."); }catch(error){self.postMessage({ok:false,error:error instanceof Error?error.message:"3D analysis failed; no geometry was substituted."});} };