diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..c13c5f62 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015"] +} diff --git a/.gitignore b/.gitignore index fb221cbf..b5bd574f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,7 @@ *.iml *.ipr *.iws -/web/app/test/viz/** \ No newline at end of file +/web/app/test/viz/** +/npm-debug.log +/node_modules +/dist diff --git a/build/.eslintignore b/build/.eslintignore new file mode 100644 index 00000000..047232a1 --- /dev/null +++ b/build/.eslintignore @@ -0,0 +1,3 @@ +/web/app/math/lm.js +/web/app/math/qr.js + diff --git a/build/.eslintrc.json b/build/.eslintrc.json new file mode 100644 index 00000000..e86eb432 --- /dev/null +++ b/build/.eslintrc.json @@ -0,0 +1,24 @@ +{ + "extends": "eslint:recommended", + "env": { + "browser": true, + "commonjs": true, + "es6": true + }, + "parser": "babel-eslint", + "plugins": [ + "babel" + ], + "globals" : { + "THREE" : true, + "CSG" : true, + "PNLTRI" : true + }, + "rules": { + "comma-dangle": "off", + "no-unused-vars": "off", + "max-len": "off", + "no-console": "off", + "no-extra-boolean-cast": "off" + } +} diff --git a/build/build.sh b/build/build.sh deleted file mode 100755 index 00533e92..00000000 --- a/build/build.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env bash - -cd `dirname "$0"` - -git rev-parse --short HEAD #make sure git in place - -mkdir -p out -rm -rf out/* - -> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/canvas.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/io.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/history.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/shapes/arc.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/shapes/circle.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/shapes/segment.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/shapes/dim.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/helpers.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/math/vector.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/math/math.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/math/qr.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/math/matrix.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/math/optim.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/math/lm.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/constr/constraints.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/constr/solver.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/parametric.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/fetchers.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/engine.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/sketcher/main2d.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/ui.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/ui/toolkit.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/math/graph.js >> out/app.js -java -jar yuic.jar --disable-optimizations ../web/app/app-init.js >> out/app.js - -sed -n \ -'/<\!--\$\$\$javascript_start\$\$\$-->/{:a;N;/<\!--\$\$\$javascript_end\$\$\$-->/!ba;N;s|.*\n| |};p' \ - ../web/sketcher.html > out/sketcher.html - -echo >> out/sketcher.html -echo '" >> out/sketcher.html - -#now make it work inside out dir -ln -sf ../../web/img/ out/img -ln -sf ../../web/css/ out/css -mkdir -p out/lib -ln -sf ../../../web/lib/jquery-2.1.0.min.js out/lib/jquery-2.1.0.min.js -ln -sf ../../../web/lib/numeric-1.2.6.js out/lib/numeric-1.2.6.js -ln -sf ../../../web/lib/diff_match_patch.js out/lib/diff_match_patch.js -ln -sf ../../../web/lib/font-awesome out/lib/font-awesome - diff --git a/build/publish.sh b/build/publish.sh old mode 100755 new mode 100644 index 229d71e2..9f0e4c31 --- a/build/publish.sh +++ b/build/publish.sh @@ -2,4 +2,4 @@ cd `dirname "$0"` -aws s3 sync ../web/ s3://sketcher/ +aws s3 sync ./web/ s3://sketcher/ diff --git a/build/yuic.jar b/build/yuic.jar deleted file mode 100644 index a1cf0a09..00000000 Binary files a/build/yuic.jar and /dev/null differ diff --git a/package.json b/package.json new file mode 100644 index 00000000..5906fb91 --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "jsketcher", + "version": "0.1.0", + "description": "JS.Sketcher is a parametric 2D and 3D CAD modeler written in pure javascript", + "scripts": { + "start": "webpack-dev-server --content-base web/ --port 3000", + "build": "webpack --config webpack.config.js --progress --profile --colors", + "lint": "eslint web/app -c ./build/.eslintrc.json --ignore-path ./build/.eslintignore" + }, + "repository": { + "type": "git", + "url": "https://github.com/xibyte/jsketcher.git" + }, + "keywords": [ + "parametric", + "cad" + ], + "author": "Val Erastov (http://github.com/xibyte)", + "license": "AGPL-3.0", + "bugs": { + "url": "https://github.com/xibyte/jsketcher/issues" + }, + "homepage": "https://github.com/xibyte/jsketcher", + "devDependencies": { + "babel-cli": "6.14.0", + "babel-core": "6.14.0", + "babel-eslint": "6.1.2", + "babel-loader": "6.2.5", + "babel-preset-es2015": "6.14.0", + "css-loader": "0.24.0", + "eslint": "3.2.0", + "eslint-config-airbnb-base": "5.0.1", + "eslint-plugin-babel": "3.2.0", + "eslint-plugin-import": "1.12.0", + "style-loader": "0.13.1", + "webpack": "1.13.2", + "webpack-dev-server": "1.15.0" + }, + "dependencies": { + "diff-match-patch": "1.0.0", + "numeric": "1.2.6" + } +} diff --git a/web/app/3d/ctrl.js b/web/app/3d/ctrl.js index d2650bfe..1a364f3e 100644 --- a/web/app/3d/ctrl.js +++ b/web/app/3d/ctrl.js @@ -1,9 +1,14 @@ +import * as tk from '../ui/toolkit' +import * as cad_utils from '../utils/cad-utils' +import * as math from '../math/math' +import * as workbench from './workbench' +import {ExtrudeWizard, PlaneWizard} from './wizards/wizards' +import {IO} from '../sketcher/io' -TCAD.UI = function(app) { +function UI(app) { this.app = app; this.viewer = app.viewer; - var tk = TCAD.toolkit; var mainBox = new tk.Box(); mainBox.root.css({height : '100%'}); var propFolder = new tk.Folder("Solid's Properties"); @@ -53,7 +58,7 @@ TCAD.UI = function(app) { rows.removeClass('history-selected'); rows.eq(craft.historyPointer).addClass('history-selected'); var op = craft.history[craft.historyPointer]; - historyWizard = TCAD.UI.createWizard(op, app, mainBox); + historyWizard = UI.createWizard(op, app, mainBox); finishHistory.root.show(); } else { finishHistory.root.hide(); @@ -80,7 +85,7 @@ TCAD.UI = function(app) { var op = JSON.parse(JSON.stringify(craft.history[craft.historyPointer])); op.protoParams = historyWizard.currentParams(); historyWizard.close(); - historyWizard = TCAD.UI.createWizard(op, app, mainBox); + historyWizard = UI.createWizard(op, app, mainBox); } }); @@ -94,7 +99,7 @@ TCAD.UI = function(app) { if (app.viewer.selectionMgr.selection.length == 0) { return; } - TCAD.UI.createCutExtrudeWizard(isCut, ui.app, app.viewer.selectionMgr.selection[0], mainBox); + UI.createCutExtrudeWizard(isCut, ui.app, app.viewer.selectionMgr.selection[0], mainBox); } } @@ -103,7 +108,7 @@ TCAD.UI = function(app) { edit.root.click(tk.methodRef(app, "sketchFace")); refreshSketches.root.click(tk.methodRef(app, "refreshSketches")); addPlane.root.click(function() { - TCAD.UI.createPlaneWizard(app, mainBox); + UI.createPlaneWizard(app, mainBox); }); printSolids.root.click(function () { app.findAllSolids().map(function(o) { @@ -139,17 +144,17 @@ TCAD.UI = function(app) { app.viewer.selectionMgr.deselectAll(); }); stlExport.root.click(function() { - var allPolygons = TCAD.utils.arrFlatten1L(app.findAllSolids().map(function (s) { + var allPolygons = cad_utils.arrFlatten1L(app.findAllSolids().map(function (s) { return s.csg.toPolygons() })); var stl = CSG.fromPolygons(allPolygons).toStlString(); - TCAD.io.exportTextData(stl.data[0], app.id + ".stl"); + IO.exportTextData(stl.data[0], app.id + ".stl"); }) -}; +} -TCAD.UI.prototype.getInfoForOp = function(op) { +UI.prototype.getInfoForOp = function(op) { var p = op.params; - var norm2 = TCAD.math.norm2; + var norm2 = math.norm2; if ('CUT' === op.type) { return op.type + " (" + norm2(p.target) + ")"; } else if ('PAD' === op.type) { @@ -162,31 +167,30 @@ TCAD.UI.prototype.getInfoForOp = function(op) { return op.type; }; -TCAD.UI.createWizard = function(op, app, alignComponent) { +UI.createWizard = function(op, app, alignComponent) { var initParams = op.protoParams; var face = op.face !== undefined ? app.findFace(op.face) : null; if (face != null) { app.viewer.selectionMgr.select(face); } if ('CUT' === op.type) { - return TCAD.UI.createCutExtrudeWizard(true, app, face, alignComponent, initParams, true); + return UI.createCutExtrudeWizard(true, app, face, alignComponent, initParams, true); } else if ('PAD' === op.type) { - return TCAD.UI.createCutExtrudeWizard(false, app, face, alignComponent, initParams, true); + return UI.createCutExtrudeWizard(false, app, face, alignComponent, initParams, true); } else if ('PLANE' === op.type) { - return TCAD.UI.createPlaneWizard(app, alignComponent, initParams, true); + return UI.createPlaneWizard(app, alignComponent, initParams, true); } return null; }; -TCAD.UI.createCutExtrudeWizard = function (isCut, app, face, alignComponent, initParams, overriding) { - var tk = TCAD.toolkit; +UI.createCutExtrudeWizard = function (isCut, app, face, alignComponent, initParams, overriding) { function def(index, fallback) { return !!initParams ? initParams[index] : fallback; } - var normal = TCAD.utils.vec(face.csgGroup.plane.normal); - var polygons = TCAD.craft.getSketchedPolygons3D(app, face); + var normal = cad_utils.vec(face.csgGroup.plane.normal); + var polygons = workbench.getSketchedPolygons3D(app, face); var box = new tk.Box(); box.root.css({left : (alignComponent.root.width() + 10) + 'px', top : 0}); @@ -196,7 +200,7 @@ TCAD.UI.createCutExtrudeWizard = function (isCut, app, face, alignComponent, ini var scale = new tk.Number("Expansion", def(1, 1), 0.1, 1); var deflection = new tk.Number("Deflection", def(2, 0), 1); var angle = new tk.Number("Angle", def(3, 0), 5); - var wizard = new TCAD.wizards.ExtrudeWizard(app.viewer, polygons); + var wizard = new ExtrudeWizard(app.viewer, polygons); function onChange() { var depthValue = theValue.input.val(); var scaleValue = scale.input.val(); @@ -248,12 +252,10 @@ TCAD.UI.createCutExtrudeWizard = function (isCut, app, face, alignComponent, ini } tk.add(folder, new tk.ButtonRow(["Cancel", "OK"], [close, isCut ? applyCut : applyExtrude])); - return new TCAD.UI.WizardRef(wizard, box, close, protoParams); + return new UI.WizardRef(wizard, box, close, protoParams); }; -TCAD.UI.createPlaneWizard = function (app, alignComponent, initParams, overiding) { - var tk = TCAD.toolkit; - +UI.createPlaneWizard = function (app, alignComponent, initParams, overiding) { var box = new tk.Box(); box.root.css({left : (alignComponent.root.width() + 10) + 'px', top : 0}); var folder = new tk.Folder("Add a Plane"); @@ -264,7 +266,7 @@ TCAD.UI.createPlaneWizard = function (app, alignComponent, initParams, overiding tk.add(folder, orientation); tk.add(folder, depth); - var wizard = new TCAD.wizards.PlaneWizard(app.viewer); + var wizard = new PlaneWizard(app.viewer); var orientationValue, w; function onChange() { wizard.update(orientationValue = orientation.getValue(), w = depth.input.val()); @@ -289,12 +291,14 @@ TCAD.UI.createPlaneWizard = function (app, alignComponent, initParams, overiding depth.input.on('t-change', onChange); onChange(); tk.add(folder, new tk.ButtonRow(["Cancel", "OK"], [close, ok])); - return new TCAD.UI.WizardRef(wizard, box, close, protoParams); + return new UI.WizardRef(wizard, box, close, protoParams); }; -TCAD.UI.WizardRef = function(wizard, box, close, currentParams) { +UI.WizardRef = function(wizard, box, close, currentParams) { this.wizard = wizard; this.box = box; this.close = close; this.currentParams = currentParams; -}; \ No newline at end of file +}; + +export {UI} \ No newline at end of file diff --git a/web/app/3d/main.js b/web/app/3d/modeler-app.js similarity index 94% rename from web/app/3d/main.js rename to web/app/3d/modeler-app.js index 41838950..d71f3f4a 100644 --- a/web/app/3d/main.js +++ b/web/app/3d/modeler-app.js @@ -1,6 +1,13 @@ -TCAD = {}; +import {Bus} from '../ui/toolkit' +import {Viewer} from './viewer' +import {UI} from './ctrl' +import Vector from '../math/vector' +import {Matrix3, AXIS, ORIGIN, IDENTITY_BASIS} from '../math/l3space' +import * as workbench from './workbench' +import * as cad_utils from '../utils/cad-utils' +import * as math from '../math/math' -TCAD.App = function() { +function App() { this.id = window.location.hash.substring(1); if (!this.id) { @@ -9,10 +16,10 @@ TCAD.App = function() { if (this.id == "sample" ) { this.initSample(); } - this.bus = new TCAD.Bus(); - this.viewer = new TCAD.Viewer(this.bus); - this.ui = new TCAD.UI(this); - this.craft = new TCAD.Craft(this); + this.bus = new Bus(); + this.viewer = new Viewer(this.bus); + this.ui = new UI(this); + this.craft = new workbench.Craft(this); if (this.id == '$scratch$') { this.addBox(); @@ -39,10 +46,10 @@ TCAD.App = function() { for (var oi = 0; oi < viewer.scene.children.length; ++oi) { var obj = viewer.scene.children[oi]; if (obj.geometry !== undefined && obj.geometry.polyFaces !== undefined) { - for (var i = 0; i < box.geometry.polyFaces.length; i++) { - var sketchFace = box.geometry.polyFaces[i]; + for (var i = 0; i < obj.geometry.polyFaces.length; i++) { + var sketchFace = obj.geometry.polyFaces[i]; if (sketchFace.id == sketchFaceId) { - var geom = TCAD.workbench.readSketchGeom(JSON.parse(evt.newValue)); + var geom = workbench.readSketchGeom(JSON.parse(evt.newValue)); sketchFace.syncSketches(geom); viewer.render(); break; @@ -60,15 +67,15 @@ TCAD.App = function() { app._refreshSketches(); }); window.addEventListener('storage', storage_handler, false); -}; +} -TCAD.App.prototype.findAllSolids = function() { +App.prototype.findAllSolids = function() { return this.viewer.workGroup.children .filter(function(obj) {return obj.__tcad_solid !== undefined} ) .map(function(obj) {return obj.__tcad_solid} ) }; -TCAD.App.prototype.findFace = function(faceId) { +App.prototype.findFace = function(faceId) { var solids = this.findAllSolids(); for (var i = 0; i < solids.length; i++) { var solid = solids[i]; @@ -82,7 +89,7 @@ TCAD.App.prototype.findFace = function(faceId) { return null; }; -TCAD.App.prototype.findSolid = function(solidId) { +App.prototype.findSolid = function(solidId) { var solids = this.findAllSolids(); for (var i = 0; i < solids.length; i++) { var solid = solids[i]; @@ -93,7 +100,7 @@ TCAD.App.prototype.findSolid = function(solidId) { return null; }; -TCAD.App.prototype.indexEntities = function() { +App.prototype.indexEntities = function() { var out = {solids : {}, faces : {}}; var solids = this.findAllSolids(); for (var i = 0; i < solids.length; i++) { @@ -107,15 +114,15 @@ TCAD.App.prototype.indexEntities = function() { return out; }; -TCAD.App.prototype.faceStorageKey = function(polyFaceId) { +App.prototype.faceStorageKey = function(polyFaceId) { return "TCAD.projects."+this.id+".sketch." + polyFaceId; }; -TCAD.App.prototype.projectStorageKey = function(polyFaceId) { +App.prototype.projectStorageKey = function(polyFaceId) { return "TCAD.projects."+this.id; }; -TCAD.App.prototype.sketchFace = function() { +App.prototype.sketchFace = function() { if (this.viewer.selectionMgr.selection.length == 0) { return; } @@ -137,10 +144,10 @@ TCAD.App.prototype.sketchFace = function() { return a.sketchConnectionObject.id === b.sketchConnectionObject.id; } - var paths = TCAD.craft.reconstructSketchBounds(polyFace.solid.csg, polyFace); + var paths = workbench.reconstructSketchBounds(polyFace.solid.csg, polyFace); //polyFace.polygon.collectPaths(paths); - var _3dTransformation = new TCAD.Matrix().setBasis(polyFace.basis()); + var _3dTransformation = new Matrix3().setBasis(polyFace.basis()); var _2dTr = _3dTransformation.invert(); function addSegment(a, b) { @@ -163,36 +170,36 @@ TCAD.App.prototype.sketchFace = function() { var a = arc[1], b = arc[arc.length - 2]; var mid = (arc.length / 2) >> 0; - var c = TCAD.math.circleFromPoints(a, arc[mid], b); + var c = math.circleFromPoints(a, arc[mid], b); if (c == null) { addArcAsSegments(arc); return; } - var dist = TCAD.math.distanceAB; + var dist = math.distanceAB; var rad = dist(a, c); - if (Math.abs(rad - dist(b, c)) > TCAD.TOLERANCE) { + if (Math.abs(rad - dist(b, c)) > math.TOLERANCE) { addArcAsSegments(arc); return; } var firstPoint = arc[0]; var lastPoint = arc[arc.length - 1]; - if (Math.abs(rad - dist(firstPoint, c)) < TCAD.TOLERANCE) { + if (Math.abs(rad - dist(firstPoint, c)) < math.TOLERANCE) { a = firstPoint; } else { addSegment(firstPoint, a); } - if (Math.abs(rad - dist(lastPoint, c)) < TCAD.TOLERANCE) { + if (Math.abs(rad - dist(lastPoint, c)) < math.TOLERANCE) { b = lastPoint; } else { addSegment(b, lastPoint); } - if (!TCAD.geom.isCCW([a, arc[mid], b])) { + if (!cad_utils.isCCW([a, arc[mid], b])) { var t = a; a = b; b = t; @@ -205,10 +212,10 @@ TCAD.App.prototype.sketchFace = function() { } function addCircle(circle) { var n = circle.length; - //var c = TCAD.math.circleFromPoints(circle[0], circle[((n / 3) >> 0) % n], circle[((2 * n / 3) >> 0) % n]); - var c = TCAD.math.circleFromPoints(circle[0], circle[1], circle[2]); + //var c = math.circleFromPoints(circle[0], circle[((n / 3) >> 0) % n], circle[((2 * n / 3) >> 0) % n]); + var c = math.circleFromPoints(circle[0], circle[1], circle[2]); if (c === null) return; - var r = TCAD.math.distanceAB(circle[0], c); + var r = math.distanceAB(circle[0], c); data.boundary.circles.push({ c : {x : c.x, y: c.y}, r : r @@ -242,13 +249,13 @@ TCAD.App.prototype.sketchFace = function() { addCircle(trPath(path)); continue; } - TCAD.utils.iteratePath(path, 0, function(a, b, ai, bi) { + cad_utils.iteratePath(path, 0, function(a, b, ai, bi) { shift = bi; return sameSketchObject(a, b); }); var currSko = null; var arc = null; - TCAD.utils.iteratePath(path, shift+1, function(a, b, ai, bi, iterNumber, path) { + cad_utils.iteratePath(path, shift+1, function(a, b, ai, bi, iterNumber, path) { var isArc = a.sketchConnectionObject !== undefined && (a.sketchConnectionObject._class == 'TCAD.TWO.Arc' || a.sketchConnectionObject._class == 'TCAD.TWO.Circle'); //if circle gets splitted var a2d = _2dTr.apply(a); @@ -284,7 +291,7 @@ TCAD.App.prototype.sketchFace = function() { window.open("sketcher.html#" + faceStorageKey.substring(14), "Edit Sketch", "height=900,width=1200"); }; -TCAD.App.prototype.extrude = function() { +App.prototype.extrude = function() { if (this.viewer.selectionMgr.selection.length == 0) { return; @@ -303,7 +310,7 @@ TCAD.App.prototype.extrude = function() { }); }; -TCAD.App.prototype.cut = function() { +App.prototype.cut = function() { if (this.viewer.selectionMgr.selection.length == 0) { return; @@ -322,7 +329,7 @@ TCAD.App.prototype.cut = function() { }); }; -TCAD.App.prototype.addBox = function() { +App.prototype.addBox = function() { this.craft.modify({ type: 'BOX', solids : [], @@ -330,13 +337,13 @@ TCAD.App.prototype.addBox = function() { }); }; -TCAD.App.prototype.refreshSketches = function() { +App.prototype.refreshSketches = function() { this._refreshSketches(); this.bus.notify('refreshSketch'); this.viewer.render(); }; -TCAD.App.prototype._refreshSketches = function() { +App.prototype._refreshSketches = function() { var allSolids = this.findAllSolids(); for (var oi = 0; oi < allSolids.length; ++oi) { var obj = allSolids[oi]; @@ -345,20 +352,20 @@ TCAD.App.prototype._refreshSketches = function() { var faceStorageKey = this.faceStorageKey(sketchFace.id); var savedFace = localStorage.getItem(faceStorageKey); if (savedFace != null) { - var geom = TCAD.workbench.readSketchGeom(JSON.parse(savedFace)); + var geom = workbench.readSketchGeom(JSON.parse(savedFace)); sketchFace.syncSketches(geom); } } } }; -TCAD.App.prototype.save = function() { +App.prototype.save = function() { var data = {}; data.history = this.craft.history; localStorage.setItem(this.projectStorageKey(), JSON.stringify(data)); }; -TCAD.App.prototype.load = function() { +App.prototype.load = function() { var project = localStorage.getItem(this.projectStorageKey()); if (!!project) { var data = JSON.parse(project); @@ -368,8 +375,7 @@ TCAD.App.prototype.load = function() { } }; - -TCAD.App.prototype.initSample = function() { +App.prototype.initSample = function() { localStorage.setItem("TCAD.projects.sample", '{"history":[{"type":"PLANE","solids":[],"params":{"basis":[[1,0,0],[0,0,1],[0,1,0]],"depth":"0"},"protoParams":["XZ","0"]},{"type":"PAD","solids":[0],"face":"0:0","params":{"target":[0,-50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]},{"type":"PAD","solids":[1],"face":"1:1","params":{"target":[0,-50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]},{"type":"CUT","solids":[2],"face":"2:0","params":{"target":[0,252,0],"expansionFactor":"1"},"protoParams":["252","1","0","0"]},{"type":"CUT","solids":[3],"face":"1:1$","params":{"target":[0,50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]}]}'); localStorage.setItem("TCAD.projects.sample.sketch.0:0", '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[]},{"name":"__bounds__","style":{"lineWidth":2,"strokeStyle":"#fff5c3","fillStyle":"#000000"},"data":[{"id":6,"_class":"TCAD.TWO.Segment","aux":true,"edge":0,"points":[[0,[1,-400],[2,400]],[3,[4,-400],[5,-400]]]},{"id":13,"_class":"TCAD.TWO.Segment","aux":true,"edge":2,"points":[[7,[8,-400],[9,-400]],[10,[11,400],[12,-400]]]},{"id":20,"_class":"TCAD.TWO.Segment","aux":true,"edge":4,"points":[[14,[15,400],[16,-400]],[17,[18,400],[19,400]]]},{"id":27,"_class":"TCAD.TWO.Segment","aux":true,"edge":6,"points":[[21,[22,400],[23,400]],[24,[25,-400],[26,400]]]}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":34,"_class":"TCAD.TWO.Segment","points":[[28,[29,-80.41502600578134],[30,240.48794311524324]],[31,[32,252.10163324769275],[33,71.15131239804411]]]},{"id":41,"_class":"TCAD.TWO.Segment","points":[[35,[36,255.946878629896],[37,-145.76094357167156]],[38,[39,-91.17342089039929],[40,-338.36716169336114]]]},{"id":48,"_class":"TCAD.TWO.Segment","points":[[42,[43,-172.00749593627577],[44,-240.71428346724593]],[45,[46,-88.51020843368133],[47,-140.46311545122035]]]},{"id":55,"_class":"TCAD.TWO.Segment","points":[[49,[50,-102.18982576106004],[51,18.31440664196805]],[52,[53,-182.7982464866314],[54,86.82364838151852]]]},{"id":72,"_class":"TCAD.TWO.Arc","points":[[63,[64,255.946878629896],[65,-145.76094357167156]],[66,[67,252.10163324769275],[68,71.15131239804411]],[69,[70,196.33682709088268],[71,-38.32745196977044]]]},{"id":83,"_class":"TCAD.TWO.Arc","points":[[74,[75,-80.41502600578134],[76,240.48794311524324]],[77,[78,-182.7982464866314],[79,86.82364838151852]],[80,[81,-122.59914075444685],[82,157.65429488839598]]]},{"id":94,"_class":"TCAD.TWO.Arc","points":[[85,[86,-88.51020843368133],[87,-140.46311545122035]],[88,[89,-102.18982576106004],[90,18.31440664196805]],[91,[92,-175.53398017227],[93,-67.98267439986091]]]},{"id":105,"_class":"TCAD.TWO.Arc","points":[[96,[97,-172.00749593627577],[98,-240.71428346724593]],[99,[100,-91.17342089039929],[101,-338.36716169336114]],[102,[103,-122.4591797419898],[104,-281.9821285194346]]]}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[]}],"constraints":[["Tangent",[72,41]],["Tangent",[72,34]],["coi",[63,35]],["coi",[66,31]],["Tangent",[83,34]],["Tangent",[83,55]],["coi",[74,28]],["coi",[77,52]],["Tangent",[94,48]],["Tangent",[94,55]],["coi",[85,45]],["coi",[88,49]],["Tangent",[105,48]],["Tangent",[105,41]],["coi",[96,42]],["coi",[99,38]]],"boundary":{"lines":[{"a":{"x":-400,"y":400},"b":{"x":-400,"y":-400}},{"a":{"x":-400,"y":-400},"b":{"x":400,"y":-400}},{"a":{"x":400,"y":-400},"b":{"x":400,"y":400}},{"a":{"x":400,"y":400},"b":{"x":-400,"y":400}}],"arcs":[],"circles":[]}}'); localStorage.setItem("TCAD.projects.sample.sketch.1:0", '{"boundary":{"lines":[{"a":{"x":80.41502600578134,"y":240.48794311524324},"b":{"x":-252.10163324769275,"y":71.15131239804411}},{"a":{"x":-255.946878629896,"y":-145.76094357167156},"b":{"x":91.17342089039929,"y":-338.36716169336114}},{"a":{"x":172.00749593627577,"y":-240.71428346724593},"b":{"x":88.51020843368133,"y":-140.46311545122035}},{"a":{"x":102.18982576106004,"y":18.31440664196805},"b":{"x":182.7982464866314,"y":86.82364838151852}}],"arcs":[{"a":{"x":-252.10163324769275,"y":71.15131239804411},"b":{"x":-255.946878629896,"y":-145.76094357167156},"c":{"x":-196.33682672526209,"y":-38.32745176660378}},{"a":{"x":91.17342089039929,"y":-338.36716169336114},"b":{"x":172.00749593627577,"y":-240.71428346724593},"c":{"x":122.45917974196499,"y":-281.98212851943595}},{"a":{"x":102.18982576106004,"y":18.31440664196805},"b":{"x":88.51020843368133,"y":-140.46311545122035},"c":{"x":175.5339801724776,"y":-67.98267439979745}},{"a":{"x":182.7982464866314,"y":86.82364838151852},"b":{"x":80.41502600578134,"y":240.48794311524324},"c":{"x":122.59914075460381,"y":157.65429488902345}}],"circles":[]}}'); @@ -377,3 +383,5 @@ TCAD.App.prototype.initSample = function() { localStorage.setItem("TCAD.projects.sample.sketch.1:1$", '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[]},{"name":"__bounds__","style":{"lineWidth":2,"strokeStyle":"#fff5c3","fillStyle":"#000000"},"data":[{"id":909,"_class":"TCAD.TWO.Segment","aux":true,"edge":0,"points":[[903,[904,-124.85084567322261],[905,-346.42086381904903]],[906,[907,-121.65017719515622],[908,-346.2848202888915]]]},{"id":916,"_class":"TCAD.TWO.Segment","aux":true,"edge":2,"points":[[910,[911,-121.65017719515622],[912,-346.2848202888915]],[913,[914,-126.76777558258588],[915,-346.1961840440328]]]},{"id":923,"_class":"TCAD.TWO.Segment","aux":true,"edge":4,"points":[[917,[918,-126.76777558258588],[919,-346.1961840440328]],[920,[921,-124.85084567322261],[922,-346.42086381904903]]]},{"id":930,"_class":"TCAD.TWO.Segment","aux":true,"edge":6,"points":[[924,[925,-116.53642857559844],[926,-346.06746181540075]],[927,[928,-114.6081175386342],[929,-345.98549948705966]]]},{"id":937,"_class":"TCAD.TWO.Segment","aux":true,"edge":8,"points":[[931,[932,-114.6081175386342],[933,-345.98549948705966]],[934,[935,-111.4694612123672],[936,-345.34392095429644]]]},{"id":944,"_class":"TCAD.TWO.Segment","aux":true,"edge":10,"points":[[938,[939,-111.4694612123672],[940,-345.34392095429644]],[941,[942,-116.53642857559844],[943,-346.06746181540075]]]},{"id":951,"_class":"TCAD.TWO.Segment","aux":true,"edge":12,"points":[[945,[946,-136.89021476237798],[947,-344.7017757862507]],[948,[949,-135.03311997329527],[950,-345.22741846263864]]]},{"id":958,"_class":"TCAD.TWO.Segment","aux":true,"edge":14,"points":[[952,[953,-135.03311997329527],[954,-345.22741846263864]],[955,[956,-131.85134223207632],[957,-345.6003486900595]]]},{"id":965,"_class":"TCAD.TWO.Segment","aux":true,"edge":16,"points":[[959,[960,-131.85134223207632],[961,-345.6003486900595]],[962,[963,-136.89021476237798],[964,-344.7017757862507]]]},{"id":972,"_class":"TCAD.TWO.Segment","aux":true,"edge":18,"points":[[966,[967,-106.45479019397476],[968,-344.31886279569994]],[969,[970,-104.5638397013956],[971,-343.9323301153285]]]},{"id":979,"_class":"TCAD.TWO.Segment","aux":true,"edge":20,"points":[[973,[974,-104.5638397013956],[975,-343.9323301153285]],[976,[977,-102.65803400883827],[978,-343.1402615618105]]]},{"id":986,"_class":"TCAD.TWO.Segment","aux":true,"edge":22,"points":[[980,[981,-102.65803400883827],[982,-343.1402615618105]],[983,[984,-106.45479019397476],[985,-344.31886279569994]]]},{"id":993,"_class":"TCAD.TWO.Segment","aux":true,"edge":24,"points":[[987,[988,-146.64788251166573],[989,-341.6220110088687]],[990,[991,-144.89756439084644],[992,-342.43532998379334]]]},{"id":1000,"_class":"TCAD.TWO.Segment","aux":true,"edge":26,"points":[[994,[995,-144.89756439084644],[996,-342.43532998379334]],[997,[998,-141.81510277637994],[999,-343.30780745905]]]},{"id":1007,"_class":"TCAD.TWO.Segment","aux":true,"edge":28,"points":[[1001,[1002,-141.81510277637994],[1003,-343.30780745905]],[1004,[1005,-146.64788251166573],[1006,-341.6220110088687]]]},{"id":1014,"_class":"TCAD.TWO.Segment","aux":true,"edge":30,"points":[[1008,[1009,-91.17342089039929],[1010,-338.36716169336114]],[1011,[1012,255.946878629896],[1013,-145.76094357167156]]]},{"id":1021,"_class":"TCAD.TWO.Segment","aux":true,"edge":32,"points":[[1015,[1016,252.10163324769275],[1017,71.15131239804411]],[1018,[1019,-80.41502600578134],[1020,240.48794311524324]]]},{"id":1028,"_class":"TCAD.TWO.Segment","aux":true,"edge":34,"points":[[1022,[1023,-80.41502600578134],[1024,240.48794311524324]],[1025,[1026,-81.03180870826053],[1027,240.74252296578175]]]},{"id":1035,"_class":"TCAD.TWO.Segment","aux":true,"edge":36,"points":[[1029,[1030,-81.03180870826053],[1031,240.74252296578175]],[1032,[1033,-68.90130878449338],[1034,233.53219455234265]]]},{"id":1042,"_class":"TCAD.TWO.Segment","aux":true,"edge":38,"points":[[1036,[1037,-68.90130878449338],[1038,233.53219455234265]],[1039,[1040,-57.55454096229795],[1041,224.06297544710796]]]},{"id":1049,"_class":"TCAD.TWO.Segment","aux":true,"edge":40,"points":[[1043,[1044,-183.60296592346776],[1045,87.66174623159009]],[1046,[1047,-182.7982464866314],[1048,86.82364838151852]]]},{"id":1056,"_class":"TCAD.TWO.Segment","aux":true,"edge":42,"points":[[1050,[1051,-182.7982464866314],[1052,86.82364838151852]],[1053,[1054,-102.18982576106004],[1055,18.31440664196805]]]},{"id":1063,"_class":"TCAD.TWO.Segment","aux":true,"edge":44,"points":[[1057,[1058,-88.51020843368133],[1059,-140.46311545122035]],[1060,[1061,-172.00749593627577],[1062,-240.71428346724593]]]},{"id":1070,"_class":"TCAD.TWO.Segment","aux":true,"edge":46,"points":[[1064,[1065,-172.00749593627577],[1066,-240.71428346724593]],[1067,[1068,-173.85553817260416],[1069,-243.3310613415531]]]},{"id":1077,"_class":"TCAD.TWO.Segment","aux":true,"edge":48,"points":[[1071,[1072,-173.85553817260416],[1073,-243.3310613415531]],[1074,[1075,-169.45270100330094],[1076,-237.82695178551998]]]},{"id":1084,"_class":"TCAD.TWO.Segment","aux":true,"edge":50,"points":[[1078,[1079,-169.45270100330094],[1080,-237.82695178551998]],[1081,[1082,-161.86089236160166],[1083,-230.93728827497424]]]},{"id":1091,"_class":"TCAD.TWO.Segment","aux":true,"edge":52,"points":[[1085,[1086,-93.05073865718533],[1087,-339.1473904301305]],[1088,[1089,-91.17342089039929],[1090,-338.36716169336114]]]},{"id":1098,"_class":"TCAD.TWO.Segment","aux":true,"edge":54,"points":[[1092,[1093,-155.79413550803565],[1094,-337.03473653312227]],[1095,[1096,-154.194836623249],[1097,-338.11517364666224]]]},{"id":1105,"_class":"TCAD.TWO.Segment","aux":true,"edge":56,"points":[[1099,[1100,-154.194836623249],[1101,-338.11517364666224]],[1102,[1103,-151.28960612438567],[1104,-339.465144867979]]]},{"id":1112,"_class":"TCAD.TWO.Segment","aux":true,"edge":58,"points":[[1106,[1107,-151.28960612438567],[1108,-339.465144867979]],[1109,[1110,-155.79413550803565],[1111,-337.03473653312227]]]},{"id":1119,"_class":"TCAD.TWO.Segment","aux":true,"edge":60,"points":[[1113,[1114,-164.09778508175484],[1115,-331.0559043105029]],[1116,[1117,-162.68993070681643],[1118,-332.3761494916342]]]},{"id":1126,"_class":"TCAD.TWO.Segment","aux":true,"edge":62,"points":[[1120,[1121,-162.68993070681643],[1122,-332.3761494916342]],[1123,[1124,-160.03536646411845],[1125,-334.1694914087516]]]},{"id":1133,"_class":"TCAD.TWO.Segment","aux":true,"edge":64,"points":[[1127,[1128,-160.03536646411845],[1129,-334.1694914087516]],[1130,[1131,-164.09778508175484],[1132,-331.0559043105029]]]},{"id":1140,"_class":"TCAD.TWO.Segment","aux":true,"edge":66,"points":[[1134,[1135,-171.34894094227198],[1136,-323.8366405200772]],[1137,[1138,-170.1681172325551],[1139,-325.3633220998529]]]},{"id":1147,"_class":"TCAD.TWO.Segment","aux":true,"edge":68,"points":[[1141,[1142,-170.1681172325551],[1143,-325.3633220998529]],[1144,[1145,-167.83131832762314],[1146,-327.5547046380108]]]},{"id":1154,"_class":"TCAD.TWO.Segment","aux":true,"edge":70,"points":[[1148,[1149,-167.83131832762314],[1150,-327.5547046380108]],[1151,[1152,-171.34894094227198],[1153,-323.8366405200772]]]},{"id":1161,"_class":"TCAD.TWO.Segment","aux":true,"edge":72,"points":[[1155,[1156,-177.36431654830434],[1157,-315.5594255713455]],[1158,[1159,-176.44037103403136],[1160,-317.2539538143128]]]},{"id":1168,"_class":"TCAD.TWO.Segment","aux":true,"edge":74,"points":[[1162,[1163,-176.44037103403136],[1164,-317.2539538143128]],[1165,[1166,-174.48040443457532],[1167,-319.787985676768]]]},{"id":1175,"_class":"TCAD.TWO.Segment","aux":true,"edge":76,"points":[[1169,[1170,-174.48040443457532],[1171,-319.787985676768]],[1172,[1173,-177.36431654830434],[1174,-315.5594255713455]]]},{"id":1182,"_class":"TCAD.TWO.Segment","aux":true,"edge":78,"points":[[1176,[1177,-181.9918620183506],[1178,-306.43348157021944]],[1179,[1180,-181.34814915237982],[1181,-308.25302410223765]]]},{"id":1189,"_class":"TCAD.TWO.Segment","aux":true,"edge":80,"points":[[1183,[1184,-181.34814915237982],[1185,-308.25302410223765]],[1186,[1187,-179.81455668401662],[1188,-311.0656528889991]]]},{"id":1196,"_class":"TCAD.TWO.Segment","aux":true,"edge":82,"points":[[1190,[1191,-179.81455668401662],[1192,-311.0656528889991]],[1193,[1194,-181.9918620183506],[1195,-306.43348157021944]]]},{"id":1203,"_class":"TCAD.TWO.Segment","aux":true,"edge":84,"points":[[1197,[1198,-185.11460747614086],[1199,-296.6894838385504]],[1200,[1201,-184.76739830644107],[1202,-298.5880483152473]]]},{"id":1210,"_class":"TCAD.TWO.Segment","aux":true,"edge":86,"points":[[1204,[1205,-184.76739830644107],[1206,-298.5880483152473]],[1207,[1208,-183.69894439028664],[1209,-301.6081795674206]]]},{"id":1217,"_class":"TCAD.TWO.Segment","aux":true,"edge":88,"points":[[1211,[1212,-183.69894439028664],[1213,-301.6081795674206]],[1214,[1215,-185.11460747614086],[1216,-296.6894838385504]]]},{"id":1224,"_class":"TCAD.TWO.Segment","aux":true,"edge":90,"points":[[1218,[1219,-186.65361968327025],[1220,-286.5737301634624]],[1221,[1222,-186.61169057171756],[1223,-288.5033268128508]]]},{"id":1231,"_class":"TCAD.TWO.Segment","aux":true,"edge":92,"points":[[1225,[1226,-186.61169057171756],[1227,-288.5033268128508]],[1228,[1229,-186.03538238106256],[1230,-291.6546210581988]]]},{"id":1238,"_class":"TCAD.TWO.Segment","aux":true,"edge":94,"points":[[1232,[1233,-186.03538238106256],[1234,-291.6546210581988]],[1235,[1236,-186.65361968327025],[1237,-286.5737301634624]]]},{"id":1245,"_class":"TCAD.TWO.Segment","aux":true,"edge":96,"points":[[1239,[1240,-186.56999722459386],[1241,-276.3419151596114]],[1242,[1243,-186.83440800799133],[1244,-278.25376981343675]]]},{"id":1252,"_class":"TCAD.TWO.Segment","aux":true,"edge":98,"points":[[1246,[1247,-186.83440800799133],[1248,-278.25376981343675]],[1249,[1250,-186.76481281142574],[1251,-281.4565721894818]]]},{"id":1259,"_class":"TCAD.TWO.Segment","aux":true,"edge":100,"points":[[1253,[1254,-186.76481281142574],[1255,-281.4565721894818]],[1256,[1257,-186.56999722459386],[1258,-276.3419151596114]]]},{"id":1266,"_class":"TCAD.TWO.Segment","aux":true,"edge":102,"points":[[1260,[1261,-184.86585381433073],[1262,-266.252667109051]],[1263,[1264,-185.42992101504922],[1265,-268.0984540612155]]]},{"id":1273,"_class":"TCAD.TWO.Segment","aux":true,"edge":104,"points":[[1267,[1268,-185.42992101504922],[1269,-268.0984540612155]],[1270,[1271,-185.86879796147372],[1272,-271.2718077410349]]]},{"id":1280,"_class":"TCAD.TWO.Segment","aux":true,"edge":106,"points":[[1274,[1275,-185.86879796147372],[1276,-271.2718077410349]],[1277,[1278,-184.86585381433073],[1279,-266.252667109051]]]},{"id":1287,"_class":"TCAD.TWO.Segment","aux":true,"edge":108,"points":[[1281,[1282,-181.58426486797975],[1283,-256.5610106471486]],[1284,[1285,-182.43373063136903],[1286,-258.2940741764191]]]},{"id":1294,"_class":"TCAD.TWO.Segment","aux":true,"edge":110,"points":[[1288,[1289,-182.43373063136903],[1290,-258.2940741764191]],[1291,[1292,-183.3699862842126],[1293,-261.35776670402527]]]},{"id":1301,"_class":"TCAD.TWO.Segment","aux":true,"edge":112,"points":[[1295,[1296,-183.3699862842126],[1297,-261.35776670402527]],[1298,[1299,-181.58426486797975],[1300,-256.5610106471486]]]},{"id":1308,"_class":"TCAD.TWO.Segment","aux":true,"edge":114,"points":[[1302,[1303,-176.80817869053936],[1304,-247.5119205374264]],[1305,[1306,-177.92157117890073],[1307,-249.08845421814587]]]},{"id":1315,"_class":"TCAD.TWO.Segment","aux":true,"edge":116,"points":[[1309,[1310,-177.92157117890073],[1311,-249.08845421814587]],[1312,[1313,-179.3315399235013],[1314,-251.96504502850303]]]},{"id":1322,"_class":"TCAD.TWO.Segment","aux":true,"edge":118,"points":[[1316,[1317,-179.3315399235013],[1318,-251.96504502850303]],[1319,[1320,-176.80817869053936],[1321,-247.5119205374264]]]},{"id":1329,"_class":"TCAD.TWO.Segment","aux":true,"edge":120,"points":[[1323,[1324,-199.52633139024357],[1325,105.99235078457345]],[1326,[1327,-195.81654775637261],[1328,100.38192696448344]]]},{"id":1336,"_class":"TCAD.TWO.Segment","aux":true,"edge":122,"points":[[1330,[1331,-195.81654775637261],[1332,100.38192696448344]],[1333,[1334,-195.41416831449038],[1335,99.96285749788738]]]},{"id":1343,"_class":"TCAD.TWO.Segment","aux":true,"edge":124,"points":[[1337,[1338,-195.41416831449038],[1339,99.96285749788738]],[1340,[1341,-199.52633139024357],[1342,105.99235078457345]]]},{"id":1350,"_class":"TCAD.TWO.Segment","aux":true,"edge":126,"points":[[1344,[1345,-206.74167768777465],[1346,118.83699711877475]],[1347,[1348,-203.9679416929228],[1349,112.70953935972136]]]},{"id":1357,"_class":"TCAD.TWO.Segment","aux":true,"edge":128,"points":[[1351,[1352,-203.9679416929228],[1353,112.70953935972136]],[1354,[1355,-203.59991146204723],[1356,112.1529555323074]]]},{"id":1364,"_class":"TCAD.TWO.Segment","aux":true,"edge":130,"points":[[1358,[1359,-203.59991146204723],[1360,112.1529555323074]],[1361,[1362,-206.74167768777465],[1363,118.83699711877475]]]},{"id":1371,"_class":"TCAD.TWO.Segment","aux":true,"edge":132,"points":[[1365,[1366,-211.83016381958026],[1367,132.6628233336642]],[1368,[1369,-210.06258683256036],[1370,126.17321460454002]]]},{"id":1378,"_class":"TCAD.TWO.Segment","aux":true,"edge":134,"points":[[1372,[1373,-210.06258683256036],[1374,126.17321460454002]],[1375,[1376,-209.7874174967478],[1377,125.56533826558501]]]},{"id":1385,"_class":"TCAD.TWO.Segment","aux":true,"edge":136,"points":[[1379,[1380,-209.7874174967478],[1381,125.56533826558501]],[1382,[1383,-211.83016381958026],[1384,132.6628233336642]]]},{"id":1392,"_class":"TCAD.TWO.Segment","aux":true,"edge":138,"points":[[1386,[1387,-214.66316877134335],[1388,147.1203557849574]],[1389,[1390,-213.94642960789847],[1391,140.43263309803072]]]},{"id":1399,"_class":"TCAD.TWO.Segment","aux":true,"edge":140,"points":[[1393,[1394,-213.94642960789847],[1395,140.43263309803072]],[1396,[1397,-213.77107658712956],[1398,139.78882946027298]]]},{"id":1406,"_class":"TCAD.TWO.Segment","aux":true,"edge":142,"points":[[1400,[1401,-213.77107658712956],[1402,139.78882946027298]],[1403,[1404,-214.66316877134335],[1405,147.1203557849574]]]},{"id":1413,"_class":"TCAD.TWO.Segment","aux":true,"edge":144,"points":[[1407,[1408,-215.16908303852756],[1409,161.84415327050888]],[1410,[1411,-215.5212986207668],[1412,155.127361338742]]]},{"id":1420,"_class":"TCAD.TWO.Segment","aux":true,"edge":146,"points":[[1414,[1415,-215.5212986207668],[1416,155.127361338742]],[1417,[1418,-215.4501942907495],[1419,154.46390374461535]]]},{"id":1427,"_class":"TCAD.TWO.Segment","aux":true,"edge":148,"points":[[1421,[1422,-215.4501942907495],[1423,154.46390374461535]],[1424,[1425,-215.16908303852756],[1426,161.84415327050888]]]},{"id":1434,"_class":"TCAD.TWO.Segment","aux":true,"edge":150,"points":[[1428,[1429,-213.33511869067203],[1430,176.46204424088245]],[1431,[1432,-214.74738610811426],[1433,169.88596255629682]]]},{"id":1441,"_class":"TCAD.TWO.Segment","aux":true,"edge":152,"points":[[1435,[1436,-214.74738610811426],[1437,169.88596255629682]],[1438,[1439,-214.7823277637057],[1440,169.21962113872806]]]},{"id":1448,"_class":"TCAD.TWO.Segment","aux":true,"edge":154,"points":[[1442,[1443,-214.7823277637057],[1444,169.21962113872806]],[1445,[1446,-213.33511869067203],[1447,176.46204424088245]]]},{"id":1455,"_class":"TCAD.TWO.Segment","aux":true,"edge":156,"points":[[1449,[1450,-209.20763261028907],[1451,190.60453413204746]],[1452,[1453,-211.6442541577552],[1454,184.335385471234]]]},{"id":1462,"_class":"TCAD.TWO.Segment","aux":true,"edge":158,"points":[[1456,[1457,-211.6442541577552],[1458,184.335385471234]],[1459,[1460,-211.78435858298565],[1461,183.68300325713744]]]},{"id":1469,"_class":"TCAD.TWO.Segment","aux":true,"edge":160,"points":[[1463,[1464,-211.78435858298565],[1465,183.68300325713744]],[1466,[1467,-209.20763261028907],[1468,190.60453413204746]]]},{"id":1476,"_class":"TCAD.TWO.Segment","aux":true,"edge":162,"points":[[1470,[1471,-202.89095473588415],[1472,203.91414503228458]],[1473,[1474,-206.29034023997258],[1475,198.11039386458984]]]},{"id":1483,"_class":"TCAD.TWO.Segment","aux":true,"edge":164,"points":[[1477,[1478,-206.29034023997258],[1479,198.11039386458984]],[1480,[1481,-206.5320660329977],[1482,197.48846103583213]]]},{"id":1490,"_class":"TCAD.TWO.Segment","aux":true,"edge":166,"points":[[1484,[1485,-206.5320660329977],[1486,197.48846103583213]],[1487,[1488,-202.89095473588415],[1489,203.91414503228458]]]},{"id":1497,"_class":"TCAD.TWO.Segment","aux":true,"edge":168,"points":[[1491,[1492,-194.54475092745736],[1493,216.05445160568848]],[1494,[1495,-198.82097455359153],[1496,210.86279860719284]]]},{"id":1504,"_class":"TCAD.TWO.Segment","aux":true,"edge":170,"points":[[1498,[1499,-198.82097455359153],[1500,210.86279860719284]],[1501,[1502,-199.1582116422664],[1503,210.28703568038364]]]},{"id":1511,"_class":"TCAD.TWO.Segment","aux":true,"edge":172,"points":[[1505,[1506,-199.1582116422664],[1507,210.28703568038364]],[1508,[1509,-194.54475092745736],[1510,216.05445160568848]]]},{"id":1518,"_class":"TCAD.TWO.Segment","aux":true,"edge":174,"points":[[1512,[1513,-184.379987112991],[1514,226.7185848724264]],[1515,[1516,-189.42495930181502],[1517,222.27025879184544]]]},{"id":1525,"_class":"TCAD.TWO.Segment","aux":true,"edge":176,"points":[[1519,[1520,-189.42495930181502],[1521,222.27025879184544]],[1522,[1523,-189.84918338721522],[1524,221.7552192528602]]]},{"id":1532,"_class":"TCAD.TWO.Segment","aux":true,"edge":178,"points":[[1526,[1527,-189.84918338721522],[1528,221.7552192528602]],[1529,[1530,-184.379987112991],[1531,226.7185848724264]]]},{"id":1539,"_class":"TCAD.TWO.Segment","aux":true,"edge":180,"points":[[1533,[1534,-172.65359672964632],[1535,235.63698889679065]],[1536,[1537,-178.3397963630285],[1538,232.04442950329735]]]},{"id":1546,"_class":"TCAD.TWO.Segment","aux":true,"edge":182,"points":[[1540,[1541,-178.3397963630285],[1542,232.04442950329735]],[1543,[1544,-178.8402843870677],[1545,231.6031319406896]]]},{"id":1553,"_class":"TCAD.TWO.Segment","aux":true,"edge":184,"points":[[1547,[1548,-178.8402843870677],[1549,231.6031319406896]],[1550,[1551,-172.65359672964632],[1552,235.63698889679065]]]},{"id":1560,"_class":"TCAD.TWO.Segment","aux":true,"edge":186,"points":[[1554,[1555,-159.66198625012984],[1556,242.58423431817306]],[1557,[1558,-165.84568398613052],[1559,239.93825027586973]]]},{"id":1567,"_class":"TCAD.TWO.Segment","aux":true,"edge":188,"points":[[1561,[1562,-165.84568398613052],[1563,239.93825027586973]],[1564,[1565,-166.40978517692938],[1566,239.58184931168483]]]},{"id":1574,"_class":"TCAD.TWO.Segment","aux":true,"edge":190,"points":[[1568,[1569,-166.40978517692938],[1570,239.58184931168483]],[1571,[1572,-159.66198625012984],[1573,242.58423431817306]]]},{"id":1581,"_class":"TCAD.TWO.Segment","aux":true,"edge":192,"points":[[1575,[1576,-87.85873092574069],[1577,243.56036599344466]],[1578,[1579,-94.0759657597847],[1580,246.1265577956006]]]},{"id":1588,"_class":"TCAD.TWO.Segment","aux":true,"edge":194,"points":[[1582,[1583,-94.0759657597847],[1584,246.1265577956006]],[1585,[1586,-94.72530009714954],[1587,246.28017003496572]]]},{"id":1595,"_class":"TCAD.TWO.Segment","aux":true,"edge":196,"points":[[1589,[1590,-94.72530009714954],[1591,246.28017003496572]],[1592,[1593,-87.85873092574069],[1594,243.56036599344466]]]},{"id":1602,"_class":"TCAD.TWO.Segment","aux":true,"edge":198,"points":[[1596,[1597,-145.73354295417178],[1598,247.38471650027034]],[1599,[1600,-152.25843425515438],[1601,245.75219000931554]]]},{"id":1609,"_class":"TCAD.TWO.Segment","aux":true,"edge":200,"points":[[1603,[1604,-152.25843425515438],[1605,245.75219000931554]],[1606,[1607,-152.8718898989769],[1608,245.48969434514922]]]},{"id":1616,"_class":"TCAD.TWO.Segment","aux":true,"edge":202,"points":[[1610,[1611,-152.8718898989769],[1612,245.48969434514922]],[1613,[1614,-145.73354295417178],[1615,247.38471650027034]]]},{"id":1623,"_class":"TCAD.TWO.Segment","aux":true,"edge":204,"points":[[1617,[1618,-101.91252341270427],[1619,247.98044276780786]],[1620,[1621,-108.45788216795745],[1622,249.5288703774163]]]},{"id":1630,"_class":"TCAD.TWO.Segment","aux":true,"edge":206,"points":[[1624,[1625,-108.45788216795745],[1626,249.5288703774163]],[1627,[1628,-109.12335499908941],[1629,249.57763216878644]]]},{"id":1637,"_class":"TCAD.TWO.Segment","aux":true,"edge":208,"points":[[1631,[1632,-109.12335499908941],[1633,249.57763216878644]],[1634,[1635,-101.91252341270427],[1636,247.98044276780786]]]},{"id":1644,"_class":"TCAD.TWO.Segment","aux":true,"edge":210,"points":[[1638,[1639,-131.22033432517946],[1640,249.91709426712018]],[1641,[1642,-137.9214903475247],[1643,249.33929049097623]]]},{"id":1651,"_class":"TCAD.TWO.Segment","aux":true,"edge":212,"points":[[1645,[1646,-137.9214903475247],[1647,249.33929049097623]],[1648,[1649,-138.56879420445267],[1650,249.17733519618488]]]},{"id":1658,"_class":"TCAD.TWO.Segment","aux":true,"edge":214,"points":[[1652,[1653,-138.56879420445267],[1654,249.17733519618488]],[1655,[1656,-131.22033432517946],[1657,249.91709426712018]]]},{"id":1665,"_class":"TCAD.TWO.Segment","aux":true,"edge":216,"points":[[1659,[1660,-116.48920888540648],[1661,250.11735702856262]],[1662,[1663,-123.19724536469215],[1664,250.60888103976808]]]},{"id":1672,"_class":"TCAD.TWO.Segment","aux":true,"edge":218,"points":[[1666,[1667,-123.19724536469215],[1668,250.60888103976808]],[1669,[1670,-123.86203561786023],[1671,250.5515598376735]]]},{"id":1679,"_class":"TCAD.TWO.Segment","aux":true,"edge":220,"points":[[1673,[1674,-123.86203561786023],[1675,250.5515598376735]],[1676,[1677,-116.48920888540648],[1678,250.11735702856262]]]},{"id":1689,"_class":"TCAD.TWO.Arc","aux":true,"edge":222,"points":[[1680,[1681,255.946878629896],[1682,-145.76094357167156]],[1683,[1684,252.10163324769275],[1685,71.15131239804411]],[1686,[1687,196.3368270908827],[1688,-38.32745196977044]]]},{"id":1700,"_class":"TCAD.TWO.Arc","aux":true,"edge":224,"points":[[1691,[1692,-183.60296592346776],[1693,87.66174623159009]],[1694,[1695,-57.55454096229795],[1696,224.06297544710796]],[1697,[1698,-122.51437135823936],[1699,157.65106605088206]]]},{"id":1711,"_class":"TCAD.TWO.Arc","aux":true,"edge":226,"points":[[1702,[1703,-88.51020843368133],[1704,-140.46311545122035]],[1705,[1706,-102.18982576106004],[1707,18.31440664196805]],[1708,[1709,-175.53398017227008],[1710,-67.98267439986091]]]},{"id":1722,"_class":"TCAD.TWO.Arc","aux":true,"edge":228,"points":[[1713,[1714,-93.05073865718533],[1715,-339.1473904301305]],[1716,[1717,-161.86089236160166],[1718,-230.93728827497424]],[1719,[1720,-122.42898493097368],[1721,-281.845807994961]]]}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":824,"_class":"TCAD.TWO.Circle","c":[821,[822,196.3368270908827],[823,-38.32745196977044]],"r":60.35462341678487},{"id":839,"_class":"TCAD.TWO.Circle","c":[836,[837,132.69721678409343],[838,-101.96706227655973]],"r":19.800361524305362},{"id":844,"_class":"TCAD.TWO.Circle","c":[841,[842,132.69721678409343],[843,25.31215833701884]],"r":19.800361524305362},{"id":1728,"_class":"TCAD.TWO.Circle","c":[1725,[1726,286.3368270908827],[1727,-38.32745196977044]],"r":19.800361524305362}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[{"id":849,"_class":"TCAD.TWO.Circle","c":[846,[847,196.3368270908827],[848,-38.32745196977044]],"r":90},{"id":857,"_class":"TCAD.TWO.Segment","points":[[851,[852,196.33682709088274],[853,132.78406845227903]],[854,[855,196.33682709088274],[856,-220.71977128010505]]]},{"id":864,"_class":"TCAD.TWO.Segment","points":[[858,[859,51.75067758157451],[860,-38.32745196977045]],[861,[862,338.80027616827897],[863,-38.32745196977045]]]},{"id":865,"_class":"TCAD.TWO.EndPoint","location":[865,[866,106.33682709088271],[867,-38.32745196977044]]},{"id":868,"_class":"TCAD.TWO.EndPoint","location":[868,[869,196.3368270908827],[870,51.67254803022956]]},{"id":871,"_class":"TCAD.TWO.EndPoint","location":[871,[872,286.3368270908827],[873,-38.32745196977044]]},{"id":874,"_class":"TCAD.TWO.EndPoint","location":[874,[875,196.33682709088274],[876,-128.32745196977044]]},{"id":877,"_class":"TCAD.TWO.EndPoint","location":[877,[878,259.976437397672],[879,-101.96706227655972]]},{"id":880,"_class":"TCAD.TWO.EndPoint","location":[880,[881,132.69721678409343],[882,-101.96706227655973]]},{"id":883,"_class":"TCAD.TWO.EndPoint","location":[883,[884,259.976437397672],[885,25.31215833701884]]},{"id":886,"_class":"TCAD.TWO.EndPoint","location":[886,[887,132.69721678409343],[888,25.31215833701884]]},{"id":895,"_class":"TCAD.TWO.Segment","points":[[889,[890,304.81959818306],[891,-146.8102230619477]],[892,[893,96.47030360363001],[894,61.539071517482256]]]},{"id":902,"_class":"TCAD.TWO.Segment","points":[[896,[897,78.91914321714893],[898,-155.74513584350424]],[899,[900,306.6329904254398],[901,71.96871136478666]]]}]}],"constraints":[["Vertical",[857]],["perpendicular",[864,857]],["PointOnLine",[846,857]],["PointOnLine",[865,864]],["PointOnArc",[865,849]],["Radius",[849,90]],["PointOnArc",[868,849]],["PointOnLine",[868,857]],["PointOnArc",[871,849]],["PointOnLine",[871,864]],["PointOnArc",[874,849]],["PointOnLine",[874,857]],["Angle",[851,854,892,889,45]],["perpendicular",[902,895]],["PointOnArc",[880,849]],["PointOnLine",[880,902]],["PointOnLine",[886,895]],["PointOnArc",[886,849]],["PointOnArc",[883,849]],["PointOnLine",[883,902]],["PointOnLine",[877,895]],["PointOnArc",[877,849]],["coi",[836,880]],["coi",[841,886]],["coi",[1725,871]],["RR",[839,844]],["RR",[844,1728]]]}'); localStorage.setItem("TCAD.projects.sample.sketch.2:0", '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[]},{"name":"__bounds__","style":{"lineWidth":2,"strokeStyle":"#fff5c3","fillStyle":"#000000"},"data":[{"id":3,"_class":"TCAD.TWO.Circle","aux":true,"edge":0,"c":[0,[1,-122.59914075460358],[2,157.65429488902262]],"r":92.95651034546636},{"id":8,"_class":"TCAD.TWO.Circle","aux":true,"edge":2,"c":[5,[6,-122.45917974196298],[7,-281.9821285194316]],"r":64.48310377876794}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":13,"_class":"TCAD.TWO.Circle","c":[10,[11,-122.59914075460358],[12,157.65429488902262]],"r":42.51842590924937},{"id":18,"_class":"TCAD.TWO.Circle","c":[15,[16,-122.45917974196298],[17,-281.9821285194316]],"r":34.86217749713944}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[]}],"constraints":[["coi",[10,0]],["coi",[15,5]]]}'); }; + +export default App; \ No newline at end of file diff --git a/web/app/3d/viewer.js b/web/app/3d/viewer.js index 8952e978..270f93a4 100644 --- a/web/app/3d/viewer.js +++ b/web/app/3d/viewer.js @@ -1,19 +1,7 @@ -TCAD.DPR = (window.devicePixelRatio) ? window.devicePixelRatio : 1; +import * as cad_utils from '../utils/cad-utils' +import {Matrix3, AXIS, ORIGIN} from '../math/l3space' -TCAD.view = {}; - -TCAD.view.setFacesColor = function(faces, color) { - for (var i = 0; i < faces.length; ++i) { - var face = faces[i]; - if (color == null) { - face.color.set(new THREE.Color()); - } else { - face.color.set( color ); - } - } -}; -TCAD.view.FACE_COLOR = 0xB0C4DE; -TCAD.Viewer = function(bus) { +function Viewer(bus) { this.bus = bus; function aspect() { return window.innerWidth / window.innerHeight; @@ -30,7 +18,7 @@ TCAD.Viewer = function(bus) { scene.add(light); var renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(TCAD.DPR); + renderer.setPixelRatio(cad_utils.DPR); renderer.setClearColor(0x808080, 1); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); @@ -87,15 +75,15 @@ TCAD.Viewer = function(bus) { } function addAxis(axis, color) { - var lineMaterial = new THREE.LineBasicMaterial({color: color, linewidth: 1/TCAD.DPR}); + var lineMaterial = new THREE.LineBasicMaterial({color: color, linewidth: 1/cad_utils.DPR}); var axisGeom = new THREE.Geometry(); axisGeom.vertices.push(axis.multiply(-1000).three()); axisGeom.vertices.push(axis.multiply(1000).three()); scene.add(new THREE.Line(axisGeom, lineMaterial)); } - addAxis(TCAD.math.AXIS.X, 0xFF0000); - addAxis(TCAD.math.AXIS.Y, 0x00FF00); - addAxis(TCAD.math.AXIS.Z, 0x0000FF); + addAxis(AXIS.X, 0xFF0000); + addAxis(AXIS.Y, 0x00FF00); + addAxis(AXIS.Z, 0x0000FF); function updateControlsAndHelpers() { trackballControls.update(); @@ -104,7 +92,7 @@ TCAD.Viewer = function(bus) { this.workGroup = new THREE.Object3D(); this.scene.add(this.workGroup); - this.selectionMgr = new TCAD.SelectionManager( this, 0xFAFAD2, 0xFF0000, null); + this.selectionMgr = new SelectionManager( this, 0xFAFAD2, 0xFF0000, null); var viewer = this; var raycaster = new THREE.Raycaster(); @@ -152,9 +140,20 @@ TCAD.Viewer = function(bus) { render(); animate(); +} + +Viewer.setFacesColor = function(faces, color) { + for (var i = 0; i < faces.length; ++i) { + var face = faces[i]; + if (color == null) { + face.color.set(new THREE.Color()); + } else { + face.color.set( color ); + } + } }; -TCAD.SelectionManager = function(viewer, selectionColor, readOnlyColor, defaultColor) { +function SelectionManager(viewer, selectionColor, readOnlyColor, defaultColor) { this.viewer = viewer; this.selectionColor = selectionColor; this.readOnlyColor = readOnlyColor; @@ -173,7 +172,7 @@ TCAD.SelectionManager = function(viewer, selectionColor, readOnlyColor, defaultC arrow.matrixAutoUpdate = false; arrow.line.renderOrder = 1e11; arrow.cone.renderOrder = 1e11; - arrow.line.material.linewidth = 1/TCAD.DPR; + arrow.line.material.linewidth = 1/cad_utils.DPR; arrow.line.material.depthWrite = false; arrow.line.material.depthTest = false; arrow.cone.material.depthWrite = false; @@ -187,9 +186,9 @@ TCAD.SelectionManager = function(viewer, selectionColor, readOnlyColor, defaultC this.basisGroup.add(yAxis); this.basisGroup.visible = false; viewer.scene.add(this.basisGroup); -}; +} -TCAD.SelectionManager.prototype.updateBasis = function(basis, depth) { +SelectionManager.prototype.updateBasis = function(basis, depth) { this.basisGroup.matrix.identity(); var mx = new THREE.Matrix4(); mx.makeBasis(basis[0].three(), basis[1].three(), basis[2].three()); @@ -199,7 +198,7 @@ TCAD.SelectionManager.prototype.updateBasis = function(basis, depth) { this.basisGroup.applyMatrix(mx); }; -TCAD.SelectionManager.prototype.handlePick = function(event) { +SelectionManager.prototype.handlePick = function(event) { var pickResults = this.viewer.raycast(event); for (var i = 0; i < pickResults.length; i++) { @@ -214,26 +213,26 @@ TCAD.SelectionManager.prototype.handlePick = function(event) { } }; -TCAD.SelectionManager.prototype.select = function(sketchFace) { +SelectionManager.prototype.select = function(sketchFace) { this.clear(); if (sketchFace.curvedSurfaces !== null) { for (var i = 0; i < sketchFace.curvedSurfaces.length; i++) { var face = sketchFace.curvedSurfaces[i]; this.selection.push(face); - TCAD.view.setFacesColor(face.faces, this.readOnlyColor); + Viewer.setFacesColor(face.faces, this.readOnlyColor); } } else { this.selection.push(sketchFace); this.updateBasis(sketchFace.basis(), sketchFace.depth()); this.basisGroup.visible = true; - TCAD.view.setFacesColor(sketchFace.faces, this.selectionColor); + Viewer.setFacesColor(sketchFace.faces, this.selectionColor); } sketchFace.solid.mesh.geometry.colorsNeedUpdate = true; this.viewer.bus.notify('selection', sketchFace); this.viewer.render(); }; -TCAD.SelectionManager.prototype.deselectAll = function() { +SelectionManager.prototype.deselectAll = function() { for (var i = 0; i < this.selection.length; ++ i) { this.selection[i].solid.mesh.geometry.colorsNeedUpdate = true; } @@ -241,15 +240,16 @@ TCAD.SelectionManager.prototype.deselectAll = function() { this.viewer.render(); }; -TCAD.SelectionManager.prototype.contains = function(face) { +SelectionManager.prototype.contains = function(face) { return this.selection.indexOf(face) != -1; }; -TCAD.SelectionManager.prototype.clear = function() { +SelectionManager.prototype.clear = function() { for (var i = 0; i < this.selection.length; ++ i) { - TCAD.view.setFacesColor(this.selection[i].faces, this.defaultColor); + Viewer.setFacesColor(this.selection[i].faces, this.defaultColor); } this.selection.length = 0; this.basisGroup.visible = false; }; +export {Viewer, SelectionManager} \ No newline at end of file diff --git a/web/app/3d/wizards/wizards.js b/web/app/3d/wizards/wizards.js index ce1f45ff..14b5b23f 100644 --- a/web/app/3d/wizards/wizards.js +++ b/web/app/3d/wizards/wizards.js @@ -1,27 +1,31 @@ -TCAD.wizards = {}; +import Vector from '../../math/vector' +import * as cad_utils from '../../utils/cad-utils' +import * as math from '../../math/math' +import {Matrix3, AXIS, ORIGIN, IDENTITY_BASIS} from '../../math/l3space' -TCAD.wizards.IMAGINE_MATERIAL = new THREE.LineBasicMaterial({ + +var IMAGINE_MATERIAL = new THREE.LineBasicMaterial({ color: 0xFA8072, - linewidth: 1/TCAD.DPR, + linewidth: 1/cad_utils.DPR, depthWrite: false, depthTest: false }); -TCAD.wizards.BASE_MATERIAL = new THREE.LineBasicMaterial({ +var BASE_MATERIAL = new THREE.LineBasicMaterial({ color: 0x8B0000, - linewidth: 3/TCAD.DPR, + linewidth: 3/cad_utils.DPR, depthWrite: false, depthTest: false }); -TCAD.wizards.OpWizard = function(viewer) { +function OpWizard(viewer) { this.previewGroup = new THREE.Object3D(); this.lines = []; this.viewer = viewer; viewer.scene.add(this.previewGroup); -}; +} -TCAD.wizards.OpWizard.prototype.setupLine = function(lineId, a, b, material) { +OpWizard.prototype.setupLine = function(lineId, a, b, material) { var line = this.lines[lineId]; if (line === undefined) { var lg = new THREE.Geometry(); @@ -38,27 +42,27 @@ TCAD.wizards.OpWizard.prototype.setupLine = function(lineId, a, b, material) { } }; -TCAD.wizards.OpWizard.prototype.dispose = function() { +OpWizard.prototype.dispose = function() { this.viewer.scene.remove(this.previewGroup); this.viewer.render(); }; -TCAD.wizards.ExtrudeWizard = function(viewer, polygons) { - TCAD.wizards.OpWizard.call(this, viewer); +function ExtrudeWizard(viewer, polygons) { + OpWizard.call(this, viewer); this.polygons = polygons; -}; +} -TCAD.wizards.ExtrudeWizard.prototype = Object.create( TCAD.wizards.OpWizard.prototype ); +ExtrudeWizard.prototype = Object.create( OpWizard.prototype ); -TCAD.wizards.ExtrudeWizard.prototype.update = function(basis, normal, depth, scale, deflection, angle) { +ExtrudeWizard.prototype.update = function(basis, normal, depth, scale, deflection, angle) { var linesCounter = 0; var target; if (deflection != 0) { target = normal.copy(); if (depth < 0) target._negate(); - target = TCAD.math.rotateMatrix(deflection * Math.PI / 180, basis[0], TCAD.math.ORIGIN)._apply(target); + target = Matrix3.rotateMatrix(deflection * Math.PI / 180, basis[0], ORIGIN)._apply(target); if (angle != 0) { - target = TCAD.math.rotateMatrix(angle * Math.PI / 180, basis[2], TCAD.math.ORIGIN)._apply(target); + target = Matrix3.rotateMatrix(angle * Math.PI / 180, basis[2], ORIGIN)._apply(target); } target._multiply(Math.abs(depth)); } else { @@ -66,14 +70,14 @@ TCAD.wizards.ExtrudeWizard.prototype.update = function(basis, normal, depth, sca } for (var i = 0; i < this.polygons.length; i++) { var poly = this.polygons[i]; - var lid = TCAD.geom.calculateExtrudedLid(poly, normal, target, scale); + var lid = cad_utils.calculateExtrudedLid(poly, normal, target, scale); var p, q, n = poly.length; for (p = n - 1, q = 0; q < n; p = q++) { - this.setupLine(linesCounter ++, poly[p], poly[q], TCAD.wizards.BASE_MATERIAL); - this.setupLine(linesCounter ++, lid[p], lid[q], TCAD.wizards.IMAGINE_MATERIAL); + this.setupLine(linesCounter ++, poly[p], poly[q], BASE_MATERIAL); + this.setupLine(linesCounter ++, lid[p], lid[q], IMAGINE_MATERIAL); } for (q = 0; q < n; q++) { - this.setupLine(linesCounter ++, poly[q], lid[q], TCAD.wizards.IMAGINE_MATERIAL); + this.setupLine(linesCounter ++, poly[q], lid[q], IMAGINE_MATERIAL); } } this.operationParams = { @@ -82,27 +86,26 @@ TCAD.wizards.ExtrudeWizard.prototype.update = function(basis, normal, depth, sca } }; - -TCAD.wizards.PlaneWizard = function(viewer) { +function PlaneWizard(viewer) { this.previewGroup = new THREE.Object3D(); this.viewer = viewer; viewer.scene.add(this.previewGroup); this.previewGroup.add(this.plane = this.createPlane()); this.viewer.render(); this.operationParams = { - basis : TCAD.math.IDENTITY_BASIS, + basis : IDENTITY_BASIS, depth : 0 }; -}; +} -TCAD.wizards.PlaneWizard.prototype.createPlane = function() { +PlaneWizard.prototype.createPlane = function() { var geometry = new THREE.PlaneGeometry(750,750,1,1,1); - var material = new THREE.MeshLambertMaterial( { color : TCAD.view.FACE_COLOR, transparent: true, opacity:0.5, side: THREE.DoubleSide }); + var material = new THREE.MeshLambertMaterial( { color : cad_utils.FACE_COLOR, transparent: true, opacity:0.5, side: THREE.DoubleSide }); var plane = new THREE.Mesh(geometry, material); return plane; }; -TCAD.wizards.PlaneWizard.prototype.update = function(orientation, w) { +PlaneWizard.prototype.update = function(orientation, w) { if (orientation === 'XY') { this.plane.rotation.x = 0; this.plane.rotation.y = 0; @@ -110,7 +113,7 @@ TCAD.wizards.PlaneWizard.prototype.update = function(orientation, w) { this.plane.position.x = 0; this.plane.position.y = 0; this.plane.position.z = w; - this.operationParams.basis = TCAD.math.IDENTITY_BASIS; + this.operationParams.basis = IDENTITY_BASIS; } else if (orientation === 'XZ') { this.plane.rotation.x = Math.PI / 2; this.plane.rotation.y = 0; @@ -118,7 +121,7 @@ TCAD.wizards.PlaneWizard.prototype.update = function(orientation, w) { this.plane.position.x = 0; this.plane.position.y = w; this.plane.position.z = 0; - this.operationParams.basis = [TCAD.math.AXIS.X, TCAD.math.AXIS.Z, TCAD.math.AXIS.Y]; + this.operationParams.basis = [AXIS.X, AXIS.Z, AXIS.Y]; } else if (orientation === 'ZY') { this.plane.rotation.x = 0; this.plane.rotation.y = Math.PI / 2; @@ -126,7 +129,7 @@ TCAD.wizards.PlaneWizard.prototype.update = function(orientation, w) { this.plane.position.x = w; this.plane.position.y = 0; this.plane.position.z = 0; - this.operationParams.basis = [TCAD.math.AXIS.Z, TCAD.math.AXIS.Y, TCAD.math.AXIS.X]; + this.operationParams.basis = [AXIS.Z, AXIS.Y, AXIS.X]; } else { throw orientation + " isn't supported yet"; } @@ -134,7 +137,9 @@ TCAD.wizards.PlaneWizard.prototype.update = function(orientation, w) { this.viewer.render(); }; -TCAD.wizards.PlaneWizard.prototype.dispose = function() { +PlaneWizard.prototype.dispose = function() { this.viewer.scene.remove(this.previewGroup); this.viewer.render(); -}; \ No newline at end of file +}; + +export {ExtrudeWizard, PlaneWizard} \ No newline at end of file diff --git a/web/app/workbench.js b/web/app/3d/workbench.js similarity index 52% rename from web/app/workbench.js rename to web/app/3d/workbench.js index 3313973b..8e715023 100644 --- a/web/app/workbench.js +++ b/web/app/3d/workbench.js @@ -1,15 +1,19 @@ -TCAD.workbench = {}; +import Vector from '../math/vector' +import * as cad_utils from '../utils/cad-utils' +import * as math from '../math/math' +import {Matrix3, AXIS, ORIGIN} from '../math/l3space' +import {HashTable} from '../utils/hashmap' -TCAD.workbench.SketchConnection = function(a, b, sketchObject) { +function SketchConnection(a, b, sketchObject) { this.a = a; this.b = b; this.sketchObject = sketchObject; -}; +} -TCAD.workbench._SKETCH_OBJ_COUNTER = 0; -TCAD.workbench.readSketchGeom = function(sketch) { +var _SKETCH_OBJ_COUNTER = 0; +export function readSketchGeom(sketch) { function genId() { - return TCAD.workbench._SKETCH_OBJ_COUNTER++; + return _SKETCH_OBJ_COUNTER++; } var out = {connections : [], loops : []}; if (sketch.layers !== undefined) { @@ -21,26 +25,26 @@ TCAD.workbench.readSketchGeom = function(sketch) { if (obj.edge !== undefined) continue; if (!!obj.aux) continue; if (obj._class === 'TCAD.TWO.Segment') { - var a = new TCAD.Vector(obj.points[0][1][1], obj.points[0][2][1], 0); - var b = new TCAD.Vector(obj.points[1][1][1], obj.points[1][2][1], 0); - out.connections.push(new TCAD.workbench.SketchConnection(a, b, {_class : obj._class, id : genId()})); + var segA = new Vector(obj.points[0][1][1], obj.points[0][2][1], 0); + var segB = new Vector(obj.points[1][1][1], obj.points[1][2][1], 0); + out.connections.push(new SketchConnection(segA, segB, {_class : obj._class, id : genId()})); } else if (obj._class === 'TCAD.TWO.Arc') { - var a = new TCAD.Vector(obj.points[0][1][1], obj.points[0][2][1], 0); - var b = new TCAD.Vector(obj.points[1][1][1], obj.points[1][2][1], 0); - var center = new TCAD.Vector(obj.points[2][1][1], obj.points[2][2][1], 0); - var approxArc = TCAD.workbench.approxArc(a, b, center, 20); - var data = {_class : obj._class, id : genId()}; - for (var j = 0; j < approxArc.length - 1; j++) { - out.connections.push(new TCAD.workbench.SketchConnection(approxArc[j], approxArc[j+1], data)); + var arcA = new Vector(obj.points[0][1][1], obj.points[0][2][1], 0); + var arcB = new Vector(obj.points[1][1][1], obj.points[1][2][1], 0); + var arcCenter = new Vector(obj.points[2][1][1], obj.points[2][2][1], 0); + var approxedArc = approxArc(arcA, arcB, arcCenter, 20); + var arcData = {_class : obj._class, id : genId()}; + for (var j = 0; j < approxedArc.length - 1; j++) { + out.connections.push(new SketchConnection(approxedArc[j], approxedArc[j+1], arcData)); } } else if (obj._class === 'TCAD.TWO.Circle') { - var center = new TCAD.Vector(obj.c[1][1], obj.c[2][1], 0); - var approxCircle = TCAD.workbench.approxCircle(center, obj.r, 20); - var data = {_class : obj._class, id : genId()}; + var circleCenter = new Vector(obj.c[1][1], obj.c[2][1], 0); + var approxedCircle = approxCircle(circleCenter, obj.r, 20); + var circleData = {_class : obj._class, id : genId()}; var loop = []; - var p, q, n = approxCircle.length; - for (var p = n - 1, q = 0; q < n; p = q++) { - loop.push(new TCAD.workbench.SketchConnection(approxCircle[p], approxCircle[q], data)); + var p, q, n = approxedCircle.length; + for (p = n - 1, q = 0; q < n; p = q++) { + loop.push(new SketchConnection(approxedCircle[p], approxedCircle[q], circleData)); } out.loops.push(loop); } @@ -48,9 +52,9 @@ TCAD.workbench.readSketchGeom = function(sketch) { } } return out; -}; +} -TCAD.workbench.approxArc = function(ao, bo, c, resolution) { +export function approxArc(ao, bo, c, resolution) { var a = ao.minus(c); var b = bo.minus(c); var points = [ao]; @@ -66,14 +70,14 @@ TCAD.workbench.approxArc = function(ao, bo, c, resolution) { var angle = Math.atan2(a.y, a.x) + step; for (var i = 0; i < k - 1; ++i) { - points.push(new TCAD.Vector(c.x + r*Math.cos(angle), c.y + r*Math.sin(angle))); + points.push(new Vector(c.x + r*Math.cos(angle), c.y + r*Math.sin(angle))); angle += step; } points.push(bo); return points; -}; +} -TCAD.workbench.approxCircle = function(c, r, resolution) { +export function approxCircle(c, r, resolution) { var points = []; resolution = 1; @@ -82,31 +86,19 @@ TCAD.workbench.approxCircle = function(c, r, resolution) { var k = Math.round((2 * Math.PI) / step); for (var i = 0, angle = 0; i < k; ++i, angle += step) { - points.push(new TCAD.Vector(c.x + r*Math.cos(angle), c.y + r*Math.sin(angle))); + points.push(new Vector(c.x + r*Math.cos(angle), c.y + r*Math.sin(angle))); } return points; -}; +} -TCAD.workbench.serializeSolid = function(solid) { - var data = {}; - data.faceCounter = TCAD.geom.FACE_COUNTER; - for (var fi = 0; fi < solid.faces.length; ++fi) { - var face = solid.faces[fi]; - var faceData = {}; - faceData.id = face.id; - } - return data; -}; -TCAD.craft = {}; - -TCAD.craft.getSketchedPolygons3D = function(app, face) { +export function getSketchedPolygons3D(app, face) { var savedFace = localStorage.getItem(app.faceStorageKey(face.id)); if (savedFace == null) return null; - var geom = TCAD.workbench.readSketchGeom(JSON.parse(savedFace)); - var polygons2D = TCAD.utils.sketchToPolygons(geom); + var geom = readSketchGeom(JSON.parse(savedFace)); + var polygons2D = cad_utils.sketchToPolygons(geom); var normal = face.csgGroup.normal; var depth = null; @@ -116,7 +108,7 @@ TCAD.craft.getSketchedPolygons3D = function(app, face) { if (poly2D.length < 3) continue; if (depth == null) { - var _3dTransformation = new TCAD.Matrix().setBasis(face.basis()); + var _3dTransformation = new Matrix3().setBasis(face.basis()); //we lost depth or z off in 2d sketch, calculate it again depth = face.csgGroup.plane.w; } @@ -125,7 +117,7 @@ TCAD.craft.getSketchedPolygons3D = function(app, face) { for (var m = 0; m < poly2D.length; ++m) { var vec = poly2D[m]; vec.z = depth; -// var a = _3dTransformation.apply(new TCAD.Vector(poly2D[m][0], poly2D[m][1], depth)); +// var a = _3dTransformation.apply(new Vector(poly2D[m][0], poly2D[m][1], depth)); var a = _3dTransformation.apply(vec); a.sketchConnectionObject = vec.sketchConnectionObject; polygon.push(a); @@ -134,32 +126,32 @@ TCAD.craft.getSketchedPolygons3D = function(app, face) { sketchedPolygons.push(polygon); } return sketchedPolygons; -}; +} -TCAD.craft.extrude = function(app, request) { +export function extrude(app, request) { var face = request.face; - var sketchedPolygons = TCAD.craft.getSketchedPolygons3D(app, face); + var sketchedPolygons = getSketchedPolygons3D(app, face); if (sketchedPolygons == null) return null; - var normal = TCAD.utils.vec(face.csgGroup.plane.normal); + var normal = cad_utils.vec(face.csgGroup.plane.normal); var toMeldWith = []; for (var i = 0; i < sketchedPolygons.length; i++) { - var extruded = TCAD.geom.extrude(sketchedPolygons[i], normal, request.params.target, request.params.expansionFactor ); + var extruded = cad_utils.extrude(sketchedPolygons[i], normal, request.params.target, request.params.expansionFactor ); toMeldWith = toMeldWith.concat(extruded); } var solid = request.solids[0]; - var meld = CSG.fromPolygons(TCAD.craft._triangulateCSG(toMeldWith)); + var meld = CSG.fromPolygons(_triangulateCSG(toMeldWith)); if (solid.mergeable) { meld = solid.csg.union(meld); } face.csgGroup.shared.__tcad.faceId += '$'; - return [TCAD.utils.createSolid(meld)]; -}; + return [cad_utils.createSolid(meld)]; +} -TCAD.craft._pointOnLine = function(p, a, b) { +function _pointOnLine(p, a, b) { var ab = a.minus(b); var ap = a.minus(p); @@ -169,12 +161,12 @@ TCAD.craft._pointOnLine = function(p, a, b) { var abLength = ab.length(); var apLength = ap.length(); - return apLength > 0 && apLength < abLength && TCAD.utils.areEqual(abLength * apLength, dp, 1E-6); -}; + return apLength > 0 && apLength < abLength && math.areEqual(abLength * apLength, dp, 1E-6); +} -TCAD.craft.polygonsToSegments = function(polygons) { +export function polygonsToSegments(polygons) { function selfIntersecting(a, b, c) { - var f = TCAD.craft._pointOnLine; + var f = _pointOnLine; return f(c, a, b) || f(a, b, c) || f(b, c, a); } //polygons.filter(function(p) { @@ -199,9 +191,9 @@ TCAD.craft.polygonsToSegments = function(polygons) { segmentsByPolygon.push(segments); } return segmentsByPolygon; -}; +} -TCAD.craft.reconstructSketchBounds = function(csg, face, strict) { +export function reconstructSketchBounds(csg, face, strict) { strict = strict || false; var polygons = csg.toPolygons(); var plane = face.csgGroup.plane; @@ -209,8 +201,8 @@ TCAD.craft.reconstructSketchBounds = function(csg, face, strict) { var planePolygons = []; for (var pi = 0; pi < polygons.length; pi++) { var poly = polygons[pi]; - if (TCAD.utils.equal(poly.plane.normal.dot(plane.normal), 1)) { - if (TCAD.utils.equal(plane.w, poly.plane.w) && (!strict || !!poly.shared.__tcad && poly.shared.__tcad.faceId === face.id)) { + if (math.equal(poly.plane.normal.dot(plane.normal), 1)) { + if (math.equal(plane.w, poly.plane.w) && (!strict || !!poly.shared.__tcad && poly.shared.__tcad.faceId === face.id)) { planePolygons.push(poly); } continue; @@ -219,68 +211,67 @@ TCAD.craft.reconstructSketchBounds = function(csg, face, strict) { for(p = n - 1, q = 0; q < n; p = q ++) { var a = poly.vertices[p]; var b = poly.vertices[q]; - var pointAOnPlane = TCAD.utils.equal(plane.signedDistanceToPoint(a.pos), 0); + var pointAOnPlane = math.equal(plane.signedDistanceToPoint(a.pos), 0); if (!pointAOnPlane) continue; - var pointBOnPlane = TCAD.utils.equal(plane.signedDistanceToPoint(b.pos), 0); + var pointBOnPlane = math.equal(plane.signedDistanceToPoint(b.pos), 0); if (pointBOnPlane) { outerEdges.push([a.pos, b.pos, poly]); } } } - var outline = TCAD.craft.findOutline(planePolygons); + var outline = findOutline(planePolygons); - TCAD.craft.pickUpCraftInfo(outline, outerEdges); + pickUpCraftInfo(outline, outerEdges); - return TCAD.craft.segmentsToPaths(outline); -}; + return segmentsToPaths(outline); +} -TCAD.craft.pickUpCraftInfo = function(outline, outerEdges) { - var eq = TCAD.utils.strictEqual; +function pickUpCraftInfo(outline, outerEdges) { + var eq = math.strictEqual; for (var psi1 = 0; psi1 < outline.length; psi1++) { var s1 = outline[psi1]; for (var psi2 = 0; psi2 < outerEdges.length; psi2++) { var s2 = outerEdges[psi2]; - if (TCAD.utils.equal(Math.abs(s1[0].minus(s1[1]).unit().dot(s2[0].minus(s2[1]).unit())), 1) && + if (math.equal(Math.abs(s1[0].minus(s1[1]).unit().dot(s2[0].minus(s2[1]).unit())), 1) && (eq(s1[0], s2[0]) || eq(s1[1], s2[1]) || eq(s1[0], s2[1]) || eq(s1[1], s2[0]) || - TCAD.craft._pointOnLine(s1[0], s2[0], s2[1]) || TCAD.craft._pointOnLine(s1[1], s2[0], s2[1]))) { + _pointOnLine(s1[0], s2[0], s2[1]) || _pointOnLine(s1[1], s2[0], s2[1]))) { s1[2] = s2[2]; } } } -}; +} - -TCAD.craft.getOutlineByCollision = function(segments, outerEdges) { - var eq = TCAD.utils.strictEqual; +function getOutlineByCollision(segments, outerEdges) { + var eq = math.strictEqual; var outline = []; for (var psi1 = 0; psi1 < segments.length; psi1++) { var s1 = segments[psi1]; for (var psi2 = 0; psi2 < outerEdges.length; psi2++) { var s2 = outerEdges[psi2]; - if (TCAD.utils.equal(Math.abs(s1[0].minus(s1[1]).unit().dot(s2[0].minus(s2[1]).unit())), 1) && + if (math.equal(Math.abs(s1[0].minus(s1[1]).unit().dot(s2[0].minus(s2[1]).unit())), 1) && (eq(s1[0], s2[0]) || eq(s1[1], s2[1]) || eq(s1[0], s2[1]) || eq(s1[1], s2[0]) || - TCAD.craft._pointOnLine(s1[0], s2[0], s2[1]) || TCAD.craft._pointOnLine(s1[1], s2[0], s2[1]))) { + _pointOnLine(s1[0], s2[0], s2[1]) || _pointOnLine(s1[1], s2[0], s2[1]))) { outline.push(s1); } } } return outline; -}; +} - TCAD.craft.findOutline = function(planePolygons, outer) { - var segmentsByPolygon = TCAD.craft.polygonsToSegments(planePolygons); - //TCAD.craft.simplifySegments(segmentsByPolygon); - var planeSegments = TCAD.utils.arrFlatten1L(segmentsByPolygon); - //planeSegments = TCAD.craft.removeSharedEdges(planeSegments); - TCAD.craft.removeTJoints(planeSegments); - planeSegments = TCAD.craft.removeSharedEdges(planeSegments); +function findOutline (planePolygons, outer) { + var segmentsByPolygon = polygonsToSegments(planePolygons); + //simplifySegments(segmentsByPolygon); + var planeSegments = cad_utils.arrFlatten1L(segmentsByPolygon); + //planeSegments = removeSharedEdges(planeSegments); + removeTJoints(planeSegments); + planeSegments = removeSharedEdges(planeSegments); return planeSegments; -}; +} -TCAD.craft.removeSharedEdges = function(segments) { +function removeSharedEdges(segments) { segments = segments.slice(); - var eq = TCAD.utils.strictEqual; + var eq = math.strictEqual; for (var psi1 = 0; psi1 < segments.length; psi1++) { var s1 = segments[psi1]; if (s1 == null) continue; @@ -295,9 +286,9 @@ TCAD.craft.removeSharedEdges = function(segments) { } } return segments.filter(function(e) {return e !== null}); -}; +} -TCAD.craft.simplifySegments = function(polygonToSegments) { +function simplifySegments(polygonToSegments) { for (var pi1 = 0; pi1 < polygonToSegments.length; ++pi1) { for (var pi2 = 0; pi2 < polygonToSegments.length; ++pi2) { if (pi1 === pi2) continue; @@ -307,7 +298,7 @@ TCAD.craft.simplifySegments = function(polygonToSegments) { var seg1 = polygon1[si1]; for (var si2 = 0; si2 < polygon2.length; ++si2) { var point = polygon2[si2][0]; - if (TCAD.craft._pointOnLine(point, seg1[0], seg1[1])) { + if (_pointOnLine(point, seg1[0], seg1[1])) { polygon1.push([point, seg1[1]]); seg1[1] = point; } @@ -315,9 +306,9 @@ TCAD.craft.simplifySegments = function(polygonToSegments) { } } } -}; +} -TCAD.craft._closeFactorToLine = function(p, seg1, seg2) { +function _closeFactorToLine(p, seg1, seg2) { var a = p.minus(seg1); var b = seg2.minus(seg1); @@ -331,10 +322,10 @@ TCAD.craft._closeFactorToLine = function(p, seg1, seg2) { var c = a.minus(bx); return c.length(); -}; +} -TCAD.craft.removeTJoints = function(segments) { - var pointIndex = TCAD.struct.hashTable.forVector3d(); +function removeTJoints(segments) { + var pointIndex = HashTable.forVector3d(); for (var i = 0; i < segments.length; ++i) { pointIndex.put(segments[i][0], 1); @@ -342,14 +333,14 @@ TCAD.craft.removeTJoints = function(segments) { } var points = pointIndex.getKeys(); - var eq = TCAD.utils.strictEqual; + var eq = math.strictEqual; for (var pi1 = 0; pi1 < points.length; ++pi1) { var point = points[pi1]; var best = null, bestFactor; for (var pi2 = 0; pi2 < segments.length; ++pi2) { var seg = segments[pi2]; if (eq(seg[0], point) || eq(seg[1], point)) continue; - var factor = TCAD.craft._closeFactorToLine(point, seg[0], seg[1]); + var factor = _closeFactorToLine(point, seg[0], seg[1]); if (factor != -1 && factor < 1E-6 && (best == null || factor < bestFactor)) { best = seg; bestFactor = factor; @@ -360,10 +351,9 @@ TCAD.craft.removeTJoints = function(segments) { best[1] = point; } } -}; +} - -TCAD.craft.deleteRedundantPoints = function(path) { +function deleteRedundantPoints(path) { var cleanedPath = []; //Delete redundant point var pathLength = path.length; @@ -373,20 +363,19 @@ TCAD.craft.deleteRedundantPoints = function(path) { var a = path[pi]; var b = path[bIdx]; var c = path[(pi + 2) % pathLength]; - var eq = TCAD.utils.areEqual; + var eq = math.areEqual; if (!skipMode) cleanedPath.push(a); skipMode = eq(a.minus(b).unit().dot(b.minus(c).unit()), 1, 1E-9); } return cleanedPath; -}; +} -TCAD.craft.segmentsToPaths = function(segments) { - - var veq = TCAD.struct.hashTable.vectorEquals; +function segmentsToPaths(segments) { + var veq = math.strictEqual; var paths = []; - var index = TCAD.struct.hashTable.forVector3d(); - var csgIndex = TCAD.struct.hashTable.forEdge(); + var index = HashTable.forVector3d(); + var csgIndex = HashTable.forEdge(); function indexPoint(p, edge) { var edges = index.get(p); @@ -425,13 +414,14 @@ TCAD.craft.segmentsToPaths = function(segments) { return null; } + var path; for (var ei = 0; ei < segments.length; ei++) { var edge = segments[ei]; if (edge[3]) { continue; } edge[3] = true; - var path = [edge[0], edge[1]]; + path = [edge[0], edge[1]]; paths.push(path); var next = nextPoint(edge[1]); while (next !== null) { @@ -446,10 +436,10 @@ TCAD.craft.segmentsToPaths = function(segments) { var filteredPaths = []; for (var i = 0; i < paths.length; i++) { - var path = paths[i]; + path = paths[i]; //Set derived from object to be able to recunstruct - TCAD.utils.iteratePath(path, 0, function (a, b) { + cad_utils.iteratePath(path, 0, function (a, b) { var fromPolygon = csgIndex.get([a, b]); if (fromPolygon !== null) { if (fromPolygon.shared.__tcad.csgInfo) { @@ -458,7 +448,7 @@ TCAD.craft.segmentsToPaths = function(segments) { } return true; }); - path = TCAD.craft.deleteRedundantPoints(path); + path = deleteRedundantPoints(path); if (path.length > 2) { filteredPaths.push({ vertices: path @@ -467,9 +457,9 @@ TCAD.craft.segmentsToPaths = function(segments) { } return filteredPaths; -}; +} -TCAD.craft._triangulateCSG = function(polygons) { +function _triangulateCSG(polygons) { function csgVec(v) { return new CSG.Vector3D(v.x, v.y, v.z); } @@ -477,7 +467,7 @@ TCAD.craft._triangulateCSG = function(polygons) { for (var ei = 0; ei < polygons.length; ++ei) { var poly = polygons[ei]; var points = poly.vertices; - var refs = TCAD.geom.triangulate(points, poly.plane.normal); + var refs = cad_utils.triangulate(points, poly.plane.normal); for ( var i = 0; i < refs.length; ++ i ) { var a = refs[i][0]; var b = refs[i][1]; @@ -487,9 +477,9 @@ TCAD.craft._triangulateCSG = function(polygons) { } } return triangled; -}; +} -TCAD.craft.splitTwoSegments = function (a, b) { +function splitTwoSegments(a, b) { var da = a[1].minus(a[0]); var db = b[1].minus(b[0]); var dc = b[0].minus(a[0]); @@ -499,34 +489,33 @@ TCAD.craft.splitTwoSegments = function (a, b) { // lines are not coplanar return null; } - var veq = TCAD.utils.vectorsEqual; + var veq = math.strictEqual; if (veq(a[0], b[0]) || veq(a[0], b[1]) || veq(a[1], b[0]) || veq(a[1], b[1])) { return null; } var dcXdb = dc.cross(db); + function _split(s, ip) { + if (s[0].equals(ip) || s[1].equals(ip)) { + return [s]; + } + return [[s[0], ip, s[2]], [ip, s[1], s[2]]] + } var s = dcXdb.dot(daXdb) / daXdb.lengthSquared(); if (s > 0.0 && s < 1.0) { var ip = a[0].plus(da.times(s)); - function _split(s, ip) { - if (s[0].equals(ip) || s[1].equals(ip)) { - return [s]; - } - return [[s[0], ip, s[2]], [ip, s[1], s[2]]] - } - return { splitterParts : _split(a, ip), residual : _split(b, ip) } } return null; -}; +} -TCAD.craft.attract = function(vectors, precision) { - var eq = TCAD.utils.areEqual(); - var dist = TCAD.math.distanceAB3; +function attract(vectors, precision) { + var eq = math.areEqual(); + var dist = math.distanceAB3; vectors = vectors.slice(); for (var i = 0; i < vectors.length; i++) { var v1 = vectors[i]; @@ -535,27 +524,28 @@ TCAD.craft.attract = function(vectors, precision) { var v2 = vectors[j]; if (v2 == null) continue; if (dist(v1, v2) <= precision) { - TCAD.Vector.prototype.setV.call(v2, v1); + Vector.prototype.setV.call(v2, v1); vectors[j] = null; } } } -}; +} -TCAD.craft.recoverySketchInfo = function(polygons) { +function recoverySketchInfo(polygons) { var nonStructuralGons = []; - var sketchEdges = TCAD.struct.hashTable.forDoubleArray(); - function key(a, b) {return [a.x, a.y, b.x, b.y]}; + var sketchEdges = HashTable.forDoubleArray(); + function key(a, b) {return [a.x, a.y, b.x, b.y]} for (var pi = 0; pi < polygons.length; pi++) { var poly = polygons[pi]; var paths = []; poly.collectPaths(paths); - for (var i = 0; i < paths.length; i++) { - var path = paths[i]; + var i, path, n, p, q; + for (i = 0; i < paths.length; i++) { + path = paths[i]; if (poly.csgInfo !== undefined && poly.csgInfo.derivedFrom !== undefined) { - var n = path.length; - for (var p = n - 1, q = 0; q < n ; p = q++ ) { + n = path.length; + for (p = n - 1, q = 0; q < n ; p = q++ ) { sketchEdges.put(key(path[p], path[q]), poly.csgInfo); } } else { @@ -564,10 +554,10 @@ TCAD.craft.recoverySketchInfo = function(polygons) { } } - for (var i = 0; i < nonStructuralGons.length; i++) { - var path = nonStructuralGons[i]; - var n = path.length; - for (var p = n - 1, q = 0; q < n ; p = q++ ) { + for (i = 0; i < nonStructuralGons.length; i++) { + path = nonStructuralGons[i]; + n = path.length; + for (p = n - 1, q = 0; q < n ; p = q++ ) { var csgInfo = sketchEdges.get(key(path[p], path[q])); if (csgInfo === null) { csgInfo = sketchEdges.get(key(path[q], path[p])); @@ -577,235 +567,33 @@ TCAD.craft.recoverySketchInfo = function(polygons) { } } } -}; +} -TCAD.craft.reconstruct = function (cut) { - function pInP(p1, p2) { - var notEqPoints = []; - - for (var i = 0; i < p1.length; ++i) { - var v1 = p1[i]; - for (var j = 0; j < p2.length; ++j) { - var v2 = p2[j]; - if (!v1.equals(v2)) { - notEqPoints.push(v1); - break; - } - } - } - - if (notEqPoints.length == 0) { - return true; - } - - for (var i = 0; i < notEqPoints.length; ++i) { - var v = notEqPoints[i]; - if (!TCAD.utils.isPointInsidePolygon(v, p2)) { - return false; - } - } - - return true; - } - - function sortPaths(paths3D) { - - var transforms = TCAD.struct.hashTable.forVector3d(); - - var paths = paths3D.map(function(path) { - var tr = transforms.get(path.normal); - if (tr === null) { - var _3dTransformation = new TCAD.Matrix().setBasis(TCAD.geom.someBasis(path.vertices, path.normal)); - var tr = _3dTransformation.invert(); - transforms.put(path.normal, tr); - } - - return { - vertices : path.vertices.map(function(v) {return tr.apply(v);}), - normal : path.normal, - shared : path.shared - } - }); - - var index = []; - for (var pi = 0; pi < paths.length; ++pi) { - index[pi] = []; - paths3D[pi].holes = []; - } - - for (var pi = 0; pi < paths.length; ++pi) { - var path = paths[pi]; - for (var piTest = 0; piTest < paths.length; ++piTest) { - var pathTest = paths[piTest]; - if (piTest === pi) continue; - if (pInP(pathTest.vertices, path.vertices)) { - index[piTest].push(pi); - } - } - } - function collect(master, level) { - var success = false; - for (var i = 0; i < index.length; ++i) { - var masters = index[i]; - if (level != masters.length) continue; - for (var j = 0; j < masters.length; ++j) { - var m = masters[j]; - if (m === master) { - paths3D[m].holes.push(paths3D[i]) - success = true; - } - } - } - return success; - } - - for (var success = true, level = 1; - level < paths3D.length && success; - level ++, success = false) { - - for (var i = 0; i < index.length; ++i) { - var masters = index[i]; - if (masters.length == level - 1) { - if (collect(i, level)) { - success = true; - } - } - } - } - - function separate(path, separated) { - separated.push(path); - for (var i = 0; i < path.holes.length; ++i) { - var hole = path.holes[i]; - for (var j = 0; j < hole.holes.length; ++j) { - var inner = hole.holes[j]; - separate(inner, separated) - } - } - } - - var separated = []; - for (var i = 0; i < index.length; ++i) { - var masters = index[i]; - if (masters.length == 0) { - separate(paths3D[i], separated); - } - } - return separated; - } - - var byShared = {}; - for (var i = 0; i < cut.polygons.length; i++) { - var p = cut.polygons[i]; - var tag = p.shared.getTag(); - if (byShared[tag] === undefined) byShared[tag] = []; - byShared[tag].push(p); - } - var result = []; - var allPoints = []; - for (var tag in byShared) { - var merged = TCAD.craft._mergeCSGPolygons(byShared[tag], allPoints); - var sorted = sortPaths(merged); - result.push.apply(result, sorted.map(function(path) { - var p = new TCAD.Polygon(path.vertices, path.holes.map(function (path) { - return path.vertices - }), path.normal); - if (path.shared !== undefined) { - p.csgInfo = path.shared.csgInfo; - p.__face = path.shared.face; - } - return p; - }) - ); - } - TCAD.craft.recoverySketchInfo(result); - return result; -}; - -TCAD.craft.collectFaces = function(solids) { - var faces = []; - for (var i = 0; i < solids.length; i++) { - TCAD.utils.addAll(faces, solids[i].polyFaces); - } - return faces; -}; - -TCAD.craft.collectCSGPolygons = function(faces) { - var out = []; - for (var fi = 0; fi < faces.length; fi++) { - var face = faces[fi]; - TCAD.utils.addAll(out, face.csgGroup.toCSGPolygons()); - } - return out; -}; - -TCAD.craft.toGroups = function(csgPolygons) { - - function vec(p) { - var v = new TCAD.Vector(); - v.setV(p); - return v; - } - - var byShared = {}; - var infos = {}; - for (var i = 0; i < csgPolygons.length; i++) { - var p = csgPolygons[i]; - var tag = p.shared.getTag(); - infos[tag] = p.shared; - if (byShared[tag] === undefined) byShared[tag] = []; - byShared[tag].push(p); - } - var result = []; - for (var tag in byShared) { - var groupedPolygons = byShared[tag]; - if (groupedPolygons.length === 0) continue; - var plane = groupedPolygons[0].plane; - var normal = vec(plane.normal); - - var simplePolygons = groupedPolygons.map(function (p) { - - var vertices = p.vertices.map(function (v) { - return vec(v.pos); - }); - return new TCAD.SimplePolygon(vertices, normal); - }); - var csgGroup = new TCAD.CSGGroup(simplePolygons, normal, plane.w); - var tcadShared = infos[tag].__tcad; - if (tcadShared !== undefined) { - csgGroup.csgInfo = tcadShared.csgInfo; - csgGroup.__face = tcadShared.face; - } - result.push(csgGroup); - } - return result; -}; - -TCAD.craft.cut = function(app, request) { +export function cut(app, request) { var face = request.face; - var sketchedPolygons = TCAD.craft.getSketchedPolygons3D(app, face); + var sketchedPolygons = getSketchedPolygons3D(app, face); if (sketchedPolygons == null) return null; - var normal = TCAD.utils.vec(face.csgGroup.plane.normal); + var normal = cad_utils.vec(face.csgGroup.plane.normal); var cutter = []; for (var i = 0; i < sketchedPolygons.length; i++) { - var extruded = TCAD.geom.extrude(sketchedPolygons[i], normal, request.params.target, request.params.expansionFactor ); + var extruded = cad_utils.extrude(sketchedPolygons[i], normal, request.params.target, request.params.expansionFactor ); cutter = cutter.concat(extruded); } - var cutterCSG = CSG.fromPolygons(TCAD.craft._triangulateCSG(cutter)); + var cutterCSG = CSG.fromPolygons(_triangulateCSG(cutter)); face.csgGroup.shared.__tcad.faceId += '$'; var outSolids = []; for (var si = 0; si < request.solids.length; si++) { var work = request.solids[si].csg; var cut = work.subtract(cutterCSG); - var solidMesh = TCAD.utils.createSolid(cut); + var solidMesh = cad_utils.createSolid(cut); outSolids.push(solidMesh); } return outSolids; -}; +} -TCAD.Craft = function(app) { +export function Craft(app) { this.app = app; this.history = []; this._historyPointer = 0; @@ -820,9 +608,9 @@ TCAD.Craft = function(app) { this.app.viewer.render(); } }); -}; +} -TCAD.Craft.prototype.loadHistory = function(history) { +Craft.prototype.loadHistory = function(history) { this.history = history; this._historyPointer = history.length; this.reset(history); @@ -831,25 +619,25 @@ TCAD.Craft.prototype.loadHistory = function(history) { this.app.viewer.render(); }; -TCAD.Craft.prototype.reset = function(modifications) { - TCAD.geom.SOLID_COUNTER = 0; - TCAD.utils.SHARED_COUNTER = 0; +Craft.prototype.reset = function(modifications) { + cad_utils.Counters.solid = 0; + cad_utils.Counters.shared = 0; this.app.findAllSolids().forEach(function(s) {s.vanish()}) for (var i = 0; i < modifications.length; i++) { - var request = TCAD.craft.materialize(this.app.indexEntities(), modifications[i]); + var request = materialize(this.app.indexEntities(), modifications[i]); this.modifyInternal(request); } }; -TCAD.Craft.prototype.finishHistoryEditing = function() { +Craft.prototype.finishHistoryEditing = function() { this.loadHistory(this.history); }; -TCAD.Craft.prototype.current = function() { +Craft.prototype.current = function() { return this.history[this.history.length - 1]; }; -TCAD.craft.detach = function(request) { +function detach(request) { var detachedConfig = {}; for (var prop in request) { if (request.hasOwnProperty(prop)) { @@ -863,16 +651,16 @@ TCAD.craft.detach = function(request) { } else if (prop == 'basis') { detachedConfig[prop] = value.map(function(v){return [v.x, v.y, v.z]}); } else if (prop == 'params') { - detachedConfig[prop] = TCAD.craft.detach(value); + detachedConfig[prop] = detach(value); } else { detachedConfig[prop] = value; } } } return detachedConfig -}; +} -TCAD.craft.materialize = function(index, detachedConfig) { +function materialize(index, detachedConfig) { var request = {}; function required(value) { if (value == null || value == undefined) throw "value is required"; @@ -884,23 +672,23 @@ TCAD.craft.materialize = function(index, detachedConfig) { if (prop == 'solids') { request[prop] = value.map(function(id){return required(index.solids[id])}); } else if (prop == 'target') { - request[prop] = new TCAD.Vector().set3(value); + request[prop] = new Vector().set3(value); } else if (prop == 'face') { request[prop] = required(index.faces[value]); } else if (prop == 'basis') { - request[prop] = value.map(function(v) {return new TCAD.Vector().set3(v)}); + request[prop] = value.map(function(v) {return new Vector().set3(v)}); } else if (prop == 'params') { - request[prop] = TCAD.craft.materialize(index, value); + request[prop] = materialize(index, value); } else { request[prop] = value; } } } return request; -}; +} -TCAD.Craft.prototype.modifyInternal = function(request) { - var op = TCAD.craft.OPS[request.type]; +Craft.prototype.modifyInternal = function(request) { + var op = OPERATIONS[request.type]; if (!op) return; var newSolids = op(this.app, request); @@ -915,9 +703,9 @@ TCAD.Craft.prototype.modifyInternal = function(request) { } }; -TCAD.Craft.prototype.modify = function(request, overriding) { +Craft.prototype.modify = function(request, overriding) { this.modifyInternal(request); - var detachedRequest = TCAD.craft.detach(request); + var detachedRequest = detach(request); if (!overriding && this._historyPointer != this.history.length) { this.history.splice(this._historyPointer + 1, 0, null); } @@ -928,13 +716,13 @@ TCAD.Craft.prototype.modify = function(request, overriding) { this.app.viewer.render(); }; -TCAD.craft.OPS = { - CUT : TCAD.craft.cut, - PAD : TCAD.craft.extrude, +export const OPERATIONS = { + CUT : cut, + PAD : extrude, PLANE : function(app, request) { - return [TCAD.utils.createPlane(request.params.basis, request.params.depth)]; + return [cad_utils.createPlane(request.params.basis, request.params.depth)]; }, BOX : function(app, request) { - return [TCAD.utils.createCSGBox(request.size)]; + return [cad_utils.createCSGBox(request.size)]; } }; diff --git a/web/app/index.js b/web/app/index.js new file mode 100644 index 00000000..aee62df5 --- /dev/null +++ b/web/app/index.js @@ -0,0 +1,5 @@ +import App from './3d/modeler-app' + +window.onload = function() { + window._TCAD_APP = new App(); +}; diff --git a/web/app/math/graph.js b/web/app/math/graph.js index d29db427..6225534b 100644 --- a/web/app/math/graph.js +++ b/web/app/math/graph.js @@ -1,12 +1,25 @@ +import {HashTable} from '../utils/hashmap' +/** @constructor */ +function Graph(data) { -TCAD.graph = {}; + this.connections = function(e) { + return data[e]; + }; + this.at = function(index) { + return index; + }; -TCAD.graph.findAllLoops = function(graph, hashCode, equals) { + this.size = function() { + return data.length; + }; +} + +Graph.findAllLoops = function(graph, hashCode, equals) { var loops = []; - var visited = new TCAD.struct.HashTable(hashCode, equals); + var visited = new HashTable(hashCode, equals); function step(vertex, comesFrom, path) { var i; visited.put(vertex, true); @@ -22,21 +35,20 @@ TCAD.graph.findAllLoops = function(graph, hashCode, equals) { path.push(vertex); var needClone = false; - VERTEX: - for (i = 0; i < next.length; i++) { - var v = next[i]; - if (equals(v, comesFrom)) { - continue; - } - - var p = needClone ? path.slice(0) : path; - needClone = true; - step(v, vertex, p); + for (i = 0; i < next.length; i++) { + var v = next[i]; + if (equals(v, comesFrom)) { + continue; } + + var p = needClone ? path.slice(0) : path; + needClone = true; + step(v, vertex, p); + } path.pop(); } - for (var i = 0; i < graph.size(); i++) { + for (i = 0; i < graph.size(); i++) { var vertex = graph.at(i); if (visited.get(vertex) !== true) { step(vertex, -1, []); @@ -70,8 +82,8 @@ TCAD.graph.findAllLoops = function(graph, hashCode, equals) { return true; } - var duplicates = 0; - for (var i = 0; i < loops.length; i++) { + var i, duplicates = 0; + for (i = 0; i < loops.length; i++) { var a = loops[i]; if (a == null) continue; for (var j = i + 1; j < loops.length; j++) { @@ -87,7 +99,7 @@ TCAD.graph.findAllLoops = function(graph, hashCode, equals) { } if (duplicates != 0) { var filtered = []; - for (var i = 0; i < loops.length; i++) { + for (i = 0; i < loops.length; i++) { if (loops[i] != null) filtered.push(loops[i]); } loops = filtered; @@ -96,23 +108,8 @@ TCAD.graph.findAllLoops = function(graph, hashCode, equals) { return loops; }; -/** @constructor */ -TCAD.graph.Graph = function(data) { - this.connections = function(e) { - return data[e]; - }; - - this.at = function(index) { - return index; - }; - - this.size = function() { - return data.length; - }; -}; - -TCAD.graph.test = function() { +var test = function() { var data = [ [], [2], @@ -126,11 +123,11 @@ TCAD.graph.test = function() { [2, 4] ]; - var graph = new TCAD.graph.Graph(data); - console.log(TCAD.graph.findAllLoops(graph)); + var graph = new Graph(data); + console.log(Graph.findAllLoops(graph)); }; -TCAD.graph.test0 = function() { +var test0 = function() { var data = [ [3, 1], [0, 2, 8], @@ -143,6 +140,8 @@ TCAD.graph.test0 = function() { [1, 7] ]; - var graph = new TCAD.graph.Graph(data); - console.log(TCAD.graph.findAllLoops(graph)); + var graph = new Graph(data); + console.log(Graph.findAllLoops(graph)); }; + +export {Graph} \ No newline at end of file diff --git a/web/app/math/l3space.js b/web/app/math/l3space.js new file mode 100644 index 00000000..1a8b85ba --- /dev/null +++ b/web/app/math/l3space.js @@ -0,0 +1,202 @@ +import Vector from './vector'; + +var ORIGIN = new Vector(0, 0, 0); + +var AXIS = { + X : new Vector(1, 0, 0), + Y : new Vector(0, 1, 0), + Z : new Vector(0, 0, 1) +}; + +var IDENTITY_BASIS = [AXIS.X, AXIS.Y, AXIS.Z]; + +/** @constructor */ +function Matrix3() { + this.reset(); +} + +Matrix3.prototype.reset = function() { + this.mxx = 1; this.mxy = 0; this.mxz = 0; this.tx = 0; + this.myx = 0; this.myy = 1; this.myz = 0; this.ty = 0; + this.mzx = 0; this.mzy = 0; this.mzz = 1; this.tz = 0; + return this; +}; + +Matrix3.prototype.setBasis = function(basis) { + var b = basis; + this.mxx = b[0].x; this.mxy = b[1].x; this.mxz = b[2].x; this.tx = 0; + this.myx = b[0].y; this.myy = b[1].y; this.myz = b[2].y; this.ty = 0; + this.mzx = b[0].z; this.mzy = b[1].z; this.mzz = b[2].z; this.tz = 0; + return this; +}; + +Matrix3.prototype.set3 = function( + mxx, mxy, mxz, + myx, myy, myz, + mzx, mzy, mzz +) { + this.mxx = mxx; this.mxy = mxy; this.mxz = mxz; + this.myx = myx; this.myy = myy; this.myz = myz; + this.mzx = mzx; this.mzy = mzy; this.mzz = mzz; + return this; +}; + +Matrix3.prototype.set34 = function( + mxx, mxy, mxz, tx, + myx, myy, myz, ty, + mzx, mzy, mzz, tz +) { + this.mxx = mxx; this.mxy = mxy; this.mxz = mxz; this.tx = tx; + this.myx = myx; this.myy = myy; this.myz = myz; this.ty = ty; + this.mzx = mzx; this.mzy = mzy; this.mzz = mzz; this.tz = tz; + return this; +}; + +Matrix3.prototype.setMatrix = function(m) { + this.mxx = m.mxx; this.mxy = m.mxy; this.mxz = m.mxz; this.tx = m.tx; + this.myx = m.myx; this.myy = m.myy; this.myz = m.myz; this.ty = m.ty; + this.mzx = m.mzx; this.mzy = m.mzy; this.mzz = m.mzz; this.tz = m.tz; + return this; +}; + +Matrix3.prototype.invert = function() { + + var det = + this.mxx * (this.myy * this.mzz - this.mzy * this.myz) + + this.mxy * (this.myz * this.mzx - this.mzz * this.myx) + + this.mxz * (this.myx * this.mzy - this.mzx * this.myy); + + if (det == 0.0) { + return null; + } + + var cxx = this.myy * this.mzz - this.myz * this.mzy; + var cyx = - this.myx * this.mzz + this.myz * this.mzx; + var czx = this.myx * this.mzy - this.myy * this.mzx; + var cxt = - this.mxy * (this.myz * this.tz - this.mzz * this.ty) + - this.mxz * (this.ty * this.mzy - this.tz * this.myy) + - this.tx * (this.myy * this.mzz - this.mzy * this.myz); + var cxy = - this.mxy * this.mzz + this.mxz * this.mzy; + var cyy = this.mxx * this.mzz - this.mxz * this.mzx; + var czy = - this.mxx * this.mzy + this.mxy * this.mzx; + var cyt = this.mxx * (this.myz * this.tz - this.mzz * this.ty) + + this.mxz * (this.ty * this.mzx - this.tz * this.myx) + + this.tx * (this.myx * this.mzz - this.mzx * this.myz); + var cxz = this.mxy * this.myz - this.mxz * this.myy; + var cyz = - this.mxx * this.myz + this.mxz * this.myx; + var czz = this.mxx * this.myy - this.mxy * this.myx; + var czt = - this.mxx * (this.myy * this.tz - this.mzy * this.ty) + - this.mxy * (this.ty * this.mzx - this.tz * this.myx) + - this.tx * (this.myx * this.mzy - this.mzx * this.myy); + + var result = new Matrix3(); + result.mxx = cxx / det; + result.mxy = cxy / det; + result.mxz = cxz / det; + result.tx = cxt / det; + result.myx = cyx / det; + result.myy = cyy / det; + result.myz = cyz / det; + result.ty = cyt / det; + result.mzx = czx / det; + result.mzy = czy / det; + result.mzz = czz / det; + result.tz = czt / det; + return result; +}; + +Matrix3.prototype.combine = function(transform) { + var txx = transform.mxx; + var txy = transform.mxy; + var txz = transform.mxz; + var ttx = transform.tx; + var tyx = transform.myx; + var tyy = transform.myy; + var tyz = transform.myz; + var tty = transform.ty; + var tzx = transform.mzx; + var tzy = transform.mzy; + var tzz = transform.mzz; + var ttz = transform.tz; + + var m = new Matrix3(); + m.mxx = (this.mxx * txx + this.mxy * tyx + this.mxz * tzx); + m.mxy = (this.mxx * txy + this.mxy * tyy + this.mxz * tzy); + m.mxz = (this.mxx * txz + this.mxy * tyz + this.mxz * tzz); + m.tx = (this.mxx * ttx + this.mxy * tty + this.mxz * ttz + this.tx); + m.myx = (this.myx * txx + this.myy * tyx + this.myz * tzx); + m.myy = (this.myx * txy + this.myy * tyy + this.myz * tzy); + m.myz = (this.myx * txz + this.myy * tyz + this.myz * tzz); + m.ty = (this.myx * ttx + this.myy * tty + this.myz * ttz + this.ty); + m.mzx = (this.mzx * txx + this.mzy * tyx + this.mzz * tzx); + m.mzy = (this.mzx * txy + this.mzy * tyy + this.mzz * tzy); + m.mzz = (this.mzx * txz + this.mzy * tyz + this.mzz * tzz); + m.tz = (this.mzx * ttx + this.mzy * tty + this.mzz * ttz + this.tz); + + return m; +}; + +Matrix3.prototype.apply = function(vector) { + return this.__apply(vector, new Vector()) +}; + +Matrix3.prototype._apply = function(vector) { + return this.__apply(vector, vector); +}; + +Matrix3.prototype.__apply = function(vector, out) { + var x = vector.x; + var y = vector.y; + var z = vector.z; + return out.set( + this.mxx * x + this.mxy * y + this.mxz * z + this.tx, + this.myx * x + this.myy * y + this.myz * z + this.ty, + this.mzx * x + this.mzy * y + this.mzz * z + this.tz); +}; + +Matrix3.rotateMatrix = function(angle, axis, pivot) { + var sin = Math.sin(angle); + var cos = Math.cos(angle); + var axisX, axisY, axisZ; + var m = new Matrix3(); + + if (axis === AXIS.X || axis === AXIS.Y || axis === AXIS.Z) { + axisX = axis.x; + axisY = axis.y; + axisZ = axis.z; + } else { + // normalize + var mag = axis.length(); + + if (mag == 0.0) { + return m; + } else { + axisX = axis.x / mag; + axisY = axis.y / mag; + axisZ = axis.z / mag; + } + } + + var px = pivot.x; + var py = pivot.y; + var pz = pivot.z; + + m.mxx = cos + axisX * axisX * (1 - cos); + m.mxy = axisX * axisY * (1 - cos) - axisZ * sin; + m.mxz = axisX * axisZ * (1 - cos) + axisY * sin; + + m.tx = px * (1 - m.mxx) - py * m.mxy - pz * m.mxz; + + m.myx = axisY * axisX * (1 - cos) + axisZ * sin; + m.myy = cos + axisY * axisY * (1 - cos); + m.myz = axisY * axisZ * (1 - cos) - axisX * sin; + m.ty = py * (1 - m.myy) - px * m.myx - pz * m.myz; + + m.mzx = axisZ * axisX * (1 - cos) - axisY * sin; + m.mzy = axisZ * axisY * (1 - cos) + axisX * sin; + m.mzz = cos + axisZ * axisZ * (1 - cos); + m.tz = pz * (1 - m.mzz) - px * m.mzx - py * m.mzy; + return m; +}; + +export {Matrix3, ORIGIN, IDENTITY_BASIS, AXIS}; \ No newline at end of file diff --git a/web/app/math/lm.js b/web/app/math/lm.js index 088f5e32..01d1054e 100644 --- a/web/app/math/lm.js +++ b/web/app/math/lm.js @@ -76,7 +76,7 @@ * @version $Id: LevenbergMarquardtOptimizer.java 1416643 2012-12-03 19:37:14Z tn $ * @constructor */ -function LMOptimizer(startPoint, target, model, jacobian) { +export default function LMOptimizer(startPoint, target, model, jacobian) { this.startPoint = startPoint; diff --git a/web/app/math/math.js b/web/app/math/math.js index 11aa2413..4d411bd0 100644 --- a/web/app/math/math.js +++ b/web/app/math/math.js @@ -1,121 +1,89 @@ -TCAD.math = {}; +import Vector from './vector' -TCAD.math._arr = function(size) { - var out = []; - out.length = size; - for (var i = 0; i < size; ++i) { - out[i] = 0; - } - return out; -}; +export const TOLERANCE = 1E-6; -TCAD.math._matrix = function(m, n) { - var out = []; - out.length = m; - for (var i = 0; i < m; ++i) { - out[i] = TCAD.math._arr(n); - } - return out; -}; +export function distanceAB(a, b) { + return distance(a.x, a.y, b.x, b.y); +} -TCAD.math.distanceAB = function(a, b) { - return TCAD.math.distance(a.x, a.y, b.x, b.y); -}; - -TCAD.math.distance = function(x1, y1, x2, y2) { +export function distance(x1, y1, x2, y2) { var dx = x1 - x2; var dy = y1 - y2; return Math.sqrt(dx * dx + dy * dy); -}; +} -TCAD.math.distanceAB3 = function(a, b) { - return TCAD.math.distance3(a.x, a.y, a.z, b.x, b.y, b.z); -}; +export function distanceAB3(a, b) { + return distance3(a.x, a.y, a.z, b.x, b.y, b.z); +} -TCAD.math.distance3 = function(x1, y1, z1, x2, y2, z2) { +export function distance3(x1, y1, z1, x2, y2, z2) { var dx = x1 - x2; var dy = y1 - y2; var dz = z1 - z2; return Math.sqrt(dx * dx + dy * dy + dz * dz); -}; +} -TCAD.math.ORIGIN = new TCAD.Vector(0, 0, 0); - -TCAD.math.AXIS = { - X : new TCAD.Vector(1, 0, 0), - Y : new TCAD.Vector(0, 1, 0), - Z : new TCAD.Vector(0, 0, 1) -}; - -TCAD.math.IDENTITY_BASIS = [TCAD.math.AXIS.X, TCAD.math.AXIS.Y, TCAD.math.AXIS.Z]; - -TCAD.math.rotateMatrix = function(angle, axis, pivot) { - var sin = Math.sin(angle); - var cos = Math.cos(angle); - var axisX, axisY, axisZ; - var m = new TCAD.Matrix(); - - var AXIS = TCAD.math.AXIS; - - if (axis === AXIS.X || axis === AXIS.Y || axis === AXIS.Z) { - axisX = axis.x; - axisY = axis.y; - axisZ = axis.z; - } else { - // normalize - var mag = axis.length(); - - if (mag == 0.0) { - return m; - } else { - axisX = axis.x / mag; - axisY = axis.y / mag; - axisZ = axis.z / mag; - } - } - - var px = pivot.x; - var py = pivot.y; - var pz = pivot.z; - - m.mxx = cos + axisX * axisX * (1 - cos); - m.mxy = axisX * axisY * (1 - cos) - axisZ * sin; - m.mxz = axisX * axisZ * (1 - cos) + axisY * sin; - - m.tx = px * (1 - m.mxx) - py * m.mxy - pz * m.mxz; - - m.myx = axisY * axisX * (1 - cos) + axisZ * sin; - m.myy = cos + axisY * axisY * (1 - cos); - m.myz = axisY * axisZ * (1 - cos) - axisX * sin; - m.ty = py * (1 - m.myy) - px * m.myx - pz * m.myz; - - m.mzx = axisZ * axisX * (1 - cos) - axisY * sin; - m.mzy = axisZ * axisY * (1 - cos) + axisX * sin; - m.mzz = cos + axisZ * axisZ * (1 - cos); - m.tz = pz * (1 - m.mzz) - px * m.mzx - py * m.mzy; - return m; -}; - -TCAD.math.circleFromPoints = function(p1, p2, p3) { - var center = new TCAD.Vector(); +export function circleFromPoints(p1, p2, p3) { + var center = new Vector(); var offset = p2.x*p2.x + p2.y*p2.y; var bc = ( p1.x*p1.x + p1.y*p1.y - offset )/2.0; var cd = (offset - p3.x*p3.x - p3.y*p3.y)/2.0; var det = (p1.x - p2.x) * (p2.y - p3.y) - (p2.x - p3.x)* (p1.y - p2.y); - if (Math.abs(det) < TCAD.TOLERANCE) { return null; } + if (Math.abs(det) < TOLERANCE) { return null; } var idet = 1/det; center.x = (bc * (p2.y - p3.y) - cd * (p1.y - p2.y)) * idet; center.y = (cd * (p1.x - p2.x) - bc * (p2.x - p3.x)) * idet; return center; -}; +} -TCAD.math.norm2 = function(vec) { +export function norm2(vec) { var sq = 0; for (var i = 0; i < vec.length; i++) { sq += vec[i] * vec[i]; } return Math.sqrt(sq); -}; \ No newline at end of file +} + +export function areEqual(v1, v2, tolerance) { + return Math.abs(v1 - v2) < tolerance; +} + +export function areVectorsEqual(v1, v2, tolerance) { + return areEqual(v1.x, v2.x, tolerance) && + areEqual(v1.y, v2.y, tolerance) && + areEqual(v1.z, v2.z, tolerance); +} + +export function vectorsEqual(v1, v2) { + return areVectorsEqual(v1, v2, TOLERANCE); +} + +export function equal(v1, v2) { + return areEqual(v1, v2, TOLERANCE); +} + +export function strictEqual(a, b) { + return a.x == b.x && a.y == b.y && a.z == b.z; +} + +export function _vec(size) { + var out = []; + out.length = size; + for (var i = 0; i < size; ++i) { + out[i] = 0; + } + return out; +} + +export function _matrix(m, n) { + var out = []; + out.length = m; + for (var i = 0; i < m; ++i) { + out[i] = _vec(n); + } + return out; +} + diff --git a/web/app/math/matrix.js b/web/app/math/matrix.js index 41e31ccd..be52aea2 100644 --- a/web/app/math/matrix.js +++ b/web/app/math/matrix.js @@ -1,15 +1,19 @@ +import * as math from 'math' -/** @constructor */ -TCAD.math.Matrix = function(r, c) { +/** + * @constructor + * @deprecated use numeric library + * */ +export function Matrix(r, c) { this.data = []; this.rSize = r; this.cSize = c; for (var i = 0; i < r; i++) { - this.data[i] = TCAD.math._arr(c) + this.data[i] = math._vec(c) } -}; +} -TCAD.math.Matrix.prototype.identity = function() { +Matrix.prototype.identity = function() { for (var i = 0; i < this.rSize; i++) { for (var j = 0; j < this.cSize; j++) { @@ -18,8 +22,8 @@ TCAD.math.Matrix.prototype.identity = function() { } }; -TCAD.math.Matrix.prototype.subtract = function(m) { - var out = new TCAD.math.Matrix(this.rSize, this.cSize); +Matrix.prototype.subtract = function(m) { + var out = new Matrix(this.rSize, this.cSize); for (var i = 0; i < this.rSize; i++) { for (var j = 0; j < this.cSize; j++) { out.data[i][j] = this.data[i][j] - m.data[i][j]; @@ -28,8 +32,8 @@ TCAD.math.Matrix.prototype.subtract = function(m) { return out; }; -TCAD.math.Matrix.prototype.add = function(m) { - var out = new TCAD.math.Matrix(this.rSize, this.cSize); +Matrix.prototype.add = function(m) { + var out = new Matrix(this.rSize, this.cSize); for (var i = 0; i < this.rSize; i++) { for (var j = 0; j < this.cSize; j++) { out.data[i][j] = this.data[i][j] + m.data[i][j]; @@ -38,16 +42,16 @@ TCAD.math.Matrix.prototype.add = function(m) { return out; }; -TCAD.math.Matrix.prototype.multiply = function(m) { +Matrix.prototype.multiply = function(m) { var nRows = this.rSize; var nCols = m.cSize; var nSum = this.cSize; - var out = new TCAD.math.Matrix(nRows, nCols); + var out = new Matrix(nRows, nCols); var outData = out.data; - var mCol = TCAD.math._arr(nSum); + var mCol = math._vec(nSum); var mData = m.data; for (var col = 0; col < nCols; col++) { @@ -68,8 +72,8 @@ TCAD.math.Matrix.prototype.multiply = function(m) { return out; }; -TCAD.math.Matrix.prototype.scalarMultiply = function(s) { - var out = new TCAD.math.Matrix(this.rSize, this.cSize); +Matrix.prototype.scalarMultiply = function(s) { + var out = new Matrix(this.rSize, this.cSize); for (var i = 0; i < this.rSize; i++) { for (var j = 0; j < this.cSize; j++) { out.data[i][j] = this.data[i][j] * s; @@ -78,8 +82,8 @@ TCAD.math.Matrix.prototype.scalarMultiply = function(s) { return out; }; -TCAD.math.Matrix.prototype.transpose = function() { - var out = new TCAD.math.Matrix(this.cSize, this.rSize); +Matrix.prototype.transpose = function() { + var out = new Matrix(this.cSize, this.rSize); for (var i = 0; i < this.rSize; i++) { for (var j = 0; j < this.cSize; j++) { out.data[j][i] = this.data[i][j]; @@ -88,8 +92,8 @@ TCAD.math.Matrix.prototype.transpose = function() { return out; }; -TCAD.math.Matrix.prototype.copy = function() { - var out = new TCAD.math.Matrix(this.rSize, this.cSize); +Matrix.prototype.copy = function() { + var out = new Matrix(this.rSize, this.cSize); for (var i = 0; i < this.rSize; i++) { for (var j = 0; j < this.cSize; j++) { out.data[i][j] = this.data[i][j]; @@ -98,7 +102,7 @@ TCAD.math.Matrix.prototype.copy = function() { return out; }; -TCAD.math.Matrix.prototype.dot = function(v) { +Matrix.prototype.dot = function(v) { var vData = v.data; var dot = 0; for (var i = 0; i < this.rSize; i++) { @@ -107,7 +111,7 @@ TCAD.math.Matrix.prototype.dot = function(v) { return dot; }; -TCAD.math.Matrix.prototype.norm = function(v) { +Matrix.prototype.norm = function(v) { var sum = 0; for (var i = 0; i < this.rSize; i++) { var a = this.data[i][0]; @@ -115,11 +119,3 @@ TCAD.math.Matrix.prototype.norm = function(v) { } return Math.sqrt(sum); }; - -/** @constructor */ -TCAD.math.Vector = function(n) { - TCAD.math.Matrix.call(this, n, 1); -}; - -TCAD.TWO.utils.extend(TCAD.math.Vector, TCAD.math.Matrix); - diff --git a/web/app/math/optim.js b/web/app/math/optim.js index f0c71ca3..9336ab7c 100644 --- a/web/app/math/optim.js +++ b/web/app/math/optim.js @@ -1,9 +1,8 @@ -optim = {}; - -optim.DEBUG_HANDLER = function() {}; +import numeric from 'numeric'; +import {_vec, _matrix} from './math' //Added strong wolfe condition to numeric's uncmin -optim.bfgs_ = function(f,x0,tol,gradient,maxit,callback,options) { +var bfgs_ = function(f,x0,tol,gradient,maxit,callback,options) { var grad = numeric.gradient; if(typeof options === "undefined") { options = {}; } if(typeof tol === "undefined") { tol = 1e-8; } @@ -44,7 +43,6 @@ optim.bfgs_ = function(f,x0,tol,gradient,maxit,callback,options) { tR = t; t = (tL + tR) * 0.5; ++it; - continue; } else { var slope = dot(gradient(x1), step); if (slope <= 0.9 * Math.abs(df0)){ @@ -52,14 +50,11 @@ optim.bfgs_ = function(f,x0,tol,gradient,maxit,callback,options) { }else if ( slope >= 0.9 * df0) { tR = t; t = (tL+ tR) * 0.5; - continue; }else{ tL = t; t = (tL+ tR)*0.5; - continue; } } - break; } if(t*nstep < tol) { msg = "Line search step size smaller than tol"; break; } if(it === maxit) { msg = "maxit reached during line search"; break; } @@ -83,7 +78,7 @@ optim.bfgs_ = function(f,x0,tol,gradient,maxit,callback,options) { }; -optim.bfgs = function(f,x0,tol,gradient,maxit,callback,options) { +var bfgs = function(f,x0,tol,gradient,maxit,callback,options) { var grad = numeric.gradient; if(typeof options === "undefined") { options = {}; } if(typeof tol === "undefined") { tol = 1e-8; } @@ -119,7 +114,7 @@ optim.bfgs = function(f,x0,tol,gradient,maxit,callback,options) { x1 = add(x0,s); var f2 = f(x1); - t3 = 2.0; + var t3 = 2.0; s = mul(step,t3); x1 = add(x0,s); var f3 = f(x1); @@ -194,7 +189,7 @@ optim.bfgs = function(f,x0,tol,gradient,maxit,callback,options) { return {solution: x0, f: f0, gradient: g0, invHessian: H1, iterations:it, message: msg}; }; -optim.bfgs_updater = function(gradient, x0) { +var bfgs_updater = function(gradient, x0) { var n = x0.length; var max = Math.max, norm2 = numeric.norm2; var g0,g1,H1 = numeric.identity(n); @@ -202,7 +197,7 @@ optim.bfgs_updater = function(gradient, x0) { var all = numeric.all, isfinite = numeric.isFinite, neg = numeric.neg; var y,Hy,Hs,ys; var msg = ""; - var g0 = gradient(x0); + g0 = gradient(x0); function step() { return neg(dot(H1,g0)); @@ -227,9 +222,10 @@ optim.bfgs_updater = function(gradient, x0) { return {step:step, update:update}; }; -optim.inv = function inv(x) { - var s = numeric.dim(x), abs = Math.abs, m = s[0], n = s[1]; - var A = numeric.clone(x), Ai, Aj; +var inv = function inv(A) { + A = numeric.clone(A); + var s = numeric.dim(A), abs = Math.abs, m = s[0], n = s[1]; + var Ai, Aj; var I = numeric.identity(m), Ii, Ij; var i,j,k,x; for(j=0;j', {type : 'checkbox', checked : 'checked', value : c.prototype.NAME}); content.append( - $('