Git Product home page Git Product logo

donalffons / opencascade.js Goto Github PK

View Code? Open in Web Editor NEW
549.0 21.0 81.0 923.64 MB

Port of the OpenCascade CAD library to JavaScript and WebAssembly via Emscripten.

Home Page: https://ocjs.org/

License: GNU Lesser General Public License v2.1

Python 51.21% Dockerfile 0.78% Shell 1.55% JavaScript 10.51% TypeScript 29.07% CSS 3.04% Vue 1.47% HTML 2.37%
emscripten opencascade cad csg brep step geometry 3d

opencascade.js's Introduction

Build OpenCascade.js OpenCascade Version

Logo

OpenCascade.js

A port of the OpenCascade CAD library to JavaScript and WebAssembly via Emscripten.
Explore the docs »

Examples · Issues · Discuss

Projects & Examples:

Contributing

Contributions are welcome! Feel free to have a look at the todo-list if you need some inspiration on what else needs to be done.

opencascade.js's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

opencascade.js's Issues

Add support for `struct`s

Currently, only APIs for class are generated. Adding APIs for structs should work in a very similar fashion.

Custom build with custom C++ classes

First of all, thank you for this project.

Is it possible to use the docker container to create a custom build including some own c++ code? I have created a c++ library using opencascade and I want to compile it to wasm using your opecascade port. But I don't see how to include my code in the custom build.

I don't need to expose anything from OpenCascade directly to javascript, I just need to expose some own c++ classes that uses openccascade internally, but I know very few about wasm/Emscripten. I suppose that if there is a way to inject my own code into the process, the custom build can build everything together and expose my classes as any other OCC class.

Thank you.

Verify bindings breaks custom cpp code

Using the latest docker build on the test.yml provided in the docs returns this

Traceback (most recent call last):
  File "/opencascade.js/src/buildFromYaml.py", line 66, in <module>
    verifyBindings(buildConfig["mainBuild"]["bindings"])
  File "/opencascade.js/src/buildFromYaml.py", line 64, in verifyBindings
    raise Exception("Requested binding " + json.dumps(binding) + " does not exist!")
Exception: Requested binding {"symbol": "CustomClass"} does not exist!

I guess you do no include the symbols in the additional cpp section in the verifyBindings section!

Pass by reference APIs

I was trying to retries the UV bounds of a face using this API. From what I understand in C++ you need to pass a reference to a real, and the function update the value pointed.

Is there a way to do this with opencascade.js? I have tried something like this:

  let u0 = 0;
  let u1 = 0;
  let v0 = 0;
  let v1 = 0;
  new oc.BRepTools.UVBounds_1(face, u0, u1, v0, v1);
  console.log(u0, u1, v0, v1);

but it fails miserably with a RuntimeError: function signature mismatch.

Am I missing a way to retrieve the values?

Consistently getting memory access out of bounds in v2.0

Hi, so I have this short snippet of code and it consistently gives me memory access out of bounds error on Chrome or crashes it completely with Aw Snap error 11. I've been getting that randomly in v1 with Cut commands and wasn't exactly sure where that comes from, but I hope I have it reduced to the mininum and reproducible. If that wouldn't be too hard to reproduce, maybe someone has any idea why would that particular code be problematic? Weirdly enough it does not crash when I have debugger open... Thanks.

        const pt1 = new oc.gp_Pnt_3(0, 0, 0);
        const x1 = new oc.BRepPrimAPI_MakeBox_3(pt1, 1, 2, 3).Shape();
        const pt2 = new oc.gp_Pnt_3(0, 1, 0);
        const x2 = new oc.BRepPrimAPI_MakeBox_3(pt2, 1, 1, 1).Shape();
        const differenceCut = new oc.BRepAlgoAPI_Cut_3(x1, x2);
        differenceCut.Build();
        const resShape = differenceCut.Shape();

Use Create Polygon Report Error

image
image

This is my code,Can someone tell me why the error was reported?

