UNPKG

@bitbybit-dev/occt-worker

Version:

Bit By Bit Developers CAD algorithms using OpenCascade Technology kernel adapted for WebWorker

448 lines (447 loc) 19.4 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /** * OCCT Assembly Manager for creating and managing assembly documents. * * This class provides a document-based API for: * - Creating parts and structure definitions (helper methods for visual programming) * - Building assembly documents from structure definitions * - Querying document parts, shapes, colors, and transforms * - Modifying document labels (color, name) * - Exporting to STEP and glTF formats * - Document lifecycle management * * Note: All methods work with document handles directly. The document stays * in worker memory until explicitly deleted with deleteDocument(). */ export class OCCTAssemblyManager { constructor(occWorkerManager) { this.occWorkerManager = occWorkerManager; } // ===================================================== // Part and Structure Definition Helpers // These are local helper methods for visual programming // ===================================================== /** * Create a part definition for use in assembly structures. * This is a helper for visual programming - it simply wraps the inputs into a part object. * * @param inputs - Part details including id, shape, name, and optional color * @returns Part definition that can be added to an assembly structure * @group assembly * @shortname create part * @drawable false * * @example * ```typescript * const box = await occt.shapes.solid.createBox({ width: 10, length: 10, height: 10 }); * const part = await occt.assembly.manager.createPart({ id: "box", shape: box, name: "Box", color: { r: 1, g: 0, b: 0, a: 1 } }); * ``` */ // eslint-disable-next-line @typescript-eslint/no-explicit-any createPart(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.createPart", inputs); }); } /** * Create an assembly node definition (a container for other nodes). * Assembly nodes group instances and other assemblies together in the hierarchy. * * @param inputs - Assembly node details including id, name, and optional parent * @returns Node definition that can be added to an assembly structure * @group assembly * @shortname create assembly node * @drawable false * * @example * ```typescript * const rootAsm = await occt.assembly.manager.createAssemblyNode({ id: "root", name: "Root Assembly" }); * const subAsm = await occt.assembly.manager.createAssemblyNode({ id: "sub", name: "Sub Assembly", parentId: "root" }); * ``` */ createAssemblyNode(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.createAssemblyNode", inputs); }); } /** * Create an imported part definition that copies a label tree from another document * (typically a STEP-loaded document) into the new assembly. Preserves sub-assembly * hierarchy, names and colors. The result can be referenced by `partId` from any * instance node to place the imported assembly multiple times. * * @param inputs - Imported part details: id, sourceDocumentIndex, optional sourceLabel/name/colorRgba * @returns Imported part definition to add to an assembly structure * * @example * ```typescript * const chairDoc = occt.assembly.manager.loadStepToDoc({ stepData }); * const chair = occt.assembly.manager.createImportedPart({ * id: "chair", sourceDocumentIndex: 0, name: "Chair" * }); * const i1 = occt.assembly.manager.createInstanceNode({ id: "c1", partId: "chair", name: "Chair 1", translation: [0,0,0] }); * const i2 = occt.assembly.manager.createInstanceNode({ id: "c2", partId: "chair", name: "Chair 2", translation: [500,0,0] }); * const structure = occt.assembly.manager.combineStructure({ parts: [], nodes: [i1, i2], loadedParts: [chair] }); * const doc = occt.assembly.manager.buildAssemblyDocument({ structure, sourceDocuments: [chairDoc] }); * ``` */ createImportedPart(inputs) { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.createImportedPart", inputs); } /** * Create an instance node definition (a reference to a part with transform). * Instance nodes place a part at a specific location with optional translation, rotation, and scale. * * @param inputs - Instance node details including id, partId, name, and transform * @returns Node definition that can be added to an assembly structure * @group assembly * @shortname create instance node * @drawable false * * @example * ```typescript * const inst1 = await occt.assembly.manager.createInstanceNode({ id: "box1", partId: "box", name: "Box 1" }); * const inst2 = await occt.assembly.manager.createInstanceNode({ * id: "box2", partId: "box", name: "Box 2", * translation: [20, 0, 0], rotation: [0, 0, 45] * }); * ``` */ createInstanceNode(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.createInstanceNode", inputs); }); } /** * Create a part update definition for modifying an existing part in a document. * Part updates can change the shape, name, and/or color of an existing part. * * @param inputs - Update details including label and optional new shape/name/color * @returns Part update definition that can be added to an assembly structure's partUpdates array * @group assembly * @shortname create part update * @drawable false * * @example * ```typescript * // Get existing parts from document * const parts = await occt.assembly.query.getDocumentParts({ document }); * * // Create a new shape to replace the old one * const newBox = await occt.shapes.solid.createBox({ width: 20, length: 20, height: 20 }); * * // Create an update definition * const update = await occt.assembly.manager.createPartUpdate({ * label: parts[0].label, * shape: newBox, * name: "Bigger Box", * colorRgba: { r: 0, g: 1, b: 0, a: 1 } * }); * * // Combine with structure and rebuild * const structure = await occt.assembly.manager.combineStructure({ parts: [], nodes: [], partUpdates: [update] }); * await occt.assembly.manager.buildAssemblyDocument({ structure, existingDocument: document }); * ``` */ // eslint-disable-next-line @typescript-eslint/no-explicit-any createPartUpdate(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.createPartUpdate", inputs); }); } /** * Combine parts and nodes into a complete assembly structure definition. * This is the final step before calling buildAssemblyDocument. * * @param inputs - Lists of parts and nodes to combine * @returns Complete assembly structure ready for building * @group assembly * @shortname combine structure * @drawable false * * @example * ```typescript * const parts = [part1, part2]; * const nodes = [rootAsm, inst1, inst2]; * const structure = await occt.assembly.manager.combineStructure({ parts, nodes }); * const result = await occt.assembly.manager.buildAssemblyDocument({ structure }); * ``` */ // eslint-disable-next-line @typescript-eslint/no-explicit-any combineStructure(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.combineStructure", inputs); }); } // ===================================================== // Document Building // ===================================================== /** * Build an assembly document from a structure definition. * Returns the document handle directly - document stays in worker memory. * * This is the recommended approach for creating assemblies: * 1. Define parts with shapes, names, and optional colors * 2. Define nodes (assemblies and instances) with hierarchy and transforms * 3. Call this method to create the document * 4. Query the document or export to STEP/glTF * 5. Call deleteDocument() to release memory when done * * If existingDocument is provided and valid, the document will be cleared and * updated instead of creating a new one. This is useful for updating an assembly * without allocating a new document each time. * * @param inputs - Assembly structure definition and optional existing document * @returns The document handle (reference to worker-side document, new or updated) * @throws Error if assembly building fails * @group assembly * @shortname build document * @drawable false * * @example * ```typescript * // Create new document * const structure = await occt.assembly.manager.combineStructure({ parts, nodes }); * const document = await occt.assembly.manager.buildAssemblyDocument({ structure }); * * // Update existing document (reuses same handle) * const updatedStructure = await occt.assembly.manager.combineStructure({ parts: newParts, nodes: newNodes }); * await occt.assembly.manager.buildAssemblyDocument({ structure: updatedStructure, existingDocument: document }); * * // Cleanup * await occt.assembly.manager.deleteDocument({ document }); * ``` */ buildAssemblyDocument(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.buildAssemblyDocument", inputs); }); } /** * Load a STEP file into a new assembly document. * Supports both regular STEP and gzip-compressed STEP-Z. * * @param inputs - STEP file data (as string, ArrayBuffer, Uint8Array, File, or Blob) * @returns The document handle (reference to worker-side document) * @throws Error if STEP loading fails * @group assembly * @shortname load STEP to document * @drawable false * * @example * ```typescript * const stepData = await fetch("model.step").then(r => r.text()); * const document = await occt.assembly.manager.loadStepToDoc({ stepData }); * const parts = await occt.assembly.query.getDocumentParts({ document }); * console.log("Found parts:", parts); * ``` */ loadStepToDoc(inputs) { return __awaiter(this, void 0, void 0, function* () { // Convert File/Blob to ArrayBuffer before sending to worker const stepData = yield this.occWorkerManager.prepareStepData(inputs.stepData); const preparedInputs = Object.assign(Object.assign({}, inputs), { stepData }); return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.loadStepToDoc", preparedInputs); }); } // ===================================================== // Document Modification // ===================================================== /** * Set the color of a label in the document. * Colors are preserved when exporting to STEP and other formats. * * @param inputs - Document, label, and RGBA color values * @returns true on success, false on failure * @group modify * @shortname set label color * @drawable false * * @example * ```typescript * const success = await occt.assembly.manager.setDocLabelColor({ * document, * label: "0:1:1:1", * r: 255, g: 0, b: 0, a: 255 * }); * ``` */ setDocLabelColor(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.setDocLabelColor", inputs); }); } /** * Set or change the name of a label (part, instance, or assembly). * * @param inputs - Document, label, and new name * @returns true on success, false on failure * @group modify * @shortname set label name * @drawable false * * @example * ```typescript * const success = await occt.assembly.manager.setDocLabelName({ * document, * label: "0:1:1:1", * name: "Updated Part Name" * }); * ``` */ setDocLabelName(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.setDocLabelName", inputs); }); } // ===================================================== // Document Export // ===================================================== /** * Export an assembly document to STEP format. * * @param inputs - Export options including document, fileName, author, organization * @returns STEP file content as Uint8Array * @group export * @shortname export document STEP * @drawable false * * @example * ```typescript * const document = await occt.assembly.manager.buildAssemblyDocument({ structure }); * const stepData = await occt.assembly.manager.exportDocumentToStep({ * document, * fileName: "my-assembly.step", * author: "John Doe", * tryDownload: true * }); * ``` */ exportDocumentToStep(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.exportDocumentToStep", inputs).then((s) => { if (inputs.tryDownload && typeof document !== "undefined") { const blob = new Blob([s.buffer], { type: "application/step" }); const blobUrl = URL.createObjectURL(blob); const fileName = inputs.fileName || (inputs.compress ? "assembly.stpZ" : "assembly.step"); const fileLink = document.createElement("a"); fileLink.href = blobUrl; fileLink.target = "_self"; fileLink.download = fileName; fileLink.click(); fileLink.remove(); } return s; }); }); } /** * Export an assembly document to glTF binary (GLB) format. * * @param inputs - Export options including document and mesh settings * @returns GLB content as Uint8Array * @group export * @shortname export document glTF * @drawable false * * @example * ```typescript * const document = await occt.assembly.manager.buildAssemblyDocument({ structure }); * const glbData = await occt.assembly.manager.exportDocumentToGltf({ * document, * meshDeflection: 0.1, * tryDownload: true * }); * ``` */ exportDocumentToGltf(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.exportDocumentToGltf", inputs).then((s) => { if (inputs.tryDownload && typeof document !== "undefined") { const blob = new Blob([s.buffer], { type: "model/gltf-binary" }); const blobUrl = URL.createObjectURL(blob); const fileName = inputs.fileName || "assembly.glb"; const fileLink = document.createElement("a"); fileLink.href = blobUrl; fileLink.target = "_self"; fileLink.download = fileName; fileLink.click(); fileLink.remove(); } return s; }); }); } /** * Export an assembly document to glTF binary (GLB) format with explicit * Draco geometry compression settings. * * @param inputs - Export options including document, mesh settings and Draco knobs * @returns GLB content as Uint8Array * @group export * @shortname export document glTF with draco * @drawable false * * @example * ```typescript * const document = await occt.assembly.manager.buildAssemblyDocument({ structure }); * const glbData = await occt.assembly.manager.exportDocumentToGltfWithDraco({ * document, * meshDeflection: 0.1, * useDraco: true, * dracoCompressionLevel: 7, * tryDownload: true * }); * ``` */ exportDocumentToGltfWithDraco(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.exportDocumentToGltfWithDraco", inputs).then((s) => { if (inputs.tryDownload && typeof document !== "undefined") { const blob = new Blob([s.buffer], { type: "model/gltf-binary" }); const blobUrl = URL.createObjectURL(blob); const fileName = inputs.fileName || "assembly.glb"; const fileLink = document.createElement("a"); fileLink.href = blobUrl; fileLink.target = "_self"; fileLink.download = fileName; fileLink.click(); fileLink.remove(); } return s; }); }); } // ===================================================== // Document Lifecycle // ===================================================== /** * Delete an assembly document and release its memory. * Call this when done with the document to free resources. * * @param inputs - Document to delete * @group lifecycle * @shortname delete document * @drawable false * * @example * ```typescript * const document = await occt.assembly.manager.buildAssemblyDocument({ structure }); * // ... use the document ... * await occt.assembly.manager.deleteDocument({ document }); * ``` */ deleteDocument(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.occWorkerManager.genericCallToWorkerPromise("assembly.manager.deleteDocument", inputs); }); } }