polynomial analysis

This commit is contained in:
Val Erastov (xibyte) 2020-01-07 00:17:20 -08:00
parent 168fb3bacd
commit 2fafec904c
40 changed files with 1896 additions and 817 deletions

494
package-lock.json generated
View file

@ -1793,7 +1793,8 @@
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"optional": true
},
"assign-symbols": {
"version": "1.0.0",
@ -2110,12 +2111,6 @@
"integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=",
"dev": true
},
"bluebird": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz",
"integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==",
"dev": true
},
"bn.js": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
@ -2350,36 +2345,6 @@
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
"dev": true
},
"cacache": {
"version": "11.3.1",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.1.tgz",
"integrity": "sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==",
"dev": true,
"requires": {
"bluebird": "^3.5.1",
"chownr": "^1.0.1",
"figgy-pudding": "^3.1.0",
"glob": "^7.1.2",
"graceful-fs": "^4.1.11",
"lru-cache": "^4.1.3",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.2",
"ssri": "^6.0.0",
"unique-filename": "^1.1.0",
"y18n": "^4.0.0"
},
"dependencies": {
"y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
}
}
},
"cache-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@ -2751,6 +2716,7 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
"integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
"optional": true,
"requires": {
"delayed-stream": "~1.0.0"
}
@ -2758,7 +2724,8 @@
"commander": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
"dev": true
},
"commondir": {
"version": "1.0.1",
@ -3357,7 +3324,8 @@
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"optional": true
},
"depd": {
"version": "1.1.2",
@ -3682,9 +3650,9 @@
}
},
"esprima": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"globals": {
@ -3694,9 +3662,9 @@
"dev": true
},
"js-yaml": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
"integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
@ -4161,7 +4129,8 @@
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"optional": true
},
"fast-deep-equal": {
"version": "1.1.0",
@ -4479,7 +4448,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -4500,12 +4470,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -4520,17 +4492,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -4647,7 +4622,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -4659,6 +4635,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -4673,6 +4650,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -4680,12 +4658,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -4704,6 +4684,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -4791,7 +4772,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -4803,6 +4785,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -4888,7 +4871,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -4924,6 +4908,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -4943,6 +4928,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -4986,12 +4972,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},
@ -5270,9 +5258,9 @@
"dev": true
},
"handlebars": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
"requires": {
"neo-async": "^2.6.0",
"optimist": "^0.6.1",
@ -5723,6 +5711,12 @@
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
"dev": true
},
"infer-owner": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
"integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
"dev": true
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -6174,7 +6168,8 @@
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"optional": true
},
"jsesc": {
"version": "2.5.2",
@ -6389,9 +6384,9 @@
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"lodash.camelcase": {
"version": "4.3.0",
@ -6760,9 +6755,9 @@
}
},
"mixin-deep": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"dev": true,
"requires": {
"for-in": "^1.0.2",
@ -8273,27 +8268,75 @@
}
},
"react": {
"version": "16.4.1",
"resolved": "https://registry.npmjs.org/react/-/react-16.4.1.tgz",
"integrity": "sha512-3GEs0giKp6E0Oh/Y9ZC60CmYgUPnp7voH9fbjWsvXtYFb4EWtgQub0ADSq0sJR0BbHc4FThLLtzlcFaFXIorwg==",
"version": "16.12.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.12.0.tgz",
"integrity": "sha512-fglqy3k5E+81pA8s+7K0/T3DBCF0ZDOher1elBFzF7O6arXJgzyu/FW+COxFvAWXJoJN9KIZbT2LXlukwphYTA==",
"requires": {
"fbjs": "^0.8.16",
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0"
"prop-types": "^15.6.2"
},
"dependencies": {
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
},
"dependencies": {
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
}
}
}
}
},
"react-dom": {
"version": "16.4.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.1.tgz",
"integrity": "sha512-1Gin+wghF/7gl4Cqcvr1DxFX2Osz7ugxSwl6gBqCMpdrxHjIFUS7GYxrFftZ9Ln44FHw0JxCFD9YtZsrbR5/4A==",
"version": "16.12.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.12.0.tgz",
"integrity": "sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw==",
"requires": {
"fbjs": "^0.8.16",
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0"
"prop-types": "^15.6.2",
"scheduler": "^0.18.0"
},
"dependencies": {
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
},
"dependencies": {
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
}
}
}
}
},
"react-is": {
"version": "16.12.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz",
"integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q=="
},
"read-pkg": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
@ -8731,6 +8774,15 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true
},
"scheduler": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.18.0.tgz",
"integrity": "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
},
"schema-utils": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
@ -8818,12 +8870,6 @@
}
}
},
"serialize-javascript": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz",
"integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==",
"dev": true
},
"serve-index": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
@ -8884,9 +8930,9 @@
"dev": true
},
"set-value": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
@ -9161,6 +9207,24 @@
"urix": "^0.1.0"
}
},
"source-map-support": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
"integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"source-map-url": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
@ -9592,65 +9656,60 @@
"integrity": "sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==",
"dev": true
},
"terser": {
"version": "3.10.12",
"resolved": "https://registry.npmjs.org/terser/-/terser-3.10.12.tgz",
"integrity": "sha512-3ODPC1eVt25EVNb04s/PkHxOmzKBQUF6bwwuR6h2DbEF8/j265Y1UkwNtOk9am/pRxfJ5HPapOlUlO6c16mKQQ==",
"terser-webpack-plugin": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
"integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
"dev": true,
"requires": {
"commander": "~2.17.1",
"source-map": "~0.6.1",
"source-map-support": "~0.5.6"
"cacache": "^12.0.2",
"find-cache-dir": "^2.1.0",
"is-wsl": "^1.1.0",
"schema-utils": "^1.0.0",
"serialize-javascript": "^2.1.2",
"source-map": "^0.6.1",
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",
"worker-farm": "^1.7.0"
},
"dependencies": {
"commander": {
"version": "2.17.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-support": {
"version": "0.5.9",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz",
"integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==",
"cacache": {
"version": "12.0.3",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
"integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
"bluebird": "^3.5.5",
"chownr": "^1.1.1",
"figgy-pudding": "^3.5.1",
"glob": "^7.1.4",
"graceful-fs": "^4.1.15",
"infer-owner": "^1.0.3",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.3",
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
}
}
}
},
"terser-webpack-plugin": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz",
"integrity": "sha512-61lV0DSxMAZ8AyZG7/A4a3UPlrbOBo8NIQ4tJzLPAdGOQ+yoNC7l5ijEow27lBAL2humer01KLS6bGIMYQxKoA==",
"dev": true,
"requires": {
"cacache": "^11.0.2",
"find-cache-dir": "^2.0.0",
"schema-utils": "^1.0.0",
"serialize-javascript": "^1.4.0",
"source-map": "^0.6.1",
"terser": "^3.8.1",
"webpack-sources": "^1.1.0",
"worker-farm": "^1.5.2"
},
"dependencies": {
},
"find-cache-dir": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz",
"integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
"integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
"dev": true,
"requires": {
"commondir": "^1.0.1",
"make-dir": "^1.0.0",
"make-dir": "^2.0.0",
"pkg-dir": "^3.0.0"
}
},
@ -9663,6 +9722,26 @@
"locate-path": "^3.0.0"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
"dev": true
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
@ -9673,10 +9752,29 @@
"path-exists": "^3.0.0"
}
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"dev": true,
"requires": {
"yallist": "^3.0.2"
}
},
"make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
"dev": true,
"requires": {
"pify": "^4.0.1",
"semver": "^5.6.0"
}
},
"p-limit": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz",
"integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==",
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
"integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
@ -9692,9 +9790,15 @@
}
},
"p-try": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz",
"integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true
},
"pkg-dir": {
@ -9706,11 +9810,68 @@
"find-up": "^3.0.0"
}
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
},
"serialize-javascript": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"terser": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.1.tgz",
"integrity": "sha512-w0f2OWFD7ka3zwetgVAhNMeyzEbj39ht2Tb0qKflw9PmW9Qbo5tjTh01QJLkhO9t9RDDQYvk+WXqpECI2C6i2A==",
"dev": true,
"requires": {
"commander": "^2.20.0",
"source-map": "~0.6.1",
"source-map-support": "~0.5.12"
}
},
"webpack-sources": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
"integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
"dev": true,
"requires": {
"source-list-map": "^2.0.0",
"source-map": "~0.6.1"
}
},
"worker-farm": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
"integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
"dev": true,
"requires": {
"errno": "~0.1.7"
}
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true
}
}
},
@ -9871,7 +10032,8 @@
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"optional": true
},
"type-check": {
"version": "0.3.2",
@ -9921,15 +10083,21 @@
"integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA=="
},
"uglify-js": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
"integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
"version": "3.7.4",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.4.tgz",
"integrity": "sha512-tinYWE8X1QfCHxS1lBS8yiDekyhSXOO6R66yNOCdUJeojxxw+PX2BHAz/BWyW7PQ7pkiWVxJfIEbiDxyLWvUGg==",
"optional": true,
"requires": {
"commander": "~2.20.0",
"commander": "~2.20.3",
"source-map": "~0.6.1"
},
"dependencies": {
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"optional": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@ -9977,38 +10145,15 @@
"dev": true
},
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
"integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"dev": true,
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
"set-value": "^0.4.3"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"requires": {
"is-extendable": "^0.1.0"
}
},
"set-value": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.1",
"to-object-path": "^0.3.0"
}
}
"set-value": "^2.0.1"
}
},
"uniq": {
@ -11411,15 +11556,6 @@
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
},
"worker-farm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz",
"integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==",
"dev": true,
"requires": {
"errno": "~0.1.7"
}
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",

View file

@ -55,7 +55,7 @@
"clipper-lib": "6.2.1",
"diff-match-patch": "1.0.0",
"earcut": "2.1.1",
"handlebars": "^4.1.2",
"handlebars": "^4.5.3",
"handlebars-loader": "1.7.1",
"jquery": "^3.4.1",
"less": "^3.8.1",
@ -63,8 +63,8 @@
"mousetrap": "1.6.1",
"numeric": "1.2.6",
"prop-types": "15.6.0",
"react": "^16.4.0",
"react-dom": "^16.4.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"sprintf": "0.1.5",
"three": "0.89.0"
}

View file

