diff --git a/.eslintrc.json b/.eslintrc.json index adeac6ca..fb299080 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -14,6 +14,13 @@ "CSG" : true, "PNLTRI" : true, "__DEBUG__": true, + "__CAD_APP": true, + "Module": true, + "_free": true, + "_malloc": true, + "writeAsciiToMemory": true, + "__E0_ENGINE_EXCHANGE_VAL": true, + "verb": true, "$": true }, "rules": { @@ -22,5 +29,9 @@ "max-len": "off", "no-console": "off", "no-extra-boolean-cast": "off" - } + }, + "ignorePatterns": [ + "/modules/math/optim/*.js", + "/modules/math/qr.js" + ] } diff --git a/build/.eslintignore b/build/.eslintignore deleted file mode 100644 index 047232a1..00000000 --- a/build/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -/web/app/math/lm.js -/web/app/math/qr.js - diff --git a/modules/brep/operations/boolean-mesh.js b/modules/brep/operations/boolean-mesh.js deleted file mode 100644 index cae5adc0..00000000 --- a/modules/brep/operations/boolean-mesh.js +++ /dev/null @@ -1,54 +0,0 @@ -import {polyhedronify} from './polyhedronify' -import {union as unionImpl, intersect as intersectImpl, subtract as subtractImpl} from './boolean' - - -export function union( shell1, shell2 ) { - return doOp(shell1, shell2, unionImpl); -} - -export function intersect( shell1, shell2 ) { - return doOp(shell1, shell2, intersectImpl); -} - -export function subtract( shell1, shell2 ) { - return doOp(shell1, shell2, subtractImpl); -} - -function doOp(shell1, shell2, transformFunc) { - shell1 = polyhedronify(shell1); - shell2 = polyhedronify(shell2); - - const result = transformFunc(shell1, shell2); - //return reconstruct(result); - return result; -} - -function extractLoops(polygons) { - const seen = new Set(); - for (let p of polygons) { - for (let v of p.vertices) { - for (let e of v.edges) { - - } - if (seen.has(v)) { - continue - } - } - } -} - -function splitByFace(polygons) { - const byFace = new Map(); - for (let p of polygons) { - addToListInMap(byFace, p.group, p); - } -} - -function addToListInMap(map, key, value) { - let list = map.get(key); - if (!list) { - list = []; - map.set(key, list); - } - list.push(value); -} diff --git a/modules/brep/operations/boolean.js b/modules/brep/operations/boolean.js index 4af2b63c..eafa80f1 100644 --- a/modules/brep/operations/boolean.js +++ b/modules/brep/operations/boolean.js @@ -182,7 +182,7 @@ function detectLoops(surface, graph) { BREP_DEBUG.startBooleanLoopDetection(graph); const loops = []; const seen = new Set(); - while (true) { + for (;;) { let edge = graph.graphEdges.pop(); if (!edge) { break; diff --git a/modules/brep/operations/polyhedronify.js b/modules/brep/operations/polyhedronify.js deleted file mode 100644 index bc62b3e9..00000000 --- a/modules/brep/operations/polyhedronify.js +++ /dev/null @@ -1,87 +0,0 @@ -import {TriangulateFace} from '../../../web/app/cad/tess/triangulation' -import {Shell} from '../topo/shell' -import {HalfEdge} from '../topo/edge' -import {Loop} from '../topo/loop' -import {Face} from '../topo/face' -import {BREPValidator} from '../brep-validator'; -import {linkSegments} from '../brep-builder'; -import {Line} from 'geom/impl/line' - -export function polyhedronify(shell) { - shell.reindexVertices(); - const faces = []; - - const edgeIndex = new EdgeIndex(); - - for (let face of shell.faces) { - const plane = face.surface; - const triangles = TriangulateFace(face); - for (let triangle of triangles) { - const loop = new Loop(); - const n = triangle.length; // obviously it's 3 - for (let p = n - 1, q = 0; q < n; p = q++) { - - const a = triangle[p]; - const b = triangle[q]; - - const edge = edgeIndex.get(a, b); - edge.loop = loop; - loop.halfEdges.push(edge); - if (a.edgeFor(b) != null) { - edge.data.outline = true; - __DEBUG__.AddHalfEdge(edge, 0x00ff00); - } else { - __DEBUG__.AddHalfEdge(edge, 0xffffff); - } - } - const newFace = new Face(face.surface); - newFace.outerLoop = loop; - loop.face = newFace; - newFace.data.originFace = face; - linkSegments(loop.halfEdges); - faces.push(newFace); - } - } - const polyhedron = new Shell(); - faces.forEach(face => { - face.shell = polyhedron; - polyhedron.faces.push(face); - }); - - BREPValidator.validateToConsole(polyhedron); - - return polyhedron; -} - -class EdgeIndex { - - constructor() { - this.index = new Map(); - } - - get(a, b) { - const subMap = this.getForPoint(a); - let edge = subMap.get(b); - - if (edge == null) { - - edge = HalfEdge.fromVertices(a, b, Line.fromSegment(a.point, b.point)); - subMap.set(b, edge); - const twinMap = this.getForPoint(b); - if (twinMap.has(a)) { - throw 'illegal state'; - } - twinMap.set(a, edge.twin()); - } - return edge; - } - - getForPoint(p) { - let subMap = this.index.get(p); - if (subMap == null) { - subMap = new Map(); - this.index.set(p, subMap); - } - return subMap; - } -} diff --git a/modules/geom/curves/closestPoint.js b/modules/geom/curves/closestPoint.js index 3a3fac0c..0b30d215 100644 --- a/modules/geom/curves/closestPoint.js +++ b/modules/geom/curves/closestPoint.js @@ -46,10 +46,6 @@ function distanceSqToSegment(a, b, pt) { export function solveClosestToCurveParamExactly(curve, pt, intMin, intMax, tol) { - function boundParam(u) { - return Math.min(max, Math.max(min, u)); - } - //solving minimization problem of squared distance //f(u) = (fx(u) - x)^2 + (fy(u) - y)^2 + (fz(u) - z)^2 = fx^2 - 2*fx*x + x^2 ... diff --git a/modules/geom/intersection/surfaceSurfaceStablePoints.js b/modules/geom/intersection/surfaceSurfaceStablePoints.js index fed42b84..75cd5dab 100644 --- a/modules/geom/intersection/surfaceSurfaceStablePoints.js +++ b/modules/geom/intersection/surfaceSurfaceStablePoints.js @@ -2,7 +2,7 @@ import {newtonIterationsOnInterval} from '../curves/newtonIterations'; export function surfaceSurfaceStablePoints(surfaceA, surfaceB) { - function impl(surfaceA, surfaceB) { + function impl(curve) { //solving minimization problem of squared distance @@ -16,8 +16,8 @@ export function surfaceSurfaceStablePoints(surfaceA, surfaceB) { let [f, d1, d2] = curve.eval(u, 2); - let r1Comp = i => 2 * f[i] * d1[i] - 2 * pt[i] * d1[i]; - let r2Comp = i => 2 * f[i] * d2[i] + 2 * d1[i] * d1[i] - 2 * pt[i] * d2[i]; + let r1Comp = i => 2 * f[i] * d1[i] - 2 * f[i] * d1[i]; + let r2Comp = i => 2 * f[i] * d2[i] + 2 * d1[i] * d1[i] - 2 * f[i] * d2[i]; let r1 = r1Comp(X) + r1Comp(Y) + r1Comp(Z); let r2 = r2Comp(X) + r2Comp(Y) + r2Comp(Z); @@ -25,7 +25,9 @@ export function surfaceSurfaceStablePoints(surfaceA, surfaceB) { return [r1, r2]; } - return newtonIterationsOnInterval(squareDistanceFn, intMin, intMax, tol); + let intMin = 0; + let intMax = 0; + return newtonIterationsOnInterval(squareDistanceFn, intMin, intMax, 1e-5); } diff --git a/modules/scene/utils/calcFaceNormal.js b/modules/scene/utils/calcFaceNormal.js deleted file mode 100644 index b1fc41b1..00000000 --- a/modules/scene/utils/calcFaceNormal.js +++ /dev/null @@ -1,9 +0,0 @@ - - -export default function(vA, vB, vC) { - let ab = new Vector3(); - face.normal.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - face.normal.cross( ab ); - face.normal.normalize(); -} \ No newline at end of file diff --git a/package.json b/package.json index 528876ec..cf78bd95 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "pack": "node ./node_modules/webpack/bin/webpack.js --config webpack.config.js --progress --profile --colors", "start-with-docs": "concurrently --kill-others 'npm start' './node_modules/grunt/bin/grunt docs-start'", "build": "grunt", - "lint": "./node_modules/eslint/bin/eslint web/app web/modules", + "lint": "./node_modules/eslint/bin/eslint.js web/app modules", "check-code": "./node_modules/typescript/bin/tsc --noEmit", "before-mainline-merging": "npm run lint && npm run check-code", "cypress": "npx cypress open" diff --git a/web/app/cad/actions/actionSystemBundle.ts b/web/app/cad/actions/actionSystemBundle.ts index 2067737d..acb3c276 100644 --- a/web/app/cad/actions/actionSystemBundle.ts +++ b/web/app/cad/actions/actionSystemBundle.ts @@ -23,7 +23,7 @@ export function activate(context: ApplicationContext) { let showAnonymousActionHint = enableAnonymousActionHint(context); - function run(id: string, data: any): void { + function run(id: string, data?: any): void { let state = streams.action.state[id].value; let runner = runners[id]; if (!state||!runner) { diff --git a/web/app/cad/actions/coreActions.js b/web/app/cad/actions/coreActions.js index 473d2af1..4287f254 100644 --- a/web/app/cad/actions/coreActions.js +++ b/web/app/cad/actions/coreActions.js @@ -1,6 +1,5 @@ import * as ActionHelpers from './actionHelpers' import {AiOutlineExport} from "react-icons/ai"; -import {CurrentWorkbenchIcon} from "cad/workbench/CurrentWorkbenchIcon"; export default [ { @@ -183,17 +182,6 @@ export default [ info: 'toggle whether to show sketches on a solid face' } }, - - { - id: 'LookAtSolid', - appearance: { - cssIcons: ['crosshairs'], - label: 'look at solid', - info: 'position camera at the solid at zoom to fit it', - }, - invoke: (context) => app.lookAtSolid(app.inputManager.context.attr('data-id')) - }, - { id: 'noIcon', appearance: { diff --git a/web/app/cad/cad-utils.js b/web/app/cad/cad-utils.js index 4eca7f4c..c2a11243 100644 --- a/web/app/cad/cad-utils.js +++ b/web/app/cad/cad-utils.js @@ -30,15 +30,6 @@ export function vec(v) { return new Vector(v.x, v.y, v.z); } -export function createBox(w, h, d) { - var square = createSquare(w, h); - //var rot = Matrix3.rotateMatrix(3/4, AXIS.Z, ORIGIN); - var halfDepth = d / 2; - square.forEach(function(v) { v.z -= halfDepth; } ); - var normal = normalOfCCWSeq(square); - return extrude(square, normal, normal.multiply(d), 1); -} - export function checkPolygon(poly) { if (poly.length < 3) { throw new Error('Polygon should contain at least 3 point'); diff --git a/web/app/cad/craft/e0/interact.js b/web/app/cad/craft/e0/interact.js index 7695bc91..722ba6bf 100644 --- a/web/app/cad/craft/e0/interact.js +++ b/web/app/cad/craft/e0/interact.js @@ -20,12 +20,10 @@ export function CallCommand(command, args) { // c_strings.forEach(_free); - // free c_arr _free(c_arr); // _free(commandPtr); - // return return rc; } diff --git a/web/app/cad/debugBundle.js b/web/app/cad/debugBundle.js index 2cc0d048..f8b600c5 100644 --- a/web/app/cad/debugBundle.js +++ b/web/app/cad/debugBundle.js @@ -300,7 +300,7 @@ const DebugMenuConfig = { cssIcons: ['bug'], info: 'set of debug actions', actions: ['DebugPrintAllSolids', 'DebugPrintFace', 'DebugFaceId', 'DebugFaceSketch', - 'DebugSetSketcherIntegerPrecision', 'DebugOpenLastTest', 'DebugGenerateTest', 'DebugOpenBrepDebugger'] + 'DebugSetSketcherIntegerPrecision', 'DebugOpenLastTest', 'DebugOpenBrepDebugger'] }; const DebugActions = [ @@ -411,50 +411,6 @@ const DebugActions = [ window.location.href = '/index.html?$$$__test__$$$'; } }, - { - id: 'DebugGenerateTest', - appearance: { - cssIcons: ['gear'], - label: 'generate unit test', - info: 'it will generate a unit code code containing sketches and operation sequence and output it to terminal', - }, - invoke: ({bus, services: {project, storage, sketchStorageService, cadRegistry}}) => { - - const pt = ({x, y}) => [x, y]; - - let sketches = sketchStorageService.getAllSketches().reduce((sketches, {id, url}) => { - let sketch = sketchStorageService.readSketch(id).getAllObjects().reduce((byType, obj) => { - - let type = obj.constructor.name; - - let arr = byType[type]; - if (!arr) { - arr = []; - byType[type] = arr; - } - - if (type === 'Segment' ){ - arr.push([pt(obj.a), pt(obj.b)]); - } else { - throw 'unsupported ' + type; - } - return byType; - }, {}); - sketches[id] = sketch; - return sketches; - }, {}); - - let testMetadata = { - name: project.id, - state: { - sketches, - operations: bus.state[CRAFT_TOKENS.MODIFICATIONS].history - }, - expected: toLoops(cadRegistry.getAllShells()[0].shell, readSketchFloat) - }; - console.log(JSON.stringify(testMetadata)); - } - }, { id: 'DebugOpenBrepDebugger', appearance: { diff --git a/web/app/cad/legacy/mesh/workbench.js b/web/app/cad/legacy/mesh/workbench.js index f88934fc..cc205559 100644 --- a/web/app/cad/legacy/mesh/workbench.js +++ b/web/app/cad/legacy/mesh/workbench.js @@ -1,8 +1,6 @@ import Vector from 'math/vector'; import * as cad_utils from '../../cad-utils' import {HashTable} from '../../../utils/hashmap' -import {Mesh} from '../mesh' -import revolve from './revolve' import {Triangulate} from '../../tess/triangulation' import {distanceAB3} from "math/distance"; import {areEqual, equal, strictEqual} from "math/equality"; @@ -51,85 +49,6 @@ export function sortPolygons(polygons) { return allShells; } -function extrudeNestedLoops(sketchedPolygons, normal, target, expansionFactor) { - const loops = sortPolygons(sketchedPolygons); - const doExtrude = (polygon) => { - const extruded = cad_utils.extrude(polygon, normal, target, expansionFactor); - return CSG.fromPolygons(_triangulateCSG(extruded)); - }; - let blob = null; - for (let loop of loops) { - let shell = doExtrude(loop.polygon); - for (let nestedLoop of loop.nesting) { - const hole = doExtrude(nestedLoop.polygon); - shell = shell.subtract(hole); - } - if (blob === null) { - blob = shell; - } else { - blob = blob.union(shell); - } - } - return blob; -} - -export function extrude(app, request) { - const face = request.face; - const sketchedPolygons = getSketchedPolygons3D(app, face); - if (sketchedPolygons == null) return null; - const normal = cad_utils.vec(face.csgGroup.plane.normal); - let blob = extrudeNestedLoops(sketchedPolygons, normal, request.params.target, request.params.expansionFactor); - let solid = request.solids[0]; - if (solid.mergeable) { - blob = solid.csg.union(blob); - } - face.csgGroup.shared.__tcad.faceId += '$'; - return [cad_utils.createSolid(blob, solid.id)]; -} - -export function cut(app, request) { - const face = request.face; - const sketchedPolygons = getSketchedPolygons3D(app, face); - if (sketchedPolygons == null) return null; - const normal = cad_utils.vec(face.csgGroup.plane.normal); - let cutter = extrudeNestedLoops(sketchedPolygons, normal, request.params.target, request.params.expansionFactor); - - face.csgGroup.shared.__tcad.faceId += '$'; - var outSolids = []; - for (var si = 0; si < request.solids.length; si++) { - let solid = request.solids[si]; - let work = solid.csg; - let cut = work.subtract(cutter); - let solidMesh = cad_utils.createSolid(cut, solid.id); - outSolids.push(solidMesh); - } - return outSolids; -} - -export function performRevolve(app, request) { - const face = request.face; - const sketchedPolygons = getSketchedPolygons3D(app, face); - if (sketchedPolygons == null) return null; - - const params = request.params; - - const vertices = face.getSketchObjectVerticesIn3D(params.pivotSketchObjectId); - if (!vertices) { - return null; - } - const axis = [vertices[0], vertices[vertices.length-1]]; - const revolved = revolve(sketchedPolygons, axis, params.angle / 180 * Math.PI, params.resolution); - - const solid = request.solids[0]; - let meld = CSG.fromPolygons(_triangulateCSG(revolved)); - if (solid.mergeable) { - meld = solid.csg.union(meld); - } - - face.csgGroup.shared.__tcad.faceId += '$'; - return [cad_utils.createSolid(meld, solid.id)]; -} - function _pointOnLine(p, a, b) { var ab = a.minus(b); @@ -512,131 +431,4 @@ function attract(vectors, precision) { } } -function recoverySketchInfo(polygons) { - var nonStructuralGons = []; - 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); - var i, path, n, p, q; - for (i = 0; i < paths.length; i++) { - path = paths[i]; - if (poly.csgInfo !== undefined && poly.csgInfo.derivedFrom !== undefined) { - n = path.length; - for (p = n - 1, q = 0; q < n ; p = q++ ) { - sketchEdges.put(key(path[p], path[q]), poly.csgInfo); - } - } else { - nonStructuralGons.push(path); - } - } - } - - 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])); - } - if (csgInfo) { - path[p].sketchConnectionObject = csgInfo.derivedFrom; - } - } - } -} - -function detach(request) { - var detachedConfig = {}; - for (var prop in request) { - if (request.hasOwnProperty(prop)) { - var value = request[prop]; - if (prop == 'solids') { - detachedConfig[prop] = value.map(function(s){return s.tCadId}); - } else if (prop == 'face') { - detachedConfig[prop] = value.id; - } else if (prop == 'target') { - detachedConfig[prop] = [value.x, value.y, value.z]; - } else if (prop == 'basis') { - detachedConfig[prop] = value.map(function(v){return [v.x, v.y, v.z]}); - } else if (prop == 'params') { - detachedConfig[prop] = detach(value); - } else { - detachedConfig[prop] = value; - } - } - } - return detachedConfig -} - -function materialize(index, detachedConfig) { - var request = {}; - function required(value) { - if (value == null || value == undefined) throw "value is required"; - return value; - } - for (var prop in detachedConfig) { - if (detachedConfig.hasOwnProperty(prop)) { - var value = detachedConfig[prop]; - if (prop == 'solids') { - request[prop] = value.map(function(id){return required(index.solids[id])}); - } else if (prop == 'target') { - 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 Vector().set3(v)}); - } else if (prop == 'params') { - request[prop] = materialize(index, value); - } else { - request[prop] = value; - } - } - } - return request; -} - -export const MESH_OPERATIONS = { - CUT : cut, - EXTRUDE : extrude, - REVOLVE : performRevolve, - PLANE : function(app, request) { - let basis, depth = request.params.depth; - const relativeToFaceId = request.params.relativeToFaceId; - if (relativeToFaceId != undefined && relativeToFaceId != '') { - const face = app.findFace(relativeToFaceId); - if (!face) return; - basis = face.basis(); - depth += face.depth(); - } else { - basis = request.params.basis; - } - return [cad_utils.createPlane(basis, depth)]; - }, - BOX : function(app, request) { - var p = request.params; - return [cad_utils.createCSGBox(p.w, p.h, p.d)]; - }, - SPHERE : function(app, request) { - return [cad_utils.createSphere(request.params.radius)]; - }, - IMPORT_STL: function(app, request) { - return request.params.objects.map(s => { - const smoothAngle = 1 / 180 * Math.PI; - const mesh = Mesh.fromPolygons(s.faces.map(f => f.vertices.map(v => new Vector().set3(v))), smoothAngle); - const polygons = []; - for (let meshFace of mesh.faces) { - const pl = meshFace.polygons[0]; - const plane = new CSG.Plane(pl.normal.csg(), pl.w); - const shared = cad_utils.createShared(); - meshFace.polygons.map(p => new CSG.Polygon(p.points.map(v => new CSG.Vertex(v.csg())), shared, plane)) - .forEach(p => polygons.push(p)); - } - return cad_utils.createSolid(CSG.fromPolygons(polygons)); - }); - } -}; diff --git a/web/app/cad/preview/scenePreviewer.js b/web/app/cad/preview/scenePreviewer.js index f6270ae6..3031091b 100644 --- a/web/app/cad/preview/scenePreviewer.js +++ b/web/app/cad/preview/scenePreviewer.js @@ -38,12 +38,6 @@ export function createPreviewer(sceneGeometryCreator, services, initialParams) { } -function sketchBasedPreviewCreator(params) { - const face = app.findFace(params.face); - if (!face) return null; - const triangles = this.createImpl(app, params, face.sketch.fetchContours(), face); - return createMeshFromTriangles(triangles, IMAGINARY_SURFACE_MATERIAL); -} // // function sketchBasedNurbsPreviewCreator(params) { // const face = app.findFace(params.face); diff --git a/web/app/cad/scene/controls/defaultSelectionState.js b/web/app/cad/scene/controls/defaultSelectionState.js deleted file mode 100644 index 1f44e80e..00000000 --- a/web/app/cad/scene/controls/defaultSelectionState.js +++ /dev/null @@ -1,28 +0,0 @@ -import {state} from 'lstream'; -import {DATUM, EDGE, FACE, SHELL, SKETCH_OBJECT} from '../../model/entities'; - -const SELECTABLE_ENTITIES = [FACE, EDGE, SKETCH_OBJECT, DATUM, SHELL]; - - -export function defineDefaultSelectionState(ctx) { - ctx.streams.selection = { - }; - SELECTABLE_ENTITIES.forEach(entity => { - ctx.streams.selection[entity] = state([]); - }); - - SELECTABLE_ENTITIES.forEach(entity => { - let entitySelectApi = { - objects: [], - single: undefined - }; - ctx.services.selection[entity] = entitySelectApi; - let selectionState = streams.selection[entity]; - selectionState.attach(selection => { - entitySelectApi.objects = selection.map(id => services.cadRegistry.findEntity(entity, id)); - entitySelectApi.single = entitySelectApi.objects[0]; - }); - entitySelectApi.select = selection => selectionState.value = selection; - }); - -} \ No newline at end of file diff --git a/web/app/cad/sketch/reassignSketchMode.js b/web/app/cad/sketch/reassignSketchMode.js index d10a518e..390d69b7 100644 --- a/web/app/cad/sketch/reassignSketchMode.js +++ b/web/app/cad/sketch/reassignSketchMode.js @@ -29,7 +29,7 @@ export default function initReassignSketchMode(ctx) { return {enter, exit}; } -function ReassignSketchTool({from, cancel}) { +function ReassignSketchToolImp({from, cancel}) { return