diff --git a/package-lock.json b/package-lock.json
index 3f63bbb4..46ec9226 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index be473f2e..28b2c65c 100644
--- a/package.json
+++ b/package.json
@@ -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"
}
diff --git a/web/app/sketcher/actions/constraintActions.js b/web/app/sketcher/actions/constraintActions.js
new file mode 100644
index 00000000..9f1a22a6
--- /dev/null
+++ b/web/app/sketcher/actions/constraintActions.js
@@ -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();
+ }
+ });
+
+ }
+ }
+
+
+
+];
\ No newline at end of file
diff --git a/web/app/sketcher/actions/index.js b/web/app/sketcher/actions/index.js
new file mode 100644
index 00000000..9634928b
--- /dev/null
+++ b/web/app/sketcher/actions/index.js
@@ -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;
+
+}
\ No newline at end of file
diff --git a/web/app/sketcher/actions/matchUtils.js b/web/app/sketcher/actions/matchUtils.js
new file mode 100644
index 00000000..57fc2d3e
--- /dev/null
+++ b/web/app/sketcher/actions/matchUtils.js
@@ -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))
+}
diff --git a/web/app/sketcher/components/ConstraintEditor.jsx b/web/app/sketcher/components/ConstraintEditor.jsx
new file mode 100644
index 00000000..ecf81ce6
--- /dev/null
+++ b/web/app/sketcher/components/ConstraintEditor.jsx
@@ -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
+ }
+);
+
+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
+
+
+
+ {Object.keys(constraint.schema.constants).sort().map(name =>
+
+ {
+ (() => {
+ const def = constraint.schema.constants[name];
+ const val = values[name];
+ if (def.type === 'number') {
+ return setValue(name, value)} />
+ } else {
+ return {val};
+ }
+
+ })()
+
+ }
+
+
)}
+
+
+
+
+
+
+
+
+
+ ;
+
+}
\ No newline at end of file
diff --git a/web/app/sketcher/components/ContextualControls.jsx b/web/app/sketcher/components/ContextualControls.jsx
new file mode 100644
index 00000000..b4d42361
--- /dev/null
+++ b/web/app/sketcher/components/ContextualControls.jsx
@@ -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
+
+ {
+ selection.map(s =>
{s.simpleClassName}: {s.id}
)
+ }
+
+
AVAILABLE ACTIONS:
+
+ {
+ availableActions.map(a =>
)
+ }
+
+
;
+
+ }
+));
\ No newline at end of file
diff --git a/web/app/sketcher/components/ContextualControls.less b/web/app/sketcher/components/ContextualControls.less
new file mode 100644
index 00000000..37ae7ee7
--- /dev/null
+++ b/web/app/sketcher/components/ContextualControls.less
@@ -0,0 +1,15 @@
+
+.root {
+ margin: 5px;
+ padding: 3px 5px;
+ background-color: #000D;
+ color: white;
+}
+
+.item {
+ padding: 3px 0;
+}
+
+.hr {
+ .item;
+}
\ No newline at end of file
diff --git a/web/app/sketcher/components/RightSideControls.jsx b/web/app/sketcher/components/RightSideControls.jsx
new file mode 100644
index 00000000..329dff76
--- /dev/null
+++ b/web/app/sketcher/components/RightSideControls.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import {ConstraintEditor} from "./ConstraintEditor";
+import {ContextualControls} from "./ContextualControls";
+
+export function RightSideControls() {
+
+ return
+
+
+ ;
+
+}
+
+
diff --git a/web/app/sketcher/constr/ANConstraints.js b/web/app/sketcher/constr/ANConstraints.js
new file mode 100644
index 00000000..032a2ad5
--- /dev/null
+++ b/web/app/sketcher/constr/ANConstraints.js
@@ -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);
+ });
+ }
+ }
+}
+
diff --git a/web/app/sketcher/constr/AlgNumSystem.js b/web/app/sketcher/constr/AlgNumSystem.js
new file mode 100644
index 00000000..60e953dd
--- /dev/null
+++ b/web/app/sketcher/constr/AlgNumSystem.js
@@ -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;
+ }
+}
diff --git a/web/app/sketcher/constr/SEACConstraints.js b/web/app/sketcher/constr/SEACConstraints.js
deleted file mode 100644
index aa33437a..00000000
--- a/web/app/sketcher/constr/SEACConstraints.js
+++ /dev/null
@@ -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);
- }
-}
-
diff --git a/web/app/sketcher/constr/SEACSystem.js b/web/app/sketcher/constr/SEACSystem.js
deleted file mode 100644
index a5e56869..00000000
--- a/web/app/sketcher/constr/SEACSystem.js
+++ /dev/null
@@ -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());
- }
- });
- }
-
-}
diff --git a/web/app/sketcher/constr/constractibles.js b/web/app/sketcher/constr/constractibles.js
index f11f8e56..d47d199d 100644
--- a/web/app/sketcher/constr/constractibles.js
+++ b/web/app/sketcher/constr/constractibles.js
@@ -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;
}
-}
\ No newline at end of file
+ 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
+
+};
\ No newline at end of file
diff --git a/web/app/sketcher/constr/polynomial.js b/web/app/sketcher/constr/polynomial.js
new file mode 100644
index 00000000..70f66923
--- /dev/null
+++ b/web/app/sketcher/constr/polynomial.js
@@ -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');
+
+
diff --git a/web/app/sketcher/constr/residuals.js b/web/app/sketcher/constr/residuals.js
index c367c41b..caa3e888 100644
--- a/web/app/sketcher/constr/residuals.js
+++ b/web/app/sketcher/constr/residuals.js
@@ -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;
diff --git a/web/app/sketcher/constr/solver.js b/web/app/sketcher/constr/solver.js
index 3cc3f45d..2849e4df 100644
--- a/web/app/sketcher/constr/solver.js
+++ b/web/app/sketcher/constr/solver.js
@@ -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) {
diff --git a/web/app/sketcher/generators/boundaryGenerator.js b/web/app/sketcher/generators/boundaryGenerator.js
new file mode 100644
index 00000000..0e65753a
--- /dev/null
+++ b/web/app/sketcher/generators/boundaryGenerator.js
@@ -0,0 +1,5 @@
+
+
+export function boundaryGenerator() {
+
+}
\ No newline at end of file
diff --git a/web/app/sketcher/io.js b/web/app/sketcher/io.js
index 47502c69..8a854c70 100644
--- a/web/app/sketcher/io.js
+++ b/web/app/sketcher/io.js
@@ -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('', [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('', [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");
diff --git a/web/app/sketcher/parametric.js b/web/app/sketcher/parametric.js
index d218868b..687fa030 100644
--- a/web/app/sketcher/parametric.js
+++ b/web/app/sketcher/parametric.js
@@ -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}
\ No newline at end of file
diff --git a/web/app/sketcher/selectionMatcher.js b/web/app/sketcher/selectionMatcher.js
new file mode 100644
index 00000000..f969228e
--- /dev/null
+++ b/web/app/sketcher/selectionMatcher.js
@@ -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) {
+
+ }
+ }
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/web/app/sketcher/shapes/arc.js b/web/app/sketcher/shapes/arc.js
index c0febaca..ad164a7d 100644
--- a/web/app/sketcher/shapes/arc.js
+++ b/web/app/sketcher/shapes/arc.js
@@ -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';
\ No newline at end of file
diff --git a/web/app/sketcher/shapes/bezier-curve.js b/web/app/sketcher/shapes/bezier-curve.js
index 0bf9378b..b0a73e4f 100644
--- a/web/app/sketcher/shapes/bezier-curve.js
+++ b/web/app/sketcher/shapes/bezier-curve.js
@@ -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;
\ No newline at end of file
diff --git a/web/app/sketcher/shapes/circle.js b/web/app/sketcher/shapes/circle.js
index 2ce309ee..a5afd60f 100644
--- a/web/app/sketcher/shapes/circle.js
+++ b/web/app/sketcher/shapes/circle.js
@@ -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';
\ No newline at end of file
diff --git a/web/app/sketcher/shapes/ellipse.js b/web/app/sketcher/shapes/ellipse.js
index ccd0b78e..e2530411 100644
--- a/web/app/sketcher/shapes/ellipse.js
+++ b/web/app/sketcher/shapes/ellipse.js
@@ -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;
\ No newline at end of file
diff --git a/web/app/sketcher/shapes/elliptical-arc.js b/web/app/sketcher/shapes/elliptical-arc.js
index 0114bd32..8da16714 100644
--- a/web/app/sketcher/shapes/elliptical-arc.js
+++ b/web/app/sketcher/shapes/elliptical-arc.js
@@ -52,3 +52,4 @@ export class EllipticalArc extends Ellipse {
}
EllipticalArc.prototype._class = 'TCAD.TWO.EllipticalArc';
+EllipticalArc.prototype.TYPE = 'ELLIPTICAL_ARC';
diff --git a/web/app/sketcher/shapes/nurbsObject.js b/web/app/sketcher/shapes/nurbsObject.js
index f225e67f..ad24ee69 100644
--- a/web/app/sketcher/shapes/nurbsObject.js
+++ b/web/app/sketcher/shapes/nurbsObject.js
@@ -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';
diff --git a/web/app/sketcher/shapes/param.js b/web/app/sketcher/shapes/param.js
new file mode 100644
index 00000000..5727cb50
--- /dev/null
+++ b/web/app/sketcher/shapes/param.js
@@ -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;
+ }
+
+}
\ No newline at end of file
diff --git a/web/app/sketcher/shapes/point.js b/web/app/sketcher/shapes/point.js
index e7eb3b9d..761a2b02 100644
--- a/web/app/sketcher/shapes/point.js
+++ b/web/app/sketcher/shapes/point.js
@@ -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];
- }
-}
diff --git a/web/app/sketcher/shapes/ref.js b/web/app/sketcher/shapes/ref.js
index f580f3a4..a6feeff8 100644
--- a/web/app/sketcher/shapes/ref.js
+++ b/web/app/sketcher/shapes/ref.js
@@ -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};
diff --git a/web/app/sketcher/shapes/segment.js b/web/app/sketcher/shapes/segment.js
index c8f169e7..f0b879e8 100644
--- a/web/app/sketcher/shapes/segment.js
+++ b/web/app/sketcher/shapes/segment.js
@@ -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';
diff --git a/web/app/sketcher/shapes/sketch-object.js b/web/app/sketcher/shapes/sketch-object.js
index 4aacabff..88f50ebd 100644
--- a/web/app/sketcher/shapes/sketch-object.js
+++ b/web/app/sketcher/shapes/sketch-object.js
@@ -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;
diff --git a/web/app/sketcher/sketcher-app.js b/web/app/sketcher/sketcher-app.js
index c7ac96c9..b9b669a0 100644
--- a/web/app/sketcher/sketcher-app.js
+++ b/web/app/sketcher/sketcher-app.js
@@ -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(
+ ,
+ reactControls
+ );
+}
+
App2D.STORAGE_PREFIX = "TCAD.projects.";
export default App2D;
\ No newline at end of file
diff --git a/web/app/sketcher/sketcherStreams.js b/web/app/sketcher/sketcherStreams.js
index b582e1d2..f2797f6e 100644
--- a/web/app/sketcher/sketcherStreams.js
+++ b/web/app/sketcher/sketcherStreams.js
@@ -17,5 +17,7 @@ export default function(viewer) {
streams.constraintsUpdate = stream();
+ streams.constraintEditRequest = state(null);
+
return streams;
};
\ No newline at end of file
diff --git a/web/app/sketcher/system.js b/web/app/sketcher/system.js
index 6ea09bb8..cbac90c8 100644
--- a/web/app/sketcher/system.js
+++ b/web/app/sketcher/system.js
@@ -25,6 +25,10 @@ class SubSystem {
});
other.nativeParams.forEach(p => this.nativeParams.add(p));
}
+
+ prepare() {
+
+ }
}
class Index {
diff --git a/web/app/sketcher/tools/drag.js b/web/app/sketcher/tools/drag.js
index 85e5476c..c8cef0b4 100644
--- a/web/app/sketcher/tools/drag.js
+++ b/web/app/sketcher/tools/drag.js
@@ -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);
diff --git a/web/app/sketcher/tools/segment.js b/web/app/sketcher/tools/segment.js
index da872918..ca55ca77 100644
--- a/web/app/sketcher/tools/segment.js
+++ b/web/app/sketcher/tools/segment.js
@@ -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();
}
}
diff --git a/web/app/sketcher/viewer2d.js b/web/app/sketcher/viewer2d.js
index d4c094b5..bb8047c7 100644
--- a/web/app/sketcher/viewer2d.js
+++ b/web/app/sketcher/viewer2d.js
@@ -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)) {
diff --git a/web/css/app.less b/web/css/app.less
index f15dd4a8..a4369bb8 100644
--- a/web/css/app.less
+++ b/web/css/app.less
@@ -346,4 +346,4 @@ input[type=checkbox], input[type=radio] {
font-size: 11px;
cursor: default;
pointer-events: none;
-}
\ No newline at end of file
+}
diff --git a/web/sketcher.html b/web/sketcher.html
index eba6ea7d..a996d478 100644
--- a/web/sketcher.html
+++ b/web/sketcher.html
@@ -70,6 +70,7 @@