-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' of git.ntnu.no:TDT4290-group-4/MolloyExplorer into…
… 10-show-coordinates-on-screen
- Loading branch information
Showing
8 changed files
with
429 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| //Cerating a customized section "Elevation Control" | ||
| window.createElevationPanel = function createElevationPanel(viewer) { | ||
| const container = document.getElementById('elevation_list') | ||
| let targetContainer = container | ||
| if (!targetContainer) { | ||
| // Create a new accordion section for Elevation Control | ||
| const menu = document.getElementById('potree_menu') | ||
| if (menu) { | ||
| const header = document.createElement('h3') | ||
| header.id = 'menu_elevation' | ||
| header.innerHTML = '<span>Elevation Control</span>' | ||
| const panel = document.createElement('div') | ||
| panel.className = 'pv-menu-list' | ||
| panel.innerHTML = '<div id="elevation_list" class="auto"></div>' | ||
| const about = document.getElementById('menu_appearance') | ||
| if (about) { | ||
| menu.insertBefore(panel, about) | ||
| menu.insertBefore(header, panel) | ||
| } else { | ||
| menu.appendChild(header) | ||
| menu.appendChild(panel) | ||
| } | ||
| // Activate accordion behavior if jQuery UI accordion already initialized | ||
| if ($(menu).accordion) { | ||
| try { | ||
| $(menu).accordion('refresh') | ||
| } catch (e) {} | ||
| } | ||
| // Toggle on header click if not managed by accordion refresh | ||
| header.addEventListener( | ||
| 'click', | ||
| () => | ||
| (panel.style.display = panel.style.display === 'none' ? '' : 'none') | ||
| ) | ||
| targetContainer = panel.querySelector('#elevation_list') | ||
| } | ||
| } | ||
| } | ||
|
|
||
| //Select the fist pointcloud in the sidebar so that the Elevation section is built | ||
| function autoSelectFirstPointCloud() { | ||
| const cloudIcon = document.querySelector( | ||
| '#scene_objects i.jstree-themeicon-custom' | ||
| ) | ||
| if (cloudIcon) { | ||
| cloudIcon.dispatchEvent(new MouseEvent('click', { bubbles: true })) | ||
| return true | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| //(re)connect the elevation labels to the slider after the container is moved (was not handled by default) | ||
| function rebindElevationLabel() { | ||
| const slider = window.jQuery ? window.jQuery('#sldHeightRange') : null | ||
| const label = document.getElementById('lblHeightRange') | ||
| if (!slider || !slider.length || !label) return | ||
|
|
||
| const update = () => { | ||
| const low = slider.slider('values', 0) | ||
| const high = slider.slider('values', 1) | ||
| label.textContent = `${low.toFixed(2)} to ${high.toFixed(2)}` | ||
| } | ||
|
|
||
| // Adjust slider limits | ||
| slider.slider({ | ||
| min: -10000, | ||
| max: 0, | ||
| values: [-10000, 0] | ||
| }) | ||
|
|
||
| //clear any old namespaced handlers and attach fresh ones | ||
| slider.off('slide.custom slidestop.custom change.custom') | ||
| slider.on('slide.custom', update) | ||
| slider.on('slidestop.custom change.custom', update) | ||
| update() | ||
| } | ||
|
|
||
| //Move the elevation range section to the customised "Elevation Control" section | ||
| function moveElevationContainer() { | ||
| const target = document.getElementById('elevation_list') | ||
| const elevationContainer = document.querySelector( | ||
| '#materials\\.elevation_container' | ||
| ) | ||
| if (!elevationContainer) return false | ||
| target.appendChild(elevationContainer) | ||
| rebindElevationLabel() | ||
| return true | ||
| } | ||
|
|
||
| //initiate and orchestrate all funcitons to render the Evelation control section of the sidebar propperly | ||
| export function initElevationControls(viewer) { | ||
| //Creates the section | ||
| createElevationPanel(viewer) | ||
|
|
||
| //Only move the ElevationContainer if the source container to exist | ||
| const menu = | ||
| document.getElementById('potree_menu') || | ||
| document.getElementById('menu') || | ||
| document.body | ||
| const observer = new MutationObserver(() => { | ||
| const found = document.querySelector('#materials\\.elevation_container') | ||
| if (found) { | ||
| observer.disconnect() | ||
| //Move and rebind once it exists | ||
| const ok = moveElevationContainer() | ||
| if (!ok) console.warn('[Elevation] moveElevationContainer failed') | ||
| } | ||
| }) | ||
| observer.observe(menu, { childList: true, subtree: true }) | ||
|
|
||
| //Trigger Potree to build Materials UI by selecting the first point cloud (if nothing selected yet) | ||
| autoSelectFirstPointCloud() | ||
| } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| /** | ||
| * Syncs Potree's point cloud with Cesium's globe. | ||
| * | ||
| * @param potreeViewer - used for point cloud | ||
| * @param cesiumViewer - used for globe | ||
| */ | ||
| export function syncCameras(potreeViewer, cesiumViewer) { | ||
| const camera = potreeViewer.scene.getActiveCamera() | ||
|
|
||
| // Compute camera position, up vector, and target (pivot) in world coordinates | ||
| const pPos = new THREE.Vector3(0, 0, 0).applyMatrix4(camera.matrixWorld) | ||
| const pUp = new THREE.Vector3(0, 600, 0).applyMatrix4(camera.matrixWorld) | ||
| const pTarget = potreeViewer.scene.view.getPivot() | ||
|
|
||
| const toCes = (v) => new Cesium.Cartesian3(v.x, v.y, v.z) | ||
|
|
||
| const cPos = toCes(pPos) | ||
| const cUpTarget = toCes(pUp) | ||
| const cTarget = toCes(pTarget) | ||
|
|
||
| // Compute Cesium camera direction and up vectors | ||
| const cDir = Cesium.Cartesian3.normalize( | ||
| Cesium.Cartesian3.subtract(cTarget, cPos, new Cesium.Cartesian3()), | ||
| new Cesium.Cartesian3() | ||
| ) | ||
| const cUp = Cesium.Cartesian3.normalize( | ||
| Cesium.Cartesian3.subtract(cUpTarget, cPos, new Cesium.Cartesian3()), | ||
| new Cesium.Cartesian3() | ||
| ) | ||
|
|
||
| // Hide globe when the camera is below the surface, blocked by the curvature of the Earth or directly above the pivot | ||
| const showGlobe = shouldShowGlobe(cPos, cTarget, cDir) | ||
| cesiumViewer.scene.globe.show = showGlobe | ||
| cesiumViewer.scene.skyAtmosphere.show = showGlobe | ||
|
|
||
| // Sync Cesium camera position and orientation with Potree | ||
| cesiumViewer.camera.setView({ | ||
| destination: cPos, | ||
| orientation: { | ||
| direction: cDir, | ||
| up: cUp | ||
| } | ||
| }) | ||
|
|
||
| // Match FOV | ||
| const aspect = camera.aspect | ||
| const fovy = Math.PI * (camera.fov / 180) | ||
| if (aspect < 1) { | ||
| cesiumViewer.camera.frustum.fov = fovy | ||
| } else { | ||
| const fovx = Math.atan(Math.tan(0.5 * fovy) * aspect) * 2 | ||
| cesiumViewer.camera.frustum.fov = fovx | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Determines whether the globe should be visible based on the camera position. | ||
| * | ||
| * Returns false if the camera is below the globe surface, if the pivot | ||
| * point would be blocked by the curvature of the Earth or if the camera | ||
| * is looking almost straight down at the pivot. | ||
| * | ||
| * @param cameraPos - The camera position in Cesium.Cartesian3 coordinates | ||
| * @param pivot - The pivot point in Cesium.Cartesian3 coordinates | ||
| * @param direction - The camera direction as a Cesium.Cartesian3 unit vector | ||
| * @returns true if the globe should be visible, false if it should be hidden | ||
| */ | ||
| function shouldShowGlobe(cameraPos, pivot, direction) { | ||
| const ellipsoid = Cesium.Ellipsoid.WGS84 | ||
| const earthCenter = Cesium.Cartesian3.ZERO | ||
|
|
||
| // Get point on globe surface directly above the pivot | ||
| const carto = Cesium.Cartographic.fromCartesian(pivot) | ||
| const pivotSurface = Cesium.Cartesian3.fromRadians( | ||
| carto.longitude, | ||
| carto.latitude, | ||
| 0, | ||
| ellipsoid | ||
| ) | ||
|
|
||
| // Axis vector from Earth center through pivot | ||
| const axis = Cesium.Cartesian3.subtract( | ||
| pivotSurface, | ||
| earthCenter, | ||
| new Cesium.Cartesian3() | ||
| ) | ||
| Cesium.Cartesian3.normalize(axis, axis) | ||
|
|
||
| // Project camera and pivot onto this axis | ||
| const camProj = Cesium.Cartesian3.dot(cameraPos, axis) | ||
| const pivotProj = Cesium.Cartesian3.dot(pivotSurface, axis) | ||
|
|
||
| // Compute the dot product between camera direction and local vertical | ||
| // Used to detect if the camera is looking almost straight down | ||
| const targetNormal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(pivot) | ||
| const dotProduct = Math.abs(Cesium.Cartesian3.dot(direction, targetNormal)) | ||
|
|
||
| // If camera is "above" pivot on the axis, and not looking nearly straight down, the globe should be visible | ||
| // Otherwise, the globe should not be visible | ||
| return camProj >= pivotProj && dotProduct < 0.99 | ||
| } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /** | ||
| * Initializes the Cesium viewer used to visualize the globe. | ||
| * | ||
| * @param containerId - id of the container | ||
| * @returns Cesium viewer | ||
| */ | ||
| export function createCesiumViewer(containerId) { | ||
| const viewer = new Cesium.Viewer(containerId, { | ||
| useDefaultRenderLoop: false, | ||
| animation: false, | ||
| baseLayerPicker: false, | ||
| fullscreenButton: false, | ||
| geocoder: false, | ||
| homeButton: false, | ||
| infoBox: false, | ||
| sceneModePicker: false, | ||
| selectionIndicator: false, | ||
| timeline: false, | ||
| navigationHelpButton: false, | ||
| imageryProvider: Cesium.createOpenStreetMapImageryProvider({ | ||
| url: 'https://a.tile.openstreetmap.org/' | ||
| }), | ||
| terrainShadows: Cesium.ShadowMode.DISABLED | ||
| }) | ||
| return viewer | ||
| } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| export const POTREE_POINTCLOUD_URL = '/pointclouds/data_converted/metadata.json' | ||
|
|
||
| export const POTREE_SETTINGS = { | ||
| edl: true, | ||
| fov: 60, | ||
| pointBudget: 1_000_000 | ||
| } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,35 @@ | ||
| import { POTREE_POINTCLOUD_URL, POTREE_SETTINGS } from './config.js' | ||
| import { createCesiumViewer } from './cesiumViewer.js' | ||
| import { createPotreeViewer } from './potreeViewer.js' | ||
| import { syncCameras } from './cameraSync.js' | ||
| import { initCanvases, updatePosition, updateTargetElevation } from "./coordinateShowing/coordinateShowing.js"; | ||
|
|
||
| function init() { | ||
| initCanvases(); | ||
|
|
||
| async function init() { | ||
| window.cesiumViewer = createCesiumViewer('cesiumContainer') | ||
|
|
||
| window.potreeViewer = await createPotreeViewer( | ||
| 'potree_render_area', | ||
| POTREE_POINTCLOUD_URL, | ||
| POTREE_SETTINGS | ||
| ) | ||
|
|
||
| initCanvases(); | ||
|
|
||
| viewer.addEventListener("update", updatePosition); | ||
| viewer.addEventListener("update", updateTargetElevation); | ||
|
|
||
| window.addEventListener('resize', initCanvases); | ||
| } | ||
|
|
||
| init(); | ||
| function loop(timestamp) { | ||
| requestAnimationFrame(loop) | ||
| potreeViewer.update(potreeViewer.clock.getDelta(), timestamp) | ||
| potreeViewer.render() | ||
| syncCameras(potreeViewer, cesiumViewer) | ||
| cesiumViewer.render() | ||
| } | ||
|
|
||
| requestAnimationFrame(loop) | ||
| } | ||
|
|
||
| init() |
Oops, something went wrong.