function Polygon(oc, points, wire) {
    let gpPoints = [];
    let curPolygon;
    for (var i = 0; i <points.length; i++){
    gpPoints.push(new oc.gp_Pnt_3(points[i].x,points[i].y,points[i].z))
    }
      let polygonWire = new oc.BRepBuilderAPI_MakeWire_1();
      for (let ind = 0; ind < points.length - 1; ind++) {
        let seg = new oc.GC_MakeSegment_1(gpPoints[ind], gpPoints[ind + 1]).Value();
        let edge = new oc.BRepBuilderAPI_MakeEdge_24(new oc.Handle_Geom_Curve_2(seg.get())).Edge();
        let innerWire = new oc.BRepBuilderAPI_MakeWire_2(edge).Wire();
        polygonWire.Add_2(innerWire);
      }
      let seg2 = new oc.GC_MakeSegment_1(gpPoints[points.length - 1], gpPoints[0]).Value();
      let edge2 = new oc.BRepBuilderAPI_MakeEdge_24(new oc.Handle_Geom_Curve_2(seg2.get())).Edge();
      let innerWire2 = new oc.BRepBuilderAPI_MakeWire_2(edge2).Wire();
      polygonWire.Add_2(innerWire2);
      let finalWire = polygonWire.Wire();
      if (wire) {
        curPolygon = finalWire;
      } else {
        curPolygon =new oc.BRepBuilderAPI_MakeFace_15(finalWire,true).Face();
      }
    return curPolygon;
  }

Implement references to built-in types

There have been several tickets about this issue. Emscripten / Embind (and therefore OpenCascade.js) do not provide a built-in way of handling reference types to built-ins, like in this example.

class SomeClass {
public:
  SomeClass() {}
  void test(int& number) {
    number++;
  }
};

I think I found a way to support this feature that should work across most (all?) cases where these kinds of reference parameters are involved.

In this example, bindings for SomeClass can be achieved using the following Embind code (thanks to a specialization of RegisterClassMethod for std::function) :

#include <functional>

EMSCRIPTEN_BINDINGS(testBindings) {
  class_<SomeClass>("SomeClass")
    .constructor<>()
    .function("test", std::function<void(SomeClass&, emscripten::val)>([](SomeClass& that, emscripten::val number) {
      if(number.typeOf().as<std::string>() == "number") {
        auto i = number.as<int>();
        that.test(i);
      } else if(number.typeOf().as<std::string>() == "object" && number["current"].typeOf().as<std::string>() == "number") {
        auto i = number["current"].as<int>();
        that.test(i);
        number.set("current", i);
      } else {
        throw("unsupported type");
      }
    }))
  ;
}

The class can then be used from JavaScript like in the following example:

const intRef = {current: 0};
const c = new oc.SomeClass();
console.log(intRef); // {current: 0}
c.test(intRef);
console.log(intRef); // {current: 1}
c.test(123); // works also, but does nothing in this case

As a side note: The naming of the reference type (an object with a single current property) is taken from how ReactJS names its useRef reference types.

embind pointer-to-reference conversion question

This is working until it gets to makeFace.Add(wire).

I can't figure out if I'm doing this wrong, or if there is a problem in the bindings.

makeFace.Add's binding entry is

.function("Add", static_cast<void (BRepBuilderAPI_MakeFace::*) (const TopoDS_Wire &) >(&BRepBuilderAPI_MakeFace::Add), allow_raw_pointers())

So it's weird that it's complaining that it wants a conversion to TopoDS_Wire.

Any idea?

This is using the embind branch

test('Offset', async t => {
  const oc = await getOc();
  const path = [[0, 0, 0], [1, 0, 0], [1, 1, 0]].map(([x, y, z]) => new oc.gp_Pnt_3(x, y, z));
  const makePolygon = new oc.BRepBuilderAPI_MakePolygon_1();
  for (let nth = 0; nth < path.length; nth++) {
    makePolygon.Add_1(path[nth]);
  }
  const wire = makePolygon.Wire();
  const makeFace = new oc.BRepBuilderAPI_MakeFace_1();
  makeFace.Add(wire);
/*
  @Object {
    message: 'Cannot convert argument of type TopoDS_Wire const* to parameter type TopoDS_Wire',
    name: 'BindingError',
    stack: `BindingError: Cannot convert argument of type TopoDS_Wire const* to parameter type TopoDS_Wire␊
        at Object.eval (webpack-internal:///../../../opencascade.js/dist/opencascade.wasm.js:12:79850)␊
        at new eval (webpack-internal:///../../../opencascade.js/dist/opencascade.wasm.js:12:79667)␊
        at throwBindingError (webpack-internal:///../../../opencascade.js/dist/opencascade.wasm.js:12:80291)␊
        at RegisteredPointer.genericPointerToWireType [as toWireType] (webpack-internal:///../../../opencascade.js/dist/opencascade.wasm.js:12:88943)␊
        at Object.eval [as Add] (webpack-internal:///../../../opencascade.js/dist/opencascade.wasm.js:12:100147)␊

*/
});

how to correctly add new interface to opencascade.idl

I am trying to add a new interface to opencascade.idl like this:

