ThatOpen / engine_web-ifc

Reading and writing IFC files with Javascript, at native speeds.
https://thatopen.github.io/engine_web-ifc/demo
Mozilla Public License 2.0
585 stars 176 forks source link

With @web-ifc we can split the Uint8Array into chunks to read? #780

Closed RyugaRyuzaki closed 3 months ago

RyugaRyuzaki commented 3 months ago

What is your idea?

beachtom commented 3 months ago

So you can pass in a callback function into web-ifc:

OpenModelFromCallback(callback: ModelLoadCallback , settings?: LoaderSettings): number

Where ModelLoadCallback is (offset:number, size: number) => Uint8Array - you can provide a function that will hookup that function to get the data from the right UInt8Array

RyugaRyuzaki commented 3 months ago

So you can pass in a callback function into web-ifc:

OpenModelFromCallback(callback: ModelLoadCallback , settings?: LoaderSettings): number

Where ModelLoadCallback is (offset:number, size: number) => Uint8Array - you can provide a function that will hookup that function to get the data from the right UInt8Array

Here i my code :

import * as WEBIFC from "web-ifc";
import * as fs from "fs";
import {IfcFragmentSettings} from "./parser/IfcFragmentSettings";

const filePath = "./input/large192.ifc";
const highWaterMark = 200 * 1024 * 1024;

class App {
  private settings = new IfcFragmentSettings();
  private _webIfc = new WEBIFC.IfcAPI();
  async streamFromBufferCallBack(callback: WEBIFC.ModelLoadCallback) {
    const before = performance.now();
    await this.readIfcFile(callback);

    this.cleanUp();

    console.log(`Streaming the IFC took ${performance.now() - before} ms!`);
  }
  private async readIfcFile(callback: WEBIFC.ModelLoadCallback) {
    const {path, absolute, logLevel} = this.settings.wasm;
    this._webIfc.SetWasmPath(path, absolute);
    await this._webIfc.Init();
    if (logLevel) {
      this._webIfc.SetLogLevel(logLevel);
    }
    this._webIfc.OpenModelFromCallback(callback, this.settings.webIfc);
  }
  private cleanUp() {
    (this._webIfc as any) = null;
    this._webIfc = new WEBIFC.IfcAPI();
  }
}

const app = new App();

(async () => {
  const exist = fs.existsSync(filePath);
  if (!exist) {
    console.error("File not found");
    process.exit(1);
  }
  try {
    let offset = 0;
    const readStream = fs.createReadStream(filePath, {
      highWaterMark,
    });

    readStream.on("data", (chunk: Buffer) => {
      const modelCallBack: WEBIFC.ModelLoadCallback = (
        callbackOffset: number,
        size: number
      ) => {
        // how can i calculate here?
        return new Uint8Array(chunk); //
      };
      offset += chunk.byteLength;
    });

    readStream.on("end", async () => {});

    readStream.on("error", (error: any) => {
      console.log(error);
      process.exit(1);
    });
  } catch (error) {
    console.log(error);
    process.exit(1);
  }
})();

Any idea for modelCallBack: WEBIFC.ModelLoadCallback ? thank @beachtom

beachtom commented 3 months ago

Are you running in node or in the browser?

RyugaRyuzaki commented 3 months ago

Are you running in node or in the browser?

hi, thank for quick reply. i'm running on Nodejs

beachtom commented 3 months ago

This one reads from an open file - streaming into web-ifc

let retriever = function (offset:number, size: number) { let data = new Uint8Array(size); let bytesRead = fs.readSync(file,data,0,size,offset);
if (bytesRead <= 0 ) return new Uint8Array(0); return data;
}

RyugaRyuzaki commented 1 month ago

This one reads from an open file - streaming into web-ifc

let retriever = function (offset:number, size: number) { let data = new Uint8Array(size); let bytesRead = fs.readSync(file,data,0,size,offset); if (bytesRead <= 0 ) return new Uint8Array(0); return data; }

@beachtom great. i did it.Thank! . However is there any way to control offset and size ? Because i test with model 3gb each callback just 67mb..

RyugaRyuzaki commented 1 month ago

