├── .gitmodules ├── src ├── GeometryBuilder.cc ├── GeometryBuilder.h ├── Tools.h ├── all.cc ├── Shape.cc ├── BooleanOperation.h ├── Shell.h ├── ShapeIterator.h ├── Vertex.h ├── Wire.h ├── Shape.h ├── Transformation.h ├── ShapeFactory.h ├── Face.h ├── BoundingBox.h ├── Solid.h ├── Edge.h ├── AsyncWorkerWithProgress.h ├── Point3Wrap.cc ├── Point3Wrap.h ├── Mesh.h ├── Shell.cc ├── Vertex.cc ├── V8Wrapper.cc ├── Transform.cc ├── Base.h ├── BooleanOperation.cc ├── BoundingBox.cc ├── Util.cc ├── Transformation.cc ├── Transform.h ├── Wire.cc ├── ShapeIterator.cc ├── OCC.h ├── Face.cc └── NodeV8.h ├── bin ├── STEPtoBREP.cmd └── STEPtoBREP.js ├── History.md ├── lib ├── libtorussphere.ggb ├── bindings.js ├── occ.js ├── mesh.js ├── scriptrunner.js ├── shape.js └── fastbuilder.js ├── test_electron ├── package.json └── main.js ├── index.js ├── Makefile ├── .npmignore ├── .vscode ├── c_cpp_properties.json └── settings.json ├── post-install.js ├── test ├── test_geometry.js ├── helpers.js ├── test_applyTransform.js ├── test_extrudeFace.js ├── test_wire.js ├── test_scriptrunner.js ├── test_transform.js ├── test_face.js ├── test_BoundingBox.js ├── test_issue17_mesh_not_invalidated_when_face_moved.js ├── test_ReadWriteSTEP.js ├── test_relativePerformanceBREPSTEP.js ├── test_BREP.js ├── test_edge.js ├── test_vertex.js └── test_fastbuilder.js ├── .github ├── FUNDING.yml └── workflows │ └── workflow1.yml ├── .gitignore ├── Gruntfile.js ├── .eslintrc ├── LICENCE ├── setenv.bat ├── package.json ├── prepare_node.sh ├── testLargeStepFile.js ├── .gitattributes ├── test1.js ├── appveyor.yml ├── README.md ├── .travis.yml └── JasmineAdapter-1.1.2.js /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/GeometryBuilder.cc: -------------------------------------------------------------------------------- 1 | #include "GeometryBuilder.h" 2 | -------------------------------------------------------------------------------- /bin/STEPtoBREP.cmd: -------------------------------------------------------------------------------- 1 | node STEPtoBREP.js %1 %2 %3 %4 %5 %6 2 | -------------------------------------------------------------------------------- /src/GeometryBuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "NodeV8.h" 3 | #include "OCC.h" 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.0.1 (2013-02-10) 3 | =================== 4 | 5 | * initial release 6 | 7 | -------------------------------------------------------------------------------- /lib/libtorussphere.ggb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenWebCAD/node-occ/HEAD/lib/libtorussphere.ggb -------------------------------------------------------------------------------- /test_electron/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "your-app", 3 | "version": "0.1.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /src/Tools.h: -------------------------------------------------------------------------------- 1 | #include "OCC.h" 2 | #include "NodeV8.h" 3 | 4 | NAN_METHOD(writeSTEP); 5 | NAN_METHOD(readSTEP); 6 | NAN_METHOD(writeBREP); 7 | NAN_METHOD(readBREP); 8 | NAN_METHOD(writeSTL); 9 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports.occ = require("./lib/occ"); 4 | module.exports.shapeFactory = require("./lib/shapeFactory"); 5 | module.exports.scriptRunner = require("./lib/scriptrunner"); 6 | module.exports.fastBuilder = require("./lib/fastbuilder"); 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/bindings.js: -------------------------------------------------------------------------------- 1 | const binary = require("node-pre-gyp"); 2 | const path = require("path"); 3 | const bindingPath = binary.find(path.resolve(path.join(__dirname, "../package.json"))); 4 | const binding = require(bindingPath); 5 | module.exports = binding;// was require("../build/Release/occ"); 6 | //xx module.exports = require("../build/Debug/occ"); -------------------------------------------------------------------------------- /test_electron/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // eslint-disable-next-line require-path-exists/exists 3 | const app = require('electron').app; 4 | 5 | try { 6 | const occ = require('..'); // eslint-disable-line no-unused-vars 7 | } catch (e) { 8 | console.error('Error loading node-occ'); 9 | console.error(e); 10 | console.error(e.stack); 11 | app.exit(-1); 12 | } 13 | 14 | app.quit(); -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | node-pre-gyp configure 3 | node-pre-gyp build 4 | mocha 5 | 6 | .PHONY: test 7 | test: 8 | mocha 9 | 10 | clean: 11 | node-pre-gyp clean 12 | 13 | packet: 14 | npm install mocha@7 15 | npm install assert 16 | npm install should 17 | npm install node-pre-gyp 18 | 19 | 20 | copy: 21 | COPY D:\projet\oce-build\bin\Debug\*.dll build\Release 22 | 23 | format: 24 | astyle --indent=spaces=4 src/* 25 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | package/ 2 | build*/ 3 | sample/ 4 | dist/ 5 | sample_angular2 6 | oce/ 7 | occt-*/ 8 | test_electron 9 | .eslintrc 10 | a.txt 11 | extrudedFace.step 12 | jasmine* 13 | Jasmine* 14 | npm-debug* 15 | *.sh 16 | *.bat 17 | t.js 18 | Gruntfile.js 19 | #.gitmodules 20 | Makefile 21 | .travis.yml 22 | appveyor.yml 23 | *.tgz 24 | *.zip 25 | node-occ-package2 26 | .gitattributes 27 | .idea 28 | *.step 29 | lib/binding 30 | 31 | 32 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${default}", 7 | "/usr/include/opencascade" 8 | ], 9 | "defines": [], 10 | "cStandard": "c17", 11 | "cppStandard": "c++14", 12 | "intelliSenseMode": "linux-clang-x64" 13 | } 14 | ], 15 | "version": 4 16 | } -------------------------------------------------------------------------------- /post-install.js: -------------------------------------------------------------------------------- 1 | 2 | const { exec }= require("child_process"); 3 | 4 | 5 | if (process.platform === "linux") { 6 | 7 | const cmd = "(cd lib/binding && ls *.so.7.2.1 | sed sP^libPPg | sed sp.so.7.2.1pp | xargs -i ln -sf lib{}.so.7.2.1 lib{}.so.7)"; 8 | 9 | exec(cmd, (error, stdout, stderr) => { 10 | if (error) { 11 | console.log(error.code); 12 | } else { 13 | console.log("done"); 14 | } 15 | }); 16 | 17 | } -------------------------------------------------------------------------------- /test/test_geometry.js: -------------------------------------------------------------------------------- 1 | 2 | const occ = require("../lib/occ"); 3 | const shapeFactory = require("../lib/shapeFactory"); 4 | 5 | 6 | const getTemporaryFilePath = require("gettemporaryfilepath"); 7 | 8 | 9 | describe("testing geometry builder",function(){ 10 | it("should create a bottle", function () { 11 | 12 | let bottle_brep = getTemporaryFilePath({prefix: "bottle", suffix: ".brep"}); 13 | let bottle = shapeFactory.makeBottle(occ); 14 | occ.writeBREP(bottle_brep, bottle); 15 | }); 16 | }); 17 | 18 | -------------------------------------------------------------------------------- /src/all.cc: -------------------------------------------------------------------------------- 1 | #include "Base.cc" 2 | #include "BooleanOperation.cc" 3 | #include "BoundingBox.cc" 4 | #include "Edge.cc" 5 | #include "Face.cc" 6 | #include "GeometryBuilder.cc" 7 | #include "Mesh.cc" 8 | #include "Point3Wrap.cc" 9 | #include "Shape.cc" 10 | #include "ShapeFactory.cc" 11 | #include "ShapeIterator.cc" 12 | #include "Shell.cc" 13 | #include "Solid.cc" 14 | #include "Tools.cc" 15 | #include "Transformation.cc" 16 | #include "Transform.cc" 17 | #include "Util.cc" 18 | #include "V8Wrapper.cc" 19 | #include "Vertex.cc" 20 | #include "Wire.cc" 21 | -------------------------------------------------------------------------------- /src/Shape.cc: -------------------------------------------------------------------------------- 1 | #include "Shape.h" 2 | #include "Util.h" 3 | #include "Transformation.h" 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | 11 | 12 | 13 | bool operator == (v8::Local str,const char* value) 14 | { 15 | return Nan::Equals(str,Nan::New(value).ToLocalChecked()).ToChecked(); 16 | } 17 | 18 | 19 | const TopoDS_Shape& Shape::shape() const 20 | { 21 | return shape_; 22 | } 23 | 24 | void Shape::setShape( const TopoDS_Shape& shape) 25 | { 26 | shape_ = shape; 27 | } 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/BooleanOperation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Shape.h" 4 | #include "Point3Wrap.h" 5 | 6 | #include 7 | 8 | 9 | 10 | class BooleanOperation : public Nan::ObjectWrap { 11 | BRepAlgoAPI_BooleanOperation* m_bop; 12 | BooleanOperation(); 13 | ~BooleanOperation(); 14 | public: 15 | typedef class BooleanOperation _ThisType; 16 | 17 | static Nan::Persistent _template; 18 | static v8::Local NewInstance(BOPAlgo_Operation op); 19 | 20 | static NAN_METHOD(New); 21 | static void Init(v8::Local target); 22 | }; 23 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [erossignon] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /bin/STEPtoBREP.js: -------------------------------------------------------------------------------- 1 | const occ = require("../lib/occ"); 2 | 3 | const pace = require("pace")(1000); 4 | 5 | const filename = process.argv[2]; 6 | let message; 7 | 8 | occ.readSTEP(filename, function (err, solids) { 9 | pace.op(100000); 10 | if (!err) { 11 | console.log(" \n\ndone y----> ", solids.length, " solids read"); 12 | 13 | // write to BREP 14 | occ.writeBREP(filename + ".brep", solids, function done() { 15 | }); 16 | } else { 17 | message = solids 18 | console.log("\n\n ERROR =", message); 19 | } 20 | 21 | }, function progress(percent, incr) { 22 | pace.op(percent * 100 * 10) 23 | // console.log("tick ", incr,bar1.step) 24 | // bar1.tick(incr); 25 | }); 26 | 27 | console.log(process.argv[0]); 28 | -------------------------------------------------------------------------------- /src/Shell.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "OCC.h" 3 | #include "NodeV8.h" 4 | 5 | #include "Base.h" 6 | 7 | #include 8 | class Face; 9 | class Shell: public Base { 10 | 11 | TopoDS_Shell m_shell; 12 | public: 13 | int numFaces(); 14 | 15 | double area(); 16 | 17 | 18 | 19 | virtual const TopoDS_Shape& shape() const; 20 | const TopoDS_Shell& shell() const { 21 | return m_shell; 22 | } 23 | virtual void setShape(const TopoDS_Shape&); 24 | 25 | virtual Base* Unwrap(v8::Local obj) const { return Nan::ObjectWrap::Unwrap(obj); } 26 | virtual v8::Local Clone() const ; 27 | 28 | static void Init(v8::Local target); 29 | static NAN_METHOD(New); 30 | static Nan::Persistent _template; 31 | }; -------------------------------------------------------------------------------- /src/ShapeIterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "NodeV8.h" 3 | #include "OCC.h" 4 | 5 | #include "Base.h" 6 | 7 | 8 | class ShapeIterator : public Nan::ObjectWrap { 9 | public: 10 | TopExp_Explorer ex; 11 | TopAbs_ShapeEnum m_toFind; 12 | 13 | ShapeIterator(Base *arg,TopAbs_ShapeEnum type) { 14 | m_toFind = type; 15 | ex.Init(arg->shape(), m_toFind); 16 | } 17 | 18 | bool more(); 19 | 20 | void reset(); 21 | static NAN_METHOD(reset); 22 | 23 | v8::Local next(); 24 | static NAN_METHOD(next); 25 | 26 | // Methods exposed to JavaScripts 27 | static void Init(v8::Local target); 28 | 29 | static NAN_METHOD(NewInstance); 30 | static NAN_METHOD(New); 31 | 32 | static Nan::Persistent _template; 33 | 34 | }; 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | toto*.step 3 | *.slo 4 | *.lo 5 | *.o 6 | *.orig 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | 11 | # Compiled Static libraries 12 | *.lai 13 | *.la 14 | *.a 15 | 16 | # log files 17 | *.log 18 | 19 | node_modules 20 | build 21 | 22 | .idea 23 | /toto.STEP 24 | /backup 25 | /debugHelper 26 | /sample/node_modules 27 | /sample/public/javascripts/*.bak 28 | /lib/*.bak 29 | 30 | toto.* 31 | deps/ 32 | /a.html 33 | /occ_.h 34 | *.bak 35 | /t.html 36 | /t.js 37 | /*.sublime-project 38 | /*.sublime-workspace 39 | 40 | /src/*.swp 41 | 42 | *.swp 43 | 44 | /sample/node_modules 45 | /sample/client/*.js~ 46 | *.html~ 47 | /sample/views/*.ejs~ 48 | 49 | build_oce*/ 50 | 51 | dist 52 | node-occ-package* 53 | extrudedFace.step 54 | lib/binding 55 | *.tgz 56 | npm-debug* 57 | occt-* 58 | 59 | bower_components 60 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | // Do grunt-related things in here 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON("package.json"), 5 | 6 | mochacli: { 7 | options: { 8 | //reporter: "nyan" 9 | reporter: "spec" 10 | }, 11 | all: ["test/**/*_test.js"] 12 | 13 | }, 14 | 15 | docco: { 16 | debug: { 17 | src: ["lib/*.js", "test/**/*.js"], 18 | options: { 19 | output: "docs/" 20 | } 21 | } 22 | 23 | } 24 | }); 25 | grunt.loadNpmTasks("grunt-mocha-cli"); 26 | grunt.loadNpmTasks("grunt-docco"); 27 | grunt.registerTask("doc", ["docco"]); 28 | 29 | grunt.registerTask("default", ["mochacli", "doc"]); 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /.github/workflows/workflow1.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI2 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-22.04 12 | strategy: 13 | matrix: 14 | node-version: [16.x, 18.x] 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Use Node.js ${{ matrix.node-version }} 18 | uses: actions/setup-node@v2 19 | with: 20 | node-version: ${{ matrix.node-version }} 21 | - run: npm install -g pnpm@6 22 | - uses: actions/cache@v2 23 | with: 24 | path: ~/.pnpm-store 25 | key: ${{ runner.os }}-pnpm-store 26 | - run: sudo apt-get install libocct-data-exchange-dev libocct-modeling-data-dev 27 | - run: npm install -g pnpm@6 28 | - run: pnpm recursive install 29 | - run: pnpm test 30 | -------------------------------------------------------------------------------- /src/Vertex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Shape.h" 3 | 4 | class Vertex : public Shape { 5 | private: 6 | TopoDS_Vertex m_vertex; 7 | public: 8 | 9 | double x() ; 10 | double y() ; 11 | double z() ; 12 | 13 | gp_Pnt point() const; 14 | 15 | virtual const TopoDS_Shape& shape() const; 16 | const TopoDS_Vertex& vertex() const { 17 | return m_vertex; 18 | } 19 | virtual void setShape( const TopoDS_Shape&); 20 | virtual v8::Local Clone() const ; 21 | virtual Base* Unwrap(v8::Local obj) const { 22 | return Nan::ObjectWrap::Unwrap(obj); 23 | } 24 | 25 | 26 | virtual void InitNew(_NAN_METHOD_ARGS); 27 | 28 | 29 | static void Init(v8::Local target); 30 | static NAN_METHOD(NewInstance); 31 | static NAN_METHOD(New); 32 | static Nan::Persistent _template; 33 | }; 34 | -------------------------------------------------------------------------------- /src/Wire.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Shape.h" 3 | 4 | #include "Edge.h" 5 | 6 | class Wire : public Base { 7 | 8 | TopoDS_Wire m_wire; 9 | public: 10 | int numVertices(); 11 | int numEdges(); 12 | bool isClosed(); 13 | 14 | 15 | virtual const TopoDS_Shape& shape() const; 16 | const TopoDS_Wire& wire() const { 17 | return m_wire; 18 | } 19 | virtual void setShape(const TopoDS_Shape&); 20 | virtual v8::Local Clone() const ; 21 | virtual Base* Unwrap(v8::Local obj) const { 22 | return Nan::ObjectWrap::Unwrap(obj); 23 | } 24 | 25 | static void Init(v8::Local target); 26 | static NAN_METHOD(New); 27 | static NAN_METHOD(getEdges); 28 | static NAN_METHOD(getVertices); 29 | 30 | static NAN_METHOD(NewInstance); 31 | virtual void InitNew(_NAN_METHOD_ARGS); 32 | 33 | static Nan::Persistent _template; 34 | }; -------------------------------------------------------------------------------- /test/helpers.js: -------------------------------------------------------------------------------- 1 | const getTemporaryFilePath = require("gettemporaryfilepath"); 2 | 3 | const _getTemporaryFilePath = function () { 4 | let tmp = getTemporaryFilePath.apply(null, arguments); 5 | return tmp.replace(/\\/g, "/"); 6 | }; 7 | exports.getTemporaryFilePath = _getTemporaryFilePath; 8 | 9 | 10 | const fs = require("fs"); 11 | 12 | function remove_file(filename, optional_callback) { 13 | 14 | optional_callback = optional_callback || function() {}; 15 | 16 | fs.exists(filename, function (exists) { 17 | 18 | if (exists) { 19 | //Show in green 20 | //xx console.log('File exists. Deleting now ... ' + filename); 21 | fs.unlink(filename, optional_callback); 22 | } else { 23 | //Show in red 24 | console.log("File " + filename + " not found, so not deleting."); 25 | optional_callback || optional_callback(); 26 | } 27 | }); 28 | } 29 | exports.remove_file = remove_file; 30 | -------------------------------------------------------------------------------- /src/Shape.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "NodeV8.h" 3 | #include "OCC.h" 4 | #include "Base.h" 5 | 6 | class Shape : public Base { 7 | 8 | public: 9 | Shape() {}; 10 | virtual ~Shape() {}; 11 | 12 | protected: 13 | TopoDS_Shape shape_; 14 | 15 | 16 | 17 | // static NAN_METHOD(ShapeType); 18 | // constructors 19 | 20 | public: 21 | virtual const TopoDS_Shape& shape() const; 22 | virtual void setShape( const TopoDS_Shape&); 23 | 24 | 25 | 26 | void setErrorMessage(const char* message) {}; 27 | 28 | }; 29 | 30 | template 31 | inline v8::Local extract_shapes_as_javascript_array(SHAPE* pThis,TopAbs_ShapeEnum type) { 32 | 33 | TopTools_IndexedMapOfShape anIndices; 34 | TopExp::MapShapes(pThis->shape(), type, anIndices); 35 | 36 | int nb =anIndices.Extent(); 37 | v8::Local arr = Nan::New(nb); 38 | for (int i=0; i obj= buildWrapper(anIndices(i+1)); // 1 based !!! 40 | Nan::Set(arr,i,obj); 41 | } 42 | return arr; 43 | } 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /test/test_applyTransform.js: -------------------------------------------------------------------------------- 1 | 2 | const occ = require("../lib/occ"); 3 | const should = require("should"); 4 | 5 | describe("testing various transformation",function() { 6 | 7 | 8 | function getVerticeData(box) { 9 | let vert = box.getVertices(); 10 | vert = vert.map(function(v) { return [v.x, v.y, v.z]; }); 11 | vert.length.should.eql(8); 12 | return vert; 13 | } 14 | function add(v1,v2) { 15 | return [v1[0]+v2[0],v1[1]+v2[1],v1[2]+v2[2]]; 16 | } 17 | 18 | it("#applyTransform",function(){ 19 | 20 | let box = occ.makeBox([0,0,0],[100,200,300]); 21 | 22 | let trsf=new occ.Transformation(); 23 | trsf.makeTranslation([10,20,30]); 24 | 25 | let vert = getVerticeData(box); 26 | 27 | vert[1].should.eql([0,0,0]); 28 | box.applyTransform(trsf); 29 | 30 | let vert_after = getVerticeData(box); 31 | 32 | // translate vertex 33 | vert = vert.map(function(v){ return add(v,[10,20,30])}); 34 | vert_after.should.eql(vert); 35 | 36 | }); 37 | 38 | }); -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 6 4 | }, 5 | "extends": [ 6 | // "standard" 7 | ], 8 | "plugins": [ 9 | "require-path-exists" 10 | ], 11 | "env": { 12 | "node": true, 13 | "mocha": true 14 | }, 15 | "rules": { 16 | "no-var": ["error"], 17 | "quotes": ["error", "double"], 18 | "indent": [ 19 | "error", 20 | 4 21 | ] 22 | /* 23 | "padded-blocks": ["error", "always"], 24 | "arrow-parens": [2, "as-needed", {"requireForBlockBody": true }], 25 | "no-unused-vars": [2, { "vars": "all", "args": "after-used" }], 26 | "no-var": 2, 27 | "object-curly-spacing": [2, "always"], 28 | "object-shorthand": 2, 29 | "prefer-arrow-callback": 2, 30 | "prefer-const": 2, 31 | "prefer-template": 2, 32 | "require-path-exists/exists": 2, 33 | "require-path-exists/notEmpty": 2, 34 | "require-path-exists/tooManyArguments": 2, 35 | "semi": [2, "always", {"omitLastInOneLineBlock": true}], 36 | "space-before-function-paren": [2, "never"], 37 | "standard/object-curly-even-spacing": 0 38 | */ 39 | } 40 | } -------------------------------------------------------------------------------- /src/Transformation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "NodeV8.h" 3 | #include "OCC.h" 4 | #include "Util.h" 5 | 6 | #include "Point3Wrap.h" 7 | 8 | 9 | 10 | class Transformation : public Nan::ObjectWrap { 11 | public: 12 | typedef class Transformation _ThisType ; 13 | Transformation() 14 | {} 15 | static NAN_METHOD(makeTranslation); 16 | static NAN_METHOD(makePlaneMirror); 17 | static NAN_METHOD(makeAxisMirror); 18 | static NAN_METHOD(makeScale); 19 | static NAN_METHOD(makeRotation); 20 | 21 | double scaleFactor() { 22 | return m_trsf.ScaleFactor(); 23 | } 24 | 25 | const gp_XYZ translationPart() const { 26 | return m_trsf.TranslationPart(); 27 | } 28 | 29 | TEAROFF_POINT(Transformation,translationPart,Point3Wrap,gp_XYZ); 30 | 31 | gp_Trsf m_trsf; 32 | 33 | 34 | 35 | 36 | // Methods exposed to JavaScripts 37 | static void Init(v8::Local target); 38 | static NAN_METHOD(NewInstance); 39 | static NAN_METHOD(New); 40 | 41 | static Nan::Persistent _template; 42 | 43 | private: 44 | Transformation(const Transformation&); 45 | void operator=(const Transformation&); 46 | }; -------------------------------------------------------------------------------- /test/test_extrudeFace.js: -------------------------------------------------------------------------------- 1 | 2 | const occ = require("../lib/occ"); 3 | const should = require("should"); 4 | 5 | describe("demonstrate how to extrude a face",function() { 6 | 7 | it("extrudeFace",function() { 8 | 9 | // create a planar wire close line. 10 | 11 | const aPnt1 = [0, 0.0, 0]; 12 | const aPnt2 = [10, 1.0, 0]; 13 | const aPnt3 = [10, 9.0, 0]; 14 | const aPnt4 = [0, 10.0, 0]; 15 | const aSegment1 = new occ.makeLine(aPnt1, aPnt2); 16 | const aSegment2 = new occ.makeLine(aPnt2, aPnt3); 17 | const aSegment3 = new occ.makeLine(aPnt3, aPnt4); 18 | const aSegment4 = new occ.makeLine(aPnt4, aPnt1); 19 | 20 | const aWire = new occ.Wire(aSegment1, aSegment2, aSegment3, aSegment4); 21 | aWire.isClosed.should.equal(true); 22 | aWire.numEdges.should.equal(4); 23 | aWire.numVertices.should.equal(4); 24 | 25 | // the vector to extrude the face along. 26 | const aVector = [-2, -2.0, 10]; 27 | const aFace = new occ.Face(aWire); 28 | 29 | const myBody = occ.makePrism(aFace, aVector); 30 | 31 | occ.writeSTEP("extrudedFace.step",[myBody]); 32 | 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | the MIT Licence 2 | ------------ 3 | 4 | Copyright (c) 2012 Etienne Rossignon ( etienne.rossignon (at) gmail.com ) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/ShapeFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "NodeV8.h" 3 | #include "OCC.h" 4 | #include 5 | 6 | 7 | 8 | class Solid; 9 | class Base; 10 | class ShapeFactory { 11 | public: 12 | // vertex 13 | static NAN_METHOD(makeVertex); 14 | //xx // edges 15 | //xx static NAN_METHOD(makeLine); 16 | //xx static NAN_METHOD(makeCircle); 17 | //xx static NAN_METHOD(makeArc3P); 18 | 19 | // wires 20 | static NAN_METHOD(makeWire); 21 | 22 | // faces 23 | static NAN_METHOD(makeFace); 24 | 25 | // boolean operation 26 | static NAN_METHOD(fuse); 27 | static NAN_METHOD(cut); 28 | static NAN_METHOD(common); 29 | static NAN_METHOD(compound); 30 | // primitive constructions 31 | static NAN_METHOD(makeBox); 32 | static NAN_METHOD(makePrism); 33 | static NAN_METHOD(makeCylinder); 34 | static NAN_METHOD(makeCone); 35 | static NAN_METHOD(makeSphere); 36 | static NAN_METHOD(makeTorus); 37 | static NAN_METHOD(makePipe); 38 | // 39 | static NAN_METHOD(makeThickSolid); 40 | static NAN_METHOD(makeDraftAngle); 41 | static NAN_METHOD(makeFillet); 42 | private: 43 | static void _boolean(_NAN_METHOD_ARGS,BOPAlgo_Operation op); 44 | static v8::Local add(const std::vector& shapes); 45 | 46 | }; 47 | -------------------------------------------------------------------------------- /setenv.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | :: SETENV.BAT 3 | 4 | set ARCH=unset 5 | 6 | if '%1' == '32' set ARCH=Win32 7 | if '%1' == '64' set ARCH=Win64 8 | if '%ARCH%' == 'unset' ( 9 | echo "USAGE : SETENV 32|64" 10 | exit /B 1 11 | ) 12 | 13 | 14 | SET CWD=%~dp0 15 | SET OCCT_VER=7.2.0 16 | SET OCCT_FOLDER="%CWD%occt-%OCCT_VER%\" 17 | ECHO %OCCT_FOLDER% 18 | IF EXIST "%OCCT_FOLDER%" ( 19 | echo OCCT-%OCCT_VER% prebuild stuff already installed 20 | ) else ( 21 | IF NOT EXIST occt-%OCCT_VER% ( 22 | curl -OL https://github.com/OpenWebCAD/occt_builder/releases/download/%OCCT_VER%/occt-%OCCT_VER%-win64.zip 23 | ) 24 | 7z x occt-%OCCT_VER%-win64.zip -y > a.txt 25 | echo DONE 26 | ) 27 | 28 | :: 29 | :: Note CL and LINK require unix style like path 30 | :: 31 | SET OCE=occt-%OCCT_VER% 32 | SET PREFIX=%OCCT_FOLDER% 33 | SET CL=/I%PREFIX%/inc 34 | SET LINK=/LIBPATH:%PREFIX%/%ARCH%/vc14/lib 35 | SET CMAKE_BIN=C:\Program Files (x86)\CMake\bin 36 | SET GIT_BIN=C:\Program Files (x86)\Git\bin 37 | :: 38 | :: set the find command to point to the windows version (avoiding inadvertant usage of gitbash find command) 39 | :: 40 | SET FIND=%WINDIR%\SYSTEM32\FIND.EXE 41 | :: 42 | :: Let check if we have already inserted element in Path 43 | :: 44 | echo ";%PATH%;" | %FIND% /C /I ";c:\%OCE%\%ARCH%\bin;" > tmp.txt 45 | set /p F= exports[method] = occ[method]); 16 | 17 | 18 | // add utilities 19 | exports.XDir = [1, 0, 0]; 20 | exports.YDir = [0, 1, 0]; 21 | exports.ZDir = [0, 0, 1]; 22 | 23 | /* 24 | exports.demo = function () { 25 | const solid = occ.makeBox([10, 20, 30], [40, 50, 60]); 26 | solid.mesh; 27 | return solid; 28 | }(); 29 | */ 30 | 31 | function f(a, w, p) { 32 | return (" " + (a + 0).toFixed(p)).substr(-w); 33 | } 34 | 35 | occ.Point3D.prototype.toString = function () { 36 | 37 | return "{" + 38 | " x: " + f(this.x, 8, 3) + "," + 39 | " y: " + f(this.y, 8, 3) + "," + 40 | " z: " + f(this.z, 8, 3) + "" + 41 | " }"; 42 | }; 43 | 44 | occ.BoundingBox.prototype.toString = function () { 45 | return "{ nearPt: " + this.nearPt.toString() + " , farPt: " + this.farPt.toString() + "}"; 46 | }; 47 | 48 | occ.Vertex.prototype.toString = occ.Point3D.prototype.toString; 49 | 50 | occ.Edge.prototype.toString = function () { 51 | 52 | return "Edge => { \n" + 53 | " numVertices: " + this.numVertices + "\n" + 54 | " vertices: " + 55 | this.getVertices().map(function (f) { 56 | return f.toString(); 57 | }).join(" ") + "}"; 58 | }; 59 | -------------------------------------------------------------------------------- /src/Face.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "OCC.h" 3 | #include "NodeV8.h" 4 | 5 | #include "Base.h" 6 | #include "Point3Wrap.h" 7 | 8 | #include 9 | class Wire; 10 | class Face: public Base { 11 | 12 | friend class Mesh; 13 | TopoDS_Face m_face; 14 | Nan::Persistent m_cacheMesh; 15 | virtual ~Face(); 16 | 17 | public: 18 | int numWires(); 19 | double area(); 20 | bool fixShape(); 21 | bool isPlanar(); 22 | bool hasMesh(); 23 | std::vector inertia(); 24 | 25 | const gp_XYZ centreOfMass() const; 26 | 27 | TEAROFF_POINT(Face,centreOfMass,Point3Wrap,gp_XYZ); 28 | 29 | virtual const TopoDS_Shape& shape() const; 30 | const TopoDS_Face& face() const { 31 | return m_face; 32 | } 33 | virtual void setShape(const TopoDS_Shape&); 34 | 35 | bool buildFace(std::vector& wires); 36 | 37 | static NAN_METHOD(extrude); 38 | 39 | virtual v8::Local Clone() const; 40 | 41 | virtual Base* Unwrap(v8::Local obj) const { 42 | return Nan::ObjectWrap::Unwrap(obj); 43 | } 44 | virtual void InitNew(_NAN_METHOD_ARGS); 45 | 46 | 47 | v8::Local createMesh(double factor, double angle, bool qualityNormals); 48 | 49 | static void Init(v8::Local target); 50 | static v8::Local NewInstance(const TopoDS_Face& face); 51 | 52 | static NAN_METHOD(New); 53 | static NAN_METHOD(createMesh); // custom mesh 54 | static NAN_PROPERTY_GETTER(_mesh); 55 | static NAN_METHOD(getWires); 56 | 57 | static NAN_METHOD(NewInstance); 58 | 59 | static Nan::Persistent _template; 60 | }; -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.lxx": "cpp", 4 | "istream": "cpp", 5 | "ostream": "cpp", 6 | "array": "cpp", 7 | "functional": "cpp", 8 | "tuple": "cpp", 9 | "type_traits": "cpp", 10 | "utility": "cpp", 11 | "atomic": "cpp", 12 | "bit": "cpp", 13 | "*.tcc": "cpp", 14 | "cctype": "cpp", 15 | "clocale": "cpp", 16 | "cmath": "cpp", 17 | "cstdarg": "cpp", 18 | "cstddef": "cpp", 19 | "cstdint": "cpp", 20 | "cstdio": "cpp", 21 | "cstdlib": "cpp", 22 | "cstring": "cpp", 23 | "ctime": "cpp", 24 | "cwchar": "cpp", 25 | "cwctype": "cpp", 26 | "deque": "cpp", 27 | "list": "cpp", 28 | "map": "cpp", 29 | "set": "cpp", 30 | "unordered_map": "cpp", 31 | "vector": "cpp", 32 | "exception": "cpp", 33 | "algorithm": "cpp", 34 | "iterator": "cpp", 35 | "memory": "cpp", 36 | "memory_resource": "cpp", 37 | "numeric": "cpp", 38 | "optional": "cpp", 39 | "random": "cpp", 40 | "string": "cpp", 41 | "string_view": "cpp", 42 | "system_error": "cpp", 43 | "fstream": "cpp", 44 | "initializer_list": "cpp", 45 | "iomanip": "cpp", 46 | "iosfwd": "cpp", 47 | "iostream": "cpp", 48 | "limits": "cpp", 49 | "new": "cpp", 50 | "sstream": "cpp", 51 | "stdexcept": "cpp", 52 | "streambuf": "cpp", 53 | "cinttypes": "cpp", 54 | "typeinfo": "cpp" 55 | } 56 | } -------------------------------------------------------------------------------- /test/test_wire.js: -------------------------------------------------------------------------------- 1 | 2 | const assert = require("assert"); 3 | const should = require("should"); 4 | 5 | const occ = require("../lib/occ"); 6 | 7 | 8 | describe("testing Wire ",function(){ 9 | 10 | describe("empty wire", function() { 11 | let wire; 12 | before(function() { 13 | wire = new occ.Wire(); 14 | }); 15 | it("should have no edges", function() { 16 | wire.numEdges.should.equal(0); 17 | }); 18 | it("should have no vertex", function() { 19 | wire.numVertices.should.equal(0); 20 | }); 21 | it("should not be closed", function() { 22 | wire.isClosed.should.equal(false); 23 | }); 24 | }); 25 | describe("wire with three segments", function () { 26 | 27 | let edge1, edge2, edge3; 28 | let wire; 29 | before(function () { 30 | let v1 = new occ.Vertex(0, 0, 0); 31 | let v2 = new occ.Vertex(10, 10, 0); 32 | let v3 = new occ.Vertex(20, 0, 0); 33 | edge1 = occ.makeLine(v1, v2); 34 | edge2 = occ.makeLine(v2, v3); 35 | edge3 = occ.makeLine(v3, v1); 36 | wire = new occ.Wire(edge1, edge2, edge3); 37 | }); 38 | 39 | it("should have three edges", function () { 40 | wire.numEdges.should.equal(3); 41 | }); 42 | 43 | it("should have three vertive", function () { 44 | wire.numVertices.should.equal(3); 45 | }); 46 | 47 | it("should be closed", function () { 48 | wire.isClosed.should.equal(true); 49 | }); 50 | }); 51 | 52 | }); 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/BoundingBox.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Shape.h" 4 | #include "Point3Wrap.h" 5 | 6 | #include 7 | 8 | const double qNaN = std::numeric_limits::quiet_NaN(); 9 | 10 | class BoundingBox : public Nan::ObjectWrap { 11 | Bnd_Box m_box; 12 | public: 13 | typedef class BoundingBox _ThisType; 14 | 15 | BoundingBox() 16 | {} 17 | 18 | const gp_XYZ nearPt() const { 19 | 20 | if (m_box.IsVoid()) { 21 | return gp_XYZ(qNaN,qNaN,qNaN); 22 | } 23 | Standard_Real aXmin,aYmin,aZmin; 24 | Standard_Real aXmax,aYmax,aZmax; 25 | m_box.Get(aXmin,aYmin,aZmin,aXmax,aYmax,aZmax); 26 | return gp_XYZ(aXmin,aYmin,aZmin); 27 | } 28 | 29 | const gp_XYZ farPt() const { 30 | if (m_box.IsVoid()) { 31 | return gp_XYZ(-qNaN,-qNaN,-qNaN); 32 | } 33 | Standard_Real aXmin,aYmin,aZmin; 34 | Standard_Real aXmax,aYmax,aZmax; 35 | m_box.Get(aXmin,aYmin,aZmin,aXmax,aYmax,aZmax); 36 | return gp_XYZ(aXmax,aYmax,aZmax); 37 | } 38 | 39 | bool isVoid() { 40 | return m_box.IsVoid() ? true : false ; 41 | } 42 | 43 | TEAROFF_POINT(BoundingBox,nearPt,Point3Wrap,gp_XYZ); 44 | TEAROFF_POINT(BoundingBox,farPt, Point3Wrap,gp_XYZ); 45 | 46 | static NAN_METHOD(addPoint); 47 | static NAN_METHOD(isOut); 48 | 49 | 50 | virtual void InitNew(_NAN_METHOD_ARGS); 51 | 52 | static Nan::Persistent _template; 53 | 54 | static v8::Local NewInstance(const gp_Pnt& near,const gp_Pnt& far); 55 | static v8::Local NewInstance(const Bnd_Box& box); 56 | 57 | static NAN_METHOD(New); 58 | static void Init(v8::Local target); 59 | 60 | protected: 61 | static void Update(BoundingBox* pThis,_NAN_METHOD_ARGS); 62 | }; -------------------------------------------------------------------------------- /test/test_scriptrunner.js: -------------------------------------------------------------------------------- 1 | const should = require("should"); 2 | const sr = require("../lib/scriptrunner"); 3 | describe("Script Runner", function () { 4 | let runner; 5 | let myEnv = {foo: "bar"}; 6 | 7 | before(function () { 8 | runner = new sr.ScriptRunner(myEnv); 9 | }); 10 | 11 | it("should not be possible load external module with require", function (done) { 12 | 13 | runner.run("let fs= require('fs');", function () { 14 | should.fail("done callback"); 15 | done(new Error("test has failed: 'require' call hasn't been intercepted")); 16 | }, function error_callback(err) { 17 | should.exist(err); 18 | err.message.should.equal("require is forbidden"); 19 | done(null); // 20 | }); 21 | }); 22 | it("should not be possible to use eval", function (done) { 23 | 24 | runner.run("eval('a=10');", 25 | 26 | function () { 27 | should.fail("done callback"); 28 | done(new Error("test has failed: 'eval' call hasn't been intercepted")); 29 | }, 30 | function error_callback(err) { 31 | should.exist(err); 32 | err.message.should.equal("eval is forbidden"); 33 | done(null); // 34 | } 35 | ); 36 | 37 | }); 38 | it("should expose environment provided by the caller", function (done) { 39 | 40 | runner.env.logs = []; // purge log 41 | runner.env.logs.length.should.equal(0); 42 | runner.env.foo.should.equal("bar"); 43 | runner.run("console.log(foo); foo='baz'", 44 | 45 | function () { 46 | 47 | runner.env.foo.should.equal("baz"); 48 | runner.env.logs.length.should.equal(1); 49 | 50 | done(); 51 | }, 52 | function error_callback(err) { 53 | done(err); // should not fail 54 | } 55 | ); 56 | 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-occ", 3 | "version": "1.0.1", 4 | "description": "OpenCascade OCCT Wrapper for Node js", 5 | "preferGlobal": true, 6 | "dependencies": { 7 | "async": "^3.2.4", 8 | "colors": "*", 9 | "gettemporaryfilepath": "1.0.1", 10 | "nan": "^2.16.0", 11 | "node-pre-gyp": "^0.15.0", 12 | "pace": "~0.0.4", 13 | "progress": "~2.0.3" 14 | }, 15 | "devDependencies": { 16 | "@types/mocha": "^9.1.1", 17 | "aws-sdk": "^2.1209.0", 18 | "eslint": "^8.23.0", 19 | "eslint-config-standard": "^17.0.0", 20 | "eslint-plugin-import": "^2.26.0", 21 | "eslint-plugin-node": "^11.1.0", 22 | "eslint-plugin-promise": "^6.0.1", 23 | "eslint-plugin-require-path-exists": "^1.1.9", 24 | "eslint-plugin-standard": "^4.1.0", 25 | "eslint-utils": "^3.0.0", 26 | "mocha": "^10.0.0", 27 | "should": "~13.2.3" 28 | }, 29 | "main": "index", 30 | "author": { 31 | "name": "Etienne Rossignon" 32 | }, 33 | "engines": { 34 | "node": "*" 35 | }, 36 | "keywords": [ 37 | "3D", 38 | "CAD", 39 | "OpenCascade", 40 | "OCE", 41 | "Solid Modeler", 42 | "geometry", 43 | "BRep" 44 | ], 45 | "repository": { 46 | "type": "git", 47 | "url": "https://github.com/openwebcad/node-occ.git" 48 | }, 49 | "scripts": { 50 | "install": "node-pre-gyp install --fallback-to-build", 51 | "test": "mocha -R spec", 52 | "lint": "eslint lib test bin", 53 | "doc": "grunt doc", 54 | "postinstall": "node post-install.js" 55 | }, 56 | "binary": { 57 | "module_name": "occ", 58 | "module_path": "./lib/binding/", 59 | "host-aws": "https://nodeocc.s3-us-west-1.amazonaws.com", 60 | "host": "https://github.com/openwebcad/node-occ/releases/download/", 61 | "remote_path": "{version}" 62 | }, 63 | "gypfile": true, 64 | "bugs": { 65 | "url": "https://github.com/openwebcad/node-occ/issues" 66 | }, 67 | "directories": { 68 | "test": "test" 69 | }, 70 | "license": "MIT" 71 | } 72 | -------------------------------------------------------------------------------- /prepare_node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ########################################################################################## 3 | # 4 | # 5 | ########################################################################################## 6 | 7 | export VERSION_FILE=/usr/include/opencascade/Standard_Version.hxx 8 | grep -i "#define OCC_VERSION_COMPLETE" ${VERSION_FILE} ; 9 | lscpu ; 10 | cmake --version ; 11 | 12 | #set NPROC=`nproc` 13 | # on linux: 14 | # NPROC=$(grep "^core id" /proc/cpuinfo | sort -u | wc -l) 15 | # on MacOS 16 | # NPROC=$(sysctl -n hw.ncpu) 17 | # on both 18 | NPROC=$(node -p "os.cpus().length") 19 | 20 | echo "Number of processors =" ${NPROC} 21 | 22 | 23 | PATH=$PATH:`pwd`/node_modules/.bin 24 | uname -a 25 | echo "NODE PATH = `which node`" 26 | echo "NODE VERSION = `node --version`" 27 | echo "NODE = `node -p 'process.platform + "@" + process.arch'`" 28 | echo "NPM VERSION = `npm --version`" 29 | 30 | 31 | # figure out if we should publish 32 | PUBLISH_BINARY=false 33 | 34 | # if we are building a tag then publish 35 | echo $TRAVIS_BRANCH 36 | export CURRENT BRANCH=`git describe --tags --always HEAD` 37 | echo "CURRENT BRANCH = $CURRENT_BRANCH" 38 | if [[ "$TRAVIS_BRANCH" == "$CURRENT_BRANCH" ]]; then PUBLISH_BINARY=true; fi; 39 | 40 | 41 | echo "Publishing native platform Binary Package? ->" $PUBLISH_BINARY 42 | 43 | # Cleanup the output of npm 44 | npm config set progress false 45 | npm config set spin false 46 | 47 | if [[ ! -z $TRAVIS_ELECTRON_VERSION ]]; then 48 | if [[ $TRAVIS_OS_NAME == "linux" ]]; then 49 | export DISPLAY=:99.0 50 | sh -e /etc/init.d/xvfb start 51 | fi 52 | export npm_config_target=$TRAVIS_ELECTRON_VERSION 53 | export npm_config_arch=$ARCH 54 | export npm_config_disturl=https://atom.io/download/atom-shell 55 | export npm_config_runtime=electron 56 | npm install --arch=$ARCH electron@$TRAVIS_ELECTRON_VERSION 57 | npm install electron-mocha 58 | echo "installed Electron $TRAVIS_ELECTRON_VERSION" 59 | fi 60 | 61 | # git submodule update --depth 50 --init --recursive 62 | npm install --build-from-source 63 | 64 | -------------------------------------------------------------------------------- /test/test_transform.js: -------------------------------------------------------------------------------- 1 | const should = require("should"); 2 | const occ = require("../lib/occ"); 3 | 4 | 5 | describe("testing transformation object", function () { 6 | 7 | let trsf; 8 | before(function () { 9 | trsf = new occ.Transformation(); 10 | should.exist(trsf); 11 | }); 12 | describe("a empty transformation", function () { 13 | it("should have a scale factor of 1.0", function () { 14 | trsf.scaleFactor.should.equal(1.0); 15 | }); 16 | it("should have a rotation axis of 0,0,1", function () { 17 | trsf.scaleFactor.should.equal(1.0); 18 | }); 19 | }); 20 | 21 | describe("testing translation [10,20,30]", function () { 22 | before(function () { 23 | trsf.makeTranslation([10, 20, 30]); 24 | }); 25 | it("should have a scale factor of 1.0", function () { 26 | trsf.scaleFactor.should.equal(1.0); 27 | }); 28 | /* 29 | it("should have a rotation axis of 0,0,1", function() { 30 | trsf.rotationAxis.i.should.equal(0.0); 31 | trsf.rotationAxis.j.should.equal(0.0); 32 | trsf.rotationAxis.k.should.equal(1.0); 33 | }); 34 | it("should have a translationPart at [10,20,30]", function() { 35 | trsf.translationPart.x.should.equal(10.0); 36 | trsf.translationPart.y.should.equal(20.0); 37 | trsf.translationPart.z.should.equal(30.0); 38 | }); 39 | */ 40 | }); 41 | describe("testing planeMirror o=[10,20,30] dir=[0,0,1", function () { 42 | 43 | before(function () { 44 | 45 | occ.ZDir.should.eql([0, 0, 1]); 46 | 47 | trsf.makePlaneMirror([10, 20, 30], occ.ZDir); 48 | 49 | }); 50 | 51 | it("should have a scale factor of -1.0", function () { 52 | trsf.scaleFactor.should.eql(-1); 53 | }); 54 | 55 | it("should flip coord on the Z axis", function () { 56 | let v = occ.makeVertex(10, 10, 40); 57 | let v2 = v.transformed(trsf); 58 | v2.x.should.eql(v.x); 59 | }) 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /lib/mesh.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const occ = require("./bindings"); 3 | 4 | 5 | function toArray(meshBuffer) { 6 | const res = []; 7 | for (let i = 0; i < meshBuffer.length; i++) { 8 | res.push(parseFloat(meshBuffer[i].toFixed(3))); 9 | } 10 | return res; 11 | } 12 | exports.init = function () { 13 | 14 | 15 | const hasFaceVertexNormal = (1 << 5); 16 | // hasFaceNormal would be (1 << 4); 17 | occ.Mesh.prototype.toThreeJS_JSONFormat = function () { 18 | 19 | // see https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3.1 20 | // https://github.com/mrdoob/three.js/blob/102497da4213b9fceae9fd9bf87a37f7574ba387/src/loaders/JSONLoader.js 21 | const json = { 22 | metadata: {"formatVersion": 3}, 23 | materials: [{ 24 | DbgColor: 15658734, // => 0xeeeeee 25 | DbgIndex: 0, 26 | DbgName: "dummy", 27 | colorDiffuse: [1, 0, 0] 28 | }], 29 | vertices: [], 30 | normals: [], 31 | faces: [] 32 | }; 33 | 34 | json.vertices = toArray(this.vertices); 35 | json.normals = toArray(this.normals); 36 | json.uvs = []; 37 | json.faces = []; 38 | 39 | for (let i = 0; i < this.numTriangles; i++) { 40 | 41 | json.faces.push(hasFaceVertexNormal); // vertex + normal index 42 | 43 | const i1 = this.triangles[i * 3 + 0]; 44 | const i2 = this.triangles[i * 3 + 1]; 45 | const i3 = this.triangles[i * 3 + 2]; 46 | 47 | const j1 = this.triangleNormals[i * 3 + 0]; 48 | const j2 = this.triangleNormals[i * 3 + 1]; 49 | const j3 = this.triangleNormals[i * 3 + 2]; 50 | 51 | // face triangle vertex indexes 52 | json.faces.push(i1); 53 | json.faces.push(i2); 54 | json.faces.push(i3); 55 | 56 | // face vertex normal indexes 57 | json.faces.push(j1); 58 | json.faces.push(j2); 59 | json.faces.push(j3); 60 | } 61 | return json; 62 | }; 63 | 64 | occ.Mesh.prototype.toJSON = occ.Mesh.prototype.toThreeJS_JSONFormat; 65 | 66 | }; 67 | -------------------------------------------------------------------------------- /test/test_face.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const should = require("should"); 3 | 4 | const occ = require("../lib/occ"); 5 | 6 | // see https://npmjs.org/package/should 7 | 8 | describe("testing face mesh ",function() { 9 | 10 | it("Face#mesh - should not have a mesh unless the parent solid has been meshed", function () { 11 | 12 | // given a box solid 13 | let solid = occ.makeBox([0,0,0],[10,10,10]); 14 | 15 | solid.faces.should.have.property("top"); 16 | 17 | let topFace = solid.faces.top; 18 | should.exist(topFace); 19 | 20 | topFace.area.should.be.within(99.99, 100.0, "face area shall be 100.00"); 21 | 22 | topFace.hasMesh.should.equal(false); 23 | 24 | // now mesh the solid 25 | let m = solid.mesh; 26 | m.vertices.length.should.eql(8 * 3, "expecting 8 vertices (made of 3 floats) in solid mesh"); 27 | m.edgeIndices.length.should.eql(24); 28 | m.triangles.length.should.eql(36); 29 | 30 | //xx console.log(m.toJSON()); 31 | 32 | // meshing the solid should cause each of its faces to be meshed 33 | topFace.hasMesh.should.equal(true, "Face must have a mesh when parent solid is meshed"); 34 | 35 | //xx m.normals.length.should.eql(72); 36 | //xx console.log(topFace.mesh.toJSON()); 37 | let faceMesh = topFace.mesh; 38 | 39 | faceMesh.vertices.length.should.eql(3 * 4, "we expect 4 points "); 40 | //xx faceMesh.normals.length.should.eql(3 * 4); 41 | faceMesh.edgeIndices.length.should.eql(2 * 4); 42 | faceMesh.triangles.length.should.eql(2 * 3); 43 | 44 | }); 45 | }); 46 | 47 | describe("testing face#getWire ", function () { 48 | 49 | 50 | it("Face#getWire", function () { 51 | 52 | let solid = occ.makeBox([0, 0, 0], [10, 10, 10]); 53 | solid.faces.should.have.property("top"); 54 | let topFace = solid.faces.top; 55 | should.exist(topFace); 56 | 57 | let wires = topFace.getWires(); 58 | wires.length.should.eql(1); 59 | 60 | wires[0].getEdges().length.should.eql(4); 61 | 62 | wires[0].getEdges()[0].getVertices()[0].should.eql(new occ.Vertex({x: 0, y: 10, z: 10})); 63 | 64 | 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /testLargeStepFile.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const occ = require(".").occ; 3 | const ProgressBar = require('progress'); 4 | const fs = require("fs"); 5 | require("should"); 6 | 7 | 8 | const filename = process.argv[2]; 9 | console.log("filename = ",filename); 10 | if (!fs.existsSync(filename)) { 11 | console.log("cannot find file ",filename); 12 | process.exit(1); 13 | } 14 | const b3_step = filename; 15 | 16 | 17 | let bar = new ProgressBar("reading file [:bar] :percent elapsed :elapseds ETA :etas", { 18 | complete: '=', 19 | incomplete: '-', 20 | width: 100, 21 | total: 1000 22 | }); 23 | 24 | 25 | function read_file(callback) { 26 | occ.readSTEP(b3_step, function (err, shapes) { 27 | 28 | console.log(" nbShapes = ",shapes.length); 29 | callback(err,shapes); 30 | }, function feedback(percent) { 31 | bar.tick(percent); 32 | }); 33 | } 34 | 35 | function performMesh(solids,callback) { 36 | let bar = new ProgressBar("meshing solids [:bar] :percent elapsed :elapseds ETA :etas", { 37 | complete: '=', 38 | incomplete: '-', 39 | width: 100, 40 | total: solids.length 41 | }); 42 | let nbTri = 0; 43 | let nbVert = 0; 44 | let jsonSize =0; 45 | for (let i in solids) { 46 | bar.tick(); 47 | let solid = solids[i]; 48 | if (solid.numFaces <= 1) { 49 | console.log("solid has only one face !",solid); 50 | } 51 | solid.numFaces.should.be.greaterThan(0); 52 | solid.name = "solid_" + i; 53 | try { 54 | const jsObj = occ.buildSolidMeshNew(solid); 55 | let mesh = solid.mesh; 56 | solid.mesh.numVertices.should.be.greaterThan(3); 57 | nbVert += solid.mesh.numVertices; 58 | nbTri += solid.mesh.numTriangles; 59 | jsonSize += JSON.stringify(jsObj).length; 60 | } 61 | catch (err) { 62 | console.log(" Error in meshing" ,err ) 63 | } 64 | } 65 | console.log(" nb Tri = ",nbTri," nbVertices = ",nbVert," size ",jsonSize); 66 | } 67 | 68 | read_file(function(err,shapes){ 69 | 70 | performMesh(shapes,function() { 71 | console.log("done"); 72 | }) 73 | }); 74 | 75 | -------------------------------------------------------------------------------- /src/Solid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Shape.h" 3 | #include "Mesh.h" 4 | 5 | class Edge; 6 | // a multi body shape 7 | class Solid : public Shape { 8 | 9 | protected: 10 | Solid() {}; 11 | virtual ~Solid() { 12 | m_cacheMesh.Reset(); 13 | }; 14 | 15 | public: 16 | virtual v8::Local Clone() const; 17 | virtual Base* Unwrap(v8::Local obj) const { return Nan::ObjectWrap::Unwrap(obj); } 18 | 19 | Nan::Persistent m_cacheMesh; 20 | 21 | const TopoDS_Solid& solid() const { 22 | return TopoDS::Solid(shape()); 23 | } 24 | 25 | int numSolids(); 26 | int numFaces(); 27 | int numShells(); 28 | 29 | double volume(); 30 | double area(); 31 | bool hasMesh(); 32 | 33 | virtual void InitNew(_NAN_METHOD_ARGS); 34 | 35 | v8::Local createMesh(double factor, double angle, bool qualityNormals = true); 36 | 37 | typedef enum BoolOpType { 38 | BOOL_FUSE, 39 | BOOL_CUT, 40 | BOOL_COMMON, 41 | } BoolOpType; 42 | 43 | int boolean(Solid *tool, BoolOpType op); 44 | //xx int chamfer(const std::vector& edges, const std::vector& distances); 45 | //xx int fillet(const std::vector& edges, const std::vector& distances); 46 | 47 | // static Handle fillet(const v8::Arguments& args); 48 | // static Handle chamfer(const v8::Arguments& args); 49 | 50 | // default mesh 51 | static NAN_PROPERTY_GETTER(_mesh); 52 | 53 | static NAN_METHOD(createMesh); // custom mesh 54 | 55 | static NAN_METHOD(getEdges); 56 | static NAN_METHOD(getVertices); 57 | static NAN_METHOD(getFaces); 58 | static NAN_METHOD(getShells); 59 | static NAN_METHOD(getSolids); 60 | static NAN_METHOD(getOuterShell); 61 | static NAN_METHOD(getShapeName); 62 | static NAN_METHOD(getAdjacentFaces); 63 | static NAN_METHOD(getCommonEdges); 64 | static NAN_METHOD(getCommonVertices); 65 | 66 | // Methods exposed to JavaScripts 67 | static void Init(v8::Local target); 68 | 69 | static NAN_METHOD(New); 70 | static NAN_METHOD(NewInstance); 71 | 72 | static v8::Local NewInstance(TopoDS_Shape shape); 73 | static v8::Local NewInstance(); 74 | 75 | static Nan::Persistent _template; 76 | 77 | void _registerNamedShape(const char* name, const TopoDS_Shape& shape); 78 | std::string _getShapeName(const TopoDS_Shape& shape); 79 | 80 | }; 81 | 82 | -------------------------------------------------------------------------------- /src/Edge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Shape.h" 3 | 4 | #include "Vertex.h" 5 | 6 | class Edge : public Base { 7 | 8 | public: 9 | TopoDS_Edge m_edge; 10 | std::vector m_positions; 11 | 12 | Edge() { 13 | ; 14 | } 15 | 16 | bool isSeam(Base *face); 17 | 18 | bool isDegenerated(); 19 | bool isClosed(); 20 | int numVertices(); 21 | double length(); 22 | 23 | v8::Local polygonize(double factor); 24 | 25 | int createLine(Vertex *start, Vertex *end); 26 | int createArc(Vertex *start, Vertex *end, const gp_Pnt& center); 27 | int createArc3P(Vertex *start, Vertex *end, const gp_Pnt& middlePoint); 28 | 29 | int createCircle(const gp_Pnt& center , const gp_Dir& normal, double radius); 30 | 31 | //int createEllipse(OCCStruct3d pnt, OCCStruct3d nor, double rMajor, double rMinor); 32 | //int createHelix(double pitch, double height, double radius, double angle, bool leftHanded); 33 | //int createBezier(OCCVertex *start, OCCVertex *end, std::vector points); 34 | //int createSpline(OCCVertex *start, OCCVertex *end, std::vector points,double tolerance); 35 | //int createNURBS(OCCVertex *start, OCCVertex *end, std::vector points, DVec knots, DVec weights, IVec mult); 36 | 37 | bool canSetShape(const TopoDS_Shape& shape) const { 38 | return shape.ShapeType() == TopAbs_EDGE; 39 | } 40 | virtual const TopoDS_Shape& shape() const { 41 | return m_edge; 42 | } 43 | virtual const TopoDS_Edge& edge() const { 44 | return m_edge; 45 | } 46 | virtual void setShape(const TopoDS_Shape& shape) { 47 | m_edge = TopoDS::Edge(shape); 48 | } 49 | virtual v8::Local Clone() const ; 50 | virtual Base* Unwrap(v8::Local obj) const { 51 | return Nan::ObjectWrap::Unwrap(obj); 52 | } 53 | 54 | static NAN_PROPERTY_GETTER(getter_firstVertex); 55 | static NAN_PROPERTY_GETTER(getter_lastVertex); 56 | 57 | // Static Methods 58 | static NAN_METHOD(static_createLine); 59 | static NAN_METHOD(static_createCircle); 60 | static NAN_METHOD(static_createArc3P); 61 | 62 | 63 | static NAN_METHOD(polygonize); 64 | static NAN_METHOD(getVertices); 65 | 66 | static NAN_METHOD(New); 67 | static NAN_METHOD(startVertex); 68 | static NAN_METHOD(endVertex); 69 | 70 | static void Init(v8::Local target); 71 | static Nan::Persistent _template; 72 | }; -------------------------------------------------------------------------------- /src/AsyncWorkerWithProgress.h: -------------------------------------------------------------------------------- 1 | #include "nan.h" 2 | 3 | struct ProgressData { 4 | public: 5 | ProgressData(); 6 | double m_lastValue; 7 | double m_percent; 8 | double m_progress; 9 | }; 10 | 11 | inline ProgressData::ProgressData() 12 | :m_lastValue(0) 13 | ,m_percent(0) 14 | ,m_progress(0) 15 | {} 16 | 17 | class AsyncWorkerWithProgress : public Nan::AsyncWorker { 18 | 19 | Nan::Callback* _progressCallback; 20 | uv_async_t async; 21 | protected: 22 | std::string _filename; 23 | public: 24 | ProgressData m_data; 25 | 26 | public: 27 | AsyncWorkerWithProgress( 28 | Nan::Callback *callback, 29 | Nan::Callback* progressCallback, 30 | std::string* pfilename 31 | ) 32 | : Nan::AsyncWorker(callback) , _progressCallback(progressCallback) 33 | { 34 | _filename = *pfilename; 35 | delete pfilename; 36 | async.data = this; 37 | uv_async_init(Nan::GetCurrentEventLoop(), &async, AsyncProgress_); 38 | 39 | } 40 | 41 | inline static void AsyncClose_(uv_handle_t* handle) { 42 | AsyncWorkerWithProgress* worker = static_cast(handle->data); 43 | delete worker; 44 | handle->data = nullptr; 45 | } 46 | 47 | virtual void Destroy() { 48 | uv_close(reinterpret_cast(&async), AsyncClose_); 49 | } 50 | ~AsyncWorkerWithProgress() { 51 | 52 | if (_progressCallback) { 53 | delete _progressCallback; 54 | } 55 | 56 | } 57 | 58 | 59 | 60 | 61 | /** 62 | * Method wich is called in the context of a working thread 63 | */ 64 | void Execute () =0; 65 | 66 | /** 67 | * send a message to the main loop so that a progress callback can be made 68 | * in the thread of the main loop. 69 | * this is equivalent of asking uv to call notify_progress in the context of the 70 | * main loop in the near future. 71 | */ 72 | void send_notify_progress() { 73 | uv_async_send(&this->async); 74 | }; 75 | 76 | 77 | static NAUV_WORK_CB(AsyncProgress_) { 78 | AsyncWorkerWithProgress *worker = static_cast(async->data); 79 | worker->notify_progress1(); 80 | } 81 | 82 | /** 83 | * 84 | * Note: 85 | * - this method is called in the main loop thread. 86 | * - there is no garanty that this method will be called for each send_notify_progress 87 | */ 88 | void notify_progress1() { 89 | 90 | Nan::HandleScope scope; 91 | if (_progressCallback && !_progressCallback->IsEmpty()) { 92 | v8::Local argv[2] = { 93 | Nan::New(this->m_data.m_progress), 94 | Nan::New((int)this->m_data.m_percent) 95 | }; 96 | _progressCallback->Call(2,argv, async_resource); 97 | } 98 | } 99 | }; -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /test/test_BoundingBox.js: -------------------------------------------------------------------------------- 1 | const occ = require("../lib/occ"); 2 | require("../lib/shapeFactory"); 3 | 4 | 5 | 6 | describe("testing bounding box",function(){ 7 | describe("an empty BoundingBox", function() { 8 | let bbox; 9 | before(function() { 10 | bbox = new occ.BoundingBox(); 11 | }); 12 | it("should be void", function() { 13 | bbox.isVoid.should.equal(true); 14 | }); 15 | }); 16 | describe("an BoundingBox built with a single point in constructor", function() { 17 | let bbox; 18 | before(function() { 19 | bbox = new occ.BoundingBox([10,20,30]); 20 | }); 21 | it("should not be void", function() { 22 | bbox.isVoid.should.equal(false); 23 | }); 24 | it("should have nearPt to be correct", function() { 25 | bbox.nearPt.x.should.equal(10); 26 | bbox.nearPt.y.should.equal(20); 27 | bbox.nearPt.z.should.equal(30); 28 | }); 29 | it("should have farPt to be correct", function() { 30 | bbox.farPt.x.should.equal(10); 31 | bbox.farPt.y.should.equal(20); 32 | bbox.farPt.z.should.equal(30); 33 | }); 34 | }); 35 | describe("adding a single point to an empty bounding box", function(){ 36 | let bbox; 37 | before(function() { 38 | bbox = new occ.BoundingBox(); 39 | bbox.addPoint([10,20,30]); 40 | }); 41 | it("should not be void", function() { 42 | bbox.isVoid.should.equal(false); 43 | }); 44 | it("should have nearPt to be correct", function() { 45 | bbox.nearPt.x.should.equal(10); 46 | bbox.nearPt.y.should.equal(20); 47 | bbox.nearPt.z.should.equal(30); 48 | }); 49 | it("should have farPt to be correct", function() { 50 | bbox.farPt.x.should.equal(10); 51 | bbox.farPt.y.should.equal(20); 52 | bbox.farPt.z.should.equal(30); 53 | }); 54 | }); 55 | describe("checking calling isOut on a empty box",function() { 56 | it("should return isOut = true for any point ",function(){ 57 | let bbox= new occ.BoundingBox(); 58 | bbox.isOut([10,20,30]).should.equal(true); 59 | }); 60 | }); 61 | describe("checking calling isOut this box [-10,-10,-10],[5,5,5]",function() { 62 | let bbox= new occ.BoundingBox([-10,-10,-10],[5,5,5]); 63 | it("should return isOut = true for [10,20,30] ",function(){ 64 | bbox.isOut([10,20,30]).should.equal(true); 65 | }); 66 | it("should return isOut = false for [1,2,3] ",function(){ 67 | bbox.isOut([1,2,3]).should.equal(false); 68 | }); 69 | }); 70 | 71 | 72 | }); 73 | -------------------------------------------------------------------------------- /lib/scriptrunner.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* global require,console,require */ 3 | const fs = require("fs"); 4 | const vm = require("vm"); 5 | const util = require("util"); 6 | const getTemporaryFilePath = require("gettemporaryfilepath"); 7 | const doDebug = false; 8 | 9 | 10 | function ScriptRunner(envparam) { 11 | const self = this; 12 | self.env = { 13 | 14 | 15 | "print": function () { 16 | self.env.console.log.apply(self.env.console, arguments); 17 | }, 18 | 19 | "fnum": function (value, width, prec) { 20 | const a = value.toFixed(prec); 21 | const s = " " + a; 22 | return s.slice(s.length - width); 23 | }, 24 | 25 | "logs": [], 26 | 27 | "console": { 28 | "log": function () { 29 | /// console.log.apply(console,arguments); 30 | self.env.logs.push(arguments); 31 | } 32 | }, 33 | 34 | "eval": function () { 35 | throw new Error("eval is forbidden"); 36 | }, 37 | "require": function () { 38 | throw new Error("require is forbidden"); 39 | }, 40 | "setTimeout": function () { 41 | throw new Error("setTimeout is forbidden"); 42 | }, 43 | "setInterval": function () { 44 | throw new Error("setInterval is forbidden"); 45 | }, 46 | error: null 47 | }; 48 | 49 | // extend default env object with env parameters 50 | Object.keys(envparam).forEach(p => { 51 | if (envparam.hasOwnProperty(p)) { 52 | self.env[p] = envparam[p]; 53 | } 54 | }); 55 | } 56 | 57 | 58 | function getLineNumber() { 59 | const original = Error.prepareStackTrace; 60 | const error = {}; 61 | Error.captureStackTrace(error, getLineNumber); 62 | const lineNumber = error.stack; 63 | Error.prepareStackTrace = original; 64 | return lineNumber; 65 | } 66 | 67 | ScriptRunner.prototype.run = function (code, done_callback, error_callback) { 68 | 69 | const settings = { 70 | prefix: "script", 71 | suffix: ".bar" 72 | }; 73 | 74 | const self = this; 75 | const log = self.env.console.log; 76 | 77 | const filename = getTemporaryFilePath(settings); 78 | 79 | try { 80 | 81 | vm.runInNewContext(code, self.env, filename); 82 | done_callback(); 83 | } 84 | catch (_err) { 85 | 86 | console.trace("\n-------------------------------- EXCEPTION CAUGHT -----------------"); 87 | 88 | log("transaction ended with an error", _err.message); 89 | log("error string = ", _err.toString()); 90 | log("error stack = ", _err.stack); 91 | error_callback(_err); 92 | } 93 | }; 94 | 95 | 96 | exports.ScriptRunner = ScriptRunner; 97 | -------------------------------------------------------------------------------- /src/Point3Wrap.cc: -------------------------------------------------------------------------------- 1 | #include "Point3Wrap.h" 2 | #include "Util.h" 3 | 4 | Nan::Persistent Point3Wrap::_template; 5 | 6 | class Point3Wrap1 : public Point3Wrap 7 | { 8 | gp_XYZ _p; 9 | public: 10 | Point3Wrap1(double x, double y, double z) :_p(x, y, z) {}; 11 | virtual const gp_XYZ get() const { 12 | return _p; 13 | } 14 | }; 15 | // Methods exposed to JavaScripts 16 | NAN_METHOD(Point3Wrap::New) 17 | { 18 | if (!info.IsConstructCall()) { 19 | return Nan::ThrowError(" use new occ.Point() to construct a Point"); 20 | } 21 | 22 | double x, y, z; 23 | ReadDouble(info[0], x); 24 | ReadDouble(info[1], y); 25 | ReadDouble(info[2], z); 26 | 27 | Point3Wrap* pThis = new Point3Wrap1(x,y,z); 28 | pThis->Wrap(info.This()); 29 | 30 | REXPOSE_READ_ONLY_PROPERTY_DOUBLE(Point3Wrap,x); 31 | REXPOSE_READ_ONLY_PROPERTY_DOUBLE(Point3Wrap,y); 32 | REXPOSE_READ_ONLY_PROPERTY_DOUBLE(Point3Wrap,z); 33 | 34 | info.GetReturnValue().Set(info.This()); 35 | } 36 | 37 | NAN_METHOD(Point3Wrap::asArray) 38 | { 39 | Point3Wrap* pThis = Nan::ObjectWrap::Unwrap(info.This()); 40 | v8::Local arr = Nan::New(3); 41 | Nan::Set(arr,0, Nan::New(pThis->x())); 42 | Nan::Set(arr,1, Nan::New(pThis->y())); 43 | Nan::Set(arr,2, Nan::New(pThis->z())); 44 | info.GetReturnValue().Set(arr); 45 | } 46 | NAN_METHOD(Point3Wrap::equals) 47 | { 48 | CHECK_THIS_DEFINED(Point3Wrap); 49 | Point3Wrap* pThis = Nan::ObjectWrap::Unwrap(info.This()); 50 | if (info.Length() == 1) { 51 | gp_Pnt p1; 52 | ReadPoint(info[0], &p1); 53 | bool isEqual = gp_Pnt(pThis->get()).IsEqual(p1, 0.0000001); 54 | return info.GetReturnValue().Set(isEqual); 55 | } 56 | else if (info.Length() == 2) { 57 | gp_Pnt p1; 58 | ReadPoint(info[0], &p1); 59 | 60 | double tol; 61 | ReadDouble(info[1], tol); 62 | 63 | bool isEqual = gp_Pnt(pThis->get()).IsEqual(p1, tol); 64 | 65 | return info.GetReturnValue().Set(isEqual); 66 | } 67 | Nan::ThrowError("Invalid"); 68 | } 69 | 70 | // Methods exposed to JavaScripts 71 | void Point3Wrap::Init(v8::Local target) 72 | { 73 | // Prepare constructor template 74 | v8::Local tpl = Nan::New(Point3Wrap::New); 75 | tpl->SetClassName(Nan::New("Point3D").ToLocalChecked()); 76 | 77 | // object has one internal filed ( the C++ object) 78 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 79 | _template.Reset(tpl); 80 | 81 | // Prototype 82 | v8::Local proto = tpl->PrototypeTemplate(); 83 | 84 | EXPOSE_READ_ONLY_PROPERTY_DOUBLE(Point3Wrap, x); 85 | EXPOSE_READ_ONLY_PROPERTY_DOUBLE(Point3Wrap, y); 86 | EXPOSE_READ_ONLY_PROPERTY_DOUBLE(Point3Wrap, z); 87 | 88 | EXPOSE_METHOD(Point3Wrap, equals); 89 | EXPOSE_METHOD(Point3Wrap, asArray); 90 | 91 | 92 | Nan::Set(target, Nan::New("Point3D").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/Point3Wrap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "NodeV8.h" 3 | #include "OCC.h" 4 | 5 | // expose a point 6 | class Point3Wrap : public Nan::ObjectWrap { 7 | virtual const gp_XYZ get() const = 0; 8 | 9 | double x() { 10 | return get().X(); 11 | } 12 | double y() { 13 | return get().Y(); 14 | } 15 | double z() { 16 | return get().Z(); 17 | } 18 | public: 19 | // Methods exposed to JavaScript 20 | static NAN_METHOD(New); 21 | static NAN_METHOD(equals); 22 | static NAN_METHOD(asArray); 23 | static void Init(v8::Local target); 24 | static Nan::Persistent _template; 25 | }; 26 | 27 | 28 | 29 | #define TEAROFF_INIT(ACCESSOR) m_##ACCESSOR(*this) 30 | 31 | template 32 | class Accessor : public Wrapper { 33 | 34 | // typedef Accessor<_ThisType, Wrapper,CLASS,ACCESSOR> THIS; 35 | _ThisType& m_parent; 36 | 37 | public: 38 | 39 | Accessor(_ThisType& parent) 40 | :m_parent(parent) { 41 | } 42 | 43 | ~Accessor() { 44 | } 45 | 46 | virtual const CLASS get() const { 47 | return (m_parent.*ACCESSOR)(); 48 | } 49 | 50 | static NAN_PROPERTY_GETTER(getter) { 51 | if (info.This().IsEmpty()) { 52 | info.GetReturnValue().SetUndefined(); 53 | return; 54 | } 55 | if (info.This()->InternalFieldCount() == 0) { 56 | info.GetReturnValue().SetUndefined(); 57 | return; 58 | } 59 | _ThisType* pThis = Nan::ObjectWrap::Unwrap<_ThisType>(info.This()); 60 | 61 | info.GetReturnValue().Set(Accessor::NewInstance(*pThis)); 62 | } 63 | static v8::Local NewInstance(_ThisType& parent) { 64 | 65 | auto f = Nan::GetFunction(Nan::New(Wrapper::_template)).ToLocalChecked(); 66 | v8::Local instance = Nan::NewInstance(f).ToLocalChecked(); 67 | 68 | // NewInstance(Nan::GetCurrentContext(),0, 0).ToLocalChecked(); 69 | Accessor* pThis = new Accessor(parent); 70 | pThis->Wrap(instance); 71 | return instance; 72 | } 73 | }; 74 | 75 | 76 | #define TEAROFF_POINT(THISTYPE,ACCESSOR,WRAPPER,CLASS) \ 77 | typedef Accessor t##ACCESSOR; \ 78 | 79 | 80 | 81 | #define EXPOSE_TEAROFF(THISTYPE,ACCESSOR) \ 82 | Nan::SetAccessor(proto, \ 83 | Nan::New(#ACCESSOR).ToLocalChecked(), \ 84 | &t##ACCESSOR::getter, 0,v8::Local(),v8::DEFAULT,(v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete)) 85 | 86 | 87 | #define REXPOSE_TEAROFF(THISTYPE,ACCESSOR) \ 88 | Nan::SetAccessor(info.This(), \ 89 | Nan::New(#ACCESSOR).ToLocalChecked(), \ 90 | &t##ACCESSOR::getter, 0,v8::Local(),v8::DEFAULT,v8::ReadOnly) 91 | 92 | -------------------------------------------------------------------------------- /src/Mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "NodeV8.h" 3 | #include "GeometryBuilder.h" 4 | #include 5 | #include 6 | 7 | struct Coord3f { 8 | float x; 9 | float y; 10 | float z; 11 | Coord3f(float _x, float _y, float _z) :x(_x), y(_y), z(_z) {} 12 | Coord3f() :x(0.0), y(0.0), z(0.0) {} 13 | Coord3f(const gp_Vec& vec) : x((float)vec.X()), y((float)vec.Y()), z((float)vec.Z()) {} 14 | }; 15 | 16 | struct Triangle3i { 17 | uint32_t i; 18 | uint32_t j; 19 | uint32_t k; 20 | }; 21 | class Mesh : public Nan::ObjectWrap { 22 | int extractEdge(const TopoDS_Edge& edge, const occHandle(Poly_Triangulation)& triangulation, const std::vector& translationMap); 23 | int extractEdgeFromFace(const TopoDS_Face& face, const occHandle(Poly_Triangulation)& triangulation, const std::vector& translationMap); 24 | public: 25 | Mesh(); 26 | int extractFaceMesh(const TopoDS_Face& face, bool qualityNormals); 27 | 28 | void optimize(); 29 | 30 | static NAN_METHOD(New); 31 | 32 | static NAN_METHOD(getEdgeIndices); 33 | static NAN_METHOD(getFaceTriangles); 34 | static NAN_METHOD(getFaceTriangleNormals); 35 | 36 | static void Init(v8::Local target); 37 | 38 | private: 39 | 40 | // a set of points to support edges and triangles 41 | std::vector _vertices; 42 | // a set of normals 43 | std::vector _normals; 44 | 45 | std::vector _triangles; 46 | std::vector _triangles_normals; 47 | 48 | std::vector _edgeIndices; 49 | 50 | // an index to quickly find the index of a vertex given its x,y,z coordinates 51 | std::map _mapVertices; 52 | // an index to quickly find the index of a vertex given its x,y,z coordinates 53 | std::map _mapNormals; 54 | 55 | 56 | // ----------------------------------------------------------------------- 57 | std::vector _faceRanges; // [start(0),nb(0),....,start(i),nb(i)] 58 | std::map _faceHashMap; // hash,index 59 | 60 | std::vector _edgeRanges; // [start(0),nb(0),....,start(i),nb(i)] 61 | std::map _edgeHashMap; // hash,index 62 | 63 | friend class MeshOptimizer; 64 | uint32_t push_point(const Coord3f& point); 65 | uint32_t push_normal(const Coord3f& normal); 66 | void updateJavaScriptArray(); 67 | public: 68 | static Nan::Persistent _template; 69 | 70 | uint32_t numTriangles() { 71 | return (uint32_t) _triangles.size(); 72 | } 73 | 74 | int32_t numVertices() { 75 | return (int32_t) _vertices.size(); 76 | } 77 | 78 | int32_t numNormals() { 79 | return (int32_t) _normals.size(); 80 | } 81 | 82 | int32_t numEdges() { 83 | return (int32_t) _edgeIndices.size()>>1; 84 | } 85 | void setErrorMessage(const char* message) { 86 | }; 87 | }; 88 | -------------------------------------------------------------------------------- /src/Shell.cc: -------------------------------------------------------------------------------- 1 | #include "Shell.h" 2 | #include "Face.h" 3 | #include "Wire.h" 4 | #include "Edge.h" 5 | #include "Util.h" 6 | 7 | 8 | const TopoDS_Shape& Shell::shape() const 9 | { 10 | return shell(); 11 | } 12 | 13 | void Shell::setShape(const TopoDS_Shape& shape) 14 | { 15 | m_shell = TopoDS::Shell(shape); 16 | } 17 | 18 | int Shell::numFaces() 19 | { 20 | if (shape().IsNull()) return 0; 21 | TopTools_IndexedMapOfShape anIndices; 22 | TopExp::MapShapes(shape(), TopAbs_FACE, anIndices); 23 | return anIndices.Extent(); 24 | } 25 | 26 | 27 | 28 | double Shell::area() 29 | { 30 | GProp_GProps prop; 31 | BRepGProp::SurfaceProperties(shape(), prop); 32 | return prop.Mass(); 33 | } 34 | 35 | 36 | // DVec Face::inertia() { 37 | // DVec ret; 38 | // GProp_GProps prop; 39 | // BRepGProp::SurfaceProperties(this->getShape(), prop); 40 | // gp_Mat mat = prop.MatrixOfInertia(); 41 | // ret.push_back(mat(1,1)); // Ixx 42 | // ret.push_back(mat(2,2)); // Iyy 43 | // ret.push_back(mat(3,3)); // Izz 44 | // ret.push_back(mat(1,2)); // Ixy 45 | // ret.push_back(mat(1,3)); // Ixz 46 | // ret.push_back(mat(2,3)); // Iyz 47 | // return ret; 48 | //} 49 | // 50 | //OCCStruct3d Face::centreOfMass() { 51 | // OCCStruct3d ret; 52 | // GProp_GProps prop; 53 | // BRepGProp::SurfaceProperties(this->getShape(), prop); 54 | // gp_Pnt cg = prop.CentreOfMass(); 55 | // ret.x = cg.X(); 56 | // ret.y = cg.Y(); 57 | // ret.z = cg.Z(); 58 | // return ret; 59 | //} 60 | // 61 | 62 | 63 | Nan::Persistent Shell::_template; 64 | 65 | 66 | NAN_METHOD(Shell::New) 67 | { 68 | if (!info.IsConstructCall()) { 69 | return Nan::ThrowError(" use new occ.Shell() to construct a Shell"); 70 | } 71 | Shell* pThis = new Shell(); 72 | pThis->Wrap(info.This()); 73 | pThis->InitNew(info); 74 | 75 | info.GetReturnValue().Set(info.This()); 76 | } 77 | 78 | v8::Local Shell::Clone() const 79 | { 80 | Shell* obj = new Shell(); 81 | v8::Local instance = makeInstance(_template); 82 | obj->Wrap(instance); 83 | obj->setShape(this->shape()); 84 | return instance; 85 | } 86 | 87 | void Shell::Init(v8::Local target) 88 | { 89 | // Prepare constructor template 90 | v8::Local tpl = Nan::New(Shell::New); 91 | tpl->SetClassName(Nan::New("Shell").ToLocalChecked()); 92 | 93 | // object has one internal filed ( the C++ object) 94 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 95 | _template.Reset(tpl); 96 | 97 | // Prototype 98 | v8::Local proto = tpl->PrototypeTemplate(); 99 | 100 | Base::InitProto(proto); 101 | 102 | EXPOSE_READ_ONLY_PROPERTY_INTEGER(Shell, numFaces); 103 | EXPOSE_READ_ONLY_PROPERTY_DOUBLE(Shell, area); 104 | 105 | Nan::Set(target, Nan::New("Shell").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); 106 | } 107 | -------------------------------------------------------------------------------- /src/Vertex.cc: -------------------------------------------------------------------------------- 1 | #include "Vertex.h" 2 | 3 | #include "Util.h" 4 | 5 | const TopoDS_Shape& Vertex::shape() const 6 | { 7 | return vertex(); 8 | } 9 | 10 | void Vertex::setShape(const TopoDS_Shape& shape) 11 | { 12 | m_vertex = TopoDS::Vertex(shape); 13 | } 14 | 15 | gp_Pnt Vertex::point() const 16 | { 17 | gp_Pnt pnt = BRep_Tool::Pnt(vertex()); 18 | return pnt; 19 | } 20 | double Vertex::x() 21 | { 22 | return point().X(); 23 | } 24 | double Vertex::y() 25 | { 26 | return point().Y(); 27 | } 28 | double Vertex::z() 29 | { 30 | return point().Z(); 31 | } 32 | 33 | Nan::Persistent Vertex::_template; 34 | 35 | 36 | NAN_METHOD(Vertex::NewInstance) { _NewInstance(info); } 37 | 38 | NAN_METHOD(Vertex::New) 39 | { 40 | if (!info.IsConstructCall()) { 41 | return Nan::ThrowError(" use new occ.Vertex() to construct a Vertex"); 42 | } 43 | 44 | Vertex* pThis = new Vertex(); 45 | pThis->Wrap(info.This()); 46 | pThis->InitNew(info); 47 | 48 | // return scope.Close(args.This()); 49 | double x = 0, y = 0, z = 0; 50 | if (info.Length() == 3) { 51 | ReadDouble(info[0], x); 52 | ReadDouble(info[1], y); 53 | ReadDouble(info[2], z); 54 | } 55 | else if (info.Length() == 1) { 56 | ReadPoint(info[0], &x, &y, &z); 57 | } 58 | else if (info.Length() == 0) { 59 | } 60 | else { 61 | return Nan::ThrowError("Wrong Arguments"); 62 | } 63 | gp_Pnt aPnt; 64 | aPnt = gp_Pnt(x, y, z); 65 | BRepBuilderAPI_MakeVertex mkVertex(aPnt); 66 | pThis->setShape(mkVertex.Vertex()); 67 | 68 | info.GetReturnValue().Set(info.This()); 69 | } 70 | 71 | 72 | v8::Local Vertex::Clone() const 73 | { 74 | Vertex* obj = new Vertex(); 75 | v8::Local instance = makeInstance(_template); 76 | obj->Wrap(instance); 77 | obj->setShape(this->shape()); 78 | return instance; 79 | } 80 | 81 | void Vertex::InitNew(_NAN_METHOD_ARGS) 82 | { 83 | Base::InitNew(info); 84 | REXPOSE_READ_ONLY_PROPERTY_DOUBLE(Vertex,x); 85 | REXPOSE_READ_ONLY_PROPERTY_DOUBLE(Vertex,y); 86 | REXPOSE_READ_ONLY_PROPERTY_DOUBLE(Vertex,z); 87 | } 88 | 89 | void Vertex::Init(v8::Local target) 90 | { 91 | // Prepare constructor template 92 | v8::Local tpl = Nan::New(Vertex::New); 93 | tpl->SetClassName(Nan::New("Vertex").ToLocalChecked()); 94 | 95 | // object has one internal filed ( the C++ object) 96 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 97 | 98 | _template.Reset(tpl); 99 | 100 | // Prototype 101 | v8::Local proto = tpl->PrototypeTemplate(); 102 | 103 | Base::InitProto(proto); 104 | 105 | EXPOSE_READ_ONLY_PROPERTY_DOUBLE(Vertex, x); 106 | EXPOSE_READ_ONLY_PROPERTY_DOUBLE(Vertex, y); 107 | EXPOSE_READ_ONLY_PROPERTY_DOUBLE(Vertex, z); 108 | 109 | Nan::Set(target,Nan::New("Vertex").ToLocalChecked(),Nan::GetFunction(tpl).ToLocalChecked()); 110 | } 111 | 112 | -------------------------------------------------------------------------------- /src/V8Wrapper.cc: -------------------------------------------------------------------------------- 1 | #include "NodeV8.h" 2 | #include "Util.h" 3 | #include "GeometryBuilder.h" 4 | #include "BoundingBox.h" 5 | #include "Solid.h" 6 | #include "Mesh.h" 7 | #include "Edge.h" 8 | #include "Vertex.h" 9 | #include "Wire.h" 10 | #include "Face.h" 11 | #include "Transformation.h" 12 | #include "ShapeIterator.h" 13 | #include "Tools.h" 14 | #include "ShapeFactory.h" 15 | #include "Shell.h" 16 | #include "BooleanOperation.h" 17 | 18 | 19 | 20 | NAN_METHOD(ForceGC) 21 | { 22 | Nan::IdleNotification(100); 23 | } 24 | 25 | void Initialize(v8::Local target) 26 | { 27 | 28 | BoundingBox::Init(target); 29 | Edge::Init(target); 30 | Face::Init(target); 31 | Mesh::Init(target); 32 | Point3Wrap::Init(target); 33 | ShapeIterator::Init(target); 34 | Shell::Init(target); 35 | Solid::Init(target); 36 | Transformation::Init(target); 37 | Vertex::Init(target); 38 | Wire::Init(target); 39 | BooleanOperation::Init(target); 40 | 41 | 42 | Nan::SetMethod(target,"makePlaneMirror", Transformation::makePlaneMirror); 43 | 44 | // Vertex 45 | Nan::SetMethod(target,"makeVertex", ShapeFactory::makeVertex); 46 | 47 | 48 | // edges 49 | Nan::SetMethod(target,"makeLine", Edge::static_createLine); 50 | Nan::SetMethod(target,"makeCircle", Edge::static_createCircle); 51 | Nan::SetMethod(target,"makeArc3P", Edge::static_createArc3P); 52 | 53 | //xx Nan::SetMethod(target,"makeEdge", ShapeFactory::makeEdge); 54 | 55 | Nan::SetMethod(target,"makeWire", ShapeFactory::makeWire); 56 | Nan::SetMethod(target,"makeFace", ShapeFactory::makeFace); 57 | 58 | //---------------------------------------------------------- 59 | Nan::SetMethod(target,"makeBox", ShapeFactory::makeBox); 60 | Nan::SetMethod(target,"makeCylinder", ShapeFactory::makeCylinder); 61 | Nan::SetMethod(target,"makeCone", ShapeFactory::makeCone); 62 | Nan::SetMethod(target,"makeSphere", ShapeFactory::makeSphere); 63 | Nan::SetMethod(target,"makeTorus", ShapeFactory::makeTorus); 64 | Nan::SetMethod(target,"makePrism", ShapeFactory::makePrism); 65 | Nan::SetMethod(target,"makeThickSolid",ShapeFactory::makeThickSolid); 66 | Nan::SetMethod(target,"makeDraftAngle",ShapeFactory::makeDraftAngle); 67 | Nan::SetMethod(target,"makeFillet", ShapeFactory::makeFillet); 68 | // target->Set(NanSymbol("makeChamfer")NanNew(ShapeFactory::makeDraftAngle); 69 | 70 | Nan::SetMethod(target,"fuse", ShapeFactory::fuse); 71 | Nan::SetMethod(target,"cut", ShapeFactory::cut); 72 | Nan::SetMethod(target,"common", ShapeFactory::common); 73 | Nan::SetMethod(target,"compound", ShapeFactory::compound); 74 | 75 | Nan::SetMethod(target,"writeSTL", writeSTL); 76 | Nan::SetMethod(target,"writeSTEP", writeSTEP); 77 | Nan::SetMethod(target,"writeBREP", writeBREP); 78 | Nan::SetMethod(target,"readSTEP", readSTEP); 79 | Nan::SetMethod(target,"readBREP", readBREP); 80 | 81 | //xx Nan::SetMethod(target,"oceVersion",NanNew("0.13")); 82 | Nan::Set(target,Nan::New("oceVersion").ToLocalChecked(), Nan::New("0.13").ToLocalChecked()); 83 | 84 | Nan::SetMethod(target,"gc",ForceGC); 85 | 86 | 87 | } 88 | NODE_MODULE(occ, Initialize) 89 | -------------------------------------------------------------------------------- /test/test_issue17_mesh_not_invalidated_when_face_moved.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const occ = require("../lib/occ"); 3 | const should = require("should"); 4 | 5 | const doDebug = false; 6 | function debugLog() { 7 | if (doDebug) { 8 | console.log.apply(console, arguments); 9 | } 10 | } 11 | describe("issue#17 testing that mesh get invalidated ", function () { 12 | 13 | 14 | function constructFaceWithWire() { 15 | const aPnt1 = [0, 0.0, 0]; 16 | const aPnt2 = [10, 1.0, 0]; 17 | const aPnt3 = [10, 9.0, 0]; 18 | const aPnt4 = [0, 10.0, 0]; 19 | const segment1 = new occ.makeLine(aPnt1, aPnt2); 20 | const segment2 = new occ.makeLine(aPnt2, aPnt3); 21 | const segment3 = new occ.makeLine(aPnt3, aPnt4); 22 | const segment4 = new occ.makeLine(aPnt4, aPnt1); 23 | 24 | const wire = new occ.Wire(segment1, segment2, segment3, segment4); 25 | wire.isClosed.should.equal(true); 26 | wire.numEdges.should.equal(4); 27 | wire.numVertices.should.equal(4); 28 | 29 | // the vector to extrude the face along. 30 | const face = new occ.Face(wire); 31 | 32 | face.getWires().length.should.eql(1); 33 | 34 | face.getWires()[0].getVertices().length.should.eql(4); 35 | return face; 36 | } 37 | 38 | it("should translate a face", function (done) { 39 | let face = constructFaceWithWire(); 40 | 41 | const vertices_before = face.getWires()[0].getVertices(); 42 | 43 | face = face.translate([20, 30, 40]); 44 | const vertices_after = face.getWires()[0].getVertices(); 45 | 46 | vertices_after[0].x.should.eql(vertices_before[0].x + 20); 47 | vertices_after[0].y.should.eql(vertices_before[0].y + 30); 48 | vertices_after[0].z.should.eql(vertices_before[0].z + 40); 49 | 50 | vertices_after[1].x.should.eql(vertices_before[1].x + 20); 51 | vertices_after[1].y.should.eql(vertices_before[1].y + 30); 52 | vertices_after[1].z.should.eql(vertices_before[1].z + 40); 53 | 54 | vertices_after[2].x.should.eql(vertices_before[2].x + 20); 55 | vertices_after[2].y.should.eql(vertices_before[2].y + 30); 56 | vertices_after[2].z.should.eql(vertices_before[2].z + 40); 57 | 58 | vertices_after[3].x.should.eql(vertices_before[3].x + 20); 59 | vertices_after[3].y.should.eql(vertices_before[3].y + 30); 60 | vertices_after[3].z.should.eql(vertices_before[3].z + 40); 61 | 62 | done(); 63 | }); 64 | 65 | it("#17-B should provide a translated mesh when face is translated", function (done) { 66 | 67 | let face = constructFaceWithWire(); 68 | face.hasMesh.should.equal(false); 69 | 70 | // now mesh the faces 71 | face.createMesh(0.1); 72 | face.hasMesh.should.equal(true); 73 | 74 | debugLog("face mesh vertices =", face.mesh.vertices.toString()); 75 | 76 | 77 | const vertices_before = face.mesh.vertices; 78 | face = face.translate([20, 30, 40]); 79 | 80 | debugLog("face mesh vertices =", face.mesh.vertices.toString()); 81 | 82 | const vertices_after = face.mesh.vertices; 83 | 84 | vertices_before.toString().should.eql("0,0,0,10,1,0,10,9,0,0,10,0"); 85 | vertices_after.toString().should.eql("20,30,40,30,31,40,30,39,40,20,40,40"); 86 | done(); 87 | }); 88 | }); 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/Transform.cc: -------------------------------------------------------------------------------- 1 | //#include "NodeV8.h" 2 | // 3 | //#include "Transform.h" 4 | //#include "Util.h" 5 | // 6 | //using namespace std; 7 | // 8 | // 9 | //// 10 | //Transform::Transform(TopoDS_Shape shape) 11 | //{ 12 | // shape_ = shape; 13 | //} 14 | // 15 | // 16 | //TopoDS_Shape RotateTransform::apply( 17 | // double multiplier, 18 | // Handle origin, 19 | // Handle parameters) 20 | //{ 21 | // double x=0,y=0,z=0; 22 | // ReadXYZ(origin,&x,&y,&z); 23 | // 24 | // double u=0,v=0,w=0; 25 | // ReadUVW(parameters,&u,&v,&w); 26 | // 27 | // double angle = ReadDouble(parameters,"angle",0.0); 28 | // 29 | // while (angle > 360) { 30 | // angle -= 360; 31 | // } 32 | // while (angle < 0) { 33 | // angle += 360; 34 | // } 35 | // 36 | // gp_Trsf transformation = gp_Trsf(); 37 | // 38 | // transformation.SetRotation(gp_Ax1(gp_Pnt(x,y,z), gp_Dir(u,v,w)), 39 | // multiplier*angle/180*M_PI); 40 | // 41 | // return BRepBuilderAPI_Transform(shape_, transformation).Shape(); 42 | //} 43 | 44 | //TopoDS_Shape Scale::apply(double multiplier, 45 | // Handle origin, 46 | // Handle parameters) { 47 | // 48 | // double x=0,y=0,z=0; 49 | // ReadXYZ(origin,&x,&y,&z); 50 | // 51 | // double factor = ReadDouble(parameters,"factor"); 52 | // 53 | // gp_Trsf transformation = gp_Trsf(); 54 | // transformation.SetScale(gp_Pnt(x, y, z), factor); 55 | // 56 | // return BRepBuilderAPI_Transform(shape_, transformation).Shape(); 57 | // 58 | //} 59 | 60 | //TopoDS_Shape AxisMirror::apply(double multiplier, 61 | // Handle origin, 62 | // Handle parameters) { 63 | // 64 | // double x=0,y=0,z=0; 65 | // ReadXYZ(origin,&x,&y,&z); 66 | // 67 | // double u=0,v=0,w=0; 68 | // ReadUVW(parameters,&u,&v,&w); 69 | // 70 | // gp_Trsf transformation = gp_Trsf(); 71 | // transformation.SetMirror(gp_Ax1(gp_Pnt(x, y, z), gp_Dir(u, v, w))); 72 | // 73 | // return BRepBuilderAPI_Transform(shape_, transformation).Shape(); 74 | // 75 | //} 76 | //TopoDS_Shape PlaneMirror::apply(double multiplier, 77 | // Handle origin, 78 | // Handle parameters) { 79 | // 80 | // double x=0,y=0,z=0; 81 | // ReadXYZ(origin,&x,&y,&z); 82 | // 83 | // double u=0,v=0,w=0; 84 | // ReadUVW(parameters,&u,&v,&w); 85 | // 86 | // gp_Trsf transformation = gp_Trsf(); 87 | // transformation.SetMirror(gp_Ax2(gp_Pnt(x, y, z), gp_Dir(u, v, w))); 88 | // 89 | // return BRepBuilderAPI_Transform(shape_, transformation).Shape(); 90 | // 91 | //} 92 | 93 | //TopoDS_Shape TranslateTransform::apply(double multiplier, 94 | // Handle origin, 95 | // Handle parameters) { 96 | // 97 | // double u=0,v=0,w=0; 98 | // ReadUVW(parameters,&u,&v,&w); 99 | // 100 | // gp_Trsf transformation = gp_Trsf(); 101 | // transformation.SetTranslation(gp_Vec(multiplier*u, 102 | // multiplier*v, 103 | // multiplier*w)); 104 | // 105 | // return BRepBuilderAPI_Transform(shape_, transformation).Shape(); 106 | // 107 | //} 108 | // 109 | -------------------------------------------------------------------------------- /src/Base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "NodeV8.h" 3 | #include "OCC.h" 4 | #include "Util.h" 5 | #include "vector" 6 | 7 | 8 | class Base : public Nan::ObjectWrap { 9 | public: 10 | int hashCode(); 11 | bool isNull(); 12 | bool isValid(); 13 | const char* shapeType(); 14 | const char* orientation(); 15 | bool fixShape(); 16 | 17 | virtual const TopoDS_Shape& shape() const = 0; 18 | virtual void setShape(const TopoDS_Shape&) = 0; 19 | virtual v8::Local Clone() const = 0; 20 | virtual Base* Unwrap(v8::Local obj) const = 0;// { return node::ObjectWrap::Unwrap(obj); } 21 | 22 | virtual ~Base(); 23 | 24 | virtual void InitNew(_NAN_METHOD_ARGS); 25 | 26 | public: 27 | // Methods exposed to JavaScripts 28 | static NAN_METHOD(translate); 29 | static NAN_METHOD(rotate); 30 | static NAN_METHOD(scale); 31 | static NAN_METHOD(mirror); 32 | static NAN_METHOD(applyTransform); 33 | static NAN_METHOD(transformed); 34 | static NAN_METHOD(fixShape); 35 | static NAN_METHOD(clone); 36 | static NAN_METHOD(getBoundingBox); 37 | 38 | static void InitProto(v8::Local& target); 39 | }; 40 | 41 | v8::Local buildEmptyWrapper(TopAbs_ShapeEnum type); 42 | v8::Local buildWrapper(const TopoDS_Shape shape); 43 | 44 | 45 | template 46 | size_t extractArgumentList(_NAN_METHOD_ARGS, std::vector& elements) 47 | { 48 | elements.reserve(elements.size() + info.Length()); 49 | 50 | for (int i = 0; i < info.Length(); i++) { 51 | if (IsInstanceOf(info[i])) { 52 | 53 | auto o = Nan::To(info[i]).ToLocalChecked(); 54 | 55 | elements.push_back(Nan::ObjectWrap::Unwrap(o)); 56 | } 57 | } 58 | return elements.size(); 59 | } 60 | 61 | template 62 | bool extractArg(const v8::Local& value, ClassType*& pObj) 63 | { 64 | assert(pObj == 0); 65 | if (value.IsEmpty()) return false; 66 | if (!value->IsObject()) return false; 67 | 68 | auto lo = Nan::To(value).ToLocalChecked(); 69 | if (IsInstanceOf(lo)) { 70 | pObj = Nan::ObjectWrap::Unwrap(lo); 71 | return true; 72 | } 73 | return false; 74 | } 75 | 76 | 77 | template 78 | bool _extractArray(const v8::Local& value, std::vector& elements) 79 | { 80 | if (value->IsArray()) { 81 | v8::Local arr = v8::Local::Cast(value); 82 | int length = arr->Length(); 83 | elements.reserve(elements.size() + length); 84 | for (int i = 0; i < length; i++) { 85 | 86 | auto elementI = Nan::Get(arr,i).ToLocalChecked(); 87 | if (!elementI->IsObject()) { 88 | return false; // element is not an object 89 | } 90 | v8::Local obj = Nan::To(elementI).ToLocalChecked(); 91 | if (IsInstanceOf(obj)) { 92 | elements.push_back(Nan::ObjectWrap::Unwrap(obj)); 93 | } 94 | } 95 | } 96 | else if (value->IsObject()) { 97 | // a single element 98 | v8::Local obj = Nan::To(value).ToLocalChecked(); 99 | if (IsInstanceOf(obj)) { 100 | elements.push_back(Nan::ObjectWrap::Unwrap(obj)); 101 | } 102 | } 103 | return elements.size() >= 1; 104 | } 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /src/BooleanOperation.cc: -------------------------------------------------------------------------------- 1 | #include "BooleanOperation.h" 2 | 3 | BooleanOperation::BooleanOperation() 4 | :m_bop(0) 5 | { 6 | } 7 | BooleanOperation::~BooleanOperation() 8 | { 9 | delete m_bop; 10 | } 11 | 12 | Nan::Persistent BooleanOperation::_template; 13 | 14 | 15 | v8::Local BooleanOperation::NewInstance(BOPAlgo_Operation op) 16 | { 17 | 18 | v8::Local instance = makeInstance(_template); 19 | BooleanOperation* pThis = ObjectWrap::Unwrap(instance); 20 | return instance; 21 | } 22 | 23 | 24 | inline bool _isEqual(v8::Local a,const std::string txt) { 25 | return txt == *Nan::Utf8String(a); 26 | } 27 | 28 | BOPAlgo_Operation ReadOperationType(const v8::Local& arg) 29 | { 30 | 31 | v8::Local str = Nan::To(arg).ToLocalChecked(); 32 | if (_isEqual(str,"SECTION")) return BOPAlgo_SECTION; 33 | if (_isEqual(str,"COMMON")) return BOPAlgo_COMMON; 34 | if (_isEqual(str,"FUSE")) return BOPAlgo_FUSE; 35 | if (_isEqual(str,"CUT")) return BOPAlgo_CUT; 36 | if (_isEqual(str,"CUT21")) return BOPAlgo_CUT21; 37 | return BOPAlgo_UNKNOWN; 38 | } 39 | 40 | NAN_METHOD(BooleanOperation::New) 41 | { 42 | if (!info.IsConstructCall()) { 43 | return Nan::ThrowError(" use new occ.BooleanOperation() to construct a BooleanOperation"); 44 | } 45 | 46 | BooleanOperation* pThis = new BooleanOperation(); 47 | pThis->Wrap(info.This()); 48 | 49 | BOPAlgo_Operation op = ReadOperationType(info[0]); 50 | if (op == BOPAlgo_UNKNOWN) { 51 | return Nan::ThrowError("bad operation type, must be SECTION COMMON FUSE CUT or CUT21"); 52 | } 53 | 54 | info.GetReturnValue().Set(info.This()); 55 | } 56 | 57 | /* 58 | Handle BooleanOperation::getSameShape1(const v8::Arguments& args) 59 | { 60 | 61 | HandleScope scope; 62 | // can work with this 63 | Handle pJhis = args.This(); 64 | if ( pJhis.IsEmpty() || !constructor->HasInstance(pJhis)) { 65 | // create a new object 66 | ThrowException(Exception::Error(String::New("invalid object"))); 67 | } 68 | BooleanOperation* pThis = Nan::ObjectWrap::Unwrap(pJhis); 69 | 70 | 71 | return scope.Close(arr); 72 | } 73 | Handle BooleanOperation_getSameShape2(const v8::Arguments& args) 74 | { 75 | } 76 | */ 77 | 78 | void BooleanOperation::Init(v8::Local target) 79 | { 80 | 81 | // Prepare constructor template 82 | v8::Local tpl = Nan::New(BooleanOperation::New); 83 | tpl->SetClassName(Nan::New("BooleanOperation").ToLocalChecked()); 84 | 85 | // object has one internal filed ( the C++ object) 86 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 87 | 88 | _template.Reset(tpl); 89 | 90 | 91 | // Prototype 92 | //xx Local proto = constructor->PrototypeTemplate(); 93 | // xx Base::InitProto(proto); 94 | //xx EXPOSE_READ_ONLY_PROPERTY_INTEGER(Face,numWires); 95 | //xx EXPOSE_READ_ONLY_PROPERTY_DOUBLE(Face,area); 96 | //XX EXPOSE_METHOD(BooleanOperation,getSameShape1); 97 | //XX EXPOSE_METHOD(BooleanOperation,getSameShape2); 98 | //XX EXPOSE_READ_ONLY_PROPERTY(BooleanOperation,_shape1,shape1); 99 | //XX EXPOSE_READ_ONLY_PROPERTY(BooleanOperation,_shape2,shape2); 100 | 101 | Nan::Set(target, Nan::New("BooleanOperation").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); 102 | } 103 | -------------------------------------------------------------------------------- /src/BoundingBox.cc: -------------------------------------------------------------------------------- 1 | #include "BoundingBox.h" 2 | 3 | #include "Util.h" 4 | #include 5 | 6 | Nan::Persistent BoundingBox::_template; 7 | 8 | 9 | v8::Local BoundingBox::NewInstance(const Bnd_Box& box) 10 | { 11 | 12 | v8::Local instance = makeInstance(_template); 13 | 14 | BoundingBox* pThis = ObjectWrap::Unwrap(instance); 15 | 16 | pThis->m_box = box; 17 | 18 | return instance; 19 | } 20 | 21 | v8::Local BoundingBox::NewInstance(const gp_Pnt& nearPt,const gp_Pnt& farPt) 22 | { 23 | Bnd_Box box; 24 | box.Add(nearPt); 25 | box.Add(farPt); 26 | return NewInstance(box); 27 | } 28 | 29 | void BoundingBox::Update(BoundingBox* pThis,_NAN_METHOD_ARGS) 30 | { 31 | // info could be one or several points 32 | // or a array of point 33 | for (int i=0; iIsArray()) { 35 | v8::Local arr = v8::Local::Cast(info[i]); 36 | 37 | v8::Local element0 = Nan::Get(arr,0).ToLocalChecked(); 38 | 39 | if ( element0->IsArray() || element0->IsObject()) { 40 | // probably an array of point 41 | } else { 42 | // a single point 43 | gp_Pnt point; 44 | ReadPoint(info[i],&point); 45 | pThis->m_box.Update(point.X(),point.Y(),point.Z()); 46 | } 47 | } 48 | } 49 | } 50 | 51 | 52 | NAN_METHOD(BoundingBox::New) 53 | { 54 | if (!info.IsConstructCall()) { 55 | return Nan::ThrowError(" use new occ.BoundingBox() to construct a BoundingBox"); 56 | } 57 | 58 | BoundingBox* pThis = new BoundingBox(); 59 | pThis->Wrap(info.This()); 60 | 61 | BoundingBox::Update(pThis,info); 62 | pThis->InitNew(info); 63 | 64 | info.GetReturnValue().Set(info.This()); 65 | 66 | } 67 | 68 | NAN_METHOD(BoundingBox::addPoint) 69 | { 70 | 71 | BoundingBox* pThis = ObjectWrap::Unwrap(info.This()); 72 | BoundingBox::Update(pThis,info); 73 | 74 | info.GetReturnValue().Set(info.This()); 75 | } 76 | 77 | bool checkCoerceToPoint(const v8::Local& v) 78 | { 79 | // TODO ... 80 | return true; 81 | } 82 | 83 | NAN_METHOD(BoundingBox::isOut) 84 | { 85 | 86 | BoundingBox* pThis = ObjectWrap::Unwrap(info.This()); 87 | bool _itOut = false; 88 | 89 | if (info.Length() != 1 || !checkCoerceToPoint(info[0])) { 90 | return Nan::ThrowError(" error expecting a point or a arrya of 3 doubles"); 91 | } 92 | gp_Pnt point; 93 | ReadPoint(info[0],&point); 94 | 95 | bool retVal = pThis->m_box.IsOut(point) ? true : false; 96 | 97 | info.GetReturnValue().Set(Nan::New(retVal)); 98 | } 99 | 100 | 101 | void BoundingBox::Init(v8::Local target) 102 | { 103 | // Prepare constructor template 104 | v8::Local tpl = Nan::New(BoundingBox::New); 105 | tpl->SetClassName(Nan::New("BoundingBox").ToLocalChecked()); 106 | 107 | // object has one internal filed ( the C++ object) 108 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 109 | 110 | _template.Reset(tpl); 111 | 112 | // Prototype 113 | v8::Local proto = tpl->PrototypeTemplate(); 114 | 115 | EXPOSE_METHOD(BoundingBox,addPoint); 116 | EXPOSE_METHOD(BoundingBox,isOut); 117 | 118 | EXPOSE_TEAROFF(BoundingBox,nearPt); 119 | EXPOSE_TEAROFF(BoundingBox,farPt); 120 | EXPOSE_READ_ONLY_PROPERTY_BOOLEAN(BoundingBox,isVoid); 121 | 122 | Nan::Set(target, Nan::New("BoundingBox").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); 123 | } 124 | 125 | void BoundingBox::InitNew(_NAN_METHOD_ARGS) 126 | { 127 | //xx Base::InitNew(info); 128 | REXPOSE_TEAROFF(BoundingBox,nearPt); 129 | REXPOSE_TEAROFF(BoundingBox,farPt); 130 | } -------------------------------------------------------------------------------- /test1.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var assert = require('assert'); 3 | 4 | var occ = require('./'); 5 | 6 | 7 | function testOuterShell() 8 | { 9 | var solid1 = occ.makeBox([10,20,30],[20,40,60]); 10 | var solid2 = occ.makeBox([15,25,35],[-20,-40,-60]); 11 | var solid = occ.fuse(solid1,solid2); 12 | 13 | 14 | solid1 = occ.makeBox([0,0,0],[20,20,20]); 15 | solid2 = occ.makeBox([10,10,10],[15,15,15]); 16 | solid = occ.cut(solid1,solid2); 17 | 18 | solid.getOuterShell(); 19 | 20 | var shells = solid.getShells(); 21 | for (var i in shells) { 22 | var shell = shells[i]; 23 | console.log(shell.shapeType,shell.numFaces); 24 | } 25 | } 26 | testOuterShell(); 27 | 28 | console.log("-------------------"); 29 | 30 | function testCyl() 31 | { 32 | var cyl =occ.makeCylinder([-100,20,30],[100,20,30],40); 33 | 34 | } 35 | testCyl(); 36 | 37 | var shapeFactory = require('./lib/shapeFactory.js'); 38 | 39 | function testCSG1() 40 | { 41 | var solid = shapeFactory.makePan(occ); 42 | } 43 | testCSG1(); 44 | 45 | 46 | var bbox = new occ.BoundingBox(); 47 | console.log(bbox.nearPt); 48 | console.log(bbox.nearPt.x); 49 | 50 | //var bottle = shapeFactory.makeBottle(); 51 | 52 | function test3() 53 | { 54 | solid = occ.makeBox([10,20,30],[20,40,60]); 55 | solid = occ.makeFillet(solid,solid.getEdges(),2); 56 | 57 | } 58 | test3(); 59 | 60 | function test2(){ 61 | var trsf ; 62 | trsf=new occ.Transformation(); 63 | trsf.makePlaneMirror([10,20,30],occ.ZDir); 64 | 65 | console.log(" Scale Factor=",trsf.scaleFactor); 66 | 67 | } 68 | test2(); 69 | 70 | function test1() { 71 | var solid; 72 | var shapeIt; 73 | 74 | solid = occ.makeBox([10,20,30],[20,40,60]); 75 | 76 | shapeIt = new occ.ShapeIterator(solid,"FACE"); 77 | shapeIt.more.should.be.true; 78 | assert(shapeIt.current === undefined); 79 | 80 | } 81 | test1(); 82 | 83 | 84 | 85 | var wire = new occ.Wire(); 86 | console.log(wire.numEdges); 87 | console.log(wire.numVertices); 88 | 89 | var trsf; 90 | trsf = new occ.Transformation(); 91 | trsf.makePlaneMirror([10,20,30],occ.ZDir); 92 | 93 | 94 | 95 | 96 | var v = new occ.Vertex(); 97 | var e = new occ.Edge().createLine([10,20,30],[10,14,15]); 98 | console.log(e.length) 99 | 100 | edge = new occ.Edge(); 101 | edge.createCircle([10,10,10],[0,0,1],20); 102 | 103 | 104 | console.log("hello"); 105 | 106 | var box1 = new occ.Solid(); 107 | 108 | assert(box1.isNull); 109 | assert(!box1.isValid); 110 | 111 | box1 = occ.makeBox([10,20,30],[30,40,50]); 112 | 113 | //xx for (var i in box1.mesh) { 114 | //xx console.log( " i=",i," => ", box1.mesh[i]); 115 | //xx } 116 | console.log("---------------!!!"); 117 | 118 | console.log( " i=",i," => ", box1.mesh.vertices); 119 | 120 | assert(!box1.isNull); 121 | assert(box1.isValid); 122 | 123 | var box2 = occ.makeBox([10,20,30],[100,100,100]); 124 | var box3 = occ.makeBox([10,20,30],100,100,100); 125 | 126 | //xx console.log("box1.x",box1.location.x); 127 | //xx console.log("box1.x",box1.location.y); 128 | //xx console.log("box1.x",box1.location.z); 129 | //xx console.log("cuboid",JSON.stringify(box1)); 130 | 131 | 132 | var solid = occ.makeBox([10,20,30],[20,30,40]); 133 | 134 | 135 | for ( var i in solid) { 136 | console.log(" i = ", i, " => " , solid[i]); 137 | } 138 | 139 | var expected = ["isNull","area","volume","numFaces","numSolids","isValid","rotate","fuse"]; 140 | 141 | for ( var j in occ.Solid.prototype) { 142 | console.log(" j = ", j, " => " , occ.Solid.prototype[j]); 143 | } 144 | 145 | 146 | console.log("------------------"); 147 | 148 | 149 | 150 | console.log("JSON =",solid.mesh.toJSON()); 151 | 152 | 153 | occ.writeSTEP("toto.STEP",solid); 154 | 155 | console.log("Done"); 156 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------- 2 | # 3 | # --------------------------------------------------------------------------------- 4 | init: 5 | - git config --global core.autocrlf input 6 | 7 | environment: 8 | 9 | node_pre_gyp_accessKeyId: 10 | secure: 6NwB/CPB/FsDOcPZUoJIQQc751Vkj3LYc2oPxGXo/Uw= 11 | node_pre_gyp_secretAccessKey: 12 | secure: FcV0jIJp3lNZR/6fGNf8xNjZ13s2pkubaYlmtFkplZYfGQgSPguUMS/CqjjRWteD 13 | NODE_PRE_GYP_GITHUB_TOKEN: 14 | secure: qa898q4P1jnKsCJ507wNDTaQV52i/qDV0mp9DxsC321ZujDEZDvHKR+pOqRT6GJY 15 | 16 | # these variables are common to all jobs 17 | # -------------- 14 Visual Studio 2015 18 | # msvs_toolset: 14 19 | # -------------- 12 VisualStudio 2013 20 | msvs_toolset: 12 21 | VisualStudioVersion: "12" 22 | matrix: 23 | 24 | - electron_version: "7.3.2" 25 | nodejs_version: 12 26 | platform: x64 27 | 28 | # - electron_version: "8.5.0" // not working yet =< GetBackingStore missing 29 | # nodejs_version: 12 30 | # platform: x64 31 | 32 | # - electron_version: "9.2.0" 33 | # nodejs_version: 12 34 | # platform: x64 35 | 36 | - nodejs_version: 8 37 | platform: x64 38 | 39 | - nodejs_version: 10 40 | platform: x64 41 | 42 | - nodejs_version: 12 43 | platform: x64 44 | 45 | - nodejs_version: 14 46 | platform: x64 47 | 48 | # - electron_version: "1.4.14" 49 | # nodejs_version: 6 50 | # platform: x86 51 | 52 | # - electron_version: "1.4.14" 53 | # nodejs_version: 6 54 | # platform: x64 55 | 56 | # - electron_version: "1.6.10" 57 | # nodejs_version: 6 58 | # platform: x86 59 | 60 | # - electron_version: "1.6.10" 61 | # nodejs_version: 6 62 | # platform: x64 63 | 64 | 65 | 66 | # clone directory 67 | clone_folder: c:\projects\node-occ 68 | 69 | clone_depth: 5 70 | 71 | matrix: 72 | fast_finish: false 73 | allow_failures: 74 | - nodejs_version: 7 75 | 76 | 77 | install: 78 | #- ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) $env:platform; 79 | - ps: Install-Product node $env:nodejs_version $env:platform; 80 | - ps: $env:Path += ";$(pwd)\node_modules\.bin"; 81 | 82 | # Check if we're building the latest tag, if so 83 | # then we publish the binaries if tests pass. 84 | - ps: > 85 | if ($env:appveyor_repo_tag -match "true" -and ("$(git describe --tags --always HEAD)" -eq $env:appveyor_repo_tag_name)) { 86 | $env:publish_binary = 1; 87 | } else { 88 | $env:publish_binary = 0; 89 | } 90 | true; 91 | - ps: > 92 | if ($env:publish_binary -eq 1) { 93 | "We're publishing a binary!" | Write-Host 94 | } else { 95 | "We're not publishing a binary" | Write-Host 96 | } 97 | true; 98 | 99 | 100 | - cmd: npm install mocha@7 https://github.com/OpenWebCAD/node-pre-gyp-github.git -g 101 | - cmd: setenv.bat 64 102 | - cmd: build.bat %PLATFORM% 103 | 104 | 105 | build_script: 106 | - cmd: node --version 107 | # - npm install --build-from-source --target_arch=%npm_config_arch% 108 | 109 | cache: 110 | # - c:\projects\node-occ\occt-7.1.0 111 | 112 | 113 | configuration: 114 | - Release 115 | 116 | test_script: 117 | - IF DEFINED electron_version (electron test_electron) 118 | - IF NOT DEFINED electron_version (npm test) 119 | 120 | after_test: 121 | - IF %PUBLISH_BINARY% == 1 (node-pre-gyp package 2>&1) 122 | - # IF %PUBLISH_BINARY% == 1 (node-pre-gyp publish 2>&1) 123 | - # IF %PUBLISH_BINARY% == 1 (node-pre-gyp-github publish --release 2>&1) 124 | - IF %PUBLISH_BINARY% == 1 (node-pre-gyp-github publish) 125 | - # IF %PUBLISH_BINARY% == 1 (node-pre-gyp-github publish 2>&1) 126 | - IF %PUBLISH_BINARY% == 1 (node-pre-gyp clean) 127 | - IF %PUBLISH_BINARY% == 1 (npm install --fallback-to-build=false) 128 | 129 | deploy: off 130 | 131 | build: off 132 | -------------------------------------------------------------------------------- /test/test_ReadWriteSTEP.js: -------------------------------------------------------------------------------- 1 | /*eslint-env node mocha*/ 2 | /*global require*/ 3 | // test_STEP 4 | const assert = require("assert"); 5 | require("should"); 6 | const occ = require("../lib/occ"); 7 | 8 | 9 | 10 | const getTemporaryFilePath = require("./helpers").getTemporaryFilePath; 11 | const remove_file = require("./helpers").remove_file; 12 | 13 | describe("testing STEP input output ", function () { 14 | 15 | let b1_step, b2_step, b3_step; 16 | 17 | before(function () { 18 | 19 | b1_step = getTemporaryFilePath({prefix: "b1_", suffix: ".step"}); 20 | b2_step = getTemporaryFilePath({prefix: "b2_", suffix: ".step"}); 21 | b3_step = getTemporaryFilePath({prefix: "b3_", suffix: ".step"}); 22 | 23 | let box = occ.makeBox([0, 0, 0], [100, 200, 300]); 24 | let b1 = occ.writeSTEP(b1_step, box); 25 | 26 | 27 | let cyl = occ.makeCylinder([0, 0, 0], [0, 0, 10], 5); 28 | let b2 = occ.writeSTEP(b2_step, cyl); 29 | let b3 = occ.writeSTEP(b3_step, [box, cyl]); 30 | 31 | b1.should.eql(true); 32 | b2.should.eql(true); 33 | b3.should.eql(true); 34 | }); 35 | after(function () { 36 | remove_file(b1_step); 37 | remove_file(b2_step); 38 | remove_file(b3_step); 39 | }); 40 | 41 | it("AZ0 - should write a simple shape", function (done) { 42 | let box = occ.makeBox([0, 0, 0], [100, 200, 300]); 43 | let b1 = occ.writeSTEP(b1_step, box); 44 | done(); 45 | }); 46 | 47 | it("AZ1 - readSTEP with callback ", function (done) { 48 | 49 | let callback_called = 0; 50 | occ.readSTEP(b3_step, (err, shapes) => { 51 | console.log(err,shapes); 52 | shapes.length.should.equal(2); 53 | shapes[0].numFaces.should.equal(6); 54 | shapes[1].numFaces.should.equal(3); 55 | callback_called.should.be.greaterThan(-1); 56 | done(); 57 | }, function callback(message, percent) { 58 | callback_called++; 59 | }); 60 | }); 61 | 62 | 63 | it("AZ2 - should raise an exception with invalid arguments", function () { 64 | (function () { 65 | occ.readSTEP(); 66 | }).should.throwError(); 67 | 68 | (function () { 69 | occ.readSTEP("filename"); 70 | }).should.throwError(); 71 | 72 | }); 73 | 74 | it("AZ3 - should call the callback with an error if the file doesn't exist", function (done) { 75 | 76 | occ.readSTEP("invalid file name", function (err, shapes) { 77 | err.message.should.match(/invalid file name/); 78 | done(); 79 | }); 80 | }); 81 | it("AZ4 - should read file one", function (done) { 82 | 83 | occ.readSTEP(b1_step, function (err, shapes) { 84 | if (err) { 85 | console.log(" err = ", err, shapes); 86 | } 87 | assert(!err); 88 | shapes.length.should.equal(1); 89 | shapes[0].numFaces.should.equal(6); 90 | done(); 91 | }); 92 | }); 93 | 94 | it("AZ5 - should read file two", function (done) { 95 | 96 | occ.readSTEP(b2_step, function (err, shapes) { 97 | if (err) { 98 | console.log(" err = ", err, shapes); 99 | } 100 | assert(!err); 101 | shapes.length.should.equal(1); 102 | shapes[0].numFaces.should.equal(3); 103 | done(); 104 | }); 105 | 106 | }); 107 | it("AZ6 - should read file three", function (done) { 108 | occ.readSTEP(b3_step, function (err, shapes) { 109 | if (err) { 110 | console.log(" err = ", err, shapes); 111 | } 112 | assert(!err); 113 | shapes.length.should.equal(2); 114 | shapes[0].numFaces.should.equal(6); 115 | shapes[1].numFaces.should.equal(3); 116 | done(); 117 | }); 118 | }); 119 | 120 | }); 121 | -------------------------------------------------------------------------------- /src/Util.cc: -------------------------------------------------------------------------------- 1 | #include "Util.h" 2 | 3 | #include "vector" 4 | 5 | using namespace std; 6 | 7 | 8 | void ReadPropertyPointFromArray(v8::Local arr, double* x, double* y, double*z) 9 | { 10 | Nan::HandleScope scope; 11 | 12 | double defaultValue =0.0; 13 | int length = arr->Length(); 14 | if (length >= 1) { 15 | auto element0 = Nan::Get(arr,0).ToLocalChecked(); 16 | *x = Nan::To(element0).FromMaybe(defaultValue); 17 | } 18 | if (length >= 2) { 19 | auto element1 = Nan::Get(arr,1).ToLocalChecked(); 20 | *y = Nan::To(element1).FromMaybe(defaultValue); 21 | } 22 | if (length >= 3) { 23 | auto element2 = Nan::Get(arr,2).ToLocalChecked(); 24 | *z = Nan::To(element2).FromMaybe(defaultValue); 25 | } 26 | 27 | } 28 | 29 | 30 | //void ReadPropertyPoint(Handle obj,const char* name,double* x,double* y, double*z ) 31 | //{ 32 | // if (!obj.IsEmpty()) { 33 | // // for exemple a THREE.Vector3 34 | // // ( we try to read the "x","y","z" property ) 35 | // Handle v = obj->Get(String::New(name)); 36 | // return ReadPropertyPointFromArray(v->ToObject(),x,y,z); 37 | // } 38 | // //xx if (obj->IsArray()) { 39 | // //xx ReadPropertyPointFromArray(value,x,y,z); 40 | // //xx } 41 | //} 42 | 43 | void ReadDouble(const v8::Local& _v, double& value) 44 | { 45 | 46 | value = 0.0; 47 | if (_v->IsNumber()) { 48 | value = extract_double(_v); 49 | } 50 | } 51 | void ReadDouble(v8::Local value, const char* name, double* retValue,double defaultValue) 52 | { 53 | Nan::HandleScope scope; 54 | auto propertyName = Nan::New(name).ToLocalChecked(); 55 | v8::Local _v = Nan::Get(value, propertyName).ToLocalChecked(); 56 | *retValue= Nan::To(_v).FromMaybe(defaultValue); 57 | } 58 | 59 | void ReadInt(v8::Local value, const char* name,int* retValue, int defaultValue) 60 | { 61 | Nan::HandleScope scope; 62 | 63 | auto o =Nan::To(value).ToLocalChecked(); 64 | 65 | v8::Local _v = Nan::Get(o,Nan::New(name).ToLocalChecked()).ToLocalChecked(); 66 | 67 | *retValue = Nan::To(_v).FromMaybe(defaultValue); 68 | } 69 | 70 | void ReadXYZ(v8::Local obj, double* x, double* y, double* z) 71 | { 72 | ReadDouble(obj, "x", x, 0.0); 73 | ReadDouble(obj, "y", y, 0.0); 74 | ReadDouble(obj, "z", z, 0.0); 75 | } 76 | 77 | void ReadPoint(v8::Local value, double* x, double* y, double*z) 78 | { 79 | 80 | if (value->IsArray()) { 81 | v8::Local arr = v8::Local::Cast(value); 82 | ReadPropertyPointFromArray(arr, x, y, z); 83 | } else if (value->IsObject()) { 84 | // object must have x,y,z property set 85 | v8::Local obj = v8::Local::Cast(value); 86 | ReadXYZ(obj, x, y, z); 87 | } else { 88 | Nan::ThrowError("Invalid Point or Vector ( must be a [] or a {x:..,y:.., z:...} )"); 89 | } 90 | } 91 | 92 | void ReadUVW(v8::Local obj, double* x, double* y, double* z) 93 | { 94 | ReadDouble(obj, "u", x, 0.0); 95 | ReadDouble(obj, "v", y, 0.0); 96 | ReadDouble(obj, "w", z, 0.0); 97 | } 98 | 99 | 100 | void ReadPoint(v8::Local value, gp_Pnt* pt) 101 | { 102 | double x = 0, y = 0, z = 0; 103 | ReadPoint(value, &x, &y, &z); 104 | pt->SetCoord(x, y, z); 105 | } 106 | void ReadDir(v8::Local value, gp_Dir* pt) 107 | { 108 | double x = 0, y = 0, z = 1.0; 109 | ReadPoint(value, &x, &y, &z); 110 | pt->SetCoord(x, y, z); 111 | } 112 | 113 | void ReadVector(v8::Local value, gp_Vec* pt) 114 | { 115 | double x = 0, y = 0, z = 0; 116 | ReadPoint(value, &x, &y, &z); 117 | pt->SetCoord(x, y, z); 118 | } 119 | 120 | void ReadRotationFromArgs(_NAN_METHOD_ARGS, gp_Trsf& trans) 121 | { 122 | 123 | double x = 0, y = 0, z = 0; 124 | ReadPoint(info[0], &x, &y, &z); 125 | 126 | double u = 0, v = 0, w = 0; 127 | ReadPoint(info[1], &u, &v, &w); 128 | 129 | double angle = extract_double(info[2]); 130 | 131 | trans.SetRotation(gp_Ax1(gp_Pnt(x, y, z), gp_Dir(u, v, w)), angle / 180.0*M_PI); 132 | } 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-occ 2 | 3 | OpenCascade NodeJS package for solid modeling. 4 | 5 | This package provides _solid construction_ to NodeJS. 6 | It provides a simple yet powerful javascript api to construct 3D geometry models. 7 | 8 | This project comes with a set of V8 wrappers around OpenCascade API and a sample web application. 9 | 10 | [![Build status](https://ci.appveyor.com/api/projects/status/s5eaux89v2c0wmu4?svg=true)](https://ci.appveyor.com/project/erossignon/node-occ-6ktv4) 11 | 12 | ### quick example 13 | 14 | ```javascript 15 | var occ = require("node-occ").occ; 16 | 17 | // construct a box 18 | var box = occ.makeBox([0, 0, 0], [100, 100, 50]); 19 | 20 | // construct a cylinder 21 | var cyl = occ.makeCylinder([50, 50, -10], [50, 50, 60], 40); 22 | 23 | // cut the box with cylinder 24 | box = occ.cut(box, cyl); 25 | 26 | // save result to a STEP file 27 | occ.writeSTEP("somefile.step", box); 28 | ``` 29 | 30 | ### video 31 | 32 | node occ 34 | 35 | ### list of features 36 | 37 | - creation of basic shapes ( box, cylinder , cone , torus ) 38 | - boolean operation ( fuse , common , cut ) 39 | - features ( draftAngle) 40 | - solid properties ( faces, edges, vertices, area , volume ) 41 | - import export ( STEP BREP ) 42 | 43 | ### sample web application 44 | 45 | [node-occ-sample](https://github.com/erossignon/node-occ-sample): sample nodejs/express REST API server to build solid , based on threejs 46 | 47 | ## installing node-occ from npm 48 | 49 | ``` 50 | $npm install node-occ 51 | ``` 52 | 53 | ## building node-occ from source : prerequisites 54 | 55 | #### on (linux Ubuntu 56 | 57 | (use nodejs 12 or 14) 58 | 59 | ```bash 60 | # installing nodejs and gyp utility to build extensions 61 | sudo apt-get install nodejs npm 62 | sudo npm install node-pre-gyp -g 63 | sudo npm install mocha@7 -g 64 | 65 | #installing cmake 66 | sudo apt-get install cmake cmake-curses-gui g++ build-essential libtbb2 67 | 68 | # ------------------------------------ 69 | git clone --recursive https://github.com/erossignon/node-occ.git 70 | cd node-occ 71 | 72 | # download prebuild OpenCascade Library and header files 73 | bash ./prepare_node.sh 74 | 75 | # 76 | export OCCT_PACKAGE=occt-7.2.0 77 | export LD_LIBRARY_PATH=`pwd`/${OCCT_PACKAGE}/lib:$LD_LIBRARY_PATH 78 | npm install --build-from-source 79 | 80 | # verify that everything is working OK 81 | make test 82 | ``` 83 | 84 | ### on windows 85 | 86 | - follow the tutorial in the [wiki](https://github.com/erossignon/node-occ/wiki) 87 | 88 | ## dependencies: 89 | 90 | - threejs : https://github.com/mrdoob/three.js 91 | 92 | ## acknowledgment: 93 | 94 | - OpenCascade : http://www.opencascade.org 95 | - occmodel : https://github.com/tenko/occmodel 96 | - ShapeSmith : https://github.com/bjnortier/shapesmith 97 | 98 | ## MIT License 99 | 100 | Copyright © 2012-2022 E. Rossignon 101 | Copyright © 2022 Sterfive SAS 102 | 103 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 104 | 105 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 106 | 107 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 108 | -------------------------------------------------------------------------------- /test/test_relativePerformanceBREPSTEP.js: -------------------------------------------------------------------------------- 1 | const occ = require("../lib/occ"); 2 | const should = require("should"); 3 | const async = require("async"); 4 | const path = require("path"); 5 | 6 | const ProgressBar = require("progress"); 7 | const remove_file = require("./helpers").remove_file; 8 | 9 | function myReadStep(filename, done) { 10 | 11 | 12 | let brep_filename = require("./helpers").getTemporaryFilePath({suffix: ".brep"}); 13 | 14 | let bar = new ProgressBar("reading file [:bar] :percent elapsed :elapseds ETA :etas", { 15 | complete: "=", 16 | incomplete: "-", 17 | width: 100, 18 | total: 1000 19 | }); 20 | 21 | let solids = []; 22 | 23 | function progressFunc(percent) { 24 | bar.tick(percent); 25 | } 26 | 27 | function performMesh(solids) { 28 | let bar = new ProgressBar("meshing solids [:bar] :percent elapsed :elapseds ETA :etas", { 29 | complete: "=", 30 | incomplete: "-", 31 | width: 100, 32 | total: solids.length 33 | }); 34 | for (let i in solids) { 35 | bar.tick(); 36 | let solid = solids[i]; 37 | solid.numFaces.should.be.greaterThan(1); 38 | 39 | solid.name = "solid_" + i; 40 | try { 41 | occ.buildSolidMesh(solid); 42 | let mesh = solid.mesh; 43 | solid.mesh.numVertices.should.be.greaterThan(3); 44 | } 45 | catch (err) { 46 | 47 | } 48 | } 49 | console.log("\n"); 50 | } 51 | 52 | 53 | function chrono(async_func, message, callback) { 54 | 55 | let t1, t2, elapsed; 56 | t1 = new Date(); 57 | 58 | async_func(function (err) { 59 | 60 | t2 = new Date(); 61 | elapsed = Math.round((t2 - t1) / 10) / 100; 62 | 63 | console.log("\ndone " + message + " in ", elapsed, " seconds"); 64 | callback(err); 65 | }); 66 | } 67 | 68 | 69 | function read_original_step_file(callback) { 70 | 71 | 72 | t1 = new Date(); 73 | occ.readSTEP(filename, function (err, _solids) { 74 | solids = _solids; 75 | if (err) { 76 | return callback(new Error(" readStep returned error = " + err.message + " while reading " + filename + " _solids =", _solids.length)); 77 | } else { 78 | console.log(" read ", solids.length, " solids"); 79 | } 80 | callback(err); 81 | }, progressFunc); 82 | 83 | } 84 | 85 | function perform_mesh_on_solids(callback) { 86 | 87 | 88 | // make sure we have a mesh, so it can be saved in the BREP file 89 | performMesh(solids); 90 | callback(); 91 | } 92 | 93 | function write_solids_to_brep(callback) { 94 | occ.writeBREP(brep_filename, solids); 95 | callback(); 96 | } 97 | 98 | function read_brep_file_again(callback) { 99 | occ.readBREP(brep_filename, function (err, _solids) { 100 | if (!err) { 101 | solids = _solids; 102 | console.log(" nb solids = ", solids.length); 103 | } 104 | return callback(err); 105 | }, progressFunc); 106 | } 107 | 108 | async.series([ 109 | 110 | chrono.bind(null, read_original_step_file, "read_original_step_file"), 111 | chrono.bind(null, perform_mesh_on_solids, "perform_mesh_on_solids"), 112 | chrono.bind(null, write_solids_to_brep, "write_solids_to_brep"), 113 | chrono.bind(null, read_brep_file_again, "read_brep_file_again"), 114 | chrono.bind(null, perform_mesh_on_solids, "perform_mesh_on_solids"), 115 | 116 | function (callback) { 117 | remove_file(brep_filename, callback); 118 | } 119 | ], done); 120 | 121 | } 122 | 123 | // myReadStep("test/kuka.stp"); 124 | describe("testing relative performance of BREP and STEP I/O", function () { 125 | this.timeout(40000); 126 | it("should read kuka robot", function (done) { 127 | let filename = path.join(__dirname, "kuka.stp"); 128 | myReadStep(filename, done); 129 | }); 130 | }); 131 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | # 18.04 3 | dist: bionic 4 | # - focal 5 | 6 | os: 7 | - linux 8 | - osx 9 | osx_image: xcode12 10 | 11 | # we use travis container based infrastructure 12 | # https://docs.travis-ci.com/user/installing-dependencies/#Installing-Packages-on-Container-Based-Infrastructure 13 | # sudo: required 14 | 15 | env: 16 | matrix: 17 | # - TRAVIS_NODE_VERSION="6" 18 | #- TRAVIS_NODE_VERSION="6" ARCH="x86" 19 | # - TRAVIS_NODE_VERSION="7" 20 | #- TRAVIS_NODE_VERSION="7" ARCH="x86" 21 | #- TRAVIS_ELECTRON_VERSION="1.4.14" TRAVIS_NODE_VERSION="6" 22 | - TRAVIS_NODE_VERSION="8" 23 | - TRAVIS_NODE_VERSION="9" 24 | - TRAVIS_NODE_VERSION="10" 25 | - TRAVIS_NODE_VERSION="11" 26 | - TRAVIS_NODE_VERSION="12" 27 | - TRAVIS_NODE_VERSION="13" 28 | - TRAVIS_NODE_VERSION="14" 29 | 30 | matrix: 31 | exclude: 32 | - os: osx 33 | env: TRAVIS_NODE_VERSION="6" 34 | - os: osx 35 | env: TRAVIS_NODE_VERSION="6" ARCH="x86" 36 | - os: osx 37 | env: TRAVIS_NODE_VERSION="7" 38 | - os: osx 39 | env: TRAVIS_NODE_VERSION="8" 40 | - os: osx 41 | env: TRAVIS_NODE_VERSION="9" 42 | #- os: osx 43 | # env: TRAVIS_NODE_VERSION="7" ARCH="x86" 44 | allow_failures: 45 | - os: osx 46 | 47 | addons: 48 | apt: 49 | sources: 50 | - sourceline: 'ppa:ubuntu-toolchain-r/test' 51 | - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' 52 | key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' 53 | packages: 54 | - g++ 55 | - libtbb2 56 | - libtbb-dev 57 | update: true 58 | homebrew: 59 | packages: 60 | - tbb 61 | - freetype 62 | - opencascade 63 | update: true 64 | 65 | before_install: 66 | - > 67 | if [[ $TRAVIS_OS_NAME == "linux" ]]; then 68 | cat /etc/apt/sources.list 69 | sudo add-apt-repository universe 70 | sudo add-apt-repository multiverse 71 | sudo apt-add-repository -y ppa:freecad-maintainers/freecad-daily 72 | sudo apt-get update -qq 73 | sudo apt-get install -y --no-install-recommends libocct-data-exchange-dev 74 | fi 75 | 76 | # reinstall latest nvm 77 | - rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh 78 | - nvm install $TRAVIS_NODE_VERSION 79 | - PATH=$PATH:`pwd`/node_modules/.bin 80 | - BASE_URL=$(node -p "'https://nodejs.org/dist/' + process.version") 81 | - X86_FILE=$(node -p "'node-' + process.version + '-' + process.platform + '-x86'") 82 | # download node if testing x86 architecture 83 | - > 84 | if [[ "$ARCH" == "x86" ]]; then 85 | wget -q $BASE_URL/$X86_FILE.tar.gz 86 | tar -xf $X86_FILE.tar.gz 87 | export PATH=$X86_FILE/bin:$PATH 88 | ls $X86_FILE/bin 89 | echo " PATH =" $PATH 90 | fi; 91 | true; 92 | 93 | # print versions 94 | - uname -a 95 | - file `which node` 96 | - node --version 97 | - node -p 'process.platform + "@" + process.arch' 98 | - npm --version 99 | 100 | # use g++ on linux 101 | - if [[ $TRAVIS_OS_NAME == "linux" ]]; then export CXX=g++; fi 102 | - $CXX --version 103 | - npm install -g https://github.com/OpenWebCAD/node-pre-gyp-github.git node-pre-gyp 104 | 105 | # compile Node-OCC 106 | - bash ./prepare_node.sh 107 | 108 | git: 109 | submodules: false 110 | 111 | install: 112 | - npm install --build-from-source 113 | 114 | script: 115 | - > 116 | if [[ -z $TRAVIS_ELECTRON_VERSION ]]; then 117 | # export LD_LIBRARY_PATH=`pwd`/occt-7.2.0/lib 118 | # export DYLD_LIBRARY_PATH=`pwd`/occt-7.2.0/lib 119 | node ./ 120 | npm test 121 | else 122 | electron test_electron 123 | electron_mocha test 124 | fi; 125 | true; 126 | 127 | # if publishing, do it 128 | # Figure out if we should publish 129 | - PUBLISH_BINARY=false 130 | # If we are building a tag then we need to publish a new binary package 131 | - if [[ $TRAVIS_BRANCH == `git describe --tags --always HEAD` ]]; then PUBLISH_BINARY=true; fi; 132 | # or if we put the string [publish binary] in the commit message 133 | - if test "${COMMIT_MESSAGE#*'[publish binary]'}" != "$COMMIT_MESSAGE"; then PUBLISH_BINARY=true; fi; 134 | - if [[ $PUBLISH_BINARY == true ]]; then node-pre-gyp package; fi; 135 | - if [[ $PUBLISH_BINARY == true ]]; then node-pre-gyp-github publish --release; fi; 136 | 137 | # cleanup 138 | - node-pre-gyp clean 139 | 140 | cache: 141 | directories: 142 | - build_oce 143 | -------------------------------------------------------------------------------- /src/Transformation.cc: -------------------------------------------------------------------------------- 1 | #include "Transformation.h" 2 | #include "Util.h" 3 | 4 | template 5 | Transformation* prepare(T& info) { 6 | Transformation* pThis = DynamicCast(info.This()); 7 | if (pThis) { 8 | info.GetReturnValue().Set(info.This()); 9 | } 10 | else { 11 | v8::Local instance = Nan::NewInstance(Constructor()).ToLocalChecked(); 12 | pThis = Transformation::Unwrap(instance); 13 | info.GetReturnValue().Set(instance); 14 | } 15 | return pThis; 16 | } 17 | 18 | NAN_METHOD(Transformation::makeTranslation) 19 | { 20 | if( info.Length()!=1) { 21 | return Nan::ThrowError("Wrong arguments"); 22 | } 23 | Transformation* pThis = prepare(info); 24 | 25 | double x=0,y=0,z=0; 26 | ReadPoint(info[0],&x,&y,&z); 27 | 28 | pThis->m_trsf.SetTranslation(gp_Vec(x,y,z)); 29 | } 30 | 31 | #include "Base.h" 32 | 33 | 34 | NAN_METHOD(Transformation::makePlaneMirror) 35 | { 36 | 37 | if (info.Length() != 2) { 38 | return Nan::ThrowError("Wrong arguments"); 39 | } 40 | Transformation* pThis = prepare(info); 41 | 42 | double x=0,y=0,z=0; 43 | ReadPoint(info[0],&x,&y,&z); 44 | 45 | double u=0,v=0,w=0; 46 | ReadPoint(info[1],&u,&v,&w); 47 | 48 | std::cout << " pThis->m_trsf ) "<< x << y << z << u << v << w << "\n"; 49 | 50 | Standard_Real D = sqrt (u * u + v * v + w * w); 51 | if (D <= gp::Resolution()) { 52 | return Nan::ThrowError("Plane Axis direction is null"); 53 | } 54 | pThis->m_trsf.SetMirror(gp_Ax2(gp_Pnt(x, y, z), gp_Dir(u, v, w))); 55 | 56 | } 57 | 58 | 59 | NAN_METHOD(Transformation::makeAxisMirror) 60 | { 61 | if (info.Length() != 2) { 62 | return Nan::ThrowError("Wrong arguments"); 63 | } 64 | Transformation* pThis = prepare(info); 65 | 66 | double x=0,y=0,z=0; 67 | ReadPoint(info[0],&x,&y,&z); 68 | 69 | double u=0,v=0,w=0; 70 | ReadPoint(info[1],&u,&v,&w); 71 | 72 | Standard_Real D = sqrt (u * u + v * v + w * w); 73 | if (D <= gp::Resolution()) { 74 | return Nan::ThrowError("Lirror Axis direction is null"); 75 | } 76 | 77 | pThis->m_trsf.SetMirror(gp_Ax1(gp_Pnt(x, y, z), gp_Dir(u, v, w))); 78 | 79 | } 80 | 81 | NAN_METHOD(Transformation::makeScale) 82 | { 83 | if (info.Length() != 2) { 84 | return Nan::ThrowError("Wrong arguments"); 85 | } 86 | 87 | Transformation* pThis = prepare(info); 88 | 89 | double factor= Nan::To(info[0]).FromJust(); 90 | double x=0,y=0,z=0; 91 | ReadPoint(info[1],&x,&y,&z); 92 | 93 | pThis->m_trsf.SetScale(gp_Pnt(x, y, z), factor); 94 | 95 | } 96 | 97 | 98 | 99 | NAN_METHOD(Transformation::makeRotation) 100 | { 101 | if(info.Length()!=3) { 102 | return Nan::ThrowError("Wrong arguments in makeRotation"); 103 | } 104 | Transformation* pThis = prepare(info); 105 | ReadRotationFromArgs(info, pThis->m_trsf); 106 | } 107 | 108 | // Methods exposed to JavaScripts 109 | Nan::Persistent Transformation::_template; 110 | 111 | void Transformation::Init(v8::Local target) 112 | { 113 | v8::Local tpl = Nan::New(Transformation::New); 114 | // Prepare constructor template 115 | tpl->SetClassName(Nan::New("Transformation").ToLocalChecked()); 116 | 117 | // object has one internal filed ( the C++ object) 118 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 119 | 120 | //xx NanAssignPersistent(_template,tpl); 121 | _template.Reset(tpl); 122 | 123 | // Prototype 124 | v8::Local proto = tpl->PrototypeTemplate(); 125 | 126 | EXPOSE_METHOD(Transformation,makeRotation); 127 | EXPOSE_METHOD(Transformation,makeTranslation); 128 | EXPOSE_METHOD(Transformation,makePlaneMirror); 129 | EXPOSE_METHOD(Transformation,makeAxisMirror); 130 | EXPOSE_METHOD(Transformation,makeScale); 131 | EXPOSE_READ_ONLY_PROPERTY_DOUBLE(Transformation,scaleFactor); 132 | 133 | Nan::Set(target,Nan::New("Transformation").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); 134 | } 135 | 136 | NAN_METHOD(Transformation::New) 137 | { 138 | if (!info.IsConstructCall()) { 139 | return Nan::ThrowError(" use new occ.Transformation() to construct a transformation"); 140 | } 141 | 142 | Transformation* pThis = new Transformation(); 143 | pThis->Wrap(info.This()); 144 | info.GetReturnValue().Set(info.This()); 145 | 146 | REXPOSE_READ_ONLY_PROPERTY_DOUBLE(Transformation,scaleFactor); 147 | 148 | } 149 | 150 | NAN_METHOD(Transformation::NewInstance) 151 | { 152 | v8::Local instance = makeInstance(_template); 153 | info.GetReturnValue().Set(instance); 154 | } 155 | -------------------------------------------------------------------------------- /src/Transform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | //#include "NodeV8.h" 3 | // 4 | //#include "OCC.h" 5 | // 6 | //using namespace std; 7 | // 8 | // 9 | //template 10 | //class Transformer { 11 | // 12 | //public: 13 | // Transformer(TopoDS_Shape shape, 14 | // Handle origin, 15 | // Handle parameters) 16 | // { 17 | // transformed_shape_ = apply(shape, origin, parameters); 18 | // } 19 | // 20 | // TopoDS_Shape transformed_shape() 21 | // { 22 | // return transformed_shape_; 23 | // } 24 | // 25 | // 26 | //private: 27 | // TopoDS_Shape transformed_shape_; 28 | // 29 | // template 30 | // 31 | // static TopoDS_Shape apply(TopoDS_Shape shape, 32 | // Handle origin, 33 | // Handle parameters) 34 | // { 35 | // int n = ReadInt(parameters,"n",0); 36 | // 37 | // // the number of time we want to apply the transform 38 | // if(n == 0) { 39 | // auto_ptr transform(new T(shape)); 40 | // return transform->apply(1.0, origin, parameters); 41 | // } 42 | // 43 | // vector copies(n+1); 44 | // copies[0] = shape; 45 | // 46 | // int remaining = n; 47 | // int grouping = 1; 48 | // float multiplier = 1.0; 49 | // int index = 1; 50 | // 51 | // while (remaining > 0) { 52 | // 53 | // int group_index = (int)(log((double)grouping)/log(2.0)); 54 | // TopoDS_Shape shape_to_copy = copies[group_index]; 55 | // 56 | // auto_ptr transform(new T(shape_to_copy)); 57 | // TopoDS_Shape transformedShape = transform->apply(multiplier, origin, parameters); 58 | // 59 | // copies[index] = BRepAlgoAPI_Fuse(transformedShape, copies[index - 1]).Shape(); 60 | // 61 | // multiplier = multiplier + grouping; 62 | // remaining = remaining - grouping; 63 | // ++index; 64 | // 65 | // if ((grouping * 2) < remaining) { 66 | // grouping = grouping * 2; 67 | // } else if (grouping > remaining) { 68 | // grouping = grouping / 2; 69 | // } 70 | // } 71 | // 72 | // return copies[index - 1]; 73 | // } 74 | // 75 | // 76 | //}; 77 | // 78 | //class Transform { 79 | //protected: 80 | // TopoDS_Shape shape_; 81 | //public: 82 | // Transform(TopoDS_Shape shape); 83 | // virtual ~Transform() {}; 84 | // 85 | // virtual TopoDS_Shape apply(double multiplier, 86 | // Handle origin, 87 | // Handle parameters) = 0; 88 | //}; 89 | // 90 | //class RotateTransform : public Transform { 91 | // 92 | //public: 93 | // RotateTransform(TopoDS_Shape shape) : Transform(shape) {} 94 | // virtual ~RotateTransform() {}; 95 | // 96 | // virtual TopoDS_Shape apply(double multiplier, 97 | // Handle origin, 98 | // Handle parameters); 99 | //}; 100 | // 101 | // 102 | //class Scale : public Transform { 103 | // 104 | //public: 105 | // Scale(TopoDS_Shape shape) : Transform(shape) {} 106 | // virtual ~Scale() {}; 107 | // 108 | // virtual TopoDS_Shape apply(double multiplier, 109 | // Handle origin, 110 | // Handle parameters); 111 | //}; 112 | // 113 | //class AxisMirror : public Transform { 114 | // 115 | //public: 116 | // AxisMirror(TopoDS_Shape shape) : Transform(shape) {} 117 | // virtual ~AxisMirror() {}; 118 | // 119 | // virtual TopoDS_Shape apply(double multiplier, 120 | // Handle origin, 121 | // Handle parameters); 122 | //}; 123 | // 124 | //class PlaneMirror : public Transform { 125 | // 126 | //public: 127 | // PlaneMirror(TopoDS_Shape shape) : Transform(shape) {} 128 | // virtual ~PlaneMirror() {}; 129 | // 130 | // virtual TopoDS_Shape apply(double multiplier, 131 | // Handle origin, 132 | // Handle parameters); 133 | //}; 134 | // 135 | //class TranslateTransform : public Transform { 136 | // 137 | //public: 138 | // TranslateTransform(TopoDS_Shape shape) : Transform(shape) {} 139 | // virtual ~TranslateTransform() {}; 140 | // 141 | // virtual TopoDS_Shape apply(double multiplier, 142 | // Handle origin, 143 | // Handle parameters); 144 | //}; 145 | // 146 | -------------------------------------------------------------------------------- /src/Wire.cc: -------------------------------------------------------------------------------- 1 | #include "Wire.h" 2 | 3 | 4 | int Wire::numVertices() 5 | { 6 | if (this->wire().IsNull()) return 0; 7 | TopTools_IndexedMapOfShape anIndices; 8 | TopExp::MapShapes(this->wire(), TopAbs_VERTEX, anIndices); 9 | return anIndices.Extent(); 10 | } 11 | 12 | int Wire::numEdges() 13 | { 14 | if (this->wire().IsNull()) return 0; 15 | TopTools_IndexedMapOfShape anIndices; 16 | TopExp::MapShapes(this->wire(), TopAbs_EDGE, anIndices); 17 | return anIndices.Extent(); 18 | } 19 | 20 | bool Wire::isClosed() 21 | { 22 | if (this->wire().IsNull()) return false; 23 | TopoDS_Vertex aV1, aV2; 24 | TopExp::Vertices(this->wire(), aV1, aV2); 25 | if (!aV1.IsNull() && !aV2.IsNull() && aV1.IsSame(aV2)) 26 | return true; 27 | return false; 28 | } 29 | 30 | 31 | const TopoDS_Shape& Wire::shape() const 32 | { 33 | return m_wire; 34 | } 35 | void Wire::setShape(const TopoDS_Shape& shape) 36 | { 37 | 38 | m_wire = TopoDS::Wire(shape); 39 | } 40 | 41 | Nan::Persistent Wire::_template; 42 | 43 | 44 | const char* toString(BRepBuilderAPI_WireError err) 45 | { 46 | switch (err) { 47 | case BRepBuilderAPI_WireDone: 48 | return "the wire is done"; 49 | break; 50 | case BRepBuilderAPI_EmptyWire: 51 | return "the wire is empty"; 52 | break; 53 | case BRepBuilderAPI_DisconnectedWire: 54 | return "the wire is disconnected"; 55 | break; 56 | case BRepBuilderAPI_NonManifoldWire: 57 | return "the wire is non-manifold"; 58 | break; 59 | } 60 | return ""; 61 | } 62 | 63 | 64 | NAN_METHOD(Wire::NewInstance) { _NewInstance(info); } 65 | 66 | 67 | 68 | NAN_METHOD(Wire::New) 69 | { 70 | if (!info.IsConstructCall()) { 71 | return Nan::ThrowError(" use new occ.Wire() to construct a Wire"); 72 | } 73 | 74 | Wire* pThis = new Wire(); 75 | pThis->Wrap(info.This()); 76 | pThis->InitNew(info); 77 | 78 | if (info.Length() == 0) { 79 | // this is a empty wire 80 | info.GetReturnValue().Set(info.This()); 81 | return; 82 | } 83 | 84 | BRepBuilderAPI_MakeWire mkWire; 85 | 86 | //Xx Standard_Boolean statusIsDone = false; 87 | 88 | BRepBuilderAPI_WireError err = BRepBuilderAPI_WireDone; 89 | 90 | for (int i = 0; i < info.Length(); i++) { 91 | 92 | Edge* edge = DynamicCast(info[i]); 93 | Wire* wire = DynamicCast(info[i]); 94 | 95 | if (edge) { 96 | // IsInstanceOf(info[i]->ToObject())) { 97 | //xx Edge* edge = Nan::ObjectWrap::Unwrap(info[i]->ToObject()); 98 | mkWire.Add(edge->edge()); 99 | 100 | //Xx statusIsDone = mkWire.IsDone(); 101 | err = mkWire.Error(); 102 | } else if (wire) { 103 | mkWire.Add(wire->wire()); 104 | //Xx statusIsDone = mkWire.IsDone(); 105 | err = mkWire.Error(); 106 | } 107 | } 108 | 109 | err = mkWire.Error(); 110 | if (BRepBuilderAPI_WireDone == err) { 111 | pThis->setShape(mkWire.Wire()); 112 | } else { 113 | std::string mesg = std::string("Invalid Wire err:=") + toString(mkWire.Error()); 114 | return Nan::ThrowError(mesg.c_str()); 115 | } 116 | info.GetReturnValue().Set(info.This()); 117 | } 118 | 119 | v8::Local Wire::Clone() const 120 | { 121 | Wire* obj = new Wire(); 122 | v8::Local instance = makeInstance(_template); 123 | obj->Wrap(instance); 124 | obj->setShape(this->shape()); 125 | return instance; 126 | } 127 | 128 | NAN_METHOD(Wire::InitNew) 129 | { 130 | Base::InitNew(info); 131 | REXPOSE_READ_ONLY_PROPERTY_INTEGER(Wire, numVertices); 132 | REXPOSE_READ_ONLY_PROPERTY_INTEGER(Wire, numEdges); 133 | REXPOSE_READ_ONLY_PROPERTY_BOOLEAN(Wire, isClosed); 134 | } 135 | 136 | void Wire::Init(v8::Local target) 137 | { 138 | // Prepare constructor template 139 | v8::Local tpl = Nan::New(Wire::New); 140 | tpl->SetClassName(Nan::New("Wire").ToLocalChecked()); 141 | 142 | // object has one internal filed ( the C++ object) 143 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 144 | 145 | _template.Reset(tpl); 146 | 147 | // Prototype 148 | v8::Local proto = tpl->PrototypeTemplate(); 149 | 150 | Base::InitProto(proto); 151 | 152 | EXPOSE_METHOD(Wire,getEdges); 153 | EXPOSE_METHOD(Wire,getVertices); 154 | EXPOSE_READ_ONLY_PROPERTY_INTEGER(Wire, numVertices); 155 | EXPOSE_READ_ONLY_PROPERTY_INTEGER(Wire, numEdges); 156 | EXPOSE_READ_ONLY_PROPERTY_BOOLEAN(Wire, isClosed); 157 | 158 | Nan::Set(target,Nan::New("Wire").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); 159 | } 160 | 161 | NAN_METHOD(Wire::getEdges) 162 | { 163 | Wire* pThis = UNWRAP(Wire); 164 | auto arr = extract_shapes_as_javascript_array(pThis,TopAbs_EDGE); 165 | info.GetReturnValue().Set(arr); 166 | } 167 | NAN_METHOD(Wire::getVertices) 168 | { 169 | Wire* pThis = UNWRAP(Wire); 170 | auto arr = extract_shapes_as_javascript_array(pThis,TopAbs_VERTEX); 171 | info.GetReturnValue().Set(arr); 172 | } 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /src/ShapeIterator.cc: -------------------------------------------------------------------------------- 1 | #include "ShapeIterator.h" 2 | #include "Solid.h" 3 | #include "Face.h" 4 | #include "Wire.h" 5 | #include "Edge.h" 6 | #include "Vertex.h" 7 | #include "Shell.h" 8 | 9 | 10 | v8::Local buildEmptyWrapper(TopAbs_ShapeEnum type) 11 | { 12 | switch (type) { 13 | case TopAbs_COMPOUND: 14 | case TopAbs_COMPSOLID: 15 | case TopAbs_SOLID: 16 | return makeInstance(Solid::_template); 17 | case TopAbs_SHELL: 18 | return makeInstance(Shell::_template); 19 | break; 20 | case TopAbs_FACE: 21 | return makeInstance(Face::_template); 22 | case TopAbs_WIRE: 23 | return makeInstance(Wire::_template); 24 | case TopAbs_EDGE: 25 | return makeInstance(Edge::_template); 26 | case TopAbs_VERTEX: 27 | return makeInstance(Vertex::_template); 28 | case TopAbs_SHAPE: 29 | break; 30 | } 31 | return v8::Local(); 32 | } 33 | v8::Local buildWrapper(const TopoDS_Shape shape) 34 | { 35 | v8::Local obj = v8::Local(buildEmptyWrapper(shape.ShapeType())); 36 | Base* pShape = Nan::ObjectWrap::Unwrap(obj); 37 | pShape->setShape(shape); 38 | return obj; 39 | } 40 | 41 | bool ShapeIterator::more() 42 | { 43 | return ex.More() ? true : false; 44 | } 45 | 46 | v8::Local ShapeIterator::next() 47 | { 48 | if (ex.More()) { 49 | 50 | v8::Local obj = buildWrapper(ex.Current()); 51 | Nan::Set(this->handle(), Nan::New("current").ToLocalChecked(), obj); 52 | ex.Next(); 53 | return obj; 54 | } 55 | else { 56 | return Nan::Undefined(); 57 | } 58 | } 59 | 60 | NAN_METHOD(ShapeIterator::next) 61 | { 62 | ShapeIterator* pThis = UNWRAP(ShapeIterator); 63 | info.GetReturnValue().Set(pThis->next()); 64 | } 65 | 66 | 67 | void ShapeIterator::reset() 68 | { 69 | ex.ReInit(); 70 | } 71 | 72 | 73 | NAN_METHOD(ShapeIterator::reset) 74 | { 75 | ShapeIterator* pThis = UNWRAP(ShapeIterator); 76 | pThis->reset(); 77 | info.GetReturnValue().Set(info.This()); 78 | } 79 | 80 | Nan::Persistent ShapeIterator::_template; 81 | 82 | void ShapeIterator::Init(v8::Local target) 83 | { 84 | // Prepare constructor template 85 | v8::Local tpl = Nan::New(ShapeIterator::New); 86 | tpl->SetClassName(Nan::New("ShapeIterator").ToLocalChecked()); 87 | 88 | // object has one internal filed ( the C++ object) 89 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 90 | 91 | _template.Reset(tpl); 92 | 93 | // Prototype 94 | v8::Local proto = tpl->PrototypeTemplate(); 95 | 96 | Base::InitProto(proto); 97 | 98 | EXPOSE_READ_ONLY_PROPERTY_BOOLEAN(ShapeIterator, more); 99 | 100 | EXPOSE_METHOD(ShapeIterator, next); 101 | EXPOSE_METHOD(ShapeIterator, reset); 102 | 103 | Nan::Set(target,Nan::New("ShapeIterator").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); 104 | 105 | } 106 | 107 | 108 | TopAbs_ShapeEnum getShapeEnum(const v8::Local arg) 109 | { 110 | if (arg->IsString()) { 111 | 112 | v8::Local str = Nan::To(arg).ToLocalChecked(); 113 | 114 | if (Nan::Equals(str, Nan::New("COMPOUND").ToLocalChecked()).ToChecked()) { 115 | return TopAbs_COMPOUND; 116 | } 117 | if (Nan::Equals(str, Nan::New("COMPSOLID").ToLocalChecked()).ToChecked()) { 118 | return TopAbs_COMPSOLID; 119 | } 120 | if (Nan::Equals(str, Nan::New("VERTEX").ToLocalChecked()).ToChecked()) { 121 | return TopAbs_VERTEX; 122 | } 123 | if (Nan::Equals(str, Nan::New("EDGE").ToLocalChecked()).ToChecked()) { 124 | return TopAbs_EDGE; 125 | } 126 | if (Nan::Equals(str, Nan::New("WIRE").ToLocalChecked()).ToChecked()) { 127 | return TopAbs_WIRE; 128 | } 129 | if (Nan::Equals(str, Nan::New("FACE").ToLocalChecked()).ToChecked()) { 130 | return TopAbs_FACE; 131 | } 132 | if (Nan::Equals(str, Nan::New("SHELL").ToLocalChecked()).ToChecked()) { 133 | return TopAbs_SHELL; 134 | } 135 | if (Nan::Equals(str, Nan::New("SOLID").ToLocalChecked()).ToChecked()) { 136 | return TopAbs_SOLID; 137 | } 138 | } 139 | return TopAbs_SHAPE; 140 | }; 141 | 142 | NAN_METHOD(ShapeIterator::New) 143 | { 144 | 145 | if (!info.IsConstructCall()) { 146 | return Nan::ThrowError(" use new occ.ShapeIterator() to construct a ShapeIterator"); 147 | } 148 | 149 | if (info.Length() != 2) { 150 | return Nan::ThrowError(" expecting two arguments : ,<'VERTEX'|'WIRE'|'SOLID'|'FACE'...>"); 151 | } 152 | 153 | // TODO (check that the object info[0] has the correct type) 154 | Base* pShape = Nan::ObjectWrap::Unwrap(Nan::To(info[0]).ToLocalChecked()); 155 | 156 | TopAbs_ShapeEnum type = getShapeEnum(info[1]); 157 | 158 | ShapeIterator* pThis = new ShapeIterator(pShape, type); 159 | 160 | Nan::Set(info.This(),Nan::New("current").ToLocalChecked(), Nan::Undefined()); 161 | 162 | pThis->Wrap(info.This()); 163 | 164 | info.GetReturnValue().Set(info.This()); 165 | } 166 | 167 | -------------------------------------------------------------------------------- /src/OCC.h: -------------------------------------------------------------------------------- 1 | // OpenCASCADE 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "BSplCLib.hxx" 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | //#include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | 51 | #include 52 | #include 53 | 54 | #include 55 | 56 | //xx #include 57 | 58 | #include 59 | #include 60 | #include 61 | 62 | #include 63 | 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | 70 | #include 71 | #include 72 | #include 73 | 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | 81 | 82 | 83 | 84 | #include 85 | #include 86 | 87 | #include 88 | #include 89 | 90 | #include 91 | 92 | 93 | #include 94 | #include 95 | 96 | #include "Message_ProgressIndicator.hxx" 97 | 98 | //xx #include 99 | 100 | #include 101 | #include 102 | #include 103 | 104 | #include 105 | #include 106 | #include 107 | 108 | #include 109 | #include 110 | 111 | //xx #include 112 | 113 | // #include 114 | 115 | #include 116 | #include 117 | #include 118 | #include 119 | 120 | #include 121 | //xx #include 122 | 123 | #include 124 | #include 125 | 126 | #include 127 | #include 128 | 129 | #include 130 | #include 131 | #include 132 | #include 133 | #include 134 | #include 135 | #include 136 | #include 137 | #include 138 | #include 139 | #include 140 | #include 141 | #include 142 | #include 143 | #include 144 | #include 145 | #include 146 | #include 147 | //xx #include 148 | //xx #include 149 | //xx #include 150 | //xx #include 151 | #include 152 | 153 | #include 154 | #include 155 | #include 156 | #include 157 | 158 | // Compatibility 6.5 and above 159 | #if (OCC_VERSION_MAJOR * 10 + OCC_VERSION_MINOR ) < 66 160 | 161 | // this makes some adjustemnts to make sure node-occ can be 162 | // build with older version of OCC. 163 | #include 164 | #define BOPAlgo_Operation BOP_Operation 165 | #define BOPAlgo_SECTION BOP_SECTION 166 | #define BOPAlgo_COMMON BOP_COMMON 167 | #define BOPAlgo_FUSE BOP_FUSE 168 | #define BOPAlgo_CUT BOP_CUT 169 | #define BOPAlgo_CUT21 BOP_CUT21 170 | #define BOPAlgo_UNKNOWN BOP_UNKNOWN 171 | #define OUTER_SHELL(x) BRepTools::OuterShell(x) 172 | #else 173 | 174 | #include 175 | #define OUTER_SHELL(x) BRepClass3d::OuterShell(x) 176 | #endif 177 | 178 | #undef Handle 179 | -------------------------------------------------------------------------------- /test/test_BREP.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const should = require("should"); 3 | const shape_factory = require("../lib/shapeFactory"); 4 | const occ = require("../lib/occ"); 5 | const fs = require("fs"); 6 | 7 | 8 | const getTemporaryFilePath = require("./helpers").getTemporaryFilePath; 9 | const remove_file = require("./helpers").remove_file; 10 | 11 | 12 | describe("testing BREP input output ", function () { 13 | 14 | let b1_brep, b2_brep, b3_brep; 15 | let b1_volume = 0; 16 | let b1_area = 0; 17 | before(function () { 18 | 19 | b1_brep = getTemporaryFilePath({prefix: "b1_", suffix: ".brep"}); 20 | b2_brep = getTemporaryFilePath({prefix: "b2_", suffix: ".brep"}); 21 | b3_brep = getTemporaryFilePath({prefix: "b3_", suffix: ".brep"}); 22 | 23 | create_shapes(); 24 | 25 | }); 26 | after(function (done) { 27 | remove_file(b1_brep); 28 | remove_file(b2_brep); 29 | remove_file(b3_brep); 30 | done(); 31 | }); 32 | 33 | function create_shapes() { 34 | 35 | let box = occ.makeBox([0, 0, 0], [100, 200, 300]); 36 | let b1_result = occ.writeBREP(b1_brep, box); 37 | b1_volume = box.volume; 38 | b1_area = box.area; 39 | 40 | let cyl = occ.makeCylinder([0, 0, 0], [0, 0, 10], 5); 41 | let b2_result = occ.writeBREP(b2_brep, cyl); 42 | 43 | let b3_result = occ.writeBREP(b3_brep, [box, cyl]); 44 | 45 | b1_result.should.eql(true); 46 | b2_result.should.eql(true); 47 | b3_result.should.eql(true); 48 | 49 | } 50 | 51 | it("should write a simple shape", function () { 52 | create_shapes(); 53 | }); 54 | 55 | describe(" readBREP ", function () { 56 | 57 | it("ZZ1 - should throw an error if used with no argument", function () { 58 | 59 | should(function () { 60 | occ.readBREP(null, function (err, shapes) { 61 | err.message.should.match(/expecting a filename/); 62 | }); 63 | }).throwError(); 64 | }); 65 | 66 | it("ZZ2 - should call the callback method with an error if used with an invalid arguments", function (done) { 67 | 68 | occ.readBREP("||this is a invalid filename||", (err, shapes) => { 69 | err.message.should.match(/cannot read/); 70 | done(); 71 | }); 72 | }); 73 | 74 | it("ZZ3 - should call the callback with an error if the file doesn't exist", function (done) { 75 | occ.readBREP("invalid file name", function (err, shapes) { 76 | console.log(" intercepting error ", err); 77 | assert(err !== undefined); 78 | done(); 79 | }); 80 | }); 81 | 82 | it("ZZ4 - should read the shape back", function (done) { 83 | 84 | occ.readBREP(b1_brep, (err, shapes) => { 85 | 86 | should(err).eql(null); 87 | 88 | if (!err) { 89 | shapes.length.should.equal(1); 90 | shapes[0].numFaces.should.equal(6); 91 | 92 | shapes[0].volume.should.equal(b1_volume); 93 | shapes[0].area.should.equal(b1_area); 94 | } 95 | done(err); 96 | }); 97 | }); 98 | 99 | it("ZZ5 - should read the shape back", function (done) { 100 | 101 | occ.readBREP(b2_brep, function (err, shapes) { 102 | if (!err) { 103 | shapes.length.should.equal(1); 104 | shapes[0].numFaces.should.equal(3); 105 | } 106 | done(err); 107 | }); 108 | 109 | }); 110 | it("ZZ6 - should read the shape back", function (done) { 111 | occ.readBREP(b3_brep, function (err, shapes) { 112 | if (!err) { 113 | shapes.length.should.equal(2); 114 | shapes[0].numFaces.should.equal(6); 115 | shapes[1].numFaces.should.equal(3); 116 | } 117 | done(); 118 | }); 119 | }); 120 | }); 121 | }); 122 | 123 | function build_large_part() { 124 | 125 | let lego_filename = getTemporaryFilePath({prefix: "legoPlate3x2_2x2", suffix: ""}); 126 | 127 | let legoPlate = shape_factory.makeLegoBrick(occ, 3, 2, "thin"); 128 | let solids = []; 129 | for (let x = 0; x < 100; x += 50) { 130 | for (let y = 0; y < 100; y += 50) { 131 | solids.push(legoPlate.translate([x, y, 0])); 132 | } 133 | } 134 | occ.writeBREP(lego_filename + ".brep", solids); 135 | 136 | /* 137 | occ.writeSTL(lego_filename + ".stl", solids); 138 | 139 | let obj = {solids: []}; 140 | let counter = 0; 141 | solids.forEach(function (solid) { 142 | solid.name = "S" + counter; 143 | counter++; 144 | obj.solids.push(occ.buildSolidMesh(solid)); 145 | }); 146 | fs.writeFile(lego_filename + ".3js", JSON.stringify(obj, null, ""), function (err) { 147 | console.log("OK"); 148 | }); 149 | 150 | */ 151 | return lego_filename; 152 | } 153 | 154 | describe("it should write and read a large brep file", function () { 155 | 156 | this.timeout(15000); 157 | 158 | let filename = build_large_part(); 159 | 160 | it("should read a large BREP file quickly", function (done) { 161 | 162 | console.log(" lego file ", filename); 163 | 164 | occ.readBREP(filename + ".brep", function (err, solids) { 165 | 166 | console.log(" read !!!"); 167 | 168 | if (!err) { 169 | console.log(" num Faces = ", solids[0].numFaces); 170 | } 171 | done(err); 172 | }); 173 | 174 | }); 175 | 176 | 177 | }); 178 | -------------------------------------------------------------------------------- /test/test_edge.js: -------------------------------------------------------------------------------- 1 | const should = require("should"); 2 | const occ = require("../lib/occ"); 3 | 4 | describe("testing Edges ",function(){ 5 | 6 | describe("EDGE0 - constructing an empty Edge",function(){ 7 | let edge; 8 | before(function(){ 9 | edge = new occ.Edge() 10 | should.exist(edge); 11 | }); 12 | it("should be valid", function(){ 13 | edge.isNull.should.equal(true); 14 | }); 15 | it("should have a zero length", function(){ 16 | edge.length.should.equal(0); 17 | }); 18 | it("should have a zero vertices", function(){ 19 | edge.numVertices.should.equal(0); 20 | }); 21 | it("should be degenerated", function(){ 22 | edge.isDegenerated.should.equal(true); 23 | }); 24 | it("shouldn't be closed", function(){ 25 | edge.isClosed.should.equal(false); 26 | }); 27 | it("should provide a bounding box", function () { 28 | edge.getBoundingBox().should.be.instanceOf(occ.BoundingBox); 29 | edge.getBoundingBox().isVoid.should.eql(true); 30 | }); 31 | }); 32 | describe("EDGE1 - an Edge constructed as as a linear Segment between (10,20,30) and (-30,20,30) ",function(){ 33 | let edge; 34 | before(function(){ 35 | let v1 = new occ.Vertex(10,20,30); 36 | let v2 = new occ.Vertex(-30,20,30); 37 | edge = occ.makeLine(v1, v2); 38 | edge.should.be.instanceOf(occ.Edge); 39 | 40 | }); 41 | it("should have a length of 40.0 ", function() { 42 | edge.length.should.equal(40.0); 43 | }); 44 | it("should have two vertices ", function() { 45 | edge.numVertices.should.equal(2.0); 46 | }); 47 | it("shouldn't be closed", function() { 48 | edge.isClosed.should.equal(false); 49 | }); 50 | it("shouldn't be degenerated", function() { 51 | edge.isDegenerated.should.equal(false); 52 | }); 53 | it("should provide a bounding box", function () { 54 | edge.getBoundingBox().should.be.instanceOf(occ.BoundingBox); 55 | edge.getBoundingBox().isVoid.should.eql(false); 56 | 57 | edge.getBoundingBox().nearPt.equals(new occ.Point3D(-30, 20, 30)).should.eql(true); 58 | edge.getBoundingBox().nearPt.equals([-30, 20, 30]).should.eql(true); 59 | edge.getBoundingBox().farPt.equals([10, 20, 30]).should.eql(true); 60 | 61 | let extra = 0.000000000001; 62 | edge.getBoundingBox().farPt.asArray().should.eql([10 + extra, 20 + extra, 30 + extra]); 63 | }); 64 | it("should polygonize a segment with two points", function () { 65 | console.log("polyligonize"); 66 | let polyline = edge.polygonize(); 67 | console.log("polyligonize2"); 68 | polyline.length.should.eql(3 * 2); 69 | [polyline[0], polyline[1], polyline[2]].should.eql([10, 20, 30]); 70 | let l = polyline.length; 71 | 72 | (l % 3).should.eql(0); 73 | [polyline[l - 3], polyline[l - 2], polyline[l - 1]].should.eql([-30, 20, 30]); 74 | }); 75 | }); 76 | 77 | describe("EDGE2 - an Edge constructed as as a linear Segment between (10,20,30) and (-30,20,30) and translated by [1,2,3]", function () { 78 | let edge; 79 | before(function () { 80 | let v1 = new occ.Vertex(10, 20, 30); 81 | let v2 = new occ.Vertex(-30, 20, 30); 82 | edge = occ.makeLine(v1, v2); 83 | edge = edge.translate([1, 2, 3]); 84 | }); 85 | it("should have a length of 40.0 ", function () { 86 | edge.length.should.equal(40.0); 87 | }); 88 | it("should provide a bounding box", function () { 89 | edge.getBoundingBox().nearPt.equals([-29, 22, 33]).should.eql(true); 90 | edge.getBoundingBox().farPt.equals([11, 22, 33]).should.eql(true); 91 | }); 92 | it("should polygonize a segment with two points", function () { 93 | let polyline = edge.polygonize(); 94 | polyline.length.should.eql(3 * 2); 95 | [polyline[0], polyline[1], polyline[2]].should.eql([11, 22, 33]); 96 | let l = polyline.length; 97 | (l % 3).should.eql(0); 98 | [polyline[l - 3], polyline[l - 2], polyline[l - 1]].should.eql([-29, 22, 33]); 99 | }); 100 | 101 | }); 102 | describe("EDGE3 - an Edge constructed as a Circle on the Z+ plan with a radius of 20", function () { 103 | let edge; 104 | before(function(){ 105 | edge = occ.makeCircle([10, 10, 10], [0, 0, 1], 20); 106 | }); 107 | 108 | it("should have a length of 2*PI*20.0 ", function(){ 109 | let epsilon = 1E-2; 110 | let PI = 3.1415; 111 | edge.length.should.be.within(2*PI*20.0-epsilon,2*PI*20.0+epsilon); 112 | }); 113 | it("should have a unique vertex ", function(){ 114 | edge.numVertices.should.equal(1); 115 | }); 116 | it("should be closed", function(){ 117 | edge.isClosed.should.equal(true); 118 | }); 119 | it("shouldn't be degenerated", function(){ 120 | edge.isDegenerated.should.equal(false); 121 | }); 122 | 123 | it("should provide a bounding box", function () { 124 | edge.getBoundingBox().should.be.instanceOf(occ.BoundingBox); 125 | edge.getBoundingBox().isVoid.should.eql(false); 126 | //xx console.log(JSON.stringify(edge.getBoundingBox()));//.toString()); 127 | edge.getBoundingBox().nearPt.equals([-11.647844, -11.647844, 10]); 128 | edge.getBoundingBox().farPt.equals([31.647844, 31.647844, 10]); 129 | }); 130 | 131 | it("should polygonize a edge", function () { 132 | 133 | let a = edge.polygonize(); 134 | 135 | [a[0], a[1], a[2]].should.eql([30, 10, 10]); 136 | let l = a.length; 137 | 138 | (l % 3).should.eql(0); 139 | [a[l - 3], a[l - 2], a[l - 1]].should.eql([30, 10, 10]); 140 | //xx console.log(a); 141 | 142 | }); 143 | }); 144 | describe("EDGE4 - an Edge constructed as as a linear Segment between (10,20,30) and (-30,20,30) ", function () { 145 | 146 | }); 147 | }); 148 | -------------------------------------------------------------------------------- /JasmineAdapter-1.1.2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Jasmine JsTestDriver Adapter. 3 | * @author misko@hevery.com (Misko Hevery) 4 | * @author olmo.maldonado@gmail.com (Olmo Maldonado) 5 | */ 6 | (function() { 7 | 8 | 9 | var Env = function(onTestDone, onComplete) { 10 | jasmine.Env.call(this); 11 | 12 | this.specFilter = function(spec) { 13 | if (!this.exclusive) return true; 14 | var blocks = spec.queue.blocks, l = blocks.length; 15 | for (var i = 0; i < l; i++) if (blocks[i].func.exclusive >= this.exclusive) return true; 16 | return false; 17 | }; 18 | 19 | this.reporter = new Reporter(onTestDone, onComplete); 20 | }; 21 | jasmine.util.inherit(Env, jasmine.Env); 22 | 23 | // Here we store: 24 | // 0: everyone runs 25 | // 1: run everything under ddescribe 26 | // 2: run only iits (ignore ddescribe) 27 | Env.prototype.exclusive = 0; 28 | 29 | 30 | Env.prototype.execute = function() { 31 | collectMode = false; 32 | playback(); 33 | jasmine.Env.prototype.execute.call(this); 34 | }; 35 | 36 | 37 | var Reporter = function(onTestDone, onComplete) { 38 | this.onTestDone = onTestDone; 39 | this.onComplete = onComplete; 40 | this.reset(); 41 | }; 42 | jasmine.util.inherit(Reporter, jasmine.Reporter); 43 | 44 | 45 | Reporter.formatStack = function(stack) { 46 | var line, lines = (stack || '').split(/\r?\n/), l = lines.length, frames = []; 47 | for (var i = 0; i < l; i++) { 48 | line = lines[i]; 49 | if (line.match(/\/jasmine[\.-]/)) continue; 50 | frames.push(line.replace(/https?:\/\/\w+(:\d+)?\/test\//, '').replace(/^\s*/, ' ')); 51 | } 52 | return frames.join('\n'); 53 | }; 54 | 55 | 56 | Reporter.prototype.reset = function() { 57 | this.specLog = jstestdriver.console.log_ = []; 58 | }; 59 | 60 | 61 | Reporter.prototype.log = function(str) { 62 | this.specLog.push(str); 63 | }; 64 | 65 | 66 | Reporter.prototype.reportSpecStarting = function() { 67 | this.reset(); 68 | this.start = +new Date(); 69 | }; 70 | 71 | 72 | Reporter.prototype.reportSpecResults = function(spec) { 73 | var elapsed = +new Date() - this.start, results = spec.results(); 74 | 75 | if (results.skipped) return; 76 | 77 | var item, state = 'passed', items = results.getItems(), l = items.length, messages = []; 78 | for (var i = 0; i < l; i++) { 79 | item = items[i]; 80 | if (item.passed()) continue; 81 | state = (item.message.indexOf('AssertionError:') != -1) ? 'error' : 'failed'; 82 | messages.push( { 83 | message: item + '', 84 | name: item.trace.name, 85 | stack: Reporter.formatStack(item.trace.stack) 86 | }); 87 | } 88 | 89 | this.onTestDone(new jstestdriver.TestResult( 90 | spec.suite.getFullName(), 91 | spec.description, 92 | state, 93 | jstestdriver.angular.toJson(messages), 94 | this.specLog.join('\n'), 95 | elapsed 96 | )); 97 | }; 98 | 99 | 100 | Reporter.prototype.reportRunnerResults = function() { 101 | this.onComplete(); 102 | }; 103 | 104 | 105 | var collectMode = true, intercepted = {}; 106 | 107 | describe = intercept('describe'); 108 | beforeEach = intercept('beforeEach'); 109 | afterEach = intercept('afterEach'); 110 | 111 | var JASMINE_TYPE = 'jasmine test case'; 112 | TestCase('Jasmine Adapter Tests', null, JASMINE_TYPE); 113 | 114 | jstestdriver.pluginRegistrar.register( { 115 | 116 | name: 'jasmine', 117 | 118 | getTestRunsConfigurationFor: function(testCaseInfos, expressions, testRunsConfiguration) { 119 | for (var i = 0; i < testCaseInfos.length; i++) { 120 | if (testCaseInfos[i].getType() == JASMINE_TYPE) { 121 | testRunsConfiguration.push(new jstestdriver.TestRunConfiguration(testCaseInfos[i], [])); 122 | } 123 | } 124 | return false; // allow other TestCases to be collected. 125 | }, 126 | 127 | runTestConfiguration: function(config, onTestDone, onComplete) { 128 | if (config.getTestCaseInfo().getType() != JASMINE_TYPE) return false; 129 | (jasmine.currentEnv_ = new Env(onTestDone, onComplete)).execute(); 130 | return true; 131 | }, 132 | 133 | onTestsFinish: function() { 134 | jasmine.currentEnv_ = null; 135 | collectMode = true; 136 | } 137 | 138 | }); 139 | 140 | function intercept(method) { 141 | var bucket = intercepted[method] = [], method = window[method]; 142 | return function(desc, fn) { 143 | if (collectMode) bucket.push(function() { 144 | method(desc, fn); 145 | }); 146 | else method(desc, fn); 147 | }; 148 | } 149 | 150 | function playback() { 151 | for (var method in intercepted) { 152 | var bucket = intercepted[method]; 153 | for (var i = 0, l = bucket.length; i < l; i++) bucket[i](); 154 | } 155 | } 156 | 157 | })(); 158 | 159 | var ddescribe = function(name, fn) { 160 | var env = jasmine.getEnv(); 161 | if (!env.exclusive) env.exclusive = 1; // run ddescribe only 162 | describe(name, function() { 163 | var oldIt = it; 164 | it = function(name, fn) { 165 | fn.exclusive = 1; // run anything under ddescribe 166 | env.it(name, fn); 167 | }; 168 | 169 | try { 170 | fn.call(this); 171 | } 172 | finally { 173 | it = oldIt; 174 | }; 175 | }); 176 | }; 177 | 178 | var iit = function(name, fn) { 179 | var env = jasmine.getEnv(); 180 | env.exclusive = fn.exclusive = 2; // run only iits 181 | env.it(name, fn); 182 | }; 183 | 184 | // Patch Jasmine for proper stack traces 185 | jasmine.Spec.prototype.fail = function (e) { 186 | var result = new jasmine.ExpectationResult( { 187 | passed: false, 188 | message: e ? jasmine.util.formatException(e) : 'Exception' 189 | }); 190 | if(e) result.trace = e; 191 | this.results_.addResult(result); 192 | }; 193 | -------------------------------------------------------------------------------- /test/test_vertex.js: -------------------------------------------------------------------------------- 1 | /* eslint: no-console: off */ 2 | const assert = require("assert"); 3 | const should = require("should"); 4 | 5 | const occ = require("../lib/occ"); 6 | 7 | const doDebug = false; 8 | 9 | 10 | describe("testing Vertex ", function () { 11 | 12 | describe("constructing a empty vertex ", function () { 13 | let vertex; 14 | before(function () { 15 | vertex = new occ.Vertex(); 16 | }); 17 | it("should be (0,0,0)", function () { 18 | vertex.x.should.equal(0); 19 | vertex.y.should.equal(0); 20 | vertex.z.should.equal(0); 21 | }); 22 | }); 23 | describe("constructing a vertex with a {x:..., y..,z: ...}", function () { 24 | let vertex; 25 | before(function () { 26 | vertex = new occ.Vertex({x: 10, y: 20, z: 30}); 27 | }); 28 | it("should be (10,20,30)", function () { 29 | vertex.x.should.equal(10); 30 | vertex.y.should.equal(20); 31 | vertex.z.should.equal(30); 32 | }); 33 | }); 34 | describe("constructing a vertex with {x:..., y..,z: ...} (property in random order)", function () { 35 | let vertex; 36 | before(function () { 37 | vertex = new occ.Vertex({a: 10, y: 20, z: 30, x: 10}); 38 | }); 39 | it("should be (10,20,30)", function () { 40 | vertex.x.should.equal(10); 41 | vertex.y.should.equal(20); 42 | vertex.z.should.equal(30); 43 | }); 44 | }); 45 | 46 | describe("constructing a vertex build by passing x,y,z coordinates to constructor", function () { 47 | let vertex; 48 | before(function () { 49 | vertex = new occ.Vertex(10, 20, 30); 50 | }); 51 | it("should be (10,20,30)", function () { 52 | vertex.x.should.equal(10); 53 | vertex.y.should.equal(20); 54 | vertex.z.should.equal(30); 55 | }); 56 | 57 | }); 58 | describe("constructing a vertex build by passing [x,y,z] coordinates to constructor", function () { 59 | let vertex; 60 | before(function () { 61 | vertex = new occ.Vertex([10, 20, 30]); 62 | }); 63 | it("should be (10,20,30)", function () { 64 | vertex.x.should.equal(10); 65 | vertex.y.should.equal(20); 66 | vertex.z.should.equal(30); 67 | }); 68 | it("should be valid", function () { 69 | vertex.isValid.should.equal(true); 70 | }); 71 | }); 72 | 73 | describe("constructing a vertex and applying a translation", function () { 74 | let vertex_org; 75 | before(function () { 76 | vertex_org = new occ.Vertex([10, 20, 30]); 77 | }); 78 | 79 | it("should be translated", function () { 80 | let vertex; 81 | vertex = vertex_org.translate([10, 20, 30]); 82 | 83 | vertex_org.x.should.equal(10); 84 | vertex_org.y.should.equal(20); 85 | vertex_org.z.should.equal(30); 86 | 87 | vertex.x.should.equal(20); 88 | vertex.y.should.equal(40); 89 | vertex.z.should.equal(60); 90 | }); 91 | it("should be translated - second form ", function () { 92 | let vertex; 93 | vertex = vertex_org.translate(/*[*/10, 20, 30/*]*/); 94 | 95 | vertex_org.x.should.equal(10); 96 | vertex_org.y.should.equal(20); 97 | vertex_org.z.should.equal(30); 98 | 99 | vertex.x.should.equal(20); 100 | vertex.y.should.equal(40); 101 | vertex.z.should.equal(60); 102 | }); 103 | it("should be mirrored", function () { 104 | 105 | const trsf = occ.makePlaneMirror([0, 0, 0], [0, 1, 0]); 106 | 107 | const vertex_dest = vertex_org.transformed(trsf); 108 | vertex_org.x.should.equal(10); 109 | vertex_org.y.should.equal(20); 110 | vertex_org.z.should.equal(30); 111 | 112 | vertex_dest.x.should.equal(10); 113 | vertex_dest.y.should.equal(-20); 114 | vertex_dest.z.should.equal(30); 115 | 116 | }) 117 | }); 118 | 119 | 120 | describe("edge cases: bad use of constructor shall not cause software to crash ", function () { 121 | 122 | it("Edge#constructor - should not crash if new is omitted", function () { 123 | should(function () { 124 | const tmp = /* new */ occ.Edge(); 125 | tmp; 126 | }).throwError(" use new occ.Edge() to construct a Edge"); 127 | }); 128 | it("Vertex#constructor - should not crash if new is omitted", function () { 129 | should(function () { 130 | const tmp = /* new */ occ.Vertex(10, 20, 30); 131 | tmp; 132 | }).throwError(" use new occ.Vertex() to construct a Vertex"); 133 | }); 134 | it("Wire#constructor - should not crash if new is omitted", function () { 135 | should(function () { 136 | const tmp = /* new */ occ.Wire(); 137 | tmp; 138 | }).throwError(" use new occ.Wire() to construct a Wire"); 139 | }); 140 | it("Solid#constructor - should not crash if new is omitted", function () { 141 | should(function () { 142 | const tmp = /* new */ occ.Solid(); 143 | tmp; 144 | }).throwError(" use new occ.Solid() to construct a Solid"); 145 | }); 146 | it("BoundingBox#constructor - should not crash if new is omitted", function () { 147 | should(function () { 148 | const tmp = /* new */ occ.BoundingBox(10, 20, 30); 149 | tmp; 150 | }).throwError(" use new occ.BoundingBox() to construct a BoundingBox"); 151 | }); 152 | 153 | it("Vertex#constructor should not crash if wrong argument are provided", function () { 154 | const tmp = new occ.Vertex({x: 10, y: 20, z: 30}); 155 | tmp; 156 | }); 157 | }); 158 | 159 | 160 | describe("should provide a way to compare vertex", function () { 161 | it("should compare 2 vertices with same coordinates", function () { 162 | const vertex1 = new occ.Vertex(10, 20, 30); 163 | const vertex2 = new occ.Vertex(10, 20, 30); 164 | should(vertex1).eql(vertex2); 165 | if (doDebug) { 166 | console.log("vertex1 ", vertex1); 167 | } 168 | should(vertex1).containEql({x: 10, y: 20, z: 30}); 169 | 170 | }); 171 | it("should compare 2 vertices with different coordinates", function () { 172 | const vertex1 = new occ.Vertex(10, 20, 30); 173 | const vertex2 = new occ.Vertex(110, 220, 330); 174 | should(vertex1).not.eql(vertex2); 175 | }); 176 | 177 | }); 178 | 179 | 180 | }); 181 | -------------------------------------------------------------------------------- /src/Face.cc: -------------------------------------------------------------------------------- 1 | #include "Face.h" 2 | #include "Wire.h" 3 | #include "Edge.h" 4 | #include "Util.h" 5 | #include "Mesh.h" 6 | 7 | Face::~Face() { 8 | m_cacheMesh.Reset(); 9 | }; 10 | 11 | const TopoDS_Shape& Face::shape() const 12 | { 13 | return face(); 14 | } 15 | 16 | void Face::setShape( const TopoDS_Shape& shape) 17 | { 18 | m_face = TopoDS::Face(shape); 19 | } 20 | 21 | int Face::numWires() 22 | { 23 | if(shape().IsNull()) return 0; 24 | TopTools_IndexedMapOfShape anIndices; 25 | TopExp::MapShapes(shape(), TopAbs_WIRE, anIndices); 26 | return anIndices.Extent(); 27 | } 28 | 29 | NAN_METHOD(Face::getWires) 30 | { 31 | Face* pThis = UNWRAP(Face); 32 | auto arr = extract_shapes_as_javascript_array(pThis,TopAbs_WIRE); 33 | info.GetReturnValue().Set(arr); 34 | } 35 | 36 | bool Face::fixShape() 37 | { 38 | return true; 39 | } 40 | 41 | double Face::area() 42 | { 43 | GProp_GProps prop; 44 | BRepGProp::SurfaceProperties(shape(), prop); 45 | return prop.Mass(); 46 | } 47 | 48 | bool Face::hasMesh() 49 | { 50 | TopLoc_Location loc; 51 | occHandle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation(this->face(), loc); 52 | return triangulation.IsNull()?false:true; 53 | } 54 | 55 | std::vector Face::inertia() 56 | { 57 | std::vector ret; 58 | GProp_GProps prop; 59 | BRepGProp::SurfaceProperties(this->shape(), prop); 60 | gp_Mat mat = prop.MatrixOfInertia(); 61 | ret.push_back(mat(1,1)); // Ixx 62 | ret.push_back(mat(2,2)); // Iyy 63 | ret.push_back(mat(3,3)); // Izz 64 | ret.push_back(mat(1,2)); // Ixy 65 | ret.push_back(mat(1,3)); // Ixz 66 | ret.push_back(mat(2,3)); // Iyz 67 | return ret; 68 | } 69 | 70 | 71 | const gp_XYZ Face::centreOfMass() const 72 | { 73 | 74 | GProp_GProps prop; 75 | BRepGProp::SurfaceProperties(this->shape(), prop); 76 | gp_Pnt cg = prop.CentreOfMass(); 77 | 78 | return cg.Coord(); 79 | } 80 | 81 | bool Face::isPlanar() 82 | { 83 | 84 | Handle_Geom_Surface surf = BRep_Tool::Surface(this->m_face); 85 | GeomLib_IsPlanarSurface tool(surf); 86 | return tool.IsPlanar() ? true : false; 87 | } 88 | 89 | Nan::Persistent Face::_template; 90 | 91 | bool Face::buildFace(std::vector& wires) 92 | { 93 | if (wires.size()==0) return false; 94 | 95 | // checling that all wires are closed 96 | for (uint32_t i = 0; i < wires.size(); i++) { 97 | if (!wires[i]->isClosed()) { 98 | Nan::ThrowError("Some of the wires are not closed"); 99 | return false; 100 | } 101 | } 102 | 103 | try { 104 | const TopoDS_Wire& outerwire = wires[0]->wire(); 105 | 106 | BRepBuilderAPI_MakeFace MF(outerwire); 107 | 108 | // add optional holes 109 | for (unsigned i = 1; i < wires.size(); i++) { 110 | const TopoDS_Wire& wire = wires[i]->wire(); 111 | 112 | if (wire.Orientation() != outerwire.Orientation()) { 113 | MF.Add(TopoDS::Wire(wire.Reversed())); 114 | } else { 115 | MF.Add(wire); 116 | } 117 | } 118 | this->setShape(MF.Shape()); 119 | 120 | // possible fix shape 121 | if (!this->fixShape()) { 122 | StdFail_NotDone::Raise("Shapes not valid"); 123 | } 124 | 125 | } 126 | CATCH_AND_RETHROW_NO_RETURN("Failed to create a face"); 127 | return true; 128 | } 129 | 130 | NAN_METHOD(Face::NewInstance) { _NewInstance(info); } 131 | 132 | NAN_METHOD(Face::New) 133 | { 134 | if (!info.IsConstructCall()) { 135 | return Nan::ThrowError(" use new occ.Face() to construct a Face"); 136 | } 137 | 138 | Face* pThis = new Face(); 139 | pThis->Wrap(info.This()); 140 | pThis->InitNew(info); 141 | 142 | std::vector wires; 143 | extractArgumentList(info,wires); 144 | pThis->buildFace(wires); 145 | 146 | info.GetReturnValue().Set(info.This()); 147 | 148 | } 149 | 150 | v8::Local Face::Clone() const 151 | { 152 | Face* obj = new Face(); 153 | v8::Local instance = makeInstance(_template); 154 | obj->Wrap(instance); 155 | obj->setShape(this->shape()); 156 | return instance; 157 | } 158 | 159 | v8::Local Face::NewInstance(const TopoDS_Face& face) 160 | { 161 | Face* obj = new Face(); 162 | v8::Local instance = makeInstance(_template); 163 | obj->Wrap(instance); 164 | obj->setShape(face); 165 | return instance; 166 | } 167 | 168 | NAN_PROPERTY_GETTER(Face::_mesh) 169 | { 170 | Face* pThis = UNWRAP(Face) 171 | 172 | if (pThis->m_cacheMesh.IsEmpty()) { 173 | pThis->m_cacheMesh.Reset(pThis->createMesh(1,0.5, true)); 174 | } 175 | info.GetReturnValue().Set(Nan::New(pThis->m_cacheMesh)); 176 | } 177 | 178 | v8::Local Face::createMesh(double factor, double angle, bool qualityNormals) 179 | { 180 | Nan::EscapableHandleScope scope; 181 | const unsigned argc = 0; 182 | v8::Local argv[1] = { }; 183 | 184 | v8::Local theMesh = makeInstance(Mesh::_template); 185 | 186 | Mesh *mesh = Mesh::Unwrap(theMesh); 187 | 188 | const TopoDS_Shape& shape = this->shape(); 189 | 190 | try { 191 | 192 | TopLoc_Location loc; 193 | occHandle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation(this->face(), loc); 194 | if (triangulation.IsNull()) { 195 | BRepMesh_IncrementalMesh MSH(shape,factor,Standard_True,angle,Standard_True); 196 | } 197 | 198 | 199 | // this code assume that the triangulation has been created 200 | // on the parent object 201 | mesh->extractFaceMesh(this->face(), qualityNormals); 202 | mesh->optimize(); 203 | 204 | } CATCH_AND_RETHROW_NO_RETURN("Failed to mesh solid "); 205 | return scope.Escape(theMesh); 206 | } 207 | 208 | 209 | void Face::InitNew(_NAN_METHOD_ARGS) 210 | { 211 | Base::InitNew(info); 212 | REXPOSE_READ_ONLY_PROPERTY_DOUBLE(Face,area); 213 | REXPOSE_READ_ONLY_PROPERTY_INTEGER(Face,numWires); 214 | REXPOSE_READ_ONLY_PROPERTY_DOUBLE(Face,area); 215 | REXPOSE_READ_ONLY_PROPERTY_BOOLEAN(Face,isPlanar); 216 | REXPOSE_READ_ONLY_PROPERTY_BOOLEAN(Face,hasMesh); 217 | } 218 | 219 | void Face::Init(v8::Local target) 220 | { 221 | // Prepare constructor template 222 | v8::Local tpl = Nan::New(Face::New); 223 | tpl->SetClassName(Nan::New("Face").ToLocalChecked()); 224 | 225 | // object has one internal filed ( the C++ object) 226 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 227 | 228 | _template.Reset(tpl); 229 | 230 | // Prototype 231 | v8::Local proto = tpl->PrototypeTemplate(); 232 | 233 | Base::InitProto(proto); 234 | 235 | EXPOSE_METHOD(Face,getWires); 236 | EXPOSE_METHOD(Face,createMesh); 237 | EXPOSE_READ_ONLY_PROPERTY_INTEGER(Face,numWires); 238 | EXPOSE_READ_ONLY_PROPERTY_DOUBLE(Face,area); 239 | EXPOSE_READ_ONLY_PROPERTY_BOOLEAN(Face,isPlanar); 240 | EXPOSE_READ_ONLY_PROPERTY_BOOLEAN(Face,hasMesh); 241 | EXPOSE_READ_ONLY_PROPERTY(_mesh,mesh); 242 | EXPOSE_TEAROFF(Face,centreOfMass); 243 | Nan::Set(target,Nan::New("Face").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); 244 | } 245 | 246 | NAN_METHOD(Face::createMesh) 247 | { 248 | Face* pThis = UNWRAP(Face); 249 | v8::Local mesh = pThis->createMesh(1,0.5,true); 250 | info.GetReturnValue().Set(mesh); 251 | } 252 | -------------------------------------------------------------------------------- /lib/shape.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const occ = require("./bindings"); 3 | const fs = require("fs"); 4 | 5 | function debugLog() { 6 | arguments; 7 | } 8 | 9 | function export_debug_step(solid) { 10 | 11 | let debug_step_file = "debug_step"; 12 | let counter= 0; 13 | while (fs.existsSync(debug_step_file + counter.toString() + ".step")) { 14 | counter ++; 15 | } 16 | debug_step_file = debug_step_file + counter.toString() + ".step"; 17 | 18 | debugLog("The solid causing problem has been saved in ", debug_step_file); 19 | occ.writeSTEP(debug_step_file, solid); 20 | } 21 | exports.init= function() { 22 | 23 | 24 | occ.Solid.prototype.getAllEdges = function() { 25 | // deprecated : use Solid.getEdgesi ! 26 | const edges = []; 27 | const iterator = new occ.ShapeIterator(this, "EDGE"); 28 | while (iterator.more) { 29 | edges.push(iterator.next()); 30 | } 31 | return edges; 32 | }; 33 | occ.Face.prototype.getAllEdges = occ.Solid.prototype.getAllEdges; 34 | occ.Wire.prototype.getAllEdges = occ.Solid.prototype.getAllEdges; 35 | 36 | 37 | occ.BoundingBox.prototype.toString = function () { 38 | return "[ " + this.nearPt.x.toFixed(3) + 39 | "," + this.nearPt.y.toFixed(3) + 40 | "," + this.nearPt.z.toFixed(3) +"]" + 41 | "[ " + this.farPt.x.toFixed(3) + 42 | "," + this.farPt.y.toFixed(3) + 43 | "," + this.farPt.z.toFixed(3) +"]"; 44 | }; 45 | 46 | 47 | occ.buildSolidMeshNew = function (solid) { 48 | 49 | function makeEdgesIndexes(solid, jsonSolidMesh) { 50 | 51 | // produce each edge 52 | const mesh = solid.mesh; 53 | let indexes = null; 54 | 55 | solid.getEdges().forEach(edge => { 56 | if (edge.isSeam) { 57 | return; 58 | } 59 | try { 60 | indexes = mesh.getEdgeIndices(edge); 61 | } 62 | catch(err) { 63 | 64 | // fall back to complete edge 65 | const polyline = edge.polygonize(); 66 | if (!polyline) { 67 | debugLog("mesh# failed ! cannot extract edges indexes on solid", err, solid.hasMesh, solid.name, solid.getShapeName(edge)); 68 | debugLog(" mesh", mesh.numVertex); 69 | debugLog(" edge", edge.polygonize()); 70 | export_debug_step(solid); 71 | //xx process.exit(2); 72 | } 73 | 74 | const entry = { 75 | name: solid.getShapeName(edge), 76 | mesh: toBase64(polyline) 77 | }; 78 | jsonSolidMesh.edges.push(entry); 79 | return; 80 | } 81 | if (!indexes || indexes.length == 0) { 82 | return ; // ignore empty edges 83 | } 84 | 85 | const entry = { 86 | name: solid.getShapeName(edge), 87 | indexes: toBase64(indexes), 88 | }; 89 | jsonSolidMesh.edges.push(entry); 90 | }); 91 | } 92 | 93 | function toBase64_1(typedArray) { 94 | return ( new Buffer(typedArray.buffer)).toString("base64"); 95 | } 96 | 97 | toBase64_1; 98 | 99 | function toBase64(typedArray) { 100 | const a = []; 101 | for (let i = 0; i < typedArray.length; i++) { 102 | a[i] = (typedArray[i]); 103 | } 104 | return a; 105 | } 106 | function makeFacesIndexes(solid, jsonSolidMesh) { 107 | 108 | const mesh = solid.mesh; 109 | solid.getFaces().forEach(face => { 110 | 111 | const indexes = mesh.getFaceTriangles(face); 112 | const normalindexes = mesh.getFaceTriangleNormals(face); 113 | 114 | const entry = { 115 | name: solid.getShapeName(face), 116 | indexes: toBase64(indexes), 117 | normalIndexes: toBase64(normalindexes) 118 | }; 119 | //xx entry.mesh.materials[0].colorDiffuse = [ Math.random(),Math.random(),Math.random()]; 120 | jsonSolidMesh.faces.push(entry); 121 | }); 122 | 123 | } 124 | 125 | assert(solid.hasOwnProperty("name"), "occ.buildSolidMesh : the solid must have a name"); 126 | 127 | 128 | // make sure object is meshed 129 | if (!solid.hasMesh) { 130 | try { 131 | solid.createMesh(0.5,5); 132 | } 133 | catch(err) { 134 | // 135 | } 136 | assert(solid.hasMesh); 137 | } 138 | const mesh = solid.mesh; 139 | 140 | 141 | const jsonSolidMesh = {name: solid.name, vertices: [], faces: [], edges: []}; 142 | 143 | jsonSolidMesh.vertices = toBase64(mesh.vertices); 144 | jsonSolidMesh.normals = toBase64(mesh.normals); 145 | 146 | makeFacesIndexes(solid, jsonSolidMesh); 147 | 148 | makeEdgesIndexes(solid, jsonSolidMesh); 149 | 150 | jsonSolidMesh.version = "2.0"; 151 | return jsonSolidMesh; 152 | }; 153 | 154 | 155 | occ.buildSolidMesh = function (solid) { 156 | 157 | assert(solid.hasOwnProperty("name"), "occ.buildSolidMesh : the solid must have a name"); 158 | 159 | // make sure object is meshed 160 | const mesh = solid.mesh; 161 | mesh; 162 | 163 | // produce each faces 164 | const faces = solid.getFaces(); 165 | let face; 166 | 167 | const jsonSolidMesh = {name: solid.name, faces: [], edges: []}; 168 | let i, entry; 169 | 170 | for (i = 0; i < faces.length; i++) { 171 | face = faces[i]; 172 | 173 | if (!face.hasMesh) { 174 | continue; 175 | } 176 | entry = { 177 | name: solid.getShapeName(face), 178 | // color:(r*255+g)*255+b, 179 | mesh: face.mesh.toJSON() 180 | }; 181 | entry.mesh.materials[0].colorDiffuse = [Math.random(), Math.random(), Math.random()]; 182 | jsonSolidMesh.faces.push(entry); 183 | } 184 | // produce each edge 185 | 186 | const edges = solid.getEdges(); 187 | let edge; 188 | for (i = 0; i < edges.length; i++) { 189 | edge = edges[i]; 190 | 191 | if (edge.isSeam) { 192 | continue; 193 | } 194 | const polygone = edge.polygonize(); 195 | 196 | //xx console.log( "polygone.length = ",polygone.length); 197 | const pts = []; 198 | for (let j = 0; j < polygone.length; j++) { 199 | pts.push(polygone[j]); 200 | } 201 | entry = { 202 | name: solid.getShapeName(edge), 203 | mesh: pts 204 | }; 205 | //entry.mesh.materials[0].colorDiffuse could be [ Math.random(),Math.random(),Math.random()]; 206 | jsonSolidMesh.edges.push(entry); 207 | } 208 | jsonSolidMesh.version = "1.0"; 209 | return jsonSolidMesh; 210 | }; 211 | 212 | }; 213 | -------------------------------------------------------------------------------- /test/test_fastbuilder.js: -------------------------------------------------------------------------------- 1 | const fastBuilder_ = require("../lib/fastbuilder"); 2 | const fast_occ = fastBuilder_.occ; 3 | const fastBuilder = fastBuilder_.fastBuilder; 4 | 5 | function makeShape() { 6 | let e = 20; 7 | let s1 = fast_occ.makeBox([10, e, 30], [110, 120, 130]); 8 | let s2 = fast_occ.makeBox(100, 200, 300); 9 | let s3 = fast_occ.fuse(s1, s2); 10 | s3 = s3.translate([0,20,30]); 11 | s3= s3.translate([0,20,30]); 12 | return s3; 13 | } 14 | 15 | function startChronometer() { 16 | return process.hrtime(); 17 | } 18 | function stopChronometer(time1) { 19 | let diff1 = process.hrtime(time1); 20 | diff1 = (diff1[0]*1E9+diff1[1]); // in nanoseconds 21 | diff1 /= 1000.0; // in microseconds 22 | diff1 /= 1000.0; // in miliseconds 23 | diff1 /= 1000.0; // in seconds 24 | return diff1; 25 | } 26 | 27 | 28 | 29 | describe("testing geometry builder",function(){ 30 | 31 | before(function(){ 32 | fastBuilder.resetCache(); 33 | }); 34 | it("should create a bottle faster the second time ", function() { 35 | 36 | fastBuilder.mapQueryCount.should.equal(0); 37 | fastBuilder.mapHit.should.equal(0); 38 | 39 | let c1 = startChronometer(); 40 | makeShape(); 41 | let diff1 = stopChronometer(c1); 42 | 43 | fastBuilder.mapQueryCount.should.equal(5); 44 | fastBuilder.mapHit.should.equal(0); 45 | 46 | let c2 = startChronometer(); 47 | makeShape(); 48 | let diff2 = stopChronometer(c2); 49 | 50 | 51 | fastBuilder.mapQueryCount.should.equal(10); 52 | fastBuilder.mapHit.should.equal(5); 53 | 54 | console.log(" time to compute first box = ", diff1 ," seconds"); 55 | console.log(" time to compute second box = ", diff2 ," seconds" ); 56 | console.log(" speed up = ", Math.round( (diff1-diff2)/diff2*100,2) ,"%" ); 57 | 58 | diff1.should.be.greaterThan(diff2); 59 | 60 | }); 61 | }); 62 | 63 | 64 | describe("testing calculateOperationHash",function(){ 65 | 66 | let fastbuilder = require("../lib/fastbuilder"); 67 | let calculateOperationHash = function () { 68 | return fastbuilder.calculateOperationHash("myFunc",arguments); 69 | }; 70 | 71 | before(function(){ 72 | 73 | }); 74 | it("should calculate the hash of [10,20,30]",function(){ 75 | calculateOperationHash([10, 20, 30])[1].should.equal("myFunc([10,20,30])"); 76 | }); 77 | }); 78 | 79 | 80 | describe("testing fast builder with array of shape",function(){ 81 | 82 | before(function(){ 83 | fastBuilder.resetCache(); 84 | }); 85 | it("should create a bottle faster the second time ", function() { 86 | 87 | fastBuilder.mapQueryCount.should.equal(0); 88 | fastBuilder.mapHit.should.equal(0); 89 | let a = []; 90 | a.push(makeShape()); 91 | a.push(makeShape().translate(10,20,30)); 92 | a.push(makeShape().translate(30,20,30)); 93 | 94 | let compound = fast_occ.compound(a); 95 | 96 | }); 97 | }); 98 | 99 | describe("testing fast builder with makeThickSolid" , function() { 100 | let s1; 101 | let s2; 102 | before(function(){ 103 | s1 = fast_occ.makeBox([10,20,30],[110,120,130]); 104 | s1 = fast_occ.makeThickSolid(s1,s1.faces.top,6); 105 | 106 | let occ = require("../lib/occ"); 107 | s2 = occ.makeBox([10,20,30],[110,120,130]); 108 | s2 = occ.makeThickSolid(s2,s2.faces.top,6); 109 | 110 | }); 111 | it(" should construct the same object as if using 'occ' ",function(){ 112 | s1.numFaces.should.equal(s2.numFaces); 113 | }); 114 | }); 115 | 116 | 117 | let factory = require("../lib/shapeFactory.js"); 118 | describe("testing fast builder with some built-in shapes", function () { 119 | let fastbuilder = require("../lib/fastbuilder"); 120 | it("should create the bottle..", function () { 121 | let s1 = factory.makeBottle(fastbuilder.occ); 122 | s1.numFaces.should.be.greaterThan(16); 123 | }); 124 | }); 125 | 126 | describe("testing fast builder with some shapes", function () { 127 | 128 | it("should create the piston..", function () { 129 | let fastbuilder = require("../lib/fastbuilder"); 130 | let s1 = factory.makePiston(fastbuilder.occ); 131 | s1.numFaces.should.be.greaterThan(7); 132 | }); 133 | }); 134 | 135 | 136 | 137 | describe("testing fast builder get Common Edge" , function() { 138 | let solid1; 139 | let solid2; 140 | 141 | function buildFilletOnTopLeftEdge() { 142 | let s1 = fast_occ.makeBox([10, 20, 30], [110, 120, 130]); 143 | let edges = s1.getCommonEdges(s1.faces.front, s1.faces.left); 144 | s1 = fast_occ.makeFillet(s1, edges, 10); 145 | s1 = fast_occ.makeDraftAngle(s1, s1.faces["mleft:0"], 0.1, s1.faces["mbottom:0"]); 146 | return s1; 147 | } 148 | 149 | before(function () { 150 | solid1 = buildFilletOnTopLeftEdge(); 151 | solid2 = buildFilletOnTopLeftEdge(); 152 | }); 153 | it("should have 7 faces", function () { 154 | solid1.numFaces.should.be.equal(7); 155 | solid2.numFaces.should.be.equal(7); 156 | }); 157 | }); 158 | 159 | 160 | describe("testing fast-builder with impossible cone" , function () { 161 | let solid1 = 0; 162 | before(function () { 163 | // this cone cannot be built : it has PI/2 for half-angle ! 164 | }); 165 | it("should have no solid",function(){ 166 | (function() { 167 | solid1 = fast_occ.makeCone( [0,0,0] , [0,0,1] , 1.5707963267948966 , 10); 168 | }).should.throwError(); 169 | }); 170 | }); 171 | 172 | describe("testing fast-builder with LEGO brick" , function () { 173 | 174 | this.timeout(10000); 175 | 176 | it("should produce a LEGO brick",function(){ 177 | 178 | let factory = require("../lib/shapeFactory.js"); 179 | 180 | function buildBrick() { 181 | 182 | let nx = 3; 183 | let ny = 6; 184 | let brick24 = factory.makeLegoBrick(fast_occ, nx, ny, "thick"); 185 | 186 | brick24.numFaces.should.be.greaterThan(40); 187 | 188 | // now check with bounding box 189 | let bbox = brick24.getBoundingBox(); 190 | 191 | let eps = 0.01; 192 | bbox.nearPt.x.should.be.within(0-eps,0+eps); 193 | bbox.nearPt.y.should.be.within(0-eps,0+eps); 194 | bbox.nearPt.z.should.be.within(0-eps,0+eps); 195 | 196 | bbox.farPt.x.should.be.within(nx * 8 - eps, nx * 8 + eps); 197 | bbox.farPt.y.should.be.within(ny * 8 - eps, ny * 8 + eps); 198 | bbox.farPt.z.should.be.within(11.2-eps,11.2+eps); 199 | } 200 | 201 | let c1 = startChronometer(); 202 | buildBrick(); 203 | let diff1 = stopChronometer(c1); 204 | 205 | let c2 = startChronometer(); 206 | buildBrick(); 207 | let diff2 = stopChronometer(c2); 208 | 209 | console.log(" time to compute first box = ", diff1 ," seconds" ); 210 | console.log(" time to compute second box = ", diff2 ," seconds"); 211 | let speedup = Math.round( (diff1-diff2)/diff2*100,2); 212 | console.log(" speed up = ", speedup ,"%" ); 213 | 214 | diff1.should.be.greaterThan(diff2); 215 | speedup.should.be.greaterThan(100); //"%" 216 | 217 | }); 218 | }); 219 | -------------------------------------------------------------------------------- /src/NodeV8.h: -------------------------------------------------------------------------------- 1 | // NodeV8 2 | #pragma once 3 | #ifdef _MSC_VER 4 | #pragma warning(disable:4530) // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc 5 | #pragma warning(disable:4506) 6 | #pragma warning(disable:4355) // warning C4355: 'this' : used in base member initializer list 7 | 8 | #endif 9 | 10 | #ifdef Handle 11 | #define Handle_was_defined 12 | #undef Handle 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #ifdef Handle_was_defined 20 | #define Handle(ClassName) Handle_##ClassName 21 | #endif 22 | #define occHandle(ClassName) Handle_##ClassName 23 | //xx using namespace v8; 24 | 25 | 26 | template bool IsInstanceOf(Nan::MaybeLocal obj) { 27 | if (obj.IsEmpty()) { 28 | return false; 29 | } 30 | v8::Local _template = Nan::New(T::_template); 31 | return _template->HasInstance(obj.ToLocalChecked()); 32 | } 33 | 34 | /* 35 | template bool IsInstanceOf(Nan::Local obj) { 36 | v8::Local _template = Nan::New(T::_template); 37 | return _template->HasInstance(obj); 38 | 39 | } 40 | template bool IsInstanceOf(Nan::Handle obj) { 41 | v8::Local _template = Nan::New(T::_template); 42 | return _template->HasInstance(obj); 43 | } 44 | */ 45 | 46 | 47 | 48 | //template v8::Local c(T e) { return v8::Local(e); } 49 | template v8::Local c(v8::Local e) { return e; } 50 | inline v8::Local c(Nan::MaybeLocal e) { return e.ToLocalChecked(); } 51 | 52 | 53 | 54 | template 55 | NAN_GETTER(ee) 56 | { 57 | //xx NanScope(); 58 | if (info.This().IsEmpty() ) { 59 | info.GetReturnValue().SetUndefined(); 60 | return; 61 | } 62 | 63 | if (info.This()->InternalFieldCount() == 0 ) { 64 | info.GetReturnValue().SetUndefined(); 65 | return; 66 | } 67 | 68 | T* obj = Nan::ObjectWrap::Unwrap(info.This()); 69 | 70 | try { 71 | 72 | auto val = (obj->*func)(); 73 | info.GetReturnValue().Set(c(Nan::New(val)) ); 74 | 75 | } catch(...) { 76 | return Nan::ThrowError("exception caught in C++ code"); 77 | } 78 | } 79 | 80 | // proto is an ObjectTemplate 81 | #define EXPOSE_METHOD(ClassName,staticMethod) \ 82 | Nan::SetTemplate(proto,#staticMethod, Nan::New(staticMethod)) 83 | 84 | // proto->Set(#staticMethod,v8::FunctionTemplate::New(staticMethod)); 85 | // NODE_SET_PROTOTYPE_METHOD(proto,#staticMethod,staticMethod); 86 | //FunctionTemplate::New(staticMethod)->GetFunction()); 87 | // proto->Set(Nan::New(#staticMethod),FunctionTemplate::New(staticMethod)->GetFunction()); 88 | 89 | #define __EXPOSE_READ_ONLY_PROPERTY(element,staticMethod,name) \ 90 | Nan::SetAccessor(element,Nan::New(#name).ToLocalChecked(), &staticMethod, 0,v8::Local(),v8::DEFAULT,v8::ReadOnly) 91 | 92 | #define EXPOSE_READ_ONLY_PROPERTY(staticMethod,name) \ 93 | __EXPOSE_READ_ONLY_PROPERTY(proto,staticMethod,name) 94 | 95 | #define EXPOSE_READ_ONLY_PROPERTY_BOOLEAN(ClassName,name) \ 96 | __EXPOSE_READ_ONLY_PROPERTY(proto, (ee< ClassName, v8::Boolean, bool, &ClassName::name>) , name ) 97 | 98 | #define EXPOSE_READ_ONLY_PROPERTY_INTEGER(ClassName,name) \ 99 | __EXPOSE_READ_ONLY_PROPERTY(proto, (ee),name) 100 | 101 | #define EXPOSE_READ_ONLY_PROPERTY_UINT32(ClassName,name) \ 102 | __EXPOSE_READ_ONLY_PROPERTY(proto, (ee),name) 103 | 104 | #define EXPOSE_READ_ONLY_PROPERTY_DOUBLE(ClassName,name) \ 105 | __EXPOSE_READ_ONLY_PROPERTY(proto, (ee),name) 106 | 107 | #define EXPOSE_READ_ONLY_PROPERTY_CONST_STRING(ClassName,name) \ 108 | __EXPOSE_READ_ONLY_PROPERTY(proto, (ee),name) 109 | 110 | #define EXPOSE_READ_ONLY_PROPERTY_OBJECT(ClassName,name) \ 111 | __EXPOSE_READ_ONLY_PROPERTY(proto, (ee,&ClassName::name>),name) 112 | 113 | 114 | #define REXPOSE_READ_ONLY_PROPERTY_DOUBLE(ClassName,name) \ 115 | __EXPOSE_READ_ONLY_PROPERTY(info.This(),(ee< ClassName, v8::Number, double, &ClassName::name>) , name ) 116 | #define REXPOSE_READ_ONLY_PROPERTY_BOOLEAN(ClassName,name) \ 117 | __EXPOSE_READ_ONLY_PROPERTY(info.This(),(ee< ClassName, v8::Boolean, bool, &ClassName::name>) , name ) 118 | #define REXPOSE_READ_ONLY_PROPERTY_INTEGER(ClassName,name) \ 119 | __EXPOSE_READ_ONLY_PROPERTY(info.This(), (ee),name) 120 | #define REXPOSE_READ_ONLY_PROPERTY_CONST_STRING(ClassName,name) \ 121 | __EXPOSE_READ_ONLY_PROPERTY(info.This(), (ee),name) 122 | /** 123 | * Extracts a C string from a V8 Utf8Value. 124 | * 125 | * v8::String::Utf8Value str(args[i]); 126 | * const char* cstr = ToCString(str); 127 | * 128 | */ 129 | inline const char* ToCString(const v8::String::Utf8Value& value) 130 | { 131 | return *value ? *value : ""; 132 | } 133 | 134 | // TO DO => SCRAP 135 | #define _NAN_METHOD_ARGS const Nan::FunctionCallbackInfo& info 136 | #define NanObjectWrapHandle(t) (t->handle()) 137 | 138 | 139 | #define CHECK_THIS_DEFINED(CLASS) \ 140 | if ( info.This().IsEmpty()) { \ 141 | return Nan::ThrowError("Internal error: 'this' is not defined"); \ 142 | } \ 143 | if (info.This()->InternalFieldCount() == 0 ) { \ 144 | return; \ 145 | return Nan::ThrowError("Internal error: 'this' is not a wrapped object"); \ 146 | } \ 147 | if (!ObjectWrap::Unwrap(info.This())) { \ 148 | return Nan::ThrowError("Internal error: 'this' is of wrong type in"); \ 149 | } 150 | 151 | #define UNWRAP(CLASS) \ 152 | 0; \ 153 | CHECK_THIS_DEFINED(CLASS) \ 154 | v8::Local pJhis = info.This(); \ 155 | if ( pJhis.IsEmpty() || !IsInstanceOf(pJhis)) { \ 156 | return Nan::ThrowError("invalid object"); \ 157 | } \ 158 | pThis = Nan::ObjectWrap::Unwrap(pJhis); 159 | 160 | 161 | // catch an open cascade exception and turn it into a Nan Execption 162 | #define CATCH_AND_RETHROW(message) \ 163 | catch(Standard_Failure& e) { \ 164 | Standard_CString msg = e.GetMessageString(); \ 165 | std::cerr << "C++ exception in OCC "<< msg << " " << message << std::endl; \ 166 | if (msg == NULL || strlen(msg) < 1) { \ 167 | msg = message; \ 168 | } \ 169 | Nan::ThrowError(msg); \ 170 | } \ 171 | 172 | #define CATCH_AND_RETHROW2(message) \ 173 | catch(Standard_Failure& ) { \ 174 | info.GetReturnValue().Set(v8::Local()); \ 175 | return Nan::ThrowError(""); \ 176 | } 177 | 178 | #define CATCH_AND_RETHROW_NO_RETURN(message) \ 179 | catch(Standard_Failure& ) { \ 180 | Nan::ThrowError(message); \ 181 | } 182 | -------------------------------------------------------------------------------- /lib/fastbuilder.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const crypto = require("crypto"); 3 | const occ = require("./occ"); 4 | const shapeFactory = require("../lib/shapeFactory"); 5 | const assert = require("assert"); 6 | 7 | function debugLog() { 8 | /* implement me*/ 9 | } 10 | 11 | class Cache { 12 | 13 | constructor() { 14 | 15 | this.resetCache(); 16 | 17 | } 18 | 19 | resetCache() { 20 | 21 | this.mapHit = 0; 22 | this.mapQueryCount = 0; 23 | this.mapObject = {}; 24 | 25 | } 26 | 27 | replaceObjectMethod(obj, _methodName) { 28 | 29 | const _originalMethod = obj[_methodName]; 30 | assert(isFunction(_originalMethod)); 31 | // create closure variable 32 | const that = this; 33 | const methodName = _methodName; 34 | const originalMethod = _originalMethod; 35 | 36 | function performOperation() { 37 | 38 | return that.__performedCachedOperation(this, originalMethod, `${methodName}#${this.uuid}`, arguments); 39 | 40 | } 41 | 42 | Object.defineProperty(obj, methodName, {value: performOperation, enumerable: false}); 43 | 44 | // xx obj[methodName] = performOperation;= 45 | 46 | } 47 | 48 | 49 | installProxyMethods(obj) { 50 | 51 | // xx console.log("xxx in installProxyMethods on",obj.constructor.name); 52 | assert(!!obj); 53 | 54 | const prototype = obj.constructor.prototype; 55 | 56 | const functionToOverride = Object.keys(prototype).filter(n => typeof prototype[n] === "function"); 57 | 58 | // ---------------- old 59 | const that = this; 60 | functionToOverride.forEach((funcName) => { 61 | 62 | if (funcName === "toString") { 63 | return; 64 | } 65 | // xx console.log("xxx in installProxyMethods replaceObjectMethod",func_name); 66 | that.replaceObjectMethod(obj, funcName); 67 | 68 | }); 69 | 70 | 71 | } 72 | 73 | prepareObject(obj, cmd, uuid, index) { 74 | 75 | if (obj === undefined) { 76 | 77 | return; 78 | 79 | } 80 | if (typeof obj === "string") { 81 | 82 | return; 83 | 84 | } 85 | 86 | assert(!obj.hasOwnProperty("cmd"), ` object should not have been inserted already ( old cmd : ${obj.cmd})`); 87 | assert(!obj.hasOwnProperty("uuid"), ` object should not have been inserted already ( old uuid : ${obj.uuid})`); 88 | 89 | // store the resulting object in cache 90 | obj.cmd = cmd; 91 | obj.uuid = uuid; 92 | if (index) { 93 | 94 | obj.uuid = hash(`${uuid}[${index}]`); 95 | obj.uuid_index = index; 96 | 97 | } 98 | debugLog(" adding object to cache ", uuid, "cmd =", cmd, " index = ", index); 99 | 100 | this.mapObject[obj.uuid] = obj; 101 | 102 | // prepare the resulting object 103 | this.installProxyMethods(obj); 104 | 105 | } 106 | 107 | __performedCachedOperation(originalObject, originalMethod, methodName, theArguments, callAsConstructor) { 108 | 109 | assert(theArguments.hasOwnProperty("length")); 110 | 111 | const h = calculateOperationHash(methodName, theArguments, callAsConstructor); 112 | const uuid = h[0]; 113 | const cmd = h[1]; 114 | 115 | debugLog(" executing method ", cmd, uuid); 116 | 117 | // check if object is already known 118 | this.mapQueryCount++; 119 | if (this.mapObject.hasOwnProperty(uuid)) { 120 | 121 | const obj = this.mapObject[uuid]; 122 | assert(obj.uuid === uuid, " checking object uuid consistency"); 123 | debugLog(" using object from cache ", obj.uuid, obj.cmd); 124 | 125 | this.mapHit++; 126 | return obj; 127 | 128 | } 129 | 130 | // otherwise perform the "costly" original operation 131 | let result; 132 | try { 133 | 134 | if (callAsConstructor) { 135 | 136 | // New object must be unique.... 137 | assert(false); 138 | const args = [null].concat(Object.keys(theArguments).map(f => theArguments[f])); 139 | const FactoryFunction = originalMethod.bind(...args); 140 | result = new FactoryFunction(); 141 | 142 | } else { 143 | 144 | const args = Object.keys(theArguments).map(f => theArguments[f]); 145 | result = originalMethod.apply(originalObject, args); 146 | 147 | } 148 | 149 | } catch (err) { 150 | 151 | debugLog(` FAILING to call ${methodName}(`, `${Object.keys(theArguments).map(e => JSON.stringify(theArguments[e])).join(" , ")})`); 152 | 153 | throw err; // re-throw execption above 154 | 155 | } 156 | 157 | const _this = this; 158 | 159 | if (result instanceof Array) { 160 | 161 | debugLog("result is an array with ", result.length, " elements"); 162 | 163 | 164 | result.forEach((el, index) => { 165 | 166 | _this.prepareObject(el, cmd, uuid, index); 167 | 168 | }); 169 | 170 | _this.prepareObject(result, cmd, uuid); 171 | 172 | } else { 173 | 174 | // xx console.log("xxx resylt ) ",methodName,result.constructor.name,result); 175 | _this.prepareObject(result, cmd, uuid); 176 | 177 | } 178 | 179 | return result; 180 | 181 | } 182 | 183 | __proxy(originalObject, methodName, theArguments, callAsConstructor) { 184 | 185 | return this.__performedCachedOperation(originalObject, originalObject[methodName], methodName, theArguments, callAsConstructor); 186 | 187 | } 188 | } 189 | 190 | function hash(args) { 191 | 192 | const shasum = crypto.createHash("sha1"); 193 | shasum.update(args); 194 | return shasum.digest("hex"); 195 | 196 | } 197 | 198 | /** 199 | * 200 | */ 201 | function replaceObjectsByGUUID(arg) { 202 | 203 | const toUUID = el => el.uuid; 204 | 205 | if (!arg) { 206 | return null; 207 | } 208 | if (arg.hasOwnProperty("uuid")) { 209 | return toUUID(arg); 210 | } else if ((arg.length > 0 && typeof arg[0] === "number") || (typeof arg === "number")) { 211 | return arg; 212 | } else if (arg.length > 0 && (arg[0] instanceof Object) && arg[0].hasOwnProperty("uuid")) { 213 | debugLog(" Found an array of object with guiid", (`arg ${arg.map(el => el.uuid)}`)); 214 | return arg.map(replaceObjectsByGUUID); 215 | 216 | } else { 217 | if (arg.hashCode) { 218 | return hash(`---${arg.hashCode}`); 219 | } 220 | // we can"t use cache yet 221 | const tmp = arg; 222 | // .map(toUUID); 223 | debugLog(" ERROR : Cannot use cache with object ", typeof arg, JSON.stringify(tmp)); 224 | 225 | return tmp; 226 | } 227 | } 228 | 229 | function calculateOperationHash(methodName, theArguments) { 230 | 231 | 232 | // build the signature of the function + arguments 233 | 234 | let key; 235 | const args = []; 236 | for (key in theArguments) { 237 | 238 | if (theArguments.hasOwnProperty(key)) { 239 | 240 | args.push(replaceObjectsByGUUID(theArguments[key])); 241 | 242 | } 243 | 244 | } 245 | const argStr = JSON.stringify(args); 246 | const cmd = `${methodName}(${argStr.substr(1, argStr.length - 2)})`; 247 | const uuid = hash(cmd); 248 | 249 | return [uuid, cmd]; 250 | 251 | } 252 | 253 | function isFunction(a) { 254 | 255 | return typeof a === "function"; 256 | 257 | } 258 | 259 | const cache = new Cache(); 260 | 261 | function replaceFunc(proxyObj, Obj, methodName) { 262 | 263 | assert(proxyObj); 264 | debugLog(` installing proxy method ${methodName}`); 265 | 266 | if (isFunction(Obj[methodName])) { 267 | 268 | assert(isFunction(Obj[methodName]), `methodName = ${methodName} ${typeof Obj[methodName]}`); 269 | const fn = function () { 270 | 271 | // http://stackoverflow.com/questions/367768/how-to-detect-if-a-function-is-called-as-constructor 272 | // Xx console.log(this.constructor.name == methodName, (this.constructor === fn), this.constructor.name); 273 | return cache.__proxy(Obj, methodName, arguments, (this.constructor === fn)); 274 | 275 | }; 276 | proxyObj[methodName] = fn; 277 | // http://stackoverflow.com/questions/5871040/how-to-dynamically-set-a-function-object-name-in-javascript-as-it-is-displayed-i 278 | Object.defineProperty(fn, "name", {value: methodName}); 279 | 280 | } 281 | 282 | } 283 | 284 | occ.makeBottle = shapeFactory.makeBottle; 285 | 286 | function createProxyObject(originalObject) { 287 | 288 | const proxyObject = {}; 289 | const properties = Object.keys(originalObject); 290 | properties.forEach((funcName) => { 291 | 292 | replaceFunc(proxyObject, originalObject, funcName); 293 | 294 | }); 295 | return proxyObject; 296 | 297 | } 298 | 299 | /* 300 | * [ 301 | * "makeBox", "makeCylinder", "makeCone", "makeSphere", 302 | * "makeTorus", "makeThickSolid", "makeDraftAngle", 303 | * "makeFillet", 304 | * "fuse", "cut", "common", "compound", 305 | * "makeVertex", "makeEdge", "makeWire", 306 | * // constructors 307 | * "Vertex", "Edge", "Wire", "Transformation","BoundingBox" 308 | * 309 | * ].forEach(function (funcName) { 310 | * replaceFunc(ProxyOCC, occ, funcName); 311 | * }); 312 | * 313 | * ["makeBottle"].forEach(function (funcName) { 314 | * replaceFunc(ProxyOCC, shapeFactory, funcName); 315 | * }); 316 | */ 317 | exports.fastBuilder = cache; 318 | 319 | exports.occ = createProxyObject(occ); 320 | exports.occ.buildSolidMesh = occ.buildSolidMesh; 321 | 322 | exports.calculateOperationHash = calculateOperationHash; 323 | --------------------------------------------------------------------------------