interface BRepBuilderAPI_Copy{
  void BRepBuilderAPI_Copy();
  void BRepBuilderAPI_Copy(
    [Const, Ref]TopoDS_Shape,
    [Const]Standard_Boolean copyGeom,
    [Const]Standard_Boolean copyMesh
  );

  void Perform(
    [Const, Ref]TopoDS_Shape S,
    [Const]Standard_Boolean copyGeom,
    [Const]Standard_Boolean copyMesh
  );
};

And then, I run the" docker run" command .
Everything works fine, except I still didn't see a openCascade.BRepBuilderAPI_Copy() function in my javascript side.

Any one can tell me what I had missed ?

How to get the hierarchy of STP?

I can only get one shape when use STEPControl_Reader to load a stp as in the opencascade-excample and CascadeStudio.
I found a way to implement it in C++, but I can't do it in js
the code:

const fileText = await loadFileAsync(inputFile)
  const fileName = inputFile.name
  // Writes the uploaded file to Emscripten's Virtual Filesystem
  openCascade.FS.createDataFile('/', fileName, fileText, true, true)

  const aDoc = new openCascade.Handle_TDocStd_Document_1()
  console.log(aDoc)

  // XCAFApp is unsupported in API.md
  // const anApp = new openCascade.Handle_XCAFApp_Application_1().get()
  // console.log(anApp)

  const reader = new openCascade.STEPCAFControl_Reader_1()
  reader.SetColorMode(true)
  reader.SetNameMode(true)

  reader.ReadFile(fileName)

  console.log(reader)
  console.log(reader.NbRootsForTransfer())

  reader.Transfer_1(aDoc)

  const label = aDoc.get().Main()

  console.log(label)

the error in reader.Transfer_1(aDoc)

Is it the wrong way I use it, or is it not supported here ?

how to build .wasm file for beta version

Hello. I am trying to build the wasm myself. first I run "docker build -t opencascade.js ." and then I run "docker run -ti --rm opencascade.js" It seems works fine but I didn't see any .wasm files ?

Generate bindings + typings for non-typedef'd template parameters

Many template specializations are currently not typedef'd by OpenCascade, e.g. Handle<IMeshTools_Context>. Therefore, this type is effectively not usable.

When the usage of such a type is encountered, the following message is written to the logs during typescript generation (the logs contain 21.500 of those messages):

could not generate proper types for type name 'opencascade::handle<Standard_DimensionMismatch>', using 'any' instead.

To fix that, it might be best to do the following:

  1. In a first pass, make a list of all the template parameters used in all declarations
  2. Filter the list and throw out all template parameters that are already typedef'd (for those, the build system will generate bindings automatically)
  3. Add some simple C++ code, with typedef's for the remaining template parameters
  4. Then run the build system as usual

Typescript Definitions from the WebIDL

webidl2ts can be used to automatically generate typescript definitions from the .idl file here (ensure that the "-emscripten" mode is active).

Typescript definitions are included in the package by adding "types": "dist/opencascade.d.ts", to the package.json.

This enables Intellisense completions in VS Code (and related editors) in both Javascript AND Typescript.

Here is an example generated typescript definitions file:
https://gist.github.com/zalo/0277def37489ef8c3ce47fc551aa243b

"UnboundTypeError" for custom builds

I was trying to create a custom build - the build worked, but there is an issue with the build result. I have the following message in the console:

"Cannot call gp_Vec.XYZ due to unbound types: 6gp_XYZ"

From what I understand you are adding already adding "raw pointers" in order to avoid this kind of error. What am I missing?

My custom build setup is the following:

