From 18364665b0fca5ca93d2ac37ccca2cd0e9293f51 Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 12:20:28 -0500 Subject: [PATCH 01/11] add w prop --- package-lock.json | 965 ++++++++++++++++++++++++++------------ package.json | 16 +- src/orientation-vector.ts | 234 ++++----- 3 files changed, 788 insertions(+), 427 deletions(-) diff --git a/package-lock.json b/package-lock.json index f57b617..b815fd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,25 +1,25 @@ { "name": "@viamrobotics/three", - "version": "0.0.2", + "version": "0.0.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@viamrobotics/three", - "version": "0.0.2", + "version": "0.0.3", "license": "Apache-2.0", "devDependencies": { "@0b5vr/tweakpane-plugin-rotation": "^0.2.0", - "@tweakpane/core": "^2.0.1", - "@tweakpane/plugin-essentials": "^0.2.0", - "@types/three": "^0.159.0", - "three": "^0.159.0", + "@tweakpane/core": "^2.0.3", + "@tweakpane/plugin-essentials": "^0.2.1", + "@types/three": "^0.161.2", + "three": "^0.162.0", "three-inspect": "^0.3.4", "trzy": "^0.3.17", - "tweakpane": "^4.0.1", - "typescript": "^5.3.2", - "vite": "^5.0.5", - "vitest": "^0.34.6" + "tweakpane": "^4.0.3", + "typescript": "^5.3.3", + "vite": "^5.1.4", + "vitest": "^1.3.1" }, "peerDependencies": { "three": "*" @@ -567,40 +567,33 @@ "dev": true }, "node_modules/@tweakpane/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@tweakpane/core/-/core-2.0.1.tgz", - "integrity": "sha512-iJNrLrLffQR0I8mWgAWcMVO9ZPNdNeXZl66WNT+Op5L9FW7BSF6lwG3izR6Ki9CaI3HzIownwjzYS5xWUaokTA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@tweakpane/core/-/core-2.0.3.tgz", + "integrity": "sha512-qHci4XA1Wngpwy8IzsLh5JEdscz8aDti/9YhyOaq01si+cgNDaZfwzTtXdn1+xTxSnCM+pW4Zb2/4eqn+K1ATw==", "dev": true }, "node_modules/@tweakpane/plugin-essentials": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@tweakpane/plugin-essentials/-/plugin-essentials-0.2.0.tgz", - "integrity": "sha512-/kO90nfm0y0CYJPUvoNrjXhjNoqr+RaoySIdJmy++pb5vrSHi/DXdxG/sPszUPZggDY9M31RTacnxXi6Dv7r8Q==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@tweakpane/plugin-essentials/-/plugin-essentials-0.2.1.tgz", + "integrity": "sha512-VbFU1/uD+CJNFQdfLXUOLjeG5HyUZH97Ox9CxmyVetg1hqjVun3C83HAGFULyhKzl8tSgii8jr304r8QpdHwzQ==", "dev": true, "peerDependencies": { - "tweakpane": "^4.0.0-beta.2" + "tweakpane": "^4.0.0" } }, - "node_modules/@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", - "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, - "node_modules/@types/chai-subset": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", - "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", - "dev": true, - "dependencies": { - "@types/chai": "*" - } - }, "node_modules/@types/node": { "version": "18.11.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/@types/stats.js": { "version": "0.17.0", @@ -609,9 +602,9 @@ "dev": true }, "node_modules/@types/three": { - "version": "0.159.0", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.159.0.tgz", - "integrity": "sha512-2gybdh7HtX+rGUgslzK7QEJfzD2I0qrbUGzKk+dK0FDx49UHkNX0rqZVRzIgeFjBd1HzzhNNgwNoMacm3Wyc7w==", + "version": "0.161.2", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.161.2.tgz", + "integrity": "sha512-DazpZ+cIfBzbW/p0zm6G8CS03HBMd748A3R1ZOXHpqaXZLv2I5zNgQUrRG//UfJ6zYFp2cUoCQaOLaz8ubH07w==", "dev": true, "dependencies": { "@types/stats.js": "*", @@ -627,13 +620,13 @@ "dev": true }, "node_modules/@vitest/expect": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", - "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", + "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==", "dev": true, "dependencies": { - "@vitest/spy": "0.34.6", - "@vitest/utils": "0.34.6", + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", "chai": "^4.3.10" }, "funding": { @@ -641,13 +634,13 @@ } }, "node_modules/@vitest/runner": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", - "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz", + "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==", "dev": true, "dependencies": { - "@vitest/utils": "0.34.6", - "p-limit": "^4.0.0", + "@vitest/utils": "1.3.1", + "p-limit": "^5.0.0", "pathe": "^1.1.1" }, "funding": { @@ -655,49 +648,50 @@ } }, "node_modules/@vitest/snapshot": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", - "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz", + "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==", "dev": true, "dependencies": { - "magic-string": "^0.30.1", + "magic-string": "^0.30.5", "pathe": "^1.1.1", - "pretty-format": "^29.5.0" + "pretty-format": "^29.7.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/spy": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", - "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz", + "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==", "dev": true, "dependencies": { - "tinyspy": "^2.1.1" + "tinyspy": "^2.2.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", - "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz", + "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==", "dev": true, "dependencies": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -707,9 +701,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true, "engines": { "node": ">=0.4.0" @@ -746,9 +740,9 @@ } }, "node_modules/chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", @@ -775,6 +769,20 @@ "node": "*" } }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -850,6 +858,38 @@ "@esbuild/win32-x64": "0.19.8" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "node_modules/fflate": { "version": "0.6.10", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", @@ -879,17 +919,66 @@ "node": "*" } }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz", + "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==", + "dev": true + }, "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true }, "node_modules/local-pkg": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", - "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", "dev": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, "engines": { "node": ">=14" }, @@ -907,9 +996,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", + "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -918,22 +1007,40 @@ "node": ">=12" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "node_modules/meshoptimizer": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", "dev": true }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mlly": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", - "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", + "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", "dev": true, "dependencies": { - "acorn": "^8.10.0", - "pathe": "^1.1.1", + "acorn": "^8.11.3", + "pathe": "^1.1.2", "pkg-types": "^1.0.3", - "ufo": "^1.3.0" + "ufo": "^1.3.2" } }, "node_modules/ms": { @@ -960,25 +1067,76 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/p-limit": { + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", "dev": true, "dependencies": { "yocto-queue": "^1.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pathe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", - "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", "dev": true }, "node_modules/pathval": { @@ -1008,9 +1166,9 @@ } }, "node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "funding": [ { @@ -1083,12 +1241,45 @@ "fsevents": "~2.3.2" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/simplex-noise": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/simplex-noise/-/simplex-noise-4.0.1.tgz", @@ -1111,27 +1302,39 @@ "dev": true }, "node_modules/std-env": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.3.tgz", - "integrity": "sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", "dev": true }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-literal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz", - "integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", + "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", "dev": true, "dependencies": { - "acorn": "^8.8.2" + "js-tokens": "^8.0.2" }, "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/three": { - "version": "0.159.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.159.0.tgz", - "integrity": "sha512-eCmhlLGbBgucuo4VEA9IO3Qpc7dh8Bd4VKzr7WfW4+8hMcIfoAVi1ev0pJYN9PTTsCslbcKgBwr2wNZ1EvLInA==", + "version": "0.162.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.162.0.tgz", + "integrity": "sha512-xfCYj4RnlozReCmUd+XQzj6/5OjDNHBy5nT6rVwrOKGENAvpXe2z1jL+DZYaMu4/9pNsjH/4Os/VvS9IrH7IOQ==", "dev": true }, "node_modules/three-inspect": { @@ -1153,24 +1356,24 @@ } }, "node_modules/tinybench": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz", - "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", + "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==", "dev": true }, "node_modules/tinypool": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", - "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.2.tgz", + "integrity": "sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==", "dev": true, "engines": { "node": ">=14.0.0" } }, "node_modules/tinyspy": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz", - "integrity": "sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", "dev": true, "engines": { "node": ">=14.0.0" @@ -1190,9 +1393,9 @@ } }, "node_modules/tweakpane": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-4.0.1.tgz", - "integrity": "sha512-1JmmGbF4h2zuFbpN1XfIWcV0kLbBUgSXpR1QtW19vJFx44asnCrufRSvd69OItOFMEWgbVtoiWM2uDPUEUKcMQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-4.0.3.tgz", + "integrity": "sha512-BlcWOAe8oe4c+k9pmLBARGdWB6MVZMszayekkixQXTgkxTaYoTUpHpwVEp+3HkoamZkomodpbBf0CkguIHTgLg==", "dev": true, "funding": { "url": "https://github.com/sponsors/cocopon" @@ -1208,9 +1411,9 @@ } }, "node_modules/typescript": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", - "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -1221,19 +1424,19 @@ } }, "node_modules/ufo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz", - "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.4.0.tgz", + "integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==", "dev": true }, "node_modules/vite": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.5.tgz", - "integrity": "sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", + "integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==", "dev": true, "dependencies": { "esbuild": "^0.19.3", - "postcss": "^8.4.32", + "postcss": "^8.4.35", "rollup": "^4.2.0" }, "bin": { @@ -1282,82 +1485,78 @@ } }, "node_modules/vite-node": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz", - "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz", + "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==", "dev": true, "dependencies": { "cac": "^6.7.14", "debug": "^4.3.4", - "mlly": "^1.4.0", "pathe": "^1.1.1", "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + "vite": "^5.0.0" }, "bin": { "vite-node": "vite-node.mjs" }, "engines": { - "node": ">=v14.18.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/vitest": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz", - "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz", + "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==", "dev": true, "dependencies": { - "@types/chai": "^4.3.5", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "@vitest/expect": "0.34.6", - "@vitest/runner": "0.34.6", - "@vitest/snapshot": "0.34.6", - "@vitest/spy": "0.34.6", - "@vitest/utils": "0.34.6", - "acorn": "^8.9.0", - "acorn-walk": "^8.2.0", - "cac": "^6.7.14", + "@vitest/expect": "1.3.1", + "@vitest/runner": "1.3.1", + "@vitest/snapshot": "1.3.1", + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", + "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.1", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", "pathe": "^1.1.1", "picocolors": "^1.0.0", - "std-env": "^3.3.3", - "strip-literal": "^1.0.1", - "tinybench": "^2.5.0", - "tinypool": "^0.7.0", - "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", - "vite-node": "0.34.6", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.2", + "vite": "^5.0.0", + "vite-node": "1.3.1", "why-is-node-running": "^2.2.2" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": ">=v14.18.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", - "@vitest/browser": "*", - "@vitest/ui": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.3.1", + "@vitest/ui": "1.3.1", "happy-dom": "*", - "jsdom": "*", - "playwright": "*", - "safaridriver": "*", - "webdriverio": "*" + "jsdom": "*" }, "peerDependenciesMeta": { "@edge-runtime/vm": { "optional": true }, + "@types/node": { + "optional": true + }, "@vitest/browser": { "optional": true }, @@ -1369,18 +1568,24 @@ }, "jsdom": { "optional": true - }, - "playwright": { - "optional": true - }, - "safaridriver": { - "optional": true - }, - "webdriverio": { - "optional": true } } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/why-is-node-running": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", @@ -1678,38 +1883,31 @@ "dev": true }, "@tweakpane/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@tweakpane/core/-/core-2.0.1.tgz", - "integrity": "sha512-iJNrLrLffQR0I8mWgAWcMVO9ZPNdNeXZl66WNT+Op5L9FW7BSF6lwG3izR6Ki9CaI3HzIownwjzYS5xWUaokTA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@tweakpane/core/-/core-2.0.3.tgz", + "integrity": "sha512-qHci4XA1Wngpwy8IzsLh5JEdscz8aDti/9YhyOaq01si+cgNDaZfwzTtXdn1+xTxSnCM+pW4Zb2/4eqn+K1ATw==", "dev": true }, "@tweakpane/plugin-essentials": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@tweakpane/plugin-essentials/-/plugin-essentials-0.2.0.tgz", - "integrity": "sha512-/kO90nfm0y0CYJPUvoNrjXhjNoqr+RaoySIdJmy++pb5vrSHi/DXdxG/sPszUPZggDY9M31RTacnxXi6Dv7r8Q==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@tweakpane/plugin-essentials/-/plugin-essentials-0.2.1.tgz", + "integrity": "sha512-VbFU1/uD+CJNFQdfLXUOLjeG5HyUZH97Ox9CxmyVetg1hqjVun3C83HAGFULyhKzl8tSgii8jr304r8QpdHwzQ==", "dev": true, "requires": {} }, - "@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", - "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, - "@types/chai-subset": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", - "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", - "dev": true, - "requires": { - "@types/chai": "*" - } - }, "@types/node": { "version": "18.11.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "@types/stats.js": { "version": "0.17.0", @@ -1718,9 +1916,9 @@ "dev": true }, "@types/three": { - "version": "0.159.0", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.159.0.tgz", - "integrity": "sha512-2gybdh7HtX+rGUgslzK7QEJfzD2I0qrbUGzKk+dK0FDx49UHkNX0rqZVRzIgeFjBd1HzzhNNgwNoMacm3Wyc7w==", + "version": "0.161.2", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.161.2.tgz", + "integrity": "sha512-DazpZ+cIfBzbW/p0zm6G8CS03HBMd748A3R1ZOXHpqaXZLv2I5zNgQUrRG//UfJ6zYFp2cUoCQaOLaz8ubH07w==", "dev": true, "requires": { "@types/stats.js": "*", @@ -1736,68 +1934,69 @@ "dev": true }, "@vitest/expect": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", - "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", + "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==", "dev": true, "requires": { - "@vitest/spy": "0.34.6", - "@vitest/utils": "0.34.6", + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", "chai": "^4.3.10" } }, "@vitest/runner": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", - "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz", + "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==", "dev": true, "requires": { - "@vitest/utils": "0.34.6", - "p-limit": "^4.0.0", + "@vitest/utils": "1.3.1", + "p-limit": "^5.0.0", "pathe": "^1.1.1" } }, "@vitest/snapshot": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", - "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz", + "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==", "dev": true, "requires": { - "magic-string": "^0.30.1", + "magic-string": "^0.30.5", "pathe": "^1.1.1", - "pretty-format": "^29.5.0" + "pretty-format": "^29.7.0" } }, "@vitest/spy": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", - "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz", + "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==", "dev": true, "requires": { - "tinyspy": "^2.1.1" + "tinyspy": "^2.2.0" } }, "@vitest/utils": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", - "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz", + "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==", "dev": true, "requires": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" } }, "acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true }, "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true }, "ansi-styles": { @@ -1819,9 +2018,9 @@ "dev": true }, "chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", "dev": true, "requires": { "assertion-error": "^1.1.0", @@ -1842,6 +2041,17 @@ "get-func-name": "^2.0.2" } }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1896,6 +2106,32 @@ "@esbuild/win32-x64": "0.19.8" } }, + "estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0" + } + }, + "execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + } + }, "fflate": { "version": "0.6.10", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", @@ -1915,17 +2151,51 @@ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true }, + "get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true + }, + "human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "js-tokens": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz", + "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==", + "dev": true + }, "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true }, "local-pkg": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", - "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", - "dev": true + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "dev": true, + "requires": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + } }, "loupe": { "version": "2.3.7", @@ -1937,30 +2207,42 @@ } }, "magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", + "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", "dev": true, "requires": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "meshoptimizer": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", "dev": true }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true + }, "mlly": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", - "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", + "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", "dev": true, "requires": { - "acorn": "^8.10.0", - "pathe": "^1.1.1", + "acorn": "^8.11.3", + "pathe": "^1.1.2", "pkg-types": "^1.0.3", - "ufo": "^1.3.0" + "ufo": "^1.3.2" } }, "ms": { @@ -1975,19 +2257,51 @@ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true }, + "npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "requires": { + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + } + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, "p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", "dev": true, "requires": { "yocto-queue": "^1.0.0" } }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, "pathe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", - "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", "dev": true }, "pathval": { @@ -2014,9 +2328,9 @@ } }, "postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "requires": { "nanoid": "^3.3.7", @@ -2062,12 +2376,33 @@ "fsevents": "~2.3.2" } }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, "simplex-noise": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/simplex-noise/-/simplex-noise-4.0.1.tgz", @@ -2087,24 +2422,30 @@ "dev": true }, "std-env": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.3.tgz", - "integrity": "sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "dev": true + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true }, "strip-literal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz", - "integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", + "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", "dev": true, "requires": { - "acorn": "^8.8.2" + "js-tokens": "^8.0.2" } }, "three": { - "version": "0.159.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.159.0.tgz", - "integrity": "sha512-eCmhlLGbBgucuo4VEA9IO3Qpc7dh8Bd4VKzr7WfW4+8hMcIfoAVi1ev0pJYN9PTTsCslbcKgBwr2wNZ1EvLInA==", + "version": "0.162.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.162.0.tgz", + "integrity": "sha512-xfCYj4RnlozReCmUd+XQzj6/5OjDNHBy5nT6rVwrOKGENAvpXe2z1jL+DZYaMu4/9pNsjH/4Os/VvS9IrH7IOQ==", "dev": true }, "three-inspect": { @@ -2122,21 +2463,21 @@ "requires": {} }, "tinybench": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz", - "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", + "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==", "dev": true }, "tinypool": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", - "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.2.tgz", + "integrity": "sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==", "dev": true }, "tinyspy": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz", - "integrity": "sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", "dev": true }, "trzy": { @@ -2150,9 +2491,9 @@ } }, "tweakpane": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-4.0.1.tgz", - "integrity": "sha512-1JmmGbF4h2zuFbpN1XfIWcV0kLbBUgSXpR1QtW19vJFx44asnCrufRSvd69OItOFMEWgbVtoiWM2uDPUEUKcMQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-4.0.3.tgz", + "integrity": "sha512-BlcWOAe8oe4c+k9pmLBARGdWB6MVZMszayekkixQXTgkxTaYoTUpHpwVEp+3HkoamZkomodpbBf0CkguIHTgLg==", "dev": true }, "type-detect": { @@ -2162,75 +2503,79 @@ "dev": true }, "typescript": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", - "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true }, "ufo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz", - "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.4.0.tgz", + "integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==", "dev": true }, "vite": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.5.tgz", - "integrity": "sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", + "integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==", "dev": true, "requires": { "esbuild": "^0.19.3", "fsevents": "~2.3.3", - "postcss": "^8.4.32", + "postcss": "^8.4.35", "rollup": "^4.2.0" } }, "vite-node": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz", - "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz", + "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==", "dev": true, "requires": { "cac": "^6.7.14", "debug": "^4.3.4", - "mlly": "^1.4.0", "pathe": "^1.1.1", "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + "vite": "^5.0.0" } }, "vitest": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz", - "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz", + "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==", "dev": true, "requires": { - "@types/chai": "^4.3.5", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "@vitest/expect": "0.34.6", - "@vitest/runner": "0.34.6", - "@vitest/snapshot": "0.34.6", - "@vitest/spy": "0.34.6", - "@vitest/utils": "0.34.6", - "acorn": "^8.9.0", - "acorn-walk": "^8.2.0", - "cac": "^6.7.14", + "@vitest/expect": "1.3.1", + "@vitest/runner": "1.3.1", + "@vitest/snapshot": "1.3.1", + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", + "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.1", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", "pathe": "^1.1.1", "picocolors": "^1.0.0", - "std-env": "^3.3.3", - "strip-literal": "^1.0.1", - "tinybench": "^2.5.0", - "tinypool": "^0.7.0", - "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", - "vite-node": "0.34.6", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.2", + "vite": "^5.0.0", + "vite-node": "1.3.1", "why-is-node-running": "^2.2.2" } }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "why-is-node-running": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", diff --git a/package.json b/package.json index cc29dd4..6b582ea 100644 --- a/package.json +++ b/package.json @@ -32,16 +32,16 @@ ], "devDependencies": { "@0b5vr/tweakpane-plugin-rotation": "^0.2.0", - "@tweakpane/core": "^2.0.1", - "@tweakpane/plugin-essentials": "^0.2.0", - "@types/three": "^0.159.0", - "three": "^0.159.0", + "@tweakpane/core": "^2.0.3", + "@tweakpane/plugin-essentials": "^0.2.1", + "@types/three": "^0.161.2", + "three": "^0.162.0", "three-inspect": "^0.3.4", "trzy": "^0.3.17", - "tweakpane": "^4.0.1", - "typescript": "^5.3.2", - "vite": "^5.0.5", - "vitest": "^0.34.6" + "tweakpane": "^4.0.3", + "typescript": "^5.3.3", + "vite": "^5.1.4", + "vitest": "^1.3.1" }, "peerDependencies": { "three": "*" diff --git a/src/orientation-vector.ts b/src/orientation-vector.ts index ef9dddc..f432646 100644 --- a/src/orientation-vector.ts +++ b/src/orientation-vector.ts @@ -1,23 +1,23 @@ -import { Euler, Quaternion, Vector3, MathUtils } from 'three' -import { EPSILON } from './constants' - -const xAxis = new Quaternion(-1, 0, 0, 0) -const zAxis = new Quaternion(0, 0, +1, 0) - -const quatA = new Quaternion() -const quatB = new Quaternion() -const quatC = new Quaternion() -const quatD = new Quaternion() -const quatE = new Quaternion() - -const vecA = new Vector3() -const vecB = new Vector3() -const vecC = new Vector3() -const vecD = new Vector3() -const vecE = new Vector3() -const vecF = new Vector3() -const vecG = new Vector3() -const vecH = new Vector3() +import { Euler, Quaternion, Vector3, MathUtils } from "three"; +import { EPSILON } from "./constants"; + +const xAxis = new Quaternion(-1, 0, 0, 0); +const zAxis = new Quaternion(0, 0, +1, 0); + +const quatA = new Quaternion(); +const quatB = new Quaternion(); +const quatC = new Quaternion(); +const quatD = new Quaternion(); +const quatE = new Quaternion(); + +const vecA = new Vector3(); +const vecB = new Vector3(); +const vecC = new Vector3(); +const vecD = new Vector3(); +const vecE = new Vector3(); +const vecF = new Vector3(); +const vecG = new Vector3(); +const vecH = new Vector3(); // Golang: https://github.com/viamrobotics/rdk/blob/main/spatialmath/orientationVector.go // Rust: https://github.com/viamrobotics/rust-utils/blob/main/src/spatialmath/utils.rs @@ -25,74 +25,83 @@ const vecH = new Vector3() /** * Viam’s orientation vector is a method for describing the orientation of an object in 3D space. * It is part of a Pose which also includes the position in 3D space. - * + * * The vector extends from the center of the object to another point in the reference frame. This defines the direction something is pointing in. - * + * * @see https://docs.viam.com/internals/orientation-vector/ */ export class OrientationVector { - readonly isOrientationVector = true + readonly isOrientationVector = true; - #vec = new Vector3() - #th = 0 + #vec = new Vector3(); + #th = 0; - #onChangeCallback: (() => void) | undefined + #onChangeCallback: (() => void) | undefined; - constructor (x = 0, y = 0, z = 1, th = 0) { - this.#vec.set(x, y, z).normalize() - this.#th = th + constructor(x = 0, y = 0, z = 1, th = 0) { + this.#vec.set(x, y, z).normalize(); + this.#th = th; } /** * The vector's x component. * @default 0 */ - get x (): number { - return this.#vec.x + get x(): number { + return this.#vec.x; } - set x (value: number) { - this.#vec.setX(value).normalize() - this.#onChangeCallback?.() + set x(value: number) { + this.#vec.setX(value).normalize(); + this.#onChangeCallback?.(); } /** * The vector's y component. * @default 0 */ - get y (): number { - return this.#vec.y + get y(): number { + return this.#vec.y; } - set y (value: number) { - this.#vec.setY(value).normalize() - this.#onChangeCallback?.() + set y(value: number) { + this.#vec.setY(value).normalize(); + this.#onChangeCallback?.(); } /** * The vector's z component. * @default 0 */ - get z () { - return this.#vec.z + get z() { + return this.#vec.z; } - set z (value: number) { - this.#vec.setY(value).normalize() - this.#onChangeCallback?.() + set z(value: number) { + this.#vec.setY(value).normalize(); + this.#onChangeCallback?.(); } /** * Describes the rotation around the vector. * @default 0 */ - get th () { - return this.#th + get th() { + return this.#th; } - set th (value: number) { - this.#th = value - this.#onChangeCallback?.() + set th(value: number) { + this.#th = value; + this.#onChangeCallback?.(); + } + + get w() { + return this.#th; + } + + set w(value: number) { + this.#th = value; + this.#onChangeCallback?.(); } _onChange(callback: () => void) { @@ -103,36 +112,36 @@ export class OrientationVector { /** * Sets the value of this orientation vector. */ - set (x = 0, y = 0, z = 0, th = 0): this { - this.#vec.set(x, y, z).normalize() - this.th = th + set(x = 0, y = 0, z = 0, th = 0): this { + this.#vec.set(x, y, z).normalize(); + this.th = th; - this.#onChangeCallback?.() + this.#onChangeCallback?.(); - return this + return this; } /** * Computes the length of this orientation vector. */ - length (): number { - return this.#vec.length() + length(): number { + return this.#vec.length(); } /** * Copies value of ov to this orientation vector. */ - copy (ov: OrientationVector): this { - this.#vec.set(ov.x, ov.y, ov.z).normalize() - this.th = ov.th + copy(ov: OrientationVector): this { + this.#vec.set(ov.x, ov.y, ov.z).normalize(); + this.th = ov.th; - this.#onChangeCallback?.() + this.#onChangeCallback?.(); - return this + return this; } fromArray(array: number[], offset = 0) { - this.#vec.set(array[offset]!, array[offset + 1]!, array[offset + 2]!) + this.#vec.set(array[offset]!, array[offset + 1]!, array[offset + 2]!); this.th = array[offset + 3]!; this.#onChangeCallback?.(); @@ -153,82 +162,89 @@ export class OrientationVector { return this.toArray(); } - setFromQuaternion (quaternion: Quaternion, update = true): this { + setFromQuaternion(quaternion: Quaternion, update = true): this { // Get the transform of our +X and +Z points - const conj = quatA.copy(quaternion).conjugate() - const newX = quatB.multiplyQuaternions(quaternion, xAxis).multiply(conj) - const newZ = quatC.multiplyQuaternions(quaternion, zAxis).multiply(conj) + const conj = quatA.copy(quaternion).conjugate(); + const newX = quatB.multiplyQuaternions(quaternion, xAxis).multiply(conj); + const newZ = quatC.multiplyQuaternions(quaternion, zAxis).multiply(conj); + + let th = 0; - let th = 0 - /* * The contents of ov.newX.Kmag are not in radians but we can use angleEpsilon anyway to check how close we are to * the pole because it's a convenient small number */ if (1 - Math.abs(newZ.z) > EPSILON) { - const newZimag = vecA.set(newZ.x, newZ.y, newZ.z) - const newXimag = vecB.set(newX.x, newX.y, newX.z) - const zImagAxis = vecC.set(zAxis.x, zAxis.y, zAxis.z) + const newZimag = vecA.set(newZ.x, newZ.y, newZ.z); + const newXimag = vecB.set(newX.x, newX.y, newX.z); + const zImagAxis = vecC.set(zAxis.x, zAxis.y, zAxis.z); // Get the vector normal to the local-x, local-z, origin plane - const normal1 = vecD.copy(newZimag).cross(newXimag) + const normal1 = vecD.copy(newZimag).cross(newXimag); // Get the vector normal to the global-z, local-z, origin plane - const normal2 = vecE.copy(newZimag).cross(zImagAxis) + const normal2 = vecE.copy(newZimag).cross(zImagAxis); // For theta, find the angle between the planes defined by local-x, global-z, origin and local-x, local-z, origin - const cosThetaCand = normal1.dot(normal2) / (normal1.length() * normal2.length()) - const cosTheta = MathUtils.clamp(cosThetaCand, -1, 1) - const theta = Math.acos(cosTheta) + const cosThetaCand = + normal1.dot(normal2) / (normal1.length() * normal2.length()); + const cosTheta = MathUtils.clamp(cosThetaCand, -1, 1); + const theta = Math.acos(cosTheta); if (theta > EPSILON) { - const newZImagUnit = vecF.copy(newXimag).normalize() - const rotQuatUnit = quatD.setFromAxisAngle(newZImagUnit, -1.0 * theta) - const conj = quatE.copy(rotQuatUnit).conjugate() - const testZ = rotQuatUnit.multiplyQuaternions(rotQuatUnit.multiply(zAxis), conj) - const normal3 = vecG.copy(newZimag).cross(vecH.set(testZ.x, testZ.y, testZ.z)) - const cosTest = normal1.dot(normal3) / (normal1.length() * normal3.length()) - th = 1 - cosTest < EPSILON ** 2 ? -theta : theta + const newZImagUnit = vecF.copy(newXimag).normalize(); + const rotQuatUnit = quatD.setFromAxisAngle(newZImagUnit, -1.0 * theta); + const conj = quatE.copy(rotQuatUnit).conjugate(); + const testZ = rotQuatUnit.multiplyQuaternions( + rotQuatUnit.multiply(zAxis), + conj + ); + const normal3 = vecG + .copy(newZimag) + .cross(vecH.set(testZ.x, testZ.y, testZ.z)); + const cosTest = + normal1.dot(normal3) / (normal1.length() * normal3.length()); + th = 1 - cosTest < EPSILON ** 2 ? -theta : theta; } else { - th = 0 + th = 0; } - /* - * Special case for when we point directly along the Z axis - * Get the vector normal to the local-x, global-z, origin plane - */ + /* + * Special case for when we point directly along the Z axis + * Get the vector normal to the local-x, global-z, origin plane + */ } else if (newZ.z < 0) { - th = -Math.atan2(newX.y, newX.x) + th = -Math.atan2(newX.y, newX.x); } else { - th = -Math.atan2(newX.y, -newX.x) + th = -Math.atan2(newX.y, -newX.x); } - this.set(newZ.x, newZ.y, newZ.z, th) + this.set(newZ.x, newZ.y, newZ.z, th); - if (update) this.#onChangeCallback?.() + if (update) this.#onChangeCallback?.(); - return this + return this; } - toQuaternion (dest: Quaternion): Quaternion { - const lat = Math.acos(this.z) - const lon = 1 - Math.abs(this.z) > EPSILON ? Math.atan2(this.y, this.x) : 0 - const s0 = Math.sin(lon / 2) - const c0 = Math.cos(lon / 2) - const s1 = Math.sin(lat / 2) - const c1 = Math.cos(lat / 2) - const s2 = Math.sin(this.th / 2) - const c2 = Math.cos(this.th / 2) + toQuaternion(dest: Quaternion): Quaternion { + const lat = Math.acos(this.z); + const lon = 1 - Math.abs(this.z) > EPSILON ? Math.atan2(this.y, this.x) : 0; + const s0 = Math.sin(lon / 2); + const c0 = Math.cos(lon / 2); + const s1 = Math.sin(lat / 2); + const c1 = Math.cos(lat / 2); + const s2 = Math.sin(this.th / 2); + const c2 = Math.cos(this.th / 2); return dest.set( - (c0 * s1 * s2) - (s0 * s1 * c2), - (c0 * s1 * c2) + (s0 * s1 * s2), - (s0 * c1 * c2) + (c0 * c1 * s2), - (c0 * c1 * c2) - (s0 * c1 * s2), - ) + c0 * s1 * s2 - s0 * s1 * c2, + c0 * s1 * c2 + s0 * s1 * s2, + s0 * c1 * c2 + c0 * c1 * s2, + c0 * c1 * c2 - s0 * c1 * s2 + ); } - toEuler (dest: Euler) { - return dest.setFromQuaternion(this.toQuaternion(quatA), 'ZYX'); + toEuler(dest: Euler) { + return dest.setFromQuaternion(this.toQuaternion(quatA), "ZYX"); } } From fdf6940357c6d1377cad58b8beec156e295aeda4 Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 12:46:29 -0500 Subject: [PATCH 02/11] add units --- .prettierrc.cjs | 3 + package-lock.json | 50 ++++++++++ package.json | 1 + playground/main.ts | 198 +++++++++++++++++++++----------------- src/orientation-vector.ts | 31 ++++-- 5 files changed, 190 insertions(+), 93 deletions(-) create mode 100644 .prettierrc.cjs diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 0000000..1ffc7bd --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('@viamrobotics/prettier-config'); diff --git a/package-lock.json b/package-lock.json index b815fd4..d68edcc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@tweakpane/core": "^2.0.3", "@tweakpane/plugin-essentials": "^0.2.1", "@types/three": "^0.161.2", + "@viamrobotics/prettier-config": "^0.3.4", "three": "^0.162.0", "three-inspect": "^0.3.4", "trzy": "^0.3.17", @@ -619,6 +620,25 @@ "integrity": "sha512-IUMDPSXnYIbEO2IereEFcgcqfDREOgmbGqtrMpVPpACTU6pltYLwHgVkrnYv0XhWEcjio9sYEfIEzgn3c7nDqA==", "dev": true }, + "node_modules/@viamrobotics/prettier-config": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@viamrobotics/prettier-config/-/prettier-config-0.3.4.tgz", + "integrity": "sha512-1SOjP9WV1OHLsQJGUP4YnG/9r3yWFC9SczbmazEobWTNa/pzJwWI3dt8keuNn/bAv7kicAhukysiJeNtQyjWZg==", + "dev": true, + "peerDependencies": { + "prettier": ">=3 <4", + "prettier-plugin-svelte": ">=3 <4", + "prettier-plugin-tailwindcss": ">=0.4.0 <0.6" + }, + "peerDependenciesMeta": { + "prettier-plugin-svelte": { + "optional": true + }, + "prettier-plugin-tailwindcss": { + "optional": true + } + } + }, "node_modules/@vitest/expect": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", @@ -1193,6 +1213,22 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -1933,6 +1969,13 @@ "integrity": "sha512-IUMDPSXnYIbEO2IereEFcgcqfDREOgmbGqtrMpVPpACTU6pltYLwHgVkrnYv0XhWEcjio9sYEfIEzgn3c7nDqA==", "dev": true }, + "@viamrobotics/prettier-config": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@viamrobotics/prettier-config/-/prettier-config-0.3.4.tgz", + "integrity": "sha512-1SOjP9WV1OHLsQJGUP4YnG/9r3yWFC9SczbmazEobWTNa/pzJwWI3dt8keuNn/bAv7kicAhukysiJeNtQyjWZg==", + "dev": true, + "requires": {} + }, "@vitest/expect": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", @@ -2338,6 +2381,13 @@ "source-map-js": "^1.0.2" } }, + "prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "peer": true + }, "pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", diff --git a/package.json b/package.json index 6b582ea..152e5de 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "@tweakpane/core": "^2.0.3", "@tweakpane/plugin-essentials": "^0.2.1", "@types/three": "^0.161.2", + "@viamrobotics/prettier-config": "^0.3.4", "three": "^0.162.0", "three-inspect": "^0.3.4", "trzy": "^0.3.17", diff --git a/playground/main.ts b/playground/main.ts index 7d22146..05d3f4c 100644 --- a/playground/main.ts +++ b/playground/main.ts @@ -1,133 +1,159 @@ -import './main.css' -import * as THREE from 'three' -import { useTrzy } from 'trzy' -import { Pane, type InputBindingApi } from 'tweakpane' -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' -import * as EssentialsPlugin from '@tweakpane/plugin-essentials' -import * as RotationPlugin from '@0b5vr/tweakpane-plugin-rotation' -import { conversion } from './conversions' -import { type InputTypes, Units, orderOptions } from './types' -import { rotations } from './rotations' +import './main.css'; +import * as THREE from 'three'; +import { useTrzy } from 'trzy'; +import { Pane, type InputBindingApi } from 'tweakpane'; +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; +import * as EssentialsPlugin from '@tweakpane/plugin-essentials'; +import * as RotationPlugin from '@0b5vr/tweakpane-plugin-rotation'; +import { conversion } from './conversions'; +import { type InputTypes, Units, orderOptions } from './types'; +import { rotations } from './rotations'; +import { OrientationVector } from '../src/orientation-vector'; -const { scene, camera, renderer } = useTrzy() +const { scene, camera, renderer } = useTrzy(); -document.body.append(renderer.domElement) +document.body.append(renderer.domElement); -const loader = new GLTFLoader() +const loader = new GLTFLoader(); -const world = new THREE.Object3D() +const world = new THREE.Object3D(); // Viam's coordinate system. -world.rotateY(-Math.PI / 2) -world.rotateX(-Math.PI / 2) +world.rotateY(-Math.PI / 2); +world.rotateX(-Math.PI / 2); -scene.add(world) +scene.add(world); -const gridHelper = new THREE.GridHelper(0.75, 5) -scene.add(gridHelper) +const gridHelper = new THREE.GridHelper(0.75, 5); +scene.add(gridHelper); -const axesHelper = new THREE.AxesHelper(5) -world.add(axesHelper) +const axesHelper = new THREE.AxesHelper(5); +world.add(axesHelper); -const gltf = await loader.loadAsync('teapot.glb') -const object = gltf.scene +const gltf = await loader.loadAsync('teapot.glb'); +const object = gltf.scene; -object.children[0].rotateY(-Math.PI / 2) -object.children[0].rotateX(Math.PI / 2) +object.children[0].rotateY(-Math.PI / 2); +object.children[0].rotateX(Math.PI / 2); -const helper = new THREE.ArrowHelper(undefined, undefined, 0.25) -object.add(helper) +const helper = new THREE.ArrowHelper(undefined, undefined, 0.25); +object.add(helper); -scene.add(new THREE.AmbientLight()) -scene.add(new THREE.DirectionalLight()) +scene.add(new THREE.AmbientLight()); +scene.add(new THREE.DirectionalLight()); -camera.current.position.set(1.5, 1.5, -1.5) -camera.current.lookAt(0, 0, 0) +camera.current.position.set(1.5, 1.5, -1.5); +camera.current.lookAt(0, 0, 0); -world.add(object) +world.add(object); -const pane = new Pane() -pane.registerPlugin(EssentialsPlugin) -pane.registerPlugin(RotationPlugin) +const pane = new Pane(); +pane.registerPlugin(EssentialsPlugin); +pane.registerPlugin(RotationPlugin); -const inputs: any[] = [] +const inputs: any[] = []; const options = { units: Units.radians, }; -let paused = false +let paused = false; const update = (key: InputTypes, event) => { if (paused) { - return + return; } - conversion(key, options.units) + conversion(key, options.units); { - const q = rotations.quaternion - object.quaternion.set(q.x, q.y, q.z, q.w) + const q = rotations.quaternion; + object.quaternion.set(q.x, q.y, q.z, q.w); } - paused = true + paused = true; for (const input of inputs) { - if (input === event.target) continue - input.refresh() + if (input === event.target) continue; + input.refresh(); } - paused = false -} + paused = false; +}; -pane.addBinding(object, 'position') -pane.addBlade({ view: 'separator' }) +pane.addBinding(object, 'position'); +pane.addBlade({ view: 'separator' }); -pane.addBinding(options, 'units', { - view: 'radiogrid', - groupName: 'units', - size: [2, 1], - cells: (x: number) => ({ - title: x === 0 ? 'radians' : 'degrees', - value: x, - }), +pane + .addBinding(options, 'units', { + view: 'radiogrid', + groupName: 'units', + size: [2, 1], + cells: (x: number) => ({ + title: x === 0 ? 'radians' : 'degrees', + value: x, + }), - label: 'units', -}).on('change', e => update('quaternion', e)); + label: 'units', + }) + .on('change', (e) => update('quaternion', e)); -pane.addBlade({ view: 'separator' }) +pane.addBlade({ view: 'separator' }); inputs.push( - pane.addBinding(rotations, 'ov', { - label: 'orientation vector (th / xyz)' - }).on('change', e => update('ov', e)) -) -pane.addBlade({ view: 'separator' }) + pane + .addBinding(rotations, 'ov', { + label: 'orientation vector (th / xyz)', + }) + .on('change', (e) => update('ov', e)) +); +pane.addBlade({ view: 'separator' }); inputs.push( - pane.addBinding(rotations, 'quaternion', { label: 'quaternion (xyz / w)'}).on('change', e => update('quaternion', e)) -) -pane.addBlade({ view: 'separator' }) + pane + .addBinding(rotations, 'quaternion', { label: 'quaternion (xyz / w)' }) + .on('change', (e) => update('quaternion', e)) +); +pane.addBlade({ view: 'separator' }); inputs.push( - pane.addBinding(rotations.euler, 'xyz', { label: 'euler' }).on('change', e => update('euler', e)) -) + pane + .addBinding(rotations.euler, 'xyz', { label: 'euler' }) + .on('change', (e) => update('euler', e)) +); inputs.push( - pane.addBinding(rotations.euler, 'order', { - label: '', - options: orderOptions, - }).on('change', e => update('euler', e)) -) -pane.addBlade({ view: 'separator' }) + pane + .addBinding(rotations.euler, 'order', { + label: '', + options: orderOptions, + }) + .on('change', (e) => update('euler', e)) +); +pane.addBlade({ view: 'separator' }); inputs.push( - pane.addBinding(rotations.matrix, 'row1', { label: 'matrix' }).on('change', e => update('matrix', e)) -) + pane + .addBinding(rotations.matrix, 'row1', { label: 'matrix' }) + .on('change', (e) => update('matrix', e)) +); inputs.push( - pane.addBinding(rotations.matrix, 'row2', { label: '' }).on('change', e => update('matrix', e)) -) + pane + .addBinding(rotations.matrix, 'row2', { label: '' }) + .on('change', (e) => update('matrix', e)) +); inputs.push( - pane.addBinding(rotations.matrix, 'row3', { label: '' }).on('change', e => update('matrix', e)) -) -pane.addBlade({ view: 'separator' }) + pane + .addBinding(rotations.matrix, 'row3', { label: '' }) + .on('change', (e) => update('matrix', e)) +); +pane.addBlade({ view: 'separator' }); inputs.push( - pane.addBinding(rotations.axisAngle, 'xyz', { label: 'axis angle' }).on('change', e => update('axis angle', e)) -) + pane + .addBinding(rotations.axisAngle, 'xyz', { label: 'axis angle' }) + .on('change', (e) => update('axis angle', e)) +); inputs.push( - pane.addBinding(rotations.axisAngle, 'angle', { label: '' }).on('change', e => update('axis angle', e)) -) + pane + .addBinding(rotations.axisAngle, 'angle', { label: '' }) + .on('change', (e) => update('axis angle', e)) +); + +const obj = { ov: new OrientationVector() }; +pane + .addBinding(obj, 'ov') + .on('change', () => console.log(obj.ov.x, obj.ov.y, obj.ov.z, obj.ov.th)); diff --git a/src/orientation-vector.ts b/src/orientation-vector.ts index f432646..1bbfcf6 100644 --- a/src/orientation-vector.ts +++ b/src/orientation-vector.ts @@ -1,5 +1,5 @@ -import { Euler, Quaternion, Vector3, MathUtils } from "three"; -import { EPSILON } from "./constants"; +import { Euler, Quaternion, Vector3, MathUtils } from 'three'; +import { EPSILON } from './constants'; const xAxis = new Quaternion(-1, 0, 0, 0); const zAxis = new Quaternion(0, 0, +1, 0); @@ -33,6 +33,7 @@ const vecH = new Vector3(); export class OrientationVector { readonly isOrientationVector = true; + #units: 'degrees' | 'radians' = 'radians'; #vec = new Vector3(); #th = 0; @@ -43,6 +44,10 @@ export class OrientationVector { this.#th = th; } + get units(): 'degrees' | 'radians' { + return this.#units; + } + /** * The vector's x component. * @default 0 @@ -87,21 +92,27 @@ export class OrientationVector { * @default 0 */ get th() { + if (this.#units === 'degrees') { + return MathUtils.radToDeg(this.#th); + } return this.#th; } set th(value: number) { - this.#th = value; + if (this.#units === 'degrees') { + this.#th = MathUtils.degToRad(value); + } else { + this.#th = value; + } this.#onChangeCallback?.(); } get w() { - return this.#th; + return this.th; } set w(value: number) { - this.#th = value; - this.#onChangeCallback?.(); + this.th = value; } _onChange(callback: () => void) { @@ -121,6 +132,12 @@ export class OrientationVector { return this; } + setUnits(units: 'degrees' | 'radians'): this { + this.#units = units; + + return this; + } + /** * Computes the length of this orientation vector. */ @@ -245,6 +262,6 @@ export class OrientationVector { } toEuler(dest: Euler) { - return dest.setFromQuaternion(this.toQuaternion(quatA), "ZYX"); + return dest.setFromQuaternion(this.toQuaternion(quatA), 'ZYX'); } } From 066e8b779b03e7793e0fc444deb3e342e1d1b331 Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 12:47:16 -0500 Subject: [PATCH 03/11] remove test code --- playground/main.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/playground/main.ts b/playground/main.ts index 05d3f4c..e35c921 100644 --- a/playground/main.ts +++ b/playground/main.ts @@ -152,8 +152,3 @@ inputs.push( .addBinding(rotations.axisAngle, 'angle', { label: '' }) .on('change', (e) => update('axis angle', e)) ); - -const obj = { ov: new OrientationVector() }; -pane - .addBinding(obj, 'ov') - .on('change', () => console.log(obj.ov.x, obj.ov.y, obj.ov.z, obj.ov.th)); From 7e0089af089e3541815dbde6df8cf943690883e0 Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 12:47:39 -0500 Subject: [PATCH 04/11] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 152e5de..b68b69e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@viamrobotics/three", - "version": "0.0.3", + "version": "0.0.4", "license": "Apache-2.0", "type": "module", "files": [ From 5fefa68f9a2631b86f32ed7e3e896c092035444a Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 12:52:08 -0500 Subject: [PATCH 05/11] fix prettier config --- .prettierrc.cjs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.prettierrc.cjs b/.prettierrc.cjs index 917a5a3..1ffc7bd 100644 --- a/.prettierrc.cjs +++ b/.prettierrc.cjs @@ -1,9 +1,3 @@ -<<<<<<< HEAD 'use strict'; module.exports = require('@viamrobotics/prettier-config'); -======= -'use strict' - -module.exports = '@viamrobotics/prettier-config'; ->>>>>>> 3aea62f3aab31018508a69ba3cc6087ced38086a From 9ea9dd2015cadb5734931df625ccb8a82de633ff Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 13:03:10 -0500 Subject: [PATCH 06/11] run format --- README.md | 23 ++-- playground/conversions.ts | 242 +++++++++++++++++++------------------- playground/main.css | 2 +- playground/main.ts | 11 +- playground/rotations.ts | 8 +- playground/types.ts | 14 +-- playground/vite-env.d.ts | 2 +- src/constants.ts | 2 +- src/main.ts | 4 +- src/object-3d.ts | 24 ++-- src/orientation-vector.ts | 30 +++-- src/vite-env.d.ts | 2 +- test/ov-to-qaut.test.ts | 115 +++++++++++------- test/quat-to-ov.test.ts | 123 +++++++++++-------- tsconfig.build.json | 2 +- tsconfig.json | 2 +- vite.site.config.ts | 4 +- 17 files changed, 345 insertions(+), 265 deletions(-) diff --git a/README.md b/README.md index d14989e..b11146d 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,32 @@ # @viamrobotics/three + Viam-related utilities for THREE.js ### Orientation Vector + A class for Viam's [Orientation Vector](https://docs.viam.com/internals/orientation-vector/#edit-on-github) rotation type. This class closely resembles other rotation formats like `THREE.Quaternion` or `THREE.Euler`. ```ts -import * as THREE from 'three' -import { OrientationVector } from '@viamrobotics/three' +import * as THREE from 'three'; +import { OrientationVector } from '@viamrobotics/three'; -const ov = new OrientationVector() -const quat = new THREE.Quaternion() -const euler = new THREE.Euler() +const ov = new OrientationVector(); +const quat = new THREE.Quaternion(); +const euler = new THREE.Euler(); // Common conversions: -ov.toQuaternion(quat) -ov.toEuler(euler) +ov.toQuaternion(quat); +ov.toEuler(euler); -ov.setFromQuaternion(quat) +ov.setFromQuaternion(quat); ``` ### ViamObject3D + Extends THREE.Object3D and adds an `.orientationVector` that auto-updates when other rotation formats are updated. ```ts -import { ViamObject3D } from '@viamrobotics/three' -``` \ No newline at end of file +import { ViamObject3D } from '@viamrobotics/three'; +``` diff --git a/playground/conversions.ts b/playground/conversions.ts index 37310d7..361a143 100644 --- a/playground/conversions.ts +++ b/playground/conversions.ts @@ -1,56 +1,52 @@ -import * as THREE from 'three' -import { Units, type InputTypes } from './types' -import { rotations } from './rotations' -import { OrientationVector, ViamObject3D } from '../src/main' +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable id-length */ +/* eslint-disable unicorn/prefer-switch */ +/* eslint-disable @typescript-eslint/no-unnecessary-condition */ +import * as THREE from 'three'; +import { Units, type InputTypes } from './types'; +import { rotations } from './rotations'; +import { OrientationVector, ViamObject3D } from '../src/main'; // These globals are just added to allow playing around in the console as well. -window.THREE = THREE +window.THREE = THREE; // @ts-expect-error For debugging -window.OrientationVector = OrientationVector +window.OrientationVector = OrientationVector; // @ts-expect-error For debugging -window.ViamObject3D = ViamObject3D +window.ViamObject3D = ViamObject3D; -const v3 = new THREE.Vector3() -const quat = new THREE.Quaternion() -const euler = new THREE.Euler() -const m4 = new THREE.Matrix4() -const ov = new OrientationVector() +const v3 = new THREE.Vector3(); +const quat = new THREE.Quaternion(); +const euler = new THREE.Euler(); +const m4 = new THREE.Matrix4(); +const ov = new OrientationVector(); const toRad = (x: number, unit: Units): number => { - if (unit === Units.degrees) { - return x / 180 * Math.PI - } else { - return x - } -} + return unit === Units.degrees ? (x / 180) * Math.PI : x; +}; const toAngle = (x: number, unit: Units): number => { - if (unit === Units.degrees) { - return x * 180 / Math.PI - } else { - return x - } -} + return unit === Units.degrees ? (x * 180) / Math.PI : x; +}; const toReal = (x: number): number => { - if (!Number.isNaN(x) && Number.isFinite(x)) { - return Number.parseFloat(x.toFixed(7)) - } else { - return x - } -} + return !Number.isNaN(x) && Number.isFinite(x) + ? Number.parseFloat(x.toFixed(7)) + : x; +}; const toFixedWidth = (x: number): number => { - if (!Number.isNaN(x) && Number.isFinite(x)) { - let s = x.toFixed(7) - if (x >= 0) s = ' ' + s - return Number.parseFloat(s) - } else { - return x - } -} + if (!Number.isNaN(x) && Number.isFinite(x)) { + let s = x.toFixed(7); + if (x >= 0) { + s = ` ${s}`; + } + return Number.parseFloat(s); + } + + return x; +}; export const conversion = (type: InputTypes, units: Units) => { if (type === 'ov') { @@ -59,117 +55,125 @@ export const conversion = (type: InputTypes, units: Units) => { rotations.ov.y, rotations.ov.z, toRad(rotations.ov.w, units) - ) - - quat.copy(ov.toQuaternion(quat)) + ); + quat.copy(ov.toQuaternion(quat)); } else if (type === 'matrix') { - const { row1, row2, row3 } = rotations.matrix + const { row1, row2, row3 } = rotations.matrix; m4.set( - row1.x, row1.y, row1.z, 1, - row2.x, row2.y, row2.z, 1, - row3.x, row3.y, row3.z, 1, - 0, 0, 0, 1 - ) - - quat.setFromRotationMatrix(m4) - + row1.x, + row1.y, + row1.z, + 1, + row2.x, + row2.y, + row2.z, + 1, + row3.x, + row3.y, + row3.z, + 1, + 0, + 0, + 0, + 1 + ); + + quat.setFromRotationMatrix(m4); } else if (type === 'quaternion') { quat.set( rotations.quaternion.x, rotations.quaternion.y, rotations.quaternion.z, rotations.quaternion.w - ) - + ); } else if (type === 'axis angle') { - const aa = rotations.axisAngle - const axis = v3 - axis.set(aa.xyz.x, aa.xyz.y, aa.xyz.z) - axis.normalize() - - quat.setFromAxisAngle(axis, toRad(aa.angle, units)) + const aa = rotations.axisAngle; + const axis = v3; + axis.set(aa.xyz.x, aa.xyz.y, aa.xyz.z); + axis.normalize(); + quat.setFromAxisAngle(axis, toRad(aa.angle, units)); } else if (type === 'axis with angle magnitude') { - const aa = rotations.axisAngleMagnitude - const axis = v3 - axis.set(aa.x, aa.y, aa.z) - - const angle = toRad(axis.length(), units) - axis.normalize() + const aa = rotations.axisAngleMagnitude; + const axis = v3; + axis.set(aa.x, aa.y, aa.z); - quat.setFromAxisAngle(axis, angle) + const angle = toRad(axis.length(), units); + axis.normalize(); + quat.setFromAxisAngle(axis, angle); } else if (type === 'euler') { - const eu = rotations.euler - - quat.setFromEuler(euler.set( - toRad(eu.xyz.x, units), - toRad(eu.xyz.y, units), - toRad(eu.xyz.z, units), - eu.order as THREE.EulerOrder - )) - + const eu = rotations.euler; + + quat.setFromEuler( + euler.set( + toRad(eu.xyz.x, units), + toRad(eu.xyz.y, units), + toRad(eu.xyz.z, units), + eu.order as THREE.EulerOrder + ) + ); } - quat.normalize() + quat.normalize(); - rotations.quaternion.x = toReal(quat.x) - rotations.quaternion.y = toReal(quat.y) - rotations.quaternion.z = toReal(quat.z) - rotations.quaternion.w = toReal(quat.w) + rotations.quaternion.x = toReal(quat.x); + rotations.quaternion.y = toReal(quat.y); + rotations.quaternion.z = toReal(quat.z); + rotations.quaternion.w = toReal(quat.w); - ov.setFromQuaternion(quat) - rotations.ov.w = toAngle(ov.th, units) - rotations.ov.x = ov.x - rotations.ov.y = ov.y - rotations.ov.z = ov.z + ov.setFromQuaternion(quat); + rotations.ov.w = toAngle(ov.th, units); + rotations.ov.x = ov.x; + rotations.ov.y = ov.y; + rotations.ov.z = ov.z; - m4.makeRotationFromQuaternion(quat) + m4.makeRotationFromQuaternion(quat); { - const r = m4.elements - rotations.matrix.row1.x = toFixedWidth(r[0]!) - rotations.matrix.row1.y = toFixedWidth(r[4]!) - rotations.matrix.row1.z = toFixedWidth(r[8]!) - rotations.matrix.row2.x = toFixedWidth(r[1]!) - rotations.matrix.row2.y = toFixedWidth(r[5]!) - rotations.matrix.row2.z = toFixedWidth(r[9]!) - rotations.matrix.row3.x = toFixedWidth(r[2]!) - rotations.matrix.row3.y = toFixedWidth(r[6]!) - rotations.matrix.row3.z = toFixedWidth(r[10]!) + const r = m4.elements; + rotations.matrix.row1.x = toFixedWidth(r[0]!); + rotations.matrix.row1.y = toFixedWidth(r[4]!); + rotations.matrix.row1.z = toFixedWidth(r[8]!); + rotations.matrix.row2.x = toFixedWidth(r[1]!); + rotations.matrix.row2.y = toFixedWidth(r[5]!); + rotations.matrix.row2.z = toFixedWidth(r[9]!); + rotations.matrix.row3.x = toFixedWidth(r[2]!); + rotations.matrix.row3.y = toFixedWidth(r[6]!); + rotations.matrix.row3.z = toFixedWidth(r[10]!); } - const axis = [0, 0, 0] - const angle = 2 * Math.acos(quat.w) + const axis = [0, 0, 0]; + const angle = 2 * Math.acos(quat.w); - if (1 - (quat.w * quat.w) < 0.000001) { - axis[0] = quat.x - axis[1] = quat.y - axis[2] = quat.z + if (1 - quat.w * quat.w < 0.000_001) { + axis[0] = quat.x; + axis[1] = quat.y; + axis[2] = quat.z; } else { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/ - const s = Math.sqrt(1 - (quat.w * quat.w)) - axis[0] = quat.x / s - axis[1] = quat.y / s - axis[2] = quat.z / s + const s = Math.sqrt(1 - quat.w * quat.w); + axis[0] = quat.x / s; + axis[1] = quat.y / s; + axis[2] = quat.z / s; } - rotations.axisAngle.xyz.x = toReal(axis[0]) - rotations.axisAngle.xyz.y = toReal(axis[1]) - rotations.axisAngle.xyz.z = toReal(axis[2]) - rotations.axisAngle.angle = toReal(toAngle(angle, units)) + rotations.axisAngle.xyz.x = toReal(axis[0]); + rotations.axisAngle.xyz.y = toReal(axis[1]); + rotations.axisAngle.xyz.z = toReal(axis[2]); + rotations.axisAngle.angle = toReal(toAngle(angle, units)); + + rotations.axisAngleMagnitude.x = toReal(toAngle(axis[0] * angle, units)); + rotations.axisAngleMagnitude.y = toReal(toAngle(axis[1] * angle, units)); + rotations.axisAngleMagnitude.z = toReal(toAngle(axis[2] * angle, units)); - rotations.axisAngleMagnitude.x = toReal(toAngle(axis[0] * angle, units)) - rotations.axisAngleMagnitude.y = toReal(toAngle(axis[1] * angle, units)) - rotations.axisAngleMagnitude.z = toReal(toAngle(axis[2] * angle, units)) - { - euler.setFromRotationMatrix(m4, rotations.euler.order as THREE.EulerOrder) - const [x, y, z] = euler.toArray() as [number, number, number] - rotations.euler.xyz.x = toReal(toAngle(x, units)) - rotations.euler.xyz.y = toReal(toAngle(y, units)) - rotations.euler.xyz.z = toReal(toAngle(z, units)) + euler.setFromRotationMatrix(m4, rotations.euler.order as THREE.EulerOrder); + const [x, y, z] = euler.toArray() as [number, number, number]; + rotations.euler.xyz.x = toReal(toAngle(x, units)); + rotations.euler.xyz.y = toReal(toAngle(y, units)); + rotations.euler.xyz.z = toReal(toAngle(z, units)); } -} +}; diff --git a/playground/main.css b/playground/main.css index d7f2533..9576410 100644 --- a/playground/main.css +++ b/playground/main.css @@ -1,7 +1,7 @@ body { margin: 0; overflow: hidden; - font-family: system-ui + font-family: system-ui; } canvas { diff --git a/playground/main.ts b/playground/main.ts index 126800c..04a9e85 100644 --- a/playground/main.ts +++ b/playground/main.ts @@ -1,3 +1,9 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable sonarjs/no-duplicate-string */ +/* eslint-disable id-length */ +/* eslint-disable unicorn/no-array-push-push */ import './main.css'; import * as THREE from 'three'; import { useTrzy } from 'trzy'; @@ -72,7 +78,10 @@ const update = (key: InputTypes, event: TpChangeEvent) => { paused = true; for (const input of inputs) { - if (input === event.target) continue; + if (input === event.target) { + continue; + } + input.refresh(); } diff --git a/playground/rotations.ts b/playground/rotations.ts index 3177969..392958c 100644 --- a/playground/rotations.ts +++ b/playground/rotations.ts @@ -3,7 +3,7 @@ export const rotations = { quaternion: { x: 0, y: 0, z: 0, w: 1 }, euler: { xyz: { x: 0, y: 0, z: 0 }, - order: 'ZYX' + order: 'ZYX', }, matrix: { row1: { x: 1, y: 0, z: 0 }, @@ -12,7 +12,7 @@ export const rotations = { }, axisAngle: { xyz: { x: 0, y: 0, z: 0 }, - angle: 0 + angle: 0, }, - axisAngleMagnitude: { x: 0, y: 0, z: 0 } -} + axisAngleMagnitude: { x: 0, y: 0, z: 0 }, +}; diff --git a/playground/types.ts b/playground/types.ts index c85fb89..09c0708 100644 --- a/playground/types.ts +++ b/playground/types.ts @@ -1,18 +1,18 @@ - export const enum Units { radians, degrees, } -export type InputTypes = +export type InputTypes = | 'ov' | 'quaternion' | 'euler' | 'matrix' | 'axis angle' - | 'axis with angle magnitude' - -export type Opts = THREE.EulerOrder + | 'axis with angle magnitude'; + +export type Opts = THREE.EulerOrder; -export const orderOptions = ['XYZ', 'YXZ', 'ZXY', 'ZYX', 'YZX', 'XZY'] - .map(opt => ({ text: opt.toLowerCase(), value: opt })) +export const orderOptions = ['XYZ', 'YXZ', 'ZXY', 'ZYX', 'YZX', 'XZY'].map( + (opt) => ({ text: opt.toLowerCase(), value: opt }) +); diff --git a/playground/vite-env.d.ts b/playground/vite-env.d.ts index 151aa68..11f02fe 100644 --- a/playground/vite-env.d.ts +++ b/playground/vite-env.d.ts @@ -1 +1 @@ -/// \ No newline at end of file +/// diff --git a/src/constants.ts b/src/constants.ts index 0a2daf5..033eff9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1 +1 @@ -export const EPSILON = 0.0001 +export const EPSILON = 0.0001; diff --git a/src/main.ts b/src/main.ts index 8ca6ed2..2d55fff 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,2 +1,2 @@ -export { OrientationVector } from './orientation-vector' -export { ViamObject3D } from './object-3d' +export { OrientationVector } from './orientation-vector'; +export { ViamObject3D } from './object-3d'; diff --git a/src/object-3d.ts b/src/object-3d.ts index fa3a89a..c6193d7 100644 --- a/src/object-3d.ts +++ b/src/object-3d.ts @@ -1,18 +1,22 @@ -import { Object3D } from 'three' -import { OrientationVector } from './orientation-vector' +/* eslint-disable no-underscore-dangle */ -const noop = () => { /* do nothing */ } +import { Object3D } from 'three'; +import { OrientationVector } from './orientation-vector'; + +const noop = () => { + /* do nothing */ +}; /** * Nearly identical to THREE.Object3D, but with an attached orientation vector that auto-updates. */ export class ViamObject3D extends Object3D { - isViamObject3D = true + isViamObject3D = true; - orientationVector: OrientationVector + orientationVector: OrientationVector; - constructor () { - super() + constructor() { + super(); const ov = new OrientationVector(); const ovChangeCallback = () => ov.setFromQuaternion(this.quaternion, false); @@ -22,12 +26,12 @@ export class ViamObject3D extends Object3D { const quatChangeCallback = () => { quatOldChangeCallback(); ovChangeCallback(); - } + }; const eulerChangeCallback = () => { eulerOldChangeCallback(); ovChangeCallback(); - } + }; ov._onChange(() => { this.quaternion._onChangeCallback = noop; @@ -38,7 +42,7 @@ export class ViamObject3D extends Object3D { this.quaternion._onChangeCallback = quatChangeCallback; this.rotation._onChangeCallback = eulerChangeCallback; - }); + }); this.quaternion._onChange(quatChangeCallback); this.rotation._onChange(eulerChangeCallback); diff --git a/src/orientation-vector.ts b/src/orientation-vector.ts index 1bbfcf6..3a8b96d 100644 --- a/src/orientation-vector.ts +++ b/src/orientation-vector.ts @@ -19,8 +19,10 @@ const vecF = new Vector3(); const vecG = new Vector3(); const vecH = new Vector3(); -// Golang: https://github.com/viamrobotics/rdk/blob/main/spatialmath/orientationVector.go -// Rust: https://github.com/viamrobotics/rust-utils/blob/main/src/spatialmath/utils.rs +/** + * Golang: https://github.com/viamrobotics/rdk/blob/main/spatialmath/orientationVector.go + * Rust: https://github.com/viamrobotics/rust-utils/blob/main/src/spatialmath/utils.rs + */ /** * Viam’s orientation vector is a method for describing the orientation of an object in 3D space. @@ -99,11 +101,7 @@ export class OrientationVector { } set th(value: number) { - if (this.#units === 'degrees') { - this.#th = MathUtils.degToRad(value); - } else { - this.#th = value; - } + this.#th = this.#units === 'degrees' ? MathUtils.degToRad(value) : value; this.#onChangeCallback?.(); } @@ -158,8 +156,12 @@ export class OrientationVector { } fromArray(array: number[], offset = 0) { - this.#vec.set(array[offset]!, array[offset + 1]!, array[offset + 2]!); - this.th = array[offset + 3]!; + this.#vec.set( + array[offset] ?? 0, + array[offset + 1] ?? 0, + array[offset + 2] ?? 0 + ); + this.th = array[offset + 3] ?? 0; this.#onChangeCallback?.(); @@ -210,11 +212,11 @@ export class OrientationVector { if (theta > EPSILON) { const newZImagUnit = vecF.copy(newXimag).normalize(); - const rotQuatUnit = quatD.setFromAxisAngle(newZImagUnit, -1.0 * theta); - const conj = quatE.copy(rotQuatUnit).conjugate(); + const rotQuatUnit = quatD.setFromAxisAngle(newZImagUnit, -1 * theta); + const conj2 = quatE.copy(rotQuatUnit).conjugate(); const testZ = rotQuatUnit.multiplyQuaternions( rotQuatUnit.multiply(zAxis), - conj + conj2 ); const normal3 = vecG .copy(newZimag) @@ -238,7 +240,9 @@ export class OrientationVector { this.set(newZ.x, newZ.y, newZ.z, th); - if (update) this.#onChangeCallback?.(); + if (update) { + this.#onChangeCallback?.(); + } return this; } diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 151aa68..11f02fe 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -1 +1 @@ -/// \ No newline at end of file +/// diff --git a/test/ov-to-qaut.test.ts b/test/ov-to-qaut.test.ts index bc337ab..e531c32 100644 --- a/test/ov-to-qaut.test.ts +++ b/test/ov-to-qaut.test.ts @@ -1,11 +1,11 @@ -import { expect, test } from 'vitest' -import { Quaternion } from 'three' -import { OrientationVector } from '../src/main' -import { EPSILON } from '../src/constants' +import { expect, test } from 'vitest'; +import { Quaternion } from 'three'; +import { OrientationVector } from '../src/main'; +import { EPSILON } from '../src/constants'; -const ov = new OrientationVector() -const expectedQuat = new Quaternion() -const convertedQuat = new Quaternion() +const ov = new OrientationVector(); +const expectedQuat = new Quaternion(); +const convertedQuat = new Quaternion(); const areQuaternionsApproxEqual = (q1: Quaternion, q2: Quaternion) => { return ( @@ -13,58 +13,85 @@ const areQuaternionsApproxEqual = (q1: Quaternion, q2: Quaternion) => { Math.abs(q1.y) - Math.abs(q2.y) < EPSILON && Math.abs(q1.z) - Math.abs(q2.z) < EPSILON && Math.abs(q1.w) - Math.abs(q2.w) < EPSILON - ) -} + ); +}; const assertApproxEqual = ( - ovx: number, ovy: number, ovz: number, ovth: number, - qw: number, qx: number, qy: number, qz: number, + ovx: number, + ovy: number, + ovz: number, + ovth: number, + qw: number, + qx: number, + qy: number, + qz: number ) => { - ov.set(ovx, ovy, ovz, ovth) - expectedQuat.set(qx, qy, qz, qw) - ov.toQuaternion(convertedQuat) + ov.set(ovx, ovy, ovz, ovth); + expectedQuat.set(qx, qy, qz, qw); + ov.toQuaternion(convertedQuat); - expect(areQuaternionsApproxEqual(convertedQuat, expectedQuat)).toBeTruthy() -} + expect(areQuaternionsApproxEqual(convertedQuat, expectedQuat)).toBeTruthy(); +}; test('orientation vector to quaternion works', () => { assertApproxEqual( - 0.0, -1.0, 0.0, 1.5707963267948966, - 0.7071067811865476, 0.7071067811865476, 0.0, 0.0 - ) + 0, + -1, + 0, + 1.570_796_326_794_896_6, + 0.707_106_781_186_547_6, + 0.707_106_781_186_547_6, + 0, + 0 + ); assertApproxEqual( - 0.0, 1.0, 0.0, -1.5707963267948966, - 0.7071067811865476, -0.7071067811865476, 0.0, 0.0 - ) + 0, + 1, + 0, + -1.570_796_326_794_896_6, + 0.707_106_781_186_547_6, + -0.707_106_781_186_547_6, + 0, + 0 + ); - assertApproxEqual( - -0.5376, 0.0, 0.8432, -1.0 * Math.PI, - 0.96, 0.0, -0.28, 0.0 - ) + assertApproxEqual(-0.5376, 0, 0.8432, -1 * Math.PI, 0.96, 0, -0.28, 0); - assertApproxEqual( - 0.0, 0.0, 1.0, -0.5675882184166557, - 0.96, 0.0, 0.0, -0.28 - ) + assertApproxEqual(0, 0, 1, -0.567_588_218_416_655_7, 0.96, 0, 0, -0.28); assertApproxEqual( - 0.0, 0.5376, 0.8432, -1.5707963267948966, - 0.96, -0.28, 0.0, 0.0 - ) + 0, + 0.5376, + 0.8432, + -1.570_796_326_794_896_6, + 0.96, + -0.28, + 0, + 0 + ); assertApproxEqual( - 0.0, -0.5376, 0.8432, 1.5707963267948966, - 0.96, 0.28, 0.0, 0.0 - ) + 0, + -0.5376, + 0.8432, + 1.570_796_326_794_896_6, + 0.96, + 0.28, + 0, + 0 + ); - assertApproxEqual( - 0.0, 1.0, 0.0, -1.0 * Math.PI, - 0.5, -0.5, -0.5, -0.5 - ) + assertApproxEqual(0, 1, 0, -1 * Math.PI, 0.5, -0.5, -0.5, -0.5); assertApproxEqual( - 0.5048437942940054, 0.5889844266763397, 0.631054742867507, 0.02, - 0.816632212270443, -0.17555966025413142, 0.39198397193979817, 0.3855375485164001 - ) -}) + 0.504_843_794_294_005_4, + 0.588_984_426_676_339_7, + 0.631_054_742_867_507, + 0.02, + 0.816_632_212_270_443, + -0.175_559_660_254_131_42, + 0.391_983_971_939_798_17, + 0.385_537_548_516_400_1 + ); +}); diff --git a/test/quat-to-ov.test.ts b/test/quat-to-ov.test.ts index 3cf3135..cf44390 100644 --- a/test/quat-to-ov.test.ts +++ b/test/quat-to-ov.test.ts @@ -1,72 +1,101 @@ -import { expect, test } from 'vitest' -import * as THREE from 'three' -import { OrientationVector } from '../src/main' -import { EPSILON } from '../src/constants' +import { expect, test } from 'vitest'; +import * as THREE from 'three'; +import { OrientationVector } from '../src/main'; +import { EPSILON } from '../src/constants'; -const quat = new THREE.Quaternion() -const expectedOv = new OrientationVector() -const convertedOv = new OrientationVector() -const vecA = new THREE.Vector3() -const vecB = new THREE.Vector3() +const quat = new THREE.Quaternion(); +const expectedOv = new OrientationVector(); +const convertedOv = new OrientationVector(); +const vecA = new THREE.Vector3(); +const vecB = new THREE.Vector3(); const areOvsApproxEqual = (ov1: OrientationVector, ov2: OrientationVector) => { - const vecDiff = vecA.set(ov1.x, ov1.y, ov1.z).sub(vecB.set(ov2.x, ov2.y, ov2.z)) + const vecDiff = vecA + .set(ov1.x, ov1.y, ov1.z) + .sub(vecB.set(ov2.x, ov2.y, ov2.z)); return ( Math.abs(vecDiff.lengthSq()) < EPSILON && Math.abs(ov1.th) - Math.abs(ov2.th) < EPSILON - ) -} + ); +}; const assertApproxEqual = ( - qw: number, qx: number, qy: number, qz: number, - ovx: number, ovy: number, ovz: number, ovth: number + qw: number, + qx: number, + qy: number, + qz: number, + ovx: number, + ovy: number, + ovz: number, + ovth: number ) => { - quat.set(qx, qy, qz, qw) - expectedOv.set(ovx, ovy, ovz, ovth) - convertedOv.setFromQuaternion(quat) + quat.set(qx, qy, qz, qw); + expectedOv.set(ovx, ovy, ovz, ovth); + convertedOv.setFromQuaternion(quat); - expect(areOvsApproxEqual(convertedOv, expectedOv)).toBeTruthy() -} + expect(areOvsApproxEqual(convertedOv, expectedOv)).toBeTruthy(); +}; test('quaternion to orientation vector works', () => { assertApproxEqual( - 0.7071067811865476, 0.7071067811865476, 0.0, 0.0, - 0.0, -1.0, 0.0, 1.5707963267948966 - ) + 0.707_106_781_186_547_6, + 0.707_106_781_186_547_6, + 0, + 0, + 0, + -1, + 0, + 1.570_796_326_794_896_6 + ); assertApproxEqual( - 0.7071067811865476, -0.7071067811865476, 0.0, 0.0, - 0.0, 1.0, 0.0, -1.5707963267948966 - ) + 0.707_106_781_186_547_6, + -0.707_106_781_186_547_6, + 0, + 0, + 0, + 1, + 0, + -1.570_796_326_794_896_6 + ); - assertApproxEqual( - 0.96, 0.0, -0.28, 0.0, - -0.5376, 0.0, 0.8432, -1.0 * Math.PI - ) + assertApproxEqual(0.96, 0, -0.28, 0, -0.5376, 0, 0.8432, -1 * Math.PI); - assertApproxEqual( - 0.96, 0.0, 0.0, -0.28, - 0.0, 0.0, 1.0, -0.5675882184166557, - ) + assertApproxEqual(0.96, 0, 0, -0.28, 0, 0, 1, -0.567_588_218_416_655_7); assertApproxEqual( - 0.96, -0.28, 0.0, 0.0, - 0.0, 0.5376, 0.8432, -1.5707963267948966 - ) + 0.96, + -0.28, + 0, + 0, + 0, + 0.5376, + 0.8432, + -1.570_796_326_794_896_6 + ); assertApproxEqual( - 0.96, 0.28, 0.0, 0.0, - 0.0, -0.5376, 0.8432, 1.5707963267948966 - ) + 0.96, + 0.28, + 0, + 0, + 0, + -0.5376, + 0.8432, + 1.570_796_326_794_896_6 + ); - assertApproxEqual( - 0.5, -0.5, -0.5, -0.5, - 0.0, 1.0, 0.0, -1.0 * Math.PI - ) + assertApproxEqual(0.5, -0.5, -0.5, -0.5, 0, 1, 0, -1 * Math.PI); assertApproxEqual( - 0.816632212270443, -0.17555966025413142, 0.39198397193979817, 0.3855375485164001, - 0.5048437942940054, 0.5889844266763397, 0.631054742867507, 0.02 - ) -}) + 0.816_632_212_270_443, + -0.175_559_660_254_131_42, + 0.391_983_971_939_798_17, + 0.385_537_548_516_400_1, + 0.504_843_794_294_005_4, + 0.588_984_426_676_339_7, + 0.631_054_742_867_507, + 0.02 + ); +}); diff --git a/tsconfig.build.json b/tsconfig.build.json index f45d110..b313cea 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -5,7 +5,7 @@ "declaration": true, "emitDeclarationOnly": true, "rootDir": "src", - "outDir": "dist", + "outDir": "dist" }, "include": ["src/**/*"] } diff --git a/tsconfig.json b/tsconfig.json index 46dda75..04fae9c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "target": "esnext", "module": "esnext", "moduleResolution": "node", - "noEmit": true, + "noEmit": true }, "include": [ ".eslintrc.cjs", diff --git a/vite.site.config.ts b/vite.site.config.ts index 6d23a36..0ea8a83 100644 --- a/vite.site.config.ts +++ b/vite.site.config.ts @@ -1,8 +1,8 @@ -import { defineConfig } from 'vite' +import { defineConfig } from 'vite'; // https://vitejs.dev/config/ export default defineConfig({ build: { target: 'esnext', }, -}) +}); From 80e2e16d0c9a308268a59805dc47a584c50da298 Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 13:06:57 -0500 Subject: [PATCH 07/11] ignore cjs for now --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 41ddd7d..aa2e850 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "lint": "pnpm _eslint && pnpm _prettier --check", "format": "pnpm _eslint --fix && pnpm _prettier --write", "_prettier": "prettier \"**/*.{js,cjs,ts,css,json,yml,yaml,md}\"", - "_eslint": "eslint \".*.cjs\" \"**/*.{js,cjs,ts}\"" + "_eslint": "eslint \".*.cjs\" \"**/*.{js,ts}\"" }, "keywords": [ "three", From a160b71986578612886ef8dd9bac24d69181620a Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 13:07:25 -0500 Subject: [PATCH 08/11] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aa2e850..a7641ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@viamrobotics/three", - "version": "0.0.4", + "version": "0.0.5", "license": "Apache-2.0", "type": "module", "files": [ From 870c1211a0cf7a1f724ae1a6cb46844b9102e53e Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 13:45:44 -0500 Subject: [PATCH 09/11] lint tests --- package.json | 19 +- pnpm-lock.yaml | 377 +++++++++++++++++++++++++++++----------- test/ov-to-qaut.spec.ts | 63 +++++++ test/ov-to-qaut.test.ts | 97 ----------- test/quat-to-ov.spec.ts | 84 +++++++++ test/quat-to-ov.test.ts | 101 ----------- 6 files changed, 428 insertions(+), 313 deletions(-) create mode 100644 test/ov-to-qaut.spec.ts delete mode 100644 test/ov-to-qaut.test.ts create mode 100644 test/quat-to-ov.spec.ts delete mode 100644 test/quat-to-ov.test.ts diff --git a/package.json b/package.json index a7641ea..e98b010 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "lint": "pnpm _eslint && pnpm _prettier --check", "format": "pnpm _eslint --fix && pnpm _prettier --write", "_prettier": "prettier \"**/*.{js,cjs,ts,css,json,yml,yaml,md}\"", - "_eslint": "eslint \".*.cjs\" \"**/*.{js,ts}\"" + "_eslint": "eslint \".*.cjs\" \"**/*.{js,cjs,ts}\"" }, "keywords": [ "three", @@ -41,17 +41,18 @@ "@0b5vr/tweakpane-plugin-rotation": "^0.2.0", "@tweakpane/core": "^2.0.3", "@tweakpane/plugin-essentials": "^0.2.1", - "@types/three": "^0.161.2", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", - "@viamrobotics/eslint-config": "^0.3.0", + "@types/three": "^0.162.0", + "@typescript-eslint/eslint-plugin": "^7.1.0", + "@typescript-eslint/parser": "^7.1.0", + "@viamrobotics/eslint-config": "^0.4.0", "@viamrobotics/prettier-config": "^0.3.4", "@viamrobotics/typescript-config": "^0.1.0", - "eslint": "^8.55.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-sonarjs": "^0.23.0", - "eslint-plugin-unicorn": "^49.0.0", - "prettier": "^3.1.1", + "eslint-plugin-sonarjs": "^0.24.0", + "eslint-plugin-unicorn": "^51.0.1", + "eslint-plugin-vitest": "^0.3.22", + "prettier": "^3.2.5", "three": "^0.162.0", "three-inspect": "^0.3.4", "trzy": "^0.3.17", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0b8f7a1..e50abd6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,38 +15,41 @@ devDependencies: specifier: ^0.2.1 version: 0.2.1(tweakpane@4.0.3) '@types/three': - specifier: ^0.161.2 - version: 0.161.2 + specifier: ^0.162.0 + version: 0.162.0 '@typescript-eslint/eslint-plugin': - specifier: ^6.14.0 - version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) + specifier: ^7.1.0 + version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3) '@typescript-eslint/parser': - specifier: ^6.14.0 - version: 6.14.0(eslint@8.55.0)(typescript@5.3.3) + specifier: ^7.1.0 + version: 7.1.0(eslint@8.57.0)(typescript@5.3.3) '@viamrobotics/eslint-config': - specifier: ^0.3.0 - version: 0.3.0(@typescript-eslint/eslint-plugin@6.14.0)(@typescript-eslint/parser@6.14.0)(eslint-config-prettier@9.1.0)(eslint-plugin-sonarjs@0.23.0)(eslint-plugin-unicorn@49.0.0)(eslint@8.55.0) + specifier: ^0.4.0 + version: 0.4.0(@typescript-eslint/eslint-plugin@7.1.0)(@typescript-eslint/parser@7.1.0)(eslint-config-prettier@9.1.0)(eslint-plugin-sonarjs@0.24.0)(eslint-plugin-unicorn@51.0.1)(eslint-plugin-vitest@0.3.22)(eslint@8.57.0) '@viamrobotics/prettier-config': specifier: ^0.3.4 - version: 0.3.4(prettier@3.1.1) + version: 0.3.4(prettier@3.2.5) '@viamrobotics/typescript-config': specifier: ^0.1.0 version: 0.1.0(typescript@5.3.3) eslint: - specifier: ^8.55.0 - version: 8.55.0 + specifier: ^8.57.0 + version: 8.57.0 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@8.55.0) + version: 9.1.0(eslint@8.57.0) eslint-plugin-sonarjs: - specifier: ^0.23.0 - version: 0.23.0(eslint@8.55.0) + specifier: ^0.24.0 + version: 0.24.0(eslint@8.57.0) eslint-plugin-unicorn: - specifier: ^49.0.0 - version: 49.0.0(eslint@8.55.0) + specifier: ^51.0.1 + version: 51.0.1(eslint@8.57.0) + eslint-plugin-vitest: + specifier: ^0.3.22 + version: 0.3.22(@typescript-eslint/eslint-plugin@7.1.0)(eslint@8.57.0)(typescript@5.3.3)(vitest@1.3.1) prettier: - specifier: ^3.1.1 - version: 3.1.1 + specifier: ^3.2.5 + version: 3.2.5 three: specifier: ^0.162.0 version: 0.162.0 @@ -304,13 +307,13 @@ packages: dev: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.55.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.55.0 + eslint: 8.57.0 eslint-visitor-keys: 3.4.3 dev: true @@ -336,16 +339,16 @@ packages: - supports-color dev: true - /@eslint/js@8.55.0: - resolution: {integrity: sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==} + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@humanwhocodes/config-array@0.11.13: - resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} dependencies: - '@humanwhocodes/object-schema': 2.0.1 + '@humanwhocodes/object-schema': 2.0.2 debug: 4.3.4 minimatch: 3.1.2 transitivePeerDependencies: @@ -357,8 +360,8 @@ packages: engines: {node: '>=12.22'} dev: true - /@humanwhocodes/object-schema@2.0.1: - resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + /@humanwhocodes/object-schema@2.0.2: + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} dev: true /@jest/schemas@29.6.3: @@ -505,6 +508,10 @@ packages: tweakpane: 4.0.3 dev: true + /@tweenjs/tween.js@23.1.1: + resolution: {integrity: sha512-ZpboH7pCPPeyBWKf8c7TJswtCEQObFo3bOBYalm99NzZarATALYCo5OhbCa/n4RQyJyHfhkdx+hNrdL5ByFYDw==} + dev: true + /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true @@ -525,9 +532,10 @@ packages: resolution: {integrity: sha512-9w+a7bR8PeB0dCT/HBULU2fMqf6BAzvKbxFboYhmDtDkKPiyXYbjoe2auwsXlEFI7CFNMF1dCv3dFH5Poy9R1w==} dev: true - /@types/three@0.161.2: - resolution: {integrity: sha512-DazpZ+cIfBzbW/p0zm6G8CS03HBMd748A3R1ZOXHpqaXZLv2I5zNgQUrRG//UfJ6zYFp2cUoCQaOLaz8ubH07w==} + /@types/three@0.162.0: + resolution: {integrity: sha512-0j5yZcVukVIhrhSIC7+LmBPkkMoMuEJ1AfYBZfgNytdYqYREMuiyXWhYOMeZLBElTEAlJIZn7r2W3vqTIgjWlg==} dependencies: + '@tweenjs/tween.js': 23.1.1 '@types/stats.js': 0.17.0 '@types/webxr': 0.5.0 fflate: 0.6.10 @@ -538,25 +546,25 @@ packages: resolution: {integrity: sha512-IUMDPSXnYIbEO2IereEFcgcqfDREOgmbGqtrMpVPpACTU6pltYLwHgVkrnYv0XhWEcjio9sYEfIEzgn3c7nDqA==} dev: true - /@typescript-eslint/eslint-plugin@6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==} + /@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/scope-manager': 6.14.0 - '@typescript-eslint/type-utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/visitor-keys': 6.14.0 + '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/scope-manager': 7.1.0 + '@typescript-eslint/type-utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 7.1.0 debug: 4.3.4 - eslint: 8.55.0 + eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.0 natural-compare: 1.4.0 @@ -567,62 +575,75 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@6.14.0(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==} + /@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint: ^8.56.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.14.0 - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) - '@typescript-eslint/visitor-keys': 6.14.0 + '@typescript-eslint/scope-manager': 7.1.0 + '@typescript-eslint/types': 7.1.0 + '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 7.1.0 debug: 4.3.4 - eslint: 8.55.0 + eslint: 8.57.0 typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@6.14.0: - resolution: {integrity: sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==} + /@typescript-eslint/scope-manager@6.21.0: + resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/visitor-keys': 6.14.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 dev: true - /@typescript-eslint/type-utils@6.14.0(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==} + /@typescript-eslint/scope-manager@7.1.0: + resolution: {integrity: sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 7.1.0 + '@typescript-eslint/visitor-keys': 7.1.0 + dev: true + + /@typescript-eslint/type-utils@7.1.0(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint: ^8.56.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) - '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) + '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) debug: 4.3.4 - eslint: 8.55.0 + eslint: 8.57.0 ts-api-utils: 1.0.3(typescript@5.3.3) typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@6.14.0: - resolution: {integrity: sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==} + /@typescript-eslint/types@6.21.0: + resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/types@7.1.0: + resolution: {integrity: sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==} engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.14.0(typescript@5.3.3): - resolution: {integrity: sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==} + /@typescript-eslint/typescript-estree@6.21.0(typescript@5.3.3): + resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -630,11 +651,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/visitor-keys': 6.14.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 + minimatch: 9.0.3 semver: 7.5.4 ts-api-utils: 1.0.3(typescript@5.3.3) typescript: 5.3.3 @@ -642,30 +664,79 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@6.14.0(eslint@8.55.0)(typescript@5.3.3): - resolution: {integrity: sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==} + /@typescript-eslint/typescript-estree@7.1.0(typescript@5.3.3): + resolution: {integrity: sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 7.1.0 + '@typescript-eslint/visitor-keys': 7.1.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.6 - '@typescript-eslint/scope-manager': 6.14.0 - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) - eslint: 8.55.0 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) + eslint: 8.57.0 semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys@6.14.0: - resolution: {integrity: sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==} + /@typescript-eslint/utils@7.1.0(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^8.56.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.6 + '@typescript-eslint/scope-manager': 7.1.0 + '@typescript-eslint/types': 7.1.0 + '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) + eslint: 8.57.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@6.21.0: + resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.21.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@typescript-eslint/visitor-keys@7.1.0: + resolution: {integrity: sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.14.0 + '@typescript-eslint/types': 7.1.0 eslint-visitor-keys: 3.4.3 dev: true @@ -673,32 +744,42 @@ packages: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true - /@viamrobotics/eslint-config@0.3.0(@typescript-eslint/eslint-plugin@6.14.0)(@typescript-eslint/parser@6.14.0)(eslint-config-prettier@9.1.0)(eslint-plugin-sonarjs@0.23.0)(eslint-plugin-unicorn@49.0.0)(eslint@8.55.0): - resolution: {integrity: sha512-yif6BOnVR+Y2Fk1+Zy16rqCI1AKuUx1BtgD6Wo9YB5JHBaNHGpId36Uw8HdtO2Pgki9aOGKkZ3urBIaUbClAbA==} + /@viamrobotics/eslint-config@0.4.0(@typescript-eslint/eslint-plugin@7.1.0)(@typescript-eslint/parser@7.1.0)(eslint-config-prettier@9.1.0)(eslint-plugin-sonarjs@0.24.0)(eslint-plugin-unicorn@51.0.1)(eslint-plugin-vitest@0.3.22)(eslint@8.57.0): + resolution: {integrity: sha512-R+fizH9jFLWShTxMONBq72BcoOX45I0gmOaTEVZZGmxn7XkcwUq5QYQ/w3HykxWhQtW4jw3UUKHkCa4gWfcLYA==} peerDependencies: '@typescript-eslint/eslint-plugin': '>=6 <7' '@typescript-eslint/parser': '>=6 <7' eslint: '>=8 <9' eslint-config-prettier: '>=9 <10' + eslint-plugin-jest-dom: '>=5 <6' eslint-plugin-sonarjs: '>=0.19 <0.24' eslint-plugin-svelte: '>=2 <3' eslint-plugin-tailwindcss: '>=3 <4' - eslint-plugin-unicorn: '>=47 <50' + eslint-plugin-testing-library: '>=6 <7' + eslint-plugin-unicorn: '>=47 <51' + eslint-plugin-vitest: '>=0.3 <0.4' peerDependenciesMeta: + eslint-plugin-jest-dom: + optional: true eslint-plugin-svelte: optional: true eslint-plugin-tailwindcss: optional: true + eslint-plugin-testing-library: + optional: true + eslint-plugin-vitest: + optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) - eslint: 8.55.0 - eslint-config-prettier: 9.1.0(eslint@8.55.0) - eslint-plugin-sonarjs: 0.23.0(eslint@8.55.0) - eslint-plugin-unicorn: 49.0.0(eslint@8.55.0) + '@typescript-eslint/eslint-plugin': 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + eslint: 8.57.0 + eslint-config-prettier: 9.1.0(eslint@8.57.0) + eslint-plugin-sonarjs: 0.24.0(eslint@8.57.0) + eslint-plugin-unicorn: 51.0.1(eslint@8.57.0) + eslint-plugin-vitest: 0.3.22(@typescript-eslint/eslint-plugin@7.1.0)(eslint@8.57.0)(typescript@5.3.3)(vitest@1.3.1) dev: true - /@viamrobotics/prettier-config@0.3.4(prettier@3.1.1): + /@viamrobotics/prettier-config@0.3.4(prettier@3.2.5): resolution: {integrity: sha512-1SOjP9WV1OHLsQJGUP4YnG/9r3yWFC9SczbmazEobWTNa/pzJwWI3dt8keuNn/bAv7kicAhukysiJeNtQyjWZg==} peerDependencies: prettier: '>=3 <4' @@ -710,7 +791,7 @@ packages: prettier-plugin-tailwindcss: optional: true dependencies: - prettier: 3.1.1 + prettier: 3.2.5 dev: true /@viamrobotics/typescript-config@0.1.0(typescript@5.3.3): @@ -836,6 +917,12 @@ packages: concat-map: 0.0.1 dev: true + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -843,6 +930,17 @@ packages: fill-range: 7.0.1 dev: true + /browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001591 + electron-to-chromium: 1.4.687 + node-releases: 2.0.14 + update-browserslist-db: 1.0.13(browserslist@4.23.0) + dev: true + /builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -858,6 +956,10 @@ packages: engines: {node: '>=6'} dev: true + /caniuse-lite@1.0.30001591: + resolution: {integrity: sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==} + dev: true + /chai@4.3.10: resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==} engines: {node: '>=4'} @@ -894,8 +996,8 @@ packages: get-func-name: 2.0.2 dev: true - /ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + /ci-info@4.0.0: + resolution: {integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==} engines: {node: '>=8'} dev: true @@ -928,7 +1030,13 @@ packages: dev: true /concat-map@0.0.1: - resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /core-js-compat@3.36.0: + resolution: {integrity: sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==} + dependencies: + browserslist: 4.23.0 dev: true /cross-spawn@7.0.3: @@ -982,6 +1090,10 @@ packages: esutils: 2.0.3 dev: true + /electron-to-chromium@1.4.687: + resolution: {integrity: sha512-Ic85cOuXSP6h7KM0AIJ2hpJ98Bo4hyTUjc4yjMbkvD+8yTxEhfK9+8exT2KKYsSjnCn2tGsKVSZwE7ZgTORQCw==} + dev: true + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -1018,6 +1130,11 @@ packages: '@esbuild/win32-x64': 0.19.8 dev: true + /escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + dev: true + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -1028,35 +1145,37 @@ packages: engines: {node: '>=10'} dev: true - /eslint-config-prettier@9.1.0(eslint@8.55.0): + /eslint-config-prettier@9.1.0(eslint@8.57.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.55.0 + eslint: 8.57.0 dev: true - /eslint-plugin-sonarjs@0.23.0(eslint@8.55.0): - resolution: {integrity: sha512-z44T3PBf9W7qQ/aR+NmofOTyg6HLhSEZOPD4zhStqBpLoMp8GYhFksuUBnCxbnf1nfISpKBVkQhiBLFI/F4Wlg==} - engines: {node: '>=14'} + /eslint-plugin-sonarjs@0.24.0(eslint@8.57.0): + resolution: {integrity: sha512-87zp50mbbNrSTuoEOebdRQBPa0mdejA5UEjyuScyIw8hEpEjfWP89Qhkq5xVZfVyVSRQKZc9alVm7yRKQvvUmg==} + engines: {node: '>=16'} peerDependencies: eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - eslint: 8.55.0 + eslint: 8.57.0 dev: true - /eslint-plugin-unicorn@49.0.0(eslint@8.55.0): - resolution: {integrity: sha512-0fHEa/8Pih5cmzFW5L7xMEfUTvI9WKeQtjmKpTUmY+BiFCDxkxrTdnURJOHKykhtwIeyYsxnecbGvDCml++z4Q==} + /eslint-plugin-unicorn@51.0.1(eslint@8.57.0): + resolution: {integrity: sha512-MuR/+9VuB0fydoI0nIn2RDA5WISRn4AsJyNSaNKLVwie9/ONvQhxOBbkfSICBPnzKrB77Fh6CZZXjgTt/4Latw==} engines: {node: '>=16'} peerDependencies: - eslint: '>=8.52.0' + eslint: '>=8.56.0' dependencies: '@babel/helper-validator-identifier': 7.22.20 - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) - ci-info: 3.9.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint/eslintrc': 2.1.4 + ci-info: 4.0.0 clean-regexp: 1.0.0 - eslint: 8.55.0 + core-js-compat: 3.36.0 + eslint: 8.57.0 esquery: 1.5.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 @@ -1067,6 +1186,30 @@ packages: regjsparser: 0.10.0 semver: 7.5.4 strip-indent: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-vitest@0.3.22(@typescript-eslint/eslint-plugin@7.1.0)(eslint@8.57.0)(typescript@5.3.3)(vitest@1.3.1): + resolution: {integrity: sha512-atkFGQ7aVgcuSeSMDqnyevIyUpfBPMnosksgEPrKE7Y8xQlqG/5z2IQ6UDau05zXaaFv7Iz8uzqvIuKshjZ0Zw==} + engines: {node: ^18.0.0 || >= 20.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': '*' + eslint: '>=8.0.0' + vitest: '*' + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + vitest: + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.3.3) + eslint: 8.57.0 + vitest: 1.3.1 + transitivePeerDependencies: + - supports-color + - typescript dev: true /eslint-scope@7.2.2: @@ -1082,16 +1225,16 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.55.0: - resolution: {integrity: sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==} + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.10.0 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.55.0 - '@humanwhocodes/config-array': 0.11.13 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 '@ungap/structured-clone': 1.2.0 @@ -1587,6 +1730,13 @@ packages: brace-expansion: 1.1.11 dev: true + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /mlly@1.4.2: resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} dependencies: @@ -1610,6 +1760,10 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + dev: true + /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: @@ -1781,8 +1935,8 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier@3.1.1: - resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==} + /prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} engines: {node: '>=14'} hasBin: true dev: true @@ -2124,6 +2278,17 @@ packages: resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} dev: true + /update-browserslist-db@1.0.13(browserslist@4.23.0): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.23.0 + escalade: 3.1.2 + picocolors: 1.0.0 + dev: true + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: diff --git a/test/ov-to-qaut.spec.ts b/test/ov-to-qaut.spec.ts new file mode 100644 index 0000000..77c1c4f --- /dev/null +++ b/test/ov-to-qaut.spec.ts @@ -0,0 +1,63 @@ +import { expect, describe, it } from 'vitest'; +import { Quaternion } from 'three'; +import { OrientationVector } from '../src/main'; +import { EPSILON } from '../src/constants'; + +const isAppxEqual = (q1: Quaternion, q2: Quaternion) => { + return ( + Math.abs(q1.x) - Math.abs(q2.x) < EPSILON && + Math.abs(q1.y) - Math.abs(q2.y) < EPSILON && + Math.abs(q1.z) - Math.abs(q2.z) < EPSILON && + Math.abs(q1.w) - Math.abs(q2.w) < EPSILON + ); +}; + +describe('OrientationVector', () => { + const ov = new OrientationVector(); + const expectedQuat = new Quaternion(); + const actualQuat = new Quaternion(); + + it('converts an orientation vector to a quaternion', () => { + ov.set(0, -1, 0, 1.570_796_326_794_896_6); + expectedQuat.set(0.707_106_781_186_547_6, 0, 0, 0.707_106_781_186_547_6); + expect(isAppxEqual(expectedQuat, ov.toQuaternion(actualQuat))).toBe(true); + + ov.set(0, 1, 0, -1.570_796_326_794_896_6); + expectedQuat.set(-0.707_106_781_186_547_6, 0, 0, 0.707_106_781_186_547_6); + expect(isAppxEqual(expectedQuat, ov.toQuaternion(actualQuat))).toBe(true); + + ov.set(-0.5376, 0, 0.8432, -1 * Math.PI); + expectedQuat.set(0, -0.28, 0, 0.96); + expect(isAppxEqual(expectedQuat, ov.toQuaternion(actualQuat))).toBe(true); + + ov.set(0, 0, 1, -0.567_588_218_416_655_7); + expectedQuat.set(0, 0, -0.28, 0.96); + expect(isAppxEqual(expectedQuat, ov.toQuaternion(actualQuat))).toBe(true); + + ov.set(0, 0.5376, 0.8432, -1.570_796_326_794_896_6); + expectedQuat.set(-0.28, 0, 0, 0.96); + expect(isAppxEqual(expectedQuat, ov.toQuaternion(actualQuat))).toBe(true); + + ov.set(0, -0.5376, 0.8432, 1.570_796_326_794_896_6); + expectedQuat.set(0.28, 0, 0, 0.96); + expect(isAppxEqual(expectedQuat, ov.toQuaternion(actualQuat))).toBe(true); + + ov.set(0, 1, 0, -1 * Math.PI); + expectedQuat.set(-0.5, -0.5, -0.5, 0.5); + expect(isAppxEqual(expectedQuat, ov.toQuaternion(actualQuat))).toBe(true); + + ov.set( + 0.504_843_794_294_005_4, + 0.588_984_426_676_339_7, + 0.631_054_742_867_507, + 0.02 + ); + expectedQuat.set( + -0.175_559_660_254_131_42, + 0.391_983_971_939_798_17, + 0.385_537_548_516_400_1, + 0.816_632_212_270_443 + ); + expect(isAppxEqual(expectedQuat, ov.toQuaternion(actualQuat))).toBe(true); + }); +}); diff --git a/test/ov-to-qaut.test.ts b/test/ov-to-qaut.test.ts deleted file mode 100644 index e531c32..0000000 --- a/test/ov-to-qaut.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { expect, test } from 'vitest'; -import { Quaternion } from 'three'; -import { OrientationVector } from '../src/main'; -import { EPSILON } from '../src/constants'; - -const ov = new OrientationVector(); -const expectedQuat = new Quaternion(); -const convertedQuat = new Quaternion(); - -const areQuaternionsApproxEqual = (q1: Quaternion, q2: Quaternion) => { - return ( - Math.abs(q1.x) - Math.abs(q2.x) < EPSILON && - Math.abs(q1.y) - Math.abs(q2.y) < EPSILON && - Math.abs(q1.z) - Math.abs(q2.z) < EPSILON && - Math.abs(q1.w) - Math.abs(q2.w) < EPSILON - ); -}; - -const assertApproxEqual = ( - ovx: number, - ovy: number, - ovz: number, - ovth: number, - qw: number, - qx: number, - qy: number, - qz: number -) => { - ov.set(ovx, ovy, ovz, ovth); - expectedQuat.set(qx, qy, qz, qw); - ov.toQuaternion(convertedQuat); - - expect(areQuaternionsApproxEqual(convertedQuat, expectedQuat)).toBeTruthy(); -}; - -test('orientation vector to quaternion works', () => { - assertApproxEqual( - 0, - -1, - 0, - 1.570_796_326_794_896_6, - 0.707_106_781_186_547_6, - 0.707_106_781_186_547_6, - 0, - 0 - ); - - assertApproxEqual( - 0, - 1, - 0, - -1.570_796_326_794_896_6, - 0.707_106_781_186_547_6, - -0.707_106_781_186_547_6, - 0, - 0 - ); - - assertApproxEqual(-0.5376, 0, 0.8432, -1 * Math.PI, 0.96, 0, -0.28, 0); - - assertApproxEqual(0, 0, 1, -0.567_588_218_416_655_7, 0.96, 0, 0, -0.28); - - assertApproxEqual( - 0, - 0.5376, - 0.8432, - -1.570_796_326_794_896_6, - 0.96, - -0.28, - 0, - 0 - ); - - assertApproxEqual( - 0, - -0.5376, - 0.8432, - 1.570_796_326_794_896_6, - 0.96, - 0.28, - 0, - 0 - ); - - assertApproxEqual(0, 1, 0, -1 * Math.PI, 0.5, -0.5, -0.5, -0.5); - - assertApproxEqual( - 0.504_843_794_294_005_4, - 0.588_984_426_676_339_7, - 0.631_054_742_867_507, - 0.02, - 0.816_632_212_270_443, - -0.175_559_660_254_131_42, - 0.391_983_971_939_798_17, - 0.385_537_548_516_400_1 - ); -}); diff --git a/test/quat-to-ov.spec.ts b/test/quat-to-ov.spec.ts new file mode 100644 index 0000000..4ced0b9 --- /dev/null +++ b/test/quat-to-ov.spec.ts @@ -0,0 +1,84 @@ +import { expect, describe, it } from 'vitest'; +import { Vector3, Quaternion } from 'three'; +import { OrientationVector } from '../src/main'; +import { EPSILON } from '../src/constants'; + +const vecA = new Vector3(); +const vecB = new Vector3(); + +const isAppxEqual = (ov1: OrientationVector, ov2: OrientationVector) => { + const vecDiff = vecA + .set(ov1.x, ov1.y, ov1.z) + .sub(vecB.set(ov2.x, ov2.y, ov2.z)); + + return ( + Math.abs(vecDiff.lengthSq()) < EPSILON && + Math.abs(ov1.th) - Math.abs(ov2.th) < EPSILON + ); +}; + +describe('OrientationVector', () => { + const quaternion = new Quaternion(); + const expectedOv = new OrientationVector(); + const actualOv = new OrientationVector(); + + it('converts quaternion to orientation vector', () => { + quaternion.set(0.707_106_781_186_547_6, 0, 0, 0.707_106_781_186_547_6); + expectedOv.set(0, -1, 0, 1.570_796_326_794_896_6); + expect( + isAppxEqual(expectedOv, actualOv.setFromQuaternion(quaternion)) + ).toBe(true); + + quaternion.set(-0.707_106_781_186_547_6, 0, 0, 0.707_106_781_186_547_6); + expectedOv.set(0, 1, 0, -1.570_796_326_794_896_6); + expect( + isAppxEqual(expectedOv, actualOv.setFromQuaternion(quaternion)) + ).toBe(true); + + quaternion.set(0, -0.28, 0, 0.96); + expectedOv.set(-0.5376, 0, 0.8432, -1 * Math.PI); + expect( + isAppxEqual(expectedOv, actualOv.setFromQuaternion(quaternion)) + ).toBe(true); + + quaternion.set(0, 0, -0.28, 0.96); + expectedOv.set(0, 0, 1, -0.567_588_218_416_655_7); + expect( + isAppxEqual(expectedOv, actualOv.setFromQuaternion(quaternion)) + ).toBe(true); + + quaternion.set(-0.28, 0, 0, 0.96); + expectedOv.set(0, 0.5376, 0.8432, -1.570_796_326_794_896_6); + expect( + isAppxEqual(expectedOv, actualOv.setFromQuaternion(quaternion)) + ).toBe(true); + + quaternion.set(0.28, 0, 0, 0.96); + expectedOv.set(0, -0.5376, 0.8432, 1.570_796_326_794_896_6); + expect( + isAppxEqual(expectedOv, actualOv.setFromQuaternion(quaternion)) + ).toBe(true); + + quaternion.set(-0.5, -0.5, -0.5, 0.5); + expectedOv.set(0, 1, 0, -1 * Math.PI); + expect( + isAppxEqual(expectedOv, actualOv.setFromQuaternion(quaternion)) + ).toBe(true); + + quaternion.set( + -0.175_559_660_254_131_42, + 0.391_983_971_939_798_17, + 0.385_537_548_516_400_1, + 0.816_632_212_270_443 + ); + expectedOv.set( + 0.504_843_794_294_005_4, + 0.588_984_426_676_339_7, + 0.631_054_742_867_507, + 0.02 + ); + expect( + isAppxEqual(expectedOv, actualOv.setFromQuaternion(quaternion)) + ).toBe(true); + }); +}); diff --git a/test/quat-to-ov.test.ts b/test/quat-to-ov.test.ts deleted file mode 100644 index cf44390..0000000 --- a/test/quat-to-ov.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { expect, test } from 'vitest'; -import * as THREE from 'three'; -import { OrientationVector } from '../src/main'; -import { EPSILON } from '../src/constants'; - -const quat = new THREE.Quaternion(); -const expectedOv = new OrientationVector(); -const convertedOv = new OrientationVector(); -const vecA = new THREE.Vector3(); -const vecB = new THREE.Vector3(); - -const areOvsApproxEqual = (ov1: OrientationVector, ov2: OrientationVector) => { - const vecDiff = vecA - .set(ov1.x, ov1.y, ov1.z) - .sub(vecB.set(ov2.x, ov2.y, ov2.z)); - - return ( - Math.abs(vecDiff.lengthSq()) < EPSILON && - Math.abs(ov1.th) - Math.abs(ov2.th) < EPSILON - ); -}; - -const assertApproxEqual = ( - qw: number, - qx: number, - qy: number, - qz: number, - ovx: number, - ovy: number, - ovz: number, - ovth: number -) => { - quat.set(qx, qy, qz, qw); - expectedOv.set(ovx, ovy, ovz, ovth); - convertedOv.setFromQuaternion(quat); - - expect(areOvsApproxEqual(convertedOv, expectedOv)).toBeTruthy(); -}; - -test('quaternion to orientation vector works', () => { - assertApproxEqual( - 0.707_106_781_186_547_6, - 0.707_106_781_186_547_6, - 0, - 0, - 0, - -1, - 0, - 1.570_796_326_794_896_6 - ); - - assertApproxEqual( - 0.707_106_781_186_547_6, - -0.707_106_781_186_547_6, - 0, - 0, - 0, - 1, - 0, - -1.570_796_326_794_896_6 - ); - - assertApproxEqual(0.96, 0, -0.28, 0, -0.5376, 0, 0.8432, -1 * Math.PI); - - assertApproxEqual(0.96, 0, 0, -0.28, 0, 0, 1, -0.567_588_218_416_655_7); - - assertApproxEqual( - 0.96, - -0.28, - 0, - 0, - 0, - 0.5376, - 0.8432, - -1.570_796_326_794_896_6 - ); - - assertApproxEqual( - 0.96, - 0.28, - 0, - 0, - 0, - -0.5376, - 0.8432, - 1.570_796_326_794_896_6 - ); - - assertApproxEqual(0.5, -0.5, -0.5, -0.5, 0, 1, 0, -1 * Math.PI); - - assertApproxEqual( - 0.816_632_212_270_443, - -0.175_559_660_254_131_42, - 0.391_983_971_939_798_17, - 0.385_537_548_516_400_1, - 0.504_843_794_294_005_4, - 0.588_984_426_676_339_7, - 0.631_054_742_867_507, - 0.02 - ); -}); From da7608af7b4fc898c0c76d54d3dc69878842661e Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 13:47:36 -0500 Subject: [PATCH 10/11] typecheck --- playground/conversions.ts | 11 +---------- playground/types.ts | 4 +++- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/playground/conversions.ts b/playground/conversions.ts index 361a143..b32bc07 100644 --- a/playground/conversions.ts +++ b/playground/conversions.ts @@ -5,16 +5,7 @@ import * as THREE from 'three'; import { Units, type InputTypes } from './types'; import { rotations } from './rotations'; -import { OrientationVector, ViamObject3D } from '../src/main'; - -// These globals are just added to allow playing around in the console as well. -window.THREE = THREE; - -// @ts-expect-error For debugging -window.OrientationVector = OrientationVector; - -// @ts-expect-error For debugging -window.ViamObject3D = ViamObject3D; +import { OrientationVector } from '../src/main'; const v3 = new THREE.Vector3(); const quat = new THREE.Quaternion(); diff --git a/playground/types.ts b/playground/types.ts index 09c0708..be9b3f4 100644 --- a/playground/types.ts +++ b/playground/types.ts @@ -1,3 +1,5 @@ +import type { EulerOrder } from 'three'; + export const enum Units { radians, degrees, @@ -11,7 +13,7 @@ export type InputTypes = | 'axis angle' | 'axis with angle magnitude'; -export type Opts = THREE.EulerOrder; +export type Opts = EulerOrder; export const orderOptions = ['XYZ', 'YXZ', 'ZXY', 'ZYX', 'YZX', 'XZY'].map( (opt) => ({ text: opt.toLowerCase(), value: opt }) From ccbd4953e45973bf63e75d7ea3bf25e01ae3379d Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 29 Feb 2024 14:13:29 -0500 Subject: [PATCH 11/11] ignore ts rule --- .prettierrc.cjs | 1 + 1 file changed, 1 insertion(+) diff --git a/.prettierrc.cjs b/.prettierrc.cjs index 1ffc7bd..3657f8e 100644 --- a/.prettierrc.cjs +++ b/.prettierrc.cjs @@ -1,3 +1,4 @@ 'use strict'; +/* eslint-disable @typescript-eslint/no-unsafe-call */ module.exports = require('@viamrobotics/prettier-config');