diff --git a/dist/bundle.js b/dist/bundle.js index ce76c00..033ffbb 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -4026,7 +4026,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac \*************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Sketcher\": () => (/* binding */ Sketcher)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/Three.js\");\n\n\n\n\n\nclass Sketcher extends _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Group {\n constructor(camera, domElement, plane) {\n super()\n this.camera = camera;\n this.domElement = domElement;\n this.scene = scene;\n this.plane = plane;\n this.matrixAutoUpdate = false;\n this.sketchNormal = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Vector3(0, 0, 1)\n this.orientSketcher(plane)\n\n\n this.add(new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.PlaneHelper(this.plane, 1, 0xffff00));\n\n\n this.linesGroup = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Group()\n this.linesArr = this.linesGroup.children\n this.pointsGroup = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Group()\n this.ptsArr = this.pointsGroup.children\n this.add(this.linesGroup)\n this.add(this.pointsGroup)\n\n window.lg = this.linesArr\n window.pg = this.ptsArr\n\n this.pickThreshold = 100\n this.grabbedObject = null\n\n this.lineMaterial = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.LineBasicMaterial({\n color: 0x555,\n })\n this.pointMaterial = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.PointsMaterial({\n color: 0xAAA,\n size: 3,\n })\n\n this.pointStart = this.pointStart.bind(this);\n this.pointEnd = this.pointEnd.bind(this);\n this.move = this.move.bind(this);\n this.keyHandler = this.keyHandler.bind(this);\n this.picker = this.picker.bind(this);\n this.grabbedMove = this.grabbedMove.bind(this);\n this.grabEnd = this.grabEnd.bind(this);\n this.raycaster = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Raycaster();\n\n\n window.addEventListener('keydown', this.keyHandler)\n domElement.addEventListener('pointerdown', this.picker)\n\n\n this.mode = \"\"\n\n\n }\n\n orientSketcher() {\n\n const theta = this.sketchNormal.angleTo(this.plane.normal)\n const axis = this.sketchNormal.clone().cross(this.plane.normal).normalize()\n const rot = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Matrix4().makeRotationAxis(axis, theta)\n const trans = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Matrix4().makeTranslation(0, 0, this.plane.constant)\n\n this.matrix = rot.multiply(trans) // world matrix will auto update in next render\n this.inverse = this.matrix.clone().invert()\n\n }\n\n keyHandler(e) {\n switch (e.key) {\n case 'Escape':\n this.clear()\n this.mode = \"\"\n break;\n case 'l':\n this.addLine()\n this.mode = \"line\"\n break;\n case 'b':\n this.solve()\n break;\n case '=':\n this.plane.applyMatrix4(new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4().makeRotationY(0.1))\n this.orientSketcher()\n\n this.dispatchEvent({ type: 'change' })\n break;\n case '-':\n this.plane.applyMatrix4(new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4().makeRotationY(-0.1))\n this.orientSketcher()\n\n this.dispatchEvent({ type: 'change' })\n break;\n }\n }\n\n\n picker(e) {\n if (this.mode || e.buttons != 1) return\n this.raycaster.setFromCamera(\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Vector2(\n (e.clientX / window.innerWidth) * 2 - 1,\n - (e.clientY / window.innerHeight) * 2 + 1\n ),\n this.camera\n );\n\n // console.log(this.ptsArr)\n const candidates = this.raycaster.intersectObjects(this.ptsArr)\n // console.log(candidates)\n\n\n if (!candidates.length) return;\n\n let minDist = candidates[0].distanceToRay\n let idx = 0\n\n for (let i = 1; i < candidates.length; i++) {\n if (candidates.distanceToRay < minDist) {\n minDist = candidates.distanceToRay\n idx = i\n }\n }\n\n if (minDist < this.pickThreshold) {\n this.grabPtIdx = this.ptsArr.indexOf(\n candidates[idx].object\n )\n } else {\n return\n }\n\n this.domElement.addEventListener('pointermove', this.grabbedMove);\n this.domElement.addEventListener('pointerup', this.grabEnd);\n }\n\n grabbedMove(e) {\n const mouseLoc = this.getLocation(e);\n\n this.moveLinePt(this.grabPtIdx, mouseLoc)\n\n this.dispatchEvent({ type: 'change' })\n }\n\n moveLinePt(ptIdx, absPos) {\n this.ptsArr[ptIdx].geometry.attributes.position.set(absPos);\n this.ptsArr[ptIdx].geometry.attributes.position.needsUpdate = true;\n\n const lineIdx = Math.floor(ptIdx / 2)\n const endPtIdx = (ptIdx % 2) * 3\n this.linesArr[lineIdx].geometry.attributes.position.set(absPos, endPtIdx)\n this.linesArr[lineIdx].geometry.attributes.position.needsUpdate = true;\n }\n\n grabEnd() {\n this.domElement.removeEventListener('pointermove', this.grabbedMove)\n this.domElement.removeEventListener('pointerup', this.grabEnd)\n this.ptsArr[this.grabPtIdx].geometry.computeBoundingSphere()\n // this.grabbedObject = null\n }\n\n\n addLine() {\n this.domElement.addEventListener('pointerdown', this.pointStart)\n }\n\n clear() {\n if (this.mode == \"\") return\n\n this.domElement.removeEventListener('pointerdown', this.pointStart)\n this.domElement.removeEventListener('pointermove', this.move);\n this.domElement.removeEventListener('pointerdown', this.pointEnd);\n this.domElement.removeEventListener('pointerdown', this.pointEnd);\n\n const lastLine = this.linesArr[this.linesArr.length - 1]\n this.linesGroup.remove(lastLine)\n lastLine.geometry.dispose()\n\n const lastPoints = this.ptsArr.slice(this.ptsArr.length - 2)\n this.pointsGroup.remove(...lastPoints)\n lastPoints.forEach(obj => obj.geometry.dispose())\n\n this.dispatchEvent({ type: 'change' })\n }\n\n getLocation(e) {\n this.raycaster.setFromCamera(\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Vector2(\n (e.clientX / window.innerWidth) * 2 - 1,\n - (e.clientY / window.innerHeight) * 2 + 1\n ),\n this.camera\n );\n // return this.worldToLocal(this.raycaster.ray.intersectPlane(this.plane)).toArray()\n return this.raycaster.ray.intersectPlane(this.plane).applyMatrix4(this.inverse).toArray()\n }\n\n pointStart(e) {\n if (e.buttons !== 1) return\n const mouseLoc = this.getLocation(e);\n\n this.lineGeom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferGeometry()\n this.lineGeom.setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferAttribute(\n new Float32Array(6), 3\n )\n );\n this.lineGeom.attributes.position.set(mouseLoc)\n this.line = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.LineSegments(this.lineGeom, this.lineMaterial);\n this.line.frustumCulled = false;\n this.linesGroup.add(this.line)\n\n this.p1Geom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferGeometry()\n this.p1Geom.setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferAttribute(\n new Float32Array(3), 3\n )\n );\n this.p1Geom.attributes.position.set(mouseLoc)\n this.p1 = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Points(this.p1Geom, this.pointMaterial);\n this.pointsGroup.add(this.p1)\n\n this.p2Geom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferGeometry()\n this.p2Geom.setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferAttribute(\n new Float32Array(3), 3\n )\n );\n this.p2 = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Points(this.p2Geom, this.pointMaterial);\n this.pointsGroup.add(this.p2)\n\n this.domElement.removeEventListener('pointerdown', this.pointStart)\n this.domElement.addEventListener('pointermove', this.move)\n this.domElement.addEventListener('pointerdown', this.pointEnd)\n }\n\n\n move(e) {\n const mouseLoc = this.getLocation(e);\n this.lineGeom.attributes.position.set(mouseLoc, 3)\n this.lineGeom.attributes.position.needsUpdate = true;\n this.p2Geom.attributes.position.set(mouseLoc);\n this.p2Geom.attributes.position.needsUpdate = true;\n this.p2Geom.computeBoundingSphere();\n this.dispatchEvent({ type: 'change' })\n }\n\n pointEnd(e) {\n if (e.buttons !== 1) return;\n this.domElement.removeEventListener('pointermove', this.move);\n this.domElement.removeEventListener('pointerdown', this.pointEnd);\n\n\n this.pointStart(e)\n }\n\n solve() {\n // const linesBuf = new Float32Array(this.linesArr.length * 4)\n // const xyOnly = [0,1,3,4];\n // let p = 0\n // for (let i = 0; i < this.linesArr.length; i++) {\n // for (let j of xyOnly) {\n // linesBuf[p++] = this.linesArr[i].geometry.attributes.position.array[j]\n // }\n // }\n\n let ptsBuf = new Float32Array(this.ptsArr.length * 2)\n for (let i = 0, p = 0; i < this.ptsArr.length; i++) {\n for (let j = 0; j < 2; j++) {\n ptsBuf[p++] = this.ptsArr[i].geometry.attributes.position.array[j]\n }\n }\n\n buffer = Module._malloc(ptsBuf.length * ptsBuf.BYTES_PER_ELEMENT)\n Module.HEAPF32.set(ptsBuf, buffer >> 2)\n\n Module[\"_solver\"](this.ptsArr.length/2, buffer)\n\n Module._free(buffer)\n }\n}\n\n\n\n\n\n//# sourceURL=webpack:///./src/Sketcher.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Sketcher\": () => (/* binding */ Sketcher)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/Three.js\");\n\n\n\n\n\nclass Sketcher extends _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Group {\n constructor(camera, domElement, plane) {\n super()\n this.camera = camera;\n this.domElement = domElement;\n this.scene = scene;\n this.plane = plane;\n this.matrixAutoUpdate = false;\n this.sketchNormal = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Vector3(0, 0, 1)\n this.orientSketcher(plane)\n\n\n this.add(new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.PlaneHelper(this.plane, 1, 0xffff00));\n\n\n this.linesGroup = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Group()\n this.linesArr = this.linesGroup.children\n this.pointsGroup = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Group()\n this.ptsArr = this.pointsGroup.children\n this.add(this.linesGroup)\n this.add(this.pointsGroup)\n\n window.lg = this.linesArr\n window.pg = this.ptsArr\n\n this.pickThreshold = 100\n this.grabbedObject = null\n\n this.lineMaterial = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.LineBasicMaterial({\n color: 0x555,\n })\n this.pointMaterial = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.PointsMaterial({\n color: 0xAAA,\n size: 3,\n })\n\n this.pointStart = this.pointStart.bind(this);\n this.pointEnd = this.pointEnd.bind(this);\n this.move = this.move.bind(this);\n this.keyHandler = this.keyHandler.bind(this);\n this.picker = this.picker.bind(this);\n this.grabbedMove = this.grabbedMove.bind(this);\n this.grabEnd = this.grabEnd.bind(this);\n this.raycaster = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Raycaster();\n\n\n window.addEventListener('keydown', this.keyHandler)\n domElement.addEventListener('pointerdown', this.picker)\n\n\n this.mode = \"\"\n\n\n }\n\n orientSketcher() {\n\n const theta = this.sketchNormal.angleTo(this.plane.normal)\n const axis = this.sketchNormal.clone().cross(this.plane.normal).normalize()\n const rot = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Matrix4().makeRotationAxis(axis, theta)\n const trans = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Matrix4().makeTranslation(0, 0, this.plane.constant)\n\n this.matrix = rot.multiply(trans) // world matrix will auto update in next render\n this.inverse = this.matrix.clone().invert()\n\n }\n\n keyHandler(e) {\n switch (e.key) {\n case 'Escape':\n this.clear()\n this.mode = \"\"\n break;\n case 'l':\n this.addLine()\n this.mode = \"line\"\n break;\n case 'b':\n this.solve()\n break;\n case '=':\n this.plane.applyMatrix4(new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4().makeRotationY(0.1))\n this.orientSketcher()\n\n this.dispatchEvent({ type: 'change' })\n break;\n case '-':\n this.plane.applyMatrix4(new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4().makeRotationY(-0.1))\n this.orientSketcher()\n\n this.dispatchEvent({ type: 'change' })\n break;\n }\n }\n\n\n picker(e) {\n if (this.mode || e.buttons != 1) return\n this.raycaster.setFromCamera(\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Vector2(\n (e.clientX / window.innerWidth) * 2 - 1,\n - (e.clientY / window.innerHeight) * 2 + 1\n ),\n this.camera\n );\n\n // console.log(this.ptsArr)\n const candidates = this.raycaster.intersectObjects(this.ptsArr)\n // console.log(candidates)\n\n\n if (!candidates.length) return;\n\n let minDist = candidates[0].distanceToRay\n let idx = 0\n\n for (let i = 1; i < candidates.length; i++) {\n if (candidates.distanceToRay < minDist) {\n minDist = candidates.distanceToRay\n idx = i\n }\n }\n\n if (minDist < this.pickThreshold) {\n this.grabPtIdx = this.ptsArr.indexOf(\n candidates[idx].object\n )\n } else {\n return\n }\n\n this.domElement.addEventListener('pointermove', this.grabbedMove);\n this.domElement.addEventListener('pointerup', this.grabEnd);\n }\n\n grabbedMove(e) {\n const mouseLoc = this.getLocation(e);\n\n this.moveLinePt(this.grabPtIdx, mouseLoc)\n\n this.dispatchEvent({ type: 'change' })\n }\n\n moveLinePt(ptIdx, absPos) {\n this.ptsArr[ptIdx].geometry.attributes.position.set(absPos);\n this.solve()\n // this.ptsArr[ptIdx].geometry.attributes.position.needsUpdate = true;\n\n // const lineIdx = Math.floor(ptIdx / 2)\n // const endPtIdx = (ptIdx % 2) * 3\n // this.linesArr[lineIdx].geometry.attributes.position.set(absPos, endPtIdx)\n // this.linesArr[lineIdx].geometry.attributes.position.needsUpdate = true;\n }\n\n grabEnd() {\n this.domElement.removeEventListener('pointermove', this.grabbedMove)\n this.domElement.removeEventListener('pointerup', this.grabEnd)\n this.ptsArr[this.grabPtIdx].geometry.computeBoundingSphere()\n // this.grabbedObject = null\n }\n\n\n addLine() {\n this.domElement.addEventListener('pointerdown', this.pointStart)\n }\n\n clear() {\n if (this.mode == \"\") return\n\n this.domElement.removeEventListener('pointerdown', this.pointStart)\n this.domElement.removeEventListener('pointermove', this.move);\n this.domElement.removeEventListener('pointerdown', this.pointEnd);\n this.domElement.removeEventListener('pointerdown', this.pointEnd);\n\n const lastLine = this.linesArr[this.linesArr.length - 1]\n this.linesGroup.remove(lastLine)\n lastLine.geometry.dispose()\n\n const lastPoints = this.ptsArr.slice(this.ptsArr.length - 2)\n this.pointsGroup.remove(...lastPoints)\n lastPoints.forEach(obj => obj.geometry.dispose())\n\n this.dispatchEvent({ type: 'change' })\n }\n\n getLocation(e) {\n this.raycaster.setFromCamera(\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Vector2(\n (e.clientX / window.innerWidth) * 2 - 1,\n - (e.clientY / window.innerHeight) * 2 + 1\n ),\n this.camera\n );\n // return this.worldToLocal(this.raycaster.ray.intersectPlane(this.plane)).toArray()\n return this.raycaster.ray.intersectPlane(this.plane).applyMatrix4(this.inverse).toArray()\n }\n\n pointStart(e) {\n if (e.buttons !== 1) return\n const mouseLoc = this.getLocation(e);\n\n this.lineGeom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferGeometry()\n this.lineGeom.setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferAttribute(\n new Float32Array(6), 3\n )\n );\n this.lineGeom.attributes.position.set(mouseLoc)\n this.line = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.LineSegments(this.lineGeom, this.lineMaterial);\n this.line.frustumCulled = false;\n this.linesGroup.add(this.line)\n\n this.p1Geom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferGeometry()\n this.p1Geom.setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferAttribute(\n new Float32Array(3), 3\n )\n );\n this.p1Geom.attributes.position.set(mouseLoc)\n this.p1 = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Points(this.p1Geom, this.pointMaterial);\n this.pointsGroup.add(this.p1)\n\n this.p2Geom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferGeometry()\n this.p2Geom.setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.BufferAttribute(\n new Float32Array(3), 3\n )\n );\n this.p2 = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Points(this.p2Geom, this.pointMaterial);\n this.pointsGroup.add(this.p2)\n\n this.domElement.removeEventListener('pointerdown', this.pointStart)\n this.domElement.addEventListener('pointermove', this.move)\n this.domElement.addEventListener('pointerdown', this.pointEnd)\n }\n\n\n move(e) {\n const mouseLoc = this.getLocation(e);\n this.lineGeom.attributes.position.set(mouseLoc, 3)\n\n this.lineGeom.attributes.position.needsUpdate = true;\n this.p2Geom.attributes.position.set(mouseLoc);\n this.p2Geom.attributes.position.needsUpdate = true;\n this.p2Geom.computeBoundingSphere();\n this.dispatchEvent({ type: 'change' })\n }\n\n pointEnd(e) {\n if (e.buttons !== 1) return;\n this.domElement.removeEventListener('pointermove', this.move);\n this.domElement.removeEventListener('pointerdown', this.pointEnd);\n\n\n this.pointStart(e)\n }\n\n solve() {\n let ptsBuf = new Float32Array(this.ptsArr.length * 2)\n for (let i = 0, p = 0; i < this.ptsArr.length; i++) {\n ptsBuf[p++] = this.ptsArr[i].geometry.attributes.position.array[0]\n ptsBuf[p++] = this.ptsArr[i].geometry.attributes.position.array[1]\n }\n\n\n buffer = Module._malloc(ptsBuf.length * ptsBuf.BYTES_PER_ELEMENT)\n Module.HEAPF32.set(ptsBuf, buffer >> 2)\n Module[\"_solver\"](this.ptsArr.length / 2, buffer)\n\n\n let ptr = buffer >> 2;\n\n\n for (let i = 0; i < ptsBuf.length; i += 4) {\n const pt1_pos = this.ptsArr[i >> 1].geometry.attributes.position;\n const pt2_pos = this.ptsArr[(i >> 1) + 1].geometry.attributes.position;\n const line_pos = this.linesArr[i >> 2].geometry.attributes.position;\n\n pt1_pos.array[0] = Module.HEAPF32[ptr]\n line_pos.array[0] = Module.HEAPF32[ptr++]\n\n pt1_pos.array[1] = Module.HEAPF32[ptr]\n line_pos.array[1] = Module.HEAPF32[ptr++]\n\n pt2_pos.array[0] = Module.HEAPF32[ptr]\n line_pos.array[3] = Module.HEAPF32[ptr++]\n\n pt2_pos.array[1] = Module.HEAPF32[ptr]\n line_pos.array[4] = Module.HEAPF32[ptr++]\n\n pt1_pos.needsUpdate = true;\n pt2_pos.needsUpdate = true;\n line_pos.needsUpdate = true;\n }\n\n this.dispatchEvent({ type: 'change' })\n\n Module._free(buffer)\n }\n\n}\n\n\n\n\n\n//# sourceURL=webpack:///./src/Sketcher.js?"); /***/ }), diff --git a/dist/solver.wasm b/dist/solver.wasm index f6efd4e..fd45f2d 100755 Binary files a/dist/solver.wasm and b/dist/solver.wasm differ diff --git a/src/Sketcher.js b/src/Sketcher.js index 4eafdb7..eb87016 100644 --- a/src/Sketcher.js +++ b/src/Sketcher.js @@ -148,12 +148,13 @@ export class Sketcher extends THREE.Group { moveLinePt(ptIdx, absPos) { this.ptsArr[ptIdx].geometry.attributes.position.set(absPos); - this.ptsArr[ptIdx].geometry.attributes.position.needsUpdate = true; + this.solve() + // this.ptsArr[ptIdx].geometry.attributes.position.needsUpdate = true; - const lineIdx = Math.floor(ptIdx / 2) - const endPtIdx = (ptIdx % 2) * 3 - this.linesArr[lineIdx].geometry.attributes.position.set(absPos, endPtIdx) - this.linesArr[lineIdx].geometry.attributes.position.needsUpdate = true; + // const lineIdx = Math.floor(ptIdx / 2) + // const endPtIdx = (ptIdx % 2) * 3 + // this.linesArr[lineIdx].geometry.attributes.position.set(absPos, endPtIdx) + // this.linesArr[lineIdx].geometry.attributes.position.needsUpdate = true; } grabEnd() { @@ -242,6 +243,7 @@ export class Sketcher extends THREE.Group { move(e) { const mouseLoc = this.getLocation(e); this.lineGeom.attributes.position.set(mouseLoc, 3) + this.lineGeom.attributes.position.needsUpdate = true; this.p2Geom.attributes.position.set(mouseLoc); this.p2Geom.attributes.position.needsUpdate = true; @@ -259,29 +261,48 @@ export class Sketcher extends THREE.Group { } solve() { - // const linesBuf = new Float32Array(this.linesArr.length * 4) - // const xyOnly = [0,1,3,4]; - // let p = 0 - // for (let i = 0; i < this.linesArr.length; i++) { - // for (let j of xyOnly) { - // linesBuf[p++] = this.linesArr[i].geometry.attributes.position.array[j] - // } - // } - let ptsBuf = new Float32Array(this.ptsArr.length * 2) for (let i = 0, p = 0; i < this.ptsArr.length; i++) { - for (let j = 0; j < 2; j++) { - ptsBuf[p++] = this.ptsArr[i].geometry.attributes.position.array[j] - } + ptsBuf[p++] = this.ptsArr[i].geometry.attributes.position.array[0] + ptsBuf[p++] = this.ptsArr[i].geometry.attributes.position.array[1] } + buffer = Module._malloc(ptsBuf.length * ptsBuf.BYTES_PER_ELEMENT) Module.HEAPF32.set(ptsBuf, buffer >> 2) + Module["_solver"](this.ptsArr.length / 2, buffer) - Module["_solver"](this.ptsArr.length/2, buffer) + + let ptr = buffer >> 2; + + + for (let i = 0; i < ptsBuf.length; i += 4) { + const pt1_pos = this.ptsArr[i >> 1].geometry.attributes.position; + const pt2_pos = this.ptsArr[(i >> 1) + 1].geometry.attributes.position; + const line_pos = this.linesArr[i >> 2].geometry.attributes.position; + + pt1_pos.array[0] = Module.HEAPF32[ptr] + line_pos.array[0] = Module.HEAPF32[ptr++] + + pt1_pos.array[1] = Module.HEAPF32[ptr] + line_pos.array[1] = Module.HEAPF32[ptr++] + + pt2_pos.array[0] = Module.HEAPF32[ptr] + line_pos.array[3] = Module.HEAPF32[ptr++] + + pt2_pos.array[1] = Module.HEAPF32[ptr] + line_pos.array[4] = Module.HEAPF32[ptr++] + + pt1_pos.needsUpdate = true; + pt2_pos.needsUpdate = true; + line_pos.needsUpdate = true; + } + + this.dispatchEvent({ type: 'change' }) Module._free(buffer) } + } diff --git a/wasm/notes b/wasm/notes index d10b6cf..a1b1761 100644 --- a/wasm/notes +++ b/wasm/notes @@ -135,4 +135,10 @@ int solver(int nLines, float *ptr) } sys.params = sys.constraints = sys.entities = 0; return 0; -} \ No newline at end of file +} + + + + + + diff --git a/wasm/solver.c b/wasm/solver.c index d82920e..9925292 100644 --- a/wasm/solver.c +++ b/wasm/solver.c @@ -32,239 +32,10 @@ static void *CheckMalloc(size_t n) * An example of a constraint in 3d. We create a single group, with some * entities and constraints. *---------------------------------------------------------------------------*/ -void Example3d() -{ - /* This will contain a single group, which will arbitrarily number 1. */ - Slvs_hGroup g = 1; - - /* A point, initially at (x y z) = (10 10 10) */ - sys.param[sys.params++] = Slvs_MakeParam(1, g, 10.0); - sys.param[sys.params++] = Slvs_MakeParam(2, g, 10.0); - sys.param[sys.params++] = Slvs_MakeParam(3, g, 10.0); - sys.entity[sys.entities++] = Slvs_MakePoint3d(101, g, 1, 2, 3); - /* and a second point at (20 20 20) */ - sys.param[sys.params++] = Slvs_MakeParam(4, g, 20.0); - sys.param[sys.params++] = Slvs_MakeParam(5, g, 20.0); - sys.param[sys.params++] = Slvs_MakeParam(6, g, 20.0); - sys.entity[sys.entities++] = Slvs_MakePoint3d(102, g, 4, 5, 6); - /* and a line segment connecting them. */ - sys.entity[sys.entities++] = Slvs_MakeLineSegment(200, g, - SLVS_FREE_IN_3D, 101, 102); - - /* The distance between the points should be 30.0 units. */ - sys.constraint[sys.constraints++] = Slvs_MakeConstraint( - 1, g, - SLVS_C_PT_PT_DISTANCE, - SLVS_FREE_IN_3D, - 30.0, - 101, 102, 0, 0); - - /* Let's tell the solver to keep the second point as close to constant - * as possible, instead moving the first point. */ - // sys.dragged[0] = 4; - // sys.dragged[1] = 5; - // sys.dragged[2] = 6; - - /* Now that we have written our system, we solve. */ - Slvs_Solve(&sys, g); - - if (sys.result == SLVS_RESULT_OKAY) - { - printf("okay; now at (%.3f %.3f %.3f)\n" - " (%.3f %.3f %.3f)\n", - sys.param[0].val, sys.param[1].val, sys.param[2].val, - sys.param[3].val, sys.param[4].val, sys.param[5].val); - printf("%d DOF\n", sys.dof); - } - else - { - printf("solve failed"); - } -} - -/*----------------------------------------------------------------------------- - * An example of a constraint in 2d. In our first group, we create a workplane - * along the reference frame's xy plane. In a second group, we create some - * entities in that group and dimension them. - *---------------------------------------------------------------------------*/ -void Example2d(float xx) -{ - Slvs_hGroup g; - double qw, qx, qy, qz; - - g = 1; - /* First, we create our workplane. Its origin corresponds to the origin - * of our base frame (x y z) = (0 0 0) */ - sys.param[sys.params++] = Slvs_MakeParam(1, g, 0.0); - sys.param[sys.params++] = Slvs_MakeParam(2, g, 0.0); - sys.param[sys.params++] = Slvs_MakeParam(3, g, 0.0); - sys.entity[sys.entities++] = Slvs_MakePoint3d(101, g, 1, 2, 3); - /* and it is parallel to the xy plane, so it has basis vectors (1 0 0) - * and (0 1 0). */ - Slvs_MakeQuaternion(1, 0, 0, - 0, 1, 0, &qw, &qx, &qy, &qz); - sys.param[sys.params++] = Slvs_MakeParam(4, g, qw); - sys.param[sys.params++] = Slvs_MakeParam(5, g, qx); - sys.param[sys.params++] = Slvs_MakeParam(6, g, qy); - sys.param[sys.params++] = Slvs_MakeParam(7, g, qz); - sys.entity[sys.entities++] = Slvs_MakeNormal3d(102, g, 4, 5, 6, 7); - - sys.entity[sys.entities++] = Slvs_MakeWorkplane(200, g, 101, 102); - - /* Now create a second group. We'll solve group 2, while leaving group 1 - * constant; so the workplane that we've created will be locked down, - * and the solver can't move it. */ - g = 2; - /* These points are represented by their coordinates (u v) within the - * workplane, so they need only two parameters each. */ - sys.param[sys.params++] = Slvs_MakeParam(11, g, 10.0); - sys.param[sys.params++] = Slvs_MakeParam(12, g, 20.0); - sys.entity[sys.entities++] = Slvs_MakePoint2d(301, g, 200, 11, 12); - - sys.param[sys.params++] = Slvs_MakeParam(13, g, 20.0); - sys.param[sys.params++] = Slvs_MakeParam(14, g, 10.0); - sys.entity[sys.entities++] = Slvs_MakePoint2d(302, g, 200, 13, 14); - - /* And we create a line segment with those endpoints. */ - sys.entity[sys.entities++] = Slvs_MakeLineSegment(400, g, - 200, 301, 302); - - /* Now three more points. */ - - sys.param[sys.params++] = Slvs_MakeParam(15, g, 110.0); - sys.param[sys.params++] = Slvs_MakeParam(16, g, 120.0); - sys.entity[sys.entities++] = Slvs_MakePoint2d(303, g, 200, 15, 16); - - sys.param[sys.params++] = Slvs_MakeParam(17, g, 120.0); - sys.param[sys.params++] = Slvs_MakeParam(18, g, 110.0); - sys.entity[sys.entities++] = Slvs_MakePoint2d(304, g, 200, 17, 18); - - sys.param[sys.params++] = Slvs_MakeParam(19, g, 115.0); - sys.param[sys.params++] = Slvs_MakeParam(20, g, xx); - sys.entity[sys.entities++] = Slvs_MakePoint2d(305, g, 200, 19, 20); - - /* And arc, centered at point 303, starting at point 304, ending at - * point 305. */ - sys.entity[sys.entities++] = Slvs_MakeArcOfCircle(401, g, 200, 102, - 303, 304, 305); - - /* Now one more point, and a distance */ - sys.param[sys.params++] = Slvs_MakeParam(21, g, 200.0); - sys.param[sys.params++] = Slvs_MakeParam(22, g, 200.0); - sys.entity[sys.entities++] = Slvs_MakePoint2d(306, g, 200, 21, 22); - - sys.param[sys.params++] = Slvs_MakeParam(23, g, 30.0); - sys.entity[sys.entities++] = Slvs_MakeDistance(307, g, 200, 23); - - /* And a complete circle, centered at point 306 with radius equal to - * distance 307. The normal is 102, the same as our workplane. */ - sys.entity[sys.entities++] = Slvs_MakeCircle(402, g, 200, - 306, 102, 307); - - /* The length of our line segment is 30.0 units. */ - sys.constraint[sys.constraints++] = Slvs_MakeConstraint( - 1, g, - SLVS_C_PT_PT_DISTANCE, - 200, - 30.0, - 301, 302, 0, 0); - - /* And the distance from our line segment to the origin is 10.0 units. */ - sys.constraint[sys.constraints++] = Slvs_MakeConstraint( - 2, g, - SLVS_C_PT_LINE_DISTANCE, - 200, - 10.0, - 101, 0, 400, 0); - /* And the line segment is vertical. */ - sys.constraint[sys.constraints++] = Slvs_MakeConstraint( - 3, g, - SLVS_C_VERTICAL, - 200, - 0.0, - 0, 0, 400, 0); - /* And the distance from one endpoint to the origin is 15.0 units. */ - sys.constraint[sys.constraints++] = Slvs_MakeConstraint( - 4, g, - SLVS_C_PT_PT_DISTANCE, - 200, - 15.0, - 301, 101, 0, 0); -#if 0 - /* And same for the other endpoint; so if you add this constraint then - * the sketch is overconstrained and will signal an error. */ - sys.constraint[sys.constraints++] = Slvs_MakeConstraint( - 5, g, - SLVS_C_PT_PT_DISTANCE, - 200, - 18.0, - 302, 101, 0, 0); -#endif /* 0 */ - - /* The arc and the circle have equal radius. */ - sys.constraint[sys.constraints++] = Slvs_MakeConstraint( - 6, g, - SLVS_C_EQUAL_RADIUS, - 200, - 0.0, - 0, 0, 401, 402); - /* The arc has radius 17.0 units. */ - sys.constraint[sys.constraints++] = Slvs_MakeConstraint( - 7, g, - SLVS_C_DIAMETER, - 200, - 17.0 * 2, - 0, 0, 401, 0); - - /* If the solver fails, then ask it to report which constraints caused - * the problem. */ - sys.calculateFaileds = 1; - - /* And solve. */ - Slvs_Solve(&sys, g); - - if (sys.result == SLVS_RESULT_OKAY) - { - printf("solved okay\n"); - printf("line from (%.3f %.3f) to (%.3f %.3f)\n", - sys.param[7].val, sys.param[8].val, - sys.param[9].val, sys.param[10].val); - - printf("arc center (%.3f %.3f) start (%.3f %.3f) finish (%.3f %.3f)\n", - sys.param[11].val, sys.param[12].val, - sys.param[13].val, sys.param[14].val, - sys.param[15].val, sys.param[16].val); - - printf("circle center (%.3f %.3f) radius %.3f\n", - sys.param[17].val, sys.param[18].val, - sys.param[19].val); - printf("%d DOF\n", sys.dof); - } - else - { - int i; - printf("solve failed: problematic constraints are:"); - for (i = 0; i < sys.faileds; i++) - { - printf(" %d", sys.failed[i]); - } - printf("\n"); - if (sys.result == SLVS_RESULT_INCONSISTENT) - { - printf("system inconsistent\n"); - } - else - { - printf("system nonconvergent\n"); - } - } -} int solver(int nLines, float *ptr) { - // for (int i=0; i 0) + { + sys.constraint[sys.constraints++] = Slvs_MakeConstraint( + con_id++, g, + SLVS_C_POINTS_COINCIDENT, + 200, + 0.0, + vh - 1, vh - 2, 0, 0); + } + } /* And solve. */ Slvs_Solve(&sys, g); - // printf("%i,wtf\n", sys.result); if (sys.result == SLVS_RESULT_OKAY) { - printf("solved okay\n"); + // printf("solved okay\n"); for (int i = 0; i < nLines * 4; i++) { - // *buf_pt_start++ = (float)sys.param[ptStart++].val; - printf("%f\n", sys.param[ptStart++].val); + *buf_pt_start++ = (float)sys.param[p_start++].val; } } else