@ -0,0 +1,89 @@
import {AlgNumConstraint, ConstraintDefinitions} from "../constr/ANConstraints";
import {EndPoint} from "../shapes/point";
import {Circle} from "../shapes/circle";
import {Segment} from "../shapes/segment";
import {matchAll, matchTypes, sortSelectionByType} from "./matchUtils";
export default [
{
shortName: 'Coincident',
description: 'Point Coincident',
selectionMatcher: (selection, sortedByType) => matchAll(selection, EndPoint, 2),
invoke: viewer => {
const [first, ...others] = viewer.selected;
let pm = viewer.parametricManager;
for (let obj of others) {
pm.algnNumSystem.addConstraint(
new AlgNumConstraint(ConstraintDefinitions.PCoincident, [first, obj])
);
}
pm.refresh();
}
},
{
shortName: 'Tangent',
description: 'Tangent Between Line And Circle',
selectionMatcher: (selection, sortedByType) => matchTypes(sortedByType, Circle, 1, Segment, 1),
invoke: viewer => {
const [circle, line] = sortSelectionByType(viewer.selected);
let pm = viewer.parametricManager;
const ang = line.params.ang.get();
const w = line.params.w.get();
const inverted = Math.cos(ang) * circle.c.x + Math.sin(ang) * circle.c.y < w ;
pm.algnNumSystem.addConstraint(new AlgNumConstraint(ConstraintDefinitions.TangentLC, [line, circle], {
inverted
}));
}
},
{
shortName: 'Point On Line',
description: 'Point On Line',
selectionMatcher: (selection, sortedByType) => matchTypes(sortedByType, EndPoint, 1, Segment, 1),
invoke: viewer => {
const [pt, line] = sortSelectionByType(viewer.selected);
let pm = viewer.parametricManager;
pm.algnNumSystem.addConstraint(new AlgNumConstraint(ConstraintDefinitions.PointOnLine, [pt, line]));
}
},
{
shortName: 'Angle',
description: 'Angle',
selectionMatcher: (selection, sortedByType) => matchAll(sortedByType, Segment, 1),
invoke: viewer => {
const firstSegment = viewer.selected[0];
const firstConstr = new AlgNumConstraint(ConstraintDefinitions.Angle, [firstSegment]);
firstConstr.initConstants();
viewer.streams.constraintEditRequest.next({
constraint: firstConstr,
onCancel: () => viewer.streams.constraintEditRequest.next(null),
onApply: () => {
viewer.streams.constraintEditRequest.next(null);
const pm = viewer.parametricManager;
pm.algnNumSystem.addConstraint(firstConstr);
for (let i = 1; i < viewer.selected.length; ++i) {
pm.algnNumSystem.addConstraint(new AlgNumConstraint(ConstraintDefinitions.Angle, viewer.selected[i], {...firstConstr.constants}));
}
pm.refresh();
}
});
}
}
];

View file

@ -0,0 +1,25 @@
import constraintActions from "./constraintActions";
import {sortSelectionByType} from "./matchUtils";
const ALL_CONTEXTUAL_ACTIONS = [
...constraintActions,
//keep going here
];
export function matchAvailableActions(selection) {
let sortedByType = sortSelectionByType(selection);
let matched = [];
if (selection.length) {
for (let action of ALL_CONTEXTUAL_ACTIONS) {
if (action.selectionMatcher(selection, sortedByType)) {
matched.push(action);
}
}
}
return matched;
}

View file

@ -0,0 +1,38 @@
export function matchAll(selection, shapeConstructor, min) {
if (min !== undefined && selection.length < min) {
return false;
}
for (let obj of selection) {
if (obj._class !== shapeConstructor.prototype._class) {
return false;
}
}
return true;
}
export function matchTypes(selection) {
let si = 0;
let i = 1;
for (; i < arguments.length; i+=2) {
let shapeConstructor = arguments[i];
let quantity = arguments[i+1];
if (si === selection.length) {
return false;
}
for (let j = 0; j < quantity && si < selection.length; j++) {
let obj = selection[si++];
if (obj._class !== shapeConstructor.prototype._class) {
return false;
}
}
}
return si === selection.length && i === arguments.length;
}
export function sortSelectionByType(selection) {
return [...selection].sort((a, b) => a._class.localeCompare(b._class))
}

View file

@ -0,0 +1,73 @@
import React, {useState} from 'react';
import Widget from "ui/components/Widget";
import NumberControl from "ui/components/controls/NumberControl";
import {DEG_RAD} from "../../math/math";
import Stack from "ui/components/Stack";
import ButtonGroup from "ui/components/controls/ButtonGroup";
import Button from "ui/components/controls/Button";
import connect from "../../../../modules/ui/connect";
export const ConstraintEditor = connect(streams => streams.sketcherApp.constraintEditRequest)(
function ConstraintEditor({constraint, onCancel, onApply}) {
return <ConstraintEditorImpl constraint={constraint}
onCancel={onCancel}
onApply={onApply} />
}
);
export function ConstraintEditorImpl({constraint, onCancel, onApply}) {
if (!constraint) {
return null;
}
const [values, setValues] = useState({...constraint.constants});
const setValue = (name, value) => {
setValues({...value, [name]: value});
};
const apply = () => {
Object.keys(constraint.schema.constants).map(name => {
const val = values[name];
if (val !== undefined) {
constraint.constants[name] = val;
}
});
onApply();
};
return <Widget>
<Stack>
{Object.keys(constraint.schema.constants).sort().map(name => <div key={name}>
{
(() => {
const def = constraint.schema.constants[name];
const val = values[name];
if (def.type === 'number') {
return <NumberControl value={val} onChange={value => setValue(name, value)} />
} else {
return <span >{val}</span>;
}
})()
}
</div>)}
<ButtonGroup>
<Button onClick={onCancel}>CANCEL</Button>
<Button type='accent' onClick={apply}>APPLY</Button>
</ButtonGroup>
</Stack>
</Widget>;
}

View file

@ -0,0 +1,38 @@
import React from 'react';
import ls from './ContextualControls.less';
import connect from "../../../../modules/ui/connect";
import {matchAvailableActions} from "../actions";
import mapContext from "../../../../modules/ui/mapContext";
export const ContextualControls =
mapContext(ctx => ({
invokeAction: action => action.invoke(ctx.viewer)
}))(
connect(streams => streams.sketcherApp.selection.map(selection => ({selection})))(
function ContextualControls({selection, invokeAction}) {
if (selection.length === 0) {
return null;
}
const availableActions = matchAvailableActions(selection);
return <div className={ls.root}>
{
selection.map(s => <div className={ls.item}>{s.simpleClassName}: {s.id}</div>)
}
<div className={ls.hr}>AVAILABLE ACTIONS:</div>
{
availableActions.map(a => <button onClick={() => invokeAction(a)}
title={a.description}>{a.shortName}</button>)
}
</div>;
}
));

View file

@ -0,0 +1,15 @@
.root {
margin: 5px;
padding: 3px 5px;
background-color: #000D;
color: white;
}
.item {
padding: 3px 0;
}
.hr {
.item;
}

View file

@ -0,0 +1,14 @@
import React from 'react';
import {ConstraintEditor} from "./ConstraintEditor";
import {ContextualControls} from "./ContextualControls";
export function RightSideControls() {
return <React.Fragment>
<ContextualControls />
<ConstraintEditor />
</React.Fragment>;
}

View file

@ -0,0 +1,238 @@
import {R_DistancePP, R_Equal, R_PointOnLine} from "./residuals";
import {indexById} from "../../../../modules/gems/iterables";
import {DEG_RAD, distanceAB} from "../../math/math";
import {COS_FN, Polynomial, POW_1_FN, POW_2_FN, SIN_FN} from "./polynomial";
import {Types} from "../io";
export const ConstraintDefinitions = indexById([
{
id: 'PCoincident',
name: 'Two Points Coincidence',
defineParamsScope: ([p1, p2], callback) => {
p1.visitParams(callback);
p2.visitParams(callback);
},
collectPolynomials: (polynomials, [x1, y1, x2, y2]) => {
polynomials.push(new Polynomial(0)
.monomial(1)
.term(x1, POW_1_FN)
.monomial(-1)
.term(x2, POW_1_FN)
);
polynomials.push(new Polynomial(0)
.monomial(1)
.term(y1, POW_1_FN)
.monomial(-1)
.term(y2, POW_1_FN)
);
},
},
{
id: 'TangentLC',
name: 'Line & Circle Tangency',
constants: {
inverted: {
type: 'boolean',
description: 'whether the circle attached from the opposite side',
initialValue: () => false
}
},
defineParamsScope: ([segment, circle], callback) => {
callback(segment.params.ang);
callback(segment.params.w);
circle.c.visitParams(callback);
callback(circle.r);
},
collectPolynomials: (polynomials, [ang, w, cx, cy, r], {inverted}) => {
polynomials.push(new Polynomial(0)
.monomial(1)
.term(cx, POW_1_FN)
.term(ang, COS_FN)
.monomial(1)
.term(cy, POW_1_FN)
.term(ang, SIN_FN)
.monomial(-1)
.term(w, POW_1_FN)
.monomial(- (inverted ? -1 : 1))
.term(r, POW_1_FN)
);
},
},
{
id: 'PointOnLine',
name: 'Point On Line',
defineParamsScope: ([pt, segment], callback) => {
pt.visitParams(callback);
callback(segment.params.ang);
callback(segment.params.w);
},
collectResiduals: (residuals, params) => {
residuals.push([R_PointOnLine, params, []]);
},
collectPolynomials: (polynomials, [x, y, ang, w]) => {
polynomials.push(new Polynomial(0)
.monomial(1)
.term(x, POW_1_FN)
.term(ang, COS_FN)
.monomial(1)
.term(y, POW_1_FN)
.term(ang, SIN_FN)
.monomial(-1)
.term(w, POW_1_FN)
);
},
},
{
id: 'DistancePP',
name: 'Distance Between Two Point',
constants: {
distance: {
type: 'number',
description: 'the distance between two points',
initialValue: (constraint) => {
const [a, b] = constraint.object;
return distanceAB(a, b).toFixed(2) + '';
}
}
},
defineParamsScope: ([pt, segment], callback) => {
pt.visitParams(callback);
callback(segment.params.ang);
callback(segment.params.w);
},
collectResiduals: (residuals, params, {distance}) => {
residuals.push([R_DistancePP, params, [distance]]);
},
collectPolynomials: (polynomials, [x1, y1, x2, y2], {distance}) => {
polynomials.push(new Polynomial( - distance * distance)
.monomial(1)
.term(x1, POW_2_FN)
.monomial(1)
.term(x2, POW_2_FN)
.monomial(-2)
.term(x1, POW_1_FN)
.term(x2, POW_1_FN)
.monomial(1)
.term(y1, POW_2_FN)
.monomial(1)
.term(y2, POW_2_FN)
.monomial(-2)
.term(y1, POW_1_FN)
.term(y2, POW_1_FN)
);
},
},
{
id: 'Angle',
name: 'Absolute Line Angle',
constants: {
angle: {
type: 'number',
description: 'line angle',
initialValue: (constraint) => {
let degrees = constraint.objects[0].params.ang.get() / DEG_RAD;
degrees = (degrees + 360 - 90) % 360;
return degrees.toFixed(2) + '';
},
transform: degree => ( (degree + 90) % 360 ) * DEG_RAD
}
},
defineParamsScope: ([segment], callback) => {
callback(segment.params.ang);
},
collectPolynomials: (polynomials, [x], {angle}) => {
polynomials.push(new Polynomial( - angle).monomial(1).term(x, POW_1_FN));
},
},
]);
export class AlgNumConstraint {
static Counter = 0;
constructor(schema, objects, constants) {
this.id = schema.id + ':' + (AlgNumConstraint.Counter ++); // only for debug purposes - not persisted
this.objects = objects;
this.constants = constants;
this.resolvedConstants = undefined;
this.internal = false;
this.schema = schema;
this.params = [];
this.schema.defineParamsScope(this.objects, p => this.params.push(p));
// this.paramSet = new Set(this.params);
}
collectPolynomials(polynomials) {
this.resolveConstants();
this.schema.collectPolynomials(polynomials, this.params, this.resolvedConstants);
}
resolveConstants() {
if (this.constants) {
if (!this.resolvedConstants) {
this.resolvedConstants = {};
}
Object.keys(this.constants).map(name => {
let def = this.schema.constants[name];
if (def.type === 'number') {
let val = parseFloat(this.constants[name]);
if (def.transform) {
val = def.transform(val);
}
this.resolvedConstants[name] = val;
}
});
}
}
write() {
return {
typeId: this.schema.id,
objects: this.objects.map(o => o.id),
constants: this.constants
}
}
static read({typeId, objects, constants}, index) {
const schema = ConstraintDefinitions[typeId];
if (!schema) {
throw "constraint schema ' + typeId + ' doesn't exist";
}
return new AlgNumConstraint(schema, objects.map(oId => index[oId]), constants);
}
initConstants() {
if (this.schema.constants) {
this.constants = {};
Object.keys(this.schema.constants).map(name => {
this.constants[name] = this.schema.constants[name].initialValue(this);
});
}
}
}

