Commit 0d3fb29f authored by Alfakhori's avatar Alfakhori
Browse files

fix darkining

parent 52b3b364
Pipeline #12458 passed with stage
in 23 seconds
/* ========================= */ /* ========================= */
/* 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: "assets/previewImages/bench.PNG", image: "assets/previewImages/bench.PNG",
...@@ -20,6 +31,7 @@ let models = { ...@@ -20,6 +31,7 @@ let models = {
minScale: 0.05, minScale: 0.05,
maxScale: 0.5 maxScale: 0.5
}, },
trashbin: { trashbin: {
name: "Trash bin", name: "Trash bin",
image: "assets/previewImages/trash_can.PNG", image: "assets/previewImages/trash_can.PNG",
...@@ -28,6 +40,7 @@ let models = { ...@@ -28,6 +40,7 @@ let models = {
minScale: 0.01, minScale: 0.01,
maxScale: 0.1 maxScale: 0.1
}, },
lantern: { lantern: {
name: "Lantern", name: "Lantern",
image: "assets/previewImages/park_light.png", image: "assets/previewImages/park_light.png",
...@@ -36,6 +49,7 @@ let models = { ...@@ -36,6 +49,7 @@ let models = {
minScale: 0.2, minScale: 0.2,
maxScale: 5 maxScale: 5
}, },
telephone_box: { telephone_box: {
name: "Telephone Box", name: "Telephone Box",
image: "assets/previewImages/telephone_box.PNG", image: "assets/previewImages/telephone_box.PNG",
...@@ -44,6 +58,7 @@ let models = { ...@@ -44,6 +58,7 @@ let models = {
minScale: 0.05, minScale: 0.05,
maxScale: 1 maxScale: 1
}, },
fire_hydrant_model: { fire_hydrant_model: {
name: "Fire Hydrant", name: "Fire Hydrant",
image: "assets/previewImages/hydrant.PNG", image: "assets/previewImages/hydrant.PNG",
...@@ -52,6 +67,7 @@ let models = { ...@@ -52,6 +67,7 @@ let models = {
minScale: 0.1, minScale: 0.1,
maxScale: 1 maxScale: 1
}, },
statue: { statue: {
name: "Statue", name: "Statue",
image: "assets/previewImages/statue.PNG", image: "assets/previewImages/statue.PNG",
...@@ -60,6 +76,7 @@ let models = { ...@@ -60,6 +76,7 @@ let models = {
minScale: 0.05, minScale: 0.05,
maxScale: 2 maxScale: 2
}, },
fountain: { fountain: {
name: "Fountain", name: "Fountain",
image: "assets/previewImages/fountain.PNG", image: "assets/previewImages/fountain.PNG",
...@@ -70,485 +87,1482 @@ let models = { ...@@ -70,485 +87,1482 @@ let models = {
} }
}; };
/* ========================= */ /* ========================= */
/* 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');
addMenu.innerHTML = Object.entries(models) const addMenu =
.map( document.getElementById('add-menu');
([key, model]) => `
<div class="menu-item" id="${key}-item" onclick="selectModel('${key}')"> addMenu.innerHTML =
<img src="${model.image}" alt="${model.name}" /> Object.entries(models)
</div> .map(
` ([key, model]) => `
) <div
.join('') + class="menu-item"
id="${key}-item"
onclick="selectModel('${key}')"
>
<img
src="${model.image}"
alt="${model.name}"
/>
</div>
`
)
.join('') +
` `
<div class="menu-item" onclick="showMenu('menu-bar')"> <div
<img src="assets/icons/back-icon.png" alt="Zurück" /> class="menu-item"
onclick="showMenu('menu-bar')"
>
<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';
// ========================================================
// Check location before opening map
// ========================================================
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;
} }
// ========================================================
// Hide all menus
// ========================================================
menus.forEach(id => { menus.forEach(id => {
document.getElementById(id).style.display = id === menuId ? 'flex' : 'none';
const element =
document.getElementById(id);
if (element) {
element.style.display =
id === menuId
? 'flex'
: 'none';
}
}); });
// ========================================================
// Close dynamic menu
// ========================================================
closeDynamicMenu(); closeDynamicMenu();
if (menuId === 'menu-bar') clearSelectedModel();
else if (isMapWindow) init_map();
// ========================================================
// Menu-specific actions
// ========================================================
if (menuId === 'menu-bar') {
clearSelectedModel();
} else if (isMapWindow) {
// Initialize map
init_map();
// Leaflet needs to know the actual size of the
// visible map container.
setTimeout(() => {
if (
typeof centerOnPlan === 'function'
) {
centerOnPlan();
}
}, 100);
}
} }
/* ============================================================ */
/* Close map and return to AR scene */
/* ============================================================ */
function closeMap() {
const mapWindow =
document.getElementById("map-window");
if (mapWindow) {
mapWindow.style.display = "none";
}
// Show the main AR menu again
const menuBar =
document.getElementById("menu-bar");
if (menuBar) {
menuBar.style.display = "flex";
}
// Stop the map update interval
if (typeof intervalId !== 'undefined') {
if (intervalId) {
clearInterval(intervalId);
intervalId = null;
}
}
// Clear selected model
clearSelectedModel();
}
function closeDynamicMenu() { function closeDynamicMenu() {
const dynamicMenu = document.getElementById("dynamic-menu");
dynamicMenu.style.display = "none"; const dynamicMenu =
document.getElementById(
"dynamic-menu"
);
if (dynamicMenu) {
dynamicMenu.style.display = "none";
}
} }
function showInfoDialog(message) { function showInfoDialog(message) {
const infoDialog = document.getElementById("info-dialog");
const infoText = document.getElementById("info-text");
infoText.textContent = message; // Nachricht setzen const infoDialog =
document.getElementById(
"info-dialog"
);
const infoText =
document.getElementById(
"info-text"
);
infoText.textContent = message;
infoDialog.style.display = "flex"; infoDialog.style.display = "flex";
} }
function closeInfoDialog() { function closeInfoDialog() {
const infoDialog = document.getElementById("info-dialog");
const infoDialog =
document.getElementById(
"info-dialog"
);
infoDialog.style.display = "none"; infoDialog.style.display = "none";
} }
/* ========================= */ /* ========================= */
/* MODELL-HANDLING */ /* MODELL-HANDLING */
/* ========================= */ /* ========================= */
function getAllPlacedModels() { function getAllPlacedModels() {
return scene.children.filter(child => child.isPlacedModel === true);
return scene.children.filter(
child =>
child.isPlacedModel === true
);
} }
function loadModel(filePath) { function loadModel(filePath) {
placeModel(filePath, reticle.position, (model) => {
selectedPlacedModel = model; placeModel(
highlightSelectedModel(); filePath,
showMenu('edit-menu'); 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); function placeModel(
const loader = new THREE.GLTFLoader(); filePath,
position,
onPlace = null
) {
const modelConfig =
Object.values(models)
.find(
model =>
model.file === filePath
);
const loader =
new THREE.GLTFLoader();
loader.load( loader.load(
filePath, filePath,
(gltf) => { (gltf) => {
const model = gltf.scene;
if (modelConfig && modelConfig.scale) { const model =
model.scale.set(modelConfig.scale.x, modelConfig.scale.y, modelConfig.scale.z); gltf.scene;
if (
modelConfig &&
modelConfig.scale
) {
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];
if (model && model.file) { const model =
models[modelId];
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(
(event.clientX / window.innerWidth) * 2 - 1, const mouse =
-(event.clientY / window.innerHeight) * 2 + 1 new THREE.Vector2(
(event.clientX /
window.innerWidth) *
2 - 1,
-(event.clientY /
window.innerHeight) *
2 + 1
);
const raycaster =
new THREE.Raycaster();
raycaster.setFromCamera(
mouse,
camera
); );
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, camera);
// Prüfe Kollisionen mit Objekten in der Szene const intersects =
const intersects = raycaster.intersectObjects(scene.children, true); raycaster.intersectObjects(
scene.children,
true
);
if (intersects.length > 0) { if (intersects.length > 0) {
// Finde das Hauptobjekt (Root-Parent), falls Mesh ausgewählt wurde
let selectedObject = intersects[0].object; let selectedObject =
while (selectedObject.parent && selectedObject.parent !== scene) { intersects[0].object;
selectedObject = selectedObject.parent;
while (
selectedObject.parent &&
selectedObject.parent !== scene
) {
selectedObject =
selectedObject.parent;
} }
// Überprüfe, ob das ausgewählte Objekt das Reticle ist
if (selectedObject === reticle) { // Reticle cannot be selected
console.log("Reticle kann nicht ausgewählt werden.");
if (
selectedObject === reticle
) {
console.log(
"Reticle kann nicht ausgewählt werden."
);
return; return;
} }
// 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) => {
if (child.isMesh) { selectedPlacedModel.traverse(
child.material.emissive.setHex(0x000000); // Markierung entfernen (child) => {
if (child.isMesh) {
child.material.emissive
.setHex(0x000000);
}
} }
}); );
selectedPlacedModel = null; selectedPlacedModel = null;
} }
} }
function highlightSelectedModel() { function highlightSelectedModel() {
if (selectedPlacedModel) { if (selectedPlacedModel) {
removeHighlightFromAllModels(); removeHighlightFromAllModels();
selectedPlacedModel.traverse((child) => {
if (child.isMesh) {
child.material.emissive.setHex(0xff0000); // Rote Hervorhebung selectedPlacedModel.traverse(
(child) => {
if (child.isMesh) {
child.material.emissive
.setHex(0xff0000);
}
} }
}); );
} }
} }
function removeHighlightFromSelectedModel() { function removeHighlightFromSelectedModel() {
if (selectedPlacedModel) { if (selectedPlacedModel) {
selectedPlacedModel.traverse((child) => {
if (child.isMesh) child.material.emissive.setHex(0x000000); // Markierung entfernen selectedPlacedModel.traverse(
}); (child) => {
if (child.isMesh) {
child.material.emissive
.setHex(0x000000);
}
}
);
} }
} }
function removeHighlightFromAllModels() { function removeHighlightFromAllModels() {
scene.traverse((child) => {
if (child.isMesh && child.material && child.material.emissive) { scene.traverse(
child.material.emissive.setHex(0x000000); // Markierung entfernen (child) => {
if (
child.isMesh &&
child.material &&
child.material.emissive
) {
child.material.emissive
.setHex(0x000000);
}
} }
}); );
} }
function deleteModel() { function deleteModel() {
if (!selectedPlacedModel) { if (!selectedPlacedModel) {
console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es löschen.");
console.log(
"Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es löschen."
);
return; return;
} }
const deleteDialog = document.getElementById('delete-confirmation-dialog');
deleteDialog.style.display = 'flex'; const deleteDialog =
document.getElementById(
'delete-confirmation-dialog'
);
deleteDialog.style.display =
'flex';
} }
function confirmDelete(shouldDelete) { function confirmDelete(shouldDelete) {
const deleteDialog = document.getElementById('delete-confirmation-dialog');
deleteDialog.style.display = 'none';
if (shouldDelete && selectedPlacedModel) { const deleteDialog =
scene.remove(selectedPlacedModel); document.getElementById(
'delete-confirmation-dialog'
);
deleteDialog.style.display =
'none';
if (
shouldDelete &&
selectedPlacedModel
) {
scene.remove(
selectedPlacedModel
);
selectedPlacedModel = null; selectedPlacedModel = null;
showMenu('menu-bar'); showMenu('menu-bar');
} }
} }
function completeEditing() { function completeEditing() {
removeHighlightFromSelectedModel(); removeHighlightFromSelectedModel();
closeDynamicMenu(); closeDynamicMenu();
selectedPlacedModel = null; selectedPlacedModel = null;
document.getElementById('edit-menu').style.display = 'none';
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() { function openRotationMenu() {
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;
} }
const currentRotation = Math.round(THREE.MathUtils.radToDeg(selectedPlacedModel.rotation.y)); // Aktuelle Y-Rotation des Modells (in Grad)
const dynamicMenu = document.getElementById("dynamic-menu"); const currentRotation =
dynamicMenu.style.display = "flex"; Math.round(
THREE.MathUtils.radToDeg(
selectedPlacedModel.rotation.y
)
);
const dynamicMenu =
document.getElementById(
"dynamic-menu"
);
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>
<button onclick="closeDynamicMenu()">Zurück</button> <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>
`;
} }
function updateRotation(axis, value) { function updateRotation(axis, value) {
if (selectedPlacedModel) { if (selectedPlacedModel) {
const radians = (value / 180) * Math.PI;
selectedPlacedModel.rotation[axis] = radians;
// Anzeige der aktuellen Rotation im Dynamic-Menü aktualisieren const radians =
const currentRotationDisplay = document.getElementById("current-rotation"); (value / 180) * Math.PI;
selectedPlacedModel.rotation[axis] =
radians;
const currentRotationDisplay =
document.getElementById(
"current-rotation"
);
if (currentRotationDisplay) { if (currentRotationDisplay) {
currentRotationDisplay.textContent = value; // Zeige den aktuellen Wert in Grad an
currentRotationDisplay.textContent =
value;
} }
} }
} }
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
const currentScale = selectedPlacedModel.scale.x;
const minScale = selectedPlacedModel.modelConfig.minScale;
const maxScale = selectedPlacedModel.modelConfig.maxScale;
const step = (maxScale - minScale) / 100; // Dynamische Schrittgröße basierend auf Grenzen
const currentScalePercent = ((currentScale - minScale) / (maxScale - minScale)) * 100; // Umrechnung der Werte in Prozent const currentScale =
selectedPlacedModel.scale.x;
const minScale =
selectedPlacedModel.modelConfig.minScale;
const maxScale =
selectedPlacedModel.modelConfig.maxScale;
const step =
(maxScale - minScale) / 100;
const currentScalePercent =
(
(currentScale - minScale) /
(maxScale - minScale)
) * 100;
const dynamicMenu =
document.getElementById(
"dynamic-menu"
);
dynamicMenu.style.display =
"flex";
const dynamicMenu = document.getElementById("dynamic-menu");
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>
<input type="range" min="0" max="100" step=""${step}"" value="${currentScalePercent}" onchange="updateScale(this.value, ${minScale}, ${maxScale})"></label> <label>
<button onclick="closeDynamicMenu()">Zurück</button> Größe:
`; <span id="scale-value">
${currentScalePercent.toFixed(0)}%
</span>
<input
type="range"
min="0"
max="100"
step="${step}"
value="${currentScalePercent}"
onchange="updateScale(
this.value,
${minScale},
${maxScale}
)"
>
</label>
<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
const scale = minScale + (percentValue / 100) * (maxScale - minScale);
selectedPlacedModel.scale.set(scale, scale, scale);
// Anzeige des aktuellen Prozentsatzes im Dynamic-Menü aktualisieren const scale =
const scaleValueDisplay = document.getElementById("scale-value"); minScale +
(percentValue / 100) *
(maxScale - minScale);
selectedPlacedModel.scale.set(
scale,
scale,
scale
);
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
let moveDelta = 0.1;
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 bearbeiten."
);
return; return;
} }
const dynamicMenu = document.getElementById("dynamic-menu");
dynamicMenu.style.display = "flex"; const dynamicMenu =
document.getElementById(
"dynamic-menu"
);
dynamicMenu.style.display =
"flex";
dynamicMenu.innerHTML = ` dynamicMenu.innerHTML = `
<h3>Position anpassen</h3>
<label> <h3>Position anpassen</h3>
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>
</label>
<div class="button-row"> Verschiebungsgröße:
<div class="control-button" id="left" onclick="moveModelDynamic('x', -moveDelta)"> <span id="move-delta-display">
<img src="assets/icons/left-arrow.png" alt="Left" /> ${moveDelta.toFixed(2)}
</div> </span>
<div class="control-button" id="right" onclick="moveModelDynamic('x', moveDelta)">
<img src="assets/icons/right-arrow.png" alt="Right" /> <input
</div> type="range"
<div class="control-button" id="up" onclick="moveModelDynamic('z', -moveDelta)"> min="0.01"
<img src="assets/icons/up-arrow.png" alt="Up" /> max="1.0"
</div> step="0.01"
<div class="control-button" id="down" onclick="moveModelDynamic('z', moveDelta)"> value="${moveDelta}"
<img src="assets/icons/down-arrow.png" alt="Down" /> onchange="updateMoveDelta(this.value)"
>
</label>
<div class="button-row">
<div
class="control-button"
id="left"
onclick="moveModelDynamic('x', -moveDelta)"
>
<img
src="assets/icons/left-arrow.png"
alt="Left"
/>
</div>
<div
class="control-button"
id="right"
onclick="moveModelDynamic('x', moveDelta)"
>
<img
src="assets/icons/right-arrow.png"
alt="Right"
/>
</div>
<div
class="control-button"
id="up"
onclick="moveModelDynamic('z', -moveDelta)"
>
<img
src="assets/icons/up-arrow.png"
alt="Up"
/>
</div>
<div
class="control-button"
id="down"
onclick="moveModelDynamic('z', moveDelta)"
>
<img
src="assets/icons/down-arrow.png"
alt="Down"
/>
</div>
</div> </div>
</div>
<button onclick="closeDynamicMenu()">Zurück</button> <button onclick="closeDynamicMenu()">
`; Zurück
</button>
`;
} }
function updateMoveDelta(value) { function updateMoveDelta(value) {
moveDelta = parseFloat(value);
const moveDeltaDisplay = document.getElementById("move-delta-display"); moveDelta =
parseFloat(value);
const moveDeltaDisplay =
document.getElementById(
"move-delta-display"
);
if (moveDeltaDisplay) { if (moveDeltaDisplay) {
moveDeltaDisplay.textContent = moveDelta.toFixed(2);
moveDeltaDisplay.textContent =
moveDelta.toFixed(2);
} }
} }
function moveModelDynamic(axis, value) {
if (selectedPlacedModel) selectedPlacedModel.position[axis] += value; function moveModelDynamic(
axis,
value
) {
if (selectedPlacedModel) {
selectedPlacedModel.position[axis] +=
value;
}
} }
/* ========================= */ /* ========================= */
/* KARTENSTEUERUNG */ /* KARTENSTEUERUNG */
/* ========================= */ /* ========================= */
function refreshMapDialog() { function refreshMapDialog() {
const mapDialog = document.getElementById('map-dialog');
mapDialog.style.display = 'flex'; const mapDialog =
document.getElementById(
'map-dialog'
);
mapDialog.style.display =
'flex';
} }
function closeMapDialog() { function closeMapDialog() {
const mapDialog = document.getElementById('map-dialog');
mapDialog.style.display = 'none'; const mapDialog =
document.getElementById(
'map-dialog'
);
mapDialog.style.display =
'none';
} }
/* ========================= */ /* ========================= */
/* AR-HANDLING */ /* AR-HANDLING */
/* ========================= */ /* ========================= */
async function activateXR(sceneData = null) {
const canvas = document.createElement('canvas'); async function activateXR(
document.body.appendChild(canvas); sceneData = null
const gl = canvas.getContext('webgl', { xrCompatible: true }); ) {
const renderer = new THREE.WebGLRenderer({ alpha: true, canvas, context: gl });
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; renderer.autoClear = false;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera();
camera.matrixAutoUpdate = false;
const light = new THREE.DirectionalLight(0xffffff, 1); scene =
light.position.set(10, 10, 10); new THREE.Scene();
camera =
new THREE.PerspectiveCamera();
camera.matrixAutoUpdate =
false;
// ========================================================
// AR lighting
// ========================================================
const light =
new THREE.DirectionalLight(
0xffffff,
1
);
light.position.set(
10,
10,
10
);
scene.add(light); 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.visible = false;
scene.add(reticle);
});
currentSession = await navigator.xr.requestSession('immersive-ar', { // ========================================================
optionalFeatures: ["dom-overlay"], // Reticle
domOverlay: { root: document.body }, // ========================================================
requiredFeatures: ['hit-test']
const loader =
new THREE.GLTFLoader();
loader.load(
"https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf",
(gltf) => {
reticle =
gltf.scene;
reticle.visible =
false;
scene.add(reticle);
}
);
// ========================================================
// Start WebXR AR session
// ========================================================
currentSession =
await navigator.xr.requestSession(
'immersive-ar',
{
optionalFeatures: [
"dom-overlay"
],
domOverlay: {
root: document.body
},
requiredFeatures: [
'hit-test'
]
}
);
currentSession.updateRenderState({
baseLayer:
new XRWebGLLayer(
currentSession,
gl
)
}); });
currentSession.updateRenderState({ baseLayer: new XRWebGLLayer(currentSession, gl) });
const referenceSpace = await currentSession.requestReferenceSpace('local');
const viewerSpace = await currentSession.requestReferenceSpace('viewer');
const hitTestSource = await currentSession.requestHitTestSource({ space: viewerSpace });
document.getElementById('menu-bar').style.display = 'flex'; const referenceSpace =
await currentSession.requestReferenceSpace(
'local'
);
const viewerSpace =
await currentSession.requestReferenceSpace(
'viewer'
);
currentSession.addEventListener("end", () => { const hitTestSource =
currentSession = null; await currentSession.requestHitTestSource({
document.getElementById("dynamic-menu").style.display = "none"; space: viewerSpace
menus.forEach(id => {
document.getElementById(id).style.display = 'none';
}); });
});
canvas.addEventListener("pointerdown", selectModelFromScene);
// ========================================================
// Show main menu
// ========================================================
document.getElementById(
'menu-bar'
).style.display = 'flex';
// ========================================================
// AR session ended
// ========================================================
currentSession.addEventListener(
"end",
() => {
currentSession =
null;
// Hide dynamic menu
document.getElementById(
"dynamic-menu"
).style.display =
"none";
// Hide all application menus
menus.forEach(id => {
const element =
document.getElementById(id);
if (element) {
element.style.display =
'none';
}
});
}
);
// ========================================================
// Select objects in AR
// ========================================================
canvas.addEventListener(
"pointerdown",
selectModelFromScene
);
// ========================================================
// Geolocation
// ========================================================
if (navigator.geolocation) { if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => {
geoLocation = { navigator.geolocation.getCurrentPosition(
latitude: roundTo(position.coords.latitude, 5),
longitude: roundTo(position.coords.longitude, 5), position => {
};
console.log("GeoLocation: " + JSON.stringify(geoLocation)); geoLocation = {
if (sceneData) {
sceneData.models.forEach((model) => { latitude:
if (model.name) { roundTo(
const filePath = Object.values(models).find(m => model.name === m.name).file; position.coords.latitude,
const { x, z } = leafletToThree(model.lat, model.lng); 5
const positionVector = new THREE.Vector3(x, model.position.y, z); ),
placeModel(filePath, positionVector, (placed) => {
if (model.rotation) { longitude:
placed.rotation._x = model.rotation._x; roundTo(
placed.rotation._y = model.rotation._y; position.coords.longitude,
placed.rotation._z = model.rotation._z; 5
} )
if (model.scale) { };
placed.scale.x = model.scale.x;
placed.scale.y = model.scale.y;
placed.scale.z = model.scale.z; console.log(
"GeoLocation: " +
JSON.stringify(
geoLocation
)
);
// =================================================
// Load saved scene models
// =================================================
if (sceneData) {
sceneData.models.forEach(
(model) => {
if (model.name) {
const modelDefinition =
Object.values(models)
.find(
m =>
model.name ===
m.name
);
if (!modelDefinition) {
console.error(
"Modell nicht gefunden:",
model.name
);
return;
}
const filePath =
modelDefinition.file;
const {
x,
z
} =
leafletToThree(
model.lat,
model.lng
);
const positionVector =
new THREE.Vector3(
x,
model.position.y,
z
);
placeModel(
filePath,
positionVector,
(placed) => {
if (
model.rotation
) {
placed.rotation._x =
model.rotation._x;
placed.rotation._y =
model.rotation._y;
placed.rotation._z =
model.rotation._z;
}
if (
model.scale
) {
placed.scale.x =
model.scale.x;
placed.scale.y =
model.scale.y;
placed.scale.z =
model.scale.z;
}
}
);
} }
}); }
} );
}); }
},
error => {
console.error(
"Fehler bei der Geolokalisierung:",
JSON.stringify(error)
);
},
{
enableHighAccuracy: true,
maximumAge: 2000,
timeout: 5000
} }
}, function (error) { );
console.error("Fehler bei der Geolokalisierung:", JSON.stringify(error));
}, { enableHighAccuracy: true, maximumAge: 2000, timeout: 5000 });
} }
currentSession.requestAnimationFrame(function onXRFrame(time, frame) {
currentSession.requestAnimationFrame(onXRFrame);
gl.bindFramebuffer(gl.FRAMEBUFFER, currentSession.renderState.baseLayer.framebuffer);
const pose = frame.getViewerPose(referenceSpace);
if (pose) {
const view = pose.views[0];
const viewport = currentSession.renderState.baseLayer.getViewport(view);
renderer.setSize(viewport.width, viewport.height);
camera.matrix.fromArray(view.transform.matrix);
camera.projectionMatrix.fromArray(view.projectionMatrix);
camera.updateMatrixWorld(true);
const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length > 0) {
const hitPose = hitTestResults[0].getPose(referenceSpace);
reticle.visible = true;
reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z);
reticle.updateMatrixWorld(true);
}
renderer.render(scene, camera); // ========================================================
// XR render loop
// ========================================================
currentSession.requestAnimationFrame(
function onXRFrame(
time,
frame
) {
currentSession.requestAnimationFrame(
onXRFrame
);
gl.bindFramebuffer(
gl.FRAMEBUFFER,
currentSession
.renderState
.baseLayer
.framebuffer
);
const pose =
frame.getViewerPose(
referenceSpace
);
if (pose) {
const view =
pose.views[0];
const viewport =
currentSession
.renderState
.baseLayer
.getViewport(view);
renderer.setSize(
viewport.width,
viewport.height
);
camera.matrix.fromArray(
view.transform.matrix
);
camera.projectionMatrix.fromArray(
view.projectionMatrix
);
camera.updateMatrixWorld(
true
);
// =================================================
// Hit testing
// =================================================
const hitTestResults =
frame.getHitTestResults(
hitTestSource
);
if (
hitTestResults.length > 0
) {
const hitPose =
hitTestResults[0]
.getPose(
referenceSpace
);
reticle.visible =
true;
reticle.position.set(
hitPose.transform.position.x,
hitPose.transform.position.y,
hitPose.transform.position.z
);
reticle.updateMatrixWorld(
true
);
}
// =================================================
// Render AR scene
// =================================================
renderer.render(
scene,
camera
);
}
} }
}); );
} }
/* ========================= */
/* AR EXIT */
/* ========================= */
function exitAR() { function exitAR() {
document.getElementById('confirmation-dialog').style.display = 'flex';
document.getElementById(
'confirmation-dialog'
).style.display =
'flex';
} }
function confirmExit(shouldExit) {
if (shouldExit && currentSession) currentSession.end(); function confirmExit(
document.getElementById('confirmation-dialog').style.display = 'none'; shouldExit
) {
if (
shouldExit &&
currentSession
) {
currentSession.end();
}
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");
sound.currentTime = 0; const sound =
document.getElementById(
"button-sound"
);
sound.currentTime =
0;
sound.play(); sound.play();
soundTimeout = true;
setTimeout(() => { soundTimeout =
soundTimeout = false; true;
}, 200); // Verzögerung von 200ms
setTimeout(
() => {
soundTimeout =
false;
},
200
);
} }
} }
\ No newline at end of file
...@@ -266,3 +266,41 @@ button:active { ...@@ -266,3 +266,41 @@ button:active {
background-color: #0056b3; background-color: #0056b3;
transform: scale(0.95); transform: scale(0.95);
} }
/* ============================================================
MAP WINDOW
============================================================ */
#map-window {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: none;
background: #ffffff;
z-index: 100;
box-sizing: border-box;
}
/* Map itself */
#map-container {
width: 100%;
height: 100%;
position: relative;
}
/* Make sure Leaflet fills the map window */
#map-container .leaflet-container {
width: 100%;
height: 100%;
}
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