Browse Source

OBB 选中

master
修宁 6 months ago
parent
commit
c29c48dac6
  1. 1
      package.json
  2. 149
      pnpm-lock.yaml
  3. 78
      src/core/ItemObbManager.bak
  4. 99
      src/core/ModelUtils.ts
  5. 120
      src/core/QuadTree.ts
  6. 10
      src/core/controls/DragControl.ts
  7. 9
      src/core/controls/SelectInspect.ts
  8. 8
      src/core/engine/Viewport.ts
  9. 41
      src/core/manager/EntityManager.ts
  10. 11
      src/core/manager/InstancePointManager.ts
  11. 200
      src/core/manager/ItemFindManager.ts
  12. 7
      src/core/manager/LineSegmentManager.ts
  13. 12
      src/example/example1.js
  14. 77
      src/modules/gstore/GstoreRenderer.ts
  15. 11
      src/modules/way/WayRenderer.ts
  16. 55
      src/types/model.d.ts

1
package.json

@ -53,7 +53,6 @@
"sortablejs": "1.15.6",
"split.js": "^1.6.4",
"three": "^0.176.0",
"three-mesh-bvh": "^0.9.0",
"troika-three-text": "^0.52.4",
"tslib": "2.8.1",
"typescript": "~5.8.0",

149
pnpm-lock.yaml

