diff --git a/dist/bundle.js b/dist/bundle.js index 294303c..6f1b72e 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -2676,7 +2676,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_7__ = __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/objects/Group.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/math/Vector3.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/helpers/PlaneHelper.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/math/Color.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/materials/Materials.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/core/Raycaster.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/math/Matrix4.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/math/Vector2.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/core/BufferGeometry.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/core/BufferAttribute.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/objects/Points.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/objects/Line.js\");\n\n\n\n\n\nconst factor = Math.tan(Math.PI / 3)\n\nfunction get2PtArc(p1, p2, divisions = 36) {\n\n const dx = p2[0] - p1[0]\n const dy = p2[1] - p1[1]\n const dist = Math.sqrt(dx ** 2 + dy ** 2)\n const midAngle = (Math.atan2(dy, dx) - Math.PI / 2) % (2 * Math.PI)\n let a1 = midAngle - Math.PI / 6\n let a2 = midAngle + Math.PI / 6\n\n a1 = a1 < 0 ? a1 + 2 * Math.PI : a1\n a2 = a2 < 0 ? a2 + 2 * Math.PI : a1\n const cx = (p1[0] + p2[0] - dy * factor) / 2\n const cy = (p1[1] + p2[1] + dx * factor) / 2\n\n const radius = dist\n const deltaAngle = Math.PI / 3\n let points = new Float32Array((divisions + 1) * 3)\n\n for (let d = 0; d <= divisions; d++) {\n const angle = a1 + (d / divisions) * deltaAngle;\n points[3 * d] = cx + radius * Math.cos(angle);\n points[3 * d + 1] = cy + radius * Math.sin(angle);\n }\n return [points, [cx, cy]];\n}\n\n\nfunction get3PtArc(p1, p2, c, divisions = 36) {\n\n const v1 = [p1[0] - c[0], p1[1] - c[1]]\n const v2 = [p2[0] - c[0], p2[1] - c[1]]\n\n let a1 = Math.atan2(v1[1], v1[0])\n let a2 = Math.atan2(v2[1], v2[0])\n\n const radius = Math.sqrt(v1[0] ** 2 + v1[1] ** 2)\n\n const deltaAngle = a2 - a1\n\n let points = new Float32Array((divisions + 1) * 3)\n\n for (let d = 0; d <= divisions; d++) {\n const angle = a1 + (d / divisions) * deltaAngle;\n points[3 * d] = c[0] + radius * Math.cos(angle);\n points[3 * d + 1] = c[1] + radius * Math.sin(angle);\n }\n return points;\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.plane = plane;\n this.matrixAutoUpdate = false;\n this.sketchNormal = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_1__.Vector3(0, 0, 1)\n this.orientSketcher(plane)\n\n this.add(new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_2__.PlaneHelper(this.plane, 1, 0xffff00));\n\n this.colorPt = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_3__.Color('white')\n this.selected = new Set()\n\n\n this.lineMaterial = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.LineBasicMaterial({\n linewidth: 3,\n color: 0x555555,\n })\n this.pointMaterial = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.PointsMaterial({\n color: 0x555555,\n size: 3,\n })\n\n\n this.onKeyPress = this.onKeyPress.bind(this);\n\n this.onClick_1 = this.onClick_1.bind(this);\n this.onClick_2 = this.onClick_2.bind(this);\n this.beforeClick_2 = this.beforeClick_2.bind(this);\n this.beforeClick_3 = this.beforeClick_3.bind(this);\n this.onPick = this.onPick.bind(this);\n this.onHover = this.onHover.bind(this);\n this.onDrag = this.onDrag.bind(this);\n this.onRelease = this.onRelease.bind(this);\n\n this.raycaster = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_5__.Raycaster();\n this.raycaster.params.Line.threshold = 0.4;\n this.raycaster.params.Points.threshold = 0.2;\n\n\n window.addEventListener('keydown', this.onKeyPress)\n domElement.addEventListener('pointerdown', this.onPick)\n domElement.addEventListener('pointermove', this.onHover)\n\n\n this.mode = \"\"\n\n this.linkedObjs = new Map()\n this.l_id = 0;\n\n this.constraints = new Map()\n this.c_id = 0;\n\n this.objIdx = new Map()\n\n this.max_pts = 1000\n this.ptsBuf = new Float32Array(this.max_pts * 2)\n\n this.max_links = 1000\n this.linksBuf = new Int32Array(this.max_links * 5) // [0]:type, [1]:pt1, [2]:pt2, [3]:pt3, [4]:pt4\n\n this.max_constraints = 1000\n this.constraintsBuf = new Float32Array(this.max_constraints * 6) // [0]:type, [1]:pt1, [2]:pt2, [3]:lk1, [4]:lk2, [5]:val\n\n this.subsequent = false;\n this.ptsBufPt = 0;\n this.endBufPt = 0;\n\n this.linkNum = {\n 'line': 0,\n 'arc': 1\n }\n\n this.contraintNum = {\n 'coincident': 0,\n 'parallel': 1\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_6__.Matrix4().makeRotationAxis(axis, theta)\n const trans = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_6__.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 onKeyPress(e) {\n switch (e.key) {\n case 'Escape':\n this.clear()\n this.mode = \"\"\n break;\n case 'l':\n this.domElement.addEventListener('pointerdown', this.onClick_1)\n this.mode = \"line\"\n break;\n case 'a':\n this.domElement.addEventListener('pointerdown', this.onClick_1)\n this.mode = \"arc\"\n break;\n case 'd':\n this.deleteSelected()\n break;\n case '=':\n this.plane.applyMatrix4(new three__WEBPACK_IMPORTED_MODULE_7__.Matrix4().makeRotationY(0.1))\n this.orientSketcher()\n this.dispatchEvent({ type: 'change' })\n break;\n case '-':\n this.plane.applyMatrix4(new three__WEBPACK_IMPORTED_MODULE_7__.Matrix4().makeRotationY(-0.1))\n this.orientSketcher()\n this.dispatchEvent({ type: 'change' })\n break;\n }\n }\n\n\n onHover(e) {\n if (this.mode || e.buttons) return\n\n if (this.hovered && !this.selected.has(this.hovered)) {\n this.hovered.material.color.set(0x555555)\n }\n\n this.raycaster.setFromCamera(\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_8__.Vector2(\n (e.clientX / window.innerWidth) * 2 - 1,\n - (e.clientY / window.innerHeight) * 2 + 1\n ),\n this.camera\n );\n\n const hoverPts = this.raycaster.intersectObjects(this.children)\n\n if (hoverPts.length) {\n let minDist = Infinity;\n let idx = 0\n for (let i = 0; i < hoverPts.length; i++) {\n if (hoverPts[i].distanceToRay && hoverPts[i].distanceToRay <= minDist) {\n minDist = hoverPts[i].distanceToRay\n idx = i\n }\n }\n\n hoverPts[idx].object.material.color.set(0xff0000)\n this.hovered = hoverPts[idx].object\n this.dispatchEvent({ type: 'change' })\n return\n }\n\n\n if (this.hovered) {\n this.hovered = null;\n this.dispatchEvent({ type: 'change' })\n }\n\n }\n\n\n\n onPick(e) {\n if (this.mode || e.buttons != 1) return\n\n if (this.hovered) {\n this.selected.add(this.hovered)\n if (this.hovered.type === \"Points\") {\n this.grabPtIdx = this.children.indexOf(\n this.hovered\n )\n this.domElement.addEventListener('pointermove', this.onDrag);\n this.domElement.addEventListener('pointerup', this.onRelease)\n }\n } else {\n for (let obj of this.selected) {\n obj.material.color.set(0x555555)\n }\n this.dispatchEvent({ type: 'change' })\n this.selected.clear()\n }\n }\n\n onDrag(e) {\n const mouseLoc = this.getLocation(e);\n this.children[this.grabPtIdx].geometry.attributes.position.set(mouseLoc);\n this.solve()\n this.dispatchEvent({ type: 'change' })\n }\n\n\n onRelease() {\n this.domElement.removeEventListener('pointermove', this.onDrag)\n this.domElement.removeEventListener('pointerup', this.onRelease)\n this.children[this.grabPtIdx].geometry.computeBoundingSphere()\n // this.grabbedObject = null\n }\n\n\n\n deleteSelected() {\n let minI = this.children.length;\n\n for (let obj of this.selected) {\n minI = Math.min(minI, this.delete(obj))\n\n }\n\n this.updateBuffer(minI)\n this.resetConstraints()\n\n this.selected.clear()\n this.dispatchEvent({ type: 'change' })\n }\n\n deleteConstraints(c_id) {\n for (let ob of this.constraints.get(c_id)[0]) {\n if (ob == -1) continue\n ob.constraints.delete(c_id)\n }\n this.constraints.delete(c_id)\n }\n\n resetConstraints() {\n let i = 0\n for (let [key,obj] of this.constraints) {\n this.constraintsBuf.set(\n [\n ...obj[0].map(ele => this.objIdx.get(ele.id) || -1),\n this.contraintNum[obj[4]], obj[5]\n ],\n (i) * 6\n )\n i++\n }\n\n i = 0;\n for (let [key,obj] of this.linkedObjs) {\n this.linksBuf.set(\n [\n ...obj[0].map(ele => this.objIdx.get(ele.id) || -1),\n this.linkNum[obj[4]]\n ],\n (i) * 5\n )\n i++\n }\n\n }\n\n delete(obj) {\n\n const link = this.linkedObjs.get(obj.l_id)\n\n let i = this.children.indexOf(link[0][0])\n if (i == -1) return Infinity\n\n for (let j = 0; j < link[0].length; j++) {\n const obj = this.children[i + j]\n obj.geometry.dispose()\n obj.material.dispose()\n\n for (let c_id of obj.constraints) {\n this.deleteConstraints(c_id)\n }\n }\n\n this.children.splice(i, link[0].length)\n\n this.linkedObjs.delete(obj.l_id)\n\n return i\n }\n\n updateBuffer(startingIdx) {\n for (let i = startingIdx; i < this.children.length; i++) {\n const obj = this.children[i]\n this.objIdx.set(obj.id, i)\n if (obj.type == \"Points\") {\n this.ptsBuf[2 * i] = obj.geometry.attributes.position.array[0]\n this.ptsBuf[2 * i + 1] = obj.geometry.attributes.position.array[1]\n }\n }\n }\n\n\n clear() {\n if (this.mode == \"\") return\n\n if (this.mode == \"line\") {\n this.domElement.removeEventListener('pointerdown', this.onClick_1)\n this.domElement.removeEventListener('pointermove', this.beforeClick_2);\n this.domElement.removeEventListener('pointerdown', this.onClick_2);\n\n this.delete(this.children[this.children.length - 1])\n\n this.dispatchEvent({ type: 'change' })\n this.subsequent = false\n }\n }\n\n getLocation(e) {\n this.raycaster.setFromCamera(\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_8__.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 onClick_1(e) {\n if (e.buttons !== 1) return\n const mouseLoc = this.getLocation(e);\n\n this.p1Geom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__.BufferGeometry().setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__.BufferAttribute(new Float32Array(mouseLoc), 3)\n )\n this.p1 = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_11__.Points(this.p1Geom,\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.PointsMaterial().copy(this.pointMaterial)\n );\n this.p1.matrixAutoUpdate = false;\n this.p1.constraints = new Set()\n\n this.p2Geom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__.BufferGeometry().setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__.BufferAttribute(new Float32Array(3), 3)\n )\n this.p2 = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_11__.Points(\n this.p2Geom,\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.PointsMaterial().copy(this.pointMaterial)\n );\n this.p2.matrixAutoUpdate = false;\n this.p2.constraints = new Set()\n\n let toPush;\n\n if (this.mode == \"line\") {\n this.lineGeom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__.BufferGeometry().setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__.BufferAttribute(new Float32Array(6), 3)\n );\n this.lineGeom.attributes.position.set(mouseLoc)\n this.line = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_12__.Line(this.lineGeom,\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.LineBasicMaterial().copy(this.lineMaterial)\n );\n this.line.constraints = new Set()\n this.line.frustumCulled = false;\n\n toPush = [this.p1, this.p2, this.line];\n\n if (this.subsequent) {\n\n this.constraintsBuf.set(\n [\n this.children.length - 2, this.children.length, -1, -1,\n this.contraintNum['coincident'], -1\n ],\n (this.constraints.size) * 6\n )\n\n this.constraints.set(this.c_id,\n [\n [this.children[this.children.length - 2], this.p1, -1, -1],\n 'coincident', -1\n ]\n )\n\n this.p1.constraints.add(this.c_id)\n this.children[this.children.length - 2].constraints.add(this.c_id)\n this.c_id += 1\n }\n\n } else if (this.mode == \"arc\") {\n\n this.arcGeom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__.BufferGeometry().setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__.BufferAttribute(new Float32Array(3 * 37), 3)\n )\n\n this.arc = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_12__.Line(this.arcGeom,\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.LineBasicMaterial().copy(this.lineMaterial)\n );\n this.arc.frustumCulled = false;\n\n this.p3Geom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__.BufferGeometry().setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__.BufferAttribute(new Float32Array(3), 3)\n )\n this.p3 = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_11__.Points(this.p3Geom,\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.PointsMaterial().copy(this.pointMaterial)\n );\n\n toPush = [this.p1, this.p2, this.p3, this.arc]\n }\n\n\n let ptr = this.children.length\n this.add(...toPush)\n this.updateBuffer(ptr)\n\n\n const link_entry = new Array(5).fill(-1)\n for (let i = ptr, j = 0; j < toPush.length - 1;) {\n link_entry[j++] = i++\n }\n link_entry[link_entry.length - 1] = this.linkNum[this.mode]\n\n this.linksBuf.set(\n link_entry,\n (this.linkedObjs.size) * 5\n )\n\n this.linkedObjs.set(this.l_id, [toPush, this.mode])\n\n for (let obj of toPush) {\n obj.l_id = this.l_id\n }\n this.l_id += 1\n\n\n\n this.domElement.removeEventListener('pointerdown', this.onClick_1)\n this.domElement.addEventListener('pointermove', this.beforeClick_2)\n this.domElement.addEventListener('pointerdown', this.onClick_2)\n }\n\n\n beforeClick_2(e) {\n const mouseLoc = this.getLocation(e);\n\n this.p2Geom.attributes.position.set(mouseLoc);\n this.p2Geom.attributes.position.needsUpdate = true;\n this.p2Geom.computeBoundingSphere()\n\n if (this.mode == \"line\") {\n this.lineGeom.attributes.position.set(mouseLoc, 3)\n this.lineGeom.attributes.position.needsUpdate = true;\n } else if (this.mode == 'arc') {\n const [points, center] = get2PtArc(\n this.p1Geom.attributes.position.array,\n this.p2Geom.attributes.position.array\n )\n this.arcGeom.attributes.position.set(\n points\n );\n this.arcGeom.attributes.position.needsUpdate = true;\n this.p3Geom.attributes.position.set(center);\n this.p3Geom.attributes.position.needsUpdate = true;\n this.p3Geom.computeBoundingSphere()\n\n }\n\n this.dispatchEvent({ type: 'change' })\n }\n\n onClick_2(e) {\n if (e.buttons !== 1) return;\n this.domElement.removeEventListener('pointermove', this.beforeClick_2);\n this.domElement.removeEventListener('pointerdown', this.onClick_2);\n if (this.mode == \"line\") {\n this.subsequent = true\n this.onClick_1(e)\n } else if (this.mode == \"arc\") {\n\n\n\n // this.domElement.addEventListener('pointermove', this.beforeClick_3)\n }\n }\n\n beforeClick_3(e) {\n const mouseLoc = this.getLocation(e);\n this.p3Geom.attributes.position.set(mouseLoc);\n this.p3Geom.attributes.position.needsUpdate = true;\n this.p3Geom.computeBoundingSphere()\n }\n\n\n solve() {\n\n\n for (let i = 0, p = 0; i < this.children.length; i++) {\n this.ptsBuf[p++] = this.children[i].geometry.attributes.position.array[0]\n this.ptsBuf[p++] = this.children[i].geometry.attributes.position.array[1]\n }\n\n buffer = Module._malloc(this.ptsBuf.length * this.ptsBuf.BYTES_PER_ELEMENT)\n Module.HEAPF32.set(this.ptsBuf, buffer >> 2)\n\n\n Module[\"_solver\"](this.children.length / 2, buffer)\n\n\n let ptr = buffer >> 2;\n\n\n for (let i = 0; i < this.linkedObjs.lengthxx; i += 1) {\n\n const pt1_pos = this.children[i >> 1].geometry.attributes.position;\n const pt2_pos = this.children[(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?"); +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_7__ = __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/objects/Group.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/math/Vector3.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/helpers/PlaneHelper.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/math/Color.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/materials/Materials.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/core/Raycaster.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/math/Matrix4.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/math/Vector2.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/core/BufferGeometry.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/core/BufferAttribute.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/objects/Points.js\");\n/* harmony import */ var _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../node_modules/three/src/Three */ \"./node_modules/three/src/objects/Line.js\");\n\n\n\n\n\nconst factor = Math.tan(Math.PI / 3)\n\nfunction get2PtArc(p1, p2, divisions = 36) {\n\n const dx = p2[0] - p1[0]\n const dy = p2[1] - p1[1]\n const dist = Math.sqrt(dx ** 2 + dy ** 2)\n const midAngle = (Math.atan2(dy, dx) - Math.PI / 2) % (2 * Math.PI)\n let a1 = midAngle - Math.PI / 6\n let a2 = midAngle + Math.PI / 6\n\n a1 = a1 < 0 ? a1 + 2 * Math.PI : a1\n a2 = a2 < 0 ? a2 + 2 * Math.PI : a1\n const cx = (p1[0] + p2[0] - dy * factor) / 2\n const cy = (p1[1] + p2[1] + dx * factor) / 2\n\n const radius = dist\n const deltaAngle = Math.PI / 3\n let points = new Float32Array((divisions + 1) * 3)\n\n for (let d = 0; d <= divisions; d++) {\n const angle = a1 + (d / divisions) * deltaAngle;\n points[3 * d] = cx + radius * Math.cos(angle);\n points[3 * d + 1] = cy + radius * Math.sin(angle);\n }\n return [points, [cx, cy]];\n}\n\n\nfunction get3PtArc(p1, p2, c, divisions = 36) {\n\n const v1 = [p1[0] - c[0], p1[1] - c[1]]\n const v2 = [p2[0] - c[0], p2[1] - c[1]]\n\n let a1 = Math.atan2(v1[1], v1[0])\n let a2 = Math.atan2(v2[1], v2[0])\n\n const radius = Math.sqrt(v1[0] ** 2 + v1[1] ** 2)\n\n const deltaAngle = a2 - a1\n\n let points = new Float32Array((divisions + 1) * 3)\n\n for (let d = 0; d <= divisions; d++) {\n const angle = a1 + (d / divisions) * deltaAngle;\n points[3 * d] = c[0] + radius * Math.cos(angle);\n points[3 * d + 1] = c[1] + radius * Math.sin(angle);\n }\n return points;\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.plane = plane;\n this.matrixAutoUpdate = false;\n this.sketchNormal = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_1__.Vector3(0, 0, 1)\n this.orientSketcher(plane)\n\n this.add(new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_2__.PlaneHelper(this.plane, 1, 0xffff00));\n\n this.colorPt = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_3__.Color('white')\n this.selected = new Set()\n\n this.geomGroup = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_0__.Group();\n scene.add(this.geomGroup);\n\n this.lineMaterial = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.LineBasicMaterial({\n linewidth: 3,\n color: 0x555555,\n })\n this.pointMaterial = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.PointsMaterial({\n color: 0x555555,\n size: 3,\n })\n\n\n this.onKeyPress = this.onKeyPress.bind(this);\n\n this.onClick_1 = this.onClick_1.bind(this);\n this.onClick_2 = this.onClick_2.bind(this);\n this.beforeClick_2 = this.beforeClick_2.bind(this);\n this.beforeClick_3 = this.beforeClick_3.bind(this);\n this.onPick = this.onPick.bind(this);\n this.onHover = this.onHover.bind(this);\n this.onDrag = this.onDrag.bind(this);\n this.onRelease = this.onRelease.bind(this);\n\n this.raycaster = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_5__.Raycaster();\n this.raycaster.params.Line.threshold = 0.4;\n this.raycaster.params.Points.threshold = 0.2;\n\n\n window.addEventListener('keydown', this.onKeyPress)\n domElement.addEventListener('pointerdown', this.onPick)\n domElement.addEventListener('pointermove', this.onHover)\n\n\n this.mode = \"\"\n\n this.linkedObjs = new Map()\n this.l_id = 0;\n\n this.constraints = new Map()\n this.c_id = 0;\n\n this.objIdx = new Map()\n\n this.max_pts = 1000\n this.ptsBuf = new Float32Array(this.max_pts * 2).fill(NaN)\n\n this.max_links = 1000\n this.linksBuf = new Float32Array(this.max_links * 5).fill(NaN) // [0]:type, [1]:pt1, [2]:pt2, [3]:pt3, [4]:pt4\n\n this.max_constraints = 1000\n this.constraintsBuf = new Float32Array(this.max_constraints * 6).fill(NaN) // [0]:type, [1]:val, [2]:pt1, [3]:pt2, [4]:lk1, [5]:lk2\n\n this.subsequent = false;\n this.ptsBufPt = 0;\n this.endBufPt = 0;\n\n this.linkNum = {\n 'line': 0,\n 'arc': 1\n }\n\n this.contraintNum = {\n 'coincident': 0,\n 'parallel': 1\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_6__.Matrix4().makeRotationAxis(axis, theta)\n const trans = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_6__.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 onKeyPress(e) {\n switch (e.key) {\n case 'Escape':\n this.clear()\n this.mode = \"\"\n break;\n case 'l':\n this.domElement.addEventListener('pointerdown', this.onClick_1)\n this.mode = \"line\"\n break;\n case 'a':\n this.domElement.addEventListener('pointerdown', this.onClick_1)\n this.mode = \"arc\"\n break;\n case 'd':\n this.deleteSelected()\n break;\n case '=':\n this.plane.applyMatrix4(new three__WEBPACK_IMPORTED_MODULE_7__.Matrix4().makeRotationY(0.1))\n this.orientSketcher()\n this.dispatchEvent({ type: 'change' })\n break;\n case '-':\n this.plane.applyMatrix4(new three__WEBPACK_IMPORTED_MODULE_7__.Matrix4().makeRotationY(-0.1))\n this.orientSketcher()\n this.dispatchEvent({ type: 'change' })\n break;\n }\n }\n\n\n onHover(e) {\n if (this.mode || e.buttons) return\n\n if (this.hovered && !this.selected.has(this.hovered)) {\n this.hovered.material.color.set(0x555555)\n }\n\n this.raycaster.setFromCamera(\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_8__.Vector2(\n (e.clientX / window.innerWidth) * 2 - 1,\n - (e.clientY / window.innerHeight) * 2 + 1\n ),\n this.camera\n );\n\n const hoverPts = this.raycaster.intersectObjects(this.geomGroup.children)\n\n if (hoverPts.length) {\n let minDist = Infinity;\n let idx = 0\n for (let i = 0; i < hoverPts.length; i++) {\n if (hoverPts[i].distanceToRay && hoverPts[i].distanceToRay <= minDist) {\n minDist = hoverPts[i].distanceToRay\n idx = i\n }\n }\n\n hoverPts[idx].object.material.color.set(0xff0000)\n this.hovered = hoverPts[idx].object\n this.dispatchEvent({ type: 'change' })\n return\n }\n\n\n if (this.hovered) {\n this.hovered = null;\n this.dispatchEvent({ type: 'change' })\n }\n\n }\n\n\n\n onPick(e) {\n if (this.mode || e.buttons != 1) return\n\n if (this.hovered) {\n this.selected.add(this.hovered)\n if (this.hovered.type === \"Points\") {\n this.grabPtIdx = this.geomGroup.children.indexOf(\n this.hovered\n )\n this.domElement.addEventListener('pointermove', this.onDrag);\n this.domElement.addEventListener('pointerup', this.onRelease)\n }\n } else {\n for (let obj of this.selected) {\n obj.material.color.set(0x555555)\n }\n this.dispatchEvent({ type: 'change' })\n this.selected.clear()\n }\n }\n\n onDrag(e) {\n const mouseLoc = this.getLocation(e);\n this.geomGroup.children[this.grabPtIdx].geometry.attributes.position.set(mouseLoc);\n this.solve()\n this.dispatchEvent({ type: 'change' })\n }\n\n\n onRelease() {\n this.domElement.removeEventListener('pointermove', this.onDrag)\n this.domElement.removeEventListener('pointerup', this.onRelease)\n this.geomGroup.children[this.grabPtIdx].geometry.computeBoundingSphere()\n // this.grabbedObject = null\n }\n\n\n\n deleteSelected() {\n let minI = this.geomGroup.children.length;\n\n for (let obj of this.selected) {\n minI = Math.min(minI, this.delete(obj))\n\n }\n\n this.updatePointsBuffer(minI)\n this.updateOtherBuffers()\n\n this.selected.clear()\n this.dispatchEvent({ type: 'change' })\n }\n\n deleteConstraints(c_id) {\n for (let ob of this.constraints.get(c_id)[0]) {\n if (ob == -1) continue\n ob.constraints.delete(c_id)\n }\n this.constraints.delete(c_id)\n }\n\n updateOtherBuffers() {\n let i = 0\n for (let [key, obj] of this.constraints) {\n this.constraintsBuf.set(\n [\n this.contraintNum[obj[1]], obj[2],\n ...obj[0].map(ele => this.objIdx.get(ele.id) || -1),\n ],\n (i) * 6\n )\n i++\n }\n\n i = 0;\n for (let [key, obj] of this.linkedObjs) {\n console.log(obj[0])\n this.linksBuf.set(\n [\n this.linkNum[obj[1]],\n ...obj[0].map(ele => this.objIdx.get(ele.id) ?? -1),\n ],\n (i) * 5\n )\n console.log(this.linksBuf)\n i++\n }\n\n }\n\n delete(obj) {\n\n const link = this.linkedObjs.get(obj.l_id)\n\n let i = this.geomGroup.children.indexOf(link[0][0])\n if (i == -1) return Infinity\n\n for (let j = 0; j < link[0].length; j++) {\n const obj = this.geomGroup.children[i + j]\n obj.geometry.dispose()\n obj.material.dispose()\n\n for (let c_id of obj.constraints) {\n this.deleteConstraints(c_id)\n }\n }\n\n this.geomGroup.children.splice(i, link[0].length)\n\n this.linkedObjs.delete(obj.l_id)\n\n return i\n }\n\n updatePointsBuffer(startingIdx=0) {\n for (let i = startingIdx; i < this.geomGroup.children.length; i++) {\n const obj = this.geomGroup.children[i]\n this.objIdx.set(obj.id, i)\n if (obj.type == \"Points\") {\n this.ptsBuf[2 * i] = obj.geometry.attributes.position.array[0]\n this.ptsBuf[2 * i + 1] = obj.geometry.attributes.position.array[1]\n }\n }\n }\n\n\n clear() {\n if (this.mode == \"\") return\n\n if (this.mode == \"line\") {\n this.domElement.removeEventListener('pointerdown', this.onClick_1)\n this.domElement.removeEventListener('pointermove', this.beforeClick_2);\n this.domElement.removeEventListener('pointerdown', this.onClick_2);\n\n this.delete(this.geomGroup.children[this.geomGroup.children.length - 1])\n\n this.dispatchEvent({ type: 'change' })\n this.subsequent = false\n }\n }\n\n getLocation(e) {\n this.raycaster.setFromCamera(\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_8__.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 onClick_1(e) {\n if (e.buttons !== 1) return\n const mouseLoc = this.getLocation(e);\n\n this.p1Geom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__.BufferGeometry().setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__.BufferAttribute(new Float32Array(mouseLoc), 3)\n )\n this.p1 = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_11__.Points(this.p1Geom,\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.PointsMaterial().copy(this.pointMaterial)\n );\n this.p1.matrixAutoUpdate = false;\n this.p1.constraints = new Set()\n\n this.p2Geom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__.BufferGeometry().setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__.BufferAttribute(new Float32Array(3), 3)\n )\n this.p2 = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_11__.Points(\n this.p2Geom,\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.PointsMaterial().copy(this.pointMaterial)\n );\n this.p2.matrixAutoUpdate = false;\n this.p2.constraints = new Set()\n\n let toPush;\n\n if (this.mode == \"line\") {\n this.lineGeom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__.BufferGeometry().setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__.BufferAttribute(new Float32Array(6), 3)\n );\n this.lineGeom.attributes.position.set(mouseLoc)\n this.line = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_12__.Line(this.lineGeom,\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.LineBasicMaterial().copy(this.lineMaterial)\n );\n this.line.constraints = new Set()\n this.line.frustumCulled = false;\n\n toPush = [this.p1, this.p2, this.line];\n\n if (this.subsequent) {\n\n this.constraints.set(this.c_id,\n [\n [this.geomGroup.children[this.geomGroup.children.length - 2], this.p1, -1, -1],\n 'coincident', -1\n ]\n )\n\n this.p1.constraints.add(this.c_id)\n this.geomGroup.children[this.geomGroup.children.length - 2].constraints.add(this.c_id)\n this.c_id += 1\n }\n\n } else if (this.mode == \"arc\") {\n\n this.arcGeom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__.BufferGeometry().setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__.BufferAttribute(new Float32Array(3 * 37), 3)\n )\n\n this.arc = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_12__.Line(this.arcGeom,\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.LineBasicMaterial().copy(this.lineMaterial)\n );\n this.arc.frustumCulled = false;\n\n this.p3Geom = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_9__.BufferGeometry().setAttribute('position',\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_10__.BufferAttribute(new Float32Array(3), 3)\n )\n this.p3 = new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_11__.Points(this.p3Geom,\n new _node_modules_three_src_Three__WEBPACK_IMPORTED_MODULE_4__.PointsMaterial().copy(this.pointMaterial)\n );\n\n toPush = [this.p1, this.p2, this.p3, this.arc]\n }\n\n\n this.updatePoint = this.geomGroup.children.length\n this.geomGroup.add(...toPush)\n\n this.linkedObjs.set(this.l_id, [toPush, this.mode])\n\n for (let obj of toPush) {\n obj.l_id = this.l_id\n }\n this.l_id += 1\n\n\n this.domElement.removeEventListener('pointerdown', this.onClick_1)\n this.domElement.addEventListener('pointermove', this.beforeClick_2)\n this.domElement.addEventListener('pointerdown', this.onClick_2)\n }\n\n\n beforeClick_2(e) {\n const mouseLoc = this.getLocation(e);\n\n this.p2Geom.attributes.position.set(mouseLoc);\n this.p2Geom.attributes.position.needsUpdate = true;\n this.p2Geom.computeBoundingSphere()\n\n if (this.mode == \"line\") {\n this.lineGeom.attributes.position.set(mouseLoc, 3)\n this.lineGeom.attributes.position.needsUpdate = true;\n } else if (this.mode == 'arc') {\n const [points, center] = get2PtArc(\n this.p1Geom.attributes.position.array,\n this.p2Geom.attributes.position.array\n )\n this.arcGeom.attributes.position.set(\n points\n );\n this.arcGeom.attributes.position.needsUpdate = true;\n this.p3Geom.attributes.position.set(center);\n this.p3Geom.attributes.position.needsUpdate = true;\n this.p3Geom.computeBoundingSphere()\n\n }\n\n this.dispatchEvent({ type: 'change' })\n }\n\n onClick_2(e) {\n if (e.buttons !== 1) return;\n this.domElement.removeEventListener('pointermove', this.beforeClick_2);\n this.domElement.removeEventListener('pointerdown', this.onClick_2);\n\n\n if (this.mode == \"line\") {\n\n\n this.updatePointsBuffer(this.updatePoint)\n this.updateOtherBuffers()\n\n\n this.subsequent = true\n this.onClick_1(e)\n } else if (this.mode == \"arc\") {\n // this.domElement.addEventListener('pointermove', this.beforeClick_3)\n }\n }\n\n beforeClick_3(e) {\n const mouseLoc = this.getLocation(e);\n this.p3Geom.attributes.position.set(mouseLoc);\n this.p3Geom.attributes.position.needsUpdate = true;\n this.p3Geom.computeBoundingSphere()\n }\n\n\n solve() {\n\n // for (let i = 0, p = 0; i < this.geomGroup.children.length; i++) {\n // this.ptsBuf[p++] = this.geomGroup.children[i].geometry.attributes.position.array[0]\n // this.ptsBuf[p++] = this.geomGroup.children[i].geometry.attributes.position.array[1]\n // }\n this.updatePointsBuffer()\n\n const pts_buffer = Module._malloc(this.ptsBuf.length * this.ptsBuf.BYTES_PER_ELEMENT)\n Module.HEAPF32.set(this.ptsBuf, pts_buffer >> 2)\n\n const constraints_buffer = Module._malloc(this.constraintsBuf.length * this.constraintsBuf.BYTES_PER_ELEMENT)\n Module.HEAPF32.set(this.constraintsBuf, constraints_buffer >> 2)\n\n const links_buffer = Module._malloc(this.linksBuf.length * this.linksBuf.BYTES_PER_ELEMENT)\n Module.HEAPF32.set(this.linksBuf, links_buffer >> 2)\n\n Module[\"_solver\"](this.geomGroup.children.length, pts_buffer, this.constraints.size, constraints_buffer, this.linkedObjs.size, links_buffer)\n\n let ptr = pts_buffer >> 2;\n\n\n for (let i = 0; i < this.geomGroup.children.length; i += 1) {\n\n const pos = this.geomGroup.children[i].geometry.attributes.position;\n if (isNaN(Module.HEAPF32[ptr])) {\n pos.array[0] = Module.HEAPF32[ptr-4]\n pos.array[1] = Module.HEAPF32[ptr-3]\n pos.array[3] = Module.HEAPF32[ptr-2]\n pos.array[4] = Module.HEAPF32[ptr-1]\n } else {\n pos.array[0] = Module.HEAPF32[ptr++]\n pos.array[1] = Module.HEAPF32[ptr++]\n }\n\n pos.needsUpdate = true;\n }\n\n this.dispatchEvent({ type: 'change' })\n\n Module._free(pts_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 0f2c682..e704296 100755 Binary files a/dist/solver.wasm and b/dist/solver.wasm differ diff --git a/src/Sketcher.js b/src/Sketcher.js index 1665018..38ea984 100644 --- a/src/Sketcher.js +++ b/src/Sketcher.js @@ -70,6 +70,8 @@ export class Sketcher extends THREE.Group { this.colorPt = new THREE.Color('white') this.selected = new Set() + this.geomGroup = new THREE.Group(); + scene.add(this.geomGroup); this.lineMaterial = new THREE.LineBasicMaterial({ linewidth: 3, @@ -113,13 +115,13 @@ export class Sketcher extends THREE.Group { this.objIdx = new Map() this.max_pts = 1000 - this.ptsBuf = new Float32Array(this.max_pts * 2) + this.ptsBuf = new Float32Array(this.max_pts * 2).fill(NaN) this.max_links = 1000 - this.linksBuf = new Int32Array(this.max_links * 5) // [0]:type, [1]:pt1, [2]:pt2, [3]:pt3, [4]:pt4 + this.linksBuf = new Float32Array(this.max_links * 5).fill(NaN) // [0]:type, [1]:pt1, [2]:pt2, [3]:pt3, [4]:pt4 this.max_constraints = 1000 - this.constraintsBuf = new Float32Array(this.max_constraints * 6) // [0]:type, [1]:pt1, [2]:pt2, [3]:lk1, [4]:lk2, [5]:val + this.constraintsBuf = new Float32Array(this.max_constraints * 6).fill(NaN) // [0]:type, [1]:val, [2]:pt1, [3]:pt2, [4]:lk1, [5]:lk2 this.subsequent = false; this.ptsBufPt = 0; @@ -194,7 +196,7 @@ export class Sketcher extends THREE.Group { this.camera ); - const hoverPts = this.raycaster.intersectObjects(this.children) + const hoverPts = this.raycaster.intersectObjects(this.geomGroup.children) if (hoverPts.length) { let minDist = Infinity; @@ -228,7 +230,7 @@ export class Sketcher extends THREE.Group { if (this.hovered) { this.selected.add(this.hovered) if (this.hovered.type === "Points") { - this.grabPtIdx = this.children.indexOf( + this.grabPtIdx = this.geomGroup.children.indexOf( this.hovered ) this.domElement.addEventListener('pointermove', this.onDrag); @@ -245,7 +247,7 @@ export class Sketcher extends THREE.Group { onDrag(e) { const mouseLoc = this.getLocation(e); - this.children[this.grabPtIdx].geometry.attributes.position.set(mouseLoc); + this.geomGroup.children[this.grabPtIdx].geometry.attributes.position.set(mouseLoc); this.solve() this.dispatchEvent({ type: 'change' }) } @@ -254,22 +256,22 @@ export class Sketcher extends THREE.Group { onRelease() { this.domElement.removeEventListener('pointermove', this.onDrag) this.domElement.removeEventListener('pointerup', this.onRelease) - this.children[this.grabPtIdx].geometry.computeBoundingSphere() + this.geomGroup.children[this.grabPtIdx].geometry.computeBoundingSphere() // this.grabbedObject = null } deleteSelected() { - let minI = this.children.length; + let minI = this.geomGroup.children.length; for (let obj of this.selected) { minI = Math.min(minI, this.delete(obj)) } - this.updateBuffer(minI) - this.resetConstraints() + this.updatePointsBuffer(minI) + this.updateOtherBuffers() this.selected.clear() this.dispatchEvent({ type: 'change' }) @@ -283,13 +285,13 @@ export class Sketcher extends THREE.Group { this.constraints.delete(c_id) } - resetConstraints() { + updateOtherBuffers() { let i = 0 - for (let [key,obj] of this.constraints) { + for (let [key, obj] of this.constraints) { this.constraintsBuf.set( [ + this.contraintNum[obj[1]], obj[2], ...obj[0].map(ele => this.objIdx.get(ele.id) || -1), - this.contraintNum[obj[4]], obj[5] ], (i) * 6 ) @@ -297,14 +299,16 @@ export class Sketcher extends THREE.Group { } i = 0; - for (let [key,obj] of this.linkedObjs) { + for (let [key, obj] of this.linkedObjs) { + console.log(obj[0]) this.linksBuf.set( [ - ...obj[0].map(ele => this.objIdx.get(ele.id) || -1), - this.linkNum[obj[4]] + this.linkNum[obj[1]], + ...obj[0].map(ele => this.objIdx.get(ele.id) ?? -1), ], (i) * 5 ) + console.log(this.linksBuf) i++ } @@ -314,11 +318,11 @@ export class Sketcher extends THREE.Group { const link = this.linkedObjs.get(obj.l_id) - let i = this.children.indexOf(link[0][0]) + let i = this.geomGroup.children.indexOf(link[0][0]) if (i == -1) return Infinity for (let j = 0; j < link[0].length; j++) { - const obj = this.children[i + j] + const obj = this.geomGroup.children[i + j] obj.geometry.dispose() obj.material.dispose() @@ -327,16 +331,16 @@ export class Sketcher extends THREE.Group { } } - this.children.splice(i, link[0].length) + this.geomGroup.children.splice(i, link[0].length) this.linkedObjs.delete(obj.l_id) return i } - updateBuffer(startingIdx) { - for (let i = startingIdx; i < this.children.length; i++) { - const obj = this.children[i] + updatePointsBuffer(startingIdx=0) { + for (let i = startingIdx; i < this.geomGroup.children.length; i++) { + const obj = this.geomGroup.children[i] this.objIdx.set(obj.id, i) if (obj.type == "Points") { this.ptsBuf[2 * i] = obj.geometry.attributes.position.array[0] @@ -354,7 +358,7 @@ export class Sketcher extends THREE.Group { this.domElement.removeEventListener('pointermove', this.beforeClick_2); this.domElement.removeEventListener('pointerdown', this.onClick_2); - this.delete(this.children[this.children.length - 1]) + this.delete(this.geomGroup.children[this.geomGroup.children.length - 1]) this.dispatchEvent({ type: 'change' }) this.subsequent = false @@ -413,23 +417,15 @@ export class Sketcher extends THREE.Group { if (this.subsequent) { - this.constraintsBuf.set( - [ - this.children.length - 2, this.children.length, -1, -1, - this.contraintNum['coincident'], -1 - ], - (this.constraints.size) * 6 - ) - this.constraints.set(this.c_id, [ - [this.children[this.children.length - 2], this.p1, -1, -1], + [this.geomGroup.children[this.geomGroup.children.length - 2], this.p1, -1, -1], 'coincident', -1 ] ) this.p1.constraints.add(this.c_id) - this.children[this.children.length - 2].constraints.add(this.c_id) + this.geomGroup.children[this.geomGroup.children.length - 2].constraints.add(this.c_id) this.c_id += 1 } @@ -455,21 +451,8 @@ export class Sketcher extends THREE.Group { } - let ptr = this.children.length - this.add(...toPush) - this.updateBuffer(ptr) - - - const link_entry = new Array(5).fill(-1) - for (let i = ptr, j = 0; j < toPush.length - 1;) { - link_entry[j++] = i++ - } - link_entry[link_entry.length - 1] = this.linkNum[this.mode] - - this.linksBuf.set( - link_entry, - (this.linkedObjs.size) * 5 - ) + this.updatePoint = this.geomGroup.children.length + this.geomGroup.add(...toPush) this.linkedObjs.set(this.l_id, [toPush, this.mode]) @@ -479,7 +462,6 @@ export class Sketcher extends THREE.Group { this.l_id += 1 - this.domElement.removeEventListener('pointerdown', this.onClick_1) this.domElement.addEventListener('pointermove', this.beforeClick_2) this.domElement.addEventListener('pointerdown', this.onClick_2) @@ -518,13 +500,18 @@ export class Sketcher extends THREE.Group { if (e.buttons !== 1) return; this.domElement.removeEventListener('pointermove', this.beforeClick_2); this.domElement.removeEventListener('pointerdown', this.onClick_2); + + if (this.mode == "line") { + + + this.updatePointsBuffer(this.updatePoint) + this.updateOtherBuffers() + + this.subsequent = true this.onClick_1(e) } else if (this.mode == "arc") { - - - // this.domElement.addEventListener('pointermove', this.beforeClick_3) } } @@ -539,48 +526,45 @@ export class Sketcher extends THREE.Group { solve() { + // for (let i = 0, p = 0; i < this.geomGroup.children.length; i++) { + // this.ptsBuf[p++] = this.geomGroup.children[i].geometry.attributes.position.array[0] + // this.ptsBuf[p++] = this.geomGroup.children[i].geometry.attributes.position.array[1] + // } + this.updatePointsBuffer() - for (let i = 0, p = 0; i < this.children.length; i++) { - this.ptsBuf[p++] = this.children[i].geometry.attributes.position.array[0] - this.ptsBuf[p++] = this.children[i].geometry.attributes.position.array[1] - } + const pts_buffer = Module._malloc(this.ptsBuf.length * this.ptsBuf.BYTES_PER_ELEMENT) + Module.HEAPF32.set(this.ptsBuf, pts_buffer >> 2) - buffer = Module._malloc(this.ptsBuf.length * this.ptsBuf.BYTES_PER_ELEMENT) - Module.HEAPF32.set(this.ptsBuf, buffer >> 2) + const constraints_buffer = Module._malloc(this.constraintsBuf.length * this.constraintsBuf.BYTES_PER_ELEMENT) + Module.HEAPF32.set(this.constraintsBuf, constraints_buffer >> 2) + + const links_buffer = Module._malloc(this.linksBuf.length * this.linksBuf.BYTES_PER_ELEMENT) + Module.HEAPF32.set(this.linksBuf, links_buffer >> 2) + + Module["_solver"](this.geomGroup.children.length, pts_buffer, this.constraints.size, constraints_buffer, this.linkedObjs.size, links_buffer) + + let ptr = pts_buffer >> 2; - Module["_solver"](this.children.length / 2, buffer) + for (let i = 0; i < this.geomGroup.children.length; i += 1) { + const pos = this.geomGroup.children[i].geometry.attributes.position; + if (isNaN(Module.HEAPF32[ptr])) { + pos.array[0] = Module.HEAPF32[ptr-4] + pos.array[1] = Module.HEAPF32[ptr-3] + pos.array[3] = Module.HEAPF32[ptr-2] + pos.array[4] = Module.HEAPF32[ptr-1] + } else { + pos.array[0] = Module.HEAPF32[ptr++] + pos.array[1] = Module.HEAPF32[ptr++] + } - let ptr = buffer >> 2; - - - for (let i = 0; i < this.linkedObjs.lengthxx; i += 1) { - - const pt1_pos = this.children[i >> 1].geometry.attributes.position; - const pt2_pos = this.children[(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; + pos.needsUpdate = true; } this.dispatchEvent({ type: 'change' }) - Module._free(buffer) + Module._free(pts_buffer) } } diff --git a/wasm/solver.c b/wasm/solver.c index 6a50493..7c3eb7d 100644 --- a/wasm/solver.c +++ b/wasm/solver.c @@ -12,7 +12,7 @@ #include #include #include - +#include #include "slvs.h" static Slvs_System sys; @@ -33,11 +33,9 @@ static void *CheckMalloc(size_t n) * entities and constraints. *---------------------------------------------------------------------------*/ -int solver(int nLines, float *ptr) +int solver(int nPts, float *p_ptr, int nConst, float *c_ptr, int nLinks, float *l_ptr) { - - float *buf_pt_start = ptr; - + // printf("first %i \n", (int)*(l_ptr + 1)); Slvs_hGroup g; double qw, qx, qy, qz; @@ -67,46 +65,77 @@ int solver(int nLines, float *ptr) /* These points are represented by their coordinates (u v) within the * workplane, so they need only two parameters each. */ - int p_start = sys.params; - - Slvs_hParam ph = 11, ph_s = 11; + Slvs_hParam ph = 11; Slvs_hParam vh = 301, vh_s = 301; Slvs_hParam lh = 400, lh_s = 400; Slvs_hParam con_id = 1; - for (int i = 0; i < nLines * 2; i++) + float *buf_pt_start = p_ptr; + int p_start = sys.params; + for (int i = 0; i < nPts; i++) { + printf("i: %i %f %f \n", i,(float)*p_ptr,(float)*(p_ptr+1)); + if (isnan((float)*p_ptr)) + { + p_ptr+=2; + continue; + } + sys.param[sys.params++] = Slvs_MakeParam(ph++, g, (float)*p_ptr++); + sys.param[sys.params++] = Slvs_MakeParam(ph++, g, (float)*p_ptr++); + sys.entity[sys.entities++] = Slvs_MakePoint2d(i, g, 200, ph - 1, ph - 2); + } - sys.param[sys.params++] = Slvs_MakeParam(ph++, g, (float)*ptr++); - sys.param[sys.params++] = Slvs_MakeParam(ph++, g, (float)*ptr++); - sys.entity[sys.entities++] = Slvs_MakePoint2d(vh++, g, 200, ph - 1, ph - 2); - - if (i % 2 == 1) + for (int i = 0; i < nLinks; i++) + { + if (*l_ptr++ == 0) { sys.entity[sys.entities++] = Slvs_MakeLineSegment(lh++, g, - 200, vh - 1, vh - 2); + 200, (int)*l_ptr++, (int)*l_ptr++); + l_ptr += 2; + } else { + l_ptr += 4; } - else if (i > 0) + } + + printf("nconst: %i \n", nConst); + for (int i = 0; i < nConst; i++) + { + if ((int)*c_ptr == 0) { + c_ptr+=2; + printf("const: %i %i \n", (int)*c_ptr, (int)*(c_ptr+1)); sys.constraint[sys.constraints++] = Slvs_MakeConstraint( con_id++, g, SLVS_C_POINTS_COINCIDENT, 200, 0.0, - vh - 2, vh - 1, 0, 0); + (int)*c_ptr++, (int)*c_ptr++, 0, 0); + + c_ptr += 2; + + } else { + c_ptr += 6; } } /* And solve. */ Slvs_Solve(&sys, g); + printf("npts: %i \n", nPts); if (sys.result == SLVS_RESULT_OKAY) { // printf("solved okay\n"); - for (int i = 0; i < nLines * 4; i++) + for (int i = 0; i < nPts; i++) { + if (isnan((float)*buf_pt_start)) + { + buf_pt_start+=2; + continue; + } + printf("res: %i %f %f \n",i, (float)sys.param[p_start].val, (float)sys.param[p_start+1].val); + *buf_pt_start++ = (float)sys.param[p_start++].val; *buf_pt_start++ = (float)sys.param[p_start++].val; } }