diff --git a/packages/chili-builder/src/appBuilder.ts b/packages/chili-builder/src/appBuilder.ts index f51d54d3..4946afe3 100644 --- a/packages/chili-builder/src/appBuilder.ts +++ b/packages/chili-builder/src/appBuilder.ts @@ -2,7 +2,6 @@ import { Application, CommandService, EditEventHandler, EditorService, HotkeyService } from "chili"; import { - DefaultDataExchange, I18n, IDataExchange, IDocument, @@ -15,6 +14,7 @@ import { Logger, } from "chili-core"; import { IAdditionalModule } from "./additionalModule"; +import { DefaultDataExchange } from "./defaultDataExchange"; export class AppBuilder { protected readonly _inits: (() => Promise)[] = []; diff --git a/packages/chili-builder/src/defaultDataExchange.ts b/packages/chili-builder/src/defaultDataExchange.ts new file mode 100644 index 00000000..11cf10f1 --- /dev/null +++ b/packages/chili-builder/src/defaultDataExchange.ts @@ -0,0 +1,126 @@ +// Copyright 2022-2023 the Chili authors. All rights reserved. AGPL-3.0 license. + +import { + EditableShapeNode, + I18n, + IDataExchange, + IDocument, + IShape, + PubSub, + Result, + ShapeNode, + VisualNode, +} from "chili-core"; + +async function importBrep(document: IDocument, file: File) { + const shape = document.application.shapeFactory.converter.convertFromBrep(await file.text()); + if (!shape.isOk) { + return Result.err(shape.error); + } + return Result.ok(new EditableShapeNode(document, file.name, shape.value)); +} + +async function exportBrep(document: IDocument, shapes: IShape[]) { + const comp = document.application.shapeFactory.combine(shapes); + if (!comp.isOk) { + return Result.err(comp.error); + } + return document.application.shapeFactory.converter.convertToBrep(comp.value); +} + +export class DefaultDataExchange implements IDataExchange { + importFormats(): string[] { + return [".step", ".stp", ".iges", ".igs", ".brep"]; + } + + exportFormats(): string[] { + return [".step", ".iges", ".brep"]; + } + + async import(document: IDocument, files: FileList | File[]): Promise { + for (const file of files) { + await this.handleSingleFileImport(document, file); + } + } + + private async handleSingleFileImport(document: IDocument, file: File) { + const nodeResult = file.name.endsWith(".brep") + ? await importBrep(document, file) + : await this.handleStepIgesImport(document, file); + + if (!nodeResult?.isOk) return; + + const node = nodeResult.value; + node.name = file.name; + document.addNode(node); + document.visual.update(); + } + + private async handleStepIgesImport(document: IDocument, file: File) { + const content = new Uint8Array(await file.arrayBuffer()); + + if (this.isStepFile(file.name)) { + return document.application.shapeFactory.converter.convertFromSTEP(document, content); + } + + if (this.isIgesFile(file.name)) { + return document.application.shapeFactory.converter.convertFromIGES(document, content); + } + + alert(I18n.translate("error.import.unsupportedFileType:{0}", file.name)); + return undefined; + } + + async export(type: string, nodes: VisualNode[]): Promise { + if (!this.validateExportType(type)) return; + + const shapes = this.getExportShapes(nodes); + if (!shapes.length) return; + + const shapeResult = await this.convertShapes(type, nodes[0].document, shapes); + return this.handleExportResult(shapeResult); + } + + private validateExportType(type: string): boolean { + const isValid = this.exportFormats().includes(type); + !isValid && PubSub.default.pub("showToast", "error.import.unsupportedFileType:{0}", type); + return isValid; + } + + private getExportShapes(nodes: VisualNode[]): IShape[] { + const shapes = nodes.filter((x): x is ShapeNode => x instanceof ShapeNode).map((x) => x.shape.value); + + !shapes.length && PubSub.default.pub("showToast", "error.export.noNodeCanBeExported"); + return shapes; + } + + private async convertShapes(type: string, doc: IDocument, shapes: IShape[]) { + if (type === ".step") return this.handleStepExport(doc, shapes); + if (type === ".iges") return this.handleIgesExport(doc, shapes); + return exportBrep(doc, shapes); + } + + private handleStepExport(doc: IDocument, shapes: IShape[]) { + return doc.application.shapeFactory.converter.convertToSTEP(...shapes); + } + + private handleIgesExport(doc: IDocument, shapes: IShape[]) { + return doc.application.shapeFactory.converter.convertToIGES(...shapes); + } + + private handleExportResult(result: Result | undefined) { + if (!result?.isOk) { + PubSub.default.pub("showToast", "error.default:{0}", result?.error); + return undefined; + } + return [result.value]; + } + + private isStepFile(filename: string) { + return filename.endsWith(".step") || filename.endsWith(".stp"); + } + + private isIgesFile(filename: string) { + return filename.endsWith(".iges") || filename.endsWith(".igs"); + } +} diff --git a/packages/chili-core/src/dataExchange.ts b/packages/chili-core/src/dataExchange.ts index 87f28fdc..5b6ad292 100644 --- a/packages/chili-core/src/dataExchange.ts +++ b/packages/chili-core/src/dataExchange.ts @@ -1,9 +1,7 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. AGPL-3.0 license. import { IDocument } from "./document"; -import { PubSub, Result } from "./foundation"; -import { I18n } from "./i18n"; -import { FolderNode, ShapeNode, VisualNode } from "./model"; +import { VisualNode } from "./model"; export interface IDataExchange { importFormats(): string[]; @@ -11,54 +9,3 @@ export interface IDataExchange { import(document: IDocument, files: FileList | File[]): Promise; export(type: string, nodes: VisualNode[]): Promise; } - -export class DefaultDataExchange implements IDataExchange { - importFormats(): string[] { - return [".step", ".stp", ".iges", ".igs"]; - } - - exportFormats(): string[] { - return [".step", ".iges"]; - } - - async import(document: IDocument, files: FileList | File[]): Promise { - for (const file of files) { - let content = new Uint8Array(await file.arrayBuffer()); - let shape: Result; - if (file.name.endsWith(".step") || file.name.endsWith(".stp")) { - shape = document.application.shapeFactory.converter.convertFromSTEP(document, content); - } else if (file.name.endsWith(".iges") || file.name.endsWith(".igs")) { - shape = document.application.shapeFactory.converter.convertFromIGES(document, content); - } else { - alert(I18n.translate("error.import.unsupportedFileType:{0}", file.name)); - continue; - } - if (!shape.isOk) { - PubSub.default.pub("showToast", "error.default:{0}", shape.error); - continue; - } - shape.value.name = file.name; - document.addNode(shape.value); - document.visual.update(); - } - } - - async export(type: string, nodes: VisualNode[]): Promise { - let shapes = nodes.filter((x) => x instanceof ShapeNode).map((x) => x.shape.value); - if (shapes.length === 0) { - PubSub.default.pub("showToast", "error.export.noNodeCanBeExported"); - return undefined; - } - let factory = nodes[0].document.application.shapeFactory.converter.convertToIGES; - if (type === ".step") { - factory = nodes[0].document.application.shapeFactory.converter.convertToSTEP; - } - let shapeString = factory(...shapes); - if (!shapeString.isOk) { - PubSub.default.pub("showToast", "error.default:{0}", shapeString.error); - return undefined; - } - - return [shapeString.value]; - } -}