diff --git a/index.html b/index.html index 432ff20..695a3bc 100644 --- a/index.html +++ b/index.html @@ -23,12 +23,17 @@ type="text/css" href="/libs/jstree/themes/mixed/style.css" /> + + - @@ -45,8 +50,10 @@ + +
+
+ + +
diff --git a/src/config.js b/src/config.js index fa55e71..16ac6ec 100644 --- a/src/config.js +++ b/src/config.js @@ -5,3 +5,6 @@ export const POTREE_SETTINGS = { fov: 60, pointBudget: 1_000_000 } + +export const ecef = '+proj=geocent +datum=WGS84 +units=m +no_defs' // EPSG:4978 (geocentric coordinates) +export const wgs84 = '+proj=longlat +datum=WGS84 +no_defs' // EPSG:4326 (geographic coordinates) \ No newline at end of file diff --git a/src/coordinateShowing/coordinateShowing.css b/src/coordinateShowing/coordinateShowing.css new file mode 100644 index 0000000..dd46e72 --- /dev/null +++ b/src/coordinateShowing/coordinateShowing.css @@ -0,0 +1,27 @@ +#canvasContainer { + display: flex; + flex-direction: column; + position: absolute; + right: 10px; + bottom: 10px; +} + +#posCanvas { + position: relative; + width: 300px; + height: 50px; + background-color: #19282c; + z-index: 10; + border-radius: 5px; +} + +#elevationCanvas { + position: relative; + width: 300px; + height: 50px; + background-color: #19282c; + z-index: 10; + margin-bottom: 10px; + border-radius: 5px; +} + diff --git a/src/coordinateShowing/coordinateShowing.js b/src/coordinateShowing/coordinateShowing.js new file mode 100644 index 0000000..bb7f360 --- /dev/null +++ b/src/coordinateShowing/coordinateShowing.js @@ -0,0 +1,80 @@ +import { ecef } from "../config.js"; +import { wgs84 } from "../config.js"; + +const posCanvas = document.getElementById('posCanvas') // lat/lon +const elevationCanvas = document.getElementById('elevationCanvas') + +export let posCtx +export let elevationCtx + +/** + * Initializes the canvases and their contexts. + */ +export function initCoordinateCanvases() { + posCtx = resizeCanvas(posCanvas) + elevationCtx = resizeCanvas(elevationCanvas) +} + +/** + * Resizes the canvas and its context to account for device pixel ratio. + * @param {*} canvas - The canvas element to resize. + * @returns {*} - The resized canvas context. + */ +function resizeCanvas(canvas) { + const dpr = window.devicePixelRatio || 1 + const ctx = canvas.getContext('2d') + + canvas.width = canvas.clientWidth * dpr + canvas.height = canvas.clientHeight * dpr + + // Scale context so drawing uses CSS pixels + ctx.setTransform(dpr, 0, 0, dpr, 0, 0) + return ctx +} + +/** + * Draw the text on a given canvas. + */ +function drawText(ctx, text, canvas) { + const centerX = canvas.clientWidth / 2 + const centerY = canvas.clientHeight / 2 + ctx.clearRect(0, 0, canvas.width, canvas.height) + ctx.fillStyle = '#cccccc' + ctx.font = '20px Arial' + ctx.textAlign = 'center' + ctx.textBaseline = 'middle' + ctx.fillText(text, centerX, centerY) +} + +/** + * Updates the lat/lon coordinates. + */ +export function updateCoordinateText() { + const cam = window.potreeViewer.scene.view.position + const [lon, lat] = proj4(ecef, wgs84, [cam.x, cam.y, cam.z]) + drawText( + posCtx, + `lat = ${lat.toFixed(5)}˚ lon = ${lon.toFixed(5)}˚`, + posCanvas + ) +} + +/** + * Shows target elevations if camera is in orbit mode. + */ +export function updateTargetElevation() { + const pivot = window.potreeViewer.scene.view.getPivot() + const controls = window.potreeViewer.getControls() + const height = proj4(ecef, wgs84, [pivot.x, pivot.y, pivot.z])[2] + + if (controls === window.potreeViewer.orbitControls) { + elevationCanvas.style.display = 'inline' + drawText( + elevationCtx, + `Target elevation = ${height.toFixed(4)}m`, + elevationCanvas + ) + } else { + elevationCanvas.style.display = 'none' + } +} diff --git a/src/main.js b/src/main.js index 82f7e1e..af6efff 100644 --- a/src/main.js +++ b/src/main.js @@ -2,6 +2,11 @@ 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 { + initCoordinateCanvases, + updateCoordinateText, + updateTargetElevation +} from "./CoordinateShowing/coordinateShowing.js"; async function init() { window.cesiumViewer = createCesiumViewer('cesiumContainer') @@ -12,6 +17,13 @@ async function init() { POTREE_SETTINGS ) + initCoordinateCanvases() + + potreeViewer.addEventListener('update', updateCoordinateText) + potreeViewer.addEventListener('update', updateTargetElevation) + + window.addEventListener('resize', initCoordinateCanvases) + function loop(timestamp) { requestAnimationFrame(loop) potreeViewer.update(potreeViewer.clock.getDelta(), timestamp) diff --git a/src/potreeViewer.js b/src/potreeViewer.js index 3f04686..4644388 100644 --- a/src/potreeViewer.js +++ b/src/potreeViewer.js @@ -1,4 +1,5 @@ import { initElevationControls } from './ElevationControl/elevationControl.js' +import { ecef } from './config.js' /** * Initializes the Potree viewer used to visualize the point cloud. @@ -55,7 +56,7 @@ export async function createPotreeViewer(containerId, pointcloudUrl, settings) { pc.material.activeAttributeName = 'elevation' pc.material.gradient = Potree.Gradients['VIRIDIS'] - e.pointcloud.projection = '+proj=geocent +datum=WGS84 +units=m +no_defs' + e.pointcloud.projection = ecef // Initialize camera position and target point (manually chosen) viewer.scene.view.setView(