View file

@ -0,0 +1,237 @@
import {createByConstraintName} from "./solverConstraints";
import {Param, prepare} from "./solver";
import {findConstructionCluster} from "./constructions";
import {GCCircle, GCPoint} from "./constractibles";
import {eqEps, eqTol} from "../../brep/geom/tolerance";
import {Polynomial} from "./polynomial";
import {NOOP} from "../../../../modules/gems/func";
export class AlgNumSubSystem {
generator = NOOP;//new BoundaryObjectsGenerator();
constraints = [];
ownParams = new Set();
readOnlyParams = new Set();
generatedParams = new Set();
beingSolvedParams = new Set();
// generators = [];
subSystems = []; //subsystems are generated by generators only
polynomials = [];
substitutedParams = [];
polyToConstr = new Map();
conflicting = new Set();
redundant = new Set();
SubSystem(generator) {
this.generator = generator;
}
addConstraint(constraint, _ancestorParams) {
if (this.canBeAdded(constraint.params)) {
// this.constraints.push(constraint);
// this.constraints
}
this.constraints.push(constraint);
}
reset() {
this.polynomials = [];
this.substitutedParams = [];
this.polyToConstr.clear();
this.conflicting.clear();
this.redundant.clear();
this.beingSolvedParams.clear();
}
evaluatePolynomials() {
this.constraints.forEach(c => {
c.collectPolynomials(this.polynomials);
this.polynomials.forEach(p => this.polyToConstr.set(p, c))
});
const toEliminate = Array.from(this.readOnlyParams);
const toSubstitute = [];
const linearSub = [];
let requirePass = true;
while (requirePass) {
requirePass = false;
for (let i = 0; i < this.polynomials.length; ++i) {
const polynomial = this.polynomials[i];
if (!polynomial) {
continue;
}
if (polynomial.monomials.length === 0) {
if (!eqEps(polynomial.constant, 0)) {
this.conflicting.add(this.polyToConstr.get(polynomial));
}
this.polynomials[i] = null;
} else if (polynomial.monomials.length === 1) {
const monomial = polynomial.monomials[0];
const terms = monomial.terms;
if (terms.length === 1) {
const term = terms[0];
if (term.fn.degree === 1) {
term.param.set(- polynomial.constant / monomial.constant);
toEliminate.push(term.param);
}
}
this.polynomials[i] = null;
} else if (polynomial.monomials.length === 2 && polynomial.isLinear) {
const [m1, m2] = polynomial.monomials;
const constant = - m2.constant / m1.constant;
if (!eqEps(polynomial.constant, 0)) {
toSubstitute.push([m1.param, m2.param, constant]);
this.substitutedParams.push([m1.param, new Polynomial().monomial(constant).addParam(m2.param)]);
} else {
// linearSub.push([m1.param, m2.param, constant, - polynomial.constant / m1.constant]);
}
this.polynomials[i] = null;
}
}
while (toEliminate.length) {
requirePass = true;
const param = toEliminate.pop();
for (let polynomial of this.polynomials) {
if (polynomial) {
polynomial.eliminate(param, param.get());
}
}
}
while (toSubstitute.length) {
requirePass = true;
const [param, toParam, dotConstant] = toSubstitute.pop();
for (let polynomial of this.polynomials) {
if (polynomial) {
polynomial.substitute(param, toParam, dotConstant);
}
}
}
if (requirePass) {
this.polynomials.forEach(polynomial => polynomial && polynomial.compact());
}
}
while (toEliminate.length || toSubstitute.length) {
// while (linearSub.length) {
// const [param, toParam, b, c] = linearSub.pop();
// for (let polynomial of polynomials) {
// if (polynomial) {
// polynomial.linerSub(param, toParam, b, c);
// }
// }
// }
}
this.polynomials = this.polynomials.filter(p => p);
}
prepare() {
this.reset();
this.evaluatePolynomials();
console.log('solving system:');
this.polynomials.forEach(p => console.log(p.toString()));
const residuals = [];
this.polynomials.forEach(p => residuals.push(p.asResidual()));
for (let residual of residuals) {
residual.params.forEach(solverParam => {
if (!this.beingSolvedParams.has(solverParam)) {
solverParam.reset(solverParam.objectParam.get());
this.beingSolvedParams.add(solverParam);
}
});
}
this.numericalSolver = prepare(residuals);
}
solve(rough) {
this.generator();
this.beingSolvedParams.forEach(solverParam => {
solverParam.set(solverParam.objectParam.get());
});
this.numericalSolver.solveSystem(rough);
this.beingSolvedParams.forEach(solverParam => {
solverParam.objectParam.set(solverParam.get());
});
for (let i = this.substitutedParams.length - 1; i >= 0; i--) {
let [param, expression] = this.substitutedParams[i];
param.set(expression.value);
}
}
canBeAdded(subjectParams, ancestorParams) {
for (let p of subjectParams) {
if (!this.ownParams.has(p) && (!ancestorParams || !ancestorParams.has(p))) {
return false;
}
}
return true;
}
}
export class AlgNumSystem {
constraints = [];
generators = [];
locked = new Set();
constantParams = new Set();
constructor(visitAllObjects) {
this.visitAllObjects = visitAllObjects;
}
addConstraint(constraint) {
this.constraints.push(constraint);
if (constraint.schema.generator) {
}
}
startTransaction(interactiveLock = []) {
this.systemTransaction.prepare(interactiveLock);
return this.systemTransaction;
}
}

View file

@ -1,99 +0,0 @@
import {R_Distance, R_DistancePP, R_PointOnLine, R_TangentLC, R_UnitVector} from "./residuals";
import {indexById} from "../../../../modules/gems/iterables";
import {distanceAB} from "../../math/math";
export const ConstraintDefinitions = indexById([
{
id: 'TangentLC',
name: 'Line & Circle Tangency',
constants: {
inverted: {
type: 'boolean',
description: 'whether the circle attached from the opposite side',
initialValue: () => false
}
},
constructibleObjects: ([line, circle]) => [line.gcLine, circle.gcCircle],
collectResiduals: (residuals, constraint) => {
const [gcLine] = constraint.objects;
residuals.push([R_TangentLC, constraint.params, [constraint.constants.inverted]]);
}
},
{
id: 'PointOnLine',
name: 'Point On Line',
constructibleObjects: ([point, line]) => [point.gcPoint, line.gcLine],
collectResiduals: (residuals, constraint) => {
residuals.push([R_PointOnLine, constraint.params, []]);
}
},
{
id: 'DistancePP',
name: 'Distance Between Two Point',
constants: {
distance: {
type: 'number',
description: 'the distance between two points',
initialValue: (constraint) => {
const [a, b] = constraint.object;
return distanceAB(a, b)
}
}
},
constructibleObjects: ([p1, p2]) => [p1.gcPoint, p2.gcPoint],
collectResiduals: (residuals, constraint) => {
residuals.push([R_DistancePP, constraint.params, [constraint.constants.distance]]);
}
},
]);
export class SEACConstraint {
static Counter = 0;
constructor(schema, attachedObjects, constants) {
this.id = schema.id + ':' + (SEACConstraint.Counter ++); // only for debug purposes - not persisted
this.attachedObjects = attachedObjects;
this.objects = schema.constructibleObjects(attachedObjects);
this.constants = constants;
this.objects.forEach(o => {
o.constraints.push(this);
});
this.internal = false;
this.schema = schema;
}
collectParams(params) {
this.objects.forEach(o => o.collectParams(params));
}
get params() {
const params = [];
this.collectParams(params);
return params;
}
visitAdjacentConstraints(fn) {
this.objects.forEach(o => o.constraints.forEach(fn));
}
collectResiduals(out) {
return this.schema.collectResiduals(out, this);
}
}