cadeau_single.js:
  bindings:
    - symbol: Message_ProgressRange
    - symbol: TColgp_Array1OfDir

    - symbol: gp_XYZ
    - symbol: gp_Vec
    - symbol: gp_Pnt
    - symbol: gp_Dir
    - symbol: gp_Ax2
    - symbol: gp_Ax3
    - symbol: gp_GTrsf

    - symbol: TopoDS
    - symbol: TopAbs_ShapeEnum
    - symbol: TopTools_ListOfShape
    - symbol: TopAbs_Orientation
    - symbol: TopLoc_Location
    - symbol: TopExp_Explorer

    - symbol: Poly_Connect
    - symbol: StdPrs_ToolTriangulatedShape

    - symbol: BRep_Tool
    - symbol: BRepTools
    - symbol: BRepGProp
    - symbol: BRepGProp_Face
    - symbol: GProp_GProps
    - symbol: BRepMesh_IncrementalMesh

    - symbol: BRepAdaptor_Curve
    - symbol: BRepAdaptor_CompCurve
    - symbol: GeomAbs_CurveType

    - symbol: StlAPI_Writer

    - symbol: BRepAlgoAPI_Cut
    - symbol: BRepAlgoAPI_Fuse

    - symbol: BRepBuilderAPI_Transform
    - symbol: BRepCheck_Analyzer
    - symbol: BRepPrimAPI_MakePrism
    - symbol: BRepOffsetAPI_MakeThickSolid
    - symbol: BRepOffsetAPI_MakeOffset
    - symbol: BRepOffset_Mode
    - symbol: BRepFilletAPI_MakeChamfer
    - symbol: ChFi3d_FilletShape
    - symbol: GeomAbs_JoinType
    - symbol: cadeau
  additionalCppCode: |
    #include <emscripten/val.h>
    class cadeau: public BRepTools {
    public:
      static emscripten::val UVBounds(const TopoDS_Face &f) {
        Standard_Real uMin;
        Standard_Real uMax;
        Standard_Real vMin;
        Standard_Real vMax;
        BRepTools::UVBounds(f, uMin, uMax, vMin, vMax);
        emscripten::val ret(emscripten::val::object());
        ret.set("uMin", emscripten::val(uMin));
        ret.set("uMax", emscripten::val(uMax));
        ret.set("vMin", emscripten::val(vMin));
        ret.set("vMax", emscripten::val(vMax));
        return ret;
      }

      static emscripten::val projectPointOnSurface( 
        const gp_Pnt & P,
        const opencascade::handle<Geom_Surface> & Surface
      ) {

        GeomAPI_ProjectPointOnSurf projectedPoint (P, Surface);

        Standard_Real u;
        Standard_Real v;

        projectedPoint.LowerDistanceParameters(u, v);

        emscripten::val ret(emscripten::val::object());
        ret.set("u", emscripten::val(u));
        ret.set("v", emscripten::val(v));
        return ret;
      }
    };
  emccFlags:
    - -sEXPORT_ES6=1
    - -sUSE_ES6_IMPORT_META=0
    - -sEXPORTED_RUNTIME_METHODS=["FS"]
    - -O3

P.S. If you want to have a look at what I am building, you can find a preview here

Getting Face UVBounds

Hey guys, I'm trying to get UVBounds of the face. OCC documentation method is in occ.BRepTools.UVBounds_1.

https://dev.opencascade.org/doc/refman/html/class_b_rep_tools.html#a2223e42bb10997431eb16296ae740ea4

Method writes to passed Umin, Umax, Vmin and Vmax Standard_Real references, I'm a bit lost how to call this from javascript.

I saw that Standard_Real is defined in TKernel, but the closest I could find in occ.js was TDataStd_Real, not sure what's the difference. I tried smth like this with no success:

        const uMin = new this.occ.TDataStd_Real();
        const uMax = new this.occ.TDataStd_Real();
        const vMin = new this.occ.TDataStd_Real();
        const vMax = new this.occ.TDataStd_Real();
        this.occ.BRepTools.UVBounds_1(face, uMin, uMax, vMin, vMax);

TypeError: Cannot convert "[object Object]" to double
I sort of get that, but yeah, double is not even a thing in javascript anyway ;)

Anything else gives
RuntimeError: call_indirect to a signature that does not match (evaluating 'cppInvokerFunc.apply(null,invokerFuncArgs)')

Any ideas?

Finalize parallelization of build process

2021-07-03_13-10
build made on a 16 vcpu compute instance

Python cannot "pickle" clang's translation_unit to share it between multiple threads. A workaround is to save it to disk after creation and then read it in every thread. The additional overhead should be quite low.

Once this is done, the build runs fully parallel and build times could be further reduced by using compute instances with higher vcpu counts.

initOpenCascade very slow with node.js

index.mjs

import opencascade from "opencascade.js/dist/opencascade.wasm.js";

new opencascade(
    {
        locateFile(path) {
            console.log(path);
            if (path.endsWith('.wasm')) {
                return "./node_modules/opencascade.js/dist/opencascade.wasm.wasm";
            }
            return path;
        }
    }
).then((openCascade) => {
    // Register the "OpenCascade" WebAssembly Module under the shorthand "oc"
    var oc = openCascade;
    console.log("oc ready")
});

It takes about 5 minutes for the code to print "oc ready"

To reproduce:

mkdir slowinit_bug; cd slowinit_bug
npm init -y
npm install --save opencascade.js


