Skip to content

Commit

Permalink
✨ feat: added the .brep format
Browse files Browse the repository at this point in the history
  • Loading branch information
xiangechen committed Feb 23, 2025
1 parent 458f411 commit b7caf91
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 55 deletions.
2 changes: 1 addition & 1 deletion packages/chili-builder/src/appBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { Application, CommandService, EditEventHandler, EditorService, HotkeyService } from "chili";
import {
DefaultDataExchange,
I18n,
IDataExchange,
IDocument,
Expand All @@ -15,6 +14,7 @@ import {
Logger,
} from "chili-core";
import { IAdditionalModule } from "./additionalModule";
import { DefaultDataExchange } from "./defaultDataExchange";

export class AppBuilder {
protected readonly _inits: (() => Promise<void>)[] = [];
Expand Down
126 changes: 126 additions & 0 deletions packages/chili-builder/src/defaultDataExchange.ts
Original file line number Diff line number Diff line change
@@ -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<void> {
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<BlobPart[] | undefined> {
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<string> | 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");
}
}
55 changes: 1 addition & 54 deletions packages/chili-core/src/dataExchange.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,11 @@
// 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[];
exportFormats(): string[];
import(document: IDocument, files: FileList | File[]): Promise<void>;
export(type: string, nodes: VisualNode[]): Promise<BlobPart[] | undefined>;
}

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<void> {
for (const file of files) {
let content = new Uint8Array(await file.arrayBuffer());
let shape: Result<FolderNode>;
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<BlobPart[] | undefined> {
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];
}
}

0 comments on commit b7caf91

Please sign in to comment.