better model management

This commit is contained in:
Yeicor
2024-02-24 20:49:07 +01:00
parent f6c0d5f936
commit 34b7c3e893
5 changed files with 32 additions and 14 deletions

View File

@@ -5,12 +5,14 @@ import Sidebar from "./misc/Sidebar.vue";
import Loading from "./misc/Loading.vue";
import Tools from "./tools/Tools.vue";
import Models from "./models/Models.vue";
import {VLayout, VMain, VToolbarTitle} from "vuetify/lib/components";
import {VBtn, VLayout, VMain, VToolbarTitle} from "vuetify/lib/components";
import {settings} from "./misc/settings";
import {NetworkManager, NetworkUpdateEvent} from "./misc/network";
import {SceneMgr} from "./misc/scene";
import {Document} from "@gltf-transform/core";
import type ModelViewerWrapperT from "./viewer/ModelViewerWrapper.vue";
import {mdiPlus} from '@mdi/js'
import SvgIcon from '@jamescoyle/vue-icon';
// NOTE: The ModelViewer library is big (THREE.js), so we split it and import it asynchronously
const ModelViewerWrapper = defineAsyncComponent({
@@ -42,6 +44,11 @@ networkMgr.addEventListener('update', onModelLoadRequest);
for (let model of settings.preloadModels) {
networkMgr.load(model);
}
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:");
if (modelUrl) await networkMgr.load(modelUrl);
}
</script>
<template>
@@ -57,6 +64,11 @@ for (let model of settings.preloadModels) {
<template #toolbar>
<v-toolbar-title>Models</v-toolbar-title>
</template>
<template #toolbar-items>
<v-btn icon="" @click="loadModelManual">
<svg-icon type="mdi" :path="mdiPlus"/>
</v-btn>
</template>
<models :viewer="viewer" :document="document" @remove="onModelRemoveRequest"/>
</sidebar>

View File

@@ -15,9 +15,12 @@ export async function mergePartial(url: string, name: string, document: Document
// Load the new document
let newDoc = await io.read(url);
// Remove any previous model with the same name and ensure consistent names
// Remove any previous model with the same name
await document.transform(dropByName(name));
// Ensure consistent names
// noinspection TypeScriptValidateJSTypes
await newDoc.transform(dropByName(name), setNames(name));
await newDoc.transform(setNames(name));
// Merge the new document into the current one
return document.merge(newDoc);
@@ -38,18 +41,19 @@ export async function removeModel(name: string, document: Document): Promise<Doc
/** Given a parsed GLTF document and a name, it forces the names of all elements to be identified by the name (or derivatives) */
function setNames(name: string): Transform {
return (doc: Document, _: any) => {
return (doc: Document) => {
// Do this automatically for all elements changing any name
for (let elem of doc.getGraph().listEdges().map(e => e.getChild())) {
if (!elem.getExtras()) elem.setExtras({});
elem.getExtras()[extrasNameKey] = name;
}
return doc;
}
}
/** Ensures that all elements with the given name are removed from the document */
export function dropByName(name: string): Transform {
return (doc: Document, _: any) => {
function dropByName(name: string): Transform {
return (doc: Document) => {
for (let elem of doc.getGraph().listEdges().map(e => e.getChild())) {
if (elem.getExtras() == null || elem instanceof Scene || elem instanceof Buffer) continue;
if ((elem.getExtras()[extrasNameKey]?.toString() ?? "") == name) {

View File

@@ -49,7 +49,7 @@ export class NetworkManager extends EventTarget {
console.error("WebSocket error", event);
}
ws.onclose = () => {
console.trace("WebSocket closed, reconnecting very soon");
//console.trace("WebSocket closed, reconnecting very soon");
setTimeout(() => this.monitorWebSocket(url), settings.checkServerEveryMs);
}
}

View File

@@ -11,10 +11,10 @@ import {
import {extrasNameKey} from "../misc/gltf";
import {Document, Mesh} from "@gltf-transform/core";
import {watch} from "vue";
import type ModelViewerWrapper from "../viewer/ModelViewerWrapper.vue";
import {mdiDelete, mdiRectangle, mdiRectangleOutline, mdiVectorRectangle} from '@mdi/js'
import SvgIcon from '@jamescoyle/vue-icon/lib/svg-icon.vue';
import type {ModelViewerElement, RGBA} from '@google/model-viewer';
const props = defineProps<{ mesh: Mesh, viewer: InstanceType<typeof ModelViewerWrapper> | null, document: Document }>();
const emit = defineEmits<{ remove: [] }>()
@@ -32,9 +32,10 @@ let hasListener = false;
function onEnabledFeaturesChange(newEnabledFeatures: Array<number>) {
//console.log('Enabled features may have changed', newEnabledFeatures)
let scene = props.viewer?.scene;
if (!scene || !scene._model) return;
let elem = props.viewer?.elem;
if (!scene || !scene._model || !elem) return;
if (!hasListener) { // Make sure we listen for reloads and re-apply enabled features
props.viewer.elem.addEventListener('load', () => onEnabledFeaturesChange(enabledFeatures.value));
elem.addEventListener('load', () => onEnabledFeaturesChange(enabledFeatures.value));
hasListener = true;
}
// Iterate all primitives of the mesh and set their visibility based on the enabled features

View File

@@ -26,7 +26,7 @@ def tessellate(
angular_tolerance: float = 0.1,
faces: bool = True,
edges: bool = True,
vertices: bool = False,
vertices: bool = True,
) -> GLTF2:
"""Tessellate a whole shape into a list of triangle vertices and a list of triangle indices."""
mgr = GLTFMgr()
@@ -40,16 +40,17 @@ def tessellate(
_tessellate_face(mgr, face.wrapped, tolerance, angular_tolerance)
if edges:
for edge in face.edges():
edge_to_faces[edge] = edge_to_faces.get(edge, []) + [face.wrapped]
edge_to_faces[edge.wrapped] = edge_to_faces.get(edge.wrapped, []) + [face.wrapped]
if vertices:
for vertex in face.vertices():
vertex_to_faces[vertex.wrapped] = vertex_to_faces.get(vertex.wrapped, []) + [face.wrapped]
if edges:
for edge in shape.edges():
_tessellate_edge(mgr, edge.wrapped, edge_to_faces[edge], angular_tolerance, angular_tolerance)
_tessellate_edge(mgr, edge.wrapped, edge_to_faces.get(edge.wrapped, []), angular_tolerance,
angular_tolerance)
if vertices:
for vertex in shape.vertices():
_tessellate_vertex(mgr, vertex_to_faces[vertex], vertex.wrapped)
_tessellate_vertex(mgr, vertex.wrapped, vertex_to_faces.get(vertex.wrapped, []))
return mgr.gltf