View file

@ -1,291 +0,0 @@
import {createByConstraintName} from "./solverConstraints";
import {Param, prepare} from "./solver";
import {findConstructionCluster} from "./constructions";
import {GCCircle, GCPoint} from "./constractibles";
const ConstraintDegree = {
PARTIALLY_SOLVABLE: 1,
NOT_SOLVABLE: 2,
SOLVABLE: 3
};
export class SEACSystem {
constraints = [];
locked = new Set();
systemTransaction = new SystemTransaction(this);
addConstraint(constraint) {
this.constraints.push(constraint);
}
startTransaction(interactiveLock = []) {
this.systemTransaction.prepare(interactiveLock);
return this.systemTransaction;
}
}
export class SystemTransaction {
locked = new Set();
scheduled = new Map();
internalObjects = new Set();
decayedObjects = new Set();
clusters = [];
constructor(system) {
this.system = system;
}
constraintDegree(constraint) {
let hasNonFreeAgents = false;
let hasFreeAgents = false;
for (let obj of constraint.objects) {
if (this.isLocked(obj) || this.decayedObjects.has(obj)) {
hasNonFreeAgents = true;
} else {
hasFreeAgents = true;
}
}
if (hasNonFreeAgents && hasFreeAgents) {
return ConstraintDegree.PARTIALLY_SOLVABLE;
} else if (hasNonFreeAgents) {
return ConstraintDegree.NOT_SOLVABLE;
} else {
return ConstraintDegree.SOLVABLE;
}
}
findClusterForIsolated(constraint) {
for (let i = this.clusters.length - 1; i >= 0; i--) {
const cluster = this.clusters[i];
if (constraint.objects.find(o => cluster.ownObjects.has(o))) {
return cluster;
}
}
console.log(`constraint ${constraint.id} can't be solved and will be skipped, most likely it's attached to read only geometry only`);
return null;
}
createCluster(constraints = []) {
const cluster = new Cluster(this, constraints);
this.clusters.push(cluster);
return cluster;
}
lock(object) {
this.locked.add(object);
}
isLocked = object => {
return this.locked.has(object);
};
schedule(constr, cluster) {
this.scheduled.set(constr, cluster);
}
isScheduled = constr => {
return this.scheduled.has(constr);
};
prepare(interactiveLock) {
const schedule = queue => {
for (let constr of queue) {
if (this.isScheduled(constr)) {
continue; // we're cool - solved as a part of construction cluster
}
let clusterConstraints = findConstructionCluster(constr, this.isScheduled);
clusterConstraints.forEach((c, i) => {
if (this.constraintDegree(c) === ConstraintDegree.NOT_SOLVABLE) {
console.log('isolation detected for constraint ' + constr.id);
const neighbour = this.findClusterForIsolated(c);
if (!neighbour) {
console.warn('unable to resolve isolation for constraint ' + constr.id);
return;
}
neighbour.add(c);
clusterConstraints[i] = null;
}
});
clusterConstraints = clusterConstraints.filter(c => c !== null);
if (clusterConstraints.length) {
this.createCluster(clusterConstraints);
}
}
};
this.cleanup();
interactiveLock.forEach(l => this.locked.add(l));
this.system.locked.forEach(l => this.locked.add(l));
this.system.constraints.forEach(c => c.objects.forEach(o => o.visitChildren( c => {
this.internalObjects.add(c);
if (this.isLocked(c)) {
this.decayedObjects.add(o);
}
} )) );
const queue = [...this.system.constraints];
const constraintRank = constr => {
const pureSEAC = !constr.objects.find(o => o instanceof GCPoint);
const hasLocks = !!constr.objects.find(o => this.locked.has(o) || this.decayedObjects.has(o));
const referToInternals = !!constr.objects.find(o => this.internalObjects.has(o));
let rank = 0;
if (referToInternals) {
rank += 1000;
}
if (!pureSEAC) {
rank += 100
}
if (!hasLocks) {
rank += 10;
}
return rank;
};
queue.sort((a,b) => constraintRank(a) - constraintRank(b));
schedule(queue);
console.log("SOLVER SCHEDULING RESULTS:");
console.dir(this.clusters);
this.clusterTransactions = this.clusters.map(cluster => cluster.startTransaction());
}
cleanup() {
this.locked.clear();
this.scheduled.clear();
this.internalObjects.clear();
this.decayedObjects.clear();
this.clusters = [];
this.clusterTransactions = undefined;
}
relaxObjects() {
this.clusterTransactions.forEach(ct => {
ct.cluster.ownObjects.forEach(o => {
if (o instanceof GCCircle) {
if (o.r.get() <= 5) {
o.r.set(20);
}
}
});
});
}
solve = rough => {
this.relaxObjects();
this.clusterTransactions.forEach(t => t.solve(rough));
}
}
class Cluster {
constructor(systemTransaction, constraints) {
this.systemTransaction = systemTransaction;
this.constraints = [];
this.ownObjects = new Set();
constraints.forEach(c => this.add(c));
}
consumeObject(o) {
this.systemTransaction.lock(o);
this.ownObjects.add(o);
}
add(constraint) {
this.systemTransaction.schedule(constraint, this);
constraint.objects.forEach(o => {
if (!this.systemTransaction.isLocked(o)) {
this.consumeObject(o);
o.visitChildren(c => {
if (!this.systemTransaction.isLocked(c)) {
this.consumeObject(c);
}
});
}
});
this.constraints.push(constraint);
}
get capacity() {
return this.constraints.length;
}
startTransaction() {
const residuals = [];
const solverConstrs = [];
const transState = new TransactionState();
this.constraints.forEach(c => c.collectResiduals(residuals));
for (let i = 0; i < residuals.length; ++i) {
const [fn, gcParams, constants] = residuals[i];
const solverParams = gcParams.map(gcParam => {
const solverParam = transState.createSolverParam(gcParam);
solverParam.constant = !this.ownObjects.has(gcParam.object);
return solverParam;
});
const constr = fn(solverParams, constants);
solverConstrs.push(constr);
}
const solver = prepare(solverConstrs);
return new ClusterTransaction(solver, transState, this);
}
}
class TransactionState {
paramMap = new Map();
createSolverParam(gcParam) {
let solverParam = this.paramMap.get(gcParam);
if (!solverParam) {
solverParam = new Param(gcParam.get());
this.paramMap.set(gcParam, solverParam);
}
return solverParam;
}
}
class ClusterTransaction {
constructor(solver, state, cluster) {
this.solver = solver;
this.state = state;
this.cluster = cluster;
}
solve(rough) {
this.state.paramMap.forEach((solverParam, gcParam) => {
solverParam.reset(gcParam.get());
});
this.solver.solveSystem(rough);
this.state.paramMap.forEach((solverParam, gcParam) => {
if (!solverParam.constant) {
gcParam.set(solverParam.get());
}
});
}
}

View file

