Compare commits

..

72 Commits

Author SHA1 Message Date
Yeicor
6aa680bf43 Automatically update version to 0.9.5 2025-04-20 10:53:32 +00:00
Yeicor
b629f07f5e Fix broken gltf exports and minor cleanup 2025-04-20 12:47:23 +02:00
renovate[bot]
9e4f571808 Update dependency vite to v6.2.6 [SECURITY] 2025-04-11 16:50:03 +00:00
renovate[bot]
eaad9f3774 Lock file maintenance 2025-04-05 18:12:03 +00:00
renovate[bot]
79f6359af1 Update dependency vuetify to v3.8.0 2025-04-05 10:28:54 +00:00
renovate[bot]
ca5e9e03ab Update dependency @types/node to v22.14.0 2025-04-05 06:44:09 +00:00
renovate[bot]
2ebdee2d42 Update dependency typescript to v5.8.3 2025-04-05 01:49:44 +00:00
renovate[bot]
c1773fb156 Update dependency vite to v6.2.5 [SECURITY] 2025-04-04 18:54:21 +00:00
renovate[bot]
e05cc70f3a Update dependency vite to v6.2.4 [SECURITY] 2025-03-31 19:41:40 +00:00
renovate[bot]
7d97ed5e93 Lock file maintenance 2025-03-29 18:54:49 +00:00
renovate[bot]
823ee5462f Update dependency three to ^0.175.0 2025-03-29 13:57:09 +00:00
renovate[bot]
64aebb5cf7 Update dependency vuetify to v3.7.19 2025-03-29 10:03:57 +00:00
renovate[bot]
979713bb48 Update dependency @types/node to v22.13.14 2025-03-29 06:13:03 +00:00
renovate[bot]
3b8efd628c Update dependency @tsconfig/node20 to v20.1.5 2025-03-29 02:27:01 +00:00
renovate[bot]
f91033ef3d Update dependency vite to v6.2.3 [SECURITY] 2025-03-25 18:56:53 +00:00
renovate[bot]
0f881a6de5 Lock file maintenance 2025-03-23 05:55:58 +00:00
renovate[bot]
fe919f539e Update dependency vuetify to v3.7.18 2025-03-22 13:49:32 +00:00
renovate[bot]
0b2efb006c Update dependency @vitejs/plugin-vue-jsx to v4.1.2 2025-03-22 09:28:10 +00:00
renovate[bot]
7584af683e Update dependency @vitejs/plugin-vue to v5.2.3 2025-03-22 06:17:04 +00:00
renovate[bot]
64358469ae Update dependency @types/node to v22.13.11 2025-03-22 01:25:57 +00:00
renovate[bot]
28ad995982 Lock file maintenance 2025-03-15 17:52:21 +00:00
renovate[bot]
3efb47fef1 Update dependency generate-license-file to v4 2025-03-15 13:16:46 +00:00
renovate[bot]
1ca655f2f4 Update dependency generate-license-file to v3.8.1 2025-03-15 10:08:32 +00:00
renovate[bot]
4fd6fc6e23 Update dependency vuetify to v3.7.16 2025-03-15 06:52:16 +00:00
renovate[bot]
b6d21e7ef1 Update dependency vite to v6.2.2 2025-03-15 01:50:55 +00:00
renovate[bot]
fb484b61da Lock file maintenance 2025-03-09 21:23:52 +00:00
renovate[bot]
1ebfa3dd3f Update dependency vuetify to v3.7.15 2025-03-08 14:27:32 +00:00
renovate[bot]
35bfb8679a Update dependency vue-tsc to v2.2.8 2025-03-08 10:54:52 +00:00
renovate[bot]
dce407ca2b Update dependency vite to v6.2.1 2025-03-08 06:46:23 +00:00
renovate[bot]
f9e90bee25 Update dependency @types/node to v22.13.9 2025-03-08 02:33:41 +00:00
renovate[bot]
ea44096200 Lock file maintenance (#232)
* Lock file maintenance

* Update Models.vue

* Update Models.vue

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Yeicor <4929005+Yeicor@users.noreply.github.com>
2025-03-02 09:43:49 +01:00
renovate[bot]
f3d19911c7 Update dependency vite to v6.2.0 2025-03-01 18:52:39 +00:00
renovate[bot]
2214a4812c Update dependency typescript to ~5.8.0 2025-03-01 13:41:42 +00:00
renovate[bot]
8b08afc1ea Update dependency three to ^0.174.0 2025-03-01 10:27:05 +00:00
renovate[bot]
4d77723fe6 Update dependency vuetify to v3.7.14 2025-03-01 06:29:08 +00:00
renovate[bot]
bd0364fcea Update dependency @types/node to v22.13.7 2025-03-01 02:09:53 +00:00
renovate[bot]
3b466c0291 Lock file maintenance 2025-02-23 14:27:42 +00:00
renovate[bot]
ade6faa6a3 Update dependency vuetify to v3.7.13 2025-02-22 10:36:17 +00:00
renovate[bot]
c88959cc11 Update dependency vite to v6.1.1 2025-02-22 06:43:26 +00:00
renovate[bot]
1e7fe81a60 Update dependency @types/node to v22.13.5 2025-02-22 02:04:41 +00:00
Yeicor
726e3927f4 Automatically update version to 0.9.4 2025-02-16 12:10:07 +00:00
renovate[bot]
5f6b6d7ba0 Update dependency build123d to >=0.9,<0.10 (#231)
* Update dependency build123d to >=0.9,<0.10

* Update pyproject.toml

* Small fix and updates

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Yeicor <4929005+Yeicor@users.noreply.github.com>
2025-02-16 13:06:21 +01:00
renovate[bot]
62bc825bc8 Lock file maintenance 2025-02-16 05:21:17 +00:00
renovate[bot]
de789ad8a9 Update dependency commander to v13 2025-02-16 02:40:30 +00:00
renovate[bot]
e657acaee3 Update dependency vite to v6.1.0 2025-02-15 22:46:27 +00:00
renovate[bot]
ba94f64ca0 Update dependency three-mesh-bvh to ^0.9.0 2025-02-15 18:51:07 +00:00
renovate[bot]
26722781d2 Update dependency three to ^0.173.0 2025-02-15 14:16:17 +00:00
renovate[bot]
2434df71aa Update dependency terser to v5.39.0 2025-02-15 10:58:14 +00:00
renovate[bot]
f02d561d8b Update dependency @types/node to v22.13.4 2025-02-15 05:43:15 +00:00
renovate[bot]
73c8715517 Update dependency vuetify to v3.7.12 2025-02-15 01:24:04 +00:00
renovate[bot]
1a0a8cae67 Update dependency vite to v6.0.9 [SECURITY] 2025-01-21 21:20:01 +00:00
renovate[bot]
a00665a3a1 Update dependency generate-license-file to v3.7.0 2025-01-19 08:43:48 +00:00
renovate[bot]
126d514ee3 Update dependency @types/node to v22.10.7 2025-01-18 00:13:20 +00:00
renovate[bot]
c0014f989f Update dependency typescript to v5.7.3 2025-01-11 09:56:22 +01:00
renovate[bot]
874413c3c2 Update dependency pillow to v11.1.0 2025-01-11 09:56:12 +01:00
Yeicor
bff2140b9f Update CI python versions 2025-01-11 09:18:31 +01:00
Yeicor
0aa20c7e8e Fix poetry commands after update 2025-01-11 09:17:05 +01:00
renovate[bot]
8bf29b18da Update dependency vite to v6.0.7 2025-01-04 23:29:19 +01:00
Yeicor
8330060bd9 "Proper" top-level-await workaround 2025-01-04 23:26:29 +01:00
renovate[bot]
b09d5a87fa Update dependency @types/node to v22.10.5 2025-01-04 01:59:41 +00:00
renovate[bot]
b976976cda Update dependency vite to v6 2024-12-29 07:49:49 +00:00
renovate[bot]
2a82d37da1 Update dependency typescript to ~5.7.0 2024-12-29 03:33:53 +00:00
renovate[bot]
632f09382f Update dependency three to ^0.171.0 2024-12-29 00:59:49 +00:00
renovate[bot]
558cc306e2 Update dependency @vue/tsconfig to ^0.7.0 2024-12-28 22:38:10 +00:00
renovate[bot]
f1476befe2 Lock file maintenance 2024-12-28 00:12:30 +00:00
renovate[bot]
cb386f0020 Lock file maintenance 2024-12-21 00:23:13 +00:00
Yeicor
ef37fad7fc Renovate bot changes 2024-12-14 10:38:58 +01:00
renovate[bot]
f42fa9515b Lock file maintenance (#226)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-14 04:00:27 +00:00
renovate[bot]
fca2018279 Lock file maintenance (#225)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-07 08:03:14 +00:00
renovate[bot]
1e0e755b0e Lock file maintenance (#224)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-07 04:20:12 +00:00
renovate[bot]
757007ad7b Lock file maintenance (#223)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-30 10:43:20 +00:00
renovate[bot]
bc2cc76b29 Lock file maintenance (#222)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-30 04:12:29 +00:00
24 changed files with 1863 additions and 1955 deletions

18
.github/renovate.json5 vendored Normal file
View File

@@ -0,0 +1,18 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
":disableDependencyDashboard"
],
"automerge": true,
"automergeType": "branch",
"schedule": [
"before 3am on Saturday"
],
"lockFileMaintenance": {
"enabled": true,
"schedule": [
"before 3am on Saturday"
]
}
}

View File

@@ -1,10 +1,6 @@
on: on:
push: push:
branches:
- "master"
pull_request: pull_request:
branches:
- "master"
workflow_call: workflow_call:
inputs: inputs:
ref: ref:
@@ -42,9 +38,9 @@ jobs:
- run: "pipx install poetry" - run: "pipx install poetry"
- uses: "actions/setup-python@v5" - uses: "actions/setup-python@v5"
with: with:
python-version: "3.11" python-version: "3.12"
cache: "poetry" cache: "poetry"
- run: "SKIP_BUILD_FRONTEND=true poetry lock --no-update" - run: "SKIP_BUILD_FRONTEND=true poetry lock"
- run: "SKIP_BUILD_FRONTEND=true poetry install" - run: "SKIP_BUILD_FRONTEND=true poetry install"
- run: "SKIP_BUILD_FRONTEND=true poetry build" - run: "SKIP_BUILD_FRONTEND=true poetry build"
@@ -58,9 +54,9 @@ jobs:
- run: "pipx install poetry" - run: "pipx install poetry"
- uses: "actions/setup-python@v5" - uses: "actions/setup-python@v5"
with: with:
python-version: "3.11" python-version: "3.12"
cache: "poetry" cache: "poetry"
- run: "SKIP_BUILD_FRONTEND=true poetry lock --no-update" - run: "SKIP_BUILD_FRONTEND=true poetry lock"
- run: "SKIP_BUILD_FRONTEND=true poetry install" - run: "SKIP_BUILD_FRONTEND=true poetry install"
- run: "poetry run python yacv_server/logo.py" - run: "poetry run python yacv_server/logo.py"
- uses: "actions/upload-artifact@v4" - uses: "actions/upload-artifact@v4"
@@ -79,9 +75,9 @@ jobs:
- run: "pipx install poetry" - run: "pipx install poetry"
- uses: "actions/setup-python@v5" - uses: "actions/setup-python@v5"
with: with:
python-version: "3.11" python-version: "3.12"
cache: "poetry" cache: "poetry"
- run: "SKIP_BUILD_FRONTEND=true poetry lock --no-update" - run: "SKIP_BUILD_FRONTEND=true poetry lock"
- run: "SKIP_BUILD_FRONTEND=true poetry install" - run: "SKIP_BUILD_FRONTEND=true poetry install"
- run: "YACV_DISABLE_SERVER=true poetry run python example/object.py" - run: "YACV_DISABLE_SERVER=true poetry run python example/object.py"
- uses: "actions/upload-artifact@v4" - uses: "actions/upload-artifact@v4"

View File

@@ -33,7 +33,7 @@ jobs:
- run: "pipx install poetry" - run: "pipx install poetry"
- uses: "actions/setup-python@v5" - uses: "actions/setup-python@v5"
with: with:
python-version: "3.11" python-version: "3.12"
cache: "poetry" cache: "poetry"
- run: "poetry version $CLEAN_VERSION" - run: "poetry version $CLEAN_VERSION"
# Commit the changes and move the tag! # Commit the changes and move the tag!

View File

@@ -67,7 +67,7 @@ jobs:
- run: "pipx install poetry" - run: "pipx install poetry"
- uses: "actions/setup-python@v5" - uses: "actions/setup-python@v5"
with: with:
python-version: "3.11" python-version: "3.12"
cache: "poetry" cache: "poetry"
- run: "poetry install" - run: "poetry install"
- run: "poetry config pypi-token.pypi ${{ secrets.PYPI_TOKEN }}" - run: "poetry config pypi-token.pypi ${{ secrets.PYPI_TOKEN }}"

View File

@@ -211,12 +211,11 @@ Apache License
----------- -----------
The following npm packages may be included in this product: The following npm package may be included in this product:
- source-map-js@1.2.0
- source-map-js@1.2.1 - source-map-js@1.2.1
These packages each contain the following license: This package contains the following license:
Copyright (c) 2009-2011, Mozilla Foundation and contributors Copyright (c) 2009-2011, Mozilla Foundation and contributors
All rights reserved. All rights reserved.
@@ -778,11 +777,13 @@ The above copyright notice and this permission notice shall be included in all c
----------- -----------
The following npm package may be included in this product: The following npm packages may be included in this product:
- sharp@0.33.4 - @img/sharp-linux-x64@0.33.5
- @img/sharp-linuxmusl-x64@0.33.5
- sharp@0.33.5
This package contains the following license: These packages each contain the following license:
Apache License Apache License
Version 2.0, January 2004 Version 2.0, January 2004
@@ -980,7 +981,7 @@ third-party archives.
The following npm package may be included in this product: The following npm package may be included in this product:
- typescript@5.6.3 - typescript@5.8.3
This package contains the following license: This package contains the following license:
@@ -1120,7 +1121,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The following npm package may be included in this product: The following npm package may be included in this product:
- @lit-labs/ssr-dom-shim@1.2.0 - @lit-labs/ssr-dom-shim@1.3.0
This package contains the following license: This package contains the following license:
@@ -1246,7 +1247,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The following npm package may be included in this product: The following npm package may be included in this product:
- @babel/parser@7.25.3 - @babel/parser@7.27.0
This package contains the following license: This package contains the following license:
@@ -1366,7 +1367,7 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The following npm package may be included in this product: The following npm package may be included in this product:
- magic-string@0.30.11 - magic-string@0.30.17
This package contains the following license: This package contains the following license:
@@ -1404,30 +1405,22 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
----------- -----------
The following npm package may be included in this product: The following npm packages may be included in this product:
- to-fast-properties@2.0.0 - @img/sharp-libvips-linux-x64@1.0.4
- @img/sharp-libvips-linuxmusl-x64@1.0.4
This package contains the following license: These packages each contain the following license:
MIT License LGPL-3.0-or-later
Copyright (c) 2014 Petka Antonov
2015 Sindre Sorhus
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
----------- -----------
The following npm packages may be included in this product: The following npm packages may be included in this product:
- @babel/helper-string-parser@7.24.8 - @babel/helper-string-parser@7.25.9
- @babel/helper-validator-identifier@7.24.7 - @babel/helper-validator-identifier@7.25.9
- @babel/types@7.25.2 - @babel/types@7.27.0
These packages each contain the following license: These packages each contain the following license:
@@ -1458,7 +1451,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The following npm package may be included in this product: The following npm package may be included in this product:
- three-mesh-bvh@0.8.3 - three-mesh-bvh@0.9.0
This package contains the following license: This package contains the following license:
@@ -1518,7 +1511,7 @@ SOFTWARE.
The following npm package may be included in this product: The following npm package may be included in this product:
- @monogrid/gainmap-js@3.0.3 - @monogrid/gainmap-js@3.1.0
This package contains the following license: This package contains the following license:
@@ -1608,7 +1601,7 @@ The MIT license applies to all non-font and non-icon files.
The following npm package may be included in this product: The following npm package may be included in this product:
- semver@7.6.2 - semver@7.7.1
This package contains the following license: This package contains the following license:
@@ -1692,13 +1685,13 @@ THE SOFTWARE.
The following npm package may be included in this product: The following npm package may be included in this product:
- three@0.169.0 - three@0.175.0
This package contains the following license: This package contains the following license:
The MIT License The MIT License
Copyright © 2010-2024 three.js authors Copyright © 2010-2025 three.js authors
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1782,7 +1775,7 @@ THE SOFTWARE.
The following npm package may be included in this product: The following npm package may be included in this product:
- vuetify@3.7.4 - vuetify@3.8.0
This package contains the following license: This package contains the following license:
@@ -1851,7 +1844,7 @@ THE SOFTWARE.
The following npm package may be included in this product: The following npm package may be included in this product:
- ktx-parse@0.7.1 - ktx-parse@1.0.0
This package contains the following license: This package contains the following license:
@@ -1913,9 +1906,9 @@ SOFTWARE.
The following npm packages may be included in this product: The following npm packages may be included in this product:
- @gltf-transform/core@4.1.0 - @gltf-transform/core@4.1.3
- @gltf-transform/extensions@4.1.0 - @gltf-transform/extensions@4.1.3
- @gltf-transform/functions@4.1.0 - @gltf-transform/functions@4.1.3
These packages each contain the following license: These packages each contain the following license:
@@ -1975,7 +1968,7 @@ THE SOFTWARE.
The following npm package may be included in this product: The following npm package may be included in this product:
- postcss@8.4.49 - postcss@8.5.3
This package contains the following license: This package contains the following license:
@@ -2004,7 +1997,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The following npm package may be included in this product: The following npm package may be included in this product:
- nanoid@3.3.7 - nanoid@3.3.11
This package contains the following license: This package contains the following license:

View File

@@ -52,10 +52,11 @@ async function onModelUpdateRequest(event: NetworkUpdateEvent) {
let model = event.models[modelIndex]; let model = event.models[modelIndex];
tools.value?.removeObjectSelections(model.name); tools.value?.removeObjectSelections(model.name);
try { try {
let loadHelpers = (await settings()).loadHelpers;
if (!model.isRemove) { if (!model.isRemove) {
doc = await SceneMgr.loadModel(sceneUrl, doc, model.name, model.url, isLast && settings.loadHelpers, isLast); doc = await SceneMgr.loadModel(sceneUrl, doc, model.name, model.url, isLast && loadHelpers, isLast);
} else { } else {
doc = await SceneMgr.removeModel(sceneUrl, doc, model.name, isLast && settings.loadHelpers, isLast); doc = await SceneMgr.removeModel(sceneUrl, doc, model.name, isLast && loadHelpers, isLast);
} }
} catch (e) { } catch (e) {
console.error("Error loading model", model, e); console.error("Error loading model", model, e);
@@ -79,16 +80,18 @@ let networkMgr = new NetworkManager();
networkMgr.addEventListener('update-early', networkMgr.addEventListener('update-early',
(e) => viewer.value?.onProgress((e as CustomEvent<Array<any>>).detail.length * 0.01)); (e) => viewer.value?.onProgress((e as CustomEvent<Array<any>>).detail.length * 0.01));
networkMgr.addEventListener('update', (e) => onModelUpdateRequest(e as NetworkUpdateEvent)); networkMgr.addEventListener('update', (e) => onModelUpdateRequest(e as NetworkUpdateEvent));
// Start loading all configured models ASAP (async () => { // Start loading all configured models ASAP
for (let model of settings.preload) { let sett = await settings();
networkMgr.load(model); watch(viewer, (newViewer) => {
} if (newViewer) {
watch(viewer, (newViewer) => { newViewer.setPosterText('<tspan x="50%" dy="1.2em">Trying to load' +
if (newViewer) { ' models from:</tspan>' + sett.preload.map((url: string) => '<tspan x="50%" dy="1.2em">- ' + url + '</tspan>').join(""));
newViewer.setPosterText('<tspan x="50%" dy="1.2em">Trying to load' + }
' models from:</tspan>' + settings.preload.map((url) => '<tspan x="50%" dy="1.2em">- ' + url + '</tspan>').join("")); });
for (let model of sett.preload) {
await networkMgr.load(model);
} }
}); })();
async function loadModelManual() { async function loadModelManual() {
const modelUrl = prompt("For an improved experience in viewing CAD/GLTF models with automatic updates, it's recommended to use the official yacv_server Python package. This ensures seamless serving of models and automatic updates.\n\nOtherwise, enter the URL of the model to load:"); const modelUrl = prompt("For an improved experience in viewing CAD/GLTF models with automatic updates, it's recommended to use the official yacv_server Python package. This ensures seamless serving of models and automatic updates.\n\nOtherwise, enter the URL of the model to load:");

View File

@@ -61,6 +61,7 @@ export class NetworkManager extends EventTarget {
private async monitorDevServer(url: URL, stop: () => boolean = () => false) { private async monitorDevServer(url: URL, stop: () => boolean = () => false) {
while (!stop()) { while (!stop()) {
let monitorEveryMs = (await settings()).monitorEveryMs;
try { try {
// WARNING: This will spam the console logs with failed requests when the server is down // WARNING: This will spam the console logs with failed requests when the server is down
const controller = new AbortController(); const controller = new AbortController();
@@ -82,12 +83,12 @@ export class NetworkManager extends EventTarget {
} }
} else { } else {
// Server is down, wait a little longer before retrying // Server is down, wait a little longer before retrying
await new Promise(resolve => setTimeout(resolve, 10 * settings.monitorEveryMs)); await new Promise(resolve => setTimeout(resolve, 10 * monitorEveryMs));
} }
controller.abort(); controller.abort();
} catch (e) { // Ignore errors (retry very soon) } catch (e) { // Ignore errors (retry very soon)
} }
await new Promise(resolve => setTimeout(resolve, settings.monitorEveryMs)); await new Promise(resolve => setTimeout(resolve, monitorEveryMs));
} }
} }

View File

@@ -1,35 +1,66 @@
// These are the default values for the settings, which are overridden below // These are the default values for the settings, which are overridden below
export const settings = { let settingsCache: any = null;
preload: [
// @ts-ignore export async function settings() {
// new URL('../../assets/fox.glb', import.meta.url).href, if (settingsCache !== null) return settingsCache;
// @ts-ignore let settings = {
// new URL('../../assets/logo_build/base.glb', import.meta.url).href, preload: [
// @ts-ignore // @ts-ignore
// new URL('../../assets/logo_build/location.glb', import.meta.url).href, // new URL('../../assets/fox.glb', import.meta.url).href,
// @ts-ignore // @ts-ignore
// new URL('../../assets/logo_build/img.jpg.glb', import.meta.url).href, // new URL('../../assets/logo_build/base.glb', import.meta.url).href,
// Websocket URLs automatically listen for new models from the python backend // @ts-ignore
'<auto>', // Get the default preload URL if not overridden // new URL('../../assets/logo_build/location.glb', import.meta.url).href,
], // @ts-ignore
loadHelpers: true, // new URL('../../assets/logo_build/img.jpg.glb', import.meta.url).href,
edgeWidth: 0, /* The default line size for edges, set to 0 to use basic gl.LINEs */ // Websocket URLs automatically listen for new models from the python backend
displayLoadingEveryMs: 1000, /* How often to display partially loaded models */ '<auto>', // Get the default preload URL if not overridden
monitorEveryMs: 100, ],
monitorOpenTimeoutMs: 1000, loadHelpers: true,
// ModelViewer settings edgeWidth: 0, /* The default line size for edges, set to 0 to use basic gl.LINEs */
autoplay: true, // Global animation toggle displayLoadingEveryMs: 1000, /* How often to display partially loaded models */
arModes: 'webxr scene-viewer quick-look', monitorEveryMs: 100,
zoomSensitivity: 0.25, monitorOpenTimeoutMs: 1000,
orbitSensitivity: 1, // ModelViewer settings
panSensitivity: 1, autoplay: true, // Global animation toggle
exposure: 1, arModes: 'webxr scene-viewer quick-look',
shadowIntensity: 0, zoomSensitivity: 0.25,
background: '', orbitSensitivity: 1,
panSensitivity: 1,
exposure: 1,
shadowIntensity: 0,
background: '',
};
// Auto-override any settings from the URL
const url = new URL(window.location.href);
url.searchParams.forEach((value, key) => {
if (key in settings) (settings as any)[key] = parseSetting(key, value, settings);
})
// Get the default preload URL if not overridden (requires a fetch that is avoided if possible)
for (let i = 0; i < settings.preload.length; i++) {
let url = settings.preload[i];
if (url === '<auto>') {
const possibleBackend = new URL("./?api_updates=true", window.location.href)
await fetch(possibleBackend, {method: "HEAD"}).then((response) => {
if (response.ok && response.headers.get("Content-Type") === "text/event-stream") {
// Frontend served by the backend: default to this URL for updates
url = "dev+" + possibleBackend.href;
}
}).catch((error) => console.error("Failed to check for backend:", error));
if (url === '<auto>') { // Fallback to the default preload URL of localhost
url = "dev+http://localhost:32323";
}
}
settings.preload[i] = url;
}
settingsCache = settings;
return settings;
} }
const firstTimeNames: Array<string> = []; // Needed for array values, which clear the array when overridden const firstTimeNames: Array<string> = []; // Needed for array values, which clear the array when overridden
function parseSetting(name: string, value: string): any { function parseSetting(name: string, value: string, settings: any): any {
let arrayElem = name.endsWith(".0") let arrayElem = name.endsWith(".0")
if (arrayElem) name = name.slice(0, -2); if (arrayElem) name = name.slice(0, -2);
let prevValue = (settings as any)[name]; let prevValue = (settings as any)[name];
@@ -42,7 +73,7 @@ function parseSetting(name: string, value: string): any {
} else { } else {
toExtend = prevValue; toExtend = prevValue;
} }
toExtend.push(parseSetting(name + ".0", value)); toExtend.push(parseSetting(name + ".0", value, settings));
return toExtend; return toExtend;
} else { } else {
prevValue = prevValue[0]; prevValue = prevValue[0];
@@ -59,27 +90,3 @@ function parseSetting(name: string, value: string): any {
throw new Error(`Unknown setting type: ${typeof prevValue} -- ${prevValue}`); throw new Error(`Unknown setting type: ${typeof prevValue} -- ${prevValue}`);
} }
} }
// Auto-override any settings from the URL
const url = new URL(window.location.href);
url.searchParams.forEach((value, key) => {
if (key in settings) (settings as any)[key] = parseSetting(key, value);
})
// Get the default preload URL if not overridden (requires a fetch that is avoided if possible)
for (let i = 0; i < settings.preload.length; i++) {
let url = settings.preload[i];
if (url === '<auto>') {
const possibleBackend = new URL("./?api_updates=true", window.location.href)
await fetch(possibleBackend, {method: "HEAD"}).then((response) => {
if (response.ok && response.headers.get("Content-Type") === "text/event-stream") {
// Frontend served by the backend: default to this URL for updates
url = "dev+" + possibleBackend.href;
}
}).catch((error) => console.error("Failed to check for backend:", error));
if (url === '<auto>') { // Fallback to the default preload URL of localhost
url = "dev+http://localhost:32323";
}
}
settings.preload[i] = url;
}

View File

@@ -55,7 +55,11 @@ const clipPlaneY = ref(1);
const clipPlaneSwappedY = ref(false); const clipPlaneSwappedY = ref(false);
const clipPlaneZ = ref(1); const clipPlaneZ = ref(1);
const clipPlaneSwappedZ = ref(false); const clipPlaneSwappedZ = ref(false);
const edgeWidth = ref(settings.edgeWidth); const edgeWidth = ref(0);
(async () => {
let s = await settings();
edgeWidth.value = s.edgeWidth;
})();
// Misc properties // Misc properties
const enabledFeatures = defineModel<Array<number>>("enabledFeatures", {default: [0, 1, 2]}); const enabledFeatures = defineModel<Array<number>>("enabledFeatures", {default: [0, 1, 2]});

View File

@@ -11,7 +11,7 @@ const emit = defineEmits<{ remove: [string] }>()
let {sceneDocument} = inject<{ sceneDocument: Ref<Document> }>('sceneDocument')!!; let {sceneDocument} = inject<{ sceneDocument: Ref<Document> }>('sceneDocument')!!;
let expandedNames = ref<Array<string>>([]); const expandedNames = ref<Array<string>>([]);
function meshesList(sceneDocument: Document): Array<Array<Mesh>> { function meshesList(sceneDocument: Document): Array<Array<Mesh>> {
// Grouped by shared name // Grouped by shared name
@@ -44,7 +44,7 @@ defineExpose({findModel})
<template> <template>
<v-expansion-panels v-for="meshes in meshesList(sceneDocument)" :key="meshName(meshes[0])" <v-expansion-panels v-for="meshes in meshesList(sceneDocument)" :key="meshName(meshes[0])"
v-model="expandedNames" multiple> v-model="expandedNames as any" multiple>
<model :meshes="meshes" :viewer="props.viewer" @remove="onRemove(meshes[0])"/> <model :meshes="meshes" :viewer="props.viewer" @remove="onRemove(meshes[0])"/>
</v-expansion-panels> </v-expansion-panels>
</template> </template>
@@ -61,4 +61,4 @@ defineExpose({findModel})
.v-overlay--active > .v-overlay__content { .v-overlay--active > .v-overlay__content {
display: block !important; /* HACK: Fix buggy tooltips not showing? */ display: block !important; /* HACK: Fix buggy tooltips not showing? */
} }
</style> </style>

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import {defineModel, inject, ref, type ShallowRef, watch} from "vue"; import {inject, ref, type ShallowRef, watch} from "vue";
import {VBtn, VSelect, VTooltip} from "vuetify/lib/components/index.mjs"; import {VBtn, VSelect, VTooltip} from "vuetify/lib/components/index.mjs";
import SvgIcon from '@jamescoyle/vue-icon'; import SvgIcon from '@jamescoyle/vue-icon';
import type {ModelViewerElement} from '@google/model-viewer'; import type {ModelViewerElement} from '@google/model-viewer';
@@ -333,7 +333,7 @@ function updateBoundingBox() {
for (let i = 0; i < 2; i++) { // Find the 2nd closest one by running twice dropping the first for (let i = 0; i < 2; i++) { // Find the 2nd closest one by running twice dropping the first
edge = axisEdges[0]; edge = axisEdges[0];
let edgeDist = Infinity; let edgeDist = Infinity;
let cameraPos: Vector3 = props.viewer?.scene.camera.position; let cameraPos: Vector3 = props.viewer?.scene?.camera?.position ?? new Vector3();
for (let testEdge of axisEdges) { for (let testEdge of axisEdges) {
let from = new Vector3(...corners[testEdge[0]]); let from = new Vector3(...corners[testEdge[0]]);
let to = new Vector3(...corners[testEdge[1]]); let to = new Vector3(...corners[testEdge[1]]);

View File

@@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import {settings} from "../misc/settings"; import {settings} from "../misc/settings";
import {inject, onMounted, type Ref, ref, watch} from "vue"; import {inject, onUpdated, type Ref, ref, watch} from "vue";
import {$renderer, $scene} from "@google/model-viewer/lib/model-viewer-base"; import {$renderer, $scene} from "@google/model-viewer/lib/model-viewer-base";
import {$controls} from '@google/model-viewer/lib/features/controls.js'; import {$controls} from '@google/model-viewer/lib/features/controls.js';
import {type SmoothControls} from '@google/model-viewer/lib/three-components/SmoothControls'; import {type SmoothControls} from '@google/model-viewer/lib/three-components/SmoothControls';
@@ -27,14 +27,19 @@ const scene = ref<ModelScene | null>(null);
const renderer = ref<Renderer | null>(null); const renderer = ref<Renderer | null>(null);
const controls = ref<SmoothControls | null>(null); const controls = ref<SmoothControls | null>(null);
const sett = ref<any | null>(null);
(async () => sett.value = await settings())();
let lastCameraTargetPosition: Vector3 | undefined = undefined; let lastCameraTargetPosition: Vector3 | undefined = undefined;
let lastCameraZoom: number | undefined = undefined; let lastCameraZoom: number | undefined = undefined;
let lastCameraUrl = props.src.toString(); let lastCameraUrl = props.src.toString();
onMounted(() => { let initialized = false
if (!elem.value) return; onUpdated(() => {
if (!elem.value) return; // Not ready yet
if (initialized) return; // Already initialized
initialized = true;
elem.value.addEventListener('before-render', () => { elem.value.addEventListener('before-render', () => {
if (!elem.value) return; if (!elem.value) return
// Extract internals of model-viewer in order to hack unsupported features // Extract internals of model-viewer in order to hack unsupported features
scene.value = elem.value[$scene] as ModelScene; scene.value = elem.value[$scene] as ModelScene;
renderer.value = elem.value[$renderer] as Renderer; renderer.value = elem.value[$renderer] as Renderer;
@@ -207,11 +212,11 @@ watch(disableTap, (newDisableTap) => {
<template> <template>
<!-- The main 3D model viewer --> <!-- The main 3D model viewer -->
<model-viewer ref="elem" :ar="settings.arModes.length > 0" :ar-modes="settings.arModes" :autoplay="settings.autoplay" <model-viewer ref="elem" v-if="sett != null" :ar="sett.arModes.length > 0" :ar-modes="sett.arModes"
:environment-image="settings.background" :exposure="settings.exposure" :environment-image="sett.background" :exposure="sett.exposure" :autoplay="sett.autoplay"
:orbit-sensitivity="settings.orbitSensitivity" :pan-sensitivity="settings.panSensitivity" :orbit-sensitivity="sett.orbitSensitivity" :pan-sensitivity="sett.panSensitivity"
:poster="poster" :shadow-intensity="settings.shadowIntensity" :skybox-image="settings.background" :poster="poster" :shadow-intensity="sett.shadowIntensity" :skybox-image="sett.background"
:src="props.src" :zoom-sensitivity="settings.zoomSensitivity" alt="The 3D model(s)" camera-controls :src="props.src" :zoom-sensitivity="sett.zoomSensitivity" alt="The 3D model(s)" camera-controls
camera-orbit="30deg 75deg auto" interaction-prompt="none" max-camera-orbit="Infinity 180deg auto" camera-orbit="30deg 75deg auto" interaction-prompt="none" max-camera-orbit="Infinity 180deg auto"
min-camera-orbit="-Infinity 0deg 5%" style="width: 100%; height: 100%"> min-camera-orbit="-Infinity 0deg 5%" style="width: 100%; height: 100%">
<slot></slot> <slot></slot>

View File

@@ -1,6 +1,6 @@
{ {
"name": "yet-another-cad-viewer", "name": "yet-another-cad-viewer",
"version": "0.9.3", "version": "0.9.5",
"description": "", "description": "",
"license": "MIT", "license": "MIT",
"private": true, "private": true,
@@ -22,8 +22,8 @@
"@jamescoyle/vue-icon": "^0.1.2", "@jamescoyle/vue-icon": "^0.1.2",
"@mdi/js": "^7.4.47", "@mdi/js": "^7.4.47",
"@mdi/svg": "^7.4.47", "@mdi/svg": "^7.4.47",
"three": "^0.170.0", "three": "^0.175.0",
"three-mesh-bvh": "^0.8.3", "three-mesh-bvh": "^0.9.0",
"three-orientation-gizmo": "https://github.com/jrj2211/three-orientation-gizmo", "three-orientation-gizmo": "https://github.com/jrj2211/three-orientation-gizmo",
"vue": "^3.5.13", "vue": "^3.5.13",
"vuetify": "^3.7.4" "vuetify": "^3.7.4"
@@ -31,18 +31,17 @@
"devDependencies": { "devDependencies": {
"@tsconfig/node20": "^20.1.4", "@tsconfig/node20": "^20.1.4",
"@types/node": "^22.9.3", "@types/node": "^22.9.3",
"@types/three": "^0.170.0", "@types/three": "^0.175.0",
"@vitejs/plugin-vue": "^5.2.0", "@vitejs/plugin-vue": "^5.2.0",
"@vitejs/plugin-vue-jsx": "^4.1.0", "@vitejs/plugin-vue-jsx": "^4.1.0",
"@vue/tsconfig": "^0.6.0", "@vue/tsconfig": "^0.7.0",
"buffer": "^5.5.0||^6.0.0", "buffer": "^5.5.0||^6.0.0",
"commander": "^12.0.0", "commander": "^13.0.0",
"generate-license-file": "^3.6.0", "generate-license-file": "^4.0.0",
"npm-run-all2": "^7.0.1", "npm-run-all2": "^7.0.1",
"terser": "^5.36.0", "terser": "^5.36.0",
"typescript": "~5.6.3", "typescript": "~5.8.0",
"vite": "^5.4.11", "vite": "^6.0.0",
"vite-plugin-top-level-await": "^1.4.4",
"vue-tsc": "^2.1.10" "vue-tsc": "^2.1.10"
} }
} }

1225
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "yacv-server" name = "yacv-server"
version = "0.9.3" version = "0.9.5"
description = "Yet Another CAD Viewer (server)" description = "Yet Another CAD Viewer (server)"
authors = ["Yeicor <4929005+Yeicor@users.noreply.github.com>"] authors = ["Yeicor <4929005+Yeicor@users.noreply.github.com>"]
license = "MIT" license = "MIT"
@@ -11,10 +11,10 @@ include = [
] ]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = ">=3.9,<3.13" python = ">=3.10,<3.13" # Due to vtk transitive dependency of build123d -> cadquery-ocp -> vtk
# CAD # CAD
build123d = ">=0.8,<0.9" build123d = ">=0.9,<0.10"
# Misc # Misc
pygltflib = "^1.16.2" pygltflib = "^1.16.2"

View File

@@ -1,12 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended", ":disableDependencyDashboard"],
"automerge": true,
"schedule": [
"before 9am on Saturday"
],
"lockFileMaintenance": {
"enabled": true,
"schedule": ["before 9am on Saturday"]
}
}

View File

@@ -5,7 +5,6 @@ import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx' import vueJsx from '@vitejs/plugin-vue-jsx'
import {name, version} from './package.json' import {name, version} from './package.json'
import {execSync} from 'child_process' import {execSync} from 'child_process'
import topLevelAwait from "vite-plugin-top-level-await";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
@@ -19,12 +18,6 @@ export default defineConfig({
} }
}), }),
vueJsx(), vueJsx(),
topLevelAwait({
// The export name of top-level await promise for each chunk module
promiseExportName: "__tla",
// The function to generate import names of top-level await promise in each chunk module
promiseImportName: i => `__tla_${i}`
}),
], ],
resolve: { resolve: {
alias: { alias: {

View File

@@ -10,7 +10,7 @@ from OCP.TopExp import TopExp
from OCP.TopLoc import TopLoc_Location from OCP.TopLoc import TopLoc_Location
from OCP.TopTools import TopTools_IndexedMapOfShape from OCP.TopTools import TopTools_IndexedMapOfShape
from OCP.TopoDS import TopoDS_Shape from OCP.TopoDS import TopoDS_Shape
from build123d import Compound, Shape, Color from build123d import Compound, Color
from yacv_server.gltf import GLTFMgr from yacv_server.gltf import GLTFMgr
@@ -78,7 +78,7 @@ def get_shape(obj: CADLike, error: bool = True) -> Optional[CADCoreLike]:
# Sorting is required to improve hashcode consistency # Sorting is required to improve hashcode consistency
shapes_raw_filtered_sorted = sorted(shapes_raw_filtered, key=lambda x: _hashcode(x)) shapes_raw_filtered_sorted = sorted(shapes_raw_filtered, key=lambda x: _hashcode(x))
# Build a single compound shape # Build a single compound shape
shapes_bd = [Shape(shape) for shape in shapes_raw_filtered_sorted if shape is not None] shapes_bd = [Compound(shape) for shape in shapes_raw_filtered_sorted if shape is not None]
return get_shape(Compound(shapes_bd), error) return get_shape(Compound(shapes_bd), error)
except TypeError: except TypeError:
pass pass
@@ -121,11 +121,11 @@ def image_to_gltf(source: str | bytes, center: any, width: Optional[float] = Non
hasher = hashlib.md5() hasher = hashlib.md5()
hasher.update(source) hasher.update(source)
name = 'image_' + hasher.hexdigest() name = 'image_' + hasher.hexdigest()
format: str _format: str
if save_mime == 'image/jpeg': if save_mime == 'image/jpeg':
format = 'JPEG' _format = 'JPEG'
elif save_mime == 'image/png': elif save_mime == 'image/png':
format = 'PNG' _format = 'PNG'
else: else:
raise ValueError(f'Unsupported save MIME type (for GLTF files): {save_mime}') raise ValueError(f'Unsupported save MIME type (for GLTF files): {save_mime}')
@@ -154,7 +154,7 @@ def image_to_gltf(source: str | bytes, center: any, width: Optional[float] = Non
img = img.resize((new_width, new_height)) img = img.resize((new_width, new_height))
# Save the image to a buffer # Save the image to a buffer
img.save(img_buf, format=format) img.save(img_buf, format=_format)
img_buf = img_buf.getvalue() img_buf = img_buf.getvalue()
# Convert coordinates system as a last step (gltf is Y-up instead of Z-up) # Convert coordinates system as a last step (gltf is Y-up instead of Z-up)

View File

@@ -169,6 +169,7 @@ class GLTFMgr:
self.gltf.images = [Image(bufferView=len(buffers_list), mimeType=self.image[1])] self.gltf.images = [Image(bufferView=len(buffers_list), mimeType=self.image[1])]
self.gltf.textures = [Texture(source=0, sampler=0)] self.gltf.textures = [Texture(source=0, sampler=0)]
self.gltf.samplers = [Sampler(magFilter=NEAREST)] self.gltf.samplers = [Sampler(magFilter=NEAREST)]
# noinspection PyPep8Naming
self.gltf.materials[0].pbrMetallicRoughness.baseColorTexture = TextureInfo(index=0) self.gltf.materials[0].pbrMetallicRoughness.baseColorTexture = TextureInfo(index=0)
buffers_list.append((Accessor(), BufferView(), self.image[0])) buffers_list.append((Accessor(), BufferView(), self.image[0]))

View File

@@ -138,3 +138,4 @@ class HTTPHandler(SimpleHTTPRequestHandler):
self.send_header('E-Tag', f'"{_hash}"') self.send_header('E-Tag', f'"{_hash}"')
self.end_headers() self.end_headers()
self.wfile.write(exported_glb) self.wfile.write(exported_glb)
return None

View File

@@ -1,8 +1,6 @@
import queue import queue
import queue
import threading import threading
from typing import List, TypeVar, \ from typing import List, TypeVar, Generic, Generator
Generic, Generator
from yacv_server.mylogger import logger from yacv_server.mylogger import logger
@@ -58,7 +56,7 @@ class BufferedPubSub(Generic[T]):
def subscribe(self, include_buffered: bool = True, include_future: bool = True, yield_timeout: float = 0.0) -> \ def subscribe(self, include_buffered: bool = True, include_future: bool = True, yield_timeout: float = 0.0) -> \
Generator[T, None, None]: Generator[T, None, None]:
"""Subscribes to events as an generator that yields events and automatically unsubscribes""" """Subscribes to events as a generator that yields events and automatically unsubscribes"""
q = self._subscribe(include_buffered, include_future) q = self._subscribe(include_buffered, include_future)
try: try:
while True: while True:

View File

@@ -5,7 +5,7 @@ from OCP.BRepAdaptor import BRepAdaptor_Curve
from OCP.GCPnts import GCPnts_TangentialDeflection from OCP.GCPnts import GCPnts_TangentialDeflection
from OCP.TopLoc import TopLoc_Location from OCP.TopLoc import TopLoc_Location
from OCP.TopoDS import TopoDS_Face, TopoDS_Edge, TopoDS_Shape, TopoDS_Vertex from OCP.TopoDS import TopoDS_Face, TopoDS_Edge, TopoDS_Shape, TopoDS_Vertex
from build123d import Shape, Vertex, Face, Location from build123d import Vertex, Face, Location, Compound
from pygltflib import GLTF2 from pygltflib import GLTF2
from yacv_server.cad import CADCoreLike, ColorTuple from yacv_server.cad import CADCoreLike, ColorTuple
@@ -33,12 +33,12 @@ def tessellate(
mgr.add_location(Location(cad_like)) mgr.add_location(Location(cad_like))
elif isinstance(cad_like, TopoDS_Shape): elif isinstance(cad_like, TopoDS_Shape):
shape = Shape(cad_like) shape = Compound(cad_like)
# Perform tessellation tasks # Perform tessellation tasks
edge_to_faces: Dict[str, List[TopoDS_Face]] = {} edge_to_faces: Dict[str, List[TopoDS_Face]] = {}
vertex_to_faces: Dict[str, List[TopoDS_Face]] = {} vertex_to_faces: Dict[str, List[TopoDS_Face]] = {}
if faces: if faces and hasattr(shape, 'faces'):
shape_faces = shape.faces() shape_faces = shape.faces()
for face in shape_faces: for face in shape_faces:
_tessellate_face(mgr, face.wrapped, tolerance, angular_tolerance, obj_color) _tessellate_face(mgr, face.wrapped, tolerance, angular_tolerance, obj_color)
@@ -49,16 +49,19 @@ def tessellate(
for vertex in face.vertices(): for vertex in face.vertices():
vertex_to_faces[vertex.wrapped] = vertex_to_faces.get(vertex.wrapped, []) + [face.wrapped] vertex_to_faces[vertex.wrapped] = vertex_to_faces.get(vertex.wrapped, []) + [face.wrapped]
if len(shape_faces) > 0: obj_color = None # Don't color edges/vertices if faces are colored if len(shape_faces) > 0: obj_color = None # Don't color edges/vertices if faces are colored
if edges: if edges and hasattr(shape, 'edges'):
shape_edges = shape.edges() shape_edges = shape.edges()
for edge in shape_edges: for edge in shape_edges:
_tessellate_edge(mgr, edge.wrapped, edge_to_faces.get(edge.wrapped, []), angular_tolerance, _tessellate_edge(mgr, edge.wrapped, edge_to_faces.get(edge.wrapped, []), angular_tolerance,
angular_tolerance, obj_color) angular_tolerance, obj_color)
if len(shape_edges) > 0: obj_color = None # Don't color vertices if edges are colored if len(shape_edges) > 0: obj_color = None # Don't color vertices if edges are colored
if vertices: if vertices and hasattr(shape, 'vertices'):
for vertex in shape.vertices(): for vertex in shape.vertices():
_tessellate_vertex(mgr, vertex.wrapped, vertex_to_faces.get(vertex.wrapped, []), obj_color) _tessellate_vertex(mgr, vertex.wrapped, vertex_to_faces.get(vertex.wrapped, []), obj_color)
else:
raise TypeError(f"Unsupported type: {type(cad_like)}: {cad_like}")
return mgr.build() return mgr.build()
@@ -69,9 +72,10 @@ def _tessellate_face(
angular_tolerance: float = 0.1, angular_tolerance: float = 0.1,
color: Optional[ColorTuple] = None, color: Optional[ColorTuple] = None,
): ):
face = Shape(ocp_face) face = Compound(ocp_face)
# face.mesh(tolerance, angular_tolerance) # face.mesh(tolerance, angular_tolerance)
tri_mesh = face.tessellate(tolerance, angular_tolerance) tri_mesh = face.tessellate(tolerance, angular_tolerance)
# noinspection PyArgumentList
poly = BRep_Tool.Triangulation_s(face.wrapped, TopLoc_Location()) poly = BRep_Tool.Triangulation_s(face.wrapped, TopLoc_Location())
if poly is None: if poly is None:
logger.warn("No triangulation found for face") logger.warn("No triangulation found for face")
@@ -86,6 +90,7 @@ def _tessellate_face(
vertices = tri_mesh[0] vertices = tri_mesh[0]
indices = tri_mesh[1] indices = tri_mesh[1]
mgr.add_face(vertices, indices, uv, color) mgr.add_face(vertices, indices, uv, color)
return None
def _push_point(v: Tuple[float, float, float], faces: List[TopoDS_Face]) -> Tuple[float, float, float]: def _push_point(v: Tuple[float, float, float], faces: List[TopoDS_Face]) -> Tuple[float, float, float]:

View File

@@ -9,18 +9,18 @@ import threading
import time import time
from dataclasses import dataclass from dataclasses import dataclass
from http.server import ThreadingHTTPServer from http.server import ThreadingHTTPServer
from io import BytesIO
from threading import Thread from threading import Thread
from typing import Optional, Dict, Union, Callable, List, Tuple from typing import Optional, Dict, Union, Callable, List, Tuple
from OCP.TopLoc import TopLoc_Location from OCP.TopLoc import TopLoc_Location
from OCP.TopoDS import TopoDS_Shape from OCP.TopoDS import TopoDS_Shape
# noinspection PyProtectedMember
from build123d import Shape, Axis, Location, Vector, Color
from dataclasses_json import dataclass_json
from PIL import Image from PIL import Image
from io import BytesIO # noinspection PyProtectedMember
from build123d import Shape, Axis, Location, Vector
from dataclasses_json import dataclass_json
from yacv_server.cad import _hashcode, ColorTuple, get_color from yacv_server.cad import _hashcode, get_color
from yacv_server.cad import get_shape, grab_all_cad, CADCoreLike, CADLike from yacv_server.cad import get_shape, grab_all_cad, CADCoreLike, CADLike
from yacv_server.gltf import get_version from yacv_server.gltf import get_version
from yacv_server.myhttp import HTTPHandler from yacv_server.myhttp import HTTPHandler
@@ -95,7 +95,7 @@ class YACV:
"""Default texture to use for model faces, in (data, mimetype) format. """Default texture to use for model faces, in (data, mimetype) format.
If left as None, a default checkerboard texture will be used. If left as None, a default checkerboard texture will be used.
It can be set with the YACV_BASE_TEXTURE=<uri> and overriden by `show(..., texture="<uri>")`. It can be set with the YACV_BASE_TEXTURE=<uri> and overridden by `show(..., texture="<uri>")`.
The <uri> can be file:<path> or data:<mime>;base64,<data> where <mime> is the mime type and The <uri> can be file:<path> or data:<mime>;base64,<data> where <mime> is the mime type and
<data> is the base64 encoded image.""" <data> is the base64 encoded image."""
@@ -331,6 +331,7 @@ class YACV:
try: try:
return next(subscription), event.hash return next(subscription), event.hash
finally: finally:
# noinspection PyInconsistentReturns
subscription.close() subscription.close()
def export_all(self, folder: str, def export_all(self, folder: str,

2210
yarn.lock

File diff suppressed because it is too large Load Diff