# edit node_modules/opencascade.js/dist/opencascade.wasm.js
# and change the last line 
# from "export default opencascade" to "module.exports = opencascade"
# I don't know much about ES6 but if I don't make this change to opencascade.wasm.js,
# node.js complains about "export" statement being a syntax error.
# (maybe someone can also tell me the correct way to do this )

sed -i  "s/export\sdefault\sopencascade/module\.exports = opencascade/g" node_modules/opencascade.js/dist/opencascade.wasm.js```

node index.mjs

EDIT: Also my CPU usage is 300% until the code prints "oc ready", I don't know anything about WebAssembly but I think this issue is related to it.

But it works perfectly when running in a browser ( opencascade.js-examples )

interfaces

Can all interfaces of OCC be supported. If I change it opencascade.idl , do you need to make other changes?

Add typescript definition for properties

E.g. for these bindings:

  class_<IMeshTools_Parameters>("IMeshTools_Parameters")
    .constructor<>()
    .class_function("RelMinSize", &IMeshTools_Parameters::RelMinSize, allow_raw_pointers())
    .property("MeshAlgo", &IMeshTools_Parameters::MeshAlgo)
    .property("Angle", &IMeshTools_Parameters::Angle)
    .property("Deflection", &IMeshTools_Parameters::Deflection)
    .property("AngleInterior", &IMeshTools_Parameters::AngleInterior)
    .property("DeflectionInterior", &IMeshTools_Parameters::DeflectionInterior)
    .property("MinSize", &IMeshTools_Parameters::MinSize)
    .property("InParallel", &IMeshTools_Parameters::InParallel)
    .property("Relative", &IMeshTools_Parameters::Relative)
    .property("InternalVerticesMode", &IMeshTools_Parameters::InternalVerticesMode)
    .property("ControlSurfaceDeflection", &IMeshTools_Parameters::ControlSurfaceDeflection)
    .property("CleanModel", &IMeshTools_Parameters::CleanModel)
    .property("AdjustMinSize", &IMeshTools_Parameters::AdjustMinSize)
    .property("ForceFaceDeflection", &IMeshTools_Parameters::ForceFaceDeflection)
    .property("AllowQualityDecrease", &IMeshTools_Parameters::AllowQualityDecrease)
  ;

the typescript definitions currently look like this:

export declare class IMeshTools_Parameters {
  constructor()
  static RelMinSize(): Standard_Real;
  delete(): void;
}

Selection of rendered objects

Thanks for the great work!

I’m able to run the example repo to read and render my step files. I’m wondering if it’s possible to render each part in the step file separately so that I can select a solid or a face with mouse click?

I did some research and found there are two possible ways to do it. One is using the AIS_InteractiveContext class in OCC. The other way is generate all the edges and faces in three.js and do the selection in three.js. The shortcoming of the latter is I can not do operations such as measurement in three.js.

Do you have any suggestions on the choice? Would it be possible to expose the AIS_InteractiveContext class through emScripten. Thanks. @donalffons

Consider adding links to OpenCascade's documentation in Typescript comments

It seems relatively straightforward to encode OpenCascade's doxygen URLs from the class names:

STEPCAFControl_Reader
https://dev.opencascade.org/doc/refman/html/class_s_t_e_p_c_a_f_control___reader.html

It seems to be less easy for enums:

TopOpeBRepBuild_LoopEnum
https://dev.opencascade.org/doc/refman/html/_top_ope_b_rep_build___loop_enum_8hxx.html (this references the file in which the enum is defined)

It seems infeasible to generate links to methods.

Custom build with default inputs errors with `wasm-ld: error: duplicate symbol: DISCRETALGO`

To reproduce:

MyBRepTools.wasm:
  bindings:
    - symbol: MyBRepTools
  additionalCppCode: |
    #include <emscripten/val.h>
    class MyBRepTools: public BRepTools {
    public:
      static emscripten::val MyUVBounds(const TopoDS_Face &f) {
        Standard_Real uMin;
        Standard_Real uMax;
        Standard_Real vMin;
        Standard_Real vMax;
        BRepTools::UVBounds(f, uMin, uMax, vMin, vMax);
        emscripten::val ret(emscripten::val::object());
        ret.set("uMin", emscripten::val(uMin));
        ret.set("uMax", emscripten::val(uMax));
        ret.set("vMin", emscripten::val(vMin));
        ret.set("vMax", emscripten::val(vMax));
        return ret;
      }
    };
  emccFlags:
    - -sSIDE_MODULE=1
    - -O3

The solution is probably to exclude the TKXMesh library as an input by default.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.