@ -1,4 +1,3 @@
import {Param} from "./solver";
import {Generator} from "../id-generator";
export class ContractibleObject {
@ -6,28 +5,46 @@ export class ContractibleObject {
constraints = [];
constructor() {
}
createParam(value) {
return new GCParam(this, value);
this.id = Generator.genID();
}
collectParams(out) {
this.visitParams(p => out.push(p));
}
init() {};
visitParams() {};
visitChildren() {};
traverse(visitor) {
visitor(this);
}
write() {
const out = [];
this.visitChildren(c => out.push(c.id));
return out;
}
read(data, resolve) {
this.init.apply(this, data.map(resolve));
}
}
export class GCPoint extends ContractibleObject {
constructor() {
super();
this.x = this.createParam(0);
this.y = this.createParam(0);
static TYPE = 'GCPoint';
static newInstance(x = 0, y = 0) {
return new GCPoint().init(new GCParam(x), new GCParam(y));
}
init(x, y) {
this.x = x;
this.y = y;
return this;
}
visitParams(visitor) {
@ -35,14 +52,35 @@ export class GCPoint extends ContractibleObject {
visitor(this.y);
}
visitChildren(visitor) {
visitor(this.x);
visitor(this.y);
}
traverse(visitor) {
super.traverse(visitor);
this.x.traverse(visitor);
this.y.traverse(visitor);
}
write() {
return [this.x.id, this.y.id];
}
}
export class GCLine extends ContractibleObject {
constructor() {
super();
this.ang = this.createParam(0);
this.w = this.createParam(0);
static TYPE = 'GCLine';
static newInstance(ang = 0, w = 0) {
return new GCLine().init(new GCParam(ang), new GCParam(w));
}
init(ang, w) {
this.ang = ang;
this.w = w;
return this;
}
visitParams(visitor) {
@ -50,14 +88,31 @@ export class GCLine extends ContractibleObject {
visitor(this.w);
}
visitChildren(visitor) {
visitor(this.ang);
visitor(this.w);
}
traverse(visitor) {
super.traverse(visitor);
this.ang.traverse(visitor)
this.w.traverse(visitor)
}
}
export class GCCircle extends ContractibleObject {
constructor() {
super();
this.c = new GCPoint();
this.r = this.createParam(0);
static TYPE = 'GCCircle';
static newInstance(x, y, r) {
return GCCircle().init(new GCPoint(x, y), new GCParam(r))
}
init(c, r) {
this.c = c;
this.r = r;
return this;
}
visitParams(visitor) {
@ -67,14 +122,27 @@ export class GCCircle extends ContractibleObject {
visitChildren(visitor) {
visitor(this.c);
visitor(this.r);
}
traverse(visitor) {
visitor(this);
this.c.traverse(visitor);
this.r.traverse(visitor);
}
}
export class GCParam {
export class GCParam extends ContractibleObject {
constructor(object, value) {
this.object = object;
static TYPE = 'GCParam';
static newInstance(value = 0) {
return new GCParam(value);
}
constructor(value) {
super();
this.value = value;
}
@ -86,4 +154,28 @@ export class GCParam {
return this.value;
}
}
visitChildren(visitor) {
}
visitParams(visitor) {
visitor(this);
}
write() {
return this.value;
}
read(data) {
this.value = data;
}
}
export const GC_TYPES = {
[GCParam.TYPE]: GCParam,
[GCPoint.TYPE]: GCPoint,
[GCLine.TYPE]: GCLine,
[GCCircle.TYPE]: GCCircle
};

View file

@ -0,0 +1,348 @@
import {eqEps} from "../../brep/geom/tolerance";
import {sq} from "../../math/math";
export class Polynomial {
monomials = [];
constant = 0;
constructor(constant) {
this.constant = constant;
}
term(p, fn) {
this.monomials[this.monomials.length - 1].addParam(p, fn);
return this;
}
monomial(k = 1) {
this.monomials.push(new Monomial(k));
return this;
}
eliminate(param, value) {
for (let m of this.monomials) {
for (let i = 0; i < m.terms.length; ++i) {
if (m.terms[i].param === param) {
m.eliminate(i, value);
}
}
}
}
substitute(param, toParam, dotConstant) {
for (let m of this.monomials) {
for (let i = 0; i < m.terms.length; ++i) {
if (m.terms[i].param === param) {
m.substitute(i, toParam, dotConstant);
}
}
}
}
linerSub(param, toParam, b, c) {
// for (let m of this.monomials) {
// for (let i = 0; i < m.terms.length; ++i) {
// if (m.terms[i].param === param) {
// m.substitute(i, toParam, dotConstant);
// }
// }
// }
}
compact() {
for (let i = 0; i < this.monomials.length; ++i) {
const m1 = this.monomials[i];
if (m1 === null) {
continue;
}
for (let j = i + 1; j < this.monomials.length; ++j) {
const m2 = this.monomials[j];
if (m2 === null) {
continue;
}
if (m1.equalVars(m2)) {
m1.constant += m2.constant;
this.monomials[j] = null;
}
}
if (eqEps(m1.constant, 0)) {
this.monomials[i] = null;
} else if (m1.terms.length === 0) {
this.constant += m1.constant;
this.monomials[i] = null;
}
}
this.monomials = this.monomials.filter(m => m !== null);
}
get isLinear() {
for (let m of this.monomials) {
if (m.terms.length !== 1 || m.terms[0].fn.degree !== 1) {
return false;
}
}
return true;
}
value(valueFn = GET_VALUE) {
let res = this.constant;
for (let m of this.monomials) {
res += m.value(valueFn);
}
return res;
}
asResidual() {
const paramsSet = new Set();
for (let m of this.monomials) {
for (let t of m.terms) {
paramsSet.add(t.param.solverParam);
}
}
const params = Array.from(paramsSet);
const solverValue = p => p.solverParam.get();
return {
params,
error: () => this.value(solverValue),
gradient: out => {
for (let i = 0; i < params.length; i++) {
out[i] = 0;
for (let m of this.monomials) {
out[i] += m.differentiate(params[i].objectParam, solverValue);
}
}
},
};
}
toString() {
return this.monomials.map(m => {
let out = '';
if (m.constant === 1) {
out += '+';
} else if (m.constant === -1) {
out += '-';
} else {
out += (m.constant >= 0 ? '+' : '') + m.constant.toFixed(2);
if (m.terms.length) {
out += '*';
}
}
out += m.terms.map(t => {
let out = 'X' + t.param.id;
if (t.fn.degree === 1) {
} else if (t.fn.degree !== Infinity) {
out += t.fn.id;
} else {
out = t.fn.id + '(' + out + ')';
}
return out;
}).join('*');
return out;
}
).join(' ') + (this.constant >= 0 ? ' + ' : ' ') + this.constant.toFixed(2);
}
}
export class Monomial {
terms = [];
constant = 1;
constructor(constant) {
this.constant = constant;
}
addParam(param, fn) {
this.terms.push({param, fn});
this.terms.sort(t => t.param.id);
}
eliminate(i, value) {
const fn = this.terms[i].fn;
this.constant *= fn.apply(value);
this.terms.splice(i, 1);
}
substitute(i, toParam, dotConstant) {
this.constant *= dotConstant;
let wasMerge = false;
for (let i = 0; i < this.terms.length; ++i) {
const merger = this.terms[i];
if (!merger) {
continue;
}
for (let j = i + 1; j < this.terms.length; ++j) {
const term = this.terms[j];
if (merger.param === term.param) {
let mergedFn = merger.fn.merge(term.fn);
if (mergedFn) {
merger.fn = mergedFn;
this.terms[j] = null;
wasMerge = true;
}
}
}
}
if (wasMerge) {
this.terms = this.terms.filter(t => t);
}
}
equalVars(other) {
if (this.terms.length !== other.terms.length) {
return false;
}
for (let i = 0; i < this.terms.length; ++i) {
const t1 = this.terms[i];
const t2 = other.terms[i];
if (t1.fn.id !== t2.fn.id || t1.param.id !== t2.param.id) {
return false;
}
}
return true;
}
differentiate(partialParam, valueFn = GET_VALUE) {
let cnst = this.constant;
let diffProduct = 0;
let freeProduct = 1;
for (let term of this.terms) {
const pVal = valueFn(term.param);
const d0 = term.fn.apply(pVal);
if (partialParam === term.param) {
const d1 = term.fn.derivative1(pVal);
diffProduct = diffProduct*d0 + freeProduct * d1;
freeProduct *= d0;
} else {
cnst *= d0;
}
}
return cnst * diffProduct;
}
value(valueFn) {
let res = this.constant;
for (let t of this.terms) {
res *= t.fn.apply(valueFn(t.param));
}
return res;
}
}
export class ToThePowerFunction {
degree = 1;
static get(degree) {
switch (degree) {
case 0: return POW_0_FN;
case 1: return POW_1_FN;
case 2: return POW_2_FN;
case 3: return POW_3_FN;
case 4: return POW_4_FN;
default: return new ToThePowerFunction(degree, x => {
let val = 1;
for (let i = 0; i < degree; ++i) {
val *= x;
}
return val
})
}
}
constructor(degree, fn, d1) {
this.fn = fn;
this.d1 = d1;
this.id = '^' + degree;
}
apply(x) {
return this.fn(x);
}
merge(fn) {
if (fn.constructor.name === this.constructor.name) {
return ToThePowerFunction.get(fn.degree + this.degree);
}
return null;
}
derivative1(x) {
return this.d1(x)
}
}
export class FreeFunction {
fn;
constructor(fn, d1, id) {
this.fn = fn;
this.d1 = d1;
this.id = id;
}
apply(x) {
return this.fn(x);
}
get degree() {
return Infinity;
}
merge(fn) {
return null;
}
derivative1(x) {
return this.d1(x)
}
}
const GET_VALUE = param => param.get();
export const POW_0_FN = new ToThePowerFunction(0, x => 1, x => 0);
export const POW_1_FN = new ToThePowerFunction(1, x => x, x => 1);
export const POW_2_FN = new ToThePowerFunction(2, x => x*x, x => 2*x);
export const POW_3_FN = new ToThePowerFunction(3, x => x*x*x, x => 3*x*x);
export const POW_4_FN = new ToThePowerFunction(3, x => x*x*x*x, x => 4*x*x*x);
export const COS_FN = new FreeFunction(x => Math.cos(x), x => -Math.sin(x), 'cos');
export const SIN_FN = new FreeFunction(x => Math.sin(x), x => Math.cos(x), 'sin');

View file

@ -1,6 +1,19 @@
import {NumericGradient} from "./solverConstraints";
import {sq} from "../../math/math";
export function R_Equal(params, [value]) {
return {
params,
error: () => params[0].get() - value,
gradient: out => {
out[0] = 1;
}
};
}
export function R_TangentLC(params, [inverted]) {
const ANG = 0;

View file

@ -7,14 +7,15 @@ import {dog_leg} from '../../math/optim'
import {newVector} from '../../math/vec';
/** @constructor */
function Param(value) {
function Param(value, objectParam) {
this.reset(value);
this.constant = false;
this.j = -1;
this.objectParam = objectParam;
}
Param.prototype.reset = function(value) {
this.value = value;
this.set(value);
this.constant = false;
this.j = -1;
};
Param.prototype.set = function(value) {

View file

@ -0,0 +1,5 @@
export function boundaryGenerator() {
}

View file

@ -16,9 +16,10 @@ import exportTextData from 'gems/exportTextData';
import NurbsCurve from '../brep/geom/curves/nurbsCurve';
import {NurbsObject} from './shapes/nurbsObject';
import {System} from './system';
import {AlgNumConstraint} from "./constr/ANConstraints";
const Types = {
END_POINT : 'TCAD.TWO.EndPoint',
POINT : 'TCAD.TWO.EndPoint',
SEGMENT : 'TCAD.TWO.Segment',
ARC : 'TCAD.TWO.Arc',
CIRCLE : 'TCAD.TWO.Circle',
@ -51,22 +52,22 @@ IO.prototype._loadSketch = function(sketch) {
this.cleanUpData();
var index = {};
const index = {};
function endPoint(p) {
var id = p[0];
var ep = index[id];
const [id, [xref, x], [yref, y]] = p;
let ep = index[id];
if (ep !== undefined) {
return
return;
}
ep = new EndPoint(p[1][1], p[2][1]);
index[p[1][0]] = ep._x;
index[p[2][0]] = ep._y;
ep = new EndPoint(x, y);
index[xref] = ep.params.x;
index[yref] = ep.params.y;
index[id] = ep;
return ep;
}
var layerIdGen = 0;
let layerIdGen = 0;
function getLayer(viewer, name) {
if (name === undefined) {
name = "layer_" + layerIdGen++;
@ -74,7 +75,7 @@ IO.prototype._loadSketch = function(sketch) {
if (name === viewer.dimLayer.name) {
return viewer.dimLayer;
}
for (var i = 0; i < viewer.layers.length; ++i) {
for (let i = 0; i < viewer.layers.length; ++i) {
if (name === viewer.layers[i].name) {
return viewer.layers[i];
}
@ -84,6 +85,7 @@ IO.prototype._loadSketch = function(sketch) {
viewer.layers.push(layer);
return layer;
}
const version = sketch.version || 1;
var T = Types;
var maxEdge = 0;
var sketchLayers = sketch['layers'];
@ -93,7 +95,7 @@ IO.prototype._loadSketch = function(sketch) {
for (var l = 0; l < sketchLayers.length; ++l) {
var ioLayer = sketchLayers[l];
var layerName = ioLayer['name'];
var boundaryProcessing = layerName == IO.BOUNDARY_LAYER_NAME && boundaryNeedsUpdate;
var boundaryProcessing = layerName === IO.BOUNDARY_LAYER_NAME && boundaryNeedsUpdate;
var layer = getLayer(this.viewer, layerName);
if (!!ioLayer.style) layer.style = ioLayer.style;
layer.readOnly = !!ioLayer.readOnly;
@ -111,28 +113,28 @@ IO.prototype._loadSketch = function(sketch) {
}
if (boundaryProcessing) {
if (_class === T.SEGMENT && boundary.lines.length == 0) continue;
else if (_class === T.ARC && boundary.arcs.length == 0) continue;
else if (_class === T.CIRCLE && boundary.circles.length == 0) continue;
if (_class === T.SEGMENT && boundary.lines.length === 0) continue;
else if (_class === T.ARC && boundary.arcs.length === 0) continue;
else if (_class === T.CIRCLE && boundary.circles.length === 0) continue;
}
if (_class === T.SEGMENT) {
const points = obj['points'];
const a = endPoint(points[0]);
const b = endPoint(points[1]);
const [aRef, bRef] = obj.points;
const a = endPoint(aRef);
const b = endPoint(bRef);
skobj = new Segment(a, b);
} else if (_class === T.END_POINT) {
skobj = endPoint(obj['location']);
} else if (_class === T.POINT) {
skobj = endPoint(obj.location);
} else if (_class === T.ARC) {
const points = obj['points'];
const points = obj.points;
const a = endPoint(points[0]);
const b = endPoint(points[1]);
const c = endPoint(points[2]);
skobj = new Arc(a, b, c);
} else if (_class === T.CIRCLE) {
const c = endPoint(obj['c']);
const c = endPoint(obj.c);
skobj = new Circle(c);
skobj.r.set(obj['r']);
skobj.r.set(obj.r);
} else if (_class === T.ELLIPSE) {
const ep1 = endPoint(obj['ep1']);
const ep2 = endPoint(obj['ep2']);
@ -214,8 +216,12 @@ IO.prototype._loadSketch = function(sketch) {
if (sketchConstraints !== undefined) {
for (var i = 0; i < sketchConstraints.length; ++i) {
try {
const c = this.parseConstr(sketchConstraints[i], index);
this.viewer.parametricManager._add(c);
if (version > 1) {
this.viewer.parametricManager.algnNumSystem.addConstraint(AlgNumConstraint.read(sketchConstraints[i], index));
} else {
const c = this.parseConstr(sketchConstraints[i], index);
this.viewer.parametricManager._add(c);
}
} catch (msg) {
console.info("Skipping. " + msg);
}
@ -232,7 +238,7 @@ IO.prototype.linkEndPoints = function(objects) {
const index = HashTable.forVector2d();
for (let obj of objects) {
obj.accept((o) => {
if (o._class == Types.END_POINT) {
if (o._class == Types.POINT) {
const equalPoint = index.get(o);
if (equalPoint == null) {
index.put(o, o);
@ -336,9 +342,9 @@ IO.prototype.cleanUpData = function() {
IO.prototype._serializeSketch = function(metadata) {
var sketch = {};
//sketch.boundary = boundary;
sketch['layers'] = [];
sketch.layers = [];
function point(p) {
return [ p.id, [p._x.id, p.x], [p._y.id, p.y] ];
return [ p.id, [p.params.x.id, p.x], [p.params.y.id, p.y] ];
}
var T = Types;
var toSave = [this.viewer.dimLayers, this.viewer.layers];
@ -346,76 +352,74 @@ IO.prototype._serializeSketch = function(metadata) {
var layers = toSave[t];
for (var l = 0; l < layers.length; ++l) {
var layer = layers[l];
var toLayer = {'name' : layer.name, style : layer.style, readOnly: layer.readOnly, 'data' : []};
sketch['layers'].push(toLayer);
var toLayer = {name : layer.name, style : layer.style, readOnly: layer.readOnly, data : []};
sketch.layers.push(toLayer);
for (var i = 0; i < layer.objects.length; ++i) {
var obj = layer.objects[i];
var to = {'id': obj.id, '_class': obj._class, role: obj.role};
var to = {id: obj.id, _class: obj._class, role: obj.role};
if (obj.aux) to.aux = obj.aux;
if (obj.edge !== undefined) to.edge = obj.edge;
toLayer['data'].push(to);
toLayer.data.push(to);
if (obj._class === T.SEGMENT) {
to['points'] = [point(obj.a), point(obj.b)];
} else if (obj._class === T.END_POINT) {
to['location'] = point(obj);
to.points = [point(obj.a), point(obj.b)];
} else if (obj._class === T.POINT) {
to.location = point(obj);
} else if (obj._class === T.ARC) {
to['points'] = [point(obj.a), point(obj.b), point(obj.c)];
to.points = [point(obj.a), point(obj.b), point(obj.c)];
} else if (obj._class === T.CIRCLE) {
to['c'] = point(obj.c);
to['r'] = obj.r.get();
to.c = point(obj.c);
to.r = obj.r.get();
} else if (obj._class === T.ELLIPSE) {
to['ep1'] = point(obj.ep1);
to['ep2'] = point(obj.ep2);
to['r'] = obj.r.get();
to.ep1 = point(obj.ep1);
to.ep2 = point(obj.ep2);
to.r = obj.r.get();
} else if (obj._class === T.ELL_ARC) {
to['ep1'] = point(obj.ep1);
to['ep2'] = point(obj.ep2);
to['a'] = point(obj.a);
to['b'] = point(obj.b);
to['r'] = obj.r.get();
to.ep1 = point(obj.ep1);
to.ep2 = point(obj.ep2);
to.a = point(obj.a);
to.b = point(obj.b);
to.r = obj.r.get();
} else if (obj._class === T.BEZIER) {
to['a'] = point(obj.a);
to['b'] = point(obj.b);
to['cp1'] = point(obj.cp1);
to['cp2'] = point(obj.cp2);
to.a = point(obj.a);
to.b = point(obj.b);
to.cp1 = point(obj.cp1);
to.cp2 = point(obj.cp2);
} else if (obj._class === T.DIM || obj._class === T.HDIM || obj._class === T.VDIM) {
to['a'] = obj.a.id;
to['b'] = obj.b.id;
to['flip'] = obj.flip;
to.a = obj.a.id;
to.b = obj.b.id;
to.flip = obj.flip;
} else if (obj._class === T.DDIM) {
to['obj'] = obj.obj.id;
to.obj = obj.obj.id;
}
const children = nonPointChildren(obj).map(c => c.id);
if (children.length != 0) {
to['children'] = children;
if (children.length !== 0) {
to.children = children;
}
}
}
}
var constrs = sketch['constraints'] = [];
var subSystems = this.viewer.parametricManager.system.subSystems;
for (var j = 0; j < subSystems.length; j++) {
var sub = subSystems[j];
for (i = 0; i < sub.constraints.length; ++i) {
if (!sub.constraints[i].aux) {
constrs.push(this.serializeConstr(sub.constraints[i]));
}
sketch.constraints = [];
const systemConstraints = this.viewer.parametricManager.algnNumSystem.constraints;
for (let sc of systemConstraints) {
if (!sc.internal) {
sketch.constraints.push(sc.write());
}
}
var constantDefinition = this.viewer.params.constantDefinition;
if (constantDefinition !== undefined && constantDefinition != null && !/^\s*$/.test(constantDefinition)) {
sketch['constants'] = constantDefinition;
sketch.constants = constantDefinition;
}
sketch.metadata = metadata;
sketch.version = 2;
return sketch;
};
function nonPointChildren(obj){
const children = [];
obj.accept((o) => {
if (o._class !== Types.END_POINT) {
if (o._class !== Types.POINT) {
children.push(o);
}
return true;
@ -440,9 +444,6 @@ IO.prototype.parseConstr = function (c, index) {
return constrCreate(find, ps);
};
IO.prototype.serializeConstr = function (c) {
return c.serialize();
};
function _format(str, args) {
if (args.length == 0) return str;
@ -499,7 +500,7 @@ function BBox() {
if (obj._class === T.SEGMENT) {
this.checkBounds(obj.a.x, obj.a.y);
this.checkBounds(obj.b.x, obj.b.y);
} else if (obj._class === T.END_POINT) {
} else if (obj._class === T.POINT) {
this.checkBounds(obj.x, obj.y);
} else if (obj._class === T.ARC) {
this.checkCircBounds(obj.c.x, obj.c.y, obj.r.get());
@ -509,7 +510,7 @@ function BBox() {
this.checkCircBounds(obj.centerX, obj.centerY, Math.max(obj.radiusX, obj.radiusY));
} else if (obj) {
obj.accept((o) => {
if (o._class == T.END_POINT) {
if (o._class == T.POINT) {
this.checkBounds(o.x, o.y);
}
return true;
@ -589,7 +590,7 @@ IO.prototype.svgExport = function () {
out.fline('<g id="$" fill="$" stroke="$" stroke-width="$">', [layer.name, "none", color, '2']);
for (var i = 0; i < layer.objects.length; ++i) {
var obj = layer.objects[i];
if (obj._class !== T.END_POINT) bbox.check(obj);
if (obj._class !== T.POINT) bbox.check(obj);
if (obj._class === T.SEGMENT) {
out.fline('<line x1="$" y1="$" x2="$" y2="$" />', [obj.a.x, obj.a.y, obj.b.x, obj.b.y]);
} else if (obj._class === T.ARC) {
@ -686,7 +687,7 @@ IO.prototype.dxfExport = function () {
var layer = toExport[l];
for (i = 0; i < layer.objects.length; ++i) {
var obj = layer.objects[i];
if (obj._class === T.END_POINT) {
if (obj._class === T.POINT) {
out.line("0");
out.line("POINT");
out.line("8");

View file

@ -14,7 +14,7 @@ class ParametricManager {
constructor(viewer) {
this.viewer = viewer;
this.system = new System();
this.seacSystem = new SEACSystem();
this.algnNumSystem = new AlgNumSubSystem();
this.constantTable = {};
this.viewer.params.define('constantDefinition', null);
@ -23,55 +23,76 @@ class ParametricManager {
this.externalConstantResolver = null;
this.messageSink = msg => alert(msg);
setTimeout(() => {
let s1 = viewer.addSegment(100, 100, 300, 300, viewer.activeLayer);
let s2 = viewer.addSegment(200, 100, 400, 300, viewer.activeLayer);
let c1 = new Circle(new EndPoint(500, 500));
c1.r.set(500);
viewer.add(c1, viewer.activeLayer);
let c2 = new Circle(new EndPoint(0, 0));
c2.r.set(50);
viewer.add(c2, viewer.activeLayer);
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s1, c1], {
inverted: false
}));
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s2, c1], {
inverted: true
}));
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s1, c2], {
inverted: false
}));
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s2, c2], {
inverted: true
}));
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.PointOnLine, [s1.a, s1]));
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.PointOnLine, [s1.b, s1]));
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.PointOnLine, [s2.a, s2]));
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.PointOnLine, [s2.b, s2]));
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.DistancePP, [s1.a, s1.b], {
distance: 350
}));
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.DistancePP, [s2.a, s2.b], {
distance: 500
}));
this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.DistancePP, [c1.c, c2.c], {
distance: 700
}));
this.refresh();
});
// setTimeout(() => {
//
// let s1 = viewer.addSegment(-100, 0, -100, 600, viewer.activeLayer);
// let s2 = viewer.addSegment(700, 0, 700, 600, viewer.activeLayer);
//
// let s3 = viewer.addSegment(0, -100, 600, -100, viewer.activeLayer);
// let s4 = viewer.addSegment(0, 700, 600, 700, viewer.activeLayer);
//
// const newCircle = (cx, cy) => {
// let c1 = new Circle(new EndPoint(cx, cy));
// c1.r.set(100);
// viewer.add(c1, viewer.activeLayer);
// return c1;
// };
//
// const c1 = newCircle(600, 600);
//
// let c2 = newCircle(0, 0);
//
//
// let c3 = newCircle(600, 0);
// let c4 = newCircle(0, 600);
//
// //
// // this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s1, c4], {
// // inverted: true
// // }));
// // this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s1, c2], {
// // inverted: true
// // }));
// // this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s2, c1], {
// // inverted: false
// // }));
// // this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s2, c3], {
// // inverted: false
// // }));
// //
// // this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s4, c4], {
// // inverted: true
// // }));
// //
// // this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s4, c1], {
// // inverted: true
// // }));
// //
// //
// // this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s3, c2], {
// // inverted: false
// // }));
// //
// // this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.TangentLC, [s3, c3], {
// // inverted: false
// // }));
//
//
//
// //
// // this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.DistancePP, [s1.a, s1.b], {
// // distance: 350
// // }));
//
//
// // this.seacSystem.addConstraint(new SEACConstraint(ConstraintDefinitions.DistancePP, [s2.a, s2.b], {
// // distance: 500
// // }));
//
//
// this.refresh();
//
// });
}
@ -79,8 +100,8 @@ class ParametricManager {
return this.system.subSystems;
}
addSEAC(constr) {
this.seacSystem.addConstraint(constr);
addAlgNum(constr) {
this.algnNumSystem.addConstraint(constr);
this.refresh();
}
@ -336,7 +357,14 @@ ParametricManager.prototype.tangent = function(objs) {
this.add(new Constraints.CurveTangent(lines[0], curves[0]));
} else {
const arcs = fetch.generic(objs, ['TCAD.TWO.Arc', 'TCAD.TWO.Circle'], 1);
this.addSEAC(new TangentLC(lines[0], arcs[0], falses));
this.addAlgNum(
new AlgNumConstraint(ConstraintDefinitions.TangentLC, [lines[0], arcs[0]], {
inverted: false
}
)
);
}
};
@ -537,10 +565,21 @@ ParametricManager.prototype.findCoincidentConstraint = function(point1, point2)
};
ParametricManager.prototype.coincident = function(objs) {
if (objs.length == 0) return;
this.linkObjects(objs);
this.solve();
this.viewer.refresh();
const [first, ...others] = objs;
for (let obj of others) {
this.algnNumSystem.addConstraint(
new AlgNumConstraint(ConstraintDefinitions.PCoincident, [first, obj])
);
}
this.refresh();
// if (objs.length === 0) return;
// this.linkObjects(objs);
// this.solve();
// this.viewer.refresh();
};
ParametricManager.prototype.getSolveData = function() {
@ -563,9 +602,9 @@ ParametricManager.prototype.__getSolveData = function(constraints, out) {
return out;
};
ParametricManager.prototype.solve = function(lock, extraConstraints, disabledObjects) {
const solver = this.prepare(lock, extraConstraints, disabledObjects);
solver.solve(false);
ParametricManager.prototype.solve = function() {
this.algnNumSystem.prepare();
this.algnNumSystem.solve(false);
};
ParametricManager.prototype.prepare = function(locked, extraConstraints, disabledObjects) {
@ -949,8 +988,8 @@ ParametricManager.prototype.updateConstraintConstants = function(constr) {
import {Constraints} from './constraints';
import {askNumber} from '../utils/utils';
import {SEACSystem} from "./constr/SEACSystem";
import {ConstraintDefinitions, SEACConstraint, TangentLC} from "./constr/SEACConstraints";
import {ConstraintDefinitions, AlgNumConstraint, TangentLC} from "./constr/ANConstraints";
import {Circle} from "./shapes/circle";
import {EndPoint} from "./shapes/point";
import {AlgNumSubSystem} from "./constr/AlgNumSystem";
export {Constraints, ParametricManager}

View file

@ -0,0 +1,26 @@
export function SelectionMatcher() {
const lowerBounds = [];
return {
moreThan(amount, type) {
lowerBounds.push(amount, type);
return this;
},
match: selection => {
for (let [amount, type] of lowerBounds) {
}
}
}
}

View file

@ -4,6 +4,7 @@ import Vector from 'math/vector';
import {Ref} from './ref'
import {Constraints} from '../parametric'
import {pointIterator, SketchObject} from './sketch-object';
import {EndPoint} from "./point";
export class Arc extends SketchObject {
@ -140,3 +141,4 @@ export class Arc extends SketchObject {
}
Arc.prototype._class = 'TCAD.TWO.Arc';
Arc.prototype.TYPE = 'ARC';

View file

@ -6,6 +6,8 @@ import {ConvexHull2D} from '../../math/convex-hull'
import * as draw_utils from '../shapes/draw-utils'
import * as math from '../../math/math';
import {Arc} from "./arc";
import {EndPoint} from "./point";
export class BezierCurve extends SketchObject {
@ -77,5 +79,6 @@ export class BezierCurve extends SketchObject {
}
}
BezierCurve.prototype._class = 'TCAD.TWO.BezierCurve';
BezierCurve.prototype.TYPE = 'BEZIER';
const RECOVER_LENGTH = 100;

View file

@ -5,18 +5,16 @@ import {EditCircleTool} from '../tools/circle'
import {EndPoint} from './point'
import {Ref} from './ref'
import {SketchObject} from './sketch-object'
import {GCCircle} from "../constr/constractibles";
export class Circle extends SketchObject {
constructor(c) {
super();
this.gcCircle = new GCCircle();
this.c = c;
c.parent = this;
this.children.push(c);
this.r = this.gcCircle.r;
this.c.coincideWith(this.gcCircle.c)
this.r = new Ref(0);
this.r.obj = this;
}
visitParams(callback) {
@ -34,7 +32,7 @@ export class Circle extends SketchObject {
drawImpl(ctx, scale) {
ctx.beginPath();
ctx.arc(this.gcCircle.c.x.get(), this.gcCircle.c.y.get(), this.gcCircle.r.get(), 0, 2 * Math.PI);
ctx.arc(this.c.x, this.c.y, this.r.get(), 0, 2 * Math.PI);
ctx.stroke();
}
@ -44,3 +42,4 @@ export class Circle extends SketchObject {
}
Circle.prototype._class = 'TCAD.TWO.Circle';
Circle.prototype.TYPE = 'CIRCLE';

View file

@ -3,6 +3,8 @@ import {SketchObject} from './sketch-object'
import {Constraints} from '../parametric'
import * as math from '../../math/math';
import {Circle} from "./circle";
import {EndPoint} from "./point";
export class Ellipse extends SketchObject {
@ -91,6 +93,7 @@ export class Ellipse extends SketchObject {
}
}
Ellipse.prototype._class = 'TCAD.TWO.Ellipse';
Ellipse.prototype.TYPE = 'ELLIPSE';
const sq = (a) => a * a;
const RECOVER_LENGTH = 100;

View file

@ -52,3 +52,4 @@ export class EllipticalArc extends Ellipse {
}
EllipticalArc.prototype._class = 'TCAD.TWO.EllipticalArc';
EllipticalArc.prototype.TYPE = 'ELLIPTICAL_ARC';

View file

@ -1,6 +1,7 @@
import {SketchObject} from './sketch-object'
import * as vec from '../../math/vec';
import {curveTessellate} from '../../brep/geom/impl/nurbs-ext';
import {Ellipse} from "./ellipse";
const __v = [0, 0, 0];
@ -89,3 +90,4 @@ export class NurbsObject extends SketchObject {
}
NurbsObject.prototype._class = 'TCAD.TWO.NurbsObject';
NurbsObject.prototype.TYPE = 'NURBS';

View file

@ -0,0 +1,20 @@
import {Generator} from "../id-generator";
import {Param as SolverParam} from '../constr/solver';
export class Param {
constructor(value) {
this.id = Generator.genID();
this.value = value;
this.solverParam = new SolverParam(value, this);
}
set(value) {
this.value = value;
}
get() {
return this.value;
}
}

View file

@ -2,46 +2,39 @@ import {SketchObject} from './sketch-object'
import {DrawPoint} from './draw-utils'
import {Generator} from '../id-generator'
import Vector from 'math/vector';
import {GCPoint} from "../constr/constractibles";
import {Param} from "./param";
export class EndPoint extends SketchObject {
constructor(x, y) {
super();
this.parent = null;
this.gcPoint = new GCPoint();
this._x = this.gcPoint.x; // legacy - yet to remove
this._y = this.gcPoint.y;
this.x = x;
this.y = y;
this.params = {
x: new Param(x),
y: new Param(y)
};
}
get x() {
return this.gcPoint.x.get();
return this.params.x.get();
}
set x(val) {
return this.gcPoint.x.set(val);
return this.params.x.set(val);
}
get y() {
return this.gcPoint.y.get();
return this.params.y.get();
}
set y(val) {
return this.gcPoint.y.set(val);
}
coincideWith(gcPoint) {
if (!this.parkedOwnGeometry) {
this.parkedOwnGeometry = this.gcPoint;
}
this.gcPoint = gcPoint;
return this.params.y.set(val);
}
visitParams(callback) {
callback(this._x);
callback(this._y);
callback(this.params.x);
callback(this.params.y);
}
normalDistance(aim) {
@ -88,20 +81,7 @@ export class EndPoint extends SketchObject {
dest.y = y;
}
}
EndPoint.prototype._class = 'TCAD.TWO.EndPoint';
EndPoint.prototype.TYPE = 'POINT';
export class Param {
constructor(obj, prop) {
this.id = Generator.genID();
this.obj = obj;
this.prop = prop;
}
set(value) {
this.obj[this.prop] = value;
}
get() {
return this.obj[this.prop];
}
}

View file

@ -1,14 +1,3 @@
import {Generator} from '../id-generator'
import {Param} from "./param";
export function Ref(value) {
this.id = Generator.genID();
this.value = value;
}
Ref.prototype.set = function(value) {
this.value = value;
};
Ref.prototype.get = function() {
return this.value;
};
export {Param as Ref};

View file

@ -1,10 +1,12 @@
import {SketchObject} from './sketch-object'
import Vector from 'math/vector';
import {Constraints} from '../parametric'
import * as math from '../../math/math'
import {GCLine} from "../constr/constractibles";
import {Styles} from "../styles";
import * as draw_utils from "./draw-utils";
import {Param} from "./param";
import {Constraints} from "../constraints";
import {ConstraintDefinitions, AlgNumConstraint} from "../constr/ANConstraints";
import {Ellipse} from "./ellipse";
export class Segment extends SketchObject {
@ -14,23 +16,36 @@ export class Segment extends SketchObject {
this.b = b;
a.parent = this;
b.parent = this;
this.gcLine = new GCLine();
this.children.push(a, b);
this.params = {
ang: new Param(undefined),
w: new Param(undefined)
}
}
const dx = b.x - a.x;
const dy = b.y - a.y;
syncLine() {
const dx = this.b.x - this.a.x;
const dy = this.b.y - this.a.y;
const l = Math.sqrt(dx*dx + dy*dy);
let nx = - dy / l;
let ny = dx / l;
let nx = (- dy / l) || 0;
let ny = (dx / l) || 0;
const ang = Math.atan2(ny, nx);
this.gcLine.ang.set(ang);
this.gcLine.w.set(nx * a.x + ny * a.y);
this.children.push(a, b);
this.params.ang.set(ang||0);
this.params.w.set(nx * this.a.x + ny * this.a.y);
}
stabilize(viewer) {
this.syncLine();
const c1 = new AlgNumConstraint(ConstraintDefinitions.PointOnLine, [this.a, this]);
const c2 = new AlgNumConstraint(ConstraintDefinitions.PointOnLine, [this.b, this]);
c1.internal = true;
c2.internal = true;
viewer.parametricManager.addAlgNum(c1);
viewer.parametricManager.addAlgNum(c2);
}
recoverIfNecessary() {
if (math.distanceAB(this.a, this.b) > math.TOLERANCE) {
return false;
@ -45,6 +60,8 @@ export class Segment extends SketchObject {
visitParams(callback) {
this.a.visitParams(callback);
this.b.visitParams(callback);
callback(this.params.ang);
callback(this.params.w);
}
normalDistance(aim) {
@ -89,10 +106,10 @@ export class Segment extends SketchObject {
// ctx.restore();
let ang = this.gcLine.ang.get();
let ang = this.params.ang.get();
let nx = Math.cos(ang) ;
let ny = Math.sin(ang) ;
let w = this.gcLine.w.get();
let w = this.params.w.get();
ctx.save();
draw_utils.SetStyle(Styles.CONSTRUCTION_OF_OBJECT, ctx, scale );
@ -122,3 +139,4 @@ export class Segment extends SketchObject {
Segment.prototype._class = 'TCAD.TWO.Segment';
Segment.prototype.TYPE = 'SEGMENT';

View file

@ -131,7 +131,7 @@ export class SketchObject extends Shape {
export function pointIterator(shape, func) {
shape.accept(o => {
if (o._class === Types.END_POINT) {
if (o._class === Types.POINT) {
func(o);
}
return true;

View file

@ -1,8 +1,8 @@
import {Viewer} from './viewer2d.js'
import * as ui from '../ui/ui'
import {Terminal} from '../ui/terminal'
import {IO, BBox} from './io'
import {AddFreeDimTool, AddHorizontalDimTool, AddVerticalDimTool, AddCircleDimTool} from './tools/dim'
import {BBox, IO} from './io'
import {AddCircleDimTool, AddFreeDimTool, AddHorizontalDimTool, AddVerticalDimTool} from './tools/dim'
import {AddPointTool} from './tools/point'
import {AddSegmentTool} from './tools/segment'
import {AddArcTool} from './tools/arc'
@ -15,6 +15,10 @@ import {OffsetTool} from './tools/offset'
import {ReferencePointTool} from './tools/origin'
import {InputManager} from './input-manager'
import genSerpinski from '../utils/genSerpinski';
import context from 'context';
import ReactDOM from "react-dom";
import React from "react";
import {RightSideControls} from "./components/RightSideControls";
function App2D() {
var app = this;
@ -54,8 +58,9 @@ function App2D() {
this.terminalHandler = undefined;
this.terminal = new Terminal(this.commandsWin, (command) => this.handleTerminalInput(command), () => this.getAllCommandList());
this.bindToolsToTerminal();
startReact(this.viewer);
this.winManager.registerResize(dockEl, ui.DIRECTIONS.EAST, function() {$('body').trigger('layout'); });
$('body').on('layout', this.viewer.onWindowResize);
@ -470,6 +475,20 @@ App2D.prototype.handleTerminalInput = function(commandStr) {
}
};
function startReact(viewer) {
context.streams.sketcherApp = viewer.streams;
context.viewer = viewer;
let reactControls = document.getElementById('react-controls');
reactControls.onkeydown = e => {
e.stopPropagation();
// e.preventDefault();
};
ReactDOM.render(
<RightSideControls />,
reactControls
);
}
App2D.STORAGE_PREFIX = "TCAD.projects.";
export default App2D;

View file

@ -17,5 +17,7 @@ export default function(viewer) {
streams.constraintsUpdate = stream();
streams.constraintEditRequest = state(null);
return streams;
};

View file

@ -25,6 +25,10 @@ class SubSystem {
});
other.nativeParams.forEach(p => this.nativeParams.add(p));
}
prepare() {
}
}
class Index {

View file

@ -25,7 +25,7 @@ export class DragTool extends Tool {
this.obj.translate(dx, dy);
if (!Tool.dumbMode(e)) {
this.solverTransaction.solve(true);
this.viewer.parametricManager.algnNumSystem.solve(true);
}
this.viewer.refresh();
}
@ -35,12 +35,12 @@ export class DragTool extends Tool {
this.origin.y = e.offsetY;
this.viewer.screenToModel2(e.offsetX, e.offsetY, this._point);
this.solverTransaction = this.viewer.parametricManager.seacSystem.startTransaction([this.obj.gcPoint]);
this.viewer.parametricManager.algnNumSystem.prepare();
}
mouseup(e) {
this.solverTransaction.solve(false);
this.viewer.parametricManager.algnNumSystem.solve(false);
this.viewer.refresh();
this.viewer.toolManager.releaseControl();
var traveled = math.distance(this.origin.x, this.origin.y, e.offsetX, e.offsetY);

View file

@ -1,6 +1,4 @@
import {Tool} from './tool'
import {Constraints} from "../constraints";
import {distanceAB} from "../../math/math";
export class AddSegmentTool extends Tool {
@ -45,7 +43,7 @@ export class AddSegmentTool extends Tool {
}
this.line = this.viewer.addSegment(a.x, a.y, b.x, b.y, this.viewer.activeLayer);
if (needSnap) {
this.viewer.parametricManager.linkObjects([this.line.a, a]);
this.line.a.coincideWith(a);
}
this.firstPointPicked();
this.viewer.refresh();
@ -55,7 +53,7 @@ export class AddSegmentTool extends Tool {
this.viewer.cleanSnap();
this.line.b.x = p.x;
this.line.b.y = p.y;
this.viewer.parametricManager.linkObjects([this.line.b, p]);
this.line.b.coincideWith(p);
}
this.nextPointPicked();
}
@ -63,11 +61,10 @@ export class AddSegmentTool extends Tool {
nextPointPicked() {
this.pointPicked(this.line.b.x, this.line.b.y);
this.viewer.parametricManager.add(new Constraints.P2PDistance(this.line.a, this.line.b, distanceAB(this.line.a, this.line.b)));
if (this.multi) {
const b = this.line.b;
this.line = this.viewer.addSegment(b.x, b.y, b.x, b.y, this.viewer.activeLayer);
this.viewer.parametricManager.linkObjects([this.line.a, b]);
this.line.a.coincideWith(b);
} else {
this.restart()
}
@ -87,7 +84,7 @@ export class AddSegmentTool extends Tool {
}
keydown(e) {
if (e.keyCode == 27) {
if (e.keyCode === 27) {
this.cancelSegment();
}
}

View file

@ -121,6 +121,7 @@ class Viewer {
var b = new EndPoint(x2, y2);
var line = new Segment(a, b);
layer.add(line);
line.stabilize(this);
return line;
};
@ -329,7 +330,7 @@ class Viewer {
return out;
};
accept(visitor) {
accept = visitor => {
for (let layer of this.layers) {
for (let object of layer.objects) {
if (!object.accept(visitor)) {

View file

@ -346,4 +346,4 @@ input[type=checkbox], input[type=radio] {
font-size: 11px;
cursor: default;
pointer-events: none;
}
}

View file

@ -70,6 +70,7 @@
<div id="viewer-container" style="background: #808080; overflow: hidden; height: 100%; position: relative">
<div class="tool-hint" style="position: absolute; bottom: 5px; right: 5px;"></div>
<canvas width="300" height="300" id="viewer"></canvas>
<div id="react-controls" style="position: absolute; top: 0; right: 0; bottom: 0;"></div>
</div>
</div>