diff --git a/.vscode/launch.json b/.vscode/launch.json index 8da9526d..f1179988 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,6 +13,12 @@ "windows": { "program": "${workspaceFolder}/node_modules/jest/bin/jest" } + }, + { + "name": "debug", + "type": "msedge", + "request": "launch", + "url": "http://localhost:8080/" } ] } diff --git a/cpp/src/converter.cpp b/cpp/src/converter.cpp index 8e2155a3..3fb1f9fa 100644 --- a/cpp/src/converter.cpp +++ b/cpp/src/converter.cpp @@ -1,20 +1,202 @@ -#include +#include "shared.hpp" +#include +#include #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace emscripten; -class Converter { +class VectorBuffer : public std::streambuf +{ +public: + VectorBuffer(const std::vector &v) + { + setg((char *)v.data(), (char *)v.data(), (char *)(v.data() + v.size())); + } +}; + +struct Color +{ + double r; + double g; + double b; + double a; +}; + +EMSCRIPTEN_DECLARE_VAL_TYPE(ShapeNodeArray) + +struct ShapeNode +{ + std::optional shape; + Color color; + std::vector children; + std::string name; + + ShapeNodeArray getChildren() const + { + return ShapeNodeArray(val::array(children)); + } +}; + +static std::string getLabelNameNoRef(const TDF_Label &label) +{ + Handle(TDataStd_Name) nameAttribute = new TDataStd_Name(); + if (!label.FindAttribute(nameAttribute->GetID(), nameAttribute)) + { + return std::string(); + } + + Standard_Integer utf8NameLength = nameAttribute->Get().LengthOfCString(); + char *nameBuf = new char[utf8NameLength + 1]; + nameAttribute->Get().ToUTF8CString(nameBuf); + std::string name(nameBuf, utf8NameLength); + delete[] nameBuf; + return name; +} + +static std::string getLabelName(const TDF_Label &label, const Handle(XCAFDoc_ShapeTool) & shapeTool) +{ + if (XCAFDoc_ShapeTool::IsReference(label)) + { + TDF_Label referredShapeLabel; + shapeTool->GetReferredShape(label, referredShapeLabel); + return getLabelName(referredShapeLabel, shapeTool); + } + return getLabelNameNoRef(label); +} + +static std::string getShapeName(const TopoDS_Shape &shape, const Handle(XCAFDoc_ShapeTool) & shapeTool) +{ + TDF_Label shapeLabel; + if (!shapeTool->Search(shape, shapeLabel)) + { + return std::string(); + } + return getLabelName(shapeLabel, shapeTool); +} + +static bool getLabelColorNoRef(const TDF_Label &label, const Handle(XCAFDoc_ColorTool) & colorTool, Color &color) +{ + static const std::vector colorTypes = { + XCAFDoc_ColorSurf, + XCAFDoc_ColorCurv, + XCAFDoc_ColorGen}; + + Quantity_Color qColor; + for (XCAFDoc_ColorType colorType : colorTypes) + { + if (colorTool->GetColor(label, colorType, qColor)) + { + color = {qColor.Red(), qColor.Green(), qColor.Blue(), 1.0}; + return true; + } + } + + return false; +} + +static bool getLabelColor(const TDF_Label &label, const Handle(XCAFDoc_ShapeTool) & shapeTool, const Handle(XCAFDoc_ColorTool) & colorTool, Color &color) +{ + if (getLabelColorNoRef(label, colorTool, color)) + { + return true; + } + + if (XCAFDoc_ShapeTool::IsReference(label)) + { + TDF_Label referredShape; + shapeTool->GetReferredShape(label, referredShape); + return getLabelColor(referredShape, shapeTool, colorTool, color); + } + + return false; +} + +static bool getShapeColor(const TopoDS_Shape &shape, const Handle(XCAFDoc_ShapeTool) & shapeTool, const Handle(XCAFDoc_ColorTool) & colorTool, Color &color) +{ + TDF_Label shapeLabel; + if (!shapeTool->Search(shape, shapeLabel)) + { + return false; + } + return getLabelColor(shapeLabel, shapeTool, colorTool, color); +} + +static ShapeNode initNode(const TDF_Label label, const Handle(XCAFDoc_ShapeTool) shapeTool, const Handle(XCAFDoc_ColorTool) colorTool) +{ + Color color; + getLabelColor(label, shapeTool, colorTool, color); + + ShapeNode node = { + .shape = std::nullopt, + .color = color, + .children = {}, + .name = getLabelName(label, shapeTool), + }; + + return node; +} + +static void addChildNodes(ShapeNode &parent, const TDF_Label &parentLabel, const Handle(XCAFDoc_ShapeTool) & shapeTool, const Handle(XCAFDoc_ColorTool) & colorTool) +{ + for (TDF_ChildIterator it(parentLabel); it.More(); it.Next()) + { + TDF_Label childLabel = it.Value(); + TopoDS_Shape tmpShape; + if (shapeTool->GetShape(childLabel, tmpShape) && shapeTool->IsFree(childLabel)) + { + ShapeNode childNode = initNode(childLabel, shapeTool, colorTool); + childNode.shape = tmpShape; + parent.children.push_back(childNode); + + addChildNodes(childNode, childLabel, shapeTool, colorTool); + } + } +} + +static ShapeNode getNodesFromDocument(Handle(TDocStd_Document) document) +{ + TDF_Label mainLabel = document->Main(); + Handle(XCAFDoc_ShapeTool) shapeTool = XCAFDoc_DocumentTool::ShapeTool(mainLabel); + Handle(XCAFDoc_ColorTool) colorTool = XCAFDoc_DocumentTool::ColorTool(mainLabel); + + TDF_Label shapeLabel = shapeTool->Label(); + ShapeNode rootNode = initNode(shapeLabel, shapeTool, colorTool); + TopoDS_Shape tmpShape; + if (shapeTool->GetShape(shapeLabel, tmpShape) && shapeTool->IsFree(shapeLabel)) + { + rootNode.shape = tmpShape; + } + addChildNodes(rootNode, shapeLabel, shapeTool, colorTool); + + return rootNode; +} + +class Converter +{ public: - static std::string convertToBrep(const TopoDS_Shape& input) { + static std::string convertToBrep(const TopoDS_Shape &input) + { std::ostringstream oss; BRepTools::Write(input, oss); return oss.str(); } - static TopoDS_Shape convertFromBrep(const std::string& input) { + static TopoDS_Shape convertFromBrep(const std::string &input) + { std::istringstream iss(input); TopoDS_Shape output; BRep_Builder builder; @@ -22,12 +204,114 @@ class Converter { return output; } + static std::optional convertFromStep(const Uint8Array &buffer) + { + std::vector input = convertJSArrayToNumberVector(buffer); + VectorBuffer vectorBuffer(input); + std::istream iss(&vectorBuffer); + + STEPCAFControl_Reader cafReader; + cafReader.SetColorMode(true); + cafReader.SetNameMode(true); + IFSelect_ReturnStatus readStatus = cafReader.ReadStream("stp", iss); + + if (readStatus != IFSelect_RetDone) + { + return std::nullopt; + } + + Handle(TDocStd_Document) document = new TDocStd_Document("bincaf"); + if (!cafReader.Transfer(document)) + { + return std::nullopt; + } + + return getNodesFromDocument(document); + } + + static std::optional convertFromIges(const Uint8Array &buffer) + { + std::vector input = convertJSArrayToNumberVector(buffer); + std::string dummyFileName = "temp.igs"; + std::ofstream dummyFile; + dummyFile.open(dummyFileName, std::ios::binary); + dummyFile.write((char *)input.data(), input.size()); + dummyFile.close(); + + IGESCAFControl_Reader igesCafReader; + igesCafReader.SetColorMode(true); + igesCafReader.SetNameMode(true); + IFSelect_ReturnStatus readStatus = igesCafReader.ReadFile(dummyFileName.c_str()); + + if (readStatus != IFSelect_RetDone) + { + return std::nullopt; + } + + Handle(TDocStd_Document) document = new TDocStd_Document("bincaf"); + if (!igesCafReader.Transfer(document)) + { + return std::nullopt; + } + + return getNodesFromDocument(document); + } + + static std::string convertToStep(const ShapeArray &input) + { + auto shapes = vecFromJSArray(input); + std::ostringstream oss; + STEPControl_Writer stepWriter; + for (const auto &shape : shapes) + { + stepWriter.Transfer(shape, STEPControl_AsIs); + } + stepWriter.WriteStream(oss); + return oss.str(); + } + + static std::string convertToIges(const ShapeArray &input) + { + auto shapes = vecFromJSArray(input); + std::ostringstream oss; + IGESControl_Writer igesWriter; + for (const auto &shape : shapes) + { + igesWriter.AddShape(shape); + } + igesWriter.ComputeModel(); + igesWriter.Write(oss); + return oss.str(); + } + }; EMSCRIPTEN_BINDINGS(Converter) { + register_optional(); + + register_type("Array"); + + value_object("Color") + .field("r", &Color::r) + .field("g", &Color::g) + .field("b", &Color::b) + .field("a", &Color::a); + + class_("ShapeNode") + .property("shape", &ShapeNode::shape) + .property("color", &ShapeNode::color) + .property("name", &ShapeNode::name) + .function("getChildren", &ShapeNode::getChildren) + ; + class_("Converter") .class_function("convertToBrep", &Converter::convertToBrep) .class_function("convertFromBrep", &Converter::convertFromBrep) + .class_function("convertFromStep", &Converter::convertFromStep) + .class_function("convertFromIges", &Converter::convertFromIges) + .class_function("convertToStep", &Converter::convertToStep) + .class_function("convertToIges", &Converter::convertToIges) + ; } \ No newline at end of file diff --git a/cpp/src/mesher.cpp b/cpp/src/mesher.cpp index 760abe55..b59794dc 100644 --- a/cpp/src/mesher.cpp +++ b/cpp/src/mesher.cpp @@ -1,6 +1,7 @@ #include "shared.hpp" #include #include +#include #include #include #include @@ -19,12 +20,33 @@ #include #include #include +#include using namespace emscripten; using namespace std; const double ANGLE_DEFLECTION = 0.5; +double boundingBoxRatio(const TopoDS_Shape &shape, double linearDeflection) +{ + Bnd_Box boundingBox; + BRepBndLib::Add(shape, boundingBox, false); + if (boundingBox.IsVoid()) + { + return linearDeflection; + } + Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; + boundingBox.Get(xMin, yMin, zMin, xMax, yMax, zMax); + + Standard_Real avgSize = ((xMax - xMin) + (yMax - yMin) + (zMax - zMin)) / 3.0; + double linDeflection = avgSize * linearDeflection; + if (linDeflection < Precision::Confusion()) + { + linDeflection = 1.0; + } + return linDeflection; +} + class EdgeMesher { private: @@ -49,7 +71,7 @@ class EdgeMesher } } - void generateEdgeMesh(const TopoDS_Edge& edge, const gp_Trsf &transform) + void generateEdgeMesh(const TopoDS_Edge &edge, const gp_Trsf &transform) { auto start = this->position.size() / 3; @@ -59,7 +81,8 @@ class EdgeMesher for (int i = 0; i < pnts.NbPoints(); i++) { auto pnt = pnts.Value(i + 1).Transformed(transform); - if (prePnt.has_value()) { + if (prePnt.has_value()) + { auto pre = prePnt.value(); this->position.push_back(pre.X()); this->position.push_back(pre.Y()); @@ -77,7 +100,7 @@ class EdgeMesher } public: - EdgeMesher(const TopoDS_Shape& shape, double lineDeflection) : shape(shape), lineDeflection(lineDeflection) + EdgeMesher(const TopoDS_Shape &shape, double lineDeflection) : shape(shape), lineDeflection(lineDeflection) { generateEdgeMeshs(); } @@ -97,15 +120,15 @@ class EdgeMesher return edges.size(); } - TopoDS_Edge& getEdge(size_t index) + TopoDS_Edge &getEdge(size_t index) { return edges[index]; } - EdgeArray getEdges() { + EdgeArray getEdges() + { return EdgeArray(val::array(edges)); } - }; class FaceMesher @@ -175,7 +198,8 @@ class FaceMesher for (int index = 0; index < handlePoly->NbNodes(); index++) { auto normal = handlePoly->Normal(index + 1); - if (shouldReverse) { + if (shouldReverse) + { normal.Reverse(); } normal = normal.Transformed(transform); @@ -195,7 +219,7 @@ class FaceMesher v2 = 3; v3 = 2; } - + auto triangle = handlePoly->Triangle(index + 1); this->index.push_back(triangle.Value(v1) - 1 + indexStart); this->index.push_back(triangle.Value(v2) - 1 + indexStart); @@ -203,10 +227,10 @@ class FaceMesher } } - void fillUv(const TopoDS_Face &face, const Handle(Poly_Triangulation) & handlePoly) + void fillUv(const TopoDS_Face &face, const Handle(Poly_Triangulation) & handlePoly) { double aUmin, aUmax, aVmin, aVmax, dUmax, dVmax; - BRepTools::UVBounds (face, aUmin, aUmax, aVmin, aVmax); + BRepTools::UVBounds(face, aUmin, aUmax, aVmin, aVmax); dUmax = (aUmax - aUmin); dVmax = (aVmax - aVmin); for (int index = 0; index < handlePoly->NbNodes(); index++) @@ -254,18 +278,21 @@ class FaceMesher return faces.size(); } - TopoDS_Face& getFace(size_t index) { + TopoDS_Face &getFace(size_t index) + { return faces[index]; } - FaceArray getFaces() { + FaceArray getFaces() + { return FaceArray(val::array(faces)); } - }; EMSCRIPTEN_BINDINGS(Mesher) { + emscripten::function("boundingBoxRatio", &boundingBoxRatio); + class_("FaceMesher") .constructor() .function("getPosition", &FaceMesher::getPosition) @@ -275,8 +302,7 @@ EMSCRIPTEN_BINDINGS(Mesher) .function("getGroups", &FaceMesher::getGroups) .function("getFaceSize", &FaceMesher::getFaceSize) .function("getFace", &FaceMesher::getFace) - .function("getFaces", &FaceMesher::getFaces) - ; + .function("getFaces", &FaceMesher::getFaces); class_("EdgeMesher") .constructor() @@ -284,9 +310,5 @@ EMSCRIPTEN_BINDINGS(Mesher) .function("getGroups", &EdgeMesher::getGroups) .function("getEdgeSize", &EdgeMesher::getEdgeSize) .function("getEdge", &EdgeMesher::getEdge) - .function("getEdges", &EdgeMesher::getEdges) - ; - - - + .function("getEdges", &EdgeMesher::getEdges); } diff --git a/cpp/src/opencascade.cpp b/cpp/src/opencascade.cpp index b1e295f2..0d51d395 100644 --- a/cpp/src/opencascade.cpp +++ b/cpp/src/opencascade.cpp @@ -50,6 +50,8 @@ using namespace emscripten; EMSCRIPTEN_BINDINGS(opencascade) { + register_optional(); + enum_("GeomAbs_Shape") .value("GeomAbs_C0", GeomAbs_C0) .value("GeomAbs_C1", GeomAbs_C1) diff --git a/packages/chili-core/src/foundation/result.ts b/packages/chili-core/src/foundation/result.ts index 5ba9cc42..bc538bf8 100644 --- a/packages/chili-core/src/foundation/result.ts +++ b/packages/chili-core/src/foundation/result.ts @@ -3,9 +3,9 @@ import { IEqualityComparer } from "./equalityComparer"; export class Result { - #isOk: boolean; - #value: T | undefined; - #error: E | undefined; + readonly #isOk: boolean; + readonly #value: T | undefined; + readonly #error: E | undefined; constructor(isOk: boolean, value: T | undefined, error: E | undefined) { this.#isOk = isOk; @@ -13,6 +13,10 @@ export class Result { this.#error = error; } + parse(): Result { + return Result.err(this.#error as E) as any; + } + get isOk(): boolean { return this.#isOk; } diff --git a/packages/chili-core/src/foundation/utils/readFileAsync.ts b/packages/chili-core/src/foundation/utils/readFileAsync.ts index 7156a7a8..e00a9b2b 100644 --- a/packages/chili-core/src/foundation/utils/readFileAsync.ts +++ b/packages/chili-core/src/foundation/utils/readFileAsync.ts @@ -2,15 +2,40 @@ import { Result } from ".."; +export async function readFilesAsync(accept: string, multiple: boolean): Promise> { + return new Promise((resolve, _reject) => { + let input = document.createElement("input"); + input.type = "file"; + input.multiple = multiple; + input.accept = accept; + input.style.visibility = "hidden"; + input.onchange = async () => { + document.body.removeChild(input); + let files = input.files; + if (files === null) { + resolve(Result.err(`no files selected`)); + } else { + resolve(Result.ok(files)); + } + }; + input.oncancel = () => { + document.body.removeChild(input); + resolve(Result.err(`cancel`)); + }; + document.body.appendChild(input); + input.click(); + }); +} + export interface FileData { fileName: string; - data: string; + data: string | ArrayBuffer; } export async function readFileAsync( accept: string, multiple: boolean, - method: "readAsText" | "readAsDataURL" = "readAsText", + method: "readAsText" | "readAsDataURL" | "readAsArrayBuffer" = "readAsText", ): Promise> { return new Promise((resolve, _reject) => { let input = document.createElement("input"); @@ -31,7 +56,10 @@ export async function readFileAsync( }); } -async function readInputedFiles(input: HTMLInputElement, method: "readAsText" | "readAsDataURL") { +async function readInputedFiles( + input: HTMLInputElement, + method: "readAsText" | "readAsDataURL" | "readAsArrayBuffer", +) { let files = input.files ?? []; let result: FileData[] = []; for (const file of files) { @@ -48,14 +76,16 @@ async function readInputedFiles(input: HTMLInputElement, method: "readAsText" | return Result.ok(result); } -function readFileDataAsync(file: File, method: any): Promise { +function readFileDataAsync(file: File, method: any): Promise { return new Promise((resolve) => { let reader = new FileReader(); reader.onload = (e) => { - resolve(e.target!.result as string); + if (e.target?.readyState === FileReader.DONE) { + resolve(e.target.result); + } }; reader.onerror = () => { - resolve(undefined); + resolve(null); }; (reader as any)[method](file); }); diff --git a/packages/chili-core/src/shape/shapeConverter.ts b/packages/chili-core/src/shape/shapeConverter.ts index acaa777e..2144a661 100644 --- a/packages/chili-core/src/shape/shapeConverter.ts +++ b/packages/chili-core/src/shape/shapeConverter.ts @@ -5,9 +5,9 @@ import { IShape } from "./shape"; export interface IShapeConverter { convertToIGES(...shapes: IShape[]): Result; - convertFromIGES(iges: string): Result; + convertFromIGES(iges: Uint8Array): Result; convertToSTEP(...shapes: IShape[]): Result; - convertFromSTEP(step: string): Result; + convertFromSTEP(step: Uint8Array): Result; convertToBrep(shape: IShape): Result; convertFromBrep(brep: string): Result; } diff --git a/packages/chili-occ/src/occConverter.ts b/packages/chili-occ/src/occConverter.ts index 82d47691..7e5a1427 100644 --- a/packages/chili-occ/src/occConverter.ts +++ b/packages/chili-occ/src/occConverter.ts @@ -50,7 +50,7 @@ export class OccShapeConverter implements IShapeConverter { }); } - convertFromIGES(data: string) { + convertFromIGES(data: Uint8Array) { return this.convertFrom("iges", data); } @@ -80,7 +80,7 @@ export class OccShapeConverter implements IShapeConverter { }); } - convertFromSTEP(data: string) { + convertFromSTEP(data: Uint8Array) { return this.convertFrom("step", data); } @@ -90,7 +90,7 @@ export class OccShapeConverter implements IShapeConverter { * @param data * @returns */ - private convertFrom(format: "step" | "iges", data: string): Result { + private convertFrom(format: "step" | "iges", data: Uint8Array): Result { return gc((c) => { const fileName = `blob.${format}`; let reader = c( diff --git a/packages/chili-ui/src/property/material/materialEditor.ts b/packages/chili-ui/src/property/material/materialEditor.ts index 2d83a8f2..79963ae1 100644 --- a/packages/chili-ui/src/property/material/materialEditor.ts +++ b/packages/chili-ui/src/property/material/materialEditor.ts @@ -129,7 +129,7 @@ export class MaterialEditor extends HTMLElement { private initEditingControl(material: Material) { const selectTexture = async () => { let file = await readFileAsync(".png, .jpg, .jpeg", false, "readAsDataURL"); - material.texture = file.ok()[0].data; + material.texture = file.ok()[0].data as string; }; let container = div({ className: style.properties, diff --git a/packages/chili-wasm/lib/chili-wasm.d.ts b/packages/chili-wasm/lib/chili-wasm.d.ts index f67a0c9e..19b9de15 100644 --- a/packages/chili-wasm/lib/chili-wasm.d.ts +++ b/packages/chili-wasm/lib/chili-wasm.d.ts @@ -15,10 +15,25 @@ declare namespace RuntimeExports { interface WasmModule {} type EmbindString = ArrayBuffer | Uint8Array | Uint8ClampedArray | Int8Array | string; +export interface ShapeNode { + color: Color; + name: EmbindString; + shape: TopoDS_Shape | undefined; + getChildren(): Array; + delete(): void; +} + export interface Converter { delete(): void; } +export type Color = { + r: number; + g: number; + b: number; + a: number; +}; + export interface ShapeResult { isOk: boolean; error: EmbindString; @@ -643,7 +658,15 @@ export interface Transient { } interface EmbindModule { - Converter: { convertToBrep(_0: TopoDS_Shape): string; convertFromBrep(_0: EmbindString): TopoDS_Shape }; + ShapeNode: {}; + Converter: { + convertToBrep(_0: TopoDS_Shape): string; + convertFromBrep(_0: EmbindString): TopoDS_Shape; + convertFromStep(_0: Uint8Array): ShapeNode | undefined; + convertFromIges(_0: Uint8Array): ShapeNode | undefined; + convertToStep(_0: Array): string; + convertToIges(_0: Array): string; + }; ShapeResult: {}; ShapeFactory: { makeThickSolidBySimple(_0: TopoDS_Shape, _1: number): ShapeResult; @@ -775,6 +798,7 @@ interface EmbindModule { compsolid(_0: TopoDS_Shape): TopoDS_CompSolid; }; TopoDS_Shape: {}; + boundingBoxRatio(_0: TopoDS_Shape, _1: number): number; TColgp_Array1OfPnt: { new (_0: number, _1: number): TColgp_Array1OfPnt }; TopoDS_Vertex: {}; TopoDS_Edge: {}; diff --git a/packages/chili-wasm/lib/chili-wasm.js b/packages/chili-wasm/lib/chili-wasm.js index 07cdd59d..9fea6094 100755 --- a/packages/chili-wasm/lib/chili-wasm.js +++ b/packages/chili-wasm/lib/chili-wasm.js @@ -219,10 +219,10 @@ var Module = (() => { var info = getWasmImports(); function receiveInstance(instance, module) { wasmExports = instance.exports; - wasmMemory = wasmExports["ka"]; + wasmMemory = wasmExports["la"]; updateMemoryViews(); - wasmTable = wasmExports["pa"]; - addOnInit(wasmExports["la"]); + wasmTable = wasmExports["qa"]; + addOnInit(wasmExports["ma"]); removeRunDependency("wasm-instantiate"); return wasmExports; } @@ -4217,6 +4217,36 @@ var Module = (() => { destructorFunction: null, }); }; + var __embind_register_function = ( + name, + argCount, + rawArgTypesAddr, + signature, + rawInvoker, + fn, + isAsync, + ) => { + var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + name = readLatin1String(name); + name = getFunctionName(name); + rawInvoker = embind__requireFunction(signature, rawInvoker); + exposePublicSymbol( + name, + function () { + throwUnboundTypeError(`Cannot call ${name} due to unbound types`, argTypes); + }, + argCount - 1, + ); + whenDependentTypesAreResolved([], argTypes, (argTypes) => { + var invokerArgsArray = [argTypes[0], null].concat(argTypes.slice(1)); + replacePublicSymbol( + name, + craftInvokerFunction(name, invokerArgsArray, null, rawInvoker, fn, isAsync), + argCount - 1, + ); + return []; + }); + }; var integerReadValueFromPointer = (name, width, signed) => { switch (width) { case 1: @@ -5748,86 +5778,89 @@ var Module = (() => { var preloadedImages = {}; var preloadedAudios = {}; var wasmImports = { - ha: OSD_MemInfo_getModuleHeapLength, + fa: OSD_MemInfo_getModuleHeapLength, a: ___cxa_throw, - ba: ___syscall_chmod, - ca: ___syscall_faccessat, - C: ___syscall_fcntl64, - Z: ___syscall_fstat64, - fa: ___syscall_ioctl, - X: ___syscall_lstat64, - T: ___syscall_mkdirat, - W: ___syscall_newfstatat, - F: ___syscall_openat, - Y: ___syscall_stat64, - S: __abort_js, - o: __embind_finalize_value_object, - L: __embind_register_bigint, - ea: __embind_register_bool, + aa: ___syscall_chmod, + ba: ___syscall_faccessat, + B: ___syscall_fcntl64, + Y: ___syscall_fstat64, + da: ___syscall_ioctl, + W: ___syscall_lstat64, + S: ___syscall_mkdirat, + V: ___syscall_newfstatat, + D: ___syscall_openat, + X: ___syscall_stat64, + R: __abort_js, + p: __embind_finalize_value_object, + K: __embind_register_bigint, + ja: __embind_register_bool, c: __embind_register_class, d: __embind_register_class_class_function, - i: __embind_register_class_constructor, + j: __embind_register_class_constructor, b: __embind_register_class_function, g: __embind_register_class_property, - I: __embind_register_emval, - y: __embind_register_enum, + ia: __embind_register_emval, + z: __embind_register_enum, h: __embind_register_enum_value, - D: __embind_register_float, + G: __embind_register_float, + ha: __embind_register_function, s: __embind_register_integer, - k: __embind_register_memory_view, - z: __embind_register_optional, - E: __embind_register_std_string, - A: __embind_register_std_wstring, - l: __embind_register_user_type, - p: __embind_register_value_object, + m: __embind_register_memory_view, + y: __embind_register_optional, + H: __embind_register_std_string, + C: __embind_register_std_wstring, + n: __embind_register_user_type, + q: __embind_register_value_object, f: __embind_register_value_object_field, - ja: __embind_register_void, - $: __emscripten_get_now_is_monotonic, - N: __emscripten_lookup_name, - _: __emscripten_memcpy_js, - R: __emscripten_runtime_keepalive_clear, - q: __emval_as, + ka: __embind_register_void, + _: __emscripten_get_now_is_monotonic, + M: __emscripten_lookup_name, + Z: __emscripten_memcpy_js, + Q: __emscripten_runtime_keepalive_clear, + o: __emval_as, u: __emval_call_method, e: __emval_decref, t: __emval_get_method_caller, r: __emval_get_property, - j: __emval_incref, + i: __emval_incref, v: __emval_new_array, w: __emval_new_array_from_memory_view, x: __emval_new_cstring, - m: __emval_run_destructors, - n: __emval_take_value, - J: __localtime_js, - M: __setitimer_js, - da: __tzset_js, - aa: _emscripten_date_now, - P: _emscripten_get_heap_max, - ia: _emscripten_get_preloaded_image_data, - O: _emscripten_resize_heap, - U: _environ_get, - V: _environ_sizes_get, - ga: _exit, - B: _fd_close, - H: _fd_read, - K: _fd_seek, - G: _fd_write, - Q: _proc_exit, + k: __emval_run_destructors, + l: __emval_take_value, + I: __localtime_js, + L: __setitimer_js, + ca: __tzset_js, + $: _emscripten_date_now, + O: _emscripten_get_heap_max, + ga: _emscripten_get_preloaded_image_data, + N: _emscripten_resize_heap, + T: _environ_get, + U: _environ_sizes_get, + ea: _exit, + A: _fd_close, + F: _fd_read, + J: _fd_seek, + E: _fd_write, + P: _proc_exit, }; var wasmExports = createWasm(); - var ___wasm_call_ctors = () => (___wasm_call_ctors = wasmExports["la"])(); - var ___getTypeName = (a0) => (___getTypeName = wasmExports["ma"])(a0); - var _malloc = (a0) => (_malloc = wasmExports["na"])(a0); - var _free = (a0) => (_free = wasmExports["oa"])(a0); - var _htons = (a0) => (_htons = wasmExports["qa"])(a0); + var ___wasm_call_ctors = () => (___wasm_call_ctors = wasmExports["ma"])(); + var ___getTypeName = (a0) => (___getTypeName = wasmExports["na"])(a0); + var _malloc = (a0) => (_malloc = wasmExports["oa"])(a0); + var _free = (a0) => (_free = wasmExports["pa"])(a0); + var _htons = (a0) => (_htons = wasmExports["ra"])(a0); var _emscripten_builtin_memalign = (a0, a1) => - (_emscripten_builtin_memalign = wasmExports["ra"])(a0, a1); - var __emscripten_timeout = (a0, a1) => (__emscripten_timeout = wasmExports["sa"])(a0, a1); + (_emscripten_builtin_memalign = wasmExports["sa"])(a0, a1); + var __emscripten_timeout = (a0, a1) => (__emscripten_timeout = wasmExports["ta"])(a0, a1); var dynCall_jiji = (Module["dynCall_jiji"] = (a0, a1, a2, a3, a4) => - (dynCall_jiji = Module["dynCall_jiji"] = wasmExports["ta"])(a0, a1, a2, a3, a4)); + (dynCall_jiji = Module["dynCall_jiji"] = wasmExports["ua"])(a0, a1, a2, a3, a4)); + var dynCall_viijii = (Module["dynCall_viijii"] = (a0, a1, a2, a3, a4, a5, a6) => + (dynCall_viijii = Module["dynCall_viijii"] = wasmExports["va"])(a0, a1, a2, a3, a4, a5, a6)); var dynCall_viiijj = (Module["dynCall_viiijj"] = (a0, a1, a2, a3, a4, a5, a6, a7) => - (dynCall_viiijj = Module["dynCall_viiijj"] = wasmExports["ua"])(a0, a1, a2, a3, a4, a5, a6, a7)); + (dynCall_viiijj = Module["dynCall_viiijj"] = wasmExports["wa"])(a0, a1, a2, a3, a4, a5, a6, a7)); var dynCall_viiiiji = (Module["dynCall_viiiiji"] = (a0, a1, a2, a3, a4, a5, a6, a7) => - (dynCall_viiiiji = Module["dynCall_viiiiji"] = wasmExports["va"])( + (dynCall_viiiiji = Module["dynCall_viiiiji"] = wasmExports["xa"])( a0, a1, a2, @@ -5837,12 +5870,10 @@ var Module = (() => { a6, a7, )); - var dynCall_viijii = (Module["dynCall_viijii"] = (a0, a1, a2, a3, a4, a5, a6) => - (dynCall_viijii = Module["dynCall_viijii"] = wasmExports["wa"])(a0, a1, a2, a3, a4, a5, a6)); var dynCall_iiiiij = (Module["dynCall_iiiiij"] = (a0, a1, a2, a3, a4, a5, a6) => - (dynCall_iiiiij = Module["dynCall_iiiiij"] = wasmExports["xa"])(a0, a1, a2, a3, a4, a5, a6)); + (dynCall_iiiiij = Module["dynCall_iiiiij"] = wasmExports["ya"])(a0, a1, a2, a3, a4, a5, a6)); var dynCall_iiiiijj = (Module["dynCall_iiiiijj"] = (a0, a1, a2, a3, a4, a5, a6, a7, a8) => - (dynCall_iiiiijj = Module["dynCall_iiiiijj"] = wasmExports["ya"])( + (dynCall_iiiiijj = Module["dynCall_iiiiijj"] = wasmExports["za"])( a0, a1, a2, @@ -5854,7 +5885,7 @@ var Module = (() => { a8, )); var dynCall_iiiiiijj = (Module["dynCall_iiiiiijj"] = (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) => - (dynCall_iiiiiijj = Module["dynCall_iiiiiijj"] = wasmExports["za"])( + (dynCall_iiiiiijj = Module["dynCall_iiiiiijj"] = wasmExports["Aa"])( a0, a1, a2, diff --git a/packages/chili-wasm/lib/chili-wasm.wasm b/packages/chili-wasm/lib/chili-wasm.wasm index aa158b98..354763dc 100644 Binary files a/packages/chili-wasm/lib/chili-wasm.wasm and b/packages/chili-wasm/lib/chili-wasm.wasm differ diff --git a/packages/chili-wasm/src/converter.ts b/packages/chili-wasm/src/converter.ts index 2bac35de..e12181b1 100644 --- a/packages/chili-wasm/src/converter.ts +++ b/packages/chili-wasm/src/converter.ts @@ -1,19 +1,61 @@ import { IShape, IShapeConverter, Result } from "chili-core"; import { OccShape } from "./shape"; import { OcctHelper } from "./helper"; +import { ShapeNode } from "../lib/chili-wasm"; + +const parseShapeNodeToShapes = (shapes: IShape[], shapeNode: ShapeNode) => { + shapeNode.getChildren().forEach((child) => { + if (child.shape) shapes.push(OcctHelper.wrapShape(child.shape)); + parseShapeNodeToShapes(shapes, child); + }); + return shapes; +}; export class OccShapeConverter implements IShapeConverter { convertToIGES(...shapes: IShape[]): Result { - throw new Error("Method not implemented."); + let occShapes = shapes.map((shape) => { + if (shape instanceof OccShape) { + return shape.shape; + } + throw new Error("Shape is not an OccShape"); + }); + return Result.ok(wasm.Converter.convertToIges(occShapes)); } - convertFromIGES(iges: string): Result { - throw new Error("Method not implemented."); + + convertFromIGES(iges: Uint8Array): Result { + let shapes: IShape[] = []; + let node = wasm.Converter.convertFromIges(iges); + + if (node) { + if (node.shape) { + shapes.push(OcctHelper.wrapShape(node.shape)); + } + parseShapeNodeToShapes(shapes, node); + } + + return Result.ok(shapes); } convertToSTEP(...shapes: IShape[]): Result { - throw new Error("Method not implemented."); + let occShapes = shapes.map((shape) => { + if (shape instanceof OccShape) { + return shape.shape; + } + throw new Error("Shape is not an OccShape"); + }); + return Result.ok(wasm.Converter.convertToStep(occShapes)); } - convertFromSTEP(step: string): Result { - throw new Error("Method not implemented."); + convertFromSTEP(step: Uint8Array): Result { + let shapes: IShape[] = []; + let node = wasm.Converter.convertFromStep(step); + + if (node) { + if (node.shape) { + shapes.push(OcctHelper.wrapShape(node.shape)); + } + parseShapeNodeToShapes(shapes, node); + } + + return Result.ok(shapes); } convertToBrep(shape: IShape): Result { if (shape instanceof OccShape) { diff --git a/packages/chili/src/commands/application/openDocument.ts b/packages/chili/src/commands/application/openDocument.ts index 6201ee45..e071b93c 100644 --- a/packages/chili/src/commands/application/openDocument.ts +++ b/packages/chili/src/commands/application/openDocument.ts @@ -14,7 +14,7 @@ export class OpenDocument implements ICommand { async () => { let files = await readFileAsync(".cd", false); if (files.isOk) { - let json: Serialized = JSON.parse(files.ok()[0].data); + let json: Serialized = JSON.parse(files.ok()[0].data as string); let document = await app.loadDocument(json); document?.application.activeView?.cameraController.fitContent(); } diff --git a/packages/chili/src/commands/importExport.ts b/packages/chili/src/commands/importExport.ts index d9ad5b97..6ab9bf3e 100644 --- a/packages/chili/src/commands/importExport.ts +++ b/packages/chili/src/commands/importExport.ts @@ -17,7 +17,7 @@ import { Transaction, command, download, - readFileAsync, + readFilesAsync, } from "chili-core"; import { ImportedBody } from "../bodys/importer"; import { SelectModelStep } from "../step"; @@ -46,7 +46,10 @@ export class Import implements ICommand { ); } - private addImportedShape = (document: IDocument, shape: [string | undefined, Result]) => { + private readonly addImportedShape = ( + document: IDocument, + shape: [string | undefined, Result], + ) => { if (!shape[1].isOk) { PubSub.default.pub("showToast", "toast.read.error"); return; @@ -63,16 +66,19 @@ export class Import implements ICommand { }; private async readShape(application: IApplication): Promise<[string | undefined, Result]> { - let data = await readFileAsync(".iges, .igs, .step, .stp", false); + let data = await readFilesAsync(".iges, .igs, .step, .stp", false); if (!data.isOk || data.ok().length === 0) { - return [undefined, Result.err("toast.read.error")]; + return [undefined, data.parse()]; } + let shape: Result; - let name = data.ok()[0].fileName.toLowerCase(); + let name = data.ok()[0].name.toLowerCase(); + let content = new Uint8Array(await data.ok()[0].arrayBuffer()); + if (name.endsWith(".igs") || name.endsWith(".iges")) { - shape = application.shapeFactory.converter.convertFromIGES(data.ok()[0].data); + shape = application.shapeFactory.converter.convertFromIGES(content); } else if (name.endsWith(".stp") || name.endsWith(".step")) { - shape = application.shapeFactory.converter.convertFromSTEP(data.ok()[0].data); + shape = application.shapeFactory.converter.convertFromSTEP(content); } else { throw new Error(`不支持的文件:${name}`); } @@ -93,14 +99,14 @@ abstract class Export implements ICommand { PubSub.default.pub( "showPermanent", async () => { - let shapes = models!.map((x) => x.geometry.shape.ok()); + let shapes = models.map((x) => x.geometry.shape.ok()); let shapeString = await this.convertAsync(application, type, ...shapes); if (!shapeString.isOk) { PubSub.default.pub("showToast", "toast.converter.error"); return; } PubSub.default.pub("showToast", "toast.downloading"); - download([shapeString.ok()], `${models![0].name}.${type}`); + download([shapeString.ok()], `${models[0].name}.${type}`); }, "toast.excuting{0}", "",