From 84466424aa0133bde94b9b7fc77bb5dadaf94c3c Mon Sep 17 00:00:00 2001 From: howard Date: Sun, 21 Mar 2021 18:57:08 -0700 Subject: [PATCH] working line coincidence --- dist/bundle.js | 2 +- dist/solver.wasm | Bin 137292 -> 135384 bytes src/Sketcher.js | 57 +++++++--- wasm/notes | 8 +- wasm/solver.c | 288 +++++------------------------------------------ 5 files changed, 75 insertions(+), 280 deletions(-) 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 f6efd4e747fa6a993245efeb3cc2f1367344f52e..fd45f2da11ee59e7e27175aa4510f8b5a7981e17 100755 GIT binary patch delta 17612 zcmc(G2b>f|_W!)<-es0$VSoiO@@hqI5eW){0T!B*U0|3k z;94oHD|2O?9s!3c=vtMl#`GMU)42*)nOTQ*h7$?s%lUH7 zh)Z1q^co%X6?_?A5!P46rT&AHZRm>^jw>-;#&L%o-0BF zSR26FVO@vo=(=22MEcU^EBVW~(DhKR7uMHsUAaZBG8F#t!->ZooH%b>q0uO`Kv&XF-;%ux`ptbu-7( z4th4{<}p3b=4R}06OPOise$|>kbey8oB3wlf?J441vWS4g1FQzQEnO5t+<8UT61eb ztgyKiuZRnM3*VBdb~o0yVvO7PwoJ9ZvA!Kb-@&)@9btVZ$anEwd}l*6IM?eoAh&s5 zN80kO+%~N5j!S)yGu6`fLY8~O`cM2PeV?-hwtaV@B^Xp z0)G(j2gCXyen|h7|5{T8^h%rW=9P9M6>#e5hf#hwtRLaO%I#5pR1ja;{0M(#H;Mp~ zsUHL6v9Nv|5Zs>NCj_#}=Er%JVZ!=JAf62Cr+~oiX?|J|t8IRYR~tk%{R|M#g!QvP z;PxCpCx|sRKg(+jBBaAWgu}WW5V$?h&jS(BYi(}FYYil*{|3n4!ukb3aC?zo6efi> zzrclpxH(|{iks@sWJ5|>(@|!Ev#RU@ay^w{>8FX z6W}lahZ7GcJ%V_Ik^5_#!TamDiX%yCBLVwR0H*X2@ka)_!Ddi5#AoKm#2@<_juIV4 z6OZ;a979fo^jP9C#ACr}oHTzzjB8wpisMb|c&PX(@hIX?ftygG;zXk&!fT=Jjn5J~z#u zL&f>Tvk+?lE+|oPp-~YtW|8fjP4G|9Hmv=-9ydL8jf%oE_&8x13KZT&SlbCup85^q4m zMtFeqCUSNL^k$idMG~r8#F<+~-EA;CR6r;~IN~kDTZy+(sDg0WE?l;Q%MRilq<0eU zB*|f0Y{r0FOq#2wcVYe!?*c5cTM(wWhj@>{ZnYWItp=N^_ZsY8VD}lQl=c(vH_&Z1 zgSyQ?SsyUa0|0zupi(+We9%C*+YIV<1Ffcu4YZgdVSUJ8i-A2%eAr-j*bM3pgAM5; z273g6qXsIaW5mY{bf?WiHPE0wZlK2j_|`zBbb|PVf$p*y)LjM|(BBb%N0||E==b8X zlf)-|hn^CL{y=<+_y_bqEv-Ki<2qg9&}=2G+3I=SQStXk!3rr@#dB*X<>V;c8CC8K zdKblAluHV>-*#8rRYka);!cWl6n9slkaX-J9ebeT+lt>-x~JlvN?f?x zW(=|0h+j|lQc~*$*gFC+rQV8r8|WUJLEU4ZnYxdG_5t)=1C>%=#eD@D(R*zMd9T5; zb`91AqMyM^={?2o8Mgau26dl-R@40rv_Alzfl6tB;sFM_-)2zv8)!(sZ=ml3Fwj7y zG)VCvRTJyKK43G*2Mji-2OI2QAch#Ml!huEYS?~*6t4Ii16BG1vD61DzCq4aoU6>r zF-+*gK<})aR6Sg3!%@qY+6bwQKn-60MCr&#sgFecgsFch)eliUN=_e3e#+(w#wi}Fc%15>KT$kJ z>GAMCg!okPc*UQp)_Q`VCMuqwc%o{rCn=t!TBHg4sNyKJ!vjE`U&0DGS-j7MZOW z*Hm;kAj3=ZT;S#@#s${ku~>3(P=BTv!+wUw&+*hl zdcI)iqq;!xf{5R;Q1L<~`-p?s1}Q!$IhXC47U0ELXcQM4O56gA&RAeEM)8$jVw7KE zloy)l{e@yczravSjYiNrUokGR)-n-eStL>KFAWNMFIS99^ezxofv@*+qj&ct?hd_| z*v?$iE2Mb^a4QwBRQfB$xG(@XEfMVjStXEFfUH)$TIn^4*BDI?VSQ2@ITT-t)+(v4 z1+GvKrnFA+I)goIGpL8-E75wz>k$e_Twg0h#sPN;dgM=M-3vv(A z5z>rmr}vi7_bEIl>_?KoUQ%|bQMOnt&YPXPLz zflBFnByK7`Df42KBgsR@0{q^fUlJ8mN@AEzY(i zU4LscsNWiBNO!bE*p3#K2}^{PQYVW$MGW=?QoF?`3^u4c8*FDFx)`jKx?0@TK)fkOrQfyF~D{=jOd zb4%#MM9JY653_hU=p!trAfQJIqmkhFp~W8}SzEHier)kaW+?DP85~Afp-KWDCGb&z zkG6QUrN>x2#)^omzPA~&es9cQPmi^vHWs*Xf-t2|EdIop|D?^Jo;1)*J>Eda1Ny0f zN@;?{6Abi}&7ht#P}UO-bRqzg3{*-{iz88k{Q>)Si+?cKYC6wg^MIIauu__0@e~6+ zZ8NB+4K$=<1{woks)0&rn#I!$^hcXP{n0>!db)v52VjPQN@-@q;+Y1Uox~t#Cn2uN zQEEK2W{Ia~TRh9sb1a^1>A4o8FxR?O&l5*|X7N0WKSL~ij#%Q)LP` zFj#2uLR617){CUmVv849ycnY|vE=;c3yX0rK|CClgNdc4c_|_(-{J)p=L5LRgu!mo zUkZce7Jq5+a?lIJqXp=R{i+{GD-05Wv{H~?S-jHXuMjY+O6aR4kk(kd+Tt~!N7h(~i#CH}n6E9~0LhWtEnX|lxI&e| zY?CnC1ZJBp-fZb2i;FB-+BzmN^yrv`r46SdTP&$g@)*9e^DMDy5wk?=;X(NepTy17*F-Kz9MK+d!qX$KpK(+Bu0q?QEdc^j?8RcrOt9 z3|30}E#7aiU6L5oE(ROY2MpT-0DNPhQaWhyK?CiY#GrOH(4a0h&|&}%8K{&FTYT6+ zyCpHG-2|Fyf-Hgrc0^ot)Z!z^b^sp}`yGQ*w^O-5YQVs-DLHOA*!+BJF|OlQsH<#> zP9SL_vIaEK-y!}Gf!|pslYK8Nz6Xo+lC4;}J_(xHiJg)N_yIE$6V8fs(5Eq7UU#y&lkM-sI%8W8P7tPxIkWAI&AouT;RwX$ZgyDb zfX+F#*?-!)yPQo82dw5BQjetT{k)&9d&`)8Z0?QY6ae29;JW~(8>3+kJJ~_qSB|M%oBP`A+M&Jb zB2@bcvLBEk7$;&jsv-TJ0Q=kAA5!#bqCK16v-JRM;%)uD%_zJNn+%j82Vu94lMvWs zFtT{uCPT0rfI5^%-_ z^+=?0P((ELk>3d)Kn0r2sLIit|^cY`>cSTDzs@f3 z;i4$sGBaD&99Y%b8&M=0-==-JE|kam=i3QaheE>199%L-ITbvmXxpIA<> zRHuKclN;UHNR>}Rmt5s6F7eEGF6#^|>x_2?v|TNf9NQ_5Q(n8fC;T|L)8dKI(5ztZT5wES(&PFhJ3+k>13-J zC$W36>yfPI)$mux2bNy zUoJ&z`{pmr6WAxof}R&`_P`Kocs|n^%GW5H+GQXmpQ94`1~6Z4S=h>ZIE8}l;}2Cn zN0ql8+9}g4Zhe@*k~wp=w$Y6qZsjigYmL(FwzSuaw=aXX%O5UF36NlmGy}O>Cqe4s zN5YEo+y@`O1fTzUeE#q0Oy_)S{35Bc?+KWFEIAX)IrGXnUqrurB2y)30Hd)eSwkno z2#-D2%DwmLL?fVGOM7O#{R#K*(@mgWy=SW6Q}Df>*@DuG&-(SSd+^x@6YA~G!CvCF z4Cf|{pVA^N!*@a%2mHKNuJ^Yzw{5$L2^h$5xsNH4@zLkkCA9w(j|HXM|bpmYhOsPoDnt%ODhUrPq7p-Y6@`j5XO((eDKlNf2R!PP#j#0JY>y~M5j z>ca`FehPDrFKd^!W82rJCG;=bA}!tyQKI_wF$(iD|KAOuI=v~Ty5P-u32l3bms2AlORl#$vhEx<_D4PeK59p@#O8M-y( zVBE|lCb;{pj-_+Q_2`F~j9%5L3c*#)I`^go0MhMEP;7IT8-Bec=-@W%+$!3m+eI?B zrMSQQkVMaE98txMkC%xYHq69sWm2N@%hkdgl@s)0MSfZs{|D1ttIm-yMF1ohg zD~V|VlH7U*5Pi(6m)MASzU^$|sP`9%WnLOA5dxXqWrNqCG;+x0ls95=DN})K+cO=_ zWWVx*eGtD=?h$+@4{MO11RQ>k<7b%M;kNtUuum>M6FnKyc!rT##FE{LZ`E+ie|VMq z$?zzKe{4hz`FyU`h-D+_CwkVC=~k*|?*v0b&_A8wZv;L0p$idve{=|+9Y1~}0Sj5~ z6YSXx`rxSQn82@(I*u50Umg<|#N9Mzs zwY&OFQbhiv4c%`Vvebx?-(g$%pGXn;-Sa5p$~o_(Ipfnx+4`qU z9r@39^}kYl2!_{)e8F~~5iIgQjsDP+k>A<;|5sOH{{M#$Rlm~wKOXS;gvu{kA!apGadTmdN_ZsTn9c_iRY+!VG!lH|nJ%B~` z)x6~i3mmmbQ=BCGxFFgdnSA0eIhAA{_p9U#spNcI$qfIiNQ@VTRtH+8SqTrKSZay! zmPfkbK4Hq3giRmXa3~eu^vU2IVw-RJRUW&n5Cu2yc@Svd*q*qxT;WHECJG%Z^3gj;TQ)r58!BURdsp`tg;PAQWH0e9L? z$BITk_pSwZwfrTSex0-2?F;^t5Ea{qKext-C-!}dUQG}c`&8R+ zgDTO9i<;B#CD;v1dL@hl83MBPYHbe6HZFNQt(5-m?O%*dK#LlFq{;I``K956NJHD% zNR#HiODEJX#q4J-2PZ7U;guh1?%(sBgds}@)w28xtqTAjt(bJ|_$_RxlWswh^oonvRM=7v^l_km4WkzePe{~D^QiHjw+3P$J+Igs)XrQF(^ zGn3`{qIHJbwy0Tj(B_W6+Z=d&%T);hfTv}1igmk2R&_^gc~eY`w-T55wsPxiy`&~6 zCj-v0gls6YrcFrWoVb)_+*h{NhChaFm6c@uwpQ-xt<6wsx~-%>c$+-U%-dGYw6`lg zgK!k)Tw=~aFoU9xY@eia+1w zd~evUFk~*bTO_|`@1S3vXGOb*U4Hh7Q_f3;+0BmXz!Y}a=y{fLg}vHm{OdB^K%!)P zl~L+QRt~9sdBu~J_MMx}I_?wSe7aA3v0$H@5CfRR<~$|c96-Iee^7nceK|Rk&d!%} z9Q_j(jW#(zmIO~xk~2I$ZEq{yoG?sDHjAHQ9SYh4@0aXMj>GRe_VhU!c*(KrAnlLG zs+5VJHM@5$tPyQ``~@W<9!+)@Rdm)@{I#JGEjrOoRYqtGx18yfoY|F}O-7N)-eV8Z z1@7NZwxyn4uLtN#_rS>~69k8S%sS!Q=h;&)RDffR2QzR;B|DxSr`DY#`O+UAPe^s( zKr(02V#%5|btM8{eZy_&2JSMuhSp<2|}J5YwMrqSL-L26qr zhIba6g_WJ{4ia1WfRk#>FLh= zbh9h_4J2=US$a~PtQ>2WN{=PUF5v8HfRSSpLv$I{|1FGFC3+=cS0PS;<-_;f;}uq- z3TdTS#*S8^c~}}^Q_`urU4E@mZCkptKixT=9z*&WoPI@VqUhUQk%d`h>{Bhn!gq9e z-pJb2FV%M$zPAM7k9FuVL#UR4Z-1fDr*&wIRjwo=WD3Qex|U{J7`;YAnndMxmu-po z!Oywy>Q!uOBYKn0#t+s&Vfx|?lt+19jT`ALbo=;5T0!Ru-L)}QrWD_GSQ}%*o6x1C z&sV}JO^Ov|(E_5J*hkIi7E-6Oyh9FEp?+SO=5(C8d#9Vz300iso%kcoqQTyjo9PP5 z^)}p0)0=f}nvo3Y@S`<(e<<0h_PnTYDl6?S`G6j+DC57zd~@snBJ&2f{`Z*2y5B}~73Fxh z-bsH;gCnt}R${PIS+V(dQU*o(!5@e{IBg}~gpe<1RX>>2!3zL`n>sm7Lp=yH0X=fh z16sLp;HaiPWZZcW_|oT<7l)k6Dm9$0i(rs3Psz907_)Ozr#LJ0c6`iLSsBSr;C6Y< zz#k#s>(_>^ylz#Ni8us62EwkjylN0{FU?*!=f^p(@(#A4x6-0jB)iS2;w-M>tc<7fn%<`(@2)Y_AGe)jXdG_tSh}iGQC<9S6mRjQmy?;K)14x3`B=K+@}jyr zggK6PBhsAgP%F@e`#>x7F7v@jbVr^^ZV z)ibC!f%j9hr~_5(ncJysXc0O6a8E58aC*k}&Zdr}3UBb{&85n*?77s&3g(Xcyj%_C z4Dbp+r`M^Mckg`g`XKhN`SeUOjq{4WpdV?fSG1HKpzYpG`SgP-Zs6UxjB@k<;Xhra z+OTeF8GM9RP-;@Z`RKaTi&1m-$F?oQcy{MT$hOZer>ByTAHQ5h*Eh&VPsxDDUBR#p z$UaP7a0*ILI`gG5BN^XBAy+BqO-}k}d(0{C#??rMBfZyFQ}xH!^SVW$BQ&hOVnR0Vs@*pB;}xsazV|jj8PY zxQ3oVMt){3b%AjXtc4GAz1IrqZOV@&ucK;&#_H?oF$mgmJ=Fnb!g~70O~M0WTDSNS zC(Pp_fY>f0$qAX3lHoA0%@&N%5b6H0uj#5(UmTg}Bfb7#Q@uK)gkv&WcNjCFfN$g* zDxpd~K(ddI7|wtSdET7eRQ*wz?EZ8=I-(O2ngO0dQQH!Hf##7$Dtn}GXr7%b?`q&R z*%N4nIOLQIJ1@0&3dgJ-lk^JS-ZEs7C&zS~5Bmr4=`!x<@@ zbO#=F5#G0@$va}T1BJrFZl8wlAWP&jQk%XTyy7Cd)Jxe&e}D|$wHxWC@`kg#JS7U| zd#`V#_UhCK@0*SEVp*RV{8#8bvx#nQCIhnyXFx6~BEU?q0+fA|p+PFfBtJF$zD;yZ zWSp@gMnv`q+?6IqlGR$sC~B}|#8?sd_zfFO$%!;nGtYQJOobP+;&r^0hPox3O4f#%m1a??_oab%aOqZ7F47=maF^`I*0o9D)U4CHs%5t&}Vh01p*q(`! z{-pICrSi>M|Umkp|Vjx0&W2cx`UTd3+462`3jsf~A0OQJf{OfvSNBfSkBsvv0ve9v-C4l3_p zXG0;r9IQNGLgDRi&I^UuH}ntW-#Q1WwV4=f`2mL)EzgO~fFGL>nGpx^DT1dIUky1Y z$1L$z0KX*K$%}?1kObD}#InyCVjMq64m7yF_&g0BE2itQKnyI#T9WVK=bh)q^zDb} z)yl%RmHggKUM-b%q(Z89%|W`%JAR0&p6{|t4x0eF?l4VGPl))E443Pj7C^3d!4aBS z(IlxzI0HYrX1W+j%iDg0UZI)Z{YR+@&5ZRwN|yy`er)n7s!nO!^0Ko7cx=fIrY^4M zee(l76ua{@RiM~IKhltNYVCbrSw)cr#;2?5X^Sro1oAHmn7^R69;AxJAe{hdL!8{$ zD_ccfu7#Y5{~-SF>2O1bS6_PSk>_4``bFs~Tv~f~R#AUQ5!j>nzu$WkRl}?gs-5vK ze|g>%km-7FQx$bvWdVmS0TuVTm!jEO>@}{c>QTAa->Rw#Wba?zjJ$U%ss{M!{NxK% PU8?5oxIjH&3;6#51U*Z! delta 19636 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

_5xECOr>2APS`O!7s{ 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 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