kovacsv / occt-import-js

The emscripten interface for OpenCascade import functionalities.
GNU Lesser General Public License v2.1
141 stars 23 forks source link

STP files larger than 100MB are not supported #19

Closed yk0n9 closed 1 year ago

yk0n9 commented 1 year ago

This is a 76MB size result it successfully shows all the data 图片


This is a 142MB size result It cannot read data, all data arrays are empty 图片

I think there may be some special surfaces in the larger file that cause the parsing to fail, such as Surface_Of_Linear_Extrusion Or the reason for the wasm runtime

kovacsv commented 1 year ago

It's hard to tell anything without the file itself. Can you share the file somehow?

yk0n9 commented 1 year ago

It's hard to tell anything without the file itself. Can you share the file somehow?

ok, I have sent it to your email through wetransfer

kovacsv commented 1 year ago

The native (non-emscripten) version can open the file without problem, so the error must be related to the emscripten version.

yk0n9 commented 1 year ago

The native (non-emscripten) version can open the file without problem, so the error must be related to the emscripten version.

I tried compiling your code with the latest version of emscripten, but it failed. 😂I really don't understand C++ these languages.

-- Build files have been written to: D:/WorkSpace/Other/occt-import-js/build_wasm
make: mingw32-make -C build_wasm
mingw32-make: Entering directory 'D:/WorkSpace/Other/occt-import-js/build_wasm'
mingw32-make[1]: Entering directory 'D:/WorkSpace/Other/occt-import-js/build_wasm'
mingw32-make[2]: Entering directory 'D:/WorkSpace/Other/occt-import-js/build_wasm'
mingw32-make[2]: Leaving directory 'D:/WorkSpace/Other/occt-import-js/build_wasm'
mingw32-make[2]: Entering directory 'D:/WorkSpace/Other/occt-import-js/build_wasm'
[ 12%] Building CXX object CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o
[ 25%] Building CXX object CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-iges.cpp.o
[ 37%] Building CXX object CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-step.cpp.o
[ 50%] Building CXX object CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-utils.cpp.o
[ 62%] Building CXX object CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-xcaf.cpp.o
[ 75%] Building CXX object CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer.cpp.o
[ 87%] Building CXX object CMakeFiles/OcctImportJS.dir/occt-import-js/src/js-interface.cpp.o
[100%] Linking CXX executable Release/occt-import-js.js
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopLoc_Location::TopLoc_Location()
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: Standard_Transient::DecrementRefCounter() const
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: BRepTools::Read(TopoDS_Shape&, std::__2::basic_istream<char, std::__2::char_traits<char>>&, BRep_Builder const&, Message_ProgressRange const&)
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: Standard_Mutex::Lock()
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: Standard_Transient::DecrementRefCounter() const
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: Standard_Transient::DecrementRefCounter() const
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: Standard_Transient::DecrementRefCounter() const
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: Standard_Transient::DecrementRefCounter() const
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::TopExp_Explorer(TopoDS_Shape const&, TopAbs_ShapeEnum, TopAbs_ShapeEnum)
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::~TopExp_Explorer()
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::TopExp_Explorer(TopoDS_Shape const&, TopAbs_ShapeEnum, TopAbs_ShapeEnum)
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::~TopExp_Explorer()
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::TopExp_Explorer(TopoDS_Shape const&, TopAbs_ShapeEnum, TopAbs_ShapeEnum)
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::~TopExp_Explorer()
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::Current() const
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::Next()
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::~TopExp_Explorer()
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::~TopExp_Explorer()
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::~TopExp_Explorer()
wasm-ld: error: CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o: undefined symbol: TopExp_Explorer::~TopExp_Explorer()
wasm-ld: error: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
em++: error: 'D:/WorkSpace/Other/occt-import-js/emsdk/upstream/bin\wasm-ld.exe -o Release/occt-import-js.wasm CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-brep.cpp.o CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-iges.cpp.o CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-step.cpp.o CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-utils.cpp.o CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer-xcaf.cpp.o CMakeFiles/OcctImportJS.dir/occt-import-js/src/importer.cpp.o CMakeFiles/OcctImportJS.dir/occt-import-js/src/js-interface.cpp.o -LD:\WorkSpace\Other\occt-import-js\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten --whole-archive -lembind-rtti --no-whole-archive -lGL -lal -lhtml5 -lstubs -lnoexit -lc -ldlmalloc -lcompiler_rt -lc++ -lc++abi -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-cxx-exceptions -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --allow-undefined-file=C:\Users\root\AppData\Local\Temp\tmpvffwhvso.undefined --strip-debug --export-if-defined=main --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=__main_argc_argv --export=stackSave --export=stackRestore --export=stackAlloc --export=__wasm_call_ctors --export=__errno_location --export=getTempRet0 --export=setTempRet0 --export=__get_temp_ret --export=__set_temp_ret --export=malloc --export=free --export=__cxa_is_pointer_type --export=__cxa_can_catch --export=setThrew --export=__cxa_free_exception --export-table -z stack-size=10485760 --initial-memory=16777216 --no-entry --max-memory=2147483648 --global-base=1024' failed (returned 1)
mingw32-make[2]: *** [CMakeFiles/OcctImportJS.dir/build.make:200: Release/occt-import-js.js] Error 1
mingw32-make[2]: Leaving directory 'D:/WorkSpace/Other/occt-import-js/build_wasm'
mingw32-make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/OcctImportJS.dir/all] Error 2
mingw32-make[1]: Leaving directory 'D:/WorkSpace/Other/occt-import-js/build_wasm'
mingw32-make: *** [Makefile:91: all] Error 2
mingw32-make: Leaving directory 'D:/WorkSpace/Other/occt-import-js/build_wasm'
emmake: error: 'mingw32-make -C build_wasm' failed (returned 2)
Build Failed with Error 1.
kovacsv commented 1 year ago