@beachtom thank you, can you tell me how can i integrate in browser?. Here my code and it thrown error .

 async function stream(payLoad: File) {
  const reader = payLoad.stream().getReader({mode: 'byob'});
  let offset = 0;

  const modelCallback = async (_callbackOffset: number, size: number) => {
    if (size > payLoad.size) size = payLoad.size;
    const data = new Uint8Array(size);
    while (offset < size) {
      const remainingSize = payLoad.size - offset;
      const view = new Uint8Array(remainingSize);
      const {value, done} = await reader.read(view);
      if (done) break;
      if (value && value.byteLength > 0) {
        data.set(value, offset);
        offset += value.byteLength;
      }
    }
    console.log(data);
    return data;
  };
  //@ts-ignore
  await new PropertyLoader(onPropertiesLoaded).streamFromCallBack(modelCallback);
}

error :

RuntimeError: memory access out of bounds
    at web-ifc.wasm:0xcf6a2
    at web-ifc.wasm:0xc6100
    at Object.OpenModel (eval at newFunc (chunk-XC6DDJAD.js?v=63910048:7308:31), <anonymous>:9:10)
    at IfcAPI2.OpenModelFromCallback (chunk-XC6DDJAD.js?v=63910048:66577:34)
    at PropertyLoader.streamIfcFile (PropertyLoader.ts:79:17)
    at async PropertyLoader.streamFromCallBack (PropertyLoader.ts:54:5)
    at async stream (IfcPropertyWorker.ts:35:3)
    at async onLoad (IfcPropertyWorker.ts:43:5)
beachtom commented 1 month ago

To increase the callback site - change the TAPE_SIZE parameter inside Loader Settings

Is the model opening in node. Opening large models in the browser is very difficult as the browsers tend to run out of memory - it is often better to convert to fragments and then use from there

RyugaRyuzaki commented 1 month ago

To increase the callback site - change the TAPE_SIZE parameter inside Loader Settings

Is the model opening in node. Opening large models in the browser is very difficult as the browsers tend to run out of memory - it is often better to convert to fragments and then use from there

Yes, in node, i set the function you gave me and it worked as well. but in browser it throws error

beachtom commented 1 month ago

I suspect the file may well be just too big for the browser to load

RyugaRyuzaki commented 1 month ago

I suspect the file may well be just too big for the browser to load

@beachtom all file I tested in browser same throw error. In node, all are ok even which ~4gb.

beachtom commented 1 month ago

Can you test if the actual callback works in the browser? By adding some test code i.e. calling

await modelCallback(0,66000) or something

RyugaRyuzaki commented 1 month ago

Can you test if the actual callback works in the browser? By adding some test code i.e. calling

await modelCallback(0,66000) or something

@beachtom Sure, here is my code:

export async function stream(payLoad: File) {
  const reader = payLoad.stream().getReader({mode: 'byob'});
  let offset = 0;

  const modelCallback = async (_callbackOffset: number, size: number) => {
    if (size > payLoad.size) size = payLoad.size;
    const newSize = size > payLoad.size ? payLoad.size : size;
    const data = new Uint8Array(newSize);
    console.log('File Size', payLoad.size);
    while (offset < newSize) {
      const remainingSize = payLoad.size - offset;
      const view = new Uint8Array(remainingSize);
      const {value, done} = await reader.read(view);
      if (done) break;
      if (value && value.byteLength > 0) {
        data.set(value, offset);
        offset += value.byteLength;
      }
    }
    return data;
  };
  const bytes = await modelCallback(0, 66 * 1024 * 1024);
  console.log('All Bytes Read', bytes);
  //@ts-ignore
  // await new PropertyLoader(onPropertiesLoaded).streamFromCallBack(modelCallback);
}

And here is result : image

Another file : (45MB) image And if i change size =20MB image

beachtom commented 1 month ago

are you able to share your code with me to take a look? Or I can provide you with debug wasm files that should help us debug exactly where in the WASM the error is occuring

RyugaRyuzaki commented 1 month ago

are you able to share your code with me to take a look? Or I can provide you with debug wasm files that should help us debug exactly where in the WASM the error is occuring

Hi @beachtom here is the code https://drive.google.com/file/d/1n_zYBnWdZB1LRAnzUQrxsvud0bHR5-8a/view?usp=sharing