/* ========================= */ /* GLOBALE VARIABLEN */ /* ========================= */ let selectedPlacedModel = null; let currentSession = null; let reticle = null; let scene, camera; let geoLocation; const menus = ['menu-bar', 'add-menu', 'edit-menu', 'options-menu', 'map-window']; /* ========================= */ /* MODELLE */ /* ========================= */ let models = { bench: { name: "Bench", image: "assets/previewImages/bench.PNG", file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/bench_model/scene.gltf", scale: { x: 0.1, y: 0.1, z: 0.1 }, minScale: 0.05, maxScale: 0.5 }, trashbin: { name: "Trash bin", image: "assets/previewImages/trash_can.PNG", file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/trash_model/scene.gltf", scale: { x: 0.03, y: 0.03, z: 0.03 }, minScale: 0.01, maxScale: 0.1 }, lantern: { name: "Lantern", image: "assets/previewImages/park_light.png", file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/park_light_model/scene.gltf", scale: { x: 0.5, y: 0.5, z: 0.5 }, minScale: 0.2, maxScale: 5 }, telephone_box: { name: "Telephone Box", image: "assets/previewImages/telephone_box.PNG", file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/telephone_box_model/scene.gltf", scale: { x: 0.5, y: 0.5, z: 0.5 }, minScale: 0.05, maxScale: 1 }, fire_hydrant_model: { name: "Fire Hydrant", image: "assets/previewImages/hydrant.PNG", file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/fire_hydrant_model/scene.gltf", scale: { x: 0.3, y: 0.3, z: 0.3 }, minScale: 0.1, maxScale: 1 }, statue: { name: "Statue", image: "assets/previewImages/statue.PNG", file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/statue_model/scene.gltf", scale: { x: 0.5, y: 0.5, z: 0.5 }, minScale: 0.05, maxScale: 2 }, fountain: { name: "Fountain", image: "assets/previewImages/fountain.PNG", file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/fountain_model/scene.gltf", scale: { x: 0.001, y: 0.001, z: 0.001 }, minScale: 0.0005, maxScale: 0.005 } }; /* ========================= */ /* INITIALISIERUNG */ /* ========================= */ window.onload = () => { initializeAddMenu(); // Allen Buttons den Sound hinzufügen const buttons = document.querySelectorAll("button, .menu-item"); buttons.forEach(button => { button.addEventListener("click", playButtonSound); }); }; function initializeAddMenu() { const addMenu = document.getElementById('add-menu'); addMenu.innerHTML = Object.entries(models) .map( ([key, model]) => `
` ) .join('') + ` `; } /* ========================= */ /* MENÜ-STEUERUNG */ /* ========================= */ function showMenu(menuId) { const isMapWindow = menuId === 'map-window'; if (isMapWindow && !geoLocation) { console.log("Standort nicht geladen"); showInfoDialog("Ihr Standort wurde noch nicht geladen"); return; } menus.forEach(id => { document.getElementById(id).style.display = id === menuId ? 'flex' : 'none'; }); closeDynamicMenu(); if (menuId === 'menu-bar') clearSelectedModel(); else if (isMapWindow) init_map(); } function closeDynamicMenu() { const dynamicMenu = document.getElementById("dynamic-menu"); dynamicMenu.style.display = "none"; } /* ========================= */ /* MODELL-HANDLING */ /* ========================= */ function getAllPlacedModels() { return scene.children.filter(child => child.isPlacedModel === true); } function loadModel(filePath) { placeModel(filePath, reticle.position, (model) => { selectedPlacedModel = model; highlightSelectedModel(); showMenu('edit-menu'); }); } function placeModel(filePath, position, onPlace = null) { const modelConfig = Object.values(models).find(model => model.file === filePath); const loader = new THREE.GLTFLoader(); loader.load( filePath, (gltf) => { const model = gltf.scene; if (modelConfig && modelConfig.scale) { model.scale.set(modelConfig.scale.x, modelConfig.scale.y, modelConfig.scale.z); } model.position.copy(position); model.isPlacedModel = true; model.modelConfig = modelConfig; scene.add(model); if (onPlace) { onPlace(model); } }, undefined, (error) => { console.error("Fehler beim Laden des Modells:", error); } ); } function selectModel(modelId) { const model = models[modelId]; if (model && model.file) { loadModel(model.file); showMenu('menu-bar'); } } function selectModelFromScene(event) { const mouse = new THREE.Vector2( (event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1 ); const raycaster = new THREE.Raycaster(); raycaster.setFromCamera(mouse, camera); // Prüfe Kollisionen mit Objekten in der Szene const intersects = raycaster.intersectObjects(scene.children, true); if (intersects.length > 0) { // Finde das Hauptobjekt (Root-Parent), falls Mesh ausgewählt wurde let selectedObject = intersects[0].object; while (selectedObject.parent && selectedObject.parent !== scene) { selectedObject = selectedObject.parent; } // Überprüfe, ob das ausgewählte Objekt das Reticle ist if (selectedObject === reticle) { console.log("Reticle kann nicht ausgewählt werden."); return; } // Markiere das gesamte Modell als ausgewählt selectedPlacedModel = selectedObject; highlightSelectedModel(); showMenu("edit-menu"); } } function clearSelectedModel() { if (selectedPlacedModel) { selectedPlacedModel.traverse((child) => { if (child.isMesh) { child.material.emissive.setHex(0x000000); // Markierung entfernen } }); selectedPlacedModel = null; } } function highlightSelectedModel() { if (selectedPlacedModel) { removeHighlightFromAllModels(); selectedPlacedModel.traverse((child) => { if (child.isMesh) { child.material.emissive.setHex(0xff0000); // Rote Hervorhebung } }); } } function removeHighlightFromSelectedModel() { if (selectedPlacedModel) { selectedPlacedModel.traverse((child) => { if (child.isMesh) child.material.emissive.setHex(0x000000); // Markierung entfernen }); } } function removeHighlightFromAllModels() { scene.traverse((child) => { if (child.isMesh && child.material && child.material.emissive) { child.material.emissive.setHex(0x000000); // Markierung entfernen } }); } function deleteModel() { if (!selectedPlacedModel) { console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es löschen."); return; } const deleteDialog = document.getElementById('delete-confirmation-dialog'); deleteDialog.style.display = 'flex'; } function confirmDelete(shouldDelete) { const deleteDialog = document.getElementById('delete-confirmation-dialog'); deleteDialog.style.display = 'none'; if (shouldDelete && selectedPlacedModel) { scene.remove(selectedPlacedModel); selectedPlacedModel = null; showMenu('menu-bar'); } } function completeEditing() { removeHighlightFromSelectedModel(); closeDynamicMenu(); selectedPlacedModel = null; document.getElementById('edit-menu').style.display = 'none'; document.getElementById('menu-bar').style.display = 'flex'; } /* ========================= */ /* BEARBEITUNGS-MENÜS */ /* ========================= */ function openRotationMenu() { if (!selectedPlacedModel) { console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bearbeiten."); return; } const currentRotation = Math.round(THREE.MathUtils.radToDeg(selectedPlacedModel.rotation.y)); // Aktuelle Y-Rotation des Modells (in Grad) const dynamicMenu = document.getElementById("dynamic-menu"); dynamicMenu.style.display = "flex"; dynamicMenu.innerHTML = `