Maybe it's not the same emscripten version I use. Did you use tools\setup_emscripten_win.bat to install emscripten?

yk0n9 commented 1 year ago

Maybe it's not the same emscripten version I use. Did you use tools\setup_emscripten_win.bat to install emscripten?

let fs = require('fs');
let util = require('util');
const occtimportjs = require('./occt-import-js.js')();

occtimportjs.then((occt) => {
    let fileUrl = 'resources/142MB.stp';
    let fileContent = fs.readFileSync(fileUrl);
    let result = occt.ReadStepFile(fileContent, null);

    console.log(util.inspect(result, {showHidden: false, depth: null, colors: true}));
});

I tried to use emscripten 3.1.29 to compile wasm, but the data cannot be read. (latest version) 图片 Then I replaced it with your script file tools\setup emscripten win.bat, your version is 3.1.28, and finally it has the same effect. This makes me suspect that it's not an emscripten version issue, it might be a wasm limitation issue. Anyway, that 142MB sized stp file. I need a wasm that can read it.

yk0n9 commented 1 year ago

I recently used the C++ code from your example. It can import STP files above 100MB. I then tried to get it to import a 500MB STP file and it failed. Because your code is written using recursion. So very large files will cause stack overflow. Can you turn it into a loop to import in a more stable way?

kovacsv commented 1 year ago

That's a good point, and the stack size is even smaller in case of webassembly. Which is the recursive function that runs into a stack overflow?

yk0n9 commented 1 year ago

That's a good point, and the stack size is even smaller in case of webassembly. Which is the recursive function that runs into a stack overflow?

I guess it is static void WriteNode (const NodePtr& node, ObjWriter& writer) in occt-import-js/occt-import-js/example/main.cpp

and I tried modifying the code from recursive to loop, it still renders the same result as recursive While I was using it, my computer's memory usage went up to 1.7GB, and then it stopped suddenly

int main(int argc, const char *argv[]) {
    ......

    ObjWriter writer;

    NodePtr node = importer->GetRootNode();
    node->EnumerateMeshes([&](const Mesh &mesh) {
        if (node->IsMeshNode()) {
            writer.OnMesh(mesh);
        }
    });

    std::vector<NodePtr> nodes = node->GetChildren();

    WriteNode(nodes, writer);

    ......
}

