Commit 67715bc3 authored by Cantuerk's avatar Cantuerk
Browse files

Update public/ar_main.js

parent 9d0b421b
Showing with 370 additions and 360 deletions
+370 -360
/* ========================= */ /* ========================= */
/* GLOBALE VARIABLEN */ /* GLOBALE VARIABLEN */
/* ========================= */ /* ========================= */
let selectedPlacedModel = null; let selectedPlacedModel = null;
let currentSession = null; let currentSession = null;
let reticle = null; let reticle = null;
let scene, camera; let scene, camera;
let geoLocation; let geoLocation;
const menus = ['menu-bar', 'add-menu', 'edit-menu', 'options-menu', 'map-window']; const menus = ['menu-bar', 'add-menu', 'edit-menu', 'options-menu', 'map-window'];
/* ========================= */ /* ========================= */
/* MODELLE */ /* MODELLE */
/* ========================= */ /* ========================= */
let models = { let models = {
bench: { bench: {
name: "Bench", name: "Bench",
image: "previewImages/bench.PNG", image: "assets/previewImages/bench.PNG",
file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/bench_model/scene.gltf", 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 }, scale: { x: 0.1, y: 0.1, z: 0.1 },
minScale: 0.05, minScale: 0.05,
maxScale: 0.5 maxScale: 0.5
}, },
trashbin: { trashbin: {
name: "Trash bin", name: "Trash bin",
image: "previewImages/trash_can.PNG", image: "assets/previewImages/trash_can.PNG",
file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/trash_model/scene.gltf", 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 }, scale: { x: 0.03, y: 0.03, z: 0.03 },
minScale: 0.01, minScale: 0.01,
maxScale: 0.1 maxScale: 0.1
}, },
lantern: { lantern: {
name: "Lantern", name: "Lantern",
image: "previewImages/park_light.png", 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", 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 }, scale: { x: 0.5, y: 0.5, z: 0.5 },
minScale: 0.2, minScale: 0.2,
maxScale: 5 maxScale: 5
}, },
telephone_box: { telephone_box: {
name: "Telephone Box", name: "Telephone Box",
image: "previewImages/telephone_box.PNG", 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", 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 }, scale: { x: 0.5, y: 0.5, z: 0.5 },
minScale: 0.05, minScale: 0.05,
maxScale: 1 maxScale: 1
}, },
fire_hydrant_model: { fire_hydrant_model: {
name: "Fire Hydrant", name: "Fire Hydrant",
image: "previewImages/hydrant.PNG", image: "assets/previewImages/hydrant.PNG",
file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/fire_hydrant_model/scene.gltf", 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 }, scale: { x: 0.3, y: 0.3, z: 0.3 },
minScale: 0.1, minScale: 0.1,
maxScale: 1 maxScale: 1
}, },
statue: { statue: {
name: "Statue", name: "Statue",
image: "previewImages/statue.PNG", image: "assets/previewImages/statue.PNG",
file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/statue_model/scene.gltf", 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 }, scale: { x: 0.5, y: 0.5, z: 0.5 },
minScale: 0.05, minScale: 0.05,
maxScale: 2 maxScale: 2
}, },
fountain: { fountain: {
name: "Fountain", name: "Fountain",
image: "previewImages/fountain.PNG", image: "assets/previewImages/fountain.PNG",
file: "https://transfer.hft-stuttgart.de/gitlab/geovistoogsi/ar/-/raw/master/public/assets/models/fountain_model/scene.gltf", 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 }, scale: { x: 0.001, y: 0.001, z: 0.001 },
minScale: 0.0005, minScale: 0.0005,
maxScale: 0.005 maxScale: 0.005
} }
}; };
/* ========================= */ /* ========================= */
/* INITIALISIERUNG */ /* INITIALISIERUNG */
/* ========================= */ /* ========================= */
window.onload = () => { window.onload = () => {
initializeAddMenu(); initializeAddMenu();
// Allen Buttons den Sound hinzufügen // Allen Buttons den Sound hinzufügen
const buttons = document.querySelectorAll("button, .menu-item"); const buttons = document.querySelectorAll("button, .menu-item");
buttons.forEach(button => { buttons.forEach(button => {
button.addEventListener("click", playButtonSound); button.addEventListener("click", playButtonSound);
}); });
}; };
function initializeAddMenu() { function initializeAddMenu() {
const addMenu = document.getElementById('add-menu'); const addMenu = document.getElementById('add-menu');
addMenu.innerHTML = Object.entries(models) addMenu.innerHTML = Object.entries(models)
.map( .map(
([key, model]) => ` ([key, model]) => `
<div class="menu-item" id="${key}-item" onclick="selectModel('${key}')"> <div class="menu-item" id="${key}-item" onclick="selectModel('${key}')">
<img src="${model.image}" alt="${model.name}" /> <img src="${model.image}" alt="${model.name}" />
</div> </div>
...@@ -96,243 +96,243 @@ ...@@ -96,243 +96,243 @@
.join('') + .join('') +
` `
<div class="menu-item" onclick="showMenu('menu-bar')"> <div class="menu-item" onclick="showMenu('menu-bar')">
<img src="previewImages/back-icon.png" alt="Zurück" /> <img src="assets/icons/back-icon.png" alt="Zurück" />
</div> </div>
`; `;
} }
/* ========================= */ /* ========================= */
/* MENÜ-STEUERUNG */ /* MENÜ-STEUERUNG */
/* ========================= */ /* ========================= */
function showMenu(menuId) { function showMenu(menuId) {
const isMapWindow = menuId === 'map-window'; const isMapWindow = menuId === 'map-window';
if (isMapWindow && !geoLocation) { if (isMapWindow && !geoLocation) {
console.log("Standort nicht geladen"); console.log("Standort nicht geladen");
showInfoDialog("Ihr Standort wurde noch nicht geladen"); showInfoDialog("Ihr Standort wurde noch nicht geladen");
return; 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";
} }
/* ========================= */ menus.forEach(id => {
/* MODELL-HANDLING */ document.getElementById(id).style.display = id === menuId ? 'flex' : 'none';
/* ========================= */ });
function getAllPlacedModels() { closeDynamicMenu();
return scene.children.filter(child => child.isPlacedModel === true); if (menuId === 'menu-bar') clearSelectedModel();
} else if (isMapWindow) init_map();
}
function loadModel(filePath) {
placeModel(filePath, reticle.position, (model) => { 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; selectedPlacedModel = model;
highlightSelectedModel(); highlightSelectedModel();
showMenu('edit-menu'); showMenu('edit-menu');
}); });
} }
function placeModel(filePath, position, onPlace = null) { function placeModel(filePath, position, onPlace = null) {
const modelConfig = Object.values(models).find(model => model.file === filePath); const modelConfig = Object.values(models).find(model => model.file === filePath);
const loader = new THREE.GLTFLoader(); const loader = new THREE.GLTFLoader();
loader.load( loader.load(
filePath, filePath,
(gltf) => { (gltf) => {
const model = gltf.scene; const model = gltf.scene;
if (modelConfig && modelConfig.scale) { if (modelConfig && modelConfig.scale) {
model.scale.set(modelConfig.scale.x, modelConfig.scale.y, modelConfig.scale.z); model.scale.set(modelConfig.scale.x, modelConfig.scale.y, modelConfig.scale.z);
} }
model.position.copy(position); model.position.copy(position);
model.isPlacedModel = true; model.isPlacedModel = true;
model.modelConfig = modelConfig; model.modelConfig = modelConfig;
scene.add(model); scene.add(model);
if (onPlace) { if (onPlace) {
onPlace(model); onPlace(model);
} }
}, },
undefined, undefined,
(error) => { (error) => {
console.error("Fehler beim Laden des Modells:", error); console.error("Fehler beim Laden des Modells:", error);
} }
); );
} }
function selectModel(modelId) { function selectModel(modelId) {
const model = models[modelId]; const model = models[modelId];
if (model && model.file) { if (model && model.file) {
loadModel(model.file); loadModel(model.file);
showMenu('menu-bar'); showMenu('menu-bar');
}
} }
}
function selectModelFromScene(event) { function selectModelFromScene(event) {
const mouse = new THREE.Vector2( const mouse = new THREE.Vector2(
(event.clientX / window.innerWidth) * 2 - 1, (event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1 -(event.clientY / window.innerHeight) * 2 + 1
); );
const raycaster = new THREE.Raycaster(); const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, camera); raycaster.setFromCamera(mouse, camera);
// Prüfe Kollisionen mit Objekten in der Szene // Prüfe Kollisionen mit Objekten in der Szene
const intersects = raycaster.intersectObjects(scene.children, true); const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) { if (intersects.length > 0) {
// Finde das Hauptobjekt (Root-Parent), falls Mesh ausgewählt wurde // Finde das Hauptobjekt (Root-Parent), falls Mesh ausgewählt wurde
let selectedObject = intersects[0].object; let selectedObject = intersects[0].object;
while (selectedObject.parent && selectedObject.parent !== scene) { while (selectedObject.parent && selectedObject.parent !== scene) {
selectedObject = selectedObject.parent; selectedObject = selectedObject.parent;
} }
// Überprüfe, ob das ausgewählte Objekt das Reticle ist // Überprüfe, ob das ausgewählte Objekt das Reticle ist
if (selectedObject === reticle) { if (selectedObject === reticle) {
console.log("Reticle kann nicht ausgewählt werden."); console.log("Reticle kann nicht ausgewählt werden.");
return; return;
} }
// Markiere das gesamte Modell als ausgewählt // Markiere das gesamte Modell als ausgewählt
selectedPlacedModel = selectedObject; selectedPlacedModel = selectedObject;
highlightSelectedModel(); highlightSelectedModel();
showMenu("edit-menu"); showMenu("edit-menu");
}
} }
}
function clearSelectedModel() { function clearSelectedModel() {
if (selectedPlacedModel) { if (selectedPlacedModel) {
selectedPlacedModel.traverse((child) => { selectedPlacedModel.traverse((child) => {
if (child.isMesh) { if (child.isMesh) {
child.material.emissive.setHex(0x000000); // Markierung entfernen child.material.emissive.setHex(0x000000); // Markierung entfernen
} }
}); });
selectedPlacedModel = null; selectedPlacedModel = null;
}
} }
}
function highlightSelectedModel() { function highlightSelectedModel() {
if (selectedPlacedModel) { if (selectedPlacedModel) {
removeHighlightFromAllModels(); removeHighlightFromAllModels();
selectedPlacedModel.traverse((child) => { selectedPlacedModel.traverse((child) => {
if (child.isMesh) { if (child.isMesh) {
child.material.emissive.setHex(0xff0000); // Rote Hervorhebung child.material.emissive.setHex(0xff0000); // Rote Hervorhebung
} }
}); });
}
} }
}
function removeHighlightFromSelectedModel() { function removeHighlightFromSelectedModel() {
if (selectedPlacedModel) { if (selectedPlacedModel) {
selectedPlacedModel.traverse((child) => { selectedPlacedModel.traverse((child) => {
if (child.isMesh) child.material.emissive.setHex(0x000000); // Markierung entfernen if (child.isMesh) child.material.emissive.setHex(0x000000); // Markierung entfernen
}); });
}
} }
}
function removeHighlightFromAllModels() { function removeHighlightFromAllModels() {
scene.traverse((child) => { scene.traverse((child) => {
if (child.isMesh && child.material && child.material.emissive) { if (child.isMesh && child.material && child.material.emissive) {
child.material.emissive.setHex(0x000000); // Markierung entfernen 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) { function deleteModel() {
const deleteDialog = document.getElementById('delete-confirmation-dialog'); if (!selectedPlacedModel) {
deleteDialog.style.display = 'none'; console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es löschen.");
return;
}
if (shouldDelete && selectedPlacedModel) { 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); scene.remove(selectedPlacedModel);
selectedPlacedModel = null; selectedPlacedModel = null;
showMenu('menu-bar'); showMenu('menu-bar');
}
} }
}
function completeEditing() {
removeHighlightFromSelectedModel(); function completeEditing() {
closeDynamicMenu(); removeHighlightFromSelectedModel();
selectedPlacedModel = null; closeDynamicMenu();
document.getElementById('edit-menu').style.display = 'none'; selectedPlacedModel = null;
document.getElementById('menu-bar').style.display = 'flex'; document.getElementById('edit-menu').style.display = 'none';
} document.getElementById('menu-bar').style.display = 'flex';
}
/* ========================= */
/* BEARBEITUNGS-MENÜS */ /* ========================= */
/* ========================= */ /* BEARBEITUNGS-MENÜS */
function openRotationMenu() { /* ========================= */
if (!selectedPlacedModel) { function openRotationMenu() {
if (!selectedPlacedModel) {
console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bearbeiten."); console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bearbeiten.");
return; return;
} }
const currentRotation = Math.round(THREE.MathUtils.radToDeg(selectedPlacedModel.rotation.y)); // Aktuelle Y-Rotation des Modells (in Grad) const currentRotation = Math.round(THREE.MathUtils.radToDeg(selectedPlacedModel.rotation.y)); // Aktuelle Y-Rotation des Modells (in Grad)
const dynamicMenu = document.getElementById("dynamic-menu"); const dynamicMenu = document.getElementById("dynamic-menu");
dynamicMenu.style.display = "flex"; dynamicMenu.style.display = "flex";
dynamicMenu.innerHTML = ` dynamicMenu.innerHTML = `
<h3>Rotation anpassen</h3> <h3>Rotation anpassen</h3>
<label>Y-Achse: <span id="current-rotation">${currentRotation}</span>°<input type="range" min="0" max="360" step="10" onchange="updateRotation('y', this.value)"></label> <label>Y-Achse: <span id="current-rotation">${currentRotation}</span>°<input type="range" min="0" max="360" step="10" onchange="updateRotation('y', this.value)"></label>
<button onclick="closeDynamicMenu()">Zurück</button> <button onclick="closeDynamicMenu()">Zurück</button>
`; `;
} }
function updateRotation(axis, value) { function updateRotation(axis, value) {
if (selectedPlacedModel) { if (selectedPlacedModel) {
const radians = (value / 180) * Math.PI; const radians = (value / 180) * Math.PI;
selectedPlacedModel.rotation[axis] = radians; selectedPlacedModel.rotation[axis] = radians;
// Anzeige der aktuellen Rotation im Dynamic-Menü aktualisieren // Anzeige der aktuellen Rotation im Dynamic-Menü aktualisieren
const currentRotationDisplay = document.getElementById("current-rotation"); const currentRotationDisplay = document.getElementById("current-rotation");
if (currentRotationDisplay) { if (currentRotationDisplay) {
currentRotationDisplay.textContent = value; // Zeige den aktuellen Wert in Grad an currentRotationDisplay.textContent = value; // Zeige den aktuellen Wert in Grad an
} }
}
} }
}
function openScaleMenu() { function openScaleMenu() {
if (!selectedPlacedModel) { if (!selectedPlacedModel) {
console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bearbeiten."); console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bearbeiten.");
return; return;
} }
// Aktuelle Skalierung und Grenzen bestimmen // Aktuelle Skalierung und Grenzen bestimmen
const currentScale = selectedPlacedModel.scale.x; const currentScale = selectedPlacedModel.scale.x;
const minScale = selectedPlacedModel.modelConfig.minScale; const minScale = selectedPlacedModel.modelConfig.minScale;
const maxScale = selectedPlacedModel.modelConfig.maxScale; const maxScale = selectedPlacedModel.modelConfig.maxScale;
const step = (maxScale - minScale) / 100; // Dynamische Schrittgröße basierend auf Grenzen const step = (maxScale - minScale) / 100; // Dynamische Schrittgröße basierend auf Grenzen
const currentScalePercent = ((currentScale - minScale) / (maxScale - minScale)) * 100; // Umrechnung der Werte in Prozent const currentScalePercent = ((currentScale - minScale) / (maxScale - minScale)) * 100; // Umrechnung der Werte in Prozent
const dynamicMenu = document.getElementById("dynamic-menu"); const dynamicMenu = document.getElementById("dynamic-menu");
dynamicMenu.style.display = "flex"; dynamicMenu.style.display = "flex";
dynamicMenu.innerHTML = ` dynamicMenu.innerHTML = `
<h3>Skalierung anpassen</h3> <h3>Skalierung anpassen</h3>
<label>Größe: <span id="scale-value">${currentScalePercent.toFixed(0)}%</span> <label>Größe: <span id="scale-value">${currentScalePercent.toFixed(0)}%</span>
<input type="range" min="0" max="100" step="1" value="${currentScalePercent}" onchange="updateScale(this.value, ${minScale}, ${maxScale})"></label> <input type="range" min="0" max="100" step=""${step}"" value="${currentScalePercent}" onchange="updateScale(this.value, ${minScale}, ${maxScale})"></label>
<button onclick="closeDynamicMenu()">Zurück</button> <button onclick="closeDynamicMenu()">Zurück</button>
`; `;
} }
function updateScale(percentValue, minScale, maxScale) { function updateScale(percentValue, minScale, maxScale) {
if (selectedPlacedModel) { if (selectedPlacedModel) {
// Berechnung der Skalierung basierend auf dem Prozentwert // Berechnung der Skalierung basierend auf dem Prozentwert
const scale = minScale + (percentValue / 100) * (maxScale - minScale); const scale = minScale + (percentValue / 100) * (maxScale - minScale);
selectedPlacedModel.scale.set(scale, scale, scale); selectedPlacedModel.scale.set(scale, scale, scale);
...@@ -340,207 +340,217 @@ ...@@ -340,207 +340,217 @@
// Anzeige des aktuellen Prozentsatzes im Dynamic-Menü aktualisieren // Anzeige des aktuellen Prozentsatzes im Dynamic-Menü aktualisieren
const scaleValueDisplay = document.getElementById("scale-value"); const scaleValueDisplay = document.getElementById("scale-value");
if (scaleValueDisplay) { if (scaleValueDisplay) {
scaleValueDisplay.textContent = `${parseInt(percentValue, 10)}%`; scaleValueDisplay.textContent = `${parseInt(percentValue, 10)}%`;
} }
}
} }
}
let moveDelta = 0.1; // Standardwert für die Verschiebungsgröße, kann mit dem Slider geändert werden
function openMoveMenu() { function openMoveMenu() {
if (!selectedPlacedModel) { if (!selectedPlacedModel) {
console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bewegen."); console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bewegen.");
return; return;
}
const dynamicMenu = document.getElementById("dynamic-menu");
dynamicMenu.style.display = "flex";
dynamicMenu.innerHTML = `
<h3>Modell bewegen</h3>
<label>
Aktuelle Position: X=${selectedPlacedModel.position.x.toFixed(2)}, Z=${selectedPlacedModel.position.z.toFixed(2)}
</label>
<label>
Verschiebungsgröße: <span id="move-delta-display">${moveDelta.toFixed(2)}</span>
<input type="range" min="0.01" max="1.0" step="0.01" value="${moveDelta}" onchange="updateMoveDelta(this.value)">
</label>
<div style="display: flex; gap: 4px;">
<button onclick="moveModelDynamic('x', -1)">← X</button>
<button onclick="moveModelDynamic('x', 1)">→ X</button>
<button onclick="moveModelDynamic('z', -1)">- Z</button>
<button onclick="moveModelDynamic('z', 1)">+ Z</button>
</div>
<button onclick="closeDynamicMenu()">Zurück</button>
`;
}
function updateMoveDelta(value) {
moveDelta = parseFloat(value);
const moveDeltaDisplay = document.getElementById("move-delta-display");
if (moveDeltaDisplay) {
moveDeltaDisplay.textContent = moveDelta.toFixed(2);
}
}
function moveModelDynamic(axis, direction) {
if (selectedPlacedModel) {
const delta = direction * moveDelta; // Dynamischer Wert basierend auf Slider
selectedPlacedModel.position[axis] += delta;
// Position im Menü aktualisieren
const positionInfo = document.getElementById("position-info");
if (positionInfo) {
positionInfo.innerHTML = `
<p>Aktuelle Position: X=${selectedPlacedModel.position.x.toFixed(2)}, Z=${selectedPlacedModel.position.z.toFixed(2)}</p>`;
}
}
} }
/* ========================= */ const dynamicMenu = document.getElementById("dynamic-menu");
/* KARTENSTEUERUNG */ dynamicMenu.style.display = "flex";
/* ========================= */
function refreshMapDialog() { dynamicMenu.innerHTML = `
const mapDialog = document.getElementById('map-dialog'); <h3>Modell bewegen</h3>
mapDialog.style.display = 'flex'; <div id="joystick-container" style="position: relative; width: 100px; height: 100px; border: 2px solid #ccc; border-radius: 50%; margin: 20px auto;">
} <div id="joystick-knob" style="position: absolute; width: 30px; height: 30px; background: #007BFF; border-radius: 50%; top: 50%; left: 50%; transform: translate(-50%, -50%);"></div>
</div>
function closeMapDialog() { <button onclick="closeDynamicMenu()">Zurück</button>
const mapDialog = document.getElementById('map-dialog'); `;
mapDialog.style.display = 'none';
} const container = document.getElementById("joystick-container");
const knob = document.getElementById("joystick-knob");
/* ========================= */ let isDragging = false;
/* AR-HANDLING */
/* ========================= */ const center = { x: container.offsetWidth / 2, y: container.offsetHeight / 2 };
async function activateXR(sceneData = null) { const maxDistance = container.offsetWidth / 2;
const canvas = document.createElement('canvas');
document.body.appendChild(canvas); knob.addEventListener("mousedown", () => (isDragging = true));
const gl = canvas.getContext('webgl', { xrCompatible: true }); document.addEventListener("mouseup", () => {
const renderer = new THREE.WebGLRenderer({ alpha: true, canvas, context: gl }); isDragging = false;
renderer.autoClear = false; knob.style.left = "50%";
knob.style.top = "50%";
scene = new THREE.Scene(); moveModelDynamic('x', 0); // Bewegung stoppen, wenn Maus losgelassen wird
camera = new THREE.PerspectiveCamera(); moveModelDynamic('z', 0);
camera.matrixAutoUpdate = false; });
const light = new THREE.DirectionalLight(0xffffff, 1); document.addEventListener("mousemove", (event) => {
light.position.set(10, 10, 10); if (!isDragging) return;
scene.add(light);
const rect = container.getBoundingClientRect();
const loader = new THREE.GLTFLoader(); const dx = event.clientX - rect.left - center.x;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf", (gltf) => { const dy = event.clientY - rect.top - center.y;
const distance = Math.min(Math.sqrt(dx * dx + dy * dy), maxDistance);
const angle = Math.atan2(dy, dx);
const offsetX = Math.cos(angle) * distance;
const offsetY = Math.sin(angle) * distance;
// Knopfposition aktualisieren
knob.style.left = `${center.x + offsetX}px`;
knob.style.top = `${center.y + offsetY}px`;
// Bewegung basierend auf Joystick-Position anwenden
const normalizedX = offsetX / maxDistance;
const normalizedY = offsetY / maxDistance;
moveModelDynamic('x', normalizedX * 0.1); // Feine Anpassung
moveModelDynamic('z', -normalizedY * 0.1); // Feine Anpassung
});
}
function moveModelDynamic(axis, value) {
if (selectedPlacedModel) selectedPlacedModel.position[axis] += value;
}
/* ========================= */
/* KARTENSTEUERUNG */
/* ========================= */
function refreshMapDialog() {
const mapDialog = document.getElementById('map-dialog');
mapDialog.style.display = 'flex';
}
function closeMapDialog() {
const mapDialog = document.getElementById('map-dialog');
mapDialog.style.display = 'none';
}
/* ========================= */
/* AR-HANDLING */
/* ========================= */
async function activateXR(sceneData = null) {
const canvas = document.createElement('canvas');
document.body.appendChild(canvas);
const gl = canvas.getContext('webgl', { xrCompatible: true });
const renderer = new THREE.WebGLRenderer({ alpha: true, canvas, context: gl });
renderer.autoClear = false;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera();
camera.matrixAutoUpdate = false;
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(10, 10, 10);
scene.add(light);
const loader = new THREE.GLTFLoader();
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf", (gltf) => {
reticle = gltf.scene; reticle = gltf.scene;
reticle.visible = false; reticle.visible = false;
scene.add(reticle); scene.add(reticle);
}); });
currentSession = await navigator.xr.requestSession('immersive-ar', { currentSession = await navigator.xr.requestSession('immersive-ar', {
optionalFeatures: ["dom-overlay"], optionalFeatures: ["dom-overlay"],
domOverlay: { root: document.body }, domOverlay: { root: document.body },
requiredFeatures: ['hit-test'] requiredFeatures: ['hit-test']
}); });
currentSession.updateRenderState({ baseLayer: new XRWebGLLayer(currentSession, gl) }); currentSession.updateRenderState({ baseLayer: new XRWebGLLayer(currentSession, gl) });
const referenceSpace = await currentSession.requestReferenceSpace('local'); const referenceSpace = await currentSession.requestReferenceSpace('local');
const viewerSpace = await currentSession.requestReferenceSpace('viewer'); const viewerSpace = await currentSession.requestReferenceSpace('viewer');
const hitTestSource = await currentSession.requestHitTestSource({ space: viewerSpace }); const hitTestSource = await currentSession.requestHitTestSource({ space: viewerSpace });
document.getElementById('menu-bar').style.display = 'flex'; document.getElementById('menu-bar').style.display = 'flex';
currentSession.addEventListener("end", () => { currentSession.addEventListener("end", () => {
currentSession = null; currentSession = null;
document.getElementById("dynamic-menu").style.display = "none"; document.getElementById("dynamic-menu").style.display = "none";
menus.forEach(id => { menus.forEach(id => {
document.getElementById(id).style.display = 'none'; document.getElementById(id).style.display = 'none';
}); });
}); });
canvas.addEventListener("pointerdown", selectModelFromScene); canvas.addEventListener("pointerdown", selectModelFromScene);
if (navigator.geolocation) { if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => { navigator.geolocation.getCurrentPosition(position => {
geoLocation = { geoLocation = {
latitude: roundTo(position.coords.latitude, 5), latitude: roundTo(position.coords.latitude, 5),
longitude: roundTo(position.coords.longitude, 5), longitude: roundTo(position.coords.longitude, 5),
}; };
console.log("GeoLocation: " + JSON.stringify(geoLocation)); console.log("GeoLocation: " + JSON.stringify(geoLocation));
if (sceneData) { if (sceneData) {
sceneData.models.forEach((model) => { sceneData.models.forEach((model) => {
if (model.name) { if (model.name) {
const filePath = Object.values(models).find(m => model.name === m.name).file; const filePath = Object.values(models).find(m => model.name === m.name).file;
const { x, z } = leafletToThree(model.lat, model.lng); const { x, z } = leafletToThree(model.lat, model.lng);
const positionVector = new THREE.Vector3(x, model.position.y, z); const positionVector = new THREE.Vector3(x, model.position.y, z);
placeModel(filePath, positionVector, (placed) => { placeModel(filePath, positionVector, (placed) => {
if (model.rotation) { if (model.rotation) {
placed.rotation._x = model.rotation._x; placed.rotation._x = model.rotation._x;
placed.rotation._y = model.rotation._y; placed.rotation._y = model.rotation._y;
placed.rotation._z = model.rotation._z; placed.rotation._z = model.rotation._z;
} }
if (model.scale) { if (model.scale) {
placed.scale.x = model.scale.x; placed.scale.x = model.scale.x;
placed.scale.y = model.scale.y; placed.scale.y = model.scale.y;
placed.scale.z = model.scale.z; placed.scale.z = model.scale.z;
} }
}); });
} }
}); });
} }
}, function(error) { }, function (error) {
console.error("Fehler bei der Geolokalisierung:", JSON.stringify(error)); console.error("Fehler bei der Geolokalisierung:", JSON.stringify(error));
}, {enableHighAccuracy: true, maximumAge: 2000, timeout: 5000}); }, { enableHighAccuracy: true, maximumAge: 2000, timeout: 5000 });
} }
currentSession.requestAnimationFrame(function onXRFrame(time, frame) { currentSession.requestAnimationFrame(function onXRFrame(time, frame) {
currentSession.requestAnimationFrame(onXRFrame); currentSession.requestAnimationFrame(onXRFrame);
gl.bindFramebuffer(gl.FRAMEBUFFER, currentSession.renderState.baseLayer.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, currentSession.renderState.baseLayer.framebuffer);
const pose = frame.getViewerPose(referenceSpace); const pose = frame.getViewerPose(referenceSpace);
if (pose) { if (pose) {
const view = pose.views[0]; const view = pose.views[0];
const viewport = currentSession.renderState.baseLayer.getViewport(view); const viewport = currentSession.renderState.baseLayer.getViewport(view);
renderer.setSize(viewport.width, viewport.height); renderer.setSize(viewport.width, viewport.height);
camera.matrix.fromArray(view.transform.matrix); camera.matrix.fromArray(view.transform.matrix);
camera.projectionMatrix.fromArray(view.projectionMatrix); camera.projectionMatrix.fromArray(view.projectionMatrix);
camera.updateMatrixWorld(true); camera.updateMatrixWorld(true);
const hitTestResults = frame.getHitTestResults(hitTestSource); const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length > 0) { if (hitTestResults.length > 0) {
const hitPose = hitTestResults[0].getPose(referenceSpace); const hitPose = hitTestResults[0].getPose(referenceSpace);
reticle.visible = true; reticle.visible = true;
reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z); reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z);
reticle.updateMatrixWorld(true); reticle.updateMatrixWorld(true);
} }
renderer.render(scene, camera); renderer.render(scene, camera);
} }
}); });
} }
function exitAR() { function exitAR() {
document.getElementById('confirmation-dialog').style.display = 'flex'; document.getElementById('confirmation-dialog').style.display = 'flex';
} }
function confirmExit(shouldExit) { function confirmExit(shouldExit) {
if (shouldExit && currentSession) currentSession.end(); if (shouldExit && currentSession) currentSession.end();
document.getElementById('confirmation-dialog').style.display = 'none'; document.getElementById('confirmation-dialog').style.display = 'none';
} }
/* ========================= */ /* ========================= */
/* BENUTZERINTERAKTIONEN */ /* BENUTZERINTERAKTIONEN */
/* ========================= */ /* ========================= */
let soundTimeout = false; let soundTimeout = false;
function playButtonSound() { function playButtonSound() {
if (!soundTimeout) { if (!soundTimeout) {
const sound = document.getElementById("button-sound"); const sound = document.getElementById("button-sound");
sound.currentTime = 0; sound.currentTime = 0;
sound.play(); sound.play();
soundTimeout = true; soundTimeout = true;
setTimeout(() => { setTimeout(() => {
soundTimeout = false; soundTimeout = false;
}, 200); // Verzögerung von 200ms }, 200); // Verzögerung von 200ms
}
} }
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment