Files
Projekt-Visualisierung/main.js
2026-05-11 23:11:05 +02:00

292 lines
8.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import maplibregl from "maplibre-gl";
const center = [9.209116842757239, 52.26520546238239]
const map = new maplibregl.Map({
container: 'map',
style: "https://tiles.openfreemap.org/styles/bright",
center: center,
zoom: 17
});
map.addControl(
new maplibregl.NavigationControl({
visualizePitch: true,
showZoom: true,
showCompass: true
})
);
const elRenderArea=document.getElementById("potree_render_area");
const viewer=new Potree.Viewer(elRenderArea, {noDragAndDrop:true});
viewer.setEDLEnabled(true);
viewer.setFOV(60);
viewer.setPointBudget(3*1000*1000);
viewer.setMinNodeSize(0);
viewer.setBackground("none");
//viewer.setControls(null);
//Dateipfade der Punktwolken
const pointCloudFiles={
//Namen sind gerade nur Platzhalter. Richtige namen müssen rein
first: 'output/metadata.json',
second: 'standpunkt2/metadata.json',
third: 'punktwolke_3_converted/metadata.json',
}
//Aktuelle Datei und Sichtbarkeit
let currentPointCloud=null;
let isVisible=true;
function loadPointCloud(path){
console.log("Laden aufgerufen")
if(currentPointCloud){
viewer.scene.removePointCloud(currentPointCloud);
currentPointCloud=null;
}
if(!path ||!isVisible) return;
Potree.loadPointCloud(path, "punktwolke", function(e) {
currentPointCloud=e.pointcloud;
viewer.scene.addPointCloud(currentPointCloud);
// View-Objekt inspizieren
console.log("view:", viewer.scene.view);
console.log("view.lookAt:", viewer.scene.view.lookAt);
console.log("view.position:", viewer.scene.view.position);
console.log("view keys:", Object.keys(viewer.scene.view));
let material =currentPointCloud.material;
material.size =1;
material.pointSizeType=Potree.PointSizeType.ADAPTIVE;
viewer.fitToScreen();
syncCamera();
});
}
// Geo-Koordinaten der Punktwolke (müssen zu euren Daten passen!)
// Das ist der Georeferenzpunkt idealerweise aus den Metadaten der Punktwolke
const CLOUD_GEO_ORIGIN = {
lng: 9.209116842757239,
lat: 52.26520546238239
};
// Hilfsfunktion: MapLibre Mercator → Meter-Offset relativ zum Ursprung
function lngLatToMeters(lng, lat, originLng, originLat) {
const R = 6378137; // Erdradius in Metern (WGS84)
const dLng = (lng - originLng) * Math.PI / 180;
const dLat = (lat - originLat) * Math.PI / 180;
const dx = R * dLng * Math.cos(originLat * Math.PI / 180);
const dy = R * dLat;
return { x: dx, y: dy };
}
function syncCamera() {
if (!currentPointCloud) return;
const mapCenter = map.getCenter();
const zoom = map.getZoom();
const pitch = map.getPitch(); // Grad, 0 = top-down
const bearing = map.getBearing(); // Grad
const box = currentPointCloud.boundingBox;
const cx = (box.min.x + box.max.x) / 2;
const cy = (box.min.y + box.max.y) / 2;
const cz = (box.min.z + box.max.z) / 2;
// Radius aus Zoom ableiten (Abstand Kamera → Target)
const earthCircumference = 2 * Math.PI * 6378137;
const canvas = map.getCanvas();
const metersPerPixel = (earthCircumference * Math.cos(mapCenter.lat * Math.PI / 180))
/ (Math.pow(2, zoom) * 512);
const radius = metersPerPixel * canvas.height;
// Potree View direkt setzen
const view = viewer.scene.view;
// Target = Wolken-Zentrum (lookAt mit 3 Argumenten nutzt new Vector3(...arguments))
view.lookAt(cx, cy, cz);
// yaw = Himmelsrichtung: MapLibre bearing 0° = Nord, Potree yaw 0° = ??
// bearing in Potree-yaw umrechnen (ggf. Vorzeichen anpassen)
view.yaw = -bearing * Math.PI / 180;
// pitch: MapLibre 0° = top-down, 60° = schräg
// Potree pitch: 0 = horizontal, -PI/2 = top-down → invertieren
view.pitch = -(90 - pitch) * Math.PI / 180;
// Radius = Zoom-abhängiger Abstand
view.radius = radius;
}
map.on('move', ()=>{
console.log(viewer.scene.view)
syncCamera();
});
map.on('zoom', syncCamera);
map.on('pitch', syncCamera);
map.on('rotate', syncCamera);
// Hintergrundkarte ändern
function changeBaseMap(newMap){
var basemapStyle;
switch(newMap){
case "openfree_dark":
basemapStyle = "https://tiles.openfreemap.org/styles/dark"
break;
case "openfree_bright":
basemapStyle = "https://tiles.openfreemap.org/styles/bright"
break;
case "openfree_liberty":
basemapStyle = "https://tiles.openfreemap.org/styles/liberty"
break;
case "google_satellite":
basemapStyle = {
version: 8,
sources: {
"raster-tiles": {
type: "raster",
tiles: [
"https://mt0.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
"https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
"https://mt2.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
"https://mt3.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
],
tileSize: 256,
},
},
layers: [{ id: "raster-layer", type: "raster", source: "raster-tiles" }],
}
break;
case "terrain":
basemapStyle = {
version: 8,
sources: {
osm: {
type: 'raster',
tiles: ['https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'],
tileSize: 256,
attribution: '© OpenStreetMap Contributors',
maxzoom: 19
},
// Use a different source for terrain and hillshade layers, to improve render quality
terrainSource: {
type: 'raster-dem',
url: 'https://tiles.mapterhorn.com/tilejson.json',
},
hillshadeSource: {
type: 'raster-dem',
url: 'https://tiles.mapterhorn.com/tilejson.json'
}
},
layers: [
{
id: 'osm',
type: 'raster',
source: 'osm'
},
{
id: 'hills',
type: 'hillshade',
source: 'hillshadeSource',
layout: {visibility: 'visible'},
paint: {'hillshade-shadow-color': '#473B24'}
}
],
terrain: {
source: 'terrainSource',
exaggeration: 1
},
sky: {}
}
break;
case "satellite_terrain":
basemapStyle = {
version: 8,
sources: {
osm: {
type: 'raster',
tiles: [
"https://mt0.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
"https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
"https://mt2.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
"https://mt3.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
],
tileSize: 256,
attribution: '© OpenStreetMap Contributors',
maxzoom: 19
},
// Use a different source for terrain and hillshade layers, to improve render quality
terrainSource: {
type: 'raster-dem',
url: 'https://tiles.mapterhorn.com/tilejson.json',
},
hillshadeSource: {
type: 'raster-dem',
url: 'https://tiles.mapterhorn.com/tilejson.json'
}
},
layers: [
{
id: 'osm',
type: 'raster',
source: 'osm'
},
{
id: 'hills',
type: 'hillshade',
source: 'hillshadeSource',
layout: {visibility: 'visible'},
paint: {'hillshade-shadow-color': '#473B24'}
}
],
terrain: {
source: 'terrainSource',
exaggeration: 1
},
sky: {}
}
}
map.setStyle(basemapStyle);
}
document.querySelector('input[type="checkbox"]').addEventListener('change', (event)=>
{
isVisible=!event.target.checked;
if (currentPointCloud){
currentPointCloud.visible=isVisible;
};
})
// ausgewähltes Element im BaseMap DropDown Feld
const selectElement = document.querySelector('select[name="basemap"]');
selectElement.addEventListener('change', (event) => {
changeBaseMap(event.target.value);
});
// ausgewähltes Element im Punktwolken DropDown Feld
document.querySelector('select[name="pointcloud"]').addEventListener('change', (event) => {
loadPointCloud(pointCloudFiles[event.target.value]);
});
// Auf Zentrum zurück zoomen
document.getElementById("location").addEventListener("click", () => {
map.flyTo({center, zoom: 17 })
});