@ -126,9 +126,6 @@ importers:
three-dxf-viewer:
specifier: ^1.0.36
version: 1.0.36
three-mesh-bvh:
specifier: ^0.9.0
version: 0.9.0(three@0.176.0)
troika-three-text:
specifier: ^0.52.4
version: 0.52.4(three@0.176.0)
@ -324,151 +321,151 @@ packages:
vue: ^3.2.0
'@esbuild/aix-ppc64@0.25.4':
resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==, tarball: https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz}
resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.25.4':
resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==, tarball: https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz}
resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.25.4':
resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==, tarball: https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.25.4.tgz}
resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.25.4':
resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==, tarball: https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.25.4.tgz}
resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.25.4':
resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==, tarball: https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz}
resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.25.4':
resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==, tarball: https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz}
resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.25.4':
resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==, tarball: https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz}
resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.25.4':
resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==, tarball: https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz}
resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.25.4':
resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==, tarball: https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz}
resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.25.4':
resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==, tarball: https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz}
resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.25.4':
resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==, tarball: https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz}
resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.25.4':
resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==, tarball: https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz}
resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.25.4':
resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==, tarball: https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz}
resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.25.4':
resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==, tarball: https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz}
resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.25.4':
resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==, tarball: https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz}
resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.25.4':
resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==, tarball: https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz}
resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.25.4':
resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==, tarball: https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz}
resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/netbsd-arm64@0.25.4':
resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==, tarball: https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz}
resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-x64@0.25.4':
resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==, tarball: https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz}
resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-arm64@0.25.4':
resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==, tarball: https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz}
resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-x64@0.25.4':
resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==, tarball: https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz}
resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/sunos-x64@0.25.4':
resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==, tarball: https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz}
resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.25.4':
resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==, tarball: https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz}
resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.25.4':
resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==, tarball: https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz}
resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.25.4':
resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==, tarball: https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz}
resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
@ -540,113 +537,102 @@ packages:
optional: true
'@rollup/rollup-android-arm-eabi@4.41.0':
resolution: {integrity: sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==, tarball: https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz}
resolution: {integrity: sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==}
cpu: [arm]
os: [android]
'@rollup/rollup-android-arm64@4.41.0':
resolution: {integrity: sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==, tarball: https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz}
resolution: {integrity: sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==}
cpu: [arm64]
os: [android]
'@rollup/rollup-darwin-arm64@4.41.0':
resolution: {integrity: sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==, tarball: https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz}
resolution: {integrity: sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==}
cpu: [arm64]
os: [darwin]
'@rollup/rollup-darwin-x64@4.41.0':
resolution: {integrity: sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==, tarball: https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz}
resolution: {integrity: sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-freebsd-arm64@4.41.0':
resolution: {integrity: sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==, tarball: https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz}
resolution: {integrity: sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==}
cpu: [arm64]
os: [freebsd]
'@rollup/rollup-freebsd-x64@4.41.0':
resolution: {integrity: sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==, tarball: https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz}
resolution: {integrity: sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==}
cpu: [x64]
os: [freebsd]
'@rollup/rollup-linux-arm-gnueabihf@4.41.0':
resolution: {integrity: sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz}
resolution: {integrity: sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.41.0':
resolution: {integrity: sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz}
resolution: {integrity: sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.41.0':
resolution: {integrity: sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz}
resolution: {integrity: sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.41.0':
resolution: {integrity: sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz}
resolution: {integrity: sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loongarch64-gnu@4.41.0':
resolution: {integrity: sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz}
resolution: {integrity: sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-powerpc64le-gnu@4.41.0':
resolution: {integrity: sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz}
resolution: {integrity: sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.41.0':
resolution: {integrity: sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz}
resolution: {integrity: sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.41.0':
resolution: {integrity: sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz}
resolution: {integrity: sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.41.0':
resolution: {integrity: sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz}
resolution: {integrity: sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.41.0':
resolution: {integrity: sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz}
resolution: {integrity: sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.41.0':
resolution: {integrity: sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==, tarball: https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.0.tgz}
resolution: {integrity: sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.41.0':
resolution: {integrity: sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==, tarball: https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz}
resolution: {integrity: sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==}
cpu: [arm64]
os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.41.0':
resolution: {integrity: sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==, tarball: https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz}
resolution: {integrity: sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==}
cpu: [ia32]
os: [win32]
'@rollup/rollup-win32-x64-msvc@4.41.0':
resolution: {integrity: sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==, tarball: https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz}
resolution: {integrity: sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==}
cpu: [x64]
os: [win32]
@ -658,7 +644,7 @@ packages:
engines: {node: '>=18'}
'@sxzz/popperjs-es@2.11.7':
resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==, tarball: https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz}
resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
'@tsconfig/node22@22.0.2':
resolution: {integrity: sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA==}
@ -879,7 +865,7 @@ packages:
resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==}
ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, tarball: https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz}
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
ansi-regex@6.1.0:
@ -887,7 +873,7 @@ packages:
engines: {node: '>=12'}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, tarball: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz}
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
ansi-styles@6.2.1:
@ -944,11 +930,11 @@ packages:
resolution: {integrity: sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, tarball: https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz}
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz}
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
@ -1032,7 +1018,7 @@ packages:
vue: ^3.2.0
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, tarball: https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz}
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
@ -1042,7 +1028,7 @@ packages:
engines: {node: '>=0.12'}
errno@0.1.8:
resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==, tarball: https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz}
resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
hasBin: true
error-stack-parser-es@0.1.5:
@ -1120,7 +1106,7 @@ packages:
engines: {node: '>=14.14'}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, tarball: https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz}
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
@ -1157,7 +1143,7 @@ packages:
engines: {node: '>= 0.4'}
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, tarball: https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz}
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
@ -1190,7 +1176,7 @@ packages:
engines: {node: '>=0.10.0'}
image-size@0.5.5:
resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==, tarball: https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz}
resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==}
engines: {node: '>=0.10.0'}
hasBin: true
@ -1203,7 +1189,7 @@ packages:
hasBin: true
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, tarball: https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz}
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
is-inside-container@1.0.0:
@ -1306,7 +1292,7 @@ packages:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
make-dir@2.1.0:
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==, tarball: https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz}
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
engines: {node: '>=6'}
math-intrinsics@1.1.0:
@ -1332,7 +1318,7 @@ packages:
engines: {node: '>= 0.6'}
mime@1.6.0:
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==, tarball: https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz}
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
engines: {node: '>=4'}
hasBin: true
@ -1372,7 +1358,7 @@ packages:
hasBin: true
needle@3.3.1:
resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==, tarball: https://registry.npmmirror.com/needle/-/needle-3.3.1.tgz}
resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==}
engines: {node: '>= 4.4.x'}
hasBin: true
@ -1569,7 +1555,7 @@ packages:
engines: {node: '>=0.10.0'}
source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, tarball: https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz}
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
speakingurl@14.0.1:
@ -1580,7 +1566,7 @@ packages:
resolution: {integrity: sha512-mPTnGCiS/RiuTNsVhCm9De9cCAUsrNFFviRbADdKiiV+Kk8HKp/0fWu7Kr8pi3/yBmsqLFHuXGT9UUZ+CNLwFw==}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, tarball: https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz}
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
string-width@5.1.2:
@ -1588,7 +1574,7 @@ packages:
engines: {node: '>=12'}
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, tarball: https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz}
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
strip-ansi@7.1.0:
@ -1606,11 +1592,6 @@ packages:
three-dxf-viewer@1.0.36:
resolution: {integrity: sha512-Tu7k+/yCyovpMJTeQ8fpGHdjtynq66vMMXYzDCwI9prJo2dRDxig4S+ixQVuMIy3I99VZa51z5KwlkeWyCnFzQ==, tarball: https://registry.npmmirror.com/three-dxf-viewer/-/three-dxf-viewer-1.0.36.tgz}
three-mesh-bvh@0.9.0:
resolution: {integrity: sha512-xAwZj0hZknpwVsdK5BBJTIAZDjDPZCRzURY1o+z/JHBON/jc2UetK1CzPeQZiiOVSfI4jV2z7sXnnGtgsgnjaA==}
peerDependencies:
three: '>= 0.159.0'
three@0.171.0:
resolution: {integrity: sha512-Y/lAXPaKZPcEdkKjh0JOAHVv8OOnv/NDJqm0wjfCzyQmfKxV7zvkwsnBgPBKTzJHToSOhRGQAGbPJObT59B/PQ==, tarball: https://registry.npmmirror.com/three/-/three-0.171.0.tgz}
@ -1796,7 +1777,7 @@ packages:
hasBin: true
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, tarball: https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz}
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
wrap-ansi@8.1.0:
@ -3268,10 +3249,6 @@ snapshots:
dxf: 5.2.0
three: 0.171.0
three-mesh-bvh@0.9.0(three@0.176.0):
dependencies:
three: 0.176.0
three@0.171.0: {}
three@0.176.0: {}

78
src/core/ItemObbManager.ts → src/core/ItemObbManager.bak

@ -1,12 +1,53 @@
// 开发一个物品 OBB 包围盒管理器
// 借助 three-mesh-bvh 库来实现
// 里面所有的物品不用管渲染(不用去到 Scene / 不用管纹理和材质),但期望他最大程度的使用 BufferGeometry 用显卡来运算
我想用 JS 开发一个浏览器 3D 场景下的物品查询工具 ItemFindManager, 借助 octree 算法结构来实现
物品数超过 100,000 个, 基于物品的 OBB 包围盒进行各种查询操作, 并可能存在频繁且少量的点位更新/删除操作
查询方法包括:
1.根据位置,获取命中到物品OBB包围盒的所有物品ID集合
2.根据位置和距离,获取给定范围内,OBB包围盒碰到的所有物品ID集合
3.给定一个矩形区域 (x1,z1)->(x2,z2),获取物品OBB包围盒与矩形有交集的所有物品ID集合
不要创建 Mesh 不要创建 Group
物品不用管渲染(不用去到 Scene / 不用管纹理和材质),但期望他最大程度的使用 BufferGeometry 用显卡来运算
OBB 不用刻意追求,可以先用 AABB 进行检索,再通过 OBB 进行进一步筛选达到目的
物品的结构是
export interface ItemMetrix {
/**
* 物体ID, 唯一标识
*/
id: string
/**
* 变换矩阵, 3x3矩阵, X轴正增长向右, Y轴正增长向屏幕外, Z轴正增长向下。右手坐标系
*/
tf: [
/**
* 平移向量 position, 三维坐标
* [0]=x轴向右, [1]=y轴高度向屏幕外, [2]=z轴向下
*/
[number, number, number],
/**
* 旋转向量 rotation, 单位为度
* [0]=X轴逆向旋转角度, [1]=Y轴逆向旋转角度, [2]=Z轴逆向旋转角度
* 对应 three.js 应进行"角度"转"弧度"的换算
*/
[number, number, number],
/**
* 缩放向量 scale, 三维缩放比例, [0]=X宽度, [1]=Y高度, [2]=Z长度
*/
[number, number, number],
]
}
参考:
import * as THREE from 'three'
/**
* 物品 OBB 包围盒管理器
* 点位数超过 100,000 个, 基于物品的 OBB 包围盒进行各种查询操作
* 物品数超过 100,000 个, 基于物品的 OBB 包围盒进行各种查询操作
* 并可能存在频繁且少量的点位更新/删除操作
*/
export default class ItemObbManager {
@ -57,32 +98,3 @@ export default class ItemObbManager {
}
}
export interface ItemMetrix {
/**
* 物体ID, 唯一标识
*/
id: string
/**
* 变换矩阵, 3x3矩阵, X轴正增长向右, Y轴正增长向屏幕外, Z轴正增长向下。右手坐标系
*/
tf: [
/**
* 平移向量 position, 三维坐标
* [0]=x轴向右, [1]=y轴高度向屏幕外, [2]=z轴向下
*/
[number, number, number],
/**
* 旋转向量 rotation, 单位为度
* [0]=X轴逆向旋转角度, [1]=Y轴逆向旋转角度, [2]=Z轴逆向旋转角度
* 对应 three.js 应进行"角度"转"弧度"的换算
*/
[number, number, number],
/**
* 缩放向量 scale, 三维缩放比例, [0]=X宽度, [1]=Y高度, [2]=Z长度
*/
[number, number, number],
]
}

99
src/core/ModelUtils.ts

@ -11,6 +11,46 @@ import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
/**
* 2D
*/
export function convexHull(points: { x: number, z: number }[]): { x: number, z: number }[] {
if (points.length <= 3) return [...points]
// 找到最左下角的点
let start = points[0]
for (const p of points) {
if (p.z < start.z || (p.z === start.z && p.x < start.x)) {
start = p
}
}
// 按极角排序
const sorted = points.filter(p => p !== start)
sorted.sort((a, b) => {
const angleA = Math.atan2(a.z - start.z, a.x - start.x)
const angleB = Math.atan2(b.z - start.z, b.x - start.x)
return angleA === angleB
? (Math.abs(a.x - start.x) - Math.abs(b.x - start.x))
: angleA - angleB
})
// 使用栈计算凸包
const stack: { x: number, z: number }[] = [start, sorted[0]]
for (let i = 1; i < sorted.length; i++) {
while (stack.length >= 2) {
const top = stack[stack.length - 1]
const nextTop = stack[stack.length - 2]
const cross = (top.x - nextTop.x) * (sorted[i].z - nextTop.z) -
(top.z - nextTop.z) * (sorted[i].x - nextTop.x)
if (cross <= 0) stack.pop()
else break
}
stack.push(sorted[i])
}
return stack
}
/**
* 线id
*/
export function getCargoLineId(linkName: string, startId: string, endId: string): string {
@ -458,63 +498,6 @@ export function findObject3DByCondition(scene: THREE.Object3D, condition: (objec
return foundObjects
}
// export function loadSceneFromJson(viewport: Viewport, scene: THREE.Scene, items: ItemJson[]) {
// console.time('loadSceneFromJson')
//
// const object3ds: THREE.Object3D[] = []
//
// // beforeLoad 通知所有加载的对象, 模型加载开始
// getAllItemTypes().forEach((itemType: ItemTypeDefineOption) => {
// const ret = itemType.clazz.beforeLoad()
// Array.isArray(ret) && object3ds.push(...ret)
// })
//
// const loads = loadObject3DFromJson(items)
// Array.isArray(loads) && object3ds.push(...loads)
//
// // afterLoadComplete 通知所有加载的对象, 模型加载完成
// getAllItemTypes().forEach((itemType: ItemTypeDefineOption) => {
// const ret = itemType.clazz.afterLoadComplete(object3ds)
// Array.isArray(ret) && object3ds.push(...ret)
// })
//
// scene.add(...object3ds)
//
// // afterAddScene 通知所有加载的对象, 模型加载完成
// getAllItemTypes().forEach(itemType => {
// itemType.clazz.afterAddScene(viewport, scene, object3ds)
// })
//
// console.log('loadSceneFromJson:', items.length, 'items,', object3ds.length, 'objects')
// console.timeEnd('loadSceneFromJson')
// }
//
// function loadObject3DFromJson(items: ItemJson[]): THREE.Object3D[] {
// const result: THREE.Object3D[] = []
//
// for (const item of items) {
// if (!item || !item.t) {
// console.error('unkown item:', item)
// continue
// }
//
// const object3D: THREE.Object3D | undefined = getItemTypeByName(item.t)?.clazz.loadFromJson(item)
// if (object3D === undefined) {
// continue
// }
//
// if (_.isArray(item.items)) {
// // 如果有子元素,递归处理
// const children = loadObject3DFromJson(item.items)
// children.forEach(child => object3D.add(child))
// }
//
// result.push(object3D)
// }
//
// return result
// }
/**
*
* @param collection
@ -547,7 +530,7 @@ export async function loadByUrl(url): Promise<any> {
* @param width
*
*/
export function createLinkPlaneMatrix4(startPosition: THREE.Vector3, endPosition: THREE.Vector3, width: number, direction: LinkDirection): THREE.Matrix4 {
export function createLinkPlaneMatrix4(startPosition: THREE.Vector3, endPosition: THREE.Vector3, width: number): THREE.Matrix4 {
const dir = new THREE.Vector3().subVectors(endPosition, startPosition)
const length = dir.length() // 平面长度 = 两点距离
dir.normalize()

120
src/core/QuadTree.ts

@ -0,0 +1,120 @@
/**
*
*/
export class QuadTreeNode {
static MAX_OBJECTS = 10
static MAX_LEVELS = 6
level: number
bounds: { minX: number, minZ: number, maxX: number, maxZ: number }
objects: { id: string, aabb: { minX: number, minZ: number, maxX: number, maxZ: number } }[]
nodes: QuadTreeNode[]
constructor(level: number, bounds: { minX: number, minZ: number, maxX: number, maxZ: number }) {
this.level = level
this.bounds = bounds
this.objects = []
this.nodes = []
}
clear(): void {
this.objects = []
for (const node of this.nodes) {
node.clear()
}
this.nodes = []
}
// 获取物体所属的子节点索引
getIndex(aabb: { minX: number, minZ: number, maxX: number, maxZ: number }): number[] {
const indices: number[] = []
const midX = (this.bounds.minX + this.bounds.maxX) / 2
const midZ = (this.bounds.minZ + this.bounds.maxZ) / 2
const top = aabb.minZ < midZ && aabb.maxZ > midZ
const bottom = aabb.minZ < this.bounds.maxZ && aabb.maxZ > midZ
const left = aabb.minX < midX && aabb.maxX > midX
const right = aabb.minX < this.bounds.maxX && aabb.maxX > midX
if (top && left) indices.push(0)
if (top && right) indices.push(1)
if (bottom && left) indices.push(2)
if (bottom && right) indices.push(3)
return indices
}
// 分裂节点
split(): void {
const { minX, minZ, maxX, maxZ } = this.bounds
const midX = (minX + maxX) / 2
const midZ = (minZ + maxZ) / 2
this.nodes[0] = new QuadTreeNode(this.level + 1, { minX, minZ, maxX: midX, maxZ: midZ })
this.nodes[1] = new QuadTreeNode(this.level + 1, { minX: midX, minZ, maxX, maxZ: midZ })
this.nodes[2] = new QuadTreeNode(this.level + 1, { minX, minZ: midZ, maxX: midX, maxZ })
this.nodes[3] = new QuadTreeNode(this.level + 1, { minX: midX, minZ: midZ, maxX, maxZ })
}
// 插入物体
insert(id: string, aabb: { minX: number, minZ: number, maxX: number, maxZ: number }): void {
if (this.nodes.length) {
const indices = this.getIndex(aabb)
for (const index of indices) {
this.nodes[index].insert(id, aabb)
}
return
}
this.objects.push({ id, aabb })
if (this.objects.length > QuadTreeNode.MAX_OBJECTS &&
this.level < QuadTreeNode.MAX_LEVELS) {
if (!this.nodes.length) {
this.split()
}
for (const obj of this.objects) {
const indices = this.getIndex(obj.aabb)
for (const index of indices) {
this.nodes[index].insert(obj.id, obj.aabb)
}
}
this.objects = []
}
}
// 查询区域
query(region: { minX: number, minZ: number, maxX: number, maxZ: number }, result: Set<string>): void {
if (!this.intersects(region)) return
if (this.nodes.length) {
for (const node of this.nodes) {
node.query(region, result)
}
} else {
for (const obj of this.objects) {
if (this.intersectsAABB(region, obj.aabb)) {
result.add(obj.id)
}
}
}
}
// 区域相交检测
private intersects(region: { minX: number, minZ: number, maxX: number, maxZ: number }): boolean {
return !(region.maxX < this.bounds.minX ||
region.minX > this.bounds.maxX ||
region.maxZ < this.bounds.minZ ||
region.minZ > this.bounds.maxZ)
}
// AABB相交检测
private intersectsAABB(a: { minX: number, minZ: number, maxX: number, maxZ: number },
b: { minX: number, minZ: number, maxX: number, maxZ: number }): boolean {
return !(a.maxX < b.minX ||
a.minX > b.maxX ||
a.maxZ < b.minZ ||
a.minZ > b.maxZ)
}
}

10
src/core/controls/DragControl.ts

@ -108,10 +108,12 @@ export default class DragControl implements IControls {
this.updateShadows(new THREE.Vector2(CurrentMouseInfo.x, CurrentMouseInfo.z))
} else {
const mouse = this.getMousePosition(event.clientX, event.clientY)
const intersected = this.getIntersectedDraggableObject(mouse)
this.domElement.style.cursor = intersected ? 'grab' : 'auto'
// 射线方法修改 ==========================
// const mouse = this.getMousePosition(event.clientX, event.clientY)
// const intersected = this.getIntersectedDraggableObject(mouse)
// =====================================
const ids = this.viewport.itemFindManager.getItemsByPosition(CurrentMouseInfo.x, CurrentMouseInfo.z)
this.domElement.style.cursor = ids.length > 0 ? 'grab' : 'auto'
}
}

9
src/core/controls/SelectInspect.ts

@ -406,7 +406,7 @@ export default class SelectInspect implements IControls {
const endZ = box.max.z
// 查找所有在矩形内的对象
const objects = this.viewport.entityManager.getObjectsInBox(startX, startZ, endX, endZ)
const ids = this.viewport.itemFindManager.getItemsByRect(startX, startZ, endX, endZ)
// 清空之前的多选对象
this.viewport.state.multiSelectedObjects = []
@ -415,19 +415,20 @@ export default class SelectInspect implements IControls {
const multiSelectedObjects = []
const multiSelectedItems = []
const multiSelectedEntityIds = []
for (const object of objects) {
for (const id of ids) {
const object = this.viewport.entityManager.findObjectById(id)
if (object.userData.entityId && object.userData.t) {
const item = this.viewport.entityManager.findItemById(object.userData.entityId)
if (item && item.dt.protected !== true) {
multiSelectedObjects.push(object)
multiSelectedItems.push(item)
multiSelectedEntityIds.push(object.userData.entityId)
multiSelectedEntityIds.push(id)
}
}
}
// 触发多选对象更新事件
this.viewport.state.multiSelectedObjects = markRaw(objects)
this.viewport.state.multiSelectedObjects = markRaw(multiSelectedObjects)
this.viewport.state.multiSelectedItems = markRaw(multiSelectedItems)
this.viewport.state.multiSelectedEntityIds = multiSelectedEntityIds
EventBus.dispatch('multiSelectedObjectsChanged', {

8
src/core/engine/Viewport.ts

@ -25,6 +25,7 @@ import type InstancePointManager from '@/core/manager/InstancePointManager.ts'
import type LineSegmentManager from '@/core/manager/LineSegmentManager.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import type InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts'
import ItemFindManager from '@/core/manager/ItemFindManager.ts'
/**
*
@ -58,6 +59,8 @@ export default class Viewport {
// 实体管理器
entityManager = new EntityManager()
itemFindManager = new ItemFindManager()
// 交互管理器
interactionManager = new InteractionManager()
@ -599,6 +602,11 @@ export default class Viewport {
this.dragControl.dispose()
this.dragControl = null
}
if (this.itemFindManager) {
this.itemFindManager.dispose()
this.itemFindManager = null
}
}
getIntersects(point: THREE.Vector2) {

41
src/core/manager/EntityManager.ts

@ -101,6 +101,9 @@ export default class EntityManager {
if (!entity?.id) {
throw new Error('Entity must have an id')
}
this.viewport.itemFindManager.addOrUpdate(entity)
// 改成非深拷贝, 直接使用原始数据, 因为 renderer 可能会修改这个数据, 后续也要能生效
// const entity = _.cloneDeep(entityRaw) as ItemJson
const originEntity = this.___entityMap.get(entity.id)
@ -157,6 +160,8 @@ export default class EntityManager {
const entity = this.___entityMap.get(id)
if (!entity) return
this.viewport.itemFindManager.remove(id)
option.originEntity = _.cloneDeep(entity)
this.writeBackEntities.add(id)
@ -510,24 +515,24 @@ export default class EntityManager {
).filter((obj: Object3DLike) => obj?.userData && obj.userData.selectable !== false)
}
/**
*
*/
getObjectsInBox(startX: number, startZ: number, endX: number, endZ: number) {
const box = new THREE.Box2(
new THREE.Vector2(startX, startZ),
new THREE.Vector2(endX, endZ)
)
const objectsInBox: Object3DLike[] = []
for (const [id, obj] of this.__objectMap.entries()) {
if (box.containsPoint(new Vector2(obj.position.x, obj.position.z))) {
objectsInBox.push(obj)
}
}
return objectsInBox
}
// /**
// * 获取指定范围内的所有对象
// */
// getObjectsInBox(startX: number, startZ: number, endX: number, endZ: number) {
// const box = new THREE.Box2(
// new THREE.Vector2(startX, startZ),
// new THREE.Vector2(endX, endZ)
// )
// const objectsInBox: Object3DLike[] = []
//
// for (const [id, obj] of this.__objectMap.entries()) {
// if (box.containsPoint(new Vector2(obj.position.x, obj.position.z))) {
// objectsInBox.push(obj)
// }
// }
//
// return objectsInBox
// }
}
interface LineDiffItem {

11
src/core/manager/InstancePointManager.ts

@ -305,6 +305,17 @@ export class PointManageWrap {
}
createBox3() {
const instancedMesh = this.manager.blocks[this.blockIndex]?.instancedMesh
const matrix = new THREE.Matrix4()
instancedMesh.getMatrixAt(this.meshIndex, matrix)
// 创建包围盒并应用矩阵
const geometry = instancedMesh.geometry
//@ts-ignore
const localBox = new THREE.Box3().setFromBufferAttribute(geometry.attributes.position)
return localBox.clone().applyMatrix4(matrix)
}
createBox3Points() {
// 原始代码 =================================
// const instancedMesh = this.manager.blocks[this.blockIndex]?.instancedMesh
//

200
src/core/manager/ItemFindManager.ts

@ -0,0 +1,200 @@
import * as THREE from 'three'
import rbush from 'rbush'
import { OBB } from 'three/examples/jsm/math/OBB'
// import { Octree } from 'three/examples/jsm/math/Octree.js'
// import { QuadTreeNode } from '@/core/QuadTree.ts'
// import { convexHull } from '@/core/ModelUtils.ts'
interface ItemEntry extends rbush.BBox {
id: string
obb: OBB
}
// 主管理器类
export default class ItemFindManager {
private spatialIndex = new rbush<ItemEntry>()
private items = new Map<string, ItemEntry>()
dispose() {
this.spatialIndex.clear()
this.items.clear()
}
constructor() {
}
// 添加或更新物品
addOrUpdate(...items: ItemMetrix[]): void {
for (const item of items) {
const aabb = itemToAABB(item)
const obb = itemToOBB(item)
if (this.items.has(item.id)) {
this.remove(item.id)
}
const entry: ItemEntry = {
id: item.id,
obb,
...aabb
}
this.items.set(item.id, entry)
this.spatialIndex.insert(entry)
}
}
// 移除物品
remove(...ids: string[]): void {
for (const id of ids) {
const entry = this.items.get(id)
if (entry) {
this.spatialIndex.remove(entry)
this.items.delete(id)
}
}
}
// 位置查询
getItemsByPosition(x: number, z: number): string[] {
const candidates = this.spatialIndex.search({
minX: x,
minY: z,
maxX: x,
maxY: z
})
const point = new THREE.Vector3(x, 0, z)
return candidates.filter((item) => pointIntersectsOBB(point, item.obb)).map((item) => item.id)
}
// 距离查询
getItemsByDistance(x: number, z: number, distance: number): string[] {
const sphere = new THREE.Sphere(new THREE.Vector3(x, 0, z), distance)
const candidates = this.spatialIndex.search({
minX: x - distance,
minY: z - distance,
maxX: x + distance,
maxY: z + distance
})
return candidates.filter((item) => sphereIntersectsOBB(sphere, item.obb)).map((item) => item.id)
}
// 矩形区域查询(有交集)
getItemsByRect(x1: number, z1: number, x2: number, z2: number): string[] {
const rect = {
minX: Math.min(x1, x2),
maxX: Math.max(x1, x2),
minY: Math.min(z1, z2),
maxY: Math.max(z1, z2)
}
const candidates = this.spatialIndex.search(rect)
return candidates.filter((item) => rectIntersectsOBB(rect, item.obb)).map((item) => item.id)
}
}
function pointIntersectsOBB(point: THREE.Vector3, obb: OBB): boolean {
const box = new THREE.Box3()
setBox3FromOBB(box, obb)
return box.containsPoint(point)
}
function sphereIntersectsOBB(sphere: THREE.Sphere, obb: OBB): boolean {
const box = new THREE.Box3()
setBox3FromOBB(box, obb)
return box.intersectsSphere(sphere)
}
function rectIntersectsOBB(rect: { minX: number; minY: number; maxX: number; maxY: number }, obb: OBB): boolean {
// 简化判断:用 AABB 投影到 XZ 平面做矩形交叉检测
const aabb = new THREE.Box3()
setBox3FromOBB(aabb, obb)
const aabb2D = {
minX: aabb.min.x,
minY: aabb.min.z,
maxX: aabb.max.x,
maxY: aabb.max.z
}
return !(
rect.maxX < aabb2D.minX ||
rect.minX > aabb2D.maxX ||
rect.maxY < aabb2D.minY ||
rect.minY > aabb2D.maxY
)
}
export function itemToAABB(item: ItemMetrix): { minX: number; minY: number; maxX: number; maxY: number } {
// 假设所有物品都是立方体,尺寸为 scale.x × scale.z
const x = item.tf[0][0]
const z = item.tf[0][2]
const halfWidth = item.tf[2][0] / 2
const halfDepth = item.tf[2][2] / 2
return {
minX: x - halfWidth,
maxX: x + halfWidth,
minY: z - halfDepth,
maxY: z + halfDepth
}
}
export function itemToOBB(item: ItemMetrix): OBB {
const position = new THREE.Vector3(...item.tf[0])
const rotation = new THREE.Euler(
THREE.MathUtils.degToRad(item.tf[1][0]),
THREE.MathUtils.degToRad(item.tf[1][1]),
THREE.MathUtils.degToRad(item.tf[1][2]),
'XYZ'
)
const scale = new THREE.Vector3(...item.tf[2])
const matrix = new THREE.Matrix4()
.makeRotationFromEuler(rotation)
.premultiply(new THREE.Matrix4().makeTranslation(position.x, position.y, position.z))
.premultiply(new THREE.Matrix4().makeScale(scale.x, scale.y, scale.z))
const obb = new OBB(
new THREE.Vector3(),
new THREE.Vector3(0.5, 0.5, 0.5),
new THREE.Matrix3().setFromMatrix4(matrix)
)
return obb
}
function setBox3FromOBB(box: THREE.Box3, obb: OBB): THREE.Box3 {
const center = obb.center
const halfSize = new THREE.Vector3().copy(obb.halfSize)
const rotation = obb.rotation
// 8 个局部顶点
const vertices = [
new THREE.Vector3().copy(halfSize).multiply(new THREE.Vector3(1, 1, 1)),
new THREE.Vector3().copy(halfSize).multiply(new THREE.Vector3(-1, 1, 1)),
new THREE.Vector3().copy(halfSize).multiply(new THREE.Vector3(-1, -1, 1)),
new THREE.Vector3().copy(halfSize).multiply(new THREE.Vector3(1, -1, 1)),
new THREE.Vector3().copy(halfSize).multiply(new THREE.Vector3(1, 1, -1)),
new THREE.Vector3().copy(halfSize).multiply(new THREE.Vector3(-1, 1, -1)),
new THREE.Vector3().copy(halfSize).multiply(new THREE.Vector3(-1, -1, -1)),
new THREE.Vector3().copy(halfSize).multiply(new THREE.Vector3(1, -1, -1))
]
// 应用旋转和平移到每个顶点
const worldVertices = vertices.map((v) => {
return v.applyMatrix3(rotation).add(center)
})
// 构造包围盒
box.min.set(Infinity, Infinity, Infinity)
box.max.set(-Infinity, -Infinity, -Infinity)
for (const v of worldVertices) {
box.expandByPoint(v)
}
return box
}

7
src/core/manager/LineSegmentManager.ts

@ -5,7 +5,6 @@ import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2'
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial'
import type { Object3DLike, Vector3Like } from '@/types/ModelTypes.ts'
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry'
import { Line2 } from 'three/examples/jsm/lines/Line2'
/**
* 线
@ -262,7 +261,7 @@ export default class LineSegmentManager {
this.lineGeometry = new LineGeometry() // new LineSegmentsGeometry()
// 创建线段的渲染对象
this.lineSegments = new Line2(this.lineGeometry, this.lineMaterial)
this.lineSegments = new LineSegments2(this.lineGeometry, this.lineMaterial)
this.lineSegments.name = name
this.lineSegments.frustumCulled = false
this.viewport.scene.add(this.lineSegments)
@ -284,6 +283,7 @@ export default class LineSegmentManager {
this.positionArray = null
this.colorArray = null
}
}
@ -312,7 +312,8 @@ export class LineManageWrap {
return false
}
updateWorldMatrix(){}
updateWorldMatrix() {
}
constructor(lineManager: LineSegmentManager, data: any, start: THREE.Vector3, end: THREE.Vector3, color: THREE.Color) {
this.manager = lineManager

12
src/example/example1.js

@ -94,22 +94,22 @@ export default {
tf: [[5, 0.1, 2], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['39zML1rnSOOQGQYQ2YUMGy'] }
}, {
id: '6UhIIw9QPYh6acwyW8OSGs',
id: 'gs1',
t: 'gstore',
v: true,
tf: [[-1, 0.1, 0.55], [0, 0, 0], [1.5, 0.1, 1.5]],
tf: [[-1, 0.1, -5.55], [0, 0, 0], [1, 0.1, 1]],
dt: { in: [], out: [], center: [] }
}, {
id: '1D0WSRPj8JJJwIcmA0UMqG',
id: 'gs2',
t: 'gstore',
v: true,
tf: [[0.75, 0.1, 0.55], [0, 0, 0], [1.5, 0.1, 1.5]],
tf: [[0.75, 0.1, -5.55], [0, 0, 0], [1, 0.1, 1]],
dt: { in: [], out: [], center: [] }
}, {
id: 'gstore333',
id: 'gs3',
t: 'gstore',
v: true,
tf: [[3, 0.1, 0.55], [0, 0, 0], [1.5, 0.1, 1.5]],
tf: [[3, 0.1, -5.55], [0, 0, 0], [1, 0.1, 1]],
dt: { in: [], out: [], center: [] }
}, {
id: 'pallet1',

77
src/modules/gstore/GstoreRenderer.ts

@ -5,6 +5,8 @@ import { type Object3DLike } from '@/types/ModelTypes.ts'
import InstancePointManager from '@/core/manager/InstancePointManager.ts'
import LineSegmentManager from '@/core/manager/LineSegmentManager.ts'
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial'
import { itemToOBB } from '@/core/manager/ItemFindManager.ts'
import { getOBBox } from '@/core/ModelUtils.ts'
/**
*
@ -59,17 +61,6 @@ export default class GstoreRenderer extends BaseRenderer {
)
}
get lineSegmentManager(): LineSegmentManager {
if (!this.tempViewport) {
throw new Error('tempViewport is not set.')
}
return this.tempViewport.getOrCreateLineManager(this.itemTypeName, () =>
// 构建 LineSegment.points 代理对象
LineSegmentManager.create(this.itemTypeName,
this.tempViewport,
this.strokeMaterial)
)
}
createPointBasic(item: ItemJson, option?: RendererCudOption): Object3DLike {
return this.pointManager.createPoint(item)
@ -78,25 +69,35 @@ export default class GstoreRenderer extends BaseRenderer {
afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, object: Object3DLike) {
super.afterCreateOrUpdatePoint(item, option, object)
// 画边线
const center = [item.tf[0][0], item.tf[0][2]]
const h = (item.tf[0][1] || this.defulePositionY) + 0.01
const widthHalf = item.tf[2][0] / 2
const depthHalf = item.tf[2][2] / 2
const lwHalf = (item.dt.strokeWidth || this.defaultPointOption.strokeWidth) / 2
// 左上角
const p1 = [center[0] - widthHalf + lwHalf, h, center[1] - depthHalf + lwHalf]
// 右上角
const p2 = [center[0] + widthHalf - lwHalf, h, center[1] - depthHalf + lwHalf]
// 右下角
const p3 = [center[0] + widthHalf - lwHalf, h, center[1] + depthHalf - lwHalf]
// 左下角
const p4 = [center[0] - widthHalf + lwHalf, h, center[1] + depthHalf - lwHalf]
this.lineSegmentManager.createLine(item.id + '_l1', p1, p2, this.strokeMaterial.color)
this.lineSegmentManager.createLine(item.id + '_l2', p2, p3, this.strokeMaterial.color)
this.lineSegmentManager.createLine(item.id + '_l3', p3, p4, this.strokeMaterial.color)
this.lineSegmentManager.createLine(item.id + '_l4', p4, p1, this.strokeMaterial.color)
const edgePositions = getOBBox(item)
// const positions = []
for (let i = 0; i < edgePositions.length; i += 2) {
const p1 = edgePositions[i]
const p2 = edgePositions[i + 1]
// positions.push(p1.x, p1.y, p1.z)
// positions.push(p2.x, p2.y, p2.z)
this.lineSegmentManager.createLine(item.id + '_l' + i, p1, p2, this.strokeMaterial.color)
}
// // 画边线
// const center = [item.tf[0][0], item.tf[0][2]]
// const h = (item.tf[0][1] || this.defulePositionY) + 0.01
// const widthHalf = item.tf[2][0] / 2
// const depthHalf = item.tf[2][2] / 2
// const lwHalf = (item.dt.strokeWidth || this.defaultPointOption.strokeWidth) / 2
// // 左上角
// const p1 = [center[0] - widthHalf + lwHalf, h, center[1] - depthHalf + lwHalf]
// // 右上角
// const p2 = [center[0] + widthHalf - lwHalf, h, center[1] - depthHalf + lwHalf]
// // 右下角
// const p3 = [center[0] + widthHalf - lwHalf, h, center[1] + depthHalf - lwHalf]
// // 左下角
// const p4 = [center[0] - widthHalf + lwHalf, h, center[1] + depthHalf - lwHalf]
//
// this.lineSegmentManager.createLine(item.id + '_l1', p1, p2, this.strokeMaterial.color)
// this.lineSegmentManager.createLine(item.id + '_l2', p2, p3, this.strokeMaterial.color)
// this.lineSegmentManager.createLine(item.id + '_l3', p3, p4, this.strokeMaterial.color)
// this.lineSegmentManager.createLine(item.id + '_l4', p4, p1, this.strokeMaterial.color)
}
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D {
@ -113,4 +114,20 @@ export default class GstoreRenderer extends BaseRenderer {
this.pointMaterial.dispose()
this.strokeMaterial.dispose()
}
get lineSegmentManager(): LineSegmentManager {
if (!this.tempViewport) {
throw new Error('tempViewport is not set.')
}
const name = this.itemTypeName + '_bj'
return this.tempViewport.getOrCreateLineManager(name, () =>
// 构建 LineSegment.points 代理对象
LineSegmentManager.create(name,
this.tempViewport,
this.strokeMaterial)
)
}
}

11
src/modules/way/WayRenderer.ts

@ -6,7 +6,7 @@ import Constract from '@/core/Constract.ts'
import InstancePointManager from '@/core/manager/InstancePointManager.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import TriangleUrl from '@/assets/images/conveyor/shapes/triangle.png'
import Triangle2Url from '@/assets/images/conveyor/shapes/triangle2.png'
import Triangle2Url from '@/assets/images/conveyor/shapes/triangle-double.png'
import InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts'
/**
@ -132,7 +132,7 @@ export default class WayRenderer extends BaseRenderer {
const endPosition = new THREE.Vector3(end.tf[0][0], this.defulePositionY, end.tf[0][2])
const wrap = this.guidewayManager.create(lineId, {})
wrap.uuid = lineId
const matrix = createLinkPlaneMatrix4(startPosition, endPosition, this.rendererOption.lineWidth, direction)
const matrix = createLinkPlaneMatrix4(startPosition, endPosition, this.rendererOption.lineWidth)
wrap.setMatrix4(matrix)
@ -153,8 +153,10 @@ export default class WayRenderer extends BaseRenderer {
const dummy = new THREE.Object3D()
dummy.position.setFromMatrixPosition(matrix)
// dummy.rotation.setFromRotationMatrix(matrix)
dummy.scale.set(0.4, 0.01, 0.2)
if (direction === '<->') {
dummy.scale.set(0.4, 0.01, 0.4)
dummy.lookAt(endPosition)
} else if (direction === '->') {
dummy.lookAt(endPosition)
@ -162,7 +164,6 @@ export default class WayRenderer extends BaseRenderer {
dummy.lookAt(startPosition)
}
dummy.scale.set(0.4, 0.01, 0.2)
dummy.updateMatrix()
dirWrap.setMatrix4(dummy.matrix)
wrap.userData.dirWraps = [dirWrap.uuid]
@ -180,8 +181,10 @@ export default class WayRenderer extends BaseRenderer {
const position = startPosition.clone().lerp(endPosition, i / length)
const dummy = new THREE.Object3D()
dummy.position.copy(position)
dummy.scale.set(0.4, 0.01, 0.2)
if (direction === '<->') {
dummy.scale.set(0.4, 0.01, 0.4)
dummy.lookAt(endPosition)
} else if (direction === '->') {
dummy.lookAt(endPosition)
@ -189,7 +192,7 @@ export default class WayRenderer extends BaseRenderer {
dummy.lookAt(startPosition)
}
dummy.scale.set(0.4, 0.01, 0.2)
dummy.updateMatrix()
dirWrap.setMatrix4(dummy.matrix)

55
src/types/model.d.ts

@ -106,6 +106,35 @@ interface IGridHelper {
snapDistance: number;
}
interface ItemMetrix {
/**
* ID,
*/
id: string
/**
* , 3x3矩阵, X轴正增长向右, Y轴正增长向屏幕外, Z轴正增长向下
*/
tf: [
/**
* position,
* [0]=x轴向右, [1]=y轴高度向屏幕外, [2]=z轴向下
*/
[number, number, number],
/**
* rotation,
* [0]=X轴逆向旋转角度, [1]=Y轴逆向旋转角度, [2]=Z轴逆向旋转角度
* three.js "角度""弧度"
*/
[number, number, number],
/**
* scale, [0]=X宽度, [1]=Y高度, [2]=Z长度
*/
[number, number, number],
]
}
/**
* ()
@ -128,12 +157,7 @@ interface IGridHelper {
* }
* }
*/
interface ItemJson {
/**
* three.js uuid, ID, , , O(1)
*/
id?: string
interface ItemJson extends ItemMetrix {
/**
* , , three.js name , , , O(N)
*/
@ -150,24 +174,6 @@ interface ItemJson {
v: boolean
/**
* , 3x3矩阵, Y轴向上为正, X轴向右, Z轴向前的右手坐标系
*/
tf: [
/**
* position,
*/
[number, number, number],
/**
* rotation, Y轴旋转的角度, three.js "角度""弧度"
*/
[number, number, number],
/**
* scale,
*/
[number, number, number],
]
/**
* , , three.js userData
*/
dt: {
@ -214,7 +220,6 @@ interface ItemJson {
}
/**
* Object3D Mesh / Geometry
*/

Loading…
Cancel
Save