static void WriteNode(std::vector<NodePtr> &nodes, ObjWriter& writer) {
    std::vector<std::vector<NodePtr>> stack;
    stack.push_back(nodes);
    while (!stack.empty()) {
        std::vector<NodePtr> item = stack.back();
        stack.pop_back();

        for (const NodePtr &node: item) {
            node->EnumerateMeshes([&](const Mesh &mesh) {
                if (node->IsMeshNode()) {
                    writer.OnMesh(mesh);
                }
            });
            std::vector<NodePtr> children = node->GetChildren();
            stack.push_back(children);
        }
    }
}
yk0n9 commented 1 year ago

That's a good point, and the stack size is even smaller in case of webassembly. Which is the recursive function that runs into a stack overflow?

I used wetransfer again to send the file to your mailbox

sookie928 commented 1 year ago

How did you solve this issue? @ykong1337

yk0n9 commented 1 year ago

How did you solve this issue? @ykong1337

It cannot be solved, because the wasm memory is 32-bit, and the maximum 2g is allocated to the application, because the memory is not enough. I try to import a 500MB STP file with a C++64-bit backend, which requires at least 4.1GB of memory, which may be the reason for the recursive algorithm.

kzhsw commented 1 year ago

@ykong1337 Would it possible to delay triangulation for OpenCascade, and free memory of meshes just after it got triangulated, to reduce overall memory usage? Maybe like this:

// placeholders for wasm-exposed functions
declare function malloc(size: number) : number;
declare function free(ptr: number) : void;
declare function read_step_file(ptr: number, size: number) : number;
declare function read_meshes(file_ptr: number) : number;
declare function get_mesh_count(meshes_ptr: number): number;
declare function get_mesh(meshes_ptr: number, offset: number): number;
declare function triangulate_mesh(mesh_ptr: number, automatic: number, linearDeflection: number, angularDeflection: number): number;
declare function get_mesh_positions_length(triangulate_mesh_ptr: number): number;
declare function get_mesh_positions(triangulate_mesh_ptr: number): number;
declare function get_mesh_normals_length(triangulate_mesh_ptr: number): number;
declare function get_mesh_normals(triangulate_mesh_ptr: number): number;
declare function get_mesh_colors_length(triangulate_mesh_ptr: number): number;
declare function get_mesh_colors(triangulate_mesh_ptr: number): number;
declare function free_triangulate_mesh(triangulate_mesh_ptr: number): void;
declare function free_mesh(mesh_ptr: number): void;
declare function free_file(mesh_ptr: number): void;
declare var memory: WebAssembly.Memory;

function read_step_file_js(file: Uint8Array) {
    let ptr = malloc(file.length);
    new Uint8Array(memory.buffer, ptr, file.length).set(file);
    let file_ptr = read_step_file(ptr, file.length);
    free(ptr);

    let meshes_ptr = read_meshes(file_ptr);
    let mesh_count = get_mesh_count(meshes_ptr);
    let meshes: any[] = [];
    for (let index = 0; index < mesh_count; index++) {
        const mesh_ptr = get_mesh(meshes_ptr, index);
        const triangulate_mesh_ptr = triangulate_mesh(mesh_ptr, 1, 1, 0.5);
        const positions_ptr = get_mesh_positions(triangulate_mesh_ptr);
        const positions_length = get_mesh_positions_length(triangulate_mesh_ptr);
        const positions = new Float32Array(memory.buffer, positions_ptr, positions_length).slice();
        const normals_ptr = get_mesh_normals(triangulate_mesh_ptr);
        const normals_length = get_mesh_normals_length(triangulate_mesh_ptr);
        const normals = new Float32Array(memory.buffer, normals_ptr, normals_length).slice();
        const colors_ptr = get_mesh_colors(triangulate_mesh_ptr);
        const colors_length = get_mesh_colors_length(triangulate_mesh_ptr);
        const colors = new Float32Array(memory.buffer, colors_ptr, colors_length).slice();
        free_triangulate_mesh(triangulate_mesh_ptr);
        free_mesh(mesh_ptr);
        meshes.push({positions, normals, colors});
    }
    free_file(file_ptr);
    return meshes;
}

For performance, there are more direct wasm-to-js calls, but less indirect calls generated by emscripten for emscripten::val, and binary interfaces should